[
  {
    "path": ".claude/.mcp.json",
    "content": "{\n  \"mcpServers\": {\n    \"angular-cli\": {\n      \"command\": \"npx\",\n      \"args\": [\n        \"-y\",\n        \"@angular/cli\",\n        \"mcp\"\n      ]\n    },\n    \"eslint\": {\n      \"command\": \"npx\",\n      \"args\": [\n        \"@eslint/mcp@latest\"\n      ],\n      \"env\": {}\n    }\n  }\n}"
  },
  {
    "path": ".claude/CLAUDE.md",
    "content": "You are an expert in TypeScript, Angular, and scalable web application development. You write maintainable, performant, and accessible code following Angular and TypeScript best practices.\n\n## TypeScript Best Practices\n\n- Use strict type checking\n- Prefer type inference when the type is obvious\n- Avoid the `any` type; use `unknown` when type is uncertain\n\n## Angular Best Practices\n\n- Always use standalone components over NgModules\n- Must NOT set `standalone: true` inside Angular decorators. It's the default.\n- Use signals for state management\n- Implement lazy loading for feature routes\n- Do NOT use the `@HostBinding` and `@HostListener` decorators. Put host bindings inside the `host` object of the `@Component` or `@Directive` decorator instead\n- Use `NgOptimizedImage` for all static images.\n  - `NgOptimizedImage` does not work for inline base64 images.\n\n## Components\n\n- Keep components small and focused on a single responsibility\n- Use `input()` and `output()` functions instead of decorators\n- Use `computed()` for derived state\n- Set `changeDetection: ChangeDetectionStrategy.OnPush` in `@Component` decorator\n- Prefer inline templates for small components\n- Prefer Reactive forms instead of Template-driven ones\n- Do NOT use `ngClass`, use `class` bindings instead\n- Do NOT use `ngStyle`, use `style` bindings instead\n\n## State Management\n\n- Use signals for local component state\n- Use `computed()` for derived state\n- Keep state transformations pure and predictable\n- Do NOT use `mutate` on signals, use `update` or `set` instead\n\n## Templates\n\n- Keep templates simple and avoid complex logic\n- Use native control flow (`@if`, `@for`, `@switch`) instead of `*ngIf`, `*ngFor`, `*ngSwitch`\n- Use the async pipe to handle observables\n\n## Services\n\n- Design services around a single responsibility\n- Use the `providedIn: 'root'` option for singleton services\n- Use the `inject()` function instead of constructor injection\n\n## More specific rules for NG Zorro project\n\n- see the full guide [here](./NG-ZORRO.md)\n"
  },
  {
    "path": ".claude/DEVELOPMENT.md",
    "content": "# Coding Style Guide\n\n### Basic Coding Guidelines\n\n- Written in TypeScript and Angular.\n- Each template must be defined in the component \"\\*.ts\" file using the `template` property of the `@Component` decorator.\n- Each official style must be defined in the component's `index.less` file.\n- Each CSS patch must be defined in the component's `patch.less` file.\n- Templates must follow the structure of the associated Ant Design component. Documentation can be found [here](https://ant.design/llms.txt) and [here](https://ant.design/llms-full.txt).\n- Support Server Side Rendering (SSR).\n- All imports of NG-ZORRO components need to be absolute. Example:\n\n```typescript\nimport { NzMentionComponent } from 'ng-zorro-antd/mention';\n```\n\n### Component Development\n\n- All code added to a component must be covered by unit tests. For guidelines on how to write unit tests, see the [testing](./TESTING.md) file.\n- New development on existing components must respect the existing structure of the component; where possible, use modern Angular features.\n- New components must be developed using the latest Angular features.\n- New features must be documented and include a demo. Guidelines on how to document can be found [here](./DOCUMENTATION.md).\n\n### TypeScript Guidelines\n\n- Use generics where appropriate to enhance type flexibility.\n- Use intersection types (&) to combine multiple types.\n- Use literal union types to define a limited set of options.\n- Avoid using `enum` in favor of union types and `as const`.\n- Rely on TypeScript's type inference whenever possible.\n- Use type assertions (`as`) only when necessary.\n\n### Responsiveness and Theming Support\n\n- Components should display well on different screen sizes.\n- All components must support dark mode.\n- Components should support right-to-left (RTL) text directions.\n- Use logical CSS properties (e.g., `margin-inline-start`) instead of directional properties (e.g., `margin-left`).\n"
  },
  {
    "path": ".claude/DOCUMENTATION.md",
    "content": "# Demo Code Standards\n\n### Basic Demo Requirements\n\n- Keep demo code as concise as possible.\n- Avoid redundant code to facilitate direct copying and use in your projects.\n- Each demo should focus on demonstrating a single feature.\n- Provide instructions in both Chinese and English.\n- Follow a demo-first principle to ensure good visual quality.\n- Demonstrate the main usage scenarios of the component.\n- Arrange demos from simple to complex.\n\n### API Documentation\n\n- Use a table format to document the API.\n\n| Property  | Description | Type                       | Default      | Global Config |\n| --------- | ----------- | -------------------------- | ------------ | ------------- |\n| `htmlType`  | xxx         | string                     | `button`     | ✅            |\n| `type`      | xxx         | `horizontal` \\| `vertical` | `horizontal` | ✅            |\n| `disabled`  | xxx         | boolean                    | false        | ✅            |\n| `minLength` | xxx         | number                     | 0            | ✅            |\n| `style`     | xxx         | CSSProperties              | -            |\n\n- Provide API documentation for each component.\n- Provide API documentation in Chinese and English.\n- API documentation is located in each component's `doc/` folder.\n"
  },
  {
    "path": ".claude/NG-ZORRO.md",
    "content": "# Introduction\n\nThis file provides guidance to Claude Code when working on the NG-ZORRO project.\n\n## Project Context\n\nThe NG-ZORRO project is an Angular project that provides a set of UI components for Angular applications. It is based on the Ant Design project but is not a fork of it.\nIt's a community project that rewrites the Ant Design project to be used with Angular.\n\n## Project Structure\n\nng-zorro-antd/\n├── components/ # Main NG-ZORRO components (70+ UI components)\n│ ├── core/ # Core utilities and services\n│ │ ├── animation/\n│ │ ├── color/\n│ │ ├── config/\n│ │ ├── form/\n│ │ ├── services/\n│ │ ├── testing/\n│ │ ├── util/\n│ │ └── ...\n│ ├── cdk/ # Component Development Kit\n│ │ ├── overflow/\n│ │ └── resize-observer/\n│ ├── i18n/\n│ │ └── languages/\n│ ├── style/ # Global styles and themes\n│ │ ├── color/\n│ │ ├── core/\n│ │ ├── mixins/\n│ │ └── themes/\n│ └── [70+ UI components]/ # Individual components (affix, alert, button, etc.)\n├── docs/ # Documentation source files\n├── node_modules/ # Dependencies (excluded from git)\n├── schematics/ # Angular schematics\n│ ├── ng-add/\n│ │ └── setup-project/\n│ ├── ng-component/\n│ │ └── files/\n│ ├── ng-generate/\n│ │ ├── blank/\n│ │ ├── side-menu/\n│ │ └── topnav/\n│ ├── ng-update/\n│ │ ├── data/\n│ │ ├── migrations/\n│ │ └── upgrade-rules/\n│ ├── testing/\n│ └── utils/\n├── scripts/ # Build and utility scripts\n│ ├── build/\n│ ├── gulp/\n│ ├── prerender/\n│ ├── release/\n│ ├── schematics/\n│ └── site/\n├── .editorconfig # Editor configuration\n├── .gitignore # Git ignore rules\n├── .lintstagedrc # Lint-staged configuration\n├── .npmrc # npm configuration\n├── .nvmrc # Node version specification\n├── .prettierignore # Prettier ignore rules\n├── .prettierrc.js # Prettier configuration\n├── .stylelintrc.json # Stylelint configuration\n├── angular.json # Angular workspace configuration\n├── azure-pipelines.yml # Azure DevOps pipeline\n├── build-config.js # Build configuration\n├── CHANGELOG.md # Version changelog\n├── CODE_OF_CONDUCT.md # Code of conduct\n├── commitlint.config.js # Commit message linting\n├── CONTRIBUTING.md # Contribution guidelines\n├── eslint.config.mjs # ESLint configuration\n├── gulpfile.js # Gulp build tasks\n├── LICENSE # MIT License\n├── logo.svg # Project logo\n├── ngsw-config.json # Angular service worker config\n├── package-lock.json # Dependency lock file\n├── package.json # Project dependencies and scripts\n├── README.md # Project documentation\n├── README-zh_CN.md # Chinese documentation\n├── tea.yaml # Tea package manager config\n├── tsconfig.json # TypeScript configuration\n└── tsconfig-build.json # Build-specific TypeScript config\n\nEach component located in the `components/` folder is composed of the following files:\n\n- `public-api.ts`: The public API of the component\n- `index.ts`: The entry point of the component\n- `src/`: The source code of the component\n- `style/`: The styles of the component\n- `demo/`: The demos of the component\n- `doc/`: The main documentation of the component\n- `*\\.component.ts`: The component file\n- `*\\.component.spec.ts`: The component tests\n\n## Installation and Setup\n\n### Development environment requirements\n\n- Node.js v20.19.0 or higher\n- npm recommended\n\n### Install dependencies\n\n- Run `npm install` to install dependencies\n\n### Development commands\n\n- Run `npm run start` to start the development server\n- Run `npm run build` to build the project\n- Run `npm run build:lib` to build the library\n- Run `npm run build:schematics` to build the schematics\n- Run `npm run test:schematics` to test the schematics\n- Run `npm run test` to run tests\n\n## Coding Style Guide\n\nMore information can be found [here](./DEVELOPMENT.md).\n"
  },
  {
    "path": ".claude/TESTING.md",
    "content": "# Testing Guidelines\n\n### Testing Framework and Tools\n\n- Use Karma and Jasmine for unit testing\n- Require 100% of code coverage\n- Follow unit testing best practices\n- Keep tests simple and focused\n- Use testing helpers. You can find the helpers in the directory `components/core/testing`\n- Respect the existing testing structure\n- Ensure all tests pass; if not, please fix them\n\n### Testing Scripts\n\n```bash\nnpm test # Run all tests\nnpm test -- --watch # Watch mode\nnpm run test -- --include=\"**/mention.spec.ts\" # Run tests for a specific file (here: mention)\n```\n"
  },
  {
    "path": ".cursor/mcp.json",
    "content": "{\n  \"mcpServers\": {\n    \"angular-cli\": {\n      \"command\": \"npx\",\n      \"args\": [\n        \"-y\",\n        \"@angular/cli\",\n        \"mcp\"\n      ]\n    },\n    \"eslint\": {\n      \"command\": \"npx\",\n      \"args\": [\n        \"@eslint/mcp@latest\"\n      ],\n      \"env\": {}\n    }\n  }\n}"
  },
  {
    "path": ".cursor/rules/cursor.mdc",
    "content": "---\ncontext: true\npriority: high\nscope: project\n---\n\nYou are an expert in TypeScript, Angular, and scalable web application development. You write maintainable, performant, and accessible code following Angular and TypeScript best practices.\n\n## TypeScript Best Practices\n\n- Use strict type checking\n- Prefer type inference when the type is obvious\n- Avoid the `any` type; use `unknown` when type is uncertain\n\n## Angular Best Practices\n\n- Always use standalone components over NgModules\n- Must NOT set `standalone: true` inside Angular decorators. It's the default.\n- Use signals for state management\n- Implement lazy loading for feature routes\n- Do NOT use the `@HostBinding` and `@HostListener` decorators. Put host bindings inside the `host` object of the `@Component` or `@Directive` decorator instead\n- Use `NgOptimizedImage` for all static images.\n  - `NgOptimizedImage` does not work for inline base64 images.\n\n## Components\n\n- Keep components small and focused on a single responsibility\n- Use `input()` and `output()` functions instead of decorators\n- Use `computed()` for derived state\n- Set `changeDetection: ChangeDetectionStrategy.OnPush` in `@Component` decorator\n- Prefer inline templates for small components\n- Prefer Reactive forms instead of Template-driven ones\n- Do NOT use `ngClass`, use `class` bindings instead\n- Do NOT use `ngStyle`, use `style` bindings instead\n\n## State Management\n\n- Use signals for local component state\n- Use `computed()` for derived state\n- Keep state transformations pure and predictable\n- Do NOT use `mutate` on signals, use `update` or `set` instead\n\n## Templates\n\n- Keep templates simple and avoid complex logic\n- Use native control flow (`@if`, `@for`, `@switch`) instead of `*ngIf`, `*ngFor`, `*ngSwitch`\n- Use the async pipe to handle observables\n\n## Services\n\n- Design services around a single responsibility\n- Use the `providedIn: 'root'` option for singleton services\n- Use the `inject()` function instead of constructor injection\n"
  },
  {
    "path": ".editorconfig",
    "content": "[*]\ncharset=utf-8\nend_of_line=lf\ntrim_trailing_whitespace=true\ninsert_final_newline=false\nindent_style=space\nindent_size=2\n\n[{*.ng,*.sht,*.html,*.shtm,*.shtml,*.htm}]\nindent_style=space\nindent_size=2\n\n[{.babelrc,.stylelintrc,.eslintrc,jest.config,*.json,*.jsb3,*.jsb2,*.bowerrc}]\nindent_style=space\nindent_size=2\n\n[*.css]\nindent_style=space\nindent_size=2\n\n[{*.applejs,*.js}]\nindent_style=space\nindent_size=2\n\n[{*.ats,*.ts}]\nindent_style=space\nindent_size=2\n\n[*.tsx]\nindent_style=space\nindent_size=2\n\n[*.js]\nindent_style=space\nindent_size=2\n\n[*.js.map]\nindent_style=space\nindent_size=2\n\n[*.less]\nindent_style=space\nindent_size=2\n\n[{.analysis_options,*.yml,*.yaml}]\nindent_style=space\nindent_size=2\n"
  },
  {
    "path": ".gemini/GEMINI.md",
    "content": "You are an expert in TypeScript, Angular, and scalable web application development. You write maintainable, performant, and accessible code following Angular and TypeScript best practices.\n\n## TypeScript Best Practices\n\n- Use strict type checking\n- Prefer type inference when the type is obvious\n- Avoid the `any` type; use `unknown` when type is uncertain\n\n## Angular Best Practices\n\n- Always use standalone components over NgModules\n- Must NOT set `standalone: true` inside Angular decorators. It's the default.\n- Use signals for state management\n- Implement lazy loading for feature routes\n- Do NOT use the `@HostBinding` and `@HostListener` decorators. Put host bindings inside the `host` object of the `@Component` or `@Directive` decorator instead\n- Use `NgOptimizedImage` for all static images.\n  - `NgOptimizedImage` does not work for inline base64 images.\n\n## Components\n\n- Keep components small and focused on a single responsibility\n- Use `input()` and `output()` functions instead of decorators\n- Use `computed()` for derived state\n- Set `changeDetection: ChangeDetectionStrategy.OnPush` in `@Component` decorator\n- Prefer inline templates for small components\n- Prefer Reactive forms instead of Template-driven ones\n- Do NOT use `ngClass`, use `class` bindings instead\n- Do NOT use `ngStyle`, use `style` bindings instead\n\n## State Management\n\n- Use signals for local component state\n- Use `computed()` for derived state\n- Keep state transformations pure and predictable\n- Do NOT use `mutate` on signals, use `update` or `set` instead\n\n## Templates\n\n- Keep templates simple and avoid complex logic\n- Use native control flow (`@if`, `@for`, `@switch`) instead of `*ngIf`, `*ngFor`, `*ngSwitch`\n- Use the async pipe to handle observables\n\n## Services\n\n- Design services around a single responsibility\n- Use the `providedIn: 'root'` option for singleton services\n- Use the `inject()` function instead of constructor injection\n"
  },
  {
    "path": ".gemini/settings.json",
    "content": "{\n  \"mcpServers\": {\n    \"angular-cli\": {\n      \"command\": \"npx\",\n      \"args\": [\n        \"-y\",\n        \"@angular/cli\",\n        \"mcp\"\n      ]\n    },\n    \"eslint\": {\n      \"command\": \"npx\",\n      \"args\": [\n        \"@eslint/mcp@latest\"\n      ],\n      \"env\": {}\n    }\n  }\n}"
  },
  {
    "path": ".gitattributes",
    "content": "# Enforce Unix newlines\n*.css   text eol=lf\n*.html  text eol=lf\n*.js    text eol=lf\n*.ts    text eol=lf\n*.json  text eol=lf\n*.less  text eol=lf\n*.md    text eol=lf\n*.yml   text eol=lf\n"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "# The components owners\ncomponents/affix/**                       @cipchk\ncomponents/anchor/**                      @cipchk\ncomponents/list/**                        @cipchk\ncomponents/upload/**                      @cipchk\ncomponents/auto-complete/**               @hsuanxyz\ncomponents/avatar/**                      @hsuanxyz\ncomponents/badge/**                       @hsuanxyz\ncomponents/comment/**                     @hsuanxyz\ncomponents/drawer/**                      @hsuanxyz\ncomponents/mention/**                     @hsuanxyz\ncomponents/modal/**                       @hsuanxyz\ncomponents/steps/**                       @hsuanxyz\ncomponents/tag/**                         @hsuanxyz\ncomponents/tree-select/**                 @hsuanxyz\ncomponents/tree-view/**                   @hsuanxyz\ncomponents/typography/**                  @hsuanxyz\ncomponents/space/**                       @hsuanxyz\ncomponents/resizable/**                   @hsuanxyz\ncomponents/tabs/**                        @hsuanxyz\ncomponents/breadcrumb/**                  @simplejason\ncomponents/empty/**                       @simplejason\ncomponents/carousel/**                    @simplejason\ncomponents/cascader/**                    @laffery\ncomponents/descriptions/**                @simplejason\ncomponents/icon/**                        @simplejason\ncomponents/message/**                     @simplejason\ncomponents/notification/**                @simplejason\ncomponents/popconfirm/**                  @simplejason\ncomponents/popover/**                     @simplejason\ncomponents/progress/**                    @simplejason\ncomponents/rate/**                        @simplejason\ncomponents/result/**                      @simplejason\ncomponents/slider/**                      @simplejason\ncomponents/statistic/**                   @simplejason\ncomponents/timeline/**                    @simplejason\ncomponents/tooltip/**                     @simplejason\ncomponents/code-editor/**                 @simplejason\ncomponents/segmented/**                   @simplejason\ncomponents/calendar/**                    @wenqi73\ncomponents/date-picker/**                 @wenqi73\ncomponents/skeleton/**                    @wenqi73\ncomponents/time-picker/**                 @wenqi73\ncomponents/alert/**                       @vthinkxie\ncomponents/button/**                      @vthinkxie\ncomponents/card/**                        @vthinkxie\ncomponents/checkbox/**                    @vthinkxie\ncomponents/collapse/**                    @vthinkxie\ncomponents/divider/**                     @vthinkxie\ncomponents/dropdown/**                    @vthinkxie\ncomponents/grid/**                        @vthinkxie\ncomponents/input/**                       @vthinkxie\ncomponents/input-number/**                @vthinkxie\ncomponents/layout/**                      @vthinkxie\ncomponents/menu/**                        @vthinkxie\ncomponents/pagination/**                  @vthinkxie\ncomponents/radio/**                       @vthinkxie\ncomponents/select/**                      @vthinkxie\ncomponents/spin/**                        @vthinkxie\ncomponents/splitter/**                    @laffery\ncomponents/switch/**                      @vthinkxie\ncomponents/table/**                       @vthinkxie\ncomponents/tree/**                        @simplejason\ncomponents/form/**                        @danranVm\ncomponents/page-header/**                 @CK110\ncomponents/transfer/**                    @Ricbet\ncomponents/i18n/**                        @wenqi73\ncomponents/pipes/**                       @chensimeng\ncomponents/image/**                       @stygian-desolator\ncomponents/qr-code/**                     @OriginRing\ncomponents/cron-expression/**             @OriginRing\ncomponents/watermark/**                   @OriginRing\ncomponents/color-picker/**                @OriginRing\ncomponents/hash-code/**                   @OriginRing\ncomponents/flex/**                        @ParsaArvanehPA\ncomponents/float-button/**                @OriginRing\ncomponents/check-list/**                  @OriginRing\n\n# The `components/core/*` owners\ncomponents/core/config/**                 @simplejason\ncomponents/core/element-patch/**          @simplejason\ncomponents/core/highlight/**              @hsuanxyz\ncomponents/core/resize-observers/**       @simplejason\ncomponents/core/logger/**                 @simplejason\ncomponents/core/no-animation/**           @hsuanxyz\ncomponents/core/outlet/**                 @vthinkxie\ncomponents/core/time/**                   @wenqi73\ncomponents/core/trans-button/**           @hsuanxyz\ncomponents/core/transition-patch/**       @vthinkxie\ncomponents/core/tree/**                   @simplejason @laffery\ncomponents/core/wave/**                   @hsuanxyz\n\n# Misc\ndocs/**                                   @NG-ZORRO/antd\nschematics/**                             @hsuanxyz\nscript/**                                 @hsuanxyz\nREADME.md                                 @vthinkxie\nREADME-zh_CN.md                           @vthinkxie\nCONTRIBUTING.md                           @vthinkxie\nCODE_OF_CONDUCT.md                        @vthinkxie\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: true\ncontact_links:\n  - name: Create new issue\n    url: https://ng.ant.design/issue-helper/#/en\n    about: The issue which is not created via issue-helper will be closed immediately.\n  - name: 报告问题\n    url: https://ng.ant.design/issue-helper/#/zh\n    about: 注意：不是用 issue-helper 创建的 issue 会被立即关闭。"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "<!--\nIMPORTANT: Please use the following link to create a new issue:\n\n  https://ng.ant.design/issue-helper/#/en\n\nIf your issue was not created using the app above, it will be closed immediately.\n-->\n\n<!--\n注意：请使用下面的链接来新建 issue：\n\n  https://ng.ant.design/issue-helper/#/zh\n\n不是用上面的链接创建的 issue 会被立即关闭。\n-->\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "## PR Checklist\nPlease check if your PR fulfills the following requirements:\n\n- [ ] The commit message follows our guidelines: https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/CONTRIBUTING.md#commit\n- [ ] Tests for the changes have been added (for bug fixes / features)\n- [ ] Docs have been added / updated (for bug fixes / features)\n\n\n## PR Type\nWhat kind of change does this PR introduce?\n\n<!-- Please check the one that applies to this PR using \"x\". -->\n- [ ] Bugfix\n- [ ] Feature\n- [ ] Code style update (formatting, local variables)\n- [ ] Refactoring (no functional changes, no api changes)\n- [ ] Build related changes\n- [ ] CI related changes\n- [ ] Documentation content changes\n- [ ] Application (the showcase website) / infrastructure changes\n- [ ] Other... Please describe:\n\n## What is the current behavior?\n<!-- Please describe the current behavior that you are modifying, or link to a relevant issue. -->\n\nIssue Number: N/A\n\n\n## What is the new behavior?\n\n\n## Does this PR introduce a breaking change?\n- [ ] Yes\n- [ ] No\n\n<!-- If this PR contains a breaking change, please describe the impact and migration path for existing applications below. -->\n\n\n## Other information\n"
  },
  {
    "path": ".github/auto_assign.yml",
    "content": "# Set to true to add reviewers to pull requests\naddReviewers: false\n\n# Set to true to add assignees to pull requests\naddAssignees: true\n\n# A list of reviewers to be added to pull requests (GitHub user name)\nreviewers:\n  - vthinkxie\n  - hsuanxyz\n  - simplejason\n  - wenqi73\n  - laffery\n\n# A list of keywords to be skipped the process that add reviewers if pull requests include it\nskipKeywords:\n  - wip\n  - WIP\n\n# A number of reviewers added to the pull request\n# Set 0 to add all the reviewers (default: 0)\nnumberOfReviewers: 1\n"
  },
  {
    "path": ".github/copilot-instructions.md",
    "content": "You are an expert in TypeScript, Angular, and scalable web application development. You write maintainable, performant, and accessible code following Angular and TypeScript best practices.\n\n## TypeScript Best Practices\n\n- Use strict type checking\n- Prefer type inference when the type is obvious\n- Avoid the `any` type; use `unknown` when type is uncertain\n\n## Angular Best Practices\n\n- Always use standalone components over NgModules\n- Must NOT set `standalone: true` inside Angular decorators. It's the default.\n- Use signals for state management\n- Implement lazy loading for feature routes\n- Do NOT use the `@HostBinding` and `@HostListener` decorators. Put host bindings inside the `host` object of the `@Component` or `@Directive` decorator instead\n- Use `NgOptimizedImage` for all static images.\n  - `NgOptimizedImage` does not work for inline base64 images.\n\n## Components\n\n- Keep components small and focused on a single responsibility\n- Use `input()` and `output()` functions instead of decorators\n- Use `computed()` for derived state\n- Set `changeDetection: ChangeDetectionStrategy.OnPush` in `@Component` decorator\n- Prefer inline templates for small components\n- Prefer Reactive forms instead of Template-driven ones\n- Do NOT use `ngClass`, use `class` bindings instead\n- Do NOT use `ngStyle`, use `style` bindings instead\n\n## State Management\n\n- Use signals for local component state\n- Use `computed()` for derived state\n- Keep state transformations pure and predictable\n- Do NOT use `mutate` on signals, use `update` or `set` instead\n\n## Templates\n\n- Keep templates simple and avoid complex logic\n- Use native control flow (`@if`, `@for`, `@switch`) instead of `*ngIf`, `*ngFor`, `*ngSwitch`\n- Use the async pipe to handle observables\n\n## Services\n\n- Design services around a single responsibility\n- Use the `providedIn: 'root'` option for singleton services\n- Use the `inject()` function instead of constructor injection\n"
  },
  {
    "path": ".github/lock.yml",
    "content": "# Configuration for lock-threads - https://github.com/dessant/lock-threads\n\n# Number of days of inactivity before a closed issue or pull request is locked\ndaysUntilLock: 365\n# Comment to post before locking. Set to `false` to disable\nlockComment: >\n  This thread has been automatically locked because it has not had recent\n  activity. Please open a new issue for related bugs and link to relevant\n  comments in this thread.\n# Issues or pull requests with these labels will not be locked\n# exemptLabels:\n#   - no-locking\n# Limit to only `issues` or `pulls`\nonly: issues"
  },
  {
    "path": ".github/no-response.yml",
    "content": "# Configuration for probot-no-response - https://github.com/probot/no-response\n\n# Number of days of inactivity before an Issue is closed for lack of response\ndaysUntilClose: 7\n# Label requiring a response\nresponseRequiredLabel: Need More Info\n# Comment to post when closing an Issue for lack of response. Set to `false` to disable\ncloseComment: >\n  This issue has been automatically closed because there has been no response\n  to our request for more information from the original author. With only the\n  information that is currently in the issue, we don't have enough information\n  to take action. If you can provide more information, feel free to ping anyone of\n  our maintainers to reopen this issue.\n  Thank you for your contributions.\n  ---\n  这个 issue 已经被自动关闭，因为您没有向我们提供更多的信息。仅凭目前的描述我们无法采取任\n  何行动，如果您能提供更多的信息请随时联系我们的开发人员重新打开这个 issue。\n  感谢您的贡献。"
  },
  {
    "path": ".github/nz-boot.yml",
    "content": "pullRequest:\n  preview:\n    replay: |\n      This [preview](https://preview-{number}-ng-zorro-antd.surge.sh/) will be available after the AzureCI is passed.\nissue:\n  labeledReplay:\n    - labels:\n        - help wanted\n      replay: |\n        Hello @{user}. We totally like your proposal/feedback, welcome to [send us a Pull Request](https://help.github.com/en/articles/creating-a-pull-request) for it. Please fill the [Pull Request Template](https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/.github/PULL_REQUEST_TEMPLATE.md) here, provide documentation/test cases if needed and make sure CI passed, we will review it soon. Appreciate it advance and we are looking forward to your contribution!\n\n        你好 @{user}, 我们完全同意你的提议/反馈，欢迎直接在此仓库 [创建一个 Pull Request](https://help.github.com/en/articles/creating-a-pull-request) 来解决这个问题。请务必填写 Pull Request 内的[预设模板](https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/.github/PULL_REQUEST_TEMPLATE.md)，提供改动所需相应的测试用例、文档等，并确保 CI 通过，我们会尽快进行 Review，提前感谢和期待您的贡献！\n        ![giphy](https://user-images.githubusercontent.com/507615/62342668-4735dc00-b51a-11e9-92a7-d46fbb1cc0c7.gif)\n    - labels:\n        - Upgrade Deps\n      replay: |\n        Hello @{user}.\n        - If you use npm, please try `rm -rf node_modules && npm install` to upgrade all your deps.\n        - If you use yarn, you may need `yarn upgrade`.\n\n        <img src=\"https://cloud.githubusercontent.com/assets/465125/26667345/4bcc8f10-46d7-11e7-8c72-32a0c68ea7ca.jpg\" width=\"500\" height=\"300\">\n    - labels:\n        - Usage\n        - Question\n      replay: |\n        Hello @{user}, we use GitHub issues to trace bugs or discuss plans of Ant Design.\n        So, please [don't ask usage questions](https://github.com/ant-design/ant-design/issues/2320) here.\n        You can try to ask questions on [Stack Overflow](http://stackoverflow.com/questions/tagged/ng-zorro-antd) or [Segment Fault](https://segmentfault.com/t/ng-zorro), then apply tag `ng-zorro-antd` or `ng-zorro` to your question.\n\n        你好 @{user}，Ant Design Issue 板块是用于 bug 反馈与需求讨论的地方。\n        请[勿询问如何使用的问题](https://github.com/ant-design/ant-design/issues/2320)\n        你可以试着在 [Stack Overflow](http://stackoverflow.com/questions/tagged/ng-zorro-antd) 或者 [Segment Fault](https://segmentfault.com/t/ng-zorro) 中提问（记得添加 `ng-zorro-antd` 或 `ng-zorro` 标签）。\n  translate:\n    replay: |\n      Translation of this issue:\n      ---\n      ## {title}\n\n      {body}\n  needReproduce:\n    label: Need Reproduce\n    afterLabel: Need More Info\n    replay: |\n      Hello @{user}. Please provide a online reproduction by forking this link https://stackblitz.com/edit/ng-zorro-antd-start or a minimal GitHub repository.\n      Issues labeled by `Need Reproduce` will be closed if no activities in 7 days.\n\n      你好 @{user}, 我们需要你提供一个在线的重现实例以便于我们帮你排查问题。你可以通过点击 [此处](https://stackblitz.com/edit/ng-zorro-antd-start) 创建一个 stackblitz 或者提供一个最小化的 GitHub 仓库\n      被标记为 `Need Reproduce` 的 issue 7 天内未跟进将会被自动关闭。\n      ![](https://gw.alipayobjects.com/zos/antfincdn/y9kwg7DVCd/reproduce.gif)\n  invalid:\n    mark: ng-zorro-issue-helper\n    labels: Invalid\n    replay: |\n      Hello @{user}, your issue has been closed because it does not conform to our issue requirements.\n      Please use the [Issue Helper](http://ng.ant.design/issue-helper/#/en) to create an issue, thank you!\n\n\n      你好 @{user}，为了能够进行高效沟通，我们对 issue 有一定的格式要求，你的 issue 因为不符合要求而被自动关闭。\n      你可以通过 [issue 助手](http://ng.ant.design/issue-helper/#/zh) 来创建 issue 以方便我们定位错误。谢谢配合！\n  assignOwner:\n    labelTemplate: 'Component: {component}'\n    components:\n      Affix: cipchk\n      Anchor: cipchk\n      List: cipchk\n      Upload: cipchk\n      AutoComplete: hsuanxyz\n      Avatar: hsuanxyz\n      Badge: hsuanxyz\n      Comment: hsuanxyz\n      Drawer: hsuanxyz\n      Mention: hsuanxyz\n      Modal: hsuanxyz\n      Steps: hsuanxyz\n      Tag: hsuanxyz\n      TreeSelect: hsuanxyz\n      TreeView: hsuanxyz\n      Typography: hsuanxyz\n      Space: hsuanxyz\n      Resizable: hsuanxyz\n      Breadcrumb: simplejason\n      Empty: simplejason\n      Carousel: simplejason\n      Cascader: simplejason\n      Descriptions: simplejason\n      Icon: simplejason\n      Message: simplejason\n      Notification: simplejason\n      Popconfirm: simplejason\n      Popover: simplejason\n      Progress: simplejason\n      Rate: simplejason\n      Result: simplejason\n      Slider: simplejason\n      Statistic: simplejason\n      Timeline: simplejason\n      Tooltip: simplejason\n      CodeEditor: simplejason\n      Calendar: wenqi73\n      DatePicker: wenqi73\n      Skeleton: wenqi73\n      TimePicker: wenqi73\n      I18n: wenqi73\n      Alert: vthinkxie\n      Button: vthinkxie\n      Card: vthinkxie\n      Checkbox: vthinkxie\n      Collapse: vthinkxie\n      Divider: vthinkxie\n      Dropdown: vthinkxie\n      Grid: vthinkxie\n      Input: vthinkxie\n      InputNumber: vthinkxie\n      Layout: vthinkxie\n      Menu: vthinkxie\n      Pagination: vthinkxie\n      Radio: vthinkxie\n      Select: vthinkxie\n      Spin: vthinkxie\n      Switch: vthinkxie\n      Table: vthinkxie\n      Tabs: NearZXH\n      Tree: simplejason\n      Form: danranVm\n      PageHeader: CK110\n      Transfer: Ricbet\n      Pipes: chensimeng\n      Image: stygian-desolator\n      Splitter: laffery\n"
  },
  {
    "path": ".github/semantic.yml",
    "content": "titleAndCommits: true\ntypes:\n  - feat\n  - fix\n  - docs\n  - style\n  - refactor\n  - perf\n  - test\n  - build\n  - ci\n  - chore\n  - revert"
  },
  {
    "path": ".github/workflows/sync-styles.yml",
    "content": "name: styles-sync\non:\n  push:\n    branches: [ master ]\n  workflow_dispatch:\n    inputs:\n      version:\n        description: 'Which version want to synchronize (Default latest)'\njobs:\n  preview:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: hsuanxyz/zorro-styles-sync-action@v1.1\n        with:\n          account_token: ${{ secrets.BOT_TOKEN }}\n          version: ${{ github.event.inputs.version }}\n"
  },
  {
    "path": ".gitignore",
    "content": "# See http://help.github.com/ignore-files/ for more about ignoring files.\n\n__ngcc_entry_points__.json\n\n# compiled output\ndist/\ntmp/\njunit/\nout-tsc/\n/site\npublish/\nlib/\nschematics/demo\nschematics/utils/version-names.ts\nng-zorro.github.io/\narchive-docs/\n\n# dependencies\nnode_modules\nnode_modules.*/\nintegration/**/package-lock.json\nyarn.lock\n\n# IDEs and editors\n.idea/\n.project\n.classpath\n.c9/\n*.launch\n.settings/\n*.sublime-workspace\n\n# IDE - VSCode\n.vscode/*\n!.vscode/mcp.json\n\n# misc\n/.angular/cache\n/.nx-cache\n/.nx\n/.sass-cache\n/connect.lock\n/coverage\n/coverage-report\n/libpeerconnection.log\nnpm-debug.log\ntestem.log\n/typings\n.eslintcache\nyarn-error.log\nreport.*.json\n\n# e2e\n/e2e/*.js\n/e2e/*.map\n\n# System Files\n.DS_Store\nThumbs.db\n\nmonospace.json\n"
  },
  {
    "path": ".husky/.gitignore",
    "content": "_\n"
  },
  {
    "path": ".husky/commit-msg",
    "content": "export 'HUSKY_GIT_PARAMS'=\"$1\"\nnpx --no-install commitlint --edit \"$1\""
  },
  {
    "path": ".husky/pre-commit",
    "content": "export NODE_OPTIONS=\"--max-old-space-size=4096\"\nnpm run pre-commit\n"
  },
  {
    "path": ".junie/guidelines.md",
    "content": "You are an expert in TypeScript, Angular, and scalable web application development. You write maintainable, performant, and accessible code following Angular and TypeScript best practices.\n\n## TypeScript Best Practices\n\n- Use strict type checking\n- Prefer type inference when the type is obvious\n- Avoid the `any` type; use `unknown` when type is uncertain\n\n## Angular Best Practices\n\n- Always use standalone components over NgModules\n- Must NOT set `standalone: true` inside Angular decorators. It's the default.\n- Use signals for state management\n- Implement lazy loading for feature routes\n- Do NOT use the `@HostBinding` and `@HostListener` decorators. Put host bindings inside the `host` object of the `@Component` or `@Directive` decorator instead\n- Use `NgOptimizedImage` for all static images.\n  - `NgOptimizedImage` does not work for inline base64 images.\n\n## Components\n\n- Keep components small and focused on a single responsibility\n- Use `input()` and `output()` functions instead of decorators\n- Use `computed()` for derived state\n- Set `changeDetection: ChangeDetectionStrategy.OnPush` in `@Component` decorator\n- Prefer inline templates for small components\n- Prefer Reactive forms instead of Template-driven ones\n- Do NOT use `ngClass`, use `class` bindings instead\n- Do NOT use `ngStyle`, use `style` bindings instead\n\n## State Management\n\n- Use signals for local component state\n- Use `computed()` for derived state\n- Keep state transformations pure and predictable\n- Do NOT use `mutate` on signals, use `update` or `set` instead\n\n## Templates\n\n- Keep templates simple and avoid complex logic\n- Use native control flow (`@if`, `@for`, `@switch`) instead of `*ngIf`, `*ngFor`, `*ngSwitch`\n- Use the async pipe to handle observables\n\n## Services\n\n- Design services around a single responsibility\n- Use the `providedIn: 'root'` option for singleton services\n- Use the `inject()` function instead of constructor injection\n"
  },
  {
    "path": ".junie/mcp.json",
    "content": "{\n  \"mcpServers\": {\n    \"angular-cli\": {\n      \"command\": \"npx\",\n      \"args\": [\n        \"-y\",\n        \"@angular/cli\",\n        \"mcp\"\n      ]\n    },\n    \"eslint\": {\n      \"command\": \"npx\",\n      \"args\": [\n        \"@eslint/mcp@latest\"\n      ],\n      \"env\": {}\n    }\n  }\n}"
  },
  {
    "path": ".lintstagedrc",
    "content": "{\n  \"*.less\": \"stylelint --fix\",\n  \"*.{md,html,ts}\": \"eslint --fix\"\n}\n"
  },
  {
    "path": ".npmrc",
    "content": "node-options=--max-old-space-size=14000\n"
  },
  {
    "path": ".nvmrc",
    "content": "20.19.0"
  },
  {
    "path": ".prettierignore",
    "content": "**/*.svg\n**/test.ts\ncoverage/\npublish/\nschematics/\npackage.json\n**/template/*\ndist\n"
  },
  {
    "path": ".prettierrc.js",
    "content": "module.exports = {\n  singleQuote: true,\n  useTabs: false,\n  printWidth: 120,\n  tabWidth: 2,\n  semi: true,\n  htmlWhitespaceSensitivity: 'strict',\n  arrowParens: 'avoid',\n  bracketSpacing: true,\n  proseWrap: 'preserve',\n  trailingComma: 'none',\n  endOfLine: 'lf'\n};\n"
  },
  {
    "path": ".stylelintrc.json",
    "content": "{\n  \"extends\": [\n    \"stylelint-config-standard-less\",\n    \"stylelint-config-rational-order\"\n  ],\n  \"customSyntax\": \"postcss-less\",\n  \"plugins\": [\n    \"stylelint-declaration-block-no-ignored-properties\"\n  ],\n  \"rules\": {\n    \"function-name-case\": [\n      \"lower\",\n      {\n        \"ignoreFunctions\": [\n          \"/colorPalette/\"\n        ]\n      }\n    ],\n    \"function-no-unknown\": [\n      true,\n      {\n        \"ignoreFunctions\": [\n          \"fade\",\n          \"fadeout\",\n          \"tint\",\n          \"darken\",\n          \"ceil\",\n          \"fadein\",\n          \"floor\",\n          \"unit\",\n          \"shade\",\n          \"lighten\",\n          \"percentage\",\n          \"-\",\n          \"~`colorPalette\"\n        ]\n      }\n    ],\n    \"import-notation\": null,\n    \"no-descending-specificity\": null,\n    \"no-invalid-position-at-import-rule\": null,\n    \"declaration-empty-line-before\": null,\n    \"keyframes-name-pattern\": null,\n    \"custom-property-pattern\": null,\n    \"number-max-precision\": 8,\n    \"alpha-value-notation\": \"number\",\n    \"color-function-notation\": \"legacy\",\n    \"selector-class-pattern\": null,\n    \"selector-id-pattern\": null,\n    \"selector-not-notation\": null,\n    \"declaration-block-no-redundant-longhand-properties\": null,\n    \"declaration-property-value-no-unknown\": null,\n    \"at-rule-no-unknown\": [\n      true,\n      {\n        \"ignoreAtRules\": [\n          \"plugin\"\n        ]\n      }\n    ],\n    \"less/no-duplicate-variables\": null\n  },\n  \"ignoreFiles\": [\n    \"components/style/color/{bezierEasing,colorPalette,tinyColor}.less\"\n  ]\n}\n"
  },
  {
    "path": ".vscode/mcp.json",
    "content": "{\n  \"servers\": {\n    \"angular-cli\": {\n      \"command\": \"npx\",\n      \"args\": [\n        \"-y\",\n        \"@angular/cli\",\n        \"mcp\"\n      ]\n    },\n    \"eslint\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\n        \"@eslint/mcp@latest\"\n      ]\n    }\n  }\n}"
  },
  {
    "path": ".windsurf/rules/guidelines.md",
    "content": "You are an expert in TypeScript, Angular, and scalable web application development. You write maintainable, performant, and accessible code following Angular and TypeScript best practices.\n\n## TypeScript Best Practices\n\n- Use strict type checking\n- Prefer type inference when the type is obvious\n- Avoid the `any` type; use `unknown` when type is uncertain\n\n## Angular Best Practices\n\n- Always use standalone components over NgModules\n- Must NOT set `standalone: true` inside Angular decorators. It's the default.\n- Use signals for state management\n- Implement lazy loading for feature routes\n- Do NOT use the `@HostBinding` and `@HostListener` decorators. Put host bindings inside the `host` object of the `@Component` or `@Directive` decorator instead\n- Use `NgOptimizedImage` for all static images.\n  - `NgOptimizedImage` does not work for inline base64 images.\n\n## Components\n\n- Keep components small and focused on a single responsibility\n- Use `input()` and `output()` functions instead of decorators\n- Use `computed()` for derived state\n- Set `changeDetection: ChangeDetectionStrategy.OnPush` in `@Component` decorator\n- Prefer inline templates for small components\n- Prefer Reactive forms instead of Template-driven ones\n- Do NOT use `ngClass`, use `class` bindings instead\n- Do NOT use `ngStyle`, use `style` bindings instead\n\n## State Management\n\n- Use signals for local component state\n- Use `computed()` for derived state\n- Keep state transformations pure and predictable\n- Do NOT use `mutate` on signals, use `update` or `set` instead\n\n## Templates\n\n- Keep templates simple and avoid complex logic\n- Use native control flow (`@if`, `@for`, `@switch`) instead of `*ngIf`, `*ngFor`, `*ngSwitch`\n- Use the async pipe to handle observables\n\n## Services\n\n- Design services around a single responsibility\n- Use the `providedIn: 'root'` option for singleton services\n- Use the `inject()` function instead of constructor injection\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "## [21.2.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/21.1.1...21.2.0) (2026-03-20)\n\n### Features\n\n- **alert:** add loop text ([#9697](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9697)) ([6b45037](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6b45037e4d71d7df60942ead1fab0ed06ac31911))\n- **form:** support `nzVariant` ([#9694](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9694)) ([51d6eb6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/51d6eb6e1c3b18e3a5dca7da266476a091ac2eaf))\n- **input-number:** add `emitter` in `nzOnStep` event options ([#9716](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9716)) ([f83af1e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f83af1e87a6eaab041c38f0ed7b26ff8d84568c4))\n- **input:** supports custom count logic for input-wrapper ([#9645](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9645)) ([2450a60](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2450a60e12b9707f71d603092207485decc9d127))\n- **tabs:** support `nzIndicator` ([#9704](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9704)) ([02befe7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/02befe7a77e2a67f41312bb498cc34372f3408c1))\n\n### Bug Fixes\n\n- **modal:** prevent flicker on open ([#9728](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9728)) ([56ad81d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/56ad81d90ee7bf5b63f53b4e4c5cb53785ae5c12))\n- **select:** fix dropdown position in Safari ([#9724](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9724)) ([1081620](https://github.com/NG-ZORRO/ng-zorro-antd/commit/10816209670407610b53ce8f2051fbd354fb620e))\n\n## [21.1.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/21.1.0...21.1.1) (2026-03-06)\n\n### Bug Fixes\n\n- **anchor:** support number id in `nzHref` ([#9683](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9683)) ([fc8a096](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fc8a096bef670cf65df2cda8cbd2f4042fdc840c))\n- **carousel:** restore responsive height on window resize ([#9612](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9612)) ([b5558ae](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b5558ae679831fa5abc1d9e4ba23c85be5a0d690))\n- **cascader:** wrong padding size ([#9699](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9699)) ([b16da90](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b16da905867fc8235d413b44e32ba3233a74dadb))\n\n## [21.1.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/21.0.2...21.1.0) (2026-02-05)\n\n### Features\n\n- **collapse:** sync the latest antd styles ([#9680](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9680)) ([4eec05f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4eec05f06def8d001e5f716372cee97859a7a5fa)) ([#9678](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9678)) ([2483498](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2483498b7f841eb2caede9cfe0ed975f1e6b284c))\n- **form:** support `nzSize` ([#9606](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9606)) ([785ca6f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/785ca6fc0dec71e84b6817a650d3976f39814518))\n- **time-picker:** support `nzPrefix` ([#9647](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9647)) ([8d75887](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8d75887faee74f7a371e4c6ca9825e30375bd295))\n- **time-picker:** support `nzNeedConfirm` ([#9638](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9638)) ([9f887af](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9f887af5e14332ecabab52560db548dbabe0158f))\n- **time-picker:** support `nzPlacement` ([#9630](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9630)) ([931b3f4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/931b3f45489c410d8f00a987b74e215fe630dfec))\n\n## [21.0.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/21.0.1...21.0.2) (2026-01-23)\n\n### Bug Fixes\n\n- **i18n:** add missing translations to `he_IL` ([#9658](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9658)) ([a3410a0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a3410a0c60eea5367f7c9bb56da378e96920ba8c))\n- **form:** error message never disappear if animation is disabled ([#9660](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9660)) ([798a556](https://github.com/NG-ZORRO/ng-zorro-antd/commit/798a5566388a03d88e64799f0b568c5e7130709e))\n- **menu:** submenu should respect `provideNzNoAnimation` ([#9661](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9661)) ([79ffce9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/79ffce9621fde0f41e10de822ba8aa45dfdda7ae))\n\n## [21.0.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/21.0.0...21.0.1) (2026-01-16)\n\n### Bug Fixes\n\n- bundle keyframes of animation into base style files ([#9653](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9653)) ([49ec060](https://github.com/NG-ZORRO/ng-zorro-antd/commit/49ec0605b31eef0a3d790319d55d9f44492b4c0b))\n- **collapse:** no ghost zone if collapsed ([#9649](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9649)) ([5378f8b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5378f8beec14f7b47e0a54b6c81583592825ffa1))\n\n## [21.0.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/20.4.4...21.0.0) (2026-01-09)\n\n### Code Refactoring\n\n- migrate to native animation API, feel free to remove the `@angular/animations` dependency\n\n### Features\n\n- **color-picker:** support `nzPresets` ([#9341](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9341)) ([d59ec99](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d59ec995b42726470ebaea39ec7a52f5c9c5e58d))\n- **core:** add `provideNzNoAnimation` ([#9555](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9555)) ([c945e81](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c945e81ce5966f34e7a96a8bccbf628a5b8d8c06))\n- **date-picker:** output date range in correct order ([#9518](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9518)) ([d0b3185](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d0b3185fb2ae891a164d3b4f28e4f68add8e166b))\n- **float-button:** add pop animation to float button menu ([#9413](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9413)) ([b40ad91](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b40ad91b26aee48fc86d92da48071751f8345ab4))\n- **input-number:** supports mouse wheel control ([#9591](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9591)) ([6ce3545](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6ce354537ec59bd0c480eed61bb8f663d2429189))\n- **input,input-number:** add additional options for `focus` method ([#9595](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9595)) ([c336711](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c3367110ccd53c5debd74799070ac6565c13c483))\n- **qrcode:** support `nzType` and `nzBoostLevel`, delete array usage of `nzPadding` ([#9535](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9535)) ([5419b51](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5419b51781478369afe3c01fe24374f2f62eeffe))\n- **tree-view:** upgrade tree view component ([#9003](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9003)) ([ae9ad57](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ae9ad576292671f3228361733b47e890d425e713))\n- **upload:** add `nzMaxCount` feature ([#9424](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9424)) ([0bf13c3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0bf13c3fa5e41289315cf4d9642ed5aa7005af9e))\n\n### Bug Fixes\n\n- **i18n:** add missing translations to `fa_IR` ([#9615](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9615)) ([1e8845d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1e8845d245ce7a98850390c61e65b301fb8fcc05))\n- **popconfirm:** allow null for `nzIcon` hide icon ([#9569](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9569)) ([760b587](https://github.com/NG-ZORRO/ng-zorro-antd/commit/760b58745a1b377d4008825a3d4c157d8a1bd590))\n- **select:** disable `nzAutoClearSearchValue` in single mode ([#9605](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9605)) ([4720c21](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4720c2175dd2bc937d8ccbf66ab804c4782f23d4))\n- **tree:** no `preventDefault` when right-clicking the node title ([#9532](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9532)) ([900efad](https://github.com/NG-ZORRO/ng-zorro-antd/commit/900efad5b0a04b1a0aca2c68728f01ed8dc4ef3b))\n\n### ⚠ BREAKING CHANGES\n\n- **back-top:** removed, please use `float-button` instead\n- **color-picker:** change DOM structure to be simpler, and remove no unnecessary payload of `nzClick` output\n- **input-number-legacy:** removed, please use `input-number` instead\n- **qrcode:** change the type of `nzPadding` from `number | number[]` to `number` ([#9535](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9535))\n- **statistic:** rename `NzStatisticNumberComponent` to `NzStatisticContentValueComponent`\n- **tabs:** remove deprecated `nz-tabset` selector ([#9613](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9613))\n- **tree-view:** `nzTreeControl` has been removed, please use `nzLevelAccessor` or `nzChildrenAccessor` instead\n- **watermark:** change import path from `ng-zorro-antd/water-mark` to `ng-zorro-antd/watermark`\n\nRemove the following APIs which were marked as deprecated in the previous version:\n\n| Module                              | API                                    |\n| ----------------------------------- | -------------------------------------- |\n| `ng-zorro-antd/back-top`            | `*`                                    |\n| `ng-zorro-antd/dropdown`            | `NzDropdownButtonDirective`            |\n| `ng-zorro-antd/input-number-legacy` | `*`                                    |\n| `ng-zorro-antd/core`                | `NzHighlightModule`                    |\n| `ng-zorro-antd/auto-complete`       | `NZ_AUTOCOMPLETE_VALUE_ACCESSOR`       |\n| `ng-zorro-antd/checkbox`            | `nz-checkbox-wrapper`                  |\n| `ng-zorro-antd/date-picker`         | `NzDatePickerComponent#nzBorderless`   |\n| `ng-zorro-antd/input`               | `NzInputDirective#nzBorderless`        |\n| `ng-zorro-antd/input-number`        | `NzInputNumberComponent#nzBordered`    |\n| `ng-zorro-antd/mention`             | `NZ_MENTION_TRIGGER_ACCESSOR`          |\n| `ng-zorro-antd/select`              | `NzSelectComponent#nzBorderless`       |\n| `ng-zorro-antd/time-picker`         | `NzTimePickerComponent#nzBorderless`   |\n| `ng-zorro-antd/tooltip`             | `NzToolTipModule` `NzToolTipComponent` |\n\nUnify and standardize component naming, involving the following name changes:\n\n| Module      | Original                      | Current                       |\n| ----------- | ----------------------------- | ----------------------------- |\n| `core`      | `NzConfig#backTop`            | `NzConfig#floatButton`        |\n| `core`      | `NzConfig#dropDown`           | `NzConfig#dropdown`           |\n| `dropdown`  | `NzDropDownModule`            | `NzDropdownModule`            |\n| `dropdown`  | `NzDropDownADirective`        | `NzDropdownADirective`        |\n| `menu`      | `NzIsMenuInsideDropDownToken` | `NzIsMenuInsideDropdownToken` |\n| `watermark` | `NzWaterMarkModule`           | `NzWatermarkModule`           |\n| `watermark` | `NzWaterMarkComponent`        | `NzWatermarkComponent`        |\n\n### Deprecations\n\nThe following APIs are marked as **deprecated** in v20 and will be removed in the next major version.\nPlease refer to related documentation for better alternatives.\n\n| Module                   | API                                                               |\n| ------------------------ | ----------------------------------------------------------------- |\n| `ng-zorro-antd/collapse` | `nz-collapse-panel[nzDisabled]`                                   |\n| `ng-zorro-antd/input`    | `textarea[nzAutosize]`, `nz-input-group`, `[nz-input-group-slot]` |\n| `ng-zorro-antd/upload`   | `nz-upload[nzTransformFile]`, `NzUploadTransformFileType`         |\n\n## [20.4.4](https://github.com/NG-ZORRO/ng-zorro-antd/compare/20.4.3...20.4.4) (2025-12-12)\n\n### Bug Fixes\n\n- **icon:** include nzSpin in change detection logic ([#9597](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9597)) ([46dc381](https://github.com/NG-ZORRO/ng-zorro-antd/commit/46dc3819244969963ca80eeac9f9c06482f48d29))\n- **result:** show default icon based on status ([#9568](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9568)) ([#9582](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9582)) ([b652105](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b652105ac71a022f4d7343e911f04fbeb2dee8d0))\n\n## [20.4.3](https://github.com/NG-ZORRO/ng-zorro-antd/compare/20.4.2...20.4.3) (2025-11-28)\n\n### Bug Fixes\n\n- **form:** animation should respect NoopAnimations ([#9562](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9562)) ([5bccf96](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5bccf968ab8cbe4164fe09e691f6664ee2664a5c))\n- **input:** fix dependency cycle ([#9561](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9561)) ([8d5782d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8d5782d5ae35769fc73bcdb49d9d7897b9b92828))\n\n## [20.4.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/20.4.1...20.4.2) (2025-11-21)\n\n### Bug Fixes\n\n- **cascader,select,date-picker,time-picker,tree-select:** add missing nzVariant global config ([#9543](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9543)) ([221386b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/221386b45cc20d6bea689a5a4c10e35ff15b06b7))\n- **button:** improve icon only logic in zoneless mode ([#9541](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9541)) ([9def420](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9def420d2da1a2b8a7993db814948151733ef772))\n\n## [20.4.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/20.4.0...20.4.1) (2025-11-14)\n\n### Bug Fixes\n\n- **badge:** hex `nzColor` should work ([#9517](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9517)) ([47d44ba](https://github.com/NG-ZORRO/ng-zorro-antd/commit/47d44ba4f826f882ee3a9de64994ad5ebd89daa5))\n- **cascader:** fix zoneless `NG0100` issue ([#9504](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9504)) ([24b4e83](https://github.com/NG-ZORRO/ng-zorro-antd/commit/24b4e83e39fe3216d02857999df78cd4fbdc35fe))\n- **color-picker:** fix `NG01350` error ([#9525](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9525)) ([fbcb8c3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fbcb8c3f78c293bd510994a28de7295e4349576c))\n- **dropdown:** update arrow placement once the position of connected overlay changes ([#9519](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9519)) ([7ff7e09](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7ff7e09d4256e8b4bd54cf2e1e01f64cabadcf4d))\n- **input:** render icon when enterButton is an empty string ([#9498](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9498)) ([6a40b0d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6a40b0db8cd23584cc4a268c16eec14cf6bbaf29))\n- **result:** nz-result-icon in ng-content does not work ([#9511](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9511)) ([0e095a1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0e095a14e0bf6014cffcb95db007b750bfe84da7))\n- **segmented:** should not block the `selected$` if no animation ([#9512](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9512)) ([af8b531](https://github.com/NG-ZORRO/ng-zorro-antd/commit/af8b53186469aa9858a9eaa883e3e597db65c598))\n- **select:** correct font size in small size ([#9516](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9516)) ([6f79005](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6f7900548ccd128b430f7a09ee3ef07dd6ea482c))\n\n## [20.4.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/20.3.1...20.4.0) (2025-10-31)\n\n### Features\n\n- **cascader:** control the visibility of popup panel by `nzOpen` ([#9448](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9448)) ([4d5ec65](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4d5ec6536f64690319e0fd219dc4b07c724764db))\n- **cascader:** toggle checkbox of option by `ENTER` key in multiple mode ([#9457](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9457)) ([e02f1f4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e02f1f45f6ae1d5836b1b751bb23bfa55c5f1c33))\n- **float-button:** support `nzBadge` ([#9489](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9489)) ([12beec7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/12beec73fe3071e116788635ae17b1668d3b5ad8))\n- **form:** support `nzRequiredMark` ([#9447](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9447)) ([800b6cf](https://github.com/NG-ZORRO/ng-zorro-antd/commit/800b6cf960af7c4dfce0378eeb9fd361d21ac06b))\n- **input-number:** add affix and addon inputs ([#9451](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9451)) ([dbebd02](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dbebd025cc5101d879301405f0e0ce4baca4bdf5))\n- **input:** add `nzAllowClear` input and `nzClear` callback ([#9452](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9452)) ([830b4b3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/830b4b3cced07ecc484375ab62a3593ac7140b39))\n- **input:** introduce new component `nz-input-wrapper` ([#9408](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9408)) ([a8e56ec](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a8e56ecbc5040dc36dd38881d2d3f7133c7c7991)), closes [#9403](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9403)\n- **input:** add affix and addon inputs to `nz-input-wrapper` ([#9450](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9450)) ([763f69e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/763f69e7e35ef3697245e9074034d17f110c5876))\n- **input:** introduce `nz-input-search` directive ([#9483](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9483)) ([af6f590](https://github.com/NG-ZORRO/ng-zorro-antd/commit/af6f590b30270205300e028287f205249b316efa))\n- **input:** introduce `nz-input-password` directive ([#9460](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9460)) ([f80832a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f80832a7741a6efd9049372a8759d710dc72bde4))\n- **message:** add support for custom styles and classes ([#9427](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9427)) ([2f866b3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2f866b31febe4c1f6dd784537fc8ca2b68a66a93))\n- **pagination:** support `nzAlign` ([#9433](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9433)) ([88d0864](https://github.com/NG-ZORRO/ng-zorro-antd/commit/88d08648570756e35b989f55e15bcb116175dbc2))\n- **segmented:** add default name if `nzName` is not provided ([#9466](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9466)) ([33f8142](https://github.com/NG-ZORRO/ng-zorro-antd/commit/33f8142626e337e1cef997bc99a289effcb64dd0))\n\n### Bug Fixes\n\n- **badge:** should `nzStyle` work even if `nzColor` is not provided ([#9486](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9486)) ([4424eb0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4424eb0a018c7d90fb74dfda6ceb5c54a080eb4d))\n- **cascader:** display activated column correctly when reopen the popup panel ([#9456](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9456)) ([7802a39](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7802a39167d0efaf1bca5e829fa4907f7af54650))\n\n## [20.3.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/20.3.0...20.3.1) (2025-09-17)\n\n### Bug Fixes\n\n- **drawer:** fix `NG0203` ([#9418](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9418)) ([7fb58ae](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7fb58aea2f03902ce3b0ac626bed99b5d8de0c6b))\n\n## [20.3.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/20.2.1...20.3.0) (2025-09-16)\n\n### Features\n\n- **carousel:** support `nzArrows` ([#9355](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9355)) ([1b9714b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1b9714baf8d320b423f390d713af6533e0390f24))\n- **check-list:** add badge and default checked ([#9343](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9343)) ([235b493](https://github.com/NG-ZORRO/ng-zorro-antd/commit/235b493705d297ccff21969f2d770b7f4eba7fb5))\n- **i18n:** enhance `provideNzI18n` to support factory function ([#9393](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9393)) ([1371265](https://github.com/NG-ZORRO/ng-zorro-antd/commit/13712654d1c3b5de2eabc577c22d0f98a59a8345))\n- **mention:** support `nzClear` ([#9377](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9377)) ([cbecebf](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cbecebfda401b2fd873163638d3e2cc4dfd638c1))\n- **mention:** support `nzVariant` ([#9379](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9379)) ([d92568b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d92568b781bb16bfef55e645a15022ef54583ba1))\n- **segmented:** support `nzShape`([#9368](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9368)) ([ffce6c3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ffce6c385a3c994132e096a33a83bd77d01a6b7b))\n- **segmented:** support `nzName` and keyboard interactions ([#9373](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9373)) ([ebd8bdc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ebd8bdc9d0c71fc6f691c7c900e8b43e26cc0e84))\n- **upload:** support promise return type for `nzBeforeUpload` ([#9402](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9402)) ([cece107](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cece1077e5f375c225ae32973b863f8123520717))\n\n### Bug Fixes\n\n- **badge:** after setting `nzColor`, display incorrect ([#9376](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9376)) ([e9abf92](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e9abf9250ab8c7c902933688610e0f2c731b97b1))\n- **input:** variant underline style on hover ([#9400](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9400)) ([74c2173](https://github.com/NG-ZORRO/ng-zorro-antd/commit/74c217382ed191b26990082586796f588fdd73c8))\n- **segmented:** fix `NG0950` error ([#9386](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9386)) ([e82fc01](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e82fc0186d2dc8061ff1db50aaa2e7b2f11beb9d))\n- **select:** refactor multiple select styles ([#9409](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9409)) ([38f9065](https://github.com/NG-ZORRO/ng-zorro-antd/commit/38f90653569b46e28e317e040040e98bee595761))\n- **schematics:** add `less` as devDependencies if choosing custom theme in non-less project ([#9412](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9412)) ([a18cffd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a18cffd8e2dd6e39836f00a42c95f1f5699d1829))\n\n## [20.2.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/20.2.0...20.2.1) (2025-08-31)\n\n### Bug Fixes\n\n- **segmented:** correctly render with-icon & icon-only ([#9367](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9367)) ([9d42b42](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9d42b42ad103e8ca498e65e7aa6ad7e72075d609))\n\n## [20.2.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/20.1.3...20.2.0) (2025-08-29)\n\n### Features\n\n- **cascader:** add `nzOpen` to control visibility ([#9339](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9339)) ([354c7cf](https://github.com/NG-ZORRO/ng-zorro-antd/commit/354c7cfb9e9746fc55ccc3f5967721ab01737652))\n- **collapse:** support `nzCollapsible` ([#9349](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9349)) ([1ddbcaf](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1ddbcaf8e8c5f47a5c2354ac61bf3da707e8a99c))\n- **collapse:** support `nzSize` ([#9348](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9348)) ([b5c256d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b5c256da531b5b306f831c8ee05acf0139bc7ad3))\n- **divider:** support `nzSize` ([#9346](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9346)) ([1f54536](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1f5453639f059c9058815834500e459df4082882))\n- **dropdown:** display arrow for content dropdown ([#9329](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9329)) ([3686b73](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3686b7375839412b0db26f896fb810a4bdb2ae0c))\n- **float-button:** `nzIcon` support string type ([#9302](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9302)) ([ce611e5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ce611e5d9096456e032db78acc886b5dde60220c))\n- **segmented:** support `nzVertical` ([#9359](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9359)) ([52322cd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/52322cd50c1d2883a0df7ca0aee91f803448315b))\n- **select,tree-select,cascader:** support prefix and suffix icon ([#9328](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9328)) ([527ffb6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/527ffb6efee5759e58c7472f1fae2a619092f246))\n- **tag:** export `NzTagColor` type ([#9314](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9314)) ([1efd29e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1efd29ee1de0f77854dd75c10c9156d50013067d))\n\n### Bug Fixes\n\n- **carousel:** wrong dot position when placement is left or right ([#9358](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9358)) ([f117ccb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f117ccb739754e5a1b73be844679357cc807a238))\n- **range-picker:** clear outline on mouse leaving ([#9352](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9352)) ([573d092](https://github.com/NG-ZORRO/ng-zorro-antd/commit/573d092f6e332acaeb33dfc03c0e370be6753df8))\n- **segmented:** should render single element in item if icon-only ([#9363](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9363)) ([89d2168](https://github.com/NG-ZORRO/ng-zorro-antd/commit/89d216871b0a9127aa4adbf6a034b7e2e1febf2d))\n\n## [20.1.3](https://github.com/NG-ZORRO/ng-zorro-antd/compare/20.1.2...20.1.3) (2025-08-21)\n\n### Bug Fixes\n\n- **i18n:** add missing translations to `cs_CZ` ([#9334](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9334)) ([93e486e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/93e486eeb848fb3cbb2073f107ae7be4bba2457b))\n- **i18n:** add missing translations to `sk_SK` ([#9335](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9335)) ([ddefc7f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ddefc7f9e95cde34101896fd5bfe587ff1dd8a89))\n- **cascader:** invalid value and label when binding dynamically ([#9338](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9338)) ([324ab5b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/324ab5b2ad281abb77344b9ca0dd66d4ca55e794))\n- **popconfirm:** correctly render icon & title ([#9322](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9322)) ([2c83788](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2c837883853a77a5a8fe1c2245daa0548a7bb2d9))\n- **select:** shaking when closing dropdown if use a TemplateRef as `nzNotFoundContent` ([#9336](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9336)) ([366f8eb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/366f8ebcd79900a4d6a512b72094af3494c55871))\n\n## [20.1.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/20.1.1...20.1.2) (2025-08-08)\n\n### Bug Fixes\n\n- **input-number:** make sure the displayed value is correct ([#9312](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9312)) ([7a2d3b6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7a2d3b6f97bf80f2f517626f5e02625c4488be80))\n- **select,tree-select,cascader:** selected item with long label displayed in ellipsis ([#9316](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9316)) ([30672d7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/30672d7978f0ca4b24ec04c196c967b69e614525))\n- **table:** add cdkScrollable to internal scrolling element ([#9308](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9308)) ([8cb4113](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8cb411332b90b55bab3ec742c455e3aaaf4618d7))\n\n## [20.1.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/20.1.0...20.1.1) (2025-08-05)\n\n### Bug Fixes\n\n- **badge:** export `NzBadgeStatusType` type ([#9298](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9298)) ([91b1ad7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/91b1ad7af23eda253c21530e2a01a5ac9f7c62a8))\n- **layout:** fix showcases ([#9303](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9303)) ([9a37ef8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9a37ef8325522ee200462b75e13a72f403ec4bef))\n\n## [20.1.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/20.0.0...20.1.0) (2025-07-21)\n\n### Features\n\n- add [llms.txt](https://ng.ant.design/llms.txt) and [llms-full.txt](https://ng.ant.design/llms-full.txt) ([#9281](https://github.com/NG-ZORRO/ng-zorro-antd/pull/9281)) ([165b963](https://github.com/NG-ZORRO/ng-zorro-antd/commit/165b96372e737a6dceac9404bded06041d286e2a))\n- **float-button:** support `nzPlacement` ([#9267](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9267)) ([9dc19f3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9dc19f35c9f4d9de0c6fc1f2b58c97f2aded95c1))\n- **input-number:** accepted numbers with commas ([#9256](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9256)) ([7567bd8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7567bd87a7862b52c12e152b9ce0c395b5e18ff0))\n- **input:** input-otp supports keyboard control positioning ([#9268](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9268)) ([da97b02](https://github.com/NG-ZORRO/ng-zorro-antd/commit/da97b02a82361e23c77f14bec76add77f6c39302))\n- **popconfirm:** add `nzDanger` support to cancel button ([#9270](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9270)) ([f94cb31](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f94cb318b05b01d1560ddfe3a5bfb226f23a83b4))\n- **space:** support array for size ([#9289](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9289)) ([8809885](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8809885be2b268e38c8ba04f57f46803e92e0c28))\n- **schematics:** align with the updated style guide ([#9295](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9295)) ([b5f607b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b5f607b874ed150fb1858eb81b19c3cc67478f37))\n\n### Bug Fixes\n\n- **core:** avoid using `setAttribute` to set `style` ([#9292](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9292)) ([12d58bd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/12d58bde7cb8d762405728825d6261fe5fc663b8))\n- **input-number:** ngModel value can be `undefined` ([#9269](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9269)) ([4c5666a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4c5666a90f477703dcda96ec135a6eea99d11105))\n- **tooltip:** rename `ToolTip` to `Tooltip` ([#9285](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9285)) ([2ebef97](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2ebef970cb7cd2855ee725b89ab8dfef9e6e35d6))\n- **schematics:** support `NzTooltipModule` migration ([#9294](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9294)) ([add21f7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/add21f71d92645be9f1c7684c2f213a6864f5891))\n\n## [20.0.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/20.0.0-next.1...20.0.0) (2025-06-27)\n\n### Features\n\n- **cascader,date-picker,input-number,input,select,time-picker,tree-select:** support `nzVariant` ([#9131](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9131)) ([b342bb4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b342bb464eb544a2e3fda8723cac7e550828b3f2))\n- **popover:** add `nzPopoverTitleContext` and `nzPopoverContentContext` ([#9126](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9126)) ([df3ead9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/df3ead9af8368eb7e2374744f01cecd5ccc21440))\n- **select:** add `nzOnClear` callback ([#9188](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9188)) ([e047ac2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e047ac249b16b547525a0ca4d13beeef620f44c4))\n- **avatar:** add `loading` and `fetchpriority` attributes ([#7347](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7347)) ([ff8419f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ff8419f6614bdac8bc3c778e470da08b679889d0))\n- **popconfirm:** add `nzOkButtonProps` and `nzCancelButtonProps` ([#9245](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9245)) ([22e2a9f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/22e2a9fb148fd875c76fb339c6582d92aef62791))\n- **tree-select:** render title of selected node in innerHTML ([#9259](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9259)) ([8066f7b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8066f7bb082c95652a2e158a01e55382992fe8c6))\n\n### Bug Fixes\n\n- **flex:** fix `NzAlign` type ([#9151](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9151)) ([b271c19](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b271c19076ead71fabbe5b224072cfea975d801d))\n- **segmented:** accepts disabled state from ng control ([#9166](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9166)) ([134cd59](https://github.com/NG-ZORRO/ng-zorro-antd/commit/134cd5976220d51179118491a4b4b2e4d7cf761c))\n- **space:** border radius compact mode one item ([#9165](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9165)) ([d2f4541](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d2f4541a9ae01d6ea8705faf2bc4b96bf34b6945))\n- **tabs:** prevent incorrect scroll offset on tab focus ([#9186](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9186)) ([4f658e0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4f658e0834e99ea2be0ffd4ead2dd041ec88fb83))\n- **schematics:** ng add failed when call twice ([#9171](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9171)) ([d0a9748](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d0a974848c0e31ad41ba69a5af60c002a7b251cd))\n- **water-mark:** make server-side compatible ([#9250](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9250)) ([a70a682](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a70a682c8aa4d073bb150abd4b69104fbe21e2ed))\n- **icon:** debounce icon rendering on animation frame ([#8579](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8579)) ([c0709d1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c0709d1e01d80969a48634fe8194dbfd49f6192f))\n\n### Code Refactoring\n\n- **core:** cleanup animation frame polyfill ([#9243](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9243)) ([272237a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/272237a7a33d150ac9c0f6965df37a678221b074))\n- migrate to `inject` pattern\n\n### ⚠ BREAKING CHANGES\n\n- **core:** refactoring in `ng-zorro-antd/core/polyfill`:\n  - rename `cancelRequestAnimationFrame` to `cancelAnimationFrame`\n  - rename `reqAnimFrame` to `requestAnimationFrame`\n- **tabs:** rename `NzTabsetComponent` to `NzTabsComponent`, `nz-tabset` selector to `nz-tabs`, the original component and selector are marked as deprecated\n- **table:** no longer compatible with material components\n\n* **popconfirm:** `nzOkDisabled` and `nzOkDanger` are marked as deprecated, use `nzOkButtonProps` and `nzCancelButtonProps` instead\n\nRemove the following APIs which were marked as deprecated in the previous version:\n\n| Module                       | API                                                      |\n| ---------------------------- | -------------------------------------------------------- |\n| `ng-zorro-antd/button`       | `NzButtonGroupComponent`                                 |\n| `ng-zorro-antd/core/form`    | `NzFormPatchModule`                                      |\n| `ng-zorro-antd/checkbox`     | `NzCheckBoxOptionInterface`                              |\n| `ng-zorro-antd/input`        | `NzInputGroupComponent#nzCompact`                        |\n| `ng-zorro-antd/message`      | `NzMessageModule`                                        |\n| `ng-zorro-antd/notification` | `NzNotificationModule`<br/>`NzNotificationServiceModule` |\n\nThe `exportAs` of components are updated to follow `camelCase` and start with `nz`, `exportAs` of internal components are removed. Changes can be seen as follow:\n\n| Component                | Original               | Current                |\n| ------------------------ | ---------------------- | ---------------------- |\n| `calendar-footer`        | `calendarFooter`       | -                      |\n| `date-helper`            | `dateHelper`           | -                      |\n| `date-range-popup`       | `dateRangePopup`       | -                      |\n| `date-table`             | `dateTable`            | -                      |\n| `decade-helper`          | `decadeHelper`         | -                      |\n| `decade-table`           | `decadeTable`          | -                      |\n| `month-helper`           | `monthHelper`          | -                      |\n| `month-table`            | `monthTable`           | -                      |\n| `quarter-helper`         | `quarterHelper`        | -                      |\n| `quarter-table`          | `quarterTable`         | -                      |\n| `year-helper`            | `yearHelper`           | -                      |\n| `year-table`             | `yearTable`            | -                      |\n| `inner-popup`            | `innerPopup`           | -                      |\n| `nz-color-block`         | `NzColorBlock`         | `nzColorBlock`         |\n| `nz-color-format`        | `NzColorFormat`        | `nzColorFormat`        |\n| `nz-color-picker`        | `NzColorPicker`        | `nzColorPicker`        |\n| `nz-model-close`         | `NzModalCloseBuiltin`  | `nzModalCloseBuiltin`  |\n| `nz-model-footer`        | `NzModalFooterBuiltin` | `nzModalFooterBuiltin` |\n| `nz-model-title`         | `NzModalTitleBuiltin`  | `nzModalTitleBuiltin`  |\n| `nz-tree-drop-indicator` | `NzTreeDropIndicator`  | `nzTreeDropIndicator`  |\n| `nz-water-mark`          | `NzWaterMark`          | `nzWaterMark`          |\n| `nz-tabs`                | `nzTabset`             | `nzTabs`               |\n\n### Deprecations\n\nThe following APIs are marked as **deprecated** in v20 and will be removed in the next major version.\nPlease refer to related documentation for better alternatives.\n\n| Module                         | API                                                                          |\n| ------------------------------ | ---------------------------------------------------------------------------- |\n| `ng-zorro-antd/autocomplete`   | `NZ_AUTOCOMPLETE_VALUE_ACCESSOR` <br /> `getNzAutocompleteMissingPanelError` |\n| `ng-zorro-antd/button`         | `NzButtonGroupComponent`                                                     |\n| `ng-zorro-antd/core/form`      | `NzFormPatchModule`                                                          |\n| `ng-zorro-antd/core/highlight` | `NzHighlightModule`                                                          |\n| `ng-zorro-antd/checkbox`       | `NzCheckBoxOptionInterface`                                                  |\n| `ng-zorro-antd/input`          | `NzInputGroupComponent#nzCompact`                                            |\n| `ng-zorro-antd/mention`        | `NZ_MENTION_TRIGGER_ACCESSOR`                                                |\n| `ng-zorro-antd/message`        | `NzMessageModule`                                                            |\n| `ng-zorro-antd/notification`   | `NzNotificationModule`<br/>`NzNotificationServiceModule`                     |\n| `ng-zorro-antd/tabs`           | `NzTabsetComponent`                                                          |\n\n## [19.3.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/19.3.0...19.3.1) (2025-05-29)\n\n### Bug Fixes\n\n- **cascader:** cannot update value when it is missing in options ([#9124](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9124)) ([689fc72](https://github.com/NG-ZORRO/ng-zorro-antd/commit/689fc72e5c8175c830f995155daf1d7d4c318c25))\n- **date-picker:** update input value when nzFormat changed ([#9129](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9129)) ([f4c4e05](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f4c4e05264dd3109a0c45018886603ddd9c45aa2))\n- **tabs:** `nzLinkRouter` not work for the first time load ([#9130](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9130)) ([925a6a5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/925a6a54dd477b687b3dd0b836c32cb17e6d8a0f))\n\n## [19.3.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/19.2.2...19.3.0) (2025-05-23)\n\n### Features\n\n- **avatar:** support custom icon by ng-content ([#9090](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9090)) ([89d0767](https://github.com/NG-ZORRO/ng-zorro-antd/commit/89d076775b542996c46e48d2fb6f49c5981be40b))\n- **input-number:** add `nzBlur` and `nzFocus` output ([#9098](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9098)) ([1b1a013](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1b1a0130df4a86fb2abd42d95213d880fd0b14d7))\n- **tabs:** support for start and end extra content ([#9097](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9097)) ([2500821](https://github.com/NG-ZORRO/ng-zorro-antd/commit/250082160770d7f24404bbed86af5df96b9f3e53))\n- **transfer:** support multiple row selection with `Shift` key ([#9092](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9092)) ([b78b99f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b78b99f9f4cec6298cffc915b8ab86f708dccddf))\n\n### Bug Fixes\n\n- **i18n:** add missing translations to `es_ES` ([#9127](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9127)) ([0aadfdf](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0aadfdf39682bd779eabae57e02596fd0f730624))\n- **segmented:** fix emitting unnecessary value changed events ([#9125](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9125)) ([fb0635b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fb0635b0dc2fed0f28d60248b60b0ecd5e3294d4))\n- **tabs:** `nzLinkRouter` not work for the first time ([#9118](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9118)) ([0f7f94d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0f7f94dab24175b28f34720f5c98e7dc9a2c6c88))\n\n### Performance Improvements\n\n- **transfer:** use item.key as tracking for the list render ([#9123](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9123)) ([adb91e4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/adb91e4ba0cbcfc72cccb26a66580fa19dc9c8aa))\n\n## [19.2.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/19.2.1...19.2.2) (2025-04-25)\n\n### Bug Fixes\n\n- **input-number:** fix `NG0600` error ([#9106](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9106)) ([9f5b525](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9f5b525e5eb5e50ed4f93ed15b6831d7db3483ee))\n- **checkbox:** fix `NG0600` error ([#9105](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9105)) ([61b6886](https://github.com/NG-ZORRO/ng-zorro-antd/commit/61b68861a6215e40bd29e14d2fe2bc02ce112ce0))\n- **checkbox:** fix type of `nzOptions` ([#9099](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9099)) ([7be2fe5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7be2fe5412aa00b9178dcae49f202b21a1b7e9e8))\n- **select:** limit number of pasted item to `nzMaxMultipleCount` ([#9080](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9080)) ([3714840](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3714840a8a72d4d7809a2cac339dd3891052225d))\n\n## [19.2.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/19.2.0...19.2.1) (2025-03-29)\n\n### Bug Fixes\n\n- **select:** remove internal comment from select-arrow ([#9074](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9074)) ([c9b2dd9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c9b2dd96db78ff257137b7a2cba79bbf70f64d3e))\n\n## [19.2.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/19.1.0...19.2.0) (2025-03-28)\n\n### Features\n\n- **splitter:** add splitter component ([#8987](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8987)) ([9b3f62e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9b3f62e088f3d0953f236910df00175edf07e26e))\n- **page-header:** disable back button if no history ([#9041](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9041)) ([bb48232](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bb482328637829b91443075dddaaaef74b85cda8))\n\n### Documentation\n\n- **tabs:** add draggable tabs [showcase](https://ng.ant.design/components/tabs/en#components-tabs-demo-card-draggable) via CDK `DragDropModule`\n\n### Bug Fixes\n\n- **input-number:** consider input value ends with 0 as incomplete ([#9051](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9051)) ([2a0c2e0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2a0c2e08bcec7577558bf2578adf7710a5235a38))\n- **segmented:** fix error with the FormControl first change ([#9039](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9039)) ([33fe53d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/33fe53de16bbafd234fa369f677355349d24860a))\n- **select:** disable `nzMaxMultipleCount` in default mode ([#9068](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9068)) ([dcf8a5d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dcf8a5d35785d5a4b282719601c0b226e67543bc))\n- **select:** ngModel change should update state of `nzMaxMultipleCount` reached ([#9056](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9056)) ([d7031da](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d7031dada3f24cf9c7e48a2eb09678d44caaf9b1))\n- **space:** nzSpaceItem margin in rtl ([#7801](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7801)) ([2d9ff5f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2d9ff5f0735afc4f4ae03e9f85ae4a8062c21f1a))\n- **tabs:** update active router tab after tabs changed ([#7649](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7649)) ([1f07121](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1f07121c3c8521036b011a6f71e1859f70cfe429))\n- **tree-select:** enable overflow-x for virtual scroll ([#9045](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9045)) ([e70cae3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e70cae3c7cbd47c82d575a49e1dc6a31faa5912d))\n\n## [19.1.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/19.0.2...19.1.0) (2025-02-21)\n\n### Features\n\n- **check-list:** add check-list component ([#8969](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8969)) ([4cd298b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4cd298bfdce3c96e47c91e689fbad16c36d72b60))\n- **message,notification:** display `nzData` when content is a template ([#9001](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9001)) ([5157470](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5157470dd7d890703e4b3a8db9909891da4932c0))\n- **popover,popconfirm,tooltip:** `overlayClassName` supports space delimited classes string ([#8972](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8972)) ([3fcec91](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3fcec916b81a284fc8934846aab26d5b8ce99a1b))\n- **popover:** add `nzPopoverOverlayClickable` to disable click on mask ([#8878](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8878)) ([5898da7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5898da718f2568cdb2a6dcc63b6e7e18ccb217aa))\n\n### Bug Fixes\n\n- **input-number,checkbox:** accept the disabled change from ng control ([#8979](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8979)) ([2d8968d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2d8968d4709aee858634274d22196ecbbfbe8764))\n- **input-number:** use input event instead of change event ([#8989](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8989)) ([6d8d915](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d8d91521a6d4315b6a01fc173e3ed8df8bdecf0))\n- **tree-select:** fix error when judging multiple instances condition ([#9008](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9008)) ([5006ea6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5006ea695430c3c0f127f04c3a9bcf6dfd6c1a29))\n\n### Code Refactoring\n\n- use ECMAScript standard class field ([#8718](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8718)) ([f1d8d92](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f1d8d926b48a798489f54d4f3da6eec0f90f9955))\n- enable `isolatedModules` compiler option ([#8970](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8970)) ([0d42aa7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0d42aa7d4605c881c242e245b8127629e9657e39))\n\nNow feel free to use `isolatedModules` compiler option in your project.\n\n## [19.0.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/19.0.1...19.0.2) (2025-01-10)\n\n### Bug Fixes\n\n- **auto-complete:** should open the popover when the focused input is clicked ([#8900](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8900)) ([79cc2f8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/79cc2f830133dfe0ee99eaabdb7b5b5f1eca2e02))\n- **progress:** fix `NG0956` error ([#8962](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8962)) ([c4d2f81](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c4d2f81f125feca0ce5ad90e12997875b4465230))\n- **transfer:** correctly set the transfer-list-body class ([#8960](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8960)) ([a3546a9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a3546a9032dcc8fbbd72088e4a431e83b99b32f1))\n\n## [19.0.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/19.0.0-beta.1...19.0.1) (2025-01-03)\n\n### Bug Fixes\n\n- **date-picker:** cell title should reflect `nzFormat` ([#8744](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8744)) ([1b7ab5a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1b7ab5adb5af783e3a6a47ffc4916961993f4d6f))\n- **i18n:** add missing translations to `zh_TW` ([#8950](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8950)) ([9607e11](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9607e1161244b441badb2c37093c4f44a2d63695))\n- **input-number:** fix `NG0600` error ([#8955](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8955)) ([8d6135e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8d6135e65a6aa716678b9485e3e7790182d160b1))\n- **table:** should col be wrapped within colgroup in ssr mode ([#8948](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8948)) ([0a73deb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0a73deb053d2d9ab8d8194038355fad898b60759))\n\n## [19.0.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/18.2.1...19.0.0) (2024-12-06)\n\n### Bug Fixes\n\n- **autocomplete:** remove inline style (CSP compliant) ([#8875](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8875)) ([30c25f0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/30c25f0201130ccb00c8d2ba2e709763d7bcfd6e))\n- **avatar:** calculate size at the right time ([#8754](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8754)) ([3a5ba37](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3a5ba37de6553c5973ac1741a250dff957ca7ec5))\n- **card:** remove `nzBorderless` input ([#8741](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8741)) ([22ce17c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/22ce17c8a4bb7345cf026fd570bc8d3984722815))\n- **carousel:** carousel not working correctly in rtl mode ([#8770](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8770)) ([0202a19](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0202a191b3259e3dc454272b53feb3687a32cf0a))\n- **cascader:** correct menu display level ([#8866](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8866)) ([5fec53e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5fec53e597d50a26a1083bb1e726af885ba807ae))\n- **drawer:** should clear previously focused element ([#8893](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8893)) ([4498af0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4498af0f1a8c700099e82f4027bec30086f6d29a))\n- **i18n:** add missing translations to `vi_VN` ([#8894](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8894)) ([f08ad1c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f08ad1cb0728d19655c8143658e6a44f8843cb4a))\n- **tree-view:** `nzTreeNodePadding` not works in virtual scroll ([#8920](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8920)) ([82b660a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/82b660ac55539e9cb2c39b399884f8bec4d028d4))\n\n### Code Refactoring\n\n- cancel support for HTML string rendering ([#8831](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8831)) ([5fae01a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5fae01ad4120841390f7ebb6267a043774ea2266))\n- remove `ngClass` and `ngStyle` ([#8895](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8895)) ([c3ab3ba](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c3ab3ba6ad50dc4a8f23b43872b3f235ee316f4c))\n- **image:** remove deprecated `FADE_CLASS_NAME_MAP` and `IMAGE_PREVIEW_MASK_CLASS_NAME` ([#8912](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8912)) ([65223d9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/65223d9a595e78f8c73347c5d1b12a807389c434))\n- **transfer,tree,tree-select** rename `CheckBox` to `Checkbox` ([#8934](https://github.com/NG-ZORRO/ng-zorro-antd/pull/8934)) ([c76433d5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c76433d5533f6d5c0467ee99c61877a0ec4d35ac))\n\n### Features\n\n- **cascader:** support multiple selection ([#8903](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8903)) ([e5dfb49](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e5dfb495dc4f9e5493e425aeab3802a13a0f5e28))\n- **cascader:** support `nzPlacement` ([#8935](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8935)) ([6fbd22c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6fbd22c5b38b78cc991bb61446acbea635f30797))\n- **checkbox:** redesign the `nz-checkbox-group` component ([#8932](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8932)) ([489e0de](https://github.com/NG-ZORRO/ng-zorro-antd/commit/489e0defbfeeb03c29562d139614451575f8ed8d))\n- **divider:** add `nzVariant` option ([#8827](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8827)) ([2c63c87](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2c63c87f557e2400224566342a0185d212055004))\n- **float-button:** add float-button component ([#7884](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7884)) ([dab4d66](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dab4d669b3ef746d1761fbb2199c1b0ae704cda5))\n- **icon:** support `nz-icon` tag selector ([#8778](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8778)) ([1406241](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1406241f2e636bb3bf11515b0ad68cbe0535d5e1))\n- **image:** close image preview when escape key pressed ([#8809](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8809)) ([d587615](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d587615c7dd8d911af06551181f1bffb6eb67149))\n- **input:** support one time password (OTP) ([#8715](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8715)) ([cdbaf4d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cdbaf4de291f380cfcfdf6788d24da3e344175a9))\n- **menu:** add `nzTriggerSubMenuAction` to support click trigger for submenu ([#8461](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8461)) ([860df87](https://github.com/NG-ZORRO/ng-zorro-antd/commit/860df87a1be62f462ac3ea136d53948ccd69213a))\n- **qrcode:** add `nzStatusRender` to support customize state rendering ([#8714](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8714)) ([6f36d75](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6f36d75741e301bc3e7634a93c106c48a02c0a1b))\n- **segmented:** redesign the segmented component ([#8753](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8753)) ([4dc866c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4dc866cb2fcc7afb4cc309f433c216d1b7cba2e1))\n- **space:** add space compact component ([#8755](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8755)) ([b9c511d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b9c511db0b1b28521e23148a6fce5b1f169f99a2))\n- **table:** add `nzSortDirections` to global config ([#6613](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6613)) ([#8721](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8721)) ([eb1fdc5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/eb1fdc5037d9122a237e317e5b93857deb51e5d5))\n- **transfer:** add `nzOneWay` to support one way style ([#8717](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8717)) ([99fd4de](https://github.com/NG-ZORRO/ng-zorro-antd/commit/99fd4de95b2a5a44a2837af38d31ddcabf0a60bf))\n- **input-number:** redesign the input-number ([#8901](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8901)) ([df55d88](https://github.com/NG-ZORRO/ng-zorro-antd/commit/df55d8882c9f36bc6a0cd8a4d752e03070658ff7))\n- **schematics:** add v19 ng update migration ([#8911](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8911)) ([1a20de2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1a20de223bc6e214b54f741f42ed8260611b9b67))\n\n### BREAKING CHANGES\n\n- **All**\n  - `nzClass` / `nzStyle` input properties no longer support the following features:\n    - `Set()`: use arrays instead\n    - Keys which multiple styles/classes separated with keys: split a key with spaces into multiple keys\n  - Cancel support for HTML string rendering\n  - Migrate `@WithConfig` to standard decorator. If you're using `@WithConfig` in your library, please turn `experimentalDecorators` off in `tsconfig.json`\n  - Migrate `[nz-icon]` to `nz-icon` tag. If you're using `[nz-icon]` selector in stylesheet to select icon **inside** zorro component, please use `nz-icon` instead\n\n- **input-number:** Redesign the input-number so that it will be much simpler and more flexible.\n\n  Now you can use affixes or addons as follows, no need for `ng-template` and `nz-input-number-group`:\n\n  ```html\n  <!-- Custom handler icons -->\n  <nz-input-number>\n    <nz-icon nzInputNumberUpIcon />\n    <nz-icon nzInputNumberDownIcon />\n  </nz-input-number>\n\n  <!-- With affixes -->\n  <nz-input-number>\n    <span nzInputPrefix>Prefix</span>\n    <span nzInputSuffix>Suffix</span>\n  </nz-input-number>\n\n  <!-- With addons -->\n  <nz-input-number>\n    <span nzInputAddonBefore>Before</span>\n    <span nzInputAddonAfter>After</span>\n  </nz-input-number>\n  ```\n\n  The old input-number component is marked as **deprecated**, and its entrypoint had changed to `ng-zorro-antd/input-number-legacy`.\n  `NzInputNumberComponent` is now `NzInputNumberLegacyComponent`, and `NzInputNumberModule` is now `NzInputNumberLegacyModule`.\n\n  Don't worry, `ng update ng-zorro-antd` will automatically do the migration.\n\n- **cascader:** Cancel support for writing value with `NzCascaderOption[]` type.\n\n  In the past, the cascader component kept a trick that if you wrote value with `NzCascaderOption[]` type, it extracted value by mapping each item to its value property, for example:\n\n  ```ts\n  @Component({\n    template: `<nz-cascader [nzOptions]=\"options\" [ngModel]=\"value\"></nz-cascader>`\n  })\n  export class ExampleComponent {\n    value = [{ label: 'NG ZORRO', value: 'ng-zorro-antd' }];\n  }\n  ```\n\n  then the value of cascader would be `'ng-zorro-antd'`.\n  It's strange that the input and output values don't match when we haven't changed the values, and it's hard to maintain. We expect that the value passed in should be the value in the list of options.\n\n  In v19, this trick is removed and if you're already using this trick in your code, please consider the add a `map` function to pass the actual value.\n\n- **checkbox** Redesign the checkbox group component.\n  - Remove `NzCheckBoxOptionInterface['checked]` field. By the way, `NzCheckBoxOptionInterface` is marked as deprecated, use `NzCheckboxOption` instead\n  - `nz-checkbox-group`: Type of `ngModel` is changed from `NzCheckBoxOptionInterface[]` to `NzCheckboxOption['value'][]`\n\n- **card:** Remove redundant `nzBorderless` input property. Use `nzBordered` instead.\n- **image:** Remove deprecated `FADE_CLASS_NAME_MAP` and `IMAGE_PREVIEW_MASK_CLASS_NAME`\n- **pipes:** Remove deprecated `NzSafeNullPipe`\n- **segmented:** Redesign the segmented component.\n  - Value of `ngModel` is changed from `index` to option's value\n  - Change emission type of `nzValueChange` from `number` to option's value type (`string | number`)\n  - Remove `nzLabelTemplate`, use `nz-segmented-item` directive instead\n- **space:** Rename `exportAs` of `NzSpaceComponent` from `NzSpace` to standard `nzSpace`\n- **transfer:** Rename `nzTreeCheckBoxChange` to `nzTreeCheckboxChange`\n- **tree,tree-select:** Rename `nzCheckBoxChange` to `nzCheckboxChange`\n\n### Deprecations\n\nThe following APIs are marked as **deprecated** in v19 and will be removed in the next major version.\nPlease refer to related documentation for better alternatives.\n\n| Module                              | API                                                      |\n| ----------------------------------- | -------------------------------------------------------- |\n| `ng-zorro-antd/button`              | `NzButtonGroupComponent`                                 |\n| `ng-zorro-antd/core/form`           | `NzFormPatchModule`                                      |\n| `ng-zorro-antd/checkbox`            | `NzCheckboxWrapperComponent`                             |\n| `ng-zorro-antd/input`               | `NzInputGroupComponent#nzCompact`                        |\n| `ng-zorro-antd/input-number-legacy` | `*`                                                      |\n| `ng-zorro-antd/message`             | `NzMessageModule`                                        |\n| `ng-zorro-antd/notification`        | `NzNotificationModule`<br/>`NzNotificationServiceModule` |\n\n## [18.2.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/18.2.0...18.2.1) (2024-11-15)\n\n### Bug Fixes\n\n- **anchor:** fix `a` tag problem with `null` or `undefined` value if TemplateRef provided ([#8864](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8864)) ([41f6609](https://github.com/NG-ZORRO/ng-zorro-antd/commit/41f66095fdaee05d8bfdae13e8ec18a63cee1f2c))\n- **color-picker:** remove inline style (CSP compliant) ([#8874](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8874)) ([0264da9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0264da98babca9f14a2c69ccb019944aa4e9f88f))\n- **image:** remove inline style (CSP compliant) ([#8876](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8876)) ([63c8953](https://github.com/NG-ZORRO/ng-zorro-antd/commit/63c895329a78575654994b607fa822f5735166f4))\n- **qrcode:** remove event listeners once settled ([#8861](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8861)) ([40d466d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/40d466dab751c51b8cecb97dc974a1d17a7692e6))\n- **select:** remove inline style (CSP compliant) ([#8873](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8873)) ([9431d0d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9431d0d9e54c76271f7dc13c9833c29bf4e7dc13))\n- **transfer:** cancel selecting all should emit `nzSelectChange` event ([#8872](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8872)) ([5ff9821](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5ff98216002da5c9fc23a9d9c8bd4d3b68495d51))\n- **watermark:** cleanup event listeners once settled ([#8862](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8862)) ([decd477](https://github.com/NG-ZORRO/ng-zorro-antd/commit/decd4772bdbfeb1a1397c2b597882503ca5685ad))\n\n## [18.2.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/18.1.1...18.2.0) (2024-11-07)\n\n### Bug Fixes\n\n- **i18n:** add missing translations to `nb_NO` ([#8712](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8712)) ([8c9bcd1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8c9bcd18867fca3778d42b844034a4d3370ebe3b))\n- **i18n:** add missing translations to `hu_HU` ([#8769](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8769)) ([9e21ae8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9e21ae8c3c771ff3bce98a11c37f5c81c62f3402))\n- **badge:** NG0955 warning in nz-badge-sup component ([#8858](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8858)) ([cc52555](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cc5255587edae6731d38f39786c701679c50020b))\n- **select:** multiple select cause switch size flash when init ([#8851](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8851)) ([d28876c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d28876cdae5bb1b4df3fda66ebdf6248e43f5a36))\n- **carousel:** correctly switch slides in rtl mode ([#8705](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8705)) ([85f23a1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/85f23a1b768151a35637c054c7bf42cbf656268e))\n- **drawer:** emit `nzVisibleChange` when close on navigation ([#8850](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8850)) ([29827df](https://github.com/NG-ZORRO/ng-zorro-antd/commit/29827dfe2346badc5178da71884bb4c3264a695d))\n- **modal,drawer:** secondary overlays not scrolling inside ([#8804](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8804)) ([ed7951d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ed7951d2e95707c93e993dbb744382e6c9c7dee8))\n- **modal:** remove dark backdrop when `nzMask` is false ([#8798](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8798)) ([f2f04fe](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f2f04fe8971b23aba9ec5807414afe5ab6f27fc7))\n- **transfer:** correctly set transfer button disable state ([#8824](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8824)) ([195ad26](https://github.com/NG-ZORRO/ng-zorro-antd/commit/195ad260a8259129517ee18a208853b9e32c132d))\n\n### Features\n\n- **datepicker:** send event emitter when panel mode change ([#8685](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8685)) ([6462a47](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6462a47538a4c7f00f180d82dc3567379277e4b3))\n- **tabs:** support `destroyInactiveTabPane` ([#8845](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8845)) ([0de6d62](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0de6d627cb9105d97b1aca827b1f89a8f3bdcec9))\n\n## [18.1.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/18.1.0...18.1.1) (2024-08-20)\n\n### Bug Fixes\n\n- fix ngtypecheck reference issue caused by [@angular/compiler-cli#56945](https://github.com/angular/angular/issues/56945) ([#8699](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8699)) ([8e459c1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8e459c192cf5c4b1903a744c0548df800aa64bfc))\n- **date-picker:** fix the NG0956 warning when recreating entire collection ([#8658](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8658)) ([70a0817](https://github.com/NG-ZORRO/ng-zorro-antd/commit/70a0817cd8db49234726f160d9c2ae36f5c650b7))\n- **grid:** fix the NG0955 warning in showcase ([#8679](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8679)) ([6414c92](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6414c924cdb013c0ffb96436dd89354e275fa544))\n- **tree-select:** clear selected nodes when user set value ([#8693](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8693)) ([91927bc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/91927bcede24a89ffc5ec4c814503547c86ad09e))\n\n## [18.1.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/18.0.1...18.1.0) (2024-07-25)\n\n### Bug Fixes\n\n- **cascader:** hide placeholder when trigger `compositionstart` event ([#8641](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8641)) ([17b0ea3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/17b0ea362021a458c18204f73c34c08695300e2a))\n- **i18n:** add missing translations to `pt_BR` ([#7790](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7790)) ([6fc1c78](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6fc1c78b4ca0d37bf5eb6e9e52f0fd150ca5855d))\n- **i18n:** add scanned field to QRCode for `fr_BE`, `fr_CA`, `fr_FR` and `lv_LV` ([#8614](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8614)) ([9b69410](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9b69410ce8f84fbd65e2f0dc627189403888d8f1))\n- **schematics:** import missing `RouterLink` in template ([#8621](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8621)) ([032a0c2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/032a0c2384434fc042674a60b005a5a479f6626a))\n- **transfer:** disabling selection does not affect selecting all ([#8633](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8633)) ([75d8c7b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/75d8c7b93310cd54677ac75f470b2967ebd092cb))\n\n### Features\n\n- **breadcrumb:** add `nzRouteFn` ([#6313](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6313)) ([6d805c4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d805c44073297ea17742d43066c6b95e4af5ffe))\n- **i18n:** add `en_AU` ([#7919](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7919)) ([c4e6c8d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c4e6c8df3fe48ced3097f0f1347ddbbfde3fda9c))\n- **icon:** add `provideNzIcons` and `provideNzIconsPatch` API ([#8650](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8650)) ([b22672d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b22672db7cbce362b14a3dad1ff3b3c45abed27f))\n- **popconfirm:** support popconfirm template context ([#7989](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7989)) ([6d27073](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d27073a52a96d17d8625a9d5d7b820984aa5000))\n- **table:** support `nzSummary` ([#8639](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8639)) ([20bb5b2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/20bb5b24c7d01d87f0d50c37248ddd862d9bf341))\n- **table:** support `nzFixed` for `nzSummary` ([#8642](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8642)) ([bef12e6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bef12e6218c53028f8907f2e917945ddc8283db5))\n- **tree-select:** support TemplateRef type for `nzNotFoundContent` ([#8638](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8638)) ([13e8a45](https://github.com/NG-ZORRO/ng-zorro-antd/commit/13e8a452c4a96f78d6cf900830ba4b585ed36735)), closes [#8631](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8631)\n\n## [18.0.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/18.0.0...18.0.1) (2024-06-27)\n\n### Bug Fixes\n\n- **graph:** fix [@for](https://angular.dev/guide/templates/control-flow#for-block---repeaters) track function ([#8587](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8587)) ([7687ff2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7687ff2c907ee5ab262ee08240bc932b6112b1ae))\n- **icon:** fix [@for](https://angular.dev/guide/templates/control-flow#for-block---repeaters) track function ([#8588](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8588)) ([8a27bab](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8a27babf30f7726113fed5511bfbd0067c0bbd37))\n- **table:** fix [@for](https://angular.dev/guide/templates/control-flow#for-block---repeaters) track function ([#8593](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8593)) ([b275063](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b2750630a0da3f415931cdf9ba6e6a618dd5d329))\n- **pagination:** fix [@for](https://angular.dev/guide/templates/control-flow#for-block---repeaters) track function ([#8586](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8586)) ([6bb95c0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6bb95c0905de9da1493590da2c6f76cc1b2a23bc))\n- **i18n:** add missing german translations `de_DE` ([#8605](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8605)) ([8d75378](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8d75378ea612a0ab91f03ec1a709f88c2d22af21))\n- **i18n:** add scanned field to QRCode `fa_IR` ([#8597](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8597)) ([9c6e4bf](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9c6e4bf6b65810b0f659a366d34b54528d55cc0f))\n- **table:** missing no-result in fixed header table ([#8574](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8574)) ([6cff80e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6cff80e90788ce0b84b232a0fb67516b795c88b0))\n\n## [18.0.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/17.4.1...18.0.0) (2024-06-06)\n\n### ⚠ BREAKING CHANGES\n\n- **collapse:** change nzExpandIconPosition type from `left` | `right` to `start` | `end` ([#8561](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8561)) ([3ad5674](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3ad56749b0c8222b37444f27f81942fba4bc53e3))\n- no longer use inline JavaScript in Less ([#8552](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8552)) ([7e873c8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7e873c863a1c8e9c053f64aca86bf9c7c9a11a21))\n\nNo need to wrap Less functions provided by antd (including `colorEasing`, `colorPalette`, `tinycolor`) with ~\\`\\` anymore.\n\n```diff\n- color(~`colorPalette('@{primary-color}', 5)`)\n+ color(colorPalette('@{primary-color}', 5))\n```\n\n### Bug Fixes\n\n- **cascader,select,time-picker,tooltip,tree-select:** take in account shadow dom when getting the target of an event ([#7853](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7853)) ([843b703](https://github.com/NG-ZORRO/ng-zorro-antd/commit/843b7035225df3d3a635a5ef8926d1e80f10ae18))\n- **tooltip:** fix arrow color when custom color ([#8555](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8555)) ([92c586b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/92c586b8f5e5fc0ec0e4cb2cc10b73a699b1555a))\n- **upload:** prevent drop event for firefox only ([#8551](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8551)) ([c6e7bd7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c6e7bd7682a776a7ad3f34b589c9c473430e6baa))\n- **rate:** half value when allow half is false ([#8536](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8536)) ([7742fe3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7742fe30b718aa19f2988f6354d982d439ad2c7b))\n\n### Features\n\n- **date-picker:** support quarter selection of date picker ([#8478](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8478)) ([3513889](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3513889367ef468b9e792698f85bb6b890edec86)), closes [#7818](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7818) [#7380](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7380)\n- **qrcode:** qrcode supports scanned state ([#8447](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8447)) ([0be6178](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0be617854d1493a342c9354ce1156fcf323acc97))\n- **rate:** emit hover change when leave ([#8448](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8448)) ([38dcc31](https://github.com/NG-ZORRO/ng-zorro-antd/commit/38dcc3196c62369cd8061a9ead8ab20752e56a66))\n- **statistic:** support for loading state ([#8537](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8537)) ([21c8b62](https://github.com/NG-ZORRO/ng-zorro-antd/commit/21c8b621f15d642c391253ca91c3b124227ca2d9))\n- **table:** support setting virtual height when having no data ([#8457](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8457)) ([724d841](https://github.com/NG-ZORRO/ng-zorro-antd/commit/724d841ebd88a329c59e2cfeee3f9625393c8372))\n\n## [17.4.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/17.4.0...17.4.1) (2024-05-24)\n\n### Bug Fixes\n\n- **card:** use skeleton instead to card-loading-content ([#8528](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8528)) ([a36ebd3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a36ebd329d042dad19733543ce96f459e4cc09d3))\n- **color-picker:** avoid emitted twice nzOnChange event ([#8530](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8530)) ([5dea059](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5dea059202947caf5ef86f802f08ba14a0867288))\n- **list:** static query list-item-action template ([#8527](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8527)) ([85301e0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/85301e0267593457560c5cdcc7fb09ed38944d45))\n- **popconfirm:** fix message icon style ([#8511](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8511)) ([4f1f9bb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4f1f9bba03f38d9ef4ee57380d61e5ca4188648c))\n- **tooltip,popover,popconfirm:** fix hydration error ([#8512](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8512)) ([5009ec0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5009ec0b3a6ff770186681bd4eb61ec662d9896e))\n\n### Features\n\n- **popconfirm:** popconfirm support for nzOkDisabled ([#8542](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8542)) ([8c247db](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8c247dbda2b633d522c53113456600315192a792))\n\n### Performance Improvements\n\n- **back-top:** remove the redundant changeDetectorRef ([c1e39e7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c1e39e7bbc1f863c3a1d26a9cc9cc359b4054dc5))\n- **qr-code:** improved background drawing efficiency ([#8543](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8543)) ([db09bf7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/db09bf73e45d03817c89bba97e1f340cc09ed5d0))\n\n## [17.4.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/17.3.0...17.4.0) (2024-04-19)\n\n### Bug Fixes\n\n- **autocomplete:** remove NgZone dependency ([#8462](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8462)) ([24bb1bc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/24bb1bc5959c0e617090f0459c39db00fd4e2d9a))\n- **button:** add ant-btn-default class ([#8501](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8501)) ([1588199](https://github.com/NG-ZORRO/ng-zorro-antd/commit/15881996f0a9b1e93b0c81843132ba5d7651e528))\n- **calendar:** year dropdown update issue when date is changed programmatically ([#8286](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8286)) ([ee68a2c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ee68a2c90370a6e3a599fe9f914af20117d2faa6))\n- **date-picker:** remove unsafe style ([#8458](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8458)) ([e6b83eb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e6b83eb1881ece341b68f9048e9d3e5ea438ba19))\n- **drawer:** remove inline style to resolve CSP issue ([#8065](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8065)) ([5e89441](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5e89441c26a7df50d0feed746d5595cde2589a7a))\n- **graph:** bring back the disappered arrows of edge ([#8493](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8493)) ([342841c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/342841ceafddb1b74f55e31bfa9ca3e7734e842e))\n- **graph:** remove NgZone dependency ([#8460](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8460)) ([a4ec21a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a4ec21a684b5c96a64bd66670c270533926252bb))\n- **image:** missing swip icon ([#8433](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8433)) ([f1a4050](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f1a405042f84fbc96ed0587ea2e748dc7d468719))\n- **image:** wrong next/prev btn in rtl mode ([#8468](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8468)) ([886138d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/886138d630965b9a0a89d1727f76fed81c6f9528))\n- **list:** remove NgZone dependency ([#8439](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8439)) ([1ec0e76](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1ec0e7672eaba0890b145c706fcc0a75cb5c47f8))\n- **notification:** nzMaxStack initial value error ([#8451](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8451)) ([2c09162](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2c0916265c00cdc026a55b3ab9d829c5e207cf31))\n- **pagination:** add accessible name for nz-pagination-item ([#8476](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8476)) ([47ee143](https://github.com/NG-ZORRO/ng-zorro-antd/commit/47ee14325910c154f1541ee2d5e97539ba9a4e52))\n- **slider:** fix the style of markers in vertical mode ([#8494](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8494)) ([9bcce6c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9bcce6c969c0bef7bdf4526407b2dfc56b7ff660))\n- **tag:** borderless style is invalid in default state ([#8495](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8495)) ([b35e6d6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b35e6d6ba2422eb2c4725b2029a2f9c60720b697)), closes [#8492](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8492)\n- **typography:** remove NgZone dependency ([#8440](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8440)) ([af7fb5d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/af7fb5d27254d26a284faaaa5b812b105f539e3f))\n- **upload:** remove inline style to resolve CSP issue ([#8064](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8064)) ([1ac84a8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1ac84a8428fe644362e0f733c9a151fa848cedbf))\n\n### Features\n\n- **modal:** supports masked layer response for each click ([#8429](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8429)) ([31b90fa](https://github.com/NG-ZORRO/ng-zorro-antd/commit/31b90fa52232abe7b090f60797d4335329677c4c))\n- **notification:** popup order adjustment ([#8450](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8450)) ([742f14a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/742f14a93472772cbdd96ce89797dc4120c55330))\n- **select:** support nzOptionHeightPx in global config ([#8504](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8504)) ([4efc5ab](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4efc5ab38f74ce07a769f57453b0da375c17ce5c)), closes [#8503](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8503)\n- **skeleton:** support for square shape of skeleton button ([#8481](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8481)) ([af1483a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/af1483a9be544bd41b8f2a4a4c8027425f22b925))\n\n## [17.3.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/17.1.0...17.3.0) (2024-03-11)\n\n### Bug Fixes\n\n- **doc:** replaced link for monaco editor options ([#8393](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8393)) ([fdfc816](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fdfc816e72938fce47bbdfe274de00ad4e89b242))\n- **docs:** fix progress, code-editor docs error ([#8383](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8383)) ([407e76a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/407e76a21afb4e1677fc73e89df69b26789da2fd))\n- **select:** issue with nzScrollToBottom while display scaling ([#8355](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8355)) ([bb0468e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bb0468e9e95c7c00efd2a5655d0266ae1ce17368))\n- **avatar:** avatar not re-scaling properly ([#8365](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8365)) ([e7b1fa0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e7b1fa0d36b173934bda10f796efa0c6e17d66e5))\n- **carousel:** not adapting to new size when resizing ([#8374](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8374)) ([6e1decb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6e1decbc7507b07dbb28897f53c6cbcc6ca2eaa6))\n- **cdk:** zIndex is not used properly when creating overlay ([#8373](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8373)) ([b932d65](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b932d65a546f0b2729249713fdaad41fefebb602))\n- **i18n:** add missing pt texts ([#8426](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8426)) ([d575c53](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d575c53371f34053a7cd2b6a020a3da1005b708a))\n- **i18n:** added missing translations to ja_JP ([#8290](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8290)) ([662b730](https://github.com/NG-ZORRO/ng-zorro-antd/commit/662b73049f8ed8ae70caea573e809016607a795a))\n- **i18n:** added missing translations to vi_VN ([#8295](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8295)) ([987a799](https://github.com/NG-ZORRO/ng-zorro-antd/commit/987a799ab1ca5bfdcef162d322423b65fb64dfe6))\n- **tabs:** slide indicator missing in small screens ([#8372](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8372)) ([a0b08be](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a0b08be73a77c0a0967f5a301fe8c7ebbfca103c))\n- **tabs:** wrong cursor ([#8386](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8386)) ([3dc1579](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3dc1579805f1a867689160fede25fd005983ddf1))\n\n### Features\n\n- improve schematics ([#8411](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8411)) ([921f1c1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/921f1c18266ead602c2e2c627a171608507807d4))\n- **anchor:** horizontal anchors ([#8342](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8342)) ([9cc44f8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9cc44f8bdb55fbf2fcf4c8ce4da4fab1120245dc))\n- **calendar:** custom header ([#8418](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8418)) ([ec7ec35](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ec7ec35573fc46ba01af1368087b5de0b13ab7c7))\n- **color-picker:** built-in color-picker package ([#8428](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8428)) ([534fe62](https://github.com/NG-ZORRO/ng-zorro-antd/commit/534fe6277287dd64730546d3d4cc0f1be90a211a))\n- **drawer:** return componentRef when nzContent is a component ([#8339](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8339)) ([f71162b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f71162bbbb30c7b362774b2bc170a0ffd1c0dcf7))\n- **image:** now supports horizontal and vertical flip ([#8168](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8168)) ([e856515](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e856515888102b5a3583a2223372263a4bff1c50))\n- **image:** zoom using mouse wheel ([#8180](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8180)) ([4235c29](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4235c293c0abf889bba0bc31d2ba18cf5d41b51d))\n- **modal:** draggable ([#8419](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8419)) ([ce33294](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ce332947c49e7e6dd02d9bb80eb2fe3f7beab3af))\n- **modal:** expose componentRef nzContent ([#8389](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8389)) ([e53000e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e53000e8b52972cc73070a8781d276dc26ebca0b))\n- **segmented:** now supports segmented with icon only ([#8368](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8368)) ([e8dea7a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e8dea7a83e6f98e2486c4e3f894f86b646025c1c))\n- **select:** select max tag count ([#8371](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8371)) ([18b898e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/18b898e8c5201c6785e5060850d3597601c39401))\n\n## [17.2.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/17.1.0...17.2.0) (2024-01-29)\n\n### Bug Fixes\n\n- **table:** add missing import to nz-table-inner-scroll ([#8328](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8328)) ([936317e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/936317e6702e790f5f8827e074fe12fd55fbf0f3))\n- **tree-select:** fix search box exception when Chinese search ([#8324](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8324)) ([aacd62b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/aacd62b0beeac35b18829ae4e382626b655c7e05))\n- pipeline job failed ([#8367](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8367)) ([6024bcc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6024bcc7a9453976d0023fe7b455dc452ced8bd4))\n\n### Features\n\n- **color-picker:** make color picker standalone ([#8316](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8316)) ([b050474](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b05047433311fe60ee82d100467c896f2167d925))\n- **tag:** borderless mode ([#8320](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8320)) ([e428083](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e428083537c8c25d463980749f63b1b8ab129057))\n- **timeline:** allow custom color ([#8335](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8335)) ([66a88db](https://github.com/NG-ZORRO/ng-zorro-antd/commit/66a88dbbb1cdd26ee9411de2394fd2231a2807f0))\n\n## [17.1.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/17.0.1...17.1.0) (2023-12-17)\n\n### Bug Fixes\n\n- fix logic for generating directive tags ([#8171](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8171)) ([e37eab2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e37eab2be160a0db8154a2074c836782caa8cda3))\n- **calendar:** style radio button not apply ([#8298](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8298)) ([996e141](https://github.com/NG-ZORRO/ng-zorro-antd/commit/996e141042470e487d915d38477ad51928d3e2a0))\n- **core:** warning cron parser common js dependencies ([#8277](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8277)) ([138d666](https://github.com/NG-ZORRO/ng-zorro-antd/commit/138d666e0527dba2f3f5ac43b05ce4810fffe9f7))\n- **cron-expression:** output type error ([#8189](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8189)) ([ad02381](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ad02381cfc4643b191caab7e056fd1a93086a45e)), closes [#8188](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8188)\n- **select:** input clear when nzAutoClear ([#8167](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8167)) ([fefcb68](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fefcb68dc9831eb2208746b3fe44346f80f8202f))\n- **tabs:** aria controls have wrong value ([#8237](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8237)) ([d9a2d27](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d9a2d27be30e9bfc635d8ac3d0e31538f6092b1c))\n- **tooltip:** color of the tooltip arrow does not change ([#8192](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8192)) ([bc344ed](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bc344edc3dca8cdf777bf986130eeae5c3543f63))\n- **water-mark:** nzWaterMark is a block element && standalone ([#8197](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8197)) ([e4d6082](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e4d608274e0b56acf9b720cf519d757c660c125e)), closes [#8187](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8187)\n\n### Features\n\n- **alert:** support standalone component ([#8182](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8182)) ([167bed0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/167bed0350400a4a69f727c62237953b71831f26))\n- **anchor:** support standalone component ([#8185](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8185)) ([03cda21](https://github.com/NG-ZORRO/ng-zorro-antd/commit/03cda216f2d0f1b31e365d6cb30a309309cbc868))\n- **autocomplete:** support standalone component ([#8193](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8193)) ([548e842](https://github.com/NG-ZORRO/ng-zorro-antd/commit/548e842c00d74fc4f8a8c9b69587bc14fdd9aecf))\n- **avatar:** support standalone component ([#8194](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8194)) ([4e2cb74](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4e2cb748b1c13ba1176b93f547fda10a188fec95))\n- **back-top:** support standalone component ([#8195](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8195)) ([db5d5f4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/db5d5f4d02531665e2a88dc114545ab225e61673))\n- **badge:** support standalone component ([#8201](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8201)) ([3d1427f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3d1427f60f450c9193669a39ef632017fa33c4f6))\n- **breadcrumb:** support standalone component ([#8202](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8202)) ([165f171](https://github.com/NG-ZORRO/ng-zorro-antd/commit/165f171dd51cff29ac3e02f046bf2966c4ad9aa0))\n- **button:** support standalone component ([#8275](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8275)) ([3c09507](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3c09507c2c50f67e4f500c4f08a15617ae8e42bc))\n- **calendar:** support standalone component ([#8274](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8274)) ([80d68a3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/80d68a31d65dd1d5505a1b96f3e02e6ea45e000b))\n- **card:** component support standalone ([#8273](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8273)) ([0902a4b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0902a4b2b3c3ad0a8bf1740c67bf94194212af7c))\n- **carousel:** support standalone component ([#8272](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8272)) ([e4244fb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e4244fb7891eed2f21253e922317eae3b8469a3a))\n- **cascader:** support standalone component ([#8271](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8271)) ([3ab6e5b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3ab6e5bafbb007a5929f347fb81ca83761e4e074))\n- **cdk:** support standalone component ([#8270](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8270)) ([d66bcba](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d66bcbad09552c3f86401948710d417bb39fd68f))\n- **checkbox:** support standalone component ([#8269](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8269)) ([1491fb3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1491fb3523ab4cd4b4ff498d37669dd9407e1638))\n- **code-editor:** support standalone component ([#8268](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8268)) ([24547c6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/24547c61858d0656a71c943a67395cffdfa05881))\n- **collapse:** support standalone component ([#8267](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8267)) ([dc43fa5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dc43fa5c189d8b6d09f661e52e10e955d873c264))\n- **color-picker:** disable alpha ([#8178](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8178)) ([0bebd6a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0bebd6a696cc29c179758951f706fd276a1dae89))\n- **comment:** support standalone component ([#8266](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8266)) ([5af11ea](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5af11ea0232c90d74607c9e4a9ffb053d0f0950c))\n- **core:** make no-animation standalone ([#8257](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8257)) ([de579bc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/de579bca2112bd9691429eee6144c09bb16d3b2b))\n- **core:** support standalone component ([#8265](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8265)) ([c51e8da](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c51e8daf1ba09646cf7c043756fd14274483c641))\n- **cron-expression:** support standalone component ([#8264](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8264)) ([ae6ceeb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ae6ceeb560f86ead21d6c9ce9a53f435c52f9944))\n- **date-picker:** support standalone component ([#8263](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8263)) ([ac48fba](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ac48fba4c6e591db03e41ab427b317c1868f8071))\n- **description:** support standalone component ([#8262](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8262)) ([128f4c0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/128f4c0055fd1150520509e1fa6bddbc74c65b85))\n- **divider:** support standalone component ([#8258](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8258)) ([3a7cd50](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3a7cd50e092ad712b66243fa5c2c582f169e658c))\n- **drawer:** support standalone component ([#8256](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8256)) ([2fbe4c0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2fbe4c0eb221f833fbb0d0801ce546a3c0300555))\n- **dropdown:** support standalone component [#8254](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8254) ([#8255](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8255)) ([c5df26f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c5df26f2ba94f00d80b66c24bf98b09e5f162081))\n- **empty:** support standalone component ([#8254](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8254)) ([15636d2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/15636d2c530f294e3b217e4150be70a5f050bccf))\n- **experimental-image:** support standalone component ([#8253](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8253)) ([7325781](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7325781367998543680af043bd19b911c3ac67e7))\n- **flex:** add flex component ([#8145](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8145)) ([f8fedfc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f8fedfc88957a449de2a9960605d3528848f9caa))\n- **form:** support standalone component ([#8252](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8252)) ([e742e39](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e742e399e2e870f7079f183f800d0d2023b8447d))\n- **graph:** support standalone component ([#8251](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8251)) ([d2f1d30](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d2f1d30fe7925205b79d7da4462a33a496fd94bf))\n- **grid:** support standalone component ([#8250](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8250)) ([208652c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/208652c1ffd98ef8ea8e52b69d9376aaafeb390a))\n- **i18n:** support standalone component ([#8249](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8249)) ([a91cac7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a91cac7e1bbd4379b9498d705a9b6fa1a00e4cd8))\n- **icon:** support standalone component ([#8248](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8248)) ([b0dbfbc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b0dbfbca5452b54ed7c8c4c0b6d1aa2ae0512a34))\n- **image:** support standalone component ([#8200](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8200)) ([63b8777](https://github.com/NG-ZORRO/ng-zorro-antd/commit/63b8777645fe93f587e7b09c5ea9d6efbd497b87))\n- **input-number:** support standalone component ([#8246](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8246)) ([6210fa0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6210fa0b571dd3d0a6b1069bcddd4ad44c3d6104))\n- **input:** support standalone component ([#8247](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8247)) ([0a7028c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0a7028c27c2018039b771cdfccd8cc0654e2a97a))\n- **layout:** support standalone component ([#8245](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8245)) ([d21f8a1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d21f8a10876d222160c5e60d467283562b21f087))\n- **list:** support standalone component ([#8244](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8244)) ([1f3010f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1f3010fccc0c6bfe8e6b0149152794e3e2371a9a))\n- **mention:** support standalone component ([#8243](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8243)) ([adc5e94](https://github.com/NG-ZORRO/ng-zorro-antd/commit/adc5e94cdd7dfc75800808a046861bc9943dd548))\n- **menu:** support standalone component ([#8242](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8242)) ([4673926](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4673926a581b532470062f7cd5672a176638f111))\n- **message:** support standalone component ([#8241](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8241)) ([c2120b2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c2120b2fad4b1ce30d496c75db27cf08d648ef8c))\n- **modal:** support standalone component ([#8240](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8240)) ([387d664](https://github.com/NG-ZORRO/ng-zorro-antd/commit/387d66434cad9b117cf3a5f54c75bc2eeab1f69f))\n- **notification:** support standalone component ([#8236](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8236)) ([686b6b0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/686b6b0d1183a15e69ba59b777d3d3078bacd1af))\n- **page-header:** support standalone component ([#8235](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8235)) ([aa91486](https://github.com/NG-ZORRO/ng-zorro-antd/commit/aa91486c5ec9ffe26a2aef62800793c909e4349f))\n- **pagination:** support standalone component ([#8234](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8234)) ([0f1690c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0f1690c89de63bc479653f4d3514a06f5d19a5f7))\n- **pipes:** make the css-unit pipe support more units ([#8260](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8260)) ([5e611e7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5e611e7d51a8cad3697a381612225b0d12879d55))\n- **pipes:** support standalone component ([#8233](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8233)) ([319381a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/319381a443b7cbb64053d7d30f12d501b0221bcb))\n- **pop-confirm:** support standalone component ([#8232](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8232)) ([9d656b2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9d656b2c9bde26bf4bb600ad5eff5fa0f3035804))\n- **popover:** support standalone component ([#8231](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8231)) ([f7468e2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f7468e212533d21655a7c74ab1efcf320facfc07))\n- **progress:** support standalone component ([#8230](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8230)) ([7022471](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7022471052e562a72e741abf5e9b9597f6437d2c))\n- **qr-code:** support standalone component ([#8228](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8228)) ([769f74c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/769f74c9323db91251c191151d48283be64781a8))\n- **radio:** support standalone component ([#8227](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8227)) ([b62ac64](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b62ac6471b7038db01ebfbb9efd597eae0b8517f))\n- **rate:** support standalone component ([#8226](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8226)) ([90edba6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/90edba69d11b82c5b31e91af8da34174b71c6fb8))\n- **resizable:** support standalone component ([#8225](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8225)) ([ff14ed0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ff14ed0e4a5ae6562a71459e407863bd9f84a1ca))\n- **result:** support standalone component ([#8224](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8224)) ([572965d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/572965d3b61045a01cb8fc14a132a5c0aa8574ec))\n- **segmented:** support standalone component ([#8223](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8223)) ([86a49d2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/86a49d277b8c8e66bd310d920c43b1e801c2d31c))\n- **select:** support standalone component ([#8222](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8222)) ([ed0de77](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ed0de779cfe63f1ca68b4b8dedbba40a5ad59e95))\n- **skeleton:** support standalone component ([#8220](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8220)) ([a2858d3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a2858d3bb10e87e472e4f917176172f283d46352))\n- **slider:** support standalone component ([#8219](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8219)) ([428c53c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/428c53c6361c5f9afe79ee147a28635c010fea4c))\n- **space:** support standalone component ([#8218](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8218)) ([a84ddef](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a84ddeff5582426a3dd608cab567245898be60c7))\n- **spin:** support standalone component ([#8217](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8217)) ([cd23e33](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cd23e3355d1f8828d93a7d3e331f20180ada4bef))\n- **statistics:** support standalone component ([#8216](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8216)) ([186ef60](https://github.com/NG-ZORRO/ng-zorro-antd/commit/186ef6049cae90e10a2c3f66186cf856f5b9abb2))\n- **steps:** support standalone component ([#8215](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8215)) ([dbb6fcb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dbb6fcb952366f200673bcec8e28097844370869))\n- **switch:** support standalone component ([#8214](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8214)) ([3f6a9ed](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3f6a9ed0a04ba93b97dedcb4b5625d3b79828c32))\n- **table:** support standalone component ([#8276](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8276)) ([5765ae9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5765ae93f1adf304020697fc84a1984ef54f9a1b))\n- **tab:** support standalone component ([#8213](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8213)) ([69dd31a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/69dd31ac275f6251b22f7af9aef4ea78fd278adf))\n- **tag:** support standalone component ([#8212](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8212)) ([15af7c8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/15af7c8956ed4c8f11f637446d0285b5a52339f1))\n- **time-picker:** support standalone component ([#8211](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8211)) ([641ebb2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/641ebb2d8072fa343c9275222be8c4a23f8fceb4))\n- **timeline:** support standalone component ([#8210](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8210)) ([b7c6859](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b7c685913abb14133955dfc81678207ec3e64aff))\n- **tooltip:** support standalone component ([#8209](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8209)) ([125768c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/125768c16f3c5030373058d120c05141208ec42c))\n- **transfer:** support standalone component ([#8208](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8208)) ([960144e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/960144e5f5a076fe8c7ad56a48ba97e147bc430b))\n- **tree-select:** support standalone component ([#8206](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8206)) ([64ec76a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/64ec76a2440c7befeaeb8409f84801fd8483af47))\n- **tree-view:** support standalone component ([#8205](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8205)) ([d4426fc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d4426fc6675515ddd1db54be84731d1ba44b52b8))\n- **tree:** support standalone component ([#8207](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8207)) ([b9cf3b0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b9cf3b03d8c51fcfd809dd8d4424aae70ff77094))\n- **typography:** support standalone component ([#8204](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8204)) ([d7e387f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d7e387fa707f3a8473225187e660459498d97ca2))\n- **upload:** support standalone component ([#8203](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8203)) ([7cd08ae](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7cd08ae3b6d7ff0e252eb237a60288930f73c15d))\n\n## [17.0.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/17.0.0...17.0.1) (2023-11-20)\n\n### Bug Fixes\n\n- **schematics:** cannot generate files and add default builders ([#8176](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8176)) ([de8a6b7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/de8a6b782d16f906198d6d6ba512059b8dcb463c))\n\n## [17.0.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/16.2.2...17.0.0) (2023-11-18)\n\n### Bug Fixes\n\n- **autocomplete:** fix the wrong value of internal nz-auto-option ([#7907](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7907)) ([0a312e3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0a312e3203db13cba6e4ebd6dc4c53e3c09ac206))\n- **cron-expression:** exception error & cancel format prompt copy ([#8114](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8114)) ([ea69790](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ea697909231753e438b2ba07d4ec15c255f3a5dc))\n- **form:** wrong element to focus when clicking label ([#8135](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8135)) ([b3d135f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b3d135fc512a016430426a36330c0f527234f4e4))\n- **i18n:** added missing translations to pl_PL ([#7950](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7950)) ([7819426](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7819426f9ff3a110e06aa9cb47e7396edcfc18d7))\n- **i18n:** update fa_IR translations ([#8143](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8143)) ([4f63198](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4f63198aae7441fe94de64e1740d1f2429a629c1))\n- **i18n:** Update fr/be/ca translations ([#8137](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8137)) ([211db31](https://github.com/NG-ZORRO/ng-zorro-antd/commit/211db31202ea7b099405aecaa5273461bbc26ef4))\n- **mention:** page not loading entirely ([#8146](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8146)) ([9505c7c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9505c7c4aa222d36e63597b128f01ab0ba3e934a))\n- **resizable:** fix pointer capture bug ([#8169](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8169)) ([a0b8a0b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a0b8a0baba0259552a8d0e9eae442daa99027f24))\n- **select:** do not run tick when scrolling to activated value ([#8159](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8159)) ([7ce50b3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7ce50b3494d01bedbfdd8413dc8ef36ef836e377))\n- **slider:** step can not click the problem ([#7820](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7820)) ([1e1c753](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1e1c753b04e5c01cc61589d16048815ec9f4b9c5))\n- **table:** custom column styles collapse when using nzScroll ([#8044](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8044)) ([fde48f9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fde48f9c8a5e934fe32f421d627960dbeb5615ef))\n- **tree-select:** 修复回显顺序问题 ([#8108](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8108)) ([eb4077d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/eb4077df104743fd7ccdc44307c2dc8aa5dbbbca))\n- **tree:** nzCheckBoxChange never emitting ([#8038](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8038)) ([a9dc205](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a9dc2052930b7f6694d5933a86fc3b488b7bd786))\n\n### Features\n\n- **affix:** support standalone component ([#8037](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8037)) ([583883c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/583883c0623d640bbea2d04b3a76896d08a68d4c))\n- **hash-code:** add HashCode component ([#8111](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8111)) ([0254ee2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0254ee2e673d8ac8cff42a2aef2933367f8b0931))\n- **image:** add scale step ([#8163](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8163)) ([5aa4db9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5aa4db9f3b429e1f973a75f65cdd8b107586634d))\n- **notification:** support for more custom templates ([#8046](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8046)) ([9689c42](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9689c4298e57d67eb340140c8924d4743f07bd04))\n- **schematics:** support ng-add in standalone app ([#8095](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8095)) ([c1b61f7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c1b61f720199ebfba0f48834b2ceaf93fed148d1))\n- **slider:** add the ability to use a template ([#7505](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7505)) ([7c79ab3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7c79ab37a8c0b4bc47bf1873c167417f316c94a9))\n- **table:** add `nzLabel` to include aria-label in checkboxes ([#7903](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7903)) ([5834e46](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5834e469291ee2a6975e4b74015468d7c1d739d2))\n- **table:** nzExpand supports custom icon ([#7886](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7886)) ([1507ed0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1507ed0e2c1e869bd45925f2335ff1c4a3570430))\n- **tooltip,popover,popconfirm:** make cdkConnectedOverlayPush open for tooltip ([#8166](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8166)) ([a821c62](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a821c62c5a438ff24282230376b18cd0bfdbfc19))\n\n## [16.2.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/16.2.1...16.2.2) (2023-10-23)\n\n### Bug Fixes\n\n- inline cdk-overlay style ([#8132](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8132)) ([3209d74](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3209d744187133e518f564bfe5a2f56ac371fc22))\n- **cascader:** compatible with rxjs v6 ([#8133](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8133)) ([54a5c76](https://github.com/NG-ZORRO/ng-zorro-antd/commit/54a5c769a061bc07e342c1f462bf27c422df44a3))\n- **drawer:** drawer not open ([#8120](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8120)) ([24d0664](https://github.com/NG-ZORRO/ng-zorro-antd/commit/24d06640a623f3ea2fd9fa459c729a103938d7fc))\n\n## [16.2.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/16.2.0...16.2.1) (2023-10-19)\n\n### Bug Fixes\n\n- inline external css ([#8122](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8122)) ([42da190](https://github.com/NG-ZORRO/ng-zorro-antd/commit/42da1905a74b5a2049c045cef90d3c5cd595b8a3))\n- **color-picker:** optimize demo copywriting and style ([#8088](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8088)) ([6d03099](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d03099e40364b85276db4c0163bae32c62bad73))\n- **menu:** ellipsis menu title content if overflow ([#8055](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8055)) ([0674f78](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0674f785213ad914ad58fddc42e3083ff750f102))\n- **tree-select:** 修复节点为禁用状态时，back快捷键能删除bug ([#8105](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8105)) ([07a1f5e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/07a1f5e41d82ac59c9de744a3528c23e2b871624))\n\n### Features\n\n- **select:** support to customize attr.title of nz-option-item ([#8097](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8097)) ([2ee261a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2ee261ac24f7ea0501d07ad35fcdb435714ffe9b))\n\n## [16.2.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/16.0.0...16.2.0) (2023-09-18)\n\n### Bug Fixes\n\n- **list:** fix the bug that synchrone action item are not displayed in the item ([#7958](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7958)) ([3b6bdec](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3b6bdecef32ee4d9bb14491b617870733cfd9553))\n- **tree:** fix nz-tree-node keep dragging class with nzBeforeDrop ([#8015](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8015)) ([2d0b3f7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2d0b3f71490e38f8512285f81fcf3baa8f6eb4db))\n- **button:** fix add class ant-btn-icon-only([#7631](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7631)) ([#7678](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7678)) ([7470ed6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7470ed66e1651d753fa43e197a4ab0d548744885))\n- **cascader:** customize the option title to undefined ([#8011](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8011)) ([10003db](https://github.com/NG-ZORRO/ng-zorro-antd/commit/10003db77b9bda21772733c41b3c503ee85d5c81)), closes [#8006](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8006)\n- **core:** resolve CSP errors ([#8059](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8059)) ([295b333](https://github.com/NG-ZORRO/ng-zorro-antd/commit/295b333774990a420c39ba67912598dafd2f1842))\n- **cron-expression:** clear console warnings ([#7926](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7926)) ([b358345](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b358345c14746501e47d7e73dffe41d32b9ab118))\n- **date-picker:** fix code comment ([#7991](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7991)) ([8b6b653](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8b6b653547d92a27079c27b3ef7e68df68a4f5fd))\n- **i18n:** update zh_TW.ts ([#7901](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7901)) ([9bfce45](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9bfce45a37a9c50aafbcaf96a8db9450bc2c5bf1))\n- **message:** clean up DOM after usage ([#7965](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7965)) ([71ead99](https://github.com/NG-ZORRO/ng-zorro-antd/commit/71ead99aa781e50f3c896107f5b668b9a2cea767)), closes [#7772](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7772)\n- **message:** fix the z-index of overlay ([#8081](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8081)) ([b1d2095](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b1d20953eda23c9dcb4f74530621cf9cf1a33e45))\n- **notification:** don't create new messageId for update ([#8000](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8000)) ([e240264](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e240264796dfd3a8692efcb92178688b78d0b69f))\n- **qrcode:** optimize demo display and nzPadding value ([#8020](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8020)) ([078aaf9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/078aaf91335d2d9fa085d06a792ddd49c17948e0))\n- **table:** remove empty space in custom columns ([#8022](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8022)) ([15e244c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/15e244cc954cab1186d33006c7915f34d92e4d6d))\n- **time-picker:** modelChange trigger twice ([#7902](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7902)) ([74c13a4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/74c13a49f92a263a05a34af63f6a2b71a554078e))\n- **tree-view:** re-rendering fix ([#8035](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8035)) ([68cb4b2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/68cb4b2d25d3bc149e4f8e80c030a16db75959c2))\n- **tree:** remove console.log ([#8019](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8019)) ([fa0312a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fa0312a4c68b26902ca28ed974754599b17b2d8a))\n- **watermark:** removing the watermark fails to redraw ([#8012](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8012)) ([030318e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/030318e82725d7650c98bf0ec06d2b23df16d9f0))\n- **showcase:** ui bug in rtl mode inside the doc site ([#8063](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8063)) ([d57b7da](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d57b7dac5817cb1de9de9edda2343a6089854fff))\n\n### Features\n\n- add provide function ([#7952](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7952)) ([150c6ca](https://github.com/NG-ZORRO/ng-zorro-antd/commit/150c6cab4636fa9daa1e892d27b894c6b7381b35))\n- **cascader:** support for load options with observable ([#8048](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8048)) ([1436f21](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1436f212130041bec03d6f2d2d7f5591dff04b7a))\n- **color-picker:** add color-picker component ([#8013](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8013)) ([8439704](https://github.com/NG-ZORRO/ng-zorro-antd/commit/843970459fdb18dfa0ddc861d02e6c21e87c12b4))\n- **cron-expression:** add Unit Testing ([#7993](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7993)) ([605e969](https://github.com/NG-ZORRO/ng-zorro-antd/commit/605e969013cf48a29f4786765cf6c6da9f10643a))\n- **cron-expression:** support nzDisabled && nzBorderless ([#7992](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7992)) ([6d31bde](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d31bde3ef1f43cc145d2009afcf90931e96a731))\n- **dropdown:** close context menu on escape ([#7915](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7915)) ([6d0032e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d0032ededc140a017c01158ae76402a86c7b334))\n- **dropdown:** improve `NzContextMenuService#create()` ([#7768](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7768)) ([9b3e6cb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9b3e6cba852d4a782d15311c910b747a3bbc4d02))\n- **form:** support form label wrap ([#7892](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7892)) ([37391de](https://github.com/NG-ZORRO/ng-zorro-antd/commit/37391de29afdd3126dbbdcae6ca3ba2e637fd596))\n- **input:** hide stepper for type number ([#8003](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8003)) ([0f3aed5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0f3aed599874e0d1c2786f2d14fec52128afbec8))\n- **modal:** Remove nzComponentParams in v16 ([#7930](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7930)) ([baab16c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/baab16c497902f0cbf2668fb061ac8d40ffd18b2))\n- **qrcode:** padding & background color for qrcode ([#8001](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8001)) ([718ba29](https://github.com/NG-ZORRO/ng-zorro-antd/commit/718ba2943c7c7e12c8526e52e8806955d3fb0504))\n- **resizable:** add direction parameter in NzResizeEvent ([#7987](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7987)) ([4143473](https://github.com/NG-ZORRO/ng-zorro-antd/commit/41434734ffe839f3ed71bd19486a5f76adc20463))\n- **resizable:** support for multiple cursor types ([#8042](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8042)) ([e564714](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e56471423142d71ce9117707f7240c83f6fe44e5))\n- **table:** support display and sorting of custom table columns ([#7966](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7966)) ([d26870f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d26870f9ffd3f5122e95246a24587c739b04fd8a))\n\n### Performance Improvements\n\n- **select:** ability to pass nzKey to nz-option ([#8033](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8033)) ([e94da4e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e94da4eddd663a1e7a5e9e6e0781f1a6da59f1c7))\n- **select:** remove unused types ([#7850](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7850)) ([71c2138](https://github.com/NG-ZORRO/ng-zorro-antd/commit/71c2138ce28e07539784d8fb228adf122ed13a33))\n- **tabs:** need add .ant-tabs-tab class reduce css computing time consuming([#7935](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7935)) ([#7936](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7936)) ([198644a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/198644a09ac828c4e9b208799c8be1a57cd8ce86))\n\n## [16.1.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/16.0.0...16.1.0) (2023-07-16)\n\n### Bug Fixes\n\n- **list:** fix the bug that synchrone action item are not displayed in the item ([#7958](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7958)) ([3b6bdec](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3b6bdecef32ee4d9bb14491b617870733cfd9553))\n- **tree:** fix nz-tree-node keep dragging class with nzBeforeDrop ([#8015](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8015)) ([2d0b3f7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2d0b3f71490e38f8512285f81fcf3baa8f6eb4db))\n- **cascader:** customize the option title to undefined ([#8011](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8011)) ([10003db](https://github.com/NG-ZORRO/ng-zorro-antd/commit/10003db77b9bda21772733c41b3c503ee85d5c81)), closes [#8006](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8006)\n- **date-picker:** fix code comment ([#7991](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7991)) ([8b6b653](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8b6b653547d92a27079c27b3ef7e68df68a4f5fd))\n- **i18n:** update zh_TW.ts ([#7901](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7901)) ([9bfce45](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9bfce45a37a9c50aafbcaf96a8db9450bc2c5bf1))\n- **notification:** don't create new messageId for update ([#8000](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8000)) ([e240264](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e240264796dfd3a8692efcb92178688b78d0b69f))\n- **time-picker:** modelChange trigger twice ([#7902](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7902)) ([74c13a4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/74c13a49f92a263a05a34af63f6a2b71a554078e))\n- **watermark:** removing the watermark fails to redraw ([#8012](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8012)) ([030318e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/030318e82725d7650c98bf0ec06d2b23df16d9f0))\n\n### Features\n\n- **cron-expression:** add Unit Testing ([#7993](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7993)) ([605e969](https://github.com/NG-ZORRO/ng-zorro-antd/commit/605e969013cf48a29f4786765cf6c6da9f10643a))\n- **cron-expression:** support nzDisabled && nzBorderless ([#7992](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7992)) ([6d31bde](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d31bde3ef1f43cc145d2009afcf90931e96a731))\n- **dropdown:** close context menu on escape ([#7915](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7915)) ([6d0032e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d0032ededc140a017c01158ae76402a86c7b334))\n- **dropdown:** improve `NzContextMenuService#create()` ([#7768](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7768)) ([9b3e6cb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9b3e6cba852d4a782d15311c910b747a3bbc4d02))\n- **form:** support form label wrap ([#7892](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7892)) ([37391de](https://github.com/NG-ZORRO/ng-zorro-antd/commit/37391de29afdd3126dbbdcae6ca3ba2e637fd596))\n- **modal:** Remove nzComponentParams in v16 ([#7930](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7930)) ([baab16c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/baab16c497902f0cbf2668fb061ac8d40ffd18b2))\n- **qrcode:** padding & background color for qrcode ([#8001](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8001)) ([718ba29](https://github.com/NG-ZORRO/ng-zorro-antd/commit/718ba2943c7c7e12c8526e52e8806955d3fb0504))\n- **resizable:** add direction parameter in NzResizeEvent ([#7987](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7987)) ([4143473](https://github.com/NG-ZORRO/ng-zorro-antd/commit/41434734ffe839f3ed71bd19486a5f76adc20463))\n- **table:** support display and sorting of custom table columns ([#7966](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7966)) ([d26870f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d26870f9ffd3f5122e95246a24587c739b04fd8a))\n\n### Performance Improvements\n\n- **select:** remove unused types ([#7850](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7850)) ([71c2138](https://github.com/NG-ZORRO/ng-zorro-antd/commit/71c2138ce28e07539784d8fb228adf122ed13a33))\n- **tabs:** need add .ant-tabs-tab class reduce css computing time consuming([#7935](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7935)) ([#7936](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7936)) ([198644a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/198644a09ac828c4e9b208799c8be1a57cd8ce86))\n\n## [16.0.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/15.1.0...16.0.0) (2023-05-31)\n\n### Bug Fixes\n\n- **date-picker:** ng-untouched when loose focus ([#7922](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7922)) ([9ebcf72](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9ebcf72bde75b735c0798bc66bb62226b7f29536))\n- **date-picker:** week number error when cross years ([#7923](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7923)) ([e7f9538](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e7f953822133ce31d2523a48766dfe6572f95430))\n- **datepicker:** ngModel not update ([#7948](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7948)) ([100796c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/100796c74cd75de9cebbf89cb58f4bf3cc58b746))\n- **slider:** the first disable is invalid ([#7947](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7947)) ([ad2faf4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ad2faf4c67cb6e7bc1b12646d0ceb9153a59d75c)), closes [#7943](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7943)\n\n## [15.1.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/15.0.2...15.1.0) (2023-04-02)\n\n### Bug Fixes\n\n- migration description ([#7890](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7890)) ([78541e1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/78541e104184998551d198ce6a4d980895d1688a))\n- **datepicker:** send OnChange event for same value ([#7815](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7815)) ([3602abc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3602abc4b36232076734d63cde125553926119a9))\n- **radio:** update `touch` status when `focus` and `blur` events ([#7885](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7885)) ([39f0cea](https://github.com/NG-ZORRO/ng-zorro-antd/commit/39f0cea785cf124abc7ddd2ccd4dd46bd9f6c30b)), closes [#7877](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7877)\n- **time-picker:** fix AM/PM selector hide ([#7701](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7701)) ([129e944](https://github.com/NG-ZORRO/ng-zorro-antd/commit/129e9446c3937dea954c7e98c25c5222a4879468))\n- **tooltip:** fix tooltip.spec.ts ([#7893](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7893)) ([3dfa655](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3dfa655127480bca2df46fc98cd946967ee05797))\n\n### Features\n\n- **form:** support form label align ([#7870](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7870)) ([d54b3b4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d54b3b4cc44b6e9404a2de1e75ece5c3928ec453))\n- **modal:** pass data to modal component through injection token ([#7849](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7849)) ([ea9969d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ea9969d840855a2ba1385f2fd3b51889a6b15258))\n- **qrcode:** add QRCode component ([#7803](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7803)) ([ff36981](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ff36981aa5289eb4d9e267d6a9a3b01770bba456))\n- **watermark:** add watermark component ([#7857](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7857)) ([11b85a4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/11b85a4e0321fea3dd8581bb191ba2ca907ef29b))\n\n### Performance Improvements\n\n- **avatar:** do not run change detection on timer and update styles directly ([#7862](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7862)) ([1c48745](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1c4874592b402f526518be03e831634e1c9e9341))\n- **date-picker:** do not trigger change detection on `mousedown` ([#7860](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7860)) ([1171460](https://github.com/NG-ZORRO/ng-zorro-antd/commit/11714605466f910b24d450f6b7e1e4b7459bbca7))\n\n## [15.0.3](https://github.com/NG-ZORRO/ng-zorro-antd/compare/14.3.0...15.0.3) (2023-01-17)\n\n### Bug Fixes\n\n- **radio:** invalid disable state ([#7812](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7812)) ([2b4df9a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2b4df9a833849c481346194c817196bc2697a1ff))\n\n## [15.0.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/14.3.0...15.0.2) (2023-01-15)\n\n### Bug Fixes\n\n- **checkbox:** checkbox group can't be disable initially ([#7806](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7806)) ([eb2cb04](https://github.com/NG-ZORRO/ng-zorro-antd/commit/eb2cb046e122eab654a2e721b51f397d2790019e))\n\n## [15.0.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/14.3.0...15.0.1) (2023-01-09)\n\n### Bug Fixes\n\n- **components:** some forms component can't be disable ([#7786](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7786)) ([bc673e7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bc673e7deef219de82e5dc23e1318f76a1ef98f6))\n\n## [15.0.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/14.3.0...15.0.0) (2022-12-21)\n\n### Bug Fixes\n\n- **drawer:** fix `nzContentParams` definition error ([#7668](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7668)) ([0074013](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0074013f585ba23ed7b9156e379b7c81be445bf1)), closes [#7620](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7620)\n\n### Performance Improvements\n\n- **date-picker:** remove unused variable ([#7767](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7767)) ([1572da5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1572da58cdd9629e1aeab3d4c0262dcc91bd597c))\n- **form:** remove a unused variable ([#7766](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7766)) ([162d290](https://github.com/NG-ZORRO/ng-zorro-antd/commit/162d290305a0bee6678c066eddc74e5e919f280c))\n\n## [14.3.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/14.2.1...14.3.0) (2022-12-11)\n\n### Bug Fixes\n\n- **tree:** nz-tree-drop-indicator for custom tree node templates ([#7579](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7579)) ([5996019](https://github.com/NG-ZORRO/ng-zorro-antd/commit/59960194773a0c1036c2142e199b9b7633383fea))\n- **input:** textarea-count combined with nzHasFeedback location ([#7709](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7709)) ([ddd44d2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ddd44d2478621370493b154ca39411552b934290)), closes [#7574](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7574)\n- **list:** specify template ref context to match instantiation ([#7756](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7756)) ([4eb32fd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4eb32fdb3411f1ebd98d2120f4ea585816263bac))\n- **select:** disabled option can be selected by Enter ([#7686](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7686)) ([5bdf244](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5bdf2440bc48547bc76a6646cce49fd8b036beb3))\n- **tree:** tree select search slow in virtual mode ([#7385](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7385)) ([21208f0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/21208f0c990db36864138a228fb5f065c4fcdb92))\n\n### Features\n\n- **cron-expression:** Optimize cron result display & support custom rendering cron time ([#7750](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7750)) ([1820da5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1820da520178e6d8ba7cecd2b039e1836f500969))\n- **date-picker:** add ElementRef type to nzSeparator ([#7721](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7721)) ([3771512](https://github.com/NG-ZORRO/ng-zorro-antd/commit/37715122bc103d9a74395fc746d39f26ffa82bd8))\n- **select:** select on Tab support ([#7728](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7728)) ([d9f9092](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d9f9092dd50beea81b48d775c5de6df507a44b90))\n- **tree-select:** support to set placement ([#7551](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7551)) ([325971e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/325971e83710271470bbd085d252b8e1eb2d838c))\n\n## [14.2.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/14.2.0...14.2.1) (2022-11-27)\n\n### Bug Fixes\n\n- **animation:** fix animation.disabled triggering condition ([#7739](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7739)) ([2df4860](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2df48601854ee8a383d3a02044f8a3bcbf7f18db))\n- **i18n:** add missing hu texts ([#7733](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7733)) ([de71300](https://github.com/NG-ZORRO/ng-zorro-antd/commit/de71300188e154a43f9abe928153f19aa8e2862f))\n- **select:** activated value resetting during load on scroll ([#7725](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7725)) ([9e08be9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9e08be9e2c0eb15e76da44df7e17d153b3b1339d))\n\n## [14.2.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/14.1.1...14.2.0) (2022-11-20)\n\n### Bug Fixes\n\n- **cron-expression:** clear ul & li default style ([#7715](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7715)) ([726ded3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/726ded31a8a8d9ad46a5095ece21e31c321cd10c))\n- **date-picker:** arrow in wrong position for RTL direction ([#7690](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7690)) ([41b56e4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/41b56e4072b6d5832c1f9e31196dcce4fe8632aa))\n- **date-picker:** fix datePicker show multi panel ([#7680](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7680)) ([ee4872e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ee4872e1c93f3439bbafe56f430aca4e0eca085c)), closes [#7450](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7450)\n- **descriptions:** nzStringTemplateOutlet title style error ([#7704](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7704)) ([bec3b42](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bec3b42bdbdad31dcb66000376e40b9528f68ba5)), closes [#7698](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7698)\n- **icon:** re-enter Angular zone after icons have been loaded ([#7719](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7719)) ([754ded6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/754ded61fe41d523c2bf216a7ea49cc2a5a6fa61))\n- **image:** preview the local upload image error ([#7615](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7615)) ([616f59f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/616f59ffe80b2f5a6d6e41787eec29de240901d4))\n\n### Features\n\n- **alert:** support custom icon ([#7691](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7691)) ([cc014a1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cc014a12099c09ae016a400c4f0a5bb3208d2503))\n- **carousel:** `nzLoop` to prevent the carousel to go in a loop ([#7693](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7693)) ([e3103f0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e3103f07860b6d57ebf32155fd3ae416afd3e386))\n- **cron-expression:** add cron-expression component ([#7677](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7677)) ([3a638af](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3a638af6f67e93cc6a029e4d96033ad9dabf555b))\n- **popconfirm:** make nzOkDanger coerce to boolean ([#7720](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7720)) ([f6a8044](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f6a804408e21f0ae7dc7385da202acd54e76cdd7))\n\n## [14.1.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/14.0.0-beta.0...14.1.1) (2022-10-15)\n\n### Bug Fixes\n\n- **code-editor:** fix declaration of Window as monaco-editor ([#7676](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7676)) ([bdf6507](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bdf65077f174512efa2ed2dcf65c87734cfe4255))\n- **date-picker:** fix datePicker can't clear ([#7671](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7671)) ([ba90876](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ba90876690e462e18da0126d8e90d682b62ebb70)), closes [#7534](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7534)\n\n## [14.1.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/14.0.0-beta.0...14.1.0) (2022-10-09)\n\n### Bug Fixes\n\n- **cascader:** fix wrong format of docs ([#7604](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7604)) ([8b92c63](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8b92c6362e9702a79ff23f3605d8a3ab84c4b9ca))\n- **i18n:** update it_IT.ts ([#7646](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7646)) ([aecb788](https://github.com/NG-ZORRO/ng-zorro-antd/commit/aecb78846138249e50dce48de9cfed29d777d6ac))\n- **pagination:** add ul tag ([#7500](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7500)) ([becdd68](https://github.com/NG-ZORRO/ng-zorro-antd/commit/becdd682514e36b188be93667a03ac74f224dcf7))\n- **segmented:** fix index.less not imported in entry.less ([#7624](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7624)) ([1d6a646](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1d6a6464e5d0fccc6f78e16af3c32d48efe95fc7))\n- **select:** fix broken cdk virtual scroll integration ([#7642](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7642)) ([1f10a9c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1f10a9cfa9e16d64737325b57cc29f3c8e8a84c9))\n- **select:** input field length restricted to 82px ([#7626](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7626)) ([82159e3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/82159e34e53c95eeff4886c03f70b2978110cc00))\n- **statistic:** remove top-level redundant `div` element ([#7659](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7659)) ([07df410](https://github.com/NG-ZORRO/ng-zorro-antd/commit/07df41046e595078d37cef3f3419db12d48b33d8))\n- **steps:** remove top-level redundant `div` element ([#7582](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7582)) ([60beabc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/60beabccd2459adcb973133fc139008b31abfca0))\n- **typography:** focus the element and set the value even if the zone is already stable ([#7320](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7320)) ([2d2fe33](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2d2fe33b135168a515abe3d41a86a0f2ba9ddfcf))\n\n### Features\n\n- **popconfirm:** support async close ([#7533](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7533)) ([797b261](https://github.com/NG-ZORRO/ng-zorro-antd/commit/797b2617f08394b56fe0a7903dc69e2d75984219))\n- **select:** support placement ([#7537](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7537)) ([dda0e6d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dda0e6d6b8e0abba46946a6ba04142500ba38328))\n- **date-picker:** add nzShowWeekNumber property ([#7621](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7621)) ([2cb80fc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2cb80fc1253322e5b02aba38f50b2f37784d0aa7))\n- **menu:** add support nzPlacement for nz-submenu ([#7420](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7420)) ([b1223bd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b1223bdda6cfd4870adbaa2fbd800e3c3aa4a0d4)), closes [#4743](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4743)\n- **select:** add string array support for nzDropdownClassName ([#7643](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7643)) ([966dc8f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/966dc8f2b39b9cc7f46e4a1c5fba157c78173a52))\n- **time-picker:** support input readonly ([#7660](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7660)) ([2dcefe2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2dcefe2c197e6438736f326206229b0287400cc3))\n\n## [14.0.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/14.0.0-beta.0...14.0.0) (2022-08-25)\n\n### Bug Fixes\n\n- **cascader:** fix wrong format of docs ([#7604](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7604)) ([8b92c63](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8b92c6362e9702a79ff23f3605d8a3ab84c4b9ca))\n- **steps:** remove top-level redundant `div` element ([#7582](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7582)) ([60beabc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/60beabccd2459adcb973133fc139008b31abfca0))\n\n### Features\n\n- **icon:** change tag of nz-icon from `<i>` to `<span>` ([#7586](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7586)) ([7242111](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7242111c8bc2523df9d13e19521473502a4f6cf1))\n- **popconfirm:** support async close ([#7533](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7533)) ([797b261](https://github.com/NG-ZORRO/ng-zorro-antd/commit/797b2617f08394b56fe0a7903dc69e2d75984219))\n\n### BREAKING CHANGES\n\n- **pagination:** add ul tag ([#7500](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7500)) ([becdd68](https://github.com/NG-ZORRO/ng-zorro-antd/commit/becdd682514e36b188be93667a03ac74f224dcf7))\n\n## [13.4.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/13.3.2...13.4.0) (2022-07-25)\n\n### Bug Fixes\n\n- **datepicker:** focus input when opened programmatically ([#7512](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7512)) ([b3a27d8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b3a27d82900b455c32226100a7dbad87f20fd18a))\n- **transfer:** uncheck \"Select all\" checkbox when filtered items are moved ([#7419](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7419)) ([1e9c11e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1e9c11e2b60dafd4320da1a3d852c17fcce1dafa))\n\n### Features\n\n- **notification:** support top and bottom placement ([#7540](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7540)) ([d8b26dd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d8b26dd6377d9546121122bd1c0498be7eaf4aa8))\n- **anchor:** sync new properties ([#7494](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7494)) ([254b429](https://github.com/NG-ZORRO/ng-zorro-antd/commit/254b4294473fdcb495ea5e7a81a81e4331e50fc2))\n- **badge:** support size ([#7405](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7405)) ([f40dd38](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f40dd38702bec197742b38afc075af8ec4bc6170))\n- **date-picker:** support date-picker placement ([#7527](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7527)) ([a652470](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a65247012bce98a891e6f46242e95cecfbbc0641))\n- **input-number:** add borderless support ([#7539](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7539)) ([ea1138b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ea1138b9a47a9c3678ce60babea5cd59b2278002))\n- **switch:** add nzId input ([#6815](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6815)) ([4c71bdb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4c71bdb6a46d4e590ab6cc1f3eb9dd3d05b49eee))\n- **time-picker:** support borderless ([#7547](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7547)) ([a8c3f95](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a8c3f957cb66315350d50b4b8d164c8e6de19d76))\n\n### Performance Improvements\n\n- **transfer:** add `trackBy` to the list and track by the `hide` property ([#7424](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7424)) ([0587236](https://github.com/NG-ZORRO/ng-zorro-antd/commit/058723643e7b52b0a470cbbc42de91be3b2275e6))\n\n## [13.3.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/13.3.0...13.3.2) (2022-06-25)\n\n### Bug Fixes\n\n- **input-number:** fix errors before initialization ([#7531](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7531)) ([800e6f4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/800e6f4f1495d63edcb0f992836a75a40e3ca5b6))\n\n## [13.3.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/13.3.0...13.3.1) (2022-06-20)\n\n### Bug Fixes\n\n- **input, input-number, steps:** fix styles in components ([#7522](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7522)) ([222b225](https://github.com/NG-ZORRO/ng-zorro-antd/commit/222b225ed4d4e56de049b08d7e6e8a77d476d481))\n\n## [13.3.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/13.2.2...13.3.0) (2022-06-15)\n\n### Bug Fixes\n\n- **icon:** add missing zorro used icon: deleteOutline ([#7499](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7499)) ([ba6bade](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ba6badee1fff04eeb811ef50ac03cf9ccfeaebf7))\n- **tooltip:** is not aligned on first display ([#7457](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7457)) ([23a2fd5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/23a2fd567af598625267187dea2db487e570b9b7)), closes [#7453](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7453)\n- **transfer:** `submit` behavior for button inside form ([#7413](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7413)) ([0cfebca](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0cfebca5ebe4f7239212f99753cbbfd1d2790f63)), closes [#7410](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7410)\n\n### Features\n\n- **cascader:** support setting status ([#7452](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7452)) ([e10908e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e10908e505b93f2e2d76f24c3f0dc7972fda266c))\n- **date-picker:** support setting status ([#7479](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7479)) ([c3d0874](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c3d08742247a2f2e12d070e352aa7932f9a0d326))\n- **form:** make form work with status ([#7489](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7489)) ([98ac620](https://github.com/NG-ZORRO/ng-zorro-antd/commit/98ac620a1eac4e307505450fbf7890f5b3da20ff))\n- **input-number:** support input number group ([#7488](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7488)) ([b038fa2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b038fa26703ab010dab1b03946986e6f5c6ee66c))\n- **input-number:** support setting status ([#7462](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7462)) ([0c9287a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0c9287a2005149f2ecd1b6b3ad58d7374013bb6b))\n- **input:** support setting status ([#7472](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7472)) ([999215e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/999215e6ba45f1e3e32f561052ce8a902af895d7))\n- **mentions:** support setting status ([#7467](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7467)) ([ac38b2d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ac38b2d64697f307e79720a691fbdf60c32fb8d0))\n- **segmented:** implement new component ([#7404](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7404)) ([95a31da](https://github.com/NG-ZORRO/ng-zorro-antd/commit/95a31dab42dce3895d012bd2458ef51ec90ef33f))\n- **select:** support setting status ([#7478](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7478)) ([44b7fe0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/44b7fe0e1f8892a2da9e9950da40081bab767d4d))\n- **time-picker:** support setting status ([#7473](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7473)) ([0d8249b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0d8249b31e70c28ea47f37b818ff1c5fe0ac8239))\n- **transfer:** support setting status ([#7475](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7475)) ([9b98fe1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9b98fe11f4832c774067b10e50f6b981b9147dbe))\n- **tree-select:** add status ([#7477](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7477)) ([40815ad](https://github.com/NG-ZORRO/ng-zorro-antd/commit/40815ad90d4160be4a6a9dd29ee7b072ecde5f75))\n\n## [13.2.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/13.2.1...13.2.2) (2022-05-12)\n\n### Bug Fixes\n\n- **tree-view:** trigger markforcheck after nodes changed ([#7426](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7426)) ([a702674](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a702674d76974bcc8fa854394bd6681d8dfe8347))\n\n## [13.2.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/13.2.0...13.2.1) (2022-04-27)\n\n### Bug Fixes\n\n- **code-editor:** remove monaco-editor dependency in config.ts ([#7392](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7392)) ([929084d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/929084d5ba65c4e9661ccaea300c58e85e39bed6))\n\n## [13.2.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/13.1.1...13.2.0) (2022-04-26)\n\n### Bug Fixes\n\n- **carousel:** fix nzAfterChange callback value not correctly ([#7326](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7326)) ([b517bd4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b517bd442fa36f4cfc5e4a37d587b4f26cfb940c)), closes [#7323](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7323)\n- **cascader:** fix the problem of disappearing drop-down menu ([#7381](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7381)) ([3d41ce0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3d41ce08769bcbf337590169ded3559b092bc5cd))\n- **cascader:** update position when click menu item ([#7306](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7306)) ([4c669a5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4c669a58f0bf02bc835e2d68402b5ea0c98511c5))\n- **i18n:** update fr translations ([#7364](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7364)) ([64e1c7c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/64e1c7cf2bd3b094a0124ed8ddb51edab284b927))\n- **list:** re-enter the Angular zone when the `NgZone.onStable` emits ([#7314](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7314)) ([425f8df](https://github.com/NG-ZORRO/ng-zorro-antd/commit/425f8dff39f29ba620cdeb6f4a6f45471845b819))\n- **modal:** no longer trigger any action when closing ([#7336](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7336)) ([d169452](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d16945249a28338ba480af46ff037d69b67b4af4))\n- **popconfirm:** reverting missing nzPopconfirmVisibleChange ([#7338](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7338)) ([561041c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/561041c3e7ce643cc57cfd2c18c22dd36da389c8))\n- **upload:** fix upload drag drop will open new tab in firefox 91 and 92 ([#7190](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7190)) ([9b51874](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9b518742e3be8c85c0b2e2e66d4ffe108e43a2d0))\n\n### Features\n\n- **code-editor:** add global configuration to support monaco require config ([#7121](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7121)) ([21ec517](https://github.com/NG-ZORRO/ng-zorro-antd/commit/21ec517ba55cd20aa78298cd1050069308a9f98b))\n- **code-editor:** support MonacoEnvironment config in NZ_CONFIG ([#7359](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7359)) ([4dfd9cd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4dfd9cd21507fcf4382d5f28f03fd969d8fc425c)), closes [#6502](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6502)\n- **image:** nz-image add press `left` or `right` to switch image ([#7321](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7321)) ([b5f82b5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b5f82b51eed45f9bc7f7418c90185693887b202a))\n- **input-number:** add `nzReadOnly` property ([#7372](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7372)) ([0da7496](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0da7496ba4dcc03be2827b6783a977382e487da1)), closes [#7369](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7369)\n\n### Performance Improvements\n\n- **anchor:** mark `scroll` listener as passive ([#7330](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7330)) ([aab060f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/aab060ffcebae479954355bf02804882935ef8d2))\n- **back-top:** mark `scroll` listener as passive ([#7329](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7329)) ([7f3c4e1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7f3c4e1c5e8330597b5b0024c7b9075bccf93f44))\n- **cascader:** do not run change detection on `change` event ([#7312](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7312)) ([cb803f9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cb803f9a8c040157d83e095ce9ab0bd28a161b64))\n- **image:** do not run change detection when the image preview is clicked ([#7309](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7309)) ([752a5b6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/752a5b6f3e76d467a839a39aa587deaed953ed72))\n- **input-number:** do not run change detection when `mouseup` and `mouseleave` events are dispatched on handlers ([#7313](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7313)) ([54386ef](https://github.com/NG-ZORRO/ng-zorro-antd/commit/54386efaac97982675c8c1e1b3504cfed9671248))\n- **modal:** call `focus()` on the next rendering frame to prevent frame drop ([#7293](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7293)) ([106d346](https://github.com/NG-ZORRO/ng-zorro-antd/commit/106d346d72568f8256a942478d808d002f5421c7))\n- **resizable:** mark `mousedown` and `touchstart` listeners as passive ([#7331](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7331)) ([518997b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/518997bcf193a59510a0dfc1db4ef306475eb990))\n- **tree-view:** do not run change detection when the `nz-tree-node-checkbox` is clicked ([#7307](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7307)) ([1e0872b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1e0872b30873644032917f6242f585ba9bd1db30))\n\n## [13.1.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/13.1.0...13.1.1) (2022-03-03)\n\n### Bug Fixes\n\n- **collapse:** markForCheck after collapse title clicked ([#7284](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7284)) ([b7433a9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b7433a9d22e82a21d1557c026ba78e07b9541bec))\n- **icon:** do not try to load SVG on the Node.js side since it will throw an error ([#7290](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7290)) ([fe0484f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fe0484f348c73fc85bf721167f6d4e6f278b98f1)), closes [#7240](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7240)\n- **select:** exact match while searching should be active ([#6816](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6816)) ([48d2a25](https://github.com/NG-ZORRO/ng-zorro-antd/commit/48d2a2538c9ddef5f77804cbecbf4c157f4e9f22)), closes [#6812](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6812)\n- **upload:** fix the problem that the transformed file is lost ([#7206](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7206)) ([b82d2f3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b82d2f3a3f74c3f915f17a650dd86b51f22ae922))\n\n## [13.1.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/13.0.1...13.1.0) (2022-02-25)\n\n### Bug Fixes\n\n- **button:** prevent default event fire ([#7267](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7267)) ([2306e0d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2306e0d61a232e79249e31357f3cbdc769312f2c))\n- **date-picker:** fix `z-index` to `auto` in inline mode ([#7172](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7172)) ([26006f6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/26006f60f9b9bdf860adef8dbfc98a5f6922899d))\n- **date-picker:** fix disable time when date changes ([#7236](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7236)) ([ae67952](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ae6795238146833d7813e3882bb2593df155ea1b))\n- **i18n:** update fa-IR.ts translations ([#7249](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7249)) ([a7a0b41](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a7a0b413c9539cb801058c1956242f50a3923972))\n- **i18n:** update pt_BR.ts translations ([#7218](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7218)) ([95c7816](https://github.com/NG-ZORRO/ng-zorro-antd/commit/95c7816b369ed8efbd89b5bb3ba67d133b1ad71d))\n- **input:** do not set box-sizing when measuring ([#7214](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7214)) ([035dc94](https://github.com/NG-ZORRO/ng-zorro-antd/commit/035dc94b58766e8565e8f4d400b9dc67c3673a08)), closes [#7203](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7203)\n- **input:** incorrect background color in disabled state ([#7250](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7250)) ([7acb8db](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7acb8db6ff858a4daec20173fde3535b024f6d89))\n- **radio:** emit `false` to the `ngModel` whenever the radio button is deselected ([#7270](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7270)) ([2704237](https://github.com/NG-ZORRO/ng-zorro-antd/commit/270423707363514112bd75ed0384c5e70d7d3755))\n- **select:** fix keyboard event error when option data is empty ([#7222](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7222)) ([4bd86ca](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4bd86ca0a72baf653fdb93d311159d97f3d36b84)), closes [#7242](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7242)\n- **slider:** fix keydown not trigger nzOnAfterChange ([#7252](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7252)) ([f419c07](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f419c07644f6fe0148a4a9990ad3f85aec590359)), closes [#7251](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7251)\n\n### Features\n\n- **alert:** support nzAction for customizing actions ([#7246](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7246)) ([eb3b1ba](https://github.com/NG-ZORRO/ng-zorro-antd/commit/eb3b1bafaedaff09d8f547a1cb7ecd4eb9aea67f))\n- **drawer:** support new apis nzSize and nzExtra ([#7227](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7227)) ([d2e5b76](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d2e5b76d176c9574dfe4a79c285e9d09e6edcc28))\n- **i18n:** add kk_KZ to i18n ([#7261](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7261)) ([3580fb0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3580fb038c5d4c88bf2efe845b8b86fb47df7ee3))\n- **i18n:** add km_KH ([#7220](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7220)) ([f972391](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f9723918ea7a4646cb282a4254054bc3b3fd5564))\n\n### Performance Improvements\n\n- **auto-complete:** do not run change detection when the promise resolves ([#7138](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7138)) ([e95d941](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e95d941c17c31504438fef770ff5dd9f7e157534))\n- **back-top:** do not run change detection if there are no `nzClick` listeners ([#7179](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7179)) ([7d091bb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7d091bba409ee9321215696568928d5684032ccf))\n- **carousel:** do not run change detection when the timer fires ([#7136](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7136)) ([fc991d1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fc991d180c1c8f006b294b3ab18950ed06e181e8))\n- **collapse:** do not run change detection if the panel is disabled ([#7181](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7181)) ([3c3eac9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3c3eac9875556134118c60c3bcdf10dc7136beea))\n- **dropdown:** do not run change detection if the dropdown has been clicked inside ([#7135](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7135)) ([4679592](https://github.com/NG-ZORRO/ng-zorro-antd/commit/467959298f57c81574ac7b25f3714e734026ac12))\n- **image:** do not run change detection if there are no `containerClick` listeners ([#7147](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7147)) ([f0f52a4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f0f52a4765da8ae26fd2fe36fe9024b8f574d204))\n- **mention:** do not run change detection when the dropdown cannot be closed ([#7146](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7146)) ([b72bd27](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b72bd2735da5d07713b6895db2842d132f62e131))\n- **mention:** do not trigger change detections if there are no event listeners ([#7130](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7130)) ([73af728](https://github.com/NG-ZORRO/ng-zorro-antd/commit/73af728527bb38ced9941e5ce29760bbae5b4a68))\n- **resizable:** do not run change detection on `mousedown` and `touchstart` events ([#7170](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7170)) ([9a8d794](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9a8d79476be545be181e11a92d849e7e543d38c6))\n- **select:** do not run change detection on events if the `nz-option-item` is disabled ([#7133](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7133)) ([a1bbdab](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a1bbdabca53bd61423564448298892c54260d48e))\n- **select:** do not run change detection unnecessarily on click events ([#7175](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7175)) ([fd63d22](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fd63d225e5ebdd800eae0be80685537746bfeb61))\n- **table:** do not run change detection if the sorting is not shown ([#7174](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7174)) ([e541761](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e5417611976bdcdde43f202bacd8b031bd8d0fab))\n- **table:** do not unnecessarily re-enter the Angular zone ([#7142](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7142)) ([5a5df13](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5a5df13bbdfe8575ef6b1fdd6df73d6100b82407))\n- **table:** spawn timers and add listener outside of the zone ([#7140](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7140)) ([ec248c9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ec248c95162bdb7c23dda1926d156ae9cb7c7ace))\n- **tabs:** do not run change detection when the promise resolves ([#7144](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7144)) ([148f84d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/148f84d11b6bf234544cfe06d1506519496e0628))\n- **time-picker:** do not run change detection when the timer fires ([#7143](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7143)) ([72da774](https://github.com/NG-ZORRO/ng-zorro-antd/commit/72da774dfd0927699c9c5f8613086a1e5d0e53c0))\n- **tree-view:** do not run change detection on click events if the `nz-tree-node-option` is disabled or there are no `nzClick` listeners ([#7178](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7178)) ([0054f59](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0054f59a383f937f6e0f71435da41c74264be6ae))\n- **typography:** do not run change detection on `input` and `keydown` events ([#7185](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7185)) ([ad547fb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ad547fb7193999735396d12c07124c70d9941daa))\n\n## [13.0.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/13.0.0...13.0.1) (2022-01-18)\n\n### Bug Fixes\n\n- **back-top:** fix more reliable scrolling listener ([#7208](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7208)) ([3bcd343](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3bcd343e38aefc35af1c2386a539d19a1d0ca279)), closes [#7199](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7199)\n- **drawer:** fix close icon position without `nzTitle` property ([#7176](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7176)) ([a6195b9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a6195b991a531e914faef2237dadf7226b8d6390)), closes [#7164](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7164)\n- **icon:** fix old icon element not removed ([#7188](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7188)) ([67ac573](https://github.com/NG-ZORRO/ng-zorro-antd/commit/67ac573d2e0a9b19263c600f020842532844566a)), closes [#7186](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7186)\n- **statistic:** re-enter the Angular zone when the `nzCountdownFinish` emits ([#7137](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7137)) ([6835544](https://github.com/NG-ZORRO/ng-zorro-antd/commit/68355448198b31d9a064710cfc4d790739909616))\n- **tree-view:** fix innerTrackBy function ([#7150](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7150)) ([4484674](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4484674e212f67dea3aad8b56f27e9de61e6d21e)), closes [#7118](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7118)\n\n### Performance Improvements\n\n- **auto-complete:** memory leak ([#7112](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7112)) ([3806250](https://github.com/NG-ZORRO/ng-zorro-antd/commit/38062508fb7e0df13e528e1c9d5bf3720bd76200))\n- **cdk:** resolve leak ([#7139](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7139)) ([2a93d05](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2a93d05c48ebba1a1f6a3add74b71f4049907337))\n- **checkbox:** reduce change detection cycles ([#7127](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7127)) ([15abe33](https://github.com/NG-ZORRO/ng-zorro-antd/commit/15abe33053ee888e31c1ad629fd5a5ecae79db43))\n- **code-editor:** always initialize outside of the Angular zone ([#7151](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7151)) ([f73be80](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f73be80ca8e55604a683827f0693455c20978214))\n- **core:** remove `resize` listener when the app is destroyed ([#7125](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7125)) ([8437111](https://github.com/NG-ZORRO/ng-zorro-antd/commit/843711117a8bd7b6feb6410b4b824bd9741147a7))\n- **image:** unsubscribe old src ([#7102](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7102)) ([87a3e27](https://github.com/NG-ZORRO/ng-zorro-antd/commit/87a3e276fc1f1a50ecc6da9edc28dd4f77ac8482))\n- **input-number:** reduce change detection cycles ([#7129](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7129)) ([9971faa](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9971faa7d9c54db40c19fa6333dce8a65d38ccd4))\n- **modal:** do not run change detection on mouse events ([#7169](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7169)) ([c20bb80](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c20bb8076b9d0e5e63880921cdfc738de12fc5a0))\n- **modal:** resolve memory leaks ([#7123](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7123)) ([3664efe](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3664efe1d6e9f5a93ed85e958652f8a898c0b987))\n- **graph:** do not run change detection on animation frame ([#7132](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7132)) ([1ceaf70](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1ceaf70e215ab854a94897aebbf6acb4bd5c2006))\n- **rate:** do not run change detection on `focus` and `blur` events if there are no output listeners ([#7182](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7182)) ([3e9e035](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3e9e035d0273427f47eb4c0200930e549711d5d4))\n- **steps:** do not run change detection if there are no `nzIndexChange` listeners ([#7183](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7183)) ([cbfc558](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cbfc558c255e7f70e2b931f751c800501474a791))\n- **transfer:** do not trigger change detection when the checkbox is clicked ([#7124](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7124)) ([b12f43a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b12f43afe78d03687000471f164ff1f5d2631d3b))\n\n## [13.0.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/12.1.0...13.0.0) (2021-12-29)\n\n### BREAKING CHANGES\n\n**dropdown**\n\n- `[nzHasBackdrop]` input value are no longer supported, please use `[nzBackdrop]` instead.\n\n## [12.1.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/12.1.0...12.1.1) (2021-12-18)\n\n### Bug Fixes\n\n- **date-picker,time-picker:** disable autocomplete completely ([#7088](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7088)) ([bddc537](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bddc537f6f64b6697f95ef421c634045656e4903)), closes [#6718](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6718)\n- **date-picker:** resolve memory leaks ([#7113](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7113)) ([fe9070a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fe9070aaf486b50b231b19ee55bfc0b4907a98a2))\n- **popconfirm:** missing arrow ([#7086](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7086)) ([3f4a704](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3f4a704fc126a3c1ccfe92ae0f045062f00fd1e8))\n- **timeline:** when the data clear. reset items ([#7109](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7109)) ([0ece612](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0ece6123a586c96a6178e2ba939b9451c031bc14))\n\n### Performance Improvements\n\n- **carousel:** do not run change detection on non-handled `keydown` events ([#7097](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7097)) ([ca3299e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ca3299ea5b00c7075d93871ec418e1527d390f8b))\n- **cascader:** do not run change detections on non-handled `keydown` events ([#7060](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7060)) ([9a37718](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9a37718d42ac05288393d7c7d9db4204ba7e640e))\n- **date-picker:** do not run change detection when the `date-range-popup` is clicked ([#7096](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7096)) ([8f8c71b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8f8c71b1aedd10ecd50c48d802835bd235f0f2ee))\n- **icon:** do not run change detection when changing icon ([#7071](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7071)) ([e998e4a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e998e4abef73f34783aa63e88e9f0adadc8301e7))\n- **mention:** do not run change detections on `mousedown` events ([#7094](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7094)) ([0d4ad23](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0d4ad23a1722a01974c29c4b9f13eeff70c40df5))\n- **switch:** reduce change detection cycles ([#7105](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7105)) ([6d9b1ff](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d9b1fff55bcb3d8a6c5ef2b9250cfcee6ce6039))\n- **table:** do not run change detections on click events for the `nz-filter-trigger` ([#7095](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7095)) ([346c50d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/346c50d0a5b19160d51c8c6a3e61a389b4b92a52))\n- **time-picker:** do not run change detection when scrolling ([#7063](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7063)) ([baf7f0a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/baf7f0a85ef386a4ebe9bef553e532e501129f6e))\n- **time-picker:** do not run change detection when the time picker panel is clicked ([#7126](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7126)) ([76da3ff](https://github.com/NG-ZORRO/ng-zorro-antd/commit/76da3ff9f6a64fb854999f3ef30c45980c3b6b7b))\n- **tree:** do not run change detection when the tree node is clicked ([#7128](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7128)) ([55f1e04](https://github.com/NG-ZORRO/ng-zorro-antd/commit/55f1e047b32597397c42c779409beff7ab13b1f7))\n\n## [12.1.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/12.0.2...12.1.0) (2021-11-29)\n\n### Bug Fixes\n\n- **tabs:** tabs add btn disappear after all tab closed ([#7076](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7076)) ([3709b73](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3709b735094edf2960b5bec8f2a565619d6f5361)), closes [#7077](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7077)\n- **tree-view:** incorrect type of `trackBy` ([#7085](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7085)) ([891a622](https://github.com/NG-ZORRO/ng-zorro-antd/commit/891a622ef54b52bdffad894258824926ce25d28d))\n- **tree-view:** not updates when datasource data changes [#7040](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7040) ([#7083](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7083)) ([cad8ca0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cad8ca038067b9c2874a8c3c6e351f46e13c4609))\n\n### Features\n\n- **core,dropdown,table:** add config for backdrop ([#6783](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6783)) ([2f7c44d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2f7c44dc1445d9a88c501e6e114507ed28ae33ae))\n- **tooltip:** add arrow point at center ([#7010](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7010)) ([7fac8eb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7fac8eb5b1e1c17dbfbf940827f1ca53dae8d5e4))\n- **tooltip:** support tooltip template context ([#6948](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6948)) ([fec40a8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fec40a8a1bba792e5722f4facda56412f200f6b2)), closes [#6607](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6607)\n\n### Performance Improvements\n\n- **auto-complete:** do not run change detection on `mousedown` and `mouseenter` for `nz-auto-option` ([#7048](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7048)) ([d6ca43e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d6ca43e4f78b5b4f6b1407a0012cd806865e9e4d))\n- **core:** do not run change detection when scrolling ([#7062](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7062)) ([a972d7b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a972d7b3986dae613e35dda13667c672878d75b4))\n- **graph:** reduce change detections on click events ([#7056](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7056)) ([1e2960a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1e2960a855991a380e44a52c31255781830c7043))\n- **graph:** resolve minimap memory leaks ([#7052](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7052)) ([f93960c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f93960c62cd5598882a98a4e6c6b78f6dbf9f77b))\n- **modal:** do not run change detection when focusing element ([#7070](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7070)) ([ffcb709](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ffcb7095873a87243ff44edd3719ce2c04c6957e))\n- **radio:** reduce change detection cycles ([#7068](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7068)) ([b8cc94f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b8cc94feeb8517337d4df12f4bf737a7848aa04a))\n- **resizable:** reduce change detection cycles ([#7036](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7036)) ([5cad154](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5cad154496851e390296830dce7d2321092fd2fc))\n- **select:** reduce change detections for `nz-select-top-control` ([#7038](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7038)) ([d45f0ab](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d45f0abc4993002f1058c3f8753930591d886c9b))\n- **upload:** do not trigger change detection for `nz-upload-btn` ([#7037](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7037)) ([7e587d1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7e587d13b382150f8f98c5f58dead14dc3ba24a7))\n- **upload:** previewing images should be cancellable when the component gets destroyed ([#7067](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7067)) ([8f21ef1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8f21ef1d79e3545d01ebb877f9e1a094f06f1a01))\n\n## [12.0.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/12.0.1...12.0.2) (2021-11-04)\n\n### Bug Fixes\n\n- **core:** correct hidden behavior ([#6919](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6919)) ([987b1ca](https://github.com/NG-ZORRO/ng-zorro-antd/commit/987b1ca675282febb274991f4d8d52f58c623e8d)), closes [#6918](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6918)\n- **pagination:** pre-ellipsis show in the wrong position ([#6793](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6793)) ([9700e89](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9700e89690f2a2a28e84a35f3e800f60d5d72ab1))\n- **affix:** fix update position when target resize ([#6896](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6896)) ([d18a8ae](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d18a8ae24a0a088de06101b1d0d060e84df29b15)), closes [#6764](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6764)\n- **date-picker:** added missing type attributes for buttons ([#7013](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7013)) ([d69d374](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d69d37469bb260b1375d6005acb217ca4ec4215f)), closes [#7012](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7012)\n- **datepicker:** fixed opacity 0 on inline datepicker reopen ([#6910](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6910)) ([d392b2e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d392b2e95365a0ffec0fa5dcef39ba7f611b2432))\n- **i18n:** update en_GB.ts translations ([#6982](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6982)) ([f89cb38](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f89cb38a1c2a5b99460b837f001a39005212352d)), closes [#6979](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6979)\n- **modal:** footer `onClick` re-throw error in promise catch ([#6928](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6928)) ([3277d22](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3277d22ec3368d7f28a5143a5cec44357dedcdb3))\n- **popconfirm:** add nzOkDanger option for nz-popconfirm ([#6866](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6866)) ([d889e98](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d889e98e935f7e7c66e10068fd2665181a9e9975))\n- **table:** show empty state regardless of loading value ([#6934](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6934)) ([013beda](https://github.com/NG-ZORRO/ng-zorro-antd/commit/013bedaf9856931b37c01e9aa24cf63cdb1be9b8))\n- **timepicker:** fix ok button + selection of default open value ([#6941](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6941)) ([daf9f57](https://github.com/NG-ZORRO/ng-zorro-antd/commit/daf9f5712c11a4b4fdbb1da1eab23c2667398e96))\n- **timepicker:** fixed auto positioning picker ([#6939](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6939)) ([65fdbc8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/65fdbc8a5442fed0d4b131ff8147b5b8f10f9f38))\n- **tooltip:** fix tooltip for deeply wrapped focusable elements ([#6965](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6965)) ([78c16a2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/78c16a2794f5e5c2f5098c83ea540c88dd9d6d98)), closes [#6955](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6955)\n\n### Performance Improvements\n\n- **autocomplete:** resolve memory leak ([#6851](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6851)) ([e61e350](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e61e350874d380cdc68bd6c8dee0f5de358c4c79))\n- **breadcrumb:** do not re-enter the Angular zone when calling `navigate` ([#6850](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6850)) ([830a1f2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/830a1f259e4b51ffcfb82f98974fc9ae52dbfef7))\n- **button:** do not trigger change detections on click events ([#6849](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6849)) ([85c79f6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/85c79f652a022dee5c6f57042c856280cc6f23db))\n- **core:** resolve memory leak ([#6852](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6852)) ([25eb0fe](https://github.com/NG-ZORRO/ng-zorro-antd/commit/25eb0fe90cf981c0ddddceac8f98dfcef6f60f8f))\n- **code-editor:** load Monaco only once ([#7033](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7033)) ([e1eafec](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e1eafecaba7235faa8819cae2ab5607c41572b3c))\n- **image:** resolve memory leak ([#6856](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6856)) ([6744eb1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6744eb1ac836637563c8ffea1b864502721711d6))\n- **select:** do not run change detection if the `triggerWidth` has not been changed ([#6858](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6858)) ([055f4a1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/055f4a12679a1538ada58d7d9460694f67b156f5))\n- **table:** resolve leak within the `nz-table-fixed-row` ([#7034](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7034)) ([cfa1ecd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cfa1ecdb419ec619a196f69cca50fbc92aa61134))\n- **upload:** do not trigger change detection for `nz-upload-btn` ([#7032](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7032)) ([47f91c7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/47f91c77a79ad85e36eb318617b12f548bb56b1f))\n\n## [12.0.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/12.0.0...12.0.1) (2021-07-12)\n\n### Bug Fixes\n\n- **code-editor:** dispose the event listener when the component is destroyed ([#6847](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6847)) ([503c6f9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/503c6f90b81aed268ec08ce301b8c71f3a479617))\n- **code-editor:** resolve memory leak ([#6846](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6846)) ([6d43b6c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d43b6c5a9ccf8603106716285a1c032608912d6))\n- **code-editor:** re-enter the Angular zone only if the value has been changed ([##6845](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6845)) ([5c09948](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5c09948ca5e0e70bf7e4d1b4246225999060a930))\n- **drawer:** trigger change detection only if there are `nzOnViewInit` listeners ([#6841](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6841)) ([c5b5741](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c5b5741a0ffaaf50b4e558faf99691977c967426))\n- **icon:** resolve memory leak ([#6839](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6839)) ([bdc2a55](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bdc2a55e8421b49d80245d3a5a714adf38f58140))\n- remove the default resize observer polyfill ([#6843](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6843)) ([29d44af](https://github.com/NG-ZORRO/ng-zorro-antd/commit/29d44afb058cb5d78f236cdfa57be5018b49dc02)), closes [#6696](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6696)\n\nIf you want to support older browsers, you can provide polyfill in the following way.\n\n```ts\nimport { NzResizeObserverFactory } from 'ng-zorro-antd/cdk/resize-observer';\nimport ResizeObserver from 'resize-observer-polyfill';\n\n@NgModule({\n  providers: [\n    {\n      provide: NzResizeObserverFactory,\n      useValue: {\n        create(callback: ResizeObserverCallback): ResizeObserver | null {\n          return typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(callback);\n        }\n      }\n    }\n  ]\n})\nexport class AppModule {}\n```\n\n## [12.0.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/11.4.2...12.0.0) (2021-07-11)\n\n### Bug Fixes\n\n- **pagination:** mark for check when the total number of pages changes ([#6780](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6780)) ([2f1f8dc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2f1f8dcb1c7eb4f89b1ff21bf8c64d7f8a75f344))\n- **pagination:** pagination in form will trigger submit ([#6744](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6744)) ([f77ab28](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f77ab28341489e9df7f757294a6a5ad6030700f4))\n- **cascader:** add nzClear functionality to cascader ([#6761](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6761)) ([3dd9534](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3dd9534d8059985dba3389fc52ea463bbf3381c5)), closes [#6751](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6751)\n- **select:** focus input when selector is clicked ([#6786](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6786)) ([1c9331a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1c9331a4f8a32a91eaaf6128bdb335f26bd6fcab))\n- **time-picker:** close time-picker after tabbing out ([#6602](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6602)) ([0e53053](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0e530538ee954ce6ccc5891c0556cfb338f00b56))\n- **tree:** stop change url in firefox ([#6771](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6771)) ([be20114](https://github.com/NG-ZORRO/ng-zorro-antd/commit/be20114f6b83f326045dd98b5ad3aa9fab61af03))\n- **typography:** single line ellipsis style ([#6776](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6776)) ([e192a70](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e192a70aa034913d87b00f863e27e0f6acc280de))\n\n### Features\n\n- **checkbox:** add nzId input ([#6813](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6813)) ([52235c9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/52235c97aaf75802cca9e81c9071fa2bdfe0208e))\n- **core:** support reset NZ_CONFIG inside component & overflow component ([#6601](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6601)) ([edd410a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/edd410ac8426c2fde490192125a66b0074227a87))\n- **date-picker:** nz-range-picker support nzId ([#6814](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6814)) ([28074e1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/28074e1749a38a19cc64bd52aefc85d3e6f1a53b))\n- **experimental/image:** add experimental image component ([#6590](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6590)) ([7e2fba3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7e2fba39354de78219be1237eea8edf19b5799e7))\n- **popconfirm:** support `nzAutoFocus` ([#6256](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6256)) ([91e5d49](https://github.com/NG-ZORRO/ng-zorro-antd/commit/91e5d49f83c8e833e70400c65b69a2e4787fc91d)), closes [#6249](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6249)\n- **rate:** support customize character ([#6787](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6787)) ([7163e36](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7163e360fc97d48cd718c65ffa301c0253801851))\n- **steps:** steps support circular progress bar ([#6132](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6132)) ([466a093](https://github.com/NG-ZORRO/ng-zorro-antd/commit/466a093d10da6d8996adc636447be3531c5d1d76)), closes [#5684](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5684)\n- **timeline:** support `nzLabel` ([#6687](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6687)) ([86c587d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/86c587d7be4b7b6e936cf50e2cafa4499d735407)), closes [#6682](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6682)\n\n### BREAKING CHANGES\n\n**button**\n\n- `[nz-button][nzType=\"danger\"]` input value are no longer supported, please use `[nz-button][nzDanger]` instead.\n\n**modal**\n\n- usage of `ng-content` has been removed, please use `<ng-template nzModalContent></ng-template>` instead.\n\n**drawer**\n\n- usage of `ng-content` has been removed, please use `<ng-template nzDrawerContent></ng-template>` instead.\n\n**tree-view**\n\n- `[nzNodeWidth]` has been removed, please use `[nzItemSize]` instead.\n\n**nz-space-item**\n\n- `nz-space-item, [nz-space-item]` has been removed, please use `<ng-template nzSpaceItem></ng-template>` instead.\n\n## [11.4.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/11.4.1...11.4.2) (2021-06-08)\n\n### Bug Fixes\n\n- **\\*:** arabic translations 'copied' & 'expand' ([#6675](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6675)) ([f9e7d23](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f9e7d2356c6841a7e7431d56fdf1b215f2620ac6))\n- **autocomplete:** no reset status when no matching inputs ([#6685](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6685)) ([7199ad5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7199ad507fffa9af138be75a7ba61bb47b5fd13f)), closes [#6286](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6286)\n- **badge:** enable nzNoAnimation support ([#6717](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6717)) ([36c03e3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/36c03e3453d80f36029d21b7ec611217411194b3))\n- **modal:** `nzVisible` not updated when implicitly closed ([#6649](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6649)) ([5faac2c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5faac2c8146d14096f2181c912baa6050d10e21b)), closes [#6647](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6647) [#6320](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6320)\n- **slider:** processing value zero correctly ([#6729](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6729)) ([62a86c0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/62a86c05dec6e58435ed5375a0da00891519284c))\n- **tabs:** fix `nzCentered` not working ([#6706](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6706)) ([439ff0a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/439ff0aae4147a1cb067a1c6b60013baa8142434))\n- **tag:** missing styles on view engine ([#6738](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6738)) ([29c316b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/29c316b6b2154b94b9faaf61036da5b07f2aef98)), closes [#6732](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6732)\n- **tree-view:** node indent line without mark change check ([#6736](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6736)) ([215a278](https://github.com/NG-ZORRO/ng-zorro-antd/commit/215a2788bc2a0402a19f33c7052d87ceb81cb6c7)), closes [#6714](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6714)\n- focus monitor cleanup ([#6562](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6562)) ([32b3254](https://github.com/NG-ZORRO/ng-zorro-antd/commit/32b3254c298787685c5152fa26cb27d59cc91407))\n\n## [11.4.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/11.4.0...11.4.1) (2021-04-22)\n\n### Bug Fixes\n\n- **\\*:** create image using `document` method to avoid ReferenceError in SSR ([#6569](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6569)) ([d7b9291](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d7b9291dfd5f99cd3775245fd0e7cbef4f7141d0))\n- **date-picker:** click outside not change value ([#6596](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6596)) ([62e4bb6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/62e4bb6a349def081492a7d59dccc75db4622de0)), closes [#6595](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6595)\n- **date-picker:** not switch month panel when range is same month ([#6616](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6616)) ([bf4ae4d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bf4ae4dab34edcb616a1f085f1504e7333580a47))\n- **date-picker:** time picker panel not scroll at first time ([#6604](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6604)) ([b97dfbe](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b97dfbedaf6b0bc422ff895394e5d5a9343e51d8))\n- **graph:** fix edge default style and wrong toggling group nodes ([#6615](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6615)) ([c434ea9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c434ea9ce9a9299bf12a823c5bda1f5fe32ee82d))\n- **i18n:** added property missing in ka_GE ([#6589](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6589)) ([825925c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/825925ce8189b8b343b9a4f441956f47e376ae49))\n- **slider:** fix range slider not working for arrow keys ([#6612](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6612)) ([51f33e6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/51f33e6b4e4e71e3ac09cf5a77a255cb082924d8)), closes [#6586](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6586)\n- **typography:** add type=\"button\" attribute to button element in nz-text-copy component ([#6606](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6606)) ([48a9714](https://github.com/NG-ZORRO/ng-zorro-antd/commit/48a97147ed78d87a69b745b060b176a9e57e314f)), closes [#6605](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6605)\n\n## [11.4.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/11.3.0...11.4.0) (2021-04-08)\n\n### Bug Fixes\n\n- **table:** fix sort and filter when nzFrontPagination is false ([#6547](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6547)) ([097cb6c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/097cb6c56b33358e9ef843dfe6a7ce4bd06daab5)), closes [#5457](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5457)\n- **date-picker:** close date-picker after tabbing out ([#6571](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6571)) ([21ded3f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/21ded3fa94689d52e01a008ee2eb7c0c541b886b)), closes [#5844](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5844)\n- **drawer:** content is attached before the drawer is opened ([#6581](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6581)) ([ac50a7b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ac50a7bc2c4866dddefe4f79459fd2d677b8528c)), closes [#6381](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6381) [#6534](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6534)\n- **space:** fix deprecated warning for nz-space-item ([#6549](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6549)) ([#6561](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6561)) ([f80a5bb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f80a5bbd5755477c63c5d73929bcdfd0d07f2dfd))\n- **tabs:** make remove icon of nz-tab-link clickable ([#6563](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6563)) ([3a68c10](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3a68c106971270982280dd0d43a387cd1b016eb5))\n- **tabs:** not scrolling to the selected tab after init ([#6580](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6580)) ([4ddd8fb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4ddd8fb878641e603f9d79a79a9a7fde21b36e1a)), closes [#6579](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6579)\n\n### Features\n\n- **select:** support number as label ([#6538](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6538)) ([1f6ce76](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1f6ce7635fa1b20370620615e77fe5165f55fae6)), closes [#6535](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6535)\n\n## [11.3.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/11.2.0...11.3.0) (2021-03-23)\n\n### Bug Fixes\n\n- **mention:** preserve white spaces when insert suggestions ([#6505](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6505)) ([d5ed97e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d5ed97e4aeeeb0635487652b7f1ecceed7caa4f0)), closes [#6175](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6175)\n- **tooltip:** detect trigger change ([#6470](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6470)) ([e8e7dc3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e8e7dc35b75b67b2621ea690a93b20b5da755d8a)), closes [#6469](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6469)\n- dropdown and autocomplete animations ([#6143](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6143)) ([70da5a2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/70da5a2f078fc864d309089421349b32b4d46649)), closes [#6018](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6018)\n- **pagination:** fix class name in NzPaginationItemComponent ([#6485](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6485)) ([0e326e7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0e326e7c214b49d838ae071641d1b0f8c4e67840))\n- **date-picker,core,i18n:** import date-fns by esm ([#6524](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6524)) ([fb4eeae](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fb4eeae9e6c3919d8c14c94f6225ace3510a0f64))\n- **descriptions:** fix dom structure under vertical layout ([#6513](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6513)) ([ef0f3a5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ef0f3a567f3feb135f21cf9c4e9e56468dcfc2d2))\n- **modal:** fix incorrect assignment of 'nzFooter' ([#6468](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6468)) ([85ea273](https://github.com/NG-ZORRO/ng-zorro-antd/commit/85ea2732e48d1de1e452be2176995a07c3ae8260)), closes [#6467](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6467)\n- **rate:** fix invalid type of `nzCount` in `strictTemplates` ([#6457](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6457)) ([4d28a60](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4d28a60740740df79341d0c05c79debd9cce835e))\n- **space:** add missing exports ([#6521](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6521)) ([e0073e4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e0073e488969c97abd04f233b5cf8ab454c79604))\n- **table:** virtual scroll bordered style ([#6493](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6493)) ([c2f44be](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c2f44bef7d07069dcb32f6b7f7cff8432ee621b5))\n- **tooltip:** keep tooltip visibility when trigger is null ([#6489](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6489)) ([0de0e6f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0de0e6f2424adde62e6869c9587602999cd534aa))\n\n### Features\n\n- **all:** global config for backdrop ([#6380](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6380)) ([ba80ec3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ba80ec3695f92b658fb4b40dbc26fd56bea2f7fb)), closes [#6029](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6029) [#6177](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6177)\n- **modal:** add nzModalTitle directive ([#6396](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6396)) ([25f6c27](https://github.com/NG-ZORRO/ng-zorro-antd/commit/25f6c273179195c4db4e1a066bad610286a6620c)), closes [#4343](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4343) [#6337](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6337)\n- **space:** add `nzSplit` support ([#6487](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6487)) ([c535f06](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c535f06369b2aba7cf55fc2b5300c0cccc6eae1d))\n\n_Deprecated_\n\n- space: `nz-space-item` in `nz-space` will be removed in 12.0.0, please use `*nzSpaceItem` instead.\n\n## [11.2.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/11.1.0...11.2.0) (2021-02-26)\n\n### Bug Fixes\n\n- **18n:** adding new translations de_DE ([#6434](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6434)) ([1c09fe1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1c09fe15522c4d22691a7f30a66970c5cbbe67b6))\n- **18n:** adding new translations es_ES ([#6421](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6421)) ([6b878b9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6b878b9ac3519ea669b8e010ebef960b392721ef))\n- **docs:** fix dependabot alert ([#6428](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6428)) ([2fbbe94](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2fbbe94cfa5923565ce61ad8f29326209ba84ab1))\n- **dropdown:** close menu when click again ([#6353](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6353)) ([#6354](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6354)) ([cd90349](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cd90349ff60db343b35dd1e2f47b134aeb16948d))\n- **grid:** `nzGutter` support string type ([#6450](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6450)) ([ec03c7f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ec03c7fb09845d5d8320801b26df549046ca447c))\n- **grid,menu,radio,table:** fix memory leak problem ([#6408](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6408)) ([94607a0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/94607a0afacafdeccd942a525b3c5fce6491df7a))\n- **input:** fix [nzAutosize]=\"true\" ([#6409](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6409)) ([8ca1e5a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8ca1e5aa6c5f02bdc308e60a9b5d2c9b602406ea))\n- **message:** avoid flicker when window close ([#6296](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6296)) ([#6370](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6370)) ([772e76c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/772e76cc23506cb368e7c717f409e3c6ef5351c6))\n- **table:** fix table filter ([#6384](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6384)) ([#6385](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6385)) ([ad01c8f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ad01c8f9deb263330389bc8b9b9f4c84b6ecbf2b))\n- **tree-view:** correct API typo ([#6386](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6386)) ([27a1c4e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/27a1c4e620e8342594f152fba65c5105e991c369))\n- **schematics:** fix `add-icon-assets` schema path ([#6404](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6404)) ([340670d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/340670d8f1d2277c6da64866dfe16f94d3fdac80))\n\n### Features\n\n- **date-picker:** add `nzInline` property ([#6436](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6436)) ([4d80873](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4d808734343178abfc8e1baac90a1539b05b4c60))\n- **time-picker:** support updating OK and Now button text ([#6410](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6410)) ([ef3af58](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ef3af58e23d1e12a1b3cccf547e990550a54fcde))\n- **time-picker,select,tree-select:** support `nzId` ([#6379](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6379)) ([85d423d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/85d423d77468e493c71220374bfac676dfc9505c))\n\n### Performance Improvements\n\n- **select:** avoid reflow when select init ([#6452](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6452)) ([342d2d1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/342d2d15bb1fb58b0fbd36c7a2bb8af183ef84c9))\n\n## [11.1.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/11.0.2...11.1.0) (2021-01-22)\n\n### Bug Fixes\n\n- **table:** fix table `nzBordered` ([#6367](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6367)) ([d6ca800](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d6ca8002ff1bc1482312f9a6340a453466627c01)), closes [#6135](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6135) [#6254](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6254)\n- **typography:** edit area cannot get the content ([#6369](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6369)) ([814ef92](https://github.com/NG-ZORRO/ng-zorro-antd/commit/814ef925f3b2c046309c388bc1b98506779a3eaf))\n\n### Features\n\n- **date-picker:** support nzId ([#6242](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6242)) ([#6246](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6246)) ([1e9f8bd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1e9f8bd9d661ad00cfde7642118127e93247000b))\n- **modal:** add nzCentered for modal ([#6333](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6333)) ([8fd4df6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8fd4df66d858066dfafd3854dba339124fca866c)), closes [#6327](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6327)\n- **table:** add support for ReadonlyArray ([#6156](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6156)) ([9d67d0b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9d67d0beac80032d07a56cd57829f3bd41da9b05))\n- **table:** support nzPaginationType property ([#5986](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5986)) ([61ca6e2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/61ca6e232a8a9625cd658abfe184ac45f2729ddf))\n- **upload:** support `NzUploadFile` parameter of `nzIconRender` ([#6283](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6283)) ([a949470](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a949470af22b9c212f96bef43ad1ef47b42b75e0)), closes [#6279](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6279)\n\n## [11.0.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/11.0.1...11.0.2) (2021-01-18)\n\n### Bug Fixes\n\n- **carousel:** fix carousel under rtl ([#6336](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6336)) ([f6a844b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f6a844b468d24ffcccb2c93e39367276778416a3)); ([#6318](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6318)) ([bef7e29](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bef7e29a3f994074abbea10512b8ec1ce213110e)), closes [#6301](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6301)\n- **date-picker:** remove wrong warning message ([#6335](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6335)) ([cf10a03](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cf10a03a7eb161b96ca01f47abfe926b1033854f)), closes [#6310](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6310)\n- **date-picker:** start and end month displays unreasonable ([#6339](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6339)) ([7f47698](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7f476984a59fe4b5097d13a4ef6768dd63b6881e)), closes [#6308](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6308) [#6142](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6142) [#5992](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5992)\n- **descriptions:** fix `nzBordered` in the global config ([#6348](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6348)) ([eb20970](https://github.com/NG-ZORRO/ng-zorro-antd/commit/eb2097036f16c66ae351d2a099eb12e869ede5b6)), closes [#6331](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6331)\n- **image:** add missing entry components ([#6300](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6300)) ([caad718](https://github.com/NG-ZORRO/ng-zorro-antd/commit/caad718e23f7617fc99aa4aa29928a9db55a1e76)), closes [#6299](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6299)\n- **table:** memory leak ([#6325](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6325)) ([7f267b6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7f267b6ebc9c3259e6824702cad36382cc7df63e))\n\n## [11.0.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/11.0.0...11.0.1) (2020-12-31)\n\n### Bug Fixes\n\n- **carousel:** remove unused patch style ([#6269](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6269)) ([3a70a2d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3a70a2dcf98ec13946e388649d4901a13dd5a1ba))\n- **collapse:** animation cannot be disabled ([#6280](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6280)) ([16fa890](https://github.com/NG-ZORRO/ng-zorro-antd/commit/16fa890bf18d8a7f7d3bb9f63ae8e0cace057226))\n- **image:** add missing imported modules ([#6273](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6273)) ([20db5d4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/20db5d4ab1bae943539386559d8188e94cc49127)), closes [#6271](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6271)\n- **image:** image fit content when drag released ([#6262](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6262)) ([07ae66a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/07ae66a60285f9debf7176684ff66335f97c5a31))\n- **modal:** mask is not set with the `nzZindex` property ([#6294](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6294)) ([54d294a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/54d294a6bec56494992fefe6b2898f7af957df3b)), closes [#6288](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6288)\n- **select:** change order for clear and arrow ([#6245](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6245)) ([c822073](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c8220737c25bf4670a697729eaadc8e762e2404f)), closes [#5989](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5989)\n- **slider:** fix slider style + reverse marks if reversed slider ([#6006](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6006)) ([fa06415](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fa064156ef59673556a62d741ae640494eefae32))\n- **table:** data is not updated when pagination exists ([#6298](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6298)) ([1f2ab41](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1f2ab41fae89d0e674102c12b3960bfc7bddebab)), closes [#6272](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6272)\n- **tabs:** fix clickable area of the anchor element ([#6278](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6278)) ([0694079](https://github.com/NG-ZORRO/ng-zorro-antd/commit/069407959850995f1a5ecbef0d71fa00c69b99a5))\n- **tabs:** index only changed by router event when nzLinkRouter ([#6293](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6293)) ([ca1b861](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ca1b861b410f92a60f214f34b39c2c5d3ae9ea63))\n\n## [11.0.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/10.2.1...11.0.0) (2020-12-21)\n\n## Highlights\n\n### RTL Support\n\nSet the dir attribute on the document body or html tag.\n\n```html\n<html dir=\"rtl\"></html>\n```\n\nOr use Angular CDK bidi module for bi-directional.\n\n```typescript\nimport { BidiModule } from '@angular/cdk/bidi';\n```\n\nSuper thanks to [@saeedrahimi](https://github.com/saeedrahimi) [@hdm91](https://github.com/hdm91) [@HDaghash](https://github.com/HDaghash) [@hmdnikoo](https://github.com/hmdnikoo) for contributing this!\n\n### New Image component\n\nUsed to handle progressive loading of images; failure fallback, and preview of image(s).\n\nSuper thanks to [@stygian-desolator](https://github.com/stygian-desolator) for contributing this!\n\n### New Graph experimental component\n\nSupport customized multi-level graph rendering.\n\n### New Tree View component\n\nThe previous Tree already contains many common features, and to handle more customizable scenarios we developed a more basic Tree View component with higher ability of customization and better control over performance.\n\n### New built-in Aliyun theme\n\n```less\n@import '~ng-zorro-antd/ng-zorro-antd.aliyun.less';\n```\n\n### Bug Fixes\n\n- **tree:** fix tree styles ([#6198](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6198)) ([a481a15](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a481a156278047472e1324b87df896b37246a0ed))\n- **button:** only warn about deprecated value when used ([#6193](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6193)) ([40c644a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/40c644aa8fe92ccfaf26220a872b0995874b2569)), closes [#6191](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6191) [#6187](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6187)\n- **i18n:** fix Ukrainian i18n file ([#6236](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6236)) ([551c7a2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/551c7a24c1ae0cec9f15f61bcaa12b9057de4bd0))\n- **image:** fix RTL direction and props ([#6227](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6227)) ([3978e0f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3978e0f48c3924fdbfda54e69438ea794b29a8ec))\n- **list:** fix template rendering order ([#6232](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6232)) ([4324011](https://github.com/NG-ZORRO/ng-zorro-antd/commit/43240113c66c583e806f87b84b669a6ddb1faffe)), closes [#6229](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6229)\n- **modal:** fix `nzOkDanger` in confirm mode ([#6214](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6214)) ([ebe2869](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ebe2869d1b9459a8e02e3993d8a93483fa531f62))\n- **select:** fix XSS vulnerabilities ([#6222](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6222)) ([a393b89](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a393b89bf82eece5b0586592d709629865b27b3a)), closes [#6209](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6209)\n- **table:** false nzFrontPagination hides pagination ([#6201](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6201)) ([8029ef4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8029ef47d6eeaf43aa5875f8a8034205dc9c69bb)), closes [#6196](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6196)\n- **time-picker:** placeholder not update with i18n changes ([#6069](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6069)) ([f34840b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f34840bf2a4c5eb2d2facba0fa00068f6fa2bd5e))\n\n### Features\n\n- **all:** add RTL support to all ng-zorro-antd ([#4703](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4703)) ([860dfed](https://github.com/NG-ZORRO/ng-zorro-antd/commit/860dfeddcf02fc7e775615244827cb224d1aa8be)), closes [#4704](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4704) [#1762](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1762) [#5261](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5261)\n- **date-picker:** add `nzShowNow` ([#6160](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6160)) ([99e3117](https://github.com/NG-ZORRO/ng-zorro-antd/commit/99e3117b70853c0aa4f6b4f475b031734840f10f)), closes [#6146](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6146)\n- **graph:** add graph component ([#6053](https://github.com/NG-ZORRO/ng-zorro-antd/pull/6053)) ([e69303f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e69303f828132cb62263867abe8afefc600f15f6))\n- **image:** add image component ([#6154](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6154)) ([83dfdf9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/83dfdf97b5a716e1cc9424d645dfc6713fe4ba64))\n- **tree-view:** add tree-view component ([#6161](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6161)) ([05d58de](https://github.com/NG-ZORRO/ng-zorro-antd/commit/05d58de21f8a3e4d3e2bf4d4333de95a2c71e1ed)), closes [#5976](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5976) [#5809](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5809) [#5739](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5739) [#5736](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5736) [#5519](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5519) [#5446](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5446) [#5152](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5152) [#4694](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4694) [#4472](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4472) [#3832](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3832) [#2785](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2785) [#2744](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2744) [#6199](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6199)\n- **schematics:** make ng-add schematics chainable ([#6203](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6203)) ([d1e76f3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d1e76f3d8d41b0e3b9f01887e4805ff43f48d0fa))\n\n### BREAKING CHANGES\n\n**date-picker**\n\n- `[nzMode]` does not support `NzDateMode[]` type any more, please adjust it manually.\n\n**modal**\n\n- `[nzGetContainer]` has been removed, please remove it manually.\n- `open` method in `NzModalRef` has been removed, please remove it manually.\n\n**tabs**\n\n- `[nzShowPagination]` input has been removed, please remove it manually.\n- `(nzOnPrevClick)` output has been removed, please remove it manually.\n- `(nzOnNextClick)` output has been removed, please remove it manually.\n- `a[nz-tab-link]` selector has been removed, please use `ng-template[nzTabLink] > a[nz-tab-link]` instead.\n\n## [10.2.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/10.1.2...10.2.1) (2020-12-11)\n\n### Bug Fixes\n\n- **date-picker,time-picker:** prevent losing input focus ([#6171](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6171)) ([a055905](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a055905)), closes [#6170](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6170)\n- **description:** fix label colon not working ([#6155](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6155)) ([47065f6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/47065f6)), closes [#6151](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6151)\n- **mention:** scroll to focus when arrow up or down ([#6137](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6137)) ([13f2281](https://github.com/NG-ZORRO/ng-zorro-antd/commit/13f2281)), closes [#5995](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5995)\n- **modal:** add nzOkDanger to avoid old button style ([#6157](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6157)) ([f22024e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f22024e)), closes [#6111](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6111)\n- **select:** activate first item or first selected item ([#6148](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6148)) ([a456c93](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a456c93)), closes [#6041](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6041)\n- **table:** showPagination in ngIf when nzHideOnSinglePage ([#6133](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6133)) ([fbe13c2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fbe13c2)), closes [#6080](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6080)\n- **tabs:** keyboard events in extra areas trigger navigation ([#6173](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6173)) ([375366f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/375366f)), closes [#6139](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6139)\n- **transfer:** fix only filtered data in `nzRenderList` ([#6169](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6169)) ([17d43fb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/17d43fb)), closes [#5641](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5641)\n\n## [10.2.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/10.1.2...10.2.0) (2020-12-01)\n\n### Bug Fixes\n\n- **cascader:** restore its value after cancel search ([#6088](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6088)) ([22ddc60](https://github.com/NG-ZORRO/ng-zorro-antd/commit/22ddc60))\n- **cascader:** scroll active options into view ([#6082](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6082)) ([b42b51f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b42b51f)), closes [#6037](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6037)\n- **date-picker:** clear wrong date input after closing panel ([#6079](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6079)) ([edffdee](https://github.com/NG-ZORRO/ng-zorro-antd/commit/edffdee)), closes [#6070](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6070)\n- **date-picker:** display error in dynamic switching `nzMode` ([#6125](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6125)) ([220a590](https://github.com/NG-ZORRO/ng-zorro-antd/commit/220a590)), closes [#6052](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6052)\n- **descriptions:** fix DOM structure ([#6112](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6112)) ([5e42d71](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5e42d71))\n- **tree:** fix indent line styles ([#6123](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6123)) ([2f8edbc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2f8edbc))\n- **tree-select:** selector cannot focus ([#6073](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6073)) ([032bd01](https://github.com/NG-ZORRO/ng-zorro-antd/commit/032bd01)), closes [#6063](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6063)\n- **upload:** fix prevent trigger submit when click list button ([#6096](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6096)) ([123982f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/123982f)), closes [#6095](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6095)\n\n### Features\n\n- **drawer:** add `nzDrawerContent` directive ([#6085](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6085)) ([6fc0683](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6fc0683))\n- **drawer:** support nzVisible two-way binding ([#6013](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6013)) ([caab8be](https://github.com/NG-ZORRO/ng-zorro-antd/commit/caab8be)), closes [#5999](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5999)\n- **input:** textarea supports character count ([#6104](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6104)) ([601ab50](https://github.com/NG-ZORRO/ng-zorro-antd/commit/601ab50)), closes [#5907](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5907)\n- **modal:** add `nzModalContent` directive ([#6081](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6081)) ([6594414](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6594414))\n- **pagination:** support global config ([#6043](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6043)) ([3c55b7c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3c55b7c)), closes [#6042](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6042)\n- **steps:** supports enable and disable ([#6101](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6101)) ([b87e72d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b87e72d)), closes [#5579](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5579)\n\n_Deprecated_\n\n- modal\n  - Usage `<ng-content></ng-content>` is deprecated, which will be removed in 12.0.0. Please instead use `<ng-template nzModalContent></ng-template>` to declare the content of the modal.\n- drawer\n  - Usage `<ng-content></ng-content>` is deprecated, which will be removed in 12.0.0. Please instead use `<ng-template nzDrawerContent></ng-template>` to declare the content of the drawer.\n\n## [10.1.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/10.1.1...10.1.2) (2020-11-16)\n\n### Bug Fixes\n\n- **i18n:** include missing language exports ([#6061](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6061)) ([6543a80](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6543a80))\n- **cascader:** fix broken nzChangeOnSelect ([#6049](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6049)) ([1575bae](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1575bae)), closes [#6048](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6048)\n- **code-editor:** memorize cursor position and selections ([#6044](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6044)) ([84f520d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/84f520d)), closes [#6038](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6038)\n- **typography:** ellipsis does not work with copy action ([#6058](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6058)) ([858fff9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/858fff9)), closes [#6057](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6057)\n\n## [10.1.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/10.1.0...10.1.1) (2020-11-09)\n\n### Bug Fixes\n\n- **breadcrumb:** patch last-child's style indule a is included ([#5994](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5994)) ([50f0744](https://github.com/NG-ZORRO/ng-zorro-antd/commit/50f0744)), closes [#5942](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5942)\n- **cascader:** menu closing behavoir ([#6023](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6023)) ([22aea7e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/22aea7e)), closes [#6022](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6022)\n- **cascader:** search bar styles error ([#6030](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6030)) ([9c4424f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9c4424f)), closes [#6020](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6020)\n- **select:** dropdown can be opened when disabled ([#6008](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6008)) ([79c52ea](https://github.com/NG-ZORRO/ng-zorro-antd/commit/79c52ea)), closes [#6005](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6005) [#6007](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6007)\n- **tabs:** `nzTabBarGutter` is not work in vertical position ([#5998](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5998)) ([516bf97](https://github.com/NG-ZORRO/ng-zorro-antd/commit/516bf97)), closes [#5396](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5396)\n- **tabs:** ink-bar does not render correctly in some cases ([#6016](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6016)) ([8af418b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8af418b)), closes [#6009](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6009) [#4802](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4802) [#3999](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3999)\n\n## [10.1.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/10.0.2...10.1.0) (2020-10-30)\n\n### Bug Fixes\n\n- **form:** remove @Host so child components recieve autotips ([#5962](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5962)) ([705d6d8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/705d6d8))\n- **select:** input search not work in IE11 ([#5953](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5953)) ([5dc1ff3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5dc1ff3)), closes [#5645](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5645) [#4296](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4296)\n- **select:** the ESC keydown event not handled correctly ([#5973](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5973)) ([d898cce](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d898cce)), closes [#5965](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5965)\n- **select:** title not display ([#5978](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5978)) ([fd77cd4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fd77cd4)), closes [#5281](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5281)\n- **tabs:** link is not active on the whole tab ([#5954](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5954)) ([5c661c5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5c661c5)), closes [#5857](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5857)\n- **time-picker:** hidden clear icon when disabled ([#5990](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5990)) ([761cf40](https://github.com/NG-ZORRO/ng-zorro-antd/commit/761cf40))\n- **upload:** ensure i18n$ is defined on unsubscribe ([#5971](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5971)) ([b067e7e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b067e7e))\n\n### Features\n\n- **avatar:** add avatar group component ([#5916](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5916)) ([2dc8d98](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2dc8d98)), closes [#5882](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5882)\n- **avatar:** support for set gap ([#5920](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5920)) ([f3f1aa9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f3f1aa9)), closes [#5883](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5883)\n- **back-top:** add `nzDuration` property ([#5892](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5892)) ([b256461](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b256461)), closes [#5887](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5887)\n- **cascader:** support suffix icon & expand icon ([#5899](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5899)) ([d235589](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d235589)), closes [#5885](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5885)\n- **date-picker:** add `nzBorderless` ([#5975](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5975)) ([25e41fa](https://github.com/NG-ZORRO/ng-zorro-antd/commit/25e41fa)), closes [#5680](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5680) [#4967](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4967)\n- **descriptions:** add extra property ([#5859](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5859)) ([846331e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/846331e)), closes [#5855](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5855)\n- **form:** `nz-form-label` support `nzFormTooltip` ([#5957](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5957)) ([4a00b69](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4a00b69)), closes [#5905](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5905)\n- **form:** support a fallback locale for validation tips ([#5967](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5967)) ([c01e20b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c01e20b)), closes [#5917](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5917)\n- **menu:** add danger style ([#5932](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5932)) ([5c19bbd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5c19bbd)), closes [#5881](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5881)\n- **tooltip:** add nzTooltipColor ([#5896](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5896)) ([643bd03](https://github.com/NG-ZORRO/ng-zorro-antd/commit/643bd03)), closes [#5884](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5884)\n- **tooltip:** enable custom placements ([#5861](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5861)) ([0fce47e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0fce47e)), closes [#5733](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5733)\n- **typography:** support custom icons and tooltips ([#5911](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5911)) ([2d4cbb0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2d4cbb0)), closes [#5888](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5888)\n- **typography:** support success type ([#5915](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5915)) ([93c0d46](https://github.com/NG-ZORRO/ng-zorro-antd/commit/93c0d46)), closes [#5906](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5906)\n\n## [10.0.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/10.0.1...10.0.2) (2020-10-16)\n\n### Bug Fixes\n\n- **code-editor:** only emit update if value changed ([#5933](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5933)) ([d8c9b4d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d8c9b4d)), closes [#5869](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5869)\n- **pagination:** fix shoule be only allowed number ([#5895](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5895)) ([69a1205](https://github.com/NG-ZORRO/ng-zorro-antd/commit/69a1205)), closes [#5668](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5668)\n- **select:** accept 0 value on enter ([#5904](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5904)) ([574fdf0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/574fdf0))\n- **slider:** fix slider precision when step is decimal ([#5862](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5862)) ([dcc743a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dcc743a)), closes [#5699](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5699)\n- **spin:** make delay behave more accurately ([#5930](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5930)) ([5c901a0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5c901a0)), closes [#5926](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5926) [#5928](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5928)\n- **tooltip:** fix mouse leave overlay not obey delaying ([#5868](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5868)) ([6b5fdee](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6b5fdee)), closes [#5713](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5713)\n\n## [10.0.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/10.0.0...10.0.1) (2020-10-09)\n\n### Bug Fixes\n\n- **breadcrumb:** fix breadcrumbs not returned ([#5863](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5863)) ([1e3fea2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1e3fea2)), closes [#4751](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4751)\n- **code-editor:** run value changes in Angular zone ([#5872](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5872)) ([3bbed21](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3bbed21))\n- **date-picker:** years which contain disabled date can be selected now ([#5804](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5804)) ([3ba0366](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3ba0366)), closes [#5633](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5633) [#3425](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3425) [#5655](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5655)\n- **date-picker,time-picker:** open the panel wrongly in IE11 ([#5841](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5841)) ([89aaa79](https://github.com/NG-ZORRO/ng-zorro-antd/commit/89aaa79)), closes [#5562](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5562)\n- **modal:** no error stacks when `nzOnOk/nzOnCancel` is rejected ([#5561](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5561)) ([6a4bddd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6a4bddd)), closes [#5321](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5321)\n- **upload:** fix upload list style of picture card type ([#5851](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5851)) ([9fda318](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9fda318)), closes [#5850](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5850)\n\n## [10.0.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/9.3.0...10.0.0) (2020-09-28)\n\n### Bug Fixes\n\n- **tree:** fix nzBlockNode not work ([#5507](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5507)) ([5337652](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5337652))\n- **breadcrumb:** fix auto-generated with lazy modules ([#5670](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5670)) ([932d92f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/932d92f)), closes [#5613](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5613) [#5615](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5615)\n- **carousel:** support SSR ([#5671](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5671)) ([65b44aa](https://github.com/NG-ZORRO/ng-zorro-antd/commit/65b44aa)), closes [#4292](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4292)\n- **code-editor:** init event never emit when using static loading ([#5677](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5677)) ([b946742](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b946742))\n- **date-picker:** modify date-fns week-year format ([#5753](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5753)) ([4911e36](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4911e36)), closes [#5327](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5327)\n- **date-picker:** nzCalendarChange not work when clicking ok ([#5790](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5790)) ([c9426f0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c9426f0)), closes [#5782](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5782)\n- **date-picker:** open the panel wrongly in IE11 ([#5643](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5643)) ([0649ceb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0649ceb)), closes [#5562](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5562)\n- **date-picker:** window is not defined ([#5640](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5640)) ([f5899ad](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f5899ad)), closes [#5630](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5630)\n- **form:** optimize code to increase robustness ([#5550](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5550)) ([fdf085b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fdf085b))\n- **mention:** not emit nzOnSearchChange when value is empty ([#5729](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5729)) ([4cc14ba](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4cc14ba)), closes [#5722](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5722)\n- **modal:** change back to FocusTrapFactory ([#5596](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5596)) ([9805620](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9805620)), closes [#5591](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5591)\n- **progress:** fix value not updated when is steps ([#5676](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5676)) ([3eecc44](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3eecc44)), closes [#5585](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5585)\n- **select:** arrow icon can be used when not using single-select ([#5785](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5785)) ([bb8677c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bb8677c)), closes [#5575](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5575)\n- **select:** cursor abnormal in nz-select with nzDisabled ([#5716](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5716)) ([0d1f027](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0d1f027)), closes [#5709](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5709)\n- **select:** display IME input completely ([#5657](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5657)) ([111721a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/111721a))\n- **select:** fix click arrow open ([#5784](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5784)) ([2d3a49c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2d3a49c))\n- **slider:** fix reverse slider value with min and max ([#5814](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5814)) ([fa46a79](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fa46a79))\n- **style:** fix 4.6.1 sync style ([#5727](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5727)) ([b5f96ca](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b5f96ca))\n- **tabs:** fix clickable area of tab-link ([#5708](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5708)) ([57962e1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/57962e1)), closes [#5696](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5696)\n- **tabs:** fix dropdown style ([#5659](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5659)) ([8415a70](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8415a70))\n- **tabs:** not emit click event from dropdown menu ([#5639](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5639)) ([201ef52](https://github.com/NG-ZORRO/ng-zorro-antd/commit/201ef52))\n- **tabs:** router link content projection error ([#5663](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5663)) ([47050b0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/47050b0))\n- **tabs:** tab-link cannot be disabled ([#5759](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5759)) ([1afabd4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1afabd4)), closes [#5549](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5549) [#5543](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5543)\n- **time-picker:** input value change not work ([#5770](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5770)) ([31ca2da](https://github.com/NG-ZORRO/ng-zorro-antd/commit/31ca2da)), closes [#5678](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5678) [#5741](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5741) [#4934](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4934)\n- **tooltip:** enable cdk push ([#5542](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5542)) ([55ec1cd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/55ec1cd)), closes [#1825](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1825)\n- **tree-select:** not clear search value when dropdown close ([#5761](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5761)) ([602ea93](https://github.com/NG-ZORRO/ng-zorro-antd/commit/602ea93)), closes [#5664](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5664)\n- **tree-select:** should be not clearable when disabled or unselected ([#5769](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5769)) ([baede4a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/baede4a)), closes [#5603](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5603)\n\n### Code Refactoring\n\n- **anchor:** remove deprecated APIs for v10 ([#5776](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5776)) ([e50d530](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e50d530))\n- **cascader:** remove deprecated APIs for v10 ([#5778](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5778)) ([7e64e4c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7e64e4c))\n- **code-editor:** remove deprecated APIs for v10 ([#5798](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5798)) ([353e657](https://github.com/NG-ZORRO/ng-zorro-antd/commit/353e657))\n- **date-picker:** remove deprecated APIs for v10 ([#5793](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5793)) ([5159900](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5159900))\n- **form,grid:** remove deprecated APIs for v10 ([#5788](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5788)) ([b215efa](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b215efa))\n- **notification:** remove deprecated APIs for v10 ([#5779](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5779)) ([e5ed4d2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e5ed4d2))\n- **table:** remove deprecated APIs for v10 ([#5792](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5792)) ([132e425](https://github.com/NG-ZORRO/ng-zorro-antd/commit/132e425))\n- **tooltip, popover, popconfirm:** change deprecated APIs for v10 ([#5817](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5817)) ([dc3088c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dc3088c))\n- **tree:** remove deprecated APIs for v10 ([#5789](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5789)) ([b378cb7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b378cb7))\n- **upload:** remove deprecated APIs for v10 ([#5774](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5774)) ([9f5baae](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9f5baae))\n\n### Features\n\n- **modal:** support params and modelRef when footer is template ([#5551](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5551)) ([07d91a1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/07d91a1)), closes [#5506](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5506)\n- **breadcrumb:** add `nzRouteLabelFn` property ([#5523](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5523)) ([#5545](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5545)) ([81ef791](https://github.com/NG-ZORRO/ng-zorro-antd/commit/81ef791))\n- **button:** support text type ([3f5d10b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3f5d10b))\n- **card:** support nzBorderless ([#5796](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5796)) ([6e4419c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6e4419c))\n- **collapse:** support nzGhost property ([1a408ee](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1a408ee))\n- **date-picker:** add `open` and `close` methods ([#5777](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5777)) ([be6eda4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/be6eda4)), closes [#3352](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3352) [#5771](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5771)\n- **date-picker:** add week month year range ([#5832](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5832)) ([0725d88](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0725d88)), closes [#5742](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5742)\n- **divider:** support nzPlain property ([d5232ac](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d5232ac))\n- **drawer:** add `nzFooter` property ([#4618](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4618)) ([#5553](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5553)) ([2cd9e12](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2cd9e12))\n- **drawer:** support `[nzCloseIcon]` ([#5546](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5546)) ([aa984f7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/aa984f7))\n- **input:** support borderless ([#5781](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5781)) ([6e7877b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6e7877b))\n- **pipes:** add pipes ([#4812](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4812)) ([e03e65b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e03e65b))\n- **skeleton:** add nzRound prop and skeleton-element image ([#5710](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5710)) ([aa2ea54](https://github.com/NG-ZORRO/ng-zorro-antd/commit/aa2ea54))\n- **space:** support `nzAlign` ([#5299](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5299)) ([2febb92](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2febb92))\n- **table:** fix scroll bar displays always even unnecessary ([#5794](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5794)) ([71be33a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/71be33a)), closes [#5405](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5405)\n- **table:** support nzOuterBordered ([#5795](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5795)) ([471b0bf](https://github.com/NG-ZORRO/ng-zorro-antd/commit/471b0bf))\n- **tabs:** support (nzContextmenu) event ([#5749](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5749)) ([76931ac](https://github.com/NG-ZORRO/ng-zorro-antd/commit/76931ac)), closes [#5712](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5712)\n- **tag:** support icon in tag ([#5801](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5801)) ([b909354](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b909354)), closes [#5628](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5628) [#4581](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4581)\n- **tree-select:** support virtual scroll ([#5760](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5760)) ([1f2d816](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1f2d816)), closes [#5589](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5589)\n- **typography:** support keyboard and link types ([#5355](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5355)) ([2d6fa62](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2d6fa62))\n\n### BREAKING CHANGES\n\n**tooltip, popover, popconfirm:**\n\n- nz-tooltip\n  - `[nzOverlayStyle]` has been removed, use `[nzTooltipOverlayStyle]` instead.\n  - `[nzOverlayClassName]` has been removed, use `[nzTooltipOverlayClassName]` instead.\n  - `[nzMouseLeaveDelay]` has been removed, use `[nzTooltipMouseLeaveDelay]` instead.\n  - `[nzMouseEnterDelay]` has been removed, use `[nzTooltipMouseEnterDelay]` instead.\n  - `(nzVisibleChange)` has been removed, use `(nzTooltipVisibleChange)` instead.\n- nz-popover\n  - `[nzOverlayStyle]` has been removed, use `[nzPopoverOverlayStyle]` instead.\n  - `[nzOverlayClassName]` has been removed, use `[nzPopoverOverlayClassName]` instead.\n  - `[nzMouseLeaveDelay]` has been removed, use `[nzPopoverMouseLeaveDelay]` instead.\n  - `[nzMouseEnterDelay]` has been removed, use `[nzPopoverMouseEnterDelay]` instead.\n  - `(nzVisibleChange)` has been removed, use `(nzPopoverVisibleChange)` instead.\n- nz-popconfirm\n  - `[nzOverlayStyle]` has been removed, use `[nzPopconfirmOverlayStyle]` instead.\n  - `[nzOverlayClassName]` has been removed, use `[nzPopconfirmOverlayClassName]` instead.\n  - `[nzMouseLeaveDelay]` has been removed, use `[nzPopconfirmMouseLeaveDelay]` instead.\n  - `[nzMouseEnterDelay]` has been removed, use `[nzPopconfirmMouseEnterDelay]` instead.\n  - `(nzVisibleChange)` has been removed, use `(nzPopconfirmVisibleChange)` instead.\n\n**code-editor:**\n\n- `NzCodeEditorService.updateDefaultOption` has been removed, use `NzConfigService.set` instead.\n- Inject token `NZ_CODE_EDITOR_CONFIG` has been removed, use `NZ_CONFIG` instead.\n\n**date-picker:**\n\n- `NZ_DATE_FNS_COMPATIBLE` has been removed. Please migrate to date-fns v2 manually.\n- nz-date-picker,nz-week-picker,nz-month-picker,nz-year-picker,nz-range-picker\n  - `[nzClassName]` has been removed, use `ngClass` instead.\n  - `[nzStyle]` has been removed, use `ngStyle` instead.\n\n**table:**\n\n- `th[nzSort]` has been removed, use `th[nzSortOrder]` instead.\n- `th(nzSortChange)` has been removed, use `th(nzSortOrderChange)` instead.\n- `th(nzSortChangeWithKey)` has been removed. Please manually remove it.\n- `thead(nzSortChange)` has been removed, use `thead(nzSortOrderChange)` instead.\n- `thead[nzSingleSort]` and `th[nzSortKey]` has been removed. Please manually change to `th[nzSortFn]`.\n\n**form,grid:**\n\n- `nz-form-item[nzFlex]` has been removed. Please manually remove this input.\n- `nz-form-item[nzType]` has been removed. Please manually remove this input.\n- `nz-row[nzType]` has been removed. Please manually remove this input.\n\n**tree:**\n\n- `NzTreeNode.isAllChecked` has been removed, use `NzTreeNode.isChecked` instead.\n- `NzTreeNode.setSelected(boolean)` has been removed, use `NzTreeNode.isSelected = boolean` instead.\n\n**notification:**\n\n- `NzNotificationDataFilled` has been removed, use `NzNotificationRef` instead.\n- `NzNotificationDataOptions.nzPosition` has been removed, use `NzNotificationDataOptions.nzPlacement` instead.\n\n**anchor:**\n\n- `nzTarget` has been removed, use `nzContainer` instead.\n\n**cascader:**\n\n- `CascaderOption` has been removed, use `NzCascaderOption` instead.\n- `CascaderSearchOption` has been removed, use `NzCascaderSearchOption` instead.\n\n**upload:**\n\n- `UploadType` has been removed, use `NzUploadType` instead.\n- `UploadListType` has been removed, use `NzUploadListType` instead.\n- `UploadFile` has been removed, use `NzUploadFile` instead.\n- `UploadChangeParam` has been removed, use `NzUploadChangeParam` instead.\n- `ShowUploadListInterface` has been removed, use `NzShowUploadList` instead.\n- `UploadTransformFileType` has been removed, use `NzUploadTransformFileType` instead.\n- `UploadXHRArgs` has been removed, use `NzUploadXHRArgs` instead.\n\n## [9.3.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/9.2.2...9.3.0) (2020-07-09)\n\n### Bug Fixes\n\n- **config:** fix empty check ([#5537](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5537)) ([fd979f7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fd979f7))\n- **date-picker:** nzDateRender render incorrectly ([#5529](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5529)) ([fa7c7b4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fa7c7b4))\n- **i18n:** export missing languages from public-api ([#5515](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5515)) ([57b1180](https://github.com/NG-ZORRO/ng-zorro-antd/commit/57b1180)), closes [#5510](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5510)\n- **list:** nz-list-item-actions rendered nothing ([#5465](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5465)) ([c126035](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c126035)), closes [#5393](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5393)\n- **select:** fix select scroll render buffer ([#5536](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5536)) ([089421c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/089421c)), closes [#5456](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5456)\n- **table:** fix table filter false or 0 error ([#5535](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5535)) ([56f052c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/56f052c)), closes [#5505](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5505)\n- **table:** fix table no data colSpan ([#5533](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5533)) ([7f133af](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7f133af)), closes [#5509](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5509) [#5481](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5481)\n- **tooltip:** replace public api with more specific ones ([#5449](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5449)) ([a165eda](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a165eda)), closes [#5365](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5365)\n- **upload:** fix `uploadError` of undefined ([#5476](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5476)) ([71218d1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/71218d1)), closes [#5472](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5472)\n\n### Features\n\n- **datapicker:** add [nzInputReadOnly] ([#4534](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4534)) ([#5488](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5488)) ([13875cb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/13875cb))\n- **drawer:** support get component instance for content ([#5498](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5498)) ([bf160b6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bf160b6)), closes [#5489](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5489) [#3283](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3283)\n- **popconfirm:** add `nzPopconfirmShowArrow` property ([#5361](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5361)) ([#5483](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5483)) ([516e02d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/516e02d))\n- **resizable:** add `nzDisabled` property ([#5475](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5475)) ([4d44d2e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4d44d2e))\n- **timeline:** support custom position ([#5478](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5478)) ([12e6b6f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/12e6b6f)), closes [#5470](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5470)\n- **tooltip:** add more specific api ([#5449](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5449)) ([#5512](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5512)) ([352e5e7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/352e5e7))\n- **upload:** add `nzPreviewIsImage` property ([#5525](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5525)) ([e55a586](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e55a586)), closes [#5520](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5520) [#4990](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4990)\n\n## [9.2.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/9.2.1...9.2.2) (2020-06-23)\n\n### Bug Fixes\n\n- **datepicker:** not open panel when input change([#5466](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5466)) ([aca104c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/aca104c)), closes [#5284](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5284) [#5411](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5411)\n- **modal:** throw an error when autofocus on the confirm-mode ([#5462](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5462)) ([6a26143](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6a26143)), closes [#5454](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5454)\n\n## [9.2.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/9.2.0...9.2.1) (2020-06-17)\n\n### Bug Fixes\n\n- **i18n:** some locales compiles error ([#5445](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5445)) ([e9ef9f3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e9ef9f3))\n\n## [9.2.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/9.1.2...9.2.0) (2020-06-16)\n\n### Bug Fixes\n\n- **affix,anchor:** wrong value is set when the initial value is non-number ([#5277](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5277)) ([1c72939](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1c72939))\n- **tree:** fix nzCheckStrictly and selected keys bug ([#5431](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5431)) ([67d9dd0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/67d9dd0)), closes [#5385](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5385) [#5195](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5195) [#5068](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5068)\n- **badge:** fix parent component use onpush nzCount not show ([#5275](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5275)) ([d1f0321](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d1f0321))\n- **button:** fix button init loading status ([#5404](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5404)) ([c764c67](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c764c67)), closes [#5392](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5392)\n- **date-picker:** get input width before panel open ([#5357](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5357)) ([39a6c28](https://github.com/NG-ZORRO/ng-zorro-antd/commit/39a6c28))\n- **drawer:** don't prevent events when nzMask is false ([#5438](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5438)) ([abe9e53](https://github.com/NG-ZORRO/ng-zorro-antd/commit/abe9e53)), closes [#5350](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5350)\n- **dropdown:** fix dropdown disabled button ([#5429](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5429)) ([797c65d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/797c65d)), closes [#5258](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5258)\n- **grid:** fix gutter zero ([#5436](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5436)) ([80a4709](https://github.com/NG-ZORRO/ng-zorro-antd/commit/80a4709)), closes [#5435](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5435)\n- **input:** fix input missing attr disabled ([#5315](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5315)) ([2b17df2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2b17df2))\n- **input:** fix reactive form disabled input-group style ([#5428](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5428)) ([6d403e3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d403e3)), closes [#5137](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5137)\n- **input:** support reactive form disabled ([#5316](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5316)) ([8270009](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8270009))\n- **menu:** fix menu group ng-template error ([#5409](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5409)) ([d0c36d6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d0c36d6)), closes [#5363](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5363)\n- **message:** fix style not changed when property changes ([#5323](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5323)) ([896f283](https://github.com/NG-ZORRO/ng-zorro-antd/commit/896f283)), closes [#5301](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5301)\n- **modal:** modal will close when clicking the scrollbar ([#5377](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5377)) ([e95d404](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e95d404)), closes [#5376](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5376)\n- **modal:** nzAutofocus doesn't work correctly ([#5313](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5313)) ([7ad64b8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7ad64b8))\n- **modal:** some cases there is no changes detected ([#5332](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5332)) ([ade6198](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ade6198)), closes [#5328](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5328) [#5287](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5287) [#5259](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5259) [#3743](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3743)\n- **notification:** fix notification template not updated ([#5382](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5382)) ([7217097](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7217097)), closes [#4787](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4787)\n- **page-header:** add compact style ([#5241](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5241)) ([74fa3d6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/74fa3d6))\n- **radio:** fix radio focus ([#5424](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5424)) ([6e0f47b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6e0f47b)), closes [#5285](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5285)\n- **select:** fix group label search ([#5407](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5407)) ([7e1b5a7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7e1b5a7)), closes [#5276](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5276)\n- **select:** fix select autofocus behavior ([#5420](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5420)) ([8617e58](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8617e58)), closes [#5381](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5381)\n- **select:** fix select nzCustomContent render ([#5425](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5425)) ([f99d7ff](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f99d7ff)), closes [#5178](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5178)\n- **select:** fix tag mode wrong value with keydown ([#5432](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5432)) ([fe5419b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fe5419b)), closes [#5220](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5220)\n- **table:** fix ExpressionChangedAfterError of nzRight and nzLeft ([#5240](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5240)) ([dc8c7e7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dc8c7e7)), closes [#5238](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5238)\n- **table:** fix table colspan & empty data style ([#5417](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5417)) ([2eda6d3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2eda6d3)), closes [#5410](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5410)\n- **table:** fix table nzWidth not work with scroll ([#5437](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5437)) ([c1e7e9f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c1e7e9f)), closes [#5370](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5370) [#5324](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5324) [#5318](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5318) [#5309](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5309) [#5167](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5167) [#5160](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5160)\n- **table:** fix table sort default value change ([#5433](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5433)) ([26469c8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/26469c8)), closes [#5262](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5262)\n- **table:** fix th nzChecked supersedes nzShowCheckbox ([#5419](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5419)) ([6f5b935](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6f5b935)), closes [#5388](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5388)\n\n### Features\n\n- **calendar:** support nzDisabledDate of calendar ([#5295](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5295)) ([aabd17e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/aabd17e))\n- **code-editor:** update the instance types ([#5422](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5422)) ([eac9b08](https://github.com/NG-ZORRO/ng-zorro-antd/commit/eac9b08))\n- **input-number:** support inputmode ([#5423](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5423)) ([cdca7bc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cdca7bc)), closes [#5341](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5341)\n- **select:** support nzBorderless in global config ([#5434](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5434)) ([459bdb0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/459bdb0)), closes [#5224](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5224)\n- **slider:** add nzReverse property ([#5268](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5268)) ([67275d2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/67275d2)), closes [#4937](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4937)\n- **table:** support the generic type of data ([#5369](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5369)) ([182e790](https://github.com/NG-ZORRO/ng-zorro-antd/commit/182e790))\n- **typography:** support `nzOnEllipsis` output ([#5297](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5297)) ([2200063](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2200063))\n- **upload:** add `nzFileListRender` property ([#5204](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5204)) ([ce5574a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ce5574a)), closes [#4875](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4875)\n\n## [9.1.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/9.1.1...9.1.2) (2020-05-13)\n\n### Bug Fixes\n\n- **all** type errors with strictTemplates ([#5265](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5265)) ([2982766](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2982766)), closes [#5171](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5171)\n- **list:** empty content is always rendered ([#5266](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5266)) ([ca7314c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ca7314c)), closes [#5260](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5260)\n- **select:** option item not selected with falsy value ([#5264](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5264)) ([1c4d7d8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1c4d7d8))\n\n## [9.1.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/9.1.0...9.1.1) (2020-05-11)\n\n### Bug Fixes\n\n- **auto-complete, drawer:** cannot reopen when reuse route snapshots([#5165](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5165)) ([7101782](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7101782)), closes [#5142](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5142)\n- **alert:** `nzNoAnimation` not work with the alert component ([#5211](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5211)) ([de9ef6b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/de9ef6b))\n- **breadcrumb:** fix breadcrumb when Routes path='' ([#4966](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4966)) ([5ffa45c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5ffa45c))\n- **button:** disabled not work with anchor ([#5233](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5233)) ([36ab993](https://github.com/NG-ZORRO/ng-zorro-antd/commit/36ab993)), closes [#5226](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5226)\n- **dropdown:** fix dropdown break SSR ([#5244](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5244)) ([016cca1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/016cca1)), closes [#5186](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5186)\n- **modal:** global config cannot work with service mode ([#5228](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5228)) ([95aab9a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/95aab9a)), closes [#5223](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5223)\n- **modal:** modal cannot close after the host view destroyed ([#5161](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5161)) ([5cb618e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5cb618e)), closes [#5128](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5128)\n- **modal:** rollback to component types can be the content of confirm-mode ([#5177](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5177)) ([5fa4c1e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5fa4c1e)), closes [#5172](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5172)\n- **schematics:** invalid version will be added when the package already exists ([#5210](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5210)) ([f406803](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f406803)), closes [#5209](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5209)\n- **table:** fix table expand in multiple thead tr ([#5246](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5246)) ([cbaeb38](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cbaeb38)), closes [#5207](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5207)\n- **timeline:** fix timeline check error ([#5245](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5245)) ([ee2859f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ee2859f)), closes [#5230](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5230)\n- **typography:** ellipsis line measurement error ([#5175](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5175)) ([93676c9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/93676c9))\n- **upload:** fix invalid preview image in picture card ([#5205](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5205)) ([cbe8225](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cbe8225)), closes [#5201](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5201)\n\n## [9.1.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/9.0.2...9.1.0) (2020-04-26)\n\n### Bug Fixes\n\n- **auto-complete:** dropdown position error with group-input ([#5157](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5157)) ([5b26479](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5b26479))\n- **cascader:** fix cascader position ([#5148](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5148)) ([7870e67](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7870e67)), closes [#5102](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5102)\n- **date-picker:** set formControl disabled not work ([#5126](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5126)) ([b83e7b5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b83e7b5)), closes [#5118](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5118)\n- **date-picker,time-picker:** clicking host to open panel ([#5105](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5105)) ([7c938b4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7c938b4)), closes [#5073](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5073)\n- **description:** fix description not accept TemplateRef ([#5139](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5139)) ([90d2ec5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/90d2ec5)), closes [#5127](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5127)\n- **form:** the setStatus needs to call again on tips changes ([#5144](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5144)) ([a08d4da](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a08d4da)), closes [#5129](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5129)\n- **menu:** fix menu matchRouter not work ([#5095](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5095)) ([2724b9b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2724b9b))\n- **menu:** fix submenu scrollable ([#5155](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5155)) ([fb52f21](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fb52f21)), closes [#4837](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4837)\n- **message:** fix message remove error when no container ([#5123](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5123)) ([1eca795](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1eca795)), closes [#5121](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5121)\n- **modal:** `NoopAnimations` do not work with modal mask ([#5103](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5103)) ([d7625db](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d7625db)), closes [#5093](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5093)\n- **notification:** fix global config nzPlacement not working ([#5140](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5140)) ([1ce1634](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1ce1634)), closes [#5135](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5135)\n- **progress:** fix nzFormat not shown status is exception ([#5136](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5136)) ([654411e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/654411e)), closes [#5130](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5130)\n- **select:** fix ie11 select search input ([#5117](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5117)) ([83cdc84](https://github.com/NG-ZORRO/ng-zorro-antd/commit/83cdc84)), closes [#5110](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5110)\n- **select:** fix virtual scroll hover bug ([#5131](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5131)) ([d69415a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d69415a)), closes [#5120](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5120) [#5116](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5116)\n- **space:** fix config name ([#5147](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5147)) ([64f772d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/64f772d))\n- **table:** remove table nzQueryParams debounceTime ([#5132](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5132)) ([07a9d34](https://github.com/NG-ZORRO/ng-zorro-antd/commit/07a9d34)), closes [#5113](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5113)\n- **time-picker:** allow undefined or null input ([#5104](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5104)) ([d0b40ce](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d0b40ce)), closes [#5100](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5100)\n- **tooltip:** fix title not updated to component ([#5097](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5097)) ([1123281](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1123281)), closes [#5087](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5087)\n- backward-compatible with the previous rendering engine ([#5090](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5090)) ([b61a914](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b61a914)), closes [#5088](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5088)\n\n### Features\n\n- **date-picker, time-picker:** support custom suffix icon ([#5072](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5072)) ([8b660bd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8b660bd))\n- **autocomplete:** support values whit object type ([#4996](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4996)) ([4bfbbf7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4bfbbf7)), closes [#4981](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4981)\n- **select:** support global config nzSuffixIcon ([#5092](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5092)) ([ad847e7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ad847e7))\n- **select:** support input nzOptions in select ([#5109](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5109)) ([251a064](https://github.com/NG-ZORRO/ng-zorro-antd/commit/251a064)), closes [#5106](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5106)\n- **select:** support option height and opiton overflow size ([#5133](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5133)) ([7b3937e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7b3937e)), closes [#5112](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5112)\n\n## [9.0.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/9.0.0...9.0.2) (2020-04-20)\n\n### Bug Fixes\n\n- **all:** fix enableIvy:false with ng-zorro-antd ([#5081](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5081)) ([83b554e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/83b554e)), closes [#5070](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5070)\n- **button:** fix button type definition ([#5085](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5085)) ([62584de](https://github.com/NG-ZORRO/ng-zorro-antd/commit/62584de)), closes [#5026](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5026)\n- **form:** modify to subscribe to the parent component input ([#4524](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4524)) ([565b530](https://github.com/NG-ZORRO/ng-zorro-antd/commit/565b530)), closes [#4554](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4554)\n- **input:** fix input group missing focus and disabled ([#5082](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5082)) ([5ff38be](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5ff38be)), closes [#5064](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5064)\n- **popover:** fix programmatically changing not trigger ngModelChange ([#5053](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5053)) ([dbc2cd3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dbc2cd3))\n- **select:** fix nzDropdownMatchSelectWidth not work ([#5066](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5066)) ([d210f4d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d210f4d)), closes [#5058](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5058)\n- **select:** options overflow content cannot be hidden ([#5057](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5057)) ([867dc87](https://github.com/NG-ZORRO/ng-zorro-antd/commit/867dc87)), closes [#5047](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5047)\n- **select:** wrong sort in group option ([#5063](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5063)) ([af39d5f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/af39d5f))\n- ngcc errors caused by overlapping entry-points ([#5055](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5055)) ([7bc8279](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7bc8279)), closes [#5045](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5045)\n\n## [9.0.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/9.0.0-beta.4...9.0.0) (2020-04-15)\n\n### Intro\n\nWelcome to the `9.0.0` version of `ng-zorro-antd`,some APIs were deprecated in version 8.x, and warning message was given under dev mode. All deprecated APIs is removed in 9.0.0, if you have fixed all warnings in the 8.x version, you can follow these steps to upgrade your version.\n\n#### Environmental Requirement\n\n1. Make sure `Node.js` >= `10.13`\n2. Create a new branch, or use other methods to back up the current project\n3. delete the package-lock.json file\n\n#### Upgrade dependencies\n\n- Upgrade Angular to 9.x version, ref https://update.angular.io/\n- Run `ng update @angular/cdk`, if you have used `@angular/cdk`.\n- if you have used `date-fns` in your project, upgrade it to `2.x` version, ref https://github.com/date-fns/date-fns-upgrade.\n- if you have used `monaco-editor` please upgrade it to `0.2.x`, don't forget to upgrade `monaco-editor-webpack-plugin` to `1.9.x` if you have used it.\n\n#### Upgrade NG-ZORRO\n\n- Run `ng update ng-zorro-antd`\n- If a warning message appears in the console, follow the prompts to modify the corresponding code\n\n#### date-fns update\n\nWe have upgraded `date-fns` to v2. When you switch to` date-fns`, some date formats will have a breaking change. Such as:\n\n```html\n<!-- datefns v1 -->\n<nz-date-picker nzFormat=\"YYYY-MM-DD\"></nz-date-picker>\n\n<!-- datefns v2 -->\n<nz-date-picker nzFormat=\"yyyy-MM-dd\"></nz-date-picker>\n```\n\n**We recommend using `date-fns` v2 date format**. If you don't want to use the new date format, you can use `NZ_DATE_FNS_COMPATIBLE`. When set to` true`, `ng-zorro-antd` will convert the format of v1 to v2. See the comparison of the old and new formats [here](https://github.com/date-fns/date-fns/blob/master/CHANGELOG.md#200---2019-08-20).\n\n```js\nproviders: [{ provide: NZ_DATE_FNS_COMPATIBLE, useValue: true }];\n```\n\n**`NZ_DATE_FNS_COMPATIBLE` won't be kept for too long, we will remove the support for `date-fns` v1 format until ` ng-zorro-antd` v10**, we hope you can update the `date-fns` date format in time. For `date-fns` upgrade guide, see [here](https://github.com/date-fns/date-fns-upgrade).\n\n#### Angular Ivy Supported\n\nWe have upgraded the `@angular/*` and `@angular/cdk` versions to v9, and now you can use the Ivy rendering engine to run your project, and enable the `strictTemplates` option to use more strict template type checking.\n\nMore help go to [Angular Ivy](https://angular.io/guide/ivy) and [Template type](https://angular.io/guide/template-typecheck) checking.\n\n#### Ant Design 4 Spec\n\nWe have synced the Ant Design 4 design specification and support the Dark and Compact themes.\n\n#### Enhanced Performance and Usability\n\n- In previous versions, the Table component has integrated virtual scrolling, also now supported for Select and Tree components.\n- Form and Table simplify usage and now allow for writing fewer templates and configurations.\n- Allow adding icons in sub-modules to reduce the first screen load time.\n- Now, the pop-up menu is automatically closed when the route is changed, and corresponding options have been added for components such as Modal.\n\n## [9.0.0-beta.4](https://github.com/NG-ZORRO/ng-zorro-antd/compare/9.0.0-beta.3...9.0.0-beta.4) (2020-04-14)\n\n### Bug Fixes\n\n- **slider:** fix handle transform in vertical mode ([#4939](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4939)) ([6fba78d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6fba78d))\n- add theme bundle files ([#5012](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5012)) ([dc8fe9d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dc8fe9d)), closes [#5007](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5007)\n- **badge:** allow `nzTitle` set to null ([#4965](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4965)) ([a35fb5e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a35fb5e)), closes [#4776](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4776)\n- **date-picker:** click date cell not work when changing month or year ([#4876](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4876)) ([3aebe7c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3aebe7c)), closes [#3499](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3499)\n- **list:** fix the avatar part old API ([#4952](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4952)) ([d8a2594](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d8a2594)), closes [#4912](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4912)\n- **modal:** `nzModalFooter` not work when the modal open on init ([#4954](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4954)) ([2f400e8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2f400e8)), closes [#4948](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4948)\n- **modal:** fix close button style ([#5014](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5014)) ([174099e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/174099e))\n- **page-header:** location inject error ([#5013](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5013)) ([9073fa5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9073fa5)), closes [#4945](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4945)\n- **table:** fix 4.1.0 style error ([#4953](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4953)) ([44f606c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/44f606c))\n- **table:** fix table no data ([#4947](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4947)) ([7f7989e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7f7989e))\n- **time-picker:** allow inputting string type ([#4949](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4949)) ([3b45a22](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3b45a22)), closes [#4775](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4775) [#4777](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4777) [#4871](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4871) [#1679](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1679)\n- **time-picker:** ngModelChange not work ([#4944](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4944)) ([a6ecdb9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a6ecdb9))\n- **time-picker:** scroll to wrong position in datepicker ([#4961](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4961)) ([cdf387f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cdf387f))\n- **tree:** fix search case sensitivity ([#4766](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4766)) ([828b13e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/828b13e)), closes [#1996](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1996) [#4765](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4765)\n- **tree:** fix tree animation ([#4973](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4973)) ([70b2fc3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/70b2fc3))\n\n### Features\n\n- **code-editor:** upgrade monaco to 0.20.0 and update interfaces ([#4984](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4984)) ([3963ad1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3963ad1))\n- **notification:** add onClick observable ([#4989](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4989)) ([9224240](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9224240)), closes [#4986](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4986)\n- **space:** add new component ([#4928](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4928)) ([df01bd1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/df01bd1)), closes [#4913](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4913)\n- **table:** support new nzQueryParams ([#4970](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4970)) ([79ea999](https://github.com/NG-ZORRO/ng-zorro-antd/commit/79ea999))\n- **tooltip,etc:** support custom origin ([#4849](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4849)) ([863fd4b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/863fd4b))\n- **tree:** support virtual scroll ([#4979](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4979)) ([6803a92](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6803a92)), closes [#4426](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4426) [#3808](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3808) [#3436](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3436) [#2680](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2680) [#1771](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1771)\n- **schematics:** add v9 migration rules for carousel and inject tokens ([#4469](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4469)) ([704cb9b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/704cb9b))\n- **schematics:** add v9 migration rules for tree ([#4602](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4602)) ([87b8e55](https://github.com/NG-ZORRO/ng-zorro-antd/commit/87b8e55))\n- support compact theme ([#4972](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4972)) ([2cf34d0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2cf34d0))\n\n### BREAKING CHANGES\n\n- **notification:**\n\n* NzMessageDataFilled is replaced by NzMessageRef\n* NzNotificationDataFilled is replaced by NzNotificationRef\n\n## [9.0.0-beta.3](https://github.com/NG-ZORRO/ng-zorro-antd/compare/9.0.0-beta.2...9.0.0-beta.3) (2020-03-24)\n\n### Bug Fixes\n\n- **empty:** fix empty image style in dark mode ([#4924](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4924)) ([bae59d7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bae59d7)), closes [#4921](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4921)\n- **table:** fix nzTotal in frontend pagination false ([#4922](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4922)) ([9ddc060](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9ddc060)), closes [#4919](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4919)\n\n### Features\n\n- **pagination:** add auto resize ([#4863](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4863)) ([1bb01b5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1bb01b5))\n\n## [9.0.0-beta.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/9.0.0-beta.1...9.0.0-beta.2) (2020-03-19)\n\n### Bug Fixes\n\n- **grid:** fix grid responsive bug ([#4906](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4906)) ([d6828ed](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d6828ed))\n- **select:** fix select empty status ([#4907](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4907)) ([f295c10](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f295c10))\n\n## [9.0.0-beta.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/8.5.1...9.0.0-beta.1) (2020-03-15)\n\n### Bug Fixes\n\n- **code-editor:** fix wrong initialization with diff mode ([#4485](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4485)) ([#4532](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4532)) ([021cf22](https://github.com/NG-ZORRO/ng-zorro-antd/commit/021cf22))\n- **auto-complete:** close the panel when tapping scrollb… ([#4551](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4551)) ([387ebc1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/387ebc1)), closes [#4333](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4333)\n- **breadcrumb:** fix breadcrumb link style ([#4880](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4880)) ([2553328](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2553328))\n- **button:** fix button animation bug caused by angular ([9e0df2a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9e0df2a)), closes [#2697](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2697)\n- **cascader:** fix not showing empty when there's no options ([#4565](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4565)) ([9d8d7e6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9d8d7e6)), closes [#4562](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4562)\n- **date-picker:** select date but nzDefaultOpenValue not work ([#4490](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4490)) ([2397819](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2397819))\n- **drawer:** disable transition animation when placement change ([#4609](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4609)) ([e539096](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e539096)), closes [#4224](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4224)\n- **dropdown:** fix ghost menu with contextmenu ([39487f1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/39487f1)), closes [#3971](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3971) [#4684](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4684)\n- **dropdown:** fix menu group style in dropdown ([d928a8c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d928a8c)), closes [#4505](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4505)\n- **layout:** fix layout demo height style ([bed60ff](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bed60ff)), closes [#4676](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4676)\n- **layout:** fix responsive sider not work ([9f951f8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9f951f8))\n- **menu:** fix menu overflow detection & replace ul with div ([4c8032b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4c8032b)), closes [#3412](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3412) [#4227](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4227) [#3687](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3687)\n- **message:** fix message and notification error in prod ([#4884](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4884)) ([3e2f85d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3e2f85d))\n- **table:** `nzFilters` can is not null ([#4595](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4595)) ([2c26e9f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2c26e9f))\n- **table:** fix table data type ([#4608](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4608)) ([70b1440](https://github.com/NG-ZORRO/ng-zorro-antd/commit/70b1440)), closes [#4593](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4593)\n- **timeline:** fix reverse bug ([#4690](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4690)) ([09bf8f4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/09bf8f4)), closes [#4509](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4509)\n- **transfer:** fix transfer nzTargetKeys property ([#4670](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4670)) ([31089a1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/31089a1)), closes [#4641](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4641) [#4360](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4360) [#4210](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4210)\n- fix github workflow action ([10a772f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/10a772f))\n\n### Chores\n\n- **calendar:** delete deprecated input nzCard ([#4464](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4464)) ([aed2e7d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/aed2e7d))\n- **carousel:** remove vertical api ([#4376](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4376)) ([37aa921](https://github.com/NG-ZORRO/ng-zorro-antd/commit/37aa921))\n- **empty:** remove injection token ([#4465](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4465)) ([cc8018a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cc8018a))\n- **icon:** remove old api ([#4375](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4375)) ([91e52ab](https://github.com/NG-ZORRO/ng-zorro-antd/commit/91e52ab))\n- **message,notification:** remove old injection tokens ([#4404](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4404)) ([f9b0e75](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f9b0e75))\n- **tooltip,popover,popconfirm:** remove component API ([#4390](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4390)) ([f82e8a6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f82e8a6))\n- **tree, tree-select:** remove deprecated API ([#4601](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4601)) ([1ec18e4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1ec18e4))\n- deprecate `NgZorroAntdModule` ([#4519](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4519)) ([1a60f27](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1a60f27))\n\n### Code Refactoring\n\n- **form:** refactor and sync antd v4.0 ([#4679](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4679)) ([a5eda6f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a5eda6f)), closes [#4526](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4526) [#4526](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4526)\n\n### Features\n\n- **breadcrumb:** support indenpendent separator ([#4713](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4713)) ([1f490e9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1f490e9))\n- **collapse:** support nzExpandIconPosition ([#4781](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4781)) ([760512a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/760512a))\n- **date-picker:** add some inputs ([#4843](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4843)) ([af4051e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/af4051e))\n- **date-picker:** support parse input value ([#4833](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4833)) ([6a523ba](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6a523ba)), closes [#4028](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4028) [#3976](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3976) [#2492](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2492) [#4101](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4101)\n- **grid:** support nzFlex and nzGutter array, deprecated nzType ([c4d2694](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c4d2694))\n- **i18n:** support for Armenian ([#4611](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4611)) ([038691f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/038691f))\n- **i18n:** support for Georgian locale ([#4491](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4491)) ([d96ebe0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d96ebe0))\n- **icon:** support add icon in feat modules ([#4711](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4711)) ([0bcd2a9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0bcd2a9))\n- **input:** support textarea with clear icon ([0af9242](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0af9242)), closes [#4623](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4623)\n- **input-number:** support nzPrecisionMode mode ([#4185](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4185)) ([bfe089f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bfe089f)), closes [#4173](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4173)\n- **input-number:** trigger ngModelChange at once ([#4769](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4769)) ([299ba6d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/299ba6d)), closes [#3039](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3039) [#3773](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3773)\n- **menu:** auto nzInlineCollapsed when sider collapsed ([51fbf5e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/51fbf5e)), closes [#4680](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4680)\n- **menu:** menu with nzMatchRouter work with CanDeactivate ([7560563](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7560563)), closes [#4407](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4407)\n- **notification:** add close icon prop ([#4495](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4495)) ([80a0b26](https://github.com/NG-ZORRO/ng-zorro-antd/commit/80a0b26)), closes [#4494](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4494)\n- **pagination:** nzItemRender support prev_5 and next_5 ([#4754](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4754)) ([41c4860](https://github.com/NG-ZORRO/ng-zorro-antd/commit/41c4860))\n- **progress:** support steps ([#4637](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4637)) ([fe8b469](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fe8b469)), closes [#4635](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4635)\n- **progress:** support TemplateRef for nzFormat ([#4598](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4598)) ([edf0e9c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/edf0e9c)), closes [#4596](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4596)\n- **select:** refactor the select to support virutal scroll ([40daee9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/40daee9)), closes [#4585](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4585) [#3497](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3497)\n- **skeleton:** add nz-skeleton-element ([#4859](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4859)) ([8dc2ff3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8dc2ff3))\n- **tabs:** add nzCanDeactivate hook ([#4476](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4476)) ([a533980](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a533980)), closes [#4432](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4432)\n- **tag:** support status colors ([#4628](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4628)) ([aa22c0f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/aa22c0f)), closes [#4622](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4622) [#4413](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4413)\n- **tree-select:** support `nzDropdownClassName` property ([#4552](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4552)) ([df8c125](https://github.com/NG-ZORRO/ng-zorro-antd/commit/df8c125)), closes [#4508](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4508)\n- **typography:** support `nzSuffix` property ([#4629](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4629)) ([ca02a07](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ca02a07)), closes [#4620](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4620)\n- **schematics:** add locale option in 'ng-add' ([#4786](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4786)) ([dcd01cb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dcd01cb))\n- **schematics:** add v9 migration rules for dropdown ([#4466](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4466)) ([aebad87](https://github.com/NG-ZORRO/ng-zorro-antd/commit/aebad87))\n- **schematics:** add v9 migration rules for icon and calendar ([#4467](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4467)) ([3c5d24e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3c5d24e))\n- **schematics:** add v9 migration rules for tooltip-like ([#4402](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4402)) ([313f7b8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/313f7b8))\n\n### Performance Improvements\n\n- **checkbox:** use css empty selector instead of observeContent ([#4761](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4761)) ([da8821a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/da8821a))\n- **input:** improve input-group perf ([7af643b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7af643b)), closes [#3950](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3950)\n- **radio:** refactor radio group data flow ([#4770](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4770)) ([423a382](https://github.com/NG-ZORRO/ng-zorro-antd/commit/423a382))\n\n### BREAKING CHANGES\n\n- **icon:** - `NZ_ICON_DEFAULT_TWOTONE_COLOR` is removed. Use `NzGlobalConfigService` instead.\n\nchore: remove strange file\n\ntest: fix test\n\nfeat: add forRoot\n\ndocs: change doc\n\ndocs: fix icon English doc\n\n- **form:** - `nz-form-extra` is removed. Please use `nzExtra` is `nz-form-control` instead.\n\n* `nz-form-explain` is removed. Please use `nzSuccessTip | nzWarningTip | nzErrorTip | nzValidatingTip` is `nz-form-control` instead.\n\n- refactor(module:form): refactor and sync antd v4.0\n\n- refactor(module:form): refactor test\n\n- refactor(module:form): fix test\n\n- refactor(module:form): refactor form control and remove useless styles\n- **form:** - `nz-form-extra` is removed. Please use `nzExtra` is `nz-form-control` instead.\n\n* `nz-form-explain` is removed. Please use `nzSuccessTip | nzWarningTip | nzErrorTip | nzValidatingTip` is `nz-form-control` instead.\n\n- chore: merge code\n\n- refactor(module:form): sync antd and fix test\n- **input-number:** ngModelChange trigger at once when user typing\n- **pagination:** prev_5 and next_5 is needed when use nzItemRender\n  'pre' typo was corrected to 'prev'\n- **tree, tree-select:** \\* tree\n\n* Removed `[nzDefaultExpandAll]` use `[nzExpandAll]` instead.\n* Removed `[nzDefaultExpandedKeys]` use `[nzExpandedKeys]` instead.\n* Removed `[nzDefaultSelectedKeys]` use `[nzSelectedKeys]` instead.\n* Removed `[nzDefaultCheckedKeys]` use `[nzCheckedKeys]` instead.\n* Removed `(nzOnSearchNode)` use `(nzSearchValueChange)` instead.\n\n- tree-select\n\n* Removed `[nzDefaultExpandedKeys]` use `[nzExpandedKeys]` instead.\n\n- **message,notification:** - `NZ_MESSAGE_CONFIG` is removed. Please use `NzGlobalConfigService` instead.\n\n* `NZ_NOTIFICATION_CONFIG` is removed. Please use `NzGlobalConfigService` instead.\n* `config` method of `NzMessageService` and `NzNotificationService` is removed. Please use `set` method of `NzGlobalConfigService` instead.\n\n- **empty:** - `NZ_DEFAULT_EMPTY_CONTENT` is removed. Please use `NzConfigService` instead.\n- **carousel:** Carousel\n\n* `nzVertical` is removed. Please use 'nzDotPosition' instead.\n\n- Removed deprecated API `NgZorroAntdModule.forRoot()`\n\n- docs: update README.md and getting-started.md\n\n- chore: fix tslint hook\n\n- style: fix lint\n\n- build: fix generate-iframe script\n\n- style: fix lint\n- **icon:** - `i[nz-icon]`: `twoToneColor` `theme` `spin` `iconfont` `type` inputs has been removed, use `nzTwoToneColor` `nzTheme` `nzSpin` `nzIconfont` `nzType` instead.\n\n* `i.anticon` selector has been removed, use `i[nz-icon]` instead.\n\n- **calendar:** `<nz-calendar>` `nzCard` input has been removed, use `nzFullscreen` instead.\n- **tooltip,popover,popconfirm:** `<nz-tooltip>` `<nz-popover>` `<nz-popconfirm>` components has been removed, use its directives instead.\n\n## [8.5.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/8.5.0...8.5.1) (2019-11-18)\n\n### Bug Fixes\n\n- **code-editor:** fix config ([#4436](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4436)) ([5283a32](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5283a32))\n- **core:** add type guard for isNotNil ([#4431](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4431)) ([b3c686c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b3c686c))\n- **drawer:** content overflow when placement is top or bottom ([#4423](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4423)) ([9451de5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9451de5)), closes [#4354](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4354)\n- **tooltip:** fix hiding when hover popover ([#4418](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4418)) ([a6b5901](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a6b5901)), closes [#4417](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4417)\n- **tree-select:** click label behavior is incorrect in strict mode ([#4424](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4424)) ([7a11124](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7a11124)), closes [#4422](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4422)\n\n## [8.5.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/8.4.1...8.5.0) (2019-11-08)\n\n### Bug Fixes\n\n- **auto-complete:** default value not selected ([#4366](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4366)) ([09f1ec6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/09f1ec6)), closes [#4362](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4362)\n- **date-picker:** `nzDefaultOpenValue` not work in time panel ([#4357](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4357)) ([dfa3d39](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dfa3d39)), closes [#4331](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4331)\n- **date-picker:** animation start after overlay open ([#4315](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4315)) ([931fd48](https://github.com/NG-ZORRO/ng-zorro-antd/commit/931fd48))\n- **mention:** unable to select on mobile device ([#4309](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4309)) ([1be6d51](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1be6d51)), closes [#4281](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4281)\n- **modal:** `nzMaskClosable` not working in the confirm mode ([#4347](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4347)) ([475bbc4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/475bbc4)), closes [#4344](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4344)\n- **page-header:** has footer or breadcrumb style bug ([#4363](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4363)) ([dcc7deb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dcc7deb))\n- **pagination:** replace full-width character with half-width ([#4371](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4371)) ([cc3868e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cc3868e))\n- **select:** prevent hidden options from being selected ([#4382](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4382)) ([cf22133](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cf22133)), closes [#4377](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4377) [#4377](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4377)\n- **table:** support nzWidthConfig null undefined value ([#4342](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4342)) ([761e8e0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/761e8e0))\n- **tooltip:** fix not undefined value not updated ([#4392](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4392)) ([2a71c43](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2a71c43))\n- **tooltip:** fix tooltip accessing destroyed view ([#4387](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4387)) ([8e9e6a9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8e9e6a9)), closes [#3875](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3875) [#4317](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4317) [#4386](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4386)\n- **tree-select:** default tags incorrect in strictly mode ([#4368](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4368)) ([a6547a0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a6547a0)), closes [#4364](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4364)\n\n### Features\n\n- **monaco-editor:** support static loading ([#4341](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4341)) ([29f732b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/29f732b))\n- **page-header:** add `nzGhost` property ([#4306](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4306)) ([4c78cca](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4c78cca)), closes [#4303](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4303)\n- **tooltip:** support changing trigger ([#4397](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4397)) ([48d7122](https://github.com/NG-ZORRO/ng-zorro-antd/commit/48d7122)), closes [#4365](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4365)\n\n## [8.4.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/8.4.0...8.4.1) (2019-10-23)\n\n### Bug Fixes\n\n- **core:** fix global config not working in prod mode ([#4325](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4325)) ([cc9308d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cc9308d)), closes [#4319](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4319)\n- **drawer:** fix the HTML structure of the drawer header ([#4311](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4311)) ([5cdd5db](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5cdd5db)), closes [#4304](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4304)\n- **page-header:** fix break change on the style ([#4303](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4303)) ([4c10e5b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4c10e5b))\n- **table:** fix table nzWidth bug without the first column ([#4329](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4329)) ([c6bdf15](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c6bdf15)), closes [#4312](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4312)\n\n## [8.4.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/8.3.1...8.4.0) (2019-10-15)\n\n### Bug Fixes\n\n- **tree:** fix nzHideUnMatched bug ([#4286](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4286)) ([87dd59e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/87dd59e)), closes [#3970](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3970)\n- **tree:** update when property isLeaf is changed ([#4289](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4289)) ([4b90577](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4b90577)), closes [#4037](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4037)\n- **\\*:** fix style error with 3.23.6 ([#4258](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4258)) ([120c5be](https://github.com/NG-ZORRO/ng-zorro-antd/commit/120c5be))\n- **auto-complete:** not emit changes when retype same value while open ([#4215](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4215)) ([21e91e3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/21e91e3))\n- **i18n:** update and add translations for de_DE ([#4239](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4239)) ([f819fad](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f819fad))\n- **pagination:** add space between page size and slash ([#4038](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4038)) ([#4039](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4039)) ([b1bba9e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b1bba9e))\n- **select:** fix select dropdown position error ([#4267](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4267)) ([0ccc62a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0ccc62a)), closes [#3855](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3855)\n- **select:** fix select focus & blur & autoFocus event ([#4270](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4270)) ([c7d90b7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c7d90b7)), closes [#3991](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3991) [#3757](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3757) [#3708](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3708)\n- **select:** fix select input not grow correctly in IE ([#4262](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4262)) ([9be58d9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9be58d9)), closes [#2427](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2427) [#3907](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3907)\n- **select:** fix select scroll bottom not emit with search ([#4272](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4272)) ([e9c5541](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e9c5541)), closes [#3777](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3777)\n- **table:** fix table fixed style when nzData change ([#4274](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4274)) ([b33533c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b33533c)), closes [#4253](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4253)\n- **tag:** nzNoAnimation not working ([#4257](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4257)) ([63f947e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/63f947e)), closes [#4244](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4244)\n- **time-picker:** add null input judgement when using datefns ([#4283](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4283)) ([a05bc02](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a05bc02)), closes [#3854](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3854)\n- **tooltip:** fix properties updated before origin is set ([#4229](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4229)) ([b2b9c13](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b2b9c13)), closes [#4250](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4250)\n- **tooltip:** fix tooltip component not destory ([#4291](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4291)) ([05cbd9f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/05cbd9f)), closes [#4103](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4103)\n\n### Features\n\n- **breadcrumb:** add `nzRouteLabel` property ([#4167](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4167)) ([34a8b0a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/34a8b0a))\n- **cascader:** support option render template ([#4127](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4127)) ([8345c54](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8345c54)), closes [#3699](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3699)\n- **mention:** support for adaptive boundary ([#4263](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4263)) ([812e1c5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/812e1c5)), closes [#4260](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4260)\n- **page-header:** new pageheader style and support avatar ([#4208](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4208)) ([c2fc616](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c2fc616))\n- **select:** support default value not in the option list ([#4261](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4261)) ([51b26b4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/51b26b4)), closes [#3672](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3672) [#4000](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4000)\n- **spin:** support global indicator ([#4221](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4221)) ([a7ecb8b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a7ecb8b)), closes [#2792](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2792)\n- **table:** support extra panel with nz-th-extra selector ([#4278](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4278)) ([4701ee6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4701ee6))\n- **table:** support td break-word display ([#4273](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4273)) ([93ab305](https://github.com/NG-ZORRO/ng-zorro-antd/commit/93ab305))\n- **tree-select:** support `nzCheckStrictly` property ([#4149](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4149)) ([1f8cf1d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1f8cf1d)), closes [#4120](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4120)\n\n### Performance Improvements\n\n- **tree:** change the collapsed of the treeNode to ngIf ([#3947](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3947)) ([cbfc5ed](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cbfc5ed))\n- **typography, tabs:** make the `destroy$` complete when destroy ([#4271](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4271)) ([51f4713](https://github.com/NG-ZORRO/ng-zorro-antd/commit/51f4713))\n\n## [8.3.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/8.3.0...8.3.1) (2019-09-24)\n\n### Bug Fixes\n\n- **affix:** fix affix not working in some browsers ([#4161](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4161)) ([d9bf4af](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d9bf4af)), closes [#4070](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4070)\n- **core:** fix HTML entities highlight error ([#4162](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4162)) ([2665762](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2665762)), closes [#4152](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4152)\n- **date-picker:** optimized interaction by using input box ([#4146](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4146)) ([f0ddb79](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f0ddb79))\n- **i18n:** add fallback mechanism ([#4163](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4163)) ([9f87b77](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9f87b77))\n- **i18n:** added property missing in Arabic ([#4165](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4165)) ([36a5ebb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/36a5ebb))\n- **progress:** fix circle gradient not sorted ([#4178](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4178)) ([7d37b1c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7d37b1c))\n- **select:** fix select compareWith array not work ([#4140](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4140)) ([2b4776d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2b4776d)), closes [#4139](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4139)\n- **steps:** fix progress dot in vertical mode ([#4193](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4193)) ([50b86be](https://github.com/NG-ZORRO/ng-zorro-antd/commit/50b86be)), closes [#4184](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4184)\n- **table:** fix nzWidthConfig conflict with nzWidth ([#4141](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4141)) ([a9900ed](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a9900ed)), closes [#4083](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4083) [#4142](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4142)\n- **time-picker:** place ViewChild decorator on correct f… ([#4156](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4156)) ([b0ed836](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b0ed836))\n\n## [8.3.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/8.2.1...8.3.0) (2019-09-09)\n\n### Bug Fixes\n\n- **cascader:** support falsy value expect for undefined and null ([#4119](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4119)) ([0cb44ac](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0cb44ac)), closes [#4110](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4110)\n- **editor:** fix type any ([#4105](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4105)) ([bd720fb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bd720fb)), closes [#4099](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4099)\n- **i18n:** fix i18n interface and Traditional Chinese ([#4102](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4102)) ([bb9e89f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bb9e89f)), closes [#4080](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4080)\n- **i18n:** fix Russian i18n file ([f267bdd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f267bdd))\n- **i18n:** missing catalan translations added ([#4116](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4116)) ([c530c74](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c530c74))\n- **tabs:** fix selected index not updated ([#4094](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4094)) ([1e76e37](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1e76e37)), closes [#3873](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3873)\n\n### Features\n\n- **\\*:** support global config ([#3613](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3613)) ([6eb041a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6eb041a))\n- **i18n:** support for Romanian locale ([#4068](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4068)) ([207e178](https://github.com/NG-ZORRO/ng-zorro-antd/commit/207e178))\n- **modal:** support for custom close icons ([#4072](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4072)) ([06b895e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/06b895e))\n- **progress:** support nzTooltipPlacement ([#4007](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4007)) ([d6a2968](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d6a2968))\n- **steps:** support navigation type and nzDisable nzSubtitle ([#4064](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4064)) ([272dc98](https://github.com/NG-ZORRO/ng-zorro-antd/commit/272dc98)), closes [#3931](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3931)\n\n### Performance Improvements\n\n- **resizable:** listen document events when resizing start ([#4021](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4021)) ([66afcf0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/66afcf0))\n\n## [8.2.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/8.2.0...8.2.1) (2019-08-26)\n\n### Bug Fixes\n\n- **cascader:** fix column is not dropped in hover mode ([#3916](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3916)) ([906849b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/906849b))\n- **code-editor:** fix destroying error when editor is not initialized ([#4002](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4002)) ([a35fb09](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a35fb09))\n- **code-editor:** remove overflow styles ([#4016](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4016)) ([ab832d9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ab832d9))\n- **descriptions:** fix colspan calcuation in horizontal bordered ([#4014](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4014)) ([345712f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/345712f))\n- **table:** fix border-right of small size and bordered table ([#4027](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4027)) ([a3bd531](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a3bd531))\n- **tabs:** fix tabs still shows when no route is matched ([#4034](https://github.com/NG-ZORRO/ng-zorro-antd/issues/4034)) ([7ca0a52](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7ca0a52))\n\n## [8.2.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/8.1.2...8.2.0) (2019-08-13)\n\n### Bug Fixes\n\n- **badge:** fix init animations ([#3925](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3925)) ([353c95b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/353c95b)), closes [#3686](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3686)\n- **date-picker:** keep the time value while clicking date ([#3911](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3911)) ([9499aec](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9499aec))\n- **date-picker:** open on enter and focus on inner input ([#3804](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3804)) ([3f03ee1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3f03ee1)), closes [#3146](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3146)\n- **date-picker:** sort range picker value when start is after end ([#3956](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3956)) ([117b453](https://github.com/NG-ZORRO/ng-zorro-antd/commit/117b453)), closes [#3940](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3940) [#1642](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1642)\n- **message:** fix container instance not destroyed in HMR ([#3859](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3859)) ([07e86a5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/07e86a5))\n- **table:** fix nzWidthConfig in nzTemplateMode ([#3958](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3958)) ([baab74b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/baab74b)), closes [#3957](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3957)\n- **tooltip:** empty judgement ([#3993](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3993)) ([a853e96](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a853e96)), closes [#3909](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3909)\n\n### Features\n\n- **avatar:** support image load error event ([#3893](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3893)) ([ab4bcbe](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ab4bcbe)), closes [#3223](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3223)\n- **badge:** support nzTitle and nzOffset property ([#3977](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3977)) ([ffb7219](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ffb7219))\n- **code-editor:** add code editor component ([#3706](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3706)) ([df78b2e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/df78b2e))\n- **descriptions:** add nzColon to toggle colon ([#3923](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3923)) ([8e95cb1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8e95cb1))\n- **drawer:** support `nzKeyboard` property ([#3896](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3896)) ([38062fb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/38062fb))\n- **i18n:** support Malay and Tamil language ([#3924](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3924)) ([b87f1fe](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b87f1fe))\n- **page-header:** add default behavior for the back button ([#3891](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3891)) ([41bc285](https://github.com/NG-ZORRO/ng-zorro-antd/commit/41bc285)), closes [#3421](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3421)\n- **resizable:** add resizable component ([#3771](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3771)) ([5e71739](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5e71739)), closes [#3701](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3701)\n- **statistics:** countdown support finish event ([#3902](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3902)) ([9ea40da](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9ea40da))\n- **steps:** support for clickable steps ([#3934](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3934)) ([ac866ce](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ac866ce))\n- **tabs:** add router exact active parameter ([#3862](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3862)) ([6b13faf](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6b13faf)), closes [#3858](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3858)\n- **timeline:** add gray as a default color ([#3922](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3922)) ([f889f34](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f889f34))\n- **schematics:** use the project's style extension ([#3930](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3930)) ([84b0355](https://github.com/NG-ZORRO/ng-zorro-antd/commit/84b0355))\n\n## [8.1.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/8.1.1...8.1.2) (2019-07-29)\n\n### Bug Fixes\n\n- **slider:** change mark style in horizontal mode ([#3879](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3879)) ([e6a6221](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e6a6221)), closes [#3876](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3876)\n- **tree-select:** should not close when the selectable is false ([#3843](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3843)) ([329ec22](https://github.com/NG-ZORRO/ng-zorro-antd/commit/329ec22)), closes [#3833](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3833)\n- **schematics:** fix template files suffix ([#3884](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3884)) ([5b4714f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5b4714f))\n\n## [8.1.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/8.1.0...8.1.1) (2019-07-29)\n\n### Bug Fixes\n\n- **\\*:** import PlatformModule when use platform in component ([#3823](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3823)) ([6ec85a4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6ec85a4))\n- **dropdown:** hide backdrop when disabled and restore escape ([#3831](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3831)) ([b758572](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b758572)), closes [#3835](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3835)\n- **form:** fix form feedback error when init with tips ([#3868](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3868)) ([7c0aa51](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7c0aa51)), closes [#3865](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3865)\n- **select:** fix select with tokenization bug ([#3869](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3869)) ([fa462c7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fa462c7)), closes [#3825](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3825)\n- **table:** fix table small sticky style ([#3849](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3849)) ([c4de8ff](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c4de8ff))\n- **tabs:** fix the pagnation padding-right when scrolling ([#3539](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3539)) ([#3709](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3709)) ([9a4df38](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9a4df38))\n- **tooltip:** fix position change not set back ([#3857](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3857)) ([3dbb6dc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3dbb6dc))\n- **schematics:** fix parse module name error ([#3848](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3848)) ([d4e7210](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d4e7210)), closes [#3844](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3844)\n- **schematics:** update copy-resources script to support Windows path ([#3856](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3856)) ([915b67d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/915b67d))\n\n## [8.1.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/8.0.3...8.1.0) (2019-07-19)\n\n### Bug Fixes\n\n- **date-picker:** missing nzUse12Hours binding ([#3781](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3781)) ([feae069](https://github.com/NG-ZORRO/ng-zorro-antd/commit/feae069))\n- **descriptions:** fix changes to inputs of children not working ([#3798](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3798)) ([3c65697](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3c65697)), closes [#3795](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3795)\n- **descriptions:** fix span calculation ([#3799](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3799)) ([aaa5852](https://github.com/NG-ZORRO/ng-zorro-antd/commit/aaa5852))\n- **message:** fix lazy load problem ([#3797](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3797)) ([679fdea](https://github.com/NG-ZORRO/ng-zorro-antd/commit/679fdea)), closes [#3794](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3794)\n- **modal:** buttons cannot disable when confirm mode ([#3707](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3707)) ([3847250](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3847250)), closes [#3679](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3679)\n- **page-header:** fix page-header style break change ([#3803](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3803)) ([39d1f45](https://github.com/NG-ZORRO/ng-zorro-antd/commit/39d1f45))\n- **select:** fix single selection choice content display issues ([#3802](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3802)) ([4dd93e6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4dd93e6)), closes [#3710](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3710)\n- **table:** fix table header scroll when fixed change ([#3806](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3806)) ([0677540](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0677540))\n- **table:** fix table scrollbar bug ([#3801](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3801)) ([7e00e52](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7e00e52)), closes [#3796](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3796)\n- **tree:** unexpected disappear of tree-node ([#3748](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3748)) ([1ff176e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1ff176e)), closes [#3739](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3739)\n\n### Features\n\n- **dropdown:** allow backdrop to be disabled ([#3769](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3769)) ([cb51069](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cb51069))\n- **i18n:** add locale files ([#3818](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3818)) ([7eac09e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7eac09e))\n- **modal:** support use directive to define the footer ([#3036](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3036)) ([f022a0f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f022a0f)), closes [#3035](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3035)\n- **result:** add component ([#3731](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3731)) ([eb6377e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/eb6377e)), closes [#2759](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2759)\n- **tabs:** support link router ([#3718](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3718)) ([ab8a58c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ab8a58c))\n- **tree-select:** add `[nzHideUnMatched]` property ([#3729](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3729)) ([3a3b33a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3a3b33a)), closes [#3527](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3527)\n\n## [8.0.3](https://github.com/NG-ZORRO/ng-zorro-antd/compare/8.0.2...8.0.3) (2019-07-14)\n\n### Bug Fixes\n\n- **dropdown:** fix dropdown contextmenu ([#3782](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3782)) ([cce920d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cce920d)), closes [#3768](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3768)\n- **input:** fix input disabled OnPush ([#3786](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3786)) ([dd81155](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dd81155)), closes [#3732](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3732)\n- **menu:** fix menu nzMatchRouter in nested menu ([#3785](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3785)) ([eb5d544](https://github.com/NG-ZORRO/ng-zorro-antd/commit/eb5d544)), closes [#3736](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3736)\n- **switch:** fix switch ViewChild static ([#3784](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3784)) ([f59d79f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f59d79f)), closes [#3760](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3760)\n- **table:** fix table custom filter panel ([#3787](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3787)) ([b9a7267](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b9a7267)), closes [#3721](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3721)\n\n## [8.0.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/8.0.1...8.0.2) (2019-07-03)\n\nFix the dependencies version ranges.\n\n## [8.0.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/8.0.0...8.0.1) (2019-07-01)\n\n### Bug Fixes\n\n- **tree:** fix warning bug ([#3692](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3692)) ([637c334](https://github.com/NG-ZORRO/ng-zorro-antd/commit/637c334))\n- **breadcrumb:** fix warning startWith operators ([fe28a0d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fe28a0d))\n- **schematics:** missing routing module in sidemenu template ([#3695](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3695)) ([fdcef82](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fdcef82))\n\n## [8.0.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/7.5.1...8.0.0) (2019-06-29)\n\n### Bug Fixes\n\n- **button:** fix order of DOM nodes in button ([#3578](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3578)) ([c3df8b5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c3df8b5)), closes [#3079](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3079)\n- **card:** fix card tab ng-template ([#3654](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3654)) ([7585ba4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7585ba4))\n- **descriptions:** fix warning without logger ([#3663](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3663)) ([5826fc1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5826fc1))\n- **dropdown:** dropdown should close when set disabled ([0bd1ae3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0bd1ae3)), closes [#3420](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3420)\n- **dropdown:** fix dropdown change after checked bug ([16d5c2d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/16d5c2d))\n- **dropdown:** fix dropdown SSR bug ([#3628](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3628)) ([ade1abd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ade1abd))\n- **form:** fix form control validate with formControl ([bc54e90](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bc54e90)), closes [#3551](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3551)\n- **form:** fix form overlap ([#3633](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3633)) ([0fc7d05](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0fc7d05)), closes [#3607](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3607)\n- **form:** fix nzValidateStatus & nzHasFeedback overlap ([fb4965b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fb4965b)), closes [#3607](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3607)\n- **grid:** Make all properties in EmbeddedProperty optional ([#3473](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3473)) ([107e731](https://github.com/NG-ZORRO/ng-zorro-antd/commit/107e731))\n- **input:** fix ng-content nzAddOnBeforeIcon transclusion ([#3597](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3597)) ([a37ec0a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a37ec0a)), closes [#3596](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3596)\n- **mention:** fix cannot to switch trigger ([#3632](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3632)) ([c8b5b09](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c8b5b09)), closes [#3629](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3629)\n- **menu:** fix menu title ExpressionChangedAfterItHasBeenCheckedError ([52975ff](https://github.com/NG-ZORRO/ng-zorro-antd/commit/52975ff)), closes [#3023](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3023)\n- **menu:** fix submenu not active when collapsed ([67f6fa2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/67f6fa2)), closes [#3345](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3345)\n- **pagination:** fix pagination nzTotal 0 bug ([#3651](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3651)) ([d28fc49](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d28fc49)), closes [#3648](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3648)\n- **select:** fix nzOpen state when nzOnSearch trigger ([3ca816d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3ca816d)), closes [#3626](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3626)\n- **select:** fix select enter open when disabled ([36db36c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/36db36c)), closes [#3408](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3408)\n- **select:** fix the bug of duplication when keyboard input chinese char ([#3440](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3440)) ([3c82f26](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3c82f26)), closes [#3439](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3439)\n- **table:** compatible with @angular/material/table ([79b02ca](https://github.com/NG-ZORRO/ng-zorro-antd/commit/79b02ca))\n- **table:** fix sortChange with dynamic columns ([#3603](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3603)) ([#3605](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3605)) ([c85743d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c85743d))\n- **typography:** fix the actions button order ([#3677](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3677)) ([c2c28a4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c2c28a4))\n- **typography:** not render when the edit text has no changes ([51b9ce0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/51b9ce0))\n\n### Features\n\n- **avatar:** add nzSrcSet & nzAlt properites ([#3583](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3583)) ([d0ad5e8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d0ad5e8)), closes [#3543](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3543)\n- **breadcrumb:** support dropdown ([#3636](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3636)) ([9dfab45](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9dfab45))\n- **carousel:** support dot position ([#3575](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3575)) ([0566331](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0566331))\n- **core:** add universal logger funcs and deprecation warnings ([#3538](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3538)) ([b893520](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b893520))\n- **form:** refactor form to support better template driven ([10d0e28](https://github.com/NG-ZORRO/ng-zorro-antd/commit/10d0e28))\n- **input-number:** support nzId ([a6500c8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a6500c8))\n- **menu:** support auto active menu-item via routerLink ([c9e84c7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c9e84c7))\n- **menu:** support nzTitle & nzIcon in nz-submenu ([0cde4d7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0cde4d7))\n- **pagination:** support pagination nzDisabled ([141bef8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/141bef8))\n- **select:** support custom template in select component ([#3071](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3071)) ([aad02a5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/aad02a5)), closes [#2946](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2946)\n- **table:** support nzVirtualForTrackBy ([cb14096](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cb14096))\n- **transfer:** add nzShowSelectAll & nzRenderList properties ([#3588](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3588)) ([1619f30](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1619f30)), closes [#3567](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3567) [#2870](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2870)\n- **typography:** add typography component ([#3119](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3119)) ([4d739ef](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4d739ef))\n- **schematics:** add template option in `ng-add` ([#3674](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3674)) ([69072de](https://github.com/NG-ZORRO/ng-zorro-antd/commit/69072de))\n\n## [7.5.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/7.4.1...7.5.0) (2019-06-05)\n\n### Bug Fixes\n\n- **cascader:** fix reset trigger redraw ([#3481](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3481)) ([7c0e30c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7c0e30c)), closes [#3480](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3480)\n- **date-picker:** replace DatePipe with formatDate function ([#3500](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3500)) ([19ad7fd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/19ad7fd)), closes [#3487](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3487)\n- **layout:** fix width type ([#3525](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3525)) ([fd803bd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fd803bd))\n- **select:** display error when in tag and search mode ([#3442](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3442)) ([a05f5a5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a05f5a5)), closes [#3424](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3424)\n\n### Features\n\n- **button:** support link type ([#3503](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3503)) ([050f141](https://github.com/NG-ZORRO/ng-zorro-antd/commit/050f141)), closes [#3479](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3479)\n- **carousel:** support custom strategies ([#3501](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3501)) ([a53a43a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a53a43a))\n- **descriptions:** add component ([#3327](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3327)) ([11bf89e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/11bf89e)), closes [#2847](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2847)\n- **drawer:** support pressing ESC to close drawer ([#3488](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3488)) ([2928f84](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2928f84))\n- **dropdown:** support customize icons ([#3517](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3517)) ([4329b51](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4329b51))\n\n## [7.4.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/7.4.0...7.4.1) (2019-05-21)\n\n### Bug Fixes\n\n- **build:** unable to build in production when importing secondary module ([#3266](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3266))\n\n## [7.4.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/7.3.3...7.4.0) (2019-05-19)\n\n### Bug Fixes\n\n- **breadcrumb:** fix input boolean and router event not caught error ([#3185](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3185)) ([fd43ec5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fd43ec5)), closes [#3186](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3186)\n- **carousel:** fix carousel in entry components ([#3367](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3367)) ([9d495fc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9d495fc))\n- **cascader,checkbox,switch,tooltip:** fix memory leak problem ([#3416](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3416)) ([c63849f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c63849f))\n- **drawer:** fix z-index level ([#3405](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3405)) ([663f6c1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/663f6c1)), closes [#3402](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3402)\n- **menu:** submenu should not remain highlighted ([#3455](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3455)) ([fd47605](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fd47605))\n- **modal:** cannot to close in order of overlay opens when using esc ([#3339](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3339)) ([0533c32](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0533c32)), closes [#3338](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3338)\n- **modal:** content not work in confirm mode when the type is component ([#3415](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3415)) ([6458c57](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6458c57)), closes [#3407](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3407)\n- **modal:** should not close when mousedown in the body ([#3400](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3400)) ([82e488a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/82e488a)), closes [#3394](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3394)\n- **progress:** fix stroke color is not updated ([#3445](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3445)) ([80c6ed4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/80c6ed4)), closes [#3441](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3441)\n- **tree,tree-select:** fix the styles of connecting line ([#3385](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3385)) ([f7e9a7c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f7e9a7c)), closes [#3382](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3382)\n\n### Features\n\n- **card:** support setting size ([#3429](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3429)) ([2015021](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2015021))\n- **drawer:** support `nzOnCancel` for service mode ([#3376](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3376)) ([3742eda](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3742eda)), closes [#3372](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3372)\n- **tree-select:** support customized icon ([#3395](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3395)) ([0deda73](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0deda73))\n\n## [7.3.3](https://github.com/NG-ZORRO/ng-zorro-antd/compare/7.3.2...7.3.3) (2019-04-25)\n\n### Bug Fixes\n\n- **auto-complete:** enter-keydown event should not be prevent when the panel is closed ([#3342](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3342)) ([414b428](https://github.com/NG-ZORRO/ng-zorro-antd/commit/414b428)), closes [#3340](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3340)\n- **radio, tab:** Fixed memory leak problem. ([#3354](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3354)) ([7d18fef](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7d18fef))\n- **table:** fix table custom filter icon position & virtual scroll style ([#3365](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3365)) ([6435ee5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6435ee5)), closes [#3357](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3357) [#3348](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3348) [#3359](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3359)\n- **tree-select:** add the public methods ([#3335](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3335)) ([ee6d18b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ee6d18b))\n\n## [7.3.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/7.3.1...7.3.2) (2019-04-22)\n\n### Bug Fixes\n\n- **build:** fix bundling error of components.less ([#3331](https://github.com/NG-ZORRO/ng-zorro-antd/pull/3331)) ([fb19921](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fb19921))\n\n## [7.3.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/7.3.0...7.3.1) (2019-04-22)\n\n### Bug Fixes\n\n- **tree:** fix nodes list to render correctly ([#3326](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3326)) ([6d759a8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d759a8)), closes [#3320](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3320)\n- **select:** fix select search display ([#3324](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3324)) ([d91af03](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d91af03)), closes [#3322](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3322)\n\n## [7.3.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/7.2.0...7.3.0) (2019-04-21)\n\n### Features\n\n- support server-side rendering ([#3295](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3295)) ([2088459](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2088459)), closes [#3222](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3222) [#43](https://github.com/NG-ZORRO/ng-zorro-antd/issues/43) [#2025](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2025) [#2474](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2474)\n- support standalone/secondary entry modules ([#3234](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3234))\n- **modal:** support `nzMask` and `nzMaskClosable` global config ([#3033](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3033)) ([12cac9e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/12cac9e))\n- **tree:** support nzBlockNode ([#3270](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3270)) ([5129f73](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5129f73))\n- **date-picker:** `nzRanges` support callback ([#3304](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3304)) ([a231cb5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a231cb5)), closes [#1629](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1629)\n- **date-picker:** support `nzOnCalendarChange` ([#3169](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3169)) ([4446005](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4446005))\n- **form:** support hide the label colon ([#3136](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3136)) ([663169f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/663169f))\n- **table:** expose CdkVirtualScrollViewport ([#3297](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3297)) ([a942312](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a942312)), closes [#3144](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3144) [#3073](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3073) [#2886](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2886)\n- **table:** support nzLoadingIndicator ([#3299](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3299)) ([1f339b3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1f339b3)), closes [#3008](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3008)\n- **time-picker:** support 12-hour with `nzUse12Hours` ([#3127](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3127)) ([7c52774](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7c52774))\n- **tree, tree-select:** support customize icons ([#2933](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2933)) ([a77f6c9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a77f6c9))\n- **schematics:** enhance component generator ([#3265](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3265)) ([c22eae5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c22eae5))\n\n### Bug Fixes\n\n- **anchor:** fix scroll bar misplacement in target container ([#3242](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3242)) ([37ac541](https://github.com/NG-ZORRO/ng-zorro-antd/commit/37ac541))\n- **drawer:** create focus trap error when `nzVisible` default value is true ([#3203](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3203)) ([327ceca](https://github.com/NG-ZORRO/ng-zorro-antd/commit/327ceca)), closes [#3200](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3200)\n- **dropdown:** fix dropdown expands outside the bounds of the page ([#3289](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3289)) ([47f0aef](https://github.com/NG-ZORRO/ng-zorro-antd/commit/47f0aef)), closes [#3288](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3288)\n- **dropdown:** fix dropdown style conflict with material style ([#3290](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3290)) ([e30a9be](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e30a9be)), closes [#3241](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3241)\n- **dropdown:** fix dropdown ul list-style ([#3284](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3284)) ([2845b57](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2845b57)), closes [#3268](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3268)\n- **form:** fix form control template driven ([#3305](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3305)) ([032d193](https://github.com/NG-ZORRO/ng-zorro-antd/commit/032d193)), closes [#3211](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3211)\n- **i18n:** fix catalan translations ([#3080](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3080)) ([81f917a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/81f917a)), closes [#2569](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2569)\n- **input-number:** blur event can't get correct current value from validation info ([#3315](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3315)) ([ee3d94c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ee3d94c)), closes [#3134](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3134)\n- **modal:** integration problem with select component ([#3245](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3245)) ([3da4b68](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3da4b68)), closes [#3213](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3213)\n- **select:** fix select disable cursor ([#3287](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3287)) ([f5528d9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f5528d9)), closes [#3246](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3246)\n- **select:** fix select not change after option input changes ([#3313](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3313)) ([74d996b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/74d996b)), closes [#3029](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3029)\n- **select:** fix select scroll top trigger ([#3285](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3285)) ([1478e59](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1478e59)), closes [#3258](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3258)\n- **steps:** updateChildrenSteps bug ([#3194](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3194)) ([8198b23](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8198b23)), closes [#3193](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3193)\n- **table:** fix table border in firefox ([#3294](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3294)) ([82407e7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/82407e7)), closes [#3164](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3164)\n- **tree:** duplicated module import ([#3286](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3286)) ([5c8b923](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5c8b923))\n- **tree, tree-select:** fix the key validity check ([#3247](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3247)) ([87f2386](https://github.com/NG-ZORRO/ng-zorro-antd/commit/87f2386)), closes [#3163](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3163)\n- **upload:** fix deprecated icon class property ([#3230](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3230)) ([bc4e7da](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bc4e7da)), closes [#3228](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3228)\n- **rate** click event is stopped ([#3262](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3262)) ([2b4bde4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2b4bde4)), closes [#3252](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3252)\n- **style** fix patch not included ([#3317](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3317)) ([5b02e48](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5b02e48))\n\n## [7.2.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/7.1.0...7.2.0) (2019-03-27)\n\n### Bug Fixes\n\n- **affix:** set correct style of Affix after trigger resize ([#3089](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3089)) ([ff482e0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ff482e0)), closes [#3040](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3040)\n- fix type of some API ([#3166](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3166)) ([c685836](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c685836))\n- **breadcrumb:** fix auto generate not working in lazy modules ([#3174](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3174)) ([4260a40](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4260a40)), closes [#2538](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2538)\n- **dropdown:** fix the style of CDK conflicts ([#3133](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3133)) ([a9cd84d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a9cd84d)), closes [#3075](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3075)\n- **progress:** should not set success when success percent is … ([#3135](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3135)) ([f85c766](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f85c766))\n- **transfer:** fix invalid trigger checked event in blank area ([#3161](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3161)) ([92097b2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/92097b2)), closes [#3160](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3160) [#3159](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3159)\n- **upload:** fix missing remove event when type is drag ([#3114](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3114)) ([2b1fdd9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2b1fdd9)), closes [#3034](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3034) [#3139](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3139) [#3171](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3171)\n\n### Features\n\n- **collapse:** support `nzExtra` ([#3177](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3177)) ([fbfb4da](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fbfb4da))\n- **menu:** support `nzMenuClassName` for the submenu ([#3176](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3176)) ([15b6724](https://github.com/NG-ZORRO/ng-zorro-antd/commit/15b6724))\n- **page-header:** add page-header component ([#2732](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2732)) ([cf51c1f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cf51c1f)), closes [#2710](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2710)\n- **schematics:** do not set boot page when the target file is modified ([#3178](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3178)) ([0a3f62c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0a3f62c))\n\n## [7.1.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/7.0.3...7.1.0) (2019-03-21)\n\n### Bug Fixes\n\n- **tree:** fix nzMultiple and rollback code ([#3060](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3060)) ([c917938](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c917938)), closes [#3076](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3076)\n- **cascader:** fix columns not dropped ([#3037](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3037)) ([72a9e67](https://github.com/NG-ZORRO/ng-zorro-antd/commit/72a9e67)), closes [#3034](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3034)\n- **date-picker:** export `year-picker` component ([#3125](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3125)) ([c5b0af9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c5b0af9))\n- **modal:** integrate with tabs and autosize ([#3065](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3065)) ([4cab26f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4cab26f)), closes [#2286](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2286) [#2713](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2713)\n- **modal:** simple confirm should not have cancel button ([#3115](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3115)) ([f0a2b51](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f0a2b51)), closes [#3107](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3107)\n- **tooltip:** fix tooltip not render after set ([#3091](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3091)) ([2841a2f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2841a2f))\n\n### Features\n\n- **message:** support `nzTop` ([#3047](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3047)) ([351135b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/351135b)), closes [#3041](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3041)\n- **message:** support template ([#3102](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3102)) ([d3f6655](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d3f6655)), closes [#3081](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3081)\n\n## [7.0.3](https://github.com/NG-ZORRO/ng-zorro-antd/compare/7.0.2...7.0.3) (2019-03-14)\n\n### Bug Fixes\n\n- **select:** fix select init touched state error when disabled ([#3084](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3084)) ([ba9d454](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ba9d454)), closes [#3059](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3059)\n\n### Build\n\n- **build:** add strictNullCheck config ([#2126](https://github.com/NG-ZORRO/ng-zorro-antd/pull/2977))\n- **build:** upgrade icon to 2.0.2 ([#3085](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3085)) ([fc72d7d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fc72d7d))\n\n## [7.0.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/7.0.1...7.0.2) (2019-03-11)\n\n### Bug Fixes\n\n- **pagination:** fix pagination bug ([#3067](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3067)) ([f4948d7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f4948d7)), closes [#3049](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3049)\n- **steps:** fix steps state change error under onpus strategy ([#3061](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3061)) ([97adb2c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/97adb2c))\n- **table:** fix table small size virtual scroll style ([#3063](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3063)) ([4fa16de](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4fa16de)), closes [#3050](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3050)\n- **table:** fix th check not trigger bug ([#3064](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3064)) ([dbc33ae](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dbc33ae)), closes [#3028](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3028) [#3056](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3056) [#3058](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3058)\n- **transfer:** fix click checkbox can't trigger selection ([#3030](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3030)) ([f077294](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f077294)), closes [#3026](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3026)\n\n## [7.0.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/7.0.0...7.0.1) (2019-03-04)\n\n### Bug Fixes\n\n- **tree:** fix default keys bug with setTimeOut ([#3003](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3003)) ([050faa0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/050faa0)), closes [#3001](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3001)\n- **tree:** fix expand state bug for tree-select ([#2997](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2997)) ([623a9ff](https://github.com/NG-ZORRO/ng-zorro-antd/commit/623a9ff))\n- **checkbox:** fix checkbox a11y error ([#3009](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3009)) ([42ed317](https://github.com/NG-ZORRO/ng-zorro-antd/commit/42ed317)), closes [#3000](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3000)\n- **fesm2015:** fix fesm2015 build error ([#3015](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3015)) ([e5b388a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e5b388a))\n- **icon:** remove icon test module export ([#3002](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3002)) ([28edb53](https://github.com/NG-ZORRO/ng-zorro-antd/commit/28edb53))\n- **schematics:** fix `add-icon-assets` schema path ([#3005](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3005)) ([5101928](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5101928))\n- **select:** fix select reset in form ([#3017](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3017)) ([30b3d86](https://github.com/NG-ZORRO/ng-zorro-antd/commit/30b3d86)), closes [#3014](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3014)\n- **table:** fix table crash with double binding ([#3007](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3007)) ([a2202b4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a2202b4)), closes [#3004](https://github.com/NG-ZORRO/ng-zorro-antd/issues/3004)\n\n## [7.0.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/7.0.0-rc.3...7.0.0) (2019-02-28)\n\n### Update Guidance\n\n1. Update Angular and other packages to newest versions.\n\n2. Update ng-zorro-antd to 7.0.\n\n**Notice**\n\nPay attention to these changes to ensure that your code works as expected:\n\n1. All components now work with OnPush strategy. Components with this strategy would not respond to mutations on object properties or array child items, even decorated with @Input(). So you should make all your @Input properties immutable objects. Not only this would ensure your code works correctly but also improve performance if you use [immutable objects](https://www.sitepoint.com/immutability-javascript/) right. Please checkout our example below.\n2. We correct the meaning of nzDropdownMatchSelectWidth of Select component. Now it means exactly opposite of the old one.\n3. If you want to add a button to an input-group in search mode, you should use nzAddOnAfter instead of nzSuffix.\n\n### Bug Fixes\n\n- **tree:** fix animation of expand method ([#2989](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2989)) ([5142d18](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5142d18))\n- **tree:** fix remove and clearChildren missing origin ([#2995](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2995)) ([41b0e67](https://github.com/NG-ZORRO/ng-zorro-antd/commit/41b0e67))\n- **tree-select:** fix nzNodes type ([#2992](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2992)) ([c435853](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c435853))\n- **affix:** fix should reset placeholder size when trigger resize event ([#2835](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2835)) ([7068a5e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7068a5e)), closes [#2818](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2818)\n- **all:** move hostbinding to constructor to fix angular transition bug ([#2895](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2895)) ([e39f6bf](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e39f6bf))\n- **anchor:** fix called detectChanges when component destroy ([#2864](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2864)) ([0e5c937](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0e5c937)), closes [#2860](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2860)\n- **cascader:** fix children state not changed in async demo ([#2985](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2985)) ([b87e8bb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b87e8bb)), closes [#2984](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2984)\n- **cascader:** fix empty shown when searching value ([#2906](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2906)) ([89c94ee](https://github.com/NG-ZORRO/ng-zorro-antd/commit/89c94ee)), closes [#2903](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2903)\n- **cascader:** fix searching error when nzOptions is an empty … ([#2846](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2846)) ([e33cc50](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e33cc50)), closes [#2784](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2784)\n- **core:** fix the style of CDK conflicts ([#2917](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2917)) ([37cf6f3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/37cf6f3)), closes [#2874](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2874)\n- **drawer:** ngOnDestory may called before onInit ([#2037](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2037)) ([9bf9299](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9bf9299))\n- **empty:** fix locale cannot change dynamically ([#2866](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2866)) ([2a2fbca](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2a2fbca))\n- **empty:** show no empty when use pass null ([#2768](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2768)) ([48d5333](https://github.com/NG-ZORRO/ng-zorro-antd/commit/48d5333))\n- **grid:** fix grid responsive ([#2915](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2915)) ([ab05619](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ab05619)), closes [#2908](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2908)\n- **i18n:** Danish locale is exported and mentioned in i18n docs ([6554cf5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6554cf5))\n- **input:** fix antd input style change & input password demo ([#2969](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2969)) ([bd03a91](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bd03a91)), closes [#2945](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2945) [#2956](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2956)\n- **radio:** children unable to focus in radio label ([#2850](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2850)) ([58743b8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/58743b8)), closes [#2774](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2774)\n- **select & module:table:** fix table style error & select error ([#2987](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2987)) ([0d6fc9e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0d6fc9e)), closes [#2983](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2983)\n- **slider:** fix defaultValue check error ([#2986](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2986)) ([c3649bc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c3649bc))\n- **switch:** fix switch error when loading or disabled ([#2896](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2896)) ([a67984c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a67984c)), closes [#2787](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2787)\n- **tooltip:** fix setTitle proxy to nzTitle ([#2698](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2698)) ([f6dfbd9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f6dfbd9)), closes [#2695](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2695)\n- **tree:** word misspelling(destory -> destroy) ([#2914](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2914)) ([a7b4e09](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a7b4e09))\n- **tree-select:** fix tree-select overlay's index problem ([#2764](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2764)) ([599ae1a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/599ae1a)), closes [#2730](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2730)\n\n### Features\n\n- **all:** support disable animations in every components ([#2975](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2975)) ([0d7736e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0d7736e)), closes [#2401](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2401) [#2922](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2922)\n- **auto-complete:** close panel when the trigger element blur ([#2916](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2916)) ([1e075f9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1e075f9)), closes [#2885](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2885)\n- **auto-complete,mention,select,tree-select:** prevent loss of focus when the options click ([#2979](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2979)) ([fcaa6d1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fcaa6d1)), closes [#2448](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2448)\n- **calendar:** sync some changes from ant-design ([#2769](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2769)) ([#2963](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2963)) ([35a6f0d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/35a6f0d)), closes [#2796](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2796)\n- **cascader:** reposition cascader when column opens ([#2836](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2836)) ([289ba54](https://github.com/NG-ZORRO/ng-zorro-antd/commit/289ba54)), closes [#2181](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2181) [#2809](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2809)\n- **collapse:** add extra field ([#2923](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2923)) ([dd0cec2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dd0cec2)), closes [#1911](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1911)\n- **collapse:** support custom icon ([#2783](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2783)) ([a530f80](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a530f80))\n- **comment:** add comment component ([#2767](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2767)) ([1d68e44](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1d68e44)), closes [#2731](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2731)\n- **date-picker:** support nzDisabledDate for year-picker ([#2949](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2949)) ([71dda9b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/71dda9b)), closes [#2194](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2194)\n- **empty:** add empty component ([#2722](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2722)) ([8906dff](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8906dff)), closes [#2711](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2711)\n- **i18n:** update missing fields in fr_FR(NG-ZORRO[#2586](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2586)) ([#2737](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2737)) ([c821d56](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c821d56))\n- **icon:** fix falsy render ([#2912](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2912)) ([6dd3cbf](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6dd3cbf)), closes [#2911](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2911)\n- **icon:** support rotate ([#2891](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2891)) ([07f76af](https://github.com/NG-ZORRO/ng-zorro-antd/commit/07f76af)), closes [#2888](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2888)\n- **icon:** update dependency to support namespace ([#2641](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2641)) ([a2000fa](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a2000fa))\n- **input:** fix \\*fix icon new api capability ([#2841](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2841)) ([3c954cb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3c954cb))\n- **layout:** support zeroTrigger ([#2938](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2938)) ([4e4231d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4e4231d)), closes [#1950](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1950) [#1951](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1951)\n- **message,notification:** add close event ([#2952](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2952)) ([f2e45ea](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f2e45ea)), closes [#2458](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2458)\n- **modal:** support set `nzOkDisabled` and `nzCancelDisabled` ([#2856](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2856)) ([fa6a8e9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fa6a8e9)), closes [#1838](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1838)\n- **notification:** support nzData as context in template ([#2926](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2926)) ([51940f7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/51940f7)), closes [#2755](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2755)\n- **popconfirm:** support custom icon ([#2964](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2964)) ([ff030ff](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ff030ff)), closes [#2196](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2196)\n- **rate:** add tooltip support ([#2794](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2794)) ([e121bd3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e121bd3))\n- **slider:** support nzTooltipVisible ([#2930](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2930)) ([d3e61d4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d3e61d4)), closes [#2373](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2373)\n- **statistic:** add statistic and countdown component ([#2760](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2760)) ([abb9ae4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/abb9ae4))\n- **tabs:** support lazy load tabs ([#2968](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2968)) ([626a0f4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/626a0f4)), closes [#2716](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2716)\n- **tree-select:** support set `nzNotFoundContent` ([#2740](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2740)) ([d9055f5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d9055f5))\n- **tree-select:** support set the max count for tags ([#2970](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2970)) ([4081abb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4081abb)), closes [#2488](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2488)\n- **upload:** support with non-image format file preview ([#2709](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2709)) ([4c41715](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4c41715))\n\n## [7.0.0-rc.3](https://github.com/NG-ZORRO/ng-zorro-antd/compare/7.0.0-rc.2...7.0.0-rc.3) (2018-12-26)\n\n### Bug Fixes\n\n- **table:** fix table sticky style ([#2688](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2688)) ([50d4fc4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/50d4fc4))\n- **transfer:** fix the `Not Found` display condition ([#2687](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2687)) ([3df5779](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3df5779)), closes [#2686](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2686)\n\n## [7.0.0-rc.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/7.0.0-rc.1...7.0.0-rc.2) (2018-12-24) [deprecated]\n\n### Bug Fixes\n\n- **input:** fix input autoresize ([#2662](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2662)) ([0621ce8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0621ce8)), closes [#2646](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2646)\n- **layout:** fix sider nzBreakPoint ([#2665](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2665)) ([4fbfccb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4fbfccb)), closes [#2603](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2603)\n- **radio:** fix radio ContentChildren error ([#2660](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2660)) ([36b2099](https://github.com/NG-ZORRO/ng-zorro-antd/commit/36b2099)), closes [#2206](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2206) [#2611](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2611)\n- **tabs:** fix tabs style error ([#2673](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2673)) ([458c062](https://github.com/NG-ZORRO/ng-zorro-antd/commit/458c062))\n\n### Features\n\n- **autocomplete,dropdown:** add class & style properties in overlay panel ([#2639](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2639)) ([b7f41f8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b7f41f8)), closes [#2634](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2634)\n- **i18n:** add Slovenian support, ICU locale sl_SI, [#2545](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2545) ([#2652](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2652)) ([d0b9a2a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d0b9a2a))\n- make the doc website a pwa ([#2661](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2661)) ([4f48ecd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4f48ecd))\n\n## [7.0.0-rc.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/7.0.0-rc.0...7.0.0-rc.1) (2018-12-12)\n\n### Bug Fixes\n\n- **drawer, modal:** fix focus bug of IE ([#2589](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2589)) ([0458604](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0458604)), closes [#2388](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2388)\n- **collapse:** fix collapse ([#2597](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2597)) ([5bb1a99](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5bb1a99)), closes [#2567](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2567)\n- **icon:** add missing icons used by ng-zorro-ant itself ([ef10595](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ef10595))\n- **select:** add title property for select component ([#2575](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2575)) ([3444634](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3444634)), closes [#1974](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1974)\n- **table:** should prevent tr click trigger when clicking expand ([#2618](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2618)) ([88be1c3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/88be1c3)), closes [#2419](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2419)\n- **schematics:** compatible with old version options ([#2622](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2622)) ([bb1489b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bb1489b))\n\n### Features\n\n- **tabs:** support forceRender in tabs ([#2619](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2619)) ([fa9160c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fa9160c))\n- **upload:** support Observable in nzFilter ([#2590](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2590)) ([c664c6f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c664c6f)), closes [#2389](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2389)\n\n## [7.0.0-rc.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/1.8.0...7.0.0-rc.0) (2018-11-30)\n\n### Bug Fixes\n\n- **menu:** fix dropdown menu item selected className ([#2434](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2434)) ([acbe5da](https://github.com/NG-ZORRO/ng-zorro-antd/commit/acbe5da)), closes [#2433](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2433)\n- **menu:** fix fold menu ([#2454](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2454)) ([f228013](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f228013)), closes [#2449](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2449)\n- **timeline:** fix loading icon ([#2386](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2386)) ([cebfff7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cebfff7)), closes [#2377](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2377)\n- **readme:** fix misspelling ([#2472](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2472)) ([e5535d2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e5535d2))\n\n### Features\n\n- Adds danish locale ([#2486](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2486)) ([1c7f983](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1c7f983)), closes [#2485](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2485)\n- **avatar:** support custom size ([#2416](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2416)) ([0bf8a36](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0bf8a36)), closes [#2380](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2380)\n- **drawer:** add input property in NzDrawerRef ([#2464](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2464)) ([9565cd5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9565cd5)), closes [#2403](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2403)\n- **modal:** support clicking ESC to close modal ([#2483](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2483)) ([c72f431](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c72f431)), closes [#1999](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1999)\n- **progress:** support custom strokeColor and strokeLinecap ([#2404](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2404)) ([167a110](https://github.com/NG-ZORRO/ng-zorro-antd/commit/167a110)), closes [#2378](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2378)\n\n## [1.8.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/1.8.0...1.8.1) (2018-11-24)\n\n### Bug Fixes\n\n- **collapse:** can't fold up active panel with accordion ([#2440](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2440)) ([a17ea49](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a17ea49)), closes [#2437](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2437)\n- **list:** fix invalid render empty style when unspecified data source ([#2415](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2415)) ([7ae325f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7ae325f)), closes [#2385](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2385)\n- **menu:** fix dropdown menu item selected className ([#2434](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2434)) ([e6e2369](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e6e2369)), closes [#2433](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2433)\n- **menu:** fix fold menu ([#2454](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2454)) ([e41640a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e41640a)), closes [#2449](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2449)\n\n### Features\n\n- Adds danish locale ([#2486](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2486)) ([811a009](https://github.com/NG-ZORRO/ng-zorro-antd/commit/811a009)), closes [#2485](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2485)\n\n## [1.8.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/1.7.1...1.8.0) (2018-10-26)\n\n### Bug Fixes\n\n- **calendar:** fix calendar year picker ([#2355](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2355)) ([a4a948c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a4a948c)), closes [#2351](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2351)\n- **esm5:** fix esm5 package ([#2357](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2357)) ([e06b9a7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e06b9a7)), closes [#2339](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2339)\n- **layout:** fix layout init breakpoint nzCollapsed value ([#2350](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2350)) ([8f58fae](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8f58fae)), closes [#2343](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2343)\n- **menu:** fix menu level 4 padding error ([#2356](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2356)) ([7906066](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7906066)), closes [#2327](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2327)\n- **spin:** fix spin hang error with submenu ([#2352](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2352)) ([65fc10a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/65fc10a)), closes [#2346](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2346)\n- **tree:** fix icon to svg & draggable event listener ([#2338](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2338)) ([8bc488e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8bc488e)), closes [#2332](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2332) [#2205](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2205) [#2336](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2336)\n- **tree-select:** can't work default values in OnPush mode ([#2364](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2364)) ([04cf7aa](https://github.com/NG-ZORRO/ng-zorro-antd/commit/04cf7aa)), closes [#2318](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2318) [#2085](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2085)\n\n### Features\n\n- **icon:** add injectiontoken config and default twotone color ([#2353](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2353)) ([bea1d05](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bea1d05))\n- **list:** list empty style ([#2365](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2365)) ([e2d09a0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e2d09a0)), closes [#2362](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2362)\n\n### Performance Improvements\n\n- **upload:** optimize invalid parameter warning ([#2363](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2363)) ([ee31a4e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ee31a4e)), closes [#2322](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2322)\n\n## [1.7.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/1.7.0...1.7.1) (2018-10-23)\n\n### Bug Fixes\n\n- **drawer:** style error when the unit is percentage ([#2334](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2334)) ([9e07702](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9e07702)), closes [#2333](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2333)\n- **icon:** fix icon miss in components ([#2321](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2321)) ([af4ddfb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/af4ddfb)), closes [#2326](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2326)\n- **icon:** fix icons problems ([#2325](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2325)) ([8a0d412](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8a0d412))\n- **schematics:** fix object comparisons method ([#2328](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2328)) ([a7beda8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a7beda8))\n\n## [1.7.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/1.6.0...1.7.0) (2018-10-18)\n\n### Bug Fixes\n\n- **tabs:** hide next and prev buttons when nzTabPosition is left or right ([#2239](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2239)) ([3bb8be5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3bb8be5))\n- **breadcrumb:** navigate within angular ([#2283](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2283)) ([0c41306](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0c41306)), closes [#2254](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2254)\n- **button:** fix button loading bug ([#2251](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2251)) ([cb71e9b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cb71e9b)), closes [#2191](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2191)\n- **cascader:** fix error when nzOptions change and in search mode ([#2241](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2241)) ([c3c2d26](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c3c2d26)), closes [#2105](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2105)\n- **cascader:** fix support to nzLabelProperty ([#2231](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2231)) ([37523c8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/37523c8)), closes [#2103](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2103)\n- **date-picker:** fix the calendar not shown up when click on the icon ([#2235](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2235)) ([8ffcfac](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8ffcfac)), closes [#2221](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2221)\n- **date-picker:** use fixed width when \"nzShowTime\" settled for picker ([#2236](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2236)) ([463a14c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/463a14c))\n- **icon:** fix broken icons ([#2248](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2248)) ([e0d9987](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e0d9987))\n- **icon:** fix icon classname writeback ([#2259](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2259)) ([c6337c2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c6337c2))\n- **list:** fix does not trigger change detection correctly when from empty array to data array ([#2199](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2199)) ([92c1a85](https://github.com/NG-ZORRO/ng-zorro-antd/commit/92c1a85))\n- **select:** fix space closing select panel ([#2240](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2240)) ([3d7fe39](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3d7fe39)), closes [#2201](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2201)\n- **select,tree-select:** prevent pop the dropdown when click remove ([#2290](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2290)) ([4fa9367](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4fa9367)), closes [#2276](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2276)\n- **spin:** fix cdk change detection ([#2255](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2255)) ([25671b6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/25671b6)), closes [#1819](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1819)\n- **table:** fix filter table header in ant design 3.10 ([#2260](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2260)) ([ebf151a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ebf151a))\n- **upload:** fix only allow type is picture or picture-card generate thumbnail ([#2219](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2219)) ([8306111](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8306111)), closes [#2216](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2216)\n\n### Features\n\n- **icon:** switch to SVG icons ([#2171](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2171)) ([7bdb79b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7bdb79b))\n- **modal:** auto focus when open and restore focus when close ([#2188](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2188)) ([7c0ced4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7c0ced4)), closes [#2124](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2124)\n- **schematics:** add fix icon schematic ([#2238](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2238)) ([8861beb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8861beb))\n\n## [1.6.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/1.5.0...1.6.0) (2018-09-22)\n\n### Bug Fixes\n\n- **date-picker:** fix year-picker and month-picker style error within compacted input group ([#2136](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2136)) ([049212f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/049212f))\n- **calendar:** fix calendar year list ([#2140](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2140)) ([e485d02](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e485d02)), closes [#2091](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2091)\n- **cascader:** search correctly when a root node is a leaf node ([#2108](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2108)) ([28556e4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/28556e4)), closes [#2104](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2104)\n- **drawer:** drawer content cannot scroll ([#2120](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2120)) ([e8dad8f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e8dad8f)), closes [#2119](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2119)\n- **steps:** fix dynamic steps error ([#2149](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2149)) ([ee3fa7e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ee3fa7e)), closes [#2148](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2148)\n- **publish:** add version number validation and rename script ([#2117](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2117)) ([bc1f6fa](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bc1f6fa))\n- **schematics:** compatibility with Angular CLI 6.2.0 ([#2131](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2131)) ([ac428db](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ac428db))\n- **test:** fix test coverage dependency ([#2146](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2146)) ([310771f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/310771f))\n- **upload:** fix typo ([#2173](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2173)) ([69c5210](https://github.com/NG-ZORRO/ng-zorro-antd/commit/69c5210))\n\n### Features\n\n- **drawer:** support service to create drawer ([#1981](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1981)) ([a232d59](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a232d59)), closes [#1937](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1937)\n- **upload:** add directory support ([#2164](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2164)) ([3ef8bcf](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3ef8bcf)), closes [#2167](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2167) [#2154](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2154)\n- **tree:** support more functions & property ([#2121](https://github.com/NG-ZORRO/ng-zorro-antd/pull/2121))\n- **skeleton:** add skeleton component ([#1829](https://github.com/NG-ZORRO/ng-zorro-antd/pull/1829))\n\n### Build\n\n- **build:** use ng-packagr to generate library ([#2126](https://github.com/NG-ZORRO/ng-zorro-antd/pull/2126))\n\n### Performance Improvements\n\n- **table:** improve table performance ([#2157](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2157)) ([cde5fb0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cde5fb0))\n\n## [1.5.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/1.4.1...1.5.0) (2018-09-09)\n\n### Bug Fixes\n\n- **drawer:** provide custom scroll strategy ([#2095](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2095)) ([b993068](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b993068)), closes [#2070](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2070)\n- **modal:** fix generic type of the \"nzComponentParams\" for user to gain more type intellisense ([#1812](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1812)) ([6ef1185](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6ef1185))\n\n### Features\n\n- **breadcrumb:** support auto generated breadcrumb ([#2050](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2050)) ([64d191c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/64d191c)), closes [#2001](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2001)\n- **button:** support block style ([#2051](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2051)) ([2858ba1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2858ba1)), closes [#2047](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2047)\n- **drawer:** support top and bottom placement ([#2039](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2039)) ([693b4eb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/693b4eb)), closes [#2015](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2015)\n- **modal:** support customized modal config (current \"autoBodyPadding\") ([#2006](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2006)) ([1d5e06c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1d5e06c)), closes [#1720](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1720)\n- **select:** support open and close panel via keyboard ([#2038](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2038)) ([b2ea96a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b2ea96a)), closes [#1909](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1909)\n- **steps:** support customized starting index ([#2021](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2021)) ([bc7bf17](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bc7bf17)), closes [#1994](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1994)\n- **publish:** add publish script ([#1979](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1979)) ([98cb651](https://github.com/NG-ZORRO/ng-zorro-antd/commit/98cb651)), closes [#1925](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1925)\n\n## [1.4.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/1.4.0...1.4.1) (2018-09-02)\n\n### Bug Fixes\n\n- **auto-complete:** can't select option when touch ([#2054](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2054)) ([2e8e63d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2e8e63d)), closes [#2053](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2053)\n- **modal:** close modal itself before destructing by the angular's lifecycle ([#1769](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1769)) ([075c7a4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/075c7a4)), closes [#1663](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1663)\n- **pagination:** take minimum of page range and total ([#2046](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2046)) ([30bccd1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/30bccd1)), closes [#2036](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2036)\n- **table:** fix row spaces ([#2061](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2061)) ([cb34983](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cb34983)), closes [#2059](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2059)\n- **tree-select:** unable close when used OnPush ([#2028](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2028)) ([fb83354](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fb83354)), closes [#2012](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2012)\n\n## [1.4.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/1.3.0...1.4.0) (2018-08-19)\n\n### Bug Fixes\n\n- **avatar:** tolerate error src ([#2008](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2008)) ([d55cdf2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d55cdf2))\n- **carousel:** carousel on desktop can't slide images ([#1970](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1970)) ([02a84a9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/02a84a9))\n- **cascader:** fix dynamic loading error ([#1931](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1931)) ([d4d24fb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d4d24fb)), closes [#1927](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1927)\n- **cascader:** should not change on hover work ([#1991](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1991)) ([577ae47](https://github.com/NG-ZORRO/ng-zorro-antd/commit/577ae47)), closes [#1966](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1966)\n- **select:** fix input not blur after user hits enter key ([#1943](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1943)) ([a64d04c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a64d04c)), closes [#1940](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1940)\n- **tooltip,popconfirm,popover:** not create element when use directive ([#1968](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1968)) ([fa40145](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fa40145)), closes [#1967](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1967)\n- **tree-select:** update selected nodes when after set nodes ([#1946](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1946)) ([cd928e1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cd928e1)), closes [#1934](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1934)\n- **tree:** fix loading style ([#1942](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1942)) ([19fc2ee](https://github.com/NG-ZORRO/ng-zorro-antd/commit/19fc2ee))\n\n### Features\n\n- **modal:** smart to determine whether to add padding-right ([#1877](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1877)) ([a5d631d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a5d631d)), closes [#1422](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1422)\n- **timeline:** custom circle color ([#1959](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1959)) ([fb3daa1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fb3daa1)), closes [#1956](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1956)\n\n## [1.3.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/1.2.0...1.3.0) (2018-08-03)\n\n### Bug Fixes\n\n- **auto-complete:** reposition when open the first time ([#1863](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1863)) ([c80bc8d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c80bc8d)), closes [#1840](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1840)\n- **date-picker:** restrict the date when it overflows at the month panel ([#1903](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1903)) ([3c654a5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3c654a5)), closes [#1899](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1899)\n\n### Features\n\n- **cascader:** add cascader search ([#1873](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1873)) ([633bc87](https://github.com/NG-ZORRO/ng-zorro-antd/commit/633bc87)), closes [#1773](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1773)\n- **date-picker:** refactoring and add new feature of year-picker ([#1906](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1906)) ([f1f5625](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f1f5625)), closes [#416](https://github.com/NG-ZORRO/ng-zorro-antd/issues/416)\n- **drawer:** add drawer component ([#1789](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1789)) ([33aff47](https://github.com/NG-ZORRO/ng-zorro-antd/commit/33aff47)), closes [#1565](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1565)\n- **radio:** add solid button style ([#1892](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1892)) ([945a924](https://github.com/NG-ZORRO/ng-zorro-antd/commit/945a924)), closes [#1891](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1891)\n- **table:** support default filter ([#1893](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1893)) ([cea0e51](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cea0e51)), closes [#1872](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1872)\n\n## [1.2.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/1.1.1...1.2.0) (2018-07-22)\n\n### Bug Fixes\n\n- **carousel:** resize content after window resized ([#1815](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1815)) ([1e0a029](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1e0a029)), closes [#1811](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1811)\n- **input-number:** NzAutoFocus doesn't work or work as expected ([#1833](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1833)) ([739b353](https://github.com/NG-ZORRO/ng-zorro-antd/commit/739b353)), closes [#1706](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1706)\n- **tree:** sync checked node status and push to checkedNodeList ([#1809](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1809)) ([5305723](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5305723)), closes [#1802](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1802)\n- **input:** mix using addon and affix ([#1857](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1857)) ([ca2d7e0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ca2d7e0)), closes [#1795](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1795)\n- **input-number:** fix touched event ([#1858](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1858)) ([7c90a72](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7c90a72)), closes [#1785](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1785)\n- **tabs:** prevent focus cause scroll offset ([#1845](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1845)) ([bbcb0de](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bbcb0de)), closes [#1821](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1821)\n- **upload:** fix parameter value muse be a function or boolean in nzRemove ([#1851](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1851)) ([3532bbe](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3532bbe)), closes [#1850](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1850)\n\n### Features\n\n- **carousel:** add swipe gesture support ([#1856](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1856)) ([bb5bdd3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bb5bdd3)), closes [#1816](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1816)\n- **carousel:** support dot render template ([#1860](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1860)) ([c1f15b6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c1f15b6)), closes [#1743](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1743)\n- **form:** support touched status update ([#1861](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1861)) ([27ca5bc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/27ca5bc)), closes [#1665](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1665)\n- **tree-select:** support custom display in the trigger ([#1832](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1832)) ([1cc3646](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1cc3646)), closes [#1823](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1823)\n\n## [1.1.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/1.1.0...1.1.1) (2018-07-02)\n\n### Bug Fixes\n\n- **tree:** fix disabled node status & doc ([#1737](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1737)) ([92675e4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/92675e4)), closes [#1721](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1721)\n- **auto-complete, mention, tree-select:** update cdk overlay positioning strategy ([#1761](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1761)) ([82af2ff](https://github.com/NG-ZORRO/ng-zorro-antd/commit/82af2ff)), closes [#1756](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1756)\n- **date-picker:** support changing language at runtime ([#1768](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1768)) ([9caabb5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9caabb5)), closes [#1717](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1717)\n- **list:** fix loading style misplacement of spin ([#1767](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1767)) ([336cc08](https://github.com/NG-ZORRO/ng-zorro-antd/commit/336cc08)), closes [#1739](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1739)\n- **radio:** fix radio disabled bug in group ([#1746](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1746)) ([86fc773](https://github.com/NG-ZORRO/ng-zorro-antd/commit/86fc773)), closes [#1734](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1734)\n- **radio:** fix radio in reactive form ([#1748](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1748)) ([b7a831d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b7a831d)), closes [#1735](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1735)\n- **select:** trigger keyboard on ios ([#1653](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1653)) ([#1751](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1751)) ([89d05f9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/89d05f9)), closes [#1752](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1752) [#1274](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1274)\n- **transfer:** fix title dislocation when form-item layout ([#1745](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1745)) ([4005c7c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4005c7c)), closes [#1732](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1732)\n- **tree-select:** fix unable to set null ([#1760](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1760)) ([689f8b4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/689f8b4)), closes [#1740](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1740)\n- **tree-select:** width is 0 when trigger element is invisible ([#1775](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1775)) ([4eb039a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4eb039a)), closes [#1772](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1772)\n- **table:** fix selector error ([#1742](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1742)) ([aeb485f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/aeb485f)), closes [#1736](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1736)\n\n### Features\n\n- **carousel:** support autoplay speed ([#1741](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1741)) ([a516949](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a516949)), closes [#1711](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1711)\n\n## [1.1.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/1.0.0...1.1.0) (2018-06-25)\n\n### Bug Fixes\n\n- **cascader:** fix custom render with nzClear ([#1676](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1676)) ([c683bc3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c683bc3)), closes [#1646](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1646)\n- **autocomplete:** AOT compiler requires public properties ([#1686](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1686)) ([a1f326d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a1f326d)), closes [#1683](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1683)\n- **card:** fix card loading style ([#1696](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1696)) ([70cb591](https://github.com/NG-ZORRO/ng-zorro-antd/commit/70cb591)), closes [#1695](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1695)\n- **date-picker:** fix date display of the end part is not as expected ([#1709](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1709)) ([b1a1235](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b1a1235)), closes [#1693](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1693)\n- **nz-alert:** emit close after fade animation is done ([#1667](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1667)) ([6b31ca3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6b31ca3)), closes [#1666](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1666)\n- **select:** move select ovarlay to the last of container ([#1673](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1673)) ([442e3f3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/442e3f3)), closes [#1672](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1672) [#1643](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1643)\n- **th:** fix table th filter & style bug ([#1674](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1674)) ([1a4332a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1a4332a)), closes [#1671](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1671) [#1660](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1660)\n- **tree-select:** position error when in the modal-box ([#1687](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1687)) ([43910f9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/43910f9)), closes [#1681](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1681)\n- **ng-add:** remove compiled css from styles when use custom theme ([#1655](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1655)) ([fc67ce5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fc67ce5))\n- **showcase:** use differenceInCalendarDays to do judgement with days for date-picker's demo ([#1648](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1648)) ([7d593e6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7d593e6))\n\n### Features\n\n- **table:** support nzSimple option ([#1699](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1699)) ([4868c41](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4868c41)), closes [#1599](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1599)\n\n## [1.0.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.7.1...1.0.0) (2018-06-11)\n\n### Bug Fixes\n\n- **tree:** fix nzOnSearchChange & folder tree demo ([#1602](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1602)) ([b8e4432](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b8e4432)), closes [#1601](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1601)\n- **tree:** support custom property ([#1584](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1584)) ([1ca696a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1ca696a)), closes [#1580](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1580)\n- **checkbox:** fix invalid setting width via style ([#1577](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1577)) ([ec4be6b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ec4be6b)), closes [#1359](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1359)\n- **modal:** fix multiple nzOnCancel calls ([#1590](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1590)) ([bc07be2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bc07be2)), closes [#958](https://github.com/NG-ZORRO/ng-zorro-antd/issues/958)\n- **modal:** miss returned value from nzOnOk or nzOnCancel ([#1456](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1456)) ([9d6e93b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9d6e93b))\n- **pagination:** fix still show when total is 0 and nzHideOnSinglePage is true ([#1583](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1583)) ([c5c33d0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c5c33d0))\n- **popover:** fix popover nzTemplate value ([#1608](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1608)) ([7cf6ee1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7cf6ee1))\n- **radio:** fix nzDisabled in radio-group ([#1574](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1574)) ([024c488](https://github.com/NG-ZORRO/ng-zorro-antd/commit/024c488)), closes [#1543](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1543)\n- **spin:** fix spin error in antd 3.6.1 ([#1607](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1607)) ([8a1a9ca](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8a1a9ca))\n- **transfer:** fix TransferItem type to work with strictNullChecks ([#1589](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1589)) ([7601af1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7601af1)), closes [#1588](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1588)\n- **ng-add:** duplicate add bugs ([#1623](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1623)) ([214a00d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/214a00d))\n- **ng-add:** fix import path in theme file ([#1611](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1611)) ([aa953dc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/aa953dc))\n\n### Features\n\n- **tree:** sync ant style & add dir demo ([#1559](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1559)) ([0fbf135](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0fbf135))\n- **table:** add nzHideOnSinglePage property ([#1585](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1585)) ([3bc2e90](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3bc2e90))\n- **schematic:** support ng add & ng generate ([#1430](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1430)) ([9ed3590](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9ed3590)), closes [#1405](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1405)\n\n## [0.7.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.7.0...0.7.1) (2018-05-24)\n\n### Bug Fixes\n\n- **tab:** fix vertical-bar error in docs ([#1499](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1499)) ([e5d5860](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e5d5860))\n- **autocomplete:** form related bugs ([#1451](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1451)) ([c91a0f8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c91a0f8)), closes [#1437](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1437)\n- **date-picker:** improve the horizontal position adaptability ([#1495](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1495)) ([64f5ce5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/64f5ce5)), closes [#1450](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1450)\n- **input-number:** fix focused style could not be removed after blur ([#1453](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1453)) ([80a559f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/80a559f)), closes [#1449](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1449)\n- **menu:** fix menu ngfor bug ([#1519](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1519)) ([4f6c266](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4f6c266))\n- **message:** increase the overlay's zindex tobe the same with… ([#1461](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1461)) ([5a51344](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5a51344)), closes [#1457](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1457)\n- **popconfirm:** add nzOkType support ([#1492](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1492)) ([6f394a4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6f394a4)), closes [#1312](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1312)\n- **sider:** fix typo - isSiderTrgger to isSiderTrigger ([#1434](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1434)) ([f1f26ad](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f1f26ad))\n\n### Features\n\n- **input-number:** support input-number placeholder ([#1512](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1512)) ([7e3d4e4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7e3d4e4))\n- **autocomplete:** support bind any types to the nzModule of trigger element ([#1397](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1397)) ([b44296e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b44296e)), closes [#1298](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1298)\n- **switch:** support fully control by user ([#1514](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1514)) ([70ca8bd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/70ca8bd))\n\n## [0.7.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.7.0-beta.5...0.7.0) (2018-05-15)\n\n### Bug Fixes\n\n- **tree:** fix wrong checked nodes ([#1425](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1425)) ([5a06694](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5a06694)), closes [#1423](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1423)\n- **autocomplete:** fix styles ([#1393](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1393)) ([5ad0452](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5ad0452)), closes [#1384](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1384)\n- **steps:** fix steps ngfor ([#1421](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1421)) ([35da659](https://github.com/NG-ZORRO/ng-zorro-antd/commit/35da659)), closes [#1418](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1418)\n\n## [0.7.0-beta.5](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.7.0-beta.4...0.7.0-beta.5) (2018-05-01)\n\n### Bug Fixes\n\n- **input-number:** fix display value after formatter changed ([#1371](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1371)) ([179c1e2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/179c1e2))\n- **upload:** fix ngModel was changed to nzPercent in nz-progress ([#1320](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1320)) ([9b7336e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9b7336e)), closes [#1209](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1209)\n\n### Features\n\n- **time-picker:** support null value in time-picker-panel ([#1388](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1388)) ([1ca1490](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1ca1490))\n\n## [0.7.0-beta.4](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.7.0-beta.3...0.7.0-beta.4) (2018-04-12)\n\n### Bug Fixes\n\n- **tree:** add origin param to NzTreeNode ([#1221](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1221)) ([c9686ca](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c9686ca))\n- **card:** fix avatar and detail alignment ([#1255](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1255)) ([6b13ce0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6b13ce0))\n- **carousel:** fix carousel autoplay bug ([#1309](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1309)) ([dd3265d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dd3265d)), closes [#1242](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1242)\n- **i18n:** fix i18n error without locale ([#1220](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1220)) ([880f0e8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/880f0e8))\n- **mention:** getMention method should kepp the mention prefix ([#1287](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1287)) ([7925f48](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7925f48))\n- **menu:** fix menu ExpressionChangedAfterItHasBeenCheckedError ([#1306](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1306)) ([e63668d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e63668d)), closes [#1216](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1216)\n- **docs:** change the homepage url of angular.cn ([#1289](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1289)) ([471e064](https://github.com/NG-ZORRO/ng-zorro-antd/commit/471e064))\n- **message,notification:** fix message/notification cause multi-detection error while used in dynamic creating component ([#1218](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1218)) ([f2624cb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f2624cb)), closes [#391](https://github.com/NG-ZORRO/ng-zorro-antd/issues/391)\n- **select:** fix select zero value & scroll bug ([#1299](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1299)) ([0552141](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0552141)), closes [#1229](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1229) [#1245](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1245)\n- **table:** fix scrollbar calc ([#1315](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1315)) ([0416900](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0416900)), closes [#1205](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1205)\n- **table:** fix table th filter style ([#1300](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1300)) ([29c559a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/29c559a)), closes [#1238](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1238)\n- **tag:** fix default color when empty color values ([#1256](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1256)) ([ba3a323](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ba3a323))\n- **transfer:** removed change detection ([#1260](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1260)) ([d507848](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d507848)), closes [#996](https://github.com/NG-ZORRO/ng-zorro-antd/issues/996)\n\n### Features\n\n- **mention:** add mention component ([#1182](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1182)) ([e28c1b5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e28c1b5))\n- **mention:** add prefix property to nzOnSearchChange payload ([#1296](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1296)) ([1af5b42](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1af5b42))\n\n## [0.7.0-beta.3](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.7.0-beta.1...0.7.0-beta.3) (2018-03-26)\n\n### Bug Fixes\n\n- **i18n:** fix doc ([#1186](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1186)) ([4ba77c2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4ba77c2))\n- **card:** fix card style ([#1194](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1194)) ([ad80297](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ad80297)), closes [#1191](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1191)\n- **form:** fix form init style miss & fix doc ([#1174](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1174)) ([ab37862](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ab37862)), closes [#1170](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1170) [#1173](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1173)\n- **input:** fix input disable style in reactive form ([#1167](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1167)) ([5c07161](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5c07161))\n- **table & i18n:** fix table style & export i18n interface ([#1163](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1163)) ([fdd03d7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fdd03d7))\n\n### Features\n\n- **modal:** add afterOpen/afterClose/afterAllClose/closeAll/openModals, adjust the boolean props and changeBodyOverflow and complete testing. ([#1165](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1165)) ([10227b8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/10227b8)), closes [#1155](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1155) [#1162](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1162)\n- **modal:** support triggerOk/triggerCancel to trigger nzOnOk/nzOnCancel manually ([#1201](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1201)) ([8cc016e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8cc016e))\n\n## [0.7.0-beta.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.6.10...0.7.0-beta.1) (2018-03-15)\n\n### Bug Fixes\n\n- **back-top:** fix style ([#1125](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1125)) ([60fe850](https://github.com/NG-ZORRO/ng-zorro-antd/commit/60fe850))\n- **calendar:** use correct classNames ([#1118](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1118)) ([5392fde](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5392fde))\n- **list:** change contentchild to input ([#1100](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1100)) ([5d9133b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5d9133b))\n- **progress:** fix 100% when specify invalid value ([#905](https://github.com/NG-ZORRO/ng-zorro-antd/issues/905)) ([8afedaa](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8afedaa))\n- **spin:** remove spin container if no content ([7639eac](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7639eac))\n- **spin:** support dynamic ng-content in spin ([#925](https://github.com/NG-ZORRO/ng-zorro-antd/issues/925)) ([cc7a83b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cc7a83b))\n- **transfer:** change contentchild to input ([#1099](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1099)) ([abb7de0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/abb7de0))\n\n### Features\n\n- **affix anchor backtop:** refactor affix anchor backtop ([#1025](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1025)) ([24abd10](https://github.com/NG-ZORRO/ng-zorro-antd/commit/24abd10))\n- **autocomplete:** add autocomplete component ([#1093](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1093)) ([1461293](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1461293))\n- **avatar:** add avatar component ([#1028](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1028)) ([65535d5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/65535d5))\n- **divider:** add divider component ([#1029](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1029)) ([7895e80](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7895e80))\n- **divider:** add nzOrientation property ([#1126](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1126)) ([e100681](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e100681))\n- **doc:** support sync single demo dir ([#936](https://github.com/NG-ZORRO/ng-zorro-antd/issues/936)) ([73e4a95](https://github.com/NG-ZORRO/ng-zorro-antd/commit/73e4a95))\n- **list:** add list component ([#1031](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1031)) ([9e71deb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9e71deb))\n- **list:** add nz-list component ([6481a88](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6481a88))\n- **menu dropdown:** refactor menu dropdown & add test & add doc ([#990](https://github.com/NG-ZORRO/ng-zorro-antd/issues/990)) ([ca1d4e2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ca1d4e2))\n- **tree:** add tree component ([#1147](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1147)) ([7ca5de3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7ca5de3))\n- **upload:** add upload component ([#1040](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1040)) ([a9efbaa](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a9efbaa))\n\n## [0.6.10](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.6.9...0.6.10) (2018-01-06)\n\n### Bug Fixes\n\n- **affix:** fix affix nzOffsetTop bug ([#868](https://github.com/NG-ZORRO/ng-zorro-antd/issues/868)) ([f0bad26](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f0bad26))\n- **radio:** fix radio button click bug ([#867](https://github.com/NG-ZORRO/ng-zorro-antd/issues/867)) ([2de24ee](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2de24ee)), closes [#854](https://github.com/NG-ZORRO/ng-zorro-antd/issues/854) [#857](https://github.com/NG-ZORRO/ng-zorro-antd/issues/857) [#855](https://github.com/NG-ZORRO/ng-zorro-antd/issues/855)\n\n### Features\n\n- **datepicker:** add range-picker component ([#656](https://github.com/NG-ZORRO/ng-zorro-antd/issues/656)) ([9df3eb9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9df3eb9))\n- **locale:** support russian locale ([#853](https://github.com/NG-ZORRO/ng-zorro-antd/issues/853)) ([8d65a83](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8d65a83))\n\n## [0.6.9](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.6.8...0.6.9) (2018-01-02)\n\n### Bug Fixes\n\n- **calendar:** fix month/year view switched ([#768](https://github.com/NG-ZORRO/ng-zorro-antd/issues/768)) ([383a0f4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/383a0f4))\n- **transfer:** 1.fix the \"checkAll\" status not updated 2.change \"ArrayObservable.of\" to \"of\" ([#834](https://github.com/NG-ZORRO/ng-zorro-antd/issues/834)) ([9c023fa](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9c023fa))\n\n### Features\n\n- **radio:** use nz-radio components alone ([#825](https://github.com/NG-ZORRO/ng-zorro-antd/issues/825)) ([15c968c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/15c968c))\n- **transfer:** add canMove property & make component using OnPush ([#824](https://github.com/NG-ZORRO/ng-zorro-antd/issues/824)) ([d31c596](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d31c596))\n\n## [0.6.8](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.6.7...0.6.8) (2017-12-21)\n\n### Bug Fixes\n\n- **modal:** fix modal type error ([#784](https://github.com/NG-ZORRO/ng-zorro-antd/issues/784)) ([cb0ab64](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cb0ab64))\n- **overlay:** update overlay width when the host component's width change ([#780](https://github.com/NG-ZORRO/ng-zorro-antd/issues/780)) ([62fc733](https://github.com/NG-ZORRO/ng-zorro-antd/commit/62fc733)), closes [#779](https://github.com/NG-ZORRO/ng-zorro-antd/issues/779)\n- **popconfirm:** fix backdrop of popconfirm ([#786](https://github.com/NG-ZORRO/ng-zorro-antd/issues/786)) ([60cf7a9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/60cf7a9)), closes [#785](https://github.com/NG-ZORRO/ng-zorro-antd/issues/785)\n- **table:** fix the missing of init table sort class ([#781](https://github.com/NG-ZORRO/ng-zorro-antd/issues/781)) ([b828025](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b828025)), closes [#771](https://github.com/NG-ZORRO/ng-zorro-antd/issues/771)\n\n## [0.6.7](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.6.6...0.6.7) (2017-12-15)\n\n### Bug Fixes\n\n- **datepicker:** disable datepicker when user input ([#738](https://github.com/NG-ZORRO/ng-zorro-antd/issues/738)) ([84c0f23](https://github.com/NG-ZORRO/ng-zorro-antd/commit/84c0f23))\n- **select:** reset select component this.\\_value ([#754](https://github.com/NG-ZORRO/ng-zorro-antd/issues/754)) ([4a50d0d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4a50d0d))\n- **slider:** fix set value in slider ([#743](https://github.com/NG-ZORRO/ng-zorro-antd/issues/743)) ([d0a6793](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d0a6793)), closes [#739](https://github.com/NG-ZORRO/ng-zorro-antd/issues/739)\n\n### Features\n\n- **calendar:** use months short format ([#737](https://github.com/NG-ZORRO/ng-zorro-antd/issues/737)) ([805538c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/805538c)), closes [#736](https://github.com/NG-ZORRO/ng-zorro-antd/issues/736)\n- **tooltip,popover,popconfirm:** support \"nzMouseEnterDelay\" and \"nzMouseLeaveDelay\" ([#758](https://github.com/NG-ZORRO/ng-zorro-antd/issues/758)) ([3a894f0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3a894f0)), closes [#757](https://github.com/NG-ZORRO/ng-zorro-antd/issues/757)\n\n## [0.6.6](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.6.5...0.6.6) (2017-12-11)\n\n### Bug Fixes\n\n- **datepicker:** enable simplified boolean usage ([#726](https://github.com/NG-ZORRO/ng-zorro-antd/issues/726)) ([6cf80b0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6cf80b0))\n- **rate:** ensure value to be number ([#728](https://github.com/NG-ZORRO/ng-zorro-antd/issues/728)) ([35687c3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/35687c3))\n- **slider:** fix slider min & max ([#732](https://github.com/NG-ZORRO/ng-zorro-antd/issues/732)) ([6eda3a7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6eda3a7))\n- **slider:** rectify return value ([#729](https://github.com/NG-ZORRO/ng-zorro-antd/issues/729)) ([6b095a8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6b095a8))\n\n### Features\n\n- **input-number:** use boundary value instead of previous value ([#731](https://github.com/NG-ZORRO/ng-zorro-antd/issues/731)) ([48e40f4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/48e40f4))\n\n## [0.6.5](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.6.4...0.6.5) (2017-12-10)\n\n## [0.6.4](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.6.3...0.6.4) (2017-12-10)\n\n### Bug Fixes\n\n- **input-number:** check value when press tab key ([#706](https://github.com/NG-ZORRO/ng-zorro-antd/issues/706)) ([9923a86](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9923a86)), closes [#651](https://github.com/NG-ZORRO/ng-zorro-antd/issues/651)\n\n### Features\n\n- **form:** support default nzValidateStatus & support more error status ([#696](https://github.com/NG-ZORRO/ng-zorro-antd/issues/696)) ([3d4213f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3d4213f)), closes [#693](https://github.com/NG-ZORRO/ng-zorro-antd/issues/693) [#692](https://github.com/NG-ZORRO/ng-zorro-antd/issues/692)\n- **grid:** support zero input in grid ([#704](https://github.com/NG-ZORRO/ng-zorro-antd/issues/704)) ([e50b72f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e50b72f)), closes [#702](https://github.com/NG-ZORRO/ng-zorro-antd/issues/702)\n- **select:** support placeholder for basic select ([#703](https://github.com/NG-ZORRO/ng-zorro-antd/issues/703)) ([a842cdd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a842cdd)), closes [#413](https://github.com/NG-ZORRO/ng-zorro-antd/issues/413)\n- **tooltip,popover,popconfirm:** do not show tooltip when it's content is empty ([54ff189](https://github.com/NG-ZORRO/ng-zorro-antd/commit/54ff189)), closes [#631](https://github.com/NG-ZORRO/ng-zorro-antd/issues/631)\n- **tooltip,popover,popconfirm:** support hover on the content of it's overlay ([e712d87](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e712d87)), closes [#701](https://github.com/NG-ZORRO/ng-zorro-antd/issues/701)\n\n## [0.6.3](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.6.2...0.6.3) (2017-12-06)\n\n### Bug Fixes\n\n- **affix:** fix position offset when has deferred render componets. ([#672](https://github.com/NG-ZORRO/ng-zorro-antd/issues/672)) ([74b01da](https://github.com/NG-ZORRO/ng-zorro-antd/commit/74b01da)), closes [#671](https://github.com/NG-ZORRO/ng-zorro-antd/issues/671)\n- **radio:** value can not be dynamically update ([#677](https://github.com/NG-ZORRO/ng-zorro-antd/issues/677)) ([bedcf96](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bedcf96)), closes [#668](https://github.com/NG-ZORRO/ng-zorro-antd/issues/668)\n- **select:** fix choose disabled item via direction key control ([#675](https://github.com/NG-ZORRO/ng-zorro-antd/issues/675)) ([80d637d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/80d637d)), closes [#674](https://github.com/NG-ZORRO/ng-zorro-antd/issues/674)\n- **select:** usage public property in accessing other components ([#679](https://github.com/NG-ZORRO/ng-zorro-antd/issues/679)) ([8ba3ea8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8ba3ea8))\n\n### Features\n\n- **turkish:** create tr-TR.ts ([#634](https://github.com/NG-ZORRO/ng-zorro-antd/issues/634)) ([a731817](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a731817))\n- **i18n:** support zh-TW ([#687](https://github.com/NG-ZORRO/ng-zorro-antd/issues/687)) ([05c1f87](https://github.com/NG-ZORRO/ng-zorro-antd/commit/05c1f87))\n- **carousel:** add enhancement API and methods ([#688](https://github.com/NG-ZORRO/ng-zorro-antd/issues/688)) ([c22dad3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c22dad3)), closes [#652](https://github.com/NG-ZORRO/ng-zorro-antd/issues/652)\n- **select:** support custom option template ([#689](https://github.com/NG-ZORRO/ng-zorro-antd/issues/689)) ([d76763c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d76763c)), closes [#227](https://github.com/NG-ZORRO/ng-zorro-antd/issues/227)\n- **select:** support nzScrollToBottom event ([#678](https://github.com/NG-ZORRO/ng-zorro-antd/issues/678)) ([b7cc148](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b7cc148)), closes [#676](https://github.com/NG-ZORRO/ng-zorro-antd/issues/676)\n- **all:** simplify boolean attributes ([#459](https://github.com/NG-ZORRO/ng-zorro-antd/issues/459)) ([08f10e4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/08f10e4))\n- **packaging:** generate sourcemaps ([#666](https://github.com/NG-ZORRO/ng-zorro-antd/issues/666)) ([8665639](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8665639)), closes [#662](https://github.com/NG-ZORRO/ng-zorro-antd/issues/662)\n\n### BREAKING CHANGES\n\n- **packaging:** umd file name simplified from 'ng-zorro-antd.js' to 'antd.js'\n\n## [0.6.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.6.1...0.6.2) (2017-11-29)\n\n### Features\n\n- **slider:** support dynamic update nzMarks from outside ([#636](https://github.com/NG-ZORRO/ng-zorro-antd/issues/636)) ([aea80c4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/aea80c4)), closes [#624](https://github.com/NG-ZORRO/ng-zorro-antd/issues/624)\n- **table and pagination:** support custom the page size changer select values([#608](https://github.com/NG-ZORRO/ng-zorro-antd/issues/608)) ([#626](https://github.com/NG-ZORRO/ng-zorro-antd/issues/626)) ([034bd71](https://github.com/NG-ZORRO/ng-zorro-antd/commit/034bd71))\n\n## [0.6.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.6.0...0.6.1) (2017-11-26)\n\n### Bug Fixes\n\n- **datepicker:** fix disabled today button ([#611](https://github.com/NG-ZORRO/ng-zorro-antd/issues/611)) ([5203614](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5203614)), closes [#604](https://github.com/NG-ZORRO/ng-zorro-antd/issues/604)\n- **select:** fix duplicated option bug ([#609](https://github.com/NG-ZORRO/ng-zorro-antd/issues/609)) ([9385826](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9385826)), closes [#590](https://github.com/NG-ZORRO/ng-zorro-antd/issues/590)\n- **transfer:** fix select all items in search ([#602](https://github.com/NG-ZORRO/ng-zorro-antd/issues/602)) ([072c97a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/072c97a)), closes [#599](https://github.com/NG-ZORRO/ng-zorro-antd/issues/599)\n\n### Features\n\n- **datepicker:** support string and number type as value ([#593](https://github.com/NG-ZORRO/ng-zorro-antd/issues/593)) ([aee7abe](https://github.com/NG-ZORRO/ng-zorro-antd/commit/aee7abe))\n\n## [0.6.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.6.0-rc.3...0.6.0) (2017-11-18)\n\n### Bug Fixes\n\n- **menu:** do not remove submenu when click title ([#576](https://github.com/NG-ZORRO/ng-zorro-antd/issues/576)) ([37cef47](https://github.com/NG-ZORRO/ng-zorro-antd/commit/37cef47)), closes [#454](https://github.com/NG-ZORRO/ng-zorro-antd/issues/454)\n- **popover,steps:** fix popover always show title placeholder & steps nzDescription property support TemplateRef ([#556](https://github.com/NG-ZORRO/ng-zorro-antd/issues/556)) ([4a4e393](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4a4e393)), closes [#555](https://github.com/NG-ZORRO/ng-zorro-antd/issues/555) [#523](https://github.com/NG-ZORRO/ng-zorro-antd/issues/523)\n- **select:** fix multiple select width ([#575](https://github.com/NG-ZORRO/ng-zorro-antd/issues/575)) ([7006766](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7006766)), closes [#560](https://github.com/NG-ZORRO/ng-zorro-antd/issues/560)\n\n### Features\n\n- **modal:** support disable the esc key to close ([#567](https://github.com/NG-ZORRO/ng-zorro-antd/issues/567)) ([75bc6b6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/75bc6b6))\n- **timepicker:** support dynamic binding [nzDisabledHours] ([#568](https://github.com/NG-ZORRO/ng-zorro-antd/issues/568)) ([22e2931](https://github.com/NG-ZORRO/ng-zorro-antd/commit/22e2931)), closes [#286](https://github.com/NG-ZORRO/ng-zorro-antd/issues/286)\n- **tooltip:** support usage like: <a nz-tooltip=\"This is a prompt text\">test</a> ([#545](https://github.com/NG-ZORRO/ng-zorro-antd/issues/545)) ([b4824d9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b4824d9)), closes [#345](https://github.com/NG-ZORRO/ng-zorro-antd/issues/345)\n- **transfer:** add transfer component ([#578](https://github.com/NG-ZORRO/ng-zorro-antd/issues/578)) ([84895cb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/84895cb)), closes [#132](https://github.com/NG-ZORRO/ng-zorro-antd/issues/132)\n\n## [0.6.0-rc.3](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.6.0-rc.2...0.6.0-rc.3) (2017-11-04)\n\n### Bug Fixes\n\n- **affix:** fix FPS drops ([#490](https://github.com/NG-ZORRO/ng-zorro-antd/issues/490)) ([50b2606](https://github.com/NG-ZORRO/ng-zorro-antd/commit/50b2606)), closes [#477](https://github.com/NG-ZORRO/ng-zorro-antd/issues/477)\n- **pagination:** wrong event by changing the page size ([#486](https://github.com/NG-ZORRO/ng-zorro-antd/issues/486)) ([ad5bc29](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ad5bc29)), closes [#482](https://github.com/NG-ZORRO/ng-zorro-antd/issues/482)\n- **tabs:** repeat rendering the TabBarExtra when used nested tabs ([#489](https://github.com/NG-ZORRO/ng-zorro-antd/issues/489)) ([3289e7f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3289e7f)), closes [#452](https://github.com/NG-ZORRO/ng-zorro-antd/issues/452)\n\n### Features\n\n- **datepicker:** support [nzDisabledDate] property in month mode ([#451](https://github.com/NG-ZORRO/ng-zorro-antd/issues/451)) ([cdc0716](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cdc0716)), closes [#442](https://github.com/NG-ZORRO/ng-zorro-antd/issues/442)\n\n### Performance Improvements\n\n- **classMap:** improve classMap performance ([#528](https://github.com/NG-ZORRO/ng-zorro-antd/issues/528)) ([e5b5cc9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e5b5cc9))\n- **polyfill:** polyfill all request animation ([#527](https://github.com/NG-ZORRO/ng-zorro-antd/issues/527)) ([8c5a41a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8c5a41a))\n\n## [0.6.0-rc.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.6.0-rc.1...0.6.0-rc.2) (2017-10-29)\n\n## [0.6.0-rc.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.5.5...0.6.0-rc.1) (2017-10-28)\n\n### Bug Fixes\n\n- **table:** fix the wrong semantics about param \"nzShowExpand\" of nz-row-expand-icon ([e4f8337](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e4f8337))\n\n### build\n\n- **packaging:** update [@angular](https://github.com/angular)/cdk to 2.0.0-beta.11 ([3e007a2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3e007a2)), closes [#238](https://github.com/NG-ZORRO/ng-zorro-antd/issues/238) [#290](https://github.com/NG-ZORRO/ng-zorro-antd/issues/290)\n\n### Features\n\n- **i18n:** support i18n functionality (zh-CN, en-US currently) ([552fa50](https://github.com/NG-ZORRO/ng-zorro-antd/commit/552fa50)), closes [#427](https://github.com/NG-ZORRO/ng-zorro-antd/issues/427)\n- **locale:** support change locale at the runtime (globally) ([af6c926](https://github.com/NG-ZORRO/ng-zorro-antd/commit/af6c926))\n\n### BREAKING CHANGES\n\n- **packaging:** 1. usage related to cdk is changed 2. @angular version dependence update to ^4.4.3 (due to @angular/cdk)\n- **table:** the usage of param \"nzShowExpand\" is changed to the opposite value. The former, \"nzShowExpand\" represent as \"hide the expand icon\", now this change correct it to \"show the expand icon\".\n\nAnd the default value of \"nzShowExpand\" has changed to \"true\".\n\n## [0.5.5](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.5.4...0.5.5) (2017-10-21)\n\n### Bug Fixes\n\n- **dropdown:** fix dropdown trigger events ([#466](https://github.com/NG-ZORRO/ng-zorro-antd/issues/466)) ([6034f54](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6034f54)), closes [#390](https://github.com/NG-ZORRO/ng-zorro-antd/issues/390)\n- **dropdown:** fix unsubscribe undefined bug ([#464](https://github.com/NG-ZORRO/ng-zorro-antd/issues/464)) ([a0dcad3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a0dcad3)), closes [#269](https://github.com/NG-ZORRO/ng-zorro-antd/issues/269)\n\n### Features\n\n- **calendar:** add year number to month template ([#465](https://github.com/NG-ZORRO/ng-zorro-antd/issues/465)) ([0eba3ae](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0eba3ae)), closes [#461](https://github.com/NG-ZORRO/ng-zorro-antd/issues/461)\n- **steps:** support [nzProgressDot] property in vertical mode ([#446](https://github.com/NG-ZORRO/ng-zorro-antd/issues/446)) ([98e2579](https://github.com/NG-ZORRO/ng-zorro-antd/commit/98e2579))\n\n## [0.5.4](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.5.3...0.5.4) (2017-10-14)\n\n### Bug Fixes\n\n- **datepicker:** data binding not work when mode is month ([#421](https://github.com/NG-ZORRO/ng-zorro-antd/issues/421)) ([dca0895](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dca0895))\n- **modal:** restore body overflow before destroyed the component ([#415](https://github.com/NG-ZORRO/ng-zorro-antd/issues/415)) ([083dd03](https://github.com/NG-ZORRO/ng-zorro-antd/commit/083dd03)), closes [#412](https://github.com/NG-ZORRO/ng-zorro-antd/issues/412)\n\n### Features\n\n- **input-number:** add nzBlur & nzFocus property ([#406](https://github.com/NG-ZORRO/ng-zorro-antd/issues/406)) ([a49a382](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a49a382)), closes [#396](https://github.com/NG-ZORRO/ng-zorro-antd/issues/396)\n\n## [0.5.3](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.5.2...0.5.3) (2017-09-30)\n\n### Bug Fixes\n\n- **demo:** fix demo site performance ([#403](https://github.com/NG-ZORRO/ng-zorro-antd/issues/403)) ([2e88b56](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2e88b56)), closes [#187](https://github.com/NG-ZORRO/ng-zorro-antd/issues/187)\n- **table:** fix nzIsPageIndexReset for wrong display ([#372](https://github.com/NG-ZORRO/ng-zorro-antd/issues/372)) ([#373](https://github.com/NG-ZORRO/ng-zorro-antd/issues/373)) ([90f0333](https://github.com/NG-ZORRO/ng-zorro-antd/commit/90f0333))\n\n### Features\n\n- **all:** export all components when build ([#404](https://github.com/NG-ZORRO/ng-zorro-antd/issues/404)) ([802a98c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/802a98c)), closes [#275](https://github.com/NG-ZORRO/ng-zorro-antd/issues/275)\n- **collapse:** support custom header ([#383](https://github.com/NG-ZORRO/ng-zorro-antd/issues/383)) ([ca42f00](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ca42f00))\n- **datepicker:** support month picker ([#397](https://github.com/NG-ZORRO/ng-zorro-antd/issues/397)) ([4cb03fa](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4cb03fa)), closes [#351](https://github.com/NG-ZORRO/ng-zorro-antd/issues/351)\n- **menu:** animate expand/collapse menu ([#330](https://github.com/NG-ZORRO/ng-zorro-antd/issues/330)) ([7edba94](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7edba94)), closes [#25](https://github.com/NG-ZORRO/ng-zorro-antd/issues/25)\n\n## [0.5.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.5.1...0.5.2) (2017-09-23)\n\n### Bug Fixes\n\n- **cascader:** select and render leaf label & reset in reactive form ([#335](https://github.com/NG-ZORRO/ng-zorro-antd/issues/335)) ([#336](https://github.com/NG-ZORRO/ng-zorro-antd/issues/336)) ([#356](https://github.com/NG-ZORRO/ng-zorro-antd/issues/356)) ([c80bb8e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c80bb8e))\n- **menu:** fix submenu ExpressionChangedAfterItHasBeenCheckedError ([#368](https://github.com/NG-ZORRO/ng-zorro-antd/issues/368)) ([10989ae](https://github.com/NG-ZORRO/ng-zorro-antd/commit/10989ae)), closes [#367](https://github.com/NG-ZORRO/ng-zorro-antd/issues/367)\n- **select:** fix select style in inline form ([#362](https://github.com/NG-ZORRO/ng-zorro-antd/issues/362)) ([ae06649](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ae06649)), closes [#306](https://github.com/NG-ZORRO/ng-zorro-antd/issues/306)\n- **table:** fix nzWidth with ngIf ([#349](https://github.com/NG-ZORRO/ng-zorro-antd/issues/349)) ([d5d379b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d5d379b)), closes [#302](https://github.com/NG-ZORRO/ng-zorro-antd/issues/302)\n- **moment:** rollup compile with incorrect sourcemap ([#331](https://github.com/NG-ZORRO/ng-zorro-antd/issues/331)) ([aec9f83](https://github.com/NG-ZORRO/ng-zorro-antd/commit/aec9f83))\n\n### Features\n\n- **modal:** show confirm loading status of modal opened by nzModalService ([#340](https://github.com/NG-ZORRO/ng-zorro-antd/issues/340)) ([90b7e12](https://github.com/NG-ZORRO/ng-zorro-antd/commit/90b7e12)), closes [#365](https://github.com/NG-ZORRO/ng-zorro-antd/issues/365)\n- **select:** support undefined reset select ([#363](https://github.com/NG-ZORRO/ng-zorro-antd/issues/363)) ([1a997c2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1a997c2)), closes [#284](https://github.com/NG-ZORRO/ng-zorro-antd/issues/284)\n- **table:** add nzIsPageIndexReset option ([#348](https://github.com/NG-ZORRO/ng-zorro-antd/issues/348)) ([#359](https://github.com/NG-ZORRO/ng-zorro-antd/issues/359)) ([60e3da9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/60e3da9))\n\n## [0.5.1](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.5.0...0.5.1) (2017-09-16)\n\n### Bug Fixes\n\n- **datepicker:** end decade cell text ([#301](https://github.com/NG-ZORRO/ng-zorro-antd/issues/301)) ([d16061f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d16061f)), closes [#300](https://github.com/NG-ZORRO/ng-zorro-antd/issues/300)\n- **input:** fix type error ([#283](https://github.com/NG-ZORRO/ng-zorro-antd/issues/283)) ([cd84e47](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cd84e47)), closes [#282](https://github.com/NG-ZORRO/ng-zorro-antd/issues/282)\n- **layout:** fix slider breakpoint in mobile device ([#299](https://github.com/NG-ZORRO/ng-zorro-antd/issues/299)) ([47c4d86](https://github.com/NG-ZORRO/ng-zorro-antd/commit/47c4d86)), closes [#292](https://github.com/NG-ZORRO/ng-zorro-antd/issues/292)\n- **pagination:** prevent repeated emit events ([#281](https://github.com/NG-ZORRO/ng-zorro-antd/issues/281)) ([ec66e13](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ec66e13)), closes [#280](https://github.com/NG-ZORRO/ng-zorro-antd/issues/280)\n- **pagination:** prevent selection after double click ([#268](https://github.com/NG-ZORRO/ng-zorro-antd/issues/268)) ([46ae81a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/46ae81a)), closes [#267](https://github.com/NG-ZORRO/ng-zorro-antd/issues/267)\n\n### Features\n\n- **menu:** selected child item, its parent highlight ([#264](https://github.com/NG-ZORRO/ng-zorro-antd/issues/264)) ([970e968](https://github.com/NG-ZORRO/ng-zorro-antd/commit/970e968)), closes [#262](https://github.com/NG-ZORRO/ng-zorro-antd/issues/262)\n\n## [0.5.0](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.5.0-rc.4...0.5.0) (2017-09-09)\n\n### Bug Fixes\n\n- **all:** patch all components with setDisabledState ([#188](https://github.com/NG-ZORRO/ng-zorro-antd/issues/188)) ([69b8979](https://github.com/NG-ZORRO/ng-zorro-antd/commit/69b8979)), closes [#134](https://github.com/NG-ZORRO/ng-zorro-antd/issues/134)\n- **carousel:** carousel slide height depend on inner content ([#242](https://github.com/NG-ZORRO/ng-zorro-antd/issues/242)) ([94bac1b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/94bac1b)), closes [#162](https://github.com/NG-ZORRO/ng-zorro-antd/issues/162) [#170](https://github.com/NG-ZORRO/ng-zorro-antd/issues/170)\n- **cascader:** fix nz-cascader don't refresh when nzOptions binding data changed ([#219](https://github.com/NG-ZORRO/ng-zorro-antd/issues/219)) ([#221](https://github.com/NG-ZORRO/ng-zorro-antd/issues/221)) ([74b2506](https://github.com/NG-ZORRO/ng-zorro-antd/commit/74b2506))\n- **checkbox:** fix trigger twitce in safari ([#256](https://github.com/NG-ZORRO/ng-zorro-antd/issues/256)) ([cd5b511](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cd5b511))\n- **core,root:** ensure compatibility to v4 ([#233](https://github.com/NG-ZORRO/ng-zorro-antd/issues/233)) ([2b5c083](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2b5c083))\n- **datepicker:** year and month display in opposite way ([#243](https://github.com/NG-ZORRO/ng-zorro-antd/issues/243)) ([4b5ea54](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4b5ea54)), closes [#232](https://github.com/NG-ZORRO/ng-zorro-antd/issues/232)\n- **dropdown:** should always debouce before subscribe visibleChange$ ([#237](https://github.com/NG-ZORRO/ng-zorro-antd/issues/237)) ([0180e1c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0180e1c)), closes [#234](https://github.com/NG-ZORRO/ng-zorro-antd/issues/234)\n- **input,datepicker,input-number,select,slider:** still dirty when \"form.reset()\" called ([#257](https://github.com/NG-ZORRO/ng-zorro-antd/issues/257)) ([4233db1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4233db1)), closes [#114](https://github.com/NG-ZORRO/ng-zorro-antd/issues/114)\n- **inputnumber:** validate inputnumber value & rewrite strategy ([#230](https://github.com/NG-ZORRO/ng-zorro-antd/issues/230)) ([28669ae](https://github.com/NG-ZORRO/ng-zorro-antd/commit/28669ae)), closes [#42](https://github.com/NG-ZORRO/ng-zorro-antd/issues/42) [#203](https://github.com/NG-ZORRO/ng-zorro-antd/issues/203)\n- **select, datepicker, timepicker:** close dropdown when change to disable status ([#222](https://github.com/NG-ZORRO/ng-zorro-antd/issues/222)) ([6e1b144](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6e1b144)), closes [#190](https://github.com/NG-ZORRO/ng-zorro-antd/issues/190) [#195](https://github.com/NG-ZORRO/ng-zorro-antd/issues/195)\n- **select, datepicker, timepicker, radio, checkbox, input-number:** fix touched state ([#248](https://github.com/NG-ZORRO/ng-zorro-antd/issues/248)) ([07f48bc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/07f48bc)), closes [#228](https://github.com/NG-ZORRO/ng-zorro-antd/issues/228)\n\n### Features\n\n- **grid:** support embedded col option ([#247](https://github.com/NG-ZORRO/ng-zorro-antd/issues/247)) ([248c7e5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/248c7e5)), closes [#101](https://github.com/NG-ZORRO/ng-zorro-antd/issues/101)\n- **input:** support nzAutosize property ([#251](https://github.com/NG-ZORRO/ng-zorro-antd/issues/251)) ([5e950ab](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5e950ab)), closes [#252](https://github.com/NG-ZORRO/ng-zorro-antd/issues/252)\n- **input:** support nzReadonly property ([#236](https://github.com/NG-ZORRO/ng-zorro-antd/issues/236)) ([6b69cf9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6b69cf9))\n- **menu:** support unfolds/folds & add demo and api docs ([#225](https://github.com/NG-ZORRO/ng-zorro-antd/issues/225)) ([23b73bb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/23b73bb)), closes [#206](https://github.com/NG-ZORRO/ng-zorro-antd/issues/206)\n- **table:** support filter & fixed header add more table demo ([#210](https://github.com/NG-ZORRO/ng-zorro-antd/issues/210)) ([5f11664](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5f11664)), closes [#86](https://github.com/NG-ZORRO/ng-zorro-antd/issues/86) [#174](https://github.com/NG-ZORRO/ng-zorro-antd/issues/174) [#218](https://github.com/NG-ZORRO/ng-zorro-antd/issues/218)\n- **table:** support table expand feature ([#259](https://github.com/NG-ZORRO/ng-zorro-antd/issues/259)) ([578819d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/578819d)), closes [#185](https://github.com/NG-ZORRO/ng-zorro-antd/issues/185)\n\n## [0.5.0-rc.4](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.5.0-rc.3...0.5.0-rc.4) (2017-08-31)\n\n### Bug Fixes\n\n- **pagination:** fix nzPageIndexChange event does not emit ([#189](https://github.com/NG-ZORRO/ng-zorro-antd/issues/189)) ([371b98a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/371b98a))\n\n### Features\n\n- **modal:** provide open & close & setConfirmLoading function ([#125](https://github.com/NG-ZORRO/ng-zorro-antd/issues/125)) ([0f87f6c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0f87f6c)), closes [#118](https://github.com/NG-ZORRO/ng-zorro-antd/issues/118)\n- **tooltip,popconfirm,popover:** support OnPush ([#143](https://github.com/NG-ZORRO/ng-zorro-antd/issues/143)) ([2f2c9ac](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2f2c9ac)), closes [#136](https://github.com/NG-ZORRO/ng-zorro-antd/issues/136)\n\n## [0.5.0-rc.3](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.5.0-rc.2...0.5.0-rc.3) (2017-08-26)\n\n### Bug Fixes\n\n- **affix,anchor,back-top:** fix and improve rxjs usage ([#159](https://github.com/NG-ZORRO/ng-zorro-antd/issues/159)) ([152b654](https://github.com/NG-ZORRO/ng-zorro-antd/commit/152b654))\n- **carousel:** fix carousel auto play bug ([#164](https://github.com/NG-ZORRO/ng-zorro-antd/issues/164)) ([01012e4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/01012e4)), closes [#161](https://github.com/NG-ZORRO/ng-zorro-antd/issues/161)\n- **checkbox:** fix checkbox host class lost bug ([#116](https://github.com/NG-ZORRO/ng-zorro-antd/issues/116)) ([81cbae9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/81cbae9)), closes [#104](https://github.com/NG-ZORRO/ng-zorro-antd/issues/104)\n- **input:** fix input disabled style bug ([#108](https://github.com/NG-ZORRO/ng-zorro-antd/issues/108)) ([5d666fc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5d666fc)), closes [#103](https://github.com/NG-ZORRO/ng-zorro-antd/issues/103)\n- **input:** fix input disabled style bug ([#160](https://github.com/NG-ZORRO/ng-zorro-antd/issues/160)) ([b7a073c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b7a073c))\n- **input:** fix input touched property ([#129](https://github.com/NG-ZORRO/ng-zorro-antd/issues/129)) ([143c080](https://github.com/NG-ZORRO/ng-zorro-antd/commit/143c080)), closes [#65](https://github.com/NG-ZORRO/ng-zorro-antd/issues/65) [#117](https://github.com/NG-ZORRO/ng-zorro-antd/issues/117)\n- **select:** fix option incorrect active status ([#141](https://github.com/NG-ZORRO/ng-zorro-antd/issues/141)) ([49e3741](https://github.com/NG-ZORRO/ng-zorro-antd/commit/49e3741))\n- **select:** fix select reset bug in form ([#153](https://github.com/NG-ZORRO/ng-zorro-antd/issues/153)) ([2bf24e0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2bf24e0)), closes [#128](https://github.com/NG-ZORRO/ng-zorro-antd/issues/128)\n\n### Features\n\n- **affix&anchor&back-top&avatar:** add components to library ([#88](https://github.com/NG-ZORRO/ng-zorro-antd/issues/88)) ([468e80b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/468e80b))\n- **root:** make nz-root optional ([#36](https://github.com/NG-ZORRO/ng-zorro-antd/issues/36)) ([9de3de1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9de3de1))\n- **showcase:** auto scroll to top when router change & sync code icon with antd ([#124](https://github.com/NG-ZORRO/ng-zorro-antd/issues/124)) ([9a1de83](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9a1de83)), closes [#26](https://github.com/NG-ZORRO/ng-zorro-antd/issues/26)\n\n## [0.5.0-rc.2](https://github.com/NG-ZORRO/ng-zorro-antd/compare/0.5.0-rc.0...0.5.0-rc.2) (2017-08-19)\n\n### Bug Fixes\n\n- **pagination:** Pagination QuickJumper bug [#37](https://github.com/NG-ZORRO/ng-zorro-antd/issues/37) ([a122238](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a122238))\n- **carousel:** support dynamic change of nz-carousel-content ([#60](https://github.com/NG-ZORRO/ng-zorro-antd/issues/60)) ([44865c2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/44865c2)), closes [#56](https://github.com/NG-ZORRO/ng-zorro-antd/issues/56)\n- **menu:** fix submenu level bug & fix menu routerLinkActive bug in lazyload module ([#77](https://github.com/NG-ZORRO/ng-zorro-antd/issues/77)) ([b914afd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b914afd)), closes [#35](https://github.com/NG-ZORRO/ng-zorro-antd/issues/35) [#52](https://github.com/NG-ZORRO/ng-zorro-antd/issues/52) [#74](https://github.com/NG-ZORRO/ng-zorro-antd/issues/74)\n- **pagination:** remove active class when reach first and last page index ([#93](https://github.com/NG-ZORRO/ng-zorro-antd/issues/93)) ([2bcddc7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2bcddc7)), closes [#17](https://github.com/NG-ZORRO/ng-zorro-antd/issues/17)\n- **steps:** fix steps width bug in tab component ([#94](https://github.com/NG-ZORRO/ng-zorro-antd/issues/94)) ([ee4428d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ee4428d)), closes [#83](https://github.com/NG-ZORRO/ng-zorro-antd/issues/83)\n- **timeline:** eliminate ExpressionChangedAfterItHasBeenCheckedError when use ngFor to render ([67df061](https://github.com/NG-ZORRO/ng-zorro-antd/commit/67df061))\n\n### Features\n\n- **input:** provide nzFocus event ([#80](https://github.com/NG-ZORRO/ng-zorro-antd/issues/80)) ([ffc1d49](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ffc1d49)), closes [#73](https://github.com/NG-ZORRO/ng-zorro-antd/issues/73)\n\n### Performance Improvements\n\n- **all:** improve rxjs imports ([#29](https://github.com/NG-ZORRO/ng-zorro-antd/issues/29)) ([f3aa2cb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f3aa2cb))\n\n# 0.5.0-rc.0 (2017-08-15)\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, sex characteristics, gender identity and expression,\nlevel of experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n- Using welcoming and inclusive language\n- Being respectful of differing viewpoints and experiences\n- Gracefully accepting constructive criticism\n- Focusing on what is best for the community\n- Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n- The use of sexualized language or imagery and unwelcome sexual attention or\n  advances\n- Trolling, insulting/derogatory comments, and personal or political attacks\n- Public or private harassment\n- Publishing others' private information, such as a physical or electronic\n  address, without explicit permission\n- Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at yadong.xyd@alibaba-inc.com. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see\nhttps://www.contributor-covenant.org/faq\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to NG-ZORRO\n\nWe would love for you to contribute to NG-ZORRO and help make it even better than it is\ntoday! As a contributor, here are the guidelines we would like you to follow:\n\n- [Code of Conduct](#coc)\n- [Question or Problem?](#question)\n- [Issues and Bugs](#issue)\n- [Feature Requests](#feature)\n- [Submission Guidelines](#submit)\n- [Coding Rules](#rules)\n- [Commit Message Guidelines](#commit)\n\n## <a name=\"coc\"></a> Code of Conduct\n\nHelp us keep NG-ZORRO open and inclusive. Please read and follow our [Code of Conduct](https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/CODE_OF_CONDUCT.md).\n\n## <a name=\"question\"></a> Got a Question or Problem?\n\nDo not open issues for general support questions as we want to keep GitHub issues for bug reports and feature requests. You've got much better chances of getting your question answered on [Segmentfault](https://segmentfault.com/t/ng-zorro) or [Stack Overflow](https://stackoverflow.com/tags/ng-zorro) where the questions should be tagged with tag `ng-zorro`.\n\nSegmentfault / Stack Overflow is a much better place to ask questions since:\n\n- there are thousands of people willing to help on Segmentfault\n- questions and answers stay available for public viewing so your question / answer might help someone else\n- Segmentfault's voting system assures that the best answers are prominently visible.\n\nTo save your and our time, we will systematically close all issues that are requests for general support and redirect people to Segmentfault / Stack Overflow.\n\nIf you would like to chat about the question in real-time, you can reach out via [![Discord](https://img.shields.io/discord/1433686455925870594?style=flat-square&logo=discord&label=Discord)](https://discord.com/channels/1433686455925870594/1433686456706138195).\n\n## <a name=\"issue\"></a> Found a Bug?\n\nIf you find a bug in the source code, you can help us by\n[submitting an issue](#submit-issue) to our [GitHub Repository](https://github.com/NG-ZORRO/ng-zorro-antd). Even better, you can\n[submit a Pull Request](#submit-pr) with a fix.\n\n## <a name=\"feature\"></a> Missing a Feature?\n\nYou can _request_ a new feature by [submitting an issue](#submit-issue) to our GitHub\nRepository. If you would like to _implement_ a new feature, please submit an issue with\na for your work first, to be sure that we can use it.\nPlease consider what kind of change it is:\n\n- For a **Major Feature**, first open an issue and outline your proposal so that it can be\n  discussed. This will also allow us to better coordinate our efforts, prevent duplication of work,\n  and help you to craft the change so that it is successfully accepted into the project.\n- **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr).\n\n## <a name=\"submit\"></a> Submission Guidelines\n\n### <a name=\"submit-issue\"></a> Submitting an Issue\n\nBefore you submit an issue, please search the issue tracker, maybe an issue for your problem already exists and the discussion might inform you of workarounds readily available.\n\nWe want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it. In order to reproduce bugs we will systematically ask you to provide a minimal reproduction scenario using http://plnkr.co. Having a live, reproducible scenario gives us wealth of important information without going back & forth to you with additional questions like:\n\n- version of NG-ZORRO used\n- 3rd-party libraries and their versions\n- and most importantly - a use-case that fails\n\nA minimal reproduce scenario using http://plnkr.co/ allows us to quickly confirm a bug (or point out coding problem) as well as confirm that we are fixing the right problem. If plunker is not a suitable way to demonstrate the problem (for example for issues related to our npm packaging), please create a standalone git repository demonstrating the problem.\n\nWe will be insisting on a minimal reproduce scenario in order to save maintainers time and ultimately be able to fix more bugs. Interestingly, from our experience users often find coding problems themselves while preparing a minimal plunk. We understand that sometimes it might be hard to extract essentials bits of code from a larger code-base but we really need to isolate the problem before we can fix it.\n\nUnfortunately we are not able to investigate / fix bugs without a minimal reproduction, so if we don't hear back from you we are going to close an issue that don't have enough info to be reproduced.\n\nYou can file new issues by filling out our [new issue form](https://github.com/NG-ZORRO/ng-zorro-antd/issues/new).\n\n### <a name=\"submit-pr\"></a> Submitting a Pull Request (PR)\n\nBefore you submit your Pull Request (PR) consider the following guidelines:\n\n- Search [GitHub](https://github.com/NG-ZORRO/ng-zorro-antd/pulls) for an open or closed PR\n  that relates to your submission. You don't want to duplicate effort.\n- Make your changes in a new git branch:\n\n  ```shell\n  git checkout -b my-fix-branch master\n  ```\n\n- Create your patch, **including appropriate test cases**.\n- Follow our [Coding Rules](#rules).\n- Run the full test suite, and ensure that all tests pass.\n- Commit your changes using a descriptive commit message that follows our\n  [commit message conventions](#commit). Adherence to these conventions\n  is necessary because release notes are automatically generated from these messages.\n\n  ```shell\n  git commit -a\n  ```\n\n  Note: the optional commit `-a` command line option will automatically \"add\" and \"rm\" edited files.\n\n- Push your branch to GitHub:\n\n  ```shell\n  git push origin my-fix-branch\n  ```\n\n- In GitHub, send a pull request to `ng-zorro-antd:master`.\n- If we suggest changes then:\n  - Make the required updates.\n  - Re-run the NG-ZORRO test suites to ensure tests are still passing.\n  - Rebase your branch and force push to your GitHub repository (this will update your Pull Request):\n\n    ```shell\n    git rebase master -i\n    git push -f\n    ```\n\nThat's it! Thank you for your contribution!\n\n#### After your pull request is merged\n\nAfter your pull request is merged, you can safely delete your branch and pull the changes\nfrom the main (upstream) repository:\n\n- Delete the remote branch on GitHub either through the GitHub web UI or your local shell as follows:\n\n  ```shell\n  git push origin --delete my-fix-branch\n  ```\n\n- Check out the master branch:\n\n  ```shell\n  git checkout master -f\n  ```\n\n- Delete the local branch:\n\n  ```shell\n  git branch -D my-fix-branch\n  ```\n\n- Update your master with the latest upstream version:\n\n  ```shell\n  git pull --ff upstream master\n  ```\n\n## <a name=\"rules\"></a> Coding Rules\n\nTo ensure consistency throughout the source code, keep these rules in mind as you are working:\n\n- All features or bug fixes **must be tested** by one or more specs (unit-tests).\n- All public API methods **must be documented**.\n\n## <a name=\"commit\"></a> Commit Message Guidelines\n\nWe have very precise rules over how our git commit messages can be formatted. This leads to **more\nreadable messages** that are easy to follow when looking through the **project history**. But also,\nwe use the git commit messages to **generate the NG-ZORRO change log**.\n\n### Commit Message Format\n\nEach commit message consists of a **header**, a **body** and a **footer**. The header has a special\nformat that includes a **type**, a **scope** and a **subject**:\n\n```txt\n<type>(<scope>): <subject>\n<BLANK LINE>\n<body>\n<BLANK LINE>\n<footer>\n```\n\nThe **header** is mandatory and the **scope** of the header is optional.\n\nAny line of the commit message cannot be longer 100 characters! This allows the message to be easier\nto read on GitHub as well as in various git tools.\n\nFooter should contain a [closing reference to an issue](https://help.github.com/articles/closing-issues-via-commit-messages/) if any.\n\nSamples: (even more [samples](https://github.com/NG-ZORRO/ng-zorro-antd/commits/master))\n\n```txt\ndocs(changelog): update change log to beta.5\n```\n\n```txt\nfix(release): need to depend on latest rxjs and zone.js\n\nThe version in our package.json gets copied to the one we publish, and users need the latest of these.\n```\n\n### Revert\n\nIf the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.\n\n### Type\n\nMust be one of the following:\n\n- **build**: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)\n- **ci**: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)\n- **docs**: Documentation only changes\n- **feat**: A new feature\n- **fix**: A bug fix\n- **perf**: A code change that improves performance\n- **refactor**: A code change that neither fixes a bug nor adds a feature\n- **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)\n- **test**: Adding missing tests or correcting existing tests\n\n### Scope\n\nThe scope should be the name of the module affected (folder name or other meaningful words), and should prefix with _module:_ (as perceived by person reading changelog generated from commit messages.\n\nThe following are some examples:\n\n- **module:alert**\n- **module:badge**\n- **module:breadcrumb**\n- **module:OTHER_COMPONENT_NAME**\n\nThere are currently a few exceptions to the \"use module name\" rule:\n\n- **packaging**: used for changes that change the npm package layout, e.g. public path changes, package.json changes, d.ts file/format changes, changes to bundles, etc.\n- **changelog**: used for updating the release notes in CHANGELOG.md\n- **showcase**: used for docs-app (ng.ant.design) related changes within the /showcase directory of the repo\n- none/empty string: useful for `style`, `test` and `refactor` changes that are done across all packages (e.g. `style: add missing semicolons`)\n\n### Subject\n\nThe subject contains succinct description of the change:\n\n- use the imperative, present tense: \"change\" not \"changed\" nor \"changes\"\n- don't capitalize first letter\n- no dot (.) at the end\n\n### Body\n\nJust as in the **subject**, use the imperative, present tense: \"change\" not \"changed\" nor \"changes\".\nThe body should include the motivation for the change and contrast this with previous behavior.\n\n### Footer\n\nThe footer should contain any information about **Breaking Changes** and is also the place to\nreference GitHub issues that this commit **Closes**.\n\n**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.\n\nA detailed explanation can be found in this [document](https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y).\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT LICENSE\n\nCopyright (c) 2017-present Alibaba.com\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "README-zh_CN.md",
    "content": "<p align=\"center\">\n  <a href=\"https://ng.ant.design\">\n    <img alt=\"logo\" width=\"230\" src=\"https://img.alicdn.com/tfs/TB1TFFaHAvoK1RjSZFwXXciCFXa-106-120.svg\">\n  </a>\n</p>\n\n<h1 align=\"center\">\nNG-ZORRO\n</h1>\n\n<div align=\"center\">\n\n`ng-zorro-antd` 是 Ant Design 的 Angular 实现，主要用于研发企业级中后台产品。全部代码开源并遵循 MIT 协议，任何企业、组织及个人均可免费使用。\n\n[![Azure branch](https://img.shields.io/azure-devops/build/ng-zorro/0d271b73-3774-4dbc-a081-088df0b28bf8/2/master?style=flat-square)](https://dev.azure.com/ng-zorro/NG-ZORRO/_build)\n[![CodeFactor](https://www.codefactor.io/repository/github/ng-zorro/ng-zorro-antd/badge?style=flat-square)](https://www.codefactor.io/repository/github/ng-zorro/ng-zorro-antd)\n[![Codecov](https://img.shields.io/codecov/c/github/NG-ZORRO/ng-zorro-antd.svg?style=flat-square)](https://codecov.io/gh/NG-ZORRO/ng-zorro-antd)\n[![GitHub Release Date](https://img.shields.io/github/release-date/NG-ZORRO/ng-zorro-antd.svg?style=flat-square)](https://github.com/NG-ZORRO/ng-zorro-antd/releases)\n[![NPM package](https://img.shields.io/npm/v/ng-zorro-antd.svg?style=flat-square)](https://npmjs.org/package/ng-zorro-antd)\n[![NPM downloads](http://img.shields.io/npm/dm/ng-zorro-antd.svg?style=flat-square)](https://npmjs.org/package/ng-zorro-antd)\n[![GitHub license](https://img.shields.io/github/license/mashape/apistatus.svg?style=flat-square)](https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE)\n[![Discord](https://img.shields.io/discord/1433686455925870594?style=flat-square&logo=discord&label=Discord)](https://discord.com/channels/1433686455925870594/1433686456706138195)\n[![VSCode Extension](https://img.shields.io/badge/extension%20for-VSCode-blue.svg?style=flat-square)](https://marketplace.visualstudio.com/items?itemName=cipchk.ng-zorro-vscode)\n[![Code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)\n[![X](https://img.shields.io/badge/NG--ZORRO-blue.svg?style=flat-square&logo=x)](http://x.com/ng_zorro)\n\n</div>\n\n[![logo](https://img.alicdn.com/tfs/TB1t6QPylr0gK0jSZFnXXbRRXXa-4000-1378.png)](http://ng.ant.design)\n\n[English](README.md) | 简体中文\n\n## ✨ 特性\n\n- 提炼自企业级中后台产品的交互语言和视觉风格。\n- 开箱即用的高质量 Angular 组件，与 Angular 保持同步升级。\n- 使用 TypeScript 构建，提供完整的类型定义文件。\n- 支持 Zoneless 和 OnPush 模式，性能卓越。\n- 数十个国际化语言支持。\n- 深入每个细节的主题定制能力。\n\n## ☀️ 授权协议\n\n[![GitHub license](https://img.shields.io/github/license/mashape/apistatus.svg?style=flat-square)](https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE)\n[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FNG-ZORRO%2Fng-zorro-antd.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2FNG-ZORRO%2Fng-zorro-antd?ref=badge_shield)\n\n## 🖥 支持环境\n\n- Angular `^21.0.0` [![npm package](https://img.shields.io/npm/v/ng-zorro-antd.svg?style=flat-square)](https://www.npmjs.org/package/ng-zorro-antd)\n- 支持服务端渲染\n- 现代浏览器，[浏览器支持](https://angular.cn/reference/versions#browser-support)\n- [Electron](http://electron.atom.io/)\n\n| [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png\" alt=\"Edge\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png\" alt=\"Firefox\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png\" alt=\"Chrome\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png\" alt=\"Safari\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png\" alt=\"Opera\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Opera | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/electron/electron_48x48.png\" alt=\"Electron\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Electron |\n| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| last 2 versions                                                                                                                                                                                       | last 2 versions                                                                                                                                                                                                   | last 2 versions                                                                                                                                                                                               | last 2 versions                                                                                                                                                                                               | last 2 versions                                                                                                                                                                                           | last 2 versions                                                                                                                                                                                                       |\n\n## 🎨 设计规范\n\n`ng-zorro-antd` 与 Ant Design 设计规范定期同步，你可以在线查看[同步日志](https://nz-styles-syncer.now.sh/)。\n\n## 📦 安装\n\n我们强烈推荐官方的 `@angular/cli` 工具链辅助进行开发，在实际项目开发中，它可以很好的满足对 TypeScript 代码的构建、调试、代理、打包部署等一系列工程化的需求。\n\n```bash\n$ ng new PROJECT_NAME\n$ cd PROJECT_NAME\n$ ng add ng-zorro-antd\n```\n\n> 如果你想了解更多CLI工具链的功能和命令，建议访问 [Angular CLI](https://github.com/angular/angular-cli) 了解更多\n\n## 🔨 使用\n\n将想要使用的组件模块引入到你的组件中。\n\n```ts\nimport { NzButtonModule } from 'ng-zorro-antd/button';\n\n@Component({\n  imports: [NzButtonModule]\n})\nexport class AppComponent {}\n```\n\n> `@angular/cli` 的用户不需要担心下面这项设置，但知道也挺有好处。\n\n然后在 `angular.json` 文件中引入样式和 SVG icon 资源。\n\n```diff\n{\n  \"assets\": [\n+   {\n+     \"glob\": \"**/*\",\n+     \"input\": \"./node_modules/@ant-design/icons-angular/src/inline-svg/\",\n+     \"output\": \"/assets/\"\n+   }\n  ],\n  \"styles\": [\n+   \"node_modules/ng-zorro-antd/ng-zorro-antd.min.css\"\n  ]\n}\n```\n\n参考[快速上手](https://ng.ant.design/docs/getting-started/zh)以了解更多。\n\n## 🔗 链接\n\n- [ng-zorro-antd-mobile](https://github.com/NG-ZORRO/ng-zorro-antd-mobile)\n- [ng-alain](https://github.com/ng-alain/ng-alain)\n- [VSCode 的 snippet 扩展](https://marketplace.visualstudio.com/items?itemName=cipchk.ng-zorro-vscode)\n\n## ⌨️ 开发\n\n```bash\n$ git clone git@github.com:NG-ZORRO/ng-zorro-antd.git\n$ cd ng-zorro-antd\n$ npm install\n$ npm run start\n```\n\n浏览器会自动打开。\n\n## 🤝 如何贡献\n\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/NG-ZORRO/ng-zorro-antd/pulls)\n\n在任何形式的参与前，请先阅读 [贡献者文档](https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/CONTRIBUTING.md)。如果你希望参与贡献，欢迎 [Pull Request](https://github.com/NG-ZORRO/ng-zorro-antd/pulls)，或给我们 [报告 Bug](http://ng.ant.design/issue-helper/#/new-issue)。\n\n> 强烈推荐阅读 [《提问的智慧》](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way)(**本指南不提供此项目的实际支持服务！**)、[《如何向开源社区提问题》](https://github.com/seajs/seajs/issues/545) 和 [《如何有效地报告 Bug》](http://www.chiark.greenend.org.uk/%7Esgtatham/bugs-cn.html)、[《如何向开源项目提交无法解答的问题》](https://zhuanlan.zhihu.com/p/25795393)，更好的问题更容易获得帮助。\n\n感谢 [JetBrains](https://www.jetbrains.com/?from=ng-zorro-antd) 提供的免费开源 License 赞助\n\n[![JetBrains](https://img.alicdn.com/tfs/TB1sSomo.z1gK0jSZLeXXb9kVXa-120-130.svg)](https://www.jetbrains.com/?from=ng-zorro-antd)\n\n## ❓ 社区互助\n\n如果您在使用的过程中碰到问题，可以通过下面几个途径寻求帮助，同时我们也鼓励资深用户通过下面的途径给新人提供帮助。\n\n通过 Stack Overflow 或者 Segment Fault 提问时，建议加上 `ng-zorro-antd` 标签。\n\n1. [Stack Overflow](https://stackoverflow.com/questions/tagged/ng-zorro-antd)（English）\n2. [Segment Fault](https://segmentfault.com/t/ng-zorro)（中文）\n3. [![Discord](https://img.shields.io/discord/748677963142135818?label=Discord&style=flat-square)](https://discord.com/channels/748677963142135818/764322550712893451)\n4. 加入钉钉 NG-ZORRO 自助服务群（中文）\n\n<img src=\"https://img.alicdn.com/imgextra/i2/O1CN01996NqO1ykdnAdOLqG_!!6000000006617-2-tps-864-822.png\" width=\"300\" height=\"300\" loading=\"lazy\" alt=\"ding talk qr-code\">\n\n## 🎉 谁在使用\n\n- [阿里巴巴](https://www.alibaba.com/)\n- [阿里云](https://www.aliyun.com/)\n- [思特沃克](https://www.thoughtworks.com/)\n- [招商银行](http://www.cmbchina.com/)\n- [共道科技](https://www.gongdao.com/)\n- [优速快递](http://www.uce.cn/)\n- [轻流](https://qingflow.com/)\n- [航天信息股份有限公司](http://www.aisino.com/)\n- [达观数据](http://datagrand.com/)\n- [Ververica](https://www.ververica.com/)\n- [Apache Flink](https://flink.apache.org/)\n- [Apache Zeppelin](https://zeppelin.apache.org/)\n- [Apache Submarine](https://submarine.apache.org/)\n- [Apache Metron](https://metron.apache.org/)\n- [Process Automation Group](http://pag.company/)\n- [ScentBird](https://www.scentbird.com/)\n- [Southern Institute of Technology](https://www.sit.ac.nz/)\n- [Hapify (Dynamic boilerplates tool)](https://hub.hapify.io/)\n\n> 我们在这里列出了部分使用者，如果你的公司和产品使用了 NG-ZORRO，欢迎到 [这里](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1142) 留言。\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://ng.ant.design\">\n    <img alt=\"logo\" width=\"230\" src=\"https://img.alicdn.com/tfs/TB1TFFaHAvoK1RjSZFwXXciCFXa-106-120.svg\">\n  </a>\n</p>\n\n<h1 align=\"center\">\nNG-ZORRO\n</h1>\n\n<div align=\"center\">\n\nAn enterprise-class Angular UI component library based on Ant Design.\n\n[![Azure branch](https://img.shields.io/azure-devops/build/ng-zorro/0d271b73-3774-4dbc-a081-088df0b28bf8/2/master?style=flat-square)](https://dev.azure.com/ng-zorro/NG-ZORRO/_build)\n[![CodeFactor](https://www.codefactor.io/repository/github/ng-zorro/ng-zorro-antd/badge?style=flat-square)](https://www.codefactor.io/repository/github/ng-zorro/ng-zorro-antd)\n[![Codecov](https://img.shields.io/codecov/c/github/NG-ZORRO/ng-zorro-antd.svg?style=flat-square)](https://codecov.io/gh/NG-ZORRO/ng-zorro-antd)\n[![GitHub Release Date](https://img.shields.io/github/release-date/NG-ZORRO/ng-zorro-antd.svg?style=flat-square)](https://github.com/NG-ZORRO/ng-zorro-antd/releases)\n[![NPM package](https://img.shields.io/npm/v/ng-zorro-antd.svg?style=flat-square)](https://npmjs.org/package/ng-zorro-antd)\n[![NPM downloads](http://img.shields.io/npm/dm/ng-zorro-antd.svg?style=flat-square)](https://npmjs.org/package/ng-zorro-antd)\n[![GitHub license](https://img.shields.io/github/license/mashape/apistatus.svg?style=flat-square)](https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE)\n[![Discord](https://img.shields.io/discord/1433686455925870594?style=flat-square&logo=discord&label=Discord)](https://discord.com/channels/1433686455925870594/1433686456706138195)\n[![VSCode Extension](https://img.shields.io/badge/extension%20for-VSCode-blue.svg?style=flat-square)](https://marketplace.visualstudio.com/items?itemName=cipchk.ng-zorro-vscode)\n[![Code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)\n[![X](https://img.shields.io/badge/NG--ZORRO-blue.svg?style=flat-square&logo=x)](http://x.com/ng_zorro)\n\n</div>\n\n[![logo](https://img.alicdn.com/tfs/TB1t6QPylr0gK0jSZFnXXbRRXXa-4000-1378.png)](http://ng.ant.design)\n\nEnglish | [简体中文](README-zh_CN.md)\n\n## ✨ Features\n\n- An enterprise-class UI design system for Angular applications.\n- 70+ high-quality Angular components out of the box.\n- Written in TypeScript with predictable static types.\n- The whole package of development and design resources and tools.\n- Support Zoneless and OnPush mode, high performance.\n- Powerful theme customization in every detail.\n- Internationalization support for dozens of languages.\n\n## ☀️ License\n\n[![GitHub license](https://img.shields.io/github/license/mashape/apistatus.svg?style=flat-square)](https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE)\n[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FNG-ZORRO%2Fng-zorro-antd.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2FNG-ZORRO%2Fng-zorro-antd?ref=badge_shield)\n\n## 🖥 Environment Support\n\n- Angular `^21.0.0` [![npm package](https://img.shields.io/npm/v/ng-zorro-antd.svg?style=flat-square)](https://www.npmjs.org/package/ng-zorro-antd)\n- Server-side Rendering\n- Modern browsers including the following [specific versions](https://angular.dev/reference/versions#browser-support)\n- [Electron](http://electron.atom.io/)\n\n| [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png\" alt=\"Edge\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png\" alt=\"Firefox\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png\" alt=\"Chrome\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png\" alt=\"Safari\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png\" alt=\"Opera\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Opera | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/electron/electron_48x48.png\" alt=\"Electron\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Electron |\n| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| last 2 versions                                                                                                                                                                                       | last 2 versions                                                                                                                                                                                                   | last 2 versions                                                                                                                                                                                               | last 2 versions                                                                                                                                                                                               | last 2 versions                                                                                                                                                                                           | last 2 versions                                                                                                                                                                                                       |\n\n## 🎨 Design Specification\n\n`ng-zorro-antd` synchronizes design specification with [Ant Design](https://ant.design/docs/spec/introduce) on a regular basis, you can check the [log](https://nz-styles-syncer.now.sh/) online.\n\n## 📦 Installation\n\n**We recommend using `@angular/cli` to install**. It not only makes development easier, but also allows you to take advantage of the rich ecosystem of angular packages and tooling.\n\n```bash\n$ ng new PROJECT_NAME\n$ cd PROJECT_NAME\n$ ng add ng-zorro-antd\n```\n\n> More information about `@angular/cli` [here](https://github.com/angular/angular-cli).\n\nYou can also install `ng-zorro-antd` with npm or yarn\n\n```bash\n$ npm install ng-zorro-antd\n```\n\n## 🔨 Usage\n\nImport the component modules you want to use into your component.\n\n```ts\nimport { NzButtonModule } from 'ng-zorro-antd/button';\n\n@Component({\n  imports: [NzButtonModule]\n})\nexport class AppComponent {}\n```\n\n> `@angular/cli` users won't have to worry about the things below but it's good to know.\n\nAnd import style and SVG icon assets file link in `angular.json`.\n\n```diff\n{\n  \"assets\": [\n+   {\n+     \"glob\": \"**/*\",\n+     \"input\": \"./node_modules/@ant-design/icons-angular/src/inline-svg/\",\n+     \"output\": \"/assets/\"\n+   }\n  ],\n  \"styles\": [\n+   \"node_modules/ng-zorro-antd/ng-zorro-antd.min.css\"\n  ]\n}\n```\n\nSee [Getting Started](https://ng.ant.design/docs/getting-started/en) for more details.\n\n## 🔗 Links\n\n- [ng-zorro-antd-mobile](https://github.com/NG-ZORRO/ng-zorro-antd-mobile)\n- [ng-alain](https://github.com/ng-alain/ng-alain)\n- [Snippet extension for VSCode](https://marketplace.visualstudio.com/items?itemName=cipchk.ng-zorro-vscode)\n\n## ⌨️ Development\n\n```bash\n$ git clone git@github.com:NG-ZORRO/ng-zorro-antd.git\n$ cd ng-zorro-antd\n$ npm install\n$ npm run start\n```\n\nBrowser would open automatically.\n\n## 🤝 Contributing\n\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/NG-ZORRO/ng-zorro-antd/pulls)\n\nWe welcome all contributions. Please read our [CONTRIBUTING.md](https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/CONTRIBUTING.md) first. You can submit any ideas as [pull requests](https://github.com/NG-ZORRO/ng-zorro-antd/pulls) or as [GitHub issues](https://github.com/NG-ZORRO/ng-zorro-antd/issues).\n\n> If you're new to posting issues, we ask that you read [_How To Ask Questions The Smart Way_](http://www.catb.org/~esr/faqs/smart-questions.html) (**This guide does not provide actual support services for this project!**), [How to Ask a Question in Open Source Community](https://github.com/seajs/seajs/issues/545) and [How to Report Bugs Effectively](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html) prior to posting. Well written bug reports help us help you!\n\nThanks to [JetBrains](https://www.jetbrains.com/?from=ng-zorro-antd) for supporting us free open source licenses.\n\n[![JetBrains](https://img.alicdn.com/tfs/TB1sSomo.z1gK0jSZLeXXb9kVXa-120-130.svg)](https://www.jetbrains.com/?from=ng-zorro-antd)\n\n## ❓ Help from the Community\n\nFor questions on how to use ng-zorro-antd, please post questions to [<img alt=\"Stack Overflow\" src=\"https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-logo.svg?v=2bb144720a66\" width=\"140\" />](http://stackoverflow.com/questions/tagged/ng-zorro-antd) using the `ng-zorro-antd` tag. If you're not finding what you need on stackoverflow, you can find us on [![Discord](https://img.shields.io/discord/748677963142135818?label=Discord&style=flat-square)](https://discord.com/channels/748677963142135818/764322550712893451) as well.\n\nAs always, we encourage experienced users to help those who are not familiar with `ng-zorro-antd`!\n\n## 🎉 Users\n\n- [Alibaba](https://www.alibaba.com/)\n- [Aliyun](https://www.aliyun.com/)\n- [ThoughtWorks](https://www.thoughtworks.com/)\n- [China Merchants Bank](http://english.cmbchina.com/)\n- [Ververica](https://www.ververica.com/)\n- [Apache Flink](https://flink.apache.org/)\n- [Apache Zeppelin](https://zeppelin.apache.org/)\n- [Apache Submarine](https://submarine.apache.org/)\n- [Apache Metron](https://metron.apache.org/)\n- [Process Automation Group](http://pag.company/)\n- [AISINOCO](http://www.aisino.com/)\n- [GongDao](https://www.gongdao.com/)\n- [UC Express](http://www.uce.cn/)\n- [Qingflow](https://qingflow.com/)\n- [DataGrand](http://datagrand.com/)\n- [ScentBird](https://www.scentbird.com/)\n- [Southern Institute of Technology](https://www.sit.ac.nz/)\n- [Hapify (Dynamic boilerplates tool)](https://hub.hapify.io/)\n\n> We list some users here, if your company or product uses NG-ZORRO, let us know [here](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1142)!\n\n**Love ng-zorro-antd? Give our repo a star :star: :arrow_up:.**\n"
  },
  {
    "path": "angular.json",
    "content": "{\n  \"$schema\": \"./node_modules/@angular/cli/lib/config/schema.json\",\n  \"version\": 1,\n  \"newProjectRoot\": \"projects\",\n  \"projects\": {\n    \"ng-zorro-antd-doc\": {\n      \"root\": \"\",\n      \"sourceRoot\": \"site\",\n      \"projectType\": \"application\",\n      \"architect\": {\n        \"build\": {\n          \"builder\": \"@angular/build:application\",\n          \"options\": {\n            \"outputPath\": \"dist\",\n            \"index\": \"site/index.html\",\n            \"browser\": \"site/main.ts\",\n            \"server\": \"site/main.server.ts\",\n            \"tsConfig\": \"site/tsconfig.app.json\",\n            \"serviceWorker\": \"ngsw-config.json\",\n            \"prerender\": true,\n            \"ssr\": {\n              \"entry\": \"site/server.ts\"\n            },\n            \"assets\": [\n              \"site/assets\",\n              \"site/manifest.json\",\n              \"site/favicon.ico\",\n              \"site/404.html\",\n              \"site/google854eb8b183564acb.html\",\n              \"site/robots.txt\",\n              \"site/llms.txt\",\n              \"site/llms-full.txt\",\n              {\n                \"glob\": \"**/*\",\n                \"input\": \"node_modules/@ant-design/icons-angular/src/inline-svg/\",\n                \"output\": \"/assets/\"\n              },\n              {\n                \"glob\": \"**/*\",\n                \"input\": \"node_modules/monaco-editor/min/vs\",\n                \"output\": \"/assets/vs/\"\n              }\n            ],\n            \"styles\": [\n              \"site/styles.less\"\n            ],\n            \"allowedCommonJsDependencies\": [\n              \"@ant-design/colors\",\n              \"cron-parser\"\n            ]\n          },\n          \"configurations\": {\n            \"production\": {\n              \"fileReplacements\": [\n                {\n                  \"replace\": \"site/environments/environment.ts\",\n                  \"with\": \"site/environments/environment.prod.ts\"\n                }\n              ],\n              \"outputHashing\": \"all\"\n            },\n            \"development\": {\n              \"optimization\": false,\n              \"extractLicenses\": false,\n              \"sourceMap\": true,\n              \"namedChunks\": true\n            }\n          },\n          \"defaultConfiguration\": \"production\"\n        },\n        \"serve\": {\n          \"builder\": \"@angular/build:dev-server\",\n          \"options\": {\n            \"buildTarget\": \"ng-zorro-antd-doc:build\"\n          },\n          \"configurations\": {\n            \"production\": {\n              \"buildTarget\": \"ng-zorro-antd-doc:build:production\"\n            },\n            \"development\": {\n              \"buildTarget\": \"ng-zorro-antd-doc:build:development\"\n            }\n          },\n          \"defaultConfiguration\": \"development\"\n        }\n      }\n    },\n    \"ng-zorro-antd-lib\": {\n      \"root\": \"components\",\n      \"sourceRoot\": \"components\",\n      \"projectType\": \"library\",\n      \"prefix\": \"nz\",\n      \"architect\": {\n        \"build\": {\n          \"builder\": \"@angular/build:ng-packagr\",\n          \"options\": {\n            \"project\": \"components/ng-package.json\"\n          },\n          \"configurations\": {\n            \"production\": {\n              \"tsConfig\": \"components/tsconfig.lib.prod.json\"\n            },\n            \"development\": {\n              \"tsConfig\": \"components/tsconfig.lib.json\"\n            }\n          },\n          \"defaultConfiguration\": \"production\"\n        },\n        \"test\": {\n          \"builder\": \"@angular/build:karma\",\n          \"options\": {\n            \"aot\": true,\n            \"inlineStyleLanguage\": \"less\",\n            \"fileReplacements\": [\n              {\n                \"replace\": \"components/core/environments/environment.ts\",\n                \"with\": \"components/core/environments/environment.test.ts\"\n              }\n            ],\n            \"assets\": [\n              {\n                \"glob\": \"**/*\",\n                \"input\": \"node_modules/monaco-editor/min/vs\",\n                \"output\": \"/assets/vs/\"\n              }\n            ],\n            \"main\": \"components/test.ts\",\n            \"karmaConfig\": \"components/karma.conf.js\",\n            \"polyfills\": [\n              \"zone.js\",\n              \"zone.js/testing\"\n            ],\n            \"tsConfig\": \"components/tsconfig.spec.json\",\n            \"scripts\": []\n          }\n        },\n        \"lint\": {\n          \"builder\": \"@angular-eslint/builder:lint\",\n          \"options\": {\n            \"fix\": true,\n            \"lintFilePatterns\": [\n              \"components/**/*.ts\",\n              \"components/**/*.html\"\n            ]\n          }\n        }\n      }\n    }\n  },\n  \"schematics\": {\n    \"@schematics/angular:component\": {\n      \"prefix\": \"app\",\n      \"style\": \"less\",\n      \"type\": \"component\"\n    },\n    \"@schematics/angular:directive\": {\n      \"prefix\": \"app\",\n      \"type\": \"directive\"\n    },\n    \"@schematics/angular:service\": {\n      \"type\": \"service\"\n    },\n    \"@schematics/angular:guard\": {\n      \"typeSeparator\": \".\"\n    },\n    \"@schematics/angular:interceptor\": {\n      \"typeSeparator\": \".\"\n    },\n    \"@schematics/angular:module\": {\n      \"typeSeparator\": \".\"\n    },\n    \"@schematics/angular:pipe\": {\n      \"typeSeparator\": \".\"\n    },\n    \"@schematics/angular:resolver\": {\n      \"typeSeparator\": \".\"\n    }\n  },\n  \"cli\": {\n    \"analytics\": false\n  }\n}\n"
  },
  {
    "path": "azure-pipelines.yml",
    "content": "# Node.js with Angular\n# Build a Node.js project that uses Angular.\n# Add steps that analyze code, save build artifacts, deploy, and more:\n# https://docs.microsoft.com/azure/devops/pipelines/languages/javascript\n\ntrigger:\n- master\n\npool:\n  vmImage: 'ubuntu-latest'\n\nstages:\n- stage: env\n  jobs:\n    - job: Nodes\n      steps:\n      - task: NodeTool@0\n        inputs:\n          versionSpec: '20.19.0'\n        displayName: 'Install Node.js'\n\n- stage: build\n  jobs:\n    - job: build_site\n      steps:\n        - task: NodeTool@0\n          displayName: 'Install Node.js'\n          inputs:\n            versionSpec: '20.19.0' # The version we're installing\n        - task: Npm@1\n          inputs:\n            command: 'ci'\n        - script: |\n            npm run build\n            export DEPLOY_DOMAIN=https://preview-${SYSTEM_PULLREQUEST_PULLREQUESTNUMBER}-ng-zorro-antd.surge.sh\n            echo 'version' >> dist/browser/.surgeignore\n            echo 'issue-helper' >> dist/browser/.surgeignore\n            npx surge --project ./dist/browser --domain $DEPLOY_DOMAIN\n            tar --transform='flags=r;s|browser|dist|' -cvzf build.tgz lib -C dist browser\n\n        - task: CopyFiles@2\n          inputs:\n            contents: build.tgz\n            targetFolder: $(Build.ArtifactStagingDirectory)\n          displayName: 'Copy archives to artifacts staging directory'\n        - task: PublishBuildArtifacts@1\n          inputs:\n            path: $(Build.ArtifactStagingDirectory)\n          displayName: 'Upload artifacts'\n\n  dependsOn: env\n\n- stage: test\n  jobs:\n    - job: test_components\n      steps:\n        - task: Npm@1\n          inputs:\n            command: 'ci'\n        - script: npm run test\n          displayName: 'Run tests'\n        - script: cat ./coverage-report/lcov.info | npx -y codecov@3.8.2\n          displayName: 'Upload coverage to Codecov'\n          condition: succeededOrFailed()\n\n        - task: PublishCodeCoverageResults@1\n          displayName: 'Publish code coverage results'\n          condition: succeededOrFailed()\n          inputs:\n            codeCoverageTool: Cobertura\n            summaryFileLocation: $(System.DefaultWorkingDirectory)/coverage-report/cobertura-coverage.xml\n            reportDirectory: $(System.DefaultWorkingDirectory)/coverage-report\n            failIfCoverageEmpty: true\n\n        - task: PublishTestResults@2\n          displayName: 'Publish test results'\n          condition: succeededOrFailed()\n          inputs:\n            searchFolder: $(System.DefaultWorkingDirectory)/junit\n            failTaskOnFailedTests: true\n            testRunTitle: NG-ZORRO\n            testResultsFormat: JUnit\n            testResultsFiles: \"**/TESTS*.xml\"\n\n    - job: test_schematics\n      steps:\n        - task: Npm@1\n          inputs:\n            command: 'ci'\n        - script: npm run test:schematics\n\n  dependsOn: env\n\n- stage: lint\n  jobs:\n    - job: lint_components\n      steps:\n        - task: Npm@1\n          inputs:\n            command: 'ci'\n        - script: npm run lint\n  dependsOn: env\n"
  },
  {
    "path": "build-config.js",
    "content": "const { join } = require('path');\n\nconst packageJson = require(`${__dirname}/components/package.json`);\nconst buildVersion = packageJson.version;\n\nmodule.exports = {\n  projectVersion: buildVersion,\n  projectDir: __dirname,\n  componentsDir: join(__dirname, 'components'),\n  scriptsDir: join(__dirname, 'scripts'),\n  outputDir: join(__dirname, 'dist'),\n  publishDir: join(__dirname, 'publish'),\n  libDir: join(__dirname, 'lib')\n};\n"
  },
  {
    "path": "commitlint.config.js",
    "content": "'use strict';\nconst message = process.env['HUSKY_GIT_PARAMS'];\nconst fs = require('fs');\n\nconst types = ['build', 'chore', 'ci', 'docs', 'feat', 'fix', 'perf', 'refactor', 'release', 'revert', 'style', 'test'];\n\nconst scopes = ['showcase', 'release', 'packaging', 'changelog', 'schematics', 'module:*'];\n\nfunction parseMessage(message) {\n  const PATTERN = /^(\\w+)(?:\\(([^)]+)\\))?\\: (.+)$/;\n  const match = PATTERN.exec(message);\n  if (!match) {\n    return null;\n  }\n  return {\n    type: match[1] || null,\n    scope: match[2] || null\n  };\n}\n\nfunction getScopesRule() {\n  const messages = fs.readFileSync(message, { encoding: 'utf-8' });\n  const parsed = parseMessage(messages.split('\\n')[0]);\n  if (!parsed) {\n    return [2, 'always', scopes];\n  }\n  const { scope, type } = parsed;\n  if (scope && !scopes.includes(scope) && type !== 'release' && !/module:.+/.test(scope)) {\n    return [2, 'always', scopes];\n  } else {\n    return [2, 'always', []];\n  }\n}\n\nmodule.exports = {\n  extends: ['@commitlint/config-angular'],\n  rules: {\n    'type-enum': [2, 'always', types],\n    'scope-enum': getScopesRule\n  }\n};\n"
  },
  {
    "path": "components/affix/affix.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { Platform } from '@angular/cdk/platform';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  DestroyRef,\n  DOCUMENT,\n  effect,\n  ElementRef,\n  inject,\n  Input,\n  NgZone,\n  OnChanges,\n  output,\n  Renderer2,\n  SimpleChanges,\n  ViewChild,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { fromEvent, merge, ReplaySubject, Subscription } from 'rxjs';\nimport { map, throttleTime } from 'rxjs/operators';\n\nimport { NzResizeObserver } from 'ng-zorro-antd/cdk/resize-observer';\nimport { NzConfigKey, WithConfig } from 'ng-zorro-antd/core/config';\nimport { NzScrollService } from 'ng-zorro-antd/core/services';\nimport { NgStyleInterface } from 'ng-zorro-antd/core/types';\nimport { getStyleAsText, numberAttributeWithZeroFallback, shallowEqual } from 'ng-zorro-antd/core/util';\n\nimport { AffixRespondEvents } from './respond-events';\nimport { getTargetRect, SimpleRect } from './utils';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'affix';\nconst NZ_AFFIX_CLS_PREFIX = 'ant-affix';\nconst NZ_AFFIX_DEFAULT_SCROLL_TIME = 20;\nconst NOOP_EVENT = {} as Event;\n\n@Component({\n  selector: 'nz-affix',\n  exportAs: 'nzAffix',\n  template: `\n    <div #fixedEl>\n      <ng-content />\n    </div>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None\n})\nexport class NzAffixComponent implements OnChanges {\n  private readonly scrollSrv = inject(NzScrollService);\n  private readonly ngZone = inject(NgZone);\n  private readonly platform = inject(Platform);\n  private readonly renderer = inject(Renderer2);\n  private readonly nzResizeObserver = inject(NzResizeObserver);\n  private readonly directionality = inject(Directionality);\n  private readonly destroyRef = inject(DestroyRef);\n  private readonly document = inject(DOCUMENT);\n  private readonly placeholderNode: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement;\n\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  @ViewChild('fixedEl', { static: true }) private fixedEl!: ElementRef<HTMLDivElement>;\n\n  @Input() nzTarget?: string | Element | Window;\n\n  @Input({ transform: numberAttributeWithZeroFallback })\n  @WithConfig()\n  nzOffsetTop?: null | number;\n\n  @Input({ transform: numberAttributeWithZeroFallback })\n  @WithConfig()\n  nzOffsetBottom?: null | number;\n\n  readonly nzChange = output<boolean>();\n\n  private affixStyle?: NgStyleInterface;\n  private placeholderStyle?: NgStyleInterface;\n  private positionChangeSubscription = Subscription.EMPTY;\n  private offsetChanged$ = new ReplaySubject<void>(1);\n  private timeout?: ReturnType<typeof setTimeout>;\n\n  private get target(): Element | Window {\n    const el = this.nzTarget;\n    return (typeof el === 'string' ? this.document.querySelector(el) : el) || window;\n  }\n\n  constructor() {\n    effect(() => {\n      this.directionality.valueSignal();\n      this.registerListeners();\n      this.updatePosition(NOOP_EVENT);\n    });\n\n    this.destroyRef.onDestroy(() => {\n      this.removeListeners();\n    });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzOffsetBottom, nzOffsetTop, nzTarget } = changes;\n\n    if (nzOffsetBottom || nzOffsetTop) {\n      this.offsetChanged$.next();\n    }\n    if (nzTarget) {\n      this.registerListeners();\n    }\n  }\n\n  private registerListeners(): void {\n    if (!this.platform.isBrowser) {\n      return;\n    }\n\n    this.removeListeners();\n    const el = this.target === window ? this.document.body : (this.target as Element);\n    this.positionChangeSubscription = this.ngZone.runOutsideAngular(() =>\n      merge(\n        ...Object.keys(AffixRespondEvents).map(evName => fromEvent(this.target, evName)),\n        this.offsetChanged$.pipe(map(() => NOOP_EVENT)),\n        this.nzResizeObserver.observe(el)\n      )\n        .pipe(\n          throttleTime(NZ_AFFIX_DEFAULT_SCROLL_TIME, undefined, { trailing: true }),\n          takeUntilDestroyed(this.destroyRef)\n        )\n        .subscribe(e => this.updatePosition(e as Event))\n    );\n    this.timeout = setTimeout(() => this.updatePosition(NOOP_EVENT));\n  }\n\n  private removeListeners(): void {\n    clearTimeout(this.timeout);\n    this.positionChangeSubscription.unsubscribe();\n  }\n\n  getOffset(element: Element, target: Element | Window | undefined): SimpleRect {\n    const elemRect = element.getBoundingClientRect();\n    const targetRect = getTargetRect(target!);\n\n    const scrollTop = this.scrollSrv.getScroll(target, true);\n    const scrollLeft = this.scrollSrv.getScroll(target, false);\n\n    const docElem = this.document.body;\n    const clientTop = docElem.clientTop || 0;\n    const clientLeft = docElem.clientLeft || 0;\n\n    return {\n      top: elemRect.top - targetRect.top + scrollTop - clientTop,\n      left: elemRect.left - targetRect.left + scrollLeft - clientLeft,\n      width: elemRect.width,\n      height: elemRect.height\n    };\n  }\n\n  private setAffixStyle(e: Event, affixStyle?: NgStyleInterface): void {\n    const originalAffixStyle = this.affixStyle;\n    if (e.type === 'scroll' && originalAffixStyle && affixStyle && this.target === window) {\n      return;\n    }\n    if (shallowEqual(originalAffixStyle, affixStyle)) {\n      return;\n    }\n\n    const fixed = !!affixStyle;\n    const wrapEl = this.fixedEl.nativeElement;\n    this.renderer.setStyle(wrapEl, 'cssText', getStyleAsText(affixStyle));\n    this.affixStyle = affixStyle;\n    if (fixed) {\n      wrapEl.classList.add(NZ_AFFIX_CLS_PREFIX);\n    } else {\n      wrapEl.classList.remove(NZ_AFFIX_CLS_PREFIX);\n    }\n    this.updateRtlClass();\n    if ((affixStyle && !originalAffixStyle) || (!affixStyle && originalAffixStyle)) {\n      this.nzChange.emit(fixed);\n    }\n  }\n\n  private setPlaceholderStyle(placeholderStyle?: NgStyleInterface): void {\n    const originalPlaceholderStyle = this.placeholderStyle;\n    if (shallowEqual(placeholderStyle, originalPlaceholderStyle)) {\n      return;\n    }\n    this.renderer.setStyle(this.placeholderNode, 'cssText', getStyleAsText(placeholderStyle));\n    this.placeholderStyle = placeholderStyle;\n  }\n\n  private syncPlaceholderStyle(e: Event): void {\n    if (!this.affixStyle) {\n      return;\n    }\n    this.renderer.setStyle(this.placeholderNode, 'cssText', '');\n    this.placeholderStyle = undefined;\n    const styleObj = {\n      width: this.placeholderNode.offsetWidth,\n      height: this.fixedEl.nativeElement.offsetHeight\n    };\n    this.setAffixStyle(e, {\n      ...this.affixStyle,\n      ...styleObj\n    });\n    this.setPlaceholderStyle(styleObj);\n  }\n\n  updatePosition(e: Event): void {\n    if (!this.platform.isBrowser) {\n      return;\n    }\n\n    const targetNode = this.target;\n    let offsetTop = this.nzOffsetTop;\n    const scrollTop = this.scrollSrv.getScroll(targetNode, true);\n    const elemOffset = this.getOffset(this.placeholderNode, targetNode!);\n    const fixedNode = this.fixedEl.nativeElement;\n    const elemSize = {\n      width: fixedNode.offsetWidth,\n      height: fixedNode.offsetHeight\n    };\n    const offsetMode = {\n      top: false,\n      bottom: false\n    };\n    // Default to `offsetTop=0`.\n    if (typeof offsetTop !== 'number' && typeof this.nzOffsetBottom !== 'number') {\n      offsetMode.top = true;\n      offsetTop = 0;\n    } else {\n      offsetMode.top = typeof offsetTop === 'number';\n      offsetMode.bottom = typeof this.nzOffsetBottom === 'number';\n    }\n    const targetRect = getTargetRect(targetNode);\n    const targetInnerHeight = (targetNode as Window).innerHeight || (targetNode as HTMLElement).clientHeight;\n    if (scrollTop >= elemOffset.top - (offsetTop as number) && offsetMode.top) {\n      const width = elemOffset.width;\n      const top = targetRect.top + (offsetTop as number);\n      this.setAffixStyle(e, {\n        position: 'fixed',\n        top,\n        left: targetRect.left + elemOffset.left,\n        width\n      });\n      this.setPlaceholderStyle({\n        width,\n        height: elemSize.height\n      });\n    } else if (\n      scrollTop <= elemOffset.top + elemSize.height + (this.nzOffsetBottom as number) - targetInnerHeight &&\n      offsetMode.bottom\n    ) {\n      const targetBottomOffset = targetNode === window ? 0 : window.innerHeight - targetRect.bottom!;\n      const width = elemOffset.width;\n      this.setAffixStyle(e, {\n        position: 'fixed',\n        bottom: targetBottomOffset + (this.nzOffsetBottom as number),\n        left: targetRect.left + elemOffset.left,\n        width\n      });\n      this.setPlaceholderStyle({\n        width,\n        height: elemOffset.height\n      });\n    } else {\n      if (\n        e.type === AffixRespondEvents.resize &&\n        this.affixStyle &&\n        this.affixStyle.position === 'fixed' &&\n        this.placeholderNode.offsetWidth\n      ) {\n        this.setAffixStyle(e, {\n          ...this.affixStyle,\n          width: this.placeholderNode.offsetWidth\n        });\n      } else {\n        this.setAffixStyle(e);\n      }\n      this.setPlaceholderStyle();\n    }\n\n    if (e.type === 'resize') {\n      this.syncPlaceholderStyle(e);\n    }\n  }\n\n  private updateRtlClass(): void {\n    const wrapEl = this.fixedEl.nativeElement;\n    if (this.directionality.valueSignal() === 'rtl' && wrapEl.classList.contains(NZ_AFFIX_CLS_PREFIX)) {\n      wrapEl.classList.add(`${NZ_AFFIX_CLS_PREFIX}-rtl`);\n    } else {\n      wrapEl.classList.remove(`${NZ_AFFIX_CLS_PREFIX}-rtl`);\n    }\n  }\n}\n"
  },
  {
    "path": "components/affix/affix.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzAffixComponent } from './affix.component';\n\n@NgModule({\n  exports: [NzAffixComponent],\n  imports: [NzAffixComponent]\n})\nexport class NzAffixModule {}\n"
  },
  {
    "path": "components/affix/affix.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { Platform } from '@angular/cdk/platform';\nimport { Component, DebugElement, DOCUMENT, ElementRef, Renderer2, ViewChild } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { Subscription } from 'rxjs';\n\nimport { NzScrollService } from 'ng-zorro-antd/core/services';\nimport { provideMockDirectionality, sleep } from 'ng-zorro-antd/core/testing';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { toCssPixelNumber } from 'ng-zorro-antd/core/util';\n\nimport { NzAffixComponent } from './affix.component';\n\ninterface Offset {\n  top: number;\n  left: number;\n  width: number;\n  height: number;\n}\n\ninterface Scroll {\n  top: number;\n  left: number;\n}\n\ndescribe('affix', () => {\n  let scrollService: NzScrollService;\n  let fixture: ComponentFixture<TestAffixComponent>;\n  let context: TestAffixComponent;\n  let debugElement: DebugElement;\n  let component: NzAffixComponent;\n  let componentObject: NzAffixPageObject;\n  const defaultOffsetTop = 0;\n  const scrollEvent: Event = new Event('scroll');\n  const startOffset = 10;\n  const handledEvents: Event[] = [\n    scrollEvent,\n    new Event('resize'),\n    new Event('touchstart'),\n    new Event('touchmove'),\n    new Event('touchend'),\n    new Event('pageshow'),\n    new Event('load')\n  ];\n  const height = 100;\n  const width = 100;\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(TestAffixComponent);\n    context = fixture.componentInstance;\n    component = context.nzAffixComponent;\n    scrollService = TestBed.inject(NzScrollService);\n    componentObject = new NzAffixPageObject();\n    debugElement = fixture.debugElement;\n    componentObject.wrap().id = 'wrap';\n  });\n\n  describe('basic', () => {\n    it('recreate bug https://github.com/NG-ZORRO/ng-zorro-antd/issues/671', async () => {\n      const edge = defaultOffsetTop + startOffset;\n      await setupInitialState();\n      await emitScroll(window, edge + 2);\n      componentObject.emitScroll(window, edge + 1);\n      componentObject.emitScroll(window, edge);\n      componentObject.emitScroll(window, edge - 1);\n      await sleep(100);\n\n      expect(componentObject.wrap().offsetTop).not.toBe(defaultOffsetTop);\n    });\n\n    describe('when scrolled within top offset', () => {\n      it('scrolls with the content', async () => {\n        await setupInitialState();\n        await emitScroll(window, defaultOffsetTop + startOffset - 1);\n\n        expect(componentObject.wrap().offsetTop !== defaultOffsetTop).toBe(true);\n      });\n    });\n\n    describe('when scrolled below the top offset', () => {\n      it('sticks to the top offset', async () => {\n        await setupInitialState();\n        await emitScroll(window, defaultOffsetTop + startOffset + 1);\n        expect(componentObject.wrap().offsetTop).toBe(defaultOffsetTop);\n      });\n\n      describe('when element gets shifted horizontally', () => {\n        it('adjusts left position accordingly to maintain natural position', async () => {\n          await setupInitialState();\n          componentObject.offsetTo(componentObject.elementRef(), { top: startOffset, left: 10, width, height });\n          await emitScroll(window, defaultOffsetTop + startOffset + 1);\n\n          expect(componentObject.wrap().offsetLeft).toBe(10);\n\n          await emitScroll(window, defaultOffsetTop + startOffset - 1);\n          componentObject.offsetTo(componentObject.elementRef(), { top: startOffset, left: 100, width, height });\n          await emitScroll(window, defaultOffsetTop + startOffset + 1);\n\n          expect(componentObject.wrap().offsetLeft).toBe(100);\n        });\n      });\n\n      for (const event of handledEvents) {\n        it(`handles '${event.type}' event`, async () => {\n          await setupInitialState();\n          await emitScroll(window, defaultOffsetTop + startOffset + 1);\n\n          expect(componentObject.wrap().offsetTop).toBe(defaultOffsetTop);\n        });\n      }\n    });\n  });\n\n  describe('resize', () => {\n    it('should be reset placeholder size', async () => {\n      const offsetTop = 150;\n      context.newOffset = offsetTop;\n      await setupInitialState({ offsetTop: offsetTop + 1 });\n      const offsetWidthSpy = spyOnProperty(componentObject.elementRef(), 'offsetWidth', 'get');\n      await emitScroll(window, 2);\n      expect(componentObject.elementRef().style.width).toBe(`${width}px`);\n      componentObject.offsetYTo(componentObject.elementRef(), offsetTop + 2);\n      await sleep(20);\n\n      offsetWidthSpy.and.returnValue(100);\n      componentObject.emitEvent(window, new Event('resize'));\n      await sleep(20);\n\n      expect(componentObject.elementRef().style.width).toBe('100px');\n    });\n\n    it('should be reset placeholder size when container becomes greater', async () => {\n      const target = componentObject.target();\n      const clientHeightSpy = spyOnProperty(target, 'clientHeight', 'get');\n      context.fakeTarget = target;\n      context.newOffsetBottom = 10;\n      clientHeightSpy.and.returnValue(10);\n      await setupInitialState();\n      await emitScroll(target, 11);\n      clientHeightSpy.and.returnValue(100);\n      componentObject.emitEvent(target, new Event('resize'));\n      await sleep(20);\n\n      expect(componentObject.elementRef().style.width).toBe(`${componentObject.elementRef().offsetWidth}px`);\n    });\n  });\n\n  describe('[nzOffsetTop]', () => {\n    const offsetTop = 150;\n\n    beforeEach(() => {\n      context.newOffset = offsetTop;\n    });\n\n    describe('when scrolled within top offset', () => {\n      it('scrolls with the content', async () => {\n        await setupInitialState({ offsetTop: offsetTop + 1 });\n        await emitScroll(window, 0);\n\n        expect(componentObject.wrap().offsetTop !== offsetTop).toBe(true);\n      });\n    });\n\n    describe('when scrolled below the top offset', () => {\n      it('sticks to the top offset', async () => {\n        await setupInitialState({ offsetTop: offsetTop + 1 });\n        await emitScroll(window, 2);\n\n        expect(componentObject.wrap().offsetTop).toBe(offsetTop);\n      });\n    });\n\n    it('recreate bug https://github.com/NG-ZORRO/ng-zorro-antd/issues/868', async () => {\n      context.newOffset = offsetTop.toString() as NzSafeAny;\n      await setupInitialState({ offsetTop: offsetTop + 1 });\n      await emitScroll(window, 2);\n\n      expect(componentObject.wrap().offsetTop).toBe(offsetTop);\n    });\n  });\n\n  describe('[nzOffsetBottom]', () => {\n    const offsetTop = 0;\n    let target: HTMLElement | Window;\n\n    describe('with window', () => {\n      beforeEach(() => {\n        target = window;\n        context.fakeTarget = target;\n        context.newOffsetBottom = 10;\n      });\n\n      describe('when scrolled below the bottom offset', () => {\n        it('should stick to the bottom with the specified offset', async () => {\n          await setupInitialState({ offsetTop: 5000 });\n          expect(toCssPixelNumber(componentObject.wrap().style.bottom)).toBe(10);\n        });\n      });\n    });\n\n    describe('with target', () => {\n      beforeEach(() => {\n        target = componentObject.target();\n        context.fakeTarget = target;\n        context.newOffsetBottom = offsetTop;\n      });\n\n      describe('when scrolled within bottom offset', () => {\n        it('should scroll with the content', async () => {\n          await setupInitialState();\n          await emitScroll(target, 0);\n          expect(toCssPixelNumber(componentObject.wrap().style.bottom)).toBeGreaterThan(0);\n        });\n      });\n\n      describe('when scrolled below the bottom offset', () => {\n        it('should stick to the bottom offset', async () => {\n          await setupInitialState();\n          await emitScroll(target, 5000);\n          expect(toCssPixelNumber(componentObject.wrap().style.bottom)).toBe(0);\n        });\n      });\n    });\n  });\n\n  describe('[nzTarget]', () => {\n    let target: HTMLElement;\n\n    beforeEach(() => {\n      target = componentObject.target();\n      context.fakeTarget = target;\n    });\n\n    describe('when window is scrolled', () => {\n      it('scrolls with the content', async () => {\n        await setupInitialState();\n        await emitScroll(window, defaultOffsetTop + startOffset + 1);\n\n        expect(componentObject.elementRef().offsetTop !== defaultOffsetTop).toBe(true);\n      });\n    });\n\n    describe('when custom target is scrolled within top offset', () => {\n      it('scrolls with the content', async () => {\n        await setupInitialState();\n        await emitScroll(target, defaultOffsetTop + startOffset - 1);\n\n        expect(componentObject.elementRef().offsetTop !== defaultOffsetTop).toBe(true);\n      });\n    });\n\n    describe('when custom target is scrolled below the top offset', () => {\n      it('sticks to the top offset', async () => {\n        await setupInitialState();\n        await emitScroll(target, defaultOffsetTop + startOffset + 1);\n\n        expect(componentObject.elementRef().offsetTop !== defaultOffsetTop).toBe(true);\n      });\n    });\n\n    it('should be a string value', async () => {\n      spyOn(component, 'updatePosition');\n      expect(component.updatePosition).not.toHaveBeenCalled();\n\n      context.fakeTarget = '#target';\n      await fixture.whenStable();\n\n      expect(component.updatePosition).toHaveBeenCalled();\n    });\n  });\n\n  describe('(nzChange)', () => {\n    let changeValue: boolean;\n    beforeEach(() => {\n      component.nzChange.subscribe(returnValue => {\n        changeValue = returnValue;\n      });\n    });\n\n    it(`emit true when is affixed`, async () => {\n      await setupInitialState();\n      await emitScroll(window, defaultOffsetTop + startOffset + 1);\n\n      expect(changeValue).toBe(true);\n    });\n\n    it(`emit false when isn't affixed`, async () => {\n      await setupInitialState();\n      await emitScroll(window, defaultOffsetTop + startOffset + 1);\n      await emitScroll(window, defaultOffsetTop + startOffset - 1);\n\n      expect(changeValue).toBe(false);\n    });\n  });\n\n  class NzAffixPageObject {\n    offsets: Record<string, Offset>;\n    scrolls: Record<string, Scroll>;\n\n    constructor() {\n      spyOn(component, 'getOffset').and.callFake(this.getOffset.bind(this));\n      spyOn(scrollService, 'getScroll').and.callFake(this.getScroll.bind(this));\n      this.offsets = { undefined: { top: 10, left: 0, height: 0, width: 0 } };\n      this.scrolls = { undefined: { top: 10, left: 0 } };\n    }\n\n    getScroll(el?: Element | Window, top: boolean = true): number {\n      const ret = this.scrolls[this.getKey(el)] || { top: 0, left: 0 };\n      return top ? ret.top : ret.left;\n    }\n\n    getOffset(el: Element): Offset {\n      return this.offsets[el.id] || { top: 10, left: 0, height, width };\n    }\n\n    emitEvent(el: Element | Window, event: Event): void {\n      el.dispatchEvent(event);\n    }\n\n    emitScroll(el: Element | Window, top: number, left: number = 0): void {\n      this.scrolls[this.getKey(el)] = { top, left };\n      this.emitEvent(el || window, scrollEvent);\n    }\n\n    offsetTo(el: Element, offset: Offset): void {\n      this.offsets[this.getKey(el)] = {\n        top: offset.top,\n        left: offset.left,\n        height,\n        width\n      };\n    }\n\n    offsetYTo(el: Element, offsetTop: number): void {\n      this.offsetTo(el, {\n        top: offsetTop,\n        left: 0,\n        height,\n        width\n      });\n    }\n\n    elementRef(): HTMLElement {\n      return debugElement.query(By.css('nz-affix')).nativeElement;\n    }\n\n    wrap(): HTMLElement {\n      return debugElement.query(By.css('div')).nativeElement;\n    }\n\n    target(): HTMLElement {\n      return debugElement.query(By.css('#target')).nativeElement;\n    }\n\n    private getKey(el?: Element | Window): string {\n      let key: string;\n      if (el instanceof Window) {\n        key = 'window';\n      } else {\n        key = (el && el.id) || 'window';\n      }\n\n      return key;\n    }\n  }\n\n  async function setupInitialState(options: { offsetTop?: number } = {}): Promise<void> {\n    componentObject.offsetYTo(componentObject.elementRef(), options.offsetTop || startOffset);\n    await sleep(20);\n    await fixture.whenStable();\n    componentObject.emitScroll(window, 0);\n    await sleep(20);\n    await fixture.whenStable();\n  }\n\n  async function emitScroll(el: Element | Window, offset: number): Promise<void> {\n    componentObject.emitScroll(el, offset);\n    await sleep(20);\n    await fixture.whenStable();\n  }\n});\n\n@Component({\n  imports: [NzAffixComponent],\n  template: `\n    <nz-affix id=\"affix\" [nzTarget]=\"fakeTarget\" [nzOffsetTop]=\"newOffset\" [nzOffsetBottom]=\"newOffsetBottom\">\n      <button id=\"content\">Affix Button</button>\n    </nz-affix>\n    <div id=\"target\"></div>\n  `\n})\nclass TestAffixComponent {\n  @ViewChild(NzAffixComponent, { static: true }) nzAffixComponent!: NzAffixComponent;\n  fakeTarget?: string | Element | Window;\n  newOffset!: number;\n  newOffsetBottom!: number;\n}\n\ndescribe('NzAffixComponent', () => {\n  let component: NzAffixComponent;\n  let fixture: ComponentFixture<NzAffixComponent>;\n  let mockPlatform: Platform;\n  let mockDirectionality: Directionality;\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [\n        NzAffixComponent,\n        NzScrollService,\n        { provide: Renderer2, useValue: jasmine.createSpyObj('Renderer2', ['setStyle', 'addClass', 'removeClass']) },\n        { provide: ElementRef, useValue: new ElementRef(document.createElement('div')) },\n        { provide: DOCUMENT, useValue: document },\n        provideMockDirectionality(),\n        { provide: Platform, useValue: { isBrowser: true } }\n      ]\n    });\n\n    fixture = TestBed.createComponent(NzAffixComponent);\n    component = fixture.componentInstance;\n    mockPlatform = TestBed.inject(Platform);\n    mockDirectionality = TestBed.inject(Directionality);\n  });\n\n  it('should handle directionality change', async () => {\n    spyOn<NzSafeAny>(component, 'registerListeners');\n    spyOn(component, 'updatePosition');\n\n    await fixture.whenStable();\n\n    expect(component['registerListeners']).toHaveBeenCalledTimes(1);\n    expect(component.updatePosition).toHaveBeenCalledTimes(1);\n\n    mockDirectionality.valueSignal.set('rtl');\n    await fixture.whenStable();\n\n    expect(component['registerListeners']).toHaveBeenCalledTimes(2);\n    expect(component.updatePosition).toHaveBeenCalledTimes(2);\n  });\n\n  it('should register listeners if platform is browser', async () => {\n    spyOn(component as NzSafeAny, 'removeListeners');\n\n    await fixture.whenStable();\n\n    expect(component['removeListeners']).toHaveBeenCalled();\n    expect(component['positionChangeSubscription']).toBeDefined();\n    expect(component['timeout']).toBeDefined();\n  });\n\n  it('should not register listeners if platform is not browser', async () => {\n    mockPlatform.isBrowser = false;\n\n    await fixture.whenStable();\n\n    expect(component['positionChangeSubscription']).toEqual(Subscription.EMPTY);\n  });\n\n  it('should remove listeners on destroy', () => {\n    spyOn(component as NzSafeAny, 'removeListeners');\n    fixture.destroy();\n    expect(component['removeListeners']).toHaveBeenCalled();\n  });\n\n  it('should update position correctly', () => {\n    spyOn<NzSafeAny>(component, 'setAffixStyle');\n    spyOn<NzSafeAny>(component, 'setPlaceholderStyle');\n\n    const event = new Event('scroll');\n    component.updatePosition(event);\n\n    expect(component['setAffixStyle']).toHaveBeenCalled();\n    expect(component['setPlaceholderStyle']).toHaveBeenCalled();\n  });\n\n  it('should update RTL class when direction changes', () => {\n    const fixedEl = component['fixedEl'].nativeElement;\n    fixedEl.classList.add('ant-affix');\n    component['updateRtlClass']();\n\n    expect(fixedEl.classList.contains('ant-affix-rtl')).toBeFalse();\n\n    mockDirectionality.valueSignal.set('rtl');\n    component['updateRtlClass']();\n\n    expect(fixedEl.classList.contains('ant-affix-rtl')).toBeTrue();\n\n    mockDirectionality.valueSignal.set('ltr');\n    component['updateRtlClass']();\n\n    expect(fixedEl.classList.contains('ant-affix-rtl')).toBeFalse();\n\n    mockDirectionality.valueSignal.set('rtl');\n    fixedEl.classList.remove('ant-affix');\n    fixedEl.classList.add('ant-affix-rtl');\n    component['updateRtlClass']();\n\n    expect(component['fixedEl'].nativeElement.classList.contains('ant-affix-rtl')).toBeFalse();\n  });\n\n  it('should not perform position updates if platform is not browser', () => {\n    mockPlatform.isBrowser = false;\n    spyOn<NzSafeAny>(component, 'getOffset');\n\n    component.updatePosition(new Event('scroll'));\n\n    expect(component['getOffset']).not.toHaveBeenCalled();\n  });\n\n  it('should update affixStyle with new width on resize event', () => {\n    mockPlatform.isBrowser = true;\n    spyOn(component, 'getOffset').and.returnValue({\n      top: 0,\n      left: 0,\n      width: 100,\n      height: 50\n    });\n    spyOn<NzSafeAny>(component, 'setAffixStyle');\n    component.nzOffsetTop = 10;\n    component.nzOffsetBottom = 10;\n\n    component.updatePosition(new Event('resize'));\n\n    expect(component['setAffixStyle']).toHaveBeenCalledWith(\n      jasmine.any(Event),\n      jasmine.objectContaining({ width: 100 })\n    );\n  });\n\n  it('should update the affix style with the correct width on resize', () => {\n    spyOn<NzSafeAny>(component, 'setAffixStyle');\n\n    const scrollTop = 40;\n    spyOn(component['scrollSrv'], 'getScroll').and.returnValue(scrollTop);\n    const elemOffset = { top: 200, left: 0, width: 200, height: 50 };\n    spyOn(component, 'getOffset').and.returnValue(elemOffset);\n    component['nzOffsetTop'] = 150;\n    component['nzOffsetBottom'] = 50;\n    spyOnProperty(component['placeholderNode'], 'offsetWidth').and.returnValue(120);\n\n    component['affixStyle'] = {\n      position: 'fixed',\n      top: '10px',\n      left: '10px',\n      width: '100px'\n    };\n\n    const mockEvent = new Event('resize');\n    component.updatePosition(mockEvent);\n\n    expect(component['setAffixStyle']).toHaveBeenCalledWith(mockEvent, {\n      position: 'fixed',\n      top: '10px',\n      left: '10px',\n      width: 120\n    });\n  });\n});\n"
  },
  {
    "path": "components/affix/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n最简单的用法。\n\n## en-US\n\nThe simplest usage.\n"
  },
  {
    "path": "components/affix/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzAffixModule } from 'ng-zorro-antd/affix';\nimport { NzButtonModule } from 'ng-zorro-antd/button';\n\n@Component({\n  selector: 'nz-demo-affix-basic',\n  imports: [NzAffixModule, NzButtonModule],\n  template: `\n    <nz-affix [nzOffsetTop]=\"offsetTop\">\n      <button nz-button nzType=\"primary\" (click)=\"setOffsetTop()\">\n        <span>Affix top</span>\n      </button>\n    </nz-affix>\n    <br />\n    <nz-affix [nzOffsetBottom]=\"nzOffsetBottom\" (click)=\"setOffsetBottom()\">\n      <button nz-button nzType=\"primary\">\n        <span>Affix bottom</span>\n      </button>\n    </nz-affix>\n  `\n})\nexport class NzDemoAffixBasicComponent {\n  offsetTop = 10;\n  nzOffsetBottom = 10;\n\n  setOffsetTop(): void {\n    this.offsetTop += 10;\n  }\n\n  setOffsetBottom(): void {\n    this.nzOffsetBottom += 10;\n  }\n}\n"
  },
  {
    "path": "components/affix/demo/on-change.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 固定状态改变的回调\n  en-US: Callback\n---\n\n## zh-CN\n\n可以获得是否固定的状态。\n\n## en-US\n\nCallback with affixed state.\n"
  },
  {
    "path": "components/affix/demo/on-change.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzAffixModule } from 'ng-zorro-antd/affix';\nimport { NzButtonModule } from 'ng-zorro-antd/button';\n\n@Component({\n  selector: 'nz-demo-affix-on-change',\n  imports: [NzAffixModule, NzButtonModule],\n  template: `\n    <nz-affix [nzOffsetTop]=\"120\" (nzChange)=\"onChange($event)\">\n      <button nz-button>\n        <span>120px to affix top</span>\n      </button>\n    </nz-affix>\n  `\n})\nexport class NzDemoAffixOnChangeComponent {\n  onChange(status: boolean): void {\n    console.log(status);\n  }\n}\n"
  },
  {
    "path": "components/affix/demo/target.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 滚动容器\n  en-US: Container to scroll.\n---\n\n## zh-CN\n\n用 `nzTarget` 设置 `nz-affix` 需要监听其滚动事件的元素，默认为 `window`。\n\n## en-US\n\nSet a `nzTarget` for 'nz-affix', which is listen to scroll event of target element (default is `window`).\n"
  },
  {
    "path": "components/affix/demo/target.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzAffixModule } from 'ng-zorro-antd/affix';\nimport { NzButtonModule } from 'ng-zorro-antd/button';\n\n@Component({\n  selector: 'nz-demo-affix-target',\n  imports: [NzAffixModule, NzButtonModule],\n  template: `\n    <div class=\"scrollable-container\" #target>\n      <div class=\"background\">\n        <nz-affix [nzTarget]=\"target\" id=\"affix-container-target\">\n          <button nz-button nzType=\"primary\">\n            <span>Fixed at the top of container</span>\n          </button>\n        </nz-affix>\n      </div>\n    </div>\n  `,\n  styles: `\n    .scrollable-container {\n      height: 100px;\n      overflow-y: scroll;\n    }\n\n    .background {\n      padding-top: 60px;\n      height: 300px;\n      background-image: url(//zos.alipayobjects.com/rmsportal/RmjwQiJorKyobvI.jpg);\n    }\n  `\n})\nexport class NzDemoAffixTargetComponent {}\n"
  },
  {
    "path": "components/affix/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Other\ntitle: Affix\ncover: 'https://gw.alipayobjects.com/zos/alicdn/tX6-md4H6/Affix.svg'\ndescription: Make an element stick to viewport.\n---\n\n## When To Use\n\nWhen user browses a long web page, some content need to stick to the viewport. This is common for menus and actions.\n\nPlease note that Affix should not cover other content on the page, especially when the size of the viewport is small.\n\n## API\n\n### nz-affix\n\n| Property           | Description                                                      | Type                    | Default  | Global Config |\n| ------------------ | ---------------------------------------------------------------- | ----------------------- | -------- | ------------- |\n| `[nzOffsetBottom]` | Pixels to offset from bottom when calculating position of scroll | `number`                | -        | ✅            |\n| `[nzOffsetTop]`    | Pixels to offset from top when calculating position of scroll    | `number`                | `0`      | ✅            |\n| `[nzTarget]`       | specifies the scrollable area dom node                           | `string \\| HTMLElement` | `window` |\n| `(nzChange)`       | Callback for when affix state is changed                         | `EventEmitter<boolean>` | -        |\n\n**Note:** Children of `nz-affix` can not be `position: absolute`, but you can set `nz-affix` as `position: absolute`:\n\n```html\n<nz-affix style=\"position: absolute; top: 10px, left: 10px\"> ... </nz-affix>\n```\n"
  },
  {
    "path": "components/affix/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 固钉\ntype: 其他\ntitle: Affix\ncover: 'https://gw.alipayobjects.com/zos/alicdn/tX6-md4H6/Affix.svg'\ndescription: 将页面元素钉在可视范围。\n---\n\n## 何时使用\n\n当内容区域比较长，需要滚动页面时，这部分内容对应的操作或者导航需要在滚动范围内始终展现。常用于侧边菜单和按钮组合。\n\n页面可视范围过小时，慎用此功能以免遮挡页面内容。\n\n## API\n\n### nz-affix\n\n| 成员               | 说明                                                                      | 类型                    | 默认值   | 全局配置 |\n| ------------------ | ------------------------------------------------------------------------- | ----------------------- | -------- | -------- |\n| `[nzOffsetBottom]` | 距离窗口底部达到指定偏移量后触发                                          | `number`                | -        | ✅       |\n| `[nzOffsetTop]`    | 距离窗口顶部达到指定偏移量后触发                                          | `number`                | `0`      | ✅       |\n| `[nzTarget]`       | 设置 `nz-affix` 需要监听其滚动事件的元素，值为一个返回对应 DOM 元素的函数 | `string \\| HTMLElement` | `window` |\n| `(nzChange)`       | 固定状态改变时触发的回调函数                                              | `EventEmitter<boolean>` | -        |\n\n**注意：**`nz-affix` 内的元素不要使用绝对定位，如需要绝对定位的效果，可以直接设置 `nz-affix` 为绝对定位：\n\n```html\n<nz-affix style=\"position: absolute; top: 10px, left: 10px\"> ... </nz-affix>\n```\n"
  },
  {
    "path": "components/affix/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/affix/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/affix/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './affix.component';\nexport * from './affix.module';\n"
  },
  {
    "path": "components/affix/respond-events.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport enum AffixRespondEvents {\n  resize = 'resize',\n  scroll = 'scroll',\n  touchstart = 'touchstart',\n  touchmove = 'touchmove',\n  touchend = 'touchend',\n  pageshow = 'pageshow',\n  load = 'LOAD'\n}\n"
  },
  {
    "path": "components/affix/style/entry.less",
    "content": "@import './index.less';\n@import \"./patch\";\n"
  },
  {
    "path": "components/affix/style/index.less",
    "content": "@import '../../style/themes/index';\n\n.@{ant-prefix}-affix {\n  position: fixed;\n  z-index: @zindex-affix;\n}\n"
  },
  {
    "path": "components/affix/style/patch.less",
    "content": "nz-affix {\n  display: block;\n}\n"
  },
  {
    "path": "components/affix/utils.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport interface SimpleRect {\n  top: number;\n  left: number;\n  width?: number;\n  height?: number;\n  bottom?: number;\n}\n\nexport function isTargetWindow(target: Element | Window): target is Window {\n  return typeof window !== 'undefined' && target === window;\n}\n\nexport function getTargetRect(target: Element | Window): SimpleRect {\n  return !isTargetWindow(target)\n    ? target.getBoundingClientRect()\n    : {\n        top: 0,\n        left: 0,\n        bottom: 0\n      };\n}\n"
  },
  {
    "path": "components/alert/alert-marquee.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  afterNextRender,\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  Component,\n  computed,\n  DestroyRef,\n  ElementRef,\n  inject,\n  input,\n  numberAttribute,\n  signal,\n  viewChild,\n  ViewEncapsulation\n} from '@angular/core';\n\n@Component({\n  selector: 'nz-alert-marquee',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <div #track1 class=\"ant-alert-marquee-track\" [style.animation-duration.s]=\"animationDuration()\">\n      <ng-content />\n    </div>\n    <div\n      #track2\n      class=\"ant-alert-marquee-track\"\n      aria-hidden=\"true\"\n      [style.animation-duration.s]=\"animationDuration()\"\n    ></div>\n  `,\n  host: {\n    '[class]': 'class()'\n  }\n})\nexport class NzAlertMarqueeComponent {\n  private readonly destroyRef = inject(DestroyRef);\n  readonly nzPauseOnHover = input(false, { transform: booleanAttribute });\n  readonly nzSpeed = input(50, { transform: numberAttribute });\n\n  private readonly track1Ref = viewChild.required<ElementRef<HTMLElement>>('track1');\n  private readonly track2Ref = viewChild.required<ElementRef<HTMLElement>>('track2');\n\n  private readonly trackWidth = signal(0);\n\n  protected readonly animationDuration = computed(() => {\n    const width = this.trackWidth();\n    const speed = this.nzSpeed();\n    return width > 0 && speed > 0 ? width / speed : 20;\n  });\n\n  protected readonly class = computed(() => ({\n    'ant-alert-marquee': true,\n    'ant-alert-marquee-pause-on-hover': this.nzPauseOnHover()\n  }));\n\n  constructor() {\n    afterNextRender(() => {\n      const track1 = this.track1Ref().nativeElement;\n      const track2 = this.track2Ref().nativeElement;\n      const updateWidth = (): void => {\n        this.trackWidth.set(track1.offsetWidth);\n      };\n\n      Array.from(track1.childNodes).forEach(node => {\n        track2.appendChild(node.cloneNode(true));\n      });\n\n      updateWidth();\n\n      if (typeof ResizeObserver !== 'undefined') {\n        const resizeObserver = new ResizeObserver(updateWidth);\n        resizeObserver.observe(track1);\n        this.destroyRef.onDestroy(() => resizeObserver.disconnect());\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "components/alert/alert-marquee.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, DebugElement, signal } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzAlertMarqueeComponent } from './alert-marquee.component';\nimport { NzAlertModule } from './alert.module';\n\ndescribe('NzAlertMarqueeComponent', () => {\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideNoopAnimations()]\n    });\n  });\n\n  describe('structure', () => {\n    let fixture: ComponentFixture<NzTestMarqueeBasicComponent>;\n    let marquee: DebugElement;\n\n    beforeEach(async () => {\n      fixture = TestBed.createComponent(NzTestMarqueeBasicComponent);\n      marquee = fixture.debugElement.query(By.directive(NzAlertMarqueeComponent));\n      fixture.autoDetectChanges();\n      await fixture.whenStable();\n    });\n\n    it('should render the marquee container', () => {\n      expect(marquee.nativeElement.classList).toContain('ant-alert-marquee');\n    });\n\n    it('should render exactly two tracks inside the container', () => {\n      const tracks = marquee.nativeElement.querySelectorAll('.ant-alert-marquee-track');\n      expect(tracks.length).toBe(2);\n    });\n\n    it('should project content into the first track', () => {\n      const tracks = marquee.nativeElement.querySelectorAll('.ant-alert-marquee-track');\n      expect(tracks[0].textContent.trim()).toContain('Scrolling message');\n    });\n\n    it('should clone content into the second track', () => {\n      const tracks = marquee.nativeElement.querySelectorAll('.ant-alert-marquee-track');\n      expect(tracks[1].textContent.trim()).toContain('Scrolling message');\n    });\n\n    it('should set aria-hidden=\"true\" on the second track for accessibility', () => {\n      const tracks = marquee.nativeElement.querySelectorAll('.ant-alert-marquee-track');\n      expect(tracks[1].getAttribute('aria-hidden')).toBe('true');\n    });\n\n    it('should not set aria-hidden on the first track', () => {\n      const tracks = marquee.nativeElement.querySelectorAll('.ant-alert-marquee-track');\n      expect(tracks[0].hasAttribute('aria-hidden')).toBeFalse();\n    });\n  });\n\n  describe('nzSpeed', () => {\n    let fixture: ComponentFixture<NzTestMarqueeBasicComponent>;\n    let marquee: DebugElement;\n\n    beforeEach(async () => {\n      spyOnProperty(HTMLElement.prototype, 'offsetWidth', 'get').and.returnValue(500);\n      fixture = TestBed.createComponent(NzTestMarqueeBasicComponent);\n      marquee = fixture.debugElement.query(By.directive(NzAlertMarqueeComponent));\n      fixture.autoDetectChanges();\n      await fixture.whenStable();\n    });\n\n    it('should calculate duration as trackWidth divided by nzSpeed', () => {\n      const tracks = marquee.nativeElement.querySelectorAll('.ant-alert-marquee-track');\n      // 500px / 50px/s = 10s\n      expect(tracks[0].style.animationDuration).toBe('10s');\n    });\n\n    it('should apply a custom animation duration via nzSpeed', () => {\n      fixture.componentInstance.speed.set(100);\n      fixture.detectChanges();\n      const tracks = marquee.nativeElement.querySelectorAll('.ant-alert-marquee-track');\n      // 500px / 100px/s = 5s\n      expect(tracks[0].style.animationDuration).toBe('5s');\n    });\n\n    it('should coerce nzSpeed string attribute to a number', () => {\n      fixture.componentInstance.speed.set(25);\n      fixture.detectChanges();\n      const tracks = marquee.nativeElement.querySelectorAll('.ant-alert-marquee-track');\n      // 500px / 25px/s = 20s\n      expect(tracks[0].style.animationDuration).toBe('20s');\n    });\n  });\n\n  describe('nzPauseOnHover', () => {\n    let fixture: ComponentFixture<NzTestMarqueeBasicComponent>;\n    let marquee: DebugElement;\n\n    beforeEach(async () => {\n      fixture = TestBed.createComponent(NzTestMarqueeBasicComponent);\n      marquee = fixture.debugElement.query(By.directive(NzAlertMarqueeComponent));\n      fixture.autoDetectChanges();\n      await fixture.whenStable();\n    });\n\n    it('should not apply the pause-on-hover class by default', () => {\n      expect(marquee.nativeElement.classList).not.toContain('ant-alert-marquee-pause-on-hover');\n    });\n\n    it('should apply the pause-on-hover class when nzPauseOnHover is true', () => {\n      fixture.componentInstance.pauseOnHover.set(true);\n      fixture.detectChanges();\n      expect(marquee.nativeElement.classList).toContain('ant-alert-marquee-pause-on-hover');\n    });\n\n    it('should remove the pause-on-hover class when nzPauseOnHover is toggled back to false', () => {\n      fixture.componentInstance.pauseOnHover.set(true);\n      fixture.detectChanges();\n      fixture.componentInstance.pauseOnHover.set(false);\n      fixture.detectChanges();\n      expect(marquee.nativeElement.classList).not.toContain('ant-alert-marquee-pause-on-hover');\n    });\n  });\n\n  describe('used inside nz-alert', () => {\n    let fixture: ComponentFixture<NzTestMarqueeInsideAlertComponent>;\n\n    beforeEach(async () => {\n      fixture = TestBed.createComponent(NzTestMarqueeInsideAlertComponent);\n      fixture.autoDetectChanges();\n      await fixture.whenStable();\n    });\n\n    it('should render inside the alert message area', () => {\n      expect(fixture.nativeElement.querySelector('.ant-alert-message .ant-alert-marquee')).not.toBeNull();\n    });\n\n    it('should render the marquee track inside the alert', () => {\n      expect(fixture.nativeElement.querySelector('.ant-alert-message .ant-alert-marquee-track')).not.toBeNull();\n    });\n\n    it('should work correctly alongside nzBanner', () => {\n      expect(fixture.nativeElement.querySelector('.ant-alert-banner')).not.toBeNull();\n      expect(fixture.nativeElement.querySelector('.ant-alert-marquee')).not.toBeNull();\n    });\n\n    it('should project content into the track when used inside nz-alert', () => {\n      const track = fixture.nativeElement.querySelector('.ant-alert-marquee-track') as HTMLElement;\n      expect(track.textContent.trim()).toContain('Loop banner text');\n    });\n  });\n});\n\n@Component({\n  imports: [NzAlertModule],\n  template: `\n    <nz-alert-marquee [nzPauseOnHover]=\"pauseOnHover()\" [nzSpeed]=\"speed()\"> Scrolling message </nz-alert-marquee>\n  `\n})\nexport class NzTestMarqueeBasicComponent {\n  readonly pauseOnHover = signal(false);\n  readonly speed = signal(50);\n}\n\n@Component({\n  imports: [NzAlertModule],\n  template: `\n    <nz-alert nzBanner [nzMessage]=\"message\" />\n    <ng-template #message>\n      <nz-alert-marquee>Loop banner text</nz-alert-marquee>\n    </ng-template>\n  `\n})\nexport class NzTestMarqueeInsideAlertComponent {}\n"
  },
  {
    "path": "components/alert/alert.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport {\n  ANIMATION_MODULE_TYPE,\n  AnimationCallbackEvent,\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DestroyRef,\n  EventEmitter,\n  inject,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  SimpleChanges,\n  TemplateRef,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { NzNoAnimationDirective } from 'ng-zorro-antd/core/animation';\nimport { NzConfigKey, onConfigChangeEventForComponent, WithConfig } from 'ng-zorro-antd/core/config';\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'alert';\nexport type NzAlertType = 'success' | 'info' | 'warning' | 'error';\n\n@Component({\n  selector: 'nz-alert',\n  exportAs: 'nzAlert',\n  imports: [NzIconModule, NzOutletModule, NzNoAnimationDirective],\n  template: `\n    @if (!closed) {\n      <div\n        class=\"ant-alert\"\n        [nzNoAnimation]=\"nzNoAnimation\"\n        [class.ant-alert-rtl]=\"dir === 'rtl'\"\n        [class.ant-alert-success]=\"nzType === 'success'\"\n        [class.ant-alert-info]=\"nzType === 'info'\"\n        [class.ant-alert-warning]=\"nzType === 'warning'\"\n        [class.ant-alert-error]=\"nzType === 'error'\"\n        [class.ant-alert-no-icon]=\"!nzShowIcon\"\n        [class.ant-alert-banner]=\"nzBanner\"\n        [class.ant-alert-closable]=\"nzCloseable\"\n        [class.ant-alert-with-description]=\"!!nzDescription\"\n        (animate.leave)=\"onLeaveAnimationDone($event)\"\n      >\n        @if (nzShowIcon) {\n          <div class=\"ant-alert-icon\">\n            @if (nzIcon) {\n              <ng-container *nzStringTemplateOutlet=\"nzIcon\" />\n            } @else {\n              <nz-icon [nzType]=\"nzIconType || inferredIconType\" [nzTheme]=\"iconTheme\" />\n            }\n          </div>\n        }\n\n        @if (nzMessage || nzDescription) {\n          <div class=\"ant-alert-content\">\n            @if (nzMessage) {\n              <span class=\"ant-alert-message\">\n                <ng-container *nzStringTemplateOutlet=\"nzMessage\">{{ nzMessage }}</ng-container>\n              </span>\n            }\n            @if (nzDescription) {\n              <span class=\"ant-alert-description\">\n                <ng-container *nzStringTemplateOutlet=\"nzDescription\">{{ nzDescription }}</ng-container>\n              </span>\n            }\n          </div>\n        }\n\n        @if (nzAction) {\n          <div class=\"ant-alert-action\">\n            <ng-container *nzStringTemplateOutlet=\"nzAction\">{{ nzAction }}</ng-container>\n          </div>\n        }\n\n        @if (nzCloseable || nzCloseText) {\n          <button type=\"button\" tabindex=\"0\" class=\"ant-alert-close-icon\" (click)=\"closeAlert()\">\n            @if (nzCloseText) {\n              <ng-container *nzStringTemplateOutlet=\"nzCloseText\">\n                <span class=\"ant-alert-close-text\">{{ nzCloseText }}</span>\n              </ng-container>\n            } @else {\n              <nz-icon nzType=\"close\" />\n            }\n          </button>\n        }\n      </div>\n    }\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None\n})\nexport class NzAlertComponent implements OnChanges, OnInit {\n  private cdr = inject(ChangeDetectorRef);\n  private directionality = inject(Directionality);\n  private readonly destroyRef = inject(DestroyRef);\n  private readonly animationType = inject(ANIMATION_MODULE_TYPE, { optional: true });\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  @Input() nzAction: string | TemplateRef<void> | null = null;\n  @Input() nzCloseText: string | TemplateRef<void> | null = null;\n  @Input() nzIconType: string | null = null;\n  @Input() nzMessage: string | TemplateRef<void> | null = null;\n  @Input() nzDescription: string | TemplateRef<void> | null = null;\n  @Input() nzType: 'success' | 'info' | 'warning' | 'error' = 'info';\n  @Input({ transform: booleanAttribute }) @WithConfig() nzCloseable: boolean = false;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzShowIcon: boolean = false;\n  @Input({ transform: booleanAttribute }) nzBanner = false;\n  @Input({ transform: booleanAttribute }) nzNoAnimation = false;\n  @Input() nzIcon: string | TemplateRef<void> | null = null;\n\n  @Output() readonly nzOnClose = new EventEmitter<boolean>();\n  closed = false;\n  iconTheme: 'outline' | 'fill' = 'fill';\n  inferredIconType: string = 'info-circle';\n  dir: Direction = 'ltr';\n  private isTypeSet = false;\n  private isShowIconSet = false;\n\n  constructor() {\n    onConfigChangeEventForComponent(NZ_CONFIG_MODULE_NAME, () => this.cdr.markForCheck());\n  }\n\n  ngOnInit(): void {\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((direction: Direction) => {\n      this.dir = direction;\n      this.cdr.detectChanges();\n    });\n\n    this.dir = this.directionality.value;\n  }\n\n  closeAlert(): void {\n    this.closed = true;\n    // When animations are disabled, emit immediately since animate.leave won't trigger\n    if (this.nzNoAnimation || this.animationType === 'NoopAnimations') {\n      this.nzOnClose.emit(true);\n    }\n  }\n\n  onLeaveAnimationDone(event: AnimationCallbackEvent): void {\n    const element = event.target as HTMLElement;\n\n    // If animations are disabled, complete immediately (nzOnClose already emitted in closeAlert)\n    if (this.nzNoAnimation || this.animationType === 'NoopAnimations') {\n      event.animationComplete();\n      return;\n    }\n\n    // Apply animation classes\n    element.classList.add('ant-alert-motion-leave', 'ant-alert-motion-leave-active');\n\n    // Listen for transition end to complete the animation\n    const onTransitionEnd = (): void => {\n      element.removeEventListener('transitionend', onTransitionEnd);\n      this.nzOnClose.emit(true);\n      event.animationComplete();\n    };\n\n    element.addEventListener('transitionend', onTransitionEnd);\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzShowIcon, nzDescription, nzType, nzBanner } = changes;\n    if (nzShowIcon) {\n      this.isShowIconSet = true;\n    }\n    if (nzType) {\n      this.isTypeSet = true;\n      switch (this.nzType) {\n        case 'error':\n          this.inferredIconType = 'close-circle';\n          break;\n        case 'success':\n          this.inferredIconType = 'check-circle';\n          break;\n        case 'info':\n          this.inferredIconType = 'info-circle';\n          break;\n        case 'warning':\n          this.inferredIconType = 'exclamation-circle';\n          break;\n      }\n    }\n    if (nzDescription) {\n      this.iconTheme = this.nzDescription ? 'outline' : 'fill';\n    }\n    if (nzBanner) {\n      if (!this.isTypeSet) {\n        this.nzType = 'warning';\n      }\n      if (!this.isShowIconSet) {\n        this.nzShowIcon = true;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/alert/alert.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzAlertMarqueeComponent } from './alert-marquee.component';\nimport { NzAlertComponent } from './alert.component';\n\n@NgModule({\n  exports: [NzAlertComponent, NzAlertMarqueeComponent],\n  imports: [NzAlertComponent, NzAlertMarqueeComponent]\n})\nexport class NzAlertModule {}\n"
  },
  {
    "path": "components/alert/alert.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport { ChangeDetectorRef, Component, DebugElement, TemplateRef, ViewChild } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\nimport { Subject } from 'rxjs';\n\nimport { NzConfigService } from 'ng-zorro-antd/core/config';\nimport { updateNonSignalsInput } from 'ng-zorro-antd/core/testing';\nimport type { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzAlertComponent, NzAlertType } from './alert.component';\nimport { NzAlertModule } from './alert.module';\n\ndescribe('alert', () => {\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideNoopAnimations()]\n    });\n  });\n\n  describe('basic alert', () => {\n    let fixture: ComponentFixture<NzDemoTestBasicComponent>;\n    let testComponent: NzDemoTestBasicComponent;\n    let alert: DebugElement;\n\n    beforeEach(async () => {\n      fixture = TestBed.createComponent(NzDemoTestBasicComponent);\n      testComponent = fixture.debugElement.componentInstance;\n      alert = fixture.debugElement.query(By.directive(NzAlertComponent));\n      fixture.autoDetectChanges();\n      await fixture.whenStable();\n    });\n\n    it('should className correct', () => {\n      expect(alert.nativeElement.firstElementChild!.classList).toContain('ant-alert');\n    });\n\n    it('should banner work', async () => {\n      expect(alert.nativeElement.firstElementChild!.classList).not.toContain('ant-alert-banner');\n      expect(alert.nativeElement.querySelector('.ant-alert').classList).toContain(`ant-alert-info`);\n      expect(alert.nativeElement.querySelector('.ant-alert-icon')).toBeNull();\n      testComponent.banner = true;\n      await updateNonSignalsInput(fixture);\n      expect(alert.nativeElement.firstElementChild!.classList).toContain('ant-alert-banner');\n      expect(alert.nativeElement.querySelector('.ant-alert').classList).toContain(`ant-alert-info`);\n      expect(alert.nativeElement.querySelector('.ant-alert-icon')).toBeNull();\n    });\n\n    it('should closeable work', async () => {\n      testComponent.closeable = true;\n      await updateNonSignalsInput(fixture);\n      expect(testComponent.onClose).toHaveBeenCalledTimes(0);\n      expect(alert.nativeElement.querySelector('.anticon-close')).toBeDefined();\n      alert.nativeElement.querySelector('.ant-alert-close-icon').click();\n      await fixture.whenStable();\n      alert = fixture.debugElement.query(By.directive(NzAlertComponent));\n      expect(alert.nativeElement.innerText).toBe('');\n      expect(testComponent.onClose).toHaveBeenCalledTimes(1);\n    });\n\n    it('should closeText work', async () => {\n      expect(alert.nativeElement.querySelector('.ant-alert-close-icon')).toBeNull();\n      testComponent.closeText = 'closeText';\n      await updateNonSignalsInput(fixture);\n      expect(alert.nativeElement.querySelector('.ant-alert-close-icon').innerText).toBe('closeText');\n      testComponent.closeText = testComponent.template;\n      await updateNonSignalsInput(fixture);\n      expect(alert.nativeElement.querySelector('.ant-alert-close-icon').innerText).toBe('template');\n    });\n\n    it('should description work', async () => {\n      expect(alert.nativeElement.querySelector('.ant-alert-description').innerText).toBe('description');\n      testComponent.description = testComponent.template;\n      await updateNonSignalsInput(fixture);\n      expect(alert.nativeElement.querySelector('.ant-alert-description').innerText).toBe('template');\n    });\n\n    it('should message work', async () => {\n      expect(alert.nativeElement.querySelector('.ant-alert-message').innerText).toBe('message');\n      testComponent.message = testComponent.template;\n      await updateNonSignalsInput(fixture);\n      expect(alert.nativeElement.querySelector('.ant-alert-message').innerText).toBe('template');\n    });\n\n    it('should showIcon work', async () => {\n      expect(alert.nativeElement.querySelector('.ant-alert-icon')).toBeNull();\n      testComponent.showIcon = true;\n      await updateNonSignalsInput(fixture);\n      expect(alert.nativeElement.querySelector('.ant-alert-icon')).toBeDefined();\n    });\n\n    it('should iconType work', async () => {\n      testComponent.showIcon = true;\n      testComponent.iconType = 'lock';\n      await updateNonSignalsInput(fixture);\n      expect(alert.nativeElement.querySelector('.ant-alert-icon').firstElementChild.classList).toContain('anticon');\n      expect(alert.nativeElement.querySelector('.ant-alert-icon').firstElementChild.classList).toContain(\n        'anticon-lock'\n      );\n    });\n\n    it('should type work', async () => {\n      const listOfType: NzAlertType[] = ['success', 'info', 'warning', 'error'];\n      for (const type of listOfType) {\n        testComponent.type = type;\n        await updateNonSignalsInput(fixture);\n        expect(alert.nativeElement.querySelector('.ant-alert').classList).toContain(`ant-alert-${type}`);\n      }\n    });\n\n    it('should action work', async () => {\n      testComponent.action = testComponent.template;\n      await updateNonSignalsInput(fixture);\n      expect(alert.nativeElement.querySelector('.ant-alert-action').classList).not.toBeNull();\n    });\n  });\n\n  describe('banner alert', () => {\n    let fixture: ComponentFixture<NzDemoTestBannerComponent>;\n    let alert: DebugElement;\n\n    beforeEach(async () => {\n      fixture = TestBed.createComponent(NzDemoTestBannerComponent);\n      alert = fixture.debugElement.query(By.directive(NzAlertComponent));\n      fixture.autoDetectChanges();\n    });\n\n    it('should banner work', async () => {\n      await fixture.whenStable();\n      expect(alert.nativeElement.querySelector('.ant-alert').classList).toContain(`ant-alert-warning`);\n      expect(alert.nativeElement.querySelector('.ant-alert-icon')).toBeDefined();\n    });\n  });\n\n  describe('RTL', () => {\n    it('should className correct on dir change', async () => {\n      const fixture = TestBed.createComponent(NzTestAlertRtlComponent);\n      const alert = fixture.debugElement.query(By.directive(NzAlertComponent));\n      await fixture.whenStable();\n      expect(alert.nativeElement.firstElementChild!.classList).toContain('ant-alert-rtl');\n\n      fixture.componentInstance.direction = 'ltr';\n      await updateNonSignalsInput(fixture);\n      expect(alert.nativeElement.firstElementChild!.classList).not.toContain('ant-alert-rtl');\n    });\n  });\n\n  describe('custom icon', () => {\n    it('should custom icon work', async () => {\n      const fixture = TestBed.createComponent(NzTestAlertCustomIconComponent);\n      const alert = fixture.debugElement.query(By.directive(NzAlertComponent));\n      await fixture.whenStable();\n      expect(alert.nativeElement.querySelector('.ant-alert-icon')).toBeDefined();\n      expect(alert.nativeElement.querySelector('.ant-alert-icon').firstElementChild).not.toContain('anticon');\n    });\n  });\n});\n\n@Component({\n  imports: [NzAlertModule],\n  selector: 'nz-test-basic-alert',\n  template: `\n    <ng-template #template>template</ng-template>\n    <nz-alert\n      [nzBanner]=\"banner\"\n      [nzCloseable]=\"closeable\"\n      [nzCloseText]=\"closeText\"\n      [nzDescription]=\"description\"\n      [nzMessage]=\"message\"\n      [nzShowIcon]=\"showIcon\"\n      [nzIconType]=\"iconType\"\n      [nzType]=\"type\"\n      [nzAction]=\"action\"\n      (nzOnClose)=\"onClose($event)\"\n    />\n  `\n})\nexport class NzDemoTestBasicComponent {\n  @ViewChild('template', { static: false }) template!: TemplateRef<void>;\n  action: string | TemplateRef<void> | null = null;\n  banner = false;\n  closeable = false;\n  closeText: string | TemplateRef<void> | null = null;\n  description: string | TemplateRef<void> = 'description';\n  message: string | TemplateRef<void> = 'message';\n  showIcon = false;\n  iconType: string | null = null;\n  type: NzAlertType = 'info';\n  onClose = jasmine.createSpy('close callback');\n}\n\n@Component({\n  imports: [NzAlertModule],\n  template: `<nz-alert nzBanner />`\n})\nexport class NzDemoTestBannerComponent {}\n\n@Component({\n  imports: [NzDemoTestBasicComponent, BidiModule],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-test-basic-alert />\n    </div>\n  `\n})\nexport class NzTestAlertRtlComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n}\n\n@Component({\n  imports: [NzAlertModule],\n  template: `\n    <nz-alert\n      nzType=\"success\"\n      nzMessage=\"Success Tips\"\n      nzDescription=\"Detailed description and advices about successful copywriting.\"\n      [nzIcon]=\"customIconTemplate\"\n      nzShowIcon\n    />\n\n    <ng-template #customIconTemplate>\n      <div> S </div>\n    </ng-template>\n  `\n})\nexport class NzTestAlertCustomIconComponent {}\n\ndescribe('NzAlertComponent', () => {\n  let component: NzAlertComponent;\n  let fixture: ComponentFixture<NzAlertComponent>;\n  let cdr: ChangeDetectorRef;\n  let configChangeEvent$: Subject<string>;\n\n  beforeEach(() => {\n    configChangeEvent$ = new Subject<string>();\n    const nzConfigServiceSpy = jasmine.createSpyObj('NzConfigService', {\n      getConfigChangeEventForComponent: configChangeEvent$.asObservable(),\n      getConfigForComponent: {}\n    });\n\n    TestBed.configureTestingModule({\n      providers: [\n        provideNoopAnimations(),\n        { provide: NzConfigService, useValue: nzConfigServiceSpy },\n        {\n          provide: ChangeDetectorRef,\n          useValue: jasmine.createSpyObj('ChangeDetectorRef', ['markForCheck', 'detectChanges'])\n        }\n      ]\n    });\n\n    fixture = TestBed.createComponent(NzAlertComponent);\n    component = fixture.componentInstance;\n    cdr = TestBed.inject(ChangeDetectorRef);\n    fixture.detectChanges();\n    cdr.markForCheck();\n  });\n\n  it('should set iconTheme based on nzDescription', () => {\n    component.nzDescription = 'Test Description';\n\n    component.ngOnChanges({\n      nzDescription: {\n        currentValue: 'Test Description',\n        firstChange: true,\n        isFirstChange: () => true,\n        previousValue: undefined\n      }\n    });\n\n    expect(component.iconTheme).toBe('outline');\n\n    component.nzDescription = null;\n    component.ngOnChanges({\n      nzDescription: {\n        currentValue: null,\n        firstChange: false,\n        isFirstChange: () => false,\n        previousValue: 'Test Description'\n      }\n    });\n\n    expect(component.iconTheme).toBe('fill');\n  });\n\n  it('should call cdr.markForCheck on config change event', async () => {\n    fixture.detectChanges();\n    spyOn(cdr, 'markForCheck');\n\n    configChangeEvent$.next('alert');\n    await fixture.whenStable();\n    expect(cdr.markForCheck).toHaveBeenCalled();\n  });\n});\n\ndescribe('NzAlertComponent Animation', () => {\n  let component: NzAlertComponent;\n  let fixture: ComponentFixture<NzAlertComponent>;\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting()],\n      animationsEnabled: true\n    });\n\n    fixture = TestBed.createComponent(NzAlertComponent);\n    component = fixture.componentInstance;\n    fixture.detectChanges();\n  });\n\n  it('should add animation classes and emit onClose when animation ends', () => {\n    spyOn(component.nzOnClose, 'emit');\n    const element = fixture.nativeElement.querySelector('.ant-alert');\n    const mockEvent = {\n      target: element,\n      animationComplete: jasmine.createSpy('animationComplete')\n    } as NzSafeAny;\n\n    component.onLeaveAnimationDone(mockEvent);\n\n    expect(element.classList).toContain('ant-alert-motion-leave');\n    expect(element.classList).toContain('ant-alert-motion-leave-active');\n    expect(component.nzOnClose.emit).not.toHaveBeenCalled();\n    expect(mockEvent.animationComplete).not.toHaveBeenCalled();\n\n    const transitionEndEvent = new Event('transitionend');\n    element.dispatchEvent(transitionEndEvent);\n\n    expect(component.nzOnClose.emit).toHaveBeenCalledWith(true);\n    expect(mockEvent.animationComplete).toHaveBeenCalled();\n  });\n\n  it('should handle no animation', () => {\n    component.nzNoAnimation = true;\n    spyOn(component.nzOnClose, 'emit');\n    const element = fixture.nativeElement.querySelector('.ant-alert');\n    const mockEvent = {\n      target: element,\n      animationComplete: jasmine.createSpy('animationComplete')\n    } as NzSafeAny;\n\n    component.onLeaveAnimationDone(mockEvent);\n\n    expect(element.classList).not.toContain('ant-alert-motion-leave');\n    expect(mockEvent.animationComplete).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "components/alert/demo/action.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 操作\n  en-US: Custom action\n---\n\n## zh-CN\n\n可以在右上角自定义操作项。\n\n## en-US\n\nCustom action.\n"
  },
  {
    "path": "components/alert/demo/action.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzAlertModule } from 'ng-zorro-antd/alert';\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\n\n@Component({\n  selector: 'nz-demo-alert-action',\n  imports: [NzAlertModule, NzButtonModule, NzSpaceModule],\n  template: `\n    <nz-alert nzShowIcon nzType=\"success\" nzMessage=\"Success Text\" [nzAction]=\"actionTemplate1\" />\n    <ng-template #actionTemplate1>\n      <button nz-button nzSize=\"small\" nzType=\"text\" (click)=\"doAction('undo')\">Undo</button></ng-template\n    >\n    <br />\n    <nz-alert\n      nzShowIcon\n      nzType=\"error\"\n      nzMessage=\"Error Text\"\n      [nzDescription]=\"descriptionTemplate1\"\n      [nzAction]=\"actionTemplate2\"\n    />\n    <ng-template #descriptionTemplate1>\n      <p>Error Description Error Description Error Description Error Description</p>\n    </ng-template>\n    <ng-template #actionTemplate2>\n      <button nz-button nzSize=\"small\" nzType=\"default\" nzDanger (click)=\"doAction('detail')\">Detail</button>\n    </ng-template>\n    <br />\n    <nz-alert nzCloseable nzType=\"warning\" nzMessage=\"Warning Text\" [nzAction]=\"actionTemplate3\" />\n    <ng-template #actionTemplate3>\n      <button nz-button nzSize=\"small\" nzType=\"primary\" nzGhost (click)=\"doAction('ignore')\">Ignore</button>\n    </ng-template>\n    <br />\n    <nz-alert\n      nzShowIcon\n      nzType=\"info\"\n      nzMessage=\"Info Text\"\n      [nzDescription]=\"descriptionTemplate2\"\n      [nzAction]=\"actionTemplate4\"\n    />\n    <ng-template #descriptionTemplate2>\n      <p>Info Description Info Description Info Description Info Description</p>\n    </ng-template>\n    <ng-template #actionTemplate4>\n      <nz-space nzDirection=\"vertical\">\n        <button *nzSpaceItem nz-button nzSize=\"small\" nzType=\"primary\" (click)=\"doAction('accept')\">Accept</button>\n        <button *nzSpaceItem nz-button nzSize=\"small\" nzType=\"default\" nzDanger (click)=\"doAction('decline')\"\n          >Decline</button\n        >\n      </nz-space>\n    </ng-template>\n  `\n})\nexport class NzDemoAlertActionComponent {\n  doAction(action: string): void {\n    console.log(`Do alert's action: ${action}`);\n  }\n}\n"
  },
  {
    "path": "components/alert/demo/banner.md",
    "content": "---\norder: 6\niframe:\n  height: 220\ntitle:\n  zh-CN: 顶部公告\n  en-US: Banner\n---\n\n## zh-CN\n\n页面顶部通告形式，默认有图标且 `nzType` 为 `'warning'`。\n\n## en-US\n\nDisplay Alert as a banner at top of page.\n"
  },
  {
    "path": "components/alert/demo/banner.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzAlertModule } from 'ng-zorro-antd/alert';\n\n@Component({\n  selector: 'nz-demo-alert-banner',\n  imports: [NzAlertModule],\n  template: `\n    <nz-alert nzBanner nzMessage=\"Warning text\" />\n    <nz-alert nzBanner nzMessage=\"Very long warning text warning text text text text text text text\" nzCloseable />\n    <nz-alert nzBanner nzMessage=\"Warning text without icon\" [nzShowIcon]=\"false\" />\n    <nz-alert nzBanner nzType=\"error\" nzMessage=\"Error text\" />\n  `,\n  styles: `\n    nz-alert {\n      margin-bottom: 12px;\n    }\n  `\n})\nexport class NzDemoAlertBannerComponent {}\n"
  },
  {
    "path": "components/alert/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n最简单的用法，适用于简短的警告提示。\n\n## en-US\n\nThe simplest usage for short messages.\n"
  },
  {
    "path": "components/alert/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzAlertModule } from 'ng-zorro-antd/alert';\n\n@Component({\n  selector: 'nz-demo-alert-basic',\n  imports: [NzAlertModule],\n  template: `<nz-alert nzType=\"success\" nzMessage=\"Success Text\" />`\n})\nexport class NzDemoAlertBasicComponent {}\n"
  },
  {
    "path": "components/alert/demo/closable.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 可关闭的警告提示\n  en-US: Closable\n---\n\n## zh-CN\n\n显示关闭按钮，点击可关闭警告提示。\n\n## en-US\n\nTo show close button.\n"
  },
  {
    "path": "components/alert/demo/closable.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzAlertModule } from 'ng-zorro-antd/alert';\n\n@Component({\n  selector: 'nz-demo-alert-closable',\n  imports: [NzAlertModule],\n  template: `\n    <nz-alert\n      nzType=\"warning\"\n      nzCloseable\n      nzMessage=\"Warning Text Warning Text Warning Text Warning Text Warning Text Warning Text Warning Text\"\n      (nzOnClose)=\"afterClose()\"\n    />\n    <nz-alert\n      nzType=\"error\"\n      nzCloseable\n      nzMessage=\"Error Text\"\n      nzDescription=\"Error Description Error Description Error Description Error Description Error Description Error Description\"\n      (nzOnClose)=\"afterClose()\"\n    />\n  `,\n  styles: `\n    nz-alert {\n      margin-bottom: 16px;\n    }\n  `\n})\nexport class NzDemoAlertClosableComponent {\n  afterClose(): void {\n    console.log('close');\n  }\n}\n"
  },
  {
    "path": "components/alert/demo/close-text.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 自定义关闭\n  en-US: Customized Close Text\n---\n\n## zh-CN\n\n可以自定义关闭，自定义的内容会替换原先的关闭按钮。\n\n## en-US\n\nReplace the default icon with customized content.\n"
  },
  {
    "path": "components/alert/demo/close-text.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzAlertModule } from 'ng-zorro-antd/alert';\n\n@Component({\n  selector: 'nz-demo-alert-close-text',\n  imports: [NzAlertModule],\n  template: `<nz-alert nzType=\"info\" nzMessage=\"Info Text\" nzCloseText=\"Close Now\" />`\n})\nexport class NzDemoAlertCloseTextComponent {}\n"
  },
  {
    "path": "components/alert/demo/custom-icon.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 自定义图标\n  en-US: Custom icon\n---\n\n## zh-CN\n\n让信息类型更加醒目, 满足定制化需求。\n\n## en-US\n\nMake information more clear and more friendly and meet customized needs.\n"
  },
  {
    "path": "components/alert/demo/custom-icon.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzAlertModule } from 'ng-zorro-antd/alert';\n\n@Component({\n  selector: 'nz-demo-alert-custom-icon',\n  imports: [NzAlertModule],\n  template: `\n    <nz-alert\n      nzType=\"success\"\n      nzMessage=\"Success Tips\"\n      nzDescription=\"Detailed description and advices about successful copywriting.\"\n      [nzIcon]=\"customIconTemplate\"\n      nzShowIcon\n    />\n\n    <ng-template #customIconTemplate>\n      <div> S </div>\n    </ng-template>\n  `\n})\nexport class NzDemoAlertCustomIconComponent {}\n"
  },
  {
    "path": "components/alert/demo/description.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 含有辅助性文字介绍\n  en-US: Description\n---\n\n## zh-CN\n\n含有辅助性文字介绍的警告提示。\n\n## en-US\n\nAdditional description for alert message.\n"
  },
  {
    "path": "components/alert/demo/description.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzAlertModule } from 'ng-zorro-antd/alert';\n\n@Component({\n  selector: 'nz-demo-alert-description',\n  imports: [NzAlertModule],\n  template: `\n    <nz-alert\n      nzType=\"success\"\n      nzMessage=\"Success Text\"\n      nzDescription=\"Success Description Success Description Success Description\"\n    />\n    <nz-alert\n      nzType=\"info\"\n      nzMessage=\"Info Text\"\n      nzDescription=\"Info Description Info Description Info Description Info Description\"\n    />\n    <nz-alert\n      nzType=\"warning\"\n      nzMessage=\"Warning Text\"\n      nzDescription=\"Warning Description Warning Description Warning Description Warning Description\"\n    />\n    <nz-alert\n      nzType=\"error\"\n      nzMessage=\"Error Text\"\n      nzDescription=\"Error Description Error Description Error Description Error Description\"\n    />\n  `,\n  styles: `\n    nz-alert {\n      margin-bottom: 16px;\n    }\n  `\n})\nexport class NzDemoAlertDescriptionComponent {}\n"
  },
  {
    "path": "components/alert/demo/icon.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 图标\n  en-US: Icon\n---\n\n## zh-CN\n\n可口的图标让信息类型更加醒目。\n\n## en-US\n\nDecent icon make information more clear and more friendly.\n"
  },
  {
    "path": "components/alert/demo/icon.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzAlertModule } from 'ng-zorro-antd/alert';\n\n@Component({\n  selector: 'nz-demo-alert-icon',\n  imports: [NzAlertModule],\n  template: `\n    <nz-alert nzType=\"success\" nzMessage=\"Success Tips\" nzShowIcon />\n    <nz-alert nzType=\"info\" nzMessage=\"Informational Notes\" nzShowIcon />\n    <nz-alert nzType=\"warning\" nzMessage=\"Warning\" nzShowIcon />\n    <nz-alert nzType=\"error\" nzMessage=\"Error\" nzShowIcon />\n    <nz-alert\n      nzType=\"success\"\n      nzMessage=\"Success Tips\"\n      nzDescription=\"Detailed description and advices about successful copywriting.\"\n      nzShowIcon\n    />\n    <nz-alert\n      nzType=\"info\"\n      nzMessage=\"Informational Notes\"\n      nzDescription=\"Additional description and informations about copywriting.\"\n      nzShowIcon\n    />\n    <nz-alert\n      nzType=\"warning\"\n      nzMessage=\"Warning\"\n      nzDescription=\"This is a warning notice about copywriting.\"\n      nzShowIcon\n    />\n    <nz-alert nzType=\"error\" nzMessage=\"Error\" nzDescription=\"This is an error message about copywriting.\" nzShowIcon />\n  `,\n  styles: `\n    nz-alert {\n      margin-bottom: 16px;\n    }\n  `\n})\nexport class NzDemoAlertIconComponent {}\n"
  },
  {
    "path": "components/alert/demo/loop-banner.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 滚动公告\n  en-US: Loop Banner\n---\n\n## zh-CN\n\n将 `nz-alert-marquee` 作为 `nzBanner` 警告的 `[nzMessage]` 模板内容传入，可实现滚动走马灯公告效果。\n使用 `nzPauseOnHover` 属性可在鼠标悬停时暂停滚动，`nzSpeed` 属性用于控制滚动速度（单位：像素/秒，默认 50，值越大滚动越快）。\n\n## en-US\n\nPass `nz-alert-marquee` as the `[nzMessage]` template content of a `nzBanner` alert to create a scrolling loop banner.\nUse `nzPauseOnHover` to pause the animation on mouse hover, and `nzSpeed` to control the scrolling speed in pixels per second (default 50, higher value = faster scrolling).\n"
  },
  {
    "path": "components/alert/demo/loop-banner.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component } from '@angular/core';\n\nimport { NzAlertModule } from 'ng-zorro-antd/alert';\n\n@Component({\n  selector: 'nz-demo-alert-loop-banner',\n  imports: [NzAlertModule],\n  template: `\n    <nz-alert nzBanner [nzMessage]=\"message\" />\n    <br />\n    <nz-alert nzBanner [nzMessage]=\"messagePauseOnHover\" />\n\n    <ng-template #message>\n      <nz-alert-marquee nzSpeed=\"60\">\n        I can be a long text that scrolls continuously in the banner alert. This text will loop seamlessly.\n      </nz-alert-marquee>\n    </ng-template>\n\n    <ng-template #messagePauseOnHover>\n      <nz-alert-marquee nzSpeed=\"60\" nzPauseOnHover=\"true\">\n        Hover over me to pause the scrolling animation. This text loops continuously.\n      </nz-alert-marquee>\n    </ng-template>\n  `\n})\nexport class NzDemoAlertLoopBannerComponent {}\n"
  },
  {
    "path": "components/alert/demo/style.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 四种样式\n  en-US: More types\n---\n\n## zh-CN\n\n共有四种样式 `success`、`info`、`warning`、`error`。\n\n## en-US\n\nThere are 4 types of Alert: `success`, `info`, `warning`, `error`.\n"
  },
  {
    "path": "components/alert/demo/style.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzAlertModule } from 'ng-zorro-antd/alert';\n\n@Component({\n  selector: 'nz-demo-alert-style',\n  imports: [NzAlertModule],\n  template: `\n    <nz-alert nzType=\"success\" nzMessage=\"Success Text\" />\n    <nz-alert nzType=\"info\" nzMessage=\"Info Text\" />\n    <nz-alert nzType=\"warning\" nzMessage=\"Warning Text\" />\n    <nz-alert nzType=\"error\" nzMessage=\"Error Text\" />\n  `,\n  styles: `\n    nz-alert {\n      margin-bottom: 16px;\n    }\n  `\n})\nexport class NzDemoAlertStyleComponent {}\n"
  },
  {
    "path": "components/alert/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Feedback\ntitle: Alert\ncover: 'https://gw.alipayobjects.com/zos/alicdn/8emPa3fjl/Alert.svg'\ndescription: Alert component for feedback.\n---\n\n## When To Use\n\n- When you need to show alert messages to users.\n- When you need a persistent static container which is closable by user actions.\n\n## API\n\n### nz-alert\n\n| Property          | Description                                                     | Type                                          | Default  | Global Config |\n| ----------------- | --------------------------------------------------------------- | --------------------------------------------- | -------- | ------------- |\n| `[nzBanner]`      | Whether to show as banner                                       | `boolean`                                     | `false`  |\n| `[nzAction]`      | Customized alert's action                                       | `string \\| TemplateRef<void>`                 | -        |\n| `[nzCloseable]`   | Whether Alert can be closed                                     | `boolean`                                     | -        | ✅            |\n| `[nzCloseText]`   | Close text to show                                              | `string \\| TemplateRef<void>`                 | -        |\n| `[nzDescription]` | Additional content of Alert                                     | `string \\| TemplateRef<void>`                 | -        |\n| `[nzMessage]`     | Content of Alert                                                | `string \\| TemplateRef<void>`                 | -        |\n| `[nzShowIcon]`    | Whether to show icon, in `nzBanner` mode default is `true`      | `boolean`                                     | `false`  | ✅            |\n| `[nzIconType]`    | Icon type, effective when `nzShowIcon` is `true`                | `string`                                      | -        |\n| `[nzType]`        | Type of Alert styles, in `nzBanner` mode default is `'warning'` | `'success' \\| 'info' \\| 'warning' \\| 'error'` | `'info'` |\n| `[nzIcon]`        | Custom icon, effective when showIcon is true                    | `string \\| TemplateRef<void>`                 | -        |\n| `(nzOnClose)`     | Callback when Alert is closed                                   | `EventEmitter<void>`                          | -        |\n\n### nz-alert-marquee\n\nUse `nz-alert-marquee` as the `[nzMessage]` template content to create a scrolling loop banner inside an alert.\n\n| Property           | Description                                                      | Type      | Default |\n| ------------------ | ---------------------------------------------------------------- | --------- | ------- |\n| `[nzPauseOnHover]` | Whether to pause the scrolling animation on mouse hover          | `boolean` | `false` |\n| `[nzSpeed]`        | Animation speed in pixels per second (higher = faster scrolling) | `number`  | `50`    |\n"
  },
  {
    "path": "components/alert/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 警告提示\ntype: 反馈\ntitle: Alert\ncover: 'https://gw.alipayobjects.com/zos/alicdn/8emPa3fjl/Alert.svg'\ndescription: 警告提示，展现需要关注的信息。\n---\n\n## 何时使用\n\n- 当某个页面需要向用户显示警告的信息时。\n- 非浮层的静态展现形式，始终展现，不会自动消失，用户可以点击关闭。\n\n## API\n\n### nz-alert\n\n| 参数              | 说明                                                      | 类型                                          | 默认值   | 全局配置 |\n| ----------------- | --------------------------------------------------------- | --------------------------------------------- | -------- | -------- |\n| `[nzBanner]`      | 是否用作顶部公告                                          | `boolean`                                     | `false`  |\n| `[nzAction]`      | 自定义操作项                                              | `string \\| TemplateRef<void>`                 | -        |\n| `[nzCloseable]`   | 默认不显示关闭按钮                                        | `boolean`                                     | -        | ✅       |\n| `[nzCloseText]`   | 自定义关闭按钮                                            | `string \\| TemplateRef<void>`                 | -        |\n| `[nzDescription]` | 警告提示的辅助性文字介绍                                  | `string \\| TemplateRef<void>`                 | -        |\n| `[nzMessage]`     | 警告提示内容                                              | `string \\| TemplateRef<void>`                 | -        |\n| `[nzShowIcon]`    | 是否显示辅助图标，`nzBanner` 模式下默认值为 `true`        | `boolean`                                     | `false`  | ✅       |\n| `[nzIconType]`    | 自定义图标类型，`nzShowIcon` 为 `true` 时有效             | `string`                                      | -        |\n| `[nzType]`        | 指定警告提示的样式，`nzBanner` 模式下默认值为 `'warning'` | `'success' \\| 'info' \\| 'warning' \\| 'error'` | `'info'` |\n| `[nzIcon]`        | 自定义图标，showIcon 为 true 时有效                       | `string \\| TemplateRef<void>`                 | -        |\n| `(nzOnClose)`     | 关闭时触发的回调函数                                      | `EventEmitter<void>`                          | -        |\n\n### nz-alert-marquee\n\n将 `nz-alert-marquee` 作为 `[nzMessage]` 的模板内容使用，可在警告提示中实现滚动走马灯效果。\n\n| 参数               | 说明                                | 类型      | 默认值  |\n| ------------------ | ----------------------------------- | --------- | ------- |\n| `[nzPauseOnHover]` | 鼠标悬停时是否暂停滚动动画          | `boolean` | `false` |\n| `[nzSpeed]`        | 滚动速度（像素/秒），值越大滚动越快 | `number`  | `50`    |\n"
  },
  {
    "path": "components/alert/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/alert/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/alert/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './alert-marquee.component';\nexport * from './alert.component';\nexport * from './alert.module';\n"
  },
  {
    "path": "components/alert/style/entry.less",
    "content": "@import './index.less';\n@import './patch.less';\n"
  },
  {
    "path": "components/alert/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@alert-prefix-cls: ~'@{ant-prefix}-alert';\n\n.@{alert-prefix-cls} {\n  .reset-component();\n\n  position: relative;\n  display: flex;\n  align-items: center;\n  padding: @alert-padding-vertical @alert-padding-horizontal;\n  word-wrap: break-word;\n  border-radius: @border-radius-base;\n\n  &-content {\n    flex: 1;\n    min-width: 0;\n  }\n\n  &-icon {\n    margin-right: @margin-xs;\n  }\n\n  &-description {\n    display: none;\n    font-size: @font-size-base;\n    line-height: @font-size-base + 8px;\n  }\n\n  &-success {\n    background-color: @alert-success-bg-color;\n    border: @border-width-base @border-style-base @alert-success-border-color;\n    .@{alert-prefix-cls}-icon {\n      color: @alert-success-icon-color;\n    }\n  }\n\n  &-info {\n    background-color: @alert-info-bg-color;\n    border: @border-width-base @border-style-base @alert-info-border-color;\n    .@{alert-prefix-cls}-icon {\n      color: @alert-info-icon-color;\n    }\n  }\n\n  &-warning {\n    background-color: @alert-warning-bg-color;\n    border: @border-width-base @border-style-base @alert-warning-border-color;\n    .@{alert-prefix-cls}-icon {\n      color: @alert-warning-icon-color;\n    }\n  }\n\n  &-error {\n    background-color: @alert-error-bg-color;\n    border: @border-width-base @border-style-base @alert-error-border-color;\n\n    .@{alert-prefix-cls}-icon {\n      color: @alert-error-icon-color;\n    }\n\n    .@{alert-prefix-cls}-description > pre {\n      margin: 0;\n      padding: 0;\n    }\n  }\n\n  &-action {\n    margin-left: @margin-xs;\n  }\n\n  &-close-icon {\n    margin-left: @margin-xs;\n    padding: 0;\n    overflow: hidden;\n    font-size: @font-size-sm;\n    line-height: @font-size-sm;\n    background-color: transparent;\n    border: none;\n    outline: none;\n    cursor: pointer;\n\n    .@{iconfont-css-prefix}-close {\n      color: @alert-close-color;\n      transition: color 0.3s;\n\n      &:hover {\n        color: @alert-close-hover-color;\n      }\n    }\n  }\n\n  &-close-text {\n    color: @alert-close-color;\n    transition: color 0.3s;\n\n    &:hover {\n      color: @alert-close-hover-color;\n    }\n  }\n\n  &-with-description {\n    align-items: flex-start;\n    padding: @alert-with-description-padding;\n  }\n\n  &-with-description&-no-icon {\n    padding: @alert-with-description-no-icon-padding-vertical 15px;\n  }\n\n  &-with-description &-icon {\n    margin-right: @alert-with-description-padding-vertical;\n    font-size: @alert-with-description-icon-size;\n  }\n\n  &-with-description &-message {\n    display: block;\n    margin-bottom: 4px;\n    color: @alert-message-color;\n    font-size: @font-size-lg;\n  }\n\n  &-message {\n    color: @alert-message-color;\n  }\n\n  &-with-description &-description {\n    display: block;\n  }\n\n  &&-motion-leave {\n    overflow: hidden;\n    opacity: 1;\n    transition: max-height 0.3s @ease-in-out-circ, opacity 0.3s @ease-in-out-circ,\n      padding-top 0.3s @ease-in-out-circ, padding-bottom 0.3s @ease-in-out-circ,\n      margin-bottom 0.3s @ease-in-out-circ;\n  }\n\n  &&-motion-leave-active {\n    max-height: 0;\n    margin-bottom: 0 !important;\n    padding-top: 0;\n    padding-bottom: 0;\n    opacity: 0;\n  }\n\n  &-banner {\n    margin-bottom: 0;\n    border: 0;\n    border-radius: 0;\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/alert/style/patch.less",
    "content": "nz-alert {\n  display: block;\n}\n\n.@{alert-prefix-cls} {\n  &-icon {\n    line-height: 1;\n  }\n\n  &-marquee {\n    display: flex;\n    flex: 1;\n    min-width: 0;\n    overflow: hidden;\n\n    &-track {\n      display: flex;\n      flex: 0 0 auto;\n      align-items: center;\n      min-width: 100%;\n      white-space: nowrap;\n      animation: alertMarquee 20s linear infinite;\n    }\n\n    &.ant-alert-marquee-pause-on-hover:hover &-track {\n      animation-play-state: paused;\n    }\n  }\n}\n\n@keyframes alertMarquee {\n  from {\n    transform: translateX(0%);\n  }\n\n  to {\n    transform: translateX(-100%);\n  }\n}\n"
  },
  {
    "path": "components/alert/style/rtl.less",
    "content": ".@{alert-prefix-cls} {\n  &&-rtl {\n    direction: rtl;\n  }\n\n  &-icon {\n    .@{alert-prefix-cls}-rtl & {\n      margin-right: auto;\n      margin-left: @margin-xs;\n    }\n  }\n\n  &-action {\n    .@{alert-prefix-cls}-rtl & {\n      margin-right: @margin-xs;\n      margin-left: auto;\n    }\n  }\n\n  &-close-icon {\n    .@{alert-prefix-cls}-rtl & {\n      margin-right: @margin-xs;\n      margin-left: auto;\n    }\n  }\n\n  &-with-description {\n    .@{alert-prefix-cls}-rtl& {\n      padding-right: @alert-with-description-icon-size;\n      padding-left: @alert-with-description-padding-vertical;\n    }\n\n    .@{alert-prefix-cls}-icon {\n      .@{alert-prefix-cls}-rtl& {\n        margin-right: auto;\n        margin-left: @alert-with-description-padding-vertical;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/anchor/anchor-link.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Platform } from '@angular/cdk/platform';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  ContentChild,\n  DestroyRef,\n  ElementRef,\n  inject,\n  Input,\n  OnInit,\n  Renderer2,\n  TemplateRef,\n  ViewChild,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { NzDirectionVHType, NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzAnchorComponent } from './anchor.component';\n\n@Component({\n  selector: 'nz-link',\n  exportAs: 'nzLink',\n  imports: [NgTemplateOutlet],\n  template: `\n    <a\n      #linkTitle\n      class=\"ant-anchor-link-title\"\n      [href]=\"nzHref\"\n      [attr.title]=\"titleStr\"\n      [target]=\"nzTarget\"\n      (click)=\"goToClick($event)\"\n    >\n      @if (titleStr) {\n        <span>{{ titleStr }}</span>\n      } @else {\n        <ng-template [ngTemplateOutlet]=\"titleTpl || nzTemplate\" />\n      }\n    </a>\n    @if (nzDirection === 'vertical') {\n      <ng-content />\n    }\n  `,\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    class: 'ant-anchor-link'\n  }\n})\nexport class NzAnchorLinkComponent implements OnInit {\n  public elementRef = inject(ElementRef<HTMLElement>);\n  private anchorComp = inject(NzAnchorComponent);\n  private platform = inject(Platform);\n  private renderer = inject(Renderer2);\n  private readonly destroyRef = inject(DestroyRef);\n\n  @Input() nzHref = '#';\n  @Input() nzTarget?: string;\n\n  titleStr: string | null = '';\n  titleTpl?: TemplateRef<NzSafeAny>;\n  nzDirection: NzDirectionVHType = 'vertical';\n\n  @Input()\n  set nzTitle(value: string | TemplateRef<void>) {\n    if (value instanceof TemplateRef) {\n      this.titleStr = null;\n      this.titleTpl = value;\n    } else {\n      this.titleStr = value;\n    }\n  }\n\n  @ContentChild('nzTemplate', { static: false }) nzTemplate!: TemplateRef<void>;\n  @ViewChild('linkTitle') linkTitle!: ElementRef<HTMLAnchorElement>;\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      this.anchorComp.unregisterLink(this);\n    });\n  }\n\n  ngOnInit(): void {\n    this.anchorComp.registerLink(this);\n    this.nzDirection = this.anchorComp.nzDirection;\n  }\n\n  getLinkTitleElement(): HTMLAnchorElement {\n    return this.linkTitle.nativeElement;\n  }\n\n  setActive(): void {\n    this.renderer.addClass(this.elementRef.nativeElement, 'ant-anchor-link-active');\n  }\n\n  unsetActive(): void {\n    this.renderer.removeClass(this.elementRef.nativeElement, 'ant-anchor-link-active');\n  }\n\n  goToClick(e: Event): void {\n    e.preventDefault();\n    e.stopPropagation();\n    if (this.platform.isBrowser) {\n      this.anchorComp.handleScrollTo(this);\n    }\n  }\n}\n"
  },
  {
    "path": "components/anchor/anchor.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { normalizePassiveListenerOptions, Platform } from '@angular/cdk/platform';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterViewInit,\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DestroyRef,\n  DOCUMENT,\n  ElementRef,\n  EventEmitter,\n  inject,\n  Input,\n  numberAttribute,\n  OnChanges,\n  Output,\n  Renderer2,\n  SimpleChanges,\n  ViewChild,\n  ViewEncapsulation\n} from '@angular/core';\nimport { Subject } from 'rxjs';\nimport { takeUntil, throttleTime } from 'rxjs/operators';\n\nimport { NzAffixModule } from 'ng-zorro-antd/affix';\nimport { NzConfigKey, NzConfigService, WithConfig } from 'ng-zorro-antd/core/config';\nimport { NzScrollService } from 'ng-zorro-antd/core/services';\nimport { NgStyleInterface, NzDirectionVHType } from 'ng-zorro-antd/core/types';\nimport { fromEventOutsideAngular, numberAttributeWithZeroFallback } from 'ng-zorro-antd/core/util';\n\nimport { NzAnchorLinkComponent } from './anchor-link.component';\nimport { getOffsetTop } from './util';\n\ninterface Section {\n  comp: NzAnchorLinkComponent;\n  top: number;\n}\n\nconst VISIBLE_CLASSNAME = 'ant-anchor-ink-ball-visible';\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'anchor';\nconst sharpMatcherRegx = /#([^#]+)$/;\n\nconst passiveEventListenerOptions = normalizePassiveListenerOptions({ passive: true });\n\n@Component({\n  selector: 'nz-anchor',\n  exportAs: 'nzAnchor',\n  imports: [NgTemplateOutlet, NzAffixModule],\n  template: `\n    @if (nzAffix) {\n      <nz-affix [nzOffsetTop]=\"nzOffsetTop\" [nzTarget]=\"container\">\n        <ng-template [ngTemplateOutlet]=\"content\" />\n      </nz-affix>\n    } @else {\n      <ng-template [ngTemplateOutlet]=\"content\" />\n    }\n\n    <ng-template #content>\n      <div\n        class=\"ant-anchor-wrapper\"\n        [class]=\"{ 'ant-anchor-wrapper-horizontal': nzDirection === 'horizontal' }\"\n        [style]=\"wrapperStyle\"\n      >\n        <div class=\"ant-anchor\" [class]=\"{ 'ant-anchor-fixed': !nzAffix && !nzShowInkInFixed }\">\n          <div class=\"ant-anchor-ink\">\n            <div class=\"ant-anchor-ink-ball\" #ink></div>\n          </div>\n          <ng-content />\n        </div>\n      </div>\n    </ng-template>\n  `,\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class NzAnchorComponent implements AfterViewInit, OnChanges {\n  public nzConfigService = inject(NzConfigService);\n  private scrollSrv = inject(NzScrollService);\n  private cdr = inject(ChangeDetectorRef);\n  private platform = inject(Platform);\n  private renderer = inject(Renderer2);\n  private doc: Document = inject(DOCUMENT);\n  private destroyRef = inject(DestroyRef);\n\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  @ViewChild('ink', { static: false }) private ink!: ElementRef;\n\n  @Input({ transform: booleanAttribute }) nzAffix = true;\n\n  @Input({ transform: booleanAttribute })\n  @WithConfig()\n  nzShowInkInFixed: boolean = false;\n\n  @Input({ transform: numberAttribute })\n  @WithConfig()\n  nzBounds: number = 5;\n\n  @Input({ transform: numberAttributeWithZeroFallback })\n  @WithConfig()\n  nzOffsetTop?: number = undefined;\n\n  @Input({ transform: numberAttributeWithZeroFallback })\n  @WithConfig()\n  nzTargetOffset?: number = undefined;\n\n  @Input() nzContainer?: string | HTMLElement;\n  @Input() nzCurrentAnchor?: string;\n  @Input() nzDirection: NzDirectionVHType = 'vertical';\n\n  @Output() readonly nzClick = new EventEmitter<string>();\n  @Output() readonly nzChange = new EventEmitter<string>();\n  @Output() readonly nzScroll = new EventEmitter<NzAnchorLinkComponent>();\n\n  visible = false;\n  wrapperStyle: NgStyleInterface = { 'max-height': '100vh' };\n\n  container?: HTMLElement | Window;\n  activeLink?: string;\n\n  private links: NzAnchorLinkComponent[] = [];\n  private animating = false;\n  private destroy$ = new Subject<boolean>();\n  private handleScrollTimeoutID?: ReturnType<typeof setTimeout>;\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      clearTimeout(this.handleScrollTimeoutID);\n      this.destroy$.next(true);\n      this.destroy$.complete();\n    });\n  }\n\n  registerLink(link: NzAnchorLinkComponent): void {\n    this.links.push(link);\n  }\n\n  unregisterLink(link: NzAnchorLinkComponent): void {\n    this.links.splice(this.links.indexOf(link), 1);\n  }\n\n  private getContainer(): HTMLElement | Window {\n    return this.container || window;\n  }\n\n  ngAfterViewInit(): void {\n    this.registerScrollEvent();\n  }\n  private registerScrollEvent(): void {\n    if (!this.platform.isBrowser) {\n      return;\n    }\n    this.destroy$.next(true);\n\n    fromEventOutsideAngular(this.getContainer(), 'scroll', passiveEventListenerOptions)\n      .pipe(throttleTime(50), takeUntil(this.destroy$))\n      .subscribe(() => this.handleScroll());\n    // Browser would maintain the scrolling position when refreshing.\n    // So we have to delay calculation in avoid of getting a incorrect result.\n    this.handleScrollTimeoutID = setTimeout(() => this.handleScroll());\n  }\n\n  handleScroll(): void {\n    if (typeof document === 'undefined' || this.animating) {\n      return;\n    }\n\n    const sections: Section[] = [];\n    const offsetTop = this.nzTargetOffset ? this.nzTargetOffset : this.nzOffsetTop || 0;\n    const scope = offsetTop + this.nzBounds;\n    this.links.forEach(comp => {\n      const sharpLinkMatch = sharpMatcherRegx.exec(comp.nzHref.toString());\n      if (!sharpLinkMatch) {\n        return;\n      }\n      const target = this.doc.getElementById(sharpLinkMatch[1]);\n      if (target) {\n        const top = getOffsetTop(target, this.getContainer());\n        if (top < scope) {\n          sections.push({\n            top,\n            comp\n          });\n        }\n      }\n    });\n\n    this.visible = !!sections.length;\n    if (!this.visible) {\n      this.clearActive();\n      this.cdr.detectChanges();\n    } else {\n      const maxSection = sections.reduce((prev, curr) => (curr.top > prev.top ? curr : prev));\n      this.handleActive(maxSection.comp);\n    }\n    this.setVisible();\n  }\n\n  private clearActive(): void {\n    this.links.forEach(i => {\n      i.unsetActive();\n    });\n  }\n\n  private setActive(comp?: NzAnchorLinkComponent): void {\n    const originalActiveLink = this.activeLink;\n    const targetComp = (this.nzCurrentAnchor && this.links.find(n => n.nzHref === this.nzCurrentAnchor)) || comp;\n    if (!targetComp) return;\n\n    targetComp.setActive();\n    const linkNode = targetComp.getLinkTitleElement();\n    if (this.nzDirection === 'vertical') {\n      this.ink.nativeElement.style.top = `${linkNode.offsetTop + linkNode.clientHeight / 2 - 4.5}px`;\n    } else {\n      this.ink.nativeElement.style.left = `${linkNode.offsetLeft + linkNode.clientWidth / 2}px`;\n    }\n    this.activeLink = (comp || targetComp).nzHref;\n    if (originalActiveLink !== this.activeLink) {\n      this.nzChange.emit(this.activeLink);\n    }\n  }\n\n  private handleActive(comp: NzAnchorLinkComponent): void {\n    this.clearActive();\n    this.setActive(comp);\n    this.visible = true;\n    this.setVisible();\n    this.nzScroll.emit(comp);\n  }\n\n  private setVisible(): void {\n    if (this.ink) {\n      const visible = this.visible;\n      if (visible) {\n        this.renderer.addClass(this.ink.nativeElement, VISIBLE_CLASSNAME);\n      } else {\n        this.renderer.removeClass(this.ink.nativeElement, VISIBLE_CLASSNAME);\n      }\n    }\n  }\n\n  handleScrollTo(linkComp: NzAnchorLinkComponent): void {\n    const id = linkComp.nzHref.replace(/^#/, '');\n    const el = this.doc.getElementById(id);\n    if (!el) {\n      return;\n    }\n\n    this.animating = true;\n    const containerScrollTop = this.scrollSrv.getScroll(this.getContainer());\n    const elOffsetTop = getOffsetTop(el, this.getContainer());\n    let targetScrollTop = containerScrollTop + elOffsetTop;\n    targetScrollTop -= this.nzTargetOffset !== undefined ? this.nzTargetOffset : this.nzOffsetTop || 0;\n    this.scrollSrv.scrollTo(this.getContainer(), targetScrollTop, {\n      callback: () => {\n        this.animating = false;\n        this.handleActive(linkComp);\n      }\n    });\n    this.nzClick.emit(linkComp.nzHref);\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzOffsetTop, nzContainer, nzCurrentAnchor } = changes;\n    if (nzOffsetTop) {\n      this.wrapperStyle = {\n        'max-height': `calc(100vh - ${this.nzOffsetTop}px)`\n      };\n    }\n    if (nzContainer) {\n      const container = this.nzContainer;\n      this.container = typeof container === 'string' ? this.doc.querySelector<HTMLElement>(container)! : container;\n      this.registerScrollEvent();\n    }\n    if (nzCurrentAnchor) {\n      this.setActive();\n    }\n  }\n}\n"
  },
  {
    "path": "components/anchor/anchor.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzAnchorLinkComponent } from './anchor-link.component';\nimport { NzAnchorComponent } from './anchor.component';\n\n@NgModule({\n  exports: [NzAnchorComponent, NzAnchorLinkComponent],\n  imports: [NzAnchorComponent, NzAnchorLinkComponent]\n})\nexport class NzAnchorModule {}\n"
  },
  {
    "path": "components/anchor/anchor.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Platform } from '@angular/cdk/platform';\nimport { Component, DebugElement, DOCUMENT, ElementRef, ViewChild } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { NzScrollService } from 'ng-zorro-antd/core/services';\nimport { sleep, updateNonSignalsInput } from 'ng-zorro-antd/core/testing';\nimport { NzDirectionVHType, NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzAnchorComponent } from './anchor.component';\nimport { NzAnchorModule } from './anchor.module';\n\nconst throttleTime = 51;\n\ndescribe('anchor', () => {\n  let fixture: ComponentFixture<TestComponent>;\n  let dl: DebugElement;\n  let context: TestComponent;\n  let page: PageObject;\n  let srv: NzScrollService;\n\n  beforeEach(async () => {\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations()]\n    });\n    fixture = TestBed.createComponent(TestComponent);\n    dl = fixture.debugElement;\n    context = fixture.componentInstance;\n    fixture.autoDetectChanges();\n    page = new PageObject();\n    srv = TestBed.inject(NzScrollService);\n    await fixture.whenStable();\n    await sleep(100);\n    spyOn(context, '_scroll');\n    spyOn(context, '_change');\n  });\n\n  afterEach(() => fixture.destroy());\n\n  describe('[default]', () => {\n    it(`should scrolling to target via click a link`, () => {\n      spyOn(srv, 'scrollTo').and.callFake((_containerEl, _targetTopValue = 0, options = {}) => {\n        if (options.callback) {\n          options.callback();\n        }\n      });\n      expect(context._scroll).not.toHaveBeenCalled();\n      page.to('#何时使用');\n      expect(context._scroll).toHaveBeenCalled();\n    });\n\n    it('should be activated when scrolling to the anchor', async () => {\n      expect(context._scroll).not.toHaveBeenCalled();\n      page.scrollTo();\n      await sleep(throttleTime);\n      const inkNode = page.getEl('.ant-anchor-ink-ball');\n      expect(+inkNode.style.top!.replace('px', '')).toBeGreaterThan(0);\n      expect(context._scroll).toHaveBeenCalled();\n    });\n\n    it('should be activated when scrolling to the anchor - horizontal', async () => {\n      context.nzDirection = 'horizontal';\n      await updateNonSignalsInput(fixture);\n      expect(context._scroll).not.toHaveBeenCalled();\n      page.scrollTo();\n      await sleep(throttleTime);\n      const inkNode = page.getEl('.ant-anchor-ink-ball');\n      expect(+inkNode.style.left!.replace('px', '')).not.toBeNull();\n      expect(context._scroll).toHaveBeenCalled();\n    });\n\n    it('should clean activated when leaving all anchor', async () => {\n      spyOn(context.comp, 'clearActive' as NzSafeAny);\n      page.scrollTo();\n      await sleep(throttleTime);\n      fixture.detectChanges();\n      expect(context.comp['clearActive']).not.toHaveBeenCalled();\n      window.scrollTo(0, 0);\n      window.dispatchEvent(new Event('scroll'));\n      await sleep(throttleTime);\n      fixture.detectChanges();\n      expect(context.comp['clearActive']!).toHaveBeenCalled();\n    });\n\n    it(`won't scrolling when is not exists link`, () => {\n      spyOn(srv, 'getScroll');\n      expect(context._scroll).not.toHaveBeenCalled();\n      expect(srv.getScroll).not.toHaveBeenCalled();\n      page!.to('#invalid');\n      expect(srv.getScroll).not.toHaveBeenCalled();\n    });\n\n    it(`won't scrolling when is invalid link`, () => {\n      spyOn(srv, 'getScroll');\n      expect(context._scroll).not.toHaveBeenCalled();\n      expect(srv.getScroll).not.toHaveBeenCalled();\n      page.to('invalidLink');\n      expect(srv.getScroll).not.toHaveBeenCalled();\n    });\n\n    it(`supports complete href link (e.g. http://www.example.com/#id)`, () => {\n      spyOn(srv, 'getScroll');\n      expect(context._scroll).not.toHaveBeenCalled();\n      expect(srv.getScroll).not.toHaveBeenCalled();\n      page.getEl('.mock-complete').click();\n      fixture.detectChanges();\n      expect(srv.getScroll).not.toHaveBeenCalled();\n    });\n\n    it(`should priorities most recently`, async () => {\n      expect(context._scroll).not.toHaveBeenCalled();\n      page.scrollTo('#parallel1');\n      await sleep(throttleTime);\n      expect(context._scroll).toHaveBeenCalled();\n    });\n  });\n\n  describe('property', () => {\n    describe('[nzAffix]', () => {\n      it(`is [true]`, () => {\n        const linkList = dl.queryAll(By.css('nz-affix'));\n        expect(linkList.length).toBe(1);\n      });\n      it(`is [false]`, async () => {\n        let linkList = dl.queryAll(By.css('nz-affix'));\n        expect(linkList.length).toBe(1);\n        context.nzAffix = false;\n        await updateNonSignalsInput(fixture);\n        linkList = dl.queryAll(By.css('nz-affix'));\n        expect(linkList.length).toBe(0);\n      });\n    });\n\n    describe('[nzOffsetTop]', () => {\n      it('should be using \"calc\" method calculate max-height', () => {\n        const wrapperEl = dl.query(By.css('.ant-anchor-wrapper'));\n        expect(wrapperEl.styles['max-height']).toContain('calc(');\n      });\n    });\n\n    describe('[nzCurrentAnchor]', () => {\n      it('customize the anchor highlight', async () => {\n        context.nzCurrentAnchor = '#basic';\n        await updateNonSignalsInput(fixture);\n        const linkList = dl.queryAll(By.css('.ant-anchor-link'));\n        expect(linkList.length).toBeGreaterThan(0);\n        const activeLink = linkList.find(n => (n.nativeElement as HTMLDivElement).getAttribute('nzhref') === '#basic')!;\n        expect(activeLink).toBeTruthy();\n        expect((activeLink.nativeElement as HTMLDivElement).classList).toContain('ant-anchor-link-active');\n      });\n    });\n\n    describe('[nzShowInkInFixed]', () => {\n      beforeEach(async () => {\n        context.nzAffix = false;\n        await updateNonSignalsInput(fixture);\n      });\n      it('should be show ink when [false]', async () => {\n        context.nzShowInkInFixed = false;\n        await updateNonSignalsInput(fixture);\n        page.scrollTo();\n        expect(dl.query(By.css('.ant-anchor-fixed')) == null).toBe(false);\n      });\n      it('should be hide ink when [true]', async () => {\n        context.nzShowInkInFixed = true;\n        await updateNonSignalsInput(fixture);\n        page.scrollTo();\n        expect(dl.query(By.css('.ant-anchor-fixed')) == null).toBe(true);\n      });\n    });\n\n    describe('[nzContainer]', () => {\n      it('with window', async () => {\n        spyOn(window, 'addEventListener');\n        context.nzContainer = window;\n        await updateNonSignalsInput(fixture);\n        expect(window.addEventListener).toHaveBeenCalled();\n      });\n      it('with string', async () => {\n        spyOn(context, '_click');\n        const el = document.querySelector('#target')!;\n        spyOn(el, 'addEventListener');\n        context.nzContainer = '#target';\n        await updateNonSignalsInput(fixture);\n        expect(el.addEventListener).toHaveBeenCalled();\n        page.to('#basic-target');\n        expect(context._click).toHaveBeenCalled();\n      });\n    });\n\n    describe('(nzChange)', () => {\n      it('should emit nzChange when click a link', async () => {\n        spyOn(srv, 'scrollTo').and.callFake((_containerEl, _targetTopValue = 0, options = {}) => {\n          if (options.callback) {\n            options.callback();\n          }\n        });\n        expect(context._change).not.toHaveBeenCalled();\n        page.to('#basic-target');\n        expect(context._change).toHaveBeenCalled();\n      });\n      it('should emit nzChange when scrolling to the anchor', async () => {\n        spyOn(context, '_change');\n        expect(context._change).not.toHaveBeenCalled();\n        page.scrollTo();\n        await sleep(throttleTime);\n        const inkNode = page.getEl('.ant-anchor-ink-ball');\n        expect(+inkNode.style.top!.replace('px', '')).toBeGreaterThan(0);\n        expect(context._change).toHaveBeenCalled();\n      });\n    });\n\n    it('(nzClick)', () => {\n      spyOn(context, '_click');\n      expect(context._click).not.toHaveBeenCalled();\n      const linkList = dl.queryAll(By.css('.ant-anchor-link-title'));\n      expect(linkList.length).toBeGreaterThan(0);\n      (linkList[0].nativeElement as HTMLLinkElement).click();\n      fixture.detectChanges();\n      expect(context._click).toHaveBeenCalled();\n    });\n  });\n\n  describe('link', () => {\n    it(`should show custom template of [nzTemplate]`, () => {\n      expect(dl.query(By.css('.nzTemplate-title')) != null).toBe(true);\n    });\n    it(`should show custom template of [nzTitle]`, () => {\n      expect(dl.query(By.css('.nzTitle-title')) != null).toBe(true);\n    });\n  });\n\n  describe('direction', () => {\n    it(`should have vertical direction by default`, () => {\n      const wrapperEl = dl.query(By.css('.ant-anchor-wrapper'));\n      expect(wrapperEl.nativeElement.classList).not.toContain('ant-anchor-wrapper-horizontal');\n    });\n\n    it(`should have correct class name in horizontal mode`, async () => {\n      context.nzDirection = 'horizontal';\n      await updateNonSignalsInput(fixture);\n      const wrapperEl = dl.query(By.css('.ant-anchor-wrapper'));\n      expect(wrapperEl.nativeElement.classList).toContain('ant-anchor-wrapper-horizontal');\n    });\n  });\n\n  describe('**boundary**', () => {\n    it('#getOffsetTop', async () => {\n      const el1 = document.getElementById('何时使用')!;\n      spyOn(el1, 'getClientRects').and.returnValue([] as NzSafeAny);\n      const el2 = document.getElementById('parallel1')!;\n      spyOn(el2, 'getBoundingClientRect').and.returnValue({\n        top: 0\n      } as NzSafeAny);\n      expect(context._scroll).not.toHaveBeenCalled();\n      page.scrollTo();\n      await sleep(throttleTime);\n      expect(context._scroll).toHaveBeenCalled();\n    });\n  });\n\n  class PageObject {\n    getEl(cls: string): HTMLElement {\n      const el = dl.query(By.css(cls));\n      expect(el).not.toBeNull();\n      return el.nativeElement as HTMLElement;\n    }\n    to(href: string = '#basic'): this {\n      this.getEl(`nz-affix [href=\"${href}\"]`).click();\n      fixture.detectChanges();\n      return this;\n    }\n    scrollTo(href: string = '#basic'): this {\n      const toNode = dl.query(By.css(href));\n      (toNode.nativeElement as HTMLElement).scrollIntoView();\n      fixture.detectChanges();\n      return this;\n    }\n  }\n});\n\n@Component({\n  imports: [NzAnchorModule],\n  template: `\n    <nz-anchor\n      [nzAffix]=\"nzAffix\"\n      [nzBounds]=\"nzBounds\"\n      [nzShowInkInFixed]=\"nzShowInkInFixed\"\n      [nzOffsetTop]=\"nzOffsetTop\"\n      [nzTargetOffset]=\"nzTargetOffset\"\n      [nzContainer]=\"nzContainer\"\n      [nzCurrentAnchor]=\"nzCurrentAnchor\"\n      [nzDirection]=\"nzDirection\"\n      (nzClick)=\"_click()\"\n      (nzScroll)=\"_scroll()\"\n      (nzChange)=\"_change()\"\n    >\n      <nz-link nzHref=\"#何时使用\" nzTitle=\"何时使用\" />\n      <nz-link nzHref=\"#basic\" nzTitle=\"Basic demo\" />\n      <nz-link nzHref=\"#API-AnchorLink\">\n        <ng-template #nzTemplate>\n          <span class=\"nzTemplate-title\">tpl</span>\n        </ng-template>\n      </nz-link>\n      <nz-link nzHref=\"#API\" nzTitle=\"API\">\n        <nz-link nzHref=\"#API-Anchor\" nzTitle=\"nz-anchor\" />\n        <nz-link nzHref=\"#API-AnchorLink\" [nzTitle]=\"title\">\n          <ng-template #title>\n            <span class=\"nzTitle-title\">tpl-title</span>\n          </ng-template>\n        </nz-link>\n      </nz-link>\n      <nz-link nzHref=\"#invalid\" nzTitle=\"invalid\" />\n      <nz-link nzHref=\"invalidLink\" nzTitle=\"invalidLink\" />\n      <nz-link nzHref=\"http://www.example.com/#id\" nzTitle=\"complete\" class=\"mock-complete\" />\n      <nz-link nzHref=\"#parallel1\" nzTitle=\"parallel1\" />\n      <nz-link nzHref=\"#parallel2\" nzTitle=\"parallel2\" />\n      <nz-link nzHref=\"#basic-target\" nzTitle=\"basic-target\" />\n    </nz-anchor>\n    <h2 id=\"何时使用\"></h2>\n    <div style=\"height: 1000px\"></div>\n    <h2 id=\"basic\"></h2>\n    <div style=\"height: 100px\"></div>\n    <h2 id=\"API\"></h2>\n    <div style=\"height: 100px\"></div>\n    <h2 id=\"API-Anchor\"></h2>\n    <div style=\"height: 100px\"></div>\n    <h2 id=\"API-AnchorLink\"></h2>\n    <table>\n      <tr>\n        <td><h2 id=\"parallel1\">parallel1</h2></td>\n        <td><h2 id=\"parallel2\">parallel2</h2></td>\n      </tr>\n    </table>\n\n    <div style=\"height: 1000px\"></div>\n    <div id=\"target\">\n      <div style=\"height: 1000px\"></div>\n      <h2 id=\"basic-target\"></h2>\n    </div>\n  `,\n  styles: `\n    @import '../style/testing.less';\n    @import './style/patch.less';\n  `\n})\nexport class TestComponent {\n  @ViewChild(NzAnchorComponent, { static: false }) comp!: NzAnchorComponent;\n  nzAffix = true;\n  nzBounds = 5;\n  nzOffsetTop = 0;\n  nzTargetOffset?: number;\n  nzShowInkInFixed = false;\n  nzContainer: NzSafeAny = null;\n  nzCurrentAnchor?: string;\n  nzDirection: NzDirectionVHType = 'vertical';\n  _click(): void {}\n  _change(): void {}\n  _scroll(): void {}\n}\n\ndescribe('NzAnchor', () => {\n  let component: NzAnchorComponent;\n  let fixture: ComponentFixture<NzAnchorComponent>;\n  let mockPlatform: Platform;\n  let scrollService: NzScrollService;\n  let mockDocument: Document;\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [\n        NzAnchorComponent,\n        { provide: DOCUMENT, useValue: document },\n        NzScrollService,\n        { provide: ElementRef, useValue: new ElementRef(document.createElement('div')) }\n      ]\n    });\n\n    fixture = TestBed.createComponent(NzAnchorComponent);\n    component = fixture.componentInstance;\n    mockPlatform = TestBed.inject(Platform);\n    scrollService = TestBed.inject(NzScrollService);\n    mockDocument = TestBed.inject(DOCUMENT);\n  });\n\n  it('should not register listeners if platform is not browser', () => {\n    mockPlatform.isBrowser = false;\n\n    component.ngAfterViewInit();\n    expect(component['handleScrollTimeoutID']).toBeFalsy();\n  });\n\n  it('should calculate the correct offsetTop in handleScroll method', () => {\n    component.nzTargetOffset = 50;\n    component.nzOffsetTop = 20;\n    component.nzBounds = 5;\n\n    component.handleScroll();\n\n    expect(component.nzTargetOffset).toBe(50);\n    expect(component.nzOffsetTop).toBe(20);\n  });\n\n  it('should calculate target scroll top correctly and call scrollTo', () => {\n    const mockElement = document.createElement('div');\n    spyOn(mockDocument, 'getElementById').and.returnValue(mockElement);\n    spyOn(mockDocument, 'querySelector').and.returnValue(mockElement);\n    spyOn(scrollService, 'getScroll').and.returnValue(100);\n    spyOn<NzSafeAny>(component, 'getContainer').and.returnValue(window);\n\n    component.nzTargetOffset = undefined;\n    component.nzOffsetTop = undefined;\n\n    const mockLinkComponent = {\n      nzHref: '#test',\n      setActive: jasmine.createSpy('setActive'),\n      getLinkTitleElement: () => document.createElement('a')\n    } as NzSafeAny;\n\n    const scrollToSpy = spyOn(scrollService, 'scrollTo').and.callThrough();\n\n    component.handleScrollTo(mockLinkComponent);\n\n    expect(scrollToSpy).toHaveBeenCalledWith(component['getContainer'](), 100, jasmine.any(Object));\n  });\n});\n"
  },
  {
    "path": "components/anchor/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n最简单的用法。\n\n## en-US\n\nThe simplest usage.\n"
  },
  {
    "path": "components/anchor/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzAnchorModule } from 'ng-zorro-antd/anchor';\n\n@Component({\n  selector: 'nz-demo-anchor-basic',\n  imports: [NzAnchorModule],\n  template: `\n    <nz-anchor>\n      <nz-link nzHref=\"#components-anchor-demo-basic\" nzTitle=\"Basic demo\" />\n      <nz-link nzHref=\"#components-anchor-demo-static\" nzTitle=\"Static demo\" />\n      <nz-link nzHref=\"#api\" nzTitle=\"API\">\n        <nz-link nzHref=\"#nz-anchor\" nzTitle=\"nz-anchor\" />\n        <nz-link nzHref=\"#nz-link\" nzTitle=\"nz-link\" />\n      </nz-link>\n    </nz-anchor>\n  `\n})\nexport class NzDemoAnchorBasicComponent {}\n"
  },
  {
    "path": "components/anchor/demo/customize-highlight.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 自定义锚点高亮\n  en-US: Customize the anchor highlight\n---\n\n## zh-CN\n\n自定义锚点高亮。\n\n## en-US\n\nCustomize the anchor highlight.\n"
  },
  {
    "path": "components/anchor/demo/customize-highlight.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzAnchorModule } from 'ng-zorro-antd/anchor';\n\n@Component({\n  selector: 'nz-demo-anchor-customize-highlight',\n  imports: [NzAnchorModule],\n  template: `\n    <nz-anchor nzCurrentAnchor=\"#components-anchor-demo-static\">\n      <nz-link nzHref=\"#components-anchor-demo-basic\" nzTitle=\"Basic demo\" />\n      <nz-link nzHref=\"#components-anchor-demo-static\" nzTitle=\"Static demo\" />\n      <nz-link nzHref=\"#api\" nzTitle=\"API\">\n        <nz-link nzHref=\"#nz-anchor\" nzTitle=\"nz-anchor\" />\n        <nz-link nzHref=\"#nz-link\" nzTitle=\"nz-link\" />\n      </nz-link>\n    </nz-anchor>\n  `\n})\nexport class NzDemoAnchorCustomizeHighlightComponent {}\n"
  },
  {
    "path": "components/anchor/demo/horizontal-anchor.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 横向 Anchor\n  en-US: Horizontal Anchor\n---\n\n## zh-CN\n\n横向 Anchor。\n\n## en-US\n\nHorizontally aligned anchors\n"
  },
  {
    "path": "components/anchor/demo/horizontal-anchor.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzAnchorModule } from 'ng-zorro-antd/anchor';\n\n@Component({\n  selector: 'nz-demo-anchor-horizontal-anchor',\n  imports: [NzAnchorModule],\n  template: `\n    <nz-anchor nzDirection=\"horizontal\">\n      <nz-link nzHref=\"#components-anchor-demo-basic\" nzTitle=\"Basic demo\" />\n      <nz-link nzHref=\"#components-anchor-demo-static\" nzTitle=\"Static demo\" />\n      <nz-link nzHref=\"#api\" nzTitle=\"API\">\n        <nz-link nzHref=\"#nz-anchor\" nzTitle=\"nz-anchor\" />\n        <nz-link nzHref=\"#nz-link\" nzTitle=\"nz-link\" />\n      </nz-link>\n    </nz-anchor>\n  `\n})\nexport class NzDemoAnchorHorizontalAnchorComponent {}\n"
  },
  {
    "path": "components/anchor/demo/on-change.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 监听锚点链接改变\n  en-US: Listening for anchor link change\n---\n\n## zh-CN\n\n监听锚点链接改变\n\n## en-US\n\nListening for anchor link change.\n"
  },
  {
    "path": "components/anchor/demo/on-change.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzAnchorModule } from 'ng-zorro-antd/anchor';\n\n@Component({\n  selector: 'nz-demo-anchor-on-change',\n  imports: [NzAnchorModule],\n  template: `\n    <nz-anchor (nzChange)=\"handleChange($event)\">\n      <nz-link nzHref=\"#components-anchor-demo-basic\" nzTitle=\"Basic demo\" />\n      <nz-link nzHref=\"#components-anchor-demo-static\" nzTitle=\"Static demo\" />\n      <nz-link nzHref=\"#api\" nzTitle=\"API\">\n        <nz-link nzHref=\"#nz-anchor\" nzTitle=\"nz-anchor\" />\n        <nz-link nzHref=\"#nz-link\" nzTitle=\"nz-link\" />\n      </nz-link>\n    </nz-anchor>\n  `\n})\nexport class NzDemoAnchorOnChangeComponent {\n  handleChange(link: string): void {\n    console.log('Anchor:OnChange', link);\n  }\n}\n"
  },
  {
    "path": "components/anchor/demo/on-click.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 自定义 onClick 事件\n  en-US: Customize the onClick event\n---\n\n## zh-CN\n\n点击锚点不记录历史。\n\n## en-US\n\nClicking on an anchor does not record history.\n"
  },
  {
    "path": "components/anchor/demo/on-click.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzAnchorModule } from 'ng-zorro-antd/anchor';\n\n@Component({\n  selector: 'nz-demo-anchor-on-click',\n  imports: [NzAnchorModule],\n  template: `\n    <nz-anchor (nzClick)=\"handleClick($event)\">\n      <nz-link nzHref=\"#components-anchor-demo-basic\" nzTitle=\"Basic demo\" />\n      <nz-link nzHref=\"#components-anchor-demo-static\" nzTitle=\"Static demo\" />\n      <nz-link nzHref=\"#api\" nzTitle=\"API\">\n        <nz-link nzHref=\"#nz-anchor\" nzTitle=\"nz-anchor\" />\n        <nz-link nzHref=\"#nz-link\" nzTitle=\"nz-link\" />\n      </nz-link>\n    </nz-anchor>\n  `\n})\nexport class NzDemoAnchorOnClickComponent {\n  handleClick(e: string): void {\n    console.log(e);\n  }\n}\n"
  },
  {
    "path": "components/anchor/demo/static.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 静态位置\n  en-US: Static Anchor\n---\n\n## zh-CN\n\n不浮动，状态不随页面滚动变化。\n\n## en-US\n\nDo not change state when page is scrolling.\n"
  },
  {
    "path": "components/anchor/demo/static.ts",
    "content": "import { Component, ViewEncapsulation } from '@angular/core';\n\nimport { NzAnchorModule } from 'ng-zorro-antd/anchor';\n\n@Component({\n  selector: 'nz-demo-anchor-static',\n  imports: [NzAnchorModule],\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <nz-anchor [nzAffix]=\"false\">\n      <nz-link nzHref=\"#components-anchor-demo-basic\" nzTitle=\"Basic demo\" />\n      <nz-link nzHref=\"#components-anchor-demo-static\" nzTitle=\"Static demo\" />\n      <nz-link nzHref=\"#api\" nzTitle=\"API\">\n        <nz-link nzHref=\"#nz-anchor\" nzTitle=\"nz-anchor\" />\n        <nz-link nzHref=\"#nz-link\" nzTitle=\"nz-link\" />\n      </nz-link>\n    </nz-anchor>\n  `\n})\nexport class NzDemoAnchorStaticComponent {}\n"
  },
  {
    "path": "components/anchor/demo/target-offset.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 设置锚点滚动偏移量\n  en-US: Set Anchor scroll offset\n---\n\n## zh-CN\n\n锚点目标滚动到屏幕正中间。\n\n## en-US\n\nAnchor target scroll to screen center.\n"
  },
  {
    "path": "components/anchor/demo/target-offset.ts",
    "content": "import { afterNextRender, Component, signal } from '@angular/core';\n\nimport { NzAnchorModule } from 'ng-zorro-antd/anchor';\n\n@Component({\n  selector: 'nz-demo-anchor-target-offset',\n  imports: [NzAnchorModule],\n  template: `\n    <nz-anchor [nzTargetOffset]=\"targetOffset()\">\n      <nz-link nzHref=\"#components-anchor-demo-basic\" nzTitle=\"Basic demo\" />\n      <nz-link nzHref=\"#components-anchor-demo-static\" nzTitle=\"Static demo\" />\n      <nz-link nzHref=\"#api\" nzTitle=\"API\">\n        <nz-link nzHref=\"#nz-anchor\" nzTitle=\"nz-anchor\" />\n        <nz-link nzHref=\"#nz-link\" nzTitle=\"nz-link\" />\n      </nz-link>\n    </nz-anchor>\n  `\n})\nexport class NzDemoAnchorTargetOffsetComponent {\n  readonly targetOffset = signal(0);\n\n  constructor() {\n    afterNextRender(() => {\n      this.targetOffset.set(window.innerHeight / 2);\n    });\n  }\n}\n"
  },
  {
    "path": "components/anchor/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Navigation\ntitle: Anchor\ncover: 'https://gw.alipayobjects.com/zos/alicdn/_1-C1JwsC/Anchor.svg'\ndescription: Hyperlinks to scroll on one page.\n---\n\n## When To Use\n\nFor displaying anchor hyperlinks on page and jumping between them.\n\n## API\n\n### nz-anchor\n\n| Property             | Description                                                        | Type                                  | Default      | Global Config |\n| -------------------- | ------------------------------------------------------------------ | ------------------------------------- | ------------ | ------------- |\n| `[nzAffix]`          | Fixed mode of Anchor                                               | `boolean`                             | `true`       |\n| `[nzBounds]`         | Bounding distance of anchor area, unit: px                         | `number`                              | `5`          | ✅            |\n| `[nzOffsetTop]`      | Pixels to offset from top when calculating position of scroll      | `number`                              | `0`          | ✅            |\n| `[nzShowInkInFixed]` | Whether show ink-balls in fixed mode                               | `boolean`                             | `false`      | ✅            |\n| `[nzTargetOffset]`   | Anchor scroll offset, default as `offsetTop`                       | `number`                              | -            |               |\n| `[nzContainer]`      | Scrolling container                                                | `string \\| HTMLElement`               | `window`     |\n| `[nzCurrentAnchor]`  | Customize the anchor highlight                                     | `string`                              | -            |               |\n| `[nzDirection]`      | Set Anchor direction                                               | `'vertical' \\| 'horizontal'`          | `'vertical'` |               |\n| `(nzClick)`          | Click of Anchor item                                               | `EventEmitter<string>`                | -            |\n| `(nzChange)`         | Listening for anchor link change                                   | `EventEmitter<string>`                | -            |               |\n| `(nzScroll)`         | The scroll function that is triggered when scrolling to an anchor. | `EventEmitter<NzAnchorLinkComponent>` | -            |\n\n### nz-link\n\n| Property     | Description                               | Type                          |\n| ------------ | ----------------------------------------- | ----------------------------- |\n| `[nzHref]`   | target of hyperlink                       | `string`                      |\n| `[nzTarget]` | Specifies where to display the linked URL | `string`                      |\n| `[nzTitle]`  | content of hyperlink                      | `string \\| TemplateRef<void>` |\n"
  },
  {
    "path": "components/anchor/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 锚点\ntype: 导航\ntitle: Anchor\ncover: 'https://gw.alipayobjects.com/zos/alicdn/_1-C1JwsC/Anchor.svg'\ndescription: 用于跳转到页面指定位置。\n---\n\n## 何时使用\n\n需要展现当前页面上可供跳转的锚点链接，以及快速在锚点之间跳转。\n\n## API\n\n### nz-anchor\n\n| 成员                 | 说明                                    | 类型                                  | 默认值       | 全局配置 |\n| -------------------- | --------------------------------------- | ------------------------------------- | ------------ | -------- |\n| `[nzAffix]`          | 固定模式                                | `boolean`                             | `true`       |\n| `[nzBounds]`         | 锚点区域边界，单位：px                  | `number`                              | `5`          | ✅       |\n| `[nzOffsetTop]`      | 距离窗口顶部达到指定偏移量后触发        | `number`                              | -            | ✅       |\n| `[nzShowInkInFixed]` | 固定模式是否显示小圆点                  | `boolean`                             | `false`      | ✅       |\n| `[nzTargetOffset]`   | 锚点滚动偏移量，默认与 `offsetTop` 相同 | number                                | -            |          |\n| `[nzContainer]`      | 指定滚动的容器                          | `string \\| HTMLElement`               | `window`     |\n| `[nzCurrentAnchor]`  | 自定义高亮的锚点                        | string                                | -            |          |\n| `[nzDirection]`      | 设置导航方向                            | `'vertical' \\| 'horizontal'`          | `'vertical'` |          |\n| `(nzClick)`          | 点击项触发                              | `EventEmitter<string>`                | -            |\n| `(nzChange)`         | 监听锚点链接改变                        | `EventEmitter<string>`                | -            |          |\n| `(nzScroll)`         | 滚动至某锚点时触发                      | `EventEmitter<NzAnchorLinkComponent>` | -            |\n\n### nz-link\n\n| 成员         | 说明                           | 类型                          |\n| ------------ | ------------------------------ | ----------------------------- |\n| `[nzHref]`   | 锚点链接                       | `string`                      |\n| `[nzTarget]` | 该属性指定在何处显示链接的资源 | `string`                      |\n| `[nzTitle]`  | 文字内容                       | `string \\| TemplateRef<void>` |\n"
  },
  {
    "path": "components/anchor/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/anchor/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/anchor/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './anchor-link.component';\nexport * from './anchor.component';\nexport * from './anchor.module';\n"
  },
  {
    "path": "components/anchor/style/entry.less",
    "content": "@import './index.less';\n@import '../../affix/style/entry.less';\n@import \"./patch\";\n"
  },
  {
    "path": "components/anchor/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@anchor-border-width: 2px;\n\n.@{ant-prefix}-anchor {\n  .reset-component();\n\n  position: relative;\n  padding-left: @anchor-border-width;\n\n  &-wrapper {\n    margin-left: -4px;\n    padding-left: 4px;\n    overflow: auto;\n    background-color: @anchor-bg;\n  }\n\n  &-ink {\n    position: absolute;\n    top: 0;\n    left: 0;\n    height: 100%;\n\n    &::before {\n      position: relative;\n      display: block;\n      width: @anchor-border-width;\n      height: 100%;\n      margin: 0 auto;\n      background-color: @anchor-border-color;\n      content: ' ';\n    }\n\n    &-ball {\n      position: absolute;\n      left: 50%;\n      display: none;\n      width: 8px;\n      height: 8px;\n      background-color: @component-background;\n      border: 2px solid @primary-color;\n      border-radius: 8px;\n      transform: translateX(-50%);\n      transition: top 0.3s ease-in-out;\n\n      &.@{ant-prefix}-anchor-ink-ball-visible {\n        display: inline-block;\n      }\n    }\n  }\n\n  &-fixed &-ink &-ink-ball {\n    display: none;\n  }\n\n  &-link {\n    padding: @anchor-link-padding;\n\n    &-title {\n      position: relative;\n      display: block;\n      margin-bottom: 3px;\n      overflow: hidden;\n      color: @text-color;\n      white-space: nowrap;\n      text-overflow: ellipsis;\n      transition: all 0.3s;\n\n      &:only-child {\n        margin-bottom: 0;\n      }\n    }\n\n    &-active > &-title {\n      color: @primary-color;\n    }\n  }\n\n  &-link &-link {\n    padding-top: 2px;\n    padding-bottom: 2px;\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/anchor/style/patch.less",
    "content": "@import '../../style/themes/index';\n\nnz-link {\n  display: block;\n}\n\n.@{ant-prefix}-anchor {\n  &-wrapper {\n    // This is a feature of Antd 5, so we need add in the patch file.\n    &-horizontal {\n      margin-left: unset;\n      padding-left: unset;\n      margin-bottom: -4px;\n      padding-bottom: 4px;\n\n      .ant-anchor {\n        display: flex;\n\n        &-ink {\n          top: unset;\n          bottom: 0;\n          width: 100%;\n          height: unset;\n\n          &:before {\n            width: 100%;\n            height: 2px;\n          }\n\n          &-ball {\n            transform: translate(-50%, -50%);\n          }\n        }\n\n        &-link {\n          &:first-of-type {\n            padding-inline: 0;\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/anchor/style/rtl.less",
    "content": ".@{ant-prefix}-anchor {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &-wrapper {\n    .@{ant-prefix}-anchor-rtl& {\n      margin-right: -4px;\n      margin-left: 0;\n      padding-right: 4px;\n      padding-left: 0;\n    }\n  }\n\n  &-ink {\n    .@{ant-prefix}-anchor-rtl & {\n      right: 0;\n      left: auto;\n    }\n\n    &-ball {\n      .@{ant-prefix}-anchor-rtl & {\n        right: 50%;\n        left: 0;\n        transform: translateX(50%);\n      }\n    }\n  }\n\n  &-link {\n    .@{ant-prefix}-anchor-rtl & {\n      padding: @anchor-link-top @anchor-link-left @anchor-link-top 0;\n    }\n  }\n}\n"
  },
  {
    "path": "components/anchor/util.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport function getOffsetTop(element: HTMLElement, container: HTMLElement | Window): number {\n  if (!element || !element.getClientRects().length) {\n    return 0;\n  }\n  const rect = element.getBoundingClientRect();\n\n  if (rect.width || rect.height) {\n    if (container === window) {\n      const documentElement = element.ownerDocument!.documentElement!;\n      return rect.top - documentElement.clientTop;\n    }\n    return rect.top - (container as HTMLElement).getBoundingClientRect().top;\n  }\n\n  return rect.top;\n}\n"
  },
  {
    "path": "components/auto-complete/autocomplete-optgroup.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, Input, TemplateRef, ViewEncapsulation } from '@angular/core';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\n\n@Component({\n  selector: 'nz-auto-optgroup',\n  exportAs: 'nzAutoOptgroup',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  imports: [NzOutletModule],\n  template: `\n    <div class=\"ant-select-item ant-select-item-group\">\n      <ng-container *nzStringTemplateOutlet=\"nzLabel\">{{ nzLabel }}</ng-container>\n    </div>\n    <ng-content select=\"nz-auto-option\" />\n  `\n})\nexport class NzAutocompleteOptgroupComponent {\n  @Input() nzLabel?: string | TemplateRef<void>;\n}\n"
  },
  {
    "path": "components/auto-complete/autocomplete-option.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ElementRef,\n  EventEmitter,\n  Input,\n  NgZone,\n  OnInit,\n  Output,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject,\n  DestroyRef\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { filter } from 'rxjs/operators';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { fromEventOutsideAngular, scrollIntoView } from 'ng-zorro-antd/core/util';\n\nimport { NzAutocompleteOptgroupComponent } from './autocomplete-optgroup.component';\n\nexport class NzOptionSelectionChange {\n  constructor(\n    public source: NzAutocompleteOptionComponent,\n    public isUserInput: boolean = false\n  ) {}\n}\n\n@Component({\n  selector: 'nz-auto-option',\n  exportAs: 'nzAutoOption',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <div class=\"ant-select-item-option-content\">\n      <ng-content />\n    </div>\n  `,\n  host: {\n    role: 'menuitem',\n    class: 'ant-select-item ant-select-item-option',\n    '[class.ant-select-item-option-grouped]': 'nzAutocompleteOptgroupComponent',\n    '[class.ant-select-item-option-selected]': 'selected',\n    '[class.ant-select-item-option-active]': 'active',\n    '[class.ant-select-item-option-disabled]': 'nzDisabled',\n    '[attr.aria-selected]': 'selected.toString()',\n    '[attr.aria-disabled]': 'nzDisabled.toString()',\n    '(click)': 'selectViaInteraction()'\n  }\n})\nexport class NzAutocompleteOptionComponent implements OnInit {\n  private ngZone = inject(NgZone);\n  private changeDetectorRef = inject(ChangeDetectorRef);\n  private element = inject(ElementRef<HTMLElement>);\n  private destroyRef = inject(DestroyRef);\n\n  @Input() nzValue: NzSafeAny;\n  @Input() nzLabel?: string;\n  @Input({ transform: booleanAttribute }) nzDisabled = false;\n  @Output() readonly selectionChange = new EventEmitter<NzOptionSelectionChange>();\n  @Output() readonly mouseEntered = new EventEmitter<NzAutocompleteOptionComponent>();\n\n  active = false;\n  selected = false;\n  nzAutocompleteOptgroupComponent = inject(NzAutocompleteOptgroupComponent, { optional: true });\n\n  ngOnInit(): void {\n    fromEventOutsideAngular(this.element.nativeElement, 'mouseenter')\n      .pipe(\n        filter(() => this.mouseEntered.observers.length > 0),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(() => {\n        this.ngZone.run(() => this.mouseEntered.emit(this));\n      });\n\n    fromEventOutsideAngular(this.element.nativeElement, 'mousedown')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(event => event.preventDefault());\n  }\n\n  select(emit: boolean = true): void {\n    this.selected = true;\n    this.changeDetectorRef.markForCheck();\n    if (emit) {\n      this.emitSelectionChangeEvent();\n    }\n  }\n\n  deselect(): void {\n    this.selected = false;\n    this.changeDetectorRef.markForCheck();\n    this.emitSelectionChangeEvent();\n  }\n\n  /** Git display label */\n  getLabel(): string {\n    return this.nzLabel || this.nzValue.toString();\n  }\n\n  /** Set active (only styles) */\n  setActiveStyles(): void {\n    if (!this.active) {\n      this.active = true;\n      this.changeDetectorRef.markForCheck();\n    }\n  }\n\n  /** Unset active (only styles) */\n  setInactiveStyles(): void {\n    if (this.active) {\n      this.active = false;\n      this.changeDetectorRef.markForCheck();\n    }\n  }\n\n  scrollIntoViewIfNeeded(): void {\n    scrollIntoView(this.element.nativeElement);\n  }\n\n  selectViaInteraction(): void {\n    if (!this.nzDisabled) {\n      this.selected = !this.selected;\n      if (this.selected) {\n        this.setActiveStyles();\n      } else {\n        this.setInactiveStyles();\n      }\n      this.emitSelectionChangeEvent(true);\n      this.changeDetectorRef.markForCheck();\n    }\n  }\n\n  private emitSelectionChangeEvent(isUserInput: boolean = false): void {\n    this.selectionChange.emit(new NzOptionSelectionChange(this, isUserInput));\n  }\n}\n"
  },
  {
    "path": "components/auto-complete/autocomplete-trigger.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { DOWN_ARROW, ENTER, ESCAPE, TAB, UP_ARROW } from '@angular/cdk/keycodes';\nimport {\n  ConnectionPositionPair,\n  createFlexibleConnectedPositionStrategy,\n  createOverlayRef,\n  createRepositionScrollStrategy,\n  FlexibleConnectedPositionStrategy,\n  OverlayRef,\n  PositionStrategy\n} from '@angular/cdk/overlay';\nimport { TemplatePortal } from '@angular/cdk/portal';\nimport {\n  AfterViewInit,\n  DestroyRef,\n  Directive,\n  DOCUMENT,\n  ElementRef,\n  forwardRef,\n  inject,\n  Injector,\n  Input,\n  NgZone,\n  ViewContainerRef\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { Subscription } from 'rxjs';\nimport { delay, filter, tap } from 'rxjs/operators';\n\nimport { NzSafeAny, OnChangeType, OnTouchedType } from 'ng-zorro-antd/core/types';\nimport { NzInputGroupWhitSuffixOrPrefixDirective } from 'ng-zorro-antd/input';\n\nimport { NzAutocompleteOptionComponent } from './autocomplete-option.component';\nimport { NzAutocompleteComponent } from './autocomplete.component';\nimport { getNzAutocompleteMissingPanelError } from './error';\n\n@Directive({\n  selector: `input[nzAutocomplete], textarea[nzAutocomplete]`,\n  exportAs: 'nzAutocompleteTrigger',\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => NzAutocompleteTriggerDirective),\n      multi: true\n    }\n  ],\n  host: {\n    autocomplete: 'off',\n    'aria-autocomplete': 'list',\n    '(focusin)': 'handleFocus()',\n    '(blur)': 'handleBlur()',\n    '(input)': 'handleInput($any($event))',\n    '(keydown)': 'handleKeydown($any($event))',\n    '(click)': 'handleClick()'\n  }\n})\nexport class NzAutocompleteTriggerDirective implements AfterViewInit, ControlValueAccessor {\n  private injector = inject(Injector);\n  private ngZone = inject(NgZone);\n  private elementRef = inject(ElementRef<HTMLElement>);\n  private viewContainerRef = inject(ViewContainerRef);\n  private destroyRef = inject(DestroyRef);\n  /** Bind nzAutocomplete component */\n  @Input() nzAutocomplete!: NzAutocompleteComponent;\n\n  onChange: OnChangeType = () => {};\n  onTouched: OnTouchedType = () => {};\n  panelOpen: boolean = false;\n\n  /** Current active option */\n  get activeOption(): NzAutocompleteOptionComponent | null {\n    if (this.nzAutocomplete && this.nzAutocomplete.options.length) {\n      return this.nzAutocomplete.activeItem;\n    } else {\n      return null;\n    }\n  }\n\n  private overlayRef: OverlayRef | null = null;\n  private portal: TemplatePortal<{}> | null = null;\n  private positionStrategy!: FlexibleConnectedPositionStrategy;\n  private previousValue: string | number | null = null;\n  private selectionChangeSubscription!: Subscription;\n  private optionsChangeSubscription!: Subscription;\n  private overlayOutsideClickSubscription!: Subscription;\n  private document = inject(DOCUMENT);\n  private nzInputGroupWhitSuffixOrPrefixDirective = inject(NzInputGroupWhitSuffixOrPrefixDirective, { optional: true });\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      this.destroyPanel();\n    });\n  }\n\n  ngAfterViewInit(): void {\n    if (this.nzAutocomplete) {\n      this.nzAutocomplete.animationStateChange.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(event => {\n        if (this.overlayRef) {\n          this.overlayRef.dispose();\n          this.overlayRef = null;\n          event.animationComplete();\n        }\n      });\n    }\n  }\n\n  writeValue(value: NzSafeAny): void {\n    this.ngZone.runOutsideAngular(() => {\n      Promise.resolve(null).then(() => this.setTriggerValue(value));\n    });\n  }\n\n  registerOnChange(fn: (value: {}) => {}): void {\n    this.onChange = fn;\n  }\n\n  registerOnTouched(fn: () => {}): void {\n    this.onTouched = fn;\n  }\n\n  setDisabledState(isDisabled: boolean): void {\n    const element: HTMLInputElement = this.elementRef.nativeElement;\n    element.disabled = isDisabled;\n    this.closePanel();\n  }\n\n  openPanel(): void {\n    this.previousValue = this.elementRef.nativeElement.value;\n    this.attachOverlay();\n    this.updateStatus();\n  }\n\n  closePanel(): void {\n    if (this.panelOpen) {\n      this.nzAutocomplete.isOpen = this.panelOpen = false;\n\n      if (this.overlayRef && this.overlayRef.hasAttached()) {\n        this.overlayRef.detach();\n        this.selectionChangeSubscription.unsubscribe();\n        this.overlayOutsideClickSubscription.unsubscribe();\n        this.optionsChangeSubscription.unsubscribe();\n        this.portal = null;\n      }\n    }\n  }\n\n  handleKeydown(event: KeyboardEvent): void {\n    const keyCode = event.keyCode;\n    const isArrowKey = keyCode === UP_ARROW || keyCode === DOWN_ARROW;\n\n    if (keyCode === ESCAPE) {\n      event.preventDefault();\n    }\n\n    if (this.panelOpen && (keyCode === ESCAPE || keyCode === TAB)) {\n      // Reset value when tab / ESC close\n      if (this.activeOption && this.activeOption.getLabel() !== this.previousValue) {\n        this.setTriggerValue(this.previousValue);\n      }\n      this.closePanel();\n    } else if (this.panelOpen && keyCode === ENTER) {\n      if (this.nzAutocomplete.showPanel) {\n        event.preventDefault();\n        if (this.activeOption) {\n          this.activeOption.selectViaInteraction();\n        } else {\n          this.closePanel();\n        }\n      }\n    } else if (this.panelOpen && isArrowKey && this.nzAutocomplete.showPanel) {\n      event.stopPropagation();\n      event.preventDefault();\n      if (keyCode === UP_ARROW) {\n        this.nzAutocomplete.setPreviousItemActive();\n      } else {\n        this.nzAutocomplete.setNextItemActive();\n      }\n      if (this.activeOption) {\n        this.activeOption.scrollIntoViewIfNeeded();\n      }\n      this.doBackfill();\n    }\n  }\n\n  handleInput(event: KeyboardEvent): void {\n    const target = event.target as HTMLInputElement;\n    const document = this.document as Document;\n    let value: number | string | null = target.value;\n\n    if (target.type === 'number') {\n      value = value === '' ? null : parseFloat(value);\n    }\n    if (this.previousValue !== value) {\n      this.previousValue = value;\n      this.onChange(value);\n\n      if (this.canOpen() && document.activeElement === event.target) {\n        this.openPanel();\n      }\n    }\n  }\n\n  handleFocus(): void {\n    if (this.canOpen()) {\n      this.openPanel();\n    }\n  }\n\n  handleClick(): void {\n    if (this.canOpen() && !this.panelOpen) {\n      this.openPanel();\n    }\n  }\n\n  handleBlur(): void {\n    this.onTouched();\n  }\n\n  /**\n   * Subscription data source changes event\n   */\n  private subscribeOptionsChange(): Subscription {\n    const optionChanges = this.nzAutocomplete.options.changes.pipe(\n      tap(() => this.positionStrategy.reapplyLastPosition()),\n      delay(0)\n    );\n    return optionChanges.subscribe(() => {\n      this.resetActiveItem();\n      if (this.panelOpen) {\n        this.overlayRef!.updatePosition();\n      }\n    });\n  }\n\n  /**\n   * Subscription option changes event and set the value\n   */\n  private subscribeSelectionChange(): Subscription {\n    return this.nzAutocomplete.selectionChange.subscribe((option: NzAutocompleteOptionComponent) => {\n      this.setValueAndClose(option);\n    });\n  }\n\n  private subscribeOverlayOutsideClick(): Subscription {\n    return this.overlayRef!.outsidePointerEvents()\n      .pipe(filter((e: MouseEvent) => !this.elementRef.nativeElement.contains(e.target)))\n      .subscribe(() => {\n        this.closePanel();\n      });\n  }\n\n  private attachOverlay(): void {\n    if (!this.nzAutocomplete) {\n      throw getNzAutocompleteMissingPanelError();\n    }\n\n    if (!this.portal && this.nzAutocomplete.template) {\n      this.portal = new TemplatePortal(this.nzAutocomplete.template, this.viewContainerRef);\n    }\n\n    if (!this.overlayRef) {\n      this.overlayRef = createOverlayRef(this.injector, {\n        positionStrategy: this.getOverlayPosition(),\n        disposeOnNavigation: true,\n        scrollStrategy: createRepositionScrollStrategy(this.injector),\n        // default host element width\n        width: this.nzAutocomplete.nzWidth || this.getHostWidth()\n      });\n    }\n\n    if (this.overlayRef && !this.overlayRef.hasAttached()) {\n      this.overlayRef.attach(this.portal);\n      this.selectionChangeSubscription = this.subscribeSelectionChange();\n      this.optionsChangeSubscription = this.subscribeOptionsChange();\n      this.overlayOutsideClickSubscription = this.subscribeOverlayOutsideClick();\n      this.overlayRef\n        .detachments()\n        .pipe(takeUntilDestroyed(this.destroyRef))\n        .subscribe(() => {\n          this.closePanel();\n        });\n    }\n    this.nzAutocomplete.isOpen = this.panelOpen = true;\n  }\n\n  private updateStatus(): void {\n    if (this.overlayRef) {\n      this.overlayRef.updateSize({ width: this.nzAutocomplete.nzWidth || this.getHostWidth() });\n    }\n    this.nzAutocomplete.setVisibility();\n    this.resetActiveItem();\n    if (this.activeOption) {\n      this.activeOption.scrollIntoViewIfNeeded();\n    }\n  }\n\n  private destroyPanel(): void {\n    if (this.overlayRef) {\n      this.closePanel();\n    }\n  }\n\n  private getConnectedElement(): ElementRef {\n    return this.nzInputGroupWhitSuffixOrPrefixDirective?.elementRef ?? this.elementRef;\n  }\n\n  private getOverlayPosition(): PositionStrategy {\n    return (this.positionStrategy = createFlexibleConnectedPositionStrategy(this.injector, this.getConnectedElement())\n      .withFlexibleDimensions(false)\n      .withPush(false)\n      .withPositions([\n        new ConnectionPositionPair({ originX: 'start', originY: 'bottom' }, { overlayX: 'start', overlayY: 'top' }),\n        new ConnectionPositionPair({ originX: 'start', originY: 'top' }, { overlayX: 'start', overlayY: 'bottom' })\n      ])\n      .withTransformOriginOn('.ant-select-dropdown'));\n  }\n\n  private getHostWidth(): number {\n    return this.getConnectedElement().nativeElement.getBoundingClientRect().width;\n  }\n\n  private resetActiveItem(): void {\n    const index = this.nzAutocomplete.getOptionIndex(this.previousValue);\n    this.nzAutocomplete.clearSelectedOptions(null, true);\n    if (index !== -1) {\n      this.nzAutocomplete.setActiveItem(index);\n      this.nzAutocomplete.activeItem!.select(false);\n    } else {\n      this.nzAutocomplete.setActiveItem(this.nzAutocomplete.nzDefaultActiveFirstOption ? 0 : -1);\n    }\n  }\n\n  private setValueAndClose(option: NzAutocompleteOptionComponent): void {\n    const value = option.nzValue;\n    this.setTriggerValue(option.getLabel());\n    this.onChange(value);\n    this.elementRef.nativeElement.focus();\n    this.closePanel();\n  }\n\n  private setTriggerValue(value: NzSafeAny): void {\n    const option = this.nzAutocomplete.getOption(value);\n    const displayValue = option ? option.getLabel() : value;\n    this.elementRef.nativeElement.value = displayValue != null ? displayValue : '';\n    if (!this.nzAutocomplete.nzBackfill) {\n      this.previousValue = displayValue;\n    }\n  }\n\n  private doBackfill(): void {\n    if (this.nzAutocomplete.nzBackfill && this.nzAutocomplete.activeItem) {\n      this.setTriggerValue(this.nzAutocomplete.activeItem.getLabel());\n    }\n  }\n\n  private canOpen(): boolean {\n    const element: HTMLInputElement = this.elementRef.nativeElement;\n    return !element.readOnly && !element.disabled;\n  }\n}\n"
  },
  {
    "path": "components/auto-complete/autocomplete.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterContentInit,\n  AfterViewInit,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ContentChildren,\n  DestroyRef,\n  ElementRef,\n  EventEmitter,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  QueryList,\n  SimpleChanges,\n  TemplateRef,\n  ViewChild,\n  ViewChildren,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject,\n  type AnimationCallbackEvent\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Observable, Subscription, defer, merge } from 'rxjs';\nimport { filter, switchMap } from 'rxjs/operators';\n\nimport {\n  NzNoAnimationDirective,\n  isAnimationEnabled,\n  slideAnimationEnter,\n  slideAnimationLeave\n} from 'ng-zorro-antd/core/animation';\nimport { NZ_AFTER_NEXT_RENDER$ } from 'ng-zorro-antd/core/render';\nimport { CompareWith, NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { numberAttributeWithZeroFallback } from 'ng-zorro-antd/core/util';\n\nimport { NzAutocompleteOptionComponent, NzOptionSelectionChange } from './autocomplete-option.component';\n\nexport interface AutocompleteDataSourceItem {\n  value: string;\n  label: string;\n}\n\nexport type AutocompleteDataSource = Array<AutocompleteDataSourceItem | string | number>;\n\nfunction normalizeDataSource(value: AutocompleteDataSource): AutocompleteDataSourceItem[] {\n  return value?.map(item => {\n    if (typeof item === 'number' || typeof item === 'string') {\n      return {\n        label: item.toString(),\n        value: item.toString()\n      };\n    }\n    return item;\n  });\n}\n\n@Component({\n  selector: 'nz-autocomplete',\n  exportAs: 'nzAutocomplete',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  imports: [NgTemplateOutlet, NzAutocompleteOptionComponent, NzNoAnimationDirective],\n  template: `\n    <ng-template>\n      <div\n        #panel\n        class=\"ant-select-dropdown ant-select-dropdown-placement-bottomLeft\"\n        [class.ant-select-dropdown-hidden]=\"!showPanel\"\n        [class.ant-select-dropdown-rtl]=\"dir === 'rtl'\"\n        [class]=\"nzOverlayClassName\"\n        [style]=\"nzOverlayStyle\"\n        [nzNoAnimation]=\"!animationEnabled()\"\n        [animate.enter]=\"autoCompleteAnimationEnter()\"\n        [animate.leave]=\"autoCompleteAnimationLeave()\"\n        (animate.leave)=\"onAnimationEvent($event)\"\n      >\n        <div class=\"ant-select-dropdown-content-wrapper\">\n          <div class=\"ant-select-dropdown-content\">\n            <ng-template *ngTemplateOutlet=\"nzDataSource ? optionsTemplate : contentTemplate\" />\n          </div>\n        </div>\n      </div>\n      <ng-template #contentTemplate>\n        <ng-content />\n      </ng-template>\n      <ng-template #optionsTemplate>\n        @for (option of normalizedDataSource; track option.value) {\n          <nz-auto-option [nzValue]=\"option.value\" [nzLabel]=\"option.label\">\n            {{ option.label }}\n          </nz-auto-option>\n        }\n      </ng-template>\n    </ng-template>\n  `\n})\nexport class NzAutocompleteComponent implements AfterContentInit, AfterViewInit, OnInit, OnChanges {\n  private changeDetectorRef = inject(ChangeDetectorRef);\n  private directionality = inject(Directionality);\n  private destroyRef = inject(DestroyRef);\n\n  @Input({ transform: numberAttributeWithZeroFallback }) nzWidth?: number;\n  @Input() nzOverlayClassName = '';\n  @Input() nzOverlayStyle: Record<string, string> = {};\n  @Input({ transform: booleanAttribute }) nzDefaultActiveFirstOption = true;\n  @Input({ transform: booleanAttribute }) nzBackfill = false;\n  @Input() compareWith: CompareWith = (o1, o2) => o1 === o2;\n  @Input() nzDataSource?: AutocompleteDataSource;\n  @Output()\n  readonly selectionChange: EventEmitter<NzAutocompleteOptionComponent> =\n    new EventEmitter<NzAutocompleteOptionComponent>();\n\n  showPanel: boolean = true;\n  isOpen: boolean = false;\n  activeItem: NzAutocompleteOptionComponent | null = null;\n  dir: Direction = 'ltr';\n  normalizedDataSource: AutocompleteDataSourceItem[] = [];\n  animationStateChange = new EventEmitter<AnimationCallbackEvent>();\n\n  /**\n   * Options accessor, its source may be content or dataSource\n   */\n  get options(): QueryList<NzAutocompleteOptionComponent> {\n    // first dataSource\n    if (this.nzDataSource) {\n      return this.fromDataSourceOptions;\n    } else {\n      return this.fromContentOptions;\n    }\n  }\n\n  /** Provided by content */\n  @ContentChildren(NzAutocompleteOptionComponent, { descendants: true })\n  fromContentOptions!: QueryList<NzAutocompleteOptionComponent>;\n  /** Provided by dataSource */\n  @ViewChildren(NzAutocompleteOptionComponent) fromDataSourceOptions!: QueryList<NzAutocompleteOptionComponent>;\n\n  /** cdk-overlay */\n  @ViewChild(TemplateRef, { static: false }) template?: TemplateRef<{}>;\n  @ViewChild('panel', { static: false }) panel?: ElementRef;\n  @ViewChild('content', { static: false }) content?: ElementRef;\n\n  private activeItemIndex: number = -1;\n  private selectionChangeSubscription: Subscription | null = Subscription.EMPTY;\n  private optionMouseEnterSubscription: Subscription | null = Subscription.EMPTY;\n  private dataSourceChangeSubscription: Subscription | null = Subscription.EMPTY;\n\n  /** Options changes listener */\n  private readonly optionSelectionChanges: Observable<NzOptionSelectionChange> = defer(() => {\n    if (this.options) {\n      return merge<NzOptionSelectionChange[]>(...this.options.map(option => option.selectionChange));\n    }\n\n    return this.afterNextRender$.pipe(switchMap(() => this.optionSelectionChanges));\n  });\n\n  private readonly optionMouseEnter: Observable<NzAutocompleteOptionComponent> = defer(() => {\n    if (this.options) {\n      return merge<NzAutocompleteOptionComponent[]>(...this.options.map(option => option.mouseEntered));\n    }\n\n    return this.afterNextRender$.pipe(switchMap(() => this.optionMouseEnter));\n  });\n\n  private afterNextRender$ = inject(NZ_AFTER_NEXT_RENDER$);\n\n  protected readonly autoCompleteAnimationEnter = slideAnimationEnter();\n  protected readonly autoCompleteAnimationLeave = slideAnimationLeave();\n  protected readonly animationEnabled = isAnimationEnabled(() => !this.noAnimation?.nzNoAnimation());\n\n  noAnimation = inject(NzNoAnimationDirective, { host: true, optional: true });\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      this.dataSourceChangeSubscription!.unsubscribe();\n      this.selectionChangeSubscription!.unsubscribe();\n      this.optionMouseEnterSubscription!.unsubscribe();\n      // Caretaker note: we have to set these subscriptions to `null` since these will be closed subscriptions, but they\n      // still keep references to destinations (which are `SafeSubscriber`s). Destinations keep referencing `next` functions,\n      // which we pass, for instance, to `this.optionSelectionChanges.subscribe(...)`.\n      this.dataSourceChangeSubscription = this.selectionChangeSubscription = this.optionMouseEnterSubscription = null;\n    });\n  }\n\n  ngOnInit(): void {\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((direction: Direction) => {\n      this.dir = direction;\n      this.changeDetectorRef.detectChanges();\n    });\n\n    this.dir = this.directionality.value;\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzDataSource } = changes;\n    if (nzDataSource) {\n      this.normalizedDataSource = normalizeDataSource(nzDataSource.currentValue);\n    }\n  }\n\n  onAnimationEvent(event: AnimationCallbackEvent): void {\n    const element = event.target as HTMLElement;\n    // If animations are disabled, complete immediately\n    if (!this.animationEnabled()) {\n      this.animationStateChange.emit(event);\n      event.animationComplete();\n      return;\n    }\n    const onAnimationEnd = (): void => {\n      element.removeEventListener('animationend', onAnimationEnd);\n      this.animationStateChange.emit(event);\n      event.animationComplete();\n    };\n    element.addEventListener('animationend', onAnimationEnd);\n  }\n\n  ngAfterContentInit(): void {\n    if (!this.nzDataSource) {\n      this.optionsInit();\n    }\n  }\n\n  ngAfterViewInit(): void {\n    if (this.nzDataSource) {\n      this.optionsInit();\n    }\n  }\n\n  setVisibility(): void {\n    this.showPanel = !!this.options.length;\n    this.changeDetectorRef.markForCheck();\n  }\n\n  setActiveItem(index: number): void {\n    const activeItem = this.options.get(index);\n    if (activeItem && !activeItem.active) {\n      this.activeItem = activeItem;\n      this.activeItemIndex = index;\n      this.clearSelectedOptions(this.activeItem);\n      this.activeItem.setActiveStyles();\n    } else {\n      this.activeItem = null;\n      this.activeItemIndex = -1;\n      this.clearSelectedOptions();\n    }\n    this.changeDetectorRef.markForCheck();\n  }\n\n  setNextItemActive(): void {\n    const nextIndex = this.activeItemIndex + 1 <= this.options.length - 1 ? this.activeItemIndex + 1 : 0;\n    this.setActiveItem(nextIndex);\n  }\n\n  setPreviousItemActive(): void {\n    const previousIndex = this.activeItemIndex - 1 < 0 ? this.options.length - 1 : this.activeItemIndex - 1;\n    this.setActiveItem(previousIndex);\n  }\n\n  getOptionIndex(value: NzSafeAny): number {\n    return this.options.reduce(\n      (result: number, current: NzAutocompleteOptionComponent, index: number) =>\n        result === -1 ? (this.compareWith(value, current.nzValue) ? index : -1) : result,\n      -1\n    )!;\n  }\n\n  getOption(value: NzSafeAny): NzAutocompleteOptionComponent | null {\n    return this.options.find(item => this.compareWith(value, item.nzValue)) || null;\n  }\n\n  private optionsInit(): void {\n    this.setVisibility();\n    this.subscribeOptionChanges();\n    const changes = this.nzDataSource ? this.fromDataSourceOptions.changes : this.fromContentOptions.changes;\n    // async\n    this.dataSourceChangeSubscription = changes.subscribe(e => {\n      if (!e.dirty && this.isOpen) {\n        setTimeout(() => this.setVisibility());\n      }\n      this.subscribeOptionChanges();\n    });\n  }\n\n  /**\n   * Clear the status of options\n   */\n  clearSelectedOptions(skip?: NzAutocompleteOptionComponent | null, deselect: boolean = false): void {\n    this.options.forEach(option => {\n      if (option !== skip) {\n        if (deselect) {\n          option.deselect();\n        }\n        option.setInactiveStyles();\n      }\n    });\n  }\n\n  private subscribeOptionChanges(): void {\n    this.selectionChangeSubscription!.unsubscribe();\n    this.selectionChangeSubscription = this.optionSelectionChanges\n      .pipe(filter((event: NzOptionSelectionChange) => event.isUserInput))\n      .subscribe((event: NzOptionSelectionChange) => {\n        event.source.select();\n        event.source.setActiveStyles();\n        this.activeItem = event.source;\n        this.activeItemIndex = this.getOptionIndex(this.activeItem.nzValue);\n        this.clearSelectedOptions(event.source, true);\n        this.selectionChange.emit(event.source);\n      });\n\n    this.optionMouseEnterSubscription!.unsubscribe();\n    this.optionMouseEnterSubscription = this.optionMouseEnter.subscribe((event: NzAutocompleteOptionComponent) => {\n      event.setActiveStyles();\n      this.activeItem = event;\n      this.activeItemIndex = this.getOptionIndex(this.activeItem.nzValue);\n      this.clearSelectedOptions(event);\n    });\n  }\n}\n"
  },
  {
    "path": "components/auto-complete/autocomplete.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzAutocompleteOptgroupComponent } from './autocomplete-optgroup.component';\nimport { NzAutocompleteOptionComponent } from './autocomplete-option.component';\nimport { NzAutocompleteTriggerDirective } from './autocomplete-trigger.directive';\nimport { NzAutocompleteComponent } from './autocomplete.component';\n\n@NgModule({\n  exports: [\n    NzAutocompleteComponent,\n    NzAutocompleteOptionComponent,\n    NzAutocompleteTriggerDirective,\n    NzAutocompleteOptgroupComponent\n  ],\n  imports: [\n    NzAutocompleteComponent,\n    NzAutocompleteOptionComponent,\n    NzAutocompleteTriggerDirective,\n    NzAutocompleteOptgroupComponent\n  ]\n})\nexport class NzAutocompleteModule {}\n"
  },
  {
    "path": "components/auto-complete/autocomplete.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { DOWN_ARROW, ENTER, ESCAPE, TAB, UP_ARROW } from '@angular/cdk/keycodes';\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport { ScrollDispatcher } from '@angular/cdk/scrolling';\nimport {\n  ApplicationRef,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ElementRef,\n  NgZone,\n  OnInit,\n  provideZoneChangeDetection,\n  QueryList,\n  SimpleChanges,\n  ViewChild,\n  ViewChildren\n} from '@angular/core';\nimport { ComponentFixture, discardPeriodicTasks, fakeAsync, flush, inject, TestBed, tick } from '@angular/core/testing';\nimport { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\nimport { Subject } from 'rxjs';\n\nimport {\n  createKeyboardEvent,\n  dispatchFakeEvent,\n  dispatchKeyboardEvent,\n  MockNgZone,\n  provideMockDirectionality,\n  typeInElement\n} from 'ng-zorro-antd/core/testing';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\nimport { getNzAutocompleteMissingPanelError } from './error';\nimport {\n  NzAutocompleteComponent,\n  NzAutocompleteModule,\n  NzAutocompleteOptionComponent,\n  NzAutocompleteTriggerDirective,\n  NzOptionSelectionChange\n} from './index';\n\ndescribe('auto-complete', () => {\n  let overlayContainer: OverlayContainer;\n  let overlayContainerElement: HTMLElement;\n  const scrolledSubject = new Subject();\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [\n        // todo: use zoneless\n        provideZoneChangeDetection(),\n        provideNoopAnimations(),\n        provideMockDirectionality(),\n        { provide: ScrollDispatcher, useFactory: () => ({ scrolled: () => scrolledSubject }) },\n        {\n          provide: NgZone,\n          useFactory: () => new MockNgZone()\n        }\n      ]\n    });\n  });\n\n  beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n    overlayContainer = oc;\n    overlayContainerElement = oc.getContainerElement();\n  }));\n\n  afterEach(inject([OverlayContainer], (currentOverlayContainer: OverlayContainer) => {\n    currentOverlayContainer.ngOnDestroy();\n    overlayContainer.ngOnDestroy();\n  }));\n\n  describe('toggling', () => {\n    let fixture: ComponentFixture<NzTestSimpleAutocompleteComponent>;\n    let input: HTMLInputElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestSimpleAutocompleteComponent);\n      fixture.detectChanges();\n      input = fixture.debugElement.query(By.css('input')).nativeElement;\n    });\n\n    it('should open the panel when the input is focused', () => {\n      expect(fixture.componentInstance.trigger.panelOpen).toBe(false);\n\n      dispatchFakeEvent(input, 'focusin');\n      fixture.detectChanges();\n\n      expect(fixture.componentInstance.trigger.panelOpen).toBe(true);\n      expect(overlayContainerElement.textContent).toContain('Burns Bay Road');\n    });\n\n    it('should open the panel when type', () => {\n      expect(fixture.componentInstance.trigger.panelOpen).toBe(false);\n      typeInElement('value', input);\n      fixture.detectChanges();\n      expect(fixture.componentInstance.trigger.panelOpen).toBe(true);\n    });\n\n    it('should not open the panel on focus if the input is readonly', fakeAsync(() => {\n      const trigger = fixture.componentInstance.trigger;\n      input.readOnly = true;\n      fixture.detectChanges();\n\n      expect(trigger.panelOpen).toBe(false);\n      dispatchFakeEvent(input, 'focusin');\n      flush();\n\n      fixture.detectChanges();\n      expect(trigger.panelOpen).toBe(false);\n    }));\n\n    it('should not open the panel on focus if the input is disabled', fakeAsync(() => {\n      const trigger = fixture.componentInstance.trigger;\n      input.disabled = true;\n      fixture.detectChanges();\n\n      dispatchFakeEvent(input, 'focusin');\n      flush();\n      fixture.detectChanges();\n\n      expect(trigger.panelOpen).toBe(false);\n    }));\n\n    it('should open the panel programmatically', () => {\n      expect(fixture.componentInstance.trigger.panelOpen).toBe(false);\n\n      fixture.componentInstance.trigger.openPanel();\n      fixture.detectChanges();\n\n      expect(fixture.componentInstance.trigger.panelOpen).toBe(true);\n      expect(overlayContainerElement.textContent).toContain('Burns Bay Road');\n    });\n\n    it('should close the panel programmatically', fakeAsync(() => {\n      fixture.componentInstance.trigger.openPanel();\n      fixture.detectChanges();\n\n      fixture.componentInstance.trigger.closePanel();\n      fixture.detectChanges();\n\n      tick(500);\n      expect(fixture.componentInstance.trigger.panelOpen).toBe(false);\n      // With native animations, the overlay is detached immediately when NoopAnimations is used\n      // The important check is that the panel state is closed, not the DOM cleanup timing\n    }));\n\n    it('should close the panel when the user clicks away', fakeAsync(() => {\n      dispatchFakeEvent(input, 'focusin');\n      fixture.detectChanges();\n      flush();\n\n      expect(fixture.componentInstance.trigger.panelOpen).toBe(true);\n\n      dispatchFakeEvent(document.body, 'click');\n\n      expect(fixture.componentInstance.trigger.panelOpen).toBe(false);\n    }));\n\n    it('should not close the panel when the user clicks this input', fakeAsync(() => {\n      dispatchFakeEvent(input, 'focusin');\n      fixture.detectChanges();\n      flush();\n\n      expect(fixture.componentInstance.trigger.panelOpen).toBe(true);\n\n      dispatchFakeEvent(input, 'click');\n\n      expect(fixture.componentInstance.trigger.panelOpen).toBe(true);\n    }));\n\n    it('should not throw when attempting to close the panel of a destroyed autocomplete', () => {\n      const trigger = fixture.componentInstance.trigger;\n\n      trigger.openPanel();\n      fixture.detectChanges();\n      // @ts-ignore\n      trigger.destroyPanel();\n\n      expect(() => trigger.closePanel()).not.toThrow();\n    });\n\n    it('should close the panel when the user taps away on a touch device', fakeAsync(() => {\n      dispatchFakeEvent(input, 'focus');\n      fixture.detectChanges();\n      flush();\n      dispatchFakeEvent(document, 'touchend');\n\n      expect(fixture.componentInstance.trigger.panelOpen).toBe(false);\n    }));\n\n    it('should close the panel when an option is clicked', fakeAsync(() => {\n      dispatchFakeEvent(input, 'focusin');\n      fixture.detectChanges();\n      flush();\n\n      const option = overlayContainerElement.querySelector('nz-auto-option') as HTMLElement;\n      option.click();\n      fixture.detectChanges();\n\n      tick(500);\n      expect(fixture.componentInstance.trigger.panelOpen).toBe(false);\n    }));\n\n    it('should open the panel when the input that has already been focused is clicked', fakeAsync(() => {\n      dispatchFakeEvent(input, 'focusin');\n      fixture.detectChanges();\n      flush();\n\n      const option = overlayContainerElement.querySelector('nz-auto-option') as HTMLElement;\n      option.click();\n      fixture.detectChanges();\n\n      tick(500);\n      expect(fixture.componentInstance.trigger.panelOpen).toBe(false);\n\n      dispatchFakeEvent(input, 'click');\n      fixture.detectChanges();\n      expect(fixture.componentInstance.trigger.panelOpen).toBe(true);\n    }));\n\n    it('should close the panel when an option is tap', fakeAsync(() => {\n      dispatchFakeEvent(input, 'focusin');\n      fixture.detectChanges();\n      flush();\n\n      const option = overlayContainerElement.querySelector('nz-auto-option') as HTMLElement;\n      dispatchFakeEvent(option, 'touchend');\n      dispatchFakeEvent(option, 'click');\n      fixture.detectChanges();\n\n      tick(500);\n      expect(fixture.componentInstance.trigger.panelOpen).toBe(false);\n    }));\n\n    it('should hide the panel when the options list is empty', fakeAsync(() => {\n      dispatchFakeEvent(input, 'focusin');\n      fixture.detectChanges();\n      tick(150);\n      const panel = overlayContainerElement.querySelector('.ant-select-dropdown') as HTMLElement;\n\n      typeInElement('B', input);\n      fixture.detectChanges();\n      tick(150);\n      fixture.detectChanges();\n\n      expect(panel.classList).not.toContain('ant-select-dropdown-hidden');\n\n      typeInElement('x', input);\n      fixture.detectChanges();\n      tick(150);\n      fixture.detectChanges();\n\n      expect(panel.classList).toContain('ant-select-dropdown-hidden');\n    }));\n\n    it('should not run change detection on `mouseenter` and `mousedown` events for `nz-auto-option`', fakeAsync(() => {\n      dispatchFakeEvent(input, 'focusin');\n      fixture.detectChanges();\n      flush();\n\n      const appRef = TestBed.inject(ApplicationRef);\n      spyOn(appRef, 'tick');\n\n      const option = overlayContainerElement.querySelector('nz-auto-option') as HTMLElement;\n      const event = new MouseEvent('mousedown');\n      spyOn(event, 'preventDefault');\n\n      option.dispatchEvent(event);\n      option.dispatchEvent(new MouseEvent('mouseenter'));\n\n      expect(event.preventDefault).toHaveBeenCalled();\n      expect(appRef.tick).not.toHaveBeenCalled();\n    }));\n  });\n\n  describe('property', () => {\n    let fixture: ComponentFixture<NzTestAutocompletePropertyComponent>;\n    let input: HTMLInputElement;\n    let DOWN_ARROW_EVENT: KeyboardEvent;\n    let ENTER_EVENT: KeyboardEvent;\n    let TAB_EVENT: KeyboardEvent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestAutocompletePropertyComponent);\n      fixture.detectChanges();\n      input = fixture.debugElement.query(By.css('input')).nativeElement;\n      DOWN_ARROW_EVENT = createKeyboardEvent('keydown', DOWN_ARROW);\n      ENTER_EVENT = createKeyboardEvent('keydown', ENTER);\n      TAB_EVENT = createKeyboardEvent('keydown', TAB);\n    });\n\n    it('should have correct width when setting', () => {\n      fixture.componentInstance.width = 500;\n      fixture.detectChanges();\n\n      fixture.componentInstance.trigger.openPanel();\n      fixture.detectChanges();\n\n      const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement;\n\n      expect(Math.ceil(parseFloat(overlayPane.style.width as string))).toBe(500);\n    });\n\n    it('should back fill display value when DOWN key is pressed', fakeAsync(() => {\n      const componentInstance = fixture.componentInstance;\n      componentInstance.trigger.openPanel();\n      fixture.detectChanges();\n      flush();\n      tick(100);\n\n      expect(componentInstance.trigger.panelOpen).toBe(true);\n      flush();\n      fixture.detectChanges();\n\n      componentInstance.trigger.handleKeydown(DOWN_ARROW_EVENT);\n      fixture.detectChanges();\n\n      expect(input.value).toBe('Burns Bay Road');\n    }));\n\n    it('should reset the backfilled value display when pressing tabbing', fakeAsync(() => {\n      const componentInstance = fixture.componentInstance;\n      componentInstance.trigger.openPanel();\n      fixture.detectChanges();\n      flush();\n\n      expect(componentInstance.trigger.panelOpen).toBe(true);\n\n      componentInstance.trigger.handleKeydown(DOWN_ARROW_EVENT);\n      fixture.detectChanges();\n\n      expect(input.value).toBe(componentInstance.options[0]);\n\n      componentInstance.trigger.handleKeydown(TAB_EVENT);\n      fixture.detectChanges();\n      flush();\n\n      expect(input.value).toBe('');\n\n      componentInstance.trigger.openPanel();\n      fixture.detectChanges();\n      flush();\n\n      componentInstance.trigger.handleKeydown(DOWN_ARROW_EVENT);\n      componentInstance.trigger.handleKeydown(DOWN_ARROW_EVENT);\n      componentInstance.trigger.handleKeydown(ENTER_EVENT);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n\n      expect(input.value).toBe(componentInstance.options[1]);\n\n      componentInstance.trigger.openPanel();\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n\n      componentInstance.trigger.handleKeydown(DOWN_ARROW_EVENT);\n      fixture.detectChanges();\n      expect(input.value).toBe(componentInstance.options[2]);\n      componentInstance.trigger.handleKeydown(TAB_EVENT);\n      fixture.detectChanges();\n      expect(input.value).toBe(componentInstance.options[1]);\n    }));\n\n    it('should overlayClassName & overlayStyle work', () => {\n      fixture.componentInstance.overlayClassName = 'testClass';\n      fixture.componentInstance.overlayStyle = { color: 'rgb(1, 2, 3)' };\n      fixture.detectChanges();\n\n      fixture.componentInstance.trigger.openPanel();\n      fixture.detectChanges();\n\n      const dropdown = overlayContainerElement.querySelector('.ant-select-dropdown') as HTMLElement;\n      expect(dropdown.classList.contains(`testClass`)).toBe(true);\n      expect(dropdown.style.color).toBe(`rgb(1, 2, 3)`);\n    });\n  });\n\n  describe('value', () => {\n    let fixture: ComponentFixture<NzTestSimpleAutocompleteComponent>;\n    let input: HTMLInputElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestSimpleAutocompleteComponent);\n      fixture.detectChanges();\n      input = fixture.debugElement.query(By.css('input')).nativeElement;\n    });\n\n    it('should update input value when option is selected with option value', fakeAsync(() => {\n      fixture.componentInstance.trigger.openPanel();\n      fixture.detectChanges();\n      flush();\n\n      fixture.detectChanges();\n      const options = overlayContainerElement.querySelectorAll('nz-auto-option') as NodeListOf<HTMLElement>;\n      options[1].click();\n      flush();\n      fixture.detectChanges();\n\n      expect(fixture.componentInstance.inputControl.value).toEqual('Downing Street');\n    }));\n\n    it('should update number-input value when option is selected with option value', fakeAsync(() => {\n      input.type = 'number';\n      fixture.componentInstance.options = [100, 200, 300];\n      fixture.componentInstance.filteredOptions = [100, 200, 300];\n      fixture.detectChanges();\n      fixture.componentInstance.trigger.openPanel();\n      fixture.detectChanges();\n      flush();\n\n      const options = overlayContainerElement.querySelectorAll('nz-auto-option') as NodeListOf<HTMLElement>;\n      options[1].click();\n      fixture.detectChanges();\n      flush();\n\n      expect(input.value).toBe('200');\n    }));\n\n    it('should handle autocomplete being attached to number inputs', fakeAsync(() => {\n      input.type = 'number';\n      fixture.detectChanges();\n\n      typeInElement('200', input);\n      fixture.detectChanges();\n      flush();\n\n      expect(fixture.componentInstance.inputControl.value).toBe(200);\n\n      typeInElement('', input);\n      fixture.detectChanges();\n      flush();\n\n      expect(fixture.componentInstance.inputControl.value).toBe(null);\n      discardPeriodicTasks();\n    }));\n\n    it('should mark the autocomplete control as touched on blur', fakeAsync(() => {\n      fixture.componentInstance.trigger.openPanel();\n      fixture.detectChanges();\n\n      expect(fixture.componentInstance.inputControl.touched).toBe(false);\n      dispatchFakeEvent(input, 'blur');\n      fixture.detectChanges();\n      flush();\n      expect(fixture.componentInstance.inputControl.touched).toBe(true);\n    }));\n\n    it('should be able to re-type the same value when it is reset while open', fakeAsync(() => {\n      fixture.componentInstance.trigger.openPanel();\n      fixture.detectChanges();\n\n      typeInElement('Burns', input);\n      fixture.detectChanges();\n\n      expect(fixture.componentInstance.inputControl.value).toBe('Burns');\n\n      fixture.componentInstance.inputControl.setValue('');\n      tick();\n      fixture.detectChanges();\n      expect(input.value).toBe('');\n\n      typeInElement('Burns', input);\n      tick();\n      fixture.detectChanges();\n\n      expect(fixture.componentInstance.inputControl.value).toBe('Burns');\n    }));\n  });\n\n  describe('object option', () => {\n    let fixture: ComponentFixture<NzTestAutocompleteWithObjectOptionComponent>;\n    let componentInstance: NzTestAutocompleteWithObjectOptionComponent;\n    let input: HTMLInputElement;\n\n    beforeEach(fakeAsync(() => {\n      fixture = TestBed.createComponent(NzTestAutocompleteWithObjectOptionComponent);\n      componentInstance = fixture.componentInstance;\n      flush();\n      fixture.detectChanges();\n      input = fixture.debugElement.query(By.css('input')).nativeElement;\n    }));\n\n    it('should select init option', fakeAsync(() => {\n      componentInstance.trigger.openPanel();\n      const options = componentInstance.trigger.nzAutocomplete.options.toArray();\n      expect(options[0].selected).toBe(true);\n      expect(input.value).toBe('Lucy');\n      expect(componentInstance.formControl.value).toEqual({ label: 'Lucy', value: 'lucy' });\n    }));\n\n    it('should set object option', fakeAsync(() => {\n      componentInstance.formControl.setValue({ label: 'Jack', value: 'jack' });\n      flush();\n      fixture.detectChanges();\n      componentInstance.trigger.openPanel();\n      const options = componentInstance.trigger.nzAutocomplete.options.toArray();\n      expect(options[0].selected).toBe(false);\n      expect(options[1].selected).toBe(true);\n      expect(input.value).toBe('Jack');\n      expect(componentInstance.formControl.value).toEqual({ label: 'Jack', value: 'jack' });\n    }));\n\n    it('should be typing other string', fakeAsync(() => {\n      typeInElement('string', input);\n      fixture.detectChanges();\n      expect(componentInstance.formControl.value).toBe('string');\n    }));\n  });\n\n  describe('form', () => {\n    let fixture: ComponentFixture<NzTestAutocompleteWithFormComponent>;\n    let input: HTMLInputElement;\n\n    beforeEach(fakeAsync(() => {\n      fixture = TestBed.createComponent(NzTestAutocompleteWithFormComponent);\n      fixture.detectChanges();\n      input = fixture.debugElement.query(By.css('input')).nativeElement;\n    }));\n\n    it('should set the value with form', fakeAsync(() => {\n      const componentInstance = fixture.componentInstance;\n      flush();\n      fixture.detectChanges();\n      expect(componentInstance.formControl.value).toContain('Burns');\n      expect(input.value).toContain('Burns');\n    }));\n\n    it('should set disabled work', () => {\n      const componentInstance = fixture.componentInstance;\n      fixture.detectChanges();\n\n      expect(input.disabled).toBe(false);\n\n      componentInstance.formControl.disable();\n      fixture.detectChanges();\n\n      expect(input.disabled).toBe(true);\n    });\n\n    it('should close the panel when the input is disabled', () => {\n      const componentInstance = fixture.componentInstance;\n      fixture.detectChanges();\n\n      componentInstance.trigger.openPanel();\n      fixture.detectChanges();\n\n      expect(componentInstance.trigger.panelOpen).toBe(true);\n\n      componentInstance.formControl.disable();\n      fixture.detectChanges();\n\n      expect(input.disabled).toBe(true);\n      expect(componentInstance.trigger.panelOpen).toBe(false);\n    });\n\n    it('should set correct label', fakeAsync(() => {\n      const differentValueWithFormFixture = TestBed.createComponent(NzTestAutocompleteDifferentValueWithFormComponent);\n      differentValueWithFormFixture.detectChanges();\n      flush();\n      differentValueWithFormFixture.detectChanges();\n\n      const differentValueWithFormInput = differentValueWithFormFixture.debugElement.query(\n        By.css('input')\n      ).nativeElement;\n\n      expect(differentValueWithFormInput.value).toBe('Lucy');\n      expect(differentValueWithFormFixture.componentInstance.formControl.value).toBe('lucy');\n    }));\n  });\n\n  describe('option groups', () => {\n    let fixture: ComponentFixture<NzTestAutocompleteGroupComponent>;\n    let input: HTMLInputElement;\n    let DOWN_ARROW_EVENT: KeyboardEvent;\n    let ENTER_EVENT: KeyboardEvent;\n\n    beforeEach(fakeAsync(() => {\n      fixture = TestBed.createComponent(NzTestAutocompleteGroupComponent);\n      fixture.detectChanges();\n\n      input = fixture.debugElement.query(By.css('input')).nativeElement;\n\n      DOWN_ARROW_EVENT = createKeyboardEvent('keydown', DOWN_ARROW);\n      ENTER_EVENT = createKeyboardEvent('keydown', ENTER);\n\n      fixture.componentInstance.trigger.openPanel();\n      fixture.detectChanges();\n      flush();\n    }));\n\n    it('should fill the text field when an option is selected with ENTER', fakeAsync(() => {\n      const componentInstance = fixture.componentInstance;\n\n      expect(componentInstance.trigger.panelOpen).toBe(true);\n\n      [1, 2, 3].forEach(() => {\n        componentInstance.trigger.handleKeydown(DOWN_ARROW_EVENT);\n      });\n      fixture.detectChanges();\n      flush();\n      componentInstance.trigger.handleKeydown(ENTER_EVENT);\n      fixture.detectChanges();\n      flush();\n      expect(componentInstance.inputValue).toContain('AntDesign four');\n\n      expect(input.value).toContain('AntDesign four');\n    }));\n  });\n\n  describe('Option selection', () => {\n    let fixture: ComponentFixture<NzTestSimpleAutocompleteComponent>;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestSimpleAutocompleteComponent);\n      fixture.detectChanges();\n    });\n\n    it('should deselect any other selected option', fakeAsync(() => {\n      fixture.componentInstance.trigger.openPanel();\n      fixture.detectChanges();\n\n      let options = overlayContainerElement.querySelectorAll('nz-auto-option') as NodeListOf<HTMLElement>;\n      options[0].click();\n\n      // `tick()` will handle over after next render hooks.\n      TestBed.inject(ApplicationRef).tick();\n\n      const componentOptions = fixture.componentInstance.optionComponents.toArray();\n      expect(componentOptions[0].selected).toBe(true);\n\n      fixture.componentInstance.trigger.openPanel();\n      fixture.detectChanges();\n\n      options = overlayContainerElement.querySelectorAll('nz-auto-option') as NodeListOf<HTMLElement>;\n      options[1].click();\n      fixture.detectChanges();\n      flush();\n\n      expect(componentOptions[0].selected).toBe(false);\n      expect(componentOptions[1].selected).toBe(true);\n    }));\n\n    it('should not deselect when repeat selected option', fakeAsync(() => {\n      fixture.componentInstance.trigger.openPanel();\n      fixture.detectChanges();\n\n      let options = overlayContainerElement.querySelectorAll('nz-auto-option') as NodeListOf<HTMLElement>;\n      options[0].click();\n\n      // `tick()` will handle over after next render hooks.\n      TestBed.inject(ApplicationRef).tick();\n\n      const componentOptions = fixture.componentInstance.optionComponents.toArray();\n      expect(componentOptions[0].selected).toBe(true);\n\n      fixture.componentInstance.trigger.openPanel();\n      fixture.detectChanges();\n\n      options = overlayContainerElement.querySelectorAll('nz-auto-option') as NodeListOf<HTMLElement>;\n      options[0].click();\n      fixture.detectChanges();\n      flush();\n      expect(componentOptions[0].selected).toBe(true);\n    }));\n  });\n\n  describe('keyboard events', () => {\n    let fixture: ComponentFixture<NzTestSimpleAutocompleteComponent>;\n    let input: HTMLInputElement;\n    let DOWN_ARROW_EVENT: KeyboardEvent;\n    let UP_ARROW_EVENT: KeyboardEvent;\n    let ENTER_EVENT: KeyboardEvent;\n\n    beforeEach(fakeAsync(() => {\n      fixture = TestBed.createComponent(NzTestSimpleAutocompleteComponent);\n      fixture.detectChanges();\n      input = fixture.debugElement.query(By.css('input')).nativeElement;\n\n      DOWN_ARROW_EVENT = createKeyboardEvent('keydown', DOWN_ARROW);\n      UP_ARROW_EVENT = createKeyboardEvent('keydown', UP_ARROW);\n      ENTER_EVENT = createKeyboardEvent('keydown', ENTER);\n\n      fixture.componentInstance.trigger.openPanel();\n      fixture.detectChanges();\n      flush();\n    }));\n\n    it('should set the active item to the second option when DOWN key is pressed', () => {\n      const componentInstance = fixture.componentInstance;\n      const optionEls = overlayContainerElement.querySelectorAll('nz-auto-option') as NodeListOf<HTMLElement>;\n\n      expect(componentInstance.trigger.panelOpen).toBe(true);\n\n      componentInstance.trigger.handleKeydown(DOWN_ARROW_EVENT);\n      fixture.detectChanges();\n\n      expect(optionEls[0].classList).not.toContain('ant-select-item-option-active');\n      expect(optionEls[1].classList).toContain('ant-select-item-option-active');\n    });\n\n    it('should set the active item to the first option when DOWN key is pressed in last item', () => {\n      const componentInstance = fixture.componentInstance;\n      const optionEls = overlayContainerElement.querySelectorAll('nz-auto-option') as NodeListOf<HTMLElement>;\n\n      expect(componentInstance.trigger.panelOpen).toBe(true);\n\n      [1, 2, 3].forEach(() => componentInstance.trigger.handleKeydown(DOWN_ARROW_EVENT));\n      fixture.detectChanges();\n\n      expect(optionEls[1].classList).not.toContain('ant-select-item-option-active');\n      expect(optionEls[0].classList).toContain('ant-select-item-option-active');\n    });\n\n    it('should set the active item when mouse is enter', () => {\n      const componentInstance = fixture.componentInstance;\n      const optionEls = overlayContainerElement.querySelectorAll('nz-auto-option') as NodeListOf<HTMLElement>;\n\n      expect(componentInstance.trigger.panelOpen).toBe(true);\n\n      fixture.detectChanges();\n\n      dispatchFakeEvent(optionEls[1], 'mouseenter');\n\n      fixture.detectChanges();\n\n      expect(optionEls[0].classList).not.toContain('ant-select-item-option-active');\n      expect(optionEls[1].classList).toContain('ant-select-item-option-active');\n      expect(optionEls[2].classList).not.toContain('ant-select-item-option-active');\n\n      dispatchFakeEvent(optionEls[0], 'mouseenter');\n\n      fixture.detectChanges();\n\n      expect(optionEls[0].classList).toContain('ant-select-item-option-active');\n      expect(optionEls[1].classList).not.toContain('ant-select-item-option-active');\n      expect(optionEls[2].classList).not.toContain('ant-select-item-option-active');\n    });\n\n    it('should set the active item to the last option when UP key is pressed', () => {\n      const componentInstance = fixture.componentInstance;\n      const optionEls = overlayContainerElement.querySelectorAll('nz-auto-option') as NodeListOf<HTMLElement>;\n\n      expect(componentInstance.trigger.panelOpen).toBe(true);\n\n      componentInstance.trigger.handleKeydown(UP_ARROW_EVENT);\n      fixture.detectChanges();\n\n      expect(optionEls[0].classList).not.toContain('ant-select-item-option-active');\n      expect(optionEls[1].classList).not.toContain('ant-select-item-option-active');\n      expect(optionEls[2].classList).toContain('ant-select-item-option-active');\n    });\n\n    it('should set the active item to the previous option when UP key is pressed', () => {\n      const componentInstance = fixture.componentInstance;\n      const optionEls = overlayContainerElement.querySelectorAll('nz-auto-option') as NodeListOf<HTMLElement>;\n\n      expect(componentInstance.trigger.panelOpen).toBe(true);\n\n      [1, 2].forEach(() => componentInstance.trigger.handleKeydown(UP_ARROW_EVENT));\n      fixture.detectChanges();\n\n      expect(optionEls[0].classList).not.toContain('ant-select-item-option-active');\n      expect(optionEls[1].classList).toContain('ant-select-item-option-active');\n      expect(optionEls[2].classList).not.toContain('ant-select-item-option-active');\n    });\n\n    it('should set the active item properly after filtering', () => {\n      const componentInstance = fixture.componentInstance;\n\n      typeInElement('Str', input);\n      fixture.detectChanges();\n\n      componentInstance.trigger.handleKeydown(DOWN_ARROW_EVENT);\n      fixture.detectChanges();\n\n      const optionEls = overlayContainerElement.querySelectorAll('nz-auto-option') as NodeListOf<HTMLElement>;\n\n      expect(optionEls[0].classList).not.toContain('ant-select-item-option-active');\n      expect(optionEls[1].classList).toContain('ant-select-item-option-active');\n      expect(optionEls[1].innerText).toEqual('Wall Street');\n    });\n\n    it('should not open the panel if the `input` event was dispatched with changing the value', fakeAsync(() => {\n      const trigger = fixture.componentInstance.trigger;\n\n      dispatchFakeEvent(input, 'focusin');\n      typeInElement('A', input);\n      fixture.detectChanges();\n\n      expect(trigger.panelOpen).toBe(true);\n\n      trigger.closePanel();\n      fixture.detectChanges();\n\n      expect(trigger.panelOpen).toBe(false);\n\n      dispatchFakeEvent(input, 'input');\n      fixture.detectChanges();\n      flush();\n\n      expect(trigger.panelOpen).toBe(false);\n    }));\n\n    it('should fill the text field when an option is selected with ENTER', fakeAsync(() => {\n      const componentInstance = fixture.componentInstance;\n      componentInstance.trigger.handleKeydown(DOWN_ARROW_EVENT);\n      fixture.detectChanges();\n      flush();\n\n      componentInstance.trigger.handleKeydown(ENTER_EVENT);\n      fixture.detectChanges();\n      flush();\n\n      expect(componentInstance.inputControl.value).toContain('Downing Street');\n\n      expect(input.value).toContain('Downing Street');\n    }));\n\n    it('should prevent the default enter key action', fakeAsync(() => {\n      fixture.componentInstance.trigger.handleKeydown(DOWN_ARROW_EVENT);\n      flush();\n\n      fixture.componentInstance.trigger.handleKeydown(ENTER_EVENT);\n      fixture.detectChanges();\n      flush();\n\n      expect(ENTER_EVENT.defaultPrevented).toBe(true);\n    }));\n\n    it('should not prevent the default enter action for a closed panel after a user action', () => {\n      fixture.componentInstance.trigger.handleKeydown(UP_ARROW_EVENT);\n      fixture.detectChanges();\n\n      fixture.componentInstance.trigger.closePanel();\n      fixture.detectChanges();\n      fixture.componentInstance.trigger.handleKeydown(ENTER_EVENT);\n\n      expect(ENTER_EVENT.defaultPrevented).toBe(false);\n    });\n\n    it('should close the panel when tabbing', fakeAsync(() => {\n      fixture.detectChanges();\n      input.focus();\n      flush();\n\n      expect(overlayContainerElement.querySelector('.ant-select-dropdown')).toBeTruthy();\n\n      dispatchKeyboardEvent(input, 'keydown', TAB);\n      fixture.detectChanges();\n\n      tick(500);\n      expect(overlayContainerElement.querySelector('.ant-select-dropdown')).toBeFalsy();\n    }));\n\n    it('should close the panel when pressing escape', fakeAsync(() => {\n      fixture.detectChanges();\n      input.focus();\n      flush();\n\n      expect(overlayContainerElement.querySelector('.ant-select-dropdown')).toBeTruthy();\n\n      dispatchKeyboardEvent(input, 'keydown', ESCAPE);\n      fixture.detectChanges();\n\n      tick(500);\n      expect(overlayContainerElement.querySelector('.ant-select-dropdown')).toBeFalsy();\n    }));\n\n    it('should call closePanel on correct circumstances', () => {\n      const trigger = fixture.componentInstance.trigger;\n\n      trigger.panelOpen = true;\n      trigger.nzAutocomplete.showPanel = true;\n      const event = new KeyboardEvent('keydown', {\n        key: 'Enter',\n        code: 'Enter',\n        which: 13,\n        keyCode: 13\n      });\n      spyOnProperty(trigger, 'activeOption', 'get').and.returnValue(null);\n      spyOn(trigger, 'closePanel');\n\n      trigger.handleKeydown(event);\n\n      expect(trigger.closePanel).toHaveBeenCalled();\n    });\n  });\n\n  // TODO: Implement this test case\n  // describe('Fallback positions', () => {\n  //   let fixture: ComponentFixture<NzTestSimpleAutocompleteComponent>;\n\n  //   beforeEach(() => {\n  //     fixture = TestBed.createComponent(NzTestSimpleAutocompleteComponent);\n  //     fixture.detectChanges();\n  //   });\n  // });\n\n  describe('misc', () => {\n    let fixture: ComponentFixture<NzTestAutocompleteWithoutPanelComponent>;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestAutocompleteWithoutPanelComponent);\n      fixture.detectChanges();\n    });\n\n    it('should throw on with the panel is not defined', fakeAsync(() => {\n      fixture.detectChanges();\n\n      expect(() => {\n        fixture.componentInstance.trigger.openPanel();\n      }).toThrow(getNzAutocompleteMissingPanelError());\n    }));\n\n    it('should show the panel when the options are initialized later within a component with OnPush change detection', fakeAsync(() => {\n      fixture = TestBed.createComponent(NzTestAutocompleteWithOnPushDelayComponent);\n      fixture.detectChanges();\n\n      dispatchFakeEvent(fixture.debugElement.query(By.css('input')).nativeElement, 'focusin');\n      fixture.detectChanges();\n      tick(1000);\n\n      fixture.detectChanges();\n      tick();\n\n      Promise.resolve().then(() => {\n        fixture.detectChanges();\n        flush();\n        fixture.detectChanges();\n        const panel = overlayContainerElement.querySelector('.ant-select-dropdown') as HTMLElement;\n        expect(panel.classList).not.toContain('ant-select-dropdown-hidden');\n      });\n    }));\n  });\n\n  describe('within input-wrapper', () => {\n    let fixture: ComponentFixture<NzTestAutocompleteWithGroupInputComponent>;\n    let input: HTMLInputElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestAutocompleteWithGroupInputComponent);\n      fixture.detectChanges();\n      input = fixture.debugElement.query(By.css('input')).nativeElement;\n    });\n\n    it('should use the input element as the dropdown target', () => {\n      const componentInstance = fixture.componentInstance;\n      fixture.detectChanges();\n      dispatchFakeEvent(input, 'blur');\n      fixture.detectChanges();\n      expect(componentInstance.trigger['getConnectedElement']().nativeElement).toEqual(\n        componentInstance.inputRef.nativeElement\n      );\n    });\n  });\n});\n\n@Component({\n  imports: [ReactiveFormsModule, NzAutocompleteModule, NzInputModule],\n  template: `\n    <div>\n      <input\n        class=\"input\"\n        nz-input\n        [formControl]=\"inputControl\"\n        [nzAutocomplete]=\"auto\"\n        (input)=\"onInput($any($event).target?.value)\"\n      />\n      <nz-autocomplete #auto>\n        @for (option of filteredOptions; track option) {\n          <nz-auto-option [nzValue]=\"option\">{{ option }}</nz-auto-option>\n        }\n      </nz-autocomplete>\n    </div>\n  `\n})\nclass NzTestSimpleAutocompleteComponent {\n  inputValue!: string;\n  filteredOptions: Array<string | number>;\n  inputControl = new FormControl<string | number | null>('');\n  options: Array<string | number> = ['Burns Bay Road', 'Downing Street', 'Wall Street'];\n\n  @ViewChild(NzAutocompleteComponent, { static: false }) panel!: NzAutocompleteComponent;\n  @ViewChild(NzAutocompleteTriggerDirective, { static: false }) trigger!: NzAutocompleteTriggerDirective;\n  @ViewChildren(NzAutocompleteOptionComponent) optionComponents!: QueryList<NzAutocompleteOptionComponent>;\n\n  constructor() {\n    this.filteredOptions = this.options;\n  }\n\n  onInput(value: string): void {\n    this.filteredOptions = this.options.filter(s => new RegExp(value, 'gi').test(`${s}`));\n  }\n}\n\n@Component({\n  imports: [FormsModule, NzAutocompleteModule],\n  template: `\n    <div>\n      <input [(ngModel)]=\"inputValue\" [nzAutocomplete]=\"auto\" />\n      <nz-autocomplete\n        [nzWidth]=\"width\"\n        [nzOverlayClassName]=\"overlayClassName\"\n        [nzOverlayStyle]=\"overlayStyle\"\n        [nzDataSource]=\"options\"\n        [nzDefaultActiveFirstOption]=\"false\"\n        nzBackfill\n        #auto\n      />\n    </div>\n  `\n})\nclass NzTestAutocompletePropertyComponent {\n  inputValue?: string;\n  width?: number;\n  overlayClassName = '';\n  overlayStyle = {};\n  options = ['Burns Bay Road', 'Downing Street', 'Wall Street'];\n  @ViewChild(NzAutocompleteComponent, { static: false }) panel!: NzAutocompleteComponent;\n  @ViewChild(NzAutocompleteTriggerDirective, { static: false }) trigger!: NzAutocompleteTriggerDirective;\n}\n\n@Component({\n  imports: [NzAutocompleteModule],\n  template: `<input [nzAutocomplete]=\"null!\" />`\n})\nclass NzTestAutocompleteWithoutPanelComponent {\n  @ViewChild(NzAutocompleteTriggerDirective, { static: false }) trigger!: NzAutocompleteTriggerDirective;\n}\n\n@Component({\n  imports: [NzAutocompleteModule],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    <div>\n      <input [nzAutocomplete]=\"auto\" />\n      <nz-autocomplete [nzDataSource]=\"options\" #auto />\n    </div>\n  `\n})\nclass NzTestAutocompleteWithOnPushDelayComponent implements OnInit {\n  options: string[] = [];\n  @ViewChild(NzAutocompleteTriggerDirective, { static: false }) trigger!: NzAutocompleteTriggerDirective;\n\n  constructor(private cdr: ChangeDetectorRef) {}\n\n  ngOnInit(): void {\n    setTimeout(() => {\n      this.options = ['One'];\n      this.cdr.markForCheck();\n    }, 1000);\n  }\n}\n\n@Component({\n  imports: [FormsModule, NzAutocompleteModule],\n  template: `\n    <input [nzAutocomplete]=\"auto\" [(ngModel)]=\"inputValue\" />\n    <nz-autocomplete #auto>\n      @for (group of optionGroups; track group.title) {\n        <nz-auto-optgroup [nzLabel]=\"groupTitle\">\n          <ng-template #groupTitle>\n            <span>\n              {{ group.title }}\n              <a class=\"more-link\" href=\"https://www.google.com/search?q=ng+zorro\" target=\"_blank\">更多</a>\n            </span>\n          </ng-template>\n          @for (option of group.children; track option.title) {\n            <nz-auto-option [nzValue]=\"option.title\" [nzDisabled]=\"option.disabled\">\n              {{ option.title }}\n              <span class=\"certain-search-item-count\">{{ option.count }} 人 关注</span>\n            </nz-auto-option>\n          }\n        </nz-auto-optgroup>\n      }\n    </nz-autocomplete>\n  `\n})\nclass NzTestAutocompleteGroupComponent {\n  inputValue!: string;\n  optionGroups: Array<{ title: string; children: Array<{ title: string; count: number; disabled?: boolean }> }> = [\n    {\n      title: '话题',\n      children: [\n        {\n          title: 'AntDesign one',\n          count: 10000\n        },\n        {\n          title: 'AntDesign two',\n          count: 10600\n        }\n      ]\n    },\n    {\n      title: '问题',\n      children: [\n        {\n          title: 'AntDesign three',\n          count: 60100\n        },\n        {\n          title: 'AntDesign four',\n          count: 30010\n        }\n      ]\n    },\n    {\n      title: '文章',\n      children: [\n        {\n          title: 'AntDesign five',\n          disabled: true,\n          count: 100000\n        }\n      ]\n    }\n  ];\n\n  @ViewChild(NzAutocompleteTriggerDirective, { static: false }) trigger!: NzAutocompleteTriggerDirective;\n}\n\n@Component({\n  imports: [ReactiveFormsModule, NzAutocompleteModule],\n  template: `\n    <form>\n      <input [formControl]=\"formControl\" [nzAutocomplete]=\"auto\" />\n      <nz-autocomplete #auto>\n        @for (option of options; track option) {\n          <nz-auto-option [nzValue]=\"option\">{{ option }}</nz-auto-option>\n        }\n      </nz-autocomplete>\n    </form>\n  `\n})\nclass NzTestAutocompleteWithFormComponent {\n  formControl = new FormControl('Burns');\n  options = ['Burns Bay Road', 'Downing Street', 'Wall Street'];\n  @ViewChild(NzAutocompleteTriggerDirective, { static: false }) trigger!: NzAutocompleteTriggerDirective;\n}\n\n@Component({\n  imports: [ReactiveFormsModule, NzAutocompleteModule],\n  template: `\n    <input [formControl]=\"formControl\" [nzAutocomplete]=\"auto\" />\n    <nz-autocomplete #auto>\n      @for (option of options; track option.value) {\n        <nz-auto-option [nzValue]=\"option.value\" [nzLabel]=\"option.label\">\n          {{ option.label }}\n        </nz-auto-option>\n      }\n    </nz-autocomplete>\n  `\n})\nclass NzTestAutocompleteDifferentValueWithFormComponent {\n  formControl = new FormControl('lucy');\n  options = [\n    { label: 'Lucy', value: 'lucy' },\n    { label: 'Jack', value: 'jack' }\n  ];\n  @ViewChild(NzAutocompleteTriggerDirective) trigger!: NzAutocompleteTriggerDirective;\n}\n\n@Component({\n  imports: [ReactiveFormsModule, NzAutocompleteModule],\n  template: `\n    <input [formControl]=\"formControl\" [nzAutocomplete]=\"auto\" />\n    <nz-autocomplete #auto [compareWith]=\"compareFun\">\n      @for (option of options; track option.value) {\n        <nz-auto-option [nzValue]=\"option\" [nzLabel]=\"option.label\">\n          {{ option.label }}\n        </nz-auto-option>\n      }\n    </nz-autocomplete>\n  `\n})\nclass NzTestAutocompleteWithObjectOptionComponent {\n  formControl = new FormControl<string | { label: string; value: string } | null>({ label: 'Lucy', value: 'lucy' });\n  options = [\n    { label: 'Lucy', value: 'lucy' },\n    { label: 'Jack', value: 'jack' }\n  ];\n  @ViewChild(NzAutocompleteTriggerDirective) trigger!: NzAutocompleteTriggerDirective;\n\n  compareFun = (o1: NzSafeAny, o2: NzSafeAny): boolean => {\n    if (o1) {\n      return typeof o1 === 'string' ? o1 === o2.label : o1.value === o2.value;\n    } else {\n      return false;\n    }\n  };\n}\n\n@Component({\n  imports: [NzAutocompleteModule, NzInputModule],\n  template: `\n    <nz-input-wrapper #inputGroupComponent>\n      <input #input placeholder=\"input here\" nz-input nzSize=\"large\" [nzAutocomplete]=\"auto\" />\n      <nz-autocomplete #auto>\n        <nz-auto-option nzValue=\"value\">label</nz-auto-option>\n      </nz-autocomplete>\n    </nz-input-wrapper>\n  `\n})\nclass NzTestAutocompleteWithGroupInputComponent {\n  @ViewChild(NzAutocompleteTriggerDirective, { static: true }) trigger!: NzAutocompleteTriggerDirective;\n  @ViewChild('input', { static: true, read: ElementRef }) inputRef!: ElementRef;\n}\n\ndescribe('auto-complete', () => {\n  let component: NzAutocompleteComponent;\n  let fixture: ComponentFixture<NzAutocompleteComponent>;\n  let mockDirectionality: Directionality;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection(), provideMockDirectionality()]\n    });\n\n    fixture = TestBed.createComponent(NzAutocompleteComponent);\n    component = fixture.componentInstance;\n    mockDirectionality = TestBed.inject(Directionality);\n  });\n\n  it('should change dir', fakeAsync(() => {\n    spyOn(component['changeDetectorRef'], 'detectChanges');\n    component.ngOnInit();\n    expect(component.dir).toEqual('ltr');\n    mockDirectionality.change.next('rtl');\n    tick();\n    expect(component.dir).toEqual('rtl');\n    expect(component['changeDetectorRef'].detectChanges).toHaveBeenCalled();\n  }));\n\n  it('should normalizeDataSource return correct value', () => {\n    let changes: SimpleChanges = {\n      nzDataSource: {\n        currentValue: [1, 2],\n        firstChange: false,\n        previousValue: undefined,\n        isFirstChange: function (): boolean {\n          throw new Error('Function not implemented.');\n        }\n      }\n    };\n    component.ngOnChanges(changes);\n    expect(component.normalizedDataSource).toEqual([\n      {\n        label: '1',\n        value: '1'\n      },\n      {\n        label: '2',\n        value: '2'\n      }\n    ]);\n\n    changes = {\n      nzDataSource: {\n        currentValue: ['1', '2'],\n        firstChange: false,\n        previousValue: undefined,\n        isFirstChange: function (): boolean {\n          throw new Error('Function not implemented.');\n        }\n      }\n    };\n    component.ngOnChanges(changes);\n    expect(component.normalizedDataSource).toEqual([\n      {\n        label: '1',\n        value: '1'\n      },\n      {\n        label: '2',\n        value: '2'\n      }\n    ]);\n\n    changes = {\n      nzDataSource: {\n        currentValue: [\n          {\n            label: '1',\n            value: '1'\n          },\n          {\n            label: '2',\n            value: '2'\n          }\n        ],\n        firstChange: false,\n        previousValue: undefined,\n        isFirstChange: function (): boolean {\n          throw new Error('Function not implemented.');\n        }\n      }\n    };\n    component.ngOnChanges(changes);\n    expect(component.normalizedDataSource).toEqual([\n      {\n        label: '1',\n        value: '1'\n      },\n      {\n        label: '2',\n        value: '2'\n      }\n    ]);\n  });\n\n  it('NzOptionSelectionChange should have correct initial value for isUserInput', () => {\n    const nzOptionSelectionChange = new NzOptionSelectionChange({} as NzSafeAny);\n    expect(nzOptionSelectionChange.isUserInput).toBeFalsy();\n  });\n});\n"
  },
  {
    "path": "components/auto-complete/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本使用\n  en-US: Basic Usage\n---\n\n## zh-CN\n\n基本使用。通过 `nzDataSource` 设置自动完成的数据源\n\n## en-US\n\nBasic Usage, set `nzDataSource` of `nz-autocomplete` with dataSource property.\n"
  },
  {
    "path": "components/auto-complete/demo/basic.ts",
    "content": "import { Component, ViewEncapsulation } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzAutocompleteModule } from 'ng-zorro-antd/auto-complete';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-auto-complete-basic',\n  imports: [FormsModule, NzAutocompleteModule, NzInputModule],\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <div class=\"example-input\">\n      <input\n        placeholder=\"input here\"\n        nz-input\n        [(ngModel)]=\"inputValue\"\n        (input)=\"onInput($event)\"\n        [nzAutocomplete]=\"auto\"\n      />\n      <nz-autocomplete [nzDataSource]=\"options\" nzBackfill #auto />\n    </div>\n  `\n})\nexport class NzDemoAutoCompleteBasicComponent {\n  inputValue?: string;\n  options: string[] = [];\n\n  onInput(event: Event): void {\n    const value = (event.target as HTMLInputElement).value;\n    this.options = value ? [value, value + value, value + value + value] : [];\n  }\n}\n"
  },
  {
    "path": "components/auto-complete/demo/certain-category.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 查询模式 - 确定类目\n  en-US: Lookup-Patterns - Certain Category\n---\n\n## zh-CN\n\n[查询模式: 确定类目](https://ant.design/docs/spec/reaction#Lookup-Patterns) 示例。\n\n## en-US\n\nDemonstration of [Lookup Patterns: Certain Category](https://ant.design/docs/spec/reaction#Lookup-Patterns).\n"
  },
  {
    "path": "components/auto-complete/demo/certain-category.ts",
    "content": "import { Component, OnInit, ViewEncapsulation } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzAutocompleteModule } from 'ng-zorro-antd/auto-complete';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\ninterface AutocompleteOptionGroups {\n  title: string;\n  count?: number;\n  children?: AutocompleteOptionGroups[];\n}\n\n@Component({\n  selector: 'nz-demo-auto-complete-certain-category',\n  imports: [FormsModule, NzAutocompleteModule, NzIconModule, NzInputModule],\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <div class=\"example-input\">\n      <nz-input-wrapper>\n        <input\n          placeholder=\"input here\"\n          nz-input\n          [(ngModel)]=\"inputValue\"\n          (ngModelChange)=\"onChange($event)\"\n          [nzAutocomplete]=\"auto\"\n        />\n        <nz-icon nzInputSuffix nzType=\"search\" />\n      </nz-input-wrapper>\n      <nz-autocomplete #auto>\n        @for (group of optionGroups; track group.title) {\n          <nz-auto-optgroup [nzLabel]=\"groupTitle\">\n            <ng-template #groupTitle>\n              <span>\n                {{ group.title }}\n                <a class=\"more-link\" href=\"https://www.google.com/search?q=ng+zorro\" target=\"_blank\">更多</a>\n              </span>\n            </ng-template>\n            @for (option of group.children; track option.title) {\n              <nz-auto-option [nzLabel]=\"option.title\" [nzValue]=\"option.title\">\n                {{ option.title }}\n                <span class=\"certain-search-item-count\">{{ option.count }} 人 关注</span>\n              </nz-auto-option>\n            }\n          </nz-auto-optgroup>\n        }\n      </nz-autocomplete>\n    </div>\n  `,\n  styles: `\n    .certain-search-item-count {\n      position: absolute;\n      color: #999;\n      right: 16px;\n    }\n\n    .more-link {\n      float: right;\n    }\n  `\n})\nexport class NzDemoAutoCompleteCertainCategoryComponent implements OnInit {\n  inputValue?: string;\n  optionGroups: AutocompleteOptionGroups[] = [];\n\n  onChange(value: string): void {\n    console.log(value);\n  }\n\n  ngOnInit(): void {\n    setTimeout(() => {\n      this.optionGroups = [\n        {\n          title: '话题',\n          children: [\n            {\n              title: 'AntDesign',\n              count: 10000\n            },\n            {\n              title: 'AntDesign UI',\n              count: 10600\n            }\n          ]\n        },\n        {\n          title: '问题',\n          children: [\n            {\n              title: 'AntDesign UI 有多好',\n              count: 60100\n            },\n            {\n              title: 'AntDesign 是啥',\n              count: 30010\n            }\n          ]\n        },\n        {\n          title: '文章',\n          children: [\n            {\n              title: 'AntDesign 是一个设计语言',\n              count: 100000\n            }\n          ]\n        }\n      ];\n    }, 1000);\n  }\n}\n"
  },
  {
    "path": "components/auto-complete/demo/custom.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 自定义输入组件\n  en-US: Customize Input Component\n---\n\n## zh-CN\n\n自定义输入组件。\n\n## en-US\n\nCustomize Input Component\n"
  },
  {
    "path": "components/auto-complete/demo/custom.ts",
    "content": "import { Component, ViewEncapsulation } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzAutocompleteModule } from 'ng-zorro-antd/auto-complete';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-auto-complete-custom',\n  imports: [FormsModule, NzAutocompleteModule, NzInputModule],\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <div class=\"example-input\">\n      <textarea\n        placeholder=\"input here\"\n        nz-input\n        rows=\"4\"\n        [(ngModel)]=\"inputValue\"\n        (input)=\"onInput($event)\"\n        [nzAutocomplete]=\"auto\"\n      ></textarea>\n      <nz-autocomplete #auto>\n        @for (option of options; track $index) {\n          <nz-auto-option [nzValue]=\"option\">{{ option }}</nz-auto-option>\n        }\n      </nz-autocomplete>\n    </div>\n  `\n})\nexport class NzDemoAutoCompleteCustomComponent {\n  inputValue?: string;\n  options: string[] = [];\n\n  onInput(event: Event): void {\n    const value = (event.target as HTMLInputElement).value;\n    this.options = value ? [value, value + value, value + value + value] : [];\n  }\n}\n"
  },
  {
    "path": "components/auto-complete/demo/non-case-sensitive.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 不区分大小写\n  en-US: Non-case-sensitive AutoComplete\n---\n\n## zh-CN\n\n不区分大小写的 AutoComplete\n\n## en-US\n\nA non-case-sensitive AutoComplete\n"
  },
  {
    "path": "components/auto-complete/demo/non-case-sensitive.ts",
    "content": "import { Component, ViewEncapsulation } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzAutocompleteModule } from 'ng-zorro-antd/auto-complete';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-auto-complete-non-case-sensitive',\n  imports: [FormsModule, NzAutocompleteModule, NzInputModule],\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <div class=\"example-input\">\n      <input\n        placeholder='try to type \"b\"'\n        nz-input\n        [(ngModel)]=\"inputValue\"\n        (ngModelChange)=\"onChange($event)\"\n        [nzAutocomplete]=\"auto\"\n      />\n      <nz-autocomplete [nzDataSource]=\"filteredOptions\" #auto />\n    </div>\n  `\n})\nexport class NzDemoAutoCompleteNonCaseSensitiveComponent {\n  inputValue?: string;\n  filteredOptions: string[] = [];\n  options = ['Burns Bay Road', 'Downing Street', 'Wall Street'];\n  constructor() {\n    this.filteredOptions = this.options;\n  }\n  onChange(value: string): void {\n    this.filteredOptions = this.options.filter(option => option.toLowerCase().indexOf(value.toLowerCase()) !== -1);\n  }\n}\n"
  },
  {
    "path": "components/auto-complete/demo/object-value.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 使用对象类型选项\n  en-US: Use option with object type\n---\n\n## zh-CN\n\n当 `nzValue` 和 `ngModel` 类型为 `object` 时使用 `compareWith`([SelectControlValueAccessor](https://angular.cn/api/forms/SelectControlValueAccessor))。\n\n## en-US\n\nUse `compareWith`([SelectControlValueAccessor](https://angular.dev/api/forms/SelectControlValueAccessor)) when the `nzValue` and `ngModel` type is `object`.\n"
  },
  {
    "path": "components/auto-complete/demo/object-value.ts",
    "content": "import { Component, ViewEncapsulation } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzAutocompleteModule } from 'ng-zorro-antd/auto-complete';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\ninterface Option {\n  label: string;\n  value: string;\n  age: number;\n}\n\n@Component({\n  selector: 'nz-demo-auto-complete-object-value',\n  imports: [FormsModule, NzAutocompleteModule, NzInputModule],\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <div class=\"example-input\">\n      <input placeholder=\"input here\" nz-input [(ngModel)]=\"inputValue\" [nzAutocomplete]=\"auto\" />\n      <nz-autocomplete #auto [compareWith]=\"compareFun\">\n        @for (option of options; track $index) {\n          <nz-auto-option [nzValue]=\"option\" [nzLabel]=\"option.label\">\n            {{ option.label }}\n          </nz-auto-option>\n        }\n      </nz-autocomplete>\n    </div>\n  `\n})\nexport class NzDemoAutoCompleteObjectValueComponent {\n  inputValue: Option = { label: 'Lucy', value: 'lucy', age: 20 };\n  options: Option[] = [\n    { label: 'Lucy', value: 'lucy', age: 20 },\n    { label: 'Jack', value: 'jack', age: 22 }\n  ];\n\n  compareFun = (o1: Option | string, o2: Option): boolean => {\n    if (o1) {\n      return typeof o1 === 'string' ? o1 === o2.label : o1.value === o2.value;\n    } else {\n      return false;\n    }\n  };\n}\n"
  },
  {
    "path": "components/auto-complete/demo/options.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 自定义选项\n  en-US: Customized\n---\n\n## zh-CN\n\n也可以直接传 `nz-auto-option` 作为 `nz-autocomplete` 的 Content，而非使用 `nzDataSource`。\n\n## en-US\n\nYou could pass `nz-auto-option` as Content of `nz-autocomplete`, instead of using nzDataSource`.\n"
  },
  {
    "path": "components/auto-complete/demo/options.ts",
    "content": "import { Component, ViewEncapsulation } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzAutocompleteModule } from 'ng-zorro-antd/auto-complete';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-auto-complete-options',\n  imports: [FormsModule, NzAutocompleteModule, NzInputModule],\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <div class=\"example-input\">\n      <input\n        placeholder=\"input here\"\n        nz-input\n        [(ngModel)]=\"inputValue\"\n        (input)=\"onInput($event)\"\n        [nzAutocomplete]=\"auto\"\n      />\n      <nz-autocomplete #auto>\n        @for (option of options; track $index) {\n          <nz-auto-option [nzValue]=\"option\">{{ option }}</nz-auto-option>\n        }\n      </nz-autocomplete>\n    </div>\n  `\n})\nexport class NzDemoAutoCompleteOptionsComponent {\n  inputValue?: string;\n  options: string[] = [];\n\n  onInput(e: Event): void {\n    const value = (e.target as HTMLInputElement).value;\n    if (!value || value.indexOf('@') >= 0) {\n      this.options = [];\n    } else {\n      this.options = ['gmail.com', '163.com', 'qq.com'].map(domain => `${value}@${domain}`);\n    }\n  }\n}\n"
  },
  {
    "path": "components/auto-complete/demo/status.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 自定义状态\n  en-US: Status\n---\n\n## zh-CN\n\n使用 `nzStatus` 为 AutoComplete 添加状态，可选 `error` 或者 `warning`。\n\n## en-US\n\nAdd status to AutoComplete with `nzStatus`, which could be `error` or `warning`.\n"
  },
  {
    "path": "components/auto-complete/demo/status.ts",
    "content": "import { Component, ViewEncapsulation } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzAutocompleteModule } from 'ng-zorro-antd/auto-complete';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-auto-complete-status',\n  imports: [FormsModule, NzAutocompleteModule, NzInputModule],\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <input nz-input [(ngModel)]=\"value\" [nzAutocomplete]=\"auto\" nzStatus=\"error\" />\n    <br />\n    <br />\n    <input nz-input [(ngModel)]=\"value\" [nzAutocomplete]=\"auto\" nzStatus=\"warning\" />\n    <nz-autocomplete [nzDataSource]=\"['12345', '23456', '34567']\" #auto />\n  `\n})\nexport class NzDemoAutoCompleteStatusComponent {\n  value?: string;\n}\n"
  },
  {
    "path": "components/auto-complete/demo/uncertain-category.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 查询模式 - 不确定类目\n  en-US: Lookup-Patterns - Uncertain Category\n---\n\n## zh-CN\n\n[查询模式: 不确定类目](https://ant.design/docs/spec/reaction#Lookup-Patterns) 示例。\n\n## en-US\n\nDemonstration of [Lookup Patterns: Uncertain Category](https://ant.design/docs/spec/reaction#Lookup-Patterns).\n"
  },
  {
    "path": "components/auto-complete/demo/uncertain-category.ts",
    "content": "import { Component, ViewEncapsulation } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzAutocompleteModule } from 'ng-zorro-antd/auto-complete';\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-auto-complete-uncertain-category',\n  imports: [FormsModule, NzAutocompleteModule, NzButtonModule, NzIconModule, NzInputModule],\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <nz-input-search nzEnterButton>\n      <input\n        nz-input\n        placeholder=\"input here\"\n        nzSize=\"large\"\n        [(ngModel)]=\"inputValue\"\n        (input)=\"onChange($event)\"\n        [nzAutocomplete]=\"auto\"\n      />\n    </nz-input-search>\n    <nz-autocomplete #auto>\n      @for (option of options; track option.category) {\n        <nz-auto-option class=\"search-item\" [nzValue]=\"option.category\">\n          Found {{ option.value }} on\n          <a\n            class=\"search-item-desc\"\n            [href]=\"'https://s.taobao.com/search?q=' + option.value\"\n            target=\"_blank\"\n            rel=\"noopener noreferrer\"\n          >\n            {{ option.category }}\n          </a>\n          <span class=\"search-item-count\">{{ option.count }} results</span>\n        </nz-auto-option>\n      }\n    </nz-autocomplete>\n  `,\n  styles: `\n    .search-item {\n      display: flex;\n    }\n\n    .search-item-desc {\n      flex: auto;\n      text-overflow: ellipsis;\n      overflow: hidden;\n    }\n\n    .search-item-count {\n      flex: none;\n    }\n  `\n})\nexport class NzDemoAutoCompleteUncertainCategoryComponent {\n  inputValue?: string;\n  options: Array<{ value: string; category: string; count: number }> = [];\n\n  onChange(e: Event): void {\n    const value = (e.target as HTMLInputElement).value;\n    this.options = new Array(this.getRandomInt(5, 15))\n      .join('.')\n      .split('.')\n      .map((_item, idx) => ({\n        value,\n        category: `${value}${idx}`,\n        count: this.getRandomInt(200, 100)\n      }));\n  }\n\n  private getRandomInt(max: number, min: number = 0): number {\n    return Math.floor(Math.random() * (max - min + 1)) + min;\n  }\n}\n"
  },
  {
    "path": "components/auto-complete/demo/variant.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 多种形态\n  en-US: Variants\n---\n\n## zh-CN\n\n通过使用 `nz-input` 并将 `nzVariant` 设置为 `outlined`、`underlined`、`filled` 和 `borderless`，即可支持变体\n\n## en-US\n\nVariant is supported out of the box by using `nz-input` and setting `nzVariant` to `outlined`, `underlined`, `filled` and `borderless`\n"
  },
  {
    "path": "components/auto-complete/demo/variant.ts",
    "content": "import { Component, model, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzAutocompleteModule } from 'ng-zorro-antd/auto-complete';\nimport type { NzVariant } from 'ng-zorro-antd/core/types';\nimport { NzFlexModule } from 'ng-zorro-antd/flex';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-auto-complete-variant',\n  imports: [FormsModule, NzAutocompleteModule, NzInputModule, NzFlexModule],\n  template: `\n    <section nz-flex nzVertical nzGap=\"1rem\">\n      @for (variant of variants(); track variant) {\n        <div class=\"example-input\">\n          <input\n            placeholder=\"input here\"\n            nz-input\n            [(ngModel)]=\"inputValue\"\n            (input)=\"onInput($event)\"\n            [nzAutocomplete]=\"auto\"\n            [nzVariant]=\"variant\"\n          />\n          <nz-autocomplete [nzDataSource]=\"options()\" nzBackfill #auto />\n        </div>\n      }\n    </section>\n  `\n})\nexport class NzDemoAutoCompleteVariantComponent {\n  options = signal<string[]>([]);\n  inputValue = model<string>('');\n  variants = signal<NzVariant[]>(['outlined', 'filled', 'borderless', 'underlined']);\n  onInput(event: Event): void {\n    const value = (event.target as HTMLInputElement).value;\n    this.options.set(value ? [value, value + value, value + value + value] : []);\n  }\n}\n"
  },
  {
    "path": "components/auto-complete/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Entry\ntitle: AutoComplete\ncover: 'https://gw.alipayobjects.com/zos/alicdn/qtJm4yt45/AutoComplete.svg'\ndescription: AutoComplete function of input field.\n---\n\n## When To Use\n\nWhen there is a need for autocomplete functionality.\n\n## API\n\n```html\n<input nz-input [(ngModel)]=\"value\" [nzAutocomplete]=\"auto\" />\n<nz-autocomplete [nzDataSource]=\"['12345', '23456', '34567']\" #auto></nz-autocomplete>\n```\n\n```html\n<input nz-input [(ngModel)]=\"value\" [nzAutocomplete]=\"auto\" />\n<nz-autocomplete #auto>\n  <nz-auto-option [nzValue]=\"'12345'\">12345</nz-auto-option>\n  <nz-auto-option [nzValue]=\"'23456'\">23456</nz-auto-option>\n  <nz-auto-option [nzValue]=\"'34567'\">34567</nz-auto-option>\n</nz-autocomplete>\n```\n\n### [nzAutocomplete]\n\n| Property           | Description                              | Type                      | Default |\n| ------------------ | ---------------------------------------- | ------------------------- | ------- |\n| `[nzAutocomplete]` | used to bind `nzAutocomplete` components | `NzAutocompleteComponent` | -       |\n\n### nz-autocomplete\n\n| Property                       | Description                                                                                    | Type                            | Default                         |\n| ------------------------------ | ---------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------------- |\n| `[nzBackfill]`                 | backfill selected item the input when using keyboard                                           | `boolean`                       | `false`                         |\n| `[nzDataSource]`               | Data source for autocomplete                                                                   | `AutocompleteDataSource`        | -                               |\n| `[nzDefaultActiveFirstOption]` | Whether active first option by default                                                         | `boolean`                       | `true`                          |\n| `[nzWidth]`                    | Custom width, unit px                                                                          | `number`                        | trigger element width           |\n| `[nzOverlayClassName]`         | Class name of the dropdown root element                                                        | `string`                        | -                               |\n| `[nzOverlayStyle]`             | Style of the dropdown root element                                                             | `object`                        | -                               |\n| `[compareWith]`                | Same as [SelectControlValueAccessor](https://angular.dev/api/forms/SelectControlValueAccessor) | `(o1: any, o2: any) => boolean` | `(o1: any, o2: any) => o1===o2` |\n\n### nz-auto-option\n\n| Property       | Description                          | Type      | Default |\n| -------------- | ------------------------------------ | --------- | ------- |\n| `[nzValue]`    | bind ngModel of the trigger element  | `any`     | -       |\n| `[nzLabel]`    | display value of the trigger element | `string`  | -       |\n| `[nzDisabled]` | disabled option                      | `boolean` | `false` |\n\n## FAQ\n\n### Q: The overlay layer element does not follow the scroll position when scrolling\n\nBy default, the overlay layer element uses body as the scroll container. If using another scroll container, add the [CdkScrollable](https://material.angular.dev/cdk/scrolling/api#CdkScrollable) directive to the custom scroll container element.\nNote: You need to import the `CdkScrollable` directive or `ScrollingModule` module from `@angular/cdk/scrolling`.\n"
  },
  {
    "path": "components/auto-complete/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ntype: 数据录入\ntitle: AutoComplete\nsubtitle: 自动完成\ncover: 'https://gw.alipayobjects.com/zos/alicdn/qtJm4yt45/AutoComplete.svg'\ndescription: 输入框自动完成功能。\n---\n\n## 何时使用\n\n需要自动完成时。\n\n## API\n\n```html\n<input nz-input [(ngModel)]=\"value\" [nzAutocomplete]=\"auto\" />\n<nz-autocomplete [nzDataSource]=\"['12345', '23456', '34567']\" #auto></nz-autocomplete>\n```\n\n```html\n<input nz-input [(ngModel)]=\"value\" [nzAutocomplete]=\"auto\" />\n<nz-autocomplete #auto>\n  <nz-auto-option [nzValue]=\"'12345'\">12345</nz-auto-option>\n  <nz-auto-option [nzValue]=\"'23456'\">23456</nz-auto-option>\n  <nz-auto-option [nzValue]=\"'34567'\">34567</nz-auto-option>\n</nz-autocomplete>\n```\n\n### [nzAutocomplete]\n\n| 属性               | 说明                         | 类型                      | 默认值 |\n| ------------------ | ---------------------------- | ------------------------- | ------ |\n| `[nzAutocomplete]` | 用于绑定 nzAutocomplete 组件 | `NzAutocompleteComponent` | -      |\n\n### nz-autocomplete\n\n| 属性                           | 说明                                                                                          | 类型                            | 默认值                          |\n| ------------------------------ | --------------------------------------------------------------------------------------------- | ------------------------------- | ------------------------------- |\n| `[nzBackfill]`                 | 使用键盘选择选项的时候，会把当前高亮项的值即时回填到输入框中                                  | `boolean`                       | `false`                         |\n| `[nzDataSource]`               | 自动完成的数据源                                                                              | `AutocompleteDataSource`        | -                               |\n| `[nzDefaultActiveFirstOption]` | 是否默认高亮第一个选项。                                                                      | `boolean`                       | `true`                          |\n| `[nzWidth]`                    | 自定义宽度单位 px                                                                             | `number`                        | 触发元素宽度                    |\n| `[nzOverlayClassName]`         | 下拉根元素的类名称                                                                            | `string`                        | -                               |\n| `[nzOverlayStyle]`             | 下拉根元素的样式                                                                              | `object`                        | -                               |\n| `[compareWith]`                | 与 [SelectControlValueAccessor](https://angular.cn/api/forms/SelectControlValueAccessor) 相同 | `(o1: any, o2: any) => boolean` | `(o1: any, o2: any) => o1===o2` |\n\n### nz-auto-option\n\n| 属性           | 说明                        | 类型      | 默认值  |\n| -------------- | --------------------------- | --------- | ------- |\n| `[nzValue]`    | 绑定到触发元素 ngModel 的值 | `any`     | -       |\n| `[nzLabel]`    | 填入触发元素显示的值        | `string`  | -       |\n| `[nzDisabled]` | 禁用选项                    | `boolean` | `false` |\n\n## FAQ\n\n### Q：滚动时浮层元素没有跟随滚动位置\n\n默认情况下，浮层元素使用 `body` 作为滚动容器，如果使用了其他滚动容器，在自定义滚动容器元素上添加 [CdkScrollable](https://material.angular.dev/cdk/scrolling/api#CdkScrollable) 指令。\n注意：您需要从 `@angular/cdk/scrolling` 导入 `CdkScrollable` 指令或 `ScrollingModule` 模块。\n"
  },
  {
    "path": "components/auto-complete/error.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\n/**\n * @note Internally used, please do not use it\n */\nexport function getNzAutocompleteMissingPanelError(): Error {\n  return Error(\n    'Attempting to open an undefined instance of `nz-autocomplete`. ' +\n      'Make sure that the id passed to the `nzAutocomplete` is correct and that ' +\n      \"you're attempting to open it after the ngAfterContentInit hook.\"\n  );\n}\n"
  },
  {
    "path": "components/auto-complete/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/auto-complete/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/auto-complete/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './autocomplete.module';\nexport * from './autocomplete.component';\nexport * from './autocomplete-trigger.directive';\nexport * from './autocomplete-option.component';\nexport * from './autocomplete-optgroup.component';\n"
  },
  {
    "path": "components/auto-complete/style/entry.less",
    "content": "@import './index.less';\n// style dependencies\n@import '../../select/style/entry.less';\n@import '../../input/style/entry.less';\n@import \"./patch\";\n"
  },
  {
    "path": "components/auto-complete/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import '../../input/style/mixin';\n\n@input-prefix-cls: ~'@{ant-prefix}-input';\n@select-prefix-cls: ~'@{ant-prefix}-select';\n@autocomplete-prefix-cls: ~'@{select-prefix-cls}-auto-complete';\n\n.@{autocomplete-prefix-cls} {\n  .reset-component();\n\n  // https://github.com/ant-design/ant-design/issues/22302\n  .@{select-prefix-cls}-clear {\n    right: 13px;\n  }\n}\n"
  },
  {
    "path": "components/auto-complete/style/patch.less",
    "content": ".ant-select-dropdown-hidden {\n  display: none;\n}\n\n.ant-select-dropdown-content-wrapper {\n  max-height: 256px;\n  overflow-y: auto;\n  overflow-anchor: none;\n}\n\n.ant-select-dropdown-content {\n  display: flex;\n  flex-direction: column;\n}\n"
  },
  {
    "path": "components/avatar/avatar-group.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component } from '@angular/core';\n\n@Component({\n  selector: 'nz-avatar-group',\n  exportAs: 'nzAvatarGroup',\n  template: `<ng-content />`,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    class: 'ant-avatar-group'\n  }\n})\nexport class NzAvatarGroupComponent {}\n"
  },
  {
    "path": "components/avatar/avatar.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  afterEveryRender,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ElementRef,\n  EventEmitter,\n  inject,\n  input,\n  Input,\n  numberAttribute,\n  OnChanges,\n  Output,\n  ViewChild,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { NzConfigKey, WithConfig } from 'ng-zorro-antd/core/config';\nimport { NzShapeSCType, NzSizeLDSType } from 'ng-zorro-antd/core/types';\nimport { toCssPixel } from 'ng-zorro-antd/core/util';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'avatar';\n\n/** https://html.spec.whatwg.org/multipage/embedded-content.html#attr-img-loading */\ntype NzAvatarLoading = 'eager' | 'lazy';\n\n/** https://wicg.github.io/priority-hints/#idl-index */\ntype NzAvatarFetchPriority = 'high' | 'low' | 'auto';\n\n@Component({\n  selector: 'nz-avatar',\n  exportAs: 'nzAvatar',\n  imports: [NzIconModule],\n  template: `\n    @if (nzIcon && hasIcon) {\n      <nz-icon [nzType]=\"nzIcon\" />\n    } @else if (nzSrc && hasSrc) {\n      <img\n        [src]=\"nzSrc\"\n        [attr.srcset]=\"nzSrcSet\"\n        [attr.alt]=\"nzAlt\"\n        [attr.loading]=\"nzLoading() || 'eager'\"\n        [attr.fetchpriority]=\"nzFetchPriority() || 'auto'\"\n        (error)=\"imgError($event)\"\n      />\n    } @else if (nzText && hasText) {\n      <span class=\"ant-avatar-string\" #textEl>{{ nzText }}</span>\n    }\n    <ng-content />\n  `,\n  host: {\n    class: 'ant-avatar',\n    '[class.ant-avatar-lg]': `nzSize === 'large'`,\n    '[class.ant-avatar-sm]': `nzSize === 'small'`,\n    '[class.ant-avatar-square]': `nzShape === 'square'`,\n    '[class.ant-avatar-circle]': `nzShape === 'circle'`,\n    '[class.ant-avatar-icon]': `nzIcon`,\n    '[class.ant-avatar-image]': `hasSrc `,\n    '[style.width]': 'customSize',\n    '[style.height]': 'customSize',\n    '[style.line-height]': 'customSize',\n    // nzSize type is number when customSize is true\n    '[style.font-size.px]': '(hasIcon && customSize) ? $any(nzSize) / 2 : null'\n  },\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None\n})\nexport class NzAvatarComponent implements OnChanges {\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n  @Input() @WithConfig() nzShape: NzShapeSCType = 'circle';\n  @Input() @WithConfig() nzSize: NzSizeLDSType | number = 'default';\n  @Input({ transform: numberAttribute }) @WithConfig() nzGap = 4;\n  @Input() nzText?: string;\n  @Input() nzSrc?: string;\n  @Input() nzSrcSet?: string;\n  @Input() nzAlt?: string;\n  @Input() nzIcon?: string;\n  readonly nzLoading = input<NzAvatarLoading>();\n  readonly nzFetchPriority = input<NzAvatarFetchPriority>();\n  @Output() readonly nzError = new EventEmitter<Event>();\n\n  hasText: boolean = false;\n  hasSrc: boolean = true;\n  hasIcon: boolean = false;\n  customSize: string | null = null;\n\n  @ViewChild('textEl', { static: false }) textEl?: ElementRef<HTMLSpanElement>;\n\n  private el: HTMLElement = inject(ElementRef).nativeElement;\n  private cdr = inject(ChangeDetectorRef);\n\n  constructor() {\n    afterEveryRender(() => this.calcStringSize());\n  }\n\n  imgError(event: Event): void {\n    this.nzError.emit(event);\n    if (!event.defaultPrevented) {\n      this.hasSrc = false;\n      this.hasIcon = false;\n      this.hasText = false;\n      if (this.nzIcon) {\n        this.hasIcon = true;\n      } else if (this.nzText) {\n        this.hasText = true;\n      }\n      this.cdr.detectChanges();\n      this.setSizeStyle();\n      this.calcStringSize();\n    }\n  }\n\n  ngOnChanges(): void {\n    this.hasText = !this.nzSrc && !!this.nzText;\n    this.hasIcon = !this.nzSrc && !!this.nzIcon;\n    this.hasSrc = !!this.nzSrc;\n\n    this.setSizeStyle();\n    this.calcStringSize();\n  }\n\n  private calcStringSize(): void {\n    if (!this.hasText || !this.textEl) {\n      return;\n    }\n\n    const textEl = this.textEl.nativeElement;\n    const childrenWidth = textEl.offsetWidth;\n    const avatarWidth = this.el.getBoundingClientRect?.().width ?? 0;\n    const offset = this.nzGap * 2 < avatarWidth ? this.nzGap * 2 : 8;\n    const scale = avatarWidth - offset < childrenWidth ? (avatarWidth - offset) / childrenWidth : 1;\n\n    textEl.style.transform = `scale(${scale}) translateX(-50%)`;\n    textEl.style.lineHeight = this.customSize || '';\n  }\n\n  private setSizeStyle(): void {\n    if (typeof this.nzSize === 'number') {\n      this.customSize = toCssPixel(this.nzSize);\n    } else {\n      this.customSize = null;\n    }\n\n    this.cdr.markForCheck();\n  }\n}\n"
  },
  {
    "path": "components/avatar/avatar.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzAvatarGroupComponent } from './avatar-group.component';\nimport { NzAvatarComponent } from './avatar.component';\n\n@NgModule({\n  exports: [NzAvatarComponent, NzAvatarGroupComponent],\n  imports: [NzAvatarComponent, NzAvatarGroupComponent]\n})\nexport class NzAvatarModule {}\n"
  },
  {
    "path": "components/avatar/avatar.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, DebugElement, ViewChild } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { createFakeEvent, updateNonSignalsInput } from 'ng-zorro-antd/core/testing';\nimport { NzSafeAny, NzShapeSCType, NzSizeLDSType } from 'ng-zorro-antd/core/types';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzAvatarGroupComponent } from './avatar-group.component';\nimport { NzAvatarComponent } from './avatar.component';\nimport { NzAvatarModule } from './avatar.module';\n\nconst imageBase64 =\n  'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+P+/HgAFhAJ/wlseKgAAAABJRU5ErkJggg==';\n\nfunction getType(dl: DebugElement): string {\n  const el = dl.nativeElement as HTMLElement;\n  if (el.querySelector('img') != null) {\n    return 'image';\n  }\n  if (el.querySelector('.anticon') != null) {\n    return 'icon';\n  }\n  return el.innerText.trim().length === 0 ? '' : 'text';\n}\n\ndescribe('avatar group', () => {\n  let fixture: ComponentFixture<TestAvatarGroupComponent>;\n  beforeEach(async () => {\n    TestBed.configureTestingModule({});\n    fixture = TestBed.createComponent(TestAvatarGroupComponent);\n    fixture.autoDetectChanges();\n  });\n\n  it('should avatar group work', async () => {\n    await fixture.whenStable();\n    const avatarGroup = fixture.debugElement.query(By.directive(NzAvatarGroupComponent));\n    expect(avatarGroup.nativeElement.classList).toContain('ant-avatar-group');\n  });\n});\n\ndescribe('avatar', () => {\n  let fixture: ComponentFixture<TestAvatarComponent>;\n  let context: TestAvatarComponent;\n  let dl: DebugElement;\n\n  function getImageElement(): HTMLImageElement {\n    return dl.query(By.css('img')).nativeElement;\n  }\n\n  beforeEach(async () => {\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting()]\n    });\n\n    fixture = TestBed.createComponent(TestAvatarComponent);\n    context = fixture.componentInstance;\n    dl = fixture.debugElement;\n    fixture.autoDetectChanges();\n    await fixture.whenStable();\n  });\n\n  describe('#nzSrc', () => {\n    it('#nzSrc', () => {\n      expect(context).not.toBeNull();\n    });\n\n    it('should tolerate error src', async () => {\n      const event = createFakeEvent('error');\n      expect(getType(dl)).toBe('image');\n      expect(context.comp.hasSrc).toBe(true);\n      // Manually dispatch error.\n      context.nzSrc = '';\n      await updateNonSignalsInput(fixture);\n      context.comp.imgError(event);\n      await updateNonSignalsInput(fixture);\n      expect(getType(dl)).toBe('icon');\n      expect(context.comp.hasSrc).toBe(false);\n      context.nzSrc = imageBase64;\n      await updateNonSignalsInput(fixture);\n      expect(context.comp.hasSrc).toBe(true);\n      expect(getType(dl)).toBe('image');\n    });\n\n    it('should prevent default fallback when error src', async () => {\n      const event = createFakeEvent('error');\n      event.preventDefault();\n      expect(getType(dl)).toBe('image');\n      expect(context.comp.hasSrc).toBe(true);\n      // Manually dispatch error.\n      context.nzSrc = 'Invalid image src';\n      await updateNonSignalsInput(fixture);\n      context.comp.imgError(event);\n      expect(getType(dl)).toBe('image');\n      expect(context.comp.hasSrc).toBe(true);\n      context.nzSrc = imageBase64;\n      await updateNonSignalsInput(fixture);\n      expect(context.comp.hasSrc).toBe(true);\n      expect(getType(dl)).toBe('image');\n    });\n\n    it('#nzSrcSet', async () => {\n      context.nzSrcSet = '1.png';\n      await updateNonSignalsInput(fixture);\n      const el = getImageElement();\n      expect(el.srcset).toBe(context.nzSrcSet);\n    });\n\n    it('#nzAlt', async () => {\n      context.nzAlt = 'alt';\n      await updateNonSignalsInput(fixture);\n      const el = getImageElement();\n      expect(el.alt).toBe(context.nzAlt);\n    });\n  });\n\n  it('#nzIcon', async () => {\n    context.nzSrc = undefined;\n    context.nzText = undefined;\n    await updateNonSignalsInput(fixture);\n    expect(getType(dl)).toBe('icon');\n  });\n\n  describe('#nzText', () => {\n    beforeEach(async () => {\n      context.nzSrc = undefined;\n      context.nzIcon = undefined;\n      await updateNonSignalsInput(fixture);\n    });\n\n    it('property', () => {\n      expect(getType(dl)).toBe('text');\n    });\n\n    it('should be normal font-size', async () => {\n      context.nzText = 'a';\n      await updateNonSignalsInput(fixture);\n      const scale = getScaleFromCSSTransform(dl.nativeElement.querySelector('.ant-avatar-string')!.style.transform!);\n      expect(scale).toBe(1);\n    });\n\n    it('should be auto set font-size', async () => {\n      context.nzText = 'LongUsername';\n      await updateNonSignalsInput(fixture);\n      context.comp['calcStringSize']();\n      const scale = getScaleFromCSSTransform(dl.nativeElement.querySelector('.ant-avatar-string')!.style.transform!);\n      expect(scale).toBeLessThan(1);\n    });\n\n    describe('nzGap', () => {\n      let firstScale: number;\n      let avatarText: HTMLElement;\n      beforeEach(async () => {\n        context.nzGap = 4;\n        context.nzText = 'Username';\n        await updateNonSignalsInput(fixture);\n        avatarText = dl.nativeElement.querySelector('.ant-avatar-string')!;\n        context.comp['calcStringSize']();\n        firstScale = getScaleFromCSSTransform(avatarText.style.transform);\n      });\n\n      it('should be set gap', async () => {\n        context.nzGap = 8;\n        await updateNonSignalsInput(fixture);\n\n        let scale = getScaleFromCSSTransform(avatarText.style.transform);\n        expect(scale).toBeLessThan(firstScale);\n\n        context.nzGap = 2;\n        await updateNonSignalsInput(fixture);\n\n        scale = getScaleFromCSSTransform(avatarText.style.transform);\n        expect(scale).toBeGreaterThan(firstScale);\n      });\n\n      it('Should be set to default when the limit is exceeded', async () => {\n        context.nzGap = 1000;\n        await updateNonSignalsInput(fixture);\n\n        let scale = getScaleFromCSSTransform(avatarText.style.transform);\n        expect(scale).toEqual(firstScale);\n\n        context.nzGap = -1000;\n        await updateNonSignalsInput(fixture);\n\n        scale = getScaleFromCSSTransform(avatarText.style.transform);\n        expect(scale).toEqual(1);\n      });\n    });\n  });\n\n  describe('#nzShape', () => {\n    for (const type of ['square', 'circle'] as const) {\n      it(type, async () => {\n        context.nzShape = type;\n        await updateNonSignalsInput(fixture);\n        expect(dl.query(By.css(`.ant-avatar-${type}`)) !== null).toBe(true);\n      });\n    }\n  });\n\n  describe('#nzSize', () => {\n    for (const item of [\n      { size: 'large', cls: 'lg' },\n      { size: 'small', cls: 'sm' }\n    ] as const) {\n      it(item.size, async () => {\n        context.nzSize = item.size;\n        await updateNonSignalsInput(fixture);\n        expect(dl.query(By.css(`.ant-avatar-${item.cls}`)) !== null).toBe(true);\n      });\n    }\n\n    it('custom size', async () => {\n      context.nzSize = 64;\n      context.nzIcon = undefined;\n      context.nzSrc = undefined;\n      await updateNonSignalsInput(fixture);\n      const size = `${64}px`;\n      const hostStyle = dl.nativeElement.querySelector('nz-avatar').style;\n      expect(hostStyle.height === size).toBe(true);\n      expect(hostStyle.width === size).toBe(true);\n      expect(hostStyle.lineHeight === size).toBe(true);\n      expect(hostStyle.fontSize === ``).toBe(true);\n\n      context.nzIcon = 'user';\n      await updateNonSignalsInput(fixture);\n      expect(hostStyle.fontSize === `${context.nzSize / 2}px`).toBe(true);\n    });\n\n    it('should set `lineHeight` on the text element considering `nzSize`', async () => {\n      const size = 64;\n      context.nzIcon = undefined;\n      context.nzSrc = undefined;\n      context.nzSize = size;\n      context.nzText = 'LongUsername';\n      await updateNonSignalsInput(fixture);\n      const textEl = document.querySelector<HTMLElement>('.ant-avatar-string')!;\n      context.comp['calcStringSize']();\n      const scale = getScaleFromCSSTransform(textEl.style.transform);\n      expect(scale).toBeLessThan(1);\n      expect(textEl.style.lineHeight).toEqual(`${size}px`);\n    });\n\n    // this case will fail in local environment but pass in CI. Ignore it first.\n\n    it('[IGNORE_LOCAL] should have 0 for avatarWidth if element.width is falsy`', async () => {\n      const size = 64;\n      context.nzIcon = undefined;\n      context.nzSrc = undefined;\n      context.nzSize = size;\n      context.nzText = 'LongUsername';\n      context.comp.hasText = true;\n\n      await updateNonSignalsInput(fixture);\n      const textEl = document.querySelector<HTMLElement>('.ant-avatar-string')!;\n      (context.comp as NzSafeAny)['el'] = {\n        getBoundingClientRect: function () {\n          return {\n            width: null\n          };\n        }\n      };\n\n      context.comp['calcStringSize']();\n\n      const scale = getScaleFromCSSTransform(textEl.style.transform);\n\n      // avatarWidth = 0\n      // childrenWidth = 86\n      // offset = 8\n      // avatarWidth = 0\n      // scale = (0 - 8) / 86\n      expect(scale).toBe(-0.0930233);\n    });\n  });\n\n  describe('[nzLoading]', () => {\n    it('should set `loading` attribute to `eager` by default', () => {\n      expect(getImageElement().loading).toEqual('eager');\n    });\n\n    it('should allow providing a binding for the `loading` attribute', async () => {\n      context.nzLoading = 'lazy';\n      await updateNonSignalsInput(fixture);\n      expect(getImageElement().loading).toEqual('lazy');\n    });\n  });\n\n  describe('[nzFetchPriority]', () => {\n    it('should set `fetchpriority` attribute to `auto` by default', () => {\n      expect(getImageElement().fetchPriority).toEqual('auto');\n    });\n\n    it('should allow providing a binding for the `fetchpriority` attribute', async () => {\n      context.nzFetchPriority = 'high';\n      await updateNonSignalsInput(fixture);\n      expect(getImageElement().fetchPriority).toEqual('high');\n    });\n  });\n\n  describe('order: image > icon > text', () => {\n    it('image priority', () => {\n      expect(getType(dl)).toBe('image');\n    });\n\n    it('should be show icon when image loaded error and icon exists', async () => {\n      const event = createFakeEvent('error');\n      expect(getType(dl)).toBe('image');\n      context.comp.imgError(event);\n      await updateNonSignalsInput(fixture);\n      expect(getType(dl)).toBe('icon');\n    });\n\n    it('should be show text when image loaded error and icon not exists', async () => {\n      const event = createFakeEvent('error');\n      expect(getType(dl)).toBe('image');\n      context.nzIcon = undefined;\n      await updateNonSignalsInput(fixture);\n      context.comp.imgError(event);\n      await updateNonSignalsInput(fixture);\n      expect(getType(dl)).toBe('text');\n    });\n\n    it('should be show empty when image loaded error and icon & text not exists', async () => {\n      const event = createFakeEvent('error');\n      expect(getType(dl)).toBe('image');\n      context.nzIcon = undefined;\n      context.nzText = undefined;\n      await updateNonSignalsInput(fixture);\n      context.comp.imgError(event);\n      await updateNonSignalsInput(fixture);\n      expect(getType(dl)).toBe('');\n    });\n  });\n});\n\nfunction getScaleFromCSSTransform(transform: string): number {\n  return +/(\\w+)\\(([^)]*)\\)/g.exec(transform)![2];\n}\n\n@Component({\n  imports: [NzAvatarModule],\n  template: `\n    <nz-avatar\n      #comp\n      [nzShape]=\"nzShape\"\n      [nzSize]=\"nzSize\"\n      [nzIcon]=\"nzIcon\"\n      [nzText]=\"nzText\"\n      [nzGap]=\"nzGap\"\n      [nzSrc]=\"nzSrc\"\n      [nzSrcSet]=\"nzSrcSet\"\n      [nzAlt]=\"nzAlt\"\n      [nzLoading]=\"nzLoading\"\n      [nzFetchPriority]=\"nzFetchPriority\"\n    />\n  `,\n  styles: `\n    @import '../style/testing.less';\n    @import './style/index.less';\n  `\n})\nclass TestAvatarComponent {\n  @ViewChild('comp', { static: false }) comp!: NzAvatarComponent;\n  nzShape: NzShapeSCType = 'square';\n  nzSize: NzSizeLDSType | number = 'large';\n  nzGap = 4;\n  nzIcon?: string = 'user';\n  nzText?: string = 'A';\n  nzSrc?: string = imageBase64;\n  nzSrcSet?: string;\n  nzAlt?: string;\n  nzLoading?: 'eager' | 'lazy';\n  nzFetchPriority?: 'high' | 'low' | 'auto';\n}\n\n@Component({\n  imports: [NzAvatarModule],\n  template: `<nz-avatar-group />`\n})\nclass TestAvatarGroupComponent {}\n"
  },
  {
    "path": "components/avatar/demo/badge.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 带徽标的头像\n  en-US: With Badge\n---\n\n## zh-CN\n\n通常用于消息提示。\n\n## en-US\n\nUsually used for messages remind.\n"
  },
  {
    "path": "components/avatar/demo/badge.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzAvatarModule } from 'ng-zorro-antd/avatar';\nimport { NzBadgeModule } from 'ng-zorro-antd/badge';\n\n@Component({\n  selector: 'nz-demo-avatar-badge',\n  imports: [NzBadgeModule, NzAvatarModule],\n  template: `\n    <nz-badge [nzCount]=\"5\" style=\"margin-right: 24px\">\n      <nz-avatar nzIcon=\"user\" nzShape=\"square\" />\n    </nz-badge>\n    <nz-badge nzDot>\n      <nz-avatar nzIcon=\"user\" nzShape=\"square\" />\n    </nz-badge>\n  `\n})\nexport class NzDemoAvatarBadgeComponent {}\n"
  },
  {
    "path": "components/avatar/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n头像有三种尺寸，两种形状可选。\n\n## en-US\n\nThree sizes and two shapes are available.\n"
  },
  {
    "path": "components/avatar/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzAvatarModule } from 'ng-zorro-antd/avatar';\n\n@Component({\n  selector: 'nz-demo-avatar-basic',\n  imports: [NzAvatarModule],\n  template: `\n    <div>\n      <nz-avatar [nzSize]=\"64\" nzIcon=\"user\" />\n      <nz-avatar nzSize=\"large\" nzIcon=\"user\" />\n      <nz-avatar nzIcon=\"user\" />\n      <nz-avatar nzSize=\"small\" nzIcon=\"user\" />\n    </div>\n    <div>\n      <nz-avatar nzShape=\"square\" [nzSize]=\"64\" nzIcon=\"user\" />\n      <nz-avatar nzShape=\"square\" nzSize=\"large\" nzIcon=\"user\" />\n      <nz-avatar nzShape=\"square\" nzIcon=\"user\" />\n      <nz-avatar nzShape=\"square\" nzSize=\"small\" nzIcon=\"user\" />\n    </div>\n  `,\n  styles: `\n    nz-avatar {\n      margin-top: 16px;\n      margin-right: 16px;\n    }\n  `\n})\nexport class NzDemoAvatarBasicComponent {}\n"
  },
  {
    "path": "components/avatar/demo/dynamic.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 自动调整字符大小\n  en-US: Autoset Font Size\n---\n\n## zh-CN\n\n对于字符型的头像，当字符串较长时，字体大小可以根据头像宽度自动调整。\n\n## en-US\n\nFor letter type Avatar, when the letters are too long to display, the font size can be automatically adjusted according to the width of the Avatar.\n"
  },
  {
    "path": "components/avatar/demo/dynamic.ts",
    "content": "import { Component, computed, model, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzAvatarModule } from 'ng-zorro-antd/avatar';\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzInputNumberModule } from 'ng-zorro-antd/input-number';\n\nconst userList = ['Lucy', 'U', 'Tom', 'Edward'];\nconst colorList = ['#f56a00', '#7265e6', '#ffbf00', '#00a2ae'];\n\n@Component({\n  selector: 'nz-demo-avatar-dynamic',\n  imports: [FormsModule, NzAvatarModule, NzButtonModule, NzInputNumberModule],\n  template: `\n    <div>\n      <label>Gap: </label>\n      <nz-input-number [nzMin]=\"0\" [nzMax]=\"16\" [nzStep]=\"1\" [(ngModel)]=\"gap\" />\n      <button nz-button (click)=\"change()\">Change Text</button>\n    </div>\n\n    <nz-avatar [nzGap]=\"gap()\" [nzText]=\"text()\" nzSize=\"large\" [style.background-color]=\"color()\" />\n  `,\n  styles: `\n    div {\n      margin-bottom: 16px;\n    }\n    button {\n      margin-left: 8px;\n    }\n  `\n})\nexport class NzDemoAvatarDynamicComponent {\n  index = signal(3);\n  text = computed(() => userList[this.index()]);\n  color = computed(() => colorList[this.index()]);\n  gap = model(4);\n  change(): void {\n    this.index.update(idx => (idx + 1) % userList.length);\n  }\n}\n"
  },
  {
    "path": "components/avatar/demo/group.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 头像组\n  en-US: Avatar Group\n---\n\n## zh-CN\n\n头像组合展现。\n\n## en-US\n\nAvatar group display.\n"
  },
  {
    "path": "components/avatar/demo/group.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzAvatarModule } from 'ng-zorro-antd/avatar';\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzTooltipModule } from 'ng-zorro-antd/tooltip';\n\n@Component({\n  selector: 'nz-demo-avatar-group',\n  imports: [NzAvatarModule, NzDividerModule, NzTooltipModule, NzIconModule],\n  template: `\n    <nz-avatar-group>\n      <nz-avatar nzIcon=\"user\" nzSrc=\"//zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png\" />\n      <nz-avatar style=\"background-color: #f56a00\" nzText=\"U\" />\n      <nz-avatar style=\"background-color: #87d068\" nz-tooltip nzTooltipTitle=\"NG-ZORRO User\" nzIcon=\"user\" />\n      <nz-avatar style=\"background-color: #1890ff\" nzText=\"NG\" />\n      <nz-avatar [nzSize]=\"32\">\n        <nz-icon nzType=\"ant-design\" nzTheme=\"outline\" />\n      </nz-avatar>\n    </nz-avatar-group>\n    <nz-divider />\n    <nz-avatar-group>\n      <nz-avatar nzIcon=\"user\" nzSrc=\"//zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png\" />\n      <nz-avatar style=\"background-color: #f56a00\" nzText=\"U\" />\n      <nz-avatar style=\"background-color: #fde3cf; color: #f56a00\" nzText=\"+2\" />\n    </nz-avatar-group>\n  `\n})\nexport class NzDemoAvatarGroupComponent {}\n"
  },
  {
    "path": "components/avatar/demo/type.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 类型\n  en-US: Type\n---\n\n## zh-CN\n\n支持三种类型：图片、Icon 以及字符，其中 Icon 和字符型可以自定义图标颜色及背景色。\n\n## en-US\n\nImage, Icon and letter are supported, and the latter two kinds avatar can have custom colors and background colors.\n"
  },
  {
    "path": "components/avatar/demo/type.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzAvatarModule } from 'ng-zorro-antd/avatar';\n\n@Component({\n  selector: 'nz-demo-avatar-type',\n  imports: [NzAvatarModule],\n  template: `\n    <nz-avatar nzIcon=\"user\" />\n    <nz-avatar nzText=\"U\" />\n    <nz-avatar nzText=\"USER\" />\n    <nz-avatar nzIcon=\"user\" nzSrc=\"//zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png\" />\n    <nz-avatar nzText=\"U\" style=\"color:#f56a00; background-color:#fde3cf;\" />\n    <nz-avatar nzIcon=\"user\" style=\"background-color:#87d068;\" />\n  `,\n  styles: `\n    nz-avatar {\n      margin-top: 16px;\n      margin-right: 16px;\n    }\n  `\n})\nexport class NzDemoAvatarTypeComponent {}\n"
  },
  {
    "path": "components/avatar/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Display\ntitle: Avatar\ncover: 'https://gw.alipayobjects.com/zos/antfincdn/aBcnbw68hP/Avatar.svg'\ndescription: Used to represent users or things, supporting the display of images, icons, or characters.\n---\n\n## API\n\n### nz-avatar\n\n| Property            | Description                                                                                                                                                     | Type                                        | Default     | Global Config |\n| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- | ----------- | ------------- |\n| `[nzIcon]`          | The `Icon` type for an icon avatar, see `Icon`                                                                                                                  | `string`                                    | -           |\n| `[nzShape]`         | The shape of avatar                                                                                                                                             | `'circle' \\| 'square'`                      | `'circle'`  | ✅            |\n| `[nzSize]`          | The size of the avatar                                                                                                                                          | `'large' \\| 'small' \\| 'default' \\| number` | `'default'` | ✅            |\n| `[nzGap]`           | Letter type unit distance between left and right sides                                                                                                          | `number`                                    | `4`         | ✅            |\n| `[nzSrc]`           | Avatar image URL                                                                                                                                                | `string`                                    | -           |\n| `[nzSrcSet]`        | a list of sources to use for different screen resolutions                                                                                                       | `string`                                    | -           |\n| `[nzAlt]`           | This attribute defines the alternative text describing the image                                                                                                | `string`                                    | -           |\n| `[nzText]`          | Letter type avatar                                                                                                                                              | `string`                                    | -           |\n| `[nzLoading]`       | Sets the native [`loading`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/img#loading) attribute on the avatar image element             | `'eager' \\| 'lazy'`                         | `'eager'`   |               |\n| `[nzFetchPriority]` | Sets the native [`fetchpriority`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/img#fetchpriority) attribute on the avatar image element | `'high' \\| 'low' \\| 'auto'`                 | `'auto'`    |               |\n| `(nzError)`         | Handler when img load error, call the `preventDefault` method to prevent default fallback behavior                                                              | `EventEmitter<Event>`                       | -           |\n\n### nz-avatar-group\n\n```html\n<nz-avatar-group>\n  <nz-avatar nzIcon=\"user\"></nz-avatar>\n  <!--  ...  -->\n</nz-avatar-group>\n```\n"
  },
  {
    "path": "components/avatar/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 头像\ntype: 数据展示\ntitle: Avatar\ncover: 'https://gw.alipayobjects.com/zos/antfincdn/aBcnbw68hP/Avatar.svg'\ndescription: 用来代表用户或事物，支持图片、图标或字符展示。\n---\n\n## API\n\n### nz-avatar\n\n| 参数                | 说明                                                                                                                                           | 类型                                        | 默认值      | 全局配置 |\n| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- | ----------- | -------- |\n| `[nzIcon]`          | 设置头像的图标类型，参考 `Icon`                                                                                                                | `string`                                    | -           |\n| `[nzShape]`         | 指定头像的形状                                                                                                                                 | `'circle' \\| 'square'`                      | `'circle'`  | ✅       |\n| `[nzSize]`          | 设置头像的大小                                                                                                                                 | `'large' \\| 'small' \\| 'default' \\| number` | `'default'` | ✅       |\n| `[nzGap]`           | 字符类型距离左右两侧边界单位像素                                                                                                               | `number`                                    | `4`         | ✅       |\n| `[nzSrc]`           | 图片类头像的资源地址                                                                                                                           | `string`                                    | -           |\n| `[nzSrcSet]`        | 设置图片类头像响应式资源地址                                                                                                                   | `string`                                    | -           |\n| `[nzAlt]`           | 图像无法显示时的替代文本                                                                                                                       | `string`                                    | -           |\n| `[nzText]`          | 文本类头像                                                                                                                                     | `string`                                    | -           |\n| `[nzLoading]`       | 设置图片类头像 `<img>` 元素原生 [`loading`](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Reference/Elements/img#loading) 属性             | `'eager' \\| 'lazy'`                         | `'eager'`   |          |\n| `[nzFetchPriority]` | 设置图片类头像 `<img>` 元素原生 [`fetchpriority`](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Reference/Elements/img#fetchpriority) 属性 | `'high' \\| 'low' \\| 'auto'`                 | `'auto'`    |          |\n| `(nzError)`         | 图片加载失败的事件，调用 `preventDefault` 方法会阻止组件默认的 fallback 行为                                                                   | `EventEmitter<Event>`                       | -           |\n\n### nz-avatar-group\n\n```html\n<nz-avatar-group>\n  <nz-avatar nzIcon=\"user\"></nz-avatar>\n  <!--  ...  -->\n</nz-avatar-group>\n```\n"
  },
  {
    "path": "components/avatar/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/avatar/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/avatar/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './avatar.component';\nexport * from './avatar-group.component';\nexport * from './avatar.module';\nexport * from './types';\n"
  },
  {
    "path": "components/avatar/style/entry.less",
    "content": "@import './index.less';\n"
  },
  {
    "path": "components/avatar/style/group.less",
    "content": ".@{avatar-prefix-cls}-group {\n  display: inline-flex;\n\n  .@{avatar-prefix-cls} {\n    border: 1px solid @avatar-group-border-color;\n\n    &:not(:first-child) {\n      margin-left: @avatar-group-overlapping;\n    }\n  }\n\n  &-popover {\n    .@{ant-prefix}-avatar + .@{ant-prefix}-avatar {\n      margin-left: @avatar-group-space;\n    }\n  }\n}\n"
  },
  {
    "path": "components/avatar/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@avatar-prefix-cls: ~'@{ant-prefix}-avatar';\n\n.@{avatar-prefix-cls} {\n  .reset-component();\n\n  position: relative;\n  display: inline-block;\n  overflow: hidden;\n  color: @avatar-color;\n  white-space: nowrap;\n  text-align: center;\n  vertical-align: middle;\n  background: @avatar-bg;\n\n  &-image {\n    background: transparent;\n  }\n\n  .@{ant-prefix}-image-img {\n    display: block;\n  }\n\n  .avatar-size(@avatar-size-base, @avatar-font-size-base);\n\n  &-lg {\n    .avatar-size(@avatar-size-lg, @avatar-font-size-lg);\n  }\n\n  &-sm {\n    .avatar-size(@avatar-size-sm, @avatar-font-size-sm);\n  }\n\n  &-square {\n    border-radius: @avatar-border-radius;\n  }\n\n  & > img {\n    display: block;\n    width: 100%;\n    height: 100%;\n    object-fit: cover;\n  }\n}\n\n.avatar-size(@size, @font-size) {\n  width: @size;\n  height: @size;\n  line-height: @size;\n  border-radius: 50%;\n\n  &-string {\n    position: absolute;\n    left: 50%;\n    transform-origin: 0 center;\n  }\n\n  &.@{avatar-prefix-cls}-icon {\n    font-size: @font-size;\n\n    > .@{iconfont-css-prefix} {\n      margin: 0;\n    }\n  }\n}\n\n@import './group';\n@import './rtl';\n"
  },
  {
    "path": "components/avatar/style/rtl.less",
    "content": ".@{avatar-prefix-cls}-group {\n  &-rtl {\n    .@{avatar-prefix-cls}:not(:first-child) {\n      margin-right: @avatar-group-overlapping;\n      margin-left: 0;\n    }\n  }\n\n  &-popover.@{ant-prefix}-popover-rtl {\n    .@{ant-prefix}-avatar + .@{ant-prefix}-avatar {\n      margin-right: @avatar-group-space;\n      margin-left: 0;\n    }\n  }\n}\n"
  },
  {
    "path": "components/avatar/types.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzShapeSCType, NzSizeLDSType } from 'ng-zorro-antd/core/types';\n\nexport interface NzAvatarProps {\n  shape?: NzShapeSCType;\n  size?: NzSizeLDSType | number;\n  gap?: number;\n  src?: string;\n  srcSet?: string;\n  alt?: string;\n  icon?: string;\n  text?: string;\n  error?: (event: Event) => void;\n}\n"
  },
  {
    "path": "components/badge/badge-sup.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  Component,\n  inject,\n  Input,\n  numberAttribute,\n  OnChanges,\n  OnInit,\n  SimpleChanges,\n  TemplateRef,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { NzNoAnimationDirective } from 'ng-zorro-antd/core/animation';\nimport { NgStyleInterface, NzSafeAny, NzSizeDSType } from 'ng-zorro-antd/core/types';\n\n@Component({\n  selector: 'nz-badge-sup',\n  exportAs: 'nzBadgeSup',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  imports: [NzNoAnimationDirective],\n  template: `\n    @if (count <= nzOverflowCount) {\n      @for (n of maxNumberArray; track n; let i = $index) {\n        <span\n          [nzNoAnimation]=\"!!noAnimation?.nzNoAnimation?.()\"\n          class=\"ant-scroll-number-only\"\n          [style.transform]=\"'translateY(' + -countArray[i] * 100 + '%)'\"\n        >\n          @if (!nzDot && countArray[i] !== undefined) {\n            @for (p of countSingleArray; track p) {\n              <p class=\"ant-scroll-number-only-unit\" [class.current]=\"p === countArray[i]\">\n                {{ p }}\n              </p>\n            }\n          }\n        </span>\n      }\n    } @else {\n      {{ nzOverflowCount }}+\n    }\n  `,\n  host: {\n    class: 'ant-scroll-number',\n    '[class]': `isPresetColor ? ('ant-badge-status-' + nzColor) : ''`,\n    '[attr.title]': `nzTitle === null ? '' : nzTitle || nzCount`,\n    '[style]': `nzStyle`,\n    '[style.right.px]': `nzOffset && nzOffset[0] ? -nzOffset[0] : null`,\n    '[style.margin-top.px]': `nzOffset && nzOffset[1] ? nzOffset[1] : null`,\n    '[class.ant-badge-count]': `!nzDot`,\n    '[class.ant-badge-count-sm]': `nzSize === 'small'`,\n    '[class.ant-badge-dot]': `nzDot`,\n    '[class.ant-badge-multiple-words]': `countArray.length >= 2`\n  }\n})\nexport class NzBadgeSupComponent implements OnInit, OnChanges {\n  protected readonly noAnimation = inject(NzNoAnimationDirective, { host: true, optional: true });\n\n  @Input() nzOffset?: [number, number];\n  @Input() nzTitle?: string | null;\n  @Input() nzStyle: NgStyleInterface | null = null;\n  @Input() nzDot = false;\n  @Input({ transform: numberAttribute }) nzOverflowCount = 99;\n  @Input() nzCount?: number | TemplateRef<NzSafeAny>;\n  @Input() nzSize: NzSizeDSType = 'default';\n  @Input({ transform: booleanAttribute }) isPresetColor = false;\n  @Input() nzColor?: string;\n\n  maxNumberArray: string[] = [];\n  countArray: number[] = [];\n  count: number = 0;\n  protected readonly countSingleArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n\n  private generateMaxNumberArray(): void {\n    this.maxNumberArray = this.nzOverflowCount\n      .toString()\n      .split('')\n      .map((value, index) => `${value}-${index}`);\n  }\n\n  ngOnInit(): void {\n    this.generateMaxNumberArray();\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzOverflowCount, nzCount } = changes;\n    if (nzCount && typeof nzCount.currentValue === 'number') {\n      this.count = Math.max(0, nzCount.currentValue);\n      this.countArray = this.count\n        .toString()\n        .split('')\n        .map(item => +item);\n    }\n    if (nzOverflowCount) {\n      this.generateMaxNumberArray();\n    }\n  }\n}\n"
  },
  {
    "path": "components/badge/badge.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  Input,\n  OnChanges,\n  SimpleChanges,\n  TemplateRef,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject\n} from '@angular/core';\n\nimport { withAnimationCheck } from 'ng-zorro-antd/core/animation';\nimport { NzConfigKey, WithConfig } from 'ng-zorro-antd/core/config';\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NgStyleInterface, NzSafeAny, NzSizeDSType } from 'ng-zorro-antd/core/types';\n\nimport { NzBadgeSupComponent } from './badge-sup.component';\nimport { badgePresetColors } from './preset-colors';\nimport { NzBadgeStatusType } from './types';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'badge';\n\n@Component({\n  selector: 'nz-badge',\n  exportAs: 'nzBadge',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  imports: [NzBadgeSupComponent, NzOutletModule],\n  template: `\n    @if ((nzStatus || nzColor) && !showSup && !nzCount) {\n      <span\n        class=\"ant-badge-status-dot\"\n        [class]=\"(nzStatus || presetColor) && 'ant-badge-status-' + (nzStatus || presetColor)\"\n        [style]=\"mergedStyle\"\n      ></span>\n      <span class=\"ant-badge-status-text\">\n        <ng-container *nzStringTemplateOutlet=\"nzText\">{{ nzText }}</ng-container>\n      </span>\n    }\n    <ng-content />\n    <ng-container *nzStringTemplateOutlet=\"nzCount\">\n      @if (showSup) {\n        <nz-badge-sup\n          [isPresetColor]=\"nzStatus || presetColor\"\n          [nzColor]=\"nzStatus || presetColor || nzColor\"\n          [nzOffset]=\"nzOffset\"\n          [nzSize]=\"nzSize\"\n          [nzTitle]=\"nzTitle\"\n          [nzStyle]=\"mergedStyle\"\n          [nzDot]=\"nzDot\"\n          [nzCount]=\"nzCount\"\n          [nzOverflowCount]=\"nzOverflowCount\"\n          [animate.enter]=\"supAnimationEnter()\"\n          [animate.leave]=\"supAnimationLeave()\"\n        />\n      }\n    </ng-container>\n  `,\n  host: {\n    class: 'ant-badge',\n    '[class.ant-badge-status]': 'nzStatus',\n    '[class.ant-badge-not-a-wrapper]': '!!(nzStandalone || ((nzStatus || nzColor) && !showSup && !nzCount))',\n    '[class.ant-badge-rtl]': 'dir() === \"rtl\"'\n  }\n})\nexport class NzBadgeComponent implements OnChanges {\n  protected readonly dir = inject(Directionality).valueSignal;\n\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  protected showSup = false;\n  protected readonly supAnimationEnter = withAnimationCheck(() => 'ant-badge-zoom-enter');\n  protected readonly supAnimationLeave = withAnimationCheck(() => 'ant-badge-zoom-leave');\n  presetColor: string | null = null;\n\n  @Input({ transform: booleanAttribute }) nzShowZero = false;\n  @Input({ transform: booleanAttribute }) nzShowDot = true;\n  @Input({ transform: booleanAttribute }) nzStandalone = false;\n  @Input({ transform: booleanAttribute }) nzDot = false;\n  @Input() @WithConfig() nzOverflowCount: number = 99;\n  @Input() @WithConfig() nzColor?: string;\n  @Input() nzStyle: NgStyleInterface | null = null;\n  @Input() nzText?: string | TemplateRef<void> | null = null;\n  @Input() nzTitle?: string | null | undefined;\n  @Input() nzStatus?: NzBadgeStatusType | string;\n  @Input() nzCount?: number | TemplateRef<NzSafeAny>;\n  @Input() nzOffset?: [number, number];\n  @Input() nzSize: NzSizeDSType = 'default';\n\n  protected get mergedStyle(): NgStyleInterface {\n    return { backgroundColor: !this.presetColor && this.nzColor, ...(this.nzStyle ?? {}) };\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzColor, nzShowDot, nzDot, nzCount, nzShowZero } = changes;\n    if (nzColor) {\n      this.presetColor = this.nzColor && badgePresetColors.indexOf(this.nzColor) !== -1 ? this.nzColor : null;\n    }\n    if (nzShowDot || nzDot || nzCount || nzShowZero) {\n      this.showSup =\n        (this.nzShowDot && this.nzDot) || (typeof this.nzCount === 'number' && (this.nzCount > 0 || this.nzShowZero));\n    }\n  }\n}\n"
  },
  {
    "path": "components/badge/badge.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzBadgeComponent } from './badge.component';\nimport { NzRibbonComponent } from './ribbon.component';\n\n@NgModule({\n  exports: [NzBadgeComponent, NzRibbonComponent],\n  imports: [NzBadgeComponent, NzRibbonComponent]\n})\nexport class NzBadgeModule {}\n"
  },
  {
    "path": "components/badge/badge.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Direction } from '@angular/cdk/bidi';\nimport { Component, DebugElement, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { NzNoAnimationDirective, provideNzNoAnimation } from 'ng-zorro-antd/core/animation';\nimport { NgStyleInterface, NzSizeDSType } from 'ng-zorro-antd/core/types';\n\nimport { NzBadgeComponent } from './badge.component';\nimport { NzBadgeModule } from './badge.module';\nimport { badgePresetColors } from './preset-colors';\nimport { NzRibbonComponent } from './ribbon.component';\nimport { NzBadgeStatusType } from './types';\n\ndescribe('badge', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzNoAnimation(), provideZoneChangeDetection()]\n    });\n  });\n\n  describe('basic', () => {\n    let fixture: ComponentFixture<NzTestBadgeBasicComponent>;\n    let testComponent: NzTestBadgeBasicComponent;\n    let badgeElement: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestBadgeBasicComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n      badgeElement = fixture.debugElement.query(By.directive(NzBadgeComponent));\n    });\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.classList).toContain('ant-badge');\n    });\n\n    it('should count work', () => {\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.querySelector('nz-badge-sup').classList).toContain('ant-scroll-number');\n      expect(badgeElement.nativeElement.querySelector('nz-badge-sup').classList).toContain('ant-badge-count');\n      expect(badgeElement.nativeElement.querySelector('nz-badge-sup').classList).not.toContain(\n        'ant-badge-multiple-words'\n      );\n      expect(badgeElement.nativeElement.querySelector('.current').innerText).toBe('5');\n      testComponent.count = 10;\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.querySelector('nz-badge-sup').classList).toContain('ant-badge-multiple-words');\n      expect(badgeElement.nativeElement.querySelectorAll('.current')[0].innerText).toBe('1');\n      expect(badgeElement.nativeElement.querySelectorAll('.current')[1].innerText).toBe('0');\n    });\n\n    it('should title work', () => {\n      testComponent.overflow = 99;\n      testComponent.count = 1000;\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.querySelector('nz-badge-sup').getAttribute('title')).toBe('1000');\n      testComponent.title = 'test';\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.querySelector('nz-badge-sup').getAttribute('title')).toBe('test');\n    });\n\n    it('should be no title attribute when `nzTitle` is null', () => {\n      testComponent.title = null;\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.querySelector('nz-badge-sup').getAttribute('title')).toBeFalsy();\n    });\n\n    it('should offset work', () => {\n      testComponent.offset = [10, 10];\n      fixture.detectChanges();\n      const style = getComputedStyle(badgeElement.nativeElement.querySelector('nz-badge-sup'));\n      expect(style.right).toBe('-10px');\n      expect(style.marginTop).toBe('10px');\n    });\n\n    it('should overflow work', () => {\n      testComponent.overflow = 4;\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.querySelector('nz-badge-sup').innerText).toBe('4+');\n      testComponent.overflow = 99;\n      testComponent.count = 100;\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.querySelector('nz-badge-sup').innerText).toBe('99+');\n      testComponent.overflow = 99;\n      testComponent.count = 99;\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.querySelector('nz-badge-sup').innerText).not.toBe('99+');\n    });\n\n    it('should showZero work', fakeAsync(() => {\n      testComponent.count = 0;\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.querySelector('nz-badge-sup')).toBeNull();\n      testComponent.showZero = true;\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.querySelector('.current').innerText).toBe('0');\n    }));\n\n    it('should negative number not display', fakeAsync(() => {\n      testComponent.count = -10;\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.querySelector('nz-badge-sup')).toBeNull();\n      testComponent.showZero = true;\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.querySelector('.current').innerText).toBe('0');\n    }));\n\n    it('should dot work', () => {\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.querySelector('nz-badge-sup').classList).not.toContain('ant-badge-dot');\n      testComponent.dot = true;\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.querySelector('nz-badge-sup').classList).toContain('ant-badge-dot');\n    });\n\n    it('should no wrapper work', fakeAsync(() => {\n      testComponent.standalone = true;\n      testComponent.style = { backgroundColor: '#52c41a' };\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n      badgeElement = fixture.debugElement.query(By.directive(NzBadgeComponent));\n      expect(badgeElement.nativeElement.classList).toContain('ant-badge-not-a-wrapper');\n      expect(badgeElement.nativeElement.querySelector('nz-badge-sup').style.backgroundColor).toBe('rgb(82, 196, 26)');\n    }));\n\n    it('should disable animation for inner elements when `noAnimation` is `true` ', fakeAsync(() => {\n      testComponent.noAnimation = true;\n      fixture.detectChanges();\n      tick(1000);\n      expect(badgeElement.nativeElement.classList).toContain('nz-animate-disabled');\n      expect(badgeElement.nativeElement.querySelector('nz-badge-sup .ant-scroll-number-only').classList).toContain(\n        'nz-animate-disabled'\n      );\n      fixture.detectChanges();\n    }));\n\n    it('should status work', () => {\n      testComponent.standalone = true;\n      testComponent.count = 0;\n      const statusList = ['success', 'processing', 'default', 'error', 'warning'];\n      statusList.forEach(status => {\n        testComponent.status = status;\n        fixture.detectChanges();\n        expect(badgeElement.nativeElement.querySelector('.ant-badge-status-dot').classList).toContain(\n          `ant-badge-status-${status}`\n        );\n      });\n      testComponent.text = 'test';\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.querySelector('.ant-badge-status-text').innerText).toBe('test');\n    });\n\n    it('should size work', () => {\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.querySelector('nz-badge-sup').classList).toContain('ant-badge-count');\n      testComponent.size = 'small';\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.querySelector('nz-badge-sup').classList).toContain('ant-badge-count-sm');\n    });\n\n    it('should set presetColor of nzColor change', () => {\n      const color = badgePresetColors[0];\n      const component: NzBadgeComponent = badgeElement.componentInstance;\n\n      testComponent.color = color;\n      fixture.detectChanges();\n      expect(component.presetColor).toEqual(color);\n\n      testComponent.color = undefined;\n      fixture.detectChanges();\n      expect(component.presetColor).toEqual(null);\n    });\n\n    it('should display correct of nzColor related change', fakeAsync(() => {\n      let color: string | undefined;\n      testComponent.standalone = true;\n      testComponent.count = 0;\n      testComponent.status = 'success';\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.classList).toContain('ant-badge-not-a-wrapper');\n      expect(badgeElement.nativeElement.querySelector('.ant-badge-status-dot').classList).toContain(\n        `ant-badge-status-success`\n      );\n      expect(badgeElement.nativeElement.querySelector('.ant-badge-status-text').innerText).toBe('');\n      expect(badgeElement.nativeElement.querySelector('nz-badge-sup')).toBeNull();\n\n      testComponent.status = '';\n      testComponent.text = 'test';\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.classList).toContain('ant-badge-not-a-wrapper');\n      expect(badgeElement.nativeElement.querySelector('.ant-badge-status-dot')).toBeNull();\n      expect(badgeElement.nativeElement.querySelector('.ant-badge-status-text')).toBeNull();\n      expect(badgeElement.nativeElement.querySelector('nz-badge-sup')).toBeNull();\n\n      color = 'blue';\n      testComponent.color = color;\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.classList).toContain('ant-badge-not-a-wrapper');\n      expect(badgeElement.nativeElement.querySelector('.ant-badge-status-dot').classList).toContain(\n        `ant-badge-status-${color}`\n      );\n      expect(badgeElement.nativeElement.querySelector('.ant-badge-status-text').innerText).toBe('test');\n      expect(badgeElement.nativeElement.querySelector('nz-badge-sup')).toBeNull();\n\n      testComponent.standalone = false;\n      color = '#f5222d';\n      testComponent.color = color;\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.classList).toContain('ant-badge-not-a-wrapper');\n      expect(badgeElement.nativeElement.querySelector('.ant-badge-status-dot').classList).not.toContain(\n        `ant-badge-status-`\n      );\n      expect(badgeElement.nativeElement.querySelector('.ant-badge-status-dot').style.backgroundColor).toBe(\n        'rgb(245, 34, 45)'\n      );\n      expect(badgeElement.nativeElement.querySelector('.ant-badge-status-text').innerText).toBe('test');\n      expect(badgeElement.nativeElement.querySelector('nz-badge-sup')).toBeNull();\n\n      testComponent.text = '';\n      testComponent.showZero = true;\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.classList).not.toContain('ant-badge-not-a-wrapper');\n      expect(badgeElement.nativeElement.querySelector('.ant-badge-status-dot')).toBeNull();\n      expect(badgeElement.nativeElement.querySelector('.ant-badge-status-text')).toBeNull();\n\n      testComponent.count = 5;\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.classList).not.toContain('ant-badge-not-a-wrapper');\n      expect(badgeElement.nativeElement.querySelector('.ant-badge-status-dot')).toBeNull();\n      expect(badgeElement.nativeElement.querySelector('.ant-badge-status-text')).toBeNull();\n    }));\n\n    it('should hex nzColor work', () => {\n      testComponent.count = 0;\n      testComponent.color = '#f5222d';\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.querySelector('.ant-badge-status-dot').style.backgroundColor).toBe(\n        'rgb(245, 34, 45)'\n      );\n\n      testComponent.count = 5;\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.querySelector('nz-badge-sup').style.backgroundColor).toBe('rgb(245, 34, 45)');\n    });\n\n    it('should nzStyle work even if nzColor is not provided', () => {\n      testComponent.color = undefined;\n      testComponent.status = 'success'; // must set nzStatus to make sure status dot is rendered\n      testComponent.style = { backgroundColor: '#52c41a' };\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.querySelector('nz-badge-sup').style.backgroundColor).toBe('rgb(82, 196, 26)');\n\n      testComponent.standalone = true;\n      testComponent.count = 0;\n      fixture.detectChanges();\n      expect(badgeElement.nativeElement.querySelector('.ant-badge-status-dot').style.backgroundColor).toBe(\n        'rgb(82, 196, 26)'\n      );\n    });\n  });\n\n  describe('ribbon', () => {\n    let fixture: ComponentFixture<NzRibbonComponent>;\n    let component: NzRibbonComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzRibbonComponent);\n      component = fixture.componentInstance;\n    });\n\n    it('default value for nzPlacement', () => {\n      expect(component.nzPlacement).toEqual('end');\n    });\n\n    it('default value for nzText', () => {\n      expect(component.nzText).toEqual(null);\n    });\n\n    it('default value for presetColor', () => {\n      expect(component.presetColor).toEqual(null);\n    });\n\n    it('should set presetColor on nzColor change', async () => {\n      const color = badgePresetColors[0];\n      fixture.componentRef.setInput('nzColor', color);\n      fixture.detectChanges();\n      await fixture.whenStable();\n      expect(component.presetColor).toEqual(color);\n\n      fixture.componentRef.setInput('nzColor', undefined);\n      fixture.detectChanges();\n      await fixture.whenStable();\n      expect(component.presetColor).toEqual(null);\n    });\n  });\n\n  describe('RTL', () => {\n    let fixture: ComponentFixture<NzTestBadgeRtlComponent>;\n    let badge: DebugElement;\n    let badgeElement: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestBadgeRtlComponent);\n      badge = fixture.debugElement.query(By.directive(NzBadgeComponent));\n      fixture.detectChanges();\n      badgeElement = badge.nativeElement;\n    });\n\n    it('should pagination className correct on dir change', () => {\n      fixture.detectChanges();\n      expect(badgeElement.classList).toContain('ant-badge-rtl');\n\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n      expect(badgeElement.classList).not.toContain('ant-badge-rtl');\n    });\n  });\n});\n\n@Component({\n  imports: [NzNoAnimationDirective, NzBadgeModule],\n  template: `\n    <nz-badge\n      [nzCount]=\"count\"\n      [nzStatus]=\"status\"\n      [nzText]=\"text\"\n      [nzShowZero]=\"showZero\"\n      [nzOverflowCount]=\"overflow\"\n      [nzNoAnimation]=\"noAnimation\"\n      [nzStyle]=\"style\"\n      [nzDot]=\"dot\"\n      [nzOffset]=\"offset\"\n      [nzTitle]=\"title\"\n      [nzStandalone]=\"standalone\"\n      [nzSize]=\"size\"\n      [nzColor]=\"color\"\n    >\n      @if (!standalone) {\n        <a></a>\n      }\n    </nz-badge>\n  `\n})\nexport class NzTestBadgeBasicComponent {\n  count = 5;\n  dot = false;\n  standalone = false;\n  overflow = 20;\n  showZero = false;\n  status!: NzBadgeStatusType | string;\n  style!: NgStyleInterface;\n  text!: string;\n  title?: string | null;\n  offset?: [number, number];\n  size: NzSizeDSType = 'default';\n  noAnimation = true;\n  color?: string;\n}\n\n@Component({\n  imports: [BidiModule, NzBadgeModule],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-badge [nzCount]=\"count\" />\n    </div>\n  `\n})\nexport class NzTestBadgeRtlComponent {\n  direction: Direction = 'rtl';\n  count = 5;\n}\n"
  },
  {
    "path": "components/badge/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n简单的徽章展示，当 `nzCount` 为 `0` 时，默认不显示，但是可以使用 `nzShowZero` 修改为显示。\n\n## en-US\n\nSimplest Usage. Badge will be hidden when `nzCount` is `0`, but we can use `nzShowZero` to show it.\n"
  },
  {
    "path": "components/badge/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzBadgeModule } from 'ng-zorro-antd/badge';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-demo-badge-basic',\n  imports: [NzBadgeModule, NzIconModule],\n  template: `\n    <nz-badge [nzCount]=\"5\">\n      <a class=\"head-example\"></a>\n    </nz-badge>\n    <nz-badge [nzCount]=\"0\" nzShowZero>\n      <a class=\"head-example\"></a>\n    </nz-badge>\n    <nz-badge [nzCount]=\"iconTemplate\">\n      <a class=\"head-example\"></a>\n    </nz-badge>\n    <ng-template #iconTemplate>\n      <nz-icon nzType=\"clock-circle\" class=\"ant-scroll-number-custom-component\" style=\"color: #f5222d\" />\n    </ng-template>\n  `,\n  styles: `\n    nz-badge {\n      margin-right: 20px;\n    }\n\n    .head-example {\n      width: 42px;\n      height: 42px;\n      border-radius: 4px;\n      background: #eee;\n      display: inline-block;\n      vertical-align: middle;\n    }\n  `\n})\nexport class NzDemoBadgeBasicComponent {}\n"
  },
  {
    "path": "components/badge/demo/colorful.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 多彩徽标\n  en-US: Colorful Badge\n---\n\n## zh-CN\n\n我们添加了多种预设色彩的徽标样式，用作不同场景使用。如果预设值不能满足你的需求，可以设置为具体的色值。\n\n## en-US\n\nWe preset a series of colorful Badge style for different situation usage.\nAnd you can always set it to a hex color string for custom color.\n"
  },
  {
    "path": "components/badge/demo/colorful.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzBadgeModule } from 'ng-zorro-antd/badge';\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\n\n@Component({\n  selector: 'nz-demo-badge-colorful',\n  imports: [NzBadgeModule, NzDividerModule],\n  template: `\n    <nz-divider nzOrientation=\"left\" nzText=\"Presets\" />\n    @for (color of presets; track color) {\n      <div>\n        <nz-badge [nzColor]=\"color\" [nzText]=\"color\" />\n      </div>\n    }\n\n    <nz-divider nzOrientation=\"left\" nzText=\"Custom\" />\n    @for (color of customColors; track color) {\n      <div>\n        <nz-badge [nzColor]=\"color\" [nzText]=\"color\" />\n      </div>\n    }\n  `\n})\nexport class NzDemoBadgeColorfulComponent {\n  readonly presets = [\n    'pink',\n    'red',\n    'yellow',\n    'orange',\n    'cyan',\n    'green',\n    'blue',\n    'purple',\n    'geekblue',\n    'magenta',\n    'volcano',\n    'gold',\n    'lime'\n  ];\n  readonly customColors = ['#f50', '#2db7f5', '#87d068', '#108ee9'];\n}\n"
  },
  {
    "path": "components/badge/demo/dot.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 讨嫌的小红点\n  en-US: Red badge\n---\n\n## zh-CN\n\n没有具体的数字。\n\n## en-US\n\nThis will simply display a red badge, without a specific count.\n"
  },
  {
    "path": "components/badge/demo/dot.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzBadgeModule } from 'ng-zorro-antd/badge';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-demo-badge-dot',\n  imports: [NzBadgeModule, NzIconModule],\n  template: `\n    <nz-badge nzDot>\n      <nz-icon nzType=\"notification\" />\n    </nz-badge>\n    <nz-badge nzDot>\n      <a>Link something</a>\n    </nz-badge>\n  `,\n  styles: `\n    nz-badge {\n      margin-right: 20px;\n    }\n\n    nz-icon {\n      font-size: 16px;\n    }\n  `\n})\nexport class NzDemoBadgeDotComponent {}\n"
  },
  {
    "path": "components/badge/demo/dynamic.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 动态\n  en-US: Dynamic\n---\n\n## zh-CN\n\n展示动态变化的效果。\n\n## en-US\n\nThe count will be animated as it changes.\n"
  },
  {
    "path": "components/badge/demo/dynamic.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzBadgeModule } from 'ng-zorro-antd/badge';\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzFlexModule } from 'ng-zorro-antd/flex';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\n\n@Component({\n  selector: 'nz-demo-badge-dynamic',\n  imports: [FormsModule, NzBadgeModule, NzButtonModule, NzFlexModule, NzIconModule, NzSwitchModule, NzSpaceModule],\n  template: `\n    <div nz-flex nzVertical nzGap=\"middle\">\n      <div nz-flex nzGap=\"large\" nzAlign=\"center\">\n        <nz-badge [nzCount]=\"count\">\n          <a class=\"head-example\"></a>\n        </nz-badge>\n        <nz-space-compact>\n          <button nz-button (click)=\"minusCount()\"><nz-icon nzType=\"minus\" /></button>\n          <button nz-button (click)=\"addCount()\"><nz-icon nzType=\"plus\" /></button>\n          <button nz-button (click)=\"random()\"><nz-icon nzType=\"question\" /></button>\n        </nz-space-compact>\n      </div>\n      <div nz-flex nzGap=\"large\" nzAlign=\"center\">\n        <nz-badge [nzDot]=\"dot\">\n          <a class=\"head-example\"></a>\n        </nz-badge>\n        <nz-switch [(ngModel)]=\"dot\" />\n      </div>\n    </div>\n  `,\n  styles: `\n    .head-example {\n      width: 42px;\n      height: 42px;\n      border-radius: 4px;\n      background: #eee;\n      display: inline-block;\n      vertical-align: middle;\n    }\n  `\n})\nexport class NzDemoBadgeDynamicComponent {\n  count = 5;\n  dot = true;\n\n  addCount(): void {\n    this.count++;\n  }\n\n  minusCount(): void {\n    this.count = Math.max(0, this.count - 1);\n  }\n\n  random(): void {\n    this.count = Math.floor(Math.random() * 100);\n  }\n}\n"
  },
  {
    "path": "components/badge/demo/link.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 可点击\n  en-US: Clickable\n---\n\n## zh-CN\n\n用 `a` 标签进行包裹即可。\n\n## en-US\n\nThe badge can be wrapped with `a` tag to make it linkable.\n"
  },
  {
    "path": "components/badge/demo/link.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzBadgeModule } from 'ng-zorro-antd/badge';\n\n@Component({\n  selector: 'nz-demo-badge-link',\n  imports: [NzBadgeModule],\n  template: `\n    <a>\n      <nz-badge [nzCount]=\"5\">\n        <a class=\"head-example\"></a>\n      </nz-badge>\n    </a>\n  `,\n  styles: `\n    .head-example {\n      width: 42px;\n      height: 42px;\n      border-radius: 4px;\n      background: #eee;\n      display: inline-block;\n      vertical-align: middle;\n    }\n  `\n})\nexport class NzDemoBadgeLinkComponent {}\n"
  },
  {
    "path": "components/badge/demo/no-wrapper.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 独立使用\n  en-US: Standalone\n---\n\n## zh-CN\n\n不包裹任何元素，增加 `nzStandalone`标签后，即是独立使用，可自定样式展现。\n\n> 在右上角的 badge 则限定为红色。\n\n## en-US\n\nAdd `nzStandalone` when there are no children.\n"
  },
  {
    "path": "components/badge/demo/no-wrapper.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzBadgeModule } from 'ng-zorro-antd/badge';\nimport { NzFlexModule } from 'ng-zorro-antd/flex';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\n\n@Component({\n  selector: 'nz-demo-badge-no-wrapper',\n  imports: [FormsModule, NzBadgeModule, NzFlexModule, NzIconModule, NzSwitchModule],\n  template: `\n    <nz-flex nzGap=\"small\" nzAlign=\"center\">\n      <nz-switch [(ngModel)]=\"show\" />\n      <nz-badge nzStandalone nzShowZero [nzCount]=\"show ? 11 : 0\" [nzStyle]=\"{ backgroundColor: '#faad14' }\" />\n      <nz-badge nzStandalone [nzCount]=\"show ? 25 : 0\" />\n      <nz-badge nzStandalone [nzCount]=\"show ? iconTemplate : 0\" />\n      <nz-badge nzStandalone [nzCount]=\"show ? 109 : 0\" [nzStyle]=\"{ backgroundColor: '#52c41a' }\" />\n    </nz-flex>\n\n    <ng-template #iconTemplate>\n      <nz-icon nzType=\"clock-circle\" class=\"ant-scroll-number-custom-component\" style=\"color: #f5222d\" />\n    </ng-template>\n  `\n})\nexport class NzDemoBadgeNoWrapperComponent {\n  show = true;\n}\n"
  },
  {
    "path": "components/badge/demo/offset.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 自定义位置偏移\n  en-US: Offset\n---\n\n## zh-CN\n\n设置状态点的位置偏移，格式为 `[left, top]`，表示状态点距默认位置左侧、上方的偏移量。\n\n## en-US\n\nSet offset of the badge dot, the format is `[left, top]`, which represents the offset of the status dot from the left and top of the default position.\n"
  },
  {
    "path": "components/badge/demo/offset.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzBadgeModule } from 'ng-zorro-antd/badge';\n\n@Component({\n  selector: 'nz-demo-badge-offset',\n  imports: [NzBadgeModule],\n  template: `\n    <a>\n      <nz-badge [nzCount]=\"5\" [nzOffset]=\"[10, 10]\">\n        <a class=\"head-example\"></a>\n      </nz-badge>\n    </a>\n  `,\n  styles: `\n    .head-example {\n      width: 42px;\n      height: 42px;\n      border-radius: 4px;\n      background: #eee;\n      display: inline-block;\n      vertical-align: middle;\n    }\n  `\n})\nexport class NzDemoBadgeOffsetComponent {}\n"
  },
  {
    "path": "components/badge/demo/overflow.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 封顶数字\n  en-US: Overflow Count\n---\n\n## zh-CN\n\n超过 `nzOverflowCount` 的会显示为 `nzOverflowCount+`，默认的 `nzOverflowCount` 为 `99`。\n\n## en-US\n\n`nzOverflowCount+` is displayed when count is larger than `nzOverflowCount`. The default value of `nzOverflowCount` is `99`.\n"
  },
  {
    "path": "components/badge/demo/overflow.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzBadgeModule } from 'ng-zorro-antd/badge';\n\n@Component({\n  selector: 'nz-demo-badge-overflow',\n  imports: [NzBadgeModule],\n  template: `\n    <nz-badge [nzCount]=\"99\">\n      <a class=\"head-example\"></a>\n    </nz-badge>\n    <nz-badge [nzCount]=\"200\">\n      <a class=\"head-example\"></a>\n    </nz-badge>\n    <nz-badge [nzCount]=\"200\" [nzOverflowCount]=\"10\">\n      <a class=\"head-example\"></a>\n    </nz-badge>\n    <nz-badge [nzCount]=\"10000\" [nzOverflowCount]=\"999\">\n      <a class=\"head-example\"></a>\n    </nz-badge>\n  `,\n  styles: `\n    nz-badge {\n      margin-right: 20px;\n    }\n\n    .head-example {\n      width: 42px;\n      height: 42px;\n      border-radius: 4px;\n      background: #eee;\n      display: inline-block;\n      vertical-align: middle;\n    }\n  `\n})\nexport class NzDemoBadgeOverflowComponent {}\n"
  },
  {
    "path": "components/badge/demo/ribbon.md",
    "content": "---\norder: 10\ntitle:\n  zh-CN: 缎带\n  en-US: Ribbon\n---\n\n## zh-CN\n\n使用缎带型的徽标。\n\n## en-US\n\nUse ribbon badge.\n"
  },
  {
    "path": "components/badge/demo/ribbon.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzBadgeModule } from 'ng-zorro-antd/badge';\nimport { NzCardModule } from 'ng-zorro-antd/card';\n\n@Component({\n  selector: 'nz-demo-badge-ribbon',\n  imports: [NzBadgeModule, NzCardModule],\n  template: `\n    <nz-ribbon nzText=\"Hippies\">\n      <nz-card nzTitle=\"Pushes open the window\" nzSize=\"small\"> And raises the spyglass. </nz-card>\n    </nz-ribbon>\n    <br />\n    <nz-ribbon nzText=\"Hippies\" nzColor=\"pink\">\n      <nz-card nzTitle=\"Pushes open the window\" nzSize=\"small\"> And raises the spyglass. </nz-card>\n    </nz-ribbon>\n    <br />\n    <nz-ribbon nzText=\"Hippies\" nzColor=\"red\">\n      <nz-card nzTitle=\"Pushes open the window\" nzSize=\"small\"> And raises the spyglass. </nz-card>\n    </nz-ribbon>\n    <br />\n    <nz-ribbon nzText=\"Hippies\" nzColor=\"cyan\">\n      <nz-card nzTitle=\"Pushes open the window\" nzSize=\"small\"> And raises the spyglass. </nz-card>\n    </nz-ribbon>\n    <br />\n    <nz-ribbon nzText=\"Hippies\" nzColor=\"green\">\n      <nz-card nzTitle=\"Pushes open the window\" nzSize=\"small\"> And raises the spyglass. </nz-card>\n    </nz-ribbon>\n    <br />\n    <nz-ribbon nzText=\"Hippies\" nzColor=\"purple\">\n      <nz-card nzTitle=\"Pushes open the window\" nzSize=\"small\"> And raises the spyglass. </nz-card>\n    </nz-ribbon>\n    <br />\n    <nz-ribbon nzText=\"Hippies\" nzColor=\"volcano\">\n      <nz-card nzTitle=\"Pushes open the window\" nzSize=\"small\"> And raises the spyglass. </nz-card>\n    </nz-ribbon>\n    <br />\n    <nz-ribbon nzText=\"Hippies\" nzColor=\"magenta\">\n      <nz-card nzTitle=\"Pushes open the window\" nzSize=\"small\"> And raises the spyglass. </nz-card>\n    </nz-ribbon>\n  `\n})\nexport class NzDemoBadgeRibbonComponent {}\n"
  },
  {
    "path": "components/badge/demo/size.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 大小\n  en-US: Size\n---\n\n## zh-CN\n\n可以设置有数字徽标的大小。\n\n## en-US\n\nSet size of numeral Badge.\n"
  },
  {
    "path": "components/badge/demo/size.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzBadgeModule } from 'ng-zorro-antd/badge';\n\n@Component({\n  selector: 'nz-demo-badge-size',\n  imports: [NzBadgeModule],\n  template: `\n    <nz-badge nzSize=\"default\" [nzCount]=\"5\">\n      <a class=\"head-example\"></a>\n    </nz-badge>\n    <nz-badge nzSize=\"small\" [nzCount]=\"5\">\n      <a class=\"head-example\"></a>\n    </nz-badge>\n  `,\n  styles: `\n    nz-badge {\n      margin-right: 20px;\n    }\n\n    .head-example {\n      width: 42px;\n      height: 42px;\n      border-radius: 4px;\n      background: #eee;\n      display: inline-block;\n      vertical-align: middle;\n    }\n  `\n})\nexport class NzDemoBadgeSizeComponent {}\n"
  },
  {
    "path": "components/badge/demo/status.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 状态点\n  en-US: Status\n---\n\n## zh-CN\n\n用于表示状态的小圆点。\n\n## en-US\n\nStandalone badge with status.\n"
  },
  {
    "path": "components/badge/demo/status.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzBadgeModule } from 'ng-zorro-antd/badge';\n\n@Component({\n  selector: 'nz-demo-badge-status',\n  imports: [NzBadgeModule],\n  template: `\n    <nz-badge nzStatus=\"success\" />\n    <nz-badge nzStatus=\"error\" />\n    <nz-badge nzStatus=\"default\" />\n    <nz-badge nzStatus=\"processing\" />\n    <nz-badge nzStatus=\"warning\" />\n    <br />\n    <nz-badge nzStatus=\"success\" nzText=\"Success\" />\n    <br />\n    <nz-badge nzStatus=\"error\" nzText=\"Error\" />\n    <br />\n    <nz-badge nzStatus=\"default\" nzText=\"Default\" />\n    <br />\n    <nz-badge nzStatus=\"processing\" nzText=\"Processing\" />\n    <br />\n    <nz-badge nzStatus=\"warning\" nzText=\"Warning\" />\n    <br />\n  `\n})\nexport class NzDemoBadgeStatusComponent {}\n"
  },
  {
    "path": "components/badge/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Display\ntitle: Badge\ncover: 'https://gw.alipayobjects.com/zos/antfincdn/6%26GF9WHwvY/Badge.svg'\ndescription: Small numerical value or status descriptor for UI elements.\n---\n\n## When To Use\n\nBadge normally appears in proximity to notifications or user avatars with eye-catching appeal, typically displaying\nunread messages count.\n\n## API\n\n### nz-badge\n\n| Property            | Description                                                                                | Type                                                             | Default     | Global Config |\n| ------------------- | ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------- | ----------- | ------------- |\n| `[nzStandalone]`    | Whether standalone mode                                                                    | `boolean`                                                        | -           | -             |\n| `[nzColor]`         | Customize Badge dot color                                                                  | `string`                                                         | -           | ✅            |\n| `[nzCount]`         | Number to show in badge                                                                    | `number \\| TemplateRef<void>`                                    | -           |\n| `[nzDot]`           | Whether to display a red dot instead of `count`                                            | `boolean`                                                        | `false`     |\n| `[nzShowDot]`       | Whether to display the red dot                                                             | `boolean`                                                        | `true`      |\n| `[nzOverflowCount]` | Max count to show                                                                          | `number`                                                         | `99`        | ✅            |\n| `[nzShowZero]`      | Whether to show badge when `count` is zero                                                 | `boolean`                                                        | `false`     |\n| `[nzSize]`          | If `nzCount` is set, `size` sets the size of badge                                         | `'default' \\| 'small'`                                           | `'default'` |\n| `[nzStatus]`        | Set `nz-badge` as a status dot                                                             | `'success' \\| 'processing' \\| 'default' \\| 'error' \\| 'warning'` | -           |\n| `[nzText]`          | If `nzStatus` is set, `text` sets the display text of the status `dot`                     | `string \\| TemplateRef<void>`                                    | -           |\n| `[nzTitle]`         | Text to show when hovering over the badge（Only Non-standalone), hide when value is `null` | `string \\| null`                                                 | `nzCount`   |\n| `[nzOffset]`        | set offset of the badge dot, like `[x, y]` (Only Non-standalone)                           | `[number, number]`                                               | -           |\n\n### nz-ribbon\n\n| Property        | Description                 | Type                          | Default |\n| --------------- | --------------------------- | ----------------------------- | ------- |\n| `[nzColor]`     | Customize Ribbon color      | `string`                      | -       |\n| `[nzPlacement]` | The placement of the Ribbon | `'start' \\| 'end'`            | `'end'` |\n| `[nzText]`      | Content inside the Ribbon   | `string \\| TemplateRef<void>` | -       |\n"
  },
  {
    "path": "components/badge/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 徽标数\ntype: 数据展示\ntitle: Badge\ncover: 'https://gw.alipayobjects.com/zos/antfincdn/6%26GF9WHwvY/Badge.svg'\ndescription: 图标右上角的圆形徽标数字。\n---\n\n## 何时使用\n\n一般出现在通知图标或头像的右上角，用于显示需要处理的消息条数，通过醒目视觉形式吸引用户处理。\n\n## API\n\n### nz-badge\n\n| 参数                | 说明                                                                         | 类型                                                             | 默认值      | 全局配置 |\n| ------------------- | ---------------------------------------------------------------------------- | ---------------------------------------------------------------- | ----------- | -------- |\n| `[nzStandalone]`    | 是否独立使用                                                                 | `boolean`                                                        | -           | -        |\n| `[nzColor]`         | 自定义小圆点的颜色                                                           | `string`                                                         | -           | ✅       |\n| `[nzCount]`         | 展示的数字，大于 nzOverflowCount 时显示为 `${nzOverflowCount}+`，为 0 时隐藏 | `number \\| TemplateRef<void>`                                    | -           |\n| `[nzDot]`           | 不展示数字，只有一个小红点                                                   | `boolean`                                                        | `false`     |\n| `[nzShowDot]`       | 是否展示小红点                                                               | `boolean`                                                        | `true`      |\n| `[nzOverflowCount]` | 展示封顶的数字值                                                             | `number`                                                         | `99`        | ✅       |\n| `[nzShowZero]`      | 当数值为 0 时，是否展示 Badge                                                | `boolean`                                                        | `false`     |\n| `[nzSize]`          | 在设置了 `nzCount` 的前提下有效，设置小圆点的大小                            | `'default' \\| 'small'`                                           | `'default'` |\n| `[nzStatus]`        | 设置 `nz-badge` 为状态点                                                     | `'success' \\| 'processing' \\| 'default' \\| 'error' \\| 'warning'` | -           |\n| `[nzText]`          | 在设置了 `nzStatus` 的前提下有效，设置状态点的文本                           | `string \\| TemplateRef<void>`                                    | -           |\n| `[nzTitle]`         | 设置鼠标放在状态点上时显示的文字 (非独立使用时), 为 `null` 时隐藏            | `string \\| null`                                                 | `nzCount`   |\n| `[nzOffset]`        | 设置状态点的位置偏移，格式为 `[x, y]` (非独立使用时)                         | `[number, number]`                                               | -           |\n\n### nz-ribbon\n\n| 参数            | 说明             | 类型                          | 默认值  |\n| --------------- | ---------------- | ----------------------------- | ------- |\n| `[nzColor]`     | 自定义缎带的颜色 | `string`                      | -       |\n| `[nzPlacement]` | 缎带的位置       | `'start' \\| 'end'`            | `'end'` |\n| `[nzText]`      | 缎带中填入的内容 | `string \\| TemplateRef<void>` | -       |\n"
  },
  {
    "path": "components/badge/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/badge/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/badge/preset-colors.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport const badgePresetColors: readonly string[] = [\n  'pink',\n  'red',\n  'yellow',\n  'orange',\n  'cyan',\n  'green',\n  'blue',\n  'purple',\n  'geekblue',\n  'magenta',\n  'volcano',\n  'gold',\n  'lime'\n];\n"
  },
  {
    "path": "components/badge/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './badge.component';\nexport * from './ribbon.component';\nexport * from './badge.module';\nexport * from './types';\n"
  },
  {
    "path": "components/badge/ribbon.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  Input,\n  OnChanges,\n  SimpleChanges,\n  TemplateRef,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\n\nimport { badgePresetColors } from './preset-colors';\n\n@Component({\n  selector: 'nz-ribbon',\n  exportAs: 'nzRibbon',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  imports: [NzOutletModule],\n  template: `\n    <ng-content />\n    <div\n      class=\"ant-ribbon\"\n      [class]=\"presetColor && 'ant-ribbon-color-' + presetColor\"\n      [class.ant-ribbon-placement-end]=\"nzPlacement === 'end'\"\n      [class.ant-ribbon-placement-start]=\"nzPlacement === 'start'\"\n      [style.background-color]=\"!presetColor && nzColor\"\n    >\n      <ng-container *nzStringTemplateOutlet=\"nzText\">\n        <span class=\"ant-ribbon-text\">{{ nzText }}</span>\n      </ng-container>\n      <div class=\"ant-ribbon-corner\" [style.color]=\"!presetColor && nzColor\"></div>\n    </div>\n  `,\n  host: { class: 'ant-ribbon-wrapper' }\n})\nexport class NzRibbonComponent implements OnChanges {\n  @Input() nzColor?: string;\n  @Input() nzPlacement: 'start' | 'end' = 'end';\n  @Input() nzText: string | TemplateRef<void> | null = null;\n  presetColor: string | null = null;\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzColor } = changes;\n    if (nzColor) {\n      this.presetColor = this.nzColor && badgePresetColors.indexOf(this.nzColor) !== -1 ? this.nzColor : null;\n    }\n  }\n}\n"
  },
  {
    "path": "components/badge/style/entry.less",
    "content": "@import './index.less';\n@import './patch.less';\n"
  },
  {
    "path": "components/badge/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@badge-prefix-cls: ~'@{ant-prefix}-badge';\n@number-prefix-cls: ~'@{ant-prefix}-scroll-number';\n@badge-shadow-size: 1px;\n@badge-shadow-color: @shadow-color-inverse;\n\n.@{badge-prefix-cls} {\n  .reset-component();\n\n  position: relative;\n  display: inline-block;\n  line-height: 1;\n\n  &-count {\n    z-index: @zindex-badge;\n    min-width: @badge-height;\n    height: @badge-height;\n    padding: 0 6px;\n    color: @badge-text-color;\n    font-weight: @badge-font-weight;\n    font-size: @badge-font-size;\n    line-height: @badge-height;\n    white-space: nowrap;\n    text-align: center;\n    background: @badge-color;\n    border-radius: (@badge-height / 2);\n    box-shadow: 0 0 0 @badge-shadow-size @badge-shadow-color;\n\n    a,\n    a:hover {\n      color: @badge-text-color;\n    }\n  }\n\n  &-count-sm {\n    min-width: @badge-height-sm;\n    height: @badge-height-sm;\n    padding: 0;\n    font-size: @badge-font-size-sm;\n    line-height: @badge-height-sm;\n    border-radius: (@badge-height-sm / 2);\n  }\n\n  &-multiple-words {\n    padding: 0 @padding-xs;\n  }\n\n  &-dot {\n    z-index: @zindex-badge;\n    width: @badge-dot-size;\n    min-width: @badge-dot-size;\n    height: @badge-dot-size;\n    background: @highlight-color;\n    border-radius: 100%;\n    box-shadow: 0 0 0 @badge-shadow-size @badge-shadow-color;\n  }\n\n  // Tricky way to resolve https://github.com/ant-design/ant-design/issues/30088\n  &-dot.@{number-prefix-cls} {\n    transition: background 1.5s;\n  }\n\n  &-count,\n  &-dot,\n  .@{number-prefix-cls}-custom-component {\n    position: absolute;\n    top: 0;\n    right: 0;\n    transform: translate(50%, -50%);\n    transform-origin: 100% 0%;\n\n    &.@{iconfont-css-prefix}-spin {\n      animation: antBadgeLoadingCircle 1s infinite linear;\n    }\n  }\n\n  &-status {\n    line-height: inherit;\n    vertical-align: baseline;\n\n    &-dot {\n      position: relative;\n      top: -1px;\n      display: inline-block;\n      width: @badge-status-size;\n      height: @badge-status-size;\n      vertical-align: middle;\n      border-radius: 50%;\n    }\n\n    &-success {\n      background-color: @success-color;\n    }\n\n    &-processing {\n      position: relative;\n      background-color: @processing-color;\n\n      &::after {\n        position: absolute;\n        top: 0;\n        left: 0;\n        width: 100%;\n        height: 100%;\n        border: 1px solid @processing-color;\n        border-radius: 50%;\n        animation: antStatusProcessing 1.2s infinite ease-in-out;\n        content: '';\n      }\n    }\n\n    &-default {\n      background-color: @normal-color;\n    }\n\n    &-error {\n      background-color: @error-color;\n    }\n\n    &-warning {\n      background-color: @warning-color;\n    }\n\n    // mixin to iterate over colors and create CSS class for each one\n    .make-color-classes(@i: length(@preset-colors)) when (@i > 0) {\n      .make-color-classes(@i - 1);\n      @color: extract(@preset-colors, @i);\n      @darkColor: '@{color}-6';\n      &-@{color} {\n        background: @@darkColor;\n      }\n    }\n    .make-color-classes();\n\n    &-text {\n      margin-left: @margin-xs;\n      color: @text-color;\n      font-size: @font-size-base;\n    }\n  }\n\n  &-zoom-appear,\n  &-zoom-enter {\n    animation: antZoomBadgeIn @animation-duration-slow @ease-out-back;\n    animation-fill-mode: both;\n  }\n\n  &-zoom-leave {\n    animation: antZoomBadgeOut @animation-duration-slow @ease-in-back;\n    animation-fill-mode: both;\n  }\n\n  &-not-a-wrapper {\n    .@{badge-prefix-cls}-zoom-appear,\n    .@{badge-prefix-cls}-zoom-enter {\n      animation: antNoWrapperZoomBadgeIn @animation-duration-slow @ease-out-back;\n    }\n\n    .@{badge-prefix-cls}-zoom-leave {\n      animation: antNoWrapperZoomBadgeOut @animation-duration-slow @ease-in-back;\n    }\n\n    &:not(.@{badge-prefix-cls}-status) {\n      vertical-align: middle;\n    }\n\n    .@{number-prefix-cls}-custom-component,\n    .@{badge-prefix-cls}-count {\n      transform: none;\n    }\n\n    .@{number-prefix-cls}-custom-component,\n    .@{number-prefix-cls} {\n      position: relative;\n      top: auto;\n      display: block;\n      transform-origin: 50% 50%;\n    }\n  }\n}\n\n@keyframes antStatusProcessing {\n  0% {\n    transform: scale(0.8);\n    opacity: 0.5;\n  }\n\n  100% {\n    transform: scale(2.4);\n    opacity: 0;\n  }\n}\n\n// Safari will blink with transform when inner element has absolute style.\n.safari-fix-motion() {\n  /* stylelint-disable property-no-vendor-prefix */\n  -webkit-transform-style: preserve-3d;\n  -webkit-backface-visibility: hidden;\n  /* stylelint-enable property-no-vendor-prefix */\n}\n\n.@{number-prefix-cls} {\n  overflow: hidden;\n  direction: ltr;\n\n  &-only {\n    position: relative;\n    display: inline-block;\n    height: @badge-height;\n    transition: all @animation-duration-slow @ease-in-out;\n    .safari-fix-motion;\n\n    > p.@{number-prefix-cls}-only-unit {\n      height: @badge-height;\n      margin: 0;\n      .safari-fix-motion;\n    }\n  }\n\n  &-symbol {\n    vertical-align: top;\n  }\n}\n\n@keyframes antZoomBadgeIn {\n  0% {\n    transform: scale(0) translate(50%, -50%);\n    opacity: 0;\n  }\n\n  100% {\n    transform: scale(1) translate(50%, -50%);\n  }\n}\n\n@keyframes antZoomBadgeOut {\n  0% {\n    transform: scale(1) translate(50%, -50%);\n  }\n\n  100% {\n    transform: scale(0) translate(50%, -50%);\n    opacity: 0;\n  }\n}\n\n@keyframes antNoWrapperZoomBadgeIn {\n  0% {\n    transform: scale(0);\n    opacity: 0;\n  }\n\n  100% {\n    transform: scale(1);\n  }\n}\n\n@keyframes antNoWrapperZoomBadgeOut {\n  0% {\n    transform: scale(1);\n  }\n\n  100% {\n    transform: scale(0);\n    opacity: 0;\n  }\n}\n\n@keyframes antBadgeLoadingCircle {\n  0% {\n    transform-origin: 50%;\n  }\n\n  100% {\n    transform: translate(50%, -50%) rotate(360deg);\n    transform-origin: 50%;\n  }\n}\n\n@import './ribbon';\n@import './rtl';\n"
  },
  {
    "path": "components/badge/style/patch.less",
    "content": ".ant-badge {\n  .ant-scroll-number:only-child {\n    position: relative;\n    top: auto;\n    display: block;\n  }\n\n  .ant-badge-count:only-child {\n    transform: none;\n  }\n}\n\nnz-ribbon {\n  display: block;\n}"
  },
  {
    "path": "components/badge/style/ribbon.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@ribbon-prefix-cls: ~'@{ant-prefix}-ribbon';\n@ribbon-wrapper-prefix-cls: ~'@{ant-prefix}-ribbon-wrapper';\n\n.@{ribbon-wrapper-prefix-cls} {\n  position: relative;\n}\n\n.@{ribbon-prefix-cls} {\n  .reset-component();\n\n  position: absolute;\n  top: 8px;\n  height: 22px;\n  padding: 0 8px;\n  color: @badge-text-color;\n  line-height: 22px;\n  white-space: nowrap;\n  background-color: @primary-color;\n  border-radius: @border-radius-sm;\n\n  &-text {\n    color: @white;\n  }\n\n  &-corner {\n    position: absolute;\n    top: 100%;\n    width: 8px;\n    height: 8px;\n    color: currentcolor;\n    border: 4px solid;\n    transform: scaleY(0.75);\n    transform-origin: top;\n    filter: brightness(75%);\n  }\n\n  // colors\n  // mixin to iterate over colors and create CSS class for each one\n  .make-color-classes(@i: length(@preset-colors)) when (@i > 0) {\n    .make-color-classes(@i - 1);\n    @color: extract(@preset-colors, @i);\n    @darkColor: '@{color}-6';\n    &-color-@{color} {\n      color: @@darkColor;\n      background: @@darkColor;\n    }\n  }\n  .make-color-classes();\n\n  // placement\n  &.@{ribbon-prefix-cls}-placement-end {\n    right: -8px;\n    border-bottom-right-radius: 0;\n    .@{ribbon-prefix-cls}-corner {\n      right: 0;\n      border-color: currentcolor transparent transparent currentcolor;\n    }\n  }\n\n  &.@{ribbon-prefix-cls}-placement-start {\n    left: -8px;\n    border-bottom-left-radius: 0;\n    .@{ribbon-prefix-cls}-corner {\n      left: 0;\n      border-color: currentcolor currentcolor transparent transparent;\n    }\n  }\n}\n"
  },
  {
    "path": "components/badge/style/rtl.less",
    "content": ".@{badge-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &:not(&-not-a-wrapper) &-count,\n  &:not(&-not-a-wrapper) &-dot,\n  &:not(&-not-a-wrapper) .@{number-prefix-cls}-custom-component {\n    .@{badge-prefix-cls}-rtl& {\n      right: auto;\n      left: 0;\n      direction: ltr;\n      transform: translate(-50%, -50%);\n      transform-origin: 0% 0%;\n    }\n  }\n\n  &-rtl&:not(&-not-a-wrapper) .@{number-prefix-cls}-custom-component {\n    right: auto;\n    left: 0;\n    transform: translate(-50%, -50%);\n    transform-origin: 0% 0%;\n  }\n\n  &-status {\n    &-text {\n      .@{badge-prefix-cls}-rtl & {\n        margin-right: @margin-xs;\n        margin-left: 0;\n      }\n    }\n  }\n\n  &:not(&-not-a-wrapper).@{badge-prefix-cls}-rtl {\n    .@{badge-prefix-cls}-zoom-appear,\n    .@{badge-prefix-cls}-zoom-enter {\n      animation-name: antZoomBadgeInRtl;\n    }\n\n    .@{badge-prefix-cls}-zoom-leave {\n      animation-name: antZoomBadgeOutRtl;\n    }\n  }\n}\n\n.@{ribbon-prefix-cls}-rtl {\n  direction: rtl;\n  &.@{ribbon-prefix-cls}-placement-end {\n    right: unset;\n    left: -8px;\n    border-bottom-right-radius: @border-radius-sm;\n    border-bottom-left-radius: 0;\n    .@{ribbon-prefix-cls}-corner {\n      right: unset;\n      left: 0;\n      border-color: currentcolor currentcolor transparent transparent;\n\n      &::after {\n        border-color: currentcolor currentcolor transparent transparent;\n      }\n    }\n  }\n  &.@{ribbon-prefix-cls}-placement-start {\n    right: -8px;\n    left: unset;\n    border-bottom-right-radius: 0;\n    border-bottom-left-radius: @border-radius-sm;\n    .@{ribbon-prefix-cls}-corner {\n      right: 0;\n      left: unset;\n      border-color: currentcolor transparent transparent currentcolor;\n\n      &::after {\n        border-color: currentcolor transparent transparent currentcolor;\n      }\n    }\n  }\n}\n\n@keyframes antZoomBadgeInRtl {\n  0% {\n    transform: scale(0) translate(-50%, -50%);\n    opacity: 0;\n  }\n\n  100% {\n    transform: scale(1) translate(-50%, -50%);\n  }\n}\n\n@keyframes antZoomBadgeOutRtl {\n  0% {\n    transform: scale(1) translate(-50%, -50%);\n  }\n\n  100% {\n    transform: scale(0) translate(-50%, -50%);\n    opacity: 0;\n  }\n}\n"
  },
  {
    "path": "components/badge/types.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport type NzBadgeStatusType = 'success' | 'processing' | 'default' | 'error' | 'warning';\n"
  },
  {
    "path": "components/breadcrumb/breadcrumb-item.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, inject, Input, ViewEncapsulation } from '@angular/core';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzDropdownMenuComponent, NzDropdownModule } from 'ng-zorro-antd/dropdown';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nimport { NzBreadcrumb } from './breadcrumb';\nimport { NzBreadCrumbSeparatorComponent } from './breadcrumb-separator.component';\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-breadcrumb-item',\n  exportAs: 'nzBreadcrumbItem',\n  imports: [NgTemplateOutlet, NzBreadCrumbSeparatorComponent, NzDropdownModule, NzIconModule, NzOutletModule],\n  template: `\n    @if (!!nzOverlay) {\n      <span class=\"ant-breadcrumb-overlay-link\" nz-dropdown [nzDropdownMenu]=\"nzOverlay\">\n        <ng-template [ngTemplateOutlet]=\"noMenuTpl\" />\n        <nz-icon nzType=\"down\" />\n      </span>\n    } @else {\n      <ng-template [ngTemplateOutlet]=\"noMenuTpl\" />\n    }\n\n    @if (nzBreadCrumbComponent.nzSeparator) {\n      <nz-breadcrumb-separator>\n        <ng-container *nzStringTemplateOutlet=\"nzBreadCrumbComponent.nzSeparator\">\n          {{ nzBreadCrumbComponent.nzSeparator }}\n        </ng-container>\n      </nz-breadcrumb-separator>\n    }\n\n    <ng-template #noMenuTpl>\n      <span class=\"ant-breadcrumb-link\">\n        <ng-content />\n      </span>\n    </ng-template>\n  `\n})\nexport class NzBreadCrumbItemComponent {\n  nzBreadCrumbComponent = inject(NzBreadcrumb);\n  /**\n   * Dropdown content of a breadcrumb item.\n   */\n  @Input() nzOverlay?: NzDropdownMenuComponent;\n}\n"
  },
  {
    "path": "components/breadcrumb/breadcrumb-separator.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component } from '@angular/core';\n\n@Component({\n  selector: 'nz-breadcrumb-separator',\n  exportAs: 'nzBreadcrumbSeparator',\n  template: `<ng-content />`,\n  host: {\n    class: 'ant-breadcrumb-separator'\n  }\n})\nexport class NzBreadCrumbSeparatorComponent {}\n"
  },
  {
    "path": "components/breadcrumb/breadcrumb.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ElementRef,\n  Injector,\n  Input,\n  OnInit,\n  Renderer2,\n  TemplateRef,\n  ViewEncapsulation,\n  booleanAttribute,\n  forwardRef,\n  inject,\n  DestroyRef\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ActivatedRoute, NavigationEnd, PRIMARY_OUTLET, Params, Router } from '@angular/router';\nimport { filter, startWith } from 'rxjs/operators';\n\nimport { PREFIX } from 'ng-zorro-antd/core/logger';\n\nimport { NzBreadcrumb } from './breadcrumb';\nimport { NzBreadCrumbItemComponent } from './breadcrumb-item.component';\n\nexport interface BreadcrumbOption {\n  label: string;\n  params: Params;\n  url: string;\n}\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-breadcrumb',\n  exportAs: 'nzBreadcrumb',\n  providers: [{ provide: NzBreadcrumb, useExisting: forwardRef(() => NzBreadCrumbComponent) }],\n  imports: [NzBreadCrumbItemComponent],\n  template: `\n    <ng-content />\n    @if (nzAutoGenerate && breadcrumbs.length) {\n      @for (breadcrumb of breadcrumbs; track breadcrumb.url) {\n        <nz-breadcrumb-item>\n          <a [attr.href]=\"breadcrumb.url\" (click)=\"navigate(breadcrumb.url, $event)\">{{ breadcrumb.label }}</a>\n        </nz-breadcrumb-item>\n      }\n    }\n  `,\n  host: {\n    class: 'ant-breadcrumb'\n  }\n})\nexport class NzBreadCrumbComponent implements OnInit, NzBreadcrumb {\n  private injector = inject(Injector);\n  private cdr = inject(ChangeDetectorRef);\n  private elementRef = inject(ElementRef<HTMLElement>);\n  private renderer = inject(Renderer2);\n  private directionality = inject(Directionality);\n  private destroyRef = inject(DestroyRef);\n\n  @Input({ transform: booleanAttribute }) nzAutoGenerate = false;\n  @Input() nzSeparator: string | TemplateRef<void> | null = '/';\n  @Input() nzRouteLabel: string = 'breadcrumb';\n  @Input() nzRouteLabelFn: (label: string) => string = label => label;\n  @Input() nzRouteFn: (route: string) => string = route => route;\n\n  breadcrumbs: BreadcrumbOption[] = [];\n  dir: Direction = 'ltr';\n\n  ngOnInit(): void {\n    if (this.nzAutoGenerate) {\n      this.registerRouterChange();\n    }\n\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((direction: Direction) => {\n      this.dir = direction;\n      this.prepareComponentForRtl();\n      this.cdr.detectChanges();\n    });\n\n    this.dir = this.directionality.value;\n    this.prepareComponentForRtl();\n  }\n\n  navigate(url: string, e: MouseEvent): void {\n    e.preventDefault();\n    this.injector.get(Router).navigateByUrl(url);\n  }\n\n  private registerRouterChange(): void {\n    try {\n      const router = this.injector.get(Router);\n      const activatedRoute = this.injector.get(ActivatedRoute);\n      router.events\n        .pipe(\n          filter(e => e instanceof NavigationEnd),\n          takeUntilDestroyed(this.destroyRef),\n          startWith(true) // trigger initial render\n        )\n        .subscribe(() => {\n          this.breadcrumbs = this.getBreadcrumbs(activatedRoute.root);\n          this.cdr.markForCheck();\n        });\n    } catch {\n      throw new Error(`${PREFIX} You should import RouterModule if you want to use 'NzAutoGenerate'.`);\n    }\n  }\n\n  private getBreadcrumbs(\n    route: ActivatedRoute,\n    url: string = '',\n    breadcrumbs: BreadcrumbOption[] = []\n  ): BreadcrumbOption[] {\n    const children: ActivatedRoute[] = route.children;\n\n    // If there's no sub root, then stop the recurse and returns the generated breadcrumbs.\n    if (children.length === 0) {\n      return breadcrumbs;\n    }\n\n    for (const child of children) {\n      if (child.outlet === PRIMARY_OUTLET) {\n        // Only parse components in primary router-outlet (in another word, router-outlet without a specific name).\n        // Parse this layer and generate a breadcrumb item.\n        const routeUrl: string = child.snapshot.url\n          .map(segment => segment.path)\n          .filter(path => path)\n          .join('/');\n\n        // Do not change nextUrl if routeUrl is falsy. This happens when it's a route lazy loading other modules.\n        const nextUrl = routeUrl ? `${url}/${routeUrl}` : url;\n        const breadcrumbLabel = this.nzRouteLabelFn(child.snapshot.data[this.nzRouteLabel]);\n        const shapedUrl = this.nzRouteFn(nextUrl);\n        // If have data, go to generate a breadcrumb for it.\n        if (routeUrl && breadcrumbLabel) {\n          const breadcrumb: BreadcrumbOption = {\n            label: breadcrumbLabel,\n            params: child.snapshot.params,\n            url: shapedUrl\n          };\n          breadcrumbs.push(breadcrumb);\n        }\n\n        return this.getBreadcrumbs(child, nextUrl, breadcrumbs);\n      }\n    }\n\n    return breadcrumbs;\n  }\n\n  private prepareComponentForRtl(): void {\n    if (this.dir === 'rtl') {\n      this.renderer.addClass(this.elementRef.nativeElement, 'ant-breadcrumb-rtl');\n    } else {\n      this.renderer.removeClass(this.elementRef.nativeElement, 'ant-breadcrumb-rtl');\n    }\n  }\n}\n"
  },
  {
    "path": "components/breadcrumb/breadcrumb.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzBreadCrumbItemComponent } from './breadcrumb-item.component';\nimport { NzBreadCrumbSeparatorComponent } from './breadcrumb-separator.component';\nimport { NzBreadCrumbComponent } from './breadcrumb.component';\n\n@NgModule({\n  imports: [NzBreadCrumbComponent, NzBreadCrumbItemComponent, NzBreadCrumbSeparatorComponent],\n  exports: [NzBreadCrumbComponent, NzBreadCrumbItemComponent, NzBreadCrumbSeparatorComponent]\n})\nexport class NzBreadCrumbModule {}\n"
  },
  {
    "path": "components/breadcrumb/breadcrumb.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport { Component, DebugElement, NgZone, provideZoneChangeDetection, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, flush, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { PRIMARY_OUTLET, provideRouter, Router, RouterOutlet, Routes } from '@angular/router';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzBreadCrumbItemComponent } from './breadcrumb-item.component';\nimport { NzBreadCrumbComponent } from './breadcrumb.component';\nimport { NzBreadCrumbModule } from './breadcrumb.module';\nimport { NzDemoBreadcrumbBasicComponent } from './demo/basic';\nimport { NzDemoBreadcrumbDropdownComponent } from './demo/dropdown';\nimport { NzDemoBreadcrumbSeparatorComponent } from './demo/separator';\n\ndescribe('breadcrumb', () => {\n  describe('basic', () => {\n    let fixture: ComponentFixture<NzDemoBreadcrumbBasicComponent>;\n    let items: DebugElement[];\n    let breadcrumb: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzDemoBreadcrumbBasicComponent);\n      items = fixture.debugElement.queryAll(By.directive(NzBreadCrumbItemComponent));\n      breadcrumb = fixture.debugElement.query(By.directive(NzBreadCrumbComponent));\n    });\n\n    it('should have correct style', () => {\n      fixture.detectChanges();\n      expect(items.every(item => item.nativeElement.firstElementChild!.classList.contains('ant-breadcrumb-link'))).toBe(\n        true\n      );\n      expect(items.every(item => item.nativeElement.children[1].classList.contains('ant-breadcrumb-separator'))).toBe(\n        true\n      );\n      expect(breadcrumb.nativeElement.classList.contains('ant-breadcrumb')).toBe(true);\n    });\n  });\n\n  describe('dropdown', () => {\n    let fixture: ComponentFixture<NzDemoBreadcrumbDropdownComponent>;\n    let items: DebugElement[];\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzDemoBreadcrumbDropdownComponent);\n      items = fixture.debugElement.queryAll(By.directive(NzBreadCrumbItemComponent));\n    });\n\n    it('should dropdown work', () => {\n      fixture.detectChanges();\n\n      const dropdownElement = items[2];\n      expect((dropdownElement.nativeElement as HTMLElement).querySelector('.ant-dropdown-trigger')).not.toBe(null);\n    });\n  });\n\n  describe('separator', () => {\n    let fixture: ComponentFixture<NzDemoBreadcrumbSeparatorComponent>;\n    let items: DebugElement[];\n    let breadcrumbs: DebugElement[];\n\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        providers: [provideNzIconsTesting()]\n      });\n    });\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzDemoBreadcrumbSeparatorComponent);\n      items = fixture.debugElement.queryAll(By.directive(NzBreadCrumbItemComponent));\n      breadcrumbs = fixture.debugElement.queryAll(By.directive(NzBreadCrumbComponent));\n    });\n\n    it('should nzSeparator work', () => {\n      fixture.detectChanges();\n      expect(items.every(item => item.nativeElement.firstElementChild!.classList.contains('ant-breadcrumb-link'))).toBe(\n        true\n      );\n      expect(items.every(item => item.nativeElement.children[1].classList.contains('ant-breadcrumb-separator'))).toBe(\n        true\n      );\n      expect(breadcrumbs.every(breadcrumb => breadcrumb.nativeElement.classList.contains('ant-breadcrumb'))).toBe(true);\n      expect(items[0].nativeElement.children[1].innerText.indexOf('>') > -1).toBe(true);\n      expect(items[3].nativeElement.children[1].firstElementChild!.classList.contains('anticon-arrow-right')).toBe(\n        true\n      );\n    });\n  });\n\n  describe('auto generated', () => {\n    let fixture: ComponentFixture<NzBreadcrumbAutoGenerateDemoComponent>;\n    let router: Router;\n    let breadcrumb: DebugElement;\n\n    it('should auto generating work', fakeAsync(() => {\n      TestBed.configureTestingModule({\n        providers: [provideRouter(routes), provideZoneChangeDetection()]\n      });\n\n      fixture = TestBed.createComponent(NzBreadcrumbAutoGenerateDemoComponent);\n      breadcrumb = fixture.debugElement.query(By.directive(NzBreadCrumbComponent));\n\n      fixture.ngZone!.run(() => {\n        router = TestBed.inject(Router);\n        router.initialNavigation();\n\n        // Should generate 2 breadcrumbs when reaching out of the `data` scope.\n        router.navigate(['one', 'two', 'three', 'four']);\n        flushFixture(fixture);\n        expect(breadcrumb.componentInstance.breadcrumbs.length).toBe(2);\n\n        // TODO: pending this test because of Angular's bug: https://github.com/angular/angular/issues/25837\n        // const items = fixture.debugElement.queryAll(By.directive(NzBreadCrumbItemComponent));\n        // dispatchMouseEvent(items[1].nativeElement.querySelector('a'), 'click');\n        // flushFixture(fixture);\n        // expect(breadcrumb.componentInstance.breadcrumbs.length).toBe(1);\n\n        // Should generate breadcrumbs correctly.\n        router.navigate(['one', 'two', 'three']);\n        flushFixture(fixture);\n        expect(breadcrumb.componentInstance.breadcrumbs.length).toBe(2);\n        router.navigate(['one', 'two']);\n        flushFixture(fixture);\n        expect(breadcrumb.componentInstance.breadcrumbs.length).toBe(1);\n\n        // Shouldn't generate breadcrumb at all.\n        router.navigate(['one']);\n        flushFixture(fixture);\n        expect(breadcrumb.componentInstance.breadcrumbs.length).toBe(0);\n\n        router.navigate(['/']);\n        flushFixture(fixture);\n        router.navigate([{ outlets: { nonPrimary: ['one', 'two'] } }]);\n        flushFixture(fixture);\n        expect(router.url).toBe('/(nonPrimary:one/two)');\n      });\n    }));\n\n    it('should route data breadcrumb label work', fakeAsync(() => {\n      TestBed.configureTestingModule({\n        providers: [provideRouter(customRouteLabelRoutes)]\n      });\n\n      fixture = TestBed.createComponent(NzBreadcrumbRouteLabelDemoComponent);\n      breadcrumb = fixture.debugElement.query(By.directive(NzBreadCrumbComponent));\n\n      fixture.ngZone!.run(() => {\n        router = TestBed.inject(Router);\n        router.initialNavigation();\n\n        // Should nzRouteLabel value is 'customBreadcrumb'\n        flushFixture(fixture);\n        expect(breadcrumb.componentInstance.nzRouteLabel).toBe('customBreadcrumb');\n\n        // Should generate 2 breadcrumbs when reaching out of the `data` scope.\n        router.navigate(['one', 'two', 'three', 'four']);\n        flushFixture(fixture);\n        expect(breadcrumb.componentInstance.breadcrumbs.length).toBe(2);\n        expect(breadcrumb.componentInstance.breadcrumbs[0].label).toBe('Layer 2');\n        expect(breadcrumb.componentInstance.breadcrumbs[1].label).toBe('Layer 3');\n      });\n    }));\n\n    it('should [nzRouteLabelFn] work', fakeAsync(() => {\n      TestBed.configureTestingModule({\n        providers: [provideRouter(customRouteLabelRoutes)]\n      });\n\n      fixture = TestBed.createComponent(NzBreadcrumbRouteLabelWithCustomFnDemoComponent);\n      breadcrumb = fixture.debugElement.query(By.directive(NzBreadCrumbComponent));\n\n      fixture.ngZone!.run(() => {\n        router = TestBed.inject(Router);\n        router.initialNavigation();\n\n        // Should nzRouteLabel value is 'customBreadcrumb'\n        flushFixture(fixture);\n        expect(breadcrumb.componentInstance.nzRouteLabel).toBe('customBreadcrumb');\n\n        // Should generate 2 breadcrumbs when reaching out of the `data` scope.\n        router.navigate(['one', 'two', 'three', 'four']);\n        flushFixture(fixture);\n        expect(breadcrumb.componentInstance.breadcrumbs.length).toBe(2);\n        expect(breadcrumb.componentInstance.breadcrumbs[0].label).toBe('Layer 2 Layer 2');\n        expect(breadcrumb.componentInstance.breadcrumbs[1].label).toBe('Layer 3 Layer 3');\n      });\n    }));\n\n    it('should [nzRouteFn] work', fakeAsync(() => {\n      TestBed.configureTestingModule({\n        providers: [provideRouter(customRouteLabelRoutes)]\n      });\n\n      fixture = TestBed.createComponent(NzBreadcrumbRouteWithCustomFnDemoComponent);\n      breadcrumb = fixture.debugElement.query(By.directive(NzBreadCrumbComponent));\n\n      fixture.ngZone!.run(() => {\n        router = TestBed.inject(Router);\n        router.initialNavigation();\n\n        // Breadcrumb should contain added params by nzRouteFn\n        router.navigate(['one', 'two']);\n        flushFixture(fixture);\n        expect(breadcrumb.componentInstance.breadcrumbs[0].url).toContain('active=true');\n      });\n    }));\n\n    it('should route data breadcrumb navigate work', fakeAsync(() => {\n      TestBed.configureTestingModule({\n        providers: [provideRouter(customRouteLabelRoutes)]\n      });\n\n      fixture = TestBed.createComponent(NzBreadcrumbRouteLabelDemoComponent);\n      breadcrumb = fixture.debugElement.query(By.directive(NzBreadCrumbComponent));\n\n      fixture.ngZone!.run(() => {\n        router = TestBed.inject(Router);\n        router.initialNavigation();\n\n        flushFixture(fixture);\n        expect(breadcrumb.componentInstance.nzRouteLabel).toBe('customBreadcrumb');\n\n        router.navigate(['one', 'two', 'three', 'four']);\n        flushFixture(fixture);\n\n        fixture.debugElement.query(By.css('a')).nativeElement.click();\n        flushFixture(fixture);\n        expect(router.url).toBe('/one/two');\n      });\n    }));\n\n    it('should raise error when RouterModule is not included', fakeAsync(() => {\n      expect(() => {\n        fixture = TestBed.createComponent(NzBreadcrumbAutoGenerateErrorDemoComponent);\n        fixture.detectChanges();\n      }).toThrowError();\n    }));\n\n    it('should call navigate() within the Angular zone', fakeAsync(() => {\n      let navigateHasBeenCalledWithinTheAngularZone = false;\n\n      // todo: use zoneless\n      TestBed.configureTestingModule({\n        providers: [provideRouter(customRouteLabelRoutes), provideZoneChangeDetection()]\n      });\n\n      fixture = TestBed.createComponent(NzBreadcrumbRouteLabelDemoComponent);\n      breadcrumb = fixture.debugElement.query(By.directive(NzBreadCrumbComponent));\n\n      const navigate = breadcrumb.componentInstance.navigate;\n      const spy = spyOn(breadcrumb.componentInstance, 'navigate').and.callFake((url: string, event: MouseEvent) => {\n        navigateHasBeenCalledWithinTheAngularZone = NgZone.isInAngularZone();\n        return navigate.call(breadcrumb.componentInstance, url, event);\n      });\n\n      router = TestBed.inject(Router);\n      router.initialNavigation();\n      flushFixture(fixture);\n\n      router.navigate(['one', 'two']);\n      flushFixture(fixture);\n\n      fixture.debugElement.query(By.css('a')).nativeElement.click();\n      flushFixture(fixture);\n\n      expect(spy).toHaveBeenCalledTimes(1);\n      expect(navigateHasBeenCalledWithinTheAngularZone).toBeTrue();\n    }));\n  });\n\n  describe('RTL', () => {\n    it('should className correct on dir change', async () => {\n      const fixture = TestBed.createComponent(NzTestBreadcrumbRtlComponent);\n      const breadcrumb = fixture.debugElement.query(By.directive(NzBreadCrumbComponent));\n      await fixture.whenStable();\n      expect(breadcrumb.nativeElement.classList).toContain('ant-breadcrumb-rtl');\n\n      fixture.componentInstance.direction = 'ltr';\n      fixture.changeDetectorRef.markForCheck();\n      await fixture.whenStable();\n      expect(breadcrumb.nativeElement.className).not.toContain('ant-breadcrumb-rtl');\n    });\n  });\n});\n\n// eslint-disable-next-line  @typescript-eslint/no-explicit-any\nfunction flushFixture(fixture: ComponentFixture<any>): void {\n  fixture.detectChanges();\n  flush();\n  fixture.detectChanges();\n}\n\n@Component({\n  imports: [RouterOutlet, NzBreadCrumbModule],\n  selector: 'nz-test-breadcrumb',\n  template: `\n    <nz-breadcrumb [nzAutoGenerate]=\"true\" />\n    <router-outlet />\n    <router-outlet name=\"nonPrimary\" />\n  `\n})\nclass NzBreadcrumbAutoGenerateDemoComponent {}\n\n@Component({\n  imports: [RouterOutlet, NzBreadCrumbModule],\n  template: `\n    <nz-breadcrumb [nzAutoGenerate]=\"true\" nzRouteLabel=\"customBreadcrumb\" />\n    <router-outlet />\n  `\n})\nclass NzBreadcrumbRouteLabelDemoComponent {}\n\n@Component({\n  imports: [RouterOutlet, NzBreadCrumbModule],\n  template: `\n    <nz-breadcrumb [nzAutoGenerate]=\"true\" nzRouteLabel=\"customBreadcrumb\" [nzRouteLabelFn]=\"labelFn\" />\n    <router-outlet />\n  `\n})\nclass NzBreadcrumbRouteLabelWithCustomFnDemoComponent {\n  labelFn = (label: string): string => (label ? `${label} ${label}` : '');\n}\n\n@Component({\n  imports: [RouterOutlet, NzBreadCrumbModule],\n  template: `\n    <nz-breadcrumb [nzAutoGenerate]=\"true\" nzRouteLabel=\"customBreadcrumb\" [nzRouteFn]=\"routeFn\" />\n    <router-outlet />\n  `\n})\nclass NzBreadcrumbRouteWithCustomFnDemoComponent {\n  routeFn = (route: string): string => `${route};active=true`;\n}\n\n@Component({\n  imports: [NzBreadCrumbModule],\n  template: '<nz-breadcrumb [nzAutoGenerate]=\"true\" />'\n})\nclass NzBreadcrumbAutoGenerateErrorDemoComponent {}\n\n@Component({\n  template: 'empty'\n})\nclass NzBreadcrumbNullComponent {}\n\nconst routes: Routes = [\n  {\n    path: 'one',\n    component: NzBreadcrumbAutoGenerateDemoComponent,\n    data: {\n      breadcrumb: ''\n    },\n    children: [\n      {\n        path: 'two',\n        component: NzBreadcrumbNullComponent,\n        data: {\n          breadcrumb: 'Layer 2'\n        },\n        children: [\n          {\n            path: 'three',\n            component: NzBreadcrumbNullComponent,\n            data: {\n              breadcrumb: 'Layer 3'\n            },\n            children: [\n              {\n                path: 'four',\n                component: NzBreadcrumbNullComponent,\n                data: {\n                  breadcrumb: ''\n                }\n              }\n            ]\n          }\n        ]\n      }\n    ]\n  },\n  // Should only work for the primary outlet.\n  {\n    path: 'one',\n    outlet: 'nonPrimary',\n    component: NzBreadcrumbAutoGenerateDemoComponent,\n    data: {\n      breadcrumb: ''\n    },\n    children: [\n      {\n        path: 'two',\n        component: NzBreadcrumbNullComponent,\n        data: {\n          breadcrumb: 'Layer 2'\n        }\n      }\n    ]\n  }\n];\n\nconst customRouteLabelRoutes: Routes = [\n  {\n    path: 'one',\n    component: NzBreadcrumbRouteLabelDemoComponent,\n    data: {\n      customBreadcrumb: ''\n    },\n    children: [\n      {\n        path: 'two',\n        component: NzBreadcrumbNullComponent,\n        data: {\n          customBreadcrumb: 'Layer 2'\n        },\n        children: [\n          {\n            path: 'three',\n            component: NzBreadcrumbNullComponent,\n            data: {\n              customBreadcrumb: 'Layer 3'\n            },\n            children: [\n              {\n                path: 'four',\n                component: NzBreadcrumbNullComponent,\n                data: {\n                  customBreadcrumb: ''\n                }\n              }\n            ]\n          }\n        ]\n      }\n    ]\n  }\n];\n\n@Component({\n  imports: [BidiModule, NzDemoBreadcrumbBasicComponent],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-demo-breadcrumb-basic />\n    </div>\n  `\n})\nexport class NzTestBreadcrumbRtlComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n}\n\ndescribe('breadcrumb', () => {\n  let fixture: ComponentFixture<NzBreadCrumbComponent>;\n  let component: NzBreadCrumbComponent;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n    fixture = TestBed.createComponent(NzBreadCrumbComponent);\n    component = fixture.componentInstance;\n  });\n\n  it('should have correct value for nextUrl', () => {\n    spyOn(component, 'nzRouteFn');\n    const mockRout = {\n      children: [\n        {\n          outlet: PRIMARY_OUTLET,\n          snapshot: {\n            url: [],\n            data: {\n              breadcrumb: 'breadcrumb'\n            }\n          },\n          children: []\n        }\n      ]\n    };\n\n    component['getBreadcrumbs'](mockRout as NzSafeAny, 'mockUrl', []);\n\n    expect(component.nzRouteFn).toHaveBeenCalledWith('mockUrl');\n  });\n});\n"
  },
  {
    "path": "components/breadcrumb/breadcrumb.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { TemplateRef } from '@angular/core';\n\n/**\n * https://angular.io/errors/NG3003\n * An intermediate interface for {@link NzBreadCrumbComponent} & {@link NzBreadCrumbItemComponent}\n */\nexport abstract class NzBreadcrumb {\n  abstract nzSeparator: string | TemplateRef<void> | null;\n}\n"
  },
  {
    "path": "components/breadcrumb/demo/auto.md",
    "content": "---\norder: 4\n\niframe:\n  source: https://stackblitz.com/edit/ng-zorro-breadcrumb-auto?embed=1&file=src/app/app.component.html&hideExplorer=1&hideNavigation=1&view=preview\n  height: 460\ntitle:\n  zh-CN: 自动生成\n  en-US: Auto generated breadcrumbs\n---\n\n## zh-CN\n\n通过配置 `router.data` 自动生成面包屑。\n\n## en-US\n\nAuto generate breadcrumbs using `router.data`.\n"
  },
  {
    "path": "components/breadcrumb/demo/auto.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';\n\n@Component({\n  selector: 'nz-demo-breadcrumb-auto',\n  imports: [NzBreadCrumbModule],\n  template: `\n    <nz-breadcrumb [nzAutoGenerate]=\"true\">\n      Please refer to StackBlitz demo at https://stackblitz.com/edit/ng-zorro-breadcrumb-auto\n    </nz-breadcrumb>\n  `\n})\nexport class NzDemoBreadcrumbAutoComponent {}\n"
  },
  {
    "path": "components/breadcrumb/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic Usage\n---\n\n## zh-CN\n\n最简单的用法。\n\n## en-US\n\nThe simplest use\n"
  },
  {
    "path": "components/breadcrumb/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';\n\n@Component({\n  selector: 'nz-demo-breadcrumb-basic',\n  imports: [NzBreadCrumbModule],\n  template: `\n    <nz-breadcrumb>\n      <nz-breadcrumb-item>Home</nz-breadcrumb-item>\n      <nz-breadcrumb-item>\n        <a>Application List</a>\n      </nz-breadcrumb-item>\n      <nz-breadcrumb-item>An Application</nz-breadcrumb-item>\n    </nz-breadcrumb>\n  `\n})\nexport class NzDemoBreadcrumbBasicComponent {}\n"
  },
  {
    "path": "components/breadcrumb/demo/dropdown.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 带下拉菜单的面包屑\n  en-US: Bread crumbs with drop down menu\n---\n\n## zh-CN\n\n面包屑支持下拉菜单。\n\n## en-US\n\nBreadcrumbs support drop down menu.\n"
  },
  {
    "path": "components/breadcrumb/demo/dropdown.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';\nimport { NzDropdownModule } from 'ng-zorro-antd/dropdown';\n\n@Component({\n  selector: 'nz-demo-breadcrumb-dropdown',\n  imports: [NzBreadCrumbModule, NzDropdownModule],\n  template: `\n    <nz-breadcrumb>\n      <nz-breadcrumb-item>Ant Design</nz-breadcrumb-item>\n      <nz-breadcrumb-item>\n        <a>Component</a>\n      </nz-breadcrumb-item>\n      <nz-breadcrumb-item [nzOverlay]=\"menu\">\n        <a href>An Application</a>\n      </nz-breadcrumb-item>\n      <nz-breadcrumb-item>Button</nz-breadcrumb-item>\n    </nz-breadcrumb>\n    <nz-dropdown-menu #menu=\"nzDropdownMenu\">\n      <ul nz-menu nzSelectable>\n        <li nz-menu-item>General</li>\n        <li nz-menu-item>Layout</li>\n        <li nz-menu-item>Navigation</li>\n      </ul>\n    </nz-dropdown-menu>\n  `\n})\nexport class NzDemoBreadcrumbDropdownComponent {}\n"
  },
  {
    "path": "components/breadcrumb/demo/router.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 路由\n  en-US: RouterLink\n---\n\n## zh-CN\n\n和 [RouterLink](https://angular.cn/api/router/RouterLink) 进行结合使用。\n\n## en-US\n\nUsed together with [RouterLink](https://angular.dev/api/router/RouterLink).\n"
  },
  {
    "path": "components/breadcrumb/demo/router.ts",
    "content": "import { Component } from '@angular/core';\nimport { RouterLink } from '@angular/router';\n\nimport { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';\n\n@Component({\n  selector: 'nz-demo-breadcrumb-router',\n  imports: [RouterLink, NzBreadCrumbModule],\n  template: `\n    <nz-breadcrumb>\n      <nz-breadcrumb-item>\n        <a [routerLink]=\"['../../']\">Home</a>\n      </nz-breadcrumb-item>\n      <nz-breadcrumb-item>Breadcrumb</nz-breadcrumb-item>\n    </nz-breadcrumb>\n  `\n})\nexport class NzDemoBreadcrumbRouterComponent {}\n"
  },
  {
    "path": "components/breadcrumb/demo/separator-independent.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 独立的分隔符\n  en-US: Configuring the Separator Independently\n---\n\n## zh-CN\n\n使用 `nz-breadcrumb-separator` 可以自定义分隔符。\n\n## en-US\n\nThe separator can be customized by using the component `nz-breadcrumb-separator`.\n"
  },
  {
    "path": "components/breadcrumb/demo/separator-independent.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';\n\n@Component({\n  selector: 'nz-demo-breadcrumb-separator-independent',\n  imports: [NzBreadCrumbModule],\n  template: `\n    <nz-breadcrumb [nzSeparator]=\"null\">\n      <nz-breadcrumb-item>Location</nz-breadcrumb-item>\n      <nz-breadcrumb-separator>:</nz-breadcrumb-separator>\n      <nz-breadcrumb-item>\n        <a>Application Center</a>\n      </nz-breadcrumb-item>\n      <nz-breadcrumb-separator>/</nz-breadcrumb-separator>\n      <nz-breadcrumb-item>Application List</nz-breadcrumb-item>\n      <nz-breadcrumb-separator>/</nz-breadcrumb-separator>\n      <nz-breadcrumb-item>An Application</nz-breadcrumb-item>\n    </nz-breadcrumb>\n  `\n})\nexport class NzDemoBreadcrumbSeparatorIndependentComponent {}\n"
  },
  {
    "path": "components/breadcrumb/demo/separator.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 分隔符\n  en-US: Configuring the Separator\n---\n\n## zh-CN\n\n使用 `nzSeparator` 可以自定义分隔符。\n\n## en-US\n\nThe separator can be customized by setting the separator property: `nzSeparator`\n"
  },
  {
    "path": "components/breadcrumb/demo/separator.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-demo-breadcrumb-separator',\n  imports: [NzBreadCrumbModule, NzIconModule],\n  template: `\n    <h4>String</h4>\n    <nz-breadcrumb nzSeparator=\">\">\n      <nz-breadcrumb-item>Home</nz-breadcrumb-item>\n      <nz-breadcrumb-item>\n        <a>Application List</a>\n      </nz-breadcrumb-item>\n      <nz-breadcrumb-item>An Application</nz-breadcrumb-item>\n    </nz-breadcrumb>\n    <br />\n    <h4>TemplateRef</h4>\n    <nz-breadcrumb [nzSeparator]=\"iconTemplate\">\n      <nz-breadcrumb-item>Home</nz-breadcrumb-item>\n      <nz-breadcrumb-item>\n        <a>Application List</a>\n      </nz-breadcrumb-item>\n      <nz-breadcrumb-item>An Application</nz-breadcrumb-item>\n    </nz-breadcrumb>\n    <ng-template #iconTemplate><nz-icon nzType=\"arrow-right\" /></ng-template>\n  `,\n  styles: `\n    h4:first-child {\n      margin-top: 0;\n    }\n\n    h4 {\n      margin: 16px 0;\n      font-size: 14px;\n      line-height: 1;\n      font-weight: normal;\n    }\n  `\n})\nexport class NzDemoBreadcrumbSeparatorComponent {}\n"
  },
  {
    "path": "components/breadcrumb/demo/with-icon.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 带有图标的\n  en-US: With an Icon\n---\n\n## zh-CN\n\n图标放在文字前面。\n\n## en-US\n\nThe icon should be placed in front of the text.\n"
  },
  {
    "path": "components/breadcrumb/demo/with-icon.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-demo-breadcrumb-with-icon',\n  imports: [NzBreadCrumbModule, NzIconModule],\n  template: `\n    <nz-breadcrumb>\n      <nz-breadcrumb-item>\n        <nz-icon nzType=\"home\" />\n      </nz-breadcrumb-item>\n      <nz-breadcrumb-item>\n        <a>\n          <nz-icon nzType=\"user\" />\n          <span>Application List</span>\n        </a>\n      </nz-breadcrumb-item>\n      <nz-breadcrumb-item>Application</nz-breadcrumb-item>\n    </nz-breadcrumb>\n  `\n})\nexport class NzDemoBreadcrumbWithIconComponent {}\n"
  },
  {
    "path": "components/breadcrumb/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Navigation\ntitle: Breadcrumb\ncover: 'https://gw.alipayobjects.com/zos/alicdn/9Ltop8JwH/Breadcrumb.svg'\ndescription: Displays the current location within a hierarchy. And allow going back to states higher up in the hierarchy.\n---\n\n## When To Use\n\n- When the system has more than two layers in a hierarchy.\n- When you need to inform the user of where they are.\n- When the user may need to navigate back to a higher level.\n- When the application has multi-layer architecture.\n\n## API\n\n### nz-breadcrumb\n\n| Property           | Description                                                                                                                                                                                                      | Type                                  | Default          |\n| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | ---------------- |\n| `[nzSeparator]`    | Custom separator                                                                                                                                                                                                 | `string \\| TemplateRef<void> \\| null` | `'/'`            |\n| `[nzAutoGenerate]` | Auto generate breadcrumb                                                                                                                                                                                         | `boolean`                             | `false`          |\n| `[nzRouteLabel]`   | Name of property that determines displayed text in routing config. It should be used when `nzAutoGenerate` is `true`                                                                                             | `string`                              | `'breadcrumb'`   |\n| `[nzRouteLabelFn]` | Format breadcrumb item label text, normally used in international app to translate i18n key. It should be used when `nzAutoGenerate` is `true`                                                                   | `(label:string) => string`            | `label => label` |\n| `[nzRouteFn]`      | Format breadcrumb item route, normally used in international app to bind current params or query strings to avoid losing them while navigate using breadcrumb. It should be used when `nzAutoGenerate` is `true` | `(route:string) => route`             | `route => route` |\n\nUsing `[nzAutoGenerate]` by configuring `data` like this:\n\n```ts\n{\n  path: '/path',\n  component: SomeComponent,\n  data: {\n    breadcrumb: 'Display Name'\n  }\n}\n```\n\nFor lazy loading modules, you should write `data` in parent module like this:\n\n```ts\n{\n  path: 'first',\n  loadChildren: () => import('./first/first.module').then(m => m.FirstModule),\n  data: {\n    breadcrumb: 'First'\n  },\n}\n```\n\nUse `nzRouteLabel` to custom `data` breadcrumb label:\n\n```html\n<nz-breadcrumb [nzAutoGenerate]=\"true\" [nzRouteLabel]=\"'customBreadcrumb'\"></nz-breadcrumb>\n```\n\n```ts\n{\n  path: 'path',\n  component: SomeComponent,\n  data: {\n    customBreadcrumb: 'Display Name'\n  }\n}\n```\n\nUse `nzRouteLabelFn` to format breadcrumb label in international application:\n\n```html\n<nz-breadcrumb\n  [nzAutoGenerate]=\"true\"\n  [nzRouteLabel]=\"'breadcrumbI18nKey'\"\n  [nzRouteLabelFn]=\"translateFn\"\n></nz-breadcrumb>\n```\n\n```ts\n// In Route\n{\n  path: 'path',\n  component: SomeComponent,\n  data: {\n    breadcrumbI18nKey: 'i18n.aaa.bbbb'\n  }\n}\n\n// In component\ntranslateFn = (key:string) => this.yourI18nService.translate(key);\n```\n\nUse `nzRouteFn` to format or bind params and query strings to the route it self in international application:\n\n```html\n<nz-breadcrumb\n  [nzAutoGenerate]=\"true\"\n  [nzRouteLabel]=\"'breadcrumbI18nKey'\"\n  [nzRouteLabelFn]=\"translateFn\"\n  [nzRouteFn]=\"customRoute\"\n></nz-breadcrumb>\n```\n\n```ts\n// In component\nbindCurrentParams(params, route) {\n  let newRoute = route;\n  for (const key in params) {\n    if (params.hasOwnProperty(key)) {\n      newRoute += `;${key}=${params[key]}`;\n    }\n  }\n  return newRoute;\n}\n\nconst params = this.activatedRoute.snapshot.params;\n\ncustomRoute = (route:string) => this.bindCurrentParams(params,route);\n```\n"
  },
  {
    "path": "components/breadcrumb/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 面包屑\ntype: 导航\ntitle: Breadcrumb\ncover: 'https://gw.alipayobjects.com/zos/alicdn/9Ltop8JwH/Breadcrumb.svg'\ndescription: 显示当前页面在系统层级结构中的位置，并能向上返回。\n---\n\n## 何时使用\n\n- 当系统拥有超过两级以上的层级结构时；\n- 当需要告知用户『你在哪里』时；\n- 当需要向上导航的功能时。\n\n## API\n\n### nz-breadcrumb\n\n| 参数               | 说明                                                                                               | 类型                                  | 默认值           |\n| ------------------ | -------------------------------------------------------------------------------------------------- | ------------------------------------- | ---------------- |\n| `[nzSeparator]`    | 分隔符自定义                                                                                       | `string \\| TemplateRef<void> \\| null` | `'/'`            |\n| `[nzAutoGenerate]` | 自动生成 Breadcrumb                                                                                | `boolean`                             | `false`          |\n| `[nzRouteLabel]`   | 自定义 route data 属性名称，`nzAutoGenerate` 为 `true` 时才生效                                    | `string`                              | `'breadcrumb'`   |\n| `[nzRouteLabelFn]` | 格式化面包屑导航项的显示文字，通常用于在国际化应用中翻译键值， `nzAutoGenerate` 为 `true` 时才生效 | `(label:string) => string`            | `label => label` |\n| `[nzRouteFn]`      | 格式化面包屑路由格式，可用于为 URL 添加 query params，`nzAutoGenerate` 为 `true` 时才生效          | `(route:string) => route`             | `route => route` |\n\n使用 `[nzAutoGenerate]` 时，需要在路由类中定义 `data`:\n\n```ts\n{\n  path: 'path',\n  component: SomeComponent,\n  data: {\n    breadcrumb: 'Display Name'\n  }\n}\n```\n\n对于懒加载路由，应该在父层路由写 `data`：\n\n```ts\n{\n  path: 'first',\n  loadChildren: () => import('./first/first.module').then(m => m.FirstModule),\n  data: {\n    breadcrumb: 'First'\n  },\n}\n```\n\n使用 `nzRouteLabel` 自定义路由属性名称:\n\n```html\n<nz-breadcrumb [nzAutoGenerate]=\"true\" [nzRouteLabel]=\"'customBreadcrumb'\"></nz-breadcrumb>\n```\n\n```ts\n{\n  path: 'path',\n  component: SomeComponent,\n  data: {\n    customBreadcrumb: 'Display Name'\n  }\n}\n```\n\n使用 `nzRouteLabelFn` 在国际化应用中格式化面包屑导航项的文本:\n\n```html\n<nz-breadcrumb\n  [nzAutoGenerate]=\"true\"\n  [nzRouteLabel]=\"'breadcrumbI18nKey'\"\n  [nzRouteLabelFn]=\"translateFn\"\n></nz-breadcrumb>\n```\n\n```ts\n// In Route\n{\n  path: 'path',\n  component: SomeComponent,\n  data: {\n    breadcrumbI18nKey: 'i18n.aaa.bbbb'\n  }\n}\n\n// In component\ntranslateFn = (key: string) => this.yourI18nService.translate(key);\n```\n\n使用 `nzRouteFn` 来使用格式化 URL 或添加 query params：\n\n```html\n<nz-breadcrumb\n  [nzAutoGenerate]=\"true\"\n  [nzRouteLabel]=\"'breadcrumbI18nKey'\"\n  [nzRouteLabelFn]=\"translateFn\"\n  [nzRouteFn]=\"customRoute\"\n></nz-breadcrumb>\n```\n\n```ts\n// In component\nbindCurrentParams(params, route) {\n  let newRoute = route;\n  for (const key in params) {\n    if (params.hasOwnProperty(key)) {\n      newRoute += `;${key}=${params[key]}`;\n    }\n  }\n  return newRoute;\n}\n\nconst params = this.activatedRoute.snapshot.params;\n\ncustomRoute = (route:string) => this.bindCurrentParams(params,route);\n```\n"
  },
  {
    "path": "components/breadcrumb/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/breadcrumb/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/breadcrumb/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './breadcrumb-item.component';\nexport * from './breadcrumb.component';\nexport * from './breadcrumb.module';\nexport * from './breadcrumb-separator.component';\n"
  },
  {
    "path": "components/breadcrumb/style/entry.less",
    "content": "@import './index.less';\n@import './patch.less';\n"
  },
  {
    "path": "components/breadcrumb/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@breadcrumb-prefix-cls: ~'@{ant-prefix}-breadcrumb';\n\n.@{breadcrumb-prefix-cls} {\n  .reset-component();\n\n  color: @breadcrumb-base-color;\n  font-size: @breadcrumb-font-size;\n\n  .@{iconfont-css-prefix} {\n    font-size: @breadcrumb-icon-font-size;\n  }\n\n  ol {\n    display: flex;\n    flex-wrap: wrap;\n    margin: 0;\n    padding: 0;\n    list-style: none;\n  }\n\n  a {\n    color: @breadcrumb-link-color;\n    transition: color 0.3s;\n\n    &:hover {\n      color: @breadcrumb-link-color-hover;\n    }\n  }\n\n  li:last-child {\n    color: @breadcrumb-last-item-color;\n\n    a {\n      color: @breadcrumb-last-item-color;\n    }\n  }\n\n  li:last-child > &-separator {\n    display: none;\n  }\n\n  &-separator {\n    margin: @breadcrumb-separator-margin;\n    color: @breadcrumb-separator-color;\n  }\n\n  &-link {\n    > .@{iconfont-css-prefix} + span,\n    > .@{iconfont-css-prefix} + a {\n      margin-left: 4px;\n    }\n  }\n\n  &-overlay-link {\n    > .@{iconfont-css-prefix} {\n      margin-left: 4px;\n    }\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/breadcrumb/style/patch.less",
    "content": ".@{breadcrumb-prefix-cls} {\n  &-link {\n    .@{iconfont-css-prefix} + span {\n      margin-left: 4px;\n    }\n  }\n\n  // We introduced an extra layer.\n  & > nz-breadcrumb-item:last-child {\n    color: @breadcrumb-last-item-color;\n\n    a {\n      color: @breadcrumb-last-item-color;\n    }\n  }\n\n  &-rtl {\n    > nz-breadcrumb-item {\n      float: right;\n    }\n  }\n}\n\nnz-breadcrumb {\n  display: block;\n}\n\nnz-breadcrumb-item:last-child .@{breadcrumb-prefix-cls}-separator {\n  display: none;\n}\n"
  },
  {
    "path": "components/breadcrumb/style/rtl.less",
    "content": ".@{breadcrumb-prefix-cls} {\n  &-rtl {\n    .clearfix();\n    direction: rtl;\n\n    > span {\n      float: right;\n    }\n  }\n\n  &-link {\n    > .@{iconfont-css-prefix} + span,\n    > .@{iconfont-css-prefix} + a {\n      .@{breadcrumb-prefix-cls}-rtl & {\n        margin-right: 4px;\n        margin-left: 0;\n      }\n    }\n  }\n\n  &-overlay-link {\n    > .@{iconfont-css-prefix} {\n      .@{breadcrumb-prefix-cls}-rtl & {\n        margin-right: 4px;\n        margin-left: 0;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/button/button.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport {\n  AfterContentInit,\n  afterEveryRender,\n  AfterViewInit,\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  computed,\n  contentChild,\n  ContentChild,\n  DestroyRef,\n  ElementRef,\n  inject,\n  Input,\n  OnChanges,\n  OnInit,\n  Renderer2,\n  signal,\n  SimpleChanges,\n  viewChild,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Subject } from 'rxjs';\nimport { filter, startWith } from 'rxjs/operators';\n\nimport { NzConfigKey, onConfigChangeEventForComponent, WithConfig } from 'ng-zorro-antd/core/config';\nimport { NZ_FORM_SIZE } from 'ng-zorro-antd/core/form';\nimport { NzSizeLDSType } from 'ng-zorro-antd/core/types';\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\nimport { NzIconDirective, NzIconModule } from 'ng-zorro-antd/icon';\nimport { NZ_SPACE_COMPACT_ITEM_TYPE, NZ_SPACE_COMPACT_SIZE, NzSpaceCompactItemDirective } from 'ng-zorro-antd/space';\n\nexport type NzButtonType = 'primary' | 'default' | 'dashed' | 'link' | 'text' | null;\nexport type NzButtonShape = 'circle' | 'round' | null;\nexport type NzButtonSize = NzSizeLDSType;\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'button';\n\n@Component({\n  selector: 'button[nz-button], a[nz-button]',\n  exportAs: 'nzButton',\n  imports: [NzIconModule],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    @if (nzLoading) {\n      <span class=\"ant-btn-icon ant-btn-loading-icon\">\n        <nz-icon nzType=\"loading\" />\n      </span>\n    }\n    <ng-content />\n  `,\n  host: {\n    class: 'ant-btn',\n    '[class.ant-btn-default]': `nzType === 'default'`,\n    '[class.ant-btn-primary]': `nzType === 'primary'`,\n    '[class.ant-btn-dashed]': `nzType === 'dashed'`,\n    '[class.ant-btn-link]': `nzType === 'link'`,\n    '[class.ant-btn-text]': `nzType === 'text'`,\n    '[class.ant-btn-circle]': `nzShape === 'circle'`,\n    '[class.ant-btn-round]': `nzShape === 'round'`,\n    '[class.ant-btn-lg]': `finalSize() === 'large'`,\n    '[class.ant-btn-sm]': `finalSize() === 'small'`,\n    '[class.ant-btn-dangerous]': `nzDanger`,\n    '[class.ant-btn-loading]': `nzLoading`,\n    '[class.ant-btn-background-ghost]': `nzGhost`,\n    '[class.ant-btn-block]': `nzBlock`,\n    '[class.ant-input-search-button]': `nzSearch`,\n    '[class.ant-btn-rtl]': `dir() === 'rtl'`,\n    '[class.ant-btn-icon-only]': `iconOnly()`,\n    '[attr.tabindex]': 'disabled ? -1 : (tabIndex === null ? null : tabIndex)',\n    '[attr.disabled]': 'disabled || null'\n  },\n  hostDirectives: [NzSpaceCompactItemDirective],\n  providers: [{ provide: NZ_SPACE_COMPACT_ITEM_TYPE, useValue: 'btn' }]\n})\nexport class NzButtonComponent implements OnChanges, AfterViewInit, AfterContentInit, OnInit {\n  private elementRef: ElementRef<HTMLButtonElement | HTMLAnchorElement> = inject(ElementRef);\n  private cdr = inject(ChangeDetectorRef);\n  private renderer = inject(Renderer2);\n  private destroyRef = inject(DestroyRef);\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  @ContentChild(NzIconDirective, { read: ElementRef }) nzIconDirectiveElement!: ElementRef;\n  @Input({ transform: booleanAttribute }) nzBlock: boolean = false;\n  @Input({ transform: booleanAttribute }) nzGhost: boolean = false;\n  /**\n   * @deprecated Will be removed in v22.0.0. Please use `nz-input-search` instead.\n   */\n  @Input({ transform: booleanAttribute }) nzSearch: boolean = false;\n  @Input({ transform: booleanAttribute }) nzLoading: boolean = false;\n  @Input({ transform: booleanAttribute }) nzDanger: boolean = false;\n  @Input({ transform: booleanAttribute }) disabled: boolean = false;\n  @Input() tabIndex: number | string | null = null;\n  @Input() nzType: NzButtonType = null;\n  @Input() nzShape: NzButtonShape = null;\n  @Input() @WithConfig() nzSize: NzButtonSize = 'default';\n  protected readonly dir = inject(Directionality).valueSignal;\n\n  private readonly elementOnly = signal(false);\n  private readonly size = signal<NzSizeLDSType>(this.nzSize);\n\n  private readonly formSize = inject(NZ_FORM_SIZE, { optional: true });\n\n  private readonly compactSize = inject(NZ_SPACE_COMPACT_SIZE, { optional: true });\n  private readonly loading$ = new Subject<boolean>();\n\n  protected readonly finalSize = computed(() => {\n    if (this.formSize?.()) {\n      return this.formSize();\n    }\n    if (this.compactSize) {\n      return this.compactSize();\n    }\n    return this.size();\n  });\n\n  readonly iconDir = contentChild(NzIconDirective);\n  readonly loadingIconDir = viewChild(NzIconDirective);\n\n  readonly iconOnly = computed(() => this.elementOnly() && (!!this.iconDir() || !!this.loadingIconDir()));\n\n  constructor() {\n    onConfigChangeEventForComponent(NZ_CONFIG_MODULE_NAME, () => {\n      this.size.set(this.nzSize);\n      this.cdr.markForCheck();\n    });\n\n    afterEveryRender({\n      read: () => {\n        const { children } = this.elementRef.nativeElement;\n        const visibleElement = Array.from(children).filter(\n          element => (element as HTMLElement).style.display !== 'none'\n        );\n        this.elementOnly.set(visibleElement.length === 1);\n      }\n    });\n  }\n\n  ngOnInit(): void {\n    this.size.set(this.nzSize);\n\n    // Caretaker note: this event listener could've been added through `host.click` or `HostListener`.\n    // The compiler generates the `ɵɵlistener` instruction which wraps the actual listener internally into the\n    // function, which runs `markDirty()` before running the actual listener (the decorated class method).\n    // Since we're preventing the default behavior and stopping event propagation this doesn't require Angular to run the change detection.\n    fromEventOutsideAngular<MouseEvent>(this.elementRef.nativeElement, 'click', { capture: true })\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(event => {\n        if ((this.disabled && (event.target as HTMLElement)?.tagName === 'A') || this.nzLoading) {\n          event.preventDefault();\n          event.stopImmediatePropagation();\n        }\n      });\n  }\n\n  ngOnChanges({ nzLoading, nzSize }: SimpleChanges): void {\n    if (nzLoading) {\n      this.loading$.next(this.nzLoading);\n    }\n    if (nzSize) {\n      this.size.set(nzSize.currentValue);\n    }\n  }\n\n  ngAfterViewInit(): void {\n    this.insertSpan();\n  }\n\n  ngAfterContentInit(): void {\n    this.loading$\n      .pipe(\n        startWith(this.nzLoading),\n        filter(() => !!this.nzIconDirectiveElement),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(loading => {\n        const nativeElement = this.nzIconDirectiveElement.nativeElement;\n        if (loading) {\n          this.renderer.setStyle(nativeElement, 'display', 'none');\n        } else {\n          this.renderer.removeStyle(nativeElement, 'display');\n        }\n      });\n  }\n\n  insertSpan(): void {\n    this.elementRef.nativeElement.childNodes.forEach(node => {\n      if (node.nodeType === Node.TEXT_NODE && node.textContent!.trim().length > 0) {\n        const span = this.renderer.createElement('span');\n        const parent = this.renderer.parentNode(node);\n        this.renderer.insertBefore(parent, span, node);\n        this.renderer.appendChild(span, node);\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "components/button/button.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { ɵNzTransitionPatchModule as NzTransitionPatchModule } from 'ng-zorro-antd/core/transition-patch';\nimport { NzWaveModule } from 'ng-zorro-antd/core/wave';\n\nimport { NzButtonComponent } from './button.component';\n\n@NgModule({\n  imports: [NzButtonComponent],\n  exports: [NzButtonComponent, NzTransitionPatchModule, NzWaveModule]\n})\nexport class NzButtonModule {}\n"
  },
  {
    "path": "components/button/button.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport {\n  ApplicationRef,\n  Component,\n  Input,\n  provideZoneChangeDetection,\n  signal,\n  ViewChild,\n  WritableSignal\n} from '@angular/core';\nimport { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { NZ_FORM_SIZE } from 'ng-zorro-antd/core/form';\nimport { NzSafeAny, NzSizeLDSType } from 'ng-zorro-antd/core/types';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\nimport { NZ_SPACE_COMPACT_SIZE } from 'ng-zorro-antd/space';\n\nimport { NzButtonComponent, NzButtonModule, NzButtonShape, NzButtonSize, NzButtonType } from './index';\n\ndescribe('button', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideZoneChangeDetection()]\n    });\n  });\n\n  describe('className', () => {\n    let fixture: ComponentFixture<TestButtonComponent>;\n    let component: TestButtonComponent;\n    let buttonElement: HTMLButtonElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(TestButtonComponent);\n      component = fixture.componentInstance;\n      buttonElement = fixture.debugElement.query(By.directive(NzButtonComponent)).nativeElement;\n    });\n\n    it('should apply classname', () => {\n      expect(buttonElement.className).toBe('ant-btn');\n    });\n\n    it('should apply classname based on nzDanger', () => {\n      expect(buttonElement.classList).not.toContain('ant-btn-dangerous');\n      component.nzDanger = true;\n      fixture.detectChanges();\n      expect(buttonElement.classList).toContain('ant-btn-dangerous');\n    });\n\n    it('should apply classname based on nzGhost', () => {\n      expect(buttonElement.classList).not.toContain('ant-btn-background-ghost');\n      component.nzGhost = true;\n      fixture.detectChanges();\n      expect(buttonElement.classList).toContain('ant-btn-background-ghost');\n    });\n\n    it('should apply classname based on nzSearch', () => {\n      expect(buttonElement.classList).not.toContain('ant-input-search-button');\n      component.nzSearch = true;\n      fixture.detectChanges();\n      expect(buttonElement.classList).toContain('ant-input-search-button');\n    });\n\n    it('should apply classname based on nzLoading', () => {\n      expect(buttonElement.classList).not.toContain('ant-btn-loading');\n      component.nzLoading = true;\n      fixture.detectChanges();\n      expect(buttonElement.classList).toContain('ant-btn-loading');\n    });\n\n    it('should apply classname based on nzBlock', () => {\n      expect(buttonElement.classList).not.toContain('ant-btn-block');\n      component.nzBlock = true;\n      fixture.detectChanges();\n      expect(buttonElement.classList).toContain('ant-btn-block');\n    });\n\n    it('should apply classname based on nzType', () => {\n      component.nzType = 'default';\n      fixture.detectChanges();\n      expect(buttonElement.classList).toContain('ant-btn-default');\n      component.nzType = 'primary';\n      fixture.detectChanges();\n      expect(buttonElement.classList).toContain('ant-btn-primary');\n      component.nzType = 'link';\n      fixture.detectChanges();\n      expect(buttonElement.classList).toContain('ant-btn-link');\n      component.nzType = 'dashed';\n      fixture.detectChanges();\n      expect(buttonElement.classList).toContain('ant-btn-dashed');\n      component.nzType = null;\n      fixture.detectChanges();\n      expect(buttonElement.className).toBe('ant-btn');\n    });\n\n    it('should apply classname based on nzShape', () => {\n      component.nzShape = 'round';\n      fixture.detectChanges();\n      expect(buttonElement.classList).toContain('ant-btn-round');\n      component.nzShape = 'circle';\n      fixture.detectChanges();\n      expect(buttonElement.classList).toContain('ant-btn-circle');\n    });\n\n    it('should apply classname based on nzSize', () => {\n      component.nzSize = 'large';\n      fixture.detectChanges();\n      expect(buttonElement.classList).toContain('ant-btn-lg');\n      component.nzSize = 'small';\n      fixture.detectChanges();\n      expect(buttonElement.classList).toContain('ant-btn-sm');\n      component.nzSize = 'default';\n      fixture.detectChanges();\n      expect(buttonElement.className).toBe('ant-btn');\n    });\n  });\n\n  describe('loading icon', () => {\n    let fixture: ComponentFixture<TestButtonBindingComponent>;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(TestButtonBindingComponent);\n    });\n\n    it('should hide icon when loading correct', fakeAsync(() => {\n      fixture.detectChanges();\n      const buttonElement = fixture.debugElement.query(By.directive(NzButtonComponent)).nativeElement;\n      expect(buttonElement.classList.contains('ant-btn-loading')).toBe(false);\n      expect(buttonElement.classList).not.toContain('ant-btn-icon-only');\n      expect(buttonElement.firstElementChild.querySelector('svg')).not.toBe(null);\n      expect(buttonElement.firstElementChild!.classList.contains('anticon-poweroff')).toBe(true);\n      expect(buttonElement.firstElementChild!.classList.contains('anticon-loading')).toBe(false);\n      buttonElement.click();\n      fixture.detectChanges();\n      expect(buttonElement.classList.contains('ant-btn-loading')).toBe(true);\n      expect(buttonElement.firstElementChild!.classList.contains('ant-btn-loading-icon')).toBe(true);\n      expect(buttonElement.querySelector('.anticon-poweroff').style.cssText).toBe('display: none;');\n      tick(1000);\n      fixture.detectChanges();\n      expect(buttonElement.classList.contains('ant-btn-loading')).toBe(false);\n      expect(buttonElement.firstElementChild!.classList.contains('ant-btn-loading-icon')).toBe(false);\n      expect(buttonElement.querySelector('.anticon-poweroff').style.cssText).toBe('');\n    }));\n  });\n\n  describe('insert span', () => {\n    let fixture: ComponentFixture<TestButtonWithIconComponent>;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(TestButtonWithIconComponent);\n    });\n\n    it('should insert span correctly', () => {\n      const buttonElement = fixture.debugElement.query(By.directive(NzButtonComponent)).nativeElement;\n      fixture.detectChanges();\n      expect(buttonElement.firstElementChild.tagName).toBe('SPAN');\n      expect(buttonElement.firstElementChild.innerText).toContain('text');\n    });\n  });\n\n  describe('icon only', () => {\n    it('should icon only works correctly', async () => {\n      const fixture = TestBed.createComponent(TestButtonIconOnlyComponent);\n      const buttonElement = fixture.debugElement.query(By.directive(NzButtonComponent)).nativeElement;\n      fixture.autoDetectChanges();\n      await fixture.whenStable();\n      expect(buttonElement.classList).toContain('ant-btn-icon-only');\n    });\n\n    it('should icon only works correctly with any tag', async () => {\n      const fixture = TestBed.createComponent(TestButtonIconOnlyWithAnyTagComponent);\n      const buttonElement = fixture.debugElement.query(By.directive(NzButtonComponent)).nativeElement;\n      fixture.autoDetectChanges();\n      await fixture.whenStable();\n      expect(buttonElement.classList).toContain('ant-btn-icon-only');\n    });\n\n    it('should icon only works correctly with any comments', async () => {\n      const fixture = TestBed.createComponent(TestButtonIconOnlyWithCommentComponent);\n      const buttonElement = fixture.debugElement.query(By.directive(NzButtonComponent)).nativeElement;\n      fixture.autoDetectChanges();\n      await fixture.whenStable();\n      expect(buttonElement.classList).toContain('ant-btn-icon-only');\n    });\n\n    it('should icon only works correctly with any text', async () => {\n      const fixture = TestBed.createComponent(TestButtonIconOnlyWithTextComponent);\n      const buttonElement = fixture.debugElement.query(By.directive(NzButtonComponent)).nativeElement;\n      fixture.autoDetectChanges();\n      await fixture.whenStable();\n      expect(buttonElement.classList).not.toContain('ant-btn-icon-only');\n    });\n\n    it('should icon only works correctly without nz-icon', async () => {\n      const fixture = TestBed.createComponent(TestButtonIconOnlyWithoutIconComponent);\n      const buttonElement = fixture.debugElement.query(By.directive(NzButtonComponent)).nativeElement;\n      fixture.autoDetectChanges();\n      await fixture.whenStable();\n      expect(buttonElement.classList).not.toContain('ant-btn-icon-only');\n    });\n\n    it('should icon only loading works correctly', async () => {\n      const fixture = TestBed.createComponent(TestButtonIconOnlyLoadingComponent);\n      const buttonElement = fixture.debugElement.query(By.directive(NzButtonComponent)).nativeElement;\n      fixture.autoDetectChanges();\n      await fixture.whenStable();\n      expect(buttonElement.classList).toContain('ant-btn-icon-only');\n    });\n  });\n\n  describe('RTL', () => {\n    let fixture: ComponentFixture<TestButtonRtlComponent>;\n    let buttonElement: HTMLButtonElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(TestButtonRtlComponent);\n      buttonElement = fixture.debugElement.query(By.directive(NzButtonComponent)).nativeElement;\n    });\n\n    it('should apply classname', () => {\n      fixture.detectChanges();\n      expect(buttonElement.classList).toContain('ant-btn-rtl');\n\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n      expect(buttonElement.classList).not.toContain('ant-btn-rtl');\n    });\n  });\n\n  describe('change detection', () => {\n    let fixture: ComponentFixture<TestButtonComponent>;\n    let buttonElement: HTMLButtonElement;\n    let component: TestButtonComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(TestButtonComponent);\n      buttonElement = fixture.debugElement.query(By.directive(NzButtonComponent)).nativeElement;\n      component = fixture.componentInstance;\n    });\n\n    it('should not trigger change detection when the button is clicked', () => {\n      const appRef = TestBed.inject(ApplicationRef);\n      const spy = spyOn(appRef, 'tick').and.callThrough();\n      buttonElement.dispatchEvent(new MouseEvent('click'));\n      buttonElement.dispatchEvent(new MouseEvent('click'));\n      // Previously, it would've caused `tick()` to be called 2 times, because 2 click events have been triggered.\n      expect(spy).toHaveBeenCalledTimes(0);\n    });\n\n    it('prevent default and stop propagation when the button state is loading', fakeAsync(() => {\n      component.nzLoading = true;\n      fixture.detectChanges();\n      const event = new MouseEvent('click');\n      const preventDefaultSpy = spyOn(event, 'preventDefault').and.callThrough();\n      const stopImmediatePropagationSpy = spyOn(event, 'stopImmediatePropagation').and.callThrough();\n      buttonElement.dispatchEvent(event);\n      expect(preventDefaultSpy).toHaveBeenCalledTimes(1);\n      expect(stopImmediatePropagationSpy).toHaveBeenCalledTimes(1);\n    }));\n  });\n\n  describe('basic', () => {\n    let fixture: ComponentFixture<NzButtonComponent>;\n    let component: NzButtonComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzButtonComponent);\n      component = fixture.componentInstance;\n    });\n\n    it('correct value for listOfNode', () => {\n      component['elementRef'] = {\n        nativeElement: {} as NzSafeAny\n      };\n      expect(component.iconOnly()).toBeFalsy();\n    });\n  });\n});\n\ndescribe('anchor', () => {\n  let fixture: ComponentFixture<TestAnchorComponent>;\n  let anchorElement: HTMLAnchorElement;\n  let component: TestAnchorComponent;\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(TestAnchorComponent);\n    anchorElement = fixture.debugElement.query(By.directive(NzButtonComponent)).nativeElement;\n    component = fixture.componentInstance;\n  });\n\n  it('should prevent default and stop propagation when the anchor is disabled', () => {\n    component.disabled = true;\n    fixture.detectChanges();\n    const event = new MouseEvent('click');\n    const preventDefaultSpy = spyOn(event, 'preventDefault').and.callThrough();\n    const stopImmediatePropagationSpy = spyOn(event, 'stopImmediatePropagation').and.callThrough();\n    anchorElement.dispatchEvent(event);\n    expect(preventDefaultSpy).toHaveBeenCalledTimes(1);\n    expect(stopImmediatePropagationSpy).toHaveBeenCalledTimes(1);\n  });\n});\n\ndescribe('finalSize', () => {\n  let fixture: ComponentFixture<TestButtonFinalSizeComponent>;\n  let buttonElement: HTMLButtonElement;\n  let compactSizeSignal: WritableSignal<NzSizeLDSType>;\n  let formSizeSignal: WritableSignal<NzSizeLDSType>;\n\n  beforeEach(() => {\n    compactSizeSignal = signal<NzSizeLDSType>('large');\n    formSizeSignal = signal<NzSizeLDSType>('default');\n  });\n  afterEach(() => {\n    TestBed.resetTestingModule();\n  });\n\n  it('should set correctly the size from the formSize signal', () => {\n    TestBed.configureTestingModule({\n      providers: [\n        { provide: NZ_FORM_SIZE, useValue: formSizeSignal },\n        { provide: NZ_SPACE_COMPACT_SIZE, useValue: compactSizeSignal }\n      ]\n    });\n    fixture = TestBed.createComponent(TestButtonFinalSizeComponent);\n    buttonElement = fixture.debugElement.query(By.directive(NzButtonComponent)).nativeElement;\n    fixture.detectChanges();\n    formSizeSignal.set('large');\n    fixture.detectChanges();\n    expect(buttonElement.classList).toContain('ant-btn-lg');\n  });\n  it('should set correctly the size from the compactSize signal', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_SPACE_COMPACT_SIZE, useValue: compactSizeSignal }]\n    });\n    fixture = TestBed.createComponent(TestButtonFinalSizeComponent);\n    buttonElement = fixture.debugElement.query(By.directive(NzButtonComponent)).nativeElement;\n    fixture.detectChanges();\n    expect(buttonElement.classList).toContain('ant-btn-lg');\n  });\n  it('should set correctly the size from the component input', () => {\n    fixture = TestBed.createComponent(TestButtonFinalSizeComponent);\n    buttonElement = fixture.debugElement.query(By.directive(NzButtonComponent)).nativeElement;\n    fixture.componentInstance.size = 'large';\n    fixture.detectChanges();\n    expect(buttonElement.classList).toContain('ant-btn-lg');\n  });\n});\n\n@Component({\n  imports: [NzButtonModule],\n  template: `\n    <button\n      nz-button\n      [nzType]=\"nzType\"\n      [nzGhost]=\"nzGhost\"\n      [nzSearch]=\"nzSearch\"\n      [nzLoading]=\"nzLoading\"\n      [nzDanger]=\"nzDanger\"\n      [nzShape]=\"nzShape\"\n      [nzBlock]=\"nzBlock\"\n      [nzSize]=\"nzSize\"\n    >\n      button\n    </button>\n  `\n})\nexport class TestButtonComponent {\n  @Input() nzBlock: boolean = false;\n  @Input() nzGhost: boolean = false;\n  @Input() nzSearch: boolean = false;\n  @Input() nzLoading: boolean = false;\n  @Input() nzDanger: boolean = false;\n  @Input() nzType: NzButtonType = null;\n  @Input() nzShape: NzButtonShape = null;\n  @Input() nzSize: NzButtonSize = 'default';\n}\n\n// https://github.com/NG-ZORRO/ng-zorro-antd/issues/2191\n@Component({\n  imports: [NzIconModule, NzButtonModule],\n  template: `\n    <button nz-button nzType=\"primary\" (click)=\"load()\" [nzLoading]=\"loading\">\n      <nz-icon nzType=\"poweroff\" />\n      {{ 'Click me!' }}\n    </button>\n  `\n})\nexport class TestButtonBindingComponent {\n  loading = false;\n  load(): void {\n    this.loading = true;\n    setTimeout(() => (this.loading = false), 1000);\n  }\n}\n\n// https://github.com/NG-ZORRO/ng-zorro-antd/issues/3079\n@Component({\n  imports: [NzIconModule, NzButtonModule],\n  template: `\n    <button nz-button>\n      text\n      <nz-icon nzType=\"caret-down\" />\n    </button>\n  `\n})\nexport class TestButtonWithIconComponent {}\n\n@Component({\n  imports: [NzIconModule, NzButtonModule],\n  template: `\n    <button nz-button>\n      <nz-icon nzType=\"caret-down\" />\n    </button>\n  `\n})\nexport class TestButtonIconOnlyComponent {}\n\n@Component({\n  imports: [NzIconModule, NzButtonModule],\n  template: `\n    <button nz-button>\n      <u nz-icon nzType=\"up\"></u>\n    </button>\n  `\n})\nexport class TestButtonIconOnlyWithAnyTagComponent {}\n\n@Component({\n  imports: [NzIconModule, NzButtonModule],\n  template: `\n    <button nz-button>\n      <nz-icon nzType=\"down\" />\n      <!-- comment -->\n    </button>\n  `\n})\nexport class TestButtonIconOnlyWithCommentComponent {}\n\n@Component({\n  imports: [NzIconModule, NzButtonModule],\n  template: `\n    <button nz-button>\n      <nz-icon nzType=\"down\" />\n      text\n    </button>\n  `\n})\nexport class TestButtonIconOnlyWithTextComponent {}\n\n@Component({\n  imports: [NzButtonModule],\n  template: `\n    <button nz-button>\n      <span>text</span>\n    </button>\n  `\n})\nexport class TestButtonIconOnlyWithoutIconComponent {}\n\n@Component({\n  imports: [NzIconModule, NzButtonModule],\n  template: `\n    <button nz-button nzLoading>\n      <nz-icon nzType=\"caret-down\" />\n    </button>\n  `\n})\nexport class TestButtonIconOnlyLoadingComponent {}\n\n@Component({\n  imports: [BidiModule, NzButtonModule],\n  template: `\n    <div [dir]=\"direction\">\n      <button\n        nz-button\n        [nzType]=\"nzType\"\n        [nzGhost]=\"nzGhost\"\n        [nzSearch]=\"nzSearch\"\n        [nzLoading]=\"nzLoading\"\n        [nzDanger]=\"nzDanger\"\n        [nzShape]=\"nzShape\"\n        [nzBlock]=\"nzBlock\"\n        [nzSize]=\"nzSize\"\n      >\n        button\n      </button>\n    </div>\n  `\n})\nexport class TestButtonRtlComponent extends TestButtonComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n}\n\n@Component({\n  imports: [NzButtonModule],\n  template: '<a nz-button [disabled]=\"disabled\">anchor</a>'\n})\nexport class TestAnchorComponent {\n  disabled = false;\n}\n\n@Component({\n  imports: [NzButtonModule],\n  template: ` <button nz-button [nzSize]=\"size\">Button</button> `\n})\nexport class TestButtonFinalSizeComponent {\n  size: NzButtonSize = 'default';\n}\n"
  },
  {
    "path": "components/button/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 按钮类型\n  en-US: Type\n---\n\n## zh-CN\n\n按钮有五种类型：主按钮、次按钮、虚线按钮、文本按钮和链接按钮。主按钮在同一个操作区域最多出现一次。\n\n## en-US\n\nThere are `primary` button, `default` button, `dashed` button, `text` button and `link` button in antd.\n"
  },
  {
    "path": "components/button/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\n\n@Component({\n  selector: 'nz-demo-button-basic',\n  imports: [NzButtonModule],\n  template: `\n    <button nz-button nzType=\"primary\">Primary Button</button>\n    <button nz-button nzType=\"default\">Default Button</button>\n    <button nz-button nzType=\"dashed\">Dashed Button</button>\n    <button nz-button nzType=\"text\">Text Button</button>\n    <a nz-button nzType=\"link\">Link Button</a>\n  `,\n  styles: `\n    [nz-button] {\n      margin-right: 8px;\n      margin-bottom: 12px;\n    }\n  `\n})\nexport class NzDemoButtonBasicComponent {}\n"
  },
  {
    "path": "components/button/demo/block.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: Block 按钮\n  en-US: Block Button\n---\n\n## zh-CN\n\n`nzBlock` 属性将使按钮适合其父宽度。\n\n## en-US\n\n`nzBlock` property will make the button fit to its parent width.\n"
  },
  {
    "path": "components/button/demo/block.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\n\n@Component({\n  selector: 'nz-demo-button-block',\n  imports: [NzButtonModule],\n  template: `\n    <button nz-button nzType=\"primary\" nzBlock>Primary</button>\n    <button nz-button nzType=\"default\" nzBlock>Default</button>\n    <button nz-button nzType=\"dashed\" nzBlock>Dashed</button>\n    <button nz-button nzType=\"text\" nzBlock>Text</button>\n    <a nz-button nzType=\"link\" nzBlock>Link</a>\n  `,\n  styles: `\n    [nz-button] {\n      margin-bottom: 12px;\n    }\n  `\n})\nexport class NzDemoButtonBlockComponent {}\n"
  },
  {
    "path": "components/button/demo/danger.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 危险按钮\n  en-US: Danger Buttons\n---\n\n## zh-CN\n\n使用 `nzDanger` 将按钮标识为危险状态。\n\n## en-US\n\nYou can use `nzDanger` to mark button as danger status.\n"
  },
  {
    "path": "components/button/demo/danger.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\n\n@Component({\n  selector: 'nz-demo-button-danger',\n  imports: [NzButtonModule],\n  template: `\n    <button nz-button nzType=\"primary\" nzDanger>Primary</button>\n    <button nz-button nzType=\"default\" nzDanger>Default</button>\n    <button nz-button nzType=\"dashed\" nzDanger>Dashed</button>\n    <button nz-button nzType=\"text\" nzDanger>Text</button>\n    <a nz-button nzType=\"link\" nzDanger>Link</a>\n  `,\n  styles: `\n    [nz-button] {\n      margin-right: 8px;\n      margin-bottom: 12px;\n    }\n  `\n})\nexport class NzDemoButtonDangerComponent {}\n"
  },
  {
    "path": "components/button/demo/disabled.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 不可用状态\n  en-US: Disabled\n---\n\n## zh-CN\n\n添加 `disabled` 属性即可让按钮处于不可用状态，同时按钮样式也会改变。\n\n## en-US\n\nTo mark a button as disabled, add the `disabled` property to the `Button`.\n"
  },
  {
    "path": "components/button/demo/disabled.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\n\n@Component({\n  selector: 'nz-demo-button-disabled',\n  imports: [NzButtonModule],\n  template: `\n    <button nz-button nzType=\"primary\">Primary</button>\n    <button nz-button nzType=\"primary\" disabled>Primary(disabled)</button>\n    <br />\n    <button nz-button nzType=\"default\">Default</button>\n    <button nz-button nzType=\"default\" disabled>Default(disabled)</button>\n    <br />\n    <button nz-button nzType=\"dashed\">Dashed</button>\n    <button nz-button nzType=\"dashed\" disabled>Dashed(disabled)</button>\n    <br />\n    <a nz-button nzType=\"text\">Text</a>\n    <a nz-button nzType=\"text\" disabled>Text(disabled)</a>\n    <br />\n    <a nz-button nzType=\"link\">Link</a>\n    <a nz-button nzType=\"link\" disabled>Link(disabled)</a>\n    <br />\n    <a nz-button nzType=\"text\" nzDanger>Danger Text</a>\n    <a nz-button nzType=\"text\" disabled nzDanger>Danger Text(disabled)</a>\n    <br />\n    <a nz-button nzType=\"link\" nzDanger>Danger Link</a>\n    <a nz-button nzType=\"link\" disabled nzDanger>Danger Link(disabled)</a>\n    <br />\n    <button nz-button nzType=\"default\" nzDanger>Danger Default</button>\n    <button nz-button nzType=\"default\" disabled nzDanger>Danger Default(disabled)</button>\n    <div class=\"ghost-background\">\n      <button nz-button nzGhost>Ghost</button>\n      <button nz-button nzGhost disabled>Ghost(disabled)</button>\n    </div>\n  `,\n  styles: `\n    [nz-button] {\n      margin-right: 8px;\n      margin-bottom: 12px;\n    }\n\n    .ghost-background {\n      padding: 8px;\n      background: rgb(190, 200, 200);\n    }\n\n    .ghost-background [nz-button] {\n      margin-right: 8px;\n      margin-bottom: 0;\n    }\n  `\n})\nexport class NzDemoButtonDisabledComponent {}\n"
  },
  {
    "path": "components/button/demo/ghost.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 幽灵按钮\n  en-US: Ghost Button\n---\n\n## zh-CN\n\n添加 `nzGhost` 属性后，幽灵按钮将其他按钮的内容反色，背景变为透明，常用在有色背景上。\n\n## en-US\n\n`nzGhost` property will make button's background transparent, it is common used in colored background.\n"
  },
  {
    "path": "components/button/demo/ghost.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\n\n@Component({\n  selector: 'nz-demo-button-ghost',\n  imports: [NzButtonModule],\n  template: `\n    <div class=\"ghost-background\">\n      <button nz-button nzType=\"primary\" nzGhost>Primary</button>\n      <button nz-button nzType=\"default\" nzGhost>Default</button>\n      <button nz-button nzType=\"dashed\" nzGhost>Dashed</button>\n      <a nz-button nzType=\"link\" nzGhost>Link</a>\n    </div>\n  `,\n  styles: `\n    .ghost-background {\n      padding: 8px;\n      background: rgb(190, 200, 200);\n    }\n\n    [nz-button] {\n      margin-right: 8px;\n    }\n  `\n})\nexport class NzDemoButtonGhostComponent {}\n"
  },
  {
    "path": "components/button/demo/icon.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 图标按钮\n  en-US: Icon\n---\n\n## zh-CN\n\n当需要在 `nz-button` 内嵌入图标时，可以直接在 `nz-button` 内嵌入对应的 `icon`。\n\n## en-US\n\n`nz-button` components can contain an `icon`. Just placing an `icon` within the `nz-button`\n"
  },
  {
    "path": "components/button/demo/icon.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-demo-button-icon',\n  imports: [NzButtonModule, NzIconModule],\n  template: `\n    <button nz-button nzType=\"primary\" nzShape=\"circle\">\n      <nz-icon nzType=\"search\" />\n    </button>\n    <button nz-button nzType=\"primary\" nzShape=\"circle\">A</button>\n    <button nz-button nzType=\"primary\">\n      <nz-icon nzType=\"search\" />\n      Search\n    </button>\n    <button nz-button nzType=\"default\" nzShape=\"circle\">\n      <nz-icon nzType=\"search\" />\n    </button>\n    <button nz-button nzType=\"default\">\n      <nz-icon nzType=\"search\" />\n      Search\n    </button>\n    <br />\n    <button nz-button nzType=\"default\" nzShape=\"circle\"><nz-icon nzType=\"search\" /></button>\n    <button nz-button nzType=\"default\">\n      <nz-icon nzType=\"search\" />\n      Search\n    </button>\n    <button nz-button nzType=\"dashed\" nzShape=\"circle\"><nz-icon nzType=\"search\" /></button>\n    <button nz-button nzType=\"dashed\">\n      <nz-icon nzType=\"search\" />\n      Search\n    </button>\n  `,\n  styles: `\n    [nz-button] {\n      margin-right: 8px;\n      margin-bottom: 12px;\n    }\n  `\n})\nexport class NzDemoButtonIconComponent {}\n"
  },
  {
    "path": "components/button/demo/loading.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 加载中状态\n  en-US: Loading\n---\n\n## zh-CN\n\n添加 `nzLoading` 属性即可让按钮处于加载状态，最后两个按钮演示点击后进入加载状态。\n\n## en-US\n\nA loading indicator can be added to a button by setting the `nzLoading` property on the `nz-button`.\n"
  },
  {
    "path": "components/button/demo/loading.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-demo-button-loading',\n  imports: [NzButtonModule, NzIconModule],\n  template: `\n    <button nz-button nzType=\"primary\" nzLoading>\n      <nz-icon nzType=\"poweroff\" />\n      Loading\n    </button>\n    <button nz-button nzType=\"primary\" nzSize=\"small\" nzLoading>Loading</button>\n    <br />\n    <button nz-button nzType=\"primary\" (click)=\"loadOne()\" [nzLoading]=\"isLoadingOne\">Click me!</button>\n    <button nz-button nzType=\"primary\" (click)=\"loadTwo()\" [nzLoading]=\"isLoadingTwo\">\n      <nz-icon nzType=\"poweroff\" />\n      Click me!\n    </button>\n    <br />\n    <button nz-button nzLoading nzShape=\"circle\"></button>\n    <button nz-button nzLoading nzType=\"primary\" nzShape=\"circle\"></button>\n  `,\n  styles: `\n    [nz-button] {\n      margin-right: 8px;\n      margin-bottom: 12px;\n    }\n  `\n})\nexport class NzDemoButtonLoadingComponent {\n  isLoadingOne = false;\n  isLoadingTwo = false;\n\n  loadOne(): void {\n    this.isLoadingOne = true;\n    setTimeout(() => {\n      this.isLoadingOne = false;\n    }, 5000);\n  }\n\n  loadTwo(): void {\n    this.isLoadingTwo = true;\n    setTimeout(() => {\n      this.isLoadingTwo = false;\n    }, 5000);\n  }\n}\n"
  },
  {
    "path": "components/button/demo/multiple.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 多个按钮组合\n  en-US: Multiple Buttons\n---\n\n## zh-CN\n\n按钮组合使用时，推荐使用1个主操作 + n 个次操作，3个以上操作时把更多操作放到 `nz-dropdown` 中组合使用。\n\n## en-US\n\nIf you need several buttons, we recommend that you use 1 primary button + n secondary buttons, and if there are more than three operations, you can group some of them into `nz-dropdown`.\n"
  },
  {
    "path": "components/button/demo/multiple.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzDropdownModule } from 'ng-zorro-antd/dropdown';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-demo-button-multiple',\n  imports: [NzButtonModule, NzDropdownModule, NzIconModule],\n  template: `\n    <button nz-button nzType=\"primary\">primary</button>\n    <button nz-button nzType=\"default\">secondary</button>\n    <button nz-button nz-dropdown [nzDropdownMenu]=\"menu\">\n      Actions\n      <nz-icon nzType=\"down\" />\n    </button>\n    <nz-dropdown-menu #menu=\"nzDropdownMenu\">\n      <ul nz-menu>\n        <li nz-menu-item>\n          <a>1st item</a>\n        </li>\n        <li nz-menu-item>\n          <a>2nd item</a>\n        </li>\n        <li nz-menu-item>\n          <a>3rd item</a>\n        </li>\n      </ul>\n    </nz-dropdown-menu>\n  `,\n  styles: `\n    [nz-button] {\n      margin-right: 8px;\n      margin-bottom: 12px;\n    }\n  `\n})\nexport class NzDemoButtonMultipleComponent {}\n"
  },
  {
    "path": "components/button/demo/size.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 按钮尺寸\n  en-US: Size\n---\n\n## zh-CN\n\n按钮有大、中、小三种尺寸。\n\n通过设置 `nzSize` 为 `large` `small` 分别把按钮设为大、小尺寸。若不设置 `nzSize`，则尺寸为中。\n\n## en-US\n\nAnt Design supports a default button size as well as a large and small size.\n\nIf a large or small button is desired, set the `nzSize` property to either `large` or `small` respectively. Omit the `nzSize` property for a button with the default size.\n"
  },
  {
    "path": "components/button/demo/size.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule, NzButtonSize } from 'ng-zorro-antd/button';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\n\n@Component({\n  selector: 'nz-demo-button-size',\n  imports: [FormsModule, NzButtonModule, NzIconModule, NzRadioModule, NzSpaceModule],\n  template: `\n    <nz-radio-group [(ngModel)]=\"size\">\n      <label nz-radio-button nzValue=\"large\">Large</label>\n      <label nz-radio-button nzValue=\"default\">Default</label>\n      <label nz-radio-button nzValue=\"small\">Small</label>\n    </nz-radio-group>\n    <br />\n    <br />\n    <button nz-button [nzSize]=\"size\" nzType=\"primary\">Primary</button>\n    <button nz-button [nzSize]=\"size\" nzType=\"default\">Default</button>\n    <button nz-button [nzSize]=\"size\" nzType=\"dashed\">Dashed</button>\n    <a nz-button [nzSize]=\"size\" nzType=\"link\">Link</a>\n    <br />\n    <button nz-button nzType=\"primary\" [nzSize]=\"size\">\n      <nz-icon nzType=\"download\" />\n    </button>\n    <button nz-button nzType=\"primary\" [nzSize]=\"size\" nzShape=\"circle\">\n      <nz-icon nzType=\"download\" />\n    </button>\n    <button nz-button nzType=\"primary\" [nzSize]=\"size\" nzShape=\"round\">\n      <nz-icon nzType=\"download\" />\n    </button>\n    <button nz-button nzType=\"primary\" [nzSize]=\"size\" nzShape=\"round\">\n      <nz-icon nzType=\"download\" />\n      Download\n    </button>\n    <button nz-button nzType=\"primary\" [nzSize]=\"size\">\n      <nz-icon nzType=\"download\" />\n      Download\n    </button>\n    <br />\n    <nz-space-compact [nzSize]=\"size\">\n      <button nz-button nzType=\"primary\">\n        <nz-icon nzType=\"left\" />\n        Backward\n      </button>\n      <button nz-button nzType=\"primary\">\n        Forward\n        <nz-icon nzType=\"right\" />\n      </button>\n    </nz-space-compact>\n  `,\n  styles: `\n    [nz-button] {\n      margin-right: 8px;\n      margin-bottom: 12px;\n    }\n  `\n})\nexport class NzDemoButtonSizeComponent {\n  size: NzButtonSize = 'large';\n}\n"
  },
  {
    "path": "components/button/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: General\ntitle: Button\ncover: 'https://gw.alipayobjects.com/zos/alicdn/fNUKzY1sk/Button.svg'\ndescription: To trigger an operation.\n---\n\n## When To Use\n\nA button means an operation (or a series of operations). Clicking a button will trigger corresponding business logic.\n\nIn Ant Design, we provide 5 types of buttons.\n\n- 🔵 Primary button: indicate the main action, one primary button at most in one section.\n- ⚪️ Default button: indicate a series of actions without priority.\n- 🫥 Dashed button: used for adding action commonly.\n- 🔤 Text button: used for the most secondary action.\n- 🔗 Link button: used for external links.\n\nAnd 4 other properties additionally.\n\n- ⚠️ `danger`: used for risk actions, like deletion or authorization.\n- 👻 `ghost`: usually used in situations with a complex background, home pages.\n- 🚫 `disabled`: when actions are not available.\n- 🔃 `loading`: add loading spinner in button, avoiding multiple submit.\n\n## API\n\n### [nz-button]\n\n> Note：nz-button is a Directive, it accepts all props which are supported by [native button](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button).\n\nTo get a customized button, just set `nzType`/`nzShape`/`nzSize`/`nzLoading`/`disabled`.\n\n| Property      | Description                                                                   | Type                                  | Default     | Global Config |\n| ------------- | ----------------------------------------------------------------------------- | ------------------------------------- | ----------- | ------------- |\n| `[disabled]`  | prevents a user from interacting with the button                              | `boolean`                             | `false`     |\n| `[nzGhost]`   | make background transparent and invert text and border colors                 | `boolean`                             | `false`     |\n| `[nzLoading]` | set the loading status of button                                              | `boolean`                             | `false`     |\n| `[nzShape]`   | can be set to `circle` `round` or omitted                                     | `'circle'\\|'round'`                   | -           |               |\n| `[nzSize]`    | can be set to `small` `large` or omitted                                      | `'large'\\|'small'\\|'default'`         | `'default'` | ✅            |\n| `[nzType]`    | can be set to `primary` `dashed` `text` `link` or omitted (meaning `default`) | `'primary'\\|'dashed'\\|'link'\\|'text'` | -           |\n| `[nzBlock]`   | option to fit button width to its parent width                                | `boolean`                             | `false`     |\n| `[nzDanger]`  | set the danger status of button                                               | boolean                               | `false`     |               |\n"
  },
  {
    "path": "components/button/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ntype: 通用\ntitle: Button\nsubtitle: 按钮\ncover: 'https://gw.alipayobjects.com/zos/alicdn/fNUKzY1sk/Button.svg'\ndescription: 按钮用于开始一个即时操作。\n---\n\n## 何时使用\n\n标记了一个（或封装一组）操作命令，响应用户点击行为，触发相应的业务逻辑。\n\n在 Ant Design 中，我们有五种按钮。\n\n- 🔵 主按钮：用于主行动点，一个操作区域只能有一个主按钮。\n- ⚪️ 默认按钮：用于没有主次之分的一组行动点。\n- 🫥 虚线按钮：常用于添加操作。\n- 🔤 文本按钮：用于最次级的行动点。\n- 🔗 链接按钮：一般用于链接，即导航至某位置。\n\n以及四种状态属性与上面配合使用。\n\n- ⚠️ 危险：删除/移动/修改权限等危险操作，一般需要二次确认。\n- 👻 幽灵：用于背景色比较复杂的地方，常用在首页/产品页等展示场景。\n- 🚫 禁用：行动点不可用的时候，一般需要文案解释。\n- 🔃 加载中：用于异步操作等待反馈的时候，也可以避免多次提交。\n\n## API\n\n### [nz-button]\n\n> 注意：nz-button 是一个 Directive，除以下表格之外还支持例如 disabled 等原生 button 的[所有属性](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/button)。\n\n通过设置 Button 的属性来产生不同的按钮样式，推荐顺序为：`nzType` -> `nzShape` -> `nzSize` -> `nzLoading` -> `disabled`\n\n按钮的属性说明如下：\n\n| 属性          | 说明                                                             | 类型                                  | 默认值      | 支持全局配置 |\n| ------------- | ---------------------------------------------------------------- | ------------------------------------- | ----------- | ------------ |\n| `[disabled]`  | 禁止与 button 交互                                               | `boolean`                             | `false`     |\n| `[nzGhost]`   | 幽灵属性，使按钮背景透明                                         | `boolean`                             | `false`     |\n| `[nzLoading]` | 设置按钮载入状态                                                 | `boolean`                             | `false`     |\n| `[nzShape]`   | 设置按钮形状，可选值为 `circle` `round` 或者不设                 | `'circle'\\|'round'`                   | -           |              |\n| `[nzSize]`    | 设置按钮大小，可选值为 `small` `large` 或者不设                  | `'large'\\|'small'\\|'default'`         | `'default'` | ✅           |\n| `[nzType]`    | 设置按钮类型，可选值为 `primary` `dashed` `text` `link` 或者不设 | `'primary'\\|'dashed'\\|'link'\\|'text'` | -           |\n| `[nzBlock]`   | 将按钮宽度调整为其父宽度的选项                                   | `boolean`                             | `false`     |\n| `[nzDanger]`  | 设置危险按钮                                                     | boolean                               | `false`     |              |\n"
  },
  {
    "path": "components/button/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/button/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/button/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './button.component';\nexport * from './button.module';\n"
  },
  {
    "path": "components/button/style/entry.less",
    "content": "@import './index.less';\n"
  },
  {
    "path": "components/button/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import './mixin';\n\n@btn-prefix-cls: ~'@{ant-prefix}-btn';\n\n// for compatible\n@btn-ghost-color: @text-color;\n@btn-ghost-bg: transparent;\n@btn-ghost-border: @border-color-base;\n\n// Button styles\n// -----------------------------\n.@{btn-prefix-cls} {\n  // Fixing https://github.com/ant-design/ant-design/issues/12978\n  // Fixing https://github.com/ant-design/ant-design/issues/20058\n  // Fixing https://github.com/ant-design/ant-design/issues/19972\n  // Fixing https://github.com/ant-design/ant-design/issues/18107\n  // Fixing https://github.com/ant-design/ant-design/issues/13214\n  // It is a render problem of chrome, which is only happened in the codesandbox demo\n  // 0.001px solution works and I don't know why\n  line-height: @btn-line-height;\n  .btn();\n  .btn-default();\n\n  // Fix loading button animation\n  // https://github.com/ant-design/ant-design/issues/24323\n  > span {\n    display: inline-block;\n  }\n\n  &-primary {\n    .btn-primary();\n\n    .@{btn-prefix-cls}-group &:not(:first-child):not(:last-child) {\n      border-right-color: @btn-group-border;\n      border-left-color: @btn-group-border;\n\n      &:disabled {\n        border-color: @btn-default-border;\n      }\n    }\n\n    .@{btn-prefix-cls}-group &:first-child {\n      &:not(:last-child) {\n        border-right-color: @btn-group-border;\n\n        &[disabled] {\n          border-right-color: @btn-default-border;\n        }\n      }\n    }\n\n    .@{btn-prefix-cls}-group &:last-child:not(:first-child),\n    .@{btn-prefix-cls}-group & + & {\n      border-left-color: @btn-group-border;\n\n      &[disabled] {\n        border-left-color: @btn-default-border;\n      }\n    }\n  }\n\n  &-ghost {\n    .btn-ghost();\n  }\n\n  &-dashed {\n    .btn-dashed();\n  }\n\n  // type=\"danger\" will deprecated\n  // use danger instead\n  &-danger {\n    .btn-danger();\n  }\n\n  &-link {\n    .btn-link();\n  }\n\n  &-text {\n    .btn-text();\n  }\n\n  &-dangerous {\n    .btn-danger-default();\n  }\n\n  &-dangerous&-primary {\n    .btn-danger();\n  }\n\n  &-dangerous&-link {\n    .btn-danger-link();\n  }\n\n  &-dangerous&-text {\n    .btn-danger-text();\n  }\n\n  &-icon-only {\n    .btn-square(@btn-prefix-cls);\n    vertical-align: -3px;\n\n    > .@{iconfont-css-prefix} {\n      display: flex;\n      justify-content: center;\n    }\n\n    .@{iconfont-css-prefix}-loading {\n      padding: 0 !important;\n    }\n  }\n\n  // https://github.com/ant-design/ant-design/issues/32365\n  a&-icon-only {\n    vertical-align: -1px;\n\n    > .@{iconfont-css-prefix} {\n      display: inline;\n    }\n  }\n\n  &-round {\n    .btn-round(@btn-prefix-cls);\n    &.@{btn-prefix-cls}-icon-only {\n      width: auto;\n    }\n  }\n\n  &-circle {\n    .btn-circle(@btn-prefix-cls);\n  }\n\n  &::before {\n    position: absolute;\n    top: -@btn-border-width;\n    right: -@btn-border-width;\n    bottom: -@btn-border-width;\n    left: -@btn-border-width;\n    z-index: 1;\n    display: none;\n    background: @component-background;\n    border-radius: inherit;\n    opacity: 0.35;\n    transition: opacity 0.2s;\n    content: '';\n    pointer-events: none;\n  }\n\n  .@{iconfont-css-prefix} {\n    transition: margin-left 0.3s @ease-in-out;\n\n    // Follow icon blur under windows. Change the render.\n    // https://github.com/ant-design/ant-design/issues/13924\n    &.@{iconfont-css-prefix}-plus,\n    &.@{iconfont-css-prefix}-minus {\n      > svg {\n        shape-rendering: optimizespeed;\n      }\n    }\n  }\n\n  &&-loading {\n    position: relative;\n    cursor: default;\n\n    &::before {\n      display: block;\n    }\n  }\n\n  & > &-loading-icon {\n    transition: width 0.3s @ease-in-out, opacity 0.3s @ease-in-out;\n\n    .@{iconfont-css-prefix} {\n      padding-right: @padding-xs;\n      animation: none;\n      // for smooth button padding transition\n      svg {\n        animation: loadingCircle 1s infinite linear;\n      }\n    }\n  }\n\n  &-group {\n    .btn-group(@btn-prefix-cls);\n  }\n\n  // http://stackoverflow.com/a/21281554/3040605\n  &:focus > span,\n  &:active > span {\n    position: relative;\n  }\n\n  // To ensure that a space will be placed between character and `Icon`.\n  > .@{iconfont-css-prefix} + span,\n  > span + .@{iconfont-css-prefix} {\n    margin-left: @margin-xs;\n  }\n\n  &&-background-ghost {\n    color: @btn-default-ghost-color;\n    border-color: @btn-default-ghost-border;\n\n    &,\n    &:hover,\n    &:active,\n    &:focus {\n      background: @btn-default-ghost-bg;\n    }\n\n    &:hover,\n    &:focus {\n      color: @primary-color-hover;\n      border-color: @primary-color-hover;\n    }\n\n    &:active {\n      color: @primary-color-active;\n      border-color: @primary-color-active;\n    }\n\n    &[disabled] {\n      color: @disabled-color;\n      background: @btn-default-ghost-bg;\n      border-color: @btn-default-border;\n    }\n  }\n\n  &-background-ghost&-primary {\n    .button-variant-ghost(@btn-primary-bg, @btn-primary-bg, @primary-color-hover, @primary-color-active);\n  }\n\n  &-background-ghost&-danger {\n    .button-variant-ghost(@btn-danger-border, @btn-danger-border, @error-color-hover, @error-color-active);\n  }\n\n  &-background-ghost&-dangerous {\n    .button-variant-ghost(@btn-danger-border, @btn-danger-border, @error-color-hover, @error-color-active);\n  }\n\n  &-background-ghost&-dangerous&-link {\n    .button-variant-ghost(@btn-danger-border, transparent, @error-color-hover, @error-color-active);\n  }\n\n  &-two-chinese-chars::first-letter {\n    letter-spacing: 0.34em;\n  }\n\n  &-two-chinese-chars > *:not(.@{iconfont-css-prefix}) {\n    margin-right: -0.34em;\n    letter-spacing: 0.34em;\n  }\n\n  &&-block {\n    width: 100%;\n  }\n\n  // https://github.com/ant-design/ant-design/issues/12681\n  // same method as Select\n  &:empty {\n    display: inline-block;\n    width: 0;\n    visibility: hidden;\n    content: '\\a0';\n  }\n}\n\na.@{btn-prefix-cls} {\n  // Fixing https://github.com/ant-design/ant-design/issues/12978\n  // https://github.com/ant-design/ant-design/issues/29978\n  // It is a render problem of chrome, which is only happened in the codesandbox demo\n  // 0.1px for padding-top solution works and I don't why\n  padding-top: 0.01px !important;\n  line-height: @btn-height-base - 2px;\n\n  &-disabled {\n    .btn-href-disabled();\n  }\n\n  &-lg {\n    line-height: @btn-height-lg - 2px;\n  }\n\n  &-sm {\n    line-height: @btn-height-sm - 2px;\n  }\n}\n\n@import './space-compact';\n@import './rtl';\n"
  },
  {
    "path": "components/button/style/mixin.less",
    "content": "// mixins for button\n// ------------------------\n.button-size(@height; @padding-horizontal; @font-size; @border-radius) {\n  @padding-vertical: max(\n    (round(((@height - @font-size * @line-height-base) / 2) * 10) / 10) - @border-width-base,\n    0\n  );\n  height: @height;\n  padding: @padding-vertical @padding-horizontal;\n  font-size: @font-size;\n  border-radius: @border-radius;\n}\n\n.button-color(@color; @background; @border) {\n  color: @color;\n  border-color: @border; // a inside Button which only work in Chrome\n  & when not(@background = null) {\n    background: @background;\n  }\n  // http://stackoverflow.com/a/17253457\n  > a:only-child {\n    color: currentcolor;\n\n    &::after {\n      position: absolute;\n      top: 0;\n      right: 0;\n      bottom: 0;\n      left: 0;\n      background: transparent;\n      content: '';\n    }\n  }\n}\n\n.button-disabled(@color: @btn-disable-color; @background: @btn-disable-bg; @border: @btn-disable-border) {\n  &[disabled] {\n    &,\n    &:hover,\n    &:focus,\n    &:active {\n      .button-color(@color; @background; @border);\n\n      text-shadow: none;\n      box-shadow: none;\n    }\n  }\n}\n\n.button-variant-primary(@color; @background; @backgroundHover: yellow; @backgroundActive: yellow) {\n  .button-color(@color; @background; @background);\n\n  text-shadow: @btn-text-shadow;\n  box-shadow: @btn-primary-shadow;\n\n  &:hover,\n  &:focus {\n    & when (@theme = dark) {\n      .button-color(\n        @color; colorPalette('@{background}', 7); colorPalette('@{background}', 7)\n      );\n    }\n    & when (not (@theme = dark) and not (@theme = variable)) {\n      .button-color(\n        @color; colorPalette('@{background}', 5); colorPalette('@{background}', 5)\n      );\n    }\n    & when (@theme = variable) {\n      .button-color(@color; @backgroundHover; @backgroundHover);\n    }\n  }\n\n  &:active {\n    & when (@theme = dark) {\n      .button-color(\n        @color; colorPalette('@{background}', 5); colorPalette('@{background}', 5)\n      );\n    }\n    & when (not (@theme = dark) and not (@theme = variable)) {\n      .button-color(\n        @color; colorPalette('@{background}', 7); colorPalette('@{background}', 7)\n      );\n    }\n    & when (@theme = variable) {\n      .button-color(@color; @backgroundActive; @backgroundActive);\n    }\n  }\n\n  .button-disabled();\n}\n\n.button-variant-other(@color; @background; @border) {\n  .button-color(@color; @background; @border);\n\n  &:hover,\n  &:focus {\n    & when (@theme = dark) {\n      .button-color(@primary-5; @background; @primary-5);\n    }\n    & when (not (@theme = dark) and not (@theme = variable)) {\n      .button-color(\n        colorPalette('@{btn-primary-bg}', 5); @background;\n          colorPalette('@{btn-primary-bg}', 5)\n      );\n    }\n    & when (@theme = variable) {\n      .button-color(@primary-color-hover; @background; @primary-color-hover);\n    }\n  }\n\n  &:active {\n    & when (@theme = dark) {\n      .button-color(@primary-7; @background; @primary-7);\n    }\n    & when (not (@theme = dark) and not (@theme = variable)) {\n      .button-color(\n        colorPalette('@{btn-primary-bg}', 7); @background;\n          colorPalette('@{btn-primary-bg}', 7)\n      );\n    }\n    & when (@theme = variable) {\n      .button-color(@primary-color-active; @background; @primary-color-active);\n    }\n  }\n  .button-disabled();\n}\n\n.button-variant-ghost(@color; @border; @borderHover: yellow; @borderActive: yellow) {\n  .button-color(@color; null; @border);\n  text-shadow: none;\n\n  &:hover,\n  &:focus {\n    & when (@border = transparent) {\n      & when (@theme = dark) {\n        .button-color(colorPalette('@{color}', 7); null; transparent);\n      }\n      & when (not (@theme = dark) and not (@theme = variable)) {\n        .button-color(colorPalette('@{color}', 5); null; transparent);\n      }\n      & when (@theme = variable) {\n        .button-color(@borderActive; transparent; transparent);\n      }\n    }\n    & when not (@border = transparent) {\n      & when (@theme = dark) {\n        .button-color(\n          colorPalette('@{color}', 7); null; colorPalette('@{color}', 7)\n        );\n      }\n      & when (not (@theme = dark) and not (@theme = variable)) {\n        .button-color(\n          colorPalette('@{color}', 5); null; colorPalette('@{color}', 5)\n        );\n      }\n      & when (@theme = variable) {\n        .button-color(@borderHover; transparent; @borderHover);\n      }\n    }\n  }\n\n  &:active {\n    & when (@border = transparent) {\n      & when (@theme = dark) {\n        .button-color(colorPalette('@{color}', 5); null; transparent);\n      }\n      & when (not (@theme = dark) and not (@theme = variable)) {\n        .button-color(colorPalette('@{color}', 7); null; transparent);\n      }\n      & when (@theme = variable) {\n        .button-color(@borderActive; transparent; transparent);\n      }\n    }\n    & when not (@border = transparent) {\n      & when (@theme = dark) {\n        .button-color(\n          colorPalette('@{color}', 5); null; colorPalette('@{color}', 5)\n        );\n      }\n      & when (not (@theme = dark) and not (@theme = variable)) {\n        .button-color(\n          colorPalette('@{color}', 7); null; colorPalette('@{color}', 7)\n        );\n      }\n      & when (@theme = variable) {\n        .button-color(@borderActive; transparent; @borderActive);\n      }\n    }\n  }\n  .button-disabled();\n}\n\n.button-group-base(@btnClassName) {\n  position: relative;\n  display: inline-flex;\n  > .@{btnClassName},\n  > span > .@{btnClassName} {\n    position: relative;\n\n    &:hover,\n    &:focus,\n    &:active {\n      z-index: 2;\n    }\n\n    &[disabled] {\n      z-index: 0;\n    }\n  }\n  .@{btnClassName}-icon-only {\n    font-size: @font-size-base;\n  }\n}\n// Base styles of buttons\n// --------------------------------------------------\n.btn() {\n  position: relative;\n  display: inline-block;\n  font-weight: @btn-font-weight;\n  white-space: nowrap;\n  text-align: center;\n  background-image: none;\n  border: @btn-border-width @btn-border-style transparent;\n  box-shadow: @btn-shadow;\n  cursor: pointer;\n  transition: all 0.3s @ease-in-out;\n  user-select: none;\n  touch-action: manipulation;\n  .button-size(\n    @btn-height-base; @btn-padding-horizontal-base; @font-size-base; @btn-border-radius-base\n  );\n  > .@{iconfont-css-prefix} {\n    line-height: 1;\n  }\n\n  &,\n  &:active,\n  &:focus {\n    outline: 0;\n  }\n\n  &:not([disabled]):hover {\n    text-decoration: none;\n  }\n\n  &:not([disabled]):active {\n    outline: 0;\n    box-shadow: none;\n  }\n\n  &[disabled] {\n    cursor: not-allowed;\n\n    > * {\n      pointer-events: none;\n    }\n  }\n\n  &-lg {\n    .button-size(\n      @btn-height-lg; @btn-padding-horizontal-lg; @btn-font-size-lg; @btn-border-radius-base\n    );\n  }\n\n  &-sm {\n    .button-size(\n      @btn-height-sm; @btn-padding-horizontal-sm; @btn-font-size-sm; @btn-border-radius-sm\n    );\n  }\n}\n// primary button style\n.btn-primary() {\n  .button-variant-primary(@btn-primary-color; @btn-primary-bg; @primary-color-hover; @primary-color-active);\n}\n// default button style\n.btn-default() {\n  .button-variant-other(@btn-default-color; @btn-default-bg; @btn-default-border; );\n\n  &:hover,\n  &:focus,\n  &:active {\n    text-decoration: none;\n    background: @btn-default-bg;\n  }\n}\n// ghost button style\n.btn-ghost() {\n  .button-variant-other(@btn-ghost-color, @btn-ghost-bg, @btn-ghost-border);\n}\n// dashed button style\n.btn-dashed() {\n  .button-variant-other(@btn-default-color, @btn-default-bg, @btn-default-border);\n  border-style: dashed;\n}\n// danger button style\n.btn-danger() {\n  .button-variant-primary(@btn-danger-color, @btn-danger-bg, @error-color-hover, @error-color-active);\n}\n// danger default button style\n.btn-danger-default() {\n  .button-color(@error-color, @btn-default-bg, @error-color);\n\n  &:hover,\n  &:focus {\n    & when (@theme = dark) {\n      .button-color(\n        colorPalette('@{error-color}', 7); @btn-default-bg; colorPalette('@{error-color}', 7)\n      );\n    }\n    & when (not (@theme = dark) and not (@theme = variable)) {\n      .button-color(\n        colorPalette('@{error-color}', 5); @btn-default-bg; colorPalette('@{error-color}', 5)\n      );\n    }\n    & when (@theme = variable) {\n      .button-color(@error-color-hover, @btn-default-bg, @error-color-hover);\n    }\n  }\n\n  &:active {\n    & when (@theme = dark) {\n      .button-color(\n        colorPalette('@{error-color}', 5); @btn-default-bg; colorPalette('@{error-color}', 5)\n      );\n    }\n    & when (not (@theme = dark) and not (@theme = variable)) {\n      .button-color(\n        colorPalette('@{error-color}', 7); @btn-default-bg; colorPalette('@{error-color}', 7)\n      );\n    }\n    & when (@theme = variable) {\n      .button-color(@error-color-active, @btn-default-bg, @error-color-active);\n    }\n  }\n  .button-disabled();\n}\n// danger link button style\n.btn-danger-link() {\n  .button-variant-other(@error-color, transparent, transparent);\n  box-shadow: none;\n\n  &:hover,\n  &:focus {\n    & when (@theme = dark) {\n      .button-color(colorPalette('@{error-color}', 7); transparent; transparent);\n    }\n    & when (not (@theme = dark) and not (@theme = variable)) {\n      .button-color(colorPalette('@{error-color}', 5); transparent; transparent);\n    }\n    & when (@theme = variable) {\n      .button-color(@error-color-hover; transparent; transparent);\n    }\n  }\n\n  &:active {\n    & when (@theme = dark) {\n      .button-color(colorPalette('@{error-color}', 5); transparent; transparent);\n    }\n    & when (not (@theme = dark) and not (@theme = variable)) {\n      .button-color(colorPalette('@{error-color}', 7); transparent; transparent);\n    }\n    & when (@theme = variable) {\n      .button-color(@error-color-active; transparent; transparent);\n    }\n  }\n  .button-disabled(@disabled-color; transparent; transparent);\n}\n// link button style\n.btn-link() {\n  .button-variant-other(@link-color, transparent, transparent);\n  box-shadow: none;\n\n  &:hover {\n    background: @btn-link-hover-bg;\n  }\n\n  &:hover,\n  &:focus,\n  &:active {\n    border-color: transparent;\n  }\n  .button-disabled(@disabled-color; transparent; transparent);\n}\n// link button disabled style\n.btn-href-disabled() {\n  cursor: not-allowed;\n\n  > * {\n    pointer-events: none;\n  }\n\n  &,\n  &:hover,\n  &:focus,\n  &:active {\n    .button-color(@btn-disable-color,transparent, transparent);\n\n    text-shadow: none;\n    box-shadow: none;\n  }\n}\n// text button style\n.btn-text() {\n  .button-variant-other(@text-color, transparent, transparent);\n  box-shadow: none;\n\n  &:hover,\n  &:focus {\n    color: @text-color;\n    background: @btn-text-hover-bg;\n    border-color: transparent;\n  }\n\n  &:active {\n    color: @text-color;\n    background: fadein(@btn-text-hover-bg, 1%);\n    border-color: transparent;\n  }\n\n  .button-disabled(@disabled-color; transparent; transparent);\n}\n.btn-danger-text() {\n  .button-variant-other(@error-color, transparent, transparent);\n  box-shadow: none;\n\n  &:hover,\n  &:focus {\n    & when (@theme = dark) {\n      .button-color(colorPalette('@{error-color}', 7); @btn-text-hover-bg; transparent);\n    }\n    & when (not (@theme = dark) and not (@theme = variable)) {\n      .button-color(colorPalette('@{error-color}', 5); @btn-text-hover-bg; transparent);\n    }\n    & when (@theme = variable) {\n      .button-color(@error-color-hover; @btn-text-hover-bg; transparent);\n    }\n  }\n\n  &:active {\n    & when (@theme = dark) {\n      .button-color(colorPalette('@{error-color}', 5); fadein(@btn-text-hover-bg, 1%); transparent);\n    }\n    & when (not (@theme = dark) and not (@theme = variable)) {\n      .button-color(colorPalette('@{error-color}', 7); fadein(@btn-text-hover-bg, 1%); transparent);\n    }\n    & when (@theme = variable) {\n      .button-color(@error-color-active; fadein(@btn-text-hover-bg, 1%); transparent);\n    }\n  }\n  .button-disabled(@disabled-color; transparent; transparent);\n}\n// round button\n.btn-round(@btnClassName: btn) {\n  .button-size(@btn-circle-size; (@btn-circle-size / 2); @font-size-base; @btn-circle-size);\n  &.@{btnClassName}-lg {\n    .button-size(\n      @btn-circle-size-lg; (@btn-circle-size-lg / 2); @btn-font-size-lg; @btn-circle-size-lg\n    );\n  }\n  &.@{btnClassName}-sm {\n    .button-size(\n      @btn-circle-size-sm; (@btn-circle-size-sm / 2); @font-size-base; @btn-circle-size-sm\n    );\n  }\n}\n// square button: the content only contains icon\n.btn-square(@btnClassName: btn) {\n  .square(@btn-square-size);\n  .button-size(@btn-square-size; 0; @btn-square-only-icon-size; @btn-border-radius-base);\n\n  & > * {\n    font-size: @btn-square-only-icon-size;\n  }\n  &.@{btnClassName}-lg {\n    .square(@btn-square-size-lg);\n    .button-size(@btn-square-size-lg; 0; @btn-square-only-icon-size-lg; @btn-border-radius-base);\n\n    & > * {\n      font-size: @btn-square-only-icon-size-lg;\n    }\n  }\n  &.@{btnClassName}-sm {\n    .square(@btn-square-size-sm);\n    .button-size(@btn-square-size-sm; 0; @btn-square-only-icon-size-sm; @btn-border-radius-base);\n\n    & > * {\n      font-size: @btn-square-only-icon-size-sm;\n    }\n  }\n}\n// circle button: the content only contains icon\n.btn-circle(@btnClassName: btn) {\n  min-width: @btn-height-base;\n  padding-right: 0;\n  padding-left: 0;\n  text-align: center;\n  border-radius: 50%;\n  &.@{btnClassName}-lg {\n    min-width: @btn-height-lg;\n    border-radius: 50%;\n  }\n  &.@{btnClassName}-sm {\n    min-width: @btn-height-sm;\n    border-radius: 50%;\n  }\n}\n// Horizontal button groups style\n// --------------------------------------------------\n.btn-group(@btnClassName: btn) {\n  .button-group-base(@btnClassName);\n  .@{btnClassName} + .@{btnClassName},\n  .@{btnClassName} + &,\n  span + .@{btnClassName},\n  .@{btnClassName} + span,\n  > span + span,\n  & + .@{btnClassName},\n  & + & {\n    margin-left: -1px;\n  }\n  .@{btnClassName}-primary + .@{btnClassName}:not(.@{btnClassName}-primary):not([disabled]) {\n    border-left-color: transparent;\n  }\n  .@{btnClassName} {\n    border-radius: 0;\n  }\n  > .@{btnClassName}:first-child,\n  > span:first-child > .@{btnClassName} {\n    margin-left: 0;\n  }\n  > .@{btnClassName}:only-child {\n    border-radius: @btn-border-radius-base;\n  }\n  > span:only-child > .@{btnClassName} {\n    border-radius: @btn-border-radius-base;\n  }\n  > .@{btnClassName}:first-child:not(:last-child),\n  > span:first-child:not(:last-child) > .@{btnClassName} {\n    border-top-left-radius: @btn-border-radius-base;\n    border-bottom-left-radius: @btn-border-radius-base;\n  }\n  > .@{btnClassName}:last-child:not(:first-child),\n  > span:last-child:not(:first-child) > .@{btnClassName} {\n    border-top-right-radius: @btn-border-radius-base;\n    border-bottom-right-radius: @btn-border-radius-base;\n  }\n\n  &-sm {\n    > .@{btnClassName}:only-child {\n      border-radius: @btn-border-radius-sm;\n    }\n    > span:only-child > .@{btnClassName} {\n      border-radius: @btn-border-radius-sm;\n    }\n    > .@{btnClassName}:first-child:not(:last-child),\n    > span:first-child:not(:last-child) > .@{btnClassName} {\n      border-top-left-radius: @btn-border-radius-sm;\n      border-bottom-left-radius: @btn-border-radius-sm;\n    }\n    > .@{btnClassName}:last-child:not(:first-child),\n    > span:last-child:not(:first-child) > .@{btnClassName} {\n      border-top-right-radius: @btn-border-radius-sm;\n      border-bottom-right-radius: @btn-border-radius-sm;\n    }\n  }\n\n  & > & {\n    float: left;\n  }\n  & > &:not(:first-child):not(:last-child) > .@{btnClassName} {\n    border-radius: 0;\n  }\n\n  & > &:first-child:not(:last-child) {\n    > .@{btnClassName}:last-child {\n      padding-right: 8px;\n      border-top-right-radius: 0;\n      border-bottom-right-radius: 0;\n    }\n  }\n  & > &:last-child:not(:first-child) > .@{btnClassName}:first-child {\n    padding-left: 8px;\n    border-top-left-radius: 0;\n    border-bottom-left-radius: 0;\n  }\n}\n"
  },
  {
    "path": "components/button/style/rtl.less",
    "content": ".@{btn-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &-primary {\n    .@{btn-prefix-cls}-group &:last-child:not(:first-child),\n    .@{btn-prefix-cls}-group & + & {\n      .@{btn-prefix-cls}-group-rtl& {\n        border-right-color: @btn-group-border;\n        border-left-color: @btn-default-border;\n      }\n\n      &[disabled] {\n        .@{btn-prefix-cls}-group-rtl& {\n          border-right-color: @btn-default-border;\n          border-left-color: @btn-group-border;\n        }\n      }\n    }\n  }\n\n  & > &-loading-icon {\n    .@{iconfont-css-prefix} {\n      .@{btn-prefix-cls}-rtl& {\n        padding-right: 0;\n        padding-left: @margin-xs;\n      }\n    }\n  }\n\n  > .@{iconfont-css-prefix} + span,\n  > span + .@{iconfont-css-prefix} {\n    .@{btn-prefix-cls}-rtl& {\n      margin-right: 8px;\n      margin-left: 0;\n    }\n  }\n}\n\n// mixin\n.btn-group(@btnClassName: btn) {\n  .@{btnClassName} + .@{btnClassName},\n  .@{btnClassName} + &,\n  span + .@{btnClassName},\n  .@{btnClassName} + span,\n  > span + span,\n  & + .@{btnClassName},\n  & + & {\n    .@{btnClassName}-rtl&,\n    .@{btnClassName}-group-rtl& {\n      margin-right: -1px;\n      margin-left: auto;\n    }\n  }\n\n  &.@{btnClassName}-group-rtl {\n    direction: rtl;\n  }\n\n  > .@{btnClassName}:first-child:not(:last-child),\n  > span:first-child:not(:last-child) > .@{btnClassName} {\n    .@{btnClassName}-group-rtl& {\n      border-radius: 0 @btn-border-radius-base @btn-border-radius-base 0;\n    }\n  }\n\n  > .@{btnClassName}:last-child:not(:first-child),\n  > span:last-child:not(:first-child) > .@{btnClassName} {\n    .@{btnClassName}-group-rtl& {\n      border-radius: @btn-border-radius-base 0 0 @btn-border-radius-base;\n    }\n  }\n\n  &-sm {\n    > .@{btnClassName}:first-child:not(:last-child),\n    > span:first-child:not(:last-child) > .@{btnClassName} {\n      .@{btnClassName}-group-rtl& {\n        border-radius: 0 @btn-border-radius-sm @btn-border-radius-sm 0;\n      }\n    }\n\n    > .@{btnClassName}:last-child:not(:first-child),\n    > span:last-child:not(:first-child) > .@{btnClassName} {\n      .@{btnClassName}-group-rtl& {\n        border-radius: @btn-border-radius-sm 0 0 @btn-border-radius-sm;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/button/style/space-compact.less",
    "content": "@import '../../style/mixins/index';\n\n@btn-prefix-cls: ~'@{ant-prefix}-btn';\n\n// Button in Space.Compact\n.@{btn-prefix-cls} {\n  .compact-item(@btn-prefix-cls);\n\n  // make `btn-icon-only` not too narrow\n  &-icon-only&-compact-item {\n    flex: none;\n  }\n\n  // Special styles for Primary Button\n  &-compact-item.@{btn-prefix-cls}-primary {\n    &:not([disabled]) + &:not([disabled]):not([ant-click-animating-without-extra-node='true']) {\n      position: relative;\n\n      &::after {\n        position: absolute;\n        top: -@border-width-base;\n        left: -@border-width-base;\n        display: inline-block;\n        width: @border-width-base;\n        height: calc(100% + @border-width-base * 2);\n        background-color: @btn-group-border;\n        content: ' ';\n      }\n    }\n  }\n\n  // ----------RTL----------\n  &-compact-item-rtl {\n    &.@{btn-prefix-cls}-compact-first-item&:not(.@{btn-prefix-cls}-compact-last-item) {\n      border-top-left-radius: 0;\n      border-bottom-left-radius: 0;\n    }\n\n    &.@{btn-prefix-cls}-compact-last-item&:not(.@{btn-prefix-cls}-compact-first-item) {\n      border-top-right-radius: 0;\n      border-bottom-right-radius: 0;\n    }\n\n    &.@{btn-prefix-cls}-sm {\n      &.@{btn-prefix-cls}-compact-first-item&:not(.@{btn-prefix-cls}-compact-last-item) {\n        border-top-left-radius: 0;\n        border-bottom-left-radius: 0;\n      }\n\n      &.@{btn-prefix-cls}-compact-last-item&:not(.@{btn-prefix-cls}-compact-first-item) {\n        border-top-right-radius: 0;\n        border-bottom-right-radius: 0;\n      }\n    }\n\n    // ----------RTL Special styles for Primary Button----------\n    &.@{btn-prefix-cls}-primary {\n      &:not([disabled]) + &:not([disabled]) {\n        &::after {\n          right: -@border-width-base;\n        }\n      }\n    }\n  }\n\n  // Button in Space.Compact when direction=vertical\n  .compact-item-vertical(@btn-prefix-cls);\n\n  // Special styles for Primary Button\n  &-compact-vertical-item {\n    &.@{btn-prefix-cls}-primary {\n      &:not([disabled]) + &:not([disabled]):not([ant-click-animating-without-extra-node='true']) {\n        position: relative;\n\n        &::after {\n          position: absolute;\n          top: -@border-width-base;\n          left: -@border-width-base;\n          display: inline-block;\n          width: calc(100% + @border-width-base * 2);\n          height: @border-width-base;\n          background-color: @btn-group-border;\n          content: ' ';\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/calendar/calendar-cells.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive } from '@angular/core';\n\n@Directive({\n  selector: '[nzDateCell]',\n  exportAs: 'nzDateCell'\n})\nexport class NzDateCellDirective {}\n\n@Directive({\n  selector: '[nzMonthCell]',\n  exportAs: 'nzMonthCell'\n})\nexport class NzMonthCellDirective {}\n\n@Directive({\n  selector: '[nzDateFullCell]',\n  exportAs: 'nzDateFullCell'\n})\nexport class NzDateFullCellDirective {}\n\n@Directive({\n  selector: '[nzMonthFullCell]',\n  exportAs: 'nzMonthFullCell'\n})\nexport class NzMonthFullCellDirective {}\n"
  },
  {
    "path": "components/calendar/calendar-header.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  EventEmitter,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  SimpleChanges,\n  TemplateRef,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzStringTemplateOutletDirective } from 'ng-zorro-antd/core/outlet';\nimport { CandyDate } from 'ng-zorro-antd/core/time';\nimport { DateHelperService, NzI18nService } from 'ng-zorro-antd/i18n';\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\nimport { NzSelectModule, NzSelectSizeType } from 'ng-zorro-antd/select';\n\n@Component({\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  selector: 'nz-calendar-header',\n  exportAs: 'nzCalendarHeader',\n  template: `\n    @if (nzCustomHeader) {\n      <ng-container *nzStringTemplateOutlet=\"nzCustomHeader\">{{ nzCustomHeader }}</ng-container>\n    } @else {\n      <div class=\"ant-picker-calendar-header\">\n        <nz-select\n          class=\"ant-picker-calendar-year-select\"\n          [nzSize]=\"size\"\n          [nzDropdownMatchSelectWidth]=\"false\"\n          [ngModel]=\"activeYear\"\n          (ngModelChange)=\"updateYear($event)\"\n        >\n          @for (year of years; track year.value) {\n            <nz-option [nzLabel]=\"year.label\" [nzValue]=\"year.value\" />\n          }\n        </nz-select>\n\n        @if (mode === 'month') {\n          <nz-select\n            class=\"ant-picker-calendar-month-select\"\n            [nzSize]=\"size\"\n            [nzDropdownMatchSelectWidth]=\"false\"\n            [ngModel]=\"activeMonth\"\n            (ngModelChange)=\"monthChange.emit($event)\"\n          >\n            @for (month of months; track month.value) {\n              <nz-option [nzLabel]=\"month.label\" [nzValue]=\"month.value\" />\n            }\n          </nz-select>\n        }\n\n        <nz-radio-group\n          class=\"ant-picker-calendar-mode-switch\"\n          [(ngModel)]=\"mode\"\n          (ngModelChange)=\"modeChange.emit($event)\"\n          [nzSize]=\"size\"\n        >\n          <label nz-radio-button nzValue=\"month\">{{ monthTypeText }}</label>\n          <label nz-radio-button nzValue=\"year\">{{ yearTypeText }}</label>\n        </nz-radio-group>\n      </div>\n    }\n  `,\n  host: {\n    class: 'ant-fullcalendar-header',\n    '[style.display]': `'block'`\n  },\n  imports: [NzSelectModule, FormsModule, NzRadioModule, NzStringTemplateOutletDirective]\n})\nexport class NzCalendarHeaderComponent implements OnInit, OnChanges {\n  private readonly dateHelper = inject(DateHelperService);\n  private readonly i18n = inject(NzI18nService);\n\n  @Input() mode: 'month' | 'year' = 'month';\n  @Input({ transform: booleanAttribute }) fullscreen: boolean = true;\n  @Input() activeDate: CandyDate = new CandyDate();\n  @Input() nzCustomHeader?: string | TemplateRef<void>;\n\n  @Output() readonly modeChange = new EventEmitter<'month' | 'year'>();\n  @Output() readonly yearChange = new EventEmitter<number>();\n  @Output() readonly monthChange = new EventEmitter<number>();\n\n  yearOffset: number = 10;\n  yearTotal: number = 20;\n  years: Array<{ label: string; value: number }> = [];\n  months: Array<{ label: string; value: number }> = [];\n\n  get activeYear(): number {\n    return this.activeDate.getYear();\n  }\n\n  get activeMonth(): number {\n    return this.activeDate.getMonth();\n  }\n\n  get size(): NzSelectSizeType {\n    return this.fullscreen ? 'default' : 'small';\n  }\n\n  get yearTypeText(): string {\n    return this.i18n.getLocale().Calendar.lang.year;\n  }\n\n  get monthTypeText(): string {\n    return this.i18n.getLocale().Calendar.lang.month;\n  }\n\n  ngOnInit(): void {\n    this.setUpYears();\n    this.setUpMonths();\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    if (changes['activeDate']) {\n      const previousActiveDate = changes['activeDate'].previousValue as CandyDate;\n      const currentActiveDate = changes['activeDate'].currentValue as CandyDate;\n      if (previousActiveDate?.getYear() !== currentActiveDate?.getYear()) {\n        this.setUpYears();\n      }\n    }\n  }\n\n  updateYear(year: number): void {\n    this.yearChange.emit(year);\n    this.setUpYears(year);\n  }\n\n  private setUpYears(year?: number): void {\n    const start = (year || this.activeYear) - this.yearOffset;\n    const end = start + this.yearTotal;\n\n    this.years = [];\n    for (let i = start; i < end; i++) {\n      this.years.push({ label: `${i}`, value: i });\n    }\n  }\n\n  private setUpMonths(): void {\n    this.months = [];\n\n    for (let i = 0; i < 12; i++) {\n      const dateInMonth = this.activeDate.setMonth(i);\n      const monthText = this.dateHelper.format(dateInMonth.nativeDate, 'MMM');\n      this.months.push({ label: monthText, value: i });\n    }\n  }\n}\n"
  },
  {
    "path": "components/calendar/calendar-header.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { registerLocaleData } from '@angular/common';\nimport zh from '@angular/common/locales/zh';\nimport { Component, provideZoneChangeDetection, TemplateRef, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';\nimport { FormsModule, NgModel } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { CandyDate } from 'ng-zorro-antd/core/time';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzCalendarHeaderComponent, NzCalendarHeaderComponent as CalendarHeader } from './calendar-header.component';\nimport { NzRadioGroupComponent as RadioGroup } from '../radio/index';\nimport { NzSelectComponent as Select } from '../select/select.component';\n\nregisterLocaleData(zh);\n\ndescribe('calendar Header', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), provideZoneChangeDetection()]\n    });\n  });\n\n  describe('mode', () => {\n    let fixture: ComponentFixture<NzTestCalendarHeaderModeComponent>;\n    let component: NzTestCalendarHeaderModeComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCalendarHeaderModeComponent);\n      component = fixture.componentInstance;\n    });\n\n    it('should be month by default', () => {\n      fixture.detectChanges();\n\n      const modeNgModel = fixture.debugElement\n        .queryAll(By.directive(CalendarHeader))[0]\n        .query(By.directive(RadioGroup))\n        .injector.get(NgModel);\n      expect(modeNgModel.model).toBe('month');\n    });\n\n    it('should update mode passed in', () => {\n      component.mode = 'year';\n\n      fixture.detectChanges();\n\n      const modeNgModel = fixture.debugElement\n        .queryAll(By.directive(CalendarHeader))[1]\n        .query(By.directive(RadioGroup))\n        .injector.get(NgModel);\n      expect(modeNgModel.model).toBe('year');\n    });\n\n    it('should emit change event for mode selection', () => {\n      fixture.detectChanges();\n\n      const modeNgModel = fixture.debugElement\n        .queryAll(By.directive(CalendarHeader))[1]\n        .query(By.directive(RadioGroup))\n        .injector.get(NgModel);\n      modeNgModel.viewToModelUpdate('year');\n\n      fixture.detectChanges();\n\n      expect(component.mode).toBe('year');\n    });\n  });\n\n  describe('fullscreen', () => {\n    let fixture: ComponentFixture<NzTestCalendarHeaderFullscreenComponent>;\n    let component: NzTestCalendarHeaderFullscreenComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCalendarHeaderFullscreenComponent);\n      component = fixture.componentInstance;\n    });\n\n    it('should be true by default', () => {\n      fixture.detectChanges();\n\n      const header = fixture.debugElement.queryAll(By.directive(CalendarHeader))[0];\n      const [yearSelect, monthSelect] = header.queryAll(By.directive(Select)).map(x => x.injector.get(Select));\n      const modeRadioGroup = header.query(By.directive(RadioGroup)).injector.get(RadioGroup);\n\n      expect(yearSelect.nzSize).not.toBe('small');\n      expect(monthSelect.nzSize).not.toBe('small');\n      expect(modeRadioGroup.nzSize).not.toBe('small');\n    });\n\n    it('should use small size when not in fullscreen', () => {\n      component.fullscreen = false;\n\n      fixture.detectChanges();\n\n      const header = fixture.debugElement.queryAll(By.directive(CalendarHeader))[1];\n      const [yearSelect, monthSelect] = header.queryAll(By.directive(Select)).map(x => x.injector.get(Select));\n      const modeRadioGroup = header.query(By.directive(RadioGroup)).injector.get(RadioGroup);\n\n      expect(yearSelect.nzSize).toBe('small');\n      expect(monthSelect.nzSize).toBe('small');\n      expect(modeRadioGroup.nzSize).toBe('small');\n    });\n  });\n\n  describe('activeDate', () => {\n    let fixture: ComponentFixture<NzTestCalendarHeaderActiveDateComponent>;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCalendarHeaderActiveDateComponent);\n    });\n\n    it('should be now by default', () => {\n      const now = new Date();\n\n      fixture.detectChanges();\n\n      const header = fixture.debugElement.queryAll(By.directive(CalendarHeader))[0];\n      const [yearModel, monthModel] = header.queryAll(By.directive(Select)).map(x => x.injector.get(NgModel));\n\n      expect(yearModel.model).toBe(now.getFullYear());\n      expect(monthModel.model).toBe(now.getMonth());\n    });\n\n    it('should update model binding to passed date', () => {\n      fixture.detectChanges();\n\n      const header = fixture.debugElement.queryAll(By.directive(CalendarHeader))[1];\n      const [yearModel, monthModel] = header.queryAll(By.directive(Select)).map(x => x.injector.get(NgModel));\n\n      expect(yearModel.model).toBe(2001);\n      expect(monthModel.model).toBe(1);\n      const headerComponent = header.injector.get(NzCalendarHeaderComponent);\n      expect(headerComponent.years[0].value).toBe(1991);\n    });\n  });\n\n  describe('changes', () => {\n    let fixture: ComponentFixture<NzTestCalendarHeaderChangesComponent>;\n    let component: NzTestCalendarHeaderChangesComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCalendarHeaderChangesComponent);\n      component = fixture.componentInstance;\n    });\n\n    it('should emit yearChange when year changed', fakeAsync(() => {\n      tick(1);\n      fixture.detectChanges();\n\n      const header = fixture.debugElement.queryAll(By.directive(CalendarHeader))[0];\n      const [yearModel] = header.queryAll(By.directive(Select)).map(x => x.injector.get(NgModel));\n\n      yearModel.viewToModelUpdate(2010);\n\n      fixture.detectChanges();\n\n      expect(component.year).toBe(2010);\n    }));\n\n    it('should emit monthChange when month changed', () => {\n      fixture.detectChanges();\n      const header = fixture.debugElement.queryAll(By.directive(CalendarHeader))[0];\n      const monthModel = header.queryAll(By.directive(Select)).map(x => x.injector.get(NgModel))[1];\n\n      monthModel.viewToModelUpdate(2);\n\n      fixture.detectChanges();\n\n      expect(component.month).toBe(2);\n    });\n\n    it('should update years when change year', () => {\n      const header = fixture.debugElement.queryAll(By.directive(CalendarHeader))[0];\n      const headerComponent = header.injector.get(NzCalendarHeaderComponent);\n      headerComponent.updateYear(2010);\n      expect(headerComponent.years[0].value).toBe(2000);\n    });\n  });\n\n  describe('custom Header', () => {\n    let fixture: ComponentFixture<NzTestCalendarHeaderChangesComponent>;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCalendarHeaderChangesComponent);\n    });\n\n    it('should have the default header if custom header is not passed', fakeAsync(() => {\n      fixture.componentInstance.customHeader = undefined;\n      tick(1);\n      fixture.detectChanges();\n\n      const defaultHeader = fixture.debugElement.query(By.css('.ant-picker-calendar-header'));\n      expect(defaultHeader).toBeTruthy();\n\n      fixture.componentInstance.customHeader = fixture.componentInstance.customHeaderElement;\n      tick(1);\n      fixture.detectChanges();\n\n      const defaultHeader2 = fixture.debugElement.query(By.css('.ant-picker-calendar-header'));\n      expect(defaultHeader2).toBeFalsy();\n    }));\n  });\n});\n\n@Component({\n  imports: [FormsModule, NzCalendarHeaderComponent],\n  template: `\n    <nz-calendar-header />\n    <nz-calendar-header [(mode)]=\"mode\" />\n  `\n})\nclass NzTestCalendarHeaderModeComponent {\n  mode: 'month' | 'year' = 'month';\n}\n\n@Component({\n  imports: [NzCalendarHeaderComponent],\n  template: `\n    <nz-calendar-header />\n    <nz-calendar-header [fullscreen]=\"fullscreen\" />\n  `\n})\nclass NzTestCalendarHeaderFullscreenComponent {\n  fullscreen = true;\n}\n\n@Component({\n  imports: [NzCalendarHeaderComponent],\n  template: `\n    <nz-calendar-header />\n    <nz-calendar-header [activeDate]=\"activeDate\" />\n  `\n})\nclass NzTestCalendarHeaderActiveDateComponent {\n  activeDate = new CandyDate(new Date(2001, 1, 3));\n}\n\n@Component({\n  imports: [NzCalendarHeaderComponent],\n  template: `\n    <nz-calendar-header [nzCustomHeader]=\"customHeader\" (yearChange)=\"year = $event\" (monthChange)=\"month = $event\" />\n\n    <ng-template #customHeaderElement>\n      <p>custom header</p>\n    </ng-template>\n  `\n})\nclass NzTestCalendarHeaderChangesComponent {\n  @ViewChild('customHeaderElement', { static: true }) customHeaderElement!: TemplateRef<NzSafeAny>;\n\n  year: number | null = null;\n  month: number | null = null;\n  customHeader?: TemplateRef<void>;\n}\n"
  },
  {
    "path": "components/calendar/calendar.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ContentChild,\n  EventEmitter,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  SimpleChanges,\n  TemplateRef,\n  ViewEncapsulation,\n  booleanAttribute,\n  forwardRef,\n  inject,\n  DestroyRef\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\n\nimport { CandyDate } from 'ng-zorro-antd/core/time';\nimport { LibPackerModule } from 'ng-zorro-antd/date-picker';\n\nimport {\n  NzDateCellDirective as DateCell,\n  NzDateFullCellDirective as DateFullCell,\n  NzMonthCellDirective as MonthCell,\n  NzMonthFullCellDirective as MonthFullCell\n} from './calendar-cells';\nimport { NzCalendarHeaderComponent } from './calendar-header.component';\n\nexport type NzCalendarMode = 'month' | 'year';\ntype NzCalendarDateTemplate = TemplateRef<{ $implicit: Date }>;\n\n@Component({\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  selector: 'nz-calendar',\n  exportAs: 'nzCalendar',\n  template: `\n    <nz-calendar-header\n      [fullscreen]=\"nzFullscreen\"\n      [activeDate]=\"activeDate\"\n      [nzCustomHeader]=\"nzCustomHeader\"\n      [(mode)]=\"nzMode\"\n      (modeChange)=\"onModeChange($event)\"\n      (yearChange)=\"onYearSelect($event)\"\n      (monthChange)=\"onMonthSelect($event)\"\n    />\n\n    <div class=\"ant-picker-panel\">\n      <div class=\"ant-picker-{{ nzMode === 'month' ? 'date' : 'month' }}-panel\">\n        <div class=\"ant-picker-body\">\n          @if (nzMode === 'month') {\n            <!--  TODO(@wenqi73) [cellRender] [fullCellRender] -->\n            <date-table\n              [prefixCls]=\"prefixCls\"\n              [value]=\"activeDate\"\n              [activeDate]=\"activeDate\"\n              [cellRender]=\"$any(dateCell)\"\n              [fullCellRender]=\"$any(dateFullCell)\"\n              [disabledDate]=\"nzDisabledDate\"\n              (valueChange)=\"onDateSelect($event)\"\n            />\n          } @else {\n            <month-table\n              [prefixCls]=\"prefixCls\"\n              [value]=\"activeDate\"\n              [activeDate]=\"activeDate\"\n              [cellRender]=\"$any(monthCell)\"\n              [fullCellRender]=\"$any(monthFullCell)\"\n              (valueChange)=\"onDateSelect($event)\"\n            />\n          }\n        </div>\n      </div>\n    </div>\n  `,\n  host: {\n    class: 'ant-picker-calendar',\n    '[class.ant-picker-calendar-full]': 'nzFullscreen',\n    '[class.ant-picker-calendar-mini]': '!nzFullscreen',\n    '[class.ant-picker-calendar-rtl]': `dir === 'rtl'`\n  },\n  providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NzCalendarComponent), multi: true }],\n  imports: [NzCalendarHeaderComponent, LibPackerModule]\n})\nexport class NzCalendarComponent implements ControlValueAccessor, OnChanges, OnInit {\n  private cdr = inject(ChangeDetectorRef);\n  private directionality = inject(Directionality);\n  private destroyRef = inject(DestroyRef);\n\n  activeDate: CandyDate = new CandyDate();\n  prefixCls: string = 'ant-picker-calendar';\n  dir: Direction = 'ltr';\n\n  private onChangeFn: (date: Date) => void = () => {};\n  private onTouchFn: () => void = () => {};\n\n  @Input() nzMode: NzCalendarMode = 'month';\n  @Input() nzValue?: Date;\n  @Input() nzDisabledDate?: (date: Date) => boolean;\n\n  @Output() readonly nzModeChange = new EventEmitter<NzCalendarMode>();\n  @Output() readonly nzPanelChange = new EventEmitter<{ date: Date; mode: NzCalendarMode }>();\n  @Output() readonly nzSelectChange = new EventEmitter<Date>();\n  @Output() readonly nzValueChange = new EventEmitter<Date>();\n\n  /**\n   * Cannot use @Input and @ContentChild on one variable\n   * because { static: false } will make @Input property get delayed\n   **/\n  @Input() nzDateCell?: NzCalendarDateTemplate;\n  @ContentChild(DateCell, { static: false, read: TemplateRef }) nzDateCellChild?: NzCalendarDateTemplate;\n  get dateCell(): NzCalendarDateTemplate {\n    return (this.nzDateCell || this.nzDateCellChild)!;\n  }\n\n  @Input() nzDateFullCell?: NzCalendarDateTemplate;\n  @ContentChild(DateFullCell, { static: false, read: TemplateRef }) nzDateFullCellChild?: NzCalendarDateTemplate;\n  get dateFullCell(): NzCalendarDateTemplate {\n    return (this.nzDateFullCell || this.nzDateFullCellChild)!;\n  }\n\n  @Input() nzMonthCell?: NzCalendarDateTemplate;\n  @ContentChild(MonthCell, { static: false, read: TemplateRef }) nzMonthCellChild?: NzCalendarDateTemplate;\n  get monthCell(): NzCalendarDateTemplate {\n    return (this.nzMonthCell || this.nzMonthCellChild)!;\n  }\n\n  @Input() nzMonthFullCell?: NzCalendarDateTemplate;\n  @ContentChild(MonthFullCell, { static: false, read: TemplateRef }) nzMonthFullCellChild?: NzCalendarDateTemplate;\n  get monthFullCell(): NzCalendarDateTemplate {\n    return (this.nzMonthFullCell || this.nzMonthFullCellChild)!;\n  }\n\n  @Input() nzCustomHeader?: string | TemplateRef<void>;\n\n  @Input({ transform: booleanAttribute })\n  nzFullscreen: boolean = true;\n\n  ngOnInit(): void {\n    this.dir = this.directionality.value;\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      this.dir = this.directionality.value;\n    });\n  }\n\n  onModeChange(mode: NzCalendarMode): void {\n    this.nzModeChange.emit(mode);\n    this.nzPanelChange.emit({ date: this.activeDate.nativeDate, mode });\n  }\n\n  onYearSelect(year: number): void {\n    const date = this.activeDate.setYear(year);\n    this.updateDate(date);\n  }\n\n  onMonthSelect(month: number): void {\n    const date = this.activeDate.setMonth(month);\n    this.updateDate(date);\n  }\n\n  onDateSelect(date: CandyDate): void {\n    // Only activeDate is enough in calendar\n    // this.value = date;\n    this.updateDate(date);\n  }\n\n  writeValue(value: Date | null): void {\n    this.updateDate(new CandyDate(value as Date), false);\n    this.cdr.markForCheck();\n  }\n\n  registerOnChange(fn: (date: Date) => void): void {\n    this.onChangeFn = fn;\n  }\n\n  registerOnTouched(fn: () => void): void {\n    this.onTouchFn = fn;\n  }\n\n  private updateDate(date: CandyDate, touched: boolean = true): void {\n    this.activeDate = date;\n\n    if (touched) {\n      this.onChangeFn(date.nativeDate);\n      this.onTouchFn();\n      this.nzSelectChange.emit(date.nativeDate);\n      this.nzValueChange.emit(date.nativeDate);\n    }\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    if (changes.nzValue) {\n      this.updateDate(new CandyDate(this.nzValue), false);\n    }\n  }\n}\n"
  },
  {
    "path": "components/calendar/calendar.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport {\n  NzDateCellDirective,\n  NzDateFullCellDirective,\n  NzMonthCellDirective,\n  NzMonthFullCellDirective\n} from './calendar-cells';\nimport { NzCalendarHeaderComponent } from './calendar-header.component';\nimport { NzCalendarComponent } from './calendar.component';\n\n@NgModule({\n  imports: [\n    NzCalendarHeaderComponent,\n    NzCalendarComponent,\n    NzDateCellDirective,\n    NzDateFullCellDirective,\n    NzMonthCellDirective,\n    NzMonthFullCellDirective\n  ],\n  exports: [\n    NzCalendarComponent,\n    NzDateCellDirective,\n    NzDateFullCellDirective,\n    NzMonthCellDirective,\n    NzMonthFullCellDirective\n  ]\n})\nexport class NzCalendarModule {}\n"
  },
  {
    "path": "components/calendar/calendar.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport { registerLocaleData } from '@angular/common';\nimport zh from '@angular/common/locales/zh';\nimport { Component, provideZoneChangeDetection, ViewChild } from '@angular/core';\nimport { ComponentFixture, TestBed, fakeAsync, flush } from '@angular/core/testing';\nimport { FormsModule, NgModel } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { CandyDate } from 'ng-zorro-antd/core/time';\nimport { NZ_DATE_CONFIG } from 'ng-zorro-antd/i18n/date-config';\n\nimport { NzCalendarHeaderComponent as CalendarHeader } from './calendar-header.component';\nimport { NzCalendarComponent as Calendar, NzCalendarMode } from './calendar.component';\nimport { NzCalendarModule } from './calendar.module';\n\nregisterLocaleData(zh);\n\ndescribe('calendar', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [\n        provideZoneChangeDetection(),\n        provideNoopAnimations(),\n        { provide: NZ_DATE_CONFIG, useValue: { firstDayOfWeek: 0 } }\n      ]\n    });\n  });\n\n  describe('mode', () => {\n    let fixture: ComponentFixture<NzTestCalendarModeComponent>;\n    let component: NzTestCalendarModeComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCalendarModeComponent);\n      component = fixture.componentInstance;\n    });\n\n    it('should be month by default', () => {\n      fixture.detectChanges();\n\n      const header = fixture.debugElement\n        .queryAll(By.directive(Calendar))[0]\n        .query(By.directive(CalendarHeader))\n        .injector.get(CalendarHeader);\n      expect(header.mode).toBe('month');\n    });\n\n    it('should update mode passed in', () => {\n      component.mode = 'year';\n\n      fixture.detectChanges();\n\n      const header = fixture.debugElement\n        .queryAll(By.directive(Calendar))[1]\n        .query(By.directive(CalendarHeader))\n        .injector.get(CalendarHeader);\n      expect(header.mode).toBe('year');\n    });\n\n    it('should emit change event for mode selection', () => {\n      const header = fixture.debugElement\n        .queryAll(By.directive(Calendar))[1]\n        .query(By.directive(CalendarHeader))\n        .injector.get(CalendarHeader);\n      header.modeChange.emit('year');\n\n      fixture.detectChanges();\n\n      expect(component.mode).toBe('year');\n    });\n\n    it('should display date grid in month mode', () => {\n      fixture.detectChanges();\n\n      const host = fixture.debugElement.queryAll(By.directive(Calendar))[1];\n      const table = host.query(By.css('.ant-picker-date-panel'));\n\n      expect(table.nativeElement).toBeTruthy();\n    });\n\n    it('should display date grid in year mode', () => {\n      component.mode = 'year';\n      fixture.detectChanges();\n\n      const host = fixture.debugElement.queryAll(By.directive(Calendar))[1];\n      const table = host.query(By.css('.ant-picker-month-panel'));\n\n      expect(table.nativeElement).toBeTruthy();\n    });\n  });\n\n  describe('value', () => {\n    let fixture: ComponentFixture<NzTestCalendarValueComponent>;\n    let component: NzTestCalendarValueComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCalendarValueComponent);\n      component = fixture.componentInstance;\n    });\n\n    it('should be now by default', () => {\n      fixture.detectChanges();\n      const now = new Date();\n\n      const host = fixture.debugElement.queryAll(By.directive(Calendar))[0];\n      const header = host.query(By.directive(CalendarHeader)).injector.get(CalendarHeader);\n\n      expect(header.activeDate.getYear()).toBe(now.getFullYear());\n      expect(header.activeDate.getMonth()).toBe(now.getMonth());\n      expect(header.activeDate.getDate()).toBe(now.getDate());\n    });\n\n    it('should support two-way binding without model', () => {\n      fixture.detectChanges();\n      const now = new Date();\n\n      const calendar = fixture.debugElement.queryAll(By.directive(Calendar))[1].injector.get(Calendar);\n\n      expect(calendar.activeDate.nativeDate).toBe(component.date0);\n\n      calendar.onDateSelect(new CandyDate(now));\n      fixture.detectChanges();\n\n      expect(component.date0).toBe(now);\n    });\n\n    it('should support model binding', fakeAsync(() => {\n      fixture.detectChanges();\n      const now = new Date();\n\n      const host = fixture.debugElement.queryAll(By.directive(Calendar))[2];\n      const calendar = host.injector.get(Calendar);\n      const model = host.injector.get(NgModel);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n\n      expect(calendar.activeDate.nativeDate).toBe(component.date1);\n\n      model.viewToModelUpdate(now);\n      fixture.detectChanges();\n\n      expect(component.date1).toBe(now);\n    }));\n\n    it('should update value when year changed', () => {\n      fixture.detectChanges();\n      const calendar = fixture.debugElement.queryAll(By.directive(Calendar))[1].injector.get(Calendar);\n      calendar.onYearSelect(2010);\n      fixture.detectChanges();\n\n      expect(component.date0.getFullYear()).toBe(2010);\n    });\n\n    it('should update value when month changed', () => {\n      fixture.detectChanges();\n      const calendar = fixture.debugElement.queryAll(By.directive(Calendar))[1].injector.get(Calendar);\n      calendar.onMonthSelect(10);\n      fixture.detectChanges();\n\n      expect(component.date0.getMonth()).toBe(10);\n    });\n\n    it('should mark current date in month mode', () => {\n      const now = new Date();\n\n      fixture.detectChanges();\n\n      const host = fixture.debugElement.queryAll(By.directive(Calendar))[0];\n      const today = host.query(By.css('td.ant-picker-cell-today .ant-picker-calendar-date-value'));\n\n      expect(today).toBeDefined();\n      expect(parseInt(today.nativeElement.textContent!, 10)).toBe(now.getDate());\n    });\n\n    it('should mark active date in month mode', () => {\n      fixture.detectChanges();\n\n      const host = fixture.debugElement.queryAll(By.directive(Calendar))[1];\n      const active = host.query(By.css('td.ant-picker-cell-selected .ant-picker-calendar-date-value'));\n\n      expect(active).toBeDefined();\n      expect(parseInt(active.nativeElement.textContent!, 10)).toBe(3);\n    });\n\n    it('should mark previous/next month date in month mode', () => {\n      fixture.detectChanges();\n\n      const host = fixture.debugElement.queryAll(By.directive(Calendar))[1];\n      const cells = host.queryAll(By.css('td'));\n      const lastPrevious = cells[3];\n      const firstNext = cells[32];\n\n      expect(lastPrevious.nativeElement.className).not.toContain('ant-picker-cell-in-view');\n      expect(firstNext.nativeElement.className).not.toContain('ant-picker-cell-in-view');\n    });\n\n    it('should mark current month in year mode', () => {\n      const now = new Date();\n      fixture.detectChanges();\n\n      const host = fixture.debugElement.queryAll(By.directive(Calendar))[3];\n      const cells = host.queryAll(By.css('td'));\n      const current = cells[now.getMonth()];\n\n      expect(current.nativeElement.className).toContain('ant-picker-cell-selected');\n    });\n\n    it('should mark active month in year mode', () => {\n      component.date2.setDate(1);\n      component.date2.setMonth(10);\n      fixture.detectChanges();\n\n      const host = fixture.debugElement.queryAll(By.directive(Calendar))[3];\n      const cells = host.queryAll(By.css('td'));\n      const current = cells[10];\n\n      expect(current.nativeElement.className).toContain('ant-picker-cell-selected');\n    });\n  });\n\n  describe('fullscreen', () => {\n    let fixture: ComponentFixture<NzTestCalendarFullscreenComponent>;\n    let component: NzTestCalendarFullscreenComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCalendarFullscreenComponent);\n      component = fixture.componentInstance;\n    });\n\n    it('should be true by default', () => {\n      fixture.detectChanges();\n\n      const host = fixture.debugElement.queryAll(By.directive(Calendar))[0];\n      const header = host.query(By.directive(CalendarHeader)).injector.get(CalendarHeader);\n\n      expect(header.fullscreen).toBe(true);\n    });\n\n    it('should update fullscreen by nzFullscreen', () => {\n      component.fullscreen = false;\n\n      fixture.detectChanges();\n\n      const host = fixture.debugElement.queryAll(By.directive(Calendar))[1];\n      const header = host.query(By.directive(CalendarHeader)).injector.get(CalendarHeader);\n\n      expect(header.fullscreen).toBe(false);\n    });\n\n    it('should support imperative access', () => {\n      component.fullscreen = false;\n\n      fixture.detectChanges();\n\n      const calendar = fixture.debugElement.queryAll(By.directive(Calendar))[1].injector.get(Calendar);\n\n      expect(calendar.nzFullscreen).toBe(false);\n    });\n  });\n\n  describe('dateCell', () => {\n    let fixture: ComponentFixture<NzTestCalendarDateCellComponent>;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCalendarDateCellComponent);\n    });\n\n    it('should work when passed via property', () => {\n      fixture.detectChanges();\n\n      const host = fixture.debugElement.queryAll(By.directive(Calendar))[0];\n      const content = host.query(By.css('td')).query(By.css('.ant-picker-calendar-date-content'));\n\n      expect(content.nativeElement.textContent).toContain('Foo');\n    });\n\n    it('should work when passed via content child', () => {\n      fixture.detectChanges();\n\n      const host = fixture.debugElement.queryAll(By.directive(Calendar))[1];\n      const content = host.query(By.css('td')).query(By.css('.ant-picker-calendar-date-content'));\n\n      expect(content.nativeElement.textContent).toContain('Bar');\n    });\n  });\n\n  describe('dateFullCell', () => {\n    let fixture: ComponentFixture<NzTestCalendarDateFullCellComponent>;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCalendarDateFullCellComponent);\n    });\n\n    it('should work when passed via property', () => {\n      fixture.detectChanges();\n\n      const host = fixture.debugElement.queryAll(By.directive(Calendar))[0];\n      const content = host.query(By.css('td')).query(By.css('.ant-picker-cell-inner'));\n      expect(content.nativeElement.textContent!.trim()).toBe('Foo');\n    });\n\n    it('should work when passed via content child', () => {\n      fixture.detectChanges();\n\n      const host = fixture.debugElement.queryAll(By.directive(Calendar))[1];\n      const content = host.query(By.css('td')).query(By.css('.ant-picker-cell-inner'));\n\n      expect(content.nativeElement.textContent!.trim()).toBe('Bar');\n    });\n  });\n\n  describe('monthCell', () => {\n    let fixture: ComponentFixture<NzTestCalendarMonthCellComponent>;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCalendarMonthCellComponent);\n    });\n\n    it('should work when passed via property', () => {\n      fixture.detectChanges();\n\n      const host = fixture.debugElement.queryAll(By.directive(Calendar))[0];\n      const content = host.query(By.css('td')).query(By.css('.ant-picker-calendar-date-content'));\n      expect(content.nativeElement.textContent).toContain('Foo');\n    });\n\n    it('should work when passed via content child', () => {\n      fixture.detectChanges();\n\n      const host = fixture.debugElement.queryAll(By.directive(Calendar))[1];\n      const content = host.query(By.css('td')).query(By.css('.ant-picker-calendar-date-content'));\n      expect(content.nativeElement.textContent).toContain('Bar');\n    });\n  });\n\n  describe('monthFullCell', () => {\n    let fixture: ComponentFixture<NzTestCalendarMonthFullCellComponent>;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCalendarMonthFullCellComponent);\n    });\n\n    it('should work when passed via property', () => {\n      fixture.detectChanges();\n\n      const host = fixture.debugElement.queryAll(By.directive(Calendar))[0];\n      const content = host.query(By.css('td')).query(By.css('.ant-picker-cell-inner'));\n      expect(content.nativeElement.textContent!.trim()).toBe('Foo');\n    });\n\n    it('should work when passed via content child', () => {\n      fixture.detectChanges();\n\n      const host = fixture.debugElement.queryAll(By.directive(Calendar))[1];\n      const content = host.query(By.css('td')).query(By.css('.ant-picker-cell-inner'));\n      expect(content.nativeElement.textContent!.trim()).toBe('Bar');\n    });\n  });\n\n  describe('changes', () => {\n    let fixture: ComponentFixture<NzTestCalendarChangesComponent>;\n    let component: NzTestCalendarChangesComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCalendarChangesComponent);\n      component = fixture.componentInstance;\n    });\n\n    it('should panelChange work', () => {\n      fixture.detectChanges();\n\n      expect(component.panelChange).toHaveBeenCalledTimes(0);\n\n      const calendar = fixture.debugElement.queryAll(By.directive(Calendar))[0].injector.get(Calendar);\n      calendar.onModeChange('year');\n      fixture.detectChanges();\n\n      expect(component.panelChange).toHaveBeenCalledTimes(1);\n    });\n\n    it('should selectChange work', () => {\n      fixture.detectChanges();\n\n      expect(component.panelChange).toHaveBeenCalledTimes(0);\n\n      const calendar = fixture.debugElement.queryAll(By.directive(Calendar))[0].injector.get(Calendar);\n      calendar.onYearSelect(2019);\n      fixture.detectChanges();\n\n      expect(component.selectChange).toHaveBeenCalledTimes(1);\n\n      calendar.onMonthSelect(2);\n      fixture.detectChanges();\n\n      expect(component.selectChange).toHaveBeenCalledTimes(2);\n    });\n  });\n\n  describe('RTL', () => {\n    let fixture: ComponentFixture<NzTestCalendarRtlComponent>;\n    let componentElement: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCalendarRtlComponent);\n      componentElement = fixture.debugElement.query(By.directive(Calendar)).nativeElement;\n      fixture.detectChanges();\n    });\n\n    it('should className correct on dir change', () => {\n      expect(componentElement.classList).toContain('ant-picker-calendar-rtl');\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n      expect(componentElement.classList).not.toContain('ant-picker-calendar-rtl');\n    });\n  });\n});\n\n@Component({\n  imports: [NzCalendarModule],\n  template: `\n    <nz-calendar />\n    <nz-calendar [(nzMode)]=\"mode\" />\n  `\n})\nclass NzTestCalendarModeComponent {\n  mode: 'month' | 'year' = 'month';\n}\n\n@Component({\n  imports: [FormsModule, NzCalendarModule],\n  template: `\n    <nz-calendar />\n    <nz-calendar [(nzValue)]=\"date0\" />\n    <nz-calendar [(ngModel)]=\"date1\" />\n    <nz-calendar [(nzValue)]=\"date2\" [(nzMode)]=\"mode\" />\n  `\n})\nclass NzTestCalendarValueComponent {\n  date0 = new Date(2001, 1, 3);\n  date1 = new Date(2001, 1, 3);\n  date2 = new Date();\n  mode: NzCalendarMode = 'year';\n}\n\n@Component({\n  imports: [NzCalendarModule],\n  template: `\n    <nz-calendar />\n    <nz-calendar [nzFullscreen]=\"fullscreen\" />\n  `\n})\nclass NzTestCalendarFullscreenComponent {\n  fullscreen = true;\n  card = false;\n}\n\n@Component({\n  imports: [NzCalendarModule],\n  template: `\n    <nz-calendar [nzDateCell]=\"tpl\" />\n    <ng-template #tpl>Foo</ng-template>\n    <nz-calendar>\n      <ng-container *nzDateCell>Bar</ng-container>\n    </nz-calendar>\n  `\n})\nclass NzTestCalendarDateCellComponent {}\n\n@Component({\n  imports: [NzCalendarModule],\n  template: `\n    <nz-calendar [nzDateFullCell]=\"tpl\" />\n    <ng-template #tpl>Foo</ng-template>\n    <nz-calendar>\n      <ng-container *nzDateFullCell>Bar</ng-container>\n    </nz-calendar>\n  `\n})\nclass NzTestCalendarDateFullCellComponent {}\n\n@Component({\n  imports: [NzCalendarModule],\n  template: `\n    <nz-calendar nzMode=\"year\" [nzMonthCell]=\"tpl\" />\n    <ng-template #tpl>Foo</ng-template>\n    <nz-calendar nzMode=\"year\">\n      <ng-container *nzMonthCell>Bar</ng-container>\n    </nz-calendar>\n  `\n})\nclass NzTestCalendarMonthCellComponent {}\n\n@Component({\n  imports: [NzCalendarModule],\n  template: `\n    <nz-calendar nzMode=\"year\" [nzMonthFullCell]=\"tpl\" />\n    <ng-template #tpl>Foo</ng-template>\n    <nz-calendar nzMode=\"year\">\n      <ng-container *nzMonthFullCell>Bar</ng-container>\n    </nz-calendar>\n  `\n})\nclass NzTestCalendarMonthFullCellComponent {}\n\n@Component({\n  imports: [FormsModule, NzCalendarModule],\n  template: `\n    <nz-calendar\n      [(nzMode)]=\"mode\"\n      [(ngModel)]=\"date0\"\n      (nzPanelChange)=\"panelChange($event)\"\n      (nzSelectChange)=\"selectChange($event)\"\n    />\n  `\n})\nclass NzTestCalendarChangesComponent {\n  mode: 'month' | 'year' = 'month';\n  date0 = new Date(2014, 3, 14);\n  panelChange = jasmine.createSpy('panelChange callback');\n  selectChange = jasmine.createSpy('selectChange callback');\n}\n\n@Component({\n  imports: [BidiModule, NzCalendarModule],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-calendar />\n    </div>\n  `\n})\nexport class NzTestCalendarRtlComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n}\n"
  },
  {
    "path": "components/calendar/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n一个通用的日历面板，支持年/月切换。\n\n## en-US\n\nA basic calendar component with Year/Month switch.\n"
  },
  {
    "path": "components/calendar/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCalendarMode, NzCalendarModule } from 'ng-zorro-antd/calendar';\n\n@Component({\n  selector: 'nz-demo-calendar-basic',\n  imports: [FormsModule, NzCalendarModule],\n  template: `<nz-calendar [(ngModel)]=\"date\" [(nzMode)]=\"mode\" (nzPanelChange)=\"panelChange($event)\" />`\n})\nexport class NzDemoCalendarBasicComponent {\n  date = new Date(2012, 11, 21);\n  mode: NzCalendarMode = 'month';\n\n  panelChange(change: { date: Date; mode: string }): void {\n    console.log(change.date, change.mode);\n  }\n}\n"
  },
  {
    "path": "components/calendar/demo/card.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 卡片模式\n  en-US: Card\n---\n\n## zh-CN\n\n用于嵌套在空间有限的容器中。\n\n## en-US\n\nNested inside a container element for rendering in limited space.\n"
  },
  {
    "path": "components/calendar/demo/card.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCalendarModule } from 'ng-zorro-antd/calendar';\n\n@Component({\n  selector: 'nz-demo-calendar-card',\n  imports: [NzCalendarModule],\n  template: `\n    <div class=\"card\">\n      <nz-calendar\n        [nzFullscreen]=\"false\"\n        (nzSelectChange)=\"onValueChange($event)\"\n        (nzPanelChange)=\"onPanelChange($event)\"\n      />\n    </div>\n  `,\n  styles: `\n    .card {\n      width: 300px;\n      border: 1px solid #d9d9d9;\n      border-radius: 4px;\n    }\n  `\n})\nexport class NzDemoCalendarCardComponent {\n  onValueChange(value: Date): void {\n    console.log(`Current value: ${value}`);\n  }\n\n  onPanelChange(change: { date: Date; mode: string }): void {\n    console.log(`Current value: ${change.date}`);\n    console.log(`Current mode: ${change.mode}`);\n  }\n}\n"
  },
  {
    "path": "components/calendar/demo/customize-header.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 自定义头部\n  en-US: Customize Header\n---\n\n## zh-CN\n\n自定义日历头部内容。\n\n## en-US\n\nCustomize Calendar header content.\n"
  },
  {
    "path": "components/calendar/demo/customize-header.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCalendarModule } from 'ng-zorro-antd/calendar';\n\n@Component({\n  selector: 'nz-demo-calendar-customize-header',\n  imports: [NzCalendarModule],\n  template: `\n    <div class=\"card\">\n      <nz-calendar [nzFullscreen]=\"false\" [nzCustomHeader]=\"customHeader\" />\n    </div>\n\n    <ng-template #customHeader>\n      <div style=\"padding: 8px\">\n        <h4>Custom header</h4>\n      </div>\n    </ng-template>\n  `,\n  styles: `\n    .card {\n      width: 300px;\n      border: 1px solid #d9d9d9;\n      border-radius: 4px;\n    }\n  `\n})\nexport class NzDemoCalendarCustomizeHeaderComponent {}\n"
  },
  {
    "path": "components/calendar/demo/notice-calendar.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 通知事项日历\n  en-US: Notice Calendar\n---\n\n## zh-CN\n\n一个复杂的应用示例，用 `nzDateCell` 和 `nzMonthCell` 模版来自定义需要渲染的数据。\n\n## en-US\n\nThis component can be rendered by using `nzDateCell` and `nzMonthCell` with the data you need.\n"
  },
  {
    "path": "components/calendar/demo/notice-calendar.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzBadgeModule } from 'ng-zorro-antd/badge';\nimport { NzCalendarModule } from 'ng-zorro-antd/calendar';\n\n@Component({\n  selector: 'nz-demo-calendar-notice-calendar',\n  imports: [NzBadgeModule, NzCalendarModule],\n  template: `\n    <nz-calendar>\n      <ul *nzDateCell=\"let date\" class=\"events\">\n        @switch (date.getDate()) {\n          @case (8) {\n            @for (item of listDataMap.eight; track $index) {\n              <li>\n                <nz-badge [nzStatus]=\"item.type\" [nzText]=\"item.content\" />\n              </li>\n            }\n          }\n          @case (10) {\n            @for (item of listDataMap.ten; track $index) {\n              <li>\n                <nz-badge [nzStatus]=\"item.type\" [nzText]=\"item.content\" />\n              </li>\n            }\n          }\n          @case (11) {\n            @for (item of listDataMap.eleven; track $index) {\n              <li>\n                <nz-badge [nzStatus]=\"item.type\" [nzText]=\"item.content\" />\n              </li>\n            }\n          }\n        }\n      </ul>\n      <ng-container *nzMonthCell=\"let month\">\n        @if (getMonthData(month); as monthData) {\n          <div class=\"notes-month\">\n            <section>{{ monthData }}</section>\n            <span>Backlog number</span>\n          </div>\n        }\n      </ng-container>\n    </nz-calendar>\n  `,\n  styles: `\n    .events {\n      list-style: none;\n      margin: 0;\n      padding: 0;\n    }\n\n    .events .ant-badge-status {\n      overflow: hidden;\n      white-space: nowrap;\n      width: 100%;\n      text-overflow: ellipsis;\n      font-size: 12px;\n    }\n  `\n})\nexport class NzDemoCalendarNoticeCalendarComponent {\n  readonly listDataMap = {\n    eight: [\n      { type: 'warning', content: 'This is warning event.' },\n      { type: 'success', content: 'This is usual event.' }\n    ],\n    ten: [\n      { type: 'warning', content: 'This is warning event.' },\n      { type: 'success', content: 'This is usual event.' },\n      { type: 'error', content: 'This is error event.' }\n    ],\n    eleven: [\n      { type: 'warning', content: 'This is warning event' },\n      { type: 'success', content: 'This is very long usual event........' },\n      { type: 'error', content: 'This is error event 1.' },\n      { type: 'error', content: 'This is error event 2.' },\n      { type: 'error', content: 'This is error event 3.' },\n      { type: 'error', content: 'This is error event 4.' }\n    ]\n  };\n\n  getMonthData(date: Date): number | null {\n    if (date.getMonth() === 8) {\n      return 1394;\n    }\n    return null;\n  }\n}\n"
  },
  {
    "path": "components/calendar/demo/select.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 选择功能\n  en-US: Selectable Calendar\n---\n\n## zh-CN\n\n一个通用的日历面板，支持年/月切换。\n\n## en-US\n\nA basic calendar component with Year/Month switch.\n"
  },
  {
    "path": "components/calendar/demo/select.ts",
    "content": "import { DatePipe } from '@angular/common';\nimport { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzAlertModule } from 'ng-zorro-antd/alert';\nimport { NzCalendarModule } from 'ng-zorro-antd/calendar';\n\n@Component({\n  selector: 'nz-demo-calendar-select',\n  imports: [DatePipe, FormsModule, NzAlertModule, NzCalendarModule],\n  template: `\n    <nz-alert nzMessage=\"Your selected date: {{ selectedValue | date: 'yyyy-MM-dd' }}\" />\n    <nz-calendar [(ngModel)]=\"selectedValue\" (nzSelectChange)=\"selectChange($event)\" />\n  `\n})\nexport class NzDemoCalendarSelectComponent {\n  selectedValue = new Date('2017-01-25');\n\n  selectChange(select: Date): void {\n    console.log(`Select value: ${select}`);\n  }\n}\n"
  },
  {
    "path": "components/calendar/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Display\ncols: 1\ntitle: Calendar\ncover: 'https://gw.alipayobjects.com/zos/antfincdn/dPQmLq08DI/Calendar.svg'\ndescription: Container for displaying data in calendar form.\n---\n\n## When To Use\n\nWhen data is in the form of dates, such as schedules, timetables, prices calendar, lunar calendar. This component also supports Year/Month switch.\n\n## API\n\n**Note:** Some of Calendar's locale are coming from [Angular i18n](https://angular.dev/guide/i18n), that should be provided in the file `app.config.ts`.\n\nFor example:\n\n```typescript\nimport { registerLocaleData } from '@angular/common';\nimport en from '@angular/common/locales/en';\nregisterLocaleData(en);\n```\n\n```html\n<nz-calendar\n  [nzDateCell]=\"dateCellTpl\"\n  [(ngModel)]=\"selectedDate\"\n  [(nzMode)]=\"mode\"\n  (nzPanelChange)=\"panelChange($event)\"\n  (nzSelectChange)=\"selectChange($event)\"\n>\n  <!-- Another method for cell definition -->\n  <div *nzDateCell>Foo</div>\n</nz-calendar>\n<!-- Passing TemplateRef -->\n<ng-template #dateCellTpl let-date><span>{{ date | date:'d'}}</span></ng-template>\n```\n\n### nz-calendar\n\n| Property            | Description                                                                                              | Type                                                    | Default      |\n| ------------------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ------------ |\n| `[(ngModel)]`       | (Two-way bindable) The current selected date                                                             | `Date`                                                  | current date |\n| `[(nzMode)]`        | The display mode of the calendar (two-way bindable)                                                      | `'month' \\| 'year'`                                     | `'month'`    |\n| `[nzFullscreen]`    | Whether to display in full-screen                                                                        | `boolean`                                               | `true`       |\n| `[nzDateCell]`      | (Contentable) Customize the display of the date cell, the template content will be appended to the cell  | `TemplateRef<Date>`                                     | -            |\n| `[nzDateFullCell]`  | (Contentable) Customize the display of the date cell, the template content will override the cell        | `TemplateRef<Date>`                                     | -            |\n| `[nzMonthCell]`     | (Contentable) Customize the display of the month cell, the template content will be appended to the cell | `TemplateRef<Date>`                                     | -            |\n| `[nzMonthFullCell]` | (Contentable) Customize the display of the month cell, the template content will override the cell       | `TemplateRef<Date>`                                     | -            |\n| `[nzCustomHeader]`  | Render custom header in panel                                                                            | `string \\| TemplateRef<void>`                           | -            |\n| `[nzDisabledDate]`  | specify the date that cannot be selected                                                                 | `(current: Date) => boolean`                            | -            |\n| `(nzPanelChange)`   | Callback for when panel changes                                                                          | `EventEmitter<{ date: Date, mode: 'month' \\| 'year' }>` | -            |\n| `(nzSelectChange)`  | A callback function of selected item                                                                     | `EventEmitter<Date>`                                    | -            |\n"
  },
  {
    "path": "components/calendar/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ntype: 数据展示\nsubtitle: 日历\ncols: 1\ntitle: Calendar\ncover: 'https://gw.alipayobjects.com/zos/antfincdn/dPQmLq08DI/Calendar.svg'\ndescription: 按照日历形式展示数据的容器。\n---\n\n## 何时使用\n\n当数据是日期或按照日期划分时，例如日程、课表、价格日历等，农历等。目前支持年/月切换。\n\n## API\n\n**注意：**Calendar 的部分 locale 来自于 Angular 自身的国际化支持，需要在 `app.config.ts` 文件中 引入相应的 Angular 语言包。\n\n例如：\n\n```typescript\nimport { registerLocaleData } from '@angular/common';\nimport zh from '@angular/common/locales/zh';\nregisterLocaleData(zh);\n```\n\n```html\n<nz-calendar\n  [nzDateCell]=\"dateCellTpl\"\n  [(ngModel)]=\"selectedDate\"\n  [(nzMode)]=\"mode\"\n  (nzPanelChange)=\"panelChange($event)\"\n  (nzSelectChange)=\"selectChange($event)\"\n>\n  <!-- 定义 Cell 的另一种方式 -->\n  <div *dateCell>Foo</div>\n</nz-calendar>\n<!-- 传入 TemplateRef 的方式 -->\n<ng-template #dateCellTpl let-date><span>{{ date | date:'d'}}</span></ng-template>\n```\n\n### nz-calendar\n\n| 参数                | 说明                                                         | 类型                                                    | 默认值    |\n| ------------------- | ------------------------------------------------------------ | ------------------------------------------------------- | --------- |\n| `[(ngModel)]`       | （可双向绑定）展示日期                                       | `Date`                                                  | 当前日期  |\n| `[(nzMode)]`        | （可双向绑定）显示模式                                       | `'month' \\| 'year'`                                     | `'month'` |\n| `[nzFullscreen]`    | 是否全屏显示                                                 | `boolean`                                               | `true`    |\n| `[nzDateCell]`      | （可作为内容）自定义渲染日期单元格，模版内容会被追加到单元格 | `TemplateRef<Date>`                                     | -         |\n| `[nzDateFullCell]`  | （可作为内容）自定义渲染日期单元格，模版内容覆盖单元格       | `TemplateRef<Date>`                                     | -         |\n| `[nzMonthCell]`     | （可作为内容）自定义渲染月单元格，模版内容会被追加到单元格   | `TemplateRef<Date>`                                     | -         |\n| `[nzMonthFullCell]` | （可作为内容）自定义渲染月单元格，模版内容覆盖单元格         | `TemplateRef<Date>`                                     | -         |\n| `[nzCustomHeader]`  | 自定义头部内容                                               | `string \\| TemplateRef<void>`                           | -         |\n| `[nzDisabledDate]`  | 不可选择的日期                                               | `(current: Date) => boolean`                            | -         |\n| `(nzPanelChange)`   | 面板变化的回调                                               | `EventEmitter<{ date: Date, mode: 'month' \\| 'year' }>` | -         |\n| `(nzSelectChange)`  | 选择日期的回调                                               | `EventEmitter<Date>`                                    | -         |\n"
  },
  {
    "path": "components/calendar/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/calendar/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/calendar/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './calendar.module';\nexport * from './calendar.component';\nexport * from './calendar-cells';\nexport * from './calendar-header.component';\n"
  },
  {
    "path": "components/calendar/style/entry.less",
    "content": "@import './index.less';\n// style dependencies\n@import '../../select/style/entry.less';\n@import '../../radio/style/entry.less';\n"
  },
  {
    "path": "components/calendar/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@calendar-prefix-cls: ~'@{ant-prefix}-picker-calendar';\n@calendar-picker-prefix-cls: ~'@{ant-prefix}-picker';\n\n.@{calendar-prefix-cls} {\n  .reset-component();\n  background: @calendar-full-bg;\n\n  // ========================= Header =========================\n  &-header {\n    display: flex;\n    justify-content: flex-end;\n    padding: @padding-sm 0;\n\n    .@{calendar-prefix-cls}-year-select {\n      min-width: 80px;\n    }\n\n    .@{calendar-prefix-cls}-month-select {\n      min-width: 70px;\n      margin-left: @padding-xs;\n    }\n\n    .@{calendar-prefix-cls}-mode-switch {\n      margin-left: @padding-xs;\n    }\n  }\n\n  .@{calendar-picker-prefix-cls}-panel {\n    background: @calendar-full-panel-bg;\n    border: 0;\n    border-top: @border-width-base @border-style-base @border-color-split;\n    border-radius: 0;\n\n    .@{calendar-picker-prefix-cls}-month-panel,\n    .@{calendar-picker-prefix-cls}-date-panel {\n      width: auto;\n    }\n\n    .@{calendar-picker-prefix-cls}-body {\n      padding: @padding-xs 0;\n    }\n\n    .@{calendar-picker-prefix-cls}-content {\n      width: 100%;\n    }\n  }\n\n  // ========================== Mini ==========================\n  &-mini {\n    border-radius: @border-radius-base;\n\n    .@{calendar-picker-prefix-cls}-calendar-header {\n      padding-right: @padding-xs;\n      padding-left: @padding-xs;\n    }\n\n    .@{calendar-picker-prefix-cls}-panel {\n      border-radius: 0 0 @border-radius-base @border-radius-base;\n    }\n\n    .@{calendar-picker-prefix-cls}-content {\n      height: 256px;\n\n      th {\n        height: auto;\n        padding: 0;\n        line-height: 18px;\n      }\n    }\n\n    .@{calendar-picker-prefix-cls}-cell::before {\n      pointer-events: none;\n    }\n  }\n\n  // ========================== Full ==========================\n  &-full {\n    .@{calendar-picker-prefix-cls}-panel {\n      display: block;\n      width: 100%;\n      text-align: right;\n      background: @calendar-full-bg;\n      border: 0;\n\n      .@{calendar-picker-prefix-cls}-body {\n        th,\n        td {\n          padding: 0;\n        }\n\n        th {\n          height: auto;\n          padding: 0 12px 5px 0;\n          line-height: 18px;\n        }\n      }\n\n      // Cell\n      .@{calendar-picker-prefix-cls}-cell {\n        &::before {\n          display: none;\n        }\n\n        &:hover {\n          .@{calendar-prefix-cls}-date {\n            background: @item-hover-bg;\n          }\n        }\n\n        .@{calendar-prefix-cls}-date-today::before {\n          display: none;\n        }\n\n        &-selected,\n        &-selected:hover {\n          .@{calendar-prefix-cls}-date,\n          .@{calendar-prefix-cls}-date-today {\n            background: @calendar-item-active-bg;\n\n            .@{calendar-prefix-cls}-date-value {\n              color: @primary-color;\n            }\n          }\n        }\n      }\n\n      // Cell date\n      .@{calendar-prefix-cls}-date {\n        display: block;\n        width: auto;\n        height: auto;\n        margin: 0 (@padding-xs / 2);\n        padding: (@padding-xs / 2) @padding-xs 0;\n        border: 0;\n        border-top: 2px solid @border-color-split;\n        border-radius: 0;\n        transition: background 0.3s;\n\n        &-value {\n          line-height: 24px;\n          transition: color 0.3s;\n        }\n\n        &-content {\n          position: static;\n          width: auto;\n          height: 86px;\n          overflow-y: auto;\n          color: @text-color;\n          line-height: @line-height-base;\n          text-align: left;\n        }\n\n        &-today {\n          border-color: @primary-color;\n\n          .@{calendar-prefix-cls}-date-value {\n            color: @text-color;\n          }\n        }\n      }\n    }\n  }\n}\n\n@media only screen and (max-width: @screen-xs) {\n  .@{calendar-prefix-cls} {\n    &-header {\n      display: block;\n\n      .@{calendar-prefix-cls}-year-select {\n        width: 50%;\n      }\n\n      .@{calendar-prefix-cls}-month-select {\n        width: ~'calc(50% - @{padding-xs})';\n      }\n\n      .@{calendar-prefix-cls}-mode-switch {\n        width: 100%;\n        margin-top: @padding-xs;\n        margin-left: 0;\n\n        > label {\n          width: 50%;\n          text-align: center;\n        }\n      }\n    }\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/calendar/style/rtl.less",
    "content": ".@{calendar-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &-header {\n    .@{calendar-prefix-cls}-month-select {\n      .@{calendar-prefix-cls}-rtl & {\n        margin-right: @padding-xs;\n        margin-left: 0;\n      }\n    }\n\n    .@{calendar-prefix-cls}-mode-switch {\n      .@{calendar-prefix-cls}-rtl & {\n        margin-right: @padding-xs;\n        margin-left: 0;\n      }\n    }\n  }\n\n  // ========================== Full ==========================\n  &-full {\n    .@{calendar-picker-prefix-cls}-panel {\n      .@{calendar-prefix-cls}-rtl& {\n        text-align: left;\n      }\n\n      .@{calendar-picker-prefix-cls}-body {\n        th {\n          .@{calendar-prefix-cls}-rtl& {\n            padding: 0 0 5px 12px;\n          }\n        }\n      }\n\n      .@{calendar-prefix-cls}-date {\n        &-content {\n          .@{calendar-prefix-cls}-rtl& {\n            text-align: right;\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/card/card-grid.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, Input, booleanAttribute } from '@angular/core';\n\n@Directive({\n  selector: '[nz-card-grid]',\n  exportAs: 'nzCardGrid',\n  host: {\n    class: 'ant-card-grid',\n    '[class.ant-card-hoverable]': 'nzHoverable'\n  }\n})\nexport class NzCardGridDirective {\n  @Input({ transform: booleanAttribute }) nzHoverable = true;\n}\n"
  },
  {
    "path": "components/card/card-meta.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, Input, TemplateRef, ViewEncapsulation } from '@angular/core';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\n\n@Component({\n  selector: 'nz-card-meta',\n  exportAs: 'nzCardMeta',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    @if (nzAvatar) {\n      <div class=\"ant-card-meta-avatar\">\n        <ng-template [ngTemplateOutlet]=\"nzAvatar\" />\n      </div>\n    }\n\n    @if (nzTitle || nzDescription) {\n      <div class=\"ant-card-meta-detail\">\n        @if (nzTitle) {\n          <div class=\"ant-card-meta-title\">\n            <ng-container *nzStringTemplateOutlet=\"nzTitle\">{{ nzTitle }}</ng-container>\n          </div>\n        }\n        @if (nzDescription) {\n          <div class=\"ant-card-meta-description\">\n            <ng-container *nzStringTemplateOutlet=\"nzDescription\">{{ nzDescription }}</ng-container>\n          </div>\n        }\n      </div>\n    }\n  `,\n  host: { class: 'ant-card-meta' },\n  imports: [NgTemplateOutlet, NzOutletModule]\n})\nexport class NzCardMetaComponent {\n  @Input() nzTitle: string | TemplateRef<void> | null = null;\n  @Input() nzDescription: string | TemplateRef<void> | null = null;\n  @Input() nzAvatar: TemplateRef<void> | null = null;\n}\n"
  },
  {
    "path": "components/card/card-tab.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, TemplateRef, ViewChild, ViewEncapsulation } from '@angular/core';\n\n@Component({\n  selector: 'nz-card-tab',\n  exportAs: 'nzCardTab',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    <ng-template>\n      <ng-content />\n    </ng-template>\n  `\n})\nexport class NzCardTabComponent {\n  @ViewChild(TemplateRef, { static: true }) template!: TemplateRef<void>;\n}\n"
  },
  {
    "path": "components/card/card.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ContentChild,\n  ContentChildren,\n  Input,\n  OnInit,\n  QueryList,\n  TemplateRef,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject,\n  DestroyRef\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { NzConfigKey, onConfigChangeEventForComponent, WithConfig } from 'ng-zorro-antd/core/config';\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NgStyleInterface, NzSizeDSType } from 'ng-zorro-antd/core/types';\nimport { NzSkeletonModule } from 'ng-zorro-antd/skeleton';\n\nimport { NzCardGridDirective } from './card-grid.directive';\nimport { NzCardTabComponent } from './card-tab.component';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'card';\n\n@Component({\n  selector: 'nz-card',\n  exportAs: 'nzCard',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    @if (nzTitle || nzExtra || listOfNzCardTabComponent) {\n      <div class=\"ant-card-head\">\n        <div class=\"ant-card-head-wrapper\">\n          @if (nzTitle) {\n            <div class=\"ant-card-head-title\">\n              <ng-container *nzStringTemplateOutlet=\"nzTitle\">{{ nzTitle }}</ng-container>\n            </div>\n          }\n          @if (nzExtra) {\n            <div class=\"ant-card-extra\">\n              <ng-container *nzStringTemplateOutlet=\"nzExtra\">{{ nzExtra }}</ng-container>\n            </div>\n          }\n        </div>\n        @if (listOfNzCardTabComponent) {\n          <ng-template [ngTemplateOutlet]=\"listOfNzCardTabComponent.template\" />\n        }\n      </div>\n    }\n\n    @if (nzCover) {\n      <div class=\"ant-card-cover\">\n        <ng-template [ngTemplateOutlet]=\"nzCover\" />\n      </div>\n    }\n\n    <div class=\"ant-card-body\" [style]=\"nzBodyStyle\">\n      @if (nzLoading) {\n        <nz-skeleton [nzActive]=\"true\" [nzTitle]=\"false\" [nzParagraph]=\"{ rows: 4 }\" />\n      } @else {\n        <ng-content />\n      }\n    </div>\n    @if (nzActions.length) {\n      <ul class=\"ant-card-actions\">\n        @for (action of nzActions; track $index) {\n          <li [style.width.%]=\"100 / $count\">\n            <span><ng-template [ngTemplateOutlet]=\"action\" /></span>\n          </li>\n        }\n      </ul>\n    }\n  `,\n  host: {\n    class: 'ant-card',\n    '[class.ant-card-loading]': 'nzLoading',\n    '[class.ant-card-bordered]': 'nzBordered',\n    '[class.ant-card-hoverable]': 'nzHoverable',\n    '[class.ant-card-small]': 'nzSize === \"small\"',\n    '[class.ant-card-contain-grid]': 'listOfNzCardGridDirective && listOfNzCardGridDirective.length',\n    '[class.ant-card-type-inner]': 'nzType === \"inner\"',\n    '[class.ant-card-contain-tabs]': '!!listOfNzCardTabComponent',\n    '[class.ant-card-rtl]': `dir === 'rtl'`\n  },\n  imports: [NzOutletModule, NgTemplateOutlet, NzSkeletonModule]\n})\nexport class NzCardComponent implements OnInit {\n  private cdr = inject(ChangeDetectorRef);\n  private directionality = inject(Directionality);\n  private destroyRef = inject(DestroyRef);\n\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  @Input({ transform: booleanAttribute }) @WithConfig() nzBordered: boolean = true;\n  @Input({ transform: booleanAttribute }) nzLoading = false;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzHoverable: boolean = false;\n  @Input() nzBodyStyle: NgStyleInterface | null = null;\n  @Input() nzCover?: TemplateRef<void>;\n  @Input() nzActions: Array<TemplateRef<void>> = [];\n  @Input() nzType: string | 'inner' | null = null;\n  @Input() @WithConfig() nzSize: NzSizeDSType = 'default';\n  @Input() nzTitle?: string | TemplateRef<void>;\n  @Input() nzExtra?: string | TemplateRef<void>;\n  @ContentChild(NzCardTabComponent, { static: false }) listOfNzCardTabComponent?: NzCardTabComponent;\n  @ContentChildren(NzCardGridDirective) listOfNzCardGridDirective!: QueryList<NzCardGridDirective>;\n  dir: Direction = 'ltr';\n\n  constructor() {\n    onConfigChangeEventForComponent(NZ_CONFIG_MODULE_NAME, () => this.cdr.markForCheck());\n  }\n\n  ngOnInit(): void {\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((direction: Direction) => {\n      this.dir = direction;\n      this.cdr.detectChanges();\n    });\n\n    this.dir = this.directionality.value;\n  }\n}\n"
  },
  {
    "path": "components/card/card.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule } from '@angular/cdk/bidi';\nimport { NgModule } from '@angular/core';\n\nimport { NzCardGridDirective } from './card-grid.directive';\nimport { NzCardMetaComponent } from './card-meta.component';\nimport { NzCardTabComponent } from './card-tab.component';\nimport { NzCardComponent } from './card.component';\n\n@NgModule({\n  imports: [NzCardComponent, NzCardGridDirective, NzCardMetaComponent, NzCardTabComponent],\n  exports: [BidiModule, NzCardComponent, NzCardGridDirective, NzCardMetaComponent, NzCardTabComponent]\n})\nexport class NzCardModule {}\n"
  },
  {
    "path": "components/card/card.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport { Component, NO_ERRORS_SCHEMA, provideZoneChangeDetection, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\nimport { Subject } from 'rxjs';\n\nimport { NzConfigService } from 'ng-zorro-antd/core/config';\nimport { NzSizeDSType } from 'ng-zorro-antd/core/types';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzCardComponent } from './card.component';\nimport { NzCardModule } from './card.module';\nimport { NzDemoCardBasicComponent } from './demo/basic';\nimport { NzDemoCardBorderLessComponent } from './demo/border-less';\nimport { NzDemoCardFlexibleContentComponent } from './demo/flexible-content';\nimport { NzDemoCardGridCardComponent } from './demo/grid-card';\nimport { NzDemoCardInColumnComponent } from './demo/in-column';\nimport { NzDemoCardInnerComponent } from './demo/inner';\nimport { NzDemoCardLoadingComponent } from './demo/loading';\nimport { NzDemoCardMetaComponent } from './demo/meta';\nimport { NzDemoCardSimpleComponent } from './demo/simple';\nimport { NzDemoCardTabsComponent } from './demo/tabs';\n\ndescribe('card', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), provideNzIconsTesting(), provideZoneChangeDetection()],\n      schemas: [NO_ERRORS_SCHEMA]\n    });\n  });\n\n  it('should basic work', () => {\n    const fixture = TestBed.createComponent(NzDemoCardBasicComponent);\n    const card = fixture.debugElement.query(By.directive(NzCardComponent));\n    fixture.detectChanges();\n    expect(card.nativeElement.classList).toContain('ant-card');\n    expect(card.nativeElement.classList).toContain('ant-card-bordered');\n    expect(card.nativeElement.querySelector('.ant-card-head-title').innerText).toBe('Card title');\n    expect(card.nativeElement.querySelector('.ant-card-extra').innerText).toBe('More');\n  });\n\n  it('should borderless work', () => {\n    const fixture = TestBed.createComponent(NzDemoCardBorderLessComponent);\n    const card = fixture.debugElement.query(By.directive(NzCardComponent));\n    fixture.detectChanges();\n    expect(card.nativeElement.classList).toContain('ant-card');\n    expect(card.nativeElement.classList).not.toContain('ant-card-bordered');\n  });\n\n  it('should simple work', () => {\n    const fixture = TestBed.createComponent(NzDemoCardSimpleComponent);\n    const card = fixture.debugElement.query(By.directive(NzCardComponent));\n    fixture.detectChanges();\n    expect(card.nativeElement.firstElementChild!.classList).toContain('ant-card-body');\n  });\n\n  it('should flexible content work', () => {\n    const fixture = TestBed.createComponent(NzDemoCardFlexibleContentComponent);\n    const card = fixture.debugElement.query(By.directive(NzCardComponent));\n    fixture.detectChanges();\n    expect(card.nativeElement.classList).toContain('ant-card-hoverable');\n    expect(card.nativeElement.firstElementChild!.classList).toContain('ant-card-cover');\n    expect(card.nativeElement.querySelector('.ant-card-meta-title').innerText).toBe('Europe Street beat');\n    expect(card.nativeElement.querySelector('.ant-card-meta-description').innerText).toBe('www.instagram.com');\n  });\n\n  it('should in column work', () => {\n    const fixture = TestBed.createComponent(NzDemoCardInColumnComponent);\n    const card = fixture.debugElement.query(By.directive(NzCardComponent));\n    fixture.detectChanges();\n    expect(card.nativeElement.classList).toContain('ant-card');\n  });\n\n  it('should loading work', () => {\n    const fixture = TestBed.createComponent(NzDemoCardLoadingComponent);\n    const card = fixture.debugElement.query(By.directive(NzCardComponent));\n    fixture.detectChanges();\n    expect(card.nativeElement.classList).toContain('ant-card-loading');\n    const skeleton = card.nativeElement.querySelector('nz-skeleton');\n    expect(skeleton).toBeTruthy();\n    expect(skeleton.classList).toContain('ant-skeleton-active');\n  });\n\n  it('should grid work', () => {\n    const fixture = TestBed.createComponent(NzDemoCardGridCardComponent);\n    const card = fixture.debugElement.query(By.directive(NzCardComponent));\n    fixture.detectChanges();\n    expect(card.nativeElement.classList).toContain('ant-card-contain-grid');\n    expect(card.nativeElement.querySelector('.ant-card-body').firstElementChild!.classList).toContain('ant-card-grid');\n  });\n\n  it('should inner work', () => {\n    const fixture = TestBed.createComponent(NzDemoCardInnerComponent);\n    const card = fixture.debugElement.query(By.directive(NzCardComponent));\n    fixture.detectChanges();\n    expect(card.nativeElement.classList).not.toContain('ant-card-type-inner');\n    expect(card.nativeElement.querySelectorAll('.ant-card-type-inner').length).toBe(2);\n  });\n\n  it('should card work', () => {\n    const fixture = TestBed.createComponent(NzDemoCardTabsComponent);\n    const cards = fixture.debugElement.queryAll(By.directive(NzCardComponent));\n    fixture.detectChanges();\n    expect(cards[0].nativeElement.classList).toContain('ant-card-contain-tabs');\n    expect(cards[0].nativeElement.firstElementChild.firstElementChild!.classList).toContain('ant-card-head-wrapper');\n    expect(cards[1].nativeElement.classList).toContain('ant-card-contain-tabs');\n    expect(cards[1].nativeElement.firstElementChild.firstElementChild!.classList).toContain('ant-card-head-wrapper');\n  });\n\n  it('should meta work', () => {\n    const fixture = TestBed.createComponent(NzDemoCardMetaComponent);\n    const card = fixture.debugElement.query(By.directive(NzCardComponent));\n    fixture.detectChanges();\n    expect(card.nativeElement.querySelector('.ant-card-actions').children.length).toBe(3);\n  });\n\n  it('should size work', () => {\n    const fixture = TestBed.createComponent(TestCardSizeComponent);\n    const card = fixture.debugElement.query(By.directive(NzCardComponent));\n    fixture.detectChanges();\n    expect(card.nativeElement.classList).not.toContain('ant-card-small');\n    fixture.componentInstance.size = 'small';\n    fixture.detectChanges();\n    expect(card.nativeElement.classList).toContain('ant-card-small');\n  });\n\n  describe('RTL', () => {\n    it('should card className correct on dir change', () => {\n      const fixture = TestBed.createComponent(NzTestCardRtlComponent);\n      const card = fixture.debugElement.query(By.directive(NzCardComponent));\n      fixture.detectChanges();\n      expect(card.nativeElement.classList).toContain('ant-card-rtl');\n\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n      expect(card.nativeElement.classList).not.toContain('ant-card-rtl');\n    });\n  });\n});\n\n@Component({\n  imports: [NzCardModule],\n  template: `\n    <nz-card [nzSize]=\"size\">\n      <p>Card content</p>\n      <p>Card content</p>\n      <p>Card content</p>\n    </nz-card>\n  `\n})\nclass TestCardSizeComponent {\n  size: NzSizeDSType = 'default';\n}\n\n@Component({\n  imports: [BidiModule, NzCardModule],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-card>\n        <p>Card content</p>\n        <p>Card content</p>\n        <p>Card content</p>\n      </nz-card>\n    </div>\n  `\n})\nexport class NzTestCardRtlComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n}\n\ndescribe('card component', () => {\n  let fixture: ComponentFixture<NzCardComponent>;\n  let component: NzCardComponent;\n  let configChangeEvent$: Subject<void>;\n\n  beforeEach(() => {\n    configChangeEvent$ = new Subject<void>();\n    const nzConfigServiceSpy = jasmine.createSpyObj('NzConfigService', {\n      getConfigChangeEventForComponent: configChangeEvent$.asObservable(),\n      getConfigForComponent: {}\n    });\n\n    TestBed.configureTestingModule({\n      imports: [NzCardModule, NzCardModule],\n      providers: [{ provide: NzConfigService, useValue: nzConfigServiceSpy }]\n    });\n\n    fixture = TestBed.createComponent(NzCardComponent);\n    component = fixture.componentInstance;\n  });\n\n  it('should call markForCheck when changing nzConfig', fakeAsync(() => {\n    spyOn(component['cdr'], 'markForCheck');\n    fixture.detectChanges();\n    configChangeEvent$.next();\n    tick();\n    expect(component['cdr'].markForCheck).toHaveBeenCalled();\n  }));\n});\n"
  },
  {
    "path": "components/card/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 典型卡片\n  en-US: Basic card\n---\n\n## zh-CN\n\n包含标题、内容、操作区域。\n\n## en-US\n\nA basic card containing a title, content and an extra corner content.\n"
  },
  {
    "path": "components/card/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCardModule } from 'ng-zorro-antd/card';\n\n@Component({\n  selector: 'nz-demo-card-basic',\n  imports: [NzCardModule],\n  template: `\n    <nz-card style=\"width:300px;\" nzTitle=\"Card title\" [nzExtra]=\"extraTemplate\">\n      <p>Card content</p>\n      <p>Card content</p>\n      <p>Card content</p>\n    </nz-card>\n    <ng-template #extraTemplate>\n      <a>More</a>\n    </ng-template>\n  `,\n  styles: `\n    p {\n      margin: 0;\n    }\n  `\n})\nexport class NzDemoCardBasicComponent {}\n"
  },
  {
    "path": "components/card/demo/border-less.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 无边框\n  en-US: No border\n---\n\n## zh-CN\n\n在灰色背景上使用无边框的卡片。\n\n## en-US\n\nA borderless card on a gray background.\n"
  },
  {
    "path": "components/card/demo/border-less.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCardModule } from 'ng-zorro-antd/card';\n\n@Component({\n  selector: 'nz-demo-card-border-less',\n  imports: [NzCardModule],\n  template: `\n    <div style=\"background: #ECECEC; padding:30px;\">\n      <nz-card style=\"width:300px;\" [nzBordered]=\"false\" nzTitle=\"Card title\" [nzExtra]=\"extraTemplate\">\n        <p>Card content</p>\n        <p>Card content</p>\n        <p>Card content</p>\n      </nz-card>\n    </div>\n    <ng-template #extraTemplate>\n      <a>More</a>\n    </ng-template>\n  `,\n  styles: `\n    p {\n      margin: 0;\n    }\n  `\n})\nexport class NzDemoCardBorderLessComponent {}\n"
  },
  {
    "path": "components/card/demo/flexible-content.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 更灵活的内容展示\n  en-US: Customized content\n---\n\n## zh-CN\n\n可以利用 `nz-card-meta` 支持更灵活的内容。\n\n## en-US\n\nYou can use `nz-card-meta` to support more flexible content.\n"
  },
  {
    "path": "components/card/demo/flexible-content.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCardModule } from 'ng-zorro-antd/card';\n\n@Component({\n  selector: 'nz-demo-card-flexible-content',\n  imports: [NzCardModule],\n  template: `\n    <nz-card nzHoverable style=\"width:240px\" [nzCover]=\"coverTemplate\">\n      <nz-card-meta nzTitle=\"Europe Street beat\" nzDescription=\"www.instagram.com\" />\n    </nz-card>\n    <ng-template #coverTemplate>\n      <img alt=\"example\" src=\"https://os.alipayobjects.com/rmsportal/QBnOOoLaAfKPirc.png\" />\n    </ng-template>\n  `\n})\nexport class NzDemoCardFlexibleContentComponent {}\n"
  },
  {
    "path": "components/card/demo/grid-card.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 网格型内嵌卡片\n  en-US: Grid card\n---\n\n## zh-CN\n\n一种常见的卡片内容区隔模式。\n\n## en-US\n\nGrid style card content.\n"
  },
  {
    "path": "components/card/demo/grid-card.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCardModule } from 'ng-zorro-antd/card';\n\n@Component({\n  selector: 'nz-demo-card-grid-card',\n  imports: [NzCardModule],\n  template: `\n    <nz-card nzTitle=\"Cart Title\">\n      <div nz-card-grid>Content</div>\n      <div nz-card-grid>Content</div>\n      <div nz-card-grid>Content</div>\n      <div nz-card-grid>Content</div>\n      <div nz-card-grid>Content</div>\n      <div nz-card-grid>Content</div>\n      <div nz-card-grid>Content</div>\n    </nz-card>\n  `,\n  styles: `\n    [nz-card-grid] {\n      width: 25%;\n      text-align: center;\n    }\n  `\n})\nexport class NzDemoCardGridCardComponent {}\n"
  },
  {
    "path": "components/card/demo/in-column.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 栅格卡片\n  en-US: Card in column\n---\n\n## zh-CN\n\n在系统概览页面常常和栅格进行配合。\n\n## en-US\n\nCards usually cooperate with grid column layout in overview page.\n"
  },
  {
    "path": "components/card/demo/in-column.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCardModule } from 'ng-zorro-antd/card';\nimport { NzGridModule } from 'ng-zorro-antd/grid';\n\n@Component({\n  selector: 'nz-demo-card-in-column',\n  imports: [NzCardModule, NzGridModule],\n  template: `\n    <div style=\"background: #ECECEC; padding:30px;\">\n      <div nz-row [nzGutter]=\"8\">\n        <div nz-col [nzSpan]=\"8\">\n          <nz-card nzTitle=\"Card title\">\n            <p>Card content</p>\n          </nz-card>\n        </div>\n        <div nz-col [nzSpan]=\"8\">\n          <nz-card nzTitle=\"Card title\">\n            <p>Card content</p>\n          </nz-card>\n        </div>\n        <div nz-col [nzSpan]=\"8\">\n          <nz-card nzTitle=\"Card title\">\n            <p>Card content</p>\n          </nz-card>\n        </div>\n      </div>\n    </div>\n  `,\n  styles: `\n    p {\n      margin: 0;\n    }\n  `\n})\nexport class NzDemoCardInColumnComponent {}\n"
  },
  {
    "path": "components/card/demo/inner.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 内部卡片\n  en-US: Inner card\n---\n\n## zh-CN\n\n可以放在普通卡片内部，展示多层级结构的信息。\n\n## en-US\n\nIt can be placed inside the ordinary card to display the information of the multilevel structure.\n"
  },
  {
    "path": "components/card/demo/inner.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCardModule } from 'ng-zorro-antd/card';\n\n@Component({\n  selector: 'nz-demo-card-inner',\n  imports: [NzCardModule],\n  template: `\n    <nz-card nzTitle=\"Card Title\">\n      <p style=\"font-size:14px;color:rgba(0, 0, 0, 0.85);margin-bottom:16px;font-weight: 500;\">Group title</p>\n      <nz-card nzType=\"inner\" nzTitle=\"Inner Card Title\" [nzExtra]=\"extraTemplate\">\n        <a>Inner Card Content</a>\n      </nz-card>\n      <nz-card nzType=\"inner\" style=\"margin-top:16px;\" nzTitle=\"Inner Card Title\" [nzExtra]=\"extraTemplate\">\n        <a>Inner Card Content</a>\n      </nz-card>\n    </nz-card>\n    <ng-template #extraTemplate>\n      <a>More</a>\n    </ng-template>\n  `\n})\nexport class NzDemoCardInnerComponent {}\n"
  },
  {
    "path": "components/card/demo/loading.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 预加载的卡片\n  en-US: Loading card\n---\n\n## zh-CN\n\n数据读入前会有文本块样式。\n\n## en-US\n\nShows a loading indicator while the contents of the card is being fetched.\n"
  },
  {
    "path": "components/card/demo/loading.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzAvatarModule } from 'ng-zorro-antd/avatar';\nimport { NzCardModule } from 'ng-zorro-antd/card';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzSkeletonModule } from 'ng-zorro-antd/skeleton';\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\n\n@Component({\n  selector: 'nz-demo-card-loading',\n  imports: [FormsModule, NzAvatarModule, NzCardModule, NzIconModule, NzSwitchModule, NzSkeletonModule],\n  template: `\n    <nz-switch [(ngModel)]=\"loading\" />\n    <nz-card style=\"width: 300px;margin-top: 16px\" [nzLoading]=\"loading\">\n      <nz-card-meta [nzAvatar]=\"avatarTemplate\" nzTitle=\"Card title\" nzDescription=\"This is the description\" />\n    </nz-card>\n    <nz-card style=\"width: 300px;margin-top: 16px\" [nzActions]=\"[actionSetting, actionEdit, actionEllipsis]\">\n      <nz-skeleton [nzActive]=\"true\" [nzLoading]=\"loading\" [nzAvatar]=\"{ size: 'large' }\">\n        <nz-card-meta [nzAvatar]=\"avatarTemplate\" nzTitle=\"Card title\" nzDescription=\"This is the description\" />\n      </nz-skeleton>\n    </nz-card>\n    <ng-template #avatarTemplate>\n      <nz-avatar nzSrc=\"https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png\" />\n    </ng-template>\n    <ng-template #actionSetting>\n      <nz-icon nzType=\"setting\" />\n    </ng-template>\n    <ng-template #actionEdit>\n      <nz-icon nzType=\"edit\" />\n    </ng-template>\n    <ng-template #actionEllipsis>\n      <nz-icon nzType=\"ellipsis\" />\n    </ng-template>\n  `\n})\nexport class NzDemoCardLoadingComponent {\n  loading = true;\n}\n"
  },
  {
    "path": "components/card/demo/meta.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 支持更多内容配置\n  en-US: Support more content configuration\n---\n\n## zh-CN\n\n一种支持封面、头像、标题和描述信息的卡片。\n\n## en-US\n\nA Card that supports `cover`, `avatar`, `title` and `description`.\n"
  },
  {
    "path": "components/card/demo/meta.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzAvatarModule } from 'ng-zorro-antd/avatar';\nimport { NzCardModule } from 'ng-zorro-antd/card';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-demo-card-meta',\n  imports: [NzAvatarModule, NzCardModule, NzIconModule],\n  template: `\n    <nz-card style=\"width:300px;\" [nzCover]=\"coverTemplate\" [nzActions]=\"[actionSetting, actionEdit, actionEllipsis]\">\n      <nz-card-meta nzTitle=\"Card title\" nzDescription=\"This is the description\" [nzAvatar]=\"avatarTemplate\" />\n    </nz-card>\n    <ng-template #avatarTemplate>\n      <nz-avatar nzSrc=\"https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png\" />\n    </ng-template>\n    <ng-template #coverTemplate>\n      <img alt=\"example\" src=\"https://gw.alipayobjects.com/zos/rmsportal/JiqGstEfoWAOHiTxclqi.png\" />\n    </ng-template>\n    <ng-template #actionSetting>\n      <nz-icon nzType=\"setting\" />\n    </ng-template>\n    <ng-template #actionEdit>\n      <nz-icon nzType=\"edit\" />\n    </ng-template>\n    <ng-template #actionEllipsis>\n      <nz-icon nzType=\"ellipsis\" />\n    </ng-template>\n  `\n})\nexport class NzDemoCardMetaComponent {}\n"
  },
  {
    "path": "components/card/demo/simple.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 简洁卡片\n  en-US: Simple card\n---\n\n## zh-CN\n\n只包含内容区域。\n\n## en-US\n\nA simple card only containing a content area.\n"
  },
  {
    "path": "components/card/demo/simple.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCardModule } from 'ng-zorro-antd/card';\n\n@Component({\n  selector: 'nz-demo-card-simple',\n  imports: [NzCardModule],\n  template: `\n    <nz-card style=\"width:300px;\">\n      <p>Card content</p>\n      <p>Card content</p>\n      <p>Card content</p>\n    </nz-card>\n  `,\n  styles: `\n    p {\n      margin: 0;\n    }\n  `\n})\nexport class NzDemoCardSimpleComponent {}\n"
  },
  {
    "path": "components/card/demo/tabs.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 带页签的卡片\n  en-US: With tabs\n---\n\n## zh-CN\n\n可承载更多内容。\n\n## en-US\n\nMore content can be hosted.\n"
  },
  {
    "path": "components/card/demo/tabs.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCardModule } from 'ng-zorro-antd/card';\nimport { NzTabsModule } from 'ng-zorro-antd/tabs';\n\n@Component({\n  selector: 'nz-demo-card-tabs',\n  imports: [NzCardModule, NzTabsModule],\n  template: `\n    <nz-card style=\"width: 100%;\" nzTitle=\"Card title\" [nzExtra]=\"extraTemplate\">\n      <nz-card-tab>\n        <nz-tabs nzSize=\"large\" [(nzSelectedIndex)]=\"index1\">\n          <nz-tab nzTitle=\"tab1\" />\n          <nz-tab nzTitle=\"tab2\" />\n        </nz-tabs>\n      </nz-card-tab>\n      content{{ index1 }}\n    </nz-card>\n    <ng-template #extraTemplate>\n      <a>More</a>\n    </ng-template>\n    <br />\n    <br />\n    <nz-card style=\"width: 100%;\">\n      <nz-card-tab>\n        <nz-tabs nzSize=\"large\" [(nzSelectedIndex)]=\"index2\">\n          <nz-tab nzTitle=\"article\" />\n          <nz-tab nzTitle=\"app\" />\n          <nz-tab nzTitle=\"project\" />\n        </nz-tabs>\n      </nz-card-tab>\n      content{{ index2 }}\n    </nz-card>\n  `\n})\nexport class NzDemoCardTabsComponent {\n  index1 = 0;\n  index2 = 0;\n}\n"
  },
  {
    "path": "components/card/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Display\ntitle: Card\ncols: 1\ncover: 'https://gw.alipayobjects.com/zos/alicdn/keNB-R8Y9/Card.svg'\ndescription: Simple rectangular container.\n---\n\n## When To Use\n\nA card can be used to display content related to a single subject. The content can consist of multiple elements of varying types and sizes.\n\n## API\n\n```html\n<nz-card nzTitle=\"card title\">card content</nz-card>\n```\n\n### nz-card\n\n| Property        | Description                                                                | Type                          | Default     | Global Config |\n| --------------- | -------------------------------------------------------------------------- | ----------------------------- | ----------- | ------------- |\n| `[nzActions]`   | The action list, shows at the bottom of the Card.                          | `Array<TemplateRef<void>>`    | -           |\n| `[nzBodyStyle]` | Inline style to apply to the card content                                  | `{ [key: string]: string }`   | -           |\n| `[nzBordered]`  | Toggles rendering of the border around the card                            | `boolean`                     | `true`      | ✅            |\n| `[nzCover]`     | Card cover                                                                 | `TemplateRef<void>`           | -           |\n| `[nzExtra]`     | Content to render in the top-right corner of the card                      | `string \\| TemplateRef<void>` | -           |\n| `[nzHoverable]` | Lift up when hovering card                                                 | `boolean`                     | `false`     | ✅            |\n| `[nzLoading]`   | Shows a loading indicator while the contents of the card are being fetched | `boolean`                     | `false`     |\n| `[nzTitle]`     | Card title                                                                 | `string \\| TemplateRef<void>` | -           |\n| `[nzType]`      | Card style type, can be set to `inner` or not set                          | `'inner'`                     | -           |\n| `[nzSize]`      | Size of card                                                               | `'default' \\| 'small'`        | `'default'` | ✅            |\n\n### nz-card-meta\n\n| Property          | Description         | Type                          | Default |\n| ----------------- | ------------------- | ----------------------------- | ------- |\n| `[nzAvatar]`      | avatar or icon      | `TemplateRef<void>`           | -       |\n| `[nzDescription]` | description content | `string \\| TemplateRef<void>` | -       |\n| `[nzTitle]`       | title content       | `string \\| TemplateRef<void>` | -       |\n\n### [nz-card-grid]\n\n| Property        | Description                | Type      | Default | Global Config |\n| --------------- | -------------------------- | --------- | ------- | ------------- |\n| `[nzHoverable]` | Lift up when hovering card | `boolean` | `true`  | -             |\n\nArea for grid style card\n\n### nz-card-tab\n\nArea for tab card\n"
  },
  {
    "path": "components/card/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ntype: 数据展示\ntitle: Card\nsubtitle: 卡片\ncols: 1\ncover: 'https://gw.alipayobjects.com/zos/alicdn/keNB-R8Y9/Card.svg'\ndescription: 通用卡片容器。\n---\n\n## 何时使用\n\n最基础的卡片容器，可承载文字、列表、图片、段落，常用于后台概览页面。\n\n## API\n\n```html\n<nz-card nzTitle=\"卡片标题\">卡片内容</nz-card>\n```\n\n### nz-card\n\n| 参数            | 说明                                                | 类型                          | 默认值      | 支持全局配置 |\n| --------------- | --------------------------------------------------- | ----------------------------- | ----------- | ------------ |\n| `[nzActions]`   | 卡片操作组，位置在卡片底部                          | `Array<TemplateRef<void>>`    | -           |\n| `[nzBodyStyle]` | 内容区域自定义样式                                  | `{ [key: string]: string }`   | -           |\n| `[nzBordered]`  | 是否有边框                                          | `boolean`                     | `true`      | ✅           |\n| `[nzCover]`     | 卡片封面                                            | `TemplateRef<void>`           | -           |\n| `[nzExtra]`     | 卡片右上角的操作区域                                | `string \\| TemplateRef<void>` | -           |\n| `[nzHoverable]` | 鼠标移过时可浮起                                    | `boolean`                     | `false`     | ✅           |\n| `[nzLoading]`   | 当卡片内容还在加载中时，可以用 loading 展示一个占位 | `boolean`                     | `false`     |\n| `[nzTitle]`     | 卡片标题                                            | `string \\| TemplateRef<void>` | -           |\n| `[nzType]`      | 卡片类型，可设置为 `inner` 或 不设置                | `'inner'`                     | -           |\n| `[nzSize]`      | 卡片的尺寸                                          | `'default' \\| 'small'`        | `'default'` | ✅           |\n\n### nz-card-meta\n\n| 参数              | 说明      | 类型                          | 默认值 |\n| ----------------- | --------- | ----------------------------- | ------ |\n| `[nzAvatar]`      | 头像/图标 | `TemplateRef<void>`           | -      |\n| `[nzDescription]` | 描述内容  | `string \\| TemplateRef<void>` | -      |\n| `[nzTitle]`       | 标题内容  | `string \\| TemplateRef<void>` | -      |\n\n### [nz-card-grid]\n\n| 参数            | 说明             | 类型      | 默认值 | 支持全局配置 |\n| --------------- | ---------------- | --------- | ------ | ------------ |\n| `[nzHoverable]` | 鼠标移过时可浮起 | `boolean` | `true` | -            |\n\n分隔卡片内容区域\n\n### nz-card-tab\n\n分隔页签标题区域\n"
  },
  {
    "path": "components/card/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/card/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/card/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './card-grid.directive';\nexport * from './card-meta.component';\nexport * from './card-tab.component';\nexport * from './card.component';\nexport * from './card.module';\n"
  },
  {
    "path": "components/card/style/entry.less",
    "content": "@import './index.less';\n// style dependencies\n@import '../../tabs/style/entry.less';\n@import '../../grid/style/entry.less';\n@import './patch.less';\n"
  },
  {
    "path": "components/card/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@card-prefix-cls: ~'@{ant-prefix}-card';\n@card-hoverable-hover-border: transparent;\n@card-action-icon-size: 16px;\n\n@gradient-min: fade(@card-skeleton-bg, 20%);\n@gradient-max: fade(@card-skeleton-bg, 40%);\n\n.@{card-prefix-cls} {\n  .reset-component();\n\n  position: relative;\n  background: @card-background;\n  border-radius: @card-radius;\n\n  &-rtl {\n    direction: rtl;\n  }\n\n  &-hoverable {\n    cursor: pointer;\n    transition: box-shadow 0.3s, border-color 0.3s;\n\n    &:hover {\n      border-color: @card-hoverable-hover-border;\n      box-shadow: @card-shadow;\n    }\n  }\n\n  &-bordered {\n    border: @border-width-base @border-style-base @border-color-split;\n  }\n\n  &-head {\n    min-height: @card-head-height;\n    margin-bottom: -1px; // Fix card grid overflow bug: https://gw.alipayobjects.com/zos/rmsportal/XonYxBikwpgbqIQBeuhk.png\n    padding: 0 @card-padding-base;\n    color: @card-head-color;\n    font-weight: 500;\n    font-size: @card-head-font-size;\n    background: @card-head-background;\n    border-bottom: @border-width-base @border-style-base @border-color-split;\n    border-radius: @card-radius @card-radius 0 0;\n    .clearfix();\n\n    &-wrapper {\n      display: flex;\n      align-items: center;\n    }\n\n    &-title {\n      display: inline-block;\n      flex: 1;\n      padding: @card-head-padding 0;\n      overflow: hidden;\n      white-space: nowrap;\n      text-overflow: ellipsis;\n\n      > .@{ant-prefix}-typography,\n      > .@{ant-prefix}-typography-edit-content {\n        left: 0;\n        margin-top: 0;\n        margin-bottom: 0;\n      }\n    }\n\n    .@{ant-prefix}-tabs-top {\n      clear: both;\n      margin-bottom: @card-head-tabs-margin-bottom;\n      color: @text-color;\n      font-weight: normal;\n      font-size: @font-size-base;\n\n      &-bar {\n        border-bottom: @border-width-base @border-style-base @border-color-split;\n      }\n    }\n  }\n\n  &-extra {\n    // https://stackoverflow.com/a/22429853/3040605\n    margin-left: auto;\n    padding: @card-head-padding 0;\n    color: @card-head-extra-color;\n    font-weight: normal;\n    font-size: @font-size-base;\n\n    .@{card-prefix-cls}-rtl & {\n      margin-right: auto;\n      margin-left: 0;\n    }\n  }\n\n  &-body {\n    padding: @card-padding-base;\n    .clearfix();\n  }\n\n  &-contain-grid &-body {\n    display: flex;\n    flex-wrap: wrap;\n  }\n\n  &-contain-grid:not(&-loading) &-body {\n    margin: -1px 0 0 -1px;\n    padding: 0;\n  }\n\n  &-grid {\n    width: 33.33%;\n    padding: @card-padding-base;\n    border: 0;\n    border-radius: 0;\n    box-shadow: 1px 0 0 0 @border-color-split, 0 1px 0 0 @border-color-split,\n      1px 1px 0 0 @border-color-split, 1px 0 0 0 @border-color-split inset,\n      0 1px 0 0 @border-color-split inset;\n    transition: all 0.3s;\n\n    &-hoverable {\n      &:hover {\n        position: relative;\n        z-index: 1;\n        box-shadow: @card-shadow;\n      }\n    }\n  }\n\n  &-contain-tabs > &-head &-head-title {\n    min-height: @card-head-height - @card-head-padding;\n    padding-bottom: 0;\n  }\n\n  &-contain-tabs > &-head &-extra {\n    padding-bottom: 0;\n  }\n\n  &-bordered &-cover {\n    margin-top: -1px;\n    margin-right: -1px;\n    margin-left: -1px;\n  }\n\n  &-cover {\n    > * {\n      display: block;\n      width: 100%;\n    }\n\n    img {\n      border-radius: @card-radius @card-radius 0 0;\n    }\n  }\n\n  &-actions {\n    display: flex;\n    margin: 0;\n    padding: 0;\n    list-style: none;\n    background: @card-actions-background;\n    border-top: @border-width-base @border-style-base @border-color-split;\n    .clearfix();\n\n    & > li {\n      margin: @card-actions-li-margin;\n      color: @text-color-secondary;\n      text-align: center;\n\n      > span {\n        position: relative;\n        display: block;\n        min-width: 32px;\n        font-size: @font-size-base;\n        line-height: @line-height-base;\n        cursor: pointer;\n\n        &:hover {\n          color: @primary-color;\n          transition: color 0.3s;\n        }\n\n        a:not(.@{ant-prefix}-btn),\n        > .@{iconfont-css-prefix} {\n          display: inline-block;\n          width: 100%;\n          color: @text-color-secondary;\n          line-height: 22px;\n          transition: color 0.3s;\n\n          &:hover {\n            color: @primary-color;\n          }\n        }\n\n        > .@{iconfont-css-prefix} {\n          font-size: @card-action-icon-size;\n          line-height: 22px;\n        }\n      }\n\n      &:not(:last-child) {\n        border-right: @border-width-base @border-style-base @border-color-split;\n\n        .@{card-prefix-cls}-rtl & {\n          border-right: none;\n          border-left: @border-width-base @border-style-base @border-color-split;\n        }\n      }\n    }\n  }\n\n  &-type-inner &-head {\n    padding: 0 @card-padding-base;\n    background: @background-color-light;\n\n    &-title {\n      padding: @card-inner-head-padding 0;\n      font-size: @font-size-base;\n    }\n  }\n\n  &-type-inner &-body {\n    padding: 16px @card-padding-base;\n  }\n\n  &-type-inner &-extra {\n    padding: @card-inner-head-padding + 1.5px 0;\n  }\n\n  &-meta {\n    display: flex;\n    margin: -4px 0;\n    .clearfix();\n\n    &-avatar {\n      padding-right: 16px;\n\n      .@{card-prefix-cls}-rtl & {\n        padding-right: 0;\n        padding-left: 16px;\n      }\n    }\n\n    &-detail {\n      flex: 1;\n      overflow: hidden;\n\n      > div:not(:last-child) {\n        margin-bottom: @margin-xs;\n      }\n    }\n\n    &-title {\n      overflow: hidden;\n      color: @card-head-color;\n      font-weight: 500;\n      font-size: @font-size-lg;\n      white-space: nowrap;\n      text-overflow: ellipsis;\n    }\n\n    &-description {\n      color: @text-color-secondary;\n    }\n  }\n\n  &-loading {\n    overflow: hidden;\n  }\n\n  &-loading &-body {\n    user-select: none;\n  }\n}\n\n@import './size';\n"
  },
  {
    "path": "components/card/style/patch.less",
    "content": "@skeleton-prefix-cls: ~'@{ant-prefix}-skeleton';\n.@{card-prefix-cls} {\n  &-rtl {\n    .@{skeleton-prefix-cls}-header {\n      padding: 0 0 0 @card-head-padding;\n    }\n  }\n}\n\nnz-card {\n  display: block;\n}\n\nnz-card-meta {\n  display: block;\n}\n\nnz-card-loading {\n  display: block;\n}\n"
  },
  {
    "path": "components/card/style/size.less",
    "content": ".@{card-prefix-cls}-small {\n  > .@{card-prefix-cls}-head {\n    min-height: @card-head-height-sm;\n    padding: 0 @card-padding-base-sm;\n    font-size: @card-head-font-size-sm;\n\n    > .@{card-prefix-cls}-head-wrapper {\n      > .@{card-prefix-cls}-head-title {\n        padding: @card-head-padding-sm 0;\n      }\n      > .@{card-prefix-cls}-extra {\n        padding: @card-head-padding-sm 0;\n        font-size: @card-head-font-size-sm;\n      }\n    }\n  }\n  > .@{card-prefix-cls}-body {\n    padding: @card-padding-base-sm;\n  }\n}\n"
  },
  {
    "path": "components/carousel/carousel-content.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, ElementRef, inject, Renderer2 } from '@angular/core';\n\n@Directive({\n  selector: '[nz-carousel-content]',\n  exportAs: 'nzCarouselContent',\n  host: {\n    class: 'slick-slide'\n  }\n})\nexport class NzCarouselContentDirective {\n  private renderer = inject(Renderer2);\n  readonly el: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement;\n\n  set isActive(value: boolean) {\n    this._active = value;\n    if (this.isActive) {\n      this.renderer.addClass(this.el, 'slick-active');\n    } else {\n      this.renderer.removeClass(this.el, 'slick-active');\n    }\n  }\n\n  get isActive(): boolean {\n    return this._active;\n  }\n\n  private _active = false;\n}\n"
  },
  {
    "path": "components/carousel/carousel.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport { LEFT_ARROW, RIGHT_ARROW } from '@angular/cdk/keycodes';\nimport { Platform } from '@angular/cdk/platform';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterContentInit,\n  AfterViewInit,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ContentChildren,\n  DestroyRef,\n  ElementRef,\n  EventEmitter,\n  Input,\n  NgZone,\n  OnChanges,\n  OnInit,\n  Output,\n  QueryList,\n  Renderer2,\n  SimpleChanges,\n  TemplateRef,\n  ViewChild,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject,\n  numberAttribute\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { debounceTime, distinctUntilChanged } from 'rxjs/operators';\n\nimport { NzResizeObserver } from 'ng-zorro-antd/cdk/resize-observer';\nimport { NzConfigKey, NzConfigService, WithConfig } from 'ng-zorro-antd/core/config';\nimport { NzDragService, NzResizeService } from 'ng-zorro-antd/core/services';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\n\nimport { NzCarouselContentDirective } from './carousel-content.directive';\nimport { NzCarouselBaseStrategy } from './strategies/base-strategy';\nimport { NzCarouselOpacityStrategy } from './strategies/opacity-strategy';\nimport { NzCarouselTransformStrategy } from './strategies/transform-strategy';\nimport {\n  FromToInterface,\n  NZ_CAROUSEL_CUSTOM_STRATEGIES,\n  NzCarouselDotPosition,\n  NzCarouselEffects,\n  PointerVector\n} from './typings';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'carousel';\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-carousel',\n  exportAs: 'nzCarousel',\n  template: `\n    <div\n      class=\"slick-initialized slick-slider\"\n      [class.slick-vertical]=\"nzDotPosition === 'left' || nzDotPosition === 'right'\"\n      dir=\"ltr\"\n    >\n      @if (nzArrows) {\n        <button\n          type=\"button\"\n          aria-label=\"prev\"\n          class=\"slick-prev slick-arrow\"\n          [class.slick-disabled]=\"this.activeIndex === 0\"\n          (click)=\"pre()\"\n        ></button>\n      }\n      <div\n        #slickList\n        class=\"slick-list\"\n        tabindex=\"-1\"\n        (mousedown)=\"pointerDown($event)\"\n        (touchstart)=\"pointerDown($event)\"\n      >\n        <!-- Render carousel items. -->\n        <div class=\"slick-track\" #slickTrack>\n          <ng-content />\n        </div>\n      </div>\n      @if (nzArrows) {\n        <button\n          type=\"button\"\n          aria-label=\"next\"\n          class=\"slick-next slick-arrow\"\n          [class.slick-disabled]=\"this.activeIndex === this.carouselContents.length - 1\"\n          (click)=\"next()\"\n        ></button>\n      }\n      <!-- Render dots. -->\n      @if (nzDots) {\n        <ul\n          class=\"slick-dots\"\n          [class.slick-dots-top]=\"nzDotPosition === 'top'\"\n          [class.slick-dots-bottom]=\"nzDotPosition === 'bottom'\"\n          [class.slick-dots-left]=\"nzDotPosition === 'left'\"\n          [class.slick-dots-right]=\"nzDotPosition === 'right'\"\n        >\n          @for (content of carouselContents; track content) {\n            <li [class.slick-active]=\"$index === activeIndex\" (click)=\"goTo($index)\">\n              <ng-template\n                [ngTemplateOutlet]=\"nzDotRender || renderDotTemplate\"\n                [ngTemplateOutletContext]=\"{ $implicit: $index }\"\n              />\n            </li>\n          }\n        </ul>\n      }\n    </div>\n\n    <ng-template #renderDotTemplate let-index>\n      <button>{{ index + 1 }}</button>\n    </ng-template>\n  `,\n  host: {\n    class: 'ant-carousel',\n    '[class.ant-carousel-vertical]': 'vertical',\n    '[class.ant-carousel-rtl]': `dir === 'rtl'`\n  },\n  imports: [NgTemplateOutlet]\n})\nexport class NzCarouselComponent implements AfterContentInit, AfterViewInit, OnChanges, OnInit {\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  public readonly nzConfigService = inject(NzConfigService);\n  public readonly ngZone = inject(NgZone);\n  private readonly renderer = inject(Renderer2);\n  private readonly cdr = inject(ChangeDetectorRef);\n  private readonly platform = inject(Platform);\n  private readonly resizeService = inject(NzResizeService);\n  private readonly nzDragService = inject(NzDragService);\n  private nzResizeObserver = inject(NzResizeObserver);\n  private destroyRef = inject(DestroyRef);\n\n  @ContentChildren(NzCarouselContentDirective) carouselContents!: QueryList<NzCarouselContentDirective>;\n\n  @ViewChild('slickList', { static: true }) slickList!: ElementRef<HTMLElement>;\n  @ViewChild('slickTrack', { static: true }) slickTrack!: ElementRef<HTMLElement>;\n\n  @Input() nzDotRender?: TemplateRef<{ $implicit: number }>;\n  @Input() @WithConfig() nzEffect: NzCarouselEffects = 'scrollx';\n  @Input({ transform: booleanAttribute }) @WithConfig() nzEnableSwipe: boolean = true;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzDots: boolean = true;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzAutoPlay: boolean = false;\n  @Input({ transform: numberAttribute }) @WithConfig() nzAutoPlaySpeed: number = 3000;\n  @Input({ transform: numberAttribute }) nzTransitionSpeed = 500;\n  @Input() @WithConfig() nzLoop: boolean = true;\n  @Input({ transform: booleanAttribute }) nzArrows = false;\n\n  /**\n   * this property is passed directly to an NzCarouselBaseStrategy\n   */\n  @Input() nzStrategyOptions: NzSafeAny = undefined;\n\n  @Input() @WithConfig() nzDotPosition: NzCarouselDotPosition = 'bottom';\n\n  @Output() readonly nzBeforeChange = new EventEmitter<FromToInterface>();\n  @Output() readonly nzAfterChange = new EventEmitter<number>();\n\n  activeIndex = 0;\n  el: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement;\n  slickListEl!: HTMLElement;\n  slickTrackEl!: HTMLElement;\n  strategy?: NzCarouselBaseStrategy;\n  vertical = false;\n  transitionInProgress?: ReturnType<typeof setTimeout>;\n  dir: Direction = 'ltr';\n\n  private gestureRect: DOMRect | null = null;\n  private pointerDelta: PointerVector | null = null;\n  private isTransiting = false;\n  private isDragging = false;\n  private directionality = inject(Directionality);\n  private customStrategies = inject(NZ_CAROUSEL_CUSTOM_STRATEGIES, { optional: true });\n\n  constructor() {\n    this.nzDotPosition = 'bottom';\n    this.destroyRef.onDestroy(() => {\n      this.clearScheduledTransition();\n      this.strategy?.dispose();\n    });\n  }\n\n  ngOnInit(): void {\n    this.slickListEl = this.slickList!.nativeElement;\n    this.slickTrackEl = this.slickTrack!.nativeElement;\n\n    this.dir = this.directionality.value;\n\n    this.directionality.change.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n      this.dir = direction;\n      this.markContentActive(this.activeIndex);\n      this.cdr.detectChanges();\n    });\n\n    fromEventOutsideAngular<KeyboardEvent>(this.slickListEl, 'keydown')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(event => {\n        const { keyCode } = event;\n\n        if (keyCode !== LEFT_ARROW && keyCode !== RIGHT_ARROW) {\n          return;\n        }\n\n        event.preventDefault();\n\n        this.ngZone.run(() => {\n          if (keyCode === LEFT_ARROW) {\n            this.pre();\n          } else {\n            this.next();\n          }\n          this.cdr.markForCheck();\n        });\n      });\n\n    this.nzResizeObserver\n      .observe(this.el)\n      .pipe(debounceTime(100), distinctUntilChanged(), takeUntilDestroyed(this.destroyRef))\n      .subscribe(() => this.layout());\n  }\n\n  ngAfterContentInit(): void {\n    this.markContentActive(0);\n  }\n\n  ngAfterViewInit(): void {\n    this.carouselContents.changes.subscribe(() => {\n      this.markContentActive(0);\n      this.layout();\n    });\n\n    this.resizeService\n      .connect()\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(() => this.layout());\n\n    this.switchStrategy();\n    this.markContentActive(0);\n    this.layout();\n\n    // If embedded in an entry component, it may do initial render at an inappropriate time.\n    // ngZone.onStable won't do this trick\n    // TODO: need to change this.\n    Promise.resolve().then(() => this.layout());\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzEffect, nzDotPosition } = changes;\n\n    if (nzEffect && !nzEffect.isFirstChange()) {\n      this.switchStrategy();\n      this.markContentActive(0);\n      this.layout();\n    }\n\n    if (nzDotPosition) {\n      this.vertical = nzDotPosition.currentValue === 'left' || nzDotPosition.currentValue === 'right';\n      if (!nzDotPosition.isFirstChange()) {\n        this.switchStrategy();\n        this.markContentActive(0);\n        this.layout();\n      }\n    }\n\n    if (!this.nzAutoPlay || !this.nzAutoPlaySpeed) {\n      this.clearScheduledTransition();\n    } else {\n      this.scheduleNextTransition();\n    }\n  }\n\n  next(): void {\n    this.goTo(this.activeIndex + 1);\n  }\n\n  pre(): void {\n    this.goTo(this.activeIndex - 1);\n  }\n\n  goTo(index: number): void {\n    if (\n      this.carouselContents &&\n      this.carouselContents.length &&\n      !this.isTransiting &&\n      (this.nzLoop || (index >= 0 && index < this.carouselContents.length))\n    ) {\n      const length = this.carouselContents.length;\n      const from = this.activeIndex;\n      const to = (index + length) % length;\n      this.isTransiting = true;\n      this.nzBeforeChange.emit({ from, to });\n      this.strategy!.switch(this.activeIndex, index).subscribe(() => {\n        this.scheduleNextTransition();\n        this.nzAfterChange.emit(to);\n        this.isTransiting = false;\n      });\n      this.markContentActive(to);\n      this.cdr.markForCheck();\n    }\n  }\n\n  private switchStrategy(): void {\n    if (this.strategy) {\n      this.strategy.dispose();\n    }\n\n    // Load custom strategies first.\n    const customStrategy = this.customStrategies ? this.customStrategies.find(s => s.name === this.nzEffect) : null;\n    if (customStrategy) {\n      this.strategy = new (customStrategy.strategy as NzSafeAny)(this, this.cdr, this.renderer, this.platform);\n      return;\n    }\n\n    this.strategy =\n      this.nzEffect === 'scrollx'\n        ? new NzCarouselTransformStrategy(this, this.cdr, this.renderer, this.platform)\n        : new NzCarouselOpacityStrategy(this, this.cdr, this.renderer, this.platform);\n  }\n\n  private scheduleNextTransition(): void {\n    this.clearScheduledTransition();\n    if (this.nzAutoPlay && this.nzAutoPlaySpeed > 0 && this.platform.isBrowser) {\n      this.transitionInProgress = setTimeout(() => {\n        this.goTo(this.activeIndex + 1);\n      }, this.nzAutoPlaySpeed);\n    }\n  }\n\n  private clearScheduledTransition(): void {\n    if (this.transitionInProgress) {\n      clearTimeout(this.transitionInProgress);\n      this.transitionInProgress = undefined;\n    }\n  }\n\n  private markContentActive(index: number): void {\n    this.activeIndex = index;\n    this.carouselContents?.forEach((slide, i) => (slide.isActive = index === i));\n    this.cdr.markForCheck();\n  }\n\n  /**\n   * Drag carousel.\n   */\n  pointerDown = (event: TouchEvent | MouseEvent): void => {\n    if (!this.isDragging && !this.isTransiting && this.nzEnableSwipe) {\n      this.clearScheduledTransition();\n      this.gestureRect = this.slickListEl.getBoundingClientRect();\n\n      this.nzDragService.requestDraggingSequence(event).subscribe({\n        next: delta => {\n          this.pointerDelta = delta;\n          this.isDragging = true;\n          this.strategy?.dragging(this.pointerDelta);\n        },\n        complete: () => {\n          if (this.nzEnableSwipe && this.isDragging) {\n            const xDelta = this.pointerDelta ? this.pointerDelta.x : 0;\n\n            // Switch to another slide if delta is bigger than third of the width.\n            if (\n              Math.abs(xDelta) > this.gestureRect!.width / 3 &&\n              (this.nzLoop ||\n                (xDelta <= 0 && this.activeIndex + 1 < this.carouselContents.length) ||\n                (xDelta > 0 && this.activeIndex > 0))\n            ) {\n              this.goTo(xDelta > 0 ? this.activeIndex - 1 : this.activeIndex + 1);\n            } else {\n              this.goTo(this.activeIndex);\n            }\n\n            this.gestureRect = null;\n            this.pointerDelta = null;\n          }\n\n          this.isDragging = false;\n        }\n      });\n    }\n  };\n\n  layout(): void {\n    this.strategy?.withCarouselContents(this.carouselContents);\n  }\n}\n"
  },
  {
    "path": "components/carousel/carousel.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzCarouselContentDirective } from './carousel-content.directive';\nimport { NzCarouselComponent } from './carousel.component';\n\n@NgModule({\n  imports: [NzCarouselComponent, NzCarouselContentDirective],\n  exports: [NzCarouselComponent, NzCarouselContentDirective]\n})\nexport class NzCarouselModule {}\n"
  },
  {
    "path": "components/carousel/carousel.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { ENTER, LEFT_ARROW, RIGHT_ARROW } from '@angular/cdk/keycodes';\nimport { Component, DebugElement, provideZoneChangeDetection, ViewChild } from '@angular/core';\nimport { ComponentFixture, discardPeriodicTasks, fakeAsync, TestBed, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { Subject } from 'rxjs';\n\nimport { NzResizeObserver } from 'ng-zorro-antd/cdk/resize-observer';\nimport { dispatchKeyboardEvent, dispatchMouseEvent } from 'ng-zorro-antd/core/testing';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzCarouselContentDirective } from './carousel-content.directive';\nimport { NzCarouselComponent } from './carousel.component';\nimport { NzCarouselModule } from './carousel.module';\nimport { NzCarouselFlipStrategy } from './strategies/experimental/flip-strategy';\nimport { NzCarouselTransformNoLoopStrategy } from './strategies/experimental/transform-no-loop-strategy';\nimport { NZ_CAROUSEL_CUSTOM_STRATEGIES } from './typings';\n\ndescribe('carousel', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  describe('basic', () => {\n    let fixture: ComponentFixture<NzTestCarouselBasicComponent>;\n    let testComponent: NzTestCarouselBasicComponent;\n    let carouselWrapper: DebugElement;\n    let carouselContents: DebugElement[];\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCarouselBasicComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n      carouselWrapper = fixture.debugElement.query(By.directive(NzCarouselComponent));\n      carouselContents = fixture.debugElement.queryAll(By.directive(NzCarouselContentDirective));\n    });\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n      expect(carouselWrapper.nativeElement.classList).toContain('ant-carousel');\n      expect(carouselContents.every(content => content.nativeElement.classList.contains('slick-slide'))).toBe(true);\n      expect(carouselContents[0].nativeElement.classList).toContain('slick-active');\n    });\n\n    it('should dynamic change content work', fakeAsync(() => {\n      fixture.detectChanges();\n      tick(3000);\n      fixture.detectChanges();\n      expect(carouselContents.length).toBe(4);\n      testComponent.array = [];\n      fixture.detectChanges();\n      tick(3000);\n      fixture.detectChanges();\n      carouselContents = fixture.debugElement.queryAll(By.directive(NzCarouselContentDirective));\n      expect(carouselContents.length).toBe(0);\n    }));\n\n    it('should nzDots work', () => {\n      fixture.detectChanges();\n      expect(testComponent.dots).toBe(true);\n      expect(carouselWrapper.nativeElement.querySelector('.slick-dots').children.length).toBe(4);\n      testComponent.dots = false;\n      fixture.detectChanges();\n      expect(carouselWrapper.nativeElement.querySelector('.slick-dots')).toBeNull();\n    });\n\n    it('should nzDotRender work', () => {\n      fixture.detectChanges();\n      expect(testComponent.dots).toBe(true);\n      expect(carouselWrapper.nativeElement.querySelector('.slick-dots').children.length).toBe(4);\n      expect(carouselWrapper.nativeElement.querySelector('.slick-dots').firstElementChild.innerText).toBe('1');\n      expect(carouselWrapper.nativeElement.querySelector('.slick-dots').lastElementChild.innerText).toBe('4');\n      expect(\n        carouselWrapper.nativeElement.querySelector('.slick-dots').firstElementChild.firstElementChild.tagName\n      ).toBe('A');\n    });\n\n    it('should call layout on component resize', fakeAsync(() => {\n      testComponent.nzCarouselComponent.ngOnInit();\n      const spy = spyOn(testComponent.nzCarouselComponent, 'layout');\n      window.dispatchEvent(new Event('resize'));\n      tick(500);\n\n      (testComponent.nzCarouselComponent['nzResizeObserver'] as NzResizeObserver)\n        .observe(testComponent.nzCarouselComponent.el)\n        .subscribe(() => {\n          expect(spy).toHaveBeenCalled();\n        });\n    }));\n\n    it('should call layout on component resize', fakeAsync(() => {\n      const spyOnResize = spyOn(testComponent.nzCarouselComponent, 'layout');\n      window.dispatchEvent(new Event('resize'));\n      tick(500);\n\n      expect(spyOnResize).toHaveBeenCalled();\n      discardPeriodicTasks();\n    }));\n\n    it('should click content change', () => {\n      expect(carouselContents[0].nativeElement.classList).toContain('slick-active');\n      carouselWrapper.nativeElement.querySelector('.slick-dots').lastElementChild.click();\n      fixture.detectChanges();\n      expect(carouselContents[3].nativeElement.classList).toContain('slick-active');\n    });\n\n    it('should keydown change content work', fakeAsync(() => {\n      fixture.detectChanges();\n      const list = carouselWrapper.nativeElement.querySelector('.slick-list');\n\n      expect(carouselContents[0].nativeElement.classList).toContain('slick-active');\n\n      dispatchKeyboardEvent(list, 'keydown', LEFT_ARROW);\n      tickMilliseconds(fixture, 700);\n      expect(carouselContents[3].nativeElement.classList).toContain('slick-active');\n      dispatchKeyboardEvent(list, 'keydown', LEFT_ARROW);\n      tickMilliseconds(fixture, 700);\n      expect(carouselContents[2].nativeElement.classList).toContain('slick-active');\n      dispatchKeyboardEvent(list, 'keydown', RIGHT_ARROW);\n      tickMilliseconds(fixture, 700);\n      expect(carouselContents[3].nativeElement.classList).toContain('slick-active');\n      dispatchKeyboardEvent(list, 'keydown', RIGHT_ARROW);\n      tickMilliseconds(fixture, 700);\n      expect(carouselContents[0].nativeElement.classList).toContain('slick-active');\n    }));\n\n    it('should nzDotPosition work', () => {\n      testComponent.dotPosition = 'left';\n      fixture.detectChanges();\n      expect(carouselWrapper.nativeElement.firstElementChild!.classList).toContain('slick-vertical');\n    });\n\n    it('should effect change work', fakeAsync(() => {\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n      expect(carouselWrapper.nativeElement.querySelector('.slick-track').style.transform).toBe(\n        'translate3d(0px, 0px, 0px)'\n      );\n      carouselWrapper.nativeElement.querySelector('.slick-dots').lastElementChild.click();\n      tickMilliseconds(fixture, 700);\n      expect(carouselWrapper.nativeElement.querySelector('.slick-track').style.transform).not.toBe('');\n\n      testComponent.effect = 'fade';\n      testComponent.dotPosition = 'left';\n      fixture.detectChanges();\n      expect(carouselContents[0].nativeElement.classList).toContain('slick-active');\n      carouselWrapper.nativeElement.querySelector('.slick-dots').lastElementChild.click();\n      tickMilliseconds(fixture, 700);\n      expect(carouselWrapper.nativeElement.querySelector('.slick-track').style.transform).toBe('');\n\n      testComponent.effect = 'scrollx';\n      fixture.detectChanges();\n      expect(carouselContents[0].nativeElement.classList).toContain('slick-active');\n      carouselWrapper.nativeElement.querySelector('.slick-dots').lastElementChild.click();\n      tickMilliseconds(fixture, 700);\n      expect(carouselWrapper.nativeElement.querySelector('.slick-track').style.transform).not.toBe(\n        'translate3d(0px, 0px, 0px)'\n      );\n    }));\n\n    it('should autoplay work', fakeAsync(() => {\n      testComponent.autoPlay = true;\n      fixture.detectChanges();\n      expect(carouselContents[0].nativeElement.classList).toContain('slick-active');\n      fixture.detectChanges();\n      tick(5000);\n      fixture.detectChanges();\n      expect(carouselContents[1].nativeElement.classList).toContain('slick-active');\n      carouselWrapper.nativeElement.querySelector('.slick-dots').lastElementChild.click();\n      fixture.detectChanges();\n      tick(5000);\n      fixture.detectChanges();\n      testComponent.autoPlay = false;\n      fixture.detectChanges();\n      expect(carouselContents[0].nativeElement.classList).toContain('slick-active');\n    }));\n\n    it('should autoplay speed work', fakeAsync(() => {\n      testComponent.autoPlay = true;\n      testComponent.autoPlaySpeed = 1000;\n      fixture.detectChanges();\n      expect(carouselContents[0].nativeElement.classList).toContain('slick-active');\n      fixture.detectChanges();\n      tick(1000 + 10);\n      fixture.detectChanges();\n      expect(carouselContents[1].nativeElement.classList).toContain('slick-active');\n      testComponent.autoPlaySpeed = 0;\n      fixture.detectChanges();\n      tick(2000 + 10);\n      fixture.detectChanges();\n      expect(carouselContents[1].nativeElement.classList).toContain('slick-active');\n    }));\n\n    it('should func work', fakeAsync(() => {\n      fixture.detectChanges();\n      expect(carouselContents[0].nativeElement.classList).toContain('slick-active');\n      testComponent.nzCarouselComponent.next();\n      tickMilliseconds(fixture, 700);\n      expect(carouselContents[1].nativeElement.classList).toContain('slick-active');\n      testComponent.nzCarouselComponent.pre();\n      tickMilliseconds(fixture, 700);\n      expect(carouselContents[0].nativeElement.classList).toContain('slick-active');\n      testComponent.nzCarouselComponent.goTo(2);\n      tickMilliseconds(fixture, 700);\n      expect(carouselContents[2].nativeElement.classList).toContain('slick-active');\n    }));\n\n    it('should resize content after window resized', fakeAsync(() => {\n      const resizeSpy = spyOn(testComponent.nzCarouselComponent.strategy!, 'withCarouselContents');\n      window.dispatchEvent(new Event('resize'));\n      tick(16);\n      expect(resizeSpy).toHaveBeenCalledTimes(1);\n    }));\n\n    // this test may fail on WSL\n    it('should support swiping to switch', fakeAsync(() => {\n      swipe(testComponent.nzCarouselComponent, 500);\n      tickMilliseconds(fixture, 700);\n      expect(carouselContents[0].nativeElement.classList).not.toContain('slick-active');\n      expect(carouselContents[1].nativeElement.classList).toContain('slick-active');\n\n      swipe(testComponent.nzCarouselComponent, -500);\n      tickMilliseconds(fixture, 700);\n      swipe(testComponent.nzCarouselComponent, -500);\n      tickMilliseconds(fixture, 700);\n      expect(carouselContents[0].nativeElement.classList).not.toContain('slick-active');\n      expect(carouselContents[3].nativeElement.classList).toContain('slick-active');\n    }));\n\n    it('should prevent swipes that are not long enough', fakeAsync(() => {\n      swipe(testComponent.nzCarouselComponent, 57);\n      tickMilliseconds(fixture, 700);\n      expect(carouselContents[0].nativeElement.classList).toContain('slick-active');\n    }));\n\n    it('should disable dragging during transitioning', fakeAsync(() => {\n      tickMilliseconds(fixture, 700);\n      testComponent.nzCarouselComponent.goTo(1);\n      swipe(testComponent.nzCarouselComponent, 500);\n      tickMilliseconds(fixture, 700);\n      expect(carouselContents[1].nativeElement.classList).toContain('slick-active');\n    }));\n\n    it('should disable loop work', fakeAsync(() => {\n      testComponent.loop = false;\n      fixture.detectChanges();\n      swipe(testComponent.nzCarouselComponent, -10);\n      tickMilliseconds(fixture, 700);\n      expect(carouselContents[0].nativeElement.classList).toContain('slick-active');\n      swipe(testComponent.nzCarouselComponent, -1000);\n      tickMilliseconds(fixture, 700);\n      expect(carouselContents[0].nativeElement.classList).toContain('slick-active');\n\n      testComponent.loop = true;\n      fixture.detectChanges();\n      swipe(testComponent.nzCarouselComponent, -1000);\n      tickMilliseconds(fixture, 700);\n      expect(carouselContents[3].nativeElement.classList).toContain('slick-active');\n      swipe(testComponent.nzCarouselComponent, 1000);\n      tickMilliseconds(fixture, 700);\n      expect(carouselContents[0].nativeElement.classList).toContain('slick-active');\n\n      testComponent.loop = false;\n      testComponent.autoPlay = true;\n      testComponent.autoPlaySpeed = 1000;\n      fixture.detectChanges();\n      tick(10000);\n      expect(carouselContents[3].nativeElement.classList).toContain('slick-active');\n      tick(1000 + 10);\n      expect(carouselContents[3].nativeElement.classList).toContain('slick-active');\n    }));\n\n    it('should call goTo function on slick dot click', () => {\n      spyOn(testComponent.nzCarouselComponent, 'goTo');\n      carouselWrapper.nativeElement.querySelector('.slick-dots').lastElementChild.click();\n      expect(testComponent.nzCarouselComponent.goTo).toHaveBeenCalledWith(3);\n    });\n  });\n\n  describe('strategies', () => {\n    let fixture: ComponentFixture<NzTestCarouselBasicComponent>;\n    let testComponent: NzTestCarouselBasicComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCarouselBasicComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n    });\n\n    describe('transform strategy', () => {\n      it('horizontal transform', fakeAsync(() => {\n        expect(testComponent.nzCarouselComponent.slickTrackEl.style.transform).toBe(`translate3d(0px, 0px, 0px)`);\n\n        testComponent.nzCarouselComponent.next();\n        tickMilliseconds(fixture, 700);\n        expect(testComponent.nzCarouselComponent.slickTrackEl.style.transform).not.toBe(`translate3d(0px, 0px, 0px)`);\n\n        testComponent.nzCarouselComponent.pre();\n        tickMilliseconds(fixture, 700);\n        expect(testComponent.nzCarouselComponent.slickTrackEl.style.transform).toBe(`translate3d(0px, 0px, 0px)`);\n\n        // From first to last.\n        testComponent.nzCarouselComponent.pre();\n        tickMilliseconds(fixture, 700);\n        expect(testComponent.nzCarouselComponent.slickTrackEl.style.transform).not.toBe(`translate3d(0px, 0px, 0px)`);\n\n        // From last to first.\n        testComponent.nzCarouselComponent.next();\n        tickMilliseconds(fixture, 700);\n        expect(testComponent.nzCarouselComponent.slickTrackEl.style.transform).toBe(`translate3d(0px, 0px, 0px)`);\n      }));\n\n      it('vertical', fakeAsync(() => {\n        testComponent.dotPosition = 'left';\n        fixture.detectChanges();\n\n        expect(testComponent.nzCarouselComponent.slickTrackEl.style.transform).toBe(`translate3d(0px, 0px, 0px)`);\n\n        testComponent.nzCarouselComponent.next();\n        tickMilliseconds(fixture, 700);\n        expect(testComponent.nzCarouselComponent.el.style.transform).not.toBe(`translate3d(0px, 0px, 0px)`);\n\n        testComponent.nzCarouselComponent.pre();\n        tickMilliseconds(fixture, 700);\n        expect(testComponent.nzCarouselComponent.slickTrackEl.style.transform).toBe(`translate3d(0px, 0px, 0px)`);\n\n        // From first to last.\n        testComponent.nzCarouselComponent.pre();\n        tickMilliseconds(fixture, 700);\n        expect(testComponent.nzCarouselComponent.slickTrackEl.style.transform).not.toBe(`translate3d(0px, 0px, 0px)`);\n\n        // From last to first.\n        testComponent.nzCarouselComponent.next();\n        tickMilliseconds(fixture, 700);\n        expect(testComponent.nzCarouselComponent.slickTrackEl.style.transform).toBe(`translate3d(0px, 0px, 0px)`);\n      }));\n    });\n  });\n\n  describe('carousel nzAfterChange return value', () => {\n    let fixture: ComponentFixture<NzTestCarouselActiveIndexComponent>;\n    let testComponent: NzTestCarouselActiveIndexComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCarouselActiveIndexComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n    });\n\n    it('carousel activeIndex should be equal to nzAfterChange return value', fakeAsync(() => {\n      fixture.detectChanges();\n      [0, 1, 2, 3, 4].forEach(_ => {\n        testComponent.nzCarouselComponent.next();\n        tickMilliseconds(fixture, 700);\n        expect(testComponent.index).toBe(testComponent.nzCarouselComponent.activeIndex);\n      });\n    }));\n  });\n});\n\ndescribe('carousel custom strategies', () => {\n  let fixture: ComponentFixture<NzTestCarouselBasicComponent>;\n  let testComponent: NzTestCarouselBasicComponent;\n  let carouselWrapper: DebugElement;\n  let carouselContents: DebugElement[];\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [\n        // todo: use zoneless\n        provideZoneChangeDetection(),\n        {\n          provide: NZ_CAROUSEL_CUSTOM_STRATEGIES,\n          useValue: [\n            {\n              name: 'flip',\n              strategy: NzCarouselFlipStrategy\n            },\n            {\n              name: 'transform-no-loop',\n              strategy: NzCarouselTransformNoLoopStrategy\n            }\n          ]\n        }\n      ]\n    });\n  });\n\n  it('could use custom strategies', fakeAsync(() => {\n    fixture = TestBed.createComponent(NzTestCarouselBasicComponent);\n    fixture.detectChanges();\n    testComponent = fixture.debugElement.componentInstance;\n    carouselWrapper = fixture.debugElement.query(By.directive(NzCarouselComponent));\n    carouselContents = fixture.debugElement.queryAll(By.directive(NzCarouselContentDirective));\n\n    testComponent.effect = 'flip';\n    fixture.detectChanges();\n    expect(carouselContents[0].nativeElement.style.transform).toBe('rotateY(0deg)');\n    expect(carouselContents[1].nativeElement.style.transform).toBe('rotateY(180deg)');\n    carouselWrapper.nativeElement.querySelector('.slick-dots').lastElementChild.click();\n    tickMilliseconds(fixture, 700);\n    expect(carouselContents[0].nativeElement.style.transform).toBe('rotateY(180deg)');\n    expect(carouselContents[3].nativeElement.style.transform).toBe('rotateY(0deg)');\n\n    testComponent.effect = 'transform-no-loop';\n    fixture.detectChanges();\n    expect(carouselWrapper.nativeElement.querySelector('.slick-track').style.transform).toBe(\n      'translate3d(0px, 0px, 0px)'\n    );\n    carouselWrapper.nativeElement.querySelector('.slick-dots').lastElementChild.click();\n    tickMilliseconds(fixture, 700);\n    expect(carouselWrapper.nativeElement.querySelector('.slick-track').style.transform).not.toBe(\n      'translate3d(0px, 0px, 0px)'\n    );\n\n    testComponent.dotPosition = 'left';\n    fixture.detectChanges();\n    carouselWrapper.nativeElement.querySelector('.slick-dots').lastElementChild.click();\n    tickMilliseconds(fixture, 700);\n    expect(carouselWrapper.nativeElement.querySelector('.slick-track').style.transform).not.toBe(\n      'translate3d(0px, 0px, 0px)'\n    );\n  }));\n});\n\ndescribe('carousel arrows', () => {\n  let fixture: ComponentFixture<NzTestCarouselArrowsComponent>;\n  let testComponent: NzTestCarouselArrowsComponent;\n  let carouselWrapper: DebugElement;\n  let carouselContents: DebugElement[];\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzTestCarouselArrowsComponent);\n    fixture.detectChanges();\n    testComponent = fixture.debugElement.componentInstance;\n    carouselWrapper = fixture.debugElement.query(By.directive(NzCarouselComponent));\n    carouselContents = fixture.debugElement.queryAll(By.directive(NzCarouselContentDirective));\n  });\n\n  it('should render arrows when nzArrows is true', () => {\n    const prev = carouselWrapper.nativeElement.querySelector('.slick-prev');\n    const next = carouselWrapper.nativeElement.querySelector('.slick-next');\n    expect(prev).not.toBeNull();\n    expect(next).not.toBeNull();\n  });\n\n  it('should navigate via arrows', fakeAsync(() => {\n    expect(carouselContents[0].nativeElement.classList).toContain('slick-active');\n    carouselWrapper.nativeElement.querySelector('.slick-next').click();\n    tickMilliseconds(fixture, 700);\n    expect(carouselContents[1].nativeElement.classList).toContain('slick-active');\n    carouselWrapper.nativeElement.querySelector('.slick-prev').click();\n    tickMilliseconds(fixture, 700);\n    expect(carouselContents[0].nativeElement.classList).toContain('slick-active');\n  }));\n\n  it('should disable arrows at edges when loop is false', fakeAsync(() => {\n    testComponent.loop = false;\n    fixture.detectChanges();\n    const prev = carouselWrapper.nativeElement.querySelector('.slick-prev');\n    const next = carouselWrapper.nativeElement.querySelector('.slick-next');\n    expect(prev.classList).toContain('slick-disabled');\n    expect(next.classList).not.toContain('slick-disabled');\n\n    // Go to last slide\n    for (let i = 0; i < 3; i++) {\n      next.click();\n      tickMilliseconds(fixture, 700);\n    }\n    expect(carouselContents[3].nativeElement.classList).toContain('slick-active');\n    expect(next.classList).toContain('slick-disabled');\n\n    // Clicking next should not move beyond last\n    next.click();\n    tickMilliseconds(fixture, 700);\n    expect(carouselContents[3].nativeElement.classList).toContain('slick-active');\n  }));\n});\n\ndescribe('carousel no swipe', () => {\n  let fixture: ComponentFixture<NzTestCarouselNoSwipeComponent>;\n  let testComponent: NzTestCarouselNoSwipeComponent;\n  let carouselContents: DebugElement[];\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzTestCarouselNoSwipeComponent);\n    fixture.detectChanges();\n    testComponent = fixture.debugElement.componentInstance;\n    carouselContents = fixture.debugElement.queryAll(By.directive(NzCarouselContentDirective));\n  });\n\n  it('should not change slide on swipe when nzEnableSwipe is false', fakeAsync(() => {\n    expect(carouselContents[0].nativeElement.classList).toContain('slick-active');\n    swipe(testComponent.nzCarouselComponent, 500);\n    tickMilliseconds(fixture, 700);\n    expect(carouselContents[0].nativeElement.classList).toContain('slick-active');\n  }));\n});\n\nfunction tickMilliseconds<T>(fixture: ComponentFixture<T>, seconds: number = 1): void {\n  fixture.detectChanges();\n  tick(seconds);\n  fixture.detectChanges();\n}\n\n/*\n * Swipe a carousel.\n *\n * @param carousel: Carousel component.\n * @param Distance: Positive to right. Negative to left.\n */\nfunction swipe(carousel: NzCarouselComponent, distance: number): void {\n  carousel.pointerDown(\n    new MouseEvent('mousedown', {\n      clientX: 500,\n      clientY: 0\n    })\n  );\n\n  dispatchMouseEvent(document, 'mousemove', 500 - distance, 0);\n  dispatchMouseEvent(document, 'mouseup');\n}\n\n@Component({\n  selector: 'nz-test-carousel',\n  imports: [NzCarouselModule],\n  template: `\n    <nz-carousel\n      [nzEffect]=\"effect\"\n      [nzDots]=\"dots\"\n      [nzDotPosition]=\"dotPosition\"\n      [nzDotRender]=\"dotRender\"\n      [nzAutoPlay]=\"autoPlay\"\n      [nzAutoPlaySpeed]=\"autoPlaySpeed\"\n      [nzLoop]=\"loop\"\n      (nzAfterChange)=\"afterChange($event)\"\n      (nzBeforeChange)=\"beforeChange($event)\"\n    >\n      @for (index of array; track index) {\n        <div nz-carousel-content>\n          <h3>{{ index }}</h3>\n        </div>\n      }\n      <ng-template #dotRender let-index>\n        <a>{{ index + 1 }}</a>\n      </ng-template>\n    </nz-carousel>\n  `\n})\nexport class NzTestCarouselBasicComponent {\n  @ViewChild(NzCarouselComponent, { static: false }) nzCarouselComponent!: NzCarouselComponent;\n  dots = true;\n  dotPosition = 'bottom';\n  effect = 'scrollx';\n  array = [1, 2, 3, 4];\n  autoPlay = false;\n  autoPlaySpeed = 3000;\n  loop = true;\n  afterChange = jasmine.createSpy('afterChange callback');\n  beforeChange = jasmine.createSpy('beforeChange callback');\n}\n\n@Component({\n  imports: [NzCarouselModule],\n  template: `\n    <nz-carousel (nzAfterChange)=\"afterChange($event)\">\n      @for (index of array; track index) {\n        <div nz-carousel-content>\n          <h3>{{ index }}</h3>\n        </div>\n      }\n    </nz-carousel>\n  `\n})\nexport class NzTestCarouselActiveIndexComponent {\n  @ViewChild(NzCarouselComponent, { static: true }) nzCarouselComponent!: NzCarouselComponent;\n  array = [0, 1, 2, 3, 4];\n  index = 0;\n\n  afterChange(index: number): void {\n    this.index = index;\n  }\n}\n\n@Component({\n  selector: 'nz-test-carousel-arrows',\n  imports: [NzCarouselModule],\n  template: `\n    <nz-carousel [nzArrows]=\"true\" [nzLoop]=\"loop\">\n      @for (index of array; track index) {\n        <div nz-carousel-content>\n          <h3>{{ index }}</h3>\n        </div>\n      }\n    </nz-carousel>\n  `\n})\nexport class NzTestCarouselArrowsComponent {\n  @ViewChild(NzCarouselComponent, { static: true }) nzCarouselComponent!: NzCarouselComponent;\n  array = [1, 2, 3, 4];\n  loop = true;\n}\n\n@Component({\n  selector: 'nz-test-carousel-no-swipe',\n  imports: [NzCarouselModule],\n  template: `\n    <nz-carousel [nzEnableSwipe]=\"false\">\n      @for (index of array; track index) {\n        <div nz-carousel-content>\n          <h3>{{ index }}</h3>\n        </div>\n      }\n    </nz-carousel>\n  `\n})\nexport class NzTestCarouselNoSwipeComponent {\n  @ViewChild(NzCarouselComponent, { static: true }) nzCarouselComponent!: NzCarouselComponent;\n  array = [1, 2, 3, 4];\n}\n\nclass MockDirectionality {\n  value = 'ltr';\n  change = new Subject();\n}\n\ndescribe('carousel', () => {\n  let fixture: ComponentFixture<NzCarouselComponent>;\n  let component: NzCarouselComponent;\n  let mockDirectionality: MockDirectionality;\n  let mockObserve$: Subject<void>;\n\n  beforeEach(() => {\n    mockObserve$ = new Subject();\n    const nzResizeObserverSpy = jasmine.createSpyObj('NzResizeObserver', {\n      observe: mockObserve$.asObservable()\n    });\n\n    TestBed.configureTestingModule({\n      providers: [\n        // todo: use zoneless\n        provideZoneChangeDetection(),\n        {\n          provide: Directionality,\n          useClass: MockDirectionality\n        },\n        {\n          provide: NzResizeObserver,\n          useValue: nzResizeObserverSpy\n        }\n      ]\n    });\n\n    fixture = TestBed.createComponent(NzCarouselComponent);\n    component = fixture.componentInstance;\n    mockDirectionality = TestBed.inject(Directionality) as unknown as MockDirectionality;\n  });\n\n  it('directionality change detection', fakeAsync(() => {\n    spyOn<NzSafeAny>(component, 'markContentActive');\n    spyOn<NzSafeAny>(component['cdr'], 'detectChanges');\n    mockDirectionality.value = 'ltr';\n    component.ngOnInit();\n    expect(component.dir).toEqual('ltr');\n\n    mockDirectionality.change.next('rtl');\n    tick();\n    expect(component.dir).toEqual('rtl');\n    expect(component['markContentActive']).toHaveBeenCalled();\n    expect(component['cdr'].detectChanges).toHaveBeenCalled();\n  }));\n\n  it('should not execute if keyCode is not of type LEFT_ARROW  or RIGHT_ARROW', fakeAsync(() => {\n    component.ngOnInit();\n    tick(1);\n    let event: KeyboardEvent;\n\n    event = new KeyboardEvent('keydown', { keyCode: LEFT_ARROW });\n    spyOn(event, 'preventDefault');\n    component.slickListEl.dispatchEvent(event);\n    expect(event.preventDefault).toHaveBeenCalled();\n\n    event = new KeyboardEvent('keydown', { keyCode: RIGHT_ARROW });\n    spyOn(event, 'preventDefault');\n    component.slickListEl.dispatchEvent(event);\n    expect(event.preventDefault).toHaveBeenCalled();\n\n    event = new KeyboardEvent('keydown', { keyCode: ENTER });\n    spyOn(event, 'preventDefault');\n    component.slickListEl.dispatchEvent(event);\n    expect(event.preventDefault).not.toHaveBeenCalled();\n  }));\n\n  it('should call layout method when resizing', fakeAsync(() => {\n    spyOn(component, 'layout');\n    component.ngOnInit();\n    tick(1);\n    mockObserve$.next();\n    tick(101);\n    expect(component.layout).toHaveBeenCalled();\n  }));\n});\n"
  },
  {
    "path": "components/carousel/demo/arrow.md",
    "content": "---\norder: 6\nversion: 20.3.0\ntitle:\n  zh-CN: 切换箭头\n  en-US: Arrows for switching\n---\n\n## zh-CN\n\n显示切换箭头。\n\n## en-US\n\nShow the arrows for switching.\n"
  },
  {
    "path": "components/carousel/demo/arrow.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCarouselModule } from 'ng-zorro-antd/carousel';\n\n@Component({\n  selector: 'nz-demo-carousel-arrow',\n  imports: [NzCarouselModule],\n  template: ` <nz-carousel [nzEffect]=\"effect\" nzArrows>\n    @for (index of array; track index) {\n      <div nz-carousel-content>\n        <h3>{{ index }}</h3>\n      </div>\n    }\n  </nz-carousel>`,\n  styles: `\n    [nz-carousel-content] {\n      text-align: center;\n      height: 160px;\n      line-height: 160px;\n      background: #364d79;\n      color: #fff;\n      overflow: hidden;\n    }\n\n    h3 {\n      color: #fff;\n      margin-bottom: 0;\n      user-select: none;\n    }\n  `\n})\nexport class NzDemoCarouselArrowComponent {\n  array = [1, 2, 3, 4];\n  effect = 'scrollx';\n}\n"
  },
  {
    "path": "components/carousel/demo/autoplay.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 自动切换\n  en-US: Scroll automatically\n---\n\n## zh-CN\n\n定时切换下一张。\n\n## en-US\n\nTiming of scrolling to the next card/picture.\n"
  },
  {
    "path": "components/carousel/demo/autoplay.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCarouselModule } from 'ng-zorro-antd/carousel';\n\n@Component({\n  selector: 'nz-demo-carousel-autoplay',\n  imports: [NzCarouselModule],\n  template: `\n    <nz-carousel nzAutoPlay>\n      @for (index of array; track index) {\n        <div nz-carousel-content>\n          <h3>{{ index }}</h3>\n        </div>\n      }\n    </nz-carousel>\n  `,\n  styles: `\n    [nz-carousel-content] {\n      text-align: center;\n      height: 160px;\n      line-height: 160px;\n      background: #364d79;\n      color: #fff;\n      overflow: hidden;\n    }\n\n    h3 {\n      color: #fff;\n      margin-bottom: 0;\n      user-select: none;\n    }\n  `\n})\nexport class NzDemoCarouselAutoplayComponent {\n  array = [1, 2, 3, 4];\n}\n"
  },
  {
    "path": "components/carousel/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n最简单的用法。\n\n## en-US\n\nBasic usage.\n"
  },
  {
    "path": "components/carousel/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCarouselModule } from 'ng-zorro-antd/carousel';\n\n@Component({\n  selector: 'nz-demo-carousel-basic',\n  imports: [NzCarouselModule],\n  template: `\n    <nz-carousel [nzEffect]=\"effect\">\n      @for (index of array; track index) {\n        <div nz-carousel-content>\n          <h3>{{ index }}</h3>\n        </div>\n      }\n    </nz-carousel>\n  `,\n  styles: `\n    [nz-carousel-content] {\n      text-align: center;\n      height: 160px;\n      line-height: 160px;\n      background: #364d79;\n      color: #fff;\n      overflow: hidden;\n    }\n\n    h3 {\n      color: #fff;\n      margin-bottom: 0;\n      user-select: none;\n    }\n  `\n})\nexport class NzDemoCarouselBasicComponent {\n  array = [1, 2, 3, 4];\n  effect = 'scrollx';\n}\n"
  },
  {
    "path": "components/carousel/demo/custom.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 自定义切换效果\n  en-US: Custom transition effect\n---\n\n## zh-CN\n\n通过继承 `NzCarouselBaseStrategy` 自定义轮播图切换动画。\n\n## en-US\n\nCustomize carousel transition effect by providing a class that extends `NzCarouselBaseStrategy`.\n"
  },
  {
    "path": "components/carousel/demo/custom.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport {\n  NZ_CAROUSEL_CUSTOM_STRATEGIES,\n  NzCarouselFlipStrategy,\n  NzCarouselModule,\n  NzCarouselTransformNoLoopStrategy\n} from 'ng-zorro-antd/carousel';\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\n\n@Component({\n  selector: 'nz-demo-carousel-custom',\n  imports: [FormsModule, NzCarouselModule, NzRadioModule],\n  template: `\n    <nz-radio-group [(ngModel)]=\"strategy\">\n      <label nz-radio-button nzValue=\"transform-no-loop\">Transform No Loop</label>\n      <label nz-radio-button nzValue=\"flip\">Flip</label>\n      <label nz-radio-button nzValue=\"fade\">Fade (built-in)</label>\n    </nz-radio-group>\n    <nz-carousel [nzEffect]=\"strategy\">\n      @for (index of array; track index) {\n        <div nz-carousel-content>\n          <h3>{{ index }}</h3>\n        </div>\n      }\n    </nz-carousel>\n  `,\n  styles: `\n    nz-radio-group {\n      margin-bottom: 8px;\n    }\n\n    [nz-carousel-content] {\n      text-align: center;\n      height: 160px;\n      line-height: 160px;\n      background: #364d79;\n      color: #fff;\n      overflow: hidden;\n    }\n\n    h3 {\n      color: #fff;\n      margin-bottom: 0;\n      user-select: none;\n    }\n  `,\n  providers: [\n    {\n      provide: NZ_CAROUSEL_CUSTOM_STRATEGIES,\n      useValue: [\n        { name: 'transform-no-loop', strategy: NzCarouselTransformNoLoopStrategy },\n        { name: 'flip', strategy: NzCarouselFlipStrategy }\n      ]\n    }\n  ]\n})\nexport class NzDemoCarouselCustomComponent {\n  strategy = 'transform-no-loop';\n  array = [1, 2, 3, 4];\n}\n"
  },
  {
    "path": "components/carousel/demo/fade.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 渐显\n  en-US: Fade in\n---\n\n## zh-CN\n\n切换效果为渐显。\n\n## en-US\n\nSlides use fade for transition.\n"
  },
  {
    "path": "components/carousel/demo/fade.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCarouselModule } from 'ng-zorro-antd/carousel';\n\n@Component({\n  selector: 'nz-demo-carousel-fade',\n  imports: [NzCarouselModule],\n  template: `\n    <nz-carousel nzEffect=\"fade\">\n      @for (index of array; track index) {\n        <div nz-carousel-content>\n          <h3>{{ index }}</h3>\n        </div>\n      }\n    </nz-carousel>\n  `,\n  styles: `\n    [nz-carousel-content] {\n      text-align: center;\n      height: 160px;\n      line-height: 160px;\n      background: #364d79;\n      color: #fff;\n      overflow: hidden;\n    }\n\n    h3 {\n      color: #fff;\n      margin-bottom: 0;\n      user-select: none;\n    }\n  `\n})\nexport class NzDemoCarouselFadeComponent {\n  array = [1, 2, 3, 4];\n}\n"
  },
  {
    "path": "components/carousel/demo/loop.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 循环\n  en-US: Loop\n---\n\n## zh-CN\n\n防止轮播进入循环\n\n## en-US\n\nPrevent the carousel to go in a loop\n"
  },
  {
    "path": "components/carousel/demo/loop.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCarouselModule } from 'ng-zorro-antd/carousel';\n\n@Component({\n  selector: 'nz-demo-carousel-loop',\n  imports: [NzCarouselModule],\n  template: `\n    <nz-carousel nzAutoPlay [nzEffect]=\"effect\" [nzLoop]=\"false\">\n      @for (index of array; track index) {\n        <div nz-carousel-content>\n          <h3>{{ index }}</h3>\n        </div>\n      }\n    </nz-carousel>\n  `,\n  styles: `\n    [nz-carousel-content] {\n      text-align: center;\n      height: 160px;\n      line-height: 160px;\n      background: #364d79;\n      color: #fff;\n      overflow: hidden;\n    }\n\n    h3 {\n      color: #fff;\n      margin-bottom: 0;\n      user-select: none;\n    }\n  `\n})\nexport class NzDemoCarouselLoopComponent {\n  array = [1, 2, 3, 4];\n  effect = 'scrollx';\n}\n"
  },
  {
    "path": "components/carousel/demo/position.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 位置\n  en-US: Position\n---\n\n## zh-CN\n\n位置有 4 个方向。\n\n## en-US\n\nThere are four positions available.\n"
  },
  {
    "path": "components/carousel/demo/position.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCarouselModule } from 'ng-zorro-antd/carousel';\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\n\n@Component({\n  selector: 'nz-demo-carousel-position',\n  imports: [FormsModule, NzCarouselModule, NzRadioModule],\n  template: `\n    <nz-radio-group [(ngModel)]=\"dotPosition\">\n      <label nz-radio-button nzValue=\"bottom\">Bottom</label>\n      <label nz-radio-button nzValue=\"top\">Top</label>\n      <label nz-radio-button nzValue=\"left\">Left</label>\n      <label nz-radio-button nzValue=\"right\">Right</label>\n    </nz-radio-group>\n    <nz-carousel [nzDotPosition]=\"dotPosition\">\n      @for (index of array; track index) {\n        <div nz-carousel-content>\n          <h3>{{ index }}</h3>\n        </div>\n      }\n    </nz-carousel>\n  `,\n  styles: `\n    nz-radio-group {\n      margin-bottom: 8px;\n    }\n\n    [nz-carousel-content] {\n      text-align: center;\n      height: 160px;\n      line-height: 160px;\n      background: #364d79;\n      color: #fff;\n      overflow: hidden;\n    }\n\n    h3 {\n      color: #fff;\n      margin-bottom: 0;\n      user-select: none;\n    }\n  `\n})\nexport class NzDemoCarouselPositionComponent {\n  array = [1, 2, 3, 4];\n  dotPosition = 'bottom';\n}\n"
  },
  {
    "path": "components/carousel/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Display\ntitle: Carousel\ncover: 'https://gw.alipayobjects.com/zos/antfincdn/%24C9tmj978R/Carousel.svg'\ndescription: A carousel component. Scales with its container.\n---\n\n## When To Use\n\n- When there is a group of content on the same level.\n- When there is insufficient content space, it can be used to save space in the form of a revolving door.\n- Commonly used for a group of pictures/cards.\n\n## API\n\n### nz-carousel\n\n| Property            | Description                                                                 | Type                                        | Default     | Global Config | Version |\n| ------------------- | --------------------------------------------------------------------------- | ------------------------------------------- | ----------- | ------------- | ------- |\n| `[nzAutoPlay]`      | Whether to scroll automatically                                             | `boolean`                                   | `false`     | ✅            |\n| `[nzAutoPlaySpeed]` | Duration (milliseconds), does not scroll when set to 0                      | `number`                                    | `3000`      | ✅            |\n| `[nzDotRender]`     | Dot render template                                                         | `TemplateRef<{ $implicit: number }>`        | -           |\n| `[nzDotPosition]`   | The position of the dots, which can be one of `top` `bottom` `left` `right` | `'top' \\| 'right' \\| 'bottom' \\| 'left'`    | `'bottom'`  | ✅            |\n| `[nzDots]`          | Whether to show the dots at the bottom of the gallery                       | `boolean`                                   | `true`      | ✅            |\n| `[nzEffect]`        | Transition effect                                                           | `'scrollx' \\| 'fade'`                       | `'scrollx'` | ✅            |\n| `[nzEnableSwipe]`   | Whether to support swipe gesture                                            | `boolean`                                   | `true`      | ✅            |\n| `[nzLoop]`          | Whether to enable the carousel to go in a loop                              | `boolean`                                   | `true`      | ✅            |\n| `[nzArrows]`        | Whether to show the arrow buttons                                           | `boolean`                                   | `false`     | -             | 20.3.0  |\n| `(nzAfterChange)`   | Callback function called after the current index changes                    | `EventEmitter<number>`                      | -           |\n| `(nzBeforeChange)`  | Callback function called before the current index changes                   | `EventEmitter{ from: number; to: number }>` | -           |\n\n#### Methods\n\n| Name                | Description                                |\n| ------------------- | ------------------------------------------ |\n| `goTo(slideNumber)` | Change current slide to given slide number |\n| `next()`            | Change current slide to next slide         |\n| `pre()`             | Change current slide to previous slide     |\n\n### InjectionToken\n\n| Token                           | Description                             | Parameters                       | Default Value |\n| ------------------------------- | --------------------------------------- | -------------------------------- | ------------- |\n| `NZ_CAROUSEL_CUSTOM_STRATEGIES` | Provide custom transitioning strategies | `CarouselStrategyRegistryItem[]` | -             |\n\n### Customizing transition effects\n\nYou can provide strategies that extends `NzCarouselBaseStrategy` to implement custom transition effects.\n"
  },
  {
    "path": "components/carousel/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ntype: 数据展示\ntitle: Carousel\nsubtitle: 走马灯\ncover: 'https://gw.alipayobjects.com/zos/antfincdn/%24C9tmj978R/Carousel.svg'\ndescription: 一组轮播的区域。\n---\n\n## 何时使用\n\n- 当有一组平级的内容。\n- 当内容空间不足时，可以用走马灯的形式进行收纳，进行轮播展现。\n- 常用于一组图片或卡片轮播。\n\n## API\n\n### nz-carousel\n\n| 参数                | 说明                                               | 类型                                         | 默认值      | 支持全局配置 | 版本   |\n| ------------------- | -------------------------------------------------- | -------------------------------------------- | ----------- | ------------ | ------ |\n| `[nzAutoPlay]`      | 是否自动切换                                       | `boolean`                                    | `false`     | ✅           |\n| `[nzAutoPlaySpeed]` | 切换时间(毫秒)，当设置为 0 时不切换                | `number`                                     | `3000`      | ✅           |\n| `[nzDotRender]`     | Dot 渲染模板                                       | `TemplateRef<{ $implicit: number }>`         | -           |\n| `[nzDotPosition]`   | 面板指示点位置，可选 `top` `bottom` `left` `right` | `'top' \\| 'right' \\| 'bottom' \\| 'left'`     | `'bottom'`  | ✅           |\n| `[nzDots]`          | 是否显示面板指示点                                 | `boolean`                                    | `true`      | ✅           |\n| `[nzEffect]`        | 动画效果函数，可取 `scrollx`, `fade`               | `'scrollx' \\| 'fade'`                        | `'scrollx'` | ✅           |\n| `[nzEnableSwipe]`   | 是否支持手势划动切换                               | `boolean`                                    | `true`      | ✅           |\n| `[nzLoop]`          | 是否支持循环                                       | `boolean`                                    | `true`      | ✅           |\n| `[nzArrows]`        | 是否显示箭头按钮                                   | `boolean`                                    | `false`     | -            | 20.3.0 |\n| `(nzAfterChange)`   | 切换面板的回调                                     | `EventEmitter<number>`                       | -           |\n| `(nzBeforeChange)`  | 切换面板的回调                                     | `EventEmitter<{ from: number; to: number }>` | -           |\n\n#### 方法\n\n| 名称                | 描述           |\n| ------------------- | -------------- |\n| `goTo(slideNumber)` | 切换到指定面板 |\n| `next()`            | 切换到下一面板 |\n| `pre()`             | 切换到上一面板 |\n\n### InjectionToken\n\n| Token                           | 说明                     | 参数                             | 默认值 |\n| ------------------------------- | ------------------------ | -------------------------------- | ------ |\n| `NZ_CAROUSEL_CUSTOM_STRATEGIES` | 提供用户自定义的切换效果 | `CarouselStrategyRegistryItem[]` | -      |\n\n### 自定义切换效果\n\n你可以提供自定义的切换效果，切换效果应当继承 `NzCarouselBaseStrategy` 类（默认的两种切换效果同样基于该类）。\n"
  },
  {
    "path": "components/carousel/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/carousel/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/carousel/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './carousel.module';\nexport * from './carousel.component';\nexport * from './carousel-content.directive';\nexport * from './typings';\n\nexport * from './strategies/base-strategy';\nexport { NzCarouselOpacityStrategy } from './strategies/opacity-strategy';\nexport { NzCarouselTransformStrategy } from './strategies/transform-strategy';\nexport { NzCarouselTransformNoLoopStrategy } from './strategies/experimental/transform-no-loop-strategy';\nexport { NzCarouselFlipStrategy } from './strategies/experimental/flip-strategy';\n"
  },
  {
    "path": "components/carousel/strategies/base-strategy.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Platform } from '@angular/cdk/platform';\nimport { ChangeDetectorRef, QueryList, Renderer2 } from '@angular/core';\nimport { Observable } from 'rxjs';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzCarouselContentDirective } from '../carousel-content.directive';\nimport { FromToInterface, NzCarouselComponentAsSource, PointerVector } from '../typings';\n\nexport abstract class NzCarouselBaseStrategy<T = NzSafeAny> {\n  // Properties that strategies may want to use.\n  protected carouselComponent: NzCarouselComponentAsSource | null;\n  protected contents!: NzCarouselContentDirective[];\n  protected slickListEl!: HTMLElement;\n  protected slickTrackEl!: HTMLElement;\n  protected length!: number;\n  protected unitWidth!: number;\n  protected unitHeight!: number;\n\n  protected get maxIndex(): number {\n    return this.length - 1;\n  }\n\n  protected get firstEl(): HTMLElement {\n    return this.contents[0].el;\n  }\n\n  protected get lastEl(): HTMLElement {\n    return this.contents[this.maxIndex].el;\n  }\n\n  constructor(\n    carouselComponent: NzCarouselComponentAsSource,\n    protected cdr: ChangeDetectorRef,\n    protected renderer: Renderer2,\n    protected platform: Platform,\n    protected options?: T\n  ) {\n    this.carouselComponent = carouselComponent;\n  }\n\n  /**\n   * Initialize dragging sequences.\n   *\n   * @param contents\n   */\n  withCarouselContents(contents: QueryList<NzCarouselContentDirective> | null): void {\n    const carousel = this.carouselComponent!;\n    this.slickListEl = carousel.slickListEl;\n    this.slickTrackEl = carousel.slickTrackEl;\n    this.contents = contents?.toArray() || [];\n    this.length = this.contents.length;\n\n    if (this.platform.isBrowser) {\n      const rect = carousel.el.getBoundingClientRect();\n      this.unitWidth = rect.width;\n      this.unitHeight = rect.height;\n    } else {\n      // Since we cannot call getBoundingClientRect in server, we just hide all items except for the first one.\n      contents?.forEach((content, index) => {\n        if (index === 0) {\n          this.renderer.setStyle(content.el, 'width', '100%');\n        } else {\n          this.renderer.setStyle(content.el, 'display', 'none');\n        }\n      });\n    }\n  }\n\n  /**\n   * Trigger transition.\n   */\n  abstract switch(_f: number, _t: number): Observable<void>;\n\n  /**\n   * When user drag the carousel component.\n   *\n   * @optional\n   */\n  dragging(_vector: PointerVector): void {}\n\n  /**\n   * Destroy a scroll strategy.\n   */\n  dispose(): void {}\n\n  protected getFromToInBoundary(f: number, t: number): FromToInterface {\n    const length = this.maxIndex + 1;\n    return { from: (f + length) % length, to: (t + length) % length };\n  }\n}\n"
  },
  {
    "path": "components/carousel/strategies/experimental/flip-strategy.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { QueryList } from '@angular/core';\nimport { type Observable, Subject } from 'rxjs';\n\nimport { NzCarouselContentDirective } from '../../carousel-content.directive';\nimport { NzCarouselBaseStrategy } from '../base-strategy';\n\nexport class NzCarouselFlipStrategy extends NzCarouselBaseStrategy {\n  override withCarouselContents(contents: QueryList<NzCarouselContentDirective> | null): void {\n    super.withCarouselContents(contents);\n\n    if (this.contents) {\n      this.renderer.setStyle(this.slickListEl, 'width', `${this.unitWidth}px`);\n      this.renderer.setStyle(this.slickTrackEl, 'width', `${this.length * this.unitWidth}px`);\n\n      this.contents.forEach((content: NzCarouselContentDirective, i: number) => {\n        const cur = this.carouselComponent!.activeIndex === i;\n\n        this.renderer.setStyle(content.el, 'transform', cur ? 'rotateY(0deg)' : 'rotateY(180deg)');\n        this.renderer.setStyle(content.el, 'position', 'relative');\n        this.renderer.setStyle(content.el, 'width', `${this.unitWidth}px`);\n        this.renderer.setStyle(content.el, 'left', `${-this.unitWidth * i}px`);\n        this.renderer.setStyle(content.el, 'transform-style', 'preserve-3d');\n        this.renderer.setStyle(content.el, 'backface-visibility', 'hidden');\n      });\n\n      const { carouselComponent } = this;\n      carouselComponent!.ngZone.runOutsideAngular(() => {\n        setTimeout(() => {\n          this.contents.forEach(c => this.renderer.setStyle(c.el, 'transition', ['transform 500ms ease 0s']));\n        }, carouselComponent!.nzTransitionSpeed);\n      });\n    }\n  }\n\n  switch(rawF: number, rawT: number): Observable<void> {\n    const { from, to } = this.getFromToInBoundary(rawF, rawT);\n    const complete$ = new Subject<void>();\n    const speed = this.carouselComponent!.nzTransitionSpeed;\n\n    setTimeout(() => {\n      complete$.next();\n      complete$.complete();\n    }, speed);\n\n    if (rawF === rawT) {\n      return complete$;\n    }\n\n    this.contents.forEach((content: NzCarouselContentDirective, i: number) => {\n      if (i === from) {\n        this.renderer.setStyle(content.el, 'transform', 'rotateY(180deg)');\n      } else if (i === to) {\n        this.renderer.setStyle(content.el, 'transform', 'rotateY(0deg)');\n      }\n    });\n\n    return complete$.asObservable();\n  }\n\n  override dispose(): void {\n    this.contents.forEach((content: NzCarouselContentDirective) => {\n      this.renderer.setStyle(content.el, 'transition', null);\n      this.renderer.setStyle(content.el, 'transform', null);\n      this.renderer.setStyle(content.el, 'width', null);\n      this.renderer.setStyle(content.el, 'left', null);\n      this.renderer.setStyle(content.el, 'transform-style', null);\n      this.renderer.setStyle(content.el, 'backface-visibility', null);\n    });\n\n    super.dispose();\n  }\n}\n"
  },
  {
    "path": "components/carousel/strategies/experimental/transform-no-loop-strategy.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Platform } from '@angular/cdk/platform';\nimport { ChangeDetectorRef, QueryList, Renderer2 } from '@angular/core';\nimport { Observable, Subject } from 'rxjs';\n\nimport { NzCarouselContentDirective } from '../../carousel-content.directive';\nimport { NzCarouselComponentAsSource, PointerVector } from '../../typings';\nimport { NzCarouselBaseStrategy } from '../base-strategy';\n\ninterface NzCarouselTransformOnLoopStrategyOptions {\n  direction: 'left' | 'right';\n}\n\n/**\n * this strategy is very much like NzCarouselTransformStrategy, but it doesn't loop between the first and the last one\n */\nexport class NzCarouselTransformNoLoopStrategy extends NzCarouselBaseStrategy<NzCarouselTransformOnLoopStrategyOptions> {\n  private isTransitioning = false;\n\n  private get vertical(): boolean {\n    return this.carouselComponent!.vertical;\n  }\n\n  constructor(\n    carouselComponent: NzCarouselComponentAsSource,\n    cdr: ChangeDetectorRef,\n    renderer: Renderer2,\n    platform: Platform,\n    options?: NzCarouselTransformOnLoopStrategyOptions\n  ) {\n    super(carouselComponent, cdr, renderer, platform, options);\n  }\n\n  override dispose(): void {\n    this.renderer.setStyle(this.slickTrackEl, 'transform', null);\n\n    super.dispose();\n  }\n\n  override withCarouselContents(contents: QueryList<NzCarouselContentDirective> | null): void {\n    super.withCarouselContents(contents);\n\n    const carousel = this.carouselComponent!;\n    const activeIndex = carousel.activeIndex;\n\n    if (this.platform.isBrowser && this.contents.length) {\n      this.renderer.setStyle(this.slickListEl, 'height', `${this.unitHeight}px`);\n\n      if (this.platform.isBrowser && this.contents.length) {\n        this.renderer.setStyle(this.slickListEl, 'height', `${this.unitHeight}px`);\n\n        if (this.vertical) {\n          this.renderer.setStyle(this.slickTrackEl, 'width', `${this.unitWidth}px`);\n          this.renderer.setStyle(this.slickTrackEl, 'height', `${this.length * this.unitHeight}px`);\n          this.renderer.setStyle(\n            this.slickTrackEl,\n            'transform',\n            `translate3d(0, ${-activeIndex * this.unitHeight}px, 0)`\n          );\n        } else {\n          this.renderer.setStyle(this.slickTrackEl, 'height', `${this.unitHeight}px`);\n          this.renderer.setStyle(this.slickTrackEl, 'width', `${this.length * this.unitWidth}px`);\n          this.renderer.setStyle(\n            this.slickTrackEl,\n            'transform',\n            `translate3d(${-activeIndex * this.unitWidth}px, 0, 0)`\n          );\n        }\n\n        this.contents.forEach((content: NzCarouselContentDirective) => {\n          this.renderer.setStyle(content.el, 'position', 'relative');\n          this.renderer.setStyle(content.el, 'width', `${this.unitWidth}px`);\n          this.renderer.setStyle(content.el, 'height', `${this.unitHeight}px`);\n        });\n      }\n    }\n  }\n\n  switch(_f: number, _t: number): Observable<void> {\n    const to = (_t + this.length) % this.length;\n    const transitionSpeed = this.carouselComponent!.nzTransitionSpeed;\n    const complete$ = new Subject<void>();\n\n    this.renderer.setStyle(this.slickTrackEl, 'transition', `transform ${transitionSpeed}ms ease`);\n\n    if (this.vertical) {\n      this.renderer.setStyle(this.slickTrackEl, 'transform', `translate3d(0, ${-to * this.unitHeight}px, 0)`);\n    } else {\n      this.renderer.setStyle(this.slickTrackEl, 'transform', `translate3d(${-to * this.unitWidth}px, 0, 0)`);\n    }\n\n    this.isTransitioning = true;\n\n    setTimeout(() => {\n      // this strategy don't need to do a following adjust\n      this.isTransitioning = false;\n\n      complete$.next();\n      complete$.complete();\n    }, transitionSpeed);\n\n    return complete$.asObservable();\n  }\n\n  override dragging(vector: PointerVector): void {\n    if (this.isTransitioning) {\n      return;\n    }\n\n    const activeIndex = this.carouselComponent!.activeIndex;\n\n    if (this.vertical) {\n      this.renderer.setStyle(\n        this.slickTrackEl,\n        'transform',\n        `translate3d(0, ${-activeIndex * this.unitHeight + vector.x}px, 0)`\n      );\n    } else {\n      this.renderer.setStyle(\n        this.slickTrackEl,\n        'transform',\n        `translate3d(${-activeIndex * this.unitWidth + vector.x}px, 0, 0)`\n      );\n    }\n  }\n}\n"
  },
  {
    "path": "components/carousel/strategies/opacity-strategy.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { QueryList } from '@angular/core';\nimport { Observable, Subject } from 'rxjs';\n\nimport { NzCarouselContentDirective } from '../carousel-content.directive';\nimport { NzCarouselBaseStrategy } from './base-strategy';\n\nexport class NzCarouselOpacityStrategy extends NzCarouselBaseStrategy {\n  override withCarouselContents(contents: QueryList<NzCarouselContentDirective> | null): void {\n    super.withCarouselContents(contents);\n\n    if (this.contents) {\n      this.slickTrackEl.style.width = `${this.length * this.unitWidth}px`;\n\n      this.contents.forEach((content: NzCarouselContentDirective, i: number) => {\n        this.renderer.setStyle(content.el, 'opacity', this.carouselComponent!.activeIndex === i ? '1' : '0');\n        this.renderer.setStyle(content.el, 'position', 'relative');\n        this.renderer.setStyle(content.el, 'width', `${this.unitWidth}px`);\n        this.renderer.setStyle(content.el, 'left', `${-this.unitWidth * i}px`);\n        this.renderer.setStyle(content.el, 'transition', ['opacity 500ms ease 0s', 'visibility 500ms ease 0s']);\n      });\n    }\n  }\n\n  switch(_f: number, _t: number): Observable<void> {\n    const { to: t } = this.getFromToInBoundary(_f, _t);\n    const complete$ = new Subject<void>();\n\n    this.contents.forEach((content: NzCarouselContentDirective, i: number) => {\n      this.renderer.setStyle(content.el, 'opacity', t === i ? '1' : '0');\n    });\n\n    setTimeout(() => {\n      complete$.next();\n      complete$.complete();\n    }, this.carouselComponent!.nzTransitionSpeed);\n\n    return complete$;\n  }\n\n  override dispose(): void {\n    this.contents.forEach((content: NzCarouselContentDirective) => {\n      this.renderer.setStyle(content.el, 'transition', null);\n      this.renderer.setStyle(content.el, 'opacity', null);\n      this.renderer.setStyle(content.el, 'width', null);\n      this.renderer.setStyle(content.el, 'left', null);\n    });\n\n    super.dispose();\n  }\n}\n"
  },
  {
    "path": "components/carousel/strategies/transform-strategy.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Platform } from '@angular/cdk/platform';\nimport { ChangeDetectorRef, QueryList, Renderer2 } from '@angular/core';\nimport { Observable, Subject } from 'rxjs';\n\nimport { NzCarouselContentDirective } from '../carousel-content.directive';\nimport { NzCarouselComponentAsSource, PointerVector } from '../typings';\nimport { NzCarouselBaseStrategy } from './base-strategy';\n\ninterface NzCarouselTransformStrategyOptions {\n  direction: 'left' | 'right';\n}\n\nexport class NzCarouselTransformStrategy extends NzCarouselBaseStrategy<NzCarouselTransformStrategyOptions> {\n  private isDragging = false;\n  private isTransitioning = false;\n\n  private get vertical(): boolean {\n    return this.carouselComponent!.vertical;\n  }\n\n  constructor(\n    carouselComponent: NzCarouselComponentAsSource,\n    cdr: ChangeDetectorRef,\n    renderer: Renderer2,\n    platform: Platform,\n    options?: NzCarouselTransformStrategyOptions\n  ) {\n    super(carouselComponent, cdr, renderer, platform, options);\n  }\n\n  override dispose(): void {\n    super.dispose();\n    this.renderer.setStyle(this.slickTrackEl, 'transform', null);\n  }\n\n  override withCarouselContents(contents: QueryList<NzCarouselContentDirective> | null): void {\n    super.withCarouselContents(contents);\n\n    const carousel = this.carouselComponent!;\n    const activeIndex = carousel.activeIndex;\n\n    // We only do when we are in browser.\n    if (this.platform.isBrowser && this.contents.length) {\n      this.renderer.setStyle(this.slickListEl, 'height', `${this.unitHeight}px`);\n\n      if (this.vertical) {\n        this.renderer.setStyle(this.slickTrackEl, 'width', `${this.unitWidth}px`);\n        this.renderer.setStyle(this.slickTrackEl, 'height', `${this.length * this.unitHeight}px`);\n        this.renderer.setStyle(\n          this.slickTrackEl,\n          'transform',\n          `translate3d(0, ${-activeIndex * this.unitHeight}px, 0)`\n        );\n      } else {\n        this.renderer.setStyle(this.slickTrackEl, 'height', `${this.unitHeight}px`);\n        this.renderer.setStyle(this.slickTrackEl, 'width', `${this.length * this.unitWidth}px`);\n        this.renderer.setStyle(this.slickTrackEl, 'transform', `translate3d(${-activeIndex * this.unitWidth}px, 0, 0)`);\n      }\n\n      this.contents.forEach((content: NzCarouselContentDirective) => {\n        this.renderer.setStyle(content.el, 'position', 'relative');\n        this.renderer.setStyle(content.el, 'width', `${this.unitWidth}px`);\n        this.renderer.setStyle(content.el, 'height', `${this.unitHeight}px`);\n      });\n    }\n  }\n\n  switch(_f: number, _t: number): Observable<void> {\n    const { to: t } = this.getFromToInBoundary(_f, _t);\n    const complete$ = new Subject<void>();\n\n    this.renderer.setStyle(\n      this.slickTrackEl,\n      'transition',\n      `transform ${this.carouselComponent!.nzTransitionSpeed}ms ease`\n    );\n\n    if (this.vertical) {\n      this.verticalTransform(_f, _t);\n    } else {\n      this.horizontalTransform(_f, _t);\n    }\n\n    this.isTransitioning = true;\n    this.isDragging = false;\n\n    // TODO: use transitionEnd event instead of setTimeout\n    setTimeout(() => {\n      this.renderer.setStyle(this.slickTrackEl, 'transition', null);\n      this.contents.forEach((content: NzCarouselContentDirective) => {\n        this.renderer.setStyle(content.el, this.vertical ? 'top' : 'left', null);\n      });\n\n      if (this.vertical) {\n        this.renderer.setStyle(this.slickTrackEl, 'transform', `translate3d(0, ${-t * this.unitHeight}px, 0)`);\n      } else {\n        this.renderer.setStyle(this.slickTrackEl, 'transform', `translate3d(${-t * this.unitWidth}px, 0, 0)`);\n      }\n\n      this.isTransitioning = false;\n\n      complete$.next();\n      complete$.complete();\n    }, this.carouselComponent!.nzTransitionSpeed);\n\n    return complete$.asObservable();\n  }\n\n  override dragging(_vector: PointerVector): void {\n    if (this.isTransitioning) {\n      return;\n    }\n\n    const activeIndex = this.carouselComponent!.activeIndex;\n\n    if (this.carouselComponent!.vertical) {\n      if (!this.isDragging && this.length > 2) {\n        if (activeIndex === this.maxIndex) {\n          this.prepareVerticalContext(true);\n        } else if (activeIndex === 0) {\n          this.prepareVerticalContext(false);\n        }\n      }\n      this.renderer.setStyle(\n        this.slickTrackEl,\n        'transform',\n        `translate3d(0, ${-activeIndex * this.unitHeight + _vector.x}px, 0)`\n      );\n    } else {\n      if (!this.isDragging && this.length > 2) {\n        if (activeIndex === this.maxIndex) {\n          this.prepareHorizontalContext(true);\n        } else if (activeIndex === 0) {\n          this.prepareHorizontalContext(false);\n        }\n      }\n      this.renderer.setStyle(\n        this.slickTrackEl,\n        'transform',\n        `translate3d(${-activeIndex * this.unitWidth + _vector.x}px, 0, 0)`\n      );\n    }\n\n    this.isDragging = true;\n  }\n\n  private verticalTransform(_f: number, _t: number): void {\n    const { from: f, to: t } = this.getFromToInBoundary(_f, _t);\n    const needToAdjust = this.length > 2 && _t !== t;\n\n    if (needToAdjust) {\n      this.prepareVerticalContext(t < f);\n      this.renderer.setStyle(this.slickTrackEl, 'transform', `translate3d(0, ${-_t * this.unitHeight}px, 0)`);\n    } else {\n      this.renderer.setStyle(this.slickTrackEl, 'transform', `translate3d(0, ${-t * this.unitHeight}px, 0`);\n    }\n  }\n\n  private horizontalTransform(_f: number, _t: number): void {\n    const { from: f, to: t } = this.getFromToInBoundary(_f, _t);\n    const needToAdjust = this.length > 2 && _t !== t;\n\n    if (needToAdjust) {\n      this.prepareHorizontalContext(t < f);\n      this.renderer.setStyle(this.slickTrackEl, 'transform', `translate3d(${-_t * this.unitWidth}px, 0, 0)`);\n    } else {\n      this.renderer.setStyle(this.slickTrackEl, 'transform', `translate3d(${-t * this.unitWidth}px, 0, 0`);\n    }\n  }\n\n  private prepareVerticalContext(lastToFirst: boolean): void {\n    if (lastToFirst) {\n      this.renderer.setStyle(this.firstEl, 'top', `${this.length * this.unitHeight}px`);\n      this.renderer.setStyle(this.lastEl, 'top', null);\n    } else {\n      this.renderer.setStyle(this.firstEl, 'top', null);\n      this.renderer.setStyle(this.lastEl, 'top', `${-this.unitHeight * this.length}px`);\n    }\n  }\n\n  private prepareHorizontalContext(lastToFirst: boolean): void {\n    if (lastToFirst) {\n      this.renderer.setStyle(this.firstEl, 'left', `${this.length * this.unitWidth}px`);\n      this.renderer.setStyle(this.lastEl, 'left', null);\n    } else {\n      this.renderer.setStyle(this.firstEl, 'left', null);\n      this.renderer.setStyle(this.lastEl, 'left', `${-this.unitWidth * this.length}px`);\n    }\n  }\n}\n"
  },
  {
    "path": "components/carousel/style/entry.less",
    "content": "@import './index.less';\n@import './patch';\n"
  },
  {
    "path": "components/carousel/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@carousel-prefix-cls: ~'@{ant-prefix}-carousel';\n@carousel-dot-margin: 4px;\n@carousel-arrow-size: 16px;\n@carousel-arrow-offset: 12px;\n@carousel-arrow-bg: fade(#000, 20%);\n@carousel-arrow-bg-hover: fade(#000, 30%);\n@carousel-arrow-color: @white;\n\n.@{carousel-prefix-cls} {\n  .reset-component();\n\n  .slick-slider {\n    position: relative;\n    display: block;\n    box-sizing: border-box;\n    touch-action: pan-y;\n    -webkit-touch-callout: none;\n    -webkit-tap-highlight-color: transparent;\n  }\n\n  .slick-list {\n    position: relative;\n    display: block;\n    margin: 0;\n    padding: 0;\n    overflow: hidden;\n\n    &:focus {\n      outline: none;\n    }\n\n    &.dragging {\n      cursor: pointer;\n    }\n\n    .slick-slide {\n      pointer-events: none;\n\n      // https://github.com/ant-design/ant-design/issues/23294\n      input.@{ant-prefix}-radio-input,\n      input.@{ant-prefix}-checkbox-input {\n        visibility: hidden;\n      }\n\n      &.slick-active {\n        pointer-events: auto;\n\n        input.@{ant-prefix}-radio-input,\n        input.@{ant-prefix}-checkbox-input {\n          visibility: visible;\n        }\n      }\n\n      // fix Carousel content height not match parent node\n      // when children is empty node\n      // https://github.com/ant-design/ant-design/issues/25878\n      > div > div {\n        vertical-align: bottom;\n      }\n    }\n  }\n\n  .slick-slider .slick-track,\n  .slick-slider .slick-list {\n    transform: translate3d(0, 0, 0);\n    touch-action: pan-y;\n  }\n\n  .slick-track {\n    position: relative;\n    top: 0;\n    left: 0;\n    display: block;\n\n    &::before,\n    &::after {\n      display: table;\n      content: '';\n    }\n\n    &::after {\n      clear: both;\n    }\n\n    .slick-loading & {\n      visibility: hidden;\n    }\n  }\n\n  .slick-slide {\n    display: none;\n    float: left;\n    height: 100%;\n    min-height: 1px;\n\n    img {\n      display: block;\n    }\n\n    &.slick-loading img {\n      display: none;\n    }\n\n    &.dragging img {\n      pointer-events: none;\n    }\n  }\n\n  .slick-initialized .slick-slide {\n    display: block;\n  }\n\n  .slick-loading .slick-slide {\n    visibility: hidden;\n  }\n\n  .slick-vertical .slick-slide {\n    display: block;\n    height: auto;\n  }\n\n  .slick-arrow.slick-hidden {\n    display: none;\n  }\n\n  // Arrows\n  .slick-prev,\n  .slick-next {\n    position: absolute;\n    top: 50%;\n    z-index: 1;\n    display: inline-block;\n    width: @carousel-arrow-size;\n    height: @carousel-arrow-size;\n    margin: 0;\n    padding: 0;\n    color: @white;\n    font-size: 0; // keep no text\n    line-height: 0;\n    background: transparent;\n    border: 0;\n    border-radius: 0;\n    outline: none;\n    transform: translateY(-50%);\n    cursor: pointer;\n    opacity: 0.3;\n    transition:\n      color 0.3s,\n      opacity 0.3s;\n\n    &::after {\n      position: absolute;\n      top: 2.3px;\n      display: inline-block;\n      box-sizing: border-box;\n      width: 11.3px;\n      height: 11.3px;\n      border: 0 solid currentcolor;\n      border-radius: 1px;\n      opacity: 1;\n      content: '';\n      inset-inline-start: 2.3px;\n      border-inline-start-width: 2px;\n      border-block-start-width: 2px;\n    }\n\n    &:hover,\n    &:focus {\n      color: @white;\n      outline: none;\n      opacity: 1;\n    }\n\n    &.slick-disabled {\n      display: none;\n    }\n  }\n\n  .slick-prev {\n    right: auto;\n    left: @carousel-arrow-offset;\n\n    &::after {\n      transform: rotate(-45deg);\n    }\n  }\n\n  .slick-next {\n    right: @carousel-arrow-offset;\n    left: auto;\n\n    &::after {\n      transform: rotate(135deg);\n    }\n  }\n\n  // Vertical mode (dots on left or right)\n  .slick-vertical {\n    .slick-prev {\n      top: @carousel-dot-margin * 3;\n      right: auto;\n      left: 50%;\n      transform: translateX(-50%);\n\n      &::after {\n        transform: rotate(45deg);\n      }\n    }\n\n    .slick-next {\n      top: auto;\n      right: auto;\n      bottom: @carousel-dot-margin * 3;\n      left: 50%;\n      transform: translateX(-50%);\n\n      &::after {\n        transform: rotate(-135deg);\n      }\n    }\n  }\n\n  .slick-dots {\n    position: absolute;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    z-index: 15;\n    display: flex !important;\n    justify-content: center;\n    margin-right: 15%;\n    margin-bottom: 0;\n    margin-left: 15%;\n    padding-left: 0;\n    list-style: none;\n\n    &-bottom {\n      bottom: 12px;\n    }\n\n    &-top {\n      top: 12px;\n      bottom: auto;\n    }\n\n    li {\n      position: relative;\n      display: inline-block;\n      flex: 0 1 auto;\n      box-sizing: content-box;\n      width: @carousel-dot-width;\n      height: @carousel-dot-height;\n      margin: 0 @carousel-dot-margin;\n      padding: 0;\n      text-align: center;\n      text-indent: -999px;\n      vertical-align: top;\n      transition: all 0.5s;\n\n      button {\n        position: relative;\n        display: block;\n        width: 100%;\n        height: @carousel-dot-height;\n        padding: 0;\n        color: transparent;\n        font-size: 0;\n        background: @component-background;\n        border: 0;\n        border-radius: 1px;\n        outline: none;\n        cursor: pointer;\n        opacity: 0.3;\n        transition: all 0.5s;\n\n        &:hover,\n        &:focus {\n          opacity: 0.75;\n        }\n\n        &::after {\n          position: absolute;\n          top: -@carousel-dot-margin;\n          right: -@carousel-dot-margin;\n          bottom: -@carousel-dot-margin;\n          left: -@carousel-dot-margin;\n          content: '';\n        }\n      }\n\n      &.slick-active {\n        width: @carousel-dot-active-width;\n\n        & button {\n          background: @component-background;\n          opacity: 1;\n        }\n\n        &:hover,\n        &:focus {\n          opacity: 1;\n        }\n      }\n    }\n  }\n}\n\n.@{ant-prefix}-carousel-vertical {\n  .slick-dots {\n    top: 50%;\n    bottom: auto;\n    flex-direction: column;\n    width: @carousel-dot-height;\n    height: auto;\n    margin: 0;\n    transform: translateY(-50%);\n\n    &-left {\n      right: auto;\n      left: 12px;\n    }\n\n    &-right {\n      right: 12px;\n      left: auto;\n    }\n\n    li {\n      width: @carousel-dot-height;\n      height: @carousel-dot-width;\n      margin: @carousel-dot-margin 0;\n      vertical-align: baseline;\n\n      button {\n        width: @carousel-dot-height;\n        height: @carousel-dot-width;\n      }\n\n      &.slick-active {\n        width: @carousel-dot-height;\n        height: @carousel-dot-active-width;\n\n        button {\n          width: @carousel-dot-height;\n          height: @carousel-dot-active-width;\n        }\n      }\n    }\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/carousel/style/patch.less",
    "content": "nz-carousel {\n  position: relative;\n  display: block;\n  width: 100%;\n  height: 100%;\n  overflow: hidden;\n}\n\n.slick-list,\n.slick-track,\n.slick-slide {\n  height: auto;\n}\n\n.slick-dots {\n  display: block;\n}\n\n.slick-track {\n  opacity: 1;\n}"
  },
  {
    "path": "components/carousel/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@carousel-prefix-cls: ~'@{ant-prefix}-carousel';\n\n.@{carousel-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n\n    .slick-next {\n      right: auto;\n      left: @carousel-arrow-offset;\n\n      &::after {\n        // In RTL, next points to the left\n        transform: rotate(-45deg);\n      }\n    }\n\n    .slick-prev {\n      right: @carousel-arrow-offset;\n      left: auto;\n\n      &::after {\n        // In RTL, previous points to the right\n        transform: rotate(135deg);\n      }\n    }\n  }\n\n  .slick-track {\n    .@{carousel-prefix-cls}-rtl & {\n      right: 0;\n      left: auto;\n    }\n  }\n  // Dots\n  .slick-dots {\n    .@{carousel-prefix-cls}-rtl& {\n      flex-direction: row-reverse;\n    }\n  }\n}\n\n.@{ant-prefix}-carousel-vertical {\n  .slick-dots {\n    .@{carousel-prefix-cls}-rtl& {\n      flex-direction: column;\n    }\n  }\n}\n\n// Vertical arrows in RTL follow the same reversal as LTR (prev up, next down)\n.@{carousel-prefix-cls} {\n  .@{carousel-prefix-cls}-rtl & {\n    .slick-vertical {\n      .slick-prev::after {\n        transform: rotate(45deg);\n      }\n\n      .slick-next::after {\n        transform: rotate(-135deg);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/carousel/typings.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction } from '@angular/cdk/bidi';\nimport { InjectionToken, NgZone, QueryList } from '@angular/core';\n\nimport { NzCarouselContentDirective } from './carousel-content.directive';\nimport { NzCarouselBaseStrategy } from './strategies/base-strategy';\n\nexport type NzCarouselEffects = 'fade' | 'scrollx' | string;\nexport type NzCarouselDotPosition = 'top' | 'bottom' | 'left' | 'right' | string;\n\nexport interface NzCarouselComponentAsSource {\n  carouselContents: QueryList<NzCarouselContentDirective>;\n  el: HTMLElement;\n  nzTransitionSpeed: number;\n  vertical: boolean;\n  slickListEl: HTMLElement;\n  slickTrackEl: HTMLElement;\n  activeIndex: number;\n  dir: Direction;\n  ngZone: NgZone;\n}\n\nexport interface NzCarouselStrategyRegistryItem {\n  name: string;\n  strategy: NzCarouselBaseStrategy;\n}\n\nexport const NZ_CAROUSEL_CUSTOM_STRATEGIES = new InjectionToken<NzCarouselStrategyRegistryItem[]>(\n  typeof ngDevMode !== 'undefined' && ngDevMode ? 'nz-carousel-custom-strategies' : ''\n);\n\nexport interface PointerVector {\n  x: number;\n  y: number;\n}\n\nexport interface FromToInterface {\n  from: number;\n  to: number;\n}\n"
  },
  {
    "path": "components/cascader/cascader-option.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction } from '@angular/cdk/bidi';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  ElementRef,\n  EventEmitter,\n  Input,\n  OnInit,\n  Output,\n  TemplateRef,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject,\n  numberAttribute,\n  ChangeDetectorRef\n} from '@angular/core';\n\nimport { NzHighlightPipe } from 'ng-zorro-antd/core/highlight';\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzTreeNode } from 'ng-zorro-antd/core/tree';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nimport { NzCascaderOption } from './typings';\n\n@Component({\n  selector: '[nz-cascader-option]',\n  exportAs: 'nzCascaderOption',\n  imports: [NgTemplateOutlet, NzHighlightPipe, NzIconModule, NzOutletModule],\n  template: `\n    @if (checkable) {\n      <span\n        class=\"ant-cascader-checkbox\"\n        [class.ant-cascader-checkbox-checked]=\"checked\"\n        [class.ant-cascader-checkbox-indeterminate]=\"halfChecked\"\n        [class.ant-cascader-checkbox-disabled]=\"disabled\"\n        (click)=\"onCheckboxClick($event)\"\n      >\n        <span class=\"ant-cascader-checkbox-inner\"></span>\n      </span>\n    }\n\n    @if (optionTemplate) {\n      <ng-template\n        [ngTemplateOutlet]=\"optionTemplate\"\n        [ngTemplateOutletContext]=\"{ $implicit: node.origin, index: columnIndex }\"\n      />\n    } @else {\n      <div\n        class=\"ant-cascader-menu-item-content\"\n        [innerHTML]=\"node.title | nzHighlight: highlightText : 'g' : 'ant-cascader-menu-item-keyword'\"\n      ></div>\n    }\n\n    @if (!node.isLeaf || node.children?.length || node.isLoading) {\n      <div class=\"ant-cascader-menu-item-expand-icon\">\n        @if (node.isLoading) {\n          <nz-icon nzType=\"loading\" />\n        } @else {\n          <ng-container *nzStringTemplateOutlet=\"expandIcon\">\n            <nz-icon [nzType]=\"$any(expandIcon)\" />\n          </ng-container>\n        }\n      </div>\n    }\n  `,\n  host: {\n    class: 'ant-cascader-menu-item ant-cascader-menu-item-expanded',\n    '[attr.title]': 'node.title',\n    '[class.ant-cascader-menu-item-active]': 'activated',\n    '[class.ant-cascader-menu-item-expand]': '!node.isLeaf',\n    '[class.ant-cascader-menu-item-disabled]': 'node.isDisabled'\n  },\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None\n})\nexport class NzCascaderOptionComponent implements OnInit {\n  private cdr = inject(ChangeDetectorRef);\n\n  @Input() optionTemplate: TemplateRef<NzCascaderOption> | null = null;\n  @Input() node!: NzTreeNode;\n  @Input() activated = false;\n  @Input() highlightText!: string;\n  @Input() nzLabelProperty = 'label';\n  @Input({ transform: numberAttribute }) columnIndex!: number;\n  @Input() expandIcon: string | TemplateRef<void> = '';\n  @Input() dir: Direction = 'ltr';\n  @Input({ transform: booleanAttribute }) checkable?: boolean = false;\n\n  @Output() readonly check = new EventEmitter<void>();\n\n  public readonly nativeElement: HTMLElement = inject(ElementRef).nativeElement;\n\n  ngOnInit(): void {\n    if (this.expandIcon === '' && this.dir === 'rtl') {\n      this.expandIcon = 'left';\n    } else if (this.expandIcon === '') {\n      this.expandIcon = 'right';\n    }\n  }\n\n  get checked(): boolean {\n    return this.node.isChecked;\n  }\n\n  get halfChecked(): boolean {\n    return this.node.isHalfChecked;\n  }\n\n  get disabled(): boolean {\n    return this.node.isDisabled || this.node.isDisableCheckbox;\n  }\n\n  markForCheck(): void {\n    this.cdr.markForCheck();\n  }\n\n  onCheckboxClick(event: MouseEvent): void {\n    event.preventDefault();\n    event.stopPropagation();\n    if (!this.checkable) {\n      return;\n    }\n    this.check.emit();\n  }\n}\n"
  },
  {
    "path": "components/cascader/cascader-tree.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Injectable } from '@angular/core';\n\nimport { NzTreeBaseService, NzTreeNode, NzTreeNodeKey } from 'ng-zorro-antd/core/tree';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { arraysEqual, isNotNil } from 'ng-zorro-antd/core/util';\n\nimport { NzCascaderOption } from './typings';\n\ninterface InternalFieldNames {\n  label: string;\n  value: string;\n}\n\n@Injectable()\nexport class NzCascaderTreeService extends NzTreeBaseService {\n  fieldNames: InternalFieldNames = {\n    label: 'label',\n    value: 'value'\n  };\n\n  override treeNodePostProcessor = (node: NzTreeNode): void => {\n    node.key = this.getOptionValue(node);\n    node.title = this.getOptionLabel(node);\n  };\n\n  getOptionValue(node: NzTreeNode): NzSafeAny {\n    return node.origin[this.fieldNames.value || 'value'];\n  }\n\n  getOptionLabel(node: NzTreeNode): string {\n    return node.origin[this.fieldNames.label || 'label'];\n  }\n\n  get children(): NzTreeNode[] {\n    return this.rootNodes;\n  }\n\n  set children(value: Array<NzTreeNode | NzSafeAny>) {\n    this.rootNodes = value.map(v => (v instanceof NzTreeNode ? v : new NzTreeNode(v, null)));\n  }\n\n  /**\n   * Map list of nodes to list of option\n   */\n  toOptions(nodes: NzTreeNode[]): NzCascaderOption[] {\n    return nodes.map(node => node.origin);\n  }\n\n  getAncestorNodeList(node: NzTreeNode | null): NzTreeNode[] {\n    if (!node) {\n      return [];\n    }\n    if (node.parentNode) {\n      return [...this.getAncestorNodeList(node.parentNode), node];\n    }\n    return [node];\n  }\n\n  /**\n   * Render by nzCheckedKeys\n   * When keys equals null, just render with checkStrictly\n   *\n   * @param paths\n   * @param checkStrictly\n   */\n  conductCheckPaths(paths: NzTreeNodeKey[][] | null, checkStrictly: boolean): void {\n    this.checkedNodeList = [];\n    this.halfCheckedNodeList = [];\n    const existsPathList: NzTreeNodeKey[][] = [];\n    const calc = (nodes: NzTreeNode[]): void => {\n      nodes.forEach(node => {\n        if (paths === null) {\n          // render tree if no default checked keys found\n          node.isChecked = !!node.origin.checked;\n        } else {\n          // if node is in checked path\n          const nodePath = this.getAncestorNodeList(node).map(n => this.getOptionValue(n));\n          if (paths.some(keys => arraysEqual(nodePath, keys))) {\n            node.isChecked = true;\n            node.isHalfChecked = false;\n            existsPathList.push(nodePath);\n          } else {\n            node.isChecked = false;\n            node.isHalfChecked = false;\n          }\n        }\n        if (node.children.length > 0) {\n          calc(node.children);\n        }\n      });\n    };\n    calc(this.rootNodes);\n    this.refreshCheckState(checkStrictly);\n    // handle missing node\n    this.handleMissingNodeList(paths, existsPathList);\n  }\n\n  conductSelectedPaths(paths: NzTreeNodeKey[][]): void {\n    this.selectedNodeList.forEach(node => (node.isSelected = false));\n    this.selectedNodeList = [];\n    const existsPathList: NzTreeNodeKey[][] = [];\n    const calc = (nodes: NzTreeNode[]): boolean =>\n      nodes.every(node => {\n        // if node is in selected path\n        const nodePath = this.getAncestorNodeList(node).map(n => this.getOptionValue(n));\n        if (paths.some(keys => arraysEqual(nodePath, keys))) {\n          node.isSelected = true;\n          this.setSelectedNodeList(node);\n          existsPathList.push(nodePath);\n          return false;\n        } else {\n          node.isSelected = false;\n        }\n        if (node.children.length > 0) {\n          return calc(node.children);\n        }\n        return true;\n      });\n    calc(this.rootNodes);\n    this.handleMissingNodeList(paths, existsPathList);\n  }\n\n  private handleMissingNodeList(paths: NzTreeNodeKey[][] | null, existsPathList: NzTreeNodeKey[][]): void {\n    const missingNodeList = this.getMissingNodeList(paths, existsPathList);\n    missingNodeList.forEach(node => {\n      this.setSelectedNodeList(node);\n    });\n  }\n\n  private getMissingNodeList(paths: NzTreeNodeKey[][] | null, existsPathList: NzTreeNodeKey[][]): NzTreeNode[] {\n    if (!paths) {\n      return [];\n    }\n    return paths\n      .filter(path => !existsPathList.some(keys => arraysEqual(path, keys)))\n      .map(path => this.createMissingNode(path))\n      .filter(isNotNil);\n  }\n\n  private createMissingNode(path: NzTreeNodeKey[]): NzTreeNode | null {\n    if (!path?.length) {\n      return null;\n    }\n\n    const createOption = (key: NzTreeNodeKey): NzSafeAny => {\n      return {\n        [this.fieldNames.value || 'value']: key,\n        [this.fieldNames.label || 'label']: key\n      };\n    };\n\n    let node = new NzTreeNode(createOption(path[0]), null, this);\n\n    for (let i = 1; i < path.length; i++) {\n      const childNode = new NzTreeNode(createOption(path[i]));\n      node.addChildren([childNode]);\n      node = childNode;\n    }\n\n    if (this.isMultiple) {\n      node.isChecked = true;\n      node.isHalfChecked = false;\n    } else {\n      node.isSelected = true;\n    }\n    return node;\n  }\n}\n"
  },
  {
    "path": "components/cascader/cascader.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport { BACKSPACE, DOWN_ARROW, ENTER, ESCAPE, LEFT_ARROW, RIGHT_ARROW, UP_ARROW } from '@angular/cdk/keycodes';\nimport {\n  CdkConnectedOverlay,\n  ConnectedOverlayPositionChange,\n  ConnectionPositionPair,\n  OverlayModule\n} from '@angular/cdk/overlay';\nimport { _getEventTarget } from '@angular/cdk/platform';\nimport { SlicePipe } from '@angular/common';\nimport {\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  computed,\n  DestroyRef,\n  ElementRef,\n  EventEmitter,\n  forwardRef,\n  HostListener,\n  inject,\n  Input,\n  NgZone,\n  numberAttribute,\n  OnChanges,\n  OnInit,\n  Output,\n  QueryList,\n  Renderer2,\n  signal,\n  SimpleChanges,\n  TemplateRef,\n  ViewChild,\n  ViewChildren,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { BehaviorSubject, merge, Observable, of } from 'rxjs';\nimport { distinctUntilChanged, map, startWith, switchMap, withLatestFrom } from 'rxjs/operators';\n\nimport { NzNoAnimationDirective, slideAnimationEnter, slideAnimationLeave } from 'ng-zorro-antd/core/animation';\nimport { NzConfigKey, onConfigChangeEventForComponent, WithConfig } from 'ng-zorro-antd/core/config';\nimport {\n  NZ_FORM_SIZE,\n  NZ_FORM_VARIANT,\n  NzFormItemFeedbackIconComponent,\n  NzFormNoStatusService,\n  NzFormStatusService\n} from 'ng-zorro-antd/core/form';\nimport { NzStringTemplateOutletDirective } from 'ng-zorro-antd/core/outlet';\nimport {\n  DEFAULT_CASCADER_POSITIONS,\n  getPlacementName,\n  NzOverlayModule,\n  POSITION_MAP,\n  POSITION_TYPE\n} from 'ng-zorro-antd/core/overlay';\nimport { NzTreeBase, NzTreeNode } from 'ng-zorro-antd/core/tree';\nimport {\n  NgClassInterface,\n  NgStyleInterface,\n  NzSafeAny,\n  NzSizeLDSType,\n  NzStatus,\n  NzValidateStatus,\n  NzVariant\n} from 'ng-zorro-antd/core/types';\nimport { fromEventOutsideAngular, getStatusClassNames, isNotNil, toArray } from 'ng-zorro-antd/core/util';\nimport { NzEmptyModule } from 'ng-zorro-antd/empty';\nimport { NzCascaderI18nInterface, NzI18nService } from 'ng-zorro-antd/i18n';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport {\n  NzSelectClearComponent,\n  NzSelectItemComponent,\n  NzSelectPlaceholderComponent,\n  NzSelectPlacementType,\n  NzSelectSearchComponent\n} from 'ng-zorro-antd/select';\nimport { NZ_SPACE_COMPACT_ITEM_TYPE, NZ_SPACE_COMPACT_SIZE, NzSpaceCompactItemDirective } from 'ng-zorro-antd/space';\n\nimport { NzCascaderOptionComponent } from './cascader-option.component';\nimport { NzCascaderTreeService } from './cascader-tree.service';\nimport { NzCascaderService } from './cascader.service';\nimport {\n  NzCascaderComponentAsSource,\n  NzCascaderExpandTrigger,\n  NzCascaderOption,\n  NzCascaderPlacement,\n  NzCascaderSize,\n  NzCascaderTriggerType,\n  NzShowSearchOptions\n} from './typings';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'cascader';\nconst defaultDisplayRender = (labels: string[]): string => labels.join(' / ');\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-cascader, [nz-cascader]',\n  exportAs: 'nzCascader',\n  template: `\n    @if (nzShowInput) {\n      <div #selectContainer class=\"ant-select-selector\">\n        @if (nzPrefix; as prefix) {\n          <div class=\"ant-select-prefix\">\n            <ng-container *nzStringTemplateOutlet=\"prefix\">{{ prefix }}</ng-container>\n          </div>\n        }\n        <span class=\"ant-select-selection-wrap\">\n          @if (nzMultiple) {\n            <div class=\"ant-select-selection-overflow\">\n              @for (node of selectedNodes | slice: 0 : nzMaxTagCount; track node) {\n                <div class=\"ant-select-selection-overflow-item\">\n                  <nz-select-item\n                    deletable\n                    [disabled]=\"nzDisabled\"\n                    [label]=\"nzDisplayWith(getAncestorOptionList(node))\"\n                    (delete)=\"removeSelected(node)\"\n                  />\n                </div>\n              }\n              @if (selectedNodes.length > nzMaxTagCount) {\n                <div class=\"ant-select-selection-overflow-item\">\n                  <nz-select-item [label]=\"'+ ' + (selectedNodes.length - nzMaxTagCount) + ' ...'\" />\n                </div>\n              }\n\n              <div class=\"ant-select-selection-overflow-item ant-select-selection-overflow-item-suffix\">\n                <nz-select-search\n                  [showInput]=\"!!nzShowSearch\"\n                  (isComposingChange)=\"isComposingChange($event)\"\n                  [value]=\"inputValue\"\n                  (valueChange)=\"inputValue = $event\"\n                  [mirrorSync]=\"true\"\n                  [disabled]=\"nzDisabled\"\n                  [autofocus]=\"nzAutoFocus\"\n                  [focusTrigger]=\"menuVisible()\"\n                />\n              </div>\n            </div>\n          } @else {\n            <nz-select-search\n              [showInput]=\"!!nzShowSearch\"\n              (isComposingChange)=\"isComposingChange($event)\"\n              [value]=\"inputValue\"\n              (valueChange)=\"inputValue = $event\"\n              [mirrorSync]=\"false\"\n              [disabled]=\"nzDisabled\"\n              [autofocus]=\"nzAutoFocus\"\n              [focusTrigger]=\"menuVisible()\"\n            />\n\n            @if (showLabelRender) {\n              <nz-select-item\n                [disabled]=\"nzDisabled\"\n                [label]=\"labelRenderText\"\n                [contentTemplateOutlet]=\"isLabelRenderTemplate ? nzLabelRender : null\"\n                [contentTemplateOutletContext]=\"labelRenderContext\"\n              />\n            }\n          }\n\n          @if (showPlaceholder) {\n            <nz-select-placeholder\n              [placeholder]=\"nzPlaceHolder || locale?.placeholder!\"\n              [style.display]=\"inputValue || isComposing ? 'none' : 'block'\"\n            />\n          }\n        </span>\n      </div>\n\n      @if (nzShowArrow) {\n        <span class=\"ant-select-arrow\" [class.ant-select-arrow-loading]=\"isLoading\">\n          @if (!isLoading) {\n            <nz-icon [nzType]=\"$any(nzSuffixIcon)\" [class.ant-cascader-picker-arrow-expand]=\"menuVisible()\" />\n          } @else {\n            <nz-icon nzType=\"loading\" />\n          }\n\n          @if (hasFeedback && !!status) {\n            <nz-form-item-feedback-icon [status]=\"status\" />\n          }\n        </span>\n      }\n      @if (clearIconVisible) {\n        <nz-select-clear (clear)=\"clearSelection($event)\" />\n      }\n    }\n    <ng-content />\n\n    <ng-template\n      cdkConnectedOverlay\n      nzConnectedOverlay\n      [cdkConnectedOverlayHasBackdrop]=\"nzBackdrop\"\n      [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n      [cdkConnectedOverlayPositions]=\"positions\"\n      cdkConnectedOverlayTransformOriginOn=\".ant-cascader-dropdown\"\n      [cdkConnectedOverlayOpen]=\"menuVisible()\"\n      (overlayOutsideClick)=\"onClickOutside($event)\"\n      (detach)=\"closeMenu()\"\n      (positionChange)=\"onPositionChange($event)\"\n    >\n      <div\n        class=\"ant-select-dropdown ant-cascader-dropdown\"\n        [class.ant-select-dropdown-placement-bottomLeft]=\"dropdownPosition === 'bottomLeft'\"\n        [class.ant-select-dropdown-placement-bottomRight]=\"dropdownPosition === 'bottomRight'\"\n        [class.ant-select-dropdown-placement-topLeft]=\"dropdownPosition === 'topLeft'\"\n        [class.ant-select-dropdown-placement-topRight]=\"dropdownPosition === 'topRight'\"\n        [class.ant-cascader-dropdown-rtl]=\"dir === 'rtl'\"\n        [animate.enter]=\"cascaderAnimationEnter()\"\n        [animate.leave]=\"cascaderAnimationLeave()\"\n        [nzNoAnimation]=\"noAnimation?.nzNoAnimation?.()\"\n        (mouseenter)=\"onTriggerMouseEnter()\"\n        (mouseleave)=\"onTriggerMouseLeave($event)\"\n      >\n        <div\n          #menu\n          class=\"ant-cascader-menus\"\n          [class.ant-cascader-rtl]=\"dir === 'rtl'\"\n          [class.ant-cascader-menus-hidden]=\"!menuVisible()\"\n          [class.ant-cascader-menu-empty]=\"shouldShowEmpty\"\n          [class]=\"nzMenuClassName\"\n          [style]=\"nzMenuStyle\"\n        >\n          @if (shouldShowEmpty) {\n            <ul class=\"ant-cascader-menu\" [style.width]=\"dropdownWidthStyle\" [style.height]=\"dropdownHeightStyle\">\n              <li class=\"ant-cascader-menu-item ant-cascader-menu-item-disabled\">\n                <nz-embed-empty\n                  class=\"ant-cascader-menu-item-content\"\n                  nzComponentName=\"cascader\"\n                  [specificContent]=\"nzNotFoundContent\"\n                />\n              </li>\n            </ul>\n          } @else {\n            @for (options of cascaderService.columns; track options; let i = $index) {\n              <ul\n                class=\"ant-cascader-menu\"\n                role=\"menuitemcheckbox\"\n                [class]=\"nzColumnClassName\"\n                [style.height]=\"dropdownHeightStyle\"\n              >\n                @for (option of options; track option) {\n                  <li\n                    nz-cascader-option\n                    [expandIcon]=\"nzExpandIcon\"\n                    [columnIndex]=\"i\"\n                    [nzLabelProperty]=\"nzLabelProperty\"\n                    [optionTemplate]=\"nzOptionRender\"\n                    [activated]=\"isOptionActivated(option, i)\"\n                    [highlightText]=\"inSearchingMode ? inputValue : ''\"\n                    [node]=\"option\"\n                    [dir]=\"dir\"\n                    [checkable]=\"nzMultiple\"\n                    (mouseenter)=\"onOptionMouseEnter(option, i, $event)\"\n                    (mouseleave)=\"onOptionMouseLeave(option, i, $event)\"\n                    (click)=\"onOptionClick(option, i, $event)\"\n                    (check)=\"onOptionCheck(option, i)\"\n                  ></li>\n                }\n              </ul>\n            }\n          }\n        </div>\n      </div>\n    </ng-template>\n  `,\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => NzCascaderComponent),\n      multi: true\n    },\n    { provide: NZ_SPACE_COMPACT_ITEM_TYPE, useValue: 'select' },\n    NzCascaderService,\n    NzCascaderTreeService\n  ],\n  host: {\n    '[attr.tabIndex]': '\"0\"',\n    '[class.ant-select-in-form-item]': '!!nzFormStatusService',\n    '[class.ant-select-lg]': 'finalSize() === \"large\"',\n    '[class.ant-select-sm]': 'finalSize() === \"small\"',\n    '[class.ant-select-allow-clear]': 'nzAllowClear',\n    '[class.ant-select-show-arrow]': 'nzShowArrow',\n    '[class.ant-select-show-search]': '!!nzShowSearch',\n    '[class.ant-select-disabled]': 'nzDisabled',\n    '[class.ant-select-borderless]': `finalVariant() === 'borderless'`,\n    '[class.ant-select-filled]': `finalVariant() === 'filled'`,\n    '[class.ant-select-underlined]': `finalVariant() === 'underlined'`,\n    '[class.ant-select-open]': 'menuVisible()',\n    '[class.ant-select-focused]': 'isFocused',\n    '[class.ant-select-multiple]': 'nzMultiple',\n    '[class.ant-select-single]': '!nzMultiple',\n    '[class.ant-select-rtl]': `dir === 'rtl'`\n  },\n  hostDirectives: [NzSpaceCompactItemDirective],\n  imports: [\n    SlicePipe,\n    OverlayModule,\n    FormsModule,\n    NzIconModule,\n    NzEmptyModule,\n    NzFormItemFeedbackIconComponent,\n    NzOverlayModule,\n    NzNoAnimationDirective,\n    NzSelectClearComponent,\n    NzSelectItemComponent,\n    NzSelectPlaceholderComponent,\n    NzSelectSearchComponent,\n    NzCascaderOptionComponent,\n    NzStringTemplateOutletDirective\n  ]\n})\nexport class NzCascaderComponent\n  extends NzTreeBase\n  implements NzCascaderComponentAsSource, OnInit, OnChanges, ControlValueAccessor\n{\n  private ngZone = inject(NgZone);\n  private cdr = inject(ChangeDetectorRef);\n  private i18nService = inject(NzI18nService);\n  private elementRef = inject(ElementRef<HTMLElement>);\n  private renderer = inject(Renderer2);\n  private directionality = inject(Directionality);\n  private destroyRef = inject(DestroyRef);\n\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  @ViewChild('selectContainer', { static: false }) selectContainer!: ElementRef;\n  protected readonly cascaderAnimationEnter = slideAnimationEnter();\n  protected readonly cascaderAnimationLeave = slideAnimationLeave();\n\n  @ViewChild(NzSelectSearchComponent)\n  set input(inputComponent: NzSelectSearchComponent | undefined) {\n    this.input$.next(inputComponent?.inputElement);\n  }\n\n  get input(): ElementRef<HTMLInputElement> | undefined {\n    return this.input$.getValue();\n  }\n\n  /** Used to store the native `<input type=\"search\" />` element since it might be set asynchronously. */\n  private input$ = new BehaviorSubject<ElementRef<HTMLInputElement> | undefined>(undefined);\n\n  @ViewChild('menu', { static: false }) menu!: ElementRef;\n  @ViewChild(CdkConnectedOverlay, { static: false }) overlay!: CdkConnectedOverlay;\n  @ViewChildren(NzCascaderOptionComponent) cascaderItems!: QueryList<NzCascaderOptionComponent>;\n\n  @Input() nzOpen?: boolean;\n  @Input() nzOptions: NzCascaderOption[] | null = [];\n  @Input() nzOptionRender: TemplateRef<{ $implicit: NzCascaderOption; index: number }> | null = null;\n  @Input({ transform: booleanAttribute }) nzShowInput = true;\n  @Input({ transform: booleanAttribute }) nzShowArrow = true;\n  @Input({ transform: booleanAttribute }) nzAllowClear = true;\n  @Input({ transform: booleanAttribute }) nzAutoFocus = false;\n  @Input({ transform: booleanAttribute }) nzChangeOnSelect = false;\n  @Input({ transform: booleanAttribute }) nzDisabled = false;\n  @Input() nzColumnClassName?: string;\n  @Input() nzExpandTrigger: NzCascaderExpandTrigger = 'click';\n  @Input() nzValueProperty: string = 'value';\n  @Input() nzLabelProperty: string = 'label';\n  @Input() nzLabelRender: TemplateRef<typeof this.labelRenderContext> | null = null;\n  @Input() @WithConfig() nzVariant: NzVariant | undefined = undefined;\n  @Input() nzNotFoundContent?: string | TemplateRef<void>;\n  @Input() @WithConfig() nzSize: NzCascaderSize = 'default';\n  @Input() @WithConfig() nzBackdrop = false;\n  @Input() nzShowSearch: boolean | NzShowSearchOptions = false;\n  @Input() nzPlaceHolder: string = '';\n  @Input() nzMenuClassName?: string;\n  @Input() nzMenuStyle: NgStyleInterface | null = null;\n  /**\n   * Duration in milliseconds before opening the menu when the mouse enters the trigger.\n   * @default 150\n   */\n  @Input({ transform: numberAttribute }) nzMouseLeaveDelay: number = 150;\n  /**\n   * Duration in milliseconds before closing the menu when the mouse leaves the trigger.\n   * @default 150\n   */\n  @Input({ transform: numberAttribute }) nzMouseEnterDelay: number = 150;\n  @Input() nzStatus: NzStatus = '';\n  @Input({ transform: booleanAttribute }) nzMultiple: boolean = false;\n  @Input() nzMaxTagCount: number = Infinity;\n  @Input() nzPlacement: NzCascaderPlacement = 'bottomLeft';\n\n  @Input() nzTriggerAction: NzCascaderTriggerType | NzCascaderTriggerType[] = ['click'] as NzCascaderTriggerType[];\n  @Input() nzChangeOn?: (option: NzCascaderOption, level: number) => boolean;\n  @Input() nzLoadData?: (node: NzCascaderOption, index: number) => PromiseLike<NzSafeAny> | Observable<NzSafeAny>;\n  @Input() nzDisplayWith: (nodes: NzCascaderOption[]) => string | undefined = (nodes: NzCascaderOption[]) => {\n    return defaultDisplayRender(nodes.map(n => this.cascaderService.getOptionLabel(n!)));\n  };\n  // TODO: RTL\n  @Input() nzPrefix: string | TemplateRef<void> | null = null;\n  @Input() nzSuffixIcon: string | TemplateRef<void> = 'down';\n  @Input() nzExpandIcon: string | TemplateRef<void> = '';\n\n  get treeService(): NzCascaderTreeService {\n    return this.nzTreeService as NzCascaderTreeService;\n  }\n\n  @Output() readonly nzVisibleChange = new EventEmitter<boolean>();\n  @Output() readonly nzSelectionChange = new EventEmitter<NzCascaderOption[]>();\n  @Output() readonly nzRemoved = new EventEmitter<NzCascaderOption>();\n  @Output() readonly nzClear = new EventEmitter<void>();\n\n  prefixCls: string = 'ant-select';\n  statusCls: NgClassInterface = {};\n  status: NzValidateStatus = '';\n  hasFeedback: boolean = false;\n\n  /**\n   * If the dropdown should show the empty content.\n   * `true` if there's no options.\n   */\n  shouldShowEmpty: boolean = false;\n\n  el: HTMLElement = this.elementRef.nativeElement;\n  readonly menuVisible = signal(false);\n  isLoading = false;\n  labelRenderText?: string;\n  labelRenderContext = {};\n  onChange = Function.prototype;\n  onTouched = Function.prototype;\n  positions: ConnectionPositionPair[] = [...DEFAULT_CASCADER_POSITIONS];\n\n  /**\n   * Dropdown width in pixel.\n   */\n  dropdownWidthStyle?: string;\n  dropdownHeightStyle: 'auto' | '' = '';\n  dropdownPosition: NzCascaderPlacement = 'bottomLeft';\n  isFocused = false;\n\n  locale!: NzCascaderI18nInterface;\n  dir: Direction = 'ltr';\n\n  isComposing = false;\n\n  protected get overlayOrigin(): ElementRef {\n    return this.elementRef;\n  }\n\n  protected readonly finalSize = computed(() => {\n    if (this.formSize?.()) {\n      return this.formSize();\n    }\n    if (this.compactSize) {\n      return this.compactSize();\n    }\n    return this.size();\n  });\n\n  protected readonly finalVariant = computed(() => this.variant() || this.formVariant?.() || 'outlined');\n\n  private size = signal<NzSizeLDSType>(this.nzSize);\n  private readonly variant = signal<NzVariant | undefined>(this.nzVariant);\n\n  private readonly formSize = inject(NZ_FORM_SIZE, { optional: true });\n  private readonly formVariant = inject(NZ_FORM_VARIANT, { optional: true });\n  private compactSize = inject(NZ_SPACE_COMPACT_SIZE, { optional: true });\n  private inputString = '';\n  private isOpening = false;\n  private delayMenuTimer?: ReturnType<typeof setTimeout>;\n  private delaySelectTimer?: ReturnType<typeof setTimeout>;\n  private isNzDisableFirstChange: boolean = true;\n  selectedNodes: NzTreeNode[] = [];\n\n  get inSearchingMode(): boolean {\n    return this.cascaderService.inSearchingMode;\n  }\n\n  set inputValue(inputValue: string) {\n    this.inputString = inputValue;\n    this.toggleSearchingMode(!!inputValue);\n  }\n\n  get inputValue(): string {\n    return this.inputString;\n  }\n\n  private get hasInput(): boolean {\n    return !!this.inputValue;\n  }\n\n  private get hasValue(): boolean {\n    return this.cascaderService.values && this.cascaderService.values.length > 0;\n  }\n\n  get showLabelRender(): boolean {\n    return !this.hasInput && !!this.selectedNodes.length;\n  }\n\n  get showPlaceholder(): boolean {\n    return !(this.hasInput || this.hasValue);\n  }\n\n  get clearIconVisible(): boolean {\n    return this.nzAllowClear && !this.nzDisabled && (this.hasValue || this.hasInput);\n  }\n\n  get isLabelRenderTemplate(): boolean {\n    return !!this.nzLabelRender;\n  }\n\n  private get openControlled(): boolean {\n    return this.nzOpen !== undefined;\n  }\n\n  noAnimation = inject(NzNoAnimationDirective, { host: true, optional: true });\n  nzFormStatusService = inject(NzFormStatusService, { optional: true });\n  private nzFormNoStatusService = inject(NzFormNoStatusService, { optional: true });\n  public cascaderService = inject(NzCascaderService);\n\n  constructor() {\n    super(inject(NzCascaderTreeService));\n    this.cascaderService.withComponent(this);\n    this.renderer.addClass(this.elementRef.nativeElement, 'ant-select');\n    this.renderer.addClass(this.elementRef.nativeElement, 'ant-cascader');\n\n    this.destroyRef.onDestroy(() => {\n      this.clearDelayMenuTimer();\n      this.clearDelaySelectTimer();\n    });\n\n    onConfigChangeEventForComponent(NZ_CONFIG_MODULE_NAME, () => {\n      this.size.set(this.nzSize);\n      this.cdr.markForCheck();\n    });\n  }\n\n  ngOnInit(): void {\n    this.nzFormStatusService?.formStatusChanges\n      .pipe(\n        distinctUntilChanged((pre, cur) => pre.status === cur.status && pre.hasFeedback === cur.hasFeedback),\n        withLatestFrom(this.nzFormNoStatusService ? this.nzFormNoStatusService.noFormStatus : of(false)),\n        map(([{ status, hasFeedback }, noStatus]) => ({ status: noStatus ? '' : status, hasFeedback })),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(({ status, hasFeedback }) => this.setStatusStyles(status, hasFeedback));\n\n    const srv = this.cascaderService;\n\n    srv.$redraw.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      // These operations would not mutate data.\n      this.checkChildren();\n      this.setDisplayLabel();\n      this.cdr.detectChanges();\n      this.reposition();\n      this.setDropdownStyles();\n    });\n\n    srv.$loading.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(loading => {\n      this.isLoading = loading;\n    });\n\n    srv.$nodeSelected.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(node => {\n      if (!node) {\n        this.emitValue([]);\n        this.nzSelectionChange.emit([]);\n      } else {\n        const shouldClose =\n          // keep menu opened if multiple mode\n          !this.nzMultiple &&\n          (node.isLeaf || (this.nzChangeOnSelect && this.nzExpandTrigger === 'hover')) &&\n          !this.openControlled;\n        if (shouldClose) {\n          this.delaySetMenuVisible(false);\n        }\n        this.nzSelectionChange.emit(this.getAncestorOptionList(node));\n        this.cdr.markForCheck();\n      }\n    });\n\n    srv.$quitSearching.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      this.inputValue = '';\n      this.dropdownWidthStyle = '';\n    });\n\n    this.i18nService.localeChange\n      .pipe(startWith(), takeUntilDestroyed(this.destroyRef))\n      .subscribe(() => this.setLocale());\n\n    this.size.set(this.nzSize);\n\n    this.dir = this.directionality.value;\n    this.directionality.change.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      this.dir = this.directionality.value;\n      srv.$redraw.next();\n    });\n\n    this.setupSelectionChangeListener();\n    this.setupChangeListener();\n    this.setupKeydownListener();\n    this.setupFocusListener();\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzOpen, nzStatus, nzSize, nzPlacement, nzOptions, nzVariant } = changes;\n    if (nzOpen && this.openControlled) {\n      this.setMenuVisible(nzOpen.currentValue);\n    }\n    if (nzOptions) {\n      this.updateOptions();\n    }\n    if (nzStatus) {\n      this.setStatusStyles(this.nzStatus, this.hasFeedback);\n    }\n    if (nzSize) {\n      this.size.set(nzSize.currentValue);\n    }\n    if (nzVariant) {\n      this.variant.set(nzVariant.currentValue);\n    }\n    if (nzPlacement) {\n      const { currentValue } = nzPlacement;\n      this.dropdownPosition = currentValue as NzCascaderPlacement;\n      const listOfPlacement = ['bottomLeft', 'topLeft', 'bottomRight', 'topRight'];\n      if (currentValue && listOfPlacement.includes(currentValue)) {\n        this.positions = [POSITION_MAP[currentValue as POSITION_TYPE]];\n      } else {\n        this.positions = listOfPlacement.map(e => POSITION_MAP[e as POSITION_TYPE]);\n      }\n    }\n  }\n\n  registerOnChange(fn: () => {}): void {\n    this.onChange = fn;\n  }\n\n  registerOnTouched(fn: () => {}): void {\n    this.onTouched = fn;\n  }\n\n  writeValue(value: NzSafeAny): void {\n    if (isNotNil(value)) {\n      if (this.nzMultiple) {\n        this.cascaderService.values = toArray(value);\n      } else {\n        this.cascaderService.values = [toArray(value)];\n      }\n      // need clear selected nodes when user set value before updating\n      this.clearSelectedNodes();\n      this.updateSelectedNodes(true, false);\n    } else {\n      this.cascaderService.values = [];\n      this.clearSelectedNodes();\n      this.selectedNodes = [];\n      this.cascaderService.$redraw.next();\n    }\n  }\n\n  private setupSelectionChangeListener(): void {\n    merge(this.nzSelectionChange, this.nzRemoved, this.nzClear)\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(() => {\n        this.updateSelectedNodes();\n        this.emitValue(this.cascaderService.values);\n        this.cascaderService.$redraw.next();\n      });\n  }\n\n  delaySetMenuVisible(visible: boolean, delay: number = 100, setOpening: boolean = false): void {\n    this.clearDelayMenuTimer();\n    if (delay) {\n      if (visible && setOpening) {\n        this.isOpening = true;\n      }\n      this.delayMenuTimer = setTimeout(() => {\n        this.setMenuVisible(visible);\n        this.cdr.detectChanges();\n        this.clearDelayMenuTimer();\n        if (visible) {\n          setTimeout(() => {\n            this.isOpening = false;\n          }, 100);\n        }\n      }, delay);\n    } else {\n      this.setMenuVisible(visible);\n    }\n  }\n\n  setMenuVisible(visible: boolean): void {\n    if (this.nzDisabled || this.menuVisible() === visible) {\n      return;\n    }\n    if (visible) {\n      this.cascaderService.$redraw.next();\n      this.updateSelectedNodes(true);\n      this.scrollToActivatedOptions();\n    } else {\n      this.inputValue = '';\n    }\n\n    this.menuVisible.set(visible);\n    this.nzVisibleChange.emit(visible);\n    this.cdr.detectChanges();\n  }\n\n  private clearDelayMenuTimer(): void {\n    if (this.delayMenuTimer) {\n      clearTimeout(this.delayMenuTimer);\n      this.delayMenuTimer = undefined;\n    }\n  }\n\n  clearSelection(event?: Event): void {\n    if (event) {\n      event.preventDefault();\n      event.stopPropagation();\n    }\n\n    this.clearSelectedNodes();\n    this.labelRenderText = '';\n    this.labelRenderContext = {};\n    this.inputValue = '';\n    if (!this.openControlled) {\n      this.setMenuVisible(false);\n    }\n    this.cascaderService.clear();\n    this.nzClear.emit();\n  }\n\n  clearSelectedNodes(): void {\n    this.selectedNodes.forEach(node => {\n      this.removeSelected(node, false);\n    });\n  }\n\n  emitValue(values: NzSafeAny[] | null): void {\n    if (this.nzMultiple) {\n      this.onChange(values);\n    } else {\n      this.onChange(values?.length ? values[0] : []);\n    }\n  }\n\n  /**\n   * @internal\n   */\n  getSubmitValue(): NzSafeAny[] {\n    if (this.nzMultiple) {\n      return this.cascaderService.values;\n    } else {\n      return this.cascaderService.values?.length ? this.cascaderService.values[0] : [];\n    }\n  }\n\n  focus(): void {\n    if (!this.isFocused) {\n      (this.input?.nativeElement || this.el).focus();\n      this.isFocused = true;\n    }\n  }\n\n  blur(): void {\n    if (this.isFocused) {\n      (this.input?.nativeElement || this.el).blur();\n      this.isFocused = false;\n    }\n  }\n\n  handleInputBlur(): void {\n    this.menuVisible() ? this.focus() : this.blur();\n  }\n\n  handleInputFocus(): void {\n    this.focus();\n  }\n\n  isComposingChange(isComposing: boolean): void {\n    this.isComposing = isComposing;\n  }\n\n  @HostListener('click')\n  onTriggerClick(): void {\n    if (this.nzDisabled || this.openControlled) {\n      return;\n    }\n    if (this.nzShowSearch) {\n      this.focus();\n    }\n    if (this.isActionTrigger('click')) {\n      this.delaySetMenuVisible(!this.menuVisible(), 100);\n    }\n    this.onTouched();\n  }\n\n  @HostListener('mouseenter')\n  onTriggerMouseEnter(): void {\n    if (this.nzDisabled || !this.isActionTrigger('hover') || this.openControlled) {\n      return;\n    }\n\n    this.delaySetMenuVisible(true, this.nzMouseEnterDelay, true);\n  }\n\n  @HostListener('mouseleave', ['$event'])\n  onTriggerMouseLeave(event: MouseEvent): void {\n    if (\n      this.nzDisabled ||\n      !this.menuVisible() ||\n      this.isOpening ||\n      !this.isActionTrigger('hover') ||\n      this.openControlled\n    ) {\n      event.preventDefault();\n      return;\n    }\n    const mouseTarget = event.relatedTarget as HTMLElement;\n    const hostEl = this.el;\n    const menuEl = this.menu && (this.menu.nativeElement as HTMLElement);\n    if (hostEl.contains(mouseTarget) || (menuEl && menuEl.contains(mouseTarget))) {\n      return;\n    }\n    this.delaySetMenuVisible(false, this.nzMouseLeaveDelay);\n  }\n\n  onOptionMouseEnter(node: NzTreeNode, columnIndex: number, event: Event): void {\n    event.preventDefault();\n    if (this.nzExpandTrigger === 'hover') {\n      if (!node.isLeaf) {\n        this.delaySetOptionActivated(node, columnIndex, false);\n      } else {\n        this.cascaderService.setNodeDeactivatedSinceColumn(columnIndex);\n      }\n    }\n  }\n\n  onOptionMouseLeave(node: NzTreeNode, _columnIndex: number, event: Event): void {\n    event.preventDefault();\n    if (this.nzExpandTrigger === 'hover' && !node.isLeaf) {\n      this.clearDelaySelectTimer();\n    }\n  }\n\n  /**\n   * Get ancestor options of a node\n   */\n  protected getAncestorOptionList(node: NzTreeNode | null): NzCascaderOption[] {\n    const ancestors = this.treeService.getAncestorNodeList(node);\n    return this.treeService.toOptions(ancestors);\n  }\n\n  updateSelectedNodes(init: boolean = false, updateValue = true): void {\n    const value = this.cascaderService.values;\n    const multiple = this.nzMultiple;\n\n    /**\n     * Update selected nodes and emit value\n     * @param shouldUpdateValue if false, only update selected nodes\n     */\n    const updateNodesAndValue = (shouldUpdateValue: boolean): void => {\n      this.selectedNodes = [...(this.nzMultiple ? this.getCheckedNodeList() : this.getSelectedNodeList())].sort(\n        (a, b) => {\n          const indexA = value.indexOf(a.key);\n          const indexB = value.indexOf(b.key);\n          if (indexA !== -1 && indexB !== -1) {\n            return indexA - indexB;\n          }\n          if (indexA !== -1) {\n            return -1;\n          }\n          if (indexB !== -1) {\n            return 1;\n          }\n          return 0;\n        }\n      );\n      if (shouldUpdateValue) {\n        this.cascaderService.values = this.selectedNodes.map(node =>\n          this.getAncestorOptionList(node).map(o => this.cascaderService.getOptionValue(o))\n        );\n      }\n      this.cascaderService.$redraw.next();\n    };\n\n    if (init) {\n      const defaultValue = value[0];\n      const lastColumnIndex = defaultValue?.length ? defaultValue.length - 1 : 0;\n      this.treeService.fieldNames = {\n        value: this.nzValueProperty,\n        label: this.nzLabelProperty\n      };\n      this.treeService.isMultiple = multiple;\n      this.treeService.isCheckStrictly = false;\n\n      /**\n       * check whether the node is checked or selected according to the value\n       */\n      const checkNodeStates = (): void => {\n        if (multiple) {\n          this.treeService.conductCheckPaths(value, this.treeService.isCheckStrictly);\n        } else {\n          this.treeService.conductSelectedPaths(value);\n        }\n      };\n\n      const initColumnWithIndex = (columnIndex = 0): void => {\n        const activatedOptionSetter = (): void => {\n          const currentValue = defaultValue?.[columnIndex];\n\n          if (!isNotNil(currentValue)) {\n            this.cascaderService.$redraw.next();\n            return;\n          }\n\n          const node =\n            this.cascaderService.columns[columnIndex].find(\n              n => this.cascaderService.getOptionValue(n.origin) === currentValue\n            ) || null;\n\n          if (isNotNil(node)) {\n            this.cascaderService.setNodeActivated(node, columnIndex, false, multiple, false);\n\n            // Load next level options till leaf node\n            if (columnIndex < lastColumnIndex) {\n              initColumnWithIndex(columnIndex + 1);\n            }\n          }\n\n          checkNodeStates();\n          updateNodesAndValue(false);\n        };\n\n        if (this.cascaderService.isLoaded(columnIndex) || !this.nzLoadData) {\n          activatedOptionSetter();\n        } else {\n          const node = this.cascaderService.activatedNodes[columnIndex - 1];\n          this.cascaderService.loadChildren(node, columnIndex - 1, activatedOptionSetter);\n        }\n      };\n\n      // if nzLoadData set, load first level data asynchronously\n      if (this.nzLoadData) {\n        initColumnWithIndex();\n      } else {\n        const nodes = this.coerceTreeNodes(this.nzOptions || []);\n        this.treeService.initTree(nodes);\n        this.cascaderService.setColumnData(nodes, 0);\n        initColumnWithIndex();\n      }\n    }\n\n    updateNodesAndValue(updateValue);\n  }\n\n  onOptionClick(node: NzTreeNode, columnIndex: number, event: Event): void {\n    if (event) {\n      event.preventDefault();\n    }\n    if (node && node.isDisabled) {\n      return;\n    }\n\n    this.el.focus();\n\n    // for multiple mode, click the leaf node can be seen as check action\n    if (this.nzMultiple && node.isLeaf) {\n      this.onOptionCheck(node, columnIndex, true);\n    } else {\n      this.inSearchingMode\n        ? this.cascaderService.setSearchOptionSelected(node, this.nzMultiple)\n        : this.cascaderService.setNodeActivated(node, columnIndex, !this.nzMultiple);\n    }\n  }\n\n  onOptionCheck(node: NzTreeNode, columnIndex: number, performActivate = false): void {\n    if (!this.nzMultiple || node.isDisabled || node.isDisableCheckbox) {\n      return;\n    }\n\n    node.isChecked = !node.isChecked;\n    node.isHalfChecked = false;\n    this.treeService.setCheckedNodeList(node);\n    this.treeService.conduct(node, this.treeService.isCheckStrictly);\n\n    if (this.inSearchingMode) {\n      this.cascaderService.setSearchOptionSelected(node, true);\n    } else if (performActivate) {\n      this.cascaderService.setNodeActivated(node, columnIndex, true, true);\n    } else {\n      // only update selected nodes and not set node activated by default\n      this.cascaderService.setNodeSelected(node, columnIndex, true);\n    }\n  }\n\n  removeSelected(node: NzTreeNode, emitEvent = true): void {\n    node.isSelected = false;\n    node.isChecked = false;\n    if (this.nzMultiple) {\n      this.treeService.conduct(node, this.treeService.isCheckStrictly);\n    }\n    this.treeService.setSelectedNodeList(node, this.nzMultiple);\n    if (emitEvent) {\n      this.nzRemoved.emit(node.origin);\n    }\n  }\n\n  onClickOutside(event: MouseEvent): void {\n    const target = _getEventTarget(event);\n    if (!this.el.contains(target as Node) && !this.openControlled) {\n      this.closeMenu();\n    }\n  }\n\n  onPositionChange(position: ConnectedOverlayPositionChange): void {\n    const placement = getPlacementName(position);\n    this.dropdownPosition = placement as NzSelectPlacementType;\n  }\n\n  private updateOptions(): void {\n    const nodes = this.coerceTreeNodes(this.nzOptions || []);\n    this.treeService.initTree(nodes);\n    this.cascaderService.setColumnData(nodes, 0);\n    this.updateSelectedNodes(true);\n\n    if (this.inSearchingMode) {\n      this.cascaderService.setSearchingMode(this.inSearchingMode);\n      this.cascaderService.prepareSearchOptions(this.inputValue);\n    }\n  }\n\n  private isActionTrigger(action: 'click' | 'hover'): boolean {\n    return typeof this.nzTriggerAction === 'string'\n      ? this.nzTriggerAction === action\n      : this.nzTriggerAction.indexOf(action) !== -1;\n  }\n\n  private onEnter(): void {\n    const columnIndex = Math.max(this.cascaderService.activatedNodes.length - 1, 0);\n    const node = this.cascaderService.activatedNodes[columnIndex];\n    if (node && !node.isDisabled) {\n      this.nzMultiple\n        ? this.onOptionCheck(node, columnIndex, true)\n        : this.inSearchingMode\n          ? this.cascaderService.setSearchOptionSelected(node)\n          : this.cascaderService.setNodeActivated(node, columnIndex, true);\n    }\n  }\n\n  private moveUpOrDown(isUp: boolean): void {\n    const columnIndex = Math.max(this.cascaderService.activatedNodes.length - 1, 0);\n    const activatedNode = this.cascaderService.activatedNodes[columnIndex];\n    const options = this.cascaderService.columns[columnIndex] || [];\n    const length = options.length;\n    let nextIndex = -1;\n    if (!activatedNode) {\n      // Not selected options in this column\n      nextIndex = isUp ? length : -1;\n    } else {\n      nextIndex = options.indexOf(activatedNode);\n    }\n\n    while (true) {\n      nextIndex = isUp ? nextIndex - 1 : nextIndex + 1;\n      if (nextIndex < 0 || nextIndex >= length) {\n        break;\n      }\n      const nextOption = options[nextIndex];\n      if (!nextOption || nextOption.isDisabled || nextOption.isDisableCheckbox) {\n        continue;\n      }\n      this.cascaderService.setNodeActivated(nextOption, columnIndex);\n      break;\n    }\n  }\n\n  private prevColumn(): void {\n    if (this.cascaderService.activatedNodes.length) {\n      this.cascaderService.activatedNodes.pop(); // Remove the last one\n      this.cascaderService.setNodeDeactivatedSinceColumn(this.cascaderService.activatedNodes.length); // collapse menu\n      if (!this.cascaderService.activatedNodes.length) {\n        this.setMenuVisible(false);\n      }\n    }\n  }\n\n  private nextColumn(): void {\n    const length = this.cascaderService.activatedNodes.length;\n    const options = this.cascaderService.columns[length];\n    if (options && options.length) {\n      const nextOpt = options.find(o => !o.isDisabled && !o.isDisableCheckbox);\n      if (nextOpt) {\n        this.cascaderService.setNodeActivated(nextOpt, length);\n      }\n    }\n  }\n\n  private clearDelaySelectTimer(): void {\n    if (this.delaySelectTimer) {\n      clearTimeout(this.delaySelectTimer);\n      this.delaySelectTimer = undefined;\n    }\n  }\n\n  private delaySetOptionActivated(node: NzTreeNode, columnIndex: number, performSelect: boolean): void {\n    this.clearDelaySelectTimer();\n    this.delaySelectTimer = setTimeout(() => {\n      this.cascaderService.setNodeActivated(node, columnIndex, performSelect, this.nzMultiple);\n      this.delaySelectTimer = undefined;\n    }, 150);\n  }\n\n  private toggleSearchingMode(toSearching: boolean): void {\n    if (this.inSearchingMode !== toSearching) {\n      this.cascaderService.setSearchingMode(toSearching);\n    }\n\n    if (this.inSearchingMode) {\n      this.cascaderService.prepareSearchOptions(this.inputValue);\n    }\n  }\n\n  isOptionActivated(node: NzTreeNode, index: number): boolean {\n    return this.cascaderService.activatedNodes[index] === node;\n  }\n\n  setDisabledState(isDisabled: boolean): void {\n    this.nzDisabled = (this.isNzDisableFirstChange && this.nzDisabled) || isDisabled;\n    this.isNzDisableFirstChange = false;\n    if (this.nzDisabled) {\n      this.closeMenu();\n    }\n  }\n\n  closeMenu(): void {\n    this.blur();\n    this.clearDelayMenuTimer();\n    this.setMenuVisible(false);\n    // if select none, clear previous state\n    if (!this.hasValue && this.cascaderService.columns.length) {\n      this.cascaderService.dropBehindColumns(0);\n    }\n  }\n\n  /**\n   * Reposition the cascader panel. When a menu opens, the cascader expands\n   * and may exceed the boundary of browser's window.\n   */\n  private reposition(): void {\n    if (this.overlay && this.overlay.overlayRef && this.menuVisible()) {\n      Promise.resolve().then(() => {\n        this.overlay.overlayRef.updatePosition();\n        this.cdr.markForCheck();\n      });\n    }\n  }\n\n  /**\n   * When a cascader options is changed, a child needs to know that it should re-render.\n   */\n  private checkChildren(): void {\n    if (this.cascaderItems) {\n      this.cascaderItems.forEach(item => item.markForCheck());\n    }\n  }\n\n  private setDisplayLabel(): void {\n    if (this.nzMultiple) {\n      return;\n    }\n\n    const node = this.selectedNodes.length ? this.selectedNodes[0] : null;\n    const selectedOptions = this.getAncestorOptionList(node);\n    const labels: string[] = selectedOptions.map(o => this.cascaderService.getOptionLabel(o));\n\n    if (this.isLabelRenderTemplate) {\n      this.labelRenderContext = { labels, selectedOptions };\n    }\n    this.labelRenderText = defaultDisplayRender.call(this, labels);\n  }\n\n  private setDropdownStyles(): void {\n    const firstColumn = this.cascaderService.columns[0];\n\n    this.shouldShowEmpty =\n      (this.inSearchingMode && (!firstColumn || !firstColumn.length)) || // Should show empty when there's no searching result\n      (!(this.nzOptions && this.nzOptions.length) && !this.nzLoadData); // Should show when there's no options and developer does not use nzLoadData\n    this.dropdownHeightStyle = this.shouldShowEmpty ? 'auto' : '';\n\n    if (this.input) {\n      this.dropdownWidthStyle =\n        this.inSearchingMode || this.shouldShowEmpty ? `${this.selectContainer.nativeElement.offsetWidth}px` : '';\n    }\n  }\n\n  private setStatusStyles(status: NzValidateStatus, hasFeedback: boolean): void {\n    // set inner status\n    this.status = status;\n    this.hasFeedback = hasFeedback;\n    this.cdr.markForCheck();\n    // render status if nzStatus is set\n    this.statusCls = getStatusClassNames(this.prefixCls, status, hasFeedback);\n    Object.keys(this.statusCls).forEach(status => {\n      if (this.statusCls[status]) {\n        this.renderer.addClass(this.elementRef.nativeElement, status);\n      } else {\n        this.renderer.removeClass(this.elementRef.nativeElement, status);\n      }\n    });\n  }\n\n  private setLocale(): void {\n    this.locale = this.i18nService.getLocaleData('global');\n    this.cdr.markForCheck();\n  }\n\n  private scrollToActivatedOptions(): void {\n    // The `scrollIntoView` is a native DOM API, which doesn't require Angular to run\n    // a change detection when a promise microtask is resolved.\n    this.ngZone.runOutsideAngular(() => {\n      Promise.resolve().then(() => {\n        // scroll only until option menu view is ready\n        this.cascaderItems\n          .toArray()\n          .filter(e => e.activated)\n          .forEach(e => {\n            e.nativeElement.scrollIntoView({ block: 'start', inline: 'nearest' });\n          });\n      });\n    });\n  }\n\n  private setupChangeListener(): void {\n    this.input$\n      .pipe(\n        switchMap(input => fromEventOutsideAngular(input?.nativeElement, 'change')),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(event => event.stopPropagation());\n  }\n\n  private setupFocusListener(): void {\n    this.input$\n      .pipe(\n        switchMap(input => fromEventOutsideAngular(input?.nativeElement, 'focus')),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(() => this.handleInputFocus());\n\n    this.input$\n      .pipe(\n        switchMap(input => fromEventOutsideAngular(input?.nativeElement, 'blur')),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(() => this.handleInputBlur());\n  }\n\n  private setupKeydownListener(): void {\n    fromEventOutsideAngular<KeyboardEvent>(this.el, 'keydown')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(event => {\n        const keyCode = event.keyCode;\n\n        if (\n          keyCode !== DOWN_ARROW &&\n          keyCode !== UP_ARROW &&\n          keyCode !== LEFT_ARROW &&\n          keyCode !== RIGHT_ARROW &&\n          keyCode !== ENTER &&\n          keyCode !== BACKSPACE &&\n          keyCode !== ESCAPE\n        ) {\n          return;\n        }\n\n        // Press any keys above to reopen menu.\n        if (!this.menuVisible() && keyCode !== BACKSPACE && keyCode !== ESCAPE && !this.openControlled) {\n          // The `setMenuVisible` runs `detectChanges()`, so we don't need to run `markForCheck()` additionally.\n          return this.ngZone.run(() => this.setMenuVisible(true));\n        }\n\n        // Make these keys work as default in searching mode.\n        if (this.inSearchingMode && (keyCode === BACKSPACE || keyCode === LEFT_ARROW || keyCode === RIGHT_ARROW)) {\n          return;\n        }\n\n        if (!this.menuVisible()) {\n          return;\n        }\n\n        event.preventDefault();\n\n        this.ngZone.run(() => {\n          // Interact with the component.\n          switch (keyCode) {\n            case DOWN_ARROW:\n              this.moveUpOrDown(false);\n              break;\n            case UP_ARROW:\n              this.moveUpOrDown(true);\n              break;\n            case LEFT_ARROW:\n              if (this.dir === 'rtl') {\n                this.nextColumn();\n              } else {\n                this.prevColumn();\n              }\n              break;\n            case RIGHT_ARROW:\n              if (this.dir === 'rtl') {\n                this.prevColumn();\n              } else {\n                this.nextColumn();\n              }\n              break;\n            case ENTER:\n              this.onEnter();\n              break;\n            case BACKSPACE:\n              this.prevColumn();\n              break;\n          }\n          // `@HostListener`s run `markForCheck()` internally before calling the actual handler so\n          // we call `markForCheck()` to be backwards-compatible.\n          this.cdr.markForCheck();\n        });\n      });\n  }\n}\n"
  },
  {
    "path": "components/cascader/cascader.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzCascaderComponent } from './cascader.component';\n\n@NgModule({\n  imports: [NzCascaderComponent],\n  exports: [NzCascaderComponent]\n})\nexport class NzCascaderModule {}\n"
  },
  {
    "path": "components/cascader/cascader.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { DestroyRef, inject, Injectable } from '@angular/core';\nimport { BehaviorSubject, Subject } from 'rxjs';\nimport { finalize } from 'rxjs/operators';\n\nimport { NzTreeNode, NzTreeNodeOptions } from 'ng-zorro-antd/core/tree';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { isNotNil, wrapIntoObservable } from 'ng-zorro-antd/core/util';\n\nimport { isShowSearchObject, NzCascaderComponentAsSource, NzCascaderFilter, NzCascaderOption } from './typings';\nimport { isChildNode, isParentNode } from './utils';\n\n/**\n * All data is stored and parsed in NzCascaderService.\n */\n@Injectable()\nexport class NzCascaderService {\n  private destroyRef = inject(DestroyRef);\n  /** Activated options in each column. */\n  activatedNodes: NzTreeNode[] = [];\n\n  /** An array to store cascader items arranged in different layers. */\n  columns: NzTreeNode[][] = [];\n\n  /** If user has entered searching mode. */\n  inSearchingMode = false;\n\n  values: NzSafeAny[] = [];\n\n  /**\n   * Emit an event when loading state changes.\n   * Emit true if nzOptions is loading by `nzLoadData`.\n   */\n  readonly $loading = new BehaviorSubject<boolean>(false);\n\n  /**\n   * Emit an event to notify cascader it needs to redraw because activated or\n   * selected options are changed.\n   */\n  readonly $redraw = new Subject<void>();\n\n  /**\n   * Emit an event when an option gets selected.\n   * Emit true if a leaf options is selected.\n   */\n  readonly $nodeSelected = new Subject<NzTreeNode | null>();\n\n  /**\n   * Emit an event to notify cascader it needs to quit searching mode.\n   * Only emit when user do select a searching option.\n   */\n  readonly $quitSearching = new Subject<void>();\n\n  /** To hold columns before entering searching mode. */\n  private columnSnapshot: NzTreeNode[][] = [[]];\n\n  private cascaderComponent!: NzCascaderComponentAsSource;\n\n  private searchOptionPathMap = new Map<NzTreeNode, NzCascaderOption[]>();\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      this.$redraw.complete();\n      this.$quitSearching.complete();\n      this.$nodeSelected.complete();\n      this.$loading.complete();\n      this.searchOptionPathMap.clear();\n    });\n  }\n\n  /** Return cascader options in the first layer. */\n  get nzOptions(): NzCascaderOption[] {\n    return this.cascaderComponent.treeService.toOptions(this.columns[0] || []);\n  }\n\n  /**\n   * Bind cascader component so this service could use inputs.\n   */\n  withComponent(cascaderComponent: NzCascaderComponentAsSource): void {\n    this.cascaderComponent = cascaderComponent;\n  }\n\n  /**\n   * Try to set an option as activated.\n   *\n   * @param node Cascader option node\n   * @param columnIndex Of which column this option is in\n   * @param performSelect Select\n   * @param multiple Multiple mode\n   * @param loadingChildren Try to load children asynchronously.\n   */\n  setNodeActivated(\n    node: NzTreeNode,\n    columnIndex: number,\n    performSelect: boolean = false,\n    multiple: boolean = false,\n    loadingChildren: boolean = true\n  ): void {\n    if (node.isDisabled) {\n      return;\n    }\n\n    this.activatedNodes[columnIndex] = node;\n    this.trackAncestorActivatedNodes(columnIndex);\n    this.dropBehindActivatedNodes(columnIndex);\n\n    if (isParentNode(node)) {\n      // Parent option that has children.\n      this.setColumnData(node.children!, columnIndex + 1);\n    } else if (!node.isLeaf && loadingChildren) {\n      // Parent option that should try to load children asynchronously.\n      this.loadChildren(node, columnIndex);\n    } else if (node.isLeaf) {\n      // Leaf option.\n      this.dropBehindColumns(columnIndex);\n    }\n\n    // Actually perform selection to make an options not only activated but also selected.\n    if (performSelect && node.isSelectable) {\n      this.setNodeSelected(node, columnIndex, multiple);\n    }\n\n    this.$redraw.next();\n  }\n\n  /**\n   * Set an option as selected.\n   * @param node\n   * @param index\n   * @param multiple\n   */\n  setNodeSelected(node: NzTreeNode, index: number, multiple: boolean = false): void {\n    const changeOn = this.cascaderComponent.nzChangeOn;\n    const shouldPerformSelection = (o: NzCascaderOption, i: number): boolean =>\n      typeof changeOn === 'function' ? changeOn(o, i) : false;\n\n    if (\n      multiple ||\n      node.isLeaf ||\n      this.cascaderComponent.nzChangeOnSelect ||\n      shouldPerformSelection(node.origin, index)\n    ) {\n      node.isSelected = true;\n      this.cascaderComponent.treeService.setSelectedNodeList(node, multiple);\n      this.cascaderComponent.updateSelectedNodes();\n      this.$redraw.next();\n      this.$nodeSelected.next(node);\n    }\n  }\n\n  setNodeDeactivatedSinceColumn(column: number): void {\n    this.dropBehindActivatedNodes(column - 1);\n    this.dropBehindColumns(column);\n    this.$redraw.next();\n  }\n\n  /**\n   * Set a searching option as selected, finishing up things.\n   *\n   * @param node\n   * @param multiple\n   */\n  setSearchOptionSelected(node: NzTreeNode, multiple = false): void {\n    this.setNodeSelected(node, node.level, multiple);\n\n    setTimeout(() => {\n      // Reset data and tell UI only to remove input and reset dropdown width style.\n      this.$quitSearching.next();\n      this.$redraw.next();\n    }, 200);\n  }\n\n  /**\n   * Reset node's `title` and `disabled` status and clear `searchOptionPathMap`.\n   */\n  private clearSearchOptions(): void {\n    for (const node of this.searchOptionPathMap.keys()) {\n      node.isDisabled = node.origin.disabled || false;\n      node.title = this.getOptionLabel(node.origin);\n    }\n    this.searchOptionPathMap.clear();\n  }\n\n  /**\n   * Filter cascader options to reset `columns`.\n   *\n   * @param searchValue The string user wants to search.\n   */\n  prepareSearchOptions(searchValue: string): void {\n    const results: NzTreeNode[] = []; // Search results only have one layer.\n    const path: NzTreeNode[] = [];\n    const defaultFilter: NzCascaderFilter = (i, p) =>\n      p.some(o => {\n        const label = this.getOptionLabel(o);\n        return !!label && label.indexOf(i) !== -1;\n      });\n    const showSearch = this.cascaderComponent.nzShowSearch;\n    const filter = isShowSearchObject(showSearch) && showSearch.filter ? showSearch.filter : defaultFilter;\n    const sorter = isShowSearchObject(showSearch) && showSearch.sorter ? showSearch.sorter : null;\n    const loopChild = (node: NzTreeNode, forceDisabled = false): void => {\n      path.push(node);\n      const cPath = this.cascaderComponent.treeService.toOptions(path);\n      if (filter(searchValue, cPath)) {\n        this.searchOptionPathMap.set(node, cPath);\n        node.isDisabled = forceDisabled || node.isDisabled;\n        node.title = cPath.map(p => this.getOptionLabel(p)).join(' / ');\n        results.push(node);\n      }\n      path.pop();\n    };\n    const loopParent = (node: NzTreeNode, forceDisabled = false): void => {\n      const disabled = forceDisabled || node.isDisabled;\n      path.push(node);\n      node.children!.forEach(sNode => {\n        if (!sNode.isLeaf) {\n          loopParent(sNode, disabled);\n        }\n        if (sNode.isLeaf || !sNode.children || !sNode.children.length) {\n          loopChild(sNode, disabled);\n        }\n      });\n      path.pop();\n    };\n\n    if (!this.columnSnapshot.length) {\n      this.columns = [[]];\n      return;\n    }\n\n    this.columnSnapshot[0].forEach(o => (isChildNode(o) ? loopChild(o) : loopParent(o)));\n\n    if (sorter) {\n      results.sort((a, b) => sorter(this.searchOptionPathMap.get(a)!, this.searchOptionPathMap.get(b)!, searchValue));\n    }\n\n    this.columns = [results];\n    this.$redraw.next(); // Search results may be empty, so should redraw.\n  }\n\n  /**\n   * Set searching mode by UI. It deals with things not directly related to UI.\n   *\n   * @param toSearching If this cascader is entering searching mode\n   */\n  setSearchingMode(toSearching: boolean): void {\n    this.inSearchingMode = toSearching;\n\n    if (toSearching) {\n      this.clearSearchOptions(); // if reset nzOptions when searching, should clear searchOptionPathMap\n      this.columnSnapshot = [...this.columns];\n      this.activatedNodes = [];\n    } else {\n      // User quit searching mode without selecting an option.\n      this.clearSearchOptions();\n      this.activatedNodes = [];\n\n      setTimeout(() => {\n        this.columns = [...this.columnSnapshot];\n        if (this.cascaderComponent.selectedNodes.length) {\n          const activatedNode = this.cascaderComponent.selectedNodes[0];\n          const columnIndex = activatedNode.level;\n          this.activatedNodes[columnIndex] = activatedNode;\n          this.trackAncestorActivatedNodes(columnIndex);\n          this.trackAncestorColumnData(columnIndex);\n        }\n        this.$redraw.next();\n      });\n    }\n\n    this.$redraw.next();\n  }\n\n  /**\n   * Clear selected options.\n   */\n  clear(): void {\n    this.values = [];\n    this.activatedNodes = [];\n    this.dropBehindColumns(0);\n    this.$redraw.next();\n    this.$nodeSelected.next(null);\n  }\n\n  getOptionLabel(o: NzCascaderOption): string {\n    return o[this.cascaderComponent.nzLabelProperty || 'label'] as string;\n  }\n\n  getOptionValue(o: NzCascaderOption): NzSafeAny {\n    return o[this.cascaderComponent.nzValueProperty || 'value'];\n  }\n\n  /**\n   * Try to insert options into a column.\n   *\n   * @param nodes Options to insert\n   * @param columnIndex Position\n   */\n  setColumnData(nodes: NzTreeNode[], columnIndex: number): void {\n    this.columns[columnIndex] = nodes;\n    this.dropBehindColumns(columnIndex);\n  }\n\n  /**\n   * Set all columns data according to activate option's path\n   */\n  private trackAncestorColumnData(startIndex: number): void {\n    const node = this.activatedNodes[startIndex];\n    if (!node) {\n      return;\n    }\n\n    this.dropBehindColumns(startIndex);\n    for (let i = 0; i < startIndex; i++) {\n      this.columns[i + 1] = this.activatedNodes[i].children;\n    }\n  }\n\n  /**\n   * Set all ancestor options as activated.\n   */\n  private trackAncestorActivatedNodes(startIndex: number): void {\n    for (let i = startIndex - 1; i >= 0; i--) {\n      if (!this.activatedNodes[i]) {\n        this.activatedNodes[i] = this.activatedNodes[i + 1].parentNode!;\n      }\n    }\n  }\n\n  private dropBehindActivatedNodes(lastReserveIndex: number): void {\n    this.activatedNodes = this.activatedNodes.splice(0, lastReserveIndex + 1);\n  }\n\n  dropBehindColumns(lastReserveIndex: number): void {\n    if (lastReserveIndex < this.columns.length - 1) {\n      this.columns = this.columns.slice(0, lastReserveIndex + 1);\n    }\n  }\n\n  /**\n   * Load children of an option asynchronously.\n   */\n  loadChildren(node: NzTreeNode | null, columnIndex: number, onLoaded?: (options: NzCascaderOption[]) => void): void {\n    const isRoot = columnIndex < 0 || !isNotNil(node);\n    const option: NzCascaderOption = node?.origin || {};\n    const loadFn = this.cascaderComponent.nzLoadData;\n\n    if (loadFn) {\n      // If there isn't any option in columns.\n      this.$loading.next(isRoot);\n\n      if (node) {\n        node.isLoading = true;\n      }\n\n      wrapIntoObservable(loadFn(option, columnIndex))\n        .pipe(\n          finalize(() => {\n            node && (node.isLoading = false);\n            this.$loading.next(false);\n            this.$redraw.next();\n          })\n        )\n        .subscribe({\n          next: () => {\n            if (option.children) {\n              if (!isRoot) {\n                const nodes = option.children.map(o => new NzTreeNode(o as NzTreeNodeOptions, node));\n                node.children = nodes;\n                this.setColumnData(nodes, columnIndex + 1);\n              } else {\n                // If it's root node, we should initialize the tree.\n                const nodes = this.cascaderComponent.coerceTreeNodes(option.children);\n                this.cascaderComponent.treeService.initTree(nodes);\n                this.setColumnData(nodes, 0);\n              }\n              onLoaded?.(option.children);\n            }\n          },\n          error: () => {\n            node && (node.isLeaf = true);\n          }\n        });\n    }\n  }\n\n  isLoaded(index: number): boolean {\n    return !!this.columns[index] && this.columns[index].length > 0;\n  }\n}\n"
  },
  {
    "path": "components/cascader/cascader.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport {\n  BACKSPACE,\n  COMMA,\n  DELETE,\n  DOWN_ARROW,\n  END,\n  ENTER,\n  ESCAPE,\n  HOME,\n  LEFT_ARROW,\n  NINE,\n  O,\n  PAGE_DOWN,\n  PAGE_UP,\n  RIGHT_ARROW,\n  SPACE,\n  TAB,\n  UP_ARROW,\n  ZERO\n} from '@angular/cdk/keycodes';\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport {\n  Component,\n  DebugElement,\n  inject,\n  provideZoneChangeDetection,\n  signal,\n  TemplateRef,\n  ViewChild,\n  type WritableSignal\n} from '@angular/core';\nimport { ComponentFixture, fakeAsync, flush, TestBed, inject as testingInject, tick } from '@angular/core/testing';\nimport { FormBuilder, FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\n\nimport { NzDemoCascaderMultipleComponent } from 'ng-zorro-antd/cascader/demo/multiple';\nimport { provideNzNoAnimation } from 'ng-zorro-antd/core/animation';\nimport { NZ_FORM_SIZE, NZ_FORM_VARIANT } from 'ng-zorro-antd/core/form';\nimport {\n  createFakeEvent,\n  dispatchFakeEvent,\n  dispatchKeyboardEvent,\n  dispatchMouseEvent\n} from 'ng-zorro-antd/core/testing';\nimport { NzSafeAny, NzStatus, NzVariant, type NzSizeLDSType } from 'ng-zorro-antd/core/types';\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\nimport { NzSelectItemComponent } from 'ng-zorro-antd/select';\nimport { NZ_SPACE_COMPACT_SIZE } from 'ng-zorro-antd/space';\n\nimport { NzCascaderComponent } from './cascader.component';\nimport { NzCascaderModule } from './cascader.module';\nimport {\n  NzCascaderExpandTrigger,\n  NzCascaderOption,\n  NzCascaderPlacement,\n  NzCascaderSize,\n  NzCascaderTriggerType,\n  NzShowSearchOptions\n} from './typings';\n\ndescribe('cascader', () => {\n  let overlayContainer: OverlayContainer;\n  let overlayContainerElement: HTMLElement;\n\n  function getItemAtColumnAndRow(column: number, row: number): HTMLElement | null {\n    if (row === -1) {\n      return overlayContainerElement.querySelector(\n        `.ant-cascader-menu:nth-child(${column}) .ant-cascader-menu-item:last-child`\n      );\n    }\n\n    return overlayContainerElement.querySelector(\n      `.ant-cascader-menu:nth-child(${column}) .ant-cascader-menu-item:nth-child(${row})`\n    );\n  }\n\n  function getAllColumns(): NodeListOf<Element> {\n    return overlayContainerElement.querySelectorAll(`.ant-cascader-menu`);\n  }\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideNzNoAnimation(), provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(\n    testingInject([OverlayContainer], (currentOverlayContainer: OverlayContainer) => {\n      overlayContainer = currentOverlayContainer;\n      overlayContainerElement = currentOverlayContainer.getContainerElement();\n    })\n  );\n\n  afterEach(\n    testingInject([OverlayContainer], (currentOverlayContainer: OverlayContainer) => {\n      currentOverlayContainer.ngOnDestroy();\n      overlayContainer.ngOnDestroy();\n    })\n  );\n\n  describe('default', () => {\n    let fixture: ComponentFixture<NzDemoCascaderDefaultComponent>;\n    let cascader: DebugElement;\n    let testComponent: NzDemoCascaderDefaultComponent;\n\n    function getLabelElement(): HTMLElement | null {\n      return cascader.nativeElement.querySelector('.ant-select-selection-item');\n    }\n\n    function getLabelText(): string {\n      return cascader.nativeElement.querySelector('.ant-select-selection-item').innerText.trim();\n    }\n\n    function getPlaceholder(): string {\n      return cascader.nativeElement.querySelector('.ant-select-selection-placeholder').innerText.trim();\n    }\n\n    function getInputEl(): HTMLElement {\n      return cascader.nativeElement.querySelector('input')!;\n    }\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzDemoCascaderDefaultComponent);\n      testComponent = fixture.debugElement.componentInstance;\n      cascader = fixture.debugElement.query(By.directive(NzCascaderComponent));\n    });\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n      expect(cascader.nativeElement.className).toContain('ant-cascader ant-select');\n    });\n\n    it('should have input', () => {\n      fixture.detectChanges();\n      expect(getInputEl()).toBeDefined();\n      expect(getPlaceholder()).toBe('please select');\n    });\n\n    it('should input change event stopPropagation', () => {\n      fixture.detectChanges();\n      const fakeInputChangeEvent = createFakeEvent('change', true, true);\n      spyOn(fakeInputChangeEvent, 'stopPropagation');\n      getInputEl().dispatchEvent(fakeInputChangeEvent);\n      fixture.detectChanges();\n      expect(fakeInputChangeEvent.stopPropagation).toHaveBeenCalled();\n    });\n\n    it('should not have EMPTY label', () => {\n      fixture.detectChanges();\n      const label: HTMLElement = cascader.nativeElement.querySelector('.ant-select-selection-item');\n      expect(label).toBeNull();\n    });\n\n    it('should placeholder work', () => {\n      const placeholder = 'placeholder test';\n      testComponent.nzPlaceHolder = placeholder;\n      fixture.detectChanges();\n      expect(getPlaceholder()).toBe(placeholder);\n    });\n\n    it('should show/hide placeholder when trigger compositionstart/compositionend event', () => {\n      testComponent.nzPlaceHolder = 'placeholder test';\n      fixture.detectChanges();\n\n      const placeholderElement = cascader.nativeElement.querySelector('.ant-select-selection-placeholder');\n      const fakeCompositionstartEvent = createFakeEvent('compositionstart', true, true);\n      getInputEl().dispatchEvent(fakeCompositionstartEvent);\n      fixture.detectChanges();\n      expect(placeholderElement.style.display).toBe('none');\n\n      const fakeCompositionendEvent = createFakeEvent('compositionend', true, true);\n      getInputEl().dispatchEvent(fakeCompositionendEvent);\n      fixture.detectChanges();\n      expect(placeholderElement.style.display).toBe('block');\n    });\n\n    it('should size work', () => {\n      testComponent.nzSize = 'small';\n      fixture.detectChanges();\n      expect(cascader.nativeElement.classList).toContain('ant-select-sm');\n      testComponent.nzSize = 'large';\n      fixture.detectChanges();\n      expect(cascader.nativeElement.classList).toContain('ant-select-lg');\n    });\n\n    it('should value and label property work', fakeAsync(() => {\n      testComponent.nzOptions = ID_NAME_LIST;\n      testComponent.nzValueProperty = 'id';\n      testComponent.nzLabelProperty = 'name';\n      fixture.detectChanges();\n      // label will not show if no item selected\n      expect(getLabelElement()).toBeNull();\n      expect(testComponent.cascader.getSubmitValue().join(',')).toBe('');\n      testComponent.values = [1, 2, 3];\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(getLabelText()).toBe('Zhejiang / Hangzhou / West Lake');\n      expect(testComponent.cascader.getSubmitValue().join(',')).toBe('1,2,3');\n    }));\n\n    it('should no value and label property work', fakeAsync(() => {\n      testComponent.nzValueProperty = null!;\n      testComponent.nzLabelProperty = null!;\n      fixture.detectChanges();\n      expect(getLabelElement()).toBeNull();\n      expect(testComponent.cascader.getSubmitValue().join(',')).toBe('');\n      testComponent.values = ['zhejiang', 'hangzhou', 'xihu'];\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(getLabelText()).toBe('Zhejiang / Hangzhou / West Lake');\n      expect(testComponent.cascader.getSubmitValue().join(',')).toBe('zhejiang,hangzhou,xihu');\n    }));\n\n    it('should showArrow work', () => {\n      testComponent.nzShowArrow = true;\n      fixture.detectChanges();\n      expect(cascader.nativeElement.querySelector('.ant-select-arrow')).toBeDefined();\n      expect(cascader.nativeElement.querySelector('.ant-select-arrow .anticon').classList).toContain('anticon-down');\n      testComponent.nzShowArrow = false;\n      fixture.detectChanges();\n      expect(cascader.nativeElement.querySelector('.ant-select-arrow')).toBeNull();\n    });\n\n    it('should allowClear work', () => {\n      fixture.detectChanges();\n      testComponent.values = ['zhejiang', 'hangzhou', 'xihu'];\n      fixture.detectChanges();\n      expect(cascader.nativeElement.querySelector('.ant-select-clear')).toBeDefined();\n      testComponent.nzAllowClear = false;\n      fixture.detectChanges();\n      expect(cascader.nativeElement.querySelector('.ant-select-clear')).toBeNull();\n    });\n\n    describe('should variant works', () => {\n      it('filled', () => {\n        fixture.detectChanges();\n        expect(cascader.nativeElement.classList).not.toContain('ant-select-filled');\n        testComponent.nzVariant = 'filled';\n        fixture.detectChanges();\n        expect(cascader.nativeElement.classList).toContain('ant-select-filled');\n      });\n      it('borderless', () => {\n        fixture.detectChanges();\n        expect(cascader.nativeElement.classList).not.toContain('ant-select-borderless');\n        testComponent.nzVariant = 'borderless';\n        fixture.detectChanges();\n        expect(cascader.nativeElement.classList).toContain('ant-select-borderless');\n      });\n      it('underlined', () => {\n        fixture.detectChanges();\n        expect(cascader.nativeElement.classList).not.toContain('ant-select-underlined');\n        testComponent.nzVariant = 'underlined';\n        fixture.detectChanges();\n        expect(cascader.nativeElement.classList).toContain('ant-select-underlined');\n      });\n    });\n\n    it('should open work', () => {\n      fixture.detectChanges();\n      expect(cascader.nativeElement.classList).not.toContain('ant-select-open');\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      expect(cascader.nativeElement.classList).toContain('ant-select-open');\n      expect(testComponent.onVisibleChange).toHaveBeenCalledTimes(1);\n      expect(testComponent.cascader.nzOptions).toEqual(options1);\n    });\n\n    it('should click toggle open', fakeAsync(() => {\n      fixture.detectChanges();\n      expect(testComponent.nzDisabled).toBe(false);\n\n      cascader.nativeElement.click();\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(true);\n      expect(testComponent.onVisibleChange).toHaveBeenCalledTimes(1);\n\n      cascader.nativeElement.click();\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n      expect(testComponent.onVisibleChange).toHaveBeenCalledTimes(2);\n    }));\n\n    it('should mouse hover toggle open', fakeAsync(() => {\n      fixture.detectChanges();\n      testComponent.nzTriggerAction = 'hover';\n      fixture.detectChanges();\n      expect(testComponent.nzDisabled).toBe(false);\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n      expect(testComponent.onVisibleChange).toHaveBeenCalledTimes(0);\n      dispatchMouseEvent(cascader.nativeElement, 'mouseenter');\n      tick(300);\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(true);\n      expect(testComponent.onVisibleChange).toHaveBeenCalledTimes(1);\n\n      dispatchMouseEvent(cascader.nativeElement, 'mouseleave');\n      tick(300);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n      expect(testComponent.onVisibleChange).toHaveBeenCalledTimes(2);\n    }));\n\n    it('should mouse hover toggle open immediately', fakeAsync(() => {\n      fixture.detectChanges();\n      testComponent.nzTriggerAction = ['hover'];\n      testComponent.nzMouseEnterDelay = 0;\n      testComponent.nzMouseLeaveDelay = 0;\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n      dispatchMouseEvent(cascader.nativeElement, 'mouseenter');\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(true);\n      expect(testComponent.onVisibleChange).toHaveBeenCalledTimes(1);\n      dispatchMouseEvent(cascader.nativeElement, 'mouseleave');\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n      expect(testComponent.onVisibleChange).toHaveBeenCalledTimes(2);\n    }));\n\n    it('should clear timer on option mouseenter and mouseleave', fakeAsync(() => {\n      testComponent.nzExpandTrigger = 'hover';\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(true);\n      flush();\n      fixture.detectChanges();\n      const optionEl = getItemAtColumnAndRow(1, 1)!;\n      expect(optionEl.classList).not.toContain('ant-cascader-menu-item-active');\n\n      dispatchMouseEvent(optionEl, 'mouseenter');\n      fixture.detectChanges();\n      tick(10);\n      fixture.detectChanges();\n      expect(optionEl.classList).not.toContain('ant-cascader-menu-item-active');\n      dispatchMouseEvent(optionEl, 'mouseleave');\n      fixture.detectChanges();\n      tick(400);\n      fixture.detectChanges();\n      expect(optionEl.classList).not.toContain('ant-cascader-menu-item-active');\n\n      dispatchMouseEvent(optionEl, 'mouseenter');\n      fixture.detectChanges();\n      tick(400);\n      fixture.detectChanges();\n      expect(optionEl.classList).toContain('ant-cascader-menu-item-active');\n    }));\n\n    it('should disabled work', fakeAsync(() => {\n      fixture.detectChanges();\n      expect(cascader.nativeElement.classList).not.toContain('ant-select-disabled');\n      testComponent.nzDisabled = true;\n      fixture.detectChanges();\n      expect(cascader.nativeElement.classList).toContain('ant-select-disabled');\n      expect(testComponent.onVisibleChange).toHaveBeenCalledTimes(0);\n      cascader.nativeElement.click();\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n      expect(testComponent.onVisibleChange).toHaveBeenCalledTimes(0);\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n      expect(testComponent.onVisibleChange).toHaveBeenCalledTimes(0);\n    }));\n\n    it('should disabled state work', fakeAsync(() => {\n      fixture.detectChanges();\n      expect(cascader.nativeElement.classList).not.toContain('ant-select-disabled');\n      testComponent.cascader.setDisabledState(true);\n      fixture.detectChanges();\n      expect(cascader.nativeElement.classList).toContain('ant-select-disabled');\n      expect(testComponent.onVisibleChange).toHaveBeenCalledTimes(0);\n      cascader.nativeElement.click();\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n      expect(testComponent.onVisibleChange).toHaveBeenCalledTimes(0);\n    }));\n\n    it('should disabled mouse hover open', fakeAsync(() => {\n      testComponent.nzTriggerAction = 'hover';\n      testComponent.nzDisabled = true;\n      fixture.detectChanges();\n      expect(testComponent.cascader.nzDisabled).toBe(true);\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n      expect(testComponent.onVisibleChange).toHaveBeenCalledTimes(0);\n      dispatchMouseEvent(cascader.nativeElement, 'mouseenter');\n      tick(300);\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n      expect(testComponent.onVisibleChange).toHaveBeenCalledTimes(0);\n\n      testComponent.nzDisabled = false;\n      fixture.detectChanges();\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      expect(testComponent.cascader.nzDisabled).toBe(false);\n      expect(testComponent.cascader.menuVisible()).toBe(true);\n      expect(testComponent.onVisibleChange).toHaveBeenCalledTimes(1);\n      testComponent.nzDisabled = true;\n      fixture.detectChanges();\n      dispatchMouseEvent(cascader.nativeElement, 'mouseleave');\n      tick(300);\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(true);\n      expect(testComponent.onVisibleChange).toHaveBeenCalledTimes(1);\n    }));\n\n    it('should mouse leave not work when menu not open', fakeAsync(() => {\n      testComponent.nzTriggerAction = ['hover'];\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n      dispatchMouseEvent(cascader.nativeElement, 'mouseleave');\n      fixture.detectChanges();\n      tick(300);\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n      expect(testComponent.onVisibleChange).toHaveBeenCalledTimes(0);\n    }));\n\n    it('should clear value work', fakeAsync(() => {\n      fixture.detectChanges();\n      testComponent.nzAllowClear = true;\n      testComponent.values = ['zhejiang', 'hangzhou', 'xihu'];\n      fixture.detectChanges();\n      flush();\n      expect(testComponent.values!.length).toBe(3);\n      fixture.detectChanges();\n      spyOn(testComponent, 'onClear');\n      cascader.nativeElement.querySelector('.ant-select-clear nz-icon').click();\n      fixture.detectChanges();\n      expect(testComponent.values!.length).toBe(0);\n      expect(testComponent.onClear).toHaveBeenCalled();\n    }));\n\n    it('should clear value work 2', fakeAsync(() => {\n      fixture.detectChanges();\n      testComponent.values = ['zhejiang', 'hangzhou', 'xihu'];\n      fixture.detectChanges();\n      flush();\n      expect(testComponent.values!.length).toBe(3);\n      fixture.detectChanges();\n      spyOn(testComponent, 'onClear');\n      testComponent.cascader.clearSelection();\n      fixture.detectChanges();\n      expect(testComponent.values!.length).toBe(0);\n      expect(testComponent.onClear).toHaveBeenCalled();\n    }));\n\n    it('should autofocus work', () => {\n      testComponent.nzShowInput = true;\n      testComponent.nzAutoFocus = true;\n      fixture.detectChanges();\n      expect(getInputEl().getAttribute('autofocus')).toBe('autofocus');\n      testComponent.nzAutoFocus = false;\n      fixture.detectChanges();\n      expect(getInputEl().getAttribute('autofocus')).toBe(null);\n    });\n\n    it('should input focus and blur work', fakeAsync(() => {\n      const fakeInputFocusEvent = createFakeEvent('focus', false, true);\n      const fakeInputBlurEvent = createFakeEvent('blur', false, true);\n\n      fixture.detectChanges();\n      expect(cascader.nativeElement.classList).not.toContain('ant-select-focused');\n      getInputEl().dispatchEvent(fakeInputFocusEvent);\n      fixture.detectChanges();\n      expect(cascader.nativeElement.classList).toContain('ant-select-focused');\n      getInputEl().dispatchEvent(fakeInputBlurEvent);\n      fixture.detectChanges();\n      expect(cascader.nativeElement.classList).not.toContain('ant-select-focused');\n\n      testComponent.cascader.setMenuVisible(true);\n      getInputEl().dispatchEvent(fakeInputFocusEvent);\n      fixture.detectChanges();\n      expect(cascader.nativeElement.classList).toContain('ant-select-focused');\n      getInputEl().dispatchEvent(fakeInputBlurEvent);\n      fixture.detectChanges();\n      expect(cascader.nativeElement.classList).toContain('ant-select-focused');\n    }));\n\n    it('should focus and blur function work', () => {\n      testComponent.nzShowInput = true;\n      cascader.nativeElement.click();\n      fixture.detectChanges();\n      expect(getInputEl() === document.activeElement).toBe(false);\n      testComponent.cascader.focus();\n      fixture.detectChanges();\n      expect(getInputEl() === document.activeElement).toBe(true);\n      testComponent.cascader.blur();\n      fixture.detectChanges();\n      expect(getInputEl() === document.activeElement).toBe(false);\n    });\n\n    it('should focus and blur function work 2', () => {\n      testComponent.nzShowInput = false;\n      cascader.nativeElement.click();\n      fixture.detectChanges();\n      expect(cascader.nativeElement === document.activeElement).toBe(false);\n      testComponent.cascader.focus();\n      fixture.detectChanges();\n      expect(cascader.nativeElement === document.activeElement).toBe(true);\n      testComponent.cascader.blur();\n      fixture.detectChanges();\n      expect(cascader.nativeElement === document.activeElement).toBe(false);\n    });\n\n    it('should menu class work', fakeAsync(() => {\n      fixture.detectChanges();\n      cascader.nativeElement.click();\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(true);\n      expect(overlayContainerElement.querySelector('.ant-cascader-menus')!.classList).toContain('menu-classA');\n      expect(overlayContainerElement.querySelector('.ant-cascader-menu')!.classList).toContain('column-classA');\n    }));\n\n    it('should menu style work', fakeAsync(() => {\n      fixture.detectChanges();\n      cascader.nativeElement.click();\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(true);\n      const targetElement = overlayContainerElement.querySelector('.menu-classA') as HTMLElement;\n      expect(targetElement.style.height).toBe('120px');\n    }));\n\n    it('should show input false work', fakeAsync(() => {\n      testComponent.nzShowInput = false;\n      fixture.detectChanges();\n      expect(cascader.nativeElement.querySelector('.ant-select-selection-search-input')).toBeNull();\n      testComponent.nzAllowClear = true;\n      testComponent.values = ['zhejiang', 'hangzhou', 'xihu'];\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.cascader.nzOptions).toEqual(options1);\n      expect(cascader.nativeElement.querySelector('.ant-select-selection-search-input')).toBeNull();\n      expect(cascader.nativeElement.querySelector('.ant-select-clear')).toBeNull();\n      expect(cascader.nativeElement.querySelector('.ant-select-selection-item')).toBeNull();\n    }));\n\n    it('should create label work', fakeAsync(() => {\n      fixture.detectChanges();\n      expect(cascader.nativeElement.querySelector('.ant-select-selection-item')).toBeNull();\n      testComponent.values = ['zhejiang', 'hangzhou', 'xihu'];\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(getLabelText()).toBe('Zhejiang / Hangzhou / West Lake');\n    }));\n\n    it('should label template work', fakeAsync(() => {\n      fixture.detectChanges();\n      expect(cascader.nativeElement.querySelector('.ant-select-selection-item')).toBeNull();\n      testComponent.values = ['zhejiang', 'hangzhou', 'xihu'];\n      testComponent.nzLabelRender = testComponent.renderTpl;\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(getLabelText().trim()).toBe('Zhejiang | Hangzhou | West Lake');\n      // fix clear\n      testComponent.cascader.clearSelection();\n      testComponent.values = ['zhejiang', 'hangzhou', 'xihu'];\n      testComponent.nzLabelRender = testComponent.renderTpl;\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(getLabelText().trim()).toBe('Zhejiang | Hangzhou | West Lake');\n    }));\n\n    it('should write value work', fakeAsync(() => {\n      const control = testComponent.cascader;\n      testComponent.nzOptions = options1;\n      fixture.detectChanges();\n      expect(control.getSubmitValue().length).toBe(0);\n      control.writeValue(null);\n      fixture.detectChanges();\n      expect(control.getSubmitValue().length).toBe(0);\n      control.writeValue(undefined);\n      fixture.detectChanges();\n      expect(control.getSubmitValue().length).toBe(0);\n      control.writeValue([]);\n      fixture.detectChanges();\n      expect(control.getSubmitValue().length).toBe(0);\n      control.writeValue(0);\n      fixture.detectChanges();\n      expect(control.getSubmitValue().length).toBe(1);\n      control.writeValue('');\n      fixture.detectChanges();\n      expect(control.getSubmitValue().length).toBe(1);\n      control.writeValue(['zhejiang']);\n      fixture.detectChanges();\n      expect(control.getSubmitValue().length).toBe(1);\n      expect(control.getSubmitValue()[0]).toBe('zhejiang');\n      control.writeValue(['zhejiang', 'hangzhou', 'xihu']);\n      fixture.detectChanges();\n      expect(control.getSubmitValue().length).toBe(3);\n      const values = control.getSubmitValue();\n      expect(values![0]).toBe('zhejiang');\n      expect(values![1]).toBe('hangzhou');\n      expect(values![2]).toBe('xihu');\n\n      testComponent.nzOptions = []; // empty collection\n      fixture.detectChanges();\n      control.writeValue(['zhejiang', 'hangzhou', 'xihu']); // so these values are not match\n      fixture.detectChanges();\n      expect(control.getSubmitValue().length).toBe(3);\n      const values3 = control.getSubmitValue();\n      expect(values3[0]).toBe('zhejiang');\n      expect(values3[1]).toBe('hangzhou');\n      expect(values3[2]).toBe('xihu');\n      expect(control.labelRenderText).toBe('zhejiang / hangzhou / xihu');\n    }));\n\n    it('should write value work on setting `nzOptions` async', fakeAsync(() => {\n      const control = testComponent.cascader;\n      testComponent.nzOptions = null;\n      fixture.detectChanges();\n      expect(control.getSubmitValue().length).toBe(0);\n      control.writeValue(null);\n      fixture.detectChanges();\n      expect(control.getSubmitValue().length).toBe(0);\n      control.writeValue(undefined);\n      fixture.detectChanges();\n      expect(control.getSubmitValue().length).toBe(0);\n      control.writeValue([]);\n      fixture.detectChanges();\n      expect(control.getSubmitValue().length).toBe(0);\n      control.writeValue(0);\n      fixture.detectChanges();\n      expect(control.getSubmitValue().length).toBe(1);\n      control.writeValue('');\n      fixture.detectChanges();\n      expect(control.getSubmitValue().length).toBe(1);\n      control.writeValue(['zhejiang']);\n      fixture.detectChanges();\n      expect(control.getSubmitValue().length).toBe(1);\n      expect(control.getSubmitValue()[0]).toBe('zhejiang');\n      expect(control.labelRenderText).toBe('zhejiang');\n      testComponent.nzOptions = options1; // update the nzOptions like async\n      fixture.detectChanges();\n      expect(control.getSubmitValue().length).toBe(1);\n      expect(control.getSubmitValue()[0]).toBe('zhejiang');\n      expect(control.labelRenderText).toBe('Zhejiang');\n    }));\n\n    it('should write value work on setting `nzOptions` async (match)', fakeAsync(() => {\n      const control = testComponent.cascader;\n      testComponent.nzOptions = null;\n      testComponent.values = ['zhejiang', 'hangzhou', 'xihu'];\n      fixture.detectChanges();\n      flush(); // force value to be written\n      fixture.detectChanges();\n      expect(control.getSubmitValue().length).toBe(3);\n      expect(control.labelRenderText).toBe('zhejiang / hangzhou / xihu');\n      testComponent.nzOptions = options1; // update the nzOptions like async\n      fixture.detectChanges();\n      const values = control.getSubmitValue();\n      expect(values![0]).toBe('zhejiang');\n      expect(values![1]).toBe('hangzhou');\n      expect(values![2]).toBe('xihu');\n      expect(control.labelRenderText).toBe('Zhejiang / Hangzhou / West Lake');\n    }));\n\n    it('should write value work on setting `nzOptions` async (not match)', fakeAsync(() => {\n      const control = testComponent.cascader;\n      testComponent.nzOptions = null;\n      testComponent.values = ['zhejiang2', 'hangzhou2', 'xihu2'];\n      fixture.detectChanges();\n      flush(); // force value to be written\n      fixture.detectChanges();\n      expect(control.getSubmitValue().length).toBe(3);\n      expect(control.labelRenderText).toBe('zhejiang2 / hangzhou2 / xihu2');\n      testComponent.nzOptions = options1; // update the nzOptions like async\n      fixture.detectChanges(); // but still the values is not match\n      const values = control.getSubmitValue();\n      expect(values![0]).toBe('zhejiang2');\n      expect(values![1]).toBe('hangzhou2');\n      expect(values![2]).toBe('xihu2');\n      expect(control.labelRenderText).toBe('zhejiang2 / hangzhou2 / xihu2');\n    }));\n\n    it('should click option to expand', () => {\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(0); // 0列：未显示菜单\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(1);\n      const itemEl1 = overlayContainerElement.querySelector('.ant-cascader-menu')!.firstElementChild as HTMLElement;\n\n      itemEl1.click();\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(2);\n      const col2 = getAllColumns().item(1);\n      const itemEl2 = col2.firstElementChild as HTMLElement;\n\n      itemEl2.click();\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(3);\n    });\n\n    it('should click option to change column count', () => {\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(0); // 0列：未显示菜单\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(1);\n      const itemEl1 = getItemAtColumnAndRow(1, 1)!;\n\n      itemEl1.click();\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(2);\n      const itemEl2 = getItemAtColumnAndRow(2, 1)!;\n\n      itemEl2.click();\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(3);\n\n      const itemEl3 = getItemAtColumnAndRow(1, 2)!;\n\n      itemEl3.click();\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(2);\n    });\n\n    it('should click option to change column count 2', fakeAsync(() => {\n      testComponent.values = ['zhejiang', 'hangzhou', 'xihu'];\n      fixture.detectChanges();\n      cascader.nativeElement.click();\n      fixture.detectChanges();\n      flush(); // wait for cdk-overlay to open\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(true);\n      expect(getAllColumns().length).toBe(3);\n\n      let itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      let itemEl2 = getItemAtColumnAndRow(2, 1)!;\n      let itemEl3 = getItemAtColumnAndRow(3, 1)!;\n\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl3.classList).toContain('ant-cascader-menu-item-active');\n\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', LEFT_ARROW);\n      fixture.detectChanges();\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', LEFT_ARROW);\n      fixture.detectChanges();\n      itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      itemEl2 = getItemAtColumnAndRow(2, 1)!;\n      itemEl3 = getItemAtColumnAndRow(3, 1)!;\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(itemEl3).toBeNull();\n      expect(getAllColumns().length).toBe(2);\n      expect(testComponent.values!.join(',')).toBe('zhejiang,hangzhou,xihu');\n\n      const itemEl4 = getItemAtColumnAndRow(2, 2)!;\n      itemEl4.click(); // 选中一个叶子\n      fixture.detectChanges();\n      tick(300);\n      fixture.detectChanges();\n      flush(); // wait for cdk-overlay close\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n      expect(testComponent.values!.join(',')).toBe('zhejiang,ningbo');\n    }));\n\n    it('should click option to change column count 3', () => {\n      testComponent.nzOptions = options3;\n      fixture.detectChanges();\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(1);\n      const itemEl1 = getItemAtColumnAndRow(1, 1)!;\n\n      itemEl1.click();\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(2);\n      let itemEl21 = getItemAtColumnAndRow(2, 1)!;\n      expect(itemEl21.innerText.trim()).toBe('Hangzhou');\n\n      const itemEl2 = getItemAtColumnAndRow(1, 2)!;\n\n      itemEl2.click();\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(2);\n\n      itemEl21 = getItemAtColumnAndRow(2, 1)!;\n      expect(itemEl21.innerText.trim()).toBe('Nanjing');\n    });\n\n    it('should click disabled option false to expand', fakeAsync(() => {\n      testComponent.nzOptions = options2;\n      fixture.detectChanges();\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      const optionEl1 = getItemAtColumnAndRow(1, 1)!;\n      const optionEl2 = getItemAtColumnAndRow(1, 2)!;\n\n      expect(optionEl1.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(optionEl2.classList).not.toContain('ant-cascader-menu-item-active');\n      optionEl1.click();\n      fixture.detectChanges();\n      expect(optionEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(optionEl2.classList).not.toContain('ant-cascader-menu-item-active');\n      optionEl2.click();\n      fixture.detectChanges();\n      expect(optionEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(optionEl2.classList).not.toContain('ant-cascader-menu-item-active');\n    }));\n\n    it('should click leaf option to close menu', fakeAsync(() => {\n      fixture.detectChanges();\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(true);\n      getItemAtColumnAndRow(1, 1)!.click();\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(true);\n      getItemAtColumnAndRow(2, 1)!.click();\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(true);\n      getItemAtColumnAndRow(3, 1)!.click();\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n      expect(getAllColumns().length).toBe(0);\n    }));\n\n    it('should open menu when press DOWN_ARROW', fakeAsync(() => {\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', DOWN_ARROW);\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(true);\n    }));\n\n    it('should open menu when press UP_ARROW', fakeAsync(() => {\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', UP_ARROW);\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(true);\n    }));\n\n    it('should close menu when press ESC', fakeAsync(() => {\n      fixture.detectChanges();\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(true);\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', ESCAPE);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n    }));\n\n    it('should init menu when selecting cancel', fakeAsync(() => {\n      // cancel select by ESCAPE\n      fixture.detectChanges();\n      testComponent.cascader.setMenuVisible(true);\n      let itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      itemEl1.click();\n      let itemEl2 = getItemAtColumnAndRow(2, 1)!;\n      itemEl2.click();\n      let itemEl3 = getItemAtColumnAndRow(3, 1)!;\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl3.classList).not.toContain('ant-cascader-menu-item-active');\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', ESCAPE);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n      expect(testComponent.cascader.cascaderService.columns.length).toBe(1);\n\n      // cancel select by clicking outside\n      fixture.detectChanges();\n      testComponent.cascader.setMenuVisible(true);\n      itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      itemEl1.click();\n      itemEl2 = getItemAtColumnAndRow(2, 1)!;\n      itemEl2.click();\n      itemEl3 = getItemAtColumnAndRow(3, 1)!;\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl3.classList).not.toContain('ant-cascader-menu-item-active');\n      dispatchFakeEvent(document.body, 'click');\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n      expect(testComponent.cascader.cascaderService.columns.length).toBe(1);\n    }));\n\n    it('should nzBackdrop works', fakeAsync(() => {\n      testComponent.nzBackdrop = true;\n      fixture.detectChanges();\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      const boundingBox = overlayContainerElement.children[0];\n      expect(boundingBox.children[0].classList).toContain('cdk-overlay-backdrop');\n    }));\n\n    it('should navigate up when press UP_ARROW', fakeAsync(() => {\n      fixture.detectChanges();\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      const itemEl1 = overlayContainerElement.querySelector(\n        '.ant-cascader-menu:nth-child(1) .ant-cascader-menu-item:last-child'\n      ) as HTMLElement; // The last of the fisrt column\n      expect(itemEl1.classList).not.toContain('ant-cascader-menu-item-active');\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', UP_ARROW);\n      fixture.detectChanges();\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      const itemEl2 = getItemAtColumnAndRow(1, 1)!;\n      expect(itemEl2.classList).not.toContain('ant-cascader-menu-item-active');\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', UP_ARROW);\n      fixture.detectChanges();\n      expect(itemEl2.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl1.classList).not.toContain('ant-cascader-menu-item-active');\n    }));\n\n    it('should navigate down when press DOWN_ARROW', fakeAsync(() => {\n      fixture.detectChanges();\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      const itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      expect(itemEl1.classList).not.toContain('ant-cascader-menu-item-active');\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', DOWN_ARROW);\n      fixture.detectChanges();\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n    }));\n\n    it('should navigate right when press RIGHT_ARROW', fakeAsync(() => {\n      fixture.detectChanges();\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', DOWN_ARROW);\n      fixture.detectChanges();\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', RIGHT_ARROW);\n      fixture.detectChanges();\n      let itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      let itemEl2 = getItemAtColumnAndRow(2, 1)!;\n      expect(itemEl2.classList).toContain('ant-cascader-menu-item-active');\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', RIGHT_ARROW);\n      fixture.detectChanges();\n\n      itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n\n      itemEl2 = getItemAtColumnAndRow(2, 1)!;\n      expect(itemEl2.classList).toContain('ant-cascader-menu-item-active');\n      const itemEl3 = getItemAtColumnAndRow(3, 1)!;\n      expect(itemEl3.classList).toContain('ant-cascader-menu-item-active');\n    }));\n\n    it('should navigate left when press LEFT_ARROW', fakeAsync(() => {\n      fixture.detectChanges();\n      testComponent.values = ['zhejiang', 'hangzhou', 'xihu'];\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      flush(); // wait for cdk-overlay to open\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(3);\n\n      const itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      const itemEl2 = getItemAtColumnAndRow(2, 1)!;\n      let itemEl3 = getItemAtColumnAndRow(3, 1)!;\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl3.classList).toContain('ant-cascader-menu-item-active');\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', LEFT_ARROW);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl3.classList).not.toContain('ant-cascader-menu-item-active');\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', LEFT_ARROW);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      itemEl3 = getItemAtColumnAndRow(3, 1)!;\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(itemEl3).toBeNull();\n      expect(getAllColumns().length).toBe(2);\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', LEFT_ARROW);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBeFalse();\n    }));\n\n    it('should navigate left when press BACKSPACE', fakeAsync(() => {\n      fixture.detectChanges();\n      testComponent.values = ['zhejiang', 'hangzhou', 'xihu'];\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      flush(); // wait for cdk-overlay to open\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(3);\n\n      const itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      const itemEl2 = getItemAtColumnAndRow(2, 1)!;\n      const itemEl3 = getItemAtColumnAndRow(3, 1)!;\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl3.classList).toContain('ant-cascader-menu-item-active');\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', BACKSPACE);\n      fixture.detectChanges();\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl3.classList).not.toContain('ant-cascader-menu-item-active');\n    }));\n\n    it('when there is only one column activated, pressing LEFT should fold the menu', fakeAsync(() => {\n      testComponent.values = ['zhejiang', 'ningbo'];\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(2);\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', LEFT_ARROW);\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', LEFT_ARROW);\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBeFalse();\n    }));\n\n    it('should select option when press ENTER', fakeAsync(() => {\n      fixture.detectChanges();\n      expect(testComponent.values).toBeNull();\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', DOWN_ARROW); // active 1\n      fixture.detectChanges();\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', ENTER);\n      fixture.detectChanges();\n      expect(testComponent.values).toBeNull(); // not select yet\n\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', RIGHT_ARROW); // active 2\n      fixture.detectChanges();\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', ENTER);\n      fixture.detectChanges();\n      expect(testComponent.values).toBeNull(); // not select yet\n\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', RIGHT_ARROW); // active 3\n      fixture.detectChanges();\n      expect(testComponent.values).toBeNull(); // not select yet\n\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', ENTER);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n\n      expect(testComponent.values).toBeDefined();\n      expect(testComponent.values!.length).toBe(3);\n      expect(testComponent.values![0]).toBe('zhejiang');\n      expect(testComponent.values![1]).toBe('hangzhou');\n      expect(testComponent.values![2]).toBe('xihu');\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n    }));\n\n    it('should key nav disabled option correct', fakeAsync(() => {\n      testComponent.nzOptions = options2;\n      fixture.detectChanges();\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      const optionEl1 = getItemAtColumnAndRow(1, 1)!;\n      const optionEl2 = getItemAtColumnAndRow(1, 2)!;\n\n      expect(optionEl1.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(optionEl2.classList).not.toContain('ant-cascader-menu-item-active');\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', DOWN_ARROW); // active 1\n      fixture.detectChanges();\n      expect(optionEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(optionEl2.classList).not.toContain('ant-cascader-menu-item-active');\n\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', DOWN_ARROW);\n      fixture.detectChanges(); // should NOT active the disabled option2\n      expect(optionEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(optionEl2.classList).not.toContain('ant-cascader-menu-item-active');\n\n      const optionEl11 = getItemAtColumnAndRow(2, 1)!;\n      const optionEl12 = getItemAtColumnAndRow(2, 2)!;\n      const optionEl13 = getItemAtColumnAndRow(2, 3)!;\n      const optionEl14 = getItemAtColumnAndRow(2, 4)!;\n      expect(optionEl11.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(optionEl12.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(optionEl13.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(optionEl14.classList).not.toContain('ant-cascader-menu-item-active');\n\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', RIGHT_ARROW); // active 2\n      fixture.detectChanges();\n      expect(optionEl11.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(optionEl12.classList).toContain('ant-cascader-menu-item-active');\n      expect(optionEl13.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(optionEl14.classList).not.toContain('ant-cascader-menu-item-active');\n\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', DOWN_ARROW);\n      fixture.detectChanges();\n      expect(optionEl11.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(optionEl12.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(optionEl13.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(optionEl14.classList).toContain('ant-cascader-menu-item-active');\n\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', UP_ARROW);\n      fixture.detectChanges();\n      expect(optionEl11.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(optionEl12.classList).toContain('ant-cascader-menu-item-active');\n      expect(optionEl13.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(optionEl14.classList).not.toContain('ant-cascader-menu-item-active');\n    }));\n\n    it('should ignore keyboardEvent on some key', fakeAsync(() => {\n      const A = 65;\n      const Z = 90;\n      const keys = [PAGE_UP, PAGE_DOWN, TAB, HOME, END, SPACE, COMMA, DELETE];\n      for (let k = A; k <= Z; k++) {\n        keys.push(k);\n      }\n      for (let k = ZERO; k <= NINE; k++) {\n        keys.push(k);\n      }\n\n      fixture.detectChanges();\n      keys.forEach(key => {\n        expect(testComponent.cascader.menuVisible()).toBe(false);\n        dispatchKeyboardEvent(cascader.nativeElement, 'keydown', key);\n        fixture.detectChanges();\n        expect(testComponent.cascader.menuVisible()).toBe(false);\n      });\n    }));\n\n    it('should expand option on hover', fakeAsync(() => {\n      testComponent.nzExpandTrigger = 'hover';\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(0); // 0列\n      expect(testComponent.values).toBeNull(); // not select yet\n\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(1);\n      expect(testComponent.values).toBeNull(); // not select yet\n\n      const itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      expect(itemEl1.classList).not.toContain('ant-cascader-menu-item-active');\n\n      dispatchMouseEvent(itemEl1, 'mouseenter');\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(2);\n      const itemEl2 = getItemAtColumnAndRow(2, 1)!;\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(testComponent.values).toBeNull(); // not select yet\n\n      dispatchMouseEvent(itemEl1, 'mouseleave');\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(2);\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(testComponent.values).toBeNull(); // not select yet\n\n      dispatchMouseEvent(itemEl2, 'mouseenter');\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(3);\n      const itemEl3 = getItemAtColumnAndRow(3, 1)!;\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl3.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(testComponent.values).toBeNull(); // not select yet\n\n      dispatchMouseEvent(itemEl2, 'mouseleave');\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(3);\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl3.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(testComponent.values).toBeNull(); // not select yet\n\n      dispatchMouseEvent(itemEl3, 'mouseenter');\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(3);\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl3.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(testComponent.values).toBeNull(); // not select yet\n\n      itemEl3.click();\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(testComponent.values).toBeDefined();\n      expect(testComponent.values!.length).toBe(3);\n      expect(testComponent.values![0]).toBe('zhejiang');\n      expect(testComponent.values![1]).toBe('hangzhou');\n      expect(testComponent.values![2]).toBe('xihu');\n      flush();\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(0); // 0列\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n    }));\n\n    it('should not expand disabled option on hover', fakeAsync(() => {\n      testComponent.nzExpandTrigger = 'hover';\n      testComponent.nzOptions = options2;\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(0); // 0列\n      expect(testComponent.values).toBeNull(); // not select yet\n\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(1);\n      expect(testComponent.values).toBeNull(); // not select yet\n\n      const itemEl2 = getItemAtColumnAndRow(1, 2)!;\n      expect(itemEl2.classList).not.toContain('ant-cascader-menu-item-active');\n\n      dispatchMouseEvent(itemEl2, 'mouseenter');\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(itemEl2.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(getAllColumns().length).toBe(1);\n\n      dispatchMouseEvent(itemEl2, 'mouseleave');\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(itemEl2.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(getAllColumns().length).toBe(1);\n    }));\n\n    // fix #3914\n    it('should drop selected items and columns if a leaf node is hovered', fakeAsync(() => {\n      testComponent.nzExpandTrigger = 'hover';\n      fixture.detectChanges();\n\n      testComponent.values = ['zhejiang', 'hangzhou', 'xihu'];\n      testComponent.cascader.setMenuVisible(true); // Open cascader dropdown.\n\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelectorAll('.ant-cascader-menu').length).toBe(3);\n\n      const c2i2 = overlayContainerElement.querySelector(\n        '.ant-cascader-menu:nth-child(2) .ant-cascader-menu-item:nth-child(2)'\n      ) as HTMLElement;\n      dispatchMouseEvent(c2i2, 'mouseenter');\n\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelectorAll('.ant-cascader-menu').length).toBe(2);\n    }));\n\n    it('should change on select work', fakeAsync(() => {\n      testComponent.nzChangeOnSelect = true;\n      fixture.detectChanges();\n      expect(testComponent.values).toBeNull();\n      expect(getAllColumns().length).toBe(0); // 0列\n      expect(testComponent.values).toBeNull(); // not select yet\n\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(1);\n      expect(testComponent.values).toBeNull(); // not select yet\n\n      const itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      expect(itemEl1.classList).not.toContain('ant-cascader-menu-item-active');\n\n      itemEl1.click();\n      fixture.detectChanges();\n\n      expect(testComponent.cascader.menuVisible()).toBe(true);\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(getAllColumns().length).toBe(2);\n      expect(testComponent.values).toBeDefined();\n      expect(testComponent.values!.length).toBe(1);\n      expect(testComponent.values![0]).toBe('zhejiang');\n\n      const itemEl2 = getItemAtColumnAndRow(2, 1)!;\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).not.toContain('ant-cascader-menu-item-active');\n\n      itemEl2.click();\n      fixture.detectChanges();\n\n      expect(testComponent.cascader.menuVisible()).toBe(true);\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).toContain('ant-cascader-menu-item-active');\n      expect(getAllColumns().length).toBe(3);\n      expect(testComponent.values).toBeDefined();\n      expect(testComponent.values!.length).toBe(2);\n      expect(testComponent.values![0]).toBe('zhejiang');\n      expect(testComponent.values![1]).toBe('hangzhou');\n\n      const itemEl3 = getItemAtColumnAndRow(3, 1)!;\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl3.classList).not.toContain('ant-cascader-menu-item-active');\n\n      itemEl3.click();\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n\n      expect(testComponent.values).toBeDefined();\n      expect(testComponent.values!.length).toBe(3);\n      expect(testComponent.values![0]).toBe('zhejiang');\n      expect(testComponent.values![1]).toBe('hangzhou');\n      expect(testComponent.values![2]).toBe('xihu');\n      flush();\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(0); // 0列\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n    }));\n\n    it('should not change on hover work', fakeAsync(() => {\n      testComponent.nzChangeOnSelect = true;\n      testComponent.nzExpandTrigger = 'hover';\n      fixture.detectChanges();\n      expect(testComponent.values).toBeNull();\n      expect(getAllColumns().length).toBe(0); // 0列\n      expect(testComponent.values).toBeNull(); // not select yet\n\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(1);\n      expect(testComponent.values).toBeNull(); // not select yet\n\n      const itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      expect(itemEl1.classList).not.toContain('ant-cascader-menu-item-active');\n      dispatchMouseEvent(itemEl1, 'mouseenter');\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n\n      expect(testComponent.cascader.menuVisible()).toBe(true);\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(getAllColumns().length).toBe(2);\n      expect(testComponent.values).toBeNull(); // mouseenter does not trigger selection\n\n      const itemEl2 = getItemAtColumnAndRow(2, 1)!;\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).not.toContain('ant-cascader-menu-item-active');\n      dispatchMouseEvent(itemEl2, 'mouseenter');\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n\n      expect(testComponent.cascader.menuVisible()).toBe(true);\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).toContain('ant-cascader-menu-item-active');\n      expect(getAllColumns().length).toBe(3);\n      expect(testComponent.values).toBeNull(); // mouseenter does not trigger selection\n\n      const itemEl3 = getItemAtColumnAndRow(3, 1)!;\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl3.classList).not.toContain('ant-cascader-menu-item-active');\n      dispatchMouseEvent(itemEl3, 'mouseenter');\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n\n      expect(testComponent.values).toBeNull(); // mouseenter does not trigger selection\n\n      itemEl3.click();\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n\n      expect(testComponent.values).toBeDefined(); // click trigger selection\n      expect(testComponent.values!.length).toBe(3);\n      expect(testComponent.values![0]).toBe('zhejiang');\n      expect(testComponent.values![1]).toBe('hangzhou');\n      expect(testComponent.values![2]).toBe('xihu');\n      flush();\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(0); // 0列\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n    }));\n\n    it('should change on function work', fakeAsync(() => {\n      testComponent.nzChangeOn = testComponent.fakeChangeOn;\n      fixture.detectChanges();\n      expect(testComponent.values).toBeNull();\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(1);\n      expect(testComponent.values).toBeNull(); // not select yet\n\n      const itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      const itemEl2 = getItemAtColumnAndRow(1, 2)!;\n      expect(itemEl1.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).not.toContain('ant-cascader-menu-item-active');\n\n      itemEl2.click();\n      fixture.detectChanges();\n      expect(itemEl1.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).toContain('ant-cascader-menu-item-active');\n      expect(testComponent.values).toBeNull(); // not select yet\n\n      itemEl1.click();\n      fixture.detectChanges();\n      tick(200);\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(true);\n      expect(testComponent.values).toBeDefined();\n      expect(testComponent.values!.length).toBe(1);\n      expect(testComponent.values![0]).toBe('zhejiang');\n    }));\n\n    it('should support search', fakeAsync(() => {\n      fixture.detectChanges();\n      testComponent.nzShowSearch = true;\n      fixture.detectChanges();\n      const spy = spyOn(testComponent.cascader, 'focus');\n      cascader.nativeElement.click();\n      fixture.detectChanges();\n      expect(spy).toHaveBeenCalled();\n      testComponent.cascader.setMenuVisible(true);\n      testComponent.cascader.inputValue = 'o';\n      fixture.detectChanges();\n      const itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      expect(testComponent.cascader.inSearchingMode).toBe(true);\n      expect(itemEl1.innerText).toBe('Zhejiang / Hangzhou / West Lake');\n\n      itemEl1.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.cascader.inSearchingMode).toBe(false);\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n      expect(testComponent.cascader.inputValue).toBe('');\n      expect(testComponent.values!.join(',')).toBe('zhejiang,hangzhou,xihu');\n    }));\n\n    it('should searching could be aborted', fakeAsync(() => {\n      testComponent.values = ['zhengjiang', 'hangzhou', 'xihu'];\n      testComponent.nzShowSearch = true;\n      fixture.detectChanges();\n      cascader.nativeElement.click();\n      flush();\n      fixture.detectChanges();\n\n      // input search value\n      testComponent.cascader.inputValue = 'o';\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(true);\n      expect(testComponent.cascader.inSearchingMode).toBe(true);\n      let itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      expect(itemEl1.innerText).toBe('Zhejiang / Hangzhou / West Lake');\n\n      // clear search value\n      testComponent.cascader.inputValue = '';\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(true);\n      expect(testComponent.cascader.inSearchingMode).toBe(false);\n\n      itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      expect(itemEl1.innerText).toBe('Zhejiang');\n    }));\n\n    it('should clear input value when searching cancel', fakeAsync(() => {\n      testComponent.values = ['zhengjiang', 'hangzhou', 'xihu'];\n      testComponent.nzShowSearch = true;\n      fixture.detectChanges();\n      cascader.nativeElement.click();\n      testComponent.cascader.inputValue = 'o';\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(true);\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', ESCAPE);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.cascader.inputValue).toBe('');\n      expect(testComponent.values).toEqual(['zhengjiang', 'hangzhou', 'xihu']);\n    }));\n\n    it('should support nzLabelProperty', fakeAsync(() => {\n      testComponent.nzShowSearch = true;\n      testComponent.nzLabelProperty = 'l';\n      fixture.detectChanges();\n      cascader.nativeElement.click();\n      fixture.detectChanges();\n      testComponent.cascader.setMenuVisible(true);\n      testComponent.cascader.inputValue = 'o';\n      fixture.detectChanges();\n      const itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      expect(testComponent.cascader.inSearchingMode).toBe(true);\n      expect(itemEl1.innerText).toBe('Zhejiang New / Hangzhou New / West Lake New');\n\n      itemEl1.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.cascader.inSearchingMode).toBe(false);\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n      expect(testComponent.cascader.inputValue).toBe('');\n      expect(testComponent.values!.join(',')).toBe('zhejiang,hangzhou,xihu');\n    }));\n\n    it('should support nzValueProperty', fakeAsync(() => {\n      testComponent.nzShowSearch = true;\n      testComponent.nzValueProperty = 'v';\n      fixture.detectChanges();\n      cascader.nativeElement.click();\n      fixture.detectChanges();\n      testComponent.cascader.setMenuVisible(true);\n      testComponent.cascader.inputValue = 'o';\n      fixture.detectChanges();\n      const itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      expect(testComponent.cascader.inSearchingMode).toBe(true);\n      expect(itemEl1.innerText).toBe('Zhejiang / Hangzhou / West Lake');\n\n      itemEl1.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.cascader.inSearchingMode).toBe(false);\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n      expect(testComponent.cascader.inputValue).toBe('');\n      expect(testComponent.values!.join(',')).toBe('zhejiang-new,hangzhou-new,xihu-new');\n    }));\n\n    it('should support custom filter', fakeAsync(() => {\n      testComponent.nzShowSearch = {\n        filter(inputValue: string, path: NzCascaderOption[]): boolean {\n          return path.some(p => p.label!.indexOf(inputValue) !== -1);\n        }\n      } as NzShowSearchOptions;\n      fixture.detectChanges();\n      testComponent.cascader.setMenuVisible(true);\n      testComponent.cascader.inputValue = 'o';\n      fixture.detectChanges();\n      const itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      expect(testComponent.cascader.inSearchingMode).toBe(true);\n      expect(itemEl1.innerText).toBe('Zhejiang / Hangzhou / West Lake');\n\n      itemEl1.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.cascader.inSearchingMode).toBe(false);\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n      expect(testComponent.cascader.inputValue).toBe('');\n      expect(testComponent.values!.join(',')).toBe('zhejiang,hangzhou,xihu');\n    }));\n\n    it('should support custom sorter', fakeAsync(() => {\n      testComponent.nzShowSearch = {\n        sorter(a: NzCascaderOption[], b: NzCascaderOption[], _inputValue: string): number {\n          const l1 = a[0].label;\n          const l2 = b[0].label; // all reversed, just to be sure it works\n          return `${l1}`.localeCompare(l2!);\n        }\n      } as NzShowSearchOptions;\n      fixture.detectChanges();\n      testComponent.cascader.setMenuVisible(true);\n      testComponent.cascader.inputValue = 'o';\n      fixture.detectChanges();\n      const itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      expect(testComponent.cascader.inSearchingMode).toBe(true);\n      expect(itemEl1.innerText).toBe('Jiangsu / Nanjing / Zhong Hua Men');\n\n      itemEl1.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.cascader.inSearchingMode).toBe(false);\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n      expect(testComponent.cascader.inputValue).toBe('');\n      expect(testComponent.values!.join(',')).toBe('jiangsu,nanjing,zhonghuamen');\n    }));\n\n    it('should forbid disabled search options to be clicked', fakeAsync(() => {\n      testComponent.nzOptions = options4;\n      fixture.detectChanges();\n      testComponent.cascader.setMenuVisible(true);\n      testComponent.cascader.inputValue = 'o';\n      fixture.detectChanges();\n      const itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      expect(itemEl1.innerText).toBe('Zhejiang / Hangzhou / West Lake');\n      expect(testComponent.cascader.cascaderService.columns[0][0].isDisabled).toBe(true);\n\n      itemEl1.click();\n      tick(300);\n      fixture.detectChanges();\n      expect(testComponent.cascader.inSearchingMode).toBe(true);\n      expect(testComponent.cascader.menuVisible()).toBe(true);\n      expect(testComponent.cascader.inputValue).toBe('o');\n      // expect(testComponent.values).toBe(null);\n    }));\n\n    it('should pass disabled property to children when searching', () => {\n      testComponent.nzOptions = options4;\n      fixture.detectChanges();\n      testComponent.cascader.setMenuVisible(true);\n      testComponent.cascader.inputValue = 'o';\n      fixture.detectChanges();\n      expect(testComponent.cascader.cascaderService.columns[0][0].isDisabled).toBe(true);\n      expect(testComponent.cascader.cascaderService.columns[0][1].isDisabled).toBe(false);\n      expect(testComponent.cascader.cascaderService.columns[0][2].isDisabled).toBe(true);\n    });\n\n    it('should support arrow in search mode', done => {\n      testComponent.nzOptions = options2;\n      fixture.detectChanges();\n      testComponent.cascader.setMenuVisible(true);\n      testComponent.cascader.inputValue = 'o';\n      fixture.detectChanges();\n      const itemEl2 = getItemAtColumnAndRow(1, 2)!;\n      const itemEl4 = getItemAtColumnAndRow(1, 4)!;\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', DOWN_ARROW);\n      fixture.detectChanges();\n      expect(itemEl2.classList).toContain('ant-cascader-menu-item-active');\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', DOWN_ARROW);\n      fixture.detectChanges();\n      expect(itemEl2.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(itemEl4.classList).toContain('ant-cascader-menu-item-active');\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', ENTER);\n      fixture.detectChanges();\n      fixture.whenStable().then(() => {\n        expect(testComponent.values!.join(',')).toBe('option1,option14');\n        done();\n      });\n    });\n\n    it('should not preventDefault left/right arrow in search mode', () => {\n      fixture.detectChanges();\n      testComponent.nzShowSearch = true;\n      testComponent.cascader.inputValue = 'o';\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', LEFT_ARROW);\n      const itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      fixture.detectChanges();\n      expect(itemEl1.classList).not.toContain('ant-cascader-menu-item-active');\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', RIGHT_ARROW);\n      fixture.detectChanges();\n      expect(itemEl1.classList).not.toContain('ant-cascader-menu-item-active');\n    });\n\n    it('should not preventDefault BACKSPACE in search mode', fakeAsync(() => {\n      testComponent.nzShowSearch = true;\n      dispatchMouseEvent(cascader.nativeElement, 'click');\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', O);\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', BACKSPACE);\n      flush();\n      fixture.detectChanges();\n      const itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      expect(itemEl1.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(itemEl1.innerText).toBe('Zhejiang');\n      expect(testComponent.cascader.inputValue).toBe('');\n    }));\n\n    it('should support search a root node have no children ', fakeAsync(() => {\n      fixture.detectChanges();\n      testComponent.nzShowSearch = true;\n      testComponent.nzOptions = options5;\n      fixture.detectChanges();\n      const spy = spyOn(testComponent.cascader, 'focus');\n      cascader.nativeElement.click();\n      fixture.detectChanges();\n      expect(spy).toHaveBeenCalled();\n      testComponent.cascader.inputValue = 'Roo';\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      const itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      expect(testComponent.cascader.inSearchingMode).toBe(true);\n      expect(itemEl1.innerText.trim()).toBe('暂无数据');\n      flush();\n    }));\n\n    it('should re-prepare search results when nzOptions change', () => {\n      fixture.detectChanges();\n      testComponent.nzShowSearch = true;\n      cascader.nativeElement.click();\n      testComponent.cascader.setMenuVisible(true);\n      testComponent.cascader.inputValue = 'o';\n      fixture.detectChanges();\n      let itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      expect(testComponent.cascader.inSearchingMode).toBe(true);\n      expect(itemEl1.innerText).toBe('Zhejiang / Hangzhou / West Lake');\n      testComponent.nzOptions = options2;\n      fixture.detectChanges();\n      expect(testComponent.cascader.inSearchingMode).toBe(true);\n\n      itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      expect(itemEl1.innerText).toBe('Option1 / Option11');\n    });\n\n    it('should nzPrefix work', () => {\n      testComponent.nzPrefix = 'prefix';\n      fixture.detectChanges();\n      expect(cascader.nativeElement.querySelector('.ant-select-prefix')!.textContent?.trim()).toBe('prefix');\n    });\n\n    it('should support changing icon', () => {\n      testComponent.nzSuffixIcon = 'home';\n      testComponent.nzExpandIcon = 'home';\n\n      fixture.detectChanges();\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      const itemEl1 = getItemAtColumnAndRow(1, 1);\n      expect(itemEl1?.querySelector('.anticon-home')).toBeTruthy();\n      expect(cascader.nativeElement.querySelector('.ant-select-arrow .anticon')!.classList).toContain('anticon-home');\n    });\n\n    it('should nzPlacement works', fakeAsync(() => {\n      fixture.detectChanges();\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      let element = overlayContainerElement.querySelector('.ant-select-dropdown') as HTMLElement;\n      expect(element.classList.contains('ant-select-dropdown-placement-bottomLeft')).toBe(true);\n      expect(element.classList.contains('ant-select-dropdown-placement-bottomRight')).toBe(false);\n      expect(element.classList.contains('ant-select-dropdown-placement-topLeft')).toBe(false);\n      expect(element.classList.contains('ant-select-dropdown-placement-topRight')).toBe(false);\n\n      const setNzPlacement = (placement: NzCascaderPlacement): void => {\n        testComponent.cascader.setMenuVisible(false);\n        fixture.detectChanges();\n        testComponent.nzPlacement = placement;\n        testComponent.cascader.setMenuVisible(true);\n        fixture.detectChanges();\n        tick();\n        fixture.detectChanges();\n      };\n\n      setNzPlacement('bottomRight');\n      element = overlayContainerElement.querySelector('.ant-select-dropdown') as HTMLElement;\n      expect(element.classList.contains('ant-select-dropdown-placement-bottomLeft')).toBe(false);\n      expect(element.classList.contains('ant-select-dropdown-placement-bottomRight')).toBe(true);\n      expect(element.classList.contains('ant-select-dropdown-placement-topLeft')).toBe(false);\n      expect(element.classList.contains('ant-select-dropdown-placement-topRight')).toBe(false);\n\n      setNzPlacement('topLeft');\n      element = overlayContainerElement.querySelector('.ant-select-dropdown') as HTMLElement;\n      expect(element.classList.contains('ant-select-dropdown-placement-bottomLeft')).toBe(false);\n      expect(element.classList.contains('ant-select-dropdown-placement-bottomRight')).toBe(false);\n      expect(element.classList.contains('ant-select-dropdown-placement-topLeft')).toBe(true);\n      expect(element.classList.contains('ant-select-dropdown-placement-topRight')).toBe(false);\n\n      setNzPlacement('topRight');\n      element = overlayContainerElement.querySelector('.ant-select-dropdown') as HTMLElement;\n      expect(element.classList.contains('ant-select-dropdown-placement-bottomLeft')).toBe(false);\n      expect(element.classList.contains('ant-select-dropdown-placement-bottomRight')).toBe(false);\n      expect(element.classList.contains('ant-select-dropdown-placement-topLeft')).toBe(false);\n      expect(element.classList.contains('ant-select-dropdown-placement-topRight')).toBe(true);\n    }));\n\n    it('should cascade work when the value of ngModel that is not existed in options', fakeAsync(() => {\n      fixture.detectChanges();\n      testComponent.values = ['zhejiang', 'a'];\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      getItemAtColumnAndRow(1, 1)!.click();\n      getItemAtColumnAndRow(2, 1)!.click();\n      getItemAtColumnAndRow(3, 1)!.click();\n      fixture.detectChanges();\n      expect(testComponent.values).toEqual(['zhejiang', 'hangzhou', 'xihu']);\n    }));\n\n    it('should display activated column correctly after clicking outside and reopen', fakeAsync(() => {\n      fixture.detectChanges();\n      testComponent.values = ['zhejiang', 'hangzhou', 'xihu'];\n      // First open - should display activated columns correctly\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(3);\n      let itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      let itemEl2 = getItemAtColumnAndRow(2, 1)!;\n      let itemEl3 = getItemAtColumnAndRow(3, 1)!;\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl3.classList).toContain('ant-cascader-menu-item-active');\n\n      // Click first column option (zhejiang) - should fold the third column\n      itemEl1.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(2);\n      itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      itemEl2 = getItemAtColumnAndRow(2, 1)!;\n      itemEl3 = getItemAtColumnAndRow(3, 1)!;\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(itemEl3).toBeNull();\n\n      // Click outside to close menu - value should remain unchanged\n      dispatchFakeEvent(document.body, 'click');\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(false);\n      expect(testComponent.values).toEqual(['zhejiang', 'hangzhou', 'xihu']);\n\n      // Reopen menu - should display activated columns correctly based on current value\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(getAllColumns().length).toBe(3);\n      itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      itemEl2 = getItemAtColumnAndRow(2, 1)!;\n      itemEl3 = getItemAtColumnAndRow(3, 1)!;\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl3.classList).toContain('ant-cascader-menu-item-active');\n    }));\n\n    describe('should nzOpen works', () => {\n      beforeEach(fakeAsync(() => {\n        testComponent.nzOpen = true;\n        flush();\n        fixture.detectChanges();\n      }));\n\n      it('should nzOpen can control the visibility of menu', fakeAsync(() => {\n        expect(testComponent.cascader.menuVisible()).toBe(true);\n        expect(testComponent.onVisibleChange).toHaveBeenCalledTimes(1);\n        testComponent.nzOpen = false;\n        flush();\n        fixture.detectChanges();\n        expect(testComponent.cascader.menuVisible()).toBe(false);\n        expect(testComponent.onVisibleChange).toHaveBeenCalledTimes(2);\n      }));\n\n      it('should not hide menu by click leaf option or outside place when nzOpen is true', fakeAsync(() => {\n        expect(testComponent.cascader.menuVisible()).toBe(true);\n        getItemAtColumnAndRow(1, 1)!.click();\n        getItemAtColumnAndRow(2, 1)!.click();\n        getItemAtColumnAndRow(3, 1)!.click(); // zhejiang, hangzhou, xihu\n        flush();\n        fixture.detectChanges();\n        expect(testComponent.onValueChanges).toHaveBeenCalled();\n        expect(testComponent.cascader.menuVisible()).toBe(true);\n        spyOn(testComponent.cascader, 'onClickOutside');\n        dispatchFakeEvent(document.body, 'click');\n        expect(testComponent.cascader.onClickOutside).toHaveBeenCalled();\n        expect(testComponent.cascader.menuVisible()).toBe(true);\n      }));\n\n      it('should not hide menu by clear options under multiple mode when nzOpen is true', fakeAsync(() => {\n        testComponent.nzMultiple = true;\n        fixture.detectChanges();\n        getItemAtColumnAndRow(1, 1)!.click();\n        getItemAtColumnAndRow(2, 1)!.click();\n        getItemAtColumnAndRow(3, 1)!.click(); // zhejiang, hangzhou, xihu\n        getItemAtColumnAndRow(1, 2)!.click();\n        getItemAtColumnAndRow(2, 1)!.click();\n        getItemAtColumnAndRow(3, 1)!.click(); // jiangsu, nanjing, zhonghuamen\n        console.log(testComponent.values);\n        expect(testComponent.values).toEqual([['zhejiang', 'hangzhou'], ['jiangsu']]);\n        flush();\n        fixture.detectChanges();\n        expect(testComponent.cascader.menuVisible()).toBe(true);\n        spyOn(testComponent.cascader, 'clearSelection');\n        expect(cascader.nativeElement.querySelector('.ant-select-clear .anticon')).toBeDefined();\n        cascader.nativeElement.querySelector('.ant-select-clear .anticon').click();\n        expect(cascader.componentInstance.clearSelection).toHaveBeenCalled();\n        expect(testComponent.cascader.menuVisible()).toBe(true);\n      }));\n    });\n  });\n\n  describe('multiple', () => {\n    let fixture: ComponentFixture<NzDemoCascaderMultipleComponent>;\n    let cascader: DebugElement;\n    let testComponent: NzDemoCascaderMultipleComponent;\n\n    function setValues(len = 10): void {\n      testComponent.values = testComponent.nzOptions[0]\n        .children!.slice(0, len)\n        .map(o => [testComponent.nzOptions[0].value, o.value]);\n      fixture.detectChanges();\n    }\n\n    function getCheckboxAtColumnAndRow(column: number, row: number): HTMLElement | null {\n      return overlayContainerElement.querySelector(\n        `.ant-cascader-menu:nth-of-type(${column}) .ant-cascader-menu-item:nth-child(${row}) .ant-cascader-checkbox`\n      );\n    }\n\n    function getCheckboxesAtColumn(column: number): HTMLElement[] {\n      return Array.from(\n        overlayContainerElement.querySelectorAll(\n          `.ant-cascader-menu:nth-of-type(${column}) .ant-cascader-menu-item .ant-cascader-checkbox`\n        )\n      );\n    }\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzDemoCascaderMultipleComponent);\n      testComponent = fixture.componentInstance;\n      cascader = fixture.debugElement.query(By.directive(NzCascaderComponent));\n    });\n\n    it('should have correct classes', () => {\n      fixture.detectChanges();\n      expect(cascader.nativeElement.classList).toContain('ant-select-multiple');\n    });\n\n    it('should maxTagCount work', fakeAsync(() => {\n      // not exceed\n      setValues(3);\n      tick();\n      fixture.detectChanges();\n      let tags = cascader.queryAll(By.directive(NzSelectItemComponent));\n      expect(tags.length).toBe(3);\n\n      // exceed maxTagCount\n      setValues(10);\n      tick();\n      fixture.detectChanges();\n      tags = cascader.queryAll(By.directive(NzSelectItemComponent));\n      expect(tags.length).toBe(4); // maxTagCount + 1\n    }));\n\n    it('should remove item work', fakeAsync(() => {\n      setValues(4);\n      tick();\n      fixture.detectChanges();\n      const removeBtn = cascader.queryAll(By.css('.ant-select-selection-item-remove'))[2];\n      removeBtn.nativeElement.click();\n      fixture.detectChanges();\n      const tags = cascader.queryAll(By.directive(NzSelectItemComponent));\n      expect(tags.length).toBe(3);\n    }));\n\n    it('should check state conduct up and down', fakeAsync(() => {\n      cascader.componentInstance.setMenuVisible(true);\n      fixture.detectChanges();\n      tick(600);\n      fixture.detectChanges();\n\n      // firstly, expand all columns (for convenience)\n      getItemAtColumnAndRow(1, 2)!.click();\n      fixture.detectChanges();\n      getItemAtColumnAndRow(2, 1)!.click();\n      fixture.detectChanges();\n\n      const rootEl = getCheckboxAtColumnAndRow(1, 2)!;\n      const parentEl = getCheckboxAtColumnAndRow(2, 1)!;\n      const children = getCheckboxesAtColumn(3).filter(c => !c.classList.contains('ant-cascader-checkbox-disabled'));\n\n      // check parent option\n      parentEl.click();\n      fixture.detectChanges();\n      expect(parentEl.classList).toContain('ant-cascader-checkbox-checked');\n      // Conduct Down: then all children should be checked\n      expect(children.every(c => c.classList.contains('ant-cascader-checkbox-checked'))).toBe(true);\n      // Conduct Up: and its parent should be checked too\n      expect(rootEl.classList).toContain('ant-cascader-checkbox-checked');\n\n      // uncheck a child option\n      children[0]!.click();\n      fixture.detectChanges();\n      // Conduct Up: then parent should be half checked\n      expect(parentEl.classList).toContain('ant-cascader-checkbox-indeterminate');\n      // Conduct Up: and root should be half checked\n      expect(rootEl.classList).toContain('ant-cascader-checkbox-indeterminate');\n\n      // check the half checked parent option\n      parentEl.click();\n      fixture.detectChanges();\n      expect(parentEl.classList).toContain('ant-cascader-checkbox-checked');\n      // Conduct Down: then all children should be checked\n      expect(children.every(c => c.classList.contains('ant-cascader-checkbox-checked'))).toBe(true);\n      // Conduct Up: and its parent should be checked too\n      expect(rootEl.classList).toContain('ant-cascader-checkbox-checked');\n\n      // uncheck the parent option\n      parentEl.click();\n      fixture.detectChanges();\n      // Conduct Down: then all children should be unchecked\n      expect(children.every(c => !c.classList.contains('ant-cascader-checkbox-checked'))).toBe(true);\n      // Conduct Up: and its parent should be unchecked too\n      expect(rootEl.classList).not.toContain('ant-cascader-checkbox-checked');\n    }));\n\n    it('should click checkbox not set option activated', fakeAsync(() => {\n      cascader.componentInstance.setMenuVisible(true);\n      fixture.detectChanges();\n      tick(600);\n      fixture.detectChanges();\n\n      const option = getItemAtColumnAndRow(1, 1)!;\n      const checkbox = getCheckboxAtColumnAndRow(1, 1)!;\n      expect(option.classList).not.toContain('ant-cascader-menu-item-active');\n\n      checkbox.click();\n      fixture.detectChanges();\n\n      expect(option.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(checkbox.classList).toContain('ant-cascader-checkbox-checked');\n    }));\n\n    it('should change check state when click leaf node', fakeAsync(() => {\n      cascader.componentInstance.setMenuVisible(true);\n      fixture.detectChanges();\n      tick(600);\n      fixture.detectChanges();\n\n      // firstly, expand all columns (for convenience)\n      getItemAtColumnAndRow(1, 2)!.click();\n      fixture.detectChanges();\n      getItemAtColumnAndRow(2, 1)!.click();\n      fixture.detectChanges();\n\n      const leaf = getItemAtColumnAndRow(3, 2)!;\n      const checkbox = getCheckboxAtColumnAndRow(3, 2)!;\n      // click leaf node\n      expect(leaf.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(checkbox.classList).not.toContain('ant-cascader-checkbox-checked');\n\n      leaf.click();\n      fixture.detectChanges();\n      expect(leaf.classList).toContain('ant-cascader-menu-item-active');\n      expect(checkbox.classList).toContain('ant-cascader-checkbox-checked');\n\n      leaf.click();\n      fixture.detectChanges();\n      expect(leaf.classList).toContain('ant-cascader-menu-item-active');\n      expect(checkbox.classList).not.toContain('ant-cascader-checkbox-checked');\n    }));\n\n    it('should change check state trigger ngModelChange', fakeAsync(() => {\n      spyOn(testComponent, 'onChanges');\n      expect(testComponent.onChanges).not.toHaveBeenCalled();\n      cascader.componentInstance.setMenuVisible(true);\n      fixture.detectChanges();\n      tick(600);\n      fixture.detectChanges();\n      expect(testComponent.onChanges).not.toHaveBeenCalled();\n\n      const checkbox = getCheckboxAtColumnAndRow(1, 1)!;\n      checkbox.click();\n      fixture.detectChanges();\n      expect(testComponent.onChanges).toHaveBeenCalledWith([['light']]);\n    }));\n\n    it('should support ENTER key to toggle option checked state in multiple mode', fakeAsync(() => {\n      cascader.componentInstance.setMenuVisible(true);\n      fixture.detectChanges();\n      tick(600);\n      fixture.detectChanges();\n      getItemAtColumnAndRow(1, 1)!.click();\n      fixture.detectChanges();\n      const optionEl = getItemAtColumnAndRow(2, 1)!;\n      const checkboxEl = getCheckboxAtColumnAndRow(2, 1)!;\n      // Initially, the option should not be checked\n      expect(checkboxEl.classList).not.toContain('ant-cascader-checkbox-checked');\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', RIGHT_ARROW);\n      fixture.detectChanges();\n      expect(optionEl.classList).toContain('ant-cascader-menu-item-active');\n      // Press ENTER to toggle the option checked state\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', ENTER);\n      fixture.detectChanges();\n      // The option should now be checked\n      expect(checkboxEl.classList).toContain('ant-cascader-checkbox-checked');\n      // Press ENTER again to toggle the option unchecked state\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', ENTER);\n      fixture.detectChanges();\n      // The option should now be unchecked\n      expect(checkboxEl.classList).not.toContain('ant-cascader-checkbox-checked');\n    }));\n\n    it('should not activate option with isDisableCheckbox by pressing RIGHT ARROW key', fakeAsync(() => {\n      cascader.componentInstance.setMenuVisible(true);\n      fixture.detectChanges();\n      tick(600);\n      fixture.detectChanges();\n      getItemAtColumnAndRow(1, 2)!.click();\n      fixture.detectChanges();\n      getItemAtColumnAndRow(2, 1)!.click();\n      fixture.detectChanges();\n      // Try to navigate to a disabled checkbox option using keyboard\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', RIGHT_ARROW);\n      fixture.detectChanges();\n      // The option with disableCheckbox should not be activatable via keyboard\n      expect(getItemAtColumnAndRow(3, 1)!.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(getCheckboxAtColumnAndRow(3, 1)!.classList).toContain('ant-cascader-checkbox-disabled');\n      // activate item (3, 2)\n      expect(getItemAtColumnAndRow(3, 2)!.classList).toContain('ant-cascader-menu-item-active');\n      expect(getCheckboxAtColumnAndRow(3, 2)!.classList).not.toContain('ant-cascader-checkbox-disabled');\n    }));\n\n    it('should not activate option with isDisableCheckbox in moveUpOrDown method', fakeAsync(() => {\n      cascader.componentInstance.setMenuVisible(true);\n      fixture.detectChanges();\n      tick(600);\n      fixture.detectChanges();\n      getItemAtColumnAndRow(1, 2)!.click();\n      fixture.detectChanges();\n      getItemAtColumnAndRow(2, 1)!.click();\n      fixture.detectChanges();\n      getItemAtColumnAndRow(3, 2)!.click();\n      fixture.detectChanges();\n      expect(getItemAtColumnAndRow(3, 2)!.classList).toContain('ant-cascader-menu-item-active');\n      // Up key\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', UP_ARROW);\n      // The option with disableCheckbox should not be activatable via keyboard\n      expect(getItemAtColumnAndRow(3, 1)!.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(getItemAtColumnAndRow(3, 2)!.classList).toContain('ant-cascader-menu-item-active');\n    }));\n\n    describe('should cascade work when the value of ngModel includes nodes that are not existed in options', () => {\n      it('should remove item work', fakeAsync(() => {\n        setValues(2);\n        testComponent.values![0] = ['light', 'a'];\n        tick();\n        fixture.detectChanges();\n        const removeBtn = cascader.queryAll(By.css('.ant-select-selection-item-remove'))[0];\n        removeBtn.nativeElement.click();\n        fixture.detectChanges();\n        const tags = cascader.queryAll(By.directive(NzSelectItemComponent));\n        expect(tags.length).toBe(1);\n      }));\n\n      it('should add item work', fakeAsync(() => {\n        spyOn(testComponent, 'onChanges');\n        setValues(2);\n        testComponent.values![0] = ['light', 'a'];\n        console.log(testComponent.values);\n        tick();\n        fixture.detectChanges();\n        cascader.componentInstance.setMenuVisible(true);\n        fixture.detectChanges();\n        const checkbox = getCheckboxAtColumnAndRow(2, 3)!;\n        checkbox.click();\n        fixture.detectChanges();\n        expect(testComponent.values!.length).toBe(3);\n        const selectedNodes = [\n          ['light', 1],\n          ['light', 'a'],\n          ['light', 2]\n        ];\n        expect(testComponent.values).toEqual(selectedNodes);\n        expect(testComponent.onChanges).toHaveBeenCalledWith(selectedNodes);\n      }));\n    });\n  });\n\n  describe('load data lazily', () => {\n    let fixture: ComponentFixture<NzDemoCascaderLoadDataComponent>;\n    let cascader: DebugElement;\n    let testComponent: NzDemoCascaderLoadDataComponent;\n\n    afterEach(\n      testingInject([OverlayContainer], (currentOverlayContainer: OverlayContainer) => {\n        currentOverlayContainer.ngOnDestroy();\n        overlayContainer.ngOnDestroy();\n      })\n    );\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzDemoCascaderLoadDataComponent);\n      testComponent = fixture.debugElement.componentInstance;\n      cascader = fixture.debugElement.query(By.directive(NzCascaderComponent));\n    });\n\n    it('should nzLoadData work', fakeAsync(() => {\n      spyOn(testComponent, 'addCallTimes');\n\n      fixture.detectChanges();\n      expect(testComponent.values).toBeNull();\n      expect(getAllColumns().length).toBe(0); // 0列\n      expect(testComponent.values).toBeNull(); // not select yet\n      expect(testComponent.addCallTimes).toHaveBeenCalledTimes(0);\n\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      expect(testComponent.addCallTimes).toHaveBeenCalledTimes(1);\n      tick(1000); // wait for first row to load finish\n      fixture.detectChanges();\n\n      expect(getAllColumns().length).toBe(1);\n      expect(testComponent.values).toBeNull(); // not select yet\n\n      const itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      expect(itemEl1.classList).not.toContain('ant-cascader-menu-item-active');\n\n      itemEl1.click();\n      fixture.detectChanges();\n      tick(600);\n      fixture.detectChanges();\n      expect(testComponent.addCallTimes).toHaveBeenCalledTimes(2);\n      expect(getAllColumns().length).toBe(2);\n      expect(testComponent.values).toBeNull(); // not select yet\n\n      const itemEl2 = getItemAtColumnAndRow(2, 1)!;\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).not.toContain('ant-cascader-menu-item-active');\n\n      itemEl2.click();\n      fixture.detectChanges();\n      tick(600);\n      fixture.detectChanges();\n      expect(testComponent.addCallTimes).toHaveBeenCalledTimes(3);\n      expect(getAllColumns().length).toBe(3);\n      expect(testComponent.values).toBeNull(); // not select yet\n\n      const itemEl3 = getItemAtColumnAndRow(3, 1)!;\n      expect(itemEl1.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl2.classList).toContain('ant-cascader-menu-item-active');\n      expect(itemEl3.classList).not.toContain('ant-cascader-menu-item-active');\n\n      itemEl3.click();\n      fixture.detectChanges();\n      tick(600);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.addCallTimes).toHaveBeenCalledTimes(4);\n      expect(testComponent.values).toBeNull(); // not select yet\n\n      itemEl3.click(); // re-click again, this time it is a leaf\n      fixture.detectChanges();\n      tick(600);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.addCallTimes).toHaveBeenCalledTimes(4);\n      expect(testComponent.values).toBeDefined();\n      expect(testComponent.values!.length).toBe(3);\n      expect(testComponent.values![0]).toBe('zhejiang');\n      expect(testComponent.values![1]).toBe('hangzhou');\n      expect(testComponent.values![2]).toBe('xihu');\n    }));\n\n    it('should nzLoadData work when specifies default value', fakeAsync(() => {\n      spyOn(testComponent, 'addCallTimes');\n      testComponent.values = ['zhejiang', 'hangzhou', 'xihu'];\n      fixture.detectChanges();\n      tick(3000);\n      fixture.detectChanges();\n      expect(testComponent.addCallTimes).toHaveBeenCalledTimes(3);\n      expect(testComponent.cascader.cascaderService.columns.length).toBe(3);\n      expect(testComponent.values.join(',')).toBe('zhejiang,hangzhou,xihu');\n    }));\n\n    it('should not emit error after clear search and reopen it', fakeAsync(() => {\n      fixture.detectChanges();\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      tick(1000); // wait for first row to load finish\n      fixture.detectChanges();\n      const itemEl1 = getItemAtColumnAndRow(1, 1)!;\n\n      itemEl1.click();\n      fixture.detectChanges();\n      tick(600);\n      fixture.detectChanges();\n      const itemEl2 = getItemAtColumnAndRow(2, 1)!;\n\n      itemEl2.click();\n      fixture.detectChanges();\n      tick(600);\n      fixture.detectChanges();\n      const itemEl3 = getItemAtColumnAndRow(3, 1)!;\n\n      itemEl3.click();\n      fixture.detectChanges();\n      tick(600);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n\n      itemEl3.click(); // re-click again, this time it is a leaf\n      fixture.detectChanges();\n      tick(600);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      cascader.nativeElement.querySelector('.ant-select-clear .anticon').click();\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      expect(testComponent.values!.length).toBe(0);\n    }));\n  });\n\n  describe('RTL', () => {\n    let fixture: ComponentFixture<NzDemoCascaderRtlComponent>;\n    let cascader: DebugElement;\n    let testComponent: NzDemoCascaderRtlComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzDemoCascaderRtlComponent);\n      testComponent = fixture.debugElement.componentInstance;\n      cascader = fixture.debugElement.query(By.directive(NzCascaderComponent));\n    });\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n      expect(cascader.nativeElement.className).toContain('ant-select-rtl');\n\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n      expect(cascader.nativeElement.className).not.toContain('ant-select-rtl');\n    });\n\n    it('should menu class work', fakeAsync(() => {\n      fixture.detectChanges();\n      cascader.nativeElement.click();\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(testComponent.cascader.menuVisible()).toBe(true);\n      expect(overlayContainerElement.querySelector('.ant-cascader-menus')!.classList).toContain('ant-cascader-rtl');\n    }));\n\n    it('should item arrow display correct direction', fakeAsync(() => {\n      fixture.detectChanges();\n      testComponent.nzOptions = options3;\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      const itemEl1 = getItemAtColumnAndRow(1, 1)!;\n      itemEl1.click();\n      fixture.detectChanges();\n      tick(600);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      const itemEl21 = getItemAtColumnAndRow(2, 1)!;\n      expect(itemEl21.querySelector('.anticon')?.classList).toContain('anticon-left');\n    }));\n\n    it('should pressing the left and right keys can correctly expand and collapse content', fakeAsync(() => {\n      testComponent.nzOptions = options3;\n      testComponent.cascader.setMenuVisible(true);\n      fixture.detectChanges();\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', LEFT_ARROW);\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', LEFT_ARROW);\n      fixture.detectChanges();\n      const zhejiangItemEl = getItemAtColumnAndRow(1, 1)!;\n      const hangzhouItemEl = getItemAtColumnAndRow(2, 1)!;\n      expect(zhejiangItemEl.classList).toContain('ant-cascader-menu-item-active');\n      expect(hangzhouItemEl.classList).toContain('ant-cascader-menu-item-active');\n      dispatchKeyboardEvent(cascader.nativeElement, 'keydown', RIGHT_ARROW);\n      fixture.detectChanges();\n      expect(hangzhouItemEl.classList).not.toContain('ant-cascader-menu-item-active');\n      expect(zhejiangItemEl.classList).toContain('ant-cascader-menu-item-active');\n    }));\n  });\n\n  describe('Status', () => {\n    let fixture: ComponentFixture<NzDemoCascaderStatusComponent>;\n    let cascader: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzDemoCascaderStatusComponent);\n      cascader = fixture.debugElement.query(By.directive(NzCascaderComponent));\n    });\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n      expect(cascader.nativeElement.className).toContain('ant-select-status-error');\n\n      fixture.componentInstance.status = 'warning';\n      fixture.detectChanges();\n      expect(cascader.nativeElement.className).toContain('ant-select-status-warning');\n\n      fixture.componentInstance.status = '';\n      fixture.detectChanges();\n      expect(cascader.nativeElement.className).not.toContain('ant-select-status-warning');\n    });\n  });\n\n  describe('In form', () => {\n    let fixture: ComponentFixture<NzDemoCascaderInFormComponent>;\n    let formGroup: FormGroup<{\n      demo: FormControl<string[] | null>;\n    }>;\n    let cascader: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzDemoCascaderInFormComponent);\n      cascader = fixture.debugElement.query(By.directive(NzCascaderComponent));\n      formGroup = fixture.componentInstance.validateForm;\n      fixture.detectChanges();\n    });\n\n    it('should className correct', () => {\n      expect(cascader.nativeElement.className).not.toContain('ant-select-status-error');\n      expect(cascader.nativeElement.querySelector('nz-form-item-feedback-icon')).toBeNull();\n      formGroup.controls.demo.markAsDirty();\n      formGroup.controls.demo.setValue(null);\n      formGroup.controls.demo.updateValueAndValidity();\n      fixture.detectChanges();\n\n      // show error\n      expect(cascader.nativeElement.className).toContain('ant-select-status-error');\n      expect(cascader.nativeElement.querySelector('nz-form-item-feedback-icon')).toBeTruthy();\n      expect(cascader.nativeElement.querySelector('nz-form-item-feedback-icon').className).toContain(\n        'ant-form-item-feedback-icon-error'\n      );\n\n      formGroup.controls.demo.markAsDirty();\n      formGroup.controls.demo.setValue(['a', 'b']);\n      formGroup.controls.demo.updateValueAndValidity();\n      fixture.detectChanges();\n      // show success\n      expect(cascader.nativeElement.className).toContain('ant-select-status-success');\n      expect(cascader.nativeElement.querySelector('nz-form-item-feedback-icon')).toBeTruthy();\n      expect(cascader.nativeElement.querySelector('nz-form-item-feedback-icon').className).toContain(\n        'ant-form-item-feedback-icon-success'\n      );\n    });\n  });\n});\n\ndescribe('finalSize', () => {\n  let fixture: ComponentFixture<NzDemoCascaderDefaultComponent>;\n  let cascaderElement: HTMLElement;\n  let compactSizeSignal: WritableSignal<NzSizeLDSType>;\n  let formSizeSignal: WritableSignal<NzSizeLDSType>;\n\n  beforeEach(() => {\n    compactSizeSignal = signal<NzSizeLDSType>('large');\n    formSizeSignal = signal<NzSizeLDSType>('default');\n  });\n  afterEach(() => {\n    TestBed.resetTestingModule();\n  });\n\n  it('should set correctly the size from the formSize signal', () => {\n    TestBed.configureTestingModule({\n      providers: [\n        { provide: NZ_FORM_SIZE, useValue: formSizeSignal },\n        { provide: NZ_SPACE_COMPACT_SIZE, useValue: compactSizeSignal }\n      ]\n    });\n    fixture = TestBed.createComponent(NzDemoCascaderDefaultComponent);\n    cascaderElement = fixture.debugElement.query(By.directive(NzCascaderComponent)).nativeElement;\n    fixture.detectChanges();\n    formSizeSignal.set('large');\n    fixture.detectChanges();\n    expect(cascaderElement.classList).toContain('ant-select-lg');\n  });\n  it('should set correctly the size from the compactSize signal', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_SPACE_COMPACT_SIZE, useValue: compactSizeSignal }]\n    });\n    fixture = TestBed.createComponent(NzDemoCascaderDefaultComponent);\n    cascaderElement = fixture.debugElement.query(By.directive(NzCascaderComponent)).nativeElement;\n    fixture.detectChanges();\n    expect(cascaderElement.classList).toContain('ant-select-lg');\n  });\n  it('should set correctly the size from the component input', () => {\n    fixture = TestBed.createComponent(NzDemoCascaderDefaultComponent);\n    cascaderElement = fixture.debugElement.query(By.directive(NzCascaderComponent)).nativeElement;\n    fixture.componentInstance.nzSize = 'large';\n    fixture.detectChanges();\n    expect(cascaderElement.classList).toContain('ant-select-lg');\n  });\n});\n\ndescribe('finalVariant', () => {\n  let fixture: ComponentFixture<TestCascaderFinalVariantComponent>;\n  let cascaderElement: HTMLElement;\n  let formVariantSignal: WritableSignal<NzVariant>;\n\n  beforeEach(() => {\n    formVariantSignal = signal<NzVariant>('outlined');\n  });\n\n  afterEach(() => {\n    TestBed.resetTestingModule();\n  });\n\n  it('should use formVariant when nzVariant is not set (default)', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_FORM_VARIANT, useValue: formVariantSignal }]\n    });\n    fixture = TestBed.createComponent(TestCascaderFinalVariantComponent);\n    cascaderElement = fixture.debugElement.query(By.directive(NzCascaderComponent)).nativeElement;\n    fixture.detectChanges();\n    formVariantSignal.set('filled');\n    fixture.detectChanges();\n    expect(cascaderElement.classList).toContain('ant-select-filled');\n  });\n\n  it('should use nzVariant over formVariant when nzVariant is explicitly set', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_FORM_VARIANT, useValue: formVariantSignal }]\n    });\n    fixture = TestBed.createComponent(TestCascaderFinalVariantComponent);\n    cascaderElement = fixture.debugElement.query(By.directive(NzCascaderComponent)).nativeElement;\n    fixture.componentInstance.variant.set('borderless');\n    fixture.detectChanges();\n    formVariantSignal.set('filled');\n    fixture.detectChanges();\n    expect(cascaderElement.classList).toContain('ant-select-borderless');\n    expect(cascaderElement.classList).not.toContain('ant-select-filled');\n  });\n\n  it('should use nzVariant when no formVariant is provided', () => {\n    fixture = TestBed.createComponent(TestCascaderFinalVariantComponent);\n    cascaderElement = fixture.debugElement.query(By.directive(NzCascaderComponent)).nativeElement;\n    fixture.componentInstance.variant.set('filled');\n    fixture.detectChanges();\n    expect(cascaderElement.classList).toContain('ant-select-filled');\n  });\n\n  it('should use outlined as default when neither nzVariant nor formVariant is provided', () => {\n    fixture = TestBed.createComponent(TestCascaderFinalVariantComponent);\n    cascaderElement = fixture.debugElement.query(By.directive(NzCascaderComponent)).nativeElement;\n    fixture.detectChanges();\n    expect(cascaderElement.classList).not.toContain('ant-select-filled');\n    expect(cascaderElement.classList).not.toContain('ant-select-borderless');\n    expect(cascaderElement.classList).not.toContain('ant-select-underlined');\n  });\n\n  it('should use explicitly set outlined over formVariant', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_FORM_VARIANT, useValue: formVariantSignal }]\n    });\n    fixture = TestBed.createComponent(TestCascaderFinalVariantComponent);\n    cascaderElement = fixture.debugElement.query(By.directive(NzCascaderComponent)).nativeElement;\n    fixture.componentInstance.variant.set('outlined');\n    fixture.detectChanges();\n    formVariantSignal.set('filled');\n    fixture.detectChanges();\n    expect(cascaderElement.classList).not.toContain('ant-select-filled');\n  });\n});\n\nconst ID_NAME_LIST = [\n  {\n    id: 1,\n    name: 'Zhejiang',\n    children: [\n      {\n        id: 2,\n        name: 'Hangzhou',\n        children: [\n          {\n            id: 3,\n            name: 'West Lake',\n            isLeaf: true\n          }\n        ]\n      }\n    ]\n  }\n];\n\nconst options1: NzCascaderOption[] = [\n  {\n    value: 'zhejiang',\n    label: 'Zhejiang',\n    v: 'zhejiang-new',\n    l: 'Zhejiang New',\n    children: [\n      {\n        value: 'hangzhou',\n        label: 'Hangzhou',\n        v: 'hangzhou-new',\n        l: 'Hangzhou New',\n        children: [\n          {\n            value: 'xihu',\n            label: 'West Lake',\n            v: 'xihu-new',\n            l: 'West Lake New',\n            isLeaf: true\n          }\n        ]\n      },\n      {\n        value: 'ningbo',\n        label: 'Ningbo',\n        v: 'ningbo-new',\n        l: 'Ningbo New',\n        isLeaf: true\n      }\n    ]\n  },\n  {\n    value: 'jiangsu',\n    label: 'Jiangsu',\n    v: 'jiangsu-new',\n    l: 'Jiangsu New',\n    children: [\n      {\n        value: 'nanjing',\n        label: 'Nanjing',\n        v: 'nanjing-new',\n        l: 'Nanjing New',\n        children: [\n          {\n            value: 'zhonghuamen',\n            label: 'Zhong Hua Men',\n            v: 'zhonghuamen-new',\n            l: 'Zhong Hua Men New',\n            isLeaf: true\n          }\n        ]\n      }\n    ]\n  }\n];\n\nconst options2 = [\n  {\n    value: 'option1',\n    label: 'Option1',\n    children: [\n      {\n        value: 'option11',\n        label: 'Option11',\n        disabled: true,\n        isLeaf: true\n      },\n      {\n        value: 'option12',\n        label: 'Option12',\n        isLeaf: true\n      },\n      {\n        value: 'option13',\n        label: 'Option13',\n        disabled: true,\n        isLeaf: true\n      },\n      {\n        value: 'option14',\n        label: 'Option14',\n        isLeaf: true\n      }\n    ]\n  },\n  {\n    value: 'option2',\n    label: 'Option2',\n    disabled: true,\n    children: [\n      {\n        value: 'option21',\n        label: 'Option21',\n        isLeaf: true\n      },\n      {\n        value: 'option22',\n        label: 'Option22',\n        isLeaf: true\n      }\n    ]\n  }\n];\n\nconst options3 = [\n  {\n    value: 'zhejiang',\n    label: 'Zhejiang',\n    children: [\n      {\n        value: 'hangzhou',\n        label: 'Hangzhou',\n        children: [\n          {\n            value: 'xihu',\n            label: 'West Lake',\n            isLeaf: true\n          }\n        ]\n      },\n      {\n        value: 'ningbo',\n        label: 'Ningbo',\n        isLeaf: true\n      }\n    ]\n  },\n  {\n    value: 'jiangsu',\n    label: 'Jiangsu',\n    children: [\n      {\n        value: 'nanjing',\n        label: 'Nanjing',\n        children: [\n          {\n            value: 'zhonghuamen',\n            label: 'Zhong Hua Men',\n            isLeaf: true\n          }\n        ]\n      },\n      {\n        value: 'suzhou',\n        label: 'Suzhou',\n        isLeaf: true\n      }\n    ]\n  }\n];\n\nconst options4 = [\n  {\n    value: 'zhejiang',\n    label: 'Zhejiang',\n    children: [\n      {\n        value: 'hangzhou',\n        label: 'Hangzhou',\n        disabled: true,\n        children: [\n          {\n            value: 'xihu',\n            label: 'West Lake',\n            isLeaf: true\n          }\n        ]\n      },\n      {\n        value: 'ningbo',\n        label: 'Ningbo',\n        isLeaf: true\n      }\n    ]\n  },\n  {\n    value: 'jiangsu',\n    label: 'Jiangsu',\n    disabled: true,\n    children: [\n      {\n        value: 'nanjing',\n        label: 'Nanjing',\n        children: [\n          {\n            value: 'zhonghuamen',\n            label: 'Zhong Hua Men',\n            isLeaf: true\n          }\n        ]\n      }\n    ]\n  }\n];\n\nconst options5: NzSafeAny[] = [];\n\n@Component({\n  imports: [FormsModule, NzCascaderModule],\n  selector: 'nz-test-cascader-default',\n  template: `\n    <nz-cascader\n      [(ngModel)]=\"values\"\n      [nzOpen]=\"nzOpen\"\n      [nzOptions]=\"nzOptions\"\n      [nzAllowClear]=\"nzAllowClear\"\n      [nzAutoFocus]=\"nzAutoFocus\"\n      [nzChangeOn]=\"nzChangeOn\"\n      [nzChangeOnSelect]=\"nzChangeOnSelect\"\n      [nzColumnClassName]=\"nzColumnClassName\"\n      [nzDisabled]=\"nzDisabled\"\n      [nzExpandIcon]=\"nzExpandIcon\"\n      [nzExpandTrigger]=\"nzExpandTrigger\"\n      [nzLabelProperty]=\"nzLabelProperty\"\n      [nzValueProperty]=\"nzValueProperty\"\n      [nzLabelRender]=\"nzLabelRender\"\n      [nzMenuClassName]=\"nzMenuClassName\"\n      [nzMenuStyle]=\"nzMenuStyle\"\n      [nzMultiple]=\"nzMultiple\"\n      [nzMouseEnterDelay]=\"nzMouseEnterDelay\"\n      [nzMouseLeaveDelay]=\"nzMouseLeaveDelay\"\n      [nzPlaceHolder]=\"nzPlaceHolder\"\n      [nzShowArrow]=\"nzShowArrow\"\n      [nzShowInput]=\"nzShowInput\"\n      [nzShowSearch]=\"nzShowSearch\"\n      [nzSize]=\"nzSize\"\n      [nzTriggerAction]=\"nzTriggerAction\"\n      [nzPrefix]=\"nzPrefix\"\n      [nzSuffixIcon]=\"nzSuffixIcon\"\n      [nzBackdrop]=\"nzBackdrop\"\n      [nzPlacement]=\"nzPlacement\"\n      [nzVariant]=\"nzVariant\"\n      (ngModelChange)=\"onValueChanges($event)\"\n      (nzVisibleChange)=\"onVisibleChange($event)\"\n      (nzClear)=\"onClear()\"\n    />\n\n    <ng-template #renderTpl let-labels=\"labels\">\n      @for (label of labels; track $index) {\n        {{ label }}{{ $last ? '' : ' | ' }}\n      }\n    </ng-template>\n  `\n})\nexport class NzDemoCascaderDefaultComponent {\n  @ViewChild(NzCascaderComponent, { static: true }) cascader!: NzCascaderComponent;\n  @ViewChild('renderTpl', { static: true }) renderTpl!: TemplateRef<NzSafeAny>;\n\n  nzOptions: NzSafeAny[] | null = options1;\n  values: string[] | string[][] | number[] | null = null;\n\n  nzOpen: boolean | undefined;\n  nzMultiple = false;\n  nzAllowClear = true;\n  nzAutoFocus = false;\n  nzMenuClassName = 'menu-classA menu-classB';\n  nzColumnClassName = 'column-classA column-classB';\n  nzMenuStyle = { height: '120px' };\n  nzExpandTrigger: NzCascaderExpandTrigger = 'click';\n  nzDisabled = false;\n  nzLabelProperty: string = 'label';\n  nzValueProperty: string = 'value';\n  nzPlaceHolder = 'please select';\n  nzShowArrow = true;\n  nzShowInput = true;\n  nzShowSearch: boolean | NzShowSearchOptions = false;\n  nzSize: NzCascaderSize = 'default';\n  nzLabelRender: TemplateRef<NzSafeAny> | null = null;\n  nzChangeOn: NzSafeAny = null;\n  nzChangeOnSelect = false;\n  nzTriggerAction: NzCascaderTriggerType | NzCascaderTriggerType[] = 'click';\n  nzMouseEnterDelay = 150; // ms\n  nzMouseLeaveDelay = 150; // ms\n  nzPrefix: string | null = null;\n  nzSuffixIcon = 'down';\n  nzExpandIcon = 'right';\n  nzBackdrop = false;\n  nzPlacement: NzCascaderPlacement = 'bottomLeft';\n  nzVariant: NzVariant = 'outlined';\n\n  onVisibleChange = jasmine.createSpy<(visible: boolean) => void>('open change');\n  onValueChanges = jasmine.createSpy('value change');\n  onClear(): void {}\n  fakeChangeOn = (node: NzSafeAny, _index: number): boolean => node.value === 'zhejiang';\n}\n\n@Component({\n  imports: [FormsModule, NzCascaderModule],\n  template: `\n    <nz-cascader\n      [(ngModel)]=\"values\"\n      [nzLoadData]=\"nzLoadData\"\n      (ngModelChange)=\"onValueChanges($event)\"\n      (nzVisibleChange)=\"onVisibleChange($event)\"\n    />\n  `\n})\nexport class NzDemoCascaderLoadDataComponent {\n  @ViewChild(NzCascaderComponent, { static: true }) cascader!: NzCascaderComponent;\n\n  values: string[] | null = null;\n\n  nzLoadData = (node: NzSafeAny, index: number): PromiseLike<NzSafeAny> => {\n    this.addCallTimes();\n    return new Promise((resolve, reject) => {\n      setTimeout(() => {\n        if (index < 0) {\n          // if index less than 0 it is root node\n          node.children = [\n            {\n              value: 'zhejiang',\n              label: 'Zhejiang'\n            }\n          ];\n          resolve(null);\n        } else if (index === 0) {\n          node.children = [\n            {\n              value: 'hangzhou',\n              label: 'Hangzhou'\n            }\n          ];\n          resolve(null);\n        } else if (index === 1) {\n          node.children = [\n            {\n              value: 'xihu',\n              label: 'West Lake'\n            }\n          ];\n          resolve(null);\n        } else {\n          reject();\n        }\n      }, 500);\n    });\n  };\n\n  addCallTimes(): void {}\n  onVisibleChange = jasmine.createSpy<(visible: boolean) => void>('open change');\n  onValueChanges = jasmine.createSpy('value change');\n}\n\n@Component({\n  imports: [BidiModule, NzCascaderModule],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-cascader [nzOptions]=\"nzOptions\" />\n    </div>\n  `\n})\nexport class NzDemoCascaderRtlComponent {\n  @ViewChild(NzCascaderComponent, { static: true }) cascader!: NzCascaderComponent;\n  nzOptions: NzSafeAny[] | null = options1;\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n}\n\n@Component({\n  imports: [FormsModule, NzCascaderModule],\n  template: `<nz-cascader [nzOptions]=\"nzOptions\" [nzStatus]=\"status\" />`\n})\nexport class NzDemoCascaderStatusComponent {\n  nzOptions: NzSafeAny[] | null = options1;\n  status: NzStatus = 'error';\n}\n\n@Component({\n  imports: [ReactiveFormsModule, NzFormModule, NzCascaderModule],\n  template: `\n    <form nz-form [formGroup]=\"validateForm\">\n      <nz-form-item>\n        <nz-form-control nzHasFeedback>\n          <nz-cascader formControlName=\"demo\" [nzOptions]=\"nzOptions\" />\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `\n})\nexport class NzDemoCascaderInFormComponent {\n  private fb = inject(FormBuilder);\n  validateForm = this.fb.group({\n    demo: this.fb.control<string[] | null>(null, Validators.required)\n  });\n  nzOptions: NzSafeAny[] | null = options1;\n}\n\n@Component({\n  imports: [NzCascaderModule],\n  template: ` <nz-cascader [nzVariant]=\"variant()\" /> `\n})\nexport class TestCascaderFinalVariantComponent {\n  readonly variant = signal<NzVariant | undefined>(undefined);\n}\n"
  },
  {
    "path": "components/cascader/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n省市区级联。\n\n## en-US\n\nCascade selection box for selecting province/city/district.\n"
  },
  {
    "path": "components/cascader/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCascaderModule, NzCascaderOption } from 'ng-zorro-antd/cascader';\n\nconst options: NzCascaderOption[] = [\n  {\n    value: 'zhejiang',\n    label: 'Zhejiang',\n    children: [\n      {\n        value: 'hangzhou',\n        label: 'Hangzhou',\n        children: [\n          {\n            value: 'xihu',\n            label: 'West Lake',\n            isLeaf: true\n          }\n        ]\n      },\n      {\n        value: 'ningbo',\n        label: 'Ningbo',\n        isLeaf: true\n      }\n    ]\n  },\n  {\n    value: 'jiangsu',\n    label: 'Jiangsu',\n    children: [\n      {\n        value: 'nanjing',\n        label: 'Nanjing',\n        children: [\n          {\n            value: 'zhonghuamen',\n            label: 'Zhong Hua Men',\n            isLeaf: true\n          }\n        ]\n      }\n    ]\n  }\n];\n\n@Component({\n  selector: 'nz-demo-cascader-basic',\n  imports: [FormsModule, NzCascaderModule],\n  template: `<nz-cascader [nzOptions]=\"nzOptions\" [(ngModel)]=\"values\" (ngModelChange)=\"onChanges($event)\" />`\n})\nexport class NzDemoCascaderBasicComponent {\n  readonly nzOptions: NzCascaderOption[] = options;\n  values: string[] | null = null;\n\n  onChanges(values: string): void {\n    console.log(values, this.values);\n  }\n}\n"
  },
  {
    "path": "components/cascader/demo/change-on-function.md",
    "content": "---\norder: 10\ntitle:\n  zh-CN: 指定选择\n  en-US: Select specified\n---\n\n## zh-CN\n\n通过函数来判断选项是否可以选择。\n\n## en-US\n\nAllow select option only on `nzChangeOn` return true.\n"
  },
  {
    "path": "components/cascader/demo/change-on-function.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCascaderModule, NzCascaderOption } from 'ng-zorro-antd/cascader';\n\nconst options: NzCascaderOption[] = [\n  {\n    value: 'zhejiang',\n    label: 'Zhejiang',\n    children: [\n      {\n        value: 'hangzhou',\n        label: 'Hangzhou',\n        children: [\n          {\n            value: 'xihu',\n            label: 'West Lake',\n            isLeaf: true\n          }\n        ]\n      },\n      {\n        value: 'ningbo',\n        label: 'Ningbo',\n        children: [\n          {\n            value: 'dongqianlake',\n            label: 'Dongqian Lake',\n            isLeaf: true\n          }\n        ]\n      }\n    ]\n  },\n  {\n    value: 'jiangsu',\n    label: 'Jiangsu',\n    children: [\n      {\n        value: 'nanjing',\n        label: 'Nanjing',\n        children: [\n          {\n            value: 'zhonghuamen',\n            label: 'Zhong Hua Men',\n            isLeaf: true\n          }\n        ]\n      }\n    ]\n  }\n];\n\n@Component({\n  selector: 'nz-demo-cascader-change-on-function',\n  imports: [FormsModule, NzCascaderModule],\n  template: `\n    <nz-cascader\n      [nzChangeOn]=\"validate\"\n      [nzOptions]=\"nzOptions\"\n      [(ngModel)]=\"values\"\n      (ngModelChange)=\"onChanges($event)\"\n    />\n  `\n})\nexport class NzDemoCascaderChangeOnFunctionComponent {\n  readonly nzOptions: NzCascaderOption[] = options;\n  values: string[] | null = null;\n\n  onChanges(values: string[]): void {\n    console.log(values, this.values);\n  }\n\n  validate(option: NzCascaderOption, _index: number): boolean {\n    const value = option.value as string;\n    return ['hangzhou', 'xihu', 'nanjing', 'zhonghuamen'].indexOf(value) >= 0;\n  }\n}\n"
  },
  {
    "path": "components/cascader/demo/change-on-select.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 选择即改变\n  en-US: Change on select\n---\n\n## zh-CN\n\n这种交互允许只选中父级选项。\n\n## en-US\n\nAllow only select parent options.\n"
  },
  {
    "path": "components/cascader/demo/change-on-select.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCascaderModule, NzCascaderOption } from 'ng-zorro-antd/cascader';\n\nconst options: NzCascaderOption[] = [\n  {\n    value: 'zhejiang',\n    label: 'Zhejiang',\n    children: [\n      {\n        value: 'hangzhou',\n        label: 'Hangzhou',\n        children: [\n          {\n            value: 'xihu',\n            label: 'West Lake',\n            isLeaf: true\n          }\n        ]\n      },\n      {\n        value: 'ningbo',\n        label: 'Ningbo',\n        isLeaf: true\n      }\n    ]\n  },\n  {\n    value: 'jiangsu',\n    label: 'Jiangsu',\n    children: [\n      {\n        value: 'nanjing',\n        label: 'Nanjing',\n        children: [\n          {\n            value: 'zhonghuamen',\n            label: 'Zhong Hua Men',\n            isLeaf: true\n          }\n        ]\n      }\n    ]\n  }\n];\n\n@Component({\n  selector: 'nz-demo-cascader-change-on-select',\n  imports: [FormsModule, NzCascaderModule],\n  template: `\n    <nz-cascader nzChangeOnSelect [nzOptions]=\"nzOptions\" [(ngModel)]=\"values\" (ngModelChange)=\"onChanges($event)\" />\n  `\n})\nexport class NzDemoCascaderChangeOnSelectComponent {\n  readonly nzOptions: NzCascaderOption[] = options;\n  values: string[] | null = null;\n\n  onChanges(values: string[]): void {\n    console.log(values, this.values);\n  }\n}\n"
  },
  {
    "path": "components/cascader/demo/custom-field-names.md",
    "content": "---\norder: 16\ntitle:\n  zh-CN: 自定义字段名\n  en-US: Custom Field Names\n---\n\n## zh-CN\n\n自定义字段名。\n\n## en-US\n\nCustom field names.\n"
  },
  {
    "path": "components/cascader/demo/custom-field-names.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCascaderModule, NzCascaderOption } from 'ng-zorro-antd/cascader';\n\nconst options = [\n  {\n    code: 'zhejiang',\n    name: 'Zhejiang',\n    children: [\n      {\n        code: 'hangzhou',\n        name: 'Hangzhou',\n        children: [\n          {\n            code: 'xihu',\n            name: 'West Lake',\n            isLeaf: true\n          }\n        ]\n      },\n      {\n        code: 'ningbo',\n        name: 'Ningbo',\n        children: [\n          {\n            code: 'dongqianlake',\n            name: 'Dongqian Lake',\n            isLeaf: true\n          }\n        ]\n      }\n    ]\n  },\n  {\n    code: 'jiangsu',\n    name: 'Jiangsu',\n    children: [\n      {\n        code: 'nanjing',\n        name: 'Nanjing',\n        children: [\n          {\n            code: 'zhonghuamen',\n            name: 'Zhong Hua Men',\n            isLeaf: true\n          }\n        ]\n      }\n    ]\n  }\n];\n\n@Component({\n  selector: 'nz-demo-cascader-custom-field-names',\n  imports: [FormsModule, NzCascaderModule],\n  template: `\n    <nz-cascader\n      [nzChangeOn]=\"validate\"\n      [nzOptions]=\"nzOptions\"\n      nzLabelProperty=\"name\"\n      nzValueProperty=\"code\"\n      [nzShowSearch]=\"true\"\n      [(ngModel)]=\"values\"\n      (ngModelChange)=\"onChanges($event)\"\n    />\n  `\n})\nexport class NzDemoCascaderCustomFieldNamesComponent {\n  readonly nzOptions: NzCascaderOption[] = options;\n  values: string[] | null = null;\n\n  onChanges(values: string[]): void {\n    console.log(values, this.values);\n  }\n\n  validate(option: NzCascaderOption, _index: number): boolean {\n    const value = option.value as string;\n    return ['hangzhou', 'xihu', 'nanjing', 'zhonghuamen'].indexOf(value) >= 0;\n  }\n}\n"
  },
  {
    "path": "components/cascader/demo/custom-render.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 自定义已选项\n  en-US: Custom render\n---\n\n## zh-CN\n\n例如给最后一项加上邮编链接。\n\n## en-US\n\nFor instance, add an external link after the selected value.\n"
  },
  {
    "path": "components/cascader/demo/custom-render.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCascaderModule, NzCascaderOption } from 'ng-zorro-antd/cascader';\n\nconst options: NzCascaderOption[] = [\n  {\n    value: 'zhejiang',\n    label: 'Zhejiang',\n    children: [\n      {\n        value: 'hangzhou',\n        label: 'Hangzhou',\n        children: [\n          {\n            value: 'xihu',\n            label: 'West Lake',\n            code: 752100,\n            isLeaf: true\n          }\n        ]\n      },\n      {\n        value: 'ningbo',\n        label: 'Ningbo',\n        code: '315000',\n        isLeaf: true\n      }\n    ]\n  },\n  {\n    value: 'jiangsu',\n    label: 'Jiangsu',\n    children: [\n      {\n        value: 'nanjing',\n        label: 'Nanjing',\n        children: [\n          {\n            value: 'zhonghuamen',\n            label: 'Zhong Hua Men',\n            code: 453400,\n            isLeaf: true\n          }\n        ]\n      }\n    ]\n  }\n];\n\n@Component({\n  selector: 'nz-demo-cascader-custom-render',\n  imports: [FormsModule, NzCascaderModule],\n  template: `\n    <nz-cascader\n      style=\"width: 100%;\"\n      [nzLabelRender]=\"renderTpl\"\n      [nzOptions]=\"nzOptions\"\n      [(ngModel)]=\"values\"\n      (ngModelChange)=\"onChanges($event)\"\n    />\n\n    <ng-template #renderTpl let-labels=\"labels\" let-selectedOptions=\"selectedOptions\">\n      @for (label of labels; track label) {\n        @if (!$last) {\n          <span>{{ label }} /</span>\n        } @else {\n          <span>\n            {{ label }} (\n            <a href=\"javascript:;\" (click)=\"handleAreaClick($event, label, selectedOptions[$index])\">\n              {{ selectedOptions[$index].code }}\n            </a>\n            )\n          </span>\n        }\n      }\n    </ng-template>\n  `\n})\nexport class NzDemoCascaderCustomRenderComponent {\n  readonly nzOptions: NzCascaderOption[] = options;\n  values: string[] | null = null;\n\n  onChanges(values: string[]): void {\n    console.log(values, this.values);\n  }\n\n  handleAreaClick(e: Event, label: string, option: NzCascaderOption): void {\n    e.preventDefault();\n    e.stopPropagation();\n    console.log('clicked \"', label, '\"', option);\n  }\n}\n"
  },
  {
    "path": "components/cascader/demo/custom-template.md",
    "content": "---\norder: 17\ntitle:\n  zh-CN: 自定义选择项\n  en-US: Custom option template\n---\n\n## zh-CN\n\n自定义选项的模板。\n\n## en-US\n\nCustom cascader option template.\n"
  },
  {
    "path": "components/cascader/demo/custom-template.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCascaderModule, NzCascaderOption } from 'ng-zorro-antd/cascader';\n\nconst options: NzCascaderOption[] = [\n  {\n    label: 'Ant Design',\n    value: 'antd',\n    children: [\n      {\n        label: 'ng-zorro-antd',\n        value: 'ng-zorro-antd',\n        isLeaf: true\n      }\n    ]\n  },\n  {\n    label: 'Angular',\n    value: 'angular',\n    children: [\n      {\n        label: 'CDK',\n        value: 'cdk',\n        isLeaf: true\n      }\n    ]\n  }\n];\n\n@Component({\n  selector: 'nz-demo-cascader-custom-template',\n  imports: [FormsModule, NzCascaderModule],\n  template: `\n    <nz-cascader\n      [nzOptionRender]=\"renderTpl\"\n      [nzOptions]=\"nzOptions\"\n      [(ngModel)]=\"values\"\n      (ngModelChange)=\"onChanges($event)\"\n    />\n    <ng-template #renderTpl let-option let-index=\"index\">{{ index + 1 }}. {{ option.label }}</ng-template>\n  `\n})\nexport class NzDemoCascaderCustomTemplateComponent {\n  readonly nzOptions = options;\n  values: string[] | null = null;\n\n  onChanges(values: string): void {\n    console.log(values, this.values);\n  }\n}\n"
  },
  {
    "path": "components/cascader/demo/default-value-and-async-options.md",
    "content": "---\norder: 14\ntitle:\n  zh-CN: 默认值与异步列表\n  en-US: Default value and async options\n---\n\n## zh-CN\n\n默认值通过数组的方式指定，但`nzOptions`通过异步加载。\n\n## en-US\n\nSpecifies default value by an array, and setting `nzOptions` in a asynchronous way.\n"
  },
  {
    "path": "components/cascader/demo/default-value-and-async-options.ts",
    "content": "import { Component, OnInit, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCascaderModule, NzCascaderOption } from 'ng-zorro-antd/cascader';\n\nconst options: NzCascaderOption[] = [\n  {\n    value: 'zhejiang',\n    label: 'Zhejiang',\n    children: [\n      {\n        value: 'hangzhou',\n        label: 'Hangzhou',\n        children: [\n          {\n            value: 'xihu',\n            label: 'West Lake',\n            isLeaf: true\n          }\n        ]\n      },\n      {\n        value: 'ningbo',\n        label: 'Ningbo',\n        isLeaf: true\n      }\n    ]\n  },\n  {\n    value: 'jiangsu',\n    label: 'Jiangsu',\n    children: [\n      {\n        value: 'nanjing',\n        label: 'Nanjing',\n        children: [\n          {\n            value: 'zhonghuamen',\n            label: 'Zhong Hua Men',\n            isLeaf: true\n          }\n        ]\n      }\n    ]\n  }\n];\n\n@Component({\n  selector: 'nz-demo-cascader-default-value-and-async-options',\n  imports: [FormsModule, NzCascaderModule],\n  template: `<nz-cascader [(ngModel)]=\"values\" [nzOptions]=\"nzOptions()\" (ngModelChange)=\"onChanges($event)\" />`\n})\nexport class NzDemoCascaderDefaultValueAndAsyncOptionsComponent implements OnInit {\n  readonly nzOptions = signal<NzCascaderOption[] | null>(null);\n  values: string[] = ['zhejiang', 'hangzhou', 'xihu'];\n\n  onChanges(values: string[]): void {\n    console.log(values, this.values);\n  }\n\n  ngOnInit(): void {\n    setTimeout(() => this.nzOptions.set(options), 500);\n  }\n}\n"
  },
  {
    "path": "components/cascader/demo/default-value-and-lazy-load.md",
    "content": "---\norder: 13\ntitle:\n  zh-CN: 默认值与延迟加载\n  en-US: Default value and Lazy load\n---\n\n## zh-CN\n\n默认值通过数组的方式指定，但`nzOptions`没有赋值，通过`nzLoadData`函数延迟加载。\n\n## en-US\n\nSpecifies default value by an array, but `nzOptions` is `null`/empty, data are loaded by `nzLoadData` function.\n"
  },
  {
    "path": "components/cascader/demo/default-value-and-lazy-load.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCascaderModule, NzCascaderOption } from 'ng-zorro-antd/cascader';\n\nconst provinces = [\n  {\n    value: 'zhejiang',\n    label: 'Zhejiang'\n  },\n  {\n    value: 'jiangsu',\n    label: 'Jiangsu'\n  }\n];\n\nconst cities: { [key: string]: Array<{ value: string; label: string; isLeaf?: boolean }> } = {\n  zhejiang: [\n    {\n      value: 'hangzhou',\n      label: 'Hangzhou'\n    },\n    {\n      value: 'ningbo',\n      label: 'Ningbo',\n      isLeaf: true\n    }\n  ],\n  jiangsu: [\n    {\n      value: 'nanjing',\n      label: 'Nanjing'\n    }\n  ]\n};\n\nconst scenicspots: { [key: string]: Array<{ value: string; label: string; isLeaf?: boolean }> } = {\n  hangzhou: [\n    {\n      value: 'xihu',\n      label: 'West Lake',\n      isLeaf: true\n    }\n  ],\n  nanjing: [\n    {\n      value: 'zhonghuamen',\n      label: 'Zhong Hua Men',\n      isLeaf: true\n    }\n  ]\n};\n\n@Component({\n  selector: 'nz-demo-cascader-default-value-and-lazy-load',\n  imports: [FormsModule, NzCascaderModule],\n  template: `<nz-cascader [(ngModel)]=\"values\" [nzLoadData]=\"loadData\" (ngModelChange)=\"onChanges($event)\" />`\n})\nexport class NzDemoCascaderDefaultValueAndLazyLoadComponent {\n  values: string[] = ['zhejiang', 'hangzhou', 'xihu'];\n\n  onChanges(values: string[]): void {\n    console.log(values, this.values);\n  }\n\n  /** load data async execute by `nzLoadData` method */\n  loadData(node: NzCascaderOption, index: number): PromiseLike<void> {\n    return new Promise(resolve => {\n      setTimeout(() => {\n        if (index < 0) {\n          // if index less than 0 it is root node\n          node.children = provinces;\n        } else if (index === 0) {\n          node.children = cities[node.value];\n        } else {\n          node.children = scenicspots[node.value];\n        }\n        resolve();\n      }, 1000);\n    });\n  }\n}\n"
  },
  {
    "path": "components/cascader/demo/default-value.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 默认值\n  en-US: Default value\n---\n\n## zh-CN\n\n默认值通过数组的方式指定。\n\n## en-US\n\nSpecifies default value by an array.\n"
  },
  {
    "path": "components/cascader/demo/default-value.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCascaderModule, NzCascaderOption } from 'ng-zorro-antd/cascader';\n\nconst options: NzCascaderOption[] = [\n  {\n    value: 'zhejiang',\n    label: 'Zhejiang',\n    children: [\n      {\n        value: 'hangzhou',\n        label: 'Hangzhou',\n        children: [\n          {\n            value: 'xihu',\n            label: 'West Lake',\n            isLeaf: true\n          }\n        ]\n      },\n      {\n        value: 'ningbo',\n        label: 'Ningbo',\n        isLeaf: true\n      }\n    ]\n  },\n  {\n    value: 'jiangsu',\n    label: 'Jiangsu',\n    children: [\n      {\n        value: 'nanjing',\n        label: 'Nanjing',\n        children: [\n          {\n            value: 'zhonghuamen',\n            label: 'Zhong Hua Men',\n            isLeaf: true\n          }\n        ]\n      }\n    ]\n  }\n];\n\n@Component({\n  selector: 'nz-demo-cascader-default-value',\n  imports: [FormsModule, NzCascaderModule],\n  template: `<nz-cascader [nzOptions]=\"nzOptions\" [(ngModel)]=\"values\" (ngModelChange)=\"onChanges($event)\" />`\n})\nexport class NzDemoCascaderDefaultValueComponent {\n  readonly nzOptions: NzCascaderOption[] = options;\n  values: string[] = ['zhejiang', 'hangzhou', 'xihu'];\n\n  onChanges(values: string[]): void {\n    console.log(values, this.values);\n  }\n}\n"
  },
  {
    "path": "components/cascader/demo/disabled.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 禁用选项\n  en-US: Disabled option\n---\n\n## zh-CN\n\n通过指定 options 里的 `disabled` 字段。\n\n## en-US\n\nDisable option by specifying the `disabled` property in `options`.\n"
  },
  {
    "path": "components/cascader/demo/disabled.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCascaderModule, NzCascaderOption } from 'ng-zorro-antd/cascader';\n\nconst options: NzCascaderOption[] = [\n  {\n    value: 'zhejiang',\n    label: 'Zhejiang',\n    children: [\n      {\n        value: 'hangzhou',\n        label: 'Hangzhou',\n        children: [\n          {\n            value: 'xihu',\n            label: 'West Lake',\n            isLeaf: true\n          }\n        ]\n      },\n      {\n        value: 'ningbo',\n        label: 'Ningbo',\n        isLeaf: true\n      }\n    ]\n  },\n  {\n    value: 'jiangsu',\n    label: 'Jiangsu',\n    disabled: true,\n    children: [\n      {\n        value: 'nanjing',\n        label: 'Nanjing',\n        children: [\n          {\n            value: 'zhonghuamen',\n            label: 'Zhong Hua Men',\n            isLeaf: true\n          }\n        ]\n      }\n    ]\n  }\n];\n\n@Component({\n  selector: 'nz-demo-cascader-disabled',\n  imports: [FormsModule, NzCascaderModule],\n  template: `<nz-cascader [nzOptions]=\"nzOptions\" [(ngModel)]=\"values\" (ngModelChange)=\"onChanges($event)\" />`\n})\nexport class NzDemoCascaderDisabledComponent {\n  readonly nzOptions: NzCascaderOption[] = options;\n  values: string[] | null = null;\n\n  onChanges(values: string[]): void {\n    console.log(values, this.values);\n  }\n}\n"
  },
  {
    "path": "components/cascader/demo/hover.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 移入展开\n  en-US: Hover\n---\n\n## zh-CN\n\n通过移入展开下级菜单，点击完成选择。\n\n## en-US\n\nHover to expand sub menu, click to select option.\n"
  },
  {
    "path": "components/cascader/demo/hover.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCascaderModule, NzCascaderOption } from 'ng-zorro-antd/cascader';\n\nconst options: NzCascaderOption[] = [\n  {\n    value: 'zhejiang',\n    label: 'Zhejiang',\n    children: [\n      {\n        value: 'hangzhou',\n        label: 'Hangzhou',\n        children: [\n          {\n            value: 'xihu',\n            label: 'West Lake',\n            isLeaf: true\n          }\n        ]\n      },\n      {\n        value: 'ningbo',\n        label: 'Ningbo',\n        isLeaf: true\n      }\n    ]\n  },\n  {\n    value: 'jiangsu',\n    label: 'Jiangsu',\n    children: [\n      {\n        value: 'nanjing',\n        label: 'Nanjing',\n        children: [\n          {\n            value: 'zhonghuamen',\n            label: 'Zhong Hua Men',\n            isLeaf: true\n          }\n        ]\n      }\n    ]\n  }\n];\n\n@Component({\n  selector: 'nz-demo-cascader-hover',\n  imports: [FormsModule, NzCascaderModule],\n  template: `\n    <nz-cascader\n      nzExpandTrigger=\"hover\"\n      [nzOptions]=\"nzOptions\"\n      [(ngModel)]=\"values\"\n      (ngModelChange)=\"onChanges($event)\"\n    />\n  `\n})\nexport class NzDemoCascaderHoverComponent {\n  readonly nzOptions: NzCascaderOption[] = options;\n  values: string[] | null = null;\n\n  onChanges(values: string[]): void {\n    console.log(values, this.values);\n  }\n}\n"
  },
  {
    "path": "components/cascader/demo/lazy.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 动态加载选项\n  en-US: Load Options Lazily\n---\n\n## zh-CN\n\n使用 `nzLoadData` 实现动态加载选项。\n\n## en-US\n\nLoad options lazily with `nzLoadData`.\n"
  },
  {
    "path": "components/cascader/demo/lazy.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCascaderModule, NzCascaderOption } from 'ng-zorro-antd/cascader';\n\nconst provinces = [\n  {\n    value: 'zhejiang',\n    label: 'Zhejiang'\n  },\n  {\n    value: 'jiangsu',\n    label: 'Jiangsu'\n  }\n];\n\nconst cities: { [key: string]: Array<{ value: string; label: string; isLeaf?: boolean }> } = {\n  zhejiang: [\n    {\n      value: 'hangzhou',\n      label: 'Hangzhou'\n    },\n    {\n      value: 'ningbo',\n      label: 'Ningbo',\n      isLeaf: true\n    }\n  ],\n  jiangsu: [\n    {\n      value: 'nanjing',\n      label: 'Nanjing'\n    }\n  ]\n};\n\nconst scenicspots: { [key: string]: Array<{ value: string; label: string; isLeaf?: boolean }> } = {\n  hangzhou: [\n    {\n      value: 'xihu',\n      label: 'West Lake',\n      isLeaf: true\n    }\n  ],\n  nanjing: [\n    {\n      value: 'zhonghuamen',\n      label: 'Zhong Hua Men',\n      isLeaf: true\n    }\n  ]\n};\n\n@Component({\n  selector: 'nz-demo-cascader-lazy',\n  imports: [FormsModule, NzCascaderModule],\n  template: `<nz-cascader [(ngModel)]=\"values\" [nzLoadData]=\"loadData\" (ngModelChange)=\"onChanges($event)\" />`\n})\nexport class NzDemoCascaderLazyComponent {\n  values: string[] | null = null;\n\n  onChanges(values: string[]): void {\n    console.log(values);\n  }\n\n  /** load data async execute by `nzLoadData` method */\n  loadData(node: NzCascaderOption, index: number): PromiseLike<void> {\n    return new Promise(resolve => {\n      setTimeout(() => {\n        if (index < 0) {\n          // if index less than 0 it is root node\n          node.children = provinces;\n        } else if (index === 0) {\n          node.children = cities[node.value];\n        } else {\n          node.children = scenicspots[node.value];\n        }\n        resolve();\n      }, 1000);\n    });\n  }\n}\n"
  },
  {
    "path": "components/cascader/demo/modal.md",
    "content": "---\norder: 11\ntitle:\n  zh-CN: 模态窗口\n  en-US: Modal Dialog\n---\n\n## zh-CN\n\n在模态窗口中使用级联控件。\n\n## en-US\n\nShow Cascade selection box in a modal dialog.\n"
  },
  {
    "path": "components/cascader/demo/modal.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzCascaderModule, NzCascaderOption } from 'ng-zorro-antd/cascader';\nimport { NzModalModule } from 'ng-zorro-antd/modal';\n\nconst options: NzCascaderOption[] = [\n  {\n    value: 'zhejiang',\n    label: 'Zhejiang',\n    children: [\n      {\n        value: 'hangzhou',\n        label: 'Hangzhou',\n        children: [\n          {\n            value: 'xihu',\n            label: 'West Lake',\n            isLeaf: true\n          }\n        ]\n      },\n      {\n        value: 'ningbo',\n        label: 'Ningbo',\n        isLeaf: true\n      }\n    ]\n  },\n  {\n    value: 'jiangsu',\n    label: 'Jiangsu',\n    children: [\n      {\n        value: 'nanjing',\n        label: 'Nanjing',\n        children: [\n          {\n            value: 'zhonghuamen',\n            label: 'Zhong Hua Men',\n            isLeaf: true\n          }\n        ]\n      }\n    ]\n  }\n];\n\n@Component({\n  selector: 'nz-demo-cascader-modal',\n  imports: [FormsModule, NzButtonModule, NzModalModule, NzCascaderModule],\n  template: `\n    <nz-modal\n      [(nzVisible)]=\"isVisible\"\n      nzTitle=\"Please select\"\n      (nzOnCancel)=\"handleCancel($event)\"\n      (nzOnOk)=\"handleOk($event)\"\n    >\n      <nz-cascader *nzModalContent [nzOptions]=\"nzOptions\" [(ngModel)]=\"values\" (ngModelChange)=\"onChanges($event)\" />\n    </nz-modal>\n\n    <button nz-button (click)=\"open()\">Open Dialog</button>\n  `\n})\nexport class NzDemoCascaderModalComponent {\n  nzOptions: NzCascaderOption[] = options;\n  values: string[] | null = null;\n  isVisible = false;\n\n  onChanges(values: string[]): void {\n    console.log(values, this.values);\n  }\n\n  open(): void {\n    this.isVisible = true;\n  }\n\n  handleOk($event: MouseEvent): void {\n    console.log('Button ok clicked!', this.values, $event);\n    this.isVisible = false;\n  }\n\n  handleCancel($event: MouseEvent): void {\n    console.log('Button cancel clicked!', $event);\n    this.isVisible = false;\n  }\n}\n"
  },
  {
    "path": "components/cascader/demo/multiple.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 多选\n  en-US: Multiple\n---\n\n## zh-CN\n\n一次性选择多个选项。通过添加 `disableCheckbox` 属性，选择具体某一个 `checkbox` 禁用。\n\n## en-US\n\nSelect multiple options. Disable the `checkbox` by adding the `disableCheckbox` property and selecting a specific item.\n"
  },
  {
    "path": "components/cascader/demo/multiple.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCascaderModule, NzCascaderOption } from 'ng-zorro-antd/cascader';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nconst getOptions = (): NzCascaderOption[] => [\n  {\n    label: 'Light',\n    value: 'light',\n    children: new Array(20).fill(null).map((_, index) => ({ label: `Number ${index}`, value: index, isLeaf: true }))\n  },\n  {\n    label: 'Bamboo',\n    value: 'bamboo',\n    children: [\n      {\n        label: 'Little',\n        value: 'little',\n        children: [\n          {\n            label: 'Toy Fish',\n            value: 'fish',\n            isLeaf: true,\n            disableCheckbox: true\n          },\n          {\n            label: 'Toy Cards',\n            value: 'cards',\n            isLeaf: true\n          },\n          {\n            label: 'Toy Bird',\n            value: 'bird',\n            isLeaf: true\n          }\n        ]\n      }\n    ]\n  }\n];\n\n@Component({\n  selector: 'nz-demo-cascader-multiple',\n  imports: [FormsModule, NzCascaderModule],\n  template: `\n    <nz-cascader\n      style=\"width: 100%;\"\n      [nzOptions]=\"nzOptions\"\n      [(ngModel)]=\"values\"\n      (ngModelChange)=\"onChanges($event)\"\n      nzMultiple\n      [nzMaxTagCount]=\"3\"\n    />\n  `\n})\nexport class NzDemoCascaderMultipleComponent {\n  readonly nzOptions: NzCascaderOption[] = getOptions();\n  values: NzSafeAny[][] | null = null;\n\n  onChanges(values: NzSafeAny[][]): void {\n    console.log(values, this.values);\n  }\n}\n"
  },
  {
    "path": "components/cascader/demo/open.md",
    "content": "---\norder: 21\nversion: 20.2.0\ntitle:\n  zh-CN: 控制浮层显隐\n  en-US: Controlled Opening\n---\n\n## zh-CN\n\n使用 `nzOpen` 控制菜单浮层显隐。\n\n## en-US\n\nUse `nzOpen` to control whether the menu overlay is displayed.\n"
  },
  {
    "path": "components/cascader/demo/open.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCascaderModule, NzCascaderOption } from 'ng-zorro-antd/cascader';\nimport { NzFlexModule } from 'ng-zorro-antd/flex';\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\n\nconst options: NzCascaderOption[] = [\n  {\n    value: 'zhejiang',\n    label: 'Zhejiang',\n    children: [\n      {\n        value: 'hangzhou',\n        label: 'Hangzhou',\n        children: [\n          {\n            value: 'xihu',\n            label: 'West Lake',\n            isLeaf: true\n          }\n        ]\n      },\n      {\n        value: 'ningbo',\n        label: 'Ningbo',\n        isLeaf: true\n      }\n    ]\n  },\n  {\n    value: 'jiangsu',\n    label: 'Jiangsu',\n    children: [\n      {\n        value: 'nanjing',\n        label: 'Nanjing',\n        children: [\n          {\n            value: 'zhonghuamen',\n            label: 'Zhong Hua Men',\n            isLeaf: true\n          }\n        ]\n      }\n    ]\n  }\n];\n\n@Component({\n  selector: 'nz-demo-cascader-open',\n  imports: [FormsModule, NzCascaderModule, NzFlexModule, NzSwitchModule],\n  template: `\n    <div nz-flex nzVertical nzGap=\"small\">\n      <nz-switch [(ngModel)]=\"open\" nzCheckedChildren=\"open\" nzUnCheckedChildren=\"close\" />\n      <nz-cascader\n        [nzOptions]=\"nzOptions\"\n        [ngModel]=\"values\"\n        [nzOpen]=\"open\"\n        (nzSelectionChange)=\"onSelectionChange($event)\"\n        (nzVisibleChange)=\"onVisibleChange($event)\"\n      />\n    </div>\n  `\n})\nexport class NzDemoCascaderOpenComponent {\n  readonly nzOptions = options;\n  values = ['zhejiang', 'hangzhou', 'xihu'];\n  open = false;\n\n  onSelectionChange(selectedOptions: NzCascaderOption[]): void {\n    console.log(selectedOptions);\n  }\n\n  onVisibleChange(visible: boolean): void {\n    console.log(visible);\n  }\n}\n"
  },
  {
    "path": "components/cascader/demo/placement.md",
    "content": "---\norder: 19\ntitle:\n  zh-CN: 弹出位置\n  en-US: Placement\n---\n\n## zh-CN\n\n可以通过 `nzPlacement` 手动指定弹出的位置。\n\n## en-US\n\nYou can manually specify the position of the popup via `nzPlacement`.\n"
  },
  {
    "path": "components/cascader/demo/placement.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCascaderModule, NzCascaderOption, NzCascaderPlacement } from 'ng-zorro-antd/cascader';\nimport { NzSegmentedModule } from 'ng-zorro-antd/segmented';\n\nconst options: NzCascaderOption[] = [\n  {\n    value: 'zhejiang',\n    label: 'Zhejiang',\n    children: [\n      {\n        value: 'hangzhou',\n        label: 'Hangzhou',\n        children: [\n          {\n            value: 'xihu',\n            label: 'West Lake',\n            isLeaf: true\n          }\n        ]\n      },\n      {\n        value: 'ningbo',\n        label: 'Ningbo',\n        isLeaf: true\n      }\n    ]\n  },\n  {\n    value: 'jiangsu',\n    label: 'Jiangsu',\n    children: [\n      {\n        value: 'nanjing',\n        label: 'Nanjing',\n        children: [\n          {\n            value: 'zhonghuamen',\n            label: 'Zhong Hua Men',\n            isLeaf: true\n          }\n        ]\n      }\n    ]\n  }\n];\n\n@Component({\n  selector: 'nz-demo-cascader-placement',\n  imports: [NzCascaderModule, NzSegmentedModule],\n  template: `\n    <nz-segmented [nzOptions]=\"placements\" (nzValueChange)=\"setPlacement($event)\" />\n    <br />\n    <br />\n    <nz-cascader [nzOptions]=\"nzOptions\" [nzPlacement]=\"placement\" />\n  `\n})\nexport class NzDemoCascaderPlacementComponent {\n  readonly nzOptions: NzCascaderOption[] = options;\n  placement: NzCascaderPlacement = 'topLeft';\n  readonly placements: NzCascaderPlacement[] = ['topLeft', 'topRight', 'bottomLeft', 'bottomRight'];\n\n  setPlacement(placement: string | number): void {\n    this.placement = placement as NzCascaderPlacement;\n  }\n}\n"
  },
  {
    "path": "components/cascader/demo/prefix-and-suffix.md",
    "content": "---\norder: 18\nversion: 20.2.0\ntitle:\n  zh-CN: 前后缀\n  en-US: Prefix and Suffix\n---\n\n## zh-CN\n\n通过 `nzPrefix` 自定前缀，通过 `nzSuffixIcon` 自定义选择框后缀图标，通过 `nzExpandIcon` 自定义次级菜单展开图标。\n\n## en-US\n\nUse `nzPrefix` to customize the prefix content, use `nzSuffixIcon` to customize the selection box suffix icon, and use `nzExpandIcon` to customize the current item expand icon.\n"
  },
  {
    "path": "components/cascader/demo/prefix-and-suffix.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCascaderModule, NzCascaderOption } from 'ng-zorro-antd/cascader';\nimport { NzFlexModule } from 'ng-zorro-antd/flex';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nconst options: NzCascaderOption[] = [\n  {\n    value: 'zhejiang',\n    label: 'Zhejiang',\n    children: [\n      {\n        value: 'hangzhou',\n        label: 'Hangzhou',\n        children: [\n          {\n            value: 'xihu',\n            label: 'West Lake',\n            isLeaf: true\n          }\n        ]\n      },\n      {\n        value: 'ningbo',\n        label: 'Ningbo',\n        isLeaf: true\n      }\n    ]\n  },\n  {\n    value: 'jiangsu',\n    label: 'Jiangsu',\n    children: [\n      {\n        value: 'nanjing',\n        label: 'Nanjing',\n        children: [\n          {\n            value: 'zhonghuamen',\n            label: 'Zhong Hua Men',\n            isLeaf: true\n          }\n        ]\n      }\n    ]\n  }\n];\n\n@Component({\n  selector: 'nz-demo-cascader-prefix-and-suffix',\n  imports: [NzCascaderModule, NzFlexModule, NzIconModule],\n  template: `\n    <nz-flex nzVertical nzGap=\"small\">\n      <nz-cascader [nzOptions]=\"nzOptions\" nzSuffixIcon=\"smile\" />\n      <nz-cascader [nzOptions]=\"nzOptions\" nzExpandIcon=\"smile\" />\n      <nz-cascader [nzOptions]=\"nzOptions\" [nzPrefix]=\"smile\" />\n    </nz-flex>\n    <ng-template #smile><nz-icon nzType=\"smile\" /></ng-template>\n  `\n})\nexport class NzDemoCascaderPrefixAndSuffixComponent {\n  readonly nzOptions: NzCascaderOption[] = options;\n}\n"
  },
  {
    "path": "components/cascader/demo/reactive-form.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 响应表单\n  en-US: ReactiveForm\n---\n\n## zh-CN\n\n通过表单的`重置`功能清空已选择的值。\n\n## en-US\n\nReset control value by Ng Reactive Form.\n"
  },
  {
    "path": "components/cascader/demo/reactive-form.ts",
    "content": "import { Component, inject } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzCascaderModule, NzCascaderOption } from 'ng-zorro-antd/cascader';\n\nconst options: NzCascaderOption[] = [\n  {\n    value: 'zhejiang',\n    label: 'Zhejiang',\n    children: [\n      {\n        value: 'hangzhou',\n        label: 'Hangzhou',\n        children: [\n          {\n            value: 'xihu',\n            label: 'West Lake',\n            isLeaf: true\n          }\n        ]\n      },\n      {\n        value: 'ningbo',\n        label: 'Ningbo',\n        isLeaf: true\n      }\n    ]\n  },\n  {\n    value: 'jiangsu',\n    label: 'Jiangsu',\n    children: [\n      {\n        value: 'nanjing',\n        label: 'Nanjing',\n        children: [\n          {\n            value: 'zhonghuamen',\n            label: 'Zhong Hua Men',\n            isLeaf: true\n          }\n        ]\n      }\n    ]\n  }\n];\n\n@Component({\n  selector: 'nz-demo-cascader-reactive-form',\n  imports: [ReactiveFormsModule, NzButtonModule, NzCascaderModule],\n  template: `\n    <form [formGroup]=\"form\" novalidate>\n      <nz-cascader [nzOptions]=\"nzOptions\" formControlName=\"name\" />\n    </form>\n    <br />\n    <button nz-button (click)=\"reset()\">Reset</button>\n    <button nz-button (click)=\"submit()\">Submit</button>\n  `,\n  styles: `\n    button {\n      margin-right: 8px;\n    }\n  `\n})\nexport class NzDemoCascaderReactiveFormComponent {\n  private fb = inject(FormBuilder);\n  form = this.fb.group({\n    name: this.fb.control<string[] | null>(null, Validators.required)\n  });\n  readonly nzOptions: NzCascaderOption[] = options;\n\n  constructor() {\n    this.form.controls.name.valueChanges.pipe(takeUntilDestroyed()).subscribe(data => {\n      this.onChanges(data);\n    });\n  }\n\n  reset(): void {\n    this.form.reset();\n    console.log(this.form.value);\n  }\n\n  submit(): void {\n    console.log(this.form.value);\n  }\n\n  onChanges(values: string[] | null): void {\n    console.log(values);\n  }\n}\n"
  },
  {
    "path": "components/cascader/demo/search.md",
    "content": "---\norder: 11\ntitle:\n  zh-CN: 搜索\n  en-US: Search\n---\n\n## zh-CN\n\n可以直接搜索选项并选择。\n\n## en-US\n\nSearch and select an option directly.\n"
  },
  {
    "path": "components/cascader/demo/search.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCascaderModule, NzCascaderOption } from 'ng-zorro-antd/cascader';\n\nconst options: NzCascaderOption[] = [\n  {\n    value: 'zhejiang',\n    label: 'Zhejiang',\n    children: [\n      {\n        value: 'hangzhou',\n        label: 'Hangzhou',\n        children: [\n          {\n            value: 'xihu',\n            label: 'West Lake',\n            isLeaf: true\n          }\n        ]\n      },\n      {\n        value: 'ningbo',\n        label: 'Ningbo',\n        isLeaf: true,\n        disabled: true\n      }\n    ]\n  },\n  {\n    value: 'jiangsu',\n    label: 'Jiangsu',\n    children: [\n      {\n        value: 'nanjing',\n        label: 'Nanjing',\n        children: [\n          {\n            value: 'zhonghuamen',\n            label: 'Zhong Hua Men',\n            isLeaf: true\n          }\n        ]\n      }\n    ]\n  }\n];\n\n@Component({\n  selector: 'nz-demo-cascader-search',\n  imports: [FormsModule, NzCascaderModule],\n  template: `\n    <nz-cascader\n      [nzOptions]=\"nzOptions\"\n      [(ngModel)]=\"values\"\n      [nzShowSearch]=\"true\"\n      (ngModelChange)=\"onChanges($event)\"\n    />\n  `\n})\nexport class NzDemoCascaderSearchComponent {\n  readonly nzOptions: NzCascaderOption[] = options;\n  values: string[] | null = null;\n\n  onChanges(values: string[]): void {\n    console.log(values, this.values);\n  }\n}\n"
  },
  {
    "path": "components/cascader/demo/size.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 大小\n  en-US: Size\n---\n\n## zh-CN\n\n不同大小的级联选择器。\n\n## en-US\n\nCascade selection box of different sizes.\n"
  },
  {
    "path": "components/cascader/demo/size.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCascaderModule, NzCascaderOption } from 'ng-zorro-antd/cascader';\nimport { NzFlexModule } from 'ng-zorro-antd/flex';\n\nconst options: NzCascaderOption[] = [\n  {\n    value: 'zhejiang',\n    label: 'Zhejiang',\n    children: [\n      {\n        value: 'hangzhou',\n        label: 'Hangzhou',\n        children: [\n          {\n            value: 'xihu',\n            label: 'West Lake',\n            isLeaf: true\n          }\n        ]\n      },\n      {\n        value: 'ningbo',\n        label: 'Ningbo',\n        isLeaf: true\n      }\n    ]\n  },\n  {\n    value: 'jiangsu',\n    label: 'Jiangsu',\n    children: [\n      {\n        value: 'nanjing',\n        label: 'Nanjing',\n        children: [\n          {\n            value: 'zhonghuamen',\n            label: 'Zhong Hua Men',\n            isLeaf: true\n          }\n        ]\n      }\n    ]\n  }\n];\n\n@Component({\n  selector: 'nz-demo-cascader-size',\n  imports: [FormsModule, NzCascaderModule, NzFlexModule],\n  template: `\n    <nz-flex nzVertical nzGap=\"middle\">\n      <nz-cascader nzSize=\"large\" [nzOptions]=\"nzOptions\" [(ngModel)]=\"value1\" (ngModelChange)=\"onChanges($event)\" />\n      <nz-cascader [nzOptions]=\"nzOptions\" [(ngModel)]=\"value2\" (ngModelChange)=\"onChanges($event)\" />\n      <nz-cascader nzSize=\"small\" [nzOptions]=\"nzOptions\" [(ngModel)]=\"value3\" (ngModelChange)=\"onChanges($event)\" />\n    </nz-flex>\n  `\n})\nexport class NzDemoCascaderSizeComponent {\n  readonly nzOptions: NzCascaderOption[] = options;\n  value1: string[] | null = null;\n  value2: string[] | null = null;\n  value3: string[] | null = null;\n\n  onChanges(values: string[]): void {\n    console.log(values);\n  }\n}\n"
  },
  {
    "path": "components/cascader/demo/status.md",
    "content": "---\norder: 20\ntitle:\n  zh-CN: 自定义状态\n  en-US: Status\n---\n\n## zh-CN\n\n使用 `nzStatus` 为 Cascader 添加状态，可选 `error` 或者 `warning`。\n\n## en-US\n\nAdd status to Cascader with `nzStatus`, which could be `error` or `warning`.\n"
  },
  {
    "path": "components/cascader/demo/status.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCascaderModule, NzCascaderOption } from 'ng-zorro-antd/cascader';\nimport { NzFlexModule } from 'ng-zorro-antd/flex';\n\n@Component({\n  selector: 'nz-demo-cascader-status',\n  imports: [FormsModule, NzCascaderModule, NzFlexModule],\n  template: `\n    <nz-flex nzVertical nzGap=\"middle\">\n      <nz-cascader [nzOptions]=\"nzOptions\" nzStatus=\"error\" />\n      <nz-cascader [nzOptions]=\"nzOptions\" nzStatus=\"warning\" />\n    </nz-flex>\n  `\n})\nexport class NzDemoCascaderStatusComponent {\n  readonly nzOptions: NzCascaderOption[] = [];\n}\n"
  },
  {
    "path": "components/cascader/demo/trigger-action.md",
    "content": "---\norder: 12\ntitle:\n  zh-CN: 鼠标移入触发\n  en-US: Trigger Action\n---\n\n## zh-CN\n\n鼠标移入触发显示菜单，移出隐藏菜单。\n\n## en-US\n\nShow menu on mouse enter and hide on mouse leave.\n"
  },
  {
    "path": "components/cascader/demo/trigger-action.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCascaderModule, NzCascaderOption } from 'ng-zorro-antd/cascader';\n\nconst options: NzCascaderOption[] = [\n  {\n    value: 'zhejiang',\n    label: 'Zhejiang',\n    children: [\n      {\n        value: 'hangzhou',\n        label: 'Hangzhou',\n        children: [\n          {\n            value: 'xihu',\n            label: 'West Lake',\n            isLeaf: true\n          }\n        ]\n      },\n      {\n        value: 'ningbo',\n        label: 'Ningbo',\n        isLeaf: true\n      }\n    ]\n  },\n  {\n    value: 'jiangsu',\n    label: 'Jiangsu',\n    children: [\n      {\n        value: 'nanjing',\n        label: 'Nanjing',\n        children: [\n          {\n            value: 'zhonghuamen',\n            label: 'Zhong Hua Men',\n            isLeaf: true\n          }\n        ]\n      }\n    ]\n  }\n];\n\n@Component({\n  selector: 'nz-demo-cascader-trigger-action',\n  imports: [FormsModule, NzCascaderModule],\n  template: `\n    <nz-cascader\n      nzTriggerAction=\"hover\"\n      nzExpandTrigger=\"hover\"\n      [nzOptions]=\"nzOptions\"\n      [(ngModel)]=\"values\"\n      (ngModelChange)=\"onChanges($event)\"\n    />\n  `\n})\nexport class NzDemoCascaderTriggerActionComponent {\n  readonly nzOptions: NzCascaderOption[] = options;\n  values: string[] | null = null;\n\n  onChanges(values: string[]): void {\n    console.log(values, this.values);\n  }\n}\n"
  },
  {
    "path": "components/cascader/demo/trigger.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 可以自定义显示\n  en-US: Custom trigger\n---\n\n## zh-CN\n\n切换按钮和结果分开。\n\n## en-US\n\nSeparate trigger button and result.\n"
  },
  {
    "path": "components/cascader/demo/trigger.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCascaderModule, NzCascaderOption } from 'ng-zorro-antd/cascader';\n\nconst options: NzCascaderOption[] = [\n  {\n    value: 'zhejiang',\n    label: 'Zhejiang',\n    children: [\n      {\n        value: 'hangzhou',\n        label: 'Hangzhou',\n        children: [\n          {\n            value: 'xihu',\n            label: 'West Lake',\n            isLeaf: true\n          }\n        ]\n      },\n      {\n        value: 'ningbo',\n        label: 'Ningbo',\n        isLeaf: true\n      }\n    ]\n  },\n  {\n    value: 'jiangsu',\n    label: 'Jiangsu',\n    children: [\n      {\n        value: 'nanjing',\n        label: 'Nanjing',\n        children: [\n          {\n            value: 'zhonghuamen',\n            label: 'Zhong Hua Men',\n            isLeaf: true\n          }\n        ]\n      }\n    ]\n  }\n];\n\n@Component({\n  selector: 'nz-demo-cascader-trigger',\n  imports: [FormsModule, NzCascaderModule],\n  template: `\n    {{ text }}\n    <nz-cascader\n      [nzShowInput]=\"false\"\n      [nzOptions]=\"nzOptions\"\n      [(ngModel)]=\"values\"\n      (ngModelChange)=\"onChanges($event)\"\n      (nzSelectionChange)=\"onSelectionChange($event)\"\n    >\n      <a href=\"javascript: void(0)\">Change city</a>\n    </nz-cascader>\n  `\n})\nexport class NzDemoCascaderTriggerComponent {\n  readonly nzOptions: NzCascaderOption[] = options;\n  values: string[] | null = null;\n  text = 'Unselect';\n\n  onChanges(values: string[]): void {\n    console.log(values, this.values);\n  }\n\n  onSelectionChange(selectedOptions: NzCascaderOption[]): void {\n    this.text = selectedOptions.map(o => o.label).join(', ');\n  }\n}\n"
  },
  {
    "path": "components/cascader/demo/variant.md",
    "content": "---\norder: 20\nversion: 20.0.0\ntitle:\n  zh-CN: 形态变体\n  en-US: Variants\n---\n\n## zh-CN\n\nCascader 形态变体，可选 `outlined`、`filled`、`borderless`、`underlined` 四种形态。\n\n## en-US\n\nVariants of Cascader, there are four variants: `outlined`, `filled`, `borderless` and `underlined`.\n"
  },
  {
    "path": "components/cascader/demo/variant.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCascaderModule, NzCascaderOption } from 'ng-zorro-antd/cascader';\nimport { NzFlexModule } from 'ng-zorro-antd/flex';\n\nconst options: NzCascaderOption[] = [\n  {\n    value: 'zhejiang',\n    label: 'Zhejiang',\n    children: [\n      {\n        value: 'hangzhou',\n        label: 'Hangzhou',\n        children: [\n          {\n            value: 'xihu',\n            label: 'West Lake',\n            isLeaf: true\n          }\n        ]\n      },\n      {\n        value: 'ningbo',\n        label: 'Ningbo',\n        isLeaf: true\n      }\n    ]\n  },\n  {\n    value: 'jiangsu',\n    label: 'Jiangsu',\n    children: [\n      {\n        value: 'nanjing',\n        label: 'Nanjing',\n        children: [\n          {\n            value: 'zhonghuamen',\n            label: 'Zhong Hua Men',\n            isLeaf: true\n          }\n        ]\n      }\n    ]\n  }\n];\n\n@Component({\n  selector: 'nz-demo-cascader-variant',\n  imports: [NzCascaderModule, NzFlexModule],\n  template: `\n    <nz-flex nzVertical nzGap=\"middle\">\n      <nz-cascader [nzOptions]=\"options\" nzVariant=\"outlined\" />\n      <nz-cascader [nzOptions]=\"options\" nzVariant=\"filled\" />\n      <nz-cascader [nzOptions]=\"options\" nzVariant=\"borderless\" />\n      <nz-cascader [nzOptions]=\"options\" nzVariant=\"underlined\" />\n    </nz-flex>\n  `\n})\nexport class NzDemoCascaderVariantComponent {\n  readonly options = options;\n}\n"
  },
  {
    "path": "components/cascader/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Entry\ntitle: Cascader\ncover: 'https://gw.alipayobjects.com/zos/alicdn/UdS8y8xyZ/Cascader.svg'\ndescription: Cascade selection box.\n---\n\n## When To Use\n\n- When you need to select from a set of a hierarchical structure. Such as province/city/district, company level, and classification.\n- When selecting from a large data set, with multi-stage classification separated for easy selection.\n- Chooses cascade items in one float layer for a better user experience.\n\n## API\n\n### nz-cascader\n\n| Property              | Description                                                                                                                            | Type                                                                  | Default           | Global Config | Version |\n| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ----------------- | ------------- | ------- |\n| `[ngModel]`           | selected value                                                                                                                         | `any[]`                                                               | -                 |\n| `[nzAllowClear]`      | whether allow clear                                                                                                                    | `boolean`                                                             | `true`            |\n| `[nzAutoFocus]`       | whether auto focus the input box                                                                                                       | `boolean`                                                             | `false`           |\n| `[nzBackdrop]`        | whether or not the overlay should attach a backdrop                                                                                    | `boolean`                                                             | `false`           |\n| `[nzChangeOn]`        | change value on each selection if this function returns `true`                                                                         | `(option: any, index: number) => boolean`                             | -                 |\n| `[nzChangeOnSelect]`  | change value on each selection if set to true, see above demo for details                                                              | `boolean`                                                             | `false`           |\n| `[nzColumnClassName]` | additional className of column in the popup overlay                                                                                    | `string`                                                              | -                 |\n| `[nzDisabled]`        | whether select should be disabled                                                                                                      | `boolean`                                                             | `false`           |\n| `[nzExpandIcon]`      | customize the current item expand icon                                                                                                 | `string \\| TemplateRef<void>`                                         | -                 |\n| `[nzExpandTrigger]`   | expand current item when clicked or hovered, one of 'click' 'hover'                                                                    | `'click' \\| 'hover'`                                                  | `'click'`         |\n| `[nzLabelProperty]`   | the label property name of options                                                                                                     | `string`                                                              | `'label'`         |\n| `[nzLabelRender]`     | render template of displaying selected options                                                                                         | `TemplateRef<any>`                                                    | -                 |\n| `[nzLoadData]`        | to load option lazily. Lazy load will be called immediately if the setting is `ngModel` with an array value and `nzOptions` is not set | `(option: any, index?: index) => PromiseLike<any> \\| Observable<any>` | -                 |\n| `[nzMenuClassName]`   | additional className of popup overlay                                                                                                  | `string`                                                              | -                 |\n| `[nzMouseEnterDelay]` | duration in milliseconds before opening the popup overlay when the mouse enters the trigger                                            | `number`                                                              | `150`             |\n| `[nzMouseLeaveDelay]` | duration in milliseconds before closing the popup overlay when the mouse leaves the trigger                                            | `number`                                                              | `150`             |\n| `[nzMenuStyle]`       | additional css style of popup overlay                                                                                                  | `object`                                                              | -                 |\n| `[nzMultiple]`        | support multiple or not                                                                                                                | `boolean`                                                             | `false`           |\n| `[nzNotFoundContent]` | specify content to show when no result matches                                                                                         | `string \\| TemplateRef<void>`                                         | -                 |\n| `[nzOptionRender]`    | render template of cascader options                                                                                                    | `TemplateRef<{ $implicit: NzCascaderOption, index: number }>`         |                   |\n| `[nzOptions]`         | data options of cascade                                                                                                                | `object[]`                                                            | -                 |\n| `[nzOpen]`            | Set visible of cascader popup                                                                                                          | `boolean`                                                             | `false`           | -             | 20.2.0  |\n| `[nzPlaceHolder]`     | input placeholder                                                                                                                      | `string`                                                              | `'Please select'` |\n| `[nzPlacement]`       | popup placement                                                                                                                        | `'bottomLeft' \\| 'bottomRight' \\| 'topLeft' \\| 'topRight'`            | `'bottomLeft'`    |\n| `[nzShowArrow]`       | whether show arrow                                                                                                                     | `boolean`                                                             | `true`            |\n| `[nzShowInput]`       | whether show input                                                                                                                     | `boolean`                                                             | `true`            |\n| `[nzShowSearch]`      | whether support search. Cannot be used with `[nzLoadData]` at the same time                                                            | `boolean \\| NzShowSearchOptions`                                      | `false`           |\n| `[nzSize]`            | input size, one of `large` `default` `small`                                                                                           | `'large' \\| 'small' \\| 'default'`                                     | `'default'`       | ✅            |\n| `[nzStatus]`          | set validation status                                                                                                                  | `'error' \\| 'warning'`                                                | -                 |\n| `[nzPrefix]`          | custom prefix                                                                                                                          | `string\\|TemplateRef<void>`                                           | -                 | -             | 20.2.0  |\n| `[nzSuffixIcon]`      | custom suffix icon                                                                                                                     | `string\\|TemplateRef<void>`                                           | -                 |\n| `[nzValueProperty]`   | value property name of options                                                                                                         | `string`                                                              | `'value'`         |\n| `[nzVariant]`         | Variants of Cascader                                                                                                                   | `'outlined' \\| 'borderless' \\| 'filled' \\| 'underlined'`              | `'outlined'`      | ✅            | 20.0.0  |\n| `(ngModelChange)`     | emit on values change                                                                                                                  | `EventEmitter<any[]>`                                                 | -                 |\n| `(nzClear)`           | emit on clear values                                                                                                                   | `EventEmitter<void>`                                                  | -                 |\n| `(nzVisibleChange)`   | emit on popup menu visible or hide                                                                                                     | `EventEmitter<boolean>`                                               | -                 |\n| `(nzRemoved)`         | emit on selected item removed when `nzMultiple` is `true`                                                                              | `EventEmitter<NzCascaderOption>`                                      | -                 |\n| `(nzSelectionChange)` | emit on values change                                                                                                                  | `EventEmitter<NzCascaderOption[]>`                                    | -                 |\n\n### Interfaces\n\n#### NzCascaderOption\n\n```ts\nexport interface NzCascaderOption {\n  value?: any;\n  label?: string;\n  title?: string;\n  disabled?: boolean;\n  loading?: boolean;\n  isLeaf?: boolean;\n  children?: NzCascaderOption[];\n  disableCheckbox?: boolean;\n\n  [key: string]: any;\n}\n```\n\n#### NzShowSearchOptions\n\nWhen `nzShowSearch` is an object it should implement `NzShowSearchOptions`:\n\n| Params   | Explanation                                                            | Type                                                                         | Default |\n| -------- | ---------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ------- |\n| `filter` | Optional. Be aware that all non-leaf CascaderOptions would be filtered | `(inputValue: string, path: NzCascaderOption[]): boolean`                    | -       |\n| `sorter` | Optional                                                               | `(a: NzCascaderOption[], b: NzCascaderOption[], inputValue: string): number` | -       |\n\nThe default filter looks as follows:\n\n```ts\nconst defaultFilter: NzCascaderFilter = (i, p) => {\n  return p.some(o => {\n    const label = o.label;\n    return !!label && label.indexOf(i) !== -1;\n  });\n};\n```\n\nFor example, if you would like to ignore lower or upper case, you could use a filter function like this:\n\n```ts\nconst filter: NzCascaderFilter = (i, p) => {\n  return p.some(o => {\n    const label = o.label;\n    return !!label && label.toLowerCase().indexOf(i.toLowerCase()) !== -1;\n  });\n};\n```\n\n#### Methods\n\n| Name          | Description   |\n| ------------- | ------------- |\n| `blur()`      | remove focus  |\n| `focus()`     | get focus     |\n| `closeMenu()` | hide the menu |\n\n## FAQ\n\n### Q: An error is thrown when `nzLoadData` is used.\n\nWhen you pass a function to `nzLoadData`, the function becomes a `NzCascaderComponent` property.\nWhen the component calls the `nzLoadData` function, `this` is bound to nothing. You have to pass an arrow function or use `Function.bind` to bind `this` to the parent component.\n[see example](https://stackoverflow.com/questions/60320913/ng-zorro-cascader-lazy-load-data-nzloaddata-function-got-this-undefined/60928983#60928983).\n\n### Q: The overlay layer element does not follow the scroll position when scrolling\n\nBy default, the overlay layer element uses body as the scroll container. If using another scroll container, add the [CdkScrollable](https://material.angular.dev/cdk/scrolling/api#CdkScrollable) directive to the custom scroll container element.\nNote: You need to import the `CdkScrollable` directive or `ScrollingModule` module from `@angular/cdk/scrolling`.\n"
  },
  {
    "path": "components/cascader/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ntype: 数据录入\ntitle: Cascader\nsubtitle: 级联选择\ncover: 'https://gw.alipayobjects.com/zos/alicdn/UdS8y8xyZ/Cascader.svg'\ndescription: 级联选择框。\n---\n\n## 何时使用\n\n- 需要从一组相关联的数据集合进行选择，例如省市区，公司层级，事物分类等。\n- 从一个较大的数据集合中进行选择时，用多级分类进行分隔，方便选择。\n- 比起 Select 组件，可以在同一个浮层中完成选择，有较好的体验。\n\n## API\n\n### nz-cascader\n\n| 参数                  | 说明                                                                                       | 类型                                                                  | 默认值         | 支持全局配置 | 版本   |\n| --------------------- | ------------------------------------------------------------------------------------------ | --------------------------------------------------------------------- | -------------- | ------------ | ------ |\n| `[ngModel]`           | 指定选中项                                                                                 | `any[]`                                                               | -              |\n| `[nzAllowClear]`      | 是否支持清除                                                                               | `boolean`                                                             | `true`         |\n| `[nzAutoFocus]`       | 是否自动聚焦，当存在输入框时                                                               | `boolean`                                                             | `false`        |\n| `[nzBackdrop]`        | 浮层是否应带有背景板                                                                       | `boolean`                                                             | `false`        |\n| `[nzChangeOn]`        | 点击父级菜单选项时，可通过该函数判断是否允许值的变化                                       | `(option: any, index: number) => boolean`                             | -              |\n| `[nzChangeOnSelect]`  | 当此项为 true 时，点选每级菜单选项值都会发生变化，具体见上面的演示                         | `boolean`                                                             | `false`        |\n| `[nzColumnClassName]` | 自定义浮层列类名                                                                           | `string`                                                              | -              |\n| `[nzDisabled]`        | 禁用                                                                                       | `boolean`                                                             | `false`        |\n| `[nzExpandIcon]`      | 自定义次级菜单展开图标                                                                     | `string \\| TemplateRef<void>`                                         | -              |\n| `[nzExpandTrigger]`   | 次级菜单的展开方式，可选 `'click'` 和 `'hover'`                                            | `'click' \\| 'hover'`                                                  | `'click'`      |\n| `[nzLabelProperty]`   | 选项的显示值的属性名                                                                       | `string`                                                              | `'label'`      |\n| `[nzLabelRender]`     | 选择后展示的渲染模板                                                                       | `TemplateRef<any>`                                                    | -              |\n| `[nzLoadData]`        | 用于动态加载选项。如果提供了`ngModel`初始值，且未提供`nzOptions`值，则会立即触发动态加载。 | `(option: any, index?: index) => PromiseLike<any> \\| Observable<any>` | -              |\n| `[nzMenuClassName]`   | 自定义浮层类名                                                                             | `string`                                                              | -              |\n| `[nzMenuStyle]`       | 自定义浮层样式                                                                             | `object`                                                              | -              |\n| `[nzMouseEnterDelay]` | 鼠标进入触发器后打开浮层的延迟时间（毫秒）                                                 | `number`                                                              | `150`          |\n| `[nzMouseLeaveDelay]` | 鼠标离开触发器后关闭浮层的延迟时间（毫秒）                                                 | `number`                                                              | `150`          |\n| `[nzMultiple]`        | 是否支持多选                                                                               | `boolean`                                                             | `false`        |\n| `[nzNotFoundContent]` | 当下拉列表为空时显示的内容                                                                 | `string \\| TemplateRef<void>`                                         | -              |\n| `[nzOptionRender]`    | 选项的渲染模板                                                                             | `TemplateRef<{ $implicit: NzCascaderOption, index: number }>`         |                |\n| `[nzOptions]`         | 可选项数据源                                                                               | `object[]`                                                            | -              |\n| `[nzOpen]`            | 控制浮层显隐                                                                               | `boolean`                                                             | `false`        | -            | 20.2.0 |\n| `[nzPlaceHolder]`     | 输入框占位文本                                                                             | `string`                                                              | `'请选择'`     |\n| `[nzPlacement]`       | 浮层弹出位置                                                                               | `'bottomLeft' \\| 'bottomRight' \\| 'topLeft' \\| 'topRight'`            | `'bottomLeft'` |\n| `[nzShowArrow]`       | 是否显示箭头                                                                               | `boolean`                                                             | `true`         |\n| `[nzShowInput]`       | 显示输入框                                                                                 | `boolean`                                                             | `true`         |\n| `[nzShowSearch]`      | 是否支持搜索，默认情况下对 `label` 进行全匹配搜索，不能和 `[nzLoadData]` 同时使用          | `boolean \\| NzShowSearchOptions`                                      | `false`        |\n| `[nzSize]`            | 输入框大小，可选 `large` `default` `small`                                                 | `'large' \\| 'small' \\| 'default'`                                     | `'default'`    | ✅           |\n| `[nzStatus]`          | 设置校验状态                                                                               | `'error' \\| 'warning'`                                                | -              |\n| `[nzPrefix]`          | 自定义的选择框前缀                                                                         | `string \\| TemplateRef<void>`                                         | -              | -            | 20.2.0 |\n| `[nzSuffixIcon]`      | 自定义的选择框后缀图标                                                                     | `string \\| TemplateRef<void>`                                         | -              |\n| `[nzValueProperty]`   | 选项的实际值的属性名                                                                       | `string`                                                              | `'value'`      |\n| `[nzVariant]`         | 形态变体                                                                                   | `'outlined' \\| 'borderless' \\| 'filled' \\| 'underlined'`              | `'outlined'`   | ✅           | 20.0.0 |\n| `(ngModelChange)`     | 值发生变化时触发                                                                           | `EventEmitter<any[]>`                                                 | -              |\n| `(nzClear)`           | 清除值时触发                                                                               | `EventEmitter<void>`                                                  | -              |\n| `(nzVisibleChange)`   | 菜单浮层的显示/隐藏                                                                        | `EventEmitter<boolean>`                                               | -              |\n| `(nzRemoved)`         | 多选模式下，移除值时触发                                                                   | `EventEmitter<NzCascaderOption>`                                      | -              |\n| `(nzSelectionChange)` | 值发生变化时触发                                                                           | `EventEmitter<NzCascaderOption[]>`                                    | -              |\n\n### Interfaces\n\n#### NzCascaderOption\n\n```ts\nexport interface NzCascaderOption {\n  value?: any;\n  label?: string;\n  title?: string;\n  disabled?: boolean;\n  loading?: boolean;\n  isLeaf?: boolean;\n  children?: NzCascaderOption[];\n  disableCheckbox?: boolean;\n\n  [key: string]: any;\n}\n```\n\n#### NzShowSearchOptions\n\n```ts\nexport type NzShowSearchOptions =\n  | boolean\n  | {\n      filter?: NzCascaderFilter;\n      sorter?: NzCascaderSorter;\n    };\n```\n\n`nzShowSearch` 为对象时需遵守 `NzShowSearchOptions` 接口：\n\n| 参数     | 说明                                                           | 类型                                                                         | 默认值 |\n| -------- | -------------------------------------------------------------- | ---------------------------------------------------------------------------- | ------ |\n| `filter` | 可选，选择是否保留选项的过滤函数，每级菜单的选项都会被匹配     | `(inputValue: string, path: NzCascaderOption[]): boolean`                    | -      |\n| `sorter` | 可选，按照到每个最终选项的路径进行排序，默认按照原始数据的顺序 | `(a: NzCascaderOption[], b: NzCascaderOption[], inputValue: string): number` | -      |\n\n默认的 filter 如下所示：\n\n```ts\nconst defaultFilter: NzCascaderFilter = (i, p) => {\n  return p.some(o => {\n    const label = o.label;\n    return !!label && label.indexOf(i) !== -1;\n  });\n};\n```\n\n如果你想要在搜索时忽略大小写，就可以编写一个这样的 filter 函数：\n\n```ts\nconst filter: NzCascaderFilter = (i, p) => {\n  return p.some(o => {\n    const label = o.label;\n    return !!label && label.toLowerCase().indexOf(i.toLowerCase()) !== -1;\n  });\n};\n```\n\n#### 方法\n\n| 名称          | 描述     |\n| ------------- | -------- |\n| `blur()`      | 移除焦点 |\n| `focus()`     | 获取焦点 |\n| `closeMenu()` | 隐藏菜单 |\n\n> 注意，如果需要获得中国省市区数据，可以参考 [china-division](https://gist.github.com/afc163/7582f35654fd03d5be7009444345ea17)。\n\n## FAQ\n\n### Q: 为什么使用 `nzLoadData` 时报了一个错误 this === undefined ？\n\n对传递给 Cascader 组件的 `nzLoadData` 参数会成为 `NzCasacderComponent` 对象的一个属性，调用这个函数时，函数中的 `this` 没有指向任何对象。\n因此，正确的做法是传递剪头函数，或者使用 `Function.bind` 将 `nzLoadData` 参数和你的对象绑定。\n[这里](https://stackoverflow.com/questions/60320913/ng-zorro-cascader-lazy-load-data-nzloaddata-function-got-this-undefined/60928983#60928983)是一个比较有代表性的例子。\n\n### Q：滚动时浮层元素没有跟随滚动位置\n\n默认情况下，浮层元素使用 `body` 作为滚动容器，如果使用了其他滚动容器，在自定义滚动容器元素上添加 [CdkScrollable](https://material.angular.dev/cdk/scrolling/api#CdkScrollable) 指令。\n注意：您需要从 `@angular/cdk/scrolling` 导入 `CdkScrollable` 指令或 `ScrollingModule` 模块。\n"
  },
  {
    "path": "components/cascader/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/cascader/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/cascader/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './typings';\nexport * from './utils';\nexport * from './cascader.component';\nexport * from './cascader.module';\nexport * from './cascader.service';\nexport * from './cascader-option.component';\n"
  },
  {
    "path": "components/cascader/style/entry.less",
    "content": "@import './index.less';\n@import './patch.less';\n// style dependencies\n@import '../../empty/style/entry.less';\n@import '../../input/style/entry.less';\n"
  },
  {
    "path": "components/cascader/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import '../../input/style/mixin';\n@import '../../checkbox/style/mixin';\n\n@cascader-prefix-cls: ~'@{ant-prefix}-cascader';\n\n.antCheckboxFn(@checkbox-prefix-cls: ~'@{cascader-prefix-cls}-checkbox');\n\n.@{cascader-prefix-cls} {\n  width: 184px;\n\n  &-checkbox {\n    top: 0;\n    margin-right: @padding-xs;\n  }\n\n  &-menus {\n    display: flex;\n    flex-wrap: nowrap;\n    align-items: flex-start;\n\n    &.@{cascader-prefix-cls}-menu-empty {\n      .@{cascader-prefix-cls}-menu {\n        width: 100%;\n        height: auto;\n      }\n    }\n  }\n\n  &-menu {\n    flex-grow: 1;\n    min-width: 111px;\n    height: 180px;\n    margin: 0;\n    padding: @cascader-dropdown-edge-child-vertical-padding;\n    overflow: auto;\n    vertical-align: top;\n    list-style: none;\n    -ms-overflow-style: -ms-autohiding-scrollbar; // https://github.com/ant-design/ant-design/issues/11857\n\n    &:not(:last-child) {\n      border-inline-end: @border-width-base @border-style-base @cascader-menu-border-color-split;\n    }\n\n    &-item {\n      display: flex;\n      flex-wrap: nowrap;\n      align-items: center;\n      padding: @cascader-dropdown-vertical-padding @control-padding-horizontal;\n      overflow: hidden;\n      line-height: @cascader-dropdown-line-height;\n      white-space: nowrap;\n      text-overflow: ellipsis;\n      cursor: pointer;\n      transition: all 0.3s;\n\n      &:hover {\n        background: @item-hover-bg;\n      }\n\n      &-disabled {\n        color: @disabled-color;\n        cursor: not-allowed;\n\n        &:hover {\n          background: transparent;\n        }\n      }\n\n      .@{cascader-prefix-cls}-menu-empty & {\n        color: @disabled-color;\n        cursor: default;\n        pointer-events: none;\n      }\n\n      &-active:not(&-disabled) {\n        &,\n        &:hover {\n          font-weight: @select-item-selected-font-weight;\n          background-color: @cascader-item-selected-bg;\n        }\n      }\n\n      &-content {\n        flex: auto;\n      }\n\n      &-expand &-expand-icon,\n      &-loading-icon {\n        margin-left: @padding-xss;\n        color: @text-color-secondary;\n        font-size: 10px;\n\n        .@{cascader-prefix-cls}-menu-item-disabled& {\n          color: @disabled-color;\n        }\n      }\n\n      &-keyword {\n        color: @highlight-color;\n      }\n    }\n  }\n\n  // ===================== Compact Item Styles =====================\n  .compact-item(@cascader-prefix-cls);\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/cascader/style/patch.less",
    "content": ".ant-cascader-dropdown {\n  padding: 0;\n}\n\n.ant-cascader-menus {\n  position: relative;\n  margin-top: 2px;\n  margin-bottom: 2px;\n}\n"
  },
  {
    "path": "components/cascader/style/rtl.less",
    "content": "// We can not import reference of `./index` directly since it will make dead loop in less\n@import (reference) '../../style/themes/index';\n@cascader-prefix-cls: ~'@{ant-prefix}-cascader';\n\n.@{cascader-prefix-cls}-rtl {\n  .@{cascader-prefix-cls}-menu-item {\n    &-expand-icon,\n    &-loading-icon {\n      margin-right: @padding-xss;\n      margin-left: 0;\n    }\n  }\n\n  .@{cascader-prefix-cls}-checkbox {\n    top: 0;\n    margin-right: 0;\n    margin-left: @padding-xs;\n  }\n}\n"
  },
  {
    "path": "components/cascader/typings.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Observable } from 'rxjs';\n\nimport { NzTreeNode } from 'ng-zorro-antd/core/tree';\nimport { NzSafeAny, NzSizeLDSType } from 'ng-zorro-antd/core/types';\n\nimport { NzCascaderTreeService } from './cascader-tree.service';\n\nexport type NzCascaderExpandTrigger = 'click' | 'hover';\nexport type NzCascaderTriggerType = 'click' | 'hover';\nexport type NzCascaderSize = NzSizeLDSType;\n\nexport type NzCascaderFilter = (searchValue: string, path: NzCascaderOption[]) => boolean;\nexport type NzCascaderSorter = (a: NzCascaderOption[], b: NzCascaderOption[], inputValue: string) => number;\nexport type NzCascaderPlacement = 'bottomLeft' | 'bottomRight' | 'topLeft' | 'topRight';\n\nexport interface NzCascaderOption {\n  value?: NzSafeAny;\n  label?: string;\n  title?: string;\n  disabled?: boolean;\n  loading?: boolean;\n  isLeaf?: boolean;\n  children?: NzCascaderOption[];\n  disableCheckbox?: boolean;\n\n  [key: string]: NzSafeAny;\n}\n\nexport interface NzShowSearchOptions {\n  filter?: NzCascaderFilter;\n  sorter?: NzCascaderSorter;\n}\n\nexport function isShowSearchObject(options: NzShowSearchOptions | boolean): options is NzShowSearchOptions {\n  return typeof options !== 'boolean';\n}\n\n/**\n * To avoid circular dependency, provide an interface of `NzCascaderComponent`\n * for `NzCascaderService`.\n */\nexport interface NzCascaderComponentAsSource {\n  inputValue: string;\n  nzShowSearch: NzShowSearchOptions | boolean;\n  nzLabelProperty: string;\n  nzValueProperty: string;\n  nzChangeOnSelect: boolean;\n  selectedNodes: NzTreeNode[];\n\n  get treeService(): NzCascaderTreeService;\n\n  coerceTreeNodes(value: NzSafeAny[]): NzTreeNode[];\n\n  updateSelectedNodes(): void;\n\n  nzChangeOn?(option: NzCascaderOption, level: number): boolean;\n\n  nzLoadData?(node: NzCascaderOption, index: number): PromiseLike<NzSafeAny> | Observable<NzSafeAny>;\n}\n"
  },
  {
    "path": "components/cascader/utils.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzTreeNode } from 'ng-zorro-antd/core/tree';\n\nexport function isChildNode(node: NzTreeNode): boolean {\n  return node.isLeaf || !node.children || !node.children.length;\n}\n\nexport function isParentNode(node: NzTreeNode): boolean {\n  return !!node.children && !!node.children.length && !node.isLeaf;\n}\n"
  },
  {
    "path": "components/cdk/overflow/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/cdk/overflow/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/cdk/overflow/overflow-container.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  Component,\n  ChangeDetectionStrategy,\n  ContentChildren,\n  QueryList,\n  ElementRef,\n  OnInit,\n  AfterContentInit,\n  ContentChild,\n  ChangeDetectorRef,\n  inject,\n  DestroyRef\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { BehaviorSubject, combineLatest, Observable, ReplaySubject, Subject } from 'rxjs';\nimport { filter, map, pairwise, startWith, switchMap, withLatestFrom } from 'rxjs/operators';\n\nimport { NzResizeObserver } from 'ng-zorro-antd/cdk/resize-observer';\n\nimport { NzOverflowItemDirective } from './overflow-item.directive';\nimport { NzOverflowRestDirective } from './overflow-rest.directive';\nimport { NzOverflowSuffixDirective } from './overflow-suffix.directive';\n\n@Component({\n  selector: 'nz-overflow-container',\n  template: `\n    <ng-content />\n    <ng-content select=\"[appOverflowRest]\" />\n    <ng-content select=\"[appOverflowSuffix]\" />\n  `,\n  providers: [NzResizeObserver],\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class NzOverflowContainerComponent implements OnInit, AfterContentInit {\n  private nzResizeObserver = inject(NzResizeObserver);\n  private elementRef = inject(ElementRef);\n  private cdr = inject(ChangeDetectorRef);\n  private destroyRef = inject(DestroyRef);\n\n  contentInit$ = new Subject<void>();\n  @ContentChildren(NzOverflowItemDirective)\n  overflowItems: QueryList<NzOverflowItemDirective> | undefined = undefined;\n  @ContentChild(NzOverflowSuffixDirective)\n  overflowSuffix: NzOverflowSuffixDirective | undefined = undefined;\n  @ContentChild(NzOverflowRestDirective) overflowRest: NzOverflowRestDirective | undefined = undefined;\n  overflowItems$ = new ReplaySubject<QueryList<NzOverflowItemDirective>>(1);\n\n  containerWidth$ = this.nzResizeObserver\n    .observe(this.elementRef.nativeElement)\n    .pipe(map(([item]) => item.target.clientWidth || 0));\n  restWidth$ = new BehaviorSubject<number>(0);\n  suffixWidth$ = new BehaviorSubject<number>(0);\n  suffixFixedStart$ = new BehaviorSubject<number | null>(null);\n  displayCount$ = new BehaviorSubject<number>(Number.MAX_SAFE_INTEGER);\n  restReady$ = new BehaviorSubject<boolean>(false);\n  maxRestWith$ = this.restWidth$.pipe(\n    pairwise(),\n    map(([prevRestWidth, restWidth]) => Math.max(prevRestWidth, restWidth))\n  );\n  omittedItems$ = combineLatest([this.overflowItems$, this.displayCount$]).pipe(\n    withLatestFrom(this.contentInit$),\n    map(([[overflowItems, displayCount]]) => overflowItems.toArray().slice(displayCount + 1))\n  );\n  displayRest$ = combineLatest([this.restReady$, this.omittedItems$]).pipe(\n    map(([restReady, omittedItems]) => restReady && !!omittedItems.length)\n  );\n\n  updateDisplayCount(count: number, notReady?: boolean): void {\n    this.displayCount$.next(count);\n    if (this.overflowItems && !notReady) {\n      this.restReady$.next(count < this.overflowItems.length - 1);\n    }\n  }\n\n  ngOnInit(): void {\n    const overflowItemsWidth$ = this.overflowItems$.pipe(\n      switchMap(items => combineLatest(items.map(item => item.itemWidth$)))\n    ) as Observable<number[]>;\n    this.overflowItems$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(overflowItems => {\n      if (!overflowItems.length) {\n        this.displayCount$.next(0);\n        this.suffixFixedStart$.next(null);\n      }\n    });\n    combineLatest([overflowItemsWidth$, this.containerWidth$, this.maxRestWith$, this.restWidth$, this.suffixWidth$])\n      .pipe(\n        filter(([, containerWidth, maxRestWith]) => !!(containerWidth && maxRestWith)),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(([overflowItemsWidth, containerWidth, maxRestWith, restWidth, suffixWidth]) => {\n        let totalWidth = suffixWidth;\n        const len = overflowItemsWidth.length;\n        const lastIndex = len - 1;\n        for (let i = 0; i < len; i += 1) {\n          const currentItemWidth = overflowItemsWidth[i];\n          // Break since data not ready\n          if (currentItemWidth === undefined) {\n            this.updateDisplayCount(i - 1, true);\n            break;\n          } else {\n            // Find best match\n            totalWidth += currentItemWidth;\n\n            if (\n              // Only one means `totalWidth` is the final width\n              (lastIndex === 0 && totalWidth <= containerWidth) ||\n              // Last two width will be the final width\n              (i === lastIndex - 1 &&\n                overflowItemsWidth[lastIndex] !== undefined &&\n                totalWidth + overflowItemsWidth[lastIndex]! <= containerWidth)\n            ) {\n              // Additional check if match the end\n              this.updateDisplayCount(lastIndex);\n              this.suffixFixedStart$.next(null);\n              break;\n            } else if (totalWidth + maxRestWith > containerWidth) {\n              // Can not hold all the content to show rest\n              this.updateDisplayCount(i - 1);\n              this.suffixFixedStart$.next(totalWidth - currentItemWidth - suffixWidth + restWidth);\n              break;\n            }\n            this.cdr.detectChanges();\n          }\n        }\n        if (\n          this.overflowSuffix &&\n          overflowItemsWidth[0] !== undefined &&\n          overflowItemsWidth[0] + suffixWidth > containerWidth\n        ) {\n          this.suffixFixedStart$.next(null);\n        }\n\n        this.cdr.detectChanges();\n      });\n    combineLatest([this.suffixFixedStart$, this.displayCount$])\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(([suffixFixedStart, displayCount]) => {\n        this.overflowSuffix?.setSuffixStyle(suffixFixedStart, displayCount);\n      });\n    combineLatest([this.displayCount$, this.overflowItems$])\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(([displayCount, overflowItems]) =>\n        overflowItems.forEach((item, index) => item.setItemStyle(index <= displayCount, index))\n      );\n    combineLatest([this.displayRest$, this.displayCount$])\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(([displayRest, displayCount]) => {\n        this.overflowRest?.setRestStyle(displayRest, displayRest ? displayCount : Number.MAX_SAFE_INTEGER);\n      });\n  }\n  ngAfterContentInit(): void {\n    this.overflowItems?.changes.pipe(startWith(this.overflowItems)).subscribe(this.overflowItems$);\n    this.overflowSuffix?.suffixWidth$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(this.suffixWidth$);\n    this.overflowRest?.restWidth$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(this.restWidth$);\n    this.contentInit$.next();\n  }\n}\n"
  },
  {
    "path": "components/cdk/overflow/overflow-item.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectorRef, Directive, ElementRef, inject } from '@angular/core';\nimport { distinctUntilChanged, map, startWith, tap } from 'rxjs/operators';\n\nimport { NzResizeObserver } from 'ng-zorro-antd/cdk/resize-observer';\n\n@Directive({\n  selector: '[nzOverflowItem]',\n  host: {\n    '[style]': 'overflowStyle'\n  }\n})\nexport class NzOverflowItemDirective {\n  private nzResizeObserver = inject(NzResizeObserver);\n  private elementRef = inject(ElementRef);\n  private cdr = inject(ChangeDetectorRef);\n\n  overflowStyle: Record<string, string | number | undefined> | undefined = undefined;\n  itemWidth$ = this.nzResizeObserver.observe(this.elementRef.nativeElement).pipe(\n    map(([item]) => (item.target as HTMLElement).offsetWidth),\n    distinctUntilChanged(),\n    startWith(undefined),\n    tap(width => {\n      this.itemWidth = width;\n    })\n  );\n  itemWidth: number | undefined = undefined;\n\n  setItemStyle(display: boolean, order: number): void {\n    const mergedHidden = !display;\n    this.overflowStyle = {\n      opacity: mergedHidden ? 0 : 1,\n      height: mergedHidden ? 0 : undefined,\n      overflowY: mergedHidden ? 'hidden' : undefined,\n      order: order,\n      pointerEvents: mergedHidden ? 'none' : undefined,\n      position: mergedHidden ? 'absolute' : undefined\n    };\n    this.cdr.detectChanges();\n  }\n}\n"
  },
  {
    "path": "components/cdk/overflow/overflow-rest.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectorRef, Directive, ElementRef, inject } from '@angular/core';\nimport { map, startWith, tap } from 'rxjs/operators';\n\nimport { NzResizeObserver } from 'ng-zorro-antd/cdk/resize-observer';\n\n@Directive({\n  selector: '[nzOverflowRest]',\n  host: {\n    '[style]': 'restStyle'\n  }\n})\nexport class NzOverflowRestDirective {\n  private nzResizeObserver = inject(NzResizeObserver);\n  private elementRef = inject(ElementRef);\n  private cdr = inject(ChangeDetectorRef);\n\n  restStyle: Record<string, string | number | undefined> | undefined = undefined;\n  restWidth$ = this.nzResizeObserver.observe(this.elementRef.nativeElement).pipe(\n    map(([item]) => (item.target as HTMLElement).offsetWidth),\n    startWith(0),\n    tap(width => (this.restWidth = width))\n  );\n  restWidth = 0;\n\n  setRestStyle(display: boolean, order: number): void {\n    const mergedHidden = !display;\n    this.restStyle = {\n      opacity: mergedHidden ? 0 : 1,\n      height: mergedHidden ? 0 : undefined,\n      overflowY: mergedHidden ? 'hidden' : undefined,\n      order: order,\n      pointerEvents: mergedHidden ? 'none' : undefined,\n      position: mergedHidden ? 'absolute' : undefined\n    };\n    this.cdr.detectChanges();\n  }\n}\n"
  },
  {
    "path": "components/cdk/overflow/overflow-suffix.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectorRef, Directive, ElementRef, inject } from '@angular/core';\nimport { map, tap } from 'rxjs/operators';\n\nimport { NzResizeObserver } from 'ng-zorro-antd/cdk/resize-observer';\n\n@Directive({\n  selector: '[nzOverflowSuffix]',\n  host: {\n    '[style]': 'suffixStyle'\n  }\n})\nexport class NzOverflowSuffixDirective {\n  private nzResizeObserver = inject(NzResizeObserver);\n  private elementRef = inject(ElementRef);\n  private cdr = inject(ChangeDetectorRef);\n\n  suffixStyle = {};\n  suffixWidth$ = this.nzResizeObserver.observe(this.elementRef.nativeElement).pipe(\n    map(([item]) => (item.target as HTMLElement).offsetWidth),\n    tap(width => (this.suffixWidth = width))\n  );\n  suffixWidth = 0;\n\n  setSuffixStyle(start: number | null, order: number): void {\n    if (start !== null) {\n      this.suffixStyle = {\n        position: 'absolute',\n        left: `${start}px`,\n        top: 0,\n        opacity: 1,\n        order: order\n      };\n    } else {\n      this.suffixStyle = {\n        opacity: 1,\n        order: order\n      };\n    }\n    this.cdr.detectChanges();\n  }\n}\n"
  },
  {
    "path": "components/cdk/overflow/overflow.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzOverflowContainerComponent } from './overflow-container.component';\nimport { NzOverflowItemDirective } from './overflow-item.directive';\nimport { NzOverflowRestDirective } from './overflow-rest.directive';\nimport { NzOverflowSuffixDirective } from './overflow-suffix.directive';\n\n@NgModule({\n  imports: [NzOverflowContainerComponent, NzOverflowItemDirective, NzOverflowRestDirective, NzOverflowSuffixDirective],\n  exports: [NzOverflowContainerComponent, NzOverflowItemDirective, NzOverflowRestDirective, NzOverflowSuffixDirective]\n})\nexport class NzOverflowModule {}\n"
  },
  {
    "path": "components/cdk/overflow/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport { NzOverflowModule } from './overflow.module';\nexport { NzOverflowContainerComponent } from './overflow-container.component';\nexport { NzOverflowItemDirective } from './overflow-item.directive';\nexport { NzOverflowRestDirective } from './overflow-rest.directive';\nexport { NzOverflowSuffixDirective } from './overflow-suffix.directive';\n"
  },
  {
    "path": "components/cdk/resize-observer/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/cdk/resize-observer/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/cdk/resize-observer/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport { NzResizeObserverModule } from './resize-observer.module';\nexport { NzResizeObserverDirective } from './resize-observer.directive';\nexport { NzResizeObserver, NzResizeObserverFactory } from './resize-observer.service';\n"
  },
  {
    "path": "components/cdk/resize-observer/resize-observer.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  AfterContentInit,\n  Directive,\n  ElementRef,\n  EventEmitter,\n  Input,\n  OnChanges,\n  Output,\n  SimpleChanges,\n  booleanAttribute,\n  inject,\n  DestroyRef\n} from '@angular/core';\nimport { Subscription } from 'rxjs';\n\nimport { NzResizeObserver, NzResizeObserverFactory } from './resize-observer.service';\n\n@Directive({\n  selector: '[nzResizeObserver]',\n  providers: [NzResizeObserverFactory]\n})\nexport class NzResizeObserverDirective implements AfterContentInit, OnChanges {\n  private nzResizeObserver = inject(NzResizeObserver);\n  private elementRef = inject(ElementRef<HTMLElement>);\n  private destroyRef = inject(DestroyRef);\n\n  @Output() readonly nzResizeObserve = new EventEmitter<ResizeObserverEntry[]>();\n  @Input({ transform: booleanAttribute }) nzResizeObserverDisabled = false;\n  private currentSubscription: Subscription | null = null;\n\n  private subscribe(): void {\n    this.unsubscribe();\n    this.currentSubscription = this.nzResizeObserver.observe(this.elementRef).subscribe(this.nzResizeObserve);\n  }\n\n  private unsubscribe(): void {\n    this.currentSubscription?.unsubscribe();\n  }\n\n  constructor() {\n    this.destroyRef.onDestroy(() => this.unsubscribe());\n  }\n\n  ngAfterContentInit(): void {\n    if (!this.currentSubscription && !this.nzResizeObserverDisabled) {\n      this.subscribe();\n    }\n  }\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzResizeObserve } = changes;\n    if (nzResizeObserve) {\n      if (this.nzResizeObserverDisabled) {\n        this.unsubscribe();\n      } else {\n        this.subscribe();\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/cdk/resize-observer/resize-observer.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzResizeObserverDirective } from './resize-observer.directive';\n\n@NgModule({\n  imports: [NzResizeObserverDirective],\n  exports: [NzResizeObserverDirective]\n})\nexport class NzResizeObserverModule {}\n"
  },
  {
    "path": "components/cdk/resize-observer/resize-observer.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { coerceElement } from '@angular/cdk/coercion';\nimport { DestroyRef, ElementRef, inject, Injectable } from '@angular/core';\nimport { Observable, Observer, Subject } from 'rxjs';\n\n/**\n * Factory that creates a new ResizeObserver and allows us to stub it out in unit tests.\n */\n@Injectable({ providedIn: 'root' })\nexport class NzResizeObserverFactory {\n  create(callback: ResizeObserverCallback): ResizeObserver | null {\n    return typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(callback);\n  }\n}\n\n/** An injectable service that allows watching elements for changes to their content. */\n@Injectable({ providedIn: 'root' })\nexport class NzResizeObserver {\n  private nzResizeObserverFactory = inject(NzResizeObserverFactory);\n  private destroyRef = inject(DestroyRef);\n  /** Keeps track of the existing ResizeObservers so they can be reused. */\n  private observedElements = new Map<\n    Element,\n    {\n      observer: ResizeObserver | null;\n      stream: Subject<ResizeObserverEntry[]>;\n      count: number;\n    }\n  >();\n\n  constructor() {\n    this.destroyRef.onDestroy(() => this.observedElements.forEach((_, element) => this.cleanupObserver(element)));\n  }\n\n  observe(elementOrRef: Element | ElementRef<Element>): Observable<ResizeObserverEntry[]> {\n    const element = coerceElement(elementOrRef);\n\n    return new Observable((observer: Observer<ResizeObserverEntry[]>) => {\n      const stream = this.observeElement(element);\n      const subscription = stream.subscribe(observer);\n\n      return () => {\n        subscription.unsubscribe();\n        this.unobserveElement(element);\n      };\n    });\n  }\n\n  /**\n   * Observes the given element by using the existing ResizeObserver if available, or creating a\n   * new one if not.\n   */\n  private observeElement(element: Element): Subject<ResizeObserverEntry[]> {\n    if (!this.observedElements.has(element)) {\n      const stream = new Subject<ResizeObserverEntry[]>();\n      const observer = this.nzResizeObserverFactory.create((mutations: ResizeObserverEntry[]) =>\n        stream.next(mutations)\n      );\n      if (observer) {\n        observer.observe(element);\n      }\n      this.observedElements.set(element, { observer, stream, count: 1 });\n    } else {\n      this.observedElements.get(element)!.count++;\n    }\n    return this.observedElements.get(element)!.stream;\n  }\n\n  /**\n   * Un-observes the given element and cleans up the underlying ResizeObserver if nobody else is\n   * observing this element.\n   */\n  private unobserveElement(element: Element): void {\n    if (this.observedElements.has(element)) {\n      this.observedElements.get(element)!.count--;\n      if (!this.observedElements.get(element)!.count) {\n        this.cleanupObserver(element);\n      }\n    }\n  }\n\n  /** Clean up the underlying ResizeObserver for the specified element. */\n  private cleanupObserver(element: Element): void {\n    if (this.observedElements.has(element)) {\n      const { observer, stream } = this.observedElements.get(element)!;\n      if (observer) {\n        observer.disconnect();\n      }\n      stream.complete();\n      this.observedElements.delete(element);\n    }\n  }\n}\n"
  },
  {
    "path": "components/cdk/resize-observer/resize-observer.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, EventEmitter, SimpleChanges } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { Subscription } from 'rxjs';\n\nimport { NzResizeObserverDirective } from 'ng-zorro-antd/cdk/resize-observer/resize-observer.directive';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\ndescribe('resize observer', () => {\n  let fixture: ComponentFixture<TestHostComponent>;\n  let directive: NzResizeObserverDirective;\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(TestHostComponent);\n    directive = fixture.debugElement.children[0].injector.get(NzResizeObserverDirective);\n  });\n\n  it('should have correct initial values', () => {\n    expect(directive.nzResizeObserve).toBeDefined();\n    expect(directive.nzResizeObserve).toBeInstanceOf(EventEmitter);\n\n    expect(directive.nzResizeObserverDisabled).toEqual(false);\n\n    expect(directive['currentSubscription']).toEqual(null);\n  });\n\n  it('should call subscribe when all the conditions are met', () => {\n    directive['currentSubscription'] = null;\n    directive.nzResizeObserverDisabled = false;\n    spyOn<NzSafeAny>(directive, 'subscribe');\n    directive.ngAfterContentInit();\n    expect(directive['subscribe']).toHaveBeenCalled();\n  });\n\n  it('should not call subscribe when nzResizeObserverDisabled is true', () => {\n    directive['currentSubscription'] = null;\n    directive.nzResizeObserverDisabled = true;\n    spyOn<NzSafeAny>(directive, 'subscribe');\n    directive.ngAfterContentInit();\n    expect(directive['subscribe']).not.toHaveBeenCalled();\n  });\n\n  it('should not call subscribe when currentSubscription is truthy', () => {\n    directive['currentSubscription'] = new Subscription();\n    directive.nzResizeObserverDisabled = false;\n    spyOn<NzSafeAny>(directive, 'subscribe');\n    directive.ngAfterContentInit();\n    expect(directive['subscribe']).not.toHaveBeenCalled();\n  });\n\n  it('should call unsubscribe when nzResizeObserve is changed and nzResizeObserverDisabled is true', () => {\n    const change = {\n      nzResizeObserve: {}\n    };\n    spyOn<NzSafeAny>(directive, 'unsubscribe');\n    directive.nzResizeObserverDisabled = true;\n    directive.ngOnChanges(change as unknown as SimpleChanges);\n    expect(directive['unsubscribe']).toHaveBeenCalled();\n  });\n\n  it('should call subscribe when nzResizeObserve is changed and nzResizeObserverDisabled is false', () => {\n    const change = {\n      nzResizeObserve: {}\n    };\n    spyOn<NzSafeAny>(directive, 'subscribe');\n    directive.nzResizeObserverDisabled = false;\n    directive.ngOnChanges(change as unknown as SimpleChanges);\n    expect(directive['subscribe']).toHaveBeenCalled();\n  });\n\n  it('should call correct methods when calling subscribe', () => {\n    spyOn<NzSafeAny>(directive, 'unsubscribe');\n    directive['subscribe']();\n    expect(directive['unsubscribe']).toHaveBeenCalled();\n  });\n\n  it('should destroy the observedElements', () => {\n    const element = document.createElement('div');\n    directive['nzResizeObserver'].observe(element);\n    fixture.detectChanges();\n    spyOn<NzSafeAny>(directive['nzResizeObserver'], 'cleanupObserver');\n    fixture.destroy();\n    expect(directive['nzResizeObserver']['cleanupObserver']).toHaveBeenCalled();\n  });\n\n  it('should return correct resizeObserver if it is supported', () => {\n    // eslint-disable-next-line no-global-assign\n    ResizeObserver = undefined as NzSafeAny;\n    const result = directive['nzResizeObserver']['nzResizeObserverFactory'].create(jasmine.createSpy('callback'));\n    expect(result).toEqual(null);\n  });\n});\n\n@Component({\n  template: `<div nzResizeObserver></div>`,\n  imports: [NzResizeObserverDirective]\n})\nclass TestHostComponent {}\n"
  },
  {
    "path": "components/check-list/check-list-button.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';\n\n@Component({\n  selector: 'nz-check-list-button',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `<ng-content />`,\n  host: {\n    class: 'ant-btn ant-btn-primary ant-check-list-button'\n  }\n})\nexport class NzCheckListButtonComponent {}\n"
  },
  {
    "path": "components/check-list/check-list-content.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { DecimalPipe } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  computed,\n  input,\n  output,\n  signal,\n  TemplateRef,\n  ViewEncapsulation\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzCheckboxModule } from 'ng-zorro-antd/checkbox';\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzCheckListI18nInterface } from 'ng-zorro-antd/i18n';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzProgressModule } from 'ng-zorro-antd/progress';\n\nimport { NzItemProps } from './typings';\n\n@Component({\n  selector: 'nz-check-list-content',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  imports: [NzIconModule, NzProgressModule, NzOutletModule, NzCheckboxModule, NzButtonModule, FormsModule, DecimalPipe],\n  template: `\n    @let i18n = locale();\n    @if (visible()) {\n      @if (progressPercent() === 100) {\n        <div class=\"ant-check-list-header-finish\">\n          <nz-icon nzType=\"check-circle\" nzTheme=\"outline\" class=\"ant-check-list-header-finish-icon\" />\n          <h3 class=\"ant-check-list-header-finish-title\">{{ i18n.checkListFinish }}</h3>\n          <button nz-button nzType=\"primary\" [style.margin.px]=\"24\" (click)=\"closePopover.emit(false)\">\n            {{ i18n.checkListClose }}\n          </button>\n        </div>\n      } @else {\n        <div class=\"ant-check-list-header\">\n          <div class=\"ant-check-list-header-title\">\n            @if (!!title()) {\n              <ng-container *nzStringTemplateOutlet=\"title()\">{{ title() }}</ng-container>\n            } @else {\n              {{ i18n.checkList }}\n            }\n          </div>\n          <div class=\"ant-check-list-header-extra\">\n            <nz-icon nzType=\"down\" nzTheme=\"outline\" (click)=\"closePopover.emit(false)\" />\n          </div>\n        </div>\n        @if (progress()) {\n          <div class=\"ant-check-list-progressBar\">\n            <div class=\"ant-check-list-progressBar-progress\">\n              <nz-progress [nzPercent]=\"progressPercent() | number: '1.0-0'\" />\n            </div>\n          </div>\n        }\n      }\n      <div class=\"ant-check-list-steps-content\">\n        @for (item of items(); track item.key || item.description) {\n          @let itemHighlight = index() === $index + 1;\n          <div\n            class=\"ant-check-list-steps\"\n            [class.ant-check-list-highlight]=\"itemHighlight\"\n            [class.ant-check-list-checked]=\"item?.checked\"\n          >\n            <div class=\"ant-check-list-steps-item\">\n              <div class=\"ant-check-list-steps-item-circle\">\n                @if (item?.checked) {\n                  <nz-icon nzType=\"check\" nzTheme=\"outline\" class=\"ant-check-list-steps-checkoutlined\" />\n                } @else {\n                  <div class=\"ant-check-list-steps-number\">{{ $index + 1 }}</div>\n                }\n              </div>\n              <div class=\"ant-check-list-steps-item-description\">{{ item.description }}</div>\n            </div>\n            @if (itemHighlight && !!item?.onClick) {\n              <nz-icon\n                nzType=\"arrow-right\"\n                nzTheme=\"outline\"\n                class=\"ant-check-list-steps-item-arrows\"\n                (click)=\"item.onClick?.(item)\"\n              />\n            }\n          </div>\n        }\n      </div>\n      <div class=\"ant-check-list-footer\" (click)=\"visible.set(false)\">\n        @if (!!footer()) {\n          <ng-container *nzStringTemplateOutlet=\"footer()\">{{ footer() }}</ng-container>\n        } @else {\n          {{ i18n.checkListFooter }}\n        }\n      </div>\n    } @else {\n      <div class=\"ant-check-list-close-check\">\n        <div class=\"ant-check-list-close-check-title\">{{ i18n.checkListCheck }}</div>\n        <div class=\"ant-check-list-close-check-action\">\n          <button nz-button nzType=\"primary\" (click)=\"visible.set(false); hide.emit(checked)\">{{ i18n.ok }}</button>\n          <button nz-button (click)=\"visible.set(true)\">{{ i18n.cancel }}</button>\n        </div>\n        <div class=\"ant-check-list-close-check-other\">\n          <label nz-checkbox [(ngModel)]=\"checked\">{{ i18n.checkListCheckOther }}</label>\n        </div>\n      </div>\n    }\n  `,\n  host: {\n    class: 'ant-check-list-content'\n  }\n})\nexport class NzCheckListContentComponent {\n  locale = input.required<NzCheckListI18nInterface>();\n  items = input<NzItemProps[]>([]);\n  index = input(0);\n  progress = input(true);\n  title = input<TemplateRef<void> | string | null>(null);\n  footer = input<TemplateRef<void> | string | null>(null);\n  readonly closePopover = output<boolean>();\n  readonly hide = output<boolean>();\n\n  protected checked = false;\n  protected visible = signal(true);\n  protected progressPercent = computed(() => {\n    const index = Math.min(Math.max(this.index() - 1, 0), this.items().length);\n    return (index / this.items().length) * 100;\n  });\n}\n"
  },
  {
    "path": "components/check-list/check-list.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport { Component, DebugElement, provideZoneChangeDetection, TemplateRef } from '@angular/core';\nimport { ComponentFixture, fakeAsync, inject, TestBed, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { dispatchMouseEvent } from 'ng-zorro-antd/core/testing';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzCheckListComponent } from './check-list.component';\nimport { NzCheckListModule } from './check-list.module';\nimport { NzItemProps } from './typings';\n\ndescribe('check-list', () => {\n  let fixture: ComponentFixture<NzTestCheckListBasicComponent>;\n  let testComponent: NzTestCheckListBasicComponent;\n  let resultEl: DebugElement;\n  let overlayContainer: OverlayContainer;\n  let overlayContainerElement: HTMLElement;\n\n  function waitingForTooltipToggling(): void {\n    fixture.detectChanges();\n    tick(500);\n    fixture.detectChanges();\n  }\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), provideNzIconsTesting(), provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzTestCheckListBasicComponent);\n    fixture.detectChanges();\n    testComponent = fixture.debugElement.componentInstance;\n    resultEl = fixture.debugElement.query(By.directive(NzCheckListComponent));\n  });\n\n  beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n    overlayContainer = oc;\n    overlayContainerElement = oc.getContainerElement();\n  }));\n\n  afterEach(() => {\n    overlayContainer.ngOnDestroy();\n  });\n\n  it('basic', () => {\n    expect(resultEl.nativeElement.classList).toContain('ant-check-list');\n    expect(!!resultEl.nativeElement.querySelector('.ant-check-list-button .ant-check-list-icon')).toBeTrue();\n    expect(!!resultEl.nativeElement.querySelector('.ant-check-list-button .ant-check-list-description')).toBeTrue();\n  });\n\n  it('nzVisible', fakeAsync(() => {\n    testComponent.visible = true;\n    fixture.detectChanges();\n    waitingForTooltipToggling();\n    expect(!!overlayContainerElement.querySelector('.ant-popover-inner-content')).toBeTrue();\n    expect(!!overlayContainerElement.querySelector('.ant-popover-inner-content .ant-check-list-header')).toBeTrue();\n    expect(\n      !!overlayContainerElement.querySelector(\n        '.ant-popover-inner-content .ant-check-list-header .ant-check-list-header-title'\n      )\n    ).toBeTrue();\n  }));\n\n  it('nzItems', fakeAsync(() => {\n    testComponent.visible = true;\n    testComponent.items = [\n      {\n        description: 'Step 1',\n        onClick: () => {}\n      }\n    ];\n    fixture.detectChanges();\n    waitingForTooltipToggling();\n    expect(!!overlayContainerElement.querySelector('.ant-check-list-steps')).toBeTrue();\n  }));\n\n  it('nzProgress', fakeAsync(() => {\n    testComponent.visible = true;\n    fixture.detectChanges();\n    waitingForTooltipToggling();\n    expect(!!overlayContainerElement.querySelector('.ant-check-list-progressBar')).toBeTrue();\n    testComponent.progress = false;\n    fixture.detectChanges();\n    expect(!overlayContainerElement.querySelector('.ant-check-list-progressBar')).toBeTrue();\n  }));\n\n  it('nzIndex', fakeAsync(() => {\n    testComponent.visible = true;\n    testComponent.items = [\n      {\n        description: 'Step 1',\n        onClick: () => {}\n      },\n      {\n        description: 'Step 2',\n        onClick: () => {}\n      }\n    ];\n    fixture.detectChanges();\n    waitingForTooltipToggling();\n    expect(overlayContainerElement.querySelectorAll('.ant-check-list-steps').length).toBe(2);\n    expect(\n      (\n        overlayContainerElement.querySelector(\n          '.ant-check-list-highlight .ant-check-list-steps-item-description'\n        ) as HTMLElement\n      ).innerText\n    ).toBe('Step 1');\n    expect((overlayContainerElement.querySelector('.ant-progress-text') as HTMLElement).innerText).toBe('0%');\n    expect(overlayContainerElement.querySelectorAll('.ant-check-list-steps-item-arrows').length).toBe(1);\n\n    testComponent.index = 2;\n    testComponent.items = [\n      {\n        description: 'Step 1',\n        checked: true,\n        onClick: () => {}\n      },\n      {\n        description: 'Step 2',\n        onClick: () => {}\n      }\n    ];\n    fixture.detectChanges();\n    expect(\n      (\n        overlayContainerElement.querySelector(\n          '.ant-check-list-checked .ant-check-list-steps-item-description'\n        ) as HTMLElement\n      ).innerText\n    ).toBe('Step 1');\n    expect(\n      (\n        overlayContainerElement.querySelector(\n          '.ant-check-list-highlight .ant-check-list-steps-item-description'\n        ) as HTMLElement\n      ).innerText\n    ).toBe('Step 2');\n    expect((overlayContainerElement.querySelector('.ant-progress-text') as HTMLElement).innerText).toBe('50%');\n\n    testComponent.index = 3;\n    testComponent.items = [\n      {\n        description: 'Step 1',\n        checked: true,\n        onClick: () => {}\n      },\n      {\n        description: 'Step 2',\n        checked: true,\n        onClick: () => {}\n      }\n    ];\n    fixture.detectChanges();\n    expect(!overlayContainerElement.querySelector('.ant-check-list-progressBar')).toBeTrue();\n    expect(!!overlayContainerElement.querySelector('.ant-check-list-header-finish')).toBeTrue();\n  }));\n\n  it('lose the list when you are finished', fakeAsync(() => {\n    testComponent.visible = true;\n    testComponent.items = [\n      {\n        description: 'Step 1',\n        onClick: () => {}\n      }\n    ];\n    testComponent.index = 2;\n    fixture.detectChanges();\n    waitingForTooltipToggling();\n    const dom = overlayContainerElement.querySelector('.ant-check-list-header-finish .ant-btn');\n    if (dom) {\n      dispatchMouseEvent(dom, 'click');\n      waitingForTooltipToggling();\n      expect(!overlayContainerElement.querySelector('.ant-popover-inner-content')).toBeTrue();\n    }\n  }));\n\n  it('icon close List', fakeAsync(() => {\n    testComponent.visible = true;\n    fixture.detectChanges();\n    waitingForTooltipToggling();\n    const dom = overlayContainerElement.querySelector('.ant-check-list-header-extra .anticon');\n    if (dom) {\n      dispatchMouseEvent(dom, 'click');\n      waitingForTooltipToggling();\n      expect(!overlayContainerElement.querySelector('.ant-popover-inner-content')).toBeTrue();\n    }\n  }));\n\n  it('actively close the list', fakeAsync(() => {\n    testComponent.visible = true;\n    fixture.detectChanges();\n    waitingForTooltipToggling();\n    const dom = overlayContainerElement.querySelector('.ant-check-list-footer');\n    if (dom) {\n      dispatchMouseEvent(dom, 'click');\n      waitingForTooltipToggling();\n      expect(!!overlayContainerElement.querySelector('.ant-check-list-close-check')).toBeTrue();\n      const btnDom = overlayContainerElement.querySelector('.ant-check-list-close-check-action .ant-btn');\n      if (btnDom) {\n        dispatchMouseEvent(btnDom, 'click');\n        waitingForTooltipToggling();\n        expect(!overlayContainerElement.querySelector('.ant-popover-inner-content')).toBeTrue();\n      }\n    }\n  }));\n\n  it('actively close hidden lists', fakeAsync(() => {\n    testComponent.visible = true;\n    fixture.detectChanges();\n    waitingForTooltipToggling();\n    const footer = overlayContainerElement.querySelector('.ant-check-list-footer');\n    expect(footer).not.toBeNull();\n    dispatchMouseEvent(footer!, 'click');\n    waitingForTooltipToggling();\n\n    expect(!!overlayContainerElement.querySelector('.ant-check-list-close-check')).toBeTrue();\n    expect(\n      !!overlayContainerElement.querySelector('.ant-check-list-close-check .ant-check-list-close-check-title')\n    ).toBeTrue();\n    expect(\n      !!overlayContainerElement.querySelector('.ant-check-list-close-check .ant-check-list-close-check-action')\n    ).toBeTrue();\n    expect(\n      !!overlayContainerElement.querySelector('.ant-check-list-close-check .ant-check-list-close-check-other')\n    ).toBeTrue();\n\n    // close manually\n    const labelEl = overlayContainerElement.querySelector('.ant-check-list-close-check-other .ant-checkbox-wrapper');\n    expect(labelEl).not.toBeNull();\n    dispatchMouseEvent(labelEl!, 'click');\n    waitingForTooltipToggling();\n    const btnEl = overlayContainerElement.querySelector('.ant-check-list-close-check-action .ant-btn-primary');\n    expect(btnEl).not.toBeNull();\n    dispatchMouseEvent(btnEl!, 'click');\n    waitingForTooltipToggling();\n    expect(overlayContainerElement.querySelector('.ant-check-list')).toBeNull();\n  }));\n\n  it('nzTriggerRender ', () => {\n    testComponent.triggerRender = 'Check List';\n    fixture.detectChanges();\n    expect((resultEl.nativeElement.querySelector('.ant-check-list-button') as HTMLElement).innerText).toBe(\n      'Check List'\n    );\n  });\n\n  it('nzTitle', fakeAsync(() => {\n    testComponent.title = 'Check List';\n    testComponent.visible = true;\n    fixture.detectChanges();\n    waitingForTooltipToggling();\n    expect((overlayContainerElement.querySelector('.ant-check-list-header-title') as HTMLElement).innerText).toBe(\n      'Check List'\n    );\n  }));\n\n  it('nzFooter', fakeAsync(() => {\n    testComponent.footer = 'Check List';\n    testComponent.visible = true;\n    fixture.detectChanges();\n    waitingForTooltipToggling();\n    expect((overlayContainerElement.querySelector('.ant-check-list-footer') as HTMLElement).innerText).toBe(\n      'Check List'\n    );\n  }));\n});\n\n@Component({\n  selector: 'nz-test-check-list-basic',\n  imports: [NzCheckListModule],\n  template: `\n    <nz-check-list\n      [nzVisible]=\"visible\"\n      [nzItems]=\"items\"\n      [nzIndex]=\"index\"\n      [nzProgress]=\"progress\"\n      [nzTriggerRender]=\"triggerRender\"\n      [nzTitle]=\"title\"\n      [nzFooter]=\"footer\"\n    />\n  `\n})\nexport class NzTestCheckListBasicComponent {\n  visible: boolean = false;\n  items: NzItemProps[] = [];\n  index: number = 1;\n  progress: boolean = true;\n  triggerRender: TemplateRef<void> | string | null = null;\n  title: TemplateRef<void> | string | null = null;\n  footer: TemplateRef<void> | string | null = null;\n}\n"
  },
  {
    "path": "components/check-list/check-list.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { DecimalPipe } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  computed,\n  inject,\n  input,\n  linkedSignal,\n  output,\n  TemplateRef,\n  ViewEncapsulation\n} from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { map } from 'rxjs/operators';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzCheckListI18nInterface, NzI18nService } from 'ng-zorro-antd/i18n';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzPopoverModule } from 'ng-zorro-antd/popover';\n\nimport { NzCheckListButtonComponent } from './check-list-button.component';\nimport { NzCheckListContentComponent } from './check-list-content.component';\nimport { NzItemProps } from './typings';\n\n@Component({\n  selector: 'nz-check-list',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  imports: [\n    NzPopoverModule,\n    NzIconModule,\n    NzOutletModule,\n    NzCheckListButtonComponent,\n    NzCheckListContentComponent,\n    DecimalPipe\n  ],\n  template: `\n    <nz-check-list-button\n      nz-popover\n      [nzPopoverContent]=\"checklistTemplate\"\n      nzPopoverTrigger=\"click\"\n      nzPopoverPlacement=\"topRight\"\n      [nzPopoverOverlayClickable]=\"false\"\n      [nzPopoverVisible]=\"visible()\"\n      (nzPopoverVisibleChange)=\"visible.set($event)\"\n    >\n      @if (!!nzTriggerRender()) {\n        <ng-container *nzStringTemplateOutlet=\"nzTriggerRender()\">{{ nzTriggerRender() }}</ng-container>\n      } @else {\n        <nz-icon nzType=\"check-circle\" nzTheme=\"outline\" class=\"ant-check-list-icon\" />\n        <div class=\"ant-check-list-description\">{{ locale().checkList }}</div>\n      }\n      @if (!visible() && !!unfinished()) {\n        <div class=\"ant-check-list-trigger-dot\">\n          <div class=\"ant-check-list-trigger-dot-text\">{{ unfinished() | number: '1.0-0' }}</div>\n        </div>\n      }\n    </nz-check-list-button>\n    <ng-template #checklistTemplate>\n      <nz-check-list-content\n        [locale]=\"locale()\"\n        [items]=\"nzItems()\"\n        [index]=\"nzIndex()\"\n        [title]=\"nzTitle()\"\n        [progress]=\"nzProgress()\"\n        [footer]=\"nzFooter()\"\n        (closePopover)=\"visible.set($event)\"\n        (hide)=\"visible.set($event); nzHide.emit($event)\"\n      />\n    </ng-template>\n  `,\n  host: {\n    class: 'ant-check-list'\n  }\n})\nexport class NzCheckListComponent {\n  nzItems = input<NzItemProps[]>([]);\n  nzVisible = input(false);\n  nzIndex = input(1);\n  nzProgress = input(true);\n  nzTriggerRender = input<TemplateRef<void> | string | null>(null);\n  nzTitle = input<TemplateRef<void> | string | null>(null);\n  nzFooter = input<TemplateRef<void> | string | null>(null);\n  readonly nzHide = output<boolean>();\n  protected unfinished = computed(() => {\n    this.visible();\n    return this.nzItems().filter(item => !item?.checked).length;\n  });\n  protected visible = linkedSignal(this.nzVisible);\n  private i18n = inject(NzI18nService);\n  locale = toSignal<NzCheckListI18nInterface>(\n    this.i18n.localeChange.pipe(map(() => this.i18n.getLocaleData('CheckList'))),\n    { requireSync: true }\n  );\n}\n"
  },
  {
    "path": "components/check-list/check-list.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzCheckListComponent } from './check-list.component';\n\n@NgModule({\n  imports: [NzCheckListComponent],\n  exports: [NzCheckListComponent]\n})\nexport class NzCheckListModule {}\n"
  },
  {
    "path": "components/check-list/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n最简单的用法。\n\n## en-US\n\nThe simplest usage.\n"
  },
  {
    "path": "components/check-list/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCheckListModule, NzItemProps } from 'ng-zorro-antd/check-list';\n\n@Component({\n  selector: 'nz-demo-check-list-basic',\n  imports: [NzCheckListModule],\n  template: `<nz-check-list [nzItems]=\"nzItems\" [nzIndex]=\"index\" />`\n})\nexport class NzDemoCheckListBasicComponent {\n  index = 2;\n  readonly nzItems: NzItemProps[] = [\n    {\n      description: 'step 1',\n      checked: true,\n      onClick: (item: NzItemProps) => {\n        this.index++;\n        item.checked = true;\n      }\n    },\n    {\n      description: 'step 2',\n      onClick: (item: NzItemProps) => {\n        this.index++;\n        item.checked = true;\n      }\n    },\n    {\n      description: 'step 3',\n      onClick: (item: NzItemProps) => {\n        this.index++;\n        item.checked = true;\n      }\n    },\n    {\n      description: 'step 4',\n      onClick: (item: NzItemProps) => {\n        this.index++;\n        item.checked = true;\n      }\n    }\n  ];\n}\n"
  },
  {
    "path": "components/check-list/demo/custom.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 复杂场景\n  en-US: Complex\n---\n\n## zh-CN\n\n通过自定义参数配置预览效果。\n\n## en-US\n\nConfigure the preview effect by customizing parameters.\n"
  },
  {
    "path": "components/check-list/demo/custom.ts",
    "content": "import { Component, inject } from '@angular/core';\nimport { NonNullableFormBuilder, ReactiveFormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzCheckListModule, NzItemProps } from 'ng-zorro-antd/check-list';\nimport { NzCheckboxModule } from 'ng-zorro-antd/checkbox';\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzSegmentedModule } from 'ng-zorro-antd/segmented';\n\n@Component({\n  selector: 'nz-demo-check-list-custom',\n  imports: [\n    NzCheckListModule,\n    NzButtonModule,\n    NzFormModule,\n    ReactiveFormsModule,\n    NzCheckboxModule,\n    NzInputModule,\n    NzSegmentedModule\n  ],\n  template: `\n    <form nz-form nzLayout=\"vertical\" [formGroup]=\"form\">\n      <nz-form-item>\n        <nz-form-label>Visible</nz-form-label>\n        <nz-form-control>\n          <label nz-checkbox formControlName=\"nzVisible\"></label>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label>Show Progress</nz-form-label>\n        <nz-form-control>\n          <label nz-checkbox formControlName=\"nzProgress\"></label>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label>Index</nz-form-label>\n        <nz-form-control>\n          <nz-segmented [nzOptions]=\"options\" (nzValueChange)=\"handleIndexChange($event)\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label>Trigger Render</nz-form-label>\n        <nz-form-control>\n          <input nz-input formControlName=\"nzTriggerRender\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label>Title</nz-form-label>\n        <nz-form-control>\n          <input nz-input formControlName=\"nzTitle\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label>Footer</nz-form-label>\n        <nz-form-control>\n          <input nz-input formControlName=\"nzFooter\" />\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n\n    <nz-check-list\n      [nzItems]=\"nzItems\"\n      [nzVisible]=\"form.controls.nzVisible.value\"\n      [nzIndex]=\"form.controls.nzIndex.value || 0\"\n      [nzProgress]=\"form.controls.nzProgress.value\"\n      [nzTriggerRender]=\"form.controls.nzTriggerRender.value\"\n      [nzTitle]=\"form.controls.nzTitle.value\"\n      [nzFooter]=\"form.controls.nzFooter.value\"\n      (nzHide)=\"hideCancel($event)\"\n    />\n  `,\n  styles: `\n    :host {\n      position: relative;\n    }\n    form {\n      width: 300px;\n    }\n    nz-check-list {\n      position: absolute;\n    }\n  `\n})\nexport class NzDemoCheckListCustomComponent {\n  private fb = inject(NonNullableFormBuilder);\n  readonly nzItems: NzItemProps[] = [\n    {\n      description: 'step 1',\n      onClick: () => console.log('step 1')\n    },\n    {\n      description: 'Step 2',\n      onClick: () => console.log('step 1')\n    },\n    {\n      description: 'Step 3',\n      onClick: () => console.log('step 3')\n    },\n    {\n      description: 'Step 4',\n      onClick: () => console.log('step 4')\n    }\n  ];\n  readonly options = this.nzItems.map((_, index) => index).concat(this.nzItems.length + 1);\n  form = this.fb.group({\n    nzProgress: true,\n    nzVisible: false,\n    nzIndex: 0,\n    nzTriggerRender: 'Open List',\n    nzTitle: 'Customize task lists',\n    nzFooter: 'Custom Footer Name'\n  });\n\n  handleIndexChange(num: number | string): void {\n    this.form.controls.nzIndex.setValue(Number(num));\n  }\n\n  hideCancel(check: boolean): void {\n    console.log(check);\n    this.form.controls.nzVisible.setValue(false);\n  }\n}\n"
  },
  {
    "path": "components/check-list/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Featured Components\ntitle: CheckList\ncols: 1\ntag: 19.1.0\ncover: 'https://img.alicdn.com/imgextra/i2/O1CN01E9BUpE1TCyZry8ETC_!!6000000002347-2-tps-386-453.png'\ndescription: Used to organize the flow of tasks in a project.\n---\n\n## When To Use\n\nIf the current page business logic is too complex, and with a more mandatory sequential flow control, then you can use this component to help you simplify the process.\n\n## API\n\n### nz-check-list\n\n| Property            | Description                                        | Type                          | Default | Global Config |\n| ------------------- | -------------------------------------------------- | ----------------------------- | ------- | ------------- |\n| `[nzItems]`         | check list elements                                | `NzItemProps`                 | `[]`    | -             |\n| `[nzVisible]`       | show check-list                                    | `boolean`                     | `false` | -             |\n| `[nzIndex]`         | current index                                      | `number`                      | `1`     | -             |\n| `[nzProgress]`      | show progress                                      | `boolean`                     | `true`  | -             |\n| `[nzTriggerRender]` | rendering template for float button                | `TemplateRef<void> \\| string` | -       | -             |\n| `[nzTitle]`         | rendering template for the check-list panel title  | `TemplateRef<void> \\| string` | -       | -             |\n| `[nzFooter]`        | rendering template for the check-list panel footer | `TemplateRef<void> \\| string` | -       | -             |\n| `(nzHide)`          | callback for hiding the check list                 | `EventEmitter<boolean>`       | `false` | -             |\n\n> Value of `(nzHide)` is whether not show the check-list anymore.\n> If the value is `true`, you can store a data in `LocalStorage` to avoid showing the check-list again.\n\n### Interfaces\n\n#### NzItemProps\n\n| Property      | Description                           | Type                          | Default |\n| ------------- | ------------------------------------- | ----------------------------- | ------- |\n| `key`         | unique identifier                     | `string`                      | -       |\n| `description` | description content                   | `string`                      | -       |\n| `checked`     | Current inventory status              | `boolean`                     | -       |\n| `onClick`     | method triggered by clicking the step | `(item: NzItemProps) => void` | -       |\n\n> `key` is the unique identifier of the current item. If not set, `description` will be used as the key.\n"
  },
  {
    "path": "components/check-list/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ntype: 特色组件\ntitle: CheckList\nsubtitle: 任务清单\ncols: 1\ntag: 19.1.0\ncover: 'https://img.alicdn.com/imgextra/i2/O1CN01E9BUpE1TCyZry8ETC_!!6000000002347-2-tps-386-453.png'\ndescription: 用于在项目中梳理任务流程。\n---\n\n## 何时使用\n\n如果当前页面业务逻辑过于复杂，且带有较为强制的顺序流控制，那么你可以采用这个组件来帮你简化流程。\n\n## API\n\n### nz-check-list\n\n| 参数                | 说明                   | 类型                          | 默认值  | 全局配置 |\n| ------------------- | ---------------------- | ----------------------------- | ------- | -------- |\n| `[nzItems]`         | 任务清单元素           | `NzItemProps`                 | `[]`    | -        |\n| `[nzVisible]`       | 显示任务清单           | `boolean`                     | `false` | -        |\n| `[nzIndex]`         | 当前所属位置           | `number`                      | `1`     | -        |\n| `[nzProgress]`      | 显示任务进度           | `boolean`                     | `true`  | -        |\n| `[nzTriggerRender]` | 清单悬浮按钮的渲染模板 | `TemplateRef<void> \\| string` | -       | -        |\n| `[nzTitle]`         | 清单面板标题的渲染模板 | `TemplateRef<void> \\| string` | -       | -        |\n| `[nzFooter]`        | 清单面板底部的渲染模板 | `TemplateRef<void> \\| string` | -       | -        |\n| `(nzHide)`          | 隐藏清单的回调         | `EventEmitter<boolean>`       | `false` | -        |\n\n> `(nzHide)` 的回调值为是否不再显示清单。你可以在回调中存储数据到 `LocalStorage` 中，以避免再次显示清单。\n\n### Interfaces\n\n#### NzItemProps\n\n| 参数          | 说明               | 类型                          | 默认值 |\n| ------------- | ------------------ | ----------------------------- | ------ |\n| `key`         | 清单元素的唯一 key | `string`                      | -      |\n| `description` | 清单元素描述内容   | `string`                      | -      |\n| `checked`     | 当前清单是否完成   | `boolean`                     | -      |\n| `onClick`     | 点击步骤触发的方法 | `(item: NzItemProps) => void` | -      |\n\n> `key` 为清单元素的唯一标识，如果不填写，则默认使用 `description` 作为 key。\n"
  },
  {
    "path": "components/check-list/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/check-list/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/check-list/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './typings';\nexport * from './check-list.component';\nexport * from './check-list.module';\n"
  },
  {
    "path": "components/check-list/style/entry.less",
    "content": "@import './index.less';\n"
  },
  {
    "path": "components/check-list/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@check-list-prefix-cls: ~'@{ant-prefix}-check-list';\n\n.@{check-list-prefix-cls} {\n  position: fixed;\n  right: 32px;\n  bottom: 32px;\n  z-index: 999;\n  font-size: @font-size-base;\n  cursor: pointer;\n\n  .@{check-list-prefix-cls}-button {\n    position: relative;\n    display: flex;\n    gap: @margin-xs;\n    align-items: center;\n    justify-content: center;\n    min-width: 110px;\n    height: 40px;\n    border-radius: 20px;\n  }\n\n  .@{check-list-prefix-cls}-icon {\n    font-size: @heading-3-size;\n    line-height: 24px;\n  }\n\n  .@{check-list-prefix-cls}-description {\n    font-size: @font-size-base;\n  }\n\n  .@{check-list-prefix-cls}-trigger-dot {\n    position: absolute;\n    top: -12px;\n    right: -12px;\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    width: 24px;\n    height: 24px;\n    color: @primary-color;\n    background-color: @component-background;\n    border: @border-width-base solid @primary-color;\n    border-radius: 50%;\n  }\n\n  .@{check-list-prefix-cls}-trigger-dot-text {\n    font-weight: 500;\n    font-size: 16px;\n    font-style: italic;\n    line-height: 16px;\n  }\n}\n\n.@{check-list-prefix-cls}-content {\n  display: block;\n  width: 303px;\n\n  .@{check-list-prefix-cls}-header {\n    display: flex;\n    align-items: center;\n    justify-content: space-between;\n    padding: @padding-sm @padding-sm @padding-md;\n    .@{check-list-prefix-cls}-header-title {\n      font-weight: 500;\n      font-size: @heading-4-size;\n    }\n    .@{check-list-prefix-cls}-header-extra {\n      cursor: pointer;\n    }\n  }\n\n  .@{check-list-prefix-cls}-header-finish {\n    width: 304px;\n    padding-top: @margin-sm;\n    text-align: center;\n\n    .@{check-list-prefix-cls}-header-finish-icon {\n      width: 64px;\n      height: 64px;\n      color: @primary-color;\n      font-size: 64px;\n    }\n\n    .@{check-list-prefix-cls}-header-finish-title {\n      margin-top: @margin-xs;\n      margin-bottom: @margin-xs;\n      font-weight: 500;\n      font-size: @font-size-lg;\n    }\n  }\n\n  .@{check-list-prefix-cls}-progressBar {\n    display: flex;\n    justify-content: space-between;\n    margin: @margin-sm @margin-md;\n    margin-top: 0;\n\n    .@{check-list-prefix-cls}-progressBar-progress {\n      flex: auto;\n    }\n  }\n\n  .@{check-list-prefix-cls}-steps-content {\n    max-height: 250px;\n    overflow-y: scroll;\n  }\n\n  .@{check-list-prefix-cls}-steps {\n    display: flex;\n    align-items: center;\n    justify-content: space-between;\n    height: 52px;\n    padding-right: @padding-sm;\n    padding-left: @padding-sm;\n    border-radius: 6px;\n    cursor: pointer;\n\n    .@{check-list-prefix-cls}-steps-item {\n      display: flex;\n      gap: 12px;\n      align-items: center;\n      justify-content: center;\n      width: calc(100% - 22px);\n      font-weight: 400;\n\n      .@{check-list-prefix-cls}-steps-item-circle {\n        display: flex;\n        flex: 0 0 28px;\n        align-items: center;\n        justify-content: center;\n        width: 28px;\n        height: 28px;\n        font-weight: 600;\n        background-color: @component-background;\n        border: @border-width-base solid @border-color-base;\n        border-radius: 50%;\n        user-select: none;\n\n        .@{check-list-prefix-cls}-steps-number {\n          color: @primary-color;\n          font-size: @font-size-lg;\n        }\n\n        .@{check-list-prefix-cls}-steps-checkoutlined {\n          color: @component-background;\n          font-size: @font-size-base;\n        }\n      }\n\n      .@{check-list-prefix-cls}-steps-item-description {\n        flex: 1;\n        overflow: hidden;\n        line-height: 2;\n        white-space: nowrap;\n        text-overflow: ellipsis;\n      }\n    }\n\n    .@{check-list-prefix-cls}-steps-item-arrows {\n      flex: 0 0 22px;\n      width: 38px;\n      height: 38px;\n      color: @primary-color;\n      font-size: 22px;\n    }\n  }\n\n  .@{check-list-prefix-cls}-checked {\n\n    .@{check-list-prefix-cls}-steps-item .@{check-list-prefix-cls}-steps-item-circle {\n      background-color: @primary-color;\n      border: none;\n    }\n\n    .@{check-list-prefix-cls}-steps-item .@{check-list-prefix-cls}-steps-item-description {\n      font-weight: 500;\n      text-decoration: line-through;\n      text-decoration-thickness: 2px;\n      text-decoration-color: @text-color;\n      opacity: 0.85;\n    }\n  }\n\n  .@{check-list-prefix-cls}-highlight {\n    background-color: @info-color-deprecated-bg;\n\n    .@{check-list-prefix-cls}-steps-item .@{check-list-prefix-cls}-steps-item-circle {\n      border: @border-width-base solid @primary-color;\n\n      .@{check-list-prefix-cls}-steps-number {\n        color: @primary-color;\n      }\n    }\n    .@{check-list-prefix-cls}-steps-item .@{check-list-prefix-cls}-steps-item-description {\n      font-weight: 600;\n    }\n  }\n\n  .@{check-list-prefix-cls}-footer {\n    padding: @padding-sm @padding-sm 0;\n    color: @text-color-secondary;\n    font-size: @font-size-base;\n    text-decoration: underline;\n    cursor: pointer;\n  }\n\n  .@{check-list-prefix-cls}-close-check {\n    display: flex;\n    flex-direction: column;\n    padding: @padding-sm;\n    .@{check-list-prefix-cls}-close-check-title {\n      margin-bottom: @margin-lg;\n      font-weight: 500;\n      font-size: @font-size-lg;\n    }\n\n    .@{check-list-prefix-cls}-close-check-action {\n      display: flex;\n      flex-direction: row;\n      gap: @margin-xs;\n      margin-bottom: @margin-md;\n    }\n\n    .@{check-list-prefix-cls}-close-check-other {\n      color: @text-color-secondary;\n      font-size: @font-size-base;\n      cursor: pointer;\n    }\n  }\n}"
  },
  {
    "path": "components/check-list/typings.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport interface NzItemProps {\n  description: string;\n  checked?: boolean;\n  onClick?: (item: NzItemProps) => void;\n  key?: string;\n}\n"
  },
  {
    "path": "components/checkbox/checkbox-group.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { FocusMonitor } from '@angular/cdk/a11y';\nimport { Directionality } from '@angular/cdk/bidi';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  DestroyRef,\n  ElementRef,\n  ViewEncapsulation,\n  afterNextRender,\n  booleanAttribute,\n  computed,\n  forwardRef,\n  inject,\n  input,\n  linkedSignal,\n  signal,\n  untracked\n} from '@angular/core';\nimport { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\n\nimport { OnChangeType, OnTouchedType } from 'ng-zorro-antd/core/types';\n\nimport { NzCheckboxComponent } from './checkbox.component';\nimport { NZ_CHECKBOX_GROUP } from './tokens';\n\nexport interface NzCheckboxOption {\n  label: string;\n  value: string | number;\n  disabled?: boolean;\n}\n\n@Component({\n  selector: 'nz-checkbox-group',\n  exportAs: 'nzCheckboxGroup',\n  imports: [NzCheckboxComponent],\n  template: `\n    <ng-content>\n      @for (option of normalizedOptions(); track option.value) {\n        <label\n          nz-checkbox\n          [nzValue]=\"option.value\"\n          [nzName]=\"nzName()\"\n          [nzDisabled]=\"option.disabled || finalDisabled()\"\n        >\n          {{ option.label }}\n        </label>\n      }\n    </ng-content>\n  `,\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => NzCheckboxGroupComponent),\n      multi: true\n    },\n    {\n      provide: NZ_CHECKBOX_GROUP,\n      useExisting: forwardRef(() => NzCheckboxGroupComponent)\n    }\n  ],\n  host: {\n    class: 'ant-checkbox-group',\n    '[class.ant-checkbox-group-rtl]': `dir() === 'rtl'`\n  },\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class NzCheckboxGroupComponent implements ControlValueAccessor {\n  private onChange: OnChangeType = () => {};\n  private onTouched: OnTouchedType = () => {};\n  private isDisabledFirstChange = true;\n  private readonly directionality = inject(Directionality);\n\n  readonly nzName = input<string | null>(null);\n  readonly nzDisabled = input(false, { transform: booleanAttribute });\n  readonly nzOptions = input<NzCheckboxOption[] | string[] | number[]>([]);\n  readonly value = signal<Array<NzCheckboxOption['value']> | null>(null);\n  readonly finalDisabled = linkedSignal(() => this.nzDisabled());\n\n  protected readonly dir = toSignal(this.directionality.change, { initialValue: this.directionality.value });\n  protected readonly normalizedOptions = computed(() => normalizeOptions(this.nzOptions()));\n\n  constructor() {\n    const elementRef = inject(ElementRef);\n    const focusMonitor = inject(FocusMonitor);\n    const destroyRef = inject(DestroyRef);\n\n    afterNextRender(() => {\n      focusMonitor\n        .monitor(elementRef, true)\n        .pipe(takeUntilDestroyed(destroyRef))\n        .subscribe(focusOrigin => {\n          if (!focusOrigin) {\n            this.onTouched();\n          }\n        });\n\n      destroyRef.onDestroy(() => {\n        focusMonitor.stopMonitoring(elementRef);\n      });\n    });\n  }\n\n  writeValue(value: Array<string | number> | null): void {\n    untracked(() => {\n      this.value.set(value);\n    });\n  }\n\n  registerOnChange(fn: OnChangeType): void {\n    this.onChange = fn;\n  }\n\n  registerOnTouched(fn: OnTouchedType): void {\n    this.onTouched = fn;\n  }\n\n  setDisabledState(disabled: boolean): void {\n    untracked(() => {\n      this.finalDisabled.set((this.isDisabledFirstChange && this.nzDisabled()) || disabled);\n    });\n    this.isDisabledFirstChange = false;\n  }\n\n  onCheckedChange(optionValue: NzCheckboxOption['value'], checked: boolean): void {\n    if (this.finalDisabled()) return;\n\n    this.value.update(value => {\n      if (checked) {\n        return value?.concat(optionValue) || [optionValue];\n      } else {\n        return value?.filter(val => val !== optionValue) || [];\n      }\n    });\n\n    this.onChange(this.value());\n  }\n}\n\nfunction normalizeOptions(value: string[] | number[] | NzCheckboxOption[]): NzCheckboxOption[] {\n  return value.map(item => {\n    if (typeof item === 'string' || typeof item === 'number') {\n      return {\n        label: `${item}`,\n        value: item\n      };\n    }\n\n    return item;\n  });\n}\n"
  },
  {
    "path": "components/checkbox/checkbox-group.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCheckboxOption } from './checkbox-group.component';\nimport { NzCheckboxModule } from './checkbox.module';\n\ndescribe('checkbox group', () => {\n  let component: CheckboxGroupTestComponent;\n  let fixture: ComponentFixture<CheckboxGroupTestComponent>;\n  let hostElement: HTMLElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(CheckboxGroupTestComponent);\n    component = fixture.componentInstance;\n    hostElement = fixture.nativeElement.querySelector('nz-checkbox-group');\n    fixture.autoDetectChanges();\n  });\n\n  it('should be render option elements', () => {\n    let elements = getOptionElements();\n    for (let index = 0; index < elements.length; index++) {\n      expect(elements[index].textContent?.trim()).toBe((component.options[index] as NzCheckboxOption).label);\n    }\n    component.options = [1, 2, 3];\n    fixture.detectChanges();\n    elements = getOptionElements();\n    for (let index = 0; index < elements.length; index++) {\n      expect(elements[index].textContent?.trim()).toBe(component.options[index].toString());\n    }\n    component.options = ['a', 'b', 'c'];\n    fixture.detectChanges();\n    elements = getOptionElements();\n    for (let index = 0; index < elements.length; index++) {\n      expect(elements[index].textContent?.trim()).toBe(component.options[index]);\n    }\n  });\n\n  it('should be name work', () => {\n    component.name = 'zorro';\n    fixture.detectChanges();\n    const elements = getOptionElements();\n    for (const element of elements) {\n      expect(element.querySelector<HTMLInputElement>('input[type=checkbox]')!.name).toBe('zorro');\n    }\n  });\n\n  it('should be apply disabled class', () => {\n    component.disabled = true;\n    fixture.detectChanges();\n    for (const element of getOptionElements()) {\n      expect(element.classList).toContain('ant-checkbox-wrapper-disabled');\n    }\n  });\n\n  it('should be set disabled by ng control', async () => {\n    component.controlDisabled = true;\n    fixture.detectChanges();\n    await fixture.whenStable();\n    for (const element of getOptionElements()) {\n      expect(element.classList).toContain('ant-checkbox-wrapper-disabled');\n    }\n  });\n\n  it('should be change value', async () => {\n    component.value = ['A'];\n    fixture.detectChanges();\n    await fixture.whenStable();\n    let checkedOptionElements = getOptionElements().filter(ele =>\n      ele.classList.contains('ant-checkbox-wrapper-checked')\n    );\n    expect(checkedOptionElements.length).toBe(1);\n    expect(checkedOptionElements[0].textContent?.trim()).toBe('A');\n\n    component.value = ['A', 'B'];\n    fixture.detectChanges();\n    await fixture.whenStable();\n    checkedOptionElements = getOptionElements().filter(ele => ele.classList.contains('ant-checkbox-wrapper-checked'));\n    expect(checkedOptionElements.length).toBe(2);\n    expect(checkedOptionElements[0].textContent?.trim()).toBe('A');\n    expect(checkedOptionElements[1].textContent?.trim()).toBe('B');\n\n    component.value = [];\n    fixture.detectChanges();\n    await fixture.whenStable();\n    checkedOptionElements = getOptionElements().filter(ele => ele.classList.contains('ant-checkbox-wrapper-checked'));\n    expect(checkedOptionElements.length).toBe(0);\n  });\n\n  function getOptionElements(): HTMLElement[] {\n    return Array.from(hostElement.querySelectorAll('.ant-checkbox-group-item'));\n  }\n});\n\ndescribe('checkbox group with custom layout', () => {\n  let component: CheckboxGroupWithCustomLayoutTestComponent;\n  let fixture: ComponentFixture<CheckboxGroupWithCustomLayoutTestComponent>;\n  let hostElement: HTMLElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(CheckboxGroupWithCustomLayoutTestComponent);\n    component = fixture.componentInstance;\n    hostElement = fixture.nativeElement.querySelector('nz-checkbox-group');\n    fixture.autoDetectChanges();\n  });\n\n  it('should be apply disabled class', () => {\n    component.disabled = true;\n    fixture.detectChanges();\n    for (const element of getOptionElements()) {\n      expect(element.classList).toContain('ant-checkbox-wrapper-disabled');\n    }\n  });\n\n  it('should be change value', async () => {\n    component.value = ['A'];\n    fixture.detectChanges();\n    await fixture.whenStable();\n    let checkedOptionElements = getOptionElements().filter(ele =>\n      ele.classList.contains('ant-checkbox-wrapper-checked')\n    );\n    expect(checkedOptionElements.length).toBe(1);\n    expect(checkedOptionElements[0].textContent?.trim()).toBe('A');\n\n    component.value = ['A', 'B'];\n    fixture.detectChanges();\n    await fixture.whenStable();\n    checkedOptionElements = getOptionElements().filter(ele => ele.classList.contains('ant-checkbox-wrapper-checked'));\n    expect(checkedOptionElements.length).toBe(2);\n    expect(checkedOptionElements[0].textContent?.trim()).toBe('A');\n    expect(checkedOptionElements[1].textContent?.trim()).toBe('B');\n\n    component.value = [];\n    fixture.detectChanges();\n    await fixture.whenStable();\n    checkedOptionElements = getOptionElements().filter(ele => ele.classList.contains('ant-checkbox-wrapper-checked'));\n    expect(checkedOptionElements.length).toBe(0);\n  });\n\n  it('should be change value by outer checkboxes', () => {\n    const checkboxElements = getOptionElements();\n    checkboxElements[0].click();\n    fixture.detectChanges();\n    expect(component.value).toEqual(['A']);\n\n    checkboxElements[1].click();\n    fixture.detectChanges();\n    expect(component.value).toEqual(['A', 'B']);\n\n    checkboxElements[0].click();\n    fixture.detectChanges();\n    expect(component.value).toEqual(['B']);\n  });\n\n  function getOptionElements(): HTMLElement[] {\n    return Array.from(hostElement.querySelectorAll('.ant-checkbox-group-item'));\n  }\n});\n\n@Component({\n  imports: [NzCheckboxModule, FormsModule],\n  template: `\n    <nz-checkbox-group\n      [nzOptions]=\"options\"\n      [nzName]=\"name\"\n      [nzDisabled]=\"disabled\"\n      [(ngModel)]=\"value\"\n      [disabled]=\"controlDisabled\"\n    />\n  `\n})\nclass CheckboxGroupTestComponent {\n  options: string[] | number[] | NzCheckboxOption[] = [\n    { label: 'A', value: 'A' },\n    { label: 'B', value: 'B' },\n    { label: 'C', value: 'C' }\n  ];\n  value: string[] = [];\n  disabled = false;\n  controlDisabled = false;\n  name: string | null = null;\n}\n\n@Component({\n  imports: [NzCheckboxModule, FormsModule],\n  template: `\n    <nz-checkbox-group [nzDisabled]=\"disabled\" [(ngModel)]=\"value\">\n      <label nz-checkbox nzValue=\"A\">A</label>\n      <label nz-checkbox nzValue=\"B\">B</label>\n      <label nz-checkbox nzValue=\"C\">C</label>\n    </nz-checkbox-group>\n  `\n})\nclass CheckboxGroupWithCustomLayoutTestComponent {\n  value: string[] = [];\n  disabled = false;\n}\n"
  },
  {
    "path": "components/checkbox/checkbox.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { FocusMonitor } from '@angular/cdk/a11y';\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport {\n  AfterViewInit,\n  ChangeDetectionStrategy,\n  Component,\n  ElementRef,\n  EventEmitter,\n  Input,\n  OnInit,\n  Output,\n  ViewChild,\n  ViewEncapsulation,\n  booleanAttribute,\n  effect,\n  forwardRef,\n  inject,\n  NgZone,\n  ChangeDetectorRef,\n  DestroyRef\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';\n\nimport { NzFormStatusService } from 'ng-zorro-antd/core/form';\nimport { NzSafeAny, OnChangeType, OnTouchedType } from 'ng-zorro-antd/core/types';\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\n\nimport { NZ_CHECKBOX_GROUP } from './tokens';\n\n@Component({\n  selector: '[nz-checkbox]',\n  exportAs: 'nzCheckbox',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <span\n      class=\"ant-checkbox\"\n      [class.ant-checkbox-checked]=\"nzChecked && !nzIndeterminate\"\n      [class.ant-checkbox-disabled]=\"nzDisabled || checkboxGroupComponent?.finalDisabled()\"\n      [class.ant-checkbox-indeterminate]=\"nzIndeterminate\"\n    >\n      <input\n        #inputElement\n        type=\"checkbox\"\n        class=\"ant-checkbox-input\"\n        [attr.autofocus]=\"nzAutoFocus ? 'autofocus' : null\"\n        [attr.id]=\"nzId\"\n        [attr.name]=\"nzName || checkboxGroupComponent?.nzName()\"\n        [checked]=\"nzChecked\"\n        [ngModel]=\"nzChecked\"\n        [disabled]=\"nzDisabled || (checkboxGroupComponent?.finalDisabled() ?? false)\"\n        (ngModelChange)=\"innerCheckedChange($event)\"\n      />\n      <span class=\"ant-checkbox-inner\"></span>\n    </span>\n    <span><ng-content /></span>\n  `,\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => NzCheckboxComponent),\n      multi: true\n    }\n  ],\n  host: {\n    class: 'ant-checkbox-wrapper',\n    '[class.ant-checkbox-group-item]': '!!checkboxGroupComponent',\n    '[class.ant-checkbox-wrapper-in-form-item]': '!!nzFormStatusService',\n    '[class.ant-checkbox-wrapper-checked]': 'nzChecked',\n    '[class.ant-checkbox-wrapper-disabled]': 'nzDisabled || checkboxGroupComponent?.finalDisabled()',\n    '[class.ant-checkbox-rtl]': `dir === 'rtl'`\n  },\n  imports: [FormsModule]\n})\nexport class NzCheckboxComponent implements OnInit, ControlValueAccessor, AfterViewInit {\n  private ngZone = inject(NgZone);\n  private elementRef = inject(ElementRef<HTMLElement>);\n  private cdr = inject(ChangeDetectorRef);\n  private focusMonitor = inject(FocusMonitor);\n  private directionality = inject(Directionality);\n  private destroyRef = inject(DestroyRef);\n  protected checkboxGroupComponent = inject(NZ_CHECKBOX_GROUP, { optional: true });\n  protected nzFormStatusService = inject(NzFormStatusService, { optional: true });\n\n  dir: Direction = 'ltr';\n  private isNzDisableFirstChange: boolean = true;\n\n  onChange: OnChangeType = () => {};\n  onTouched: OnTouchedType = () => {};\n  @ViewChild('inputElement', { static: true }) inputElement!: ElementRef<HTMLInputElement>;\n  @Output() readonly nzCheckedChange = new EventEmitter<boolean>();\n  @Input() nzValue: NzSafeAny | null = null;\n  @Input({ transform: booleanAttribute }) nzAutoFocus = false;\n  @Input({ transform: booleanAttribute }) nzDisabled = false;\n  @Input({ transform: booleanAttribute }) nzIndeterminate = false;\n  @Input({ transform: booleanAttribute }) nzChecked = false;\n  @Input() nzId: string | null = null;\n  @Input() nzName: string | null = null;\n\n  innerCheckedChange(checked: boolean): void {\n    if (!this.nzDisabled && !this.checkboxGroupComponent?.finalDisabled()) {\n      this.setValue(checked);\n      this.checkboxGroupComponent?.onCheckedChange(this.nzValue, checked);\n    }\n  }\n\n  writeValue(value: boolean): void {\n    this.nzChecked = value;\n    this.cdr.markForCheck();\n  }\n\n  registerOnChange(fn: OnChangeType): void {\n    this.onChange = fn;\n  }\n\n  registerOnTouched(fn: OnTouchedType): void {\n    this.onTouched = fn;\n  }\n\n  setDisabledState(disabled: boolean): void {\n    this.nzDisabled = (this.isNzDisableFirstChange && this.nzDisabled) || disabled;\n    this.isNzDisableFirstChange = false;\n    this.cdr.markForCheck();\n  }\n\n  focus(): void {\n    this.focusMonitor.focusVia(this.inputElement, 'keyboard');\n  }\n\n  blur(): void {\n    this.inputElement.nativeElement.blur();\n  }\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      this.focusMonitor.stopMonitoring(this.elementRef);\n    });\n    if (this.checkboxGroupComponent) {\n      effect(() => {\n        const values = this.checkboxGroupComponent!.value() || [];\n        this.setValue(values.includes(this.nzValue));\n        this.cdr.markForCheck();\n      });\n    }\n  }\n\n  ngOnInit(): void {\n    this.focusMonitor\n      .monitor(this.elementRef, true)\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(focusOrigin => {\n        if (!focusOrigin) {\n          Promise.resolve().then(() => this.onTouched());\n        }\n      });\n\n    this.directionality.change.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n      this.dir = direction;\n      this.cdr.detectChanges();\n    });\n\n    this.dir = this.directionality.value;\n\n    fromEventOutsideAngular(this.elementRef.nativeElement, 'click')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(event => {\n        event.preventDefault();\n        this.focus();\n        if (this.nzDisabled) {\n          return;\n        }\n        this.ngZone.run(() => {\n          this.innerCheckedChange(!this.nzChecked);\n          this.cdr.markForCheck();\n        });\n      });\n\n    fromEventOutsideAngular(this.inputElement.nativeElement, 'click')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(event => event.stopPropagation());\n  }\n\n  ngAfterViewInit(): void {\n    if (this.nzAutoFocus) {\n      this.focus();\n    }\n  }\n\n  private setValue(value: boolean): void {\n    this.nzChecked = value;\n    this.onChange(value);\n    this.nzCheckedChange.emit(value);\n  }\n}\n"
  },
  {
    "path": "components/checkbox/checkbox.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzCheckboxGroupComponent } from './checkbox-group.component';\nimport { NzCheckboxComponent } from './checkbox.component';\n\n@NgModule({\n  imports: [NzCheckboxComponent, NzCheckboxGroupComponent],\n  exports: [NzCheckboxComponent, NzCheckboxGroupComponent]\n})\nexport class NzCheckboxModule {}\n"
  },
  {
    "path": "components/checkbox/checkbox.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport { ApplicationRef, Component, DebugElement, provideZoneChangeDetection, ViewChild } from '@angular/core';\nimport { ComponentFixture, TestBed, fakeAsync, flush } from '@angular/core/testing';\nimport { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\n\nimport { NzCheckboxComponent } from './checkbox.component';\nimport { NzCheckboxModule } from './checkbox.module';\n\ndescribe('checkbox', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  describe('basic', () => {\n    let fixture: ComponentFixture<NzTestCheckboxSingleComponent>;\n    let testComponent: NzTestCheckboxSingleComponent;\n    let checkbox: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCheckboxSingleComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n      checkbox = fixture.debugElement.query(By.directive(NzCheckboxComponent));\n    });\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n      expect(checkbox.nativeElement.classList.contains('ant-checkbox-wrapper')).toBe(true);\n      expect(checkbox.nativeElement.firstElementChild!.classList.contains('ant-checkbox')).toBe(true);\n      expect(checkbox.nativeElement.firstElementChild.firstElementChild!.classList.contains('ant-checkbox-input')).toBe(\n        true\n      );\n      expect(checkbox.nativeElement.firstElementChild.lastElementChild.classList.contains('ant-checkbox-inner')).toBe(\n        true\n      );\n      expect(checkbox.nativeElement.lastElementChild.innerText).toBe(' Checkbox');\n    });\n\n    it('should click change', () => {\n      fixture.detectChanges();\n      expect(testComponent.checked).toBe(false);\n      expect(checkbox.nativeElement.firstElementChild!.classList.contains('ant-checkbox-checked')).toBe(false);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(0);\n      checkbox.nativeElement.click();\n      fixture.detectChanges();\n      expect(testComponent.checked).toBe(true);\n      expect(checkbox.nativeElement.firstElementChild!.classList.contains('ant-checkbox-checked')).toBe(true);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(1);\n    });\n\n    it('should click input a11y correct', () => {\n      fixture.detectChanges();\n      const inputElement = checkbox.nativeElement.querySelector('input');\n      expect(testComponent.checked).toBe(false);\n      expect(inputElement.checked).toBe(false);\n      expect(checkbox.nativeElement.firstElementChild.classList.contains('ant-checkbox-checked')).toBe(false);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(0);\n      inputElement.click();\n      fixture.detectChanges();\n      expect(testComponent.checked).toBe(true);\n      expect(checkbox.nativeElement.firstElementChild.classList.contains('ant-checkbox-checked')).toBe(true);\n      expect(inputElement.checked).toBe(true);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(1);\n    });\n\n    it('should ngModel change', fakeAsync(() => {\n      testComponent.checked = true;\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.checked).toBe(true);\n      expect(checkbox.nativeElement.firstElementChild!.classList.contains('ant-checkbox-checked')).toBe(true);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(0);\n    }));\n\n    it('should disabled work', () => {\n      fixture.detectChanges();\n      testComponent.disabled = true;\n      fixture.detectChanges();\n      expect(testComponent.checked).toBe(false);\n      expect(checkbox.nativeElement.firstElementChild!.classList.contains('ant-checkbox-checked')).toBe(false);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(0);\n      checkbox.nativeElement.click();\n      fixture.detectChanges();\n      expect(testComponent.checked).toBe(false);\n      expect(checkbox.nativeElement.firstElementChild!.classList.contains('ant-checkbox-checked')).toBe(false);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(0);\n    });\n\n    it('should indeterminate work', () => {\n      fixture.detectChanges();\n      testComponent.indeterminate = true;\n      fixture.detectChanges();\n      expect(checkbox.nativeElement.firstElementChild!.classList.contains('ant-checkbox-indeterminate')).toBe(true);\n      testComponent.checked = true;\n      fixture.detectChanges();\n      expect(checkbox.nativeElement.firstElementChild!.classList.contains('ant-checkbox-indeterminate')).toBe(true);\n    });\n\n    it('should autofocus work', () => {\n      fixture.detectChanges();\n      testComponent.autoFocus = true;\n      fixture.detectChanges();\n      expect(checkbox.nativeElement.querySelector('input').attributes.getNamedItem('autofocus').name).toBe('autofocus');\n      testComponent.autoFocus = false;\n      fixture.detectChanges();\n      expect(checkbox.nativeElement.querySelector('input').attributes.getNamedItem('autofocus')).toBe(null);\n    });\n\n    it('should focus and blur function work', () => {\n      fixture.detectChanges();\n      expect(checkbox.nativeElement.querySelector('input') === document.activeElement).toBe(false);\n      testComponent.nzCheckboxComponent.focus();\n      fixture.detectChanges();\n      expect(checkbox.nativeElement.querySelector('input') === document.activeElement).toBe(true);\n      testComponent.nzCheckboxComponent.blur();\n      fixture.detectChanges();\n      expect(checkbox.nativeElement.querySelector('input') === document.activeElement).toBe(false);\n    });\n\n    describe('change detection behavior', () => {\n      it('should not run change detection when the `input` is clicked', () => {\n        const appRef = TestBed.inject(ApplicationRef);\n        const event = new MouseEvent('click');\n\n        spyOn(appRef, 'tick');\n        spyOn(event, 'stopPropagation').and.callThrough();\n\n        const nzCheckbox = fixture.debugElement.query(By.directive(NzCheckboxComponent));\n        nzCheckbox.nativeElement.querySelector('.ant-checkbox-input').dispatchEvent(event);\n\n        expect(appRef.tick).not.toHaveBeenCalled();\n        expect(event.stopPropagation).toHaveBeenCalled();\n      });\n\n      it('should not run change detection when the `nz-checkbox` is clicked and it is disabled', () => {\n        testComponent.disabled = true;\n        fixture.detectChanges();\n\n        const appRef = TestBed.inject(ApplicationRef);\n        const event = new MouseEvent('click');\n\n        spyOn(appRef, 'tick');\n        spyOn(event, 'preventDefault').and.callThrough();\n\n        const nzCheckbox = fixture.debugElement.query(By.directive(NzCheckboxComponent));\n        nzCheckbox.nativeElement.dispatchEvent(event);\n\n        expect(appRef.tick).not.toHaveBeenCalled();\n        expect(event.preventDefault).toHaveBeenCalled();\n      });\n    });\n  });\n\n  describe('form', () => {\n    let fixture: ComponentFixture<NzTestCheckboxFormComponent>;\n    let testComponent: NzTestCheckboxFormComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCheckboxFormComponent);\n      testComponent = fixture.componentInstance;\n    });\n\n    it('should be in pristine, untouched, and valid states and enable initially', fakeAsync(() => {\n      fixture.detectChanges();\n      flush();\n      const checkbox = fixture.debugElement.query(By.directive(NzCheckboxComponent));\n      const inputElement = checkbox.nativeElement.querySelector('input') as HTMLInputElement;\n      expect(checkbox.nativeElement.firstElementChild!.classList).not.toContain('ant-checkbox-disabled');\n      expect(inputElement.disabled).toBeFalsy();\n      expect(testComponent.formControl.valid).toBe(true);\n      expect(testComponent.formControl.pristine).toBe(true);\n      expect(testComponent.formControl.touched).toBe(false);\n    }));\n\n    it('should be disable if form is disable and nzDisable set to false', fakeAsync(() => {\n      testComponent.disable();\n      fixture.detectChanges();\n      flush();\n      const checkbox = fixture.debugElement.query(By.directive(NzCheckboxComponent));\n      const inputElement = checkbox.nativeElement.querySelector('input') as HTMLInputElement;\n      expect(checkbox.nativeElement.firstElementChild!.classList).toContain('ant-checkbox-disabled');\n      expect(inputElement.disabled).toBeTruthy();\n    }));\n\n    it('should set disabled work', fakeAsync(() => {\n      testComponent.disabled = true;\n      fixture.detectChanges();\n      flush();\n      const checkbox = fixture.debugElement.query(By.directive(NzCheckboxComponent));\n      const inputElement = checkbox.nativeElement.querySelector('input') as HTMLInputElement;\n\n      expect(checkbox.nativeElement.firstElementChild!.classList).toContain('ant-checkbox-disabled');\n      expect(inputElement.disabled).toBeTruthy();\n      inputElement.click();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.formControl.value).toBe(false);\n\n      testComponent.enable();\n      fixture.detectChanges();\n      flush();\n      expect(checkbox.nativeElement.firstElementChild!.classList).not.toContain('ant-checkbox-disabled');\n      expect(inputElement.disabled).toBeFalsy();\n      inputElement.click();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.formControl.value).toBe(true);\n\n      testComponent.disable();\n      fixture.detectChanges();\n      flush();\n      expect(checkbox.nativeElement.firstElementChild!.classList).toContain('ant-checkbox-disabled');\n      expect(inputElement.disabled).toBeTruthy();\n      inputElement.click();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.formControl.value).toBe(true);\n    }));\n  });\n\n  describe('RTL', () => {\n    it('should single checkbox className correct on dir change', () => {\n      const fixture = TestBed.createComponent(NzTestCheckboxSingleRtlComponent);\n      const checkbox = fixture.debugElement.query(By.directive(NzCheckboxComponent));\n      fixture.detectChanges();\n      expect(checkbox.nativeElement.classList).toContain('ant-checkbox-rtl');\n\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n      expect(checkbox.nativeElement.classList).not.toContain('ant-checkbox-rtl');\n    });\n  });\n});\n\n@Component({\n  imports: [FormsModule, NzCheckboxModule],\n  selector: 'nz-test-single-checkbox',\n  template: `\n    <label\n      nz-checkbox\n      [nzDisabled]=\"disabled\"\n      [(ngModel)]=\"checked\"\n      [nzAutoFocus]=\"autoFocus\"\n      [nzIndeterminate]=\"indeterminate\"\n      (ngModelChange)=\"modelChange($event)\"\n    >\n      Checkbox\n    </label>\n  `\n})\nexport class NzTestCheckboxSingleComponent {\n  @ViewChild(NzCheckboxComponent, { static: false }) nzCheckboxComponent!: NzCheckboxComponent;\n  disabled = false;\n  autoFocus = false;\n  checked = false;\n  indeterminate = false;\n  modelChange = jasmine.createSpy('change callback');\n}\n\n@Component({\n  imports: [ReactiveFormsModule, NzCheckboxModule],\n  template: `\n    <form>\n      <label nz-checkbox [formControl]=\"formControl\" [nzDisabled]=\"disabled\"></label>\n    </form>\n  `\n})\nexport class NzTestCheckboxFormComponent {\n  formControl = new FormControl(false);\n  disabled = false;\n\n  disable(): void {\n    this.formControl.disable();\n  }\n\n  enable(): void {\n    this.formControl.enable();\n  }\n}\n\n@Component({\n  imports: [BidiModule, NzTestCheckboxSingleComponent],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-test-single-checkbox />\n    </div>\n  `\n})\nexport class NzTestCheckboxSingleRtlComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n}\n\ndescribe('checkbox component', () => {\n  let fixture: ComponentFixture<NzCheckboxComponent>;\n  let component: NzCheckboxComponent;\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzCheckboxComponent);\n    component = fixture.componentInstance;\n  });\n\n  it('focus should be called in afterViewInit if nzAutoFocus is set', () => {\n    spyOn(component, 'focus');\n    component.nzAutoFocus = false;\n    component.ngAfterViewInit();\n    expect(component.focus).not.toHaveBeenCalled();\n\n    spyOn(component, 'focus');\n    component.nzAutoFocus = true;\n    component.ngAfterViewInit();\n    expect(component.focus).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "components/checkbox/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本用法\n  en-US: Basic\n---\n\n## zh-CN\n\n简单的 checkbox。\n\n## en-US\n\nBasic usage of checkbox.\n"
  },
  {
    "path": "components/checkbox/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCheckboxModule } from 'ng-zorro-antd/checkbox';\n\n@Component({\n  selector: 'nz-demo-checkbox-basic',\n  imports: [FormsModule, NzCheckboxModule],\n  template: `<label nz-checkbox [(ngModel)]=\"checked\">Checkbox</label>`\n})\nexport class NzDemoCheckboxBasicComponent {\n  checked = true;\n}\n"
  },
  {
    "path": "components/checkbox/demo/check-all.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 全选\n  en-US: Check all\n---\n\n## zh-CN\n\n在实现全选效果时，你可能会用到 `nzIndeterminate` 属性。\n\n## en-US\n\nThe `nzIndeterminate` property can help you to achieve a 'check all' effect.\n"
  },
  {
    "path": "components/checkbox/demo/check-all.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCheckboxModule, NzCheckboxOption } from 'ng-zorro-antd/checkbox';\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\n\n@Component({\n  selector: 'nz-demo-checkbox-check-all',\n  imports: [FormsModule, NzCheckboxModule, NzDividerModule],\n  template: `\n    <label\n      nz-checkbox\n      [(ngModel)]=\"allChecked\"\n      (ngModelChange)=\"updateAllChecked()\"\n      [nzIndeterminate]=\"value.length > 0 && value.length !== options.length\"\n    >\n      Check all\n    </label>\n\n    <nz-divider />\n\n    <nz-checkbox-group [nzOptions]=\"options\" [(ngModel)]=\"value\" (ngModelChange)=\"updateSingleChecked()\" />\n  `\n})\nexport class NzDemoCheckboxCheckAllComponent {\n  isAllCheckedFirstChange = true;\n  allChecked = false;\n  value: Array<string | number> = ['Apple', 'Orange'];\n  options: NzCheckboxOption[] = [\n    { label: 'Apple', value: 'Apple' },\n    { label: 'Pear', value: 'Pear' },\n    { label: 'Orange', value: 'Orange' }\n  ];\n\n  updateAllChecked(): void {\n    if (!this.isAllCheckedFirstChange) {\n      this.value = this.allChecked ? this.options.map(item => item.value) : [];\n    }\n    this.isAllCheckedFirstChange = false;\n  }\n\n  updateSingleChecked(): void {\n    this.allChecked = this.value.length === this.options.length;\n  }\n}\n"
  },
  {
    "path": "components/checkbox/demo/controller.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 受控的 Checkbox\n  en-US: Controlled Checkbox\n---\n\n## zh-CN\n\n联动 checkbox。\n\n## en-US\n\nCommunicated with other components.\n"
  },
  {
    "path": "components/checkbox/demo/controller.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzCheckboxModule } from 'ng-zorro-antd/checkbox';\n\n@Component({\n  selector: 'nz-demo-checkbox-controller',\n  imports: [FormsModule, NzButtonModule, NzCheckboxModule],\n  template: `\n    <label nz-checkbox [(ngModel)]=\"isCheckedButton\" [nzDisabled]=\"isDisabledButton\">\n      {{ isCheckedButton ? 'Checked' : 'Unchecked' }} - {{ isDisabledButton ? 'Disabled' : 'Enabled' }}\n    </label>\n    <br />\n    <br />\n    <button nz-button nzType=\"primary\" (click)=\"checkButton()\" nzSize=\"small\">\n      {{ !isCheckedButton ? 'Checked' : 'Unchecked' }}\n    </button>\n    <button nz-button nzType=\"primary\" (click)=\"disableButton()\" nzSize=\"small\">\n      {{ isDisabledButton ? 'Enabled' : 'Disabled' }}\n    </button>\n  `,\n  styles: `\n    button {\n      margin-right: 8px;\n    }\n  `\n})\nexport class NzDemoCheckboxControllerComponent {\n  isCheckedButton = true;\n  isDisabledButton = false;\n\n  checkButton(): void {\n    this.isCheckedButton = !this.isCheckedButton;\n  }\n\n  disableButton(): void {\n    this.isDisabledButton = !this.isDisabledButton;\n  }\n}\n"
  },
  {
    "path": "components/checkbox/demo/disabled.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 不可用\n  en-US: Disabled\n---\n\n## zh-CN\n\ncheckbox 不可用。\n\n## en-US\n\nDisabled checkbox.\n"
  },
  {
    "path": "components/checkbox/demo/disabled.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCheckboxModule } from 'ng-zorro-antd/checkbox';\n\n@Component({\n  selector: 'nz-demo-checkbox-disabled',\n  imports: [FormsModule, NzCheckboxModule],\n  template: `\n    <label nz-checkbox nzDisabled [ngModel]=\"false\"></label>\n    <br />\n    <label nz-checkbox nzDisabled [ngModel]=\"true\"></label>\n  `\n})\nexport class NzDemoCheckboxDisabledComponent {}\n"
  },
  {
    "path": "components/checkbox/demo/group.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: Checkbox 组\n  en-US: Checkbox Group\n---\n\n## zh-CN\n\n方便的从数组生成 Checkbox 组。\n\n## en-US\n\nGenerate a group of checkboxes from an array.\n"
  },
  {
    "path": "components/checkbox/demo/group.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCheckboxModule, NzCheckboxOption } from 'ng-zorro-antd/checkbox';\n\n@Component({\n  selector: 'nz-demo-checkbox-group',\n  imports: [FormsModule, NzCheckboxModule],\n  template: `\n    <nz-checkbox-group [nzOptions]=\"options1\" [(ngModel)]=\"value\" (ngModelChange)=\"log($event)\" />\n    <br />\n    <br />\n    <nz-checkbox-group [nzOptions]=\"options2\" [(ngModel)]=\"value\" (ngModelChange)=\"log($event)\" />\n    <br />\n    <br />\n    <nz-checkbox-group nzDisabled [nzOptions]=\"options3\" [(ngModel)]=\"value\" (ngModelChange)=\"log($event)\" />\n  `\n})\nexport class NzDemoCheckboxGroupComponent {\n  options1: NzCheckboxOption[] = [\n    { label: 'Apple', value: 'Apple' },\n    { label: 'Pear', value: 'Pear' },\n    { label: 'Orange', value: 'Orange' }\n  ];\n  options2: NzCheckboxOption[] = [\n    { label: 'Apple', value: 'Apple' },\n    { label: 'Pear', value: 'Pear' },\n    { label: 'Orange', value: 'Orange', disabled: true }\n  ];\n  options3: NzCheckboxOption[] = [\n    { label: 'Apple', value: 'Apple' },\n    { label: 'Pear', value: 'Pear' },\n    { label: 'Orange', value: 'Orange' }\n  ];\n\n  value = ['Apple'];\n\n  log(value: string[]): void {\n    console.log(value);\n  }\n}\n"
  },
  {
    "path": "components/checkbox/demo/layout.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 布局\n  en-US: Use with Grid\n---\n\n## zh-CN\n\n`nz-checkbox-group` 内嵌 `nz-checkbox` 并与 Grid 组件一起使用，可以实现灵活的布局。\n\n## en-US\n\nWe can use `nz-checkbox` and Grid in `nz-checkbox-group`, to implement complex layout.\n"
  },
  {
    "path": "components/checkbox/demo/layout.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCheckboxModule } from 'ng-zorro-antd/checkbox';\nimport { NzGridModule } from 'ng-zorro-antd/grid';\n\n@Component({\n  selector: 'nz-demo-checkbox-layout',\n  imports: [FormsModule, NzCheckboxModule, NzGridModule],\n  template: `\n    <nz-checkbox-group [(ngModel)]=\"value\" [style.width.%]=\"100\" (ngModelChange)=\"log($event)\">\n      <nz-row>\n        <nz-col nzSpan=\"8\">\n          <label nz-checkbox nzValue=\"A\">A</label>\n        </nz-col>\n        <nz-col nzSpan=\"8\">\n          <label nz-checkbox nzValue=\"B\">B</label>\n        </nz-col>\n        <nz-col nzSpan=\"8\">\n          <label nz-checkbox nzValue=\"C\">C</label>\n        </nz-col>\n        <nz-col nzSpan=\"8\">\n          <label nz-checkbox nzValue=\"D\">D</label>\n        </nz-col>\n        <nz-col nzSpan=\"8\">\n          <label nz-checkbox nzValue=\"E\">E</label>\n        </nz-col>\n      </nz-row>\n    </nz-checkbox-group>\n  `\n})\nexport class NzDemoCheckboxLayoutComponent {\n  value = ['A'];\n\n  log(value: string[]): void {\n    console.log(value);\n  }\n}\n"
  },
  {
    "path": "components/checkbox/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Entry\ntitle: Checkbox\ncover: 'https://gw.alipayobjects.com/zos/alicdn/8nbVbHEm_/CheckBox.svg'\ndescription: Collect user's choices.\n---\n\n## When To Use\n\n- Used for selecting multiple values from several options.\n- If you use only one checkbox, it is the same as using Switch to toggle between two states. The difference is that Switch will trigger the state change directly, but Checkbox just marks the state as changed and this needs to be submitted.\n\n## API\n\n### [nz-checkbox]\n\n| Property            | Description                                                     | Type                    | Default |\n| ------------------- | --------------------------------------------------------------- | ----------------------- | ------- |\n| `[nzId]`            | input id attribute inside the component                         | `string`                | -       |\n| `[nzName]`          | input name attribute inside the component                       | `string`                | -       |\n| `[nzAutoFocus]`     | get focus when component mounted                                | `boolean`               | `false` |\n| `[nzDisabled]`      | Disable checkbox                                                | `boolean`               | `false` |\n| `[ngModel]`         | Specifies whether the checkbox is selected, double binding      | `boolean`               | `false` |\n| `[nzIndeterminate]` | set the status of indeterminate，only affect the style          | `boolean`               | `false` |\n| `[nzValue]`         | use for the callback of `nz-checkbox-wrapper`                   | `any`                   | -       |\n| `(ngModelChange)`   | The callback function that is triggered when the state changes. | `EventEmitter<boolean>` | -       |\n\n### nz-checkbox-group\n\n| Property          | Description                                                     | Type                                         | Default |\n| ----------------- | --------------------------------------------------------------- | -------------------------------------------- | ------- |\n| `[ngModel]`       | Specifies options, double binding                               | `string[] \\| number[]`                       | `[]`    |\n| `[nzName]`        | The `name` property of all input children                       | `string`                                     | -       |\n| `[nzOptions]`     | Specifies options                                               | `string[] \\| number[] \\| NzCheckboxOption[]` | `[]`    |\n| `[nzDisabled]`    | Disable all checkboxes                                          | `boolean`                                    | `false` |\n| `(ngModelChange)` | The callback function that is triggered when the state changes. | `EventEmitter<string[] \\| number[]>`         | -       |\n\n## Methods\n\n### [nz-checkbox]\n\n| Name      | Description  |\n| --------- | ------------ |\n| `focus()` | get focus    |\n| `blur()`  | remove focus |\n\n## Interfaces\n\n### NzCheckboxOption\n\n```ts\nexport interface NzCheckboxOption {\n  label: string;\n  value: string | number;\n  disabled?: boolean;\n}\n```\n"
  },
  {
    "path": "components/checkbox/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 多选框\ntype: 数据录入\ntitle: Checkbox\ncover: 'https://gw.alipayobjects.com/zos/alicdn/8nbVbHEm_/CheckBox.svg'\ndescription: 收集用户的多项选择。\n---\n\n## 何时使用\n\n- 在一组可选项中进行多项选择时；\n- 单独使用可以表示两种状态之间的切换，和 `switch` 类似。区别在于切换 `switch` 会直接触发状态改变，而 `checkbox` 一般用于状态标记，需要和提交操作配合。\n\n## API\n\n### [nz-checkbox]\n\n| 参数                | 说明                                          | 类型                    | 默认值  |\n| ------------------- | --------------------------------------------- | ----------------------- | ------- |\n| `[nzId]`            | 组件内部 input 的 `id` 值                     | `string`                | -       |\n| `[nzName]`          | 组件内部 input 的 `name` 值                   | `string`                | -       |\n| `[nzAutoFocus]`     | 自动获取焦点                                  | `boolean`               | `false` |\n| `[nzDisabled]`      | 设定 disable 状态                             | `boolean`               | `false` |\n| `[ngModel]`         | 指定当前是否选中，可双向绑定                  | `boolean`               | `false` |\n| `[nzIndeterminate]` | 设置 indeterminate 状态，只负责样式控制       | `boolean`               | `false` |\n| `[nzValue]`         | 仅与 `nz-checkbox-wrapper` 的选中回调配合使用 | `any`                   | -       |\n| `(ngModelChange)`   | 选中变化时回调                                | `EventEmitter<boolean>` | -       |\n\n### nz-checkbox-group\n\n| 参数              | 说明                                      | 类型                                         | 默认值  |\n| ----------------- | ----------------------------------------- | -------------------------------------------- | ------- |\n| `[ngModel]`       | 指定可选项，可双向绑定                    | `string[] \\| number[]`                       | `[]`    |\n| `[nzName]`        | CheckboxGroup 下所有 input 的 `name` 属性 | `string`                                     | -       |\n| `[nzOptions]`     | 指定可选项                                | `string[] \\| number[] \\| NzCheckboxOption[]` | `[]`    |\n| `[nzDisabled]`    | 设定全部 checkbox disable 状态            | `boolean`                                    | `false` |\n| `(ngModelChange)` | 选中数据变化时的回调                      | `EventEmitter<string[] \\| number[]>`         | -       |\n\n## 方法\n\n### [nz-checkbox]\n\n| 名称      | 描述     |\n| --------- | -------- |\n| `focus()` | 获取焦点 |\n| `blur()`  | 移除焦点 |\n\n## Interfaces\n\n### NzCheckboxOption\n\n```ts\nexport interface NzCheckboxOption {\n  label: string;\n  value: string | number;\n  disabled?: boolean;\n}\n```\n"
  },
  {
    "path": "components/checkbox/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/checkbox/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/checkbox/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './checkbox-group.component';\nexport * from './checkbox.component';\nexport * from './checkbox.module';\nexport * from './tokens';\n"
  },
  {
    "path": "components/checkbox/style/entry.less",
    "content": "@import './index.less';\n@import './patch.less';\n"
  },
  {
    "path": "components/checkbox/style/index.less",
    "content": "@import '../../style/themes/index';\n@import './mixin';\n\n.antCheckboxFn();\n\n@import './rtl';\n"
  },
  {
    "path": "components/checkbox/style/mixin.less",
    "content": "@import '../../style/mixins/index';\n\n.antCheckboxFn(@checkbox-prefix-cls: ~'@{ant-prefix}-checkbox') {\n  @checkbox-inner-prefix-cls: ~'@{checkbox-prefix-cls}-inner';\n  // 一般状态\n  .@{checkbox-prefix-cls} {\n    .reset-component();\n\n    position: relative;\n    top: 0.2em;\n    line-height: 1;\n    white-space: nowrap;\n    outline: none;\n    cursor: pointer;\n\n    .@{checkbox-prefix-cls}-wrapper:hover &-inner,\n    &:hover &-inner,\n    &-input:focus + &-inner {\n      border-color: @checkbox-color;\n    }\n\n    &-checked::after {\n      position: absolute;\n      top: 0;\n      left: 0;\n      width: 100%;\n      height: 100%;\n      border: 1px solid @checkbox-color;\n      border-radius: @checkbox-border-radius;\n      visibility: hidden;\n      animation: antCheckboxEffect 0.36s ease-in-out;\n      animation-fill-mode: backwards;\n      content: '';\n    }\n\n    &:hover::after,\n    .@{checkbox-prefix-cls}-wrapper:hover &::after {\n      visibility: visible;\n    }\n\n    &-inner {\n      position: relative;\n      top: 0;\n      left: 0;\n      display: block;\n      width: @checkbox-size;\n      height: @checkbox-size;\n      direction: ltr;\n      background-color: @checkbox-check-bg;\n      border: @checkbox-border-width @border-style-base @border-color-base;\n      border-radius: @checkbox-border-radius;\n      // Fix IE checked style\n      // https://github.com/ant-design/ant-design/issues/12597\n      border-collapse: separate;\n      transition: all 0.3s;\n\n      &::after {\n        @check-width: (@checkbox-size / 14) * 5px;\n        @check-height: (@checkbox-size / 14) * 8px;\n\n        position: absolute;\n        top: 50%;\n        // https://github.com/ant-design/ant-design/pull/19452\n        // https://github.com/ant-design/ant-design/pull/31726\n        left: 21.5%;\n        display: table;\n        width: @check-width;\n        height: @check-height;\n        border: 2px solid @checkbox-check-color;\n        border-top: 0;\n        border-left: 0;\n        transform: rotate(45deg) scale(0) translate(-50%, -50%);\n        opacity: 0;\n        transition: all 0.1s @ease-in-back, opacity 0.1s;\n        content: ' ';\n      }\n    }\n\n    &-input {\n      position: absolute;\n      top: 0;\n      right: 0;\n      bottom: 0;\n      left: 0;\n      z-index: 1;\n      width: 100%;\n      height: 100%;\n      cursor: pointer;\n      opacity: 0;\n    }\n  }\n\n  // 选中状态\n  .@{checkbox-prefix-cls}-checked .@{checkbox-inner-prefix-cls}::after {\n    position: absolute;\n    display: table;\n    border: 2px solid @checkbox-check-color;\n    border-top: 0;\n    border-left: 0;\n    transform: rotate(45deg) scale(1) translate(-50%, -50%);\n    opacity: 1;\n    transition: all 0.2s @ease-out-back 0.1s;\n    content: ' ';\n  }\n\n  .@{checkbox-prefix-cls}-checked {\n    .@{checkbox-inner-prefix-cls} {\n      background-color: @checkbox-color;\n      border-color: @checkbox-color;\n    }\n  }\n\n  .@{checkbox-prefix-cls}-disabled {\n    cursor: not-allowed;\n\n    &.@{checkbox-prefix-cls}-checked {\n      .@{checkbox-inner-prefix-cls}::after {\n        border-color: @disabled-color;\n        animation-name: none;\n      }\n    }\n\n    .@{checkbox-prefix-cls}-input {\n      cursor: not-allowed;\n      pointer-events: none;\n    }\n\n    .@{checkbox-inner-prefix-cls} {\n      background-color: @input-disabled-bg;\n      border-color: @border-color-base !important;\n\n      &::after {\n        border-color: @input-disabled-bg;\n        border-collapse: separate;\n        animation-name: none;\n      }\n    }\n\n    & + span {\n      color: @disabled-color;\n      cursor: not-allowed;\n    }\n\n    // Not show highlight border of checkbox when disabled\n    &:hover::after,\n    .@{checkbox-prefix-cls}-wrapper:hover &::after {\n      visibility: hidden;\n    }\n  }\n\n  .@{checkbox-prefix-cls}-wrapper {\n    .reset-component();\n    display: inline-flex;\n    align-items: baseline;\n    line-height: unset;\n    cursor: pointer;\n\n    &::after {\n      display: inline-block;\n      width: 0;\n      overflow: hidden;\n      content: '\\a0';\n    }\n\n    &.@{checkbox-prefix-cls}-wrapper-disabled {\n      cursor: not-allowed;\n    }\n\n    & + & {\n      margin-left: 8px;\n    }\n\n    &&-in-form-item {\n      input[type='checkbox'] {\n        width: 14px;\n        height: 14px;\n      }\n    }\n  }\n\n  .@{checkbox-prefix-cls} + span {\n    padding-right: 8px;\n    padding-left: 8px;\n  }\n\n  .@{checkbox-prefix-cls}-group {\n    .reset-component();\n    display: inline-block;\n\n    &-item {\n      margin-right: @checkbox-group-item-margin-right;\n\n      &:last-child {\n        margin-right: 0;\n      }\n    }\n\n    &-item + &-item {\n      margin-left: 0;\n    }\n  }\n\n  // 半选状态\n  .@{checkbox-prefix-cls}-indeterminate {\n    .@{checkbox-inner-prefix-cls} {\n      background-color: @checkbox-check-bg;\n      border-color: @border-color-base;\n    }\n    .@{checkbox-inner-prefix-cls}::after {\n      @indeterminate-width: @checkbox-size - 8px;\n      @indeterminate-height: @checkbox-size - 8px;\n\n      top: 50%;\n      left: 50%;\n      width: @indeterminate-width;\n      height: @indeterminate-height;\n      background-color: @checkbox-color;\n      border: 0;\n      transform: translate(-50%, -50%) scale(1);\n      opacity: 1;\n      content: ' ';\n    }\n\n    &.@{checkbox-prefix-cls}-disabled .@{checkbox-inner-prefix-cls}::after {\n      background-color: @disabled-color;\n      border-color: @disabled-color;\n    }\n  }\n}\n\n@keyframes antCheckboxEffect {\n  0% {\n    transform: scale(1);\n    opacity: 0.5;\n  }\n\n  100% {\n    transform: scale(1.6);\n    opacity: 0;\n  }\n}\n"
  },
  {
    "path": "components/checkbox/style/patch.less",
    "content": ".ant-checkbox + span {\n  &:empty {\n    display: none;\n  }\n}\n"
  },
  {
    "path": "components/checkbox/style/rtl.less",
    "content": "@import '../../style/mixins/index';\n\n.antCheckboxFn(@checkbox-prefix-cls: ~'@{ant-prefix}-checkbox') {\n  .@{checkbox-prefix-cls}-rtl {\n    direction: rtl;\n  }\n\n  .@{checkbox-prefix-cls}-group {\n    &-item {\n      .@{checkbox-prefix-cls}-group-rtl & {\n        margin-right: 0;\n        margin-left: @checkbox-group-item-margin-right;\n      }\n\n      &:last-child {\n        .@{checkbox-prefix-cls}-group-rtl & {\n          margin-left: 0 !important;\n        }\n      }\n    }\n\n    &-item + &-item {\n      .@{checkbox-prefix-cls}-group-rtl & {\n        margin-left: @checkbox-group-item-margin-right;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/checkbox/tokens.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { InjectionToken } from '@angular/core';\n\nimport type { NzCheckboxGroupComponent } from './checkbox-group.component';\n\nexport const NZ_CHECKBOX_GROUP = new InjectionToken<NzCheckboxGroupComponent>(\n  typeof ngDevMode !== 'undefined' && ngDevMode ? 'nz-checkbox-group' : ''\n);\n"
  },
  {
    "path": "components/code-editor/code-editor.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Platform } from '@angular/cdk/platform';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterViewInit,\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  Component,\n  DestroyRef,\n  ElementRef,\n  EventEmitter,\n  forwardRef,\n  inject,\n  Input,\n  NgZone,\n  Output,\n  TemplateRef,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { BehaviorSubject, combineLatest, Subject } from 'rxjs';\nimport { debounceTime, distinctUntilChanged, filter, map } from 'rxjs/operators';\n\nimport type { editor, IDisposable } from 'monaco-editor';\n\nimport { warn } from 'ng-zorro-antd/core/logger';\nimport { NzSafeAny, OnChangeType, OnTouchedType } from 'ng-zorro-antd/core/types';\nimport { fromEventOutsideAngular, inNextTick } from 'ng-zorro-antd/core/util';\nimport { NzSpinComponent } from 'ng-zorro-antd/spin';\n\nimport { NzCodeEditorService } from './code-editor.service';\nimport { DiffEditorOptions, EditorOptions, JoinedEditorOptions, NzEditorMode } from './typings';\n\n// Import types from monaco editor.\ntype ITextModel = editor.ITextModel;\ntype IStandaloneCodeEditor = editor.IStandaloneCodeEditor;\ntype IStandaloneDiffEditor = editor.IStandaloneDiffEditor;\n\ndeclare const monaco: NzSafeAny;\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-code-editor',\n  exportAs: 'nzCodeEditor',\n  template: `\n    @if (nzLoading) {\n      <div class=\"ant-code-editor-loading\">\n        <nz-spin />\n      </div>\n    }\n    @if (nzToolkit) {\n      <div class=\"ant-code-editor-toolkit\">\n        <ng-template [ngTemplateOutlet]=\"nzToolkit\" />\n      </div>\n    }\n  `,\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => NzCodeEditorComponent),\n      multi: true\n    }\n  ],\n  imports: [NzSpinComponent, NgTemplateOutlet]\n})\nexport class NzCodeEditorComponent implements AfterViewInit, ControlValueAccessor {\n  private nzCodeEditorService = inject(NzCodeEditorService);\n  private ngZone = inject(NgZone);\n  private platform = inject(Platform);\n  private destroyRef = inject(DestroyRef);\n\n  @Input() nzEditorMode: NzEditorMode = 'normal';\n  @Input() nzOriginalText = '';\n  @Input({ transform: booleanAttribute }) nzLoading = false;\n  @Input({ transform: booleanAttribute }) nzFullControl = false;\n  @Input() nzToolkit?: TemplateRef<void>;\n\n  @Input() set nzEditorOption(value: JoinedEditorOptions) {\n    this.editorOption$.next(value);\n  }\n\n  @Output() readonly nzEditorInitialized = new EventEmitter<IStandaloneCodeEditor | IStandaloneDiffEditor>();\n\n  editorOptionCached: JoinedEditorOptions = {};\n\n  private readonly el: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement;\n  private resize$ = new Subject<void>();\n  private editorOption$ = new BehaviorSubject<JoinedEditorOptions>({});\n  private editorInstance: IStandaloneCodeEditor | IStandaloneDiffEditor | null = null;\n  private value = '';\n  private modelSet = false;\n  private onDidChangeContentDisposable: IDisposable | null = null;\n\n  constructor() {\n    this.el.classList.add('ant-code-editor');\n    this.destroyRef.onDestroy(() => {\n      if (this.onDidChangeContentDisposable) {\n        this.onDidChangeContentDisposable.dispose();\n        this.onDidChangeContentDisposable = null;\n      }\n\n      if (this.editorInstance) {\n        this.editorInstance.dispose();\n        this.editorInstance = null;\n      }\n    });\n  }\n\n  /**\n   * Initialize a monaco editor instance.\n   */\n  ngAfterViewInit(): void {\n    if (!this.platform.isBrowser) {\n      return;\n    }\n\n    this.nzCodeEditorService\n      .requestToInit()\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(option => this.setup(option));\n  }\n\n  writeValue(value: string): void {\n    this.value = value;\n    this.setValue();\n  }\n\n  registerOnChange(fn: OnChangeType): NzSafeAny {\n    this.onChange = fn;\n  }\n\n  registerOnTouched(fn: OnTouchedType): void {\n    this.onTouch = fn;\n  }\n\n  onChange: OnChangeType = (_value: string) => {};\n\n  onTouch: OnTouchedType = () => {};\n\n  layout(): void {\n    this.resize$.next();\n  }\n\n  private setup(option: JoinedEditorOptions): void {\n    // The `setup()` is invoked when the Monaco editor is loaded. This may happen asynchronously for the first\n    // time, and it'll always happen synchronously afterwards. The first `setup()` invokation is outside the Angular\n    // zone, but further invokations will happen within the Angular zone. We call the `setModel()` on the editor\n    // instance, which tells Monaco to add event listeners lazily internally (`mousemove`, `mouseout`, etc.).\n    // We should avoid adding them within the Angular zone since this will drastically affect the performance.\n    this.ngZone.runOutsideAngular(() =>\n      inNextTick()\n        .pipe(takeUntilDestroyed(this.destroyRef))\n        .subscribe(() => {\n          this.editorOptionCached = option;\n          this.registerOptionChanges();\n          this.initMonacoEditorInstance();\n          this.registerResizeChange();\n          this.setValue();\n\n          if (!this.nzFullControl) {\n            this.setValueEmitter();\n          }\n\n          if (this.nzEditorInitialized.observers.length) {\n            this.ngZone.run(() => this.nzEditorInitialized.emit(this.editorInstance!));\n          }\n        })\n    );\n  }\n\n  private registerOptionChanges(): void {\n    combineLatest([this.editorOption$, this.nzCodeEditorService.option$])\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(([selfOpt, defaultOpt]) => {\n        this.editorOptionCached = {\n          ...this.editorOptionCached,\n          ...defaultOpt,\n          ...selfOpt\n        };\n        this.updateOptionToMonaco();\n      });\n  }\n\n  private initMonacoEditorInstance(): void {\n    this.ngZone.runOutsideAngular(() => {\n      this.editorInstance =\n        this.nzEditorMode === 'normal'\n          ? monaco.editor.create(this.el, { ...this.editorOptionCached })\n          : monaco.editor.createDiffEditor(this.el, {\n              ...(this.editorOptionCached as DiffEditorOptions)\n            });\n    });\n  }\n\n  private registerResizeChange(): void {\n    fromEventOutsideAngular(window, 'resize')\n      .pipe(debounceTime(300), takeUntilDestroyed(this.destroyRef))\n      .subscribe(() => {\n        this.layout();\n      });\n\n    this.resize$\n      .pipe(\n        takeUntilDestroyed(this.destroyRef),\n        filter(() => !!this.editorInstance),\n        map(() => ({\n          width: this.el.clientWidth,\n          height: this.el.clientHeight\n        })),\n        distinctUntilChanged((a, b) => a.width === b.width && a.height === b.height),\n        debounceTime(50)\n      )\n      .subscribe(() => {\n        this.editorInstance!.layout();\n      });\n  }\n\n  private setValue(): void {\n    if (!this.editorInstance) {\n      return;\n    }\n\n    if (this.nzFullControl && this.value) {\n      warn(`should not set value when you are using full control mode! It would result in ambiguous data flow!`);\n      return;\n    }\n\n    if (this.nzEditorMode === 'normal') {\n      if (this.modelSet) {\n        const model = this.editorInstance.getModel() as ITextModel;\n        this.preservePositionAndSelections(() => model.setValue(this.value));\n      } else {\n        (this.editorInstance as IStandaloneCodeEditor).setModel(\n          monaco.editor.createModel(this.value, (this.editorOptionCached as EditorOptions).language)\n        );\n        this.modelSet = true;\n      }\n    } else {\n      if (this.modelSet) {\n        const model = (this.editorInstance as IStandaloneDiffEditor).getModel()!;\n        this.preservePositionAndSelections(() => {\n          model.modified.setValue(this.value);\n          model.original.setValue(this.nzOriginalText);\n        });\n      } else {\n        const language = (this.editorOptionCached as EditorOptions).language;\n        (this.editorInstance as IStandaloneDiffEditor).setModel({\n          original: monaco.editor.createModel(this.nzOriginalText, language),\n          modified: monaco.editor.createModel(this.value, language)\n        });\n        this.modelSet = true;\n      }\n    }\n  }\n\n  /**\n   * {@link editor.ICodeEditor}#setValue resets the cursor position to the start of the document.\n   * This helper memorizes the cursor position and selections and restores them after the given\n   * function has been called.\n   */\n  private preservePositionAndSelections(fn: () => unknown): void {\n    if (!this.editorInstance) {\n      fn();\n      return;\n    }\n\n    const position = this.editorInstance.getPosition();\n    const selections = this.editorInstance.getSelections();\n\n    fn();\n\n    if (position) {\n      this.editorInstance.setPosition(position);\n    }\n    if (selections) {\n      this.editorInstance.setSelections(selections);\n    }\n  }\n\n  private setValueEmitter(): void {\n    const model = (\n      this.nzEditorMode === 'normal'\n        ? (this.editorInstance as IStandaloneCodeEditor).getModel()\n        : (this.editorInstance as IStandaloneDiffEditor).getModel()!.modified\n    ) as ITextModel;\n\n    // The `onDidChangeContent` returns a disposable object (an object with `dispose()` method) which will cleanup\n    // the listener. The callback, that we pass to `onDidChangeContent`, captures `this`. This leads to a circular reference\n    // (`nz-code-editor -> monaco -> nz-code-editor`) and prevents the `nz-code-editor` from being GC'd.\n    this.onDidChangeContentDisposable = model.onDidChangeContent(() => {\n      this.emitValue(model.getValue());\n    });\n  }\n\n  private emitValue(value: string): void {\n    if (this.value === value) {\n      // If the value didn't change there's no reason to send an update.\n      // Specifically this may happen during an update from the model (writeValue) where sending an update to the model would actually be incorrect.\n      return;\n    }\n\n    this.value = value;\n    // We're re-entering the Angular zone only if the value has been changed since there's a `return` expression previously.\n    // This won't cause \"dead\" change detections (basically when the `tick()` has been run, but there's nothing to update).\n    this.ngZone.run(() => {\n      this.onChange(value);\n    });\n  }\n\n  private updateOptionToMonaco(): void {\n    if (this.editorInstance) {\n      this.editorInstance.updateOptions({ ...this.editorOptionCached });\n    }\n  }\n}\n"
  },
  {
    "path": "components/code-editor/code-editor.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzCodeEditorComponent } from './code-editor.component';\n\n@NgModule({\n  imports: [NzCodeEditorComponent],\n  exports: [NzCodeEditorComponent]\n})\nexport class NzCodeEditorModule {}\n"
  },
  {
    "path": "components/code-editor/code-editor.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { DOCUMENT, inject, Injectable } from '@angular/core';\nimport { BehaviorSubject, Observable, of, ReplaySubject } from 'rxjs';\nimport { map, tap } from 'rxjs/operators';\n\nimport { CodeEditorConfig, NzConfigService, onConfigChangeEventForComponent } from 'ng-zorro-antd/core/config';\nimport { PREFIX, warn } from 'ng-zorro-antd/core/logger';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { JoinedEditorOptions, NzCodeEditorLoadingStatus } from './typings';\n\ndeclare const monaco: NzSafeAny;\n\nconst NZ_CONFIG_MODULE_NAME = 'codeEditor';\n\nfunction tryTriggerFunc(fn?: (...args: NzSafeAny[]) => NzSafeAny): (...args: NzSafeAny) => void {\n  return (...args: NzSafeAny[]) => {\n    if (fn) {\n      fn(...args);\n    }\n  };\n}\n\n// Caretaker note: previously, these were `NzCodeEditorService` properties.\n// They're kept as static variables because this will allow loading Monaco only once.\n// This applies to micro frontend apps with multiple Angular apps or a single Angular app\n// that can be bootstrapped and destroyed multiple times (e.g. using Webpack module federation).\n// Root providers are re-initialized each time the app is bootstrapped. Platform providers aren't.\n// We can't make the `NzCodeEditorService` to be a platform provider (`@Injectable({ providedIn: 'platform' })`)\n// since it depends on other root providers.\nconst loaded$ = new ReplaySubject<boolean>(1);\nlet loadingStatus: NzCodeEditorLoadingStatus = NzCodeEditorLoadingStatus.UNLOAD;\n\n@Injectable({\n  providedIn: 'root'\n})\nexport class NzCodeEditorService {\n  private readonly nzConfigService = inject(NzConfigService);\n  private document: Document = inject(DOCUMENT);\n  private firstEditorInitialized = false;\n  private option: JoinedEditorOptions = {};\n  private config: CodeEditorConfig;\n\n  option$ = new BehaviorSubject<JoinedEditorOptions>(this.option);\n\n  constructor() {\n    const globalConfig = this.nzConfigService.getConfigForComponent(NZ_CONFIG_MODULE_NAME);\n\n    this.config = { ...globalConfig };\n    if (this.config.monacoEnvironment) {\n      (this.document.defaultView as NzSafeAny).MonacoEnvironment = { ...this.config.monacoEnvironment };\n    }\n    this.option = this.config.defaultEditorOption || {};\n\n    onConfigChangeEventForComponent(NZ_CONFIG_MODULE_NAME, () => {\n      const newGlobalConfig: NzSafeAny = this.nzConfigService.getConfigForComponent(NZ_CONFIG_MODULE_NAME);\n      if (newGlobalConfig) {\n        this._updateDefaultOption(newGlobalConfig.defaultEditorOption);\n      }\n    });\n  }\n\n  private _updateDefaultOption(option: JoinedEditorOptions): void {\n    this.option = { ...this.option, ...option };\n    this.option$.next(this.option);\n\n    if ('theme' in option && option.theme) {\n      monaco.editor.setTheme(option.theme);\n    }\n  }\n\n  requestToInit(): Observable<JoinedEditorOptions> {\n    if (loadingStatus === NzCodeEditorLoadingStatus.LOADED) {\n      this.onInit();\n      return of(this.getLatestOption());\n    }\n\n    if (loadingStatus === NzCodeEditorLoadingStatus.UNLOAD) {\n      if (this.config.useStaticLoading && typeof monaco === 'undefined') {\n        warn(\n          'You choose to use static loading but it seems that you forget ' +\n            'to config webpack plugin correctly. Please refer to our official website' +\n            'for more details about static loading.'\n        );\n      } else {\n        this.loadMonacoScript();\n      }\n    }\n\n    return loaded$.pipe(\n      tap(() => this.onInit()),\n      map(() => this.getLatestOption())\n    );\n  }\n\n  private loadMonacoScript(): void {\n    if (this.config.useStaticLoading) {\n      Promise.resolve().then(() => this.onLoad());\n      return;\n    }\n\n    if (loadingStatus === NzCodeEditorLoadingStatus.LOADING) {\n      return;\n    }\n\n    loadingStatus = NzCodeEditorLoadingStatus.LOADING;\n\n    const assetsRoot = this.config.assetsRoot;\n    const vs = assetsRoot ? `${assetsRoot}/vs` : 'assets/vs';\n    const windowAsAny = window as NzSafeAny;\n    const loadScript = this.document.createElement('script');\n\n    loadScript.type = 'text/javascript';\n    loadScript.src = `${vs}/loader.js`;\n\n    const onLoad = (): void => {\n      cleanup();\n      windowAsAny.require.config({\n        paths: { vs },\n        ...this.config.extraConfig\n      });\n      windowAsAny.require(['vs/editor/editor.main'], () => {\n        this.onLoad();\n      });\n    };\n\n    const onError = (): void => {\n      cleanup();\n      throw new Error(`${PREFIX} cannot load assets of monaco editor from source \"${vs}\".`);\n    };\n\n    const cleanup = (): void => {\n      // Caretaker note: we have to remove these listeners once the `<script>` is loaded successfully\n      // or not since the `onLoad` listener captures `this`, which will prevent the `NzCodeEditorService`\n      // from being garbage collected.\n      loadScript.removeEventListener('load', onLoad);\n      loadScript.removeEventListener('error', onError);\n      // We don't need to keep the `<script>` element within the `<body>` since JavaScript has\n      // been executed and Monaco is available globally. E.g. Webpack, always removes `<script>`\n      // elements after loading chunks (see its `LoadScriptRuntimeModule`).\n      this.document.documentElement.removeChild(loadScript);\n    };\n\n    loadScript.addEventListener('load', onLoad);\n    loadScript.addEventListener('error', onError);\n\n    this.document.documentElement.appendChild(loadScript);\n  }\n\n  private onLoad(): void {\n    loadingStatus = NzCodeEditorLoadingStatus.LOADED;\n    loaded$.next(true);\n    loaded$.complete();\n\n    tryTriggerFunc(this.config.onLoad)();\n  }\n\n  private onInit(): void {\n    if (!this.firstEditorInitialized) {\n      this.firstEditorInitialized = true;\n      tryTriggerFunc(this.config.onFirstEditorInit)();\n    }\n\n    tryTriggerFunc(this.config.onInit)();\n  }\n\n  private getLatestOption(): JoinedEditorOptions {\n    return { ...this.option };\n  }\n}\n"
  },
  {
    "path": "components/code-editor/code-editor.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component } from '@angular/core';\nimport { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCodeEditorModule } from 'ng-zorro-antd/code-editor';\n\n// eslint-disable-next-line  @typescript-eslint/no-explicit-any\ndeclare const monaco: any;\n\n@Component({\n  imports: [FormsModule, NzCodeEditorModule],\n  template: `\n    <nz-code-editor\n      class=\"editor\"\n      [ngModel]=\"code\"\n      [nzFullControl]=\"true\"\n      (nzEditorInitialized)=\"onEditorInit($event)\"\n    />\n  `\n})\nexport class NzTestCodeEditorFullControlComponent {\n  // eslint-disable-next-line  @typescript-eslint/no-explicit-any\n  editor: any;\n\n  code = '';\n\n  // eslint-disable-next-line  @typescript-eslint/no-explicit-any\n  onEditorInit(e: any): void {\n    this.editor = e;\n    this.editor.setModel(monaco.editor.createModel(\"console.log('Hello ng-zorro-antd')\", 'typescript'));\n  }\n}\n\ndescribe('code editor', () => {\n  // describe('basic', () => {\n  //   // let fixture: ComponentFixture<NzDemoCodeEditorBasicComponent>;\n\n  //   beforeEach(waitForAsync(() => {\n  //     TestBed.configureTestingModule({\n  //       imports: [FormsModule, NzCodeEditorModule],\n  //       declarations: [NzDemoCodeEditorBasicComponent]\n  //     });\n  //   }));\n\n  //   beforeEach(() => {\n  //     // fixture = TestBed.createComponent(NzDemoCodeEditorBasicComponent);\n  //   });\n  // });\n\n  describe('full control', () => {\n    let fixture: ComponentFixture<NzTestCodeEditorFullControlComponent>;\n    let testComponent: NzTestCodeEditorFullControlComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCodeEditorFullControlComponent);\n      testComponent = fixture.debugElement.componentInstance;\n    });\n\n    // It seems that there is no way to waiting for monaco editor to load.\n    xit('should raise error when user try to set value in full control mode', waitForAsync(() => {\n      const spy = spyOn(console, 'warn');\n      testComponent.code = '123';\n      fixture.detectChanges();\n      expect(spy).toHaveBeenCalledWith(\n        '[NG-ZORRO]',\n        'should not set value when you are using full control mode! It would result in ambiguous data flow!'\n      );\n    }));\n  });\n});\n"
  },
  {
    "path": "components/code-editor/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n最简单的用法。\n\n## en-US\n\nThe simplest usage.\n"
  },
  {
    "path": "components/code-editor/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCodeEditorModule } from 'ng-zorro-antd/code-editor';\n\n@Component({\n  selector: 'nz-demo-code-editor-basic',\n  imports: [FormsModule, NzCodeEditorModule],\n  template: ` <nz-code-editor class=\"editor\" [ngModel]=\"code\" [nzEditorOption]=\"{ language: 'typescript' }\" /> `,\n  styles: `\n    .editor {\n      height: 200px;\n    }\n  `\n})\nexport class NzDemoCodeEditorBasicComponent {\n  code = `import { NzCodeEditorModule } from 'ng-zorro-antd/code-editor'\n\n@Component({})\nexport class SomeComponent {}`;\n}\n"
  },
  {
    "path": "components/code-editor/demo/complex.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 复杂\n  en-US: Complex\n---\n\n## zh-CN\n\n带加载效果和工具条的更复杂的例子。\n\n## en-US\n\nA more complex demo with loading effect and toolkit.\n"
  },
  {
    "path": "components/code-editor/demo/complex.ts",
    "content": "import { Component, DOCUMENT, inject, Renderer2, ViewChild } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCodeEditorComponent, NzCodeEditorModule } from 'ng-zorro-antd/code-editor';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\nimport { NzTooltipDirective, NzTooltipModule } from 'ng-zorro-antd/tooltip';\nimport { NzTypographyModule } from 'ng-zorro-antd/typography';\n\n@Component({\n  selector: 'nz-demo-code-editor-complex',\n  imports: [FormsModule, NzCodeEditorModule, NzIconModule, NzTypographyModule, NzSwitchModule, NzTooltipModule],\n  template: `\n    <p nz-paragraph style=\"margin-bottom: 8px;\">\n      Loading\n      <nz-switch [(ngModel)]=\"loading\" />\n    </p>\n    <nz-code-editor\n      class=\"editor\"\n      [class.full-screen]=\"fullScreen\"\n      [ngModel]=\"code\"\n      [nzLoading]=\"loading\"\n      [nzToolkit]=\"toolkit\"\n      [nzEditorOption]=\"{ language: 'javascript' }\"\n    />\n    <ng-template #toolkit>\n      <nz-icon\n        [class.active]=\"fullScreen\"\n        nz-tooltip\n        nzTooltipTitle=\"Toggle Fullscreen\"\n        [nzType]=\"fullScreen ? 'fullscreen-exit' : 'fullscreen'\"\n        (click)=\"toggleFullScreen()\"\n      />\n    </ng-template>\n  `,\n  styles: `\n    .editor {\n      height: 200px;\n    }\n\n    .full-screen {\n      position: fixed;\n      z-index: 999;\n      height: 100vh;\n      left: 0;\n      top: 0;\n      bottom: 0;\n      right: 0;\n    }\n  `\n})\nexport class NzDemoCodeEditorComplexComponent {\n  @ViewChild(NzCodeEditorComponent, { static: false }) editorComponent?: NzCodeEditorComponent;\n  @ViewChild(NzTooltipDirective, { static: false }) tooltip?: NzTooltipDirective;\n\n  loading = true;\n  fullScreen = false;\n  code = `function flatten(arr) {\n  if (!(arr instanceof Array)) {\n    throw new Error('The parameter must be an array.');\n  }\n\n  function partial(arr_) {\n    return arr_.reduce((previous, current) => {\n      if (current instanceof Array) {\n        previous.push(...partial(current));\n        return previous;\n      } else {\n        previous.push(current);\n        return previous;\n      }\n    }, []);\n  }\n\n  return partial(arr);\n}\n\nconsole.log(flatten(['1', 2, [[3]]]))`;\n  private document: Document = inject(DOCUMENT);\n  private renderer: Renderer2 = inject(Renderer2);\n\n  toggleFullScreen(): void {\n    this.fullScreen = !this.fullScreen;\n    this.renderer.setStyle(this.document.body, 'overflow-y', this.fullScreen ? 'hidden' : null);\n    this.editorComponent?.layout();\n    this.tooltip?.hide();\n  }\n}\n"
  },
  {
    "path": "components/code-editor/demo/config.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 修改配置\n  en-US: Change Config\n---\n\n## zh-CN\n\n可以在运行时修改编辑器的默认配置，和页面上编辑器的配置。\n\n## en-US\n\nYou can change default options and options of existing editors at runtime.\n"
  },
  {
    "path": "components/code-editor/demo/config.ts",
    "content": "import { Component, inject } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCodeEditorModule } from 'ng-zorro-antd/code-editor';\nimport { NzConfigService } from 'ng-zorro-antd/core/config';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\nimport { NzTypographyModule } from 'ng-zorro-antd/typography';\n\n@Component({\n  selector: 'nz-demo-code-editor-config',\n  imports: [FormsModule, NzCodeEditorModule, NzIconModule, NzSwitchModule, NzTypographyModule],\n  template: `\n    <p nz-paragraph style=\"margin-bottom: 8px;\">\n      Change Theme\n      <nz-switch\n        [ngModel]=\"dark\"\n        (ngModelChange)=\"onDarkModeChange($event)\"\n        [nzUnCheckedChildren]=\"unchecked\"\n        [nzCheckedChildren]=\"checked\"\n      />\n    </p>\n    <ng-template #unchecked>\n      <nz-icon nzType=\"bulb\" />\n    </ng-template>\n    <ng-template #checked>\n      <nz-icon nzType=\"poweroff\" />\n    </ng-template>\n    <nz-code-editor style=\"height: 200px\" [ngModel]=\"code\" [nzEditorOption]=\"{ language: 'markdown' }\" />\n  `\n})\nexport class NzDemoCodeEditorConfigComponent {\n  private nzConfigService = inject(NzConfigService);\n\n  dark = false;\n\n  code = `**All monaco editor instances on the same page always have the same color. It's a by-design of monaco editor.**\n\nYou can refer to [this issue](https://github.com/Microsoft/monaco-editor/issues/338).`;\n\n  onDarkModeChange(dark: boolean): void {\n    this.dark = dark;\n    const defaultEditorOption = this.nzConfigService.getConfigForComponent('codeEditor')?.defaultEditorOption || {};\n    this.nzConfigService.set('codeEditor', {\n      defaultEditorOption: {\n        ...defaultEditorOption,\n        theme: dark ? 'vs-dark' : 'vs'\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "components/code-editor/demo/diff.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: Diff 编辑器\n  en-US: Diff Editor\n---\n\n## zh-CN\n\n使用 diff 模式。\n\n## en-US\n\nUse diff editor mode.\n"
  },
  {
    "path": "components/code-editor/demo/diff.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCodeEditorModule } from 'ng-zorro-antd/code-editor';\n\n@Component({\n  selector: 'nz-demo-code-editor-diff',\n  imports: [FormsModule, NzCodeEditorModule],\n  template: `\n    <nz-code-editor\n      class=\"editor\"\n      [nzOriginalText]=\"originalCode\"\n      nzEditorMode=\"diff\"\n      [ngModel]=\"code\"\n      [nzEditorOption]=\"{ language: 'typescript' }\"\n    />\n  `,\n  styles: `\n    .editor {\n      height: 200px;\n    }\n  `\n})\nexport class NzDemoCodeEditorDiffComponent {\n  originalCode = `import { NzCodeEditorModule } from 'ng-zorro-antd/code-editor';\n\n@Component({})\nexport class SomeComponent {}`;\n\n  code = `import { NzCodeEditorModule } from 'ng-zorro-antd/code-editor';\n\n@Component({})\nexport class SomeComponent {}`;\n}\n"
  },
  {
    "path": "components/code-editor/demo/full-control.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 完全受控模式\n  en-US: Full Control Mode\n---\n\n## zh-CN\n\n使用完全受控模式，自行管理 monaco editor 的 TextModel。\n\n## en-US\n\nUse full control mode and mangage TextModel of monaco editor by yourself.\n"
  },
  {
    "path": "components/code-editor/demo/full-control.ts",
    "content": "import { Component } from '@angular/core';\n\nimport type { editor } from 'monaco-editor';\n\nimport { NzCodeEditorModule } from 'ng-zorro-antd/code-editor';\n\n// eslint-disable-next-line  @typescript-eslint/no-explicit-any\ndeclare const monaco: any;\n\n@Component({\n  selector: 'nz-demo-code-editor-full-control',\n  imports: [NzCodeEditorModule],\n  template: ` <nz-code-editor class=\"editor\" [nzFullControl]=\"true\" (nzEditorInitialized)=\"onEditorInit($event)\" /> `,\n  styles: `\n    .editor {\n      height: 200px;\n    }\n  `\n})\nexport class NzDemoCodeEditorFullControlComponent {\n  editor?: editor.ICodeEditor | editor.IEditor;\n\n  onEditorInit(e: editor.ICodeEditor | editor.IEditor): void {\n    this.editor = e;\n    this.editor.setModel(monaco.editor.createModel(\"console.log('Hello ng-zorro-antd')\", 'typescript'));\n  }\n}\n"
  },
  {
    "path": "components/code-editor/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Entry\ntitle: Code Editor\ncols: 1\nexperimental: true\ndescription: Code Editor based on monaco-editor.\n---\n\n## When To Use\n\nWhen you want to use monaco editor in Angular.\n\n### Import Style\n\n```less\n@import 'node_modules/ng-zorro-antd/code-editor/style/entry.less';\n```\n\n## API\n\nInstall `monaco-editor` in your project first:\n\n```sh\nnpm install monaco-editor\n```\n\n### Dynamic Loading\n\nIf you would like to load monaco dynamically (which means you load resources of monaco editor right before you would like to use it), you will need to register assets of monaco editor itself. You can do that by adding these lines in `angular.json` file:\n\n```diff\n\"assets\": [\n+ {\n+   \"glob\": \"**/*\",\n+   \"input\": \"./node_modules/monaco-editor/min/vs\",\n+   \"output\": \"/assets/vs/\"\n+ }\n],\n```\n\nIf you deploy resources of monaco editor on CDN, you won't need to modify `angular.json`. Instead, you must configure the `assetsRoot` property via `NzConfigService`. For example, you put resources of monaco editor on https://mycdn.com/assets/vs, you should provide `{ assets: 'https://mycdn.com/assets/vs' }`.\n\n> If you are going to use static loading (which we will explain in detail at the bottom of this page), you don't need to modify angular.json file.\n\n### Static Loading\n\nSometimes you need to load AMD module dynamically. But since monaco editor's loader patches `window[require]`, you can not use AMD loader like requireJS. In this situation you need to enable static loading.\n\nWith help of [monaco-editor-webpack-plugin](https://github.com/microsoft/monaco-editor-webpack-plugin) by Microsoft, you can do that in a convenient way.\n\n1. Provide the value of `NZ_CONFIG` in `app.config.ts` and set `useStaticLoading` in the `codeEditor` property to `true`.\n2. Create a `webpack.partial.js` file, and config monaco-editor-webpack-loader.\n3. Use custom webpack loader like [ngx-build-plus](https://github.com/manfredsteyer/ngx-build-plus) to load this webpack config.\n\nIf you use static loading, you should not add assets of monaco editor to your project by modifying `angular.json` file.\n\n### nz-code-editor\n\n| Parameter               | Description                                                                                                                                        | Type                                               | Default  |\n| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | -------- |\n| `[nzEditorMode]`        | Mode of monaco editor                                                                                                                              | `normal`\\|`diff`                                   | `normal` |\n| `[nzLoading]`           | Show the loading spin                                                                                                                              | `boolean`                                          | `false`  |\n| `[nzOriginalText]`      | The content of the left editor in `diff` mode                                                                                                      | `boolean`                                          | `false`  |\n| `[nzFullControl]`       | Enable full control mode. User should manage `TextModel` manually in this mode                                                                     | `boolean`                                          | `false`  |\n| `[nzEditorOption]`      | [Please refer to the doc of monaco editor](https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.ieditorconstructionoptions.html) | `IEditorConstructionOptions`                       | `{}`     |\n| `[nzToolkit]`           | A placeholder for adding some quick actions                                                                                                        | `TemplateRef<void>`                                | -        |\n| `(nzEditorInitialized)` | The event that a code editor is initialized                                                                                                        | `IStandaloneCodeEditor` \\| `IStandaloneDiffEditor` | -        |\n\n#### Methods\n\n| Method     | Description                             |\n| ---------- | --------------------------------------- |\n| `layout()` | Force monaco editor to re-render itself |\n\n### Global Configuration\n\nYou can set the default configuration of the `CodeEditor` component through the `set` method of `NzConfigService`.\n\n#### CodeEditorConfig\n\n| Parameter             | Description                                                                                                                                                                                                                                                 | Type                         | Default |\n| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | ------- |\n| `assetsRoot`          | Where should the component load resource of monaco editor                                                                                                                                                                                                   | `string` \\| `SafeUrl`        | -       |\n| `defaultEditorOption` | Default options. [Please refer to the doc of monaco editor](https://microsoft.github.io/monaco-editor/docs.html#interfaces/editor.IEditorConstructionOptions.html)                                                                                          | `IEditorConstructionOptions` | `{}`    |\n| `onLoad`              | The hook invoked when the resource of monaco editor is loaded. At this moment and afterwards the global variable `monaco` is usable (`window.MonacoEnvironment = { globalAPI: true }` is required if monaco-editor's version is greater or equal to 0.22.0) | `() => void`                 | -       |\n| `onFirstEditorInit`   | The hook invoked when the first monaco editor is initialized                                                                                                                                                                                                | `() => void`                 | -       |\n| `onInit`              | The hook invoked every time a monaco editor is initialized                                                                                                                                                                                                  | `() => void`                 | -       |\n| `useStaticLoading`    | Load monaco editor statically                                                                                                                                                                                                                               | `boolean`                    | `false` |\n"
  },
  {
    "path": "components/code-editor/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 代码编辑器\ntype: 数据录入\ntitle: Code Editor\ncols: 1\nexperimental: true\ndescription: 基于 monaco-editor 的代码编辑器。\n---\n\n## 何时使用\n\n需要在网页上渲染 monaco editor 时使用。\n\n### 引入样式\n\n```less\n@import 'node_modules/ng-zorro-antd/code-editor/style/entry.less';\n```\n\n## API\n\n别忘记先安装 monaco editor：\n\n```sh\nnpm install monaco-editor\n```\n\n### 动态加载\n\n如果你使用动态加载，你就需要在运行时加载 monaco editor 本身的资源。\n\n在 `angular.json` 中添加：\n\n```diff\n\"assets\": [\n+ {\n+   \"glob\": \"**/*\",\n+   \"input\": \"./node_modules/monaco-editor/min/vs\",\n+   \"output\": \"/assets/vs/\"\n+ }\n],\n```\n\n这样就 OK 了！CodeEditor 组件在需要加载 monaco editor 时自动去 `/assets/vs/` 目录下查询。\n\n如果你的静态资源都部署在 CDN 上，你就无须修改 `angular.json` 文件，但你必须通过 `NzConfigService` 配置 `assetsRoot` 属性。例如你将 monaco editor 的资源放置在了 https://mycdn.com/assets/vs ，你就需要传递 `{ assetsRoot: 'https://mycdn.com/assets' }` 。\n\n> 如果你使用静态加载，你就无需修改 `angular.json` 文件，详见下文。\n\n### 静态加载\n\n有时候你可能需要在运行时加载 AMD module，但 monaco editor 的加载文件 loader.js patch 了 `window[require]` 属性，导致你无法使用 requireJS 等模块加载库，这时，你可以启用静态加载功能。\n\n方法是使用 Microsoft 提供的 [monaco-editor-webpack-plugin](https://github.com/microsoft/monaco-editor-webpack-plugin) 插件。\n\n1. 在 `app.config.ts` 中提供 `NZ_CONFIG` 的值，并设置 `codeEditor` 属性下的 `useStaticLoading` 为 `true` 。\n2. 创建一个 webpack.partial.js 文件，根据插件文档进行相应的配置。\n3. 使用自定义脚本加载器，例如 [ngx-build-plus](https://github.com/manfredsteyer/ngx-build-plus)，在打包时加载这个 webpack 配置。\n\n使用静态加载时，你无需在 `angular.json` 文件中注册 monaco editor 的资源。\n\n### nz-code-editor\n\n| 参数                    | 说明                                                                                                                                | 类型                                               | 默认值   |\n| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | -------- |\n| `[nzEditorMode]`        | 编辑器的模式                                                                                                                        | `normal`\\|`diff`                                   | `normal` |\n| `[nzLoading]`           | 加载中                                                                                                                              | `boolean`                                          | `false`  |\n| `[nzOriginalText]`      | Diff 模式下，左半边的文本内容                                                                                                       | `boolean`                                          | `false`  |\n| `[nzFullControl]`       | 完全控制模式，此模式下组件不会帮助用户处理 `TextModel`，用户应当自行管理 monaco editor 实例                                         | `boolean`                                          | `false`  |\n| `[nzEditorOption]`      | 编辑器选项，[参考 monaco editor 的定义](https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IEditorOptions.html) | `IEditorConstructionOptions`                       | `{}`     |\n| `[nzToolkit]`           | 暴露快捷操作                                                                                                                        | `TemplateRef<void>`                                | -        |\n| `(nzEditorInitialized)` | 当编辑器组件初始化完毕之后派发事件                                                                                                  | `IStandaloneCodeEditor` \\| `IStandaloneDiffEditor` | -        |\n\n#### 方法\n\n| 名称       | 描述             |\n| ---------- | ---------------- |\n| `layout()` | 强制组件重新渲染 |\n\n### 全局配置\n\n你可以通过 `NzConfigService` 的 `set` 方法，设置 `CodeEditor` 组件的默认配置。\n\n#### CodeEditorConfig\n\n| 属性                  | 说明                                                                                                                                                              | 类型                         | 默认值  |\n| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | ------- |\n| `assetsRoot`          | 组件加载 monaco editor 资源文件的位置                                                                                                                             | `string` \\| `SafeUrl`        | -       |\n| `defaultEditorOption` | 默认的编辑器设置，[参考 monaco editor 的定义](https://microsoft.github.io/monaco-editor/docs.html#interfaces/editor.IEditorConstructionOptions.html)              | `IEditorConstructionOptions` | `{}`    |\n| `onLoad`              | 当 monaco editor 资源加载完毕时触发的钩子，此时全局对象 `monaco` 可用 (monaco-editor 版本不小于 0.22.0 时需定义 `window.MonacoEnvironment = { globalAPI: true }`) | `() => void`                 | -       |\n| `onFirstEditorInit`   | 当第一个编辑器请求初始化时触发的钩子                                                                                                                              | `() => void`                 | -       |\n| `onInit`              | 每个编辑器请求初始化时触发的钩子                                                                                                                                  | `() => void`                 | -       |\n| `useStaticLoading`    | 使用静态加载                                                                                                                                                      | `boolean`                    | `false` |\n"
  },
  {
    "path": "components/code-editor/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/code-editor/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/code-editor/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './typings';\nexport * from './code-editor.component';\nexport * from './code-editor.module';\nexport * from './code-editor.service';\n"
  },
  {
    "path": "components/code-editor/style/entry.less",
    "content": "@import './index.less';\n// style dependencies\n@import '../../spin/style/entry.less';\n"
  },
  {
    "path": "components/code-editor/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@code-editor-prefix-cls: ~'@{ant-prefix}-code-editor';\n\n.@{code-editor-prefix-cls} {\n  position: relative;\n  display: block;\n  width: 100%;\n  height: 100%;\n  background-color: @component-background;\n\n  .@{code-editor-prefix-cls}-loading {\n    position: absolute;\n    z-index: 100;\n    display: flex;\n    justify-content: center;\n    width: 100%;\n    height: 100%;\n    background-color: @component-background;\n  }\n\n  .@{code-editor-prefix-cls}-toolkit {\n    position: absolute;\n    top: 20px;\n    right: 160px;\n    z-index: 2;\n    min-width: 100px;\n    height: 24px;\n    text-align: right;\n    background: transparent;\n\n    i,\n    span[nz-icon],\n    nz-icon {\n      position: relative;\n      right: 4px;\n      cursor: pointer;\n\n      &:not(:last-child) {\n        padding-right: 4px;\n      }\n\n      &.active {\n        color: @primary-color;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/code-editor/typings.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { editor } from 'monaco-editor';\n\nimport IStandAloneEditorConstructionOptions = editor.IStandaloneEditorConstructionOptions;\nimport IDiffEditorConstructionOptions = editor.IDiffEditorConstructionOptions;\n\nexport type EditorOptions = IStandAloneEditorConstructionOptions;\nexport type DiffEditorOptions = IDiffEditorConstructionOptions;\nexport type JoinedEditorOptions = EditorOptions | DiffEditorOptions;\n\nexport type NzEditorMode = 'normal' | 'diff';\n\nexport const NzCodeEditorLoadingStatus = {\n  UNLOAD: 'unload',\n  LOADING: 'loading',\n  LOADED: 'LOADED'\n} as const;\n\nexport type NzCodeEditorLoadingStatus = (typeof NzCodeEditorLoadingStatus)[keyof typeof NzCodeEditorLoadingStatus];\n"
  },
  {
    "path": "components/collapse/collapse-panel.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  AfterViewInit,\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DestroyRef,\n  ElementRef,\n  inject,\n  Input,\n  input,\n  linkedSignal,\n  NgZone,\n  output,\n  TemplateRef,\n  viewChild,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { filter } from 'rxjs/operators';\n\nimport { NzAnimationCollapseDirective } from 'ng-zorro-antd/core/animation';\nimport { NzConfigKey, onConfigChangeEventForComponent, WithConfig } from 'ng-zorro-antd/core/config';\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nimport { NzCollapseComponent } from './collapse.component';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'collapsePanel';\n\n@Component({\n  selector: 'nz-collapse-panel',\n  exportAs: 'nzCollapsePanel',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <div\n      #collapseHeader\n      role=\"button\"\n      [attr.aria-expanded]=\"active()\"\n      [attr.aria-disabled]=\"nzDisabled || nzCollapsible === 'disabled'\"\n      [attr.tabindex]=\"nzDisabled || nzCollapsible === 'disabled' ? -1 : 0\"\n      class=\"ant-collapse-header\"\n      [class.ant-collapse-collapsible-icon]=\"nzCollapsible === 'icon'\"\n      [class.ant-collapse-collapsible-header]=\"nzCollapsible === 'header'\"\n    >\n      @if (nzShowArrow) {\n        <div role=\"button\" #collapseIcon class=\"ant-collapse-expand-icon\">\n          <ng-container *nzStringTemplateOutlet=\"nzExpandedIcon; let expandedIcon\">\n            <nz-icon [nzType]=\"expandedIcon || 'right'\" class=\"ant-collapse-arrow\" [nzRotate]=\"active() ? 90 : 0\" />\n          </ng-container>\n        </div>\n      }\n      <span class=\"ant-collapse-title\">\n        <ng-container *nzStringTemplateOutlet=\"nzHeader\">{{ nzHeader }}</ng-container>\n      </span>\n      @if (nzExtra) {\n        <div class=\"ant-collapse-extra\">\n          <ng-container *nzStringTemplateOutlet=\"nzExtra\">{{ nzExtra }}</ng-container>\n        </div>\n      }\n    </div>\n    <div\n      class=\"ant-collapse-panel\"\n      [class.ant-collapse-panel-active]=\"active()\"\n      animation-collapse\n      [open]=\"active()\"\n      leavedClassName=\"ant-collapse-panel-hidden\"\n    >\n      <div class=\"ant-collapse-body\">\n        <ng-content />\n      </div>\n    </div>\n  `,\n  host: {\n    class: 'ant-collapse-item',\n    '[class.ant-collapse-no-arrow]': '!nzShowArrow',\n    '[class.ant-collapse-item-active]': 'active()',\n    '[class.ant-collapse-item-disabled]': `nzDisabled || nzCollapsible === 'disabled'`\n  },\n  imports: [NzOutletModule, NzIconModule, NzAnimationCollapseDirective]\n})\nexport class NzCollapsePanelComponent implements AfterViewInit {\n  private readonly ngZone = inject(NgZone);\n  private readonly cdr = inject(ChangeDetectorRef);\n  private readonly destroyRef = inject(DestroyRef);\n  private readonly nzCollapseComponent = inject(NzCollapseComponent, { host: true });\n\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  readonly nzActive = input(false, { transform: booleanAttribute });\n  /**\n   * @deprecated Will be removed in v22, please use `nzCollapsible` with the value `'disabled'` instead.\n   */\n  @Input({ transform: booleanAttribute }) nzDisabled = false;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzShowArrow: boolean = true;\n  @Input() nzExtra?: string | TemplateRef<void>;\n  @Input() nzHeader?: string | TemplateRef<void>;\n  @Input() nzExpandedIcon?: string | TemplateRef<void>;\n  @Input() nzCollapsible?: 'disabled' | 'header' | 'icon';\n  readonly nzActiveChange = output<boolean>();\n\n  /**\n   * @description Actual active state of the panel.\n   */\n  readonly active = linkedSignal(() => this.nzActive());\n\n  readonly collapseHeader = viewChild.required('collapseHeader', { read: ElementRef });\n  readonly collapseIcon = viewChild('collapseIcon', { read: ElementRef });\n\n  constructor() {\n    onConfigChangeEventForComponent(NZ_CONFIG_MODULE_NAME, () => this.cdr.markForCheck());\n\n    this.nzCollapseComponent.addPanel(this);\n    this.destroyRef.onDestroy(() => {\n      this.nzCollapseComponent.removePanel(this);\n    });\n  }\n\n  ngAfterViewInit(): void {\n    const icon = this.collapseIcon();\n    const header = this.collapseHeader();\n    const element =\n      this.nzShowArrow && this.nzCollapsible === 'icon' && icon\n        ? (icon.nativeElement as HTMLElement)\n        : (header.nativeElement as HTMLElement);\n    fromEventOutsideAngular(element, 'click')\n      .pipe(\n        filter(() => !this.nzDisabled && this.nzCollapsible !== 'disabled'),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(() => {\n        this.ngZone.run(() => {\n          this.nzCollapseComponent.click(this);\n        });\n      });\n  }\n\n  activate(active: boolean): void {\n    this.active.set(active);\n    this.nzActiveChange.emit(active);\n  }\n}\n"
  },
  {
    "path": "components/collapse/collapse.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport {\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  inject,\n  Input,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { NzConfigKey, onConfigChangeEventForComponent, WithConfig } from 'ng-zorro-antd/core/config';\nimport type { NzSizeLMSType } from 'ng-zorro-antd/core/types';\n\nimport { NzCollapsePanelComponent } from './collapse-panel.component';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'collapse';\n\n@Component({\n  selector: 'nz-collapse',\n  exportAs: 'nzCollapse',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `<ng-content />`,\n  host: {\n    class: 'ant-collapse',\n    '[class.ant-collapse-icon-placement-start]': `nzExpandIconPosition === 'start'`,\n    '[class.ant-collapse-icon-placement-end]': `nzExpandIconPosition === 'end'`,\n    '[class.ant-collapse-ghost]': `nzGhost`,\n    '[class.ant-collapse-borderless]': '!nzBordered',\n    '[class.ant-collapse-rtl]': `dir() === 'rtl'`,\n    '[class.ant-collapse-small]': `nzSize === 'small'`,\n    '[class.ant-collapse-large]': `nzSize === 'large'`\n  }\n})\nexport class NzCollapseComponent {\n  private cdr = inject(ChangeDetectorRef);\n  protected readonly dir = inject(Directionality).valueSignal;\n\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  @Input({ transform: booleanAttribute }) @WithConfig() nzAccordion: boolean = false;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzBordered: boolean = true;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzGhost: boolean = false;\n  @Input() nzExpandIconPosition: 'start' | 'end' = 'start';\n  @Input() nzSize: NzSizeLMSType = 'middle';\n\n  private listOfNzCollapsePanelComponent: NzCollapsePanelComponent[] = [];\n\n  constructor() {\n    onConfigChangeEventForComponent(NZ_CONFIG_MODULE_NAME, () => this.cdr.markForCheck());\n  }\n\n  addPanel(value: NzCollapsePanelComponent): void {\n    this.listOfNzCollapsePanelComponent.push(value);\n  }\n\n  removePanel(value: NzCollapsePanelComponent): void {\n    this.listOfNzCollapsePanelComponent.splice(this.listOfNzCollapsePanelComponent.indexOf(value), 1);\n  }\n\n  click(collapse: NzCollapsePanelComponent): void {\n    const active = collapse.active();\n    // if accordion mode, close all panels except the clicked one\n    if (this.nzAccordion && !active) {\n      this.listOfNzCollapsePanelComponent\n        .filter(item => item !== collapse && item.active())\n        .forEach(item => item.activate(false));\n    }\n    collapse.activate(!active);\n  }\n}\n"
  },
  {
    "path": "components/collapse/collapse.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzCollapsePanelComponent } from './collapse-panel.component';\nimport { NzCollapseComponent } from './collapse.component';\n\n@NgModule({\n  imports: [NzCollapsePanelComponent, NzCollapseComponent],\n  exports: [NzCollapsePanelComponent, NzCollapseComponent]\n})\nexport class NzCollapseModule {}\n"
  },
  {
    "path": "components/collapse/collapse.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { Component, DebugElement, provideZoneChangeDetection, TemplateRef, ViewChild } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { provideNzNoAnimation } from 'ng-zorro-antd/core/animation';\nimport { provideMockDirectionality } from 'ng-zorro-antd/core/testing';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzCollapsePanelComponent } from './collapse-panel.component';\nimport { NzCollapseComponent } from './collapse.component';\nimport { NzCollapseModule } from './collapse.module';\n\ndescribe('collapse', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [\n        provideNzIconsTesting(),\n        provideNzNoAnimation(),\n        provideZoneChangeDetection(),\n        provideMockDirectionality()\n      ]\n    });\n  });\n\n  describe('collapse basic', () => {\n    let fixture: ComponentFixture<NzTestCollapseBasicComponent>;\n    let testComponent: NzTestCollapseBasicComponent;\n    let collapse: DebugElement;\n    let panels: DebugElement[];\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCollapseBasicComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n      collapse = fixture.debugElement.query(By.directive(NzCollapseComponent));\n      panels = fixture.debugElement.queryAll(By.directive(NzCollapsePanelComponent));\n    });\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n      expect(collapse.nativeElement!.classList).toContain('ant-collapse');\n      expect(panels.every(panel => panel.nativeElement.classList.contains('ant-collapse-item'))).toBe(true);\n    });\n\n    it('should border work', () => {\n      fixture.detectChanges();\n      expect(collapse.nativeElement!.classList).not.toContain('ant-collapse-borderless');\n      testComponent.bordered = false;\n      fixture.detectChanges();\n      expect(collapse.nativeElement!.classList).toContain('ant-collapse-borderless');\n    });\n\n    it('should showArrow work', () => {\n      fixture.detectChanges();\n      expect(panels[0].nativeElement.querySelector('.ant-collapse-arrow').firstElementChild).toBeDefined();\n      testComponent.showArrow = false;\n      fixture.detectChanges();\n      expect(panels[0].nativeElement.querySelector('.ant-collapse-arrow')).toBeNull();\n    });\n\n    it('should active work', () => {\n      fixture.detectChanges();\n      expect(panels[0].nativeElement.classList).not.toContain('ant-collapse-item-active');\n      testComponent.active01 = true;\n      fixture.detectChanges();\n      expect(panels[0].nativeElement.classList).toContain('ant-collapse-item-active');\n      expect(testComponent.active01Change).toHaveBeenCalledTimes(0);\n    });\n\n    it('should click work', () => {\n      fixture.detectChanges();\n      expect(panels[0].nativeElement.classList).not.toContain('ant-collapse-item-active');\n      expect(testComponent.active01).toBe(false);\n      panels[0].nativeElement.querySelector('.ant-collapse-header').click();\n      fixture.detectChanges();\n      expect(testComponent.active01).toBe(true);\n      expect(panels[0].nativeElement.classList).toContain('ant-collapse-item-active');\n      expect(testComponent.active01Change).toHaveBeenCalledTimes(1);\n    });\n\n    it('should disabled work', () => {\n      testComponent.disabled = true;\n      fixture.detectChanges();\n      expect(panels[1].nativeElement.classList).not.toContain('ant-collapse-item-active');\n      expect(testComponent.active02).toBe(false);\n      panels[1].nativeElement.querySelector('.ant-collapse-header').click();\n      fixture.detectChanges();\n      expect(testComponent.active02).toBe(false);\n      expect(panels[1].nativeElement.classList).toContain('ant-collapse-item-disabled');\n      expect(panels[1].nativeElement.classList).not.toContain('ant-collapse-item-active');\n      expect(testComponent.active02Change).toHaveBeenCalledTimes(0);\n    });\n\n    it('should accordion work', () => {\n      testComponent.accordion = true;\n      fixture.detectChanges();\n      expect(panels[0].nativeElement.classList).not.toContain('ant-collapse-item-active');\n      expect(testComponent.active01).toBe(false);\n      panels[0].nativeElement.querySelector('.ant-collapse-header').click();\n      fixture.detectChanges();\n      expect(testComponent.active01).toBe(true);\n      expect(testComponent.active02).toBe(false);\n      expect(panels[0].nativeElement.classList).toContain('ant-collapse-item-active');\n      expect(panels[1].nativeElement.classList).not.toContain('ant-collapse-item-active');\n      expect(testComponent.active01Change).toHaveBeenCalledTimes(1);\n      expect(testComponent.active02Change).toHaveBeenCalledTimes(0);\n      panels[1].nativeElement.querySelector('.ant-collapse-header').click();\n      fixture.detectChanges();\n      expect(testComponent.active01).toBe(false);\n      expect(testComponent.active02).toBe(true);\n      expect(panels[0].nativeElement.classList).not.toContain('ant-collapse-item-active');\n      expect(panels[1].nativeElement.classList).toContain('ant-collapse-item-active');\n      expect(testComponent.active01Change).toHaveBeenCalledTimes(2);\n      expect(testComponent.active02Change).toHaveBeenCalledTimes(1);\n    });\n\n    it('should click to fold up work with accordion', () => {\n      testComponent.accordion = true;\n      fixture.detectChanges();\n      expect(panels[0].nativeElement.classList).not.toContain('ant-collapse-item-active');\n      expect(testComponent.active01).toBe(false);\n      panels[0].nativeElement.querySelector('.ant-collapse-header').click();\n      fixture.detectChanges();\n      panels[1].nativeElement.querySelector('.ant-collapse-header').click();\n      fixture.detectChanges();\n      panels[0].nativeElement.querySelector('.ant-collapse-header').click();\n      fixture.detectChanges();\n      expect(testComponent.active01).toBe(true);\n      expect(testComponent.active02).toBe(false);\n      expect(panels[0].nativeElement.classList).toContain('ant-collapse-item-active');\n      expect(panels[1].nativeElement.classList).not.toContain('ant-collapse-item-active');\n      expect(testComponent.active01Change).toHaveBeenCalledTimes(3);\n      expect(testComponent.active02Change).toHaveBeenCalledTimes(2);\n      panels[0].nativeElement.querySelector('.ant-collapse-header').click();\n      fixture.detectChanges();\n      expect(testComponent.active01).toBe(false);\n      expect(testComponent.active02).toBe(false);\n      expect(panels[0].nativeElement.classList).not.toContain('ant-collapse-item-active');\n      expect(panels[1].nativeElement.classList).not.toContain('ant-collapse-item-active');\n      expect(testComponent.active01Change).toHaveBeenCalledTimes(4);\n      expect(testComponent.active02Change).toHaveBeenCalledTimes(2);\n    });\n\n    it('should header work', () => {\n      fixture.detectChanges();\n      expect(panels[0].nativeElement.querySelector('.ant-collapse-header').innerText).toBe('string');\n    });\n\n    it('should extra work', () => {\n      fixture.detectChanges();\n      expect(panels[0].nativeElement.querySelector('.ant-collapse-extra')).toBeFalsy();\n\n      testComponent.showExtra = 'Extra';\n      fixture.detectChanges();\n      const extraEl = panels[0].nativeElement.querySelector('.ant-collapse-extra');\n      expect(extraEl!).not.toBeFalsy();\n      expect(extraEl!.innerText).toBe('Extra');\n    });\n  });\n\n  describe('collapse template', () => {\n    let fixture: ComponentFixture<NzTestCollapseTemplateComponent>;\n    let panels: DebugElement[];\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCollapseTemplateComponent);\n      fixture.detectChanges();\n      panels = fixture.debugElement.queryAll(By.directive(NzCollapsePanelComponent));\n    });\n\n    it('should header work', () => {\n      fixture.detectChanges();\n      expect(panels[0].nativeElement.querySelector('.ant-collapse-header').innerText).toBe('template');\n    });\n  });\n\n  describe('collapse icon', () => {\n    let fixture: ComponentFixture<NzTestCollapseIconComponent>;\n    let panels: DebugElement[];\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCollapseIconComponent);\n      fixture.detectChanges();\n      panels = fixture.debugElement.queryAll(By.directive(NzCollapsePanelComponent));\n    });\n\n    it('should icon work', () => {\n      fixture.detectChanges();\n      expect(panels[0].nativeElement.querySelector('.anticon-right')).toBeDefined();\n      expect(panels[1].nativeElement.querySelector('.anticon-double-right')).toBeDefined();\n      expect(panels[2].nativeElement.querySelector('.anticon-caret-right')).toBeDefined();\n    });\n  });\n\n  describe('collapse collapsible', () => {\n    let fixture: ComponentFixture<NzTestCollapseCollapsibleComponent>;\n    let panel: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCollapseCollapsibleComponent);\n      fixture.detectChanges();\n      panel = fixture.debugElement.query(By.directive(NzCollapsePanelComponent));\n    });\n\n    it('should only toggle by icon when nzCollapsible is \"icon\"', () => {\n      const headerEl = panel.nativeElement.querySelector('.ant-collapse-header') as HTMLElement;\n      expect(headerEl.classList).toContain('ant-collapse-collapsible-icon');\n      // initial state\n      expect(panel.nativeElement.classList).not.toContain('ant-collapse-item-active');\n\n      // click header text should NOT toggle\n      (panel.nativeElement.querySelector('.ant-collapse-title') as HTMLElement).click();\n      fixture.detectChanges();\n      expect(panel.nativeElement.classList).not.toContain('ant-collapse-item-active');\n\n      // click icon should toggle open\n      (panel.nativeElement.querySelector('.ant-collapse-expand-icon') as HTMLElement).click();\n      fixture.detectChanges();\n      expect(panel.nativeElement.classList).toContain('ant-collapse-item-active');\n\n      // click header text again should NOT toggle\n      (panel.nativeElement.querySelector('.ant-collapse-title') as HTMLElement).click();\n      fixture.detectChanges();\n      expect(panel.nativeElement.classList).toContain('ant-collapse-item-active');\n\n      // click icon should toggle close\n      (panel.nativeElement.querySelector('.ant-collapse-expand-icon') as HTMLElement).click();\n      fixture.detectChanges();\n      expect(panel.nativeElement.classList).not.toContain('ant-collapse-item-active');\n    });\n\n    it('should not toggle when nzCollapsible is \"disabled\"', () => {\n      fixture.componentInstance.collapsible = 'disabled';\n      fixture.detectChanges();\n\n      const header = panel.nativeElement.querySelector('.ant-collapse-header') as HTMLElement;\n      header.click();\n      fixture.detectChanges();\n      expect(panel.nativeElement.classList).not.toContain('ant-collapse-item-active');\n\n      const icon = panel.nativeElement.querySelector('.ant-collapse-expand-icon') as HTMLElement;\n      icon.click();\n      fixture.detectChanges();\n      expect(panel.nativeElement.classList).not.toContain('ant-collapse-item-active');\n    });\n\n    it('should toggle by header when nzCollapsible is \"header\"', () => {\n      // Recreate fixture and set mode BEFORE first detectChanges so listeners bind to header\n      const localFixture = TestBed.createComponent(NzTestCollapseCollapsibleComponent);\n      localFixture.componentInstance.collapsible = 'header';\n      localFixture.detectChanges();\n      const localPanel = localFixture.debugElement.query(By.directive(NzCollapsePanelComponent));\n\n      const header = localPanel.nativeElement.querySelector('.ant-collapse-header') as HTMLElement;\n      expect(header.classList).toContain('ant-collapse-collapsible-header');\n      expect(localPanel.nativeElement.classList).not.toContain('ant-collapse-item-active');\n\n      // click header toggles\n      (localPanel.nativeElement.querySelector('.ant-collapse-title') as HTMLElement).click();\n      localFixture.detectChanges();\n      expect(localPanel.nativeElement.classList).toContain('ant-collapse-item-active');\n\n      // click header toggles again (close)\n      (localPanel.nativeElement.querySelector('.ant-collapse-title') as HTMLElement).click();\n      localFixture.detectChanges();\n      expect(localPanel.nativeElement.classList).not.toContain('ant-collapse-item-active');\n\n      // clicking icon (which is inside header) should also toggle because header listens\n      (localPanel.nativeElement.querySelector('.ant-collapse-expand-icon') as HTMLElement).click();\n      localFixture.detectChanges();\n      expect(localPanel.nativeElement.classList).toContain('ant-collapse-item-active');\n    });\n  });\n\n  describe('RTL', () => {\n    it('should className correct on dir change', () => {\n      const fixture = TestBed.createComponent(NzTestCollapseBasicComponent);\n      const directionality = TestBed.inject(Directionality);\n\n      const collapse = fixture.debugElement.query(By.directive(NzCollapseComponent));\n\n      fixture.detectChanges();\n      expect(collapse.nativeElement!.classList).not.toContain('ant-collapse-rtl');\n\n      directionality.valueSignal.set('rtl');\n      fixture.detectChanges();\n      expect(collapse.nativeElement!.classList).toContain('ant-collapse-rtl');\n    });\n  });\n\n  describe('collapse size', () => {\n    let fixture: ComponentFixture<NzTestCollapseSizeSpecComponent>;\n    let collapse: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCollapseSizeSpecComponent);\n      fixture.detectChanges();\n      collapse = fixture.debugElement.query(By.directive(NzCollapseComponent));\n    });\n\n    it('should apply correct host classes for nzSize', () => {\n      // default is middle: no small/large classes\n      expect(collapse.nativeElement!.classList).not.toContain('ant-collapse-small');\n      expect(collapse.nativeElement!.classList).not.toContain('ant-collapse-large');\n\n      // small\n      fixture.componentInstance.size = 'small';\n      fixture.detectChanges();\n      expect(collapse.nativeElement!.classList).toContain('ant-collapse-small');\n      expect(collapse.nativeElement!.classList).not.toContain('ant-collapse-large');\n\n      // large\n      fixture.componentInstance.size = 'large';\n      fixture.detectChanges();\n      expect(collapse.nativeElement!.classList).toContain('ant-collapse-large');\n      expect(collapse.nativeElement!.classList).not.toContain('ant-collapse-small');\n    });\n  });\n});\n\n@Component({\n  selector: 'nz-test-basic-collapse',\n  imports: [NzCollapseModule],\n  template: `\n    <ng-template #headerTemplate>template</ng-template>\n    <nz-collapse [nzAccordion]=\"accordion\" [nzBordered]=\"bordered\">\n      <nz-collapse-panel\n        [(nzActive)]=\"active01\"\n        (nzActiveChange)=\"active01Change($event)\"\n        [nzHeader]=\"header\"\n        [nzShowArrow]=\"showArrow\"\n        [nzExtra]=\"showExtra\"\n      >\n        <p>Panel01</p>\n      </nz-collapse-panel>\n      <nz-collapse-panel [(nzActive)]=\"active02\" (nzActiveChange)=\"active02Change($event)\" [nzDisabled]=\"disabled\">\n        <p>Panel02</p>\n      </nz-collapse-panel>\n    </nz-collapse>\n  `\n})\nexport class NzTestCollapseBasicComponent {\n  @ViewChild('headerTemplate', { static: false }) headerTemplate!: TemplateRef<void>;\n  accordion = false;\n  bordered = true;\n  disabled = false;\n  active01 = false;\n  active02 = false;\n  showArrow = true;\n  showExtra = '';\n  header = 'string';\n  active01Change = jasmine.createSpy<NzSafeAny>('active01 callback');\n  active02Change = jasmine.createSpy<NzSafeAny>('active02 callback');\n}\n\n@Component({\n  imports: [NzCollapseModule],\n  template: `\n    <ng-template #headerTemplate>template</ng-template>\n    <nz-collapse>\n      <nz-collapse-panel [nzHeader]=\"headerTemplate\">\n        <p>Panel01</p>\n      </nz-collapse-panel>\n    </nz-collapse>\n  `\n})\nexport class NzTestCollapseTemplateComponent {}\n\n@Component({\n  imports: [NzIconModule, NzCollapseModule],\n  template: `\n    <nz-collapse>\n      <nz-collapse-panel>\n        <p>Panel01</p>\n      </nz-collapse-panel>\n      <nz-collapse-panel nzExpandedIcon=\"double-right\">\n        <p>Panel02</p>\n      </nz-collapse-panel>\n      <nz-collapse-panel [nzExpandedIcon]=\"expandedIcon\">\n        <p>Panel01</p>\n      </nz-collapse-panel>\n      <ng-template #expandedIcon>\n        <nz-icon nzType=\"caret-right\" class=\"ant-collapse-arrow\" />\n      </ng-template>\n    </nz-collapse>\n  `\n})\nexport class NzTestCollapseIconComponent {}\n\n@Component({\n  imports: [NzCollapseModule],\n  template: `\n    <nz-collapse>\n      <nz-collapse-panel\n        [(nzActive)]=\"active\"\n        [nzCollapsible]=\"collapsible\"\n        [nzShowArrow]=\"showArrow\"\n        nzHeader=\"Header\"\n      >\n        <p>Content</p>\n      </nz-collapse-panel>\n    </nz-collapse>\n  `\n})\nexport class NzTestCollapseCollapsibleComponent {\n  active = false;\n  collapsible: 'disabled' | 'header' | 'icon' = 'icon';\n  showArrow = true;\n}\n\n@Component({\n  imports: [NzCollapseModule],\n  template: `\n    <nz-collapse [nzSize]=\"size\">\n      <nz-collapse-panel nzHeader=\"header\" nzActive>\n        <p>content</p>\n      </nz-collapse-panel>\n    </nz-collapse>\n  `\n})\nexport class NzTestCollapseSizeSpecComponent {\n  size: 'small' | 'middle' | 'large' = 'middle';\n}\n"
  },
  {
    "path": "components/collapse/demo/accordion.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 手风琴\n  en-US: Accordion\n---\n\n## zh-CN\n\n手风琴，每次只打开一个tab。默认打开第一个。\n\n## en-US\n\nAccordion mode, only one panel can be expanded at a time. The first panel will be expanded by default.\n"
  },
  {
    "path": "components/collapse/demo/accordion.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCollapseModule } from 'ng-zorro-antd/collapse';\n\n@Component({\n  selector: 'nz-demo-collapse-accordion',\n  imports: [NzCollapseModule],\n  template: `\n    <nz-collapse nzAccordion>\n      @for (panel of panels; track panel) {\n        <nz-collapse-panel [nzHeader]=\"panel.name\" [nzActive]=\"panel.active\">\n          <p>{{ panel.name }} content</p>\n        </nz-collapse-panel>\n      }\n    </nz-collapse>\n  `\n})\nexport class NzDemoCollapseAccordionComponent {\n  panels = [\n    {\n      active: true,\n      name: 'This is panel header 1',\n      childPanel: [\n        {\n          active: false,\n          name: 'This is panel header 1-1'\n        }\n      ]\n    },\n    {\n      active: false,\n      name: 'This is panel header 2'\n    },\n    {\n      active: false,\n      name: 'This is panel header 3'\n    }\n  ];\n}\n"
  },
  {
    "path": "components/collapse/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 折叠面板\n  en-US: Collapse\n---\n\n## zh-CN\n\n可以同时展开多个面板，这个例子默认展开了第一个。\n\n## en-US\n\nMore than one panel can be expanded at a time, the first panel is initialized to be active in this case.\n"
  },
  {
    "path": "components/collapse/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCollapseModule } from 'ng-zorro-antd/collapse';\n\n@Component({\n  selector: 'nz-demo-collapse-basic',\n  imports: [NzCollapseModule],\n  template: `\n    <nz-collapse>\n      @for (panel of panels; track panel) {\n        <nz-collapse-panel [nzHeader]=\"panel.name\" [nzActive]=\"panel.active\" [nzDisabled]=\"panel.disabled\">\n          <p style=\"margin:0;\">\n            A dog is a type of domesticated animal. Known for its loyalty and faithfulness, it can be found as a welcome\n            guest in many households across the world.\n          </p>\n        </nz-collapse-panel>\n      }\n    </nz-collapse>\n  `\n})\nexport class NzDemoCollapseBasicComponent {\n  panels = [\n    {\n      active: true,\n      name: 'This is panel header 1',\n      disabled: false\n    },\n    {\n      active: false,\n      disabled: false,\n      name: 'This is panel header 2'\n    },\n    {\n      active: false,\n      disabled: true,\n      name: 'This is panel header 3'\n    }\n  ];\n}\n"
  },
  {
    "path": "components/collapse/demo/borderless.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 简洁风格\n  en-US: Borderless\n---\n\n## zh-CN\n\n一套没有边框的简洁样式。\n\n## en-US\n\nA borderless style of Collapse.\n"
  },
  {
    "path": "components/collapse/demo/borderless.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCollapseModule } from 'ng-zorro-antd/collapse';\n\n@Component({\n  selector: 'nz-demo-collapse-borderless',\n  imports: [NzCollapseModule],\n  template: `\n    <nz-collapse [nzBordered]=\"false\">\n      @for (panel of panels; track panel) {\n        <nz-collapse-panel [nzHeader]=\"panel.name\" [nzActive]=\"panel.active\">\n          <p>{{ panel.name }} content</p>\n        </nz-collapse-panel>\n      }\n    </nz-collapse>\n  `\n})\nexport class NzDemoCollapseBorderlessComponent {\n  panels = [\n    {\n      active: true,\n      disabled: false,\n      name: 'This is panel header 1',\n      childPannel: [\n        {\n          active: false,\n          disabled: true,\n          name: 'This is panel header 1-1'\n        }\n      ]\n    },\n    {\n      active: false,\n      disabled: true,\n      name: 'This is panel header 2'\n    },\n    {\n      active: false,\n      disabled: false,\n      name: 'This is panel header 3'\n    }\n  ];\n}\n"
  },
  {
    "path": "components/collapse/demo/collapsible.md",
    "content": "---\norder: 8\nversion: 20.2.0\ntitle:\n  zh-CN: 可折叠\n  en-US: Collapsible\n---\n\n## zh-CN\n\n通过 `nzCollapsible` 属性，可以设置面板的可折叠触发区域\n\n## en-US\n\nSpecify the trigger area of collapsible by `nzCollapsible`.\n"
  },
  {
    "path": "components/collapse/demo/collapsible.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCollapseModule } from 'ng-zorro-antd/collapse';\nimport { NzFlexModule } from 'ng-zorro-antd/flex';\n\n@Component({\n  selector: 'nz-demo-collapse-collapsible',\n  imports: [NzCollapseModule, NzFlexModule],\n  template: `\n    <div nz-flex nzVertical nzWrap=\"wrap\" [nzGap]=\"16\">\n      <nz-collapse>\n        <nz-collapse-panel nzHeader=\"This is panel with header collapsible\" nzCollapsible=\"header\">\n          <p style=\"margin:0;\">\n            A dog is a type of domesticated animal. Known for its loyalty and faithfulness, it can be found as a welcome\n            guest in many households across the world.\n          </p>\n        </nz-collapse-panel>\n      </nz-collapse>\n      <nz-collapse>\n        <nz-collapse-panel nzHeader=\"This is panel with icon collapsible\" nzCollapsible=\"icon\">\n          <p style=\"margin:0;\">\n            A dog is a type of domesticated animal. Known for its loyalty and faithfulness, it can be found as a welcome\n            guest in many households across the world.\n          </p>\n        </nz-collapse-panel>\n      </nz-collapse>\n      <nz-collapse>\n        <nz-collapse-panel nzHeader=\"This is panel with disabled collapsible\" nzCollapsible=\"disabled\">\n          <p style=\"margin:0;\">\n            A dog is a type of domesticated animal. Known for its loyalty and faithfulness, it can be found as a welcome\n            guest in many households across the world.\n          </p>\n        </nz-collapse-panel>\n      </nz-collapse>\n    </div>\n  `\n})\nexport class NzDemoCollapseCollapsibleComponent {}\n"
  },
  {
    "path": "components/collapse/demo/custom.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 自定义面板\n  en-US: Custom Panel\n---\n\n## zh-CN\n\n自定义各个面板的背景色、圆角、边距和图标。\n\n## en-US\n\nCustomize the background, border, margin and icon styles for each panel.\n"
  },
  {
    "path": "components/collapse/demo/custom.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCollapseModule } from 'ng-zorro-antd/collapse';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-demo-collapse-custom',\n  imports: [NzIconModule, NzCollapseModule],\n  template: `\n    <nz-collapse [nzBordered]=\"false\">\n      @for (panel of panels; track panel) {\n        <nz-collapse-panel\n          #p\n          [nzHeader]=\"panel.name\"\n          [nzActive]=\"panel.active\"\n          [nzExpandedIcon]=\"!$first ? panel.icon || expandedIcon : undefined\"\n        >\n          <p>{{ panel.name }} content</p>\n          <ng-template #expandedIcon let-active>\n            {{ active }}\n            <nz-icon nzType=\"caret-right\" class=\"ant-collapse-arrow\" [nzRotate]=\"p.active() ? 90 : -90\" />\n          </ng-template>\n        </nz-collapse-panel>\n      }\n    </nz-collapse>\n  `,\n  styles: `\n    nz-collapse {\n      background: transparent;\n    }\n\n    nz-collapse-panel {\n      margin-bottom: 24px;\n      background: rgba(0, 0, 0, 0.02);\n      border-radius: 8px !important;\n      border: none !important;\n    }\n  `\n})\nexport class NzDemoCollapseCustomComponent {\n  readonly panels = [\n    {\n      active: true,\n      disabled: false,\n      name: 'This is panel header 1'\n    },\n    {\n      active: false,\n      disabled: true,\n      name: 'This is panel header 2',\n      icon: 'double-right'\n    },\n    {\n      active: false,\n      disabled: false,\n      name: 'This is panel header 3'\n    }\n  ];\n}\n"
  },
  {
    "path": "components/collapse/demo/extra.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 额外节点\n  en-US: Extra Node\n---\n\n## zh-CN\n\n你可以通过 `nzExtra` 来指定面板右上角的额外内容。\n\n## en-US\n\nYou can use `nzExtra` to put extra elements in the top right corner.\n"
  },
  {
    "path": "components/collapse/demo/extra.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCollapseModule } from 'ng-zorro-antd/collapse';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\n@Component({\n  selector: 'nz-demo-collapse-extra',\n  imports: [FormsModule, NzCollapseModule, NzIconModule, NzSelectModule],\n  template: `\n    <nz-collapse [nzExpandIconPosition]=\"expandIconPosition\">\n      @for (panel of panels; track panel) {\n        <nz-collapse-panel\n          [nzHeader]=\"panel.name\"\n          [nzActive]=\"panel.active\"\n          [nzExtra]=\"extraTpl\"\n          [nzDisabled]=\"panel.disabled\"\n        >\n          <p style=\"margin:0;\">\n            A dog is a type of domesticated animal. Known for its loyalty and faithfulness, it can be found as a welcome\n            guest in many households across the world.\n          </p>\n        </nz-collapse-panel>\n      }\n    </nz-collapse>\n    <ng-template #extraTpl>\n      <!-- You can use stopPropagation if you don't want the panel to toggle -->\n      <nz-icon nzType=\"setting\" (click)=\"$event.stopPropagation()\" />\n    </ng-template>\n    <br />\n    <span>Expand Icon Position: </span>\n    <nz-select [(ngModel)]=\"expandIconPosition\">\n      <nz-option nzValue=\"start\" nzLabel=\"start\" />\n      <nz-option nzValue=\"end\" nzLabel=\"end\" />\n    </nz-select>\n  `\n})\nexport class NzDemoCollapseExtraComponent {\n  expandIconPosition: 'start' | 'end' = 'start';\n\n  panels = [\n    {\n      active: true,\n      name: 'This is panel header 1',\n      disabled: false\n    },\n    {\n      active: false,\n      disabled: false,\n      name: 'This is panel header 2'\n    },\n    {\n      active: false,\n      disabled: true,\n      name: 'This is panel header 3'\n    }\n  ];\n}\n"
  },
  {
    "path": "components/collapse/demo/ghost.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 幽灵折叠面板\n  en-US: Ghost Collapse\n---\n\n## zh-CN\n\n将折叠面板的背景变成透明。\n\n## en-US\n\nMaking collapse's background to transparent.\n"
  },
  {
    "path": "components/collapse/demo/ghost.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCollapseModule } from 'ng-zorro-antd/collapse';\n\n@Component({\n  selector: 'nz-demo-collapse-ghost',\n  imports: [NzCollapseModule],\n  template: `\n    <nz-collapse nzGhost>\n      @for (panel of panels; track panel) {\n        <nz-collapse-panel [nzHeader]=\"panel.name\" [nzActive]=\"panel.active\" [nzDisabled]=\"panel.disabled\">\n          <p style=\"margin:0;\">\n            A dog is a type of domesticated animal. Known for its loyalty and faithfulness, it can be found as a welcome\n            guest in many households across the world.\n          </p>\n        </nz-collapse-panel>\n      }\n    </nz-collapse>\n  `\n})\nexport class NzDemoCollapseGhostComponent {\n  panels = [\n    {\n      active: true,\n      name: 'This is panel header 1',\n      disabled: false\n    },\n    {\n      active: false,\n      disabled: false,\n      name: 'This is panel header 2'\n    },\n    {\n      active: false,\n      disabled: true,\n      name: 'This is panel header 3'\n    }\n  ];\n}\n"
  },
  {
    "path": "components/collapse/demo/mix.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 面板嵌套\n  en-US: Nested panel\n---\n\n## zh-CN\n\n嵌套折叠面板。\n\n## en-US\n\n`Collapse` is nested inside the `Collapse`.\n"
  },
  {
    "path": "components/collapse/demo/mix.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCollapseModule } from 'ng-zorro-antd/collapse';\n\n@Component({\n  selector: 'nz-demo-collapse-mix',\n  imports: [NzCollapseModule],\n  template: `\n    <nz-collapse>\n      @for (panel of panels; track panel) {\n        <nz-collapse-panel [nzHeader]=\"panel.name\" [nzActive]=\"panel.active\">\n          <p>{{ panel.name }}</p>\n          @if (panel.childPanel && panel.childPanel.length > 0) {\n            <div>\n              <nz-collapse>\n                @for (childPanel of panel.childPanel; track childPanel) {\n                  <nz-collapse-panel [nzHeader]=\"childPanel.name\" [nzActive]=\"childPanel.active\">\n                    <p>\n                      A dog is a type of domesticated animal. Known for its loyalty and faithfulness, it can be found as\n                      a welcome guest in many households across the world.\n                    </p>\n                  </nz-collapse-panel>\n                }\n              </nz-collapse>\n            </div>\n          }\n        </nz-collapse-panel>\n      }\n    </nz-collapse>\n  `\n})\nexport class NzDemoCollapseMixComponent {\n  panels = [\n    {\n      active: true,\n      disabled: false,\n      name: 'This is panel header 1',\n      childPanel: [\n        {\n          active: true,\n          name: 'This is panel header 1-1'\n        },\n        {\n          active: false,\n          name: 'This is panel header 1-2'\n        }\n      ]\n    },\n    {\n      active: false,\n      disabled: true,\n      name: 'This is panel header 2'\n    },\n    {\n      active: false,\n      disabled: false,\n      name: 'This is panel header 3'\n    }\n  ];\n}\n"
  },
  {
    "path": "components/collapse/demo/noarrow.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 隐藏箭头\n  en-US: No arrow\n---\n\n## zh-CN\n\n你可以通过 `[nzShowArrow]=\"false\"` 隐藏 `nz-collapse-panel` 组件的箭头图标。\n\n## en-US\n\nYou can disable showing arrow icon by passing `[nzShowArrow]=\"false\"` to `nz-collapse-panel` component.\n"
  },
  {
    "path": "components/collapse/demo/noarrow.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCollapseModule } from 'ng-zorro-antd/collapse';\n\n@Component({\n  selector: 'nz-demo-collapse-noarrow',\n  imports: [NzCollapseModule],\n  template: `\n    <nz-collapse>\n      @for (panel of panels; track panel) {\n        <nz-collapse-panel [nzHeader]=\"panel.name\" [nzActive]=\"panel.active\" [nzShowArrow]=\"panel.arrow\">\n          <p style=\"margin:0;\">\n            A dog is a type of domesticated animal. Known for its loyalty and faithfulness, it can be found as a welcome\n            guest in many households across the world.\n          </p>\n        </nz-collapse-panel>\n      }\n    </nz-collapse>\n  `\n})\nexport class NzDemoCollapseNoarrowComponent {\n  panels = [\n    {\n      active: true,\n      name: 'This is panel header 1',\n      arrow: true\n    },\n    {\n      active: false,\n      arrow: false,\n      name: 'This is panel header 2'\n    }\n  ];\n}\n"
  },
  {
    "path": "components/collapse/demo/size.md",
    "content": "---\norder: 1\nversion: 20.2.0\ntitle:\n  zh-CN: 大小\n  en-US: Size\n---\n\n## zh-CN\n\n设置折叠面板的大小。\n通过设置 `nzSize` 为 `large` 或 `small` 分别把折叠面板设为大、小尺寸。若不设置则尺寸默认为中。\n\n## en-US\n\nSet the size of the collapse.\nIf a large or small collapse is desired, set the `nzSize` property to either `large` or `small` respectively. Omit the `nzSize` property for a collapse with the default size.\n"
  },
  {
    "path": "components/collapse/demo/size.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCollapseModule } from 'ng-zorro-antd/collapse';\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\n\n@Component({\n  selector: 'nz-demo-collapse-size',\n  imports: [NzCollapseModule, NzDividerModule],\n  template: `\n    <nz-divider nzText=\"Default Size\" nzOrientation=\"left\" />\n    <nz-collapse>\n      <nz-collapse-panel nzHeader=\"This is default size panel header\" nzActive>\n        <p style=\"margin:0;\">\n          A dog is a type of domesticated animal. Known for its loyalty and faithfulness, it can be found as a welcome\n          guest in many households across the world.\n        </p>\n      </nz-collapse-panel>\n    </nz-collapse>\n    <nz-divider nzText=\"Small Size\" nzOrientation=\"left\" />\n    <nz-collapse nzSize=\"small\">\n      <nz-collapse-panel nzHeader=\"This is small size panel header\" nzActive>\n        <p style=\"margin:0;\">\n          A dog is a type of domesticated animal. Known for its loyalty and faithfulness, it can be found as a welcome\n          guest in many households across the world.\n        </p>\n      </nz-collapse-panel>\n    </nz-collapse>\n    <nz-divider nzText=\"Large Size\" nzOrientation=\"left\" />\n    <nz-collapse nzSize=\"large\">\n      <nz-collapse-panel nzHeader=\"This is large size panel header\" nzActive>\n        <p style=\"margin:0;\">\n          A dog is a type of domesticated animal. Known for its loyalty and faithfulness, it can be found as a welcome\n          guest in many households across the world.\n        </p>\n      </nz-collapse-panel>\n    </nz-collapse>\n  `\n})\nexport class NzDemoCollapseSizeComponent {}\n"
  },
  {
    "path": "components/collapse/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Display\ntitle: Collapse\ncols: 1\ncover: 'https://gw.alipayobjects.com/zos/alicdn/IxH16B9RD/Collapse.svg'\ndescription: A content area which can be collapsed and expanded.\n---\n\n## When To Use\n\n- Can be used to group or hide complex regions to keep the page clean.\n- `Accordion` is a special kind of `Collapse`, which allows only one panel to be expanded at a time.\n\n## API\n\n### nz-collapse\n\n| Property                 | Description                                                 | Type                 | Default    | Global Config | Version |\n| ------------------------ | ----------------------------------------------------------- | -------------------- | ---------- | ------------- | ------- |\n| `[nzAccordion]`          | Accordion mode                                              | `boolean`            | `false`    | ✅            |\n| `[nzBordered]`           | Set border style                                            | `boolean`            | `true`     | ✅            |\n| `[nzGhost]`              | Make the collapse borderless and its background transparent | `boolean`            | `false`    | ✅            |\n| `[nzExpandIconPosition]` | Set expand icon position                                    | `'start' \\| 'end'`   | `'start'`  | -             |\n| `[nzSize]`               | Set size of collapse                                        | `'small' \\| 'large'` | `'middle'` | -             | 20.2.0  |\n\n### nz-collapse-panel\n\n| Property           | Description                                 | Type                               | Default | Global Config | Version |\n| ------------------ | ------------------------------------------- | ---------------------------------- | ------- | ------------- | ------- |\n| `[nzDisabled]`     | If `true`, panel cannot be opened or closed | `boolean`                          | `false` | -             |\n| `[nzHeader]`       | Title of the panel                          | `string \\| TemplateRef<void>`      | -       | -             |\n| `[nzExpandedIcon]` | Customize an icon for toggle                | `string \\| TemplateRef<void>`      | -       | -             |\n| `[nzExtra]`        | Extra element in the corner                 | `string \\| TemplateRef<void>`      | -       | -             |\n| `[nzShowArrow]`    | Display arrow or not                        | `boolean`                          | `true`  | ✅            |\n| `[nzActive]`       | Active status of panel, double binding      | `boolean`                          | -       | -             |\n| `[nzCollapsible]`  | Set collapsible trigger area                | `'header' \\| 'icon' \\| 'disabled'` | -       | -             | 20.2.0  |\n| `(nzActiveChange)` | Callback function of the active status      | `EventEmitter<boolean>`            | -       | -             |\n"
  },
  {
    "path": "components/collapse/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ntype: 数据展示\ntitle: Collapse\nsubtitle: 折叠面板\ncols: 1\ncover: 'https://gw.alipayobjects.com/zos/alicdn/IxH16B9RD/Collapse.svg'\ndescription: 可以折叠/展开的内容区域。\n---\n\n## 何时使用\n\n- 对复杂区域进行分组和隐藏，保持页面的整洁。\n- `手风琴` 是一种特殊的折叠面板，只允许单个内容区域展开。\n\n## API\n\n### nz-collapse\n\n| 参数                     | 说明                   | 类型                 | 默认值     | 全局配置 | 版本   |\n| ------------------------ | ---------------------- | -------------------- | ---------- | -------- | ------ |\n| `[nzAccordion]`          | 是否每次只打开一个 tab | `boolean`            | `false`    | ✅       |\n| `[nzBordered]`           | 是否有边框             | `boolean`            | `true`     | ✅       |\n| `[nzGhost]`              | 使折叠面板透明且无边框 | `boolean`            | `false`    | ✅       |\n| `[nzExpandIconPosition]` | 设置图标位置           | `'start' \\| 'end'`   | `'start'`  | -        |\n| `[nzSize]`               | 设置折叠面板大小       | `'small' \\| 'large'` | `'middle'` | -        | 20.2.0 |\n\n### nz-collapse-panel\n\n| 参数               | 说明                                       | 类型                               | 默认值  | 全局配置 | 版本   |\n| ------------------ | ------------------------------------------ | ---------------------------------- | ------- | -------- | ------ |\n| `[nzDisabled]`     | 禁用后的面板展开与否将无法通过用户交互改变 | `boolean`                          | `false` | -        |\n| `[nzHeader]`       | 面板头内容                                 | `string \\| TemplateRef<void>`      | -       | -        |\n| `[nzExpandedIcon]` | 自定义切换图标                             | `string \\| TemplateRef<void>`      | -       | -        |\n| `[nzExtra]`        | 自定义渲染每个面板右上角的内容             | `string \\| TemplateRef<void>`      | -       | -        |\n| `[nzShowArrow]`    | 是否展示箭头                               | `boolean`                          | `true`  | ✅       |\n| `[nzActive]`       | 面板是否展开，可双向绑定                   | `boolean`                          | -       | -        |\n| `[nzCollapsible]`  | 设置可折叠触发区域                         | `'header' \\| 'icon' \\| 'disabled'` | -       | -        | 20.2.0 |\n| `(nzActiveChange)` | 面板展开回调                               | `EventEmitter<boolean>`            | -       | -        |\n"
  },
  {
    "path": "components/collapse/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/collapse/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/collapse/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './collapse-panel.component';\nexport * from './collapse.component';\nexport * from './collapse.module';\n"
  },
  {
    "path": "components/collapse/style/entry.less",
    "content": "@import './index.less';\n@import './patch.less';\n"
  },
  {
    "path": "components/collapse/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@collapse-prefix-cls: ~'@{ant-prefix}-collapse';\n\n.@{collapse-prefix-cls} {\n  .reset-component();\n\n  @font-height: floor(@font-size-base * @line-height-base);\n\n  background-color: @collapse-header-bg;\n  border: @border-width-base @border-style-base @border-color-base;\n  border-radius: @collapse-panel-border-radius;\n\n  &-rtl {\n    direction: rtl;\n  }\n\n  & > &-item {\n    border-bottom: @border-width-base @border-style-base @border-color-base;\n\n    &:first-child {\n      &,\n      & > .@{collapse-prefix-cls}-header {\n        border-radius: @collapse-panel-border-radius @collapse-panel-border-radius 0 0;\n      }\n    }\n\n    &:last-child {\n      &,\n      & > .@{collapse-prefix-cls}-header {\n        border-radius: 0 0 @collapse-panel-border-radius @collapse-panel-border-radius;\n      }\n    }\n\n    > .@{collapse-prefix-cls}-header {\n      position: relative; // Compatible with old version of antd, should remove in next version\n      display: flex;\n      flex-wrap: nowrap;\n      align-items: flex-start;\n      padding: @collapse-header-padding;\n      color: @heading-color;\n      line-height: @line-height-base;\n      cursor: pointer;\n      transition: all @animation-duration-slow, visibility 0s;\n\n      > .@{collapse-prefix-cls}-title {\n        flex: auto;\n      }\n\n      // >>>>> Arrow\n      .@{collapse-prefix-cls}-expand-icon {\n        display: flex;\n        align-items: center;\n        height: @font-height;\n        margin-inline-end: @margin-sm;\n      }\n\n      .@{collapse-prefix-cls}-arrow {\n        font-size: @font-size-icon;\n        // when `transform: rotate()` is applied to icon's root element\n        transition: transform @animation-duration-slow;\n        // when `transform: rotate()` is applied to icon's child element\n        svg {\n          transition: transform @animation-duration-slow;\n        }\n      }\n\n      // >>>>> Text\n      .@{collapse-prefix-cls}-title {\n        margin-inline-end: auto;\n      }\n\n      &:focus-visible {\n        outline: @line-width-focus solid @border-color-primary;\n        outline-offset: 1px;\n        transition: outline-offset 0s, outline 0s;\n      }\n    }\n\n    .@{collapse-prefix-cls}-collapsible-header {\n      cursor: default;\n\n      .@{collapse-prefix-cls}-title {\n        flex: none;\n        cursor: pointer;\n      }\n\n      .@{collapse-prefix-cls}-expand-icon {\n        cursor: pointer;\n      }\n    }\n\n    .@{collapse-prefix-cls}-collapsible-icon {\n      cursor: unset;\n\n      .@{collapse-prefix-cls}-expand-icon {\n        cursor: pointer;\n      }\n    }\n\n    &.@{collapse-prefix-cls}-no-arrow {\n      > .@{collapse-prefix-cls}-header {\n        padding-left: @padding-sm;\n      }\n    }\n  }\n\n  &-panel {\n    color: @text-color;\n    background-color: @collapse-content-bg;\n    border-top: @border-width-base @border-style-base @border-color-base;\n\n    & > .@{collapse-prefix-cls}-body {\n      padding: @collapse-content-padding;\n    }\n\n    &-hidden {\n      display: none;\n    }\n  }\n\n  &-small {\n    > .@{collapse-prefix-cls}-item {\n      > .@{collapse-prefix-cls}-header {\n        padding: @padding-xs @padding-sm;\n        padding-inline-start: @padding-xs;\n      }\n\n      > .@{collapse-prefix-cls}-expand-icon {\n        // Arrow offset\n        margin-inline-end: calc(@padding-sm - @padding-xs);\n      }\n\n      > .@{collapse-prefix-cls}-panel > .@{collapse-prefix-cls}-body {\n        padding: @padding-sm;\n      }\n    }\n  }\n\n  &-large {\n    > .@{collapse-prefix-cls}-item {\n      font-size: @font-size-lg;\n      line-height: @line-height-lg;\n\n      > .@{collapse-prefix-cls}-header {\n        padding: @padding-md @padding-lg;\n        padding-inline-start: @padding-md;\n      }\n\n      > .@{collapse-prefix-cls}-panel > .@{collapse-prefix-cls}-body {\n        padding: @padding-lg;\n      }\n    }\n  }\n\n  &-item:last-child {\n    border-bottom: 0;\n\n    > .@{collapse-prefix-cls}-panel {\n      border-radius: 0 0 @collapse-panel-border-radius @collapse-panel-border-radius;\n    }\n  }\n\n  & &-item-disabled > &-header {\n    &,\n    & > .arrow {\n      color: @disabled-color;\n      cursor: not-allowed;\n    }\n  }\n\n  // ========================== Icon Placement ==========================\n  &-icon-placement-end {\n    & > .@{collapse-prefix-cls}-item {\n      > .@{collapse-prefix-cls}-header {\n        .@{collapse-prefix-cls}-expand-icon {\n          order: 1;\n          margin-inline-end: 0;\n          margin-inline-start: @margin-sm;\n        }\n      }\n    }\n  }\n\n  &-borderless {\n    background-color: @collapse-header-bg;\n    border: 0;\n\n    > .@{collapse-prefix-cls}-item {\n      border-bottom: 1px solid @border-color-base;\n    }\n\n    > .@{collapse-prefix-cls}-item:last-child,\n    > .@{collapse-prefix-cls}-item:last-child > .@{collapse-prefix-cls}-header {\n      border-radius: 0;\n    }\n\n    > .@{collapse-prefix-cls}-item:last-child {\n      border-bottom: 0;\n    }\n\n    > .@{collapse-prefix-cls}-item > .@{collapse-prefix-cls}-panel {\n      background-color: transparent;\n      border-top: 0;\n    }\n\n    > .@{collapse-prefix-cls}-item > .@{collapse-prefix-cls}-panel > .@{collapse-prefix-cls}-body {\n      padding: @padding-xss 12px @padding-md;\n    }\n  }\n\n  &-ghost {\n    background-color: transparent;\n    border: 0;\n\n    > .@{collapse-prefix-cls}-item {\n      border-bottom: 0;\n\n      > .@{collapse-prefix-cls}-panel {\n        background-color: transparent;\n        border: 0;\n\n        > .@{collapse-prefix-cls}-body {\n          padding-block: @padding-sm;\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/collapse/style/patch.less",
    "content": "nz-collapse {\n  display: block;\n}\n\nnz-collapse-panel {\n  display: block;\n}\n"
  },
  {
    "path": "components/color-picker/color-block.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, DebugElement, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { NzColorBlockComponent, NzColorPickerModule } from 'ng-zorro-antd/color-picker';\nimport { NzSizeLDSType } from 'ng-zorro-antd/core/types';\n\ndescribe('color-block', () => {\n  let fixture: ComponentFixture<NzTestColorBlockComponent>;\n  let component: NzTestColorBlockComponent;\n  let resultEl: DebugElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzTestColorBlockComponent);\n    fixture.detectChanges();\n    component = fixture.componentInstance;\n    resultEl = fixture.debugElement.query(By.directive(NzColorBlockComponent));\n  });\n\n  it('color-block basic', () => {\n    fixture.detectChanges();\n    const colorDom = resultEl.nativeElement.querySelector('.ant-color-picker-color-block-inner');\n    expect(colorDom.style.backgroundColor).toBe('rgb(22, 119, 255)');\n  });\n\n  it('color-block color', () => {\n    component.nzColor = '#ff6600';\n    fixture.detectChanges();\n    expect(resultEl.nativeElement.querySelector('.ant-color-picker-color-block-inner').style.backgroundColor).toBe(\n      'rgb(255, 102, 0)'\n    );\n  });\n\n  it('color-block size', () => {\n    component.nzSize = 'small';\n    fixture.detectChanges();\n    expect(resultEl.nativeElement.querySelector('ng-antd-color-block').parentNode.classList).toContain(\n      'ant-color-picker-inline-sm'\n    );\n    component.nzSize = 'large';\n    fixture.detectChanges();\n    expect(resultEl.nativeElement.querySelector('ng-antd-color-block').parentNode.classList).toContain(\n      'ant-color-picker-inline-lg'\n    );\n  });\n\n  it('color-block click', () => {\n    fixture.detectChanges();\n    resultEl.nativeElement.querySelector('.ant-color-picker-color-block').click();\n    expect(component.isClick).toBeTrue();\n  });\n});\n\n@Component({\n  imports: [NzColorPickerModule],\n  template: ` <nz-color-block [nzColor]=\"nzColor\" [nzSize]=\"nzSize\" (nzOnClick)=\"clickHandle()\" /> `\n})\nexport class NzTestColorBlockComponent {\n  nzColor = '#1677ff';\n  nzSize: NzSizeLDSType = 'default';\n  isClick: boolean = false;\n\n  clickHandle(): void {\n    this.isClick = true;\n  }\n}\n"
  },
  {
    "path": "components/color-picker/color-block.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';\n\nimport { NzSizeLDSType } from 'ng-zorro-antd/core/types';\n\nimport { NgAntdColorPickerModule } from './src/ng-antd-color-picker.module';\nimport { defaultColor } from './src/util/util';\n\n@Component({\n  selector: 'nz-color-block',\n  exportAs: 'nzColorBlock',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  imports: [NgAntdColorPickerModule],\n  template: `<ng-antd-color-block [color]=\"nzColor\" (nzOnClick)=\"nzOnClick.emit()\" />`,\n  host: {\n    class: 'ant-color-picker-inline',\n    '[class.ant-color-picker-inline-sm]': `nzSize === 'small'`,\n    '[class.ant-color-picker-inline-lg]': `nzSize === 'large'`\n  }\n})\nexport class NzColorBlockComponent {\n  @Input() nzColor: string = defaultColor.toHexString();\n  @Input() nzSize: NzSizeLDSType = 'default';\n  @Output() readonly nzOnClick = new EventEmitter<void>();\n}\n"
  },
  {
    "path": "components/color-picker/color-format.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  DestroyRef,\n  EventEmitter,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  SimpleChanges,\n  booleanAttribute,\n  inject\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport {\n  AbstractControl,\n  FormBuilder,\n  FormControl,\n  FormGroup,\n  ReactiveFormsModule,\n  ValidationErrors,\n  ValidatorFn\n} from '@angular/forms';\nimport { debounceTime, distinctUntilChanged, filter } from 'rxjs/operators';\n\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzInputNumberModule } from 'ng-zorro-antd/input-number';\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\nimport { generateColor } from './src/util/util';\nimport { NzColorPickerFormatType, ValidFormKey } from './typings';\n\n@Component({\n  selector: 'nz-color-format',\n  exportAs: 'nzColorFormat',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  imports: [ReactiveFormsModule, NzSelectModule, NzInputModule, NzInputNumberModule],\n  template: `\n    <div class=\"ant-color-picker-format-select\">\n      <nz-select [formControl]=\"validateForm.controls.isFormat\" nzVariant=\"borderless\" nzSize=\"small\">\n        <nz-option nzValue=\"hex\" nzLabel=\"HEX\" />\n        <nz-option nzValue=\"hsb\" nzLabel=\"HSB\" />\n        <nz-option nzValue=\"rgb\" nzLabel=\"RGB\" />\n      </nz-select>\n    </div>\n\n    <div class=\"ant-color-picker-input\">\n      @switch (validateForm.controls.isFormat.value) {\n        @case ('hex') {\n          <div class=\"ant-color-picker-hex-input\">\n            <nz-input-wrapper nzPrefix=\"#\">\n              <input nz-input nzSize=\"small\" [formControl]=\"validateForm.controls.hex\" />\n            </nz-input-wrapper>\n          </div>\n        }\n        @case ('hsb') {\n          <div class=\"ant-color-picker-hsb-input\">\n            <div class=\"ant-color-picker-steppers ant-color-picker-hsb-input\">\n              <nz-input-number\n                [formControl]=\"validateForm.controls.hsbH\"\n                [nzMin]=\"0\"\n                [nzMax]=\"360\"\n                [nzStep]=\"1\"\n                [nzPrecision]=\"0\"\n                nzSize=\"small\"\n              />\n            </div>\n            <div class=\"ant-color-picker-steppers ant-color-picker-hsb-input\">\n              <nz-input-number\n                [formControl]=\"validateForm.controls.hsbS\"\n                [nzMin]=\"0\"\n                [nzMax]=\"100\"\n                [nzStep]=\"1\"\n                [nzFormatter]=\"formatterPercent\"\n                [nzParser]=\"parserPercent\"\n                nzSize=\"small\"\n              />\n            </div>\n            <div class=\"ant-color-picker-steppers ant-color-picker-hsb-input\">\n              <nz-input-number\n                [formControl]=\"validateForm.controls.hsbB\"\n                [nzMin]=\"0\"\n                [nzMax]=\"100\"\n                [nzStep]=\"1\"\n                [nzFormatter]=\"formatterPercent\"\n                [nzParser]=\"parserPercent\"\n                nzSize=\"small\"\n              />\n            </div>\n          </div>\n        }\n        @default {\n          <div class=\"ant-color-picker-rgb-input\">\n            <div class=\"ant-color-picker-steppers ant-color-picker-rgb-input\">\n              <nz-input-number\n                [formControl]=\"validateForm.controls.rgbR\"\n                [nzMin]=\"0\"\n                [nzMax]=\"255\"\n                [nzStep]=\"1\"\n                nzSize=\"small\"\n              />\n            </div>\n            <div class=\"ant-color-picker-steppers ant-color-picker-rgb-input\">\n              <nz-input-number\n                [formControl]=\"validateForm.controls.rgbG\"\n                [nzMin]=\"0\"\n                [nzMax]=\"255\"\n                [nzStep]=\"1\"\n                nzSize=\"small\"\n              />\n            </div>\n            <div class=\"ant-color-picker-steppers ant-color-picker-rgb-input\">\n              <nz-input-number\n                [formControl]=\"validateForm.controls.rgbB\"\n                [nzMin]=\"0\"\n                [nzMax]=\"255\"\n                [nzStep]=\"1\"\n                nzSize=\"small\"\n              />\n            </div>\n          </div>\n        }\n      }\n    </div>\n\n    @if (!nzDisabledAlpha) {\n      <div class=\"ant-color-picker-steppers ant-color-picker-alpha-input\">\n        <nz-input-number\n          [formControl]=\"validateForm.controls.roundA\"\n          [nzMin]=\"0\"\n          [nzMax]=\"100\"\n          [nzStep]=\"1\"\n          [nzFormatter]=\"formatterPercent\"\n          [nzParser]=\"parserPercent\"\n          nzSize=\"small\"\n        />\n      </div>\n    }\n  `,\n  host: {\n    class: 'ant-color-picker-input-container'\n  }\n})\nexport class NzColorFormatComponent implements OnChanges, OnInit {\n  private destroyRef = inject(DestroyRef);\n  private formBuilder = inject(FormBuilder);\n  @Input() format: NzColorPickerFormatType | null = null;\n  @Input() colorValue: string = '';\n  @Input({ transform: booleanAttribute }) clearColor: boolean = false;\n  @Input({ transform: booleanAttribute }) nzDisabledAlpha: boolean = false;\n  @Output() readonly formatChange = new EventEmitter<{ color: string; format: NzColorPickerFormatType }>();\n  @Output() readonly nzOnFormatChange = new EventEmitter<NzColorPickerFormatType>();\n\n  validateForm: FormGroup<{\n    isFormat: FormControl<NzColorPickerFormatType | null>;\n    hex: FormControl<string | null>;\n    hsbH: FormControl<number>;\n    hsbS: FormControl<number>;\n    hsbB: FormControl<number>;\n    rgbR: FormControl<number>;\n    rgbG: FormControl<number>;\n    rgbB: FormControl<number>;\n    roundA: FormControl<number>;\n  }> = this.formBuilder.nonNullable.group({\n    isFormat: this.formBuilder.control<NzColorPickerFormatType>('hex'),\n    hex: this.formBuilder.control<string>('1677FF', hexValidator),\n    hsbH: 215,\n    hsbS: 91,\n    hsbB: 100,\n    rgbR: 22,\n    rgbG: 119,\n    rgbB: 255,\n    roundA: 100\n  });\n\n  formatterPercent = (value: number): string => `${value} %`;\n  parserPercent = (value: string): number => +value.replace(' %', '');\n\n  ngOnInit(): void {\n    this.validateForm.valueChanges\n      .pipe(\n        filter(() => this.validateForm.valid),\n        debounceTime(200),\n        distinctUntilChanged((prev, current) =>\n          Object.keys(prev).every(key => prev[key as ValidFormKey] === current[key as ValidFormKey])\n        ),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(value => {\n        let color = '';\n        switch (value.isFormat) {\n          case 'hsb':\n            color = generateColor({\n              h: Number(value.hsbH),\n              s: Number(value.hsbS) / 100,\n              b: Number(value.hsbB) / 100,\n              a: Number(value.roundA) / 100\n            }).toHsbString();\n            break;\n          case 'rgb':\n            color = generateColor({\n              r: Number(value.rgbR),\n              g: Number(value.rgbG),\n              b: Number(value.rgbB),\n              a: Number(value.roundA) / 100\n            }).toRgbString();\n            break;\n          default: {\n            const hex = generateColor(value.hex as NzColorPickerFormatType);\n            const hexColor = generateColor({\n              r: hex.r,\n              g: hex.g,\n              b: hex.b,\n              a: Number(value.roundA) / 100\n            });\n            color = hexColor.getAlpha() < 1 ? hexColor.toHex8String() : hexColor.toHexString();\n            break;\n          }\n        }\n        this.formatChange.emit({ color, format: value.isFormat || this.format || 'hex' });\n      });\n\n    this.validateForm\n      .get('isFormat')\n      ?.valueChanges.pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(value => {\n        this.nzOnFormatChange.emit(value as NzColorPickerFormatType);\n      });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { colorValue, format, clearColor } = changes;\n    if (colorValue) {\n      const colorValue = {\n        hex: generateColor(this.colorValue).toHex(),\n        hsbH: Math.round(generateColor(this.colorValue).toHsb().h),\n        hsbS: Math.round(generateColor(this.colorValue).toHsb().s * 100),\n        hsbB: Math.round(generateColor(this.colorValue).toHsb().b * 100),\n        rgbR: Math.round(generateColor(this.colorValue).r),\n        rgbG: Math.round(generateColor(this.colorValue).g),\n        rgbB: Math.round(generateColor(this.colorValue).b),\n        roundA: Math.round(generateColor(this.colorValue).roundA * 100)\n      };\n      this.validateForm.patchValue(colorValue);\n    }\n\n    if (format && this.format) {\n      this.validateForm.get('isFormat')?.patchValue(this.format);\n    }\n\n    if (clearColor && this.clearColor) {\n      this.validateForm.get('roundA')?.patchValue(0);\n    }\n  }\n}\n\nconst hexValidator: ValidatorFn = (control: AbstractControl): ValidationErrors | null => {\n  const REGEXP = /^[0-9a-fA-F]{6}$/;\n  if (!control.value) {\n    return { error: true };\n  } else if (!REGEXP.test(control.value)) {\n    return { error: true };\n  }\n  return null;\n};\n"
  },
  {
    "path": "components/color-picker/color-picker.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport { Component, DebugElement, provideZoneChangeDetection, signal, WritableSignal } from '@angular/core';\nimport { ComponentFixture, discardPeriodicTasks, fakeAsync, inject, TestBed, tick } from '@angular/core/testing';\nimport { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzColorPickerComponent, NzColorPickerModule } from 'ng-zorro-antd/color-picker';\nimport {\n  NzColor,\n  NzColorPickerFormatType,\n  NzColorPickerTriggerType,\n  NzPresetColor\n} from 'ng-zorro-antd/color-picker/typings';\nimport { NZ_FORM_SIZE } from 'ng-zorro-antd/core/form';\nimport { dispatchMouseEvent } from 'ng-zorro-antd/core/testing';\nimport { NzSizeLDSType } from 'ng-zorro-antd/core/types';\nimport { NzFormModule } from 'ng-zorro-antd/form';\n\ndescribe('color-picker', () => {\n  let fixture: ComponentFixture<NzTestColorPickerComponent>;\n  let testComponent: NzTestColorPickerComponent;\n  let resultEl: DebugElement;\n  let overlayContainer: OverlayContainer;\n  let overlayContainerElement: HTMLElement;\n\n  function waitingForTooltipToggling(): void {\n    fixture.detectChanges();\n    tick(500);\n    fixture.detectChanges();\n  }\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzTestColorPickerComponent);\n    fixture.detectChanges();\n    testComponent = fixture.componentInstance;\n    resultEl = fixture.debugElement.query(By.directive(NzColorPickerComponent));\n  });\n\n  beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n    overlayContainer = oc;\n    overlayContainerElement = oc.getContainerElement();\n  }));\n\n  afterEach(() => {\n    overlayContainer.ngOnDestroy();\n  });\n\n  it('color-picker basic', () => {\n    fixture.detectChanges();\n    const colorDom = resultEl.nativeElement.querySelector('.ant-color-picker-color-block-inner');\n    expect(colorDom.style.backgroundColor).toBe('rgb(22, 119, 255)');\n  });\n\n  it('color-picker nzValue', () => {\n    testComponent.nzValue = '#ff6600';\n    fixture.detectChanges();\n    const colorDom = resultEl.nativeElement.querySelector('.ant-color-picker-color-block-inner');\n    expect(colorDom.style.backgroundColor).toBe('rgb(255, 102, 0)');\n  });\n\n  it('color-picker nzDefaultValue', () => {\n    testComponent.nzDefaultValue = '#ff6600';\n    fixture.detectChanges();\n    const colorDom = resultEl.nativeElement.querySelector('.ant-color-picker-color-block-inner');\n    expect(colorDom.style.backgroundColor).toBe('rgb(255, 102, 0)');\n  });\n\n  it('color-picker nzSize', () => {\n    testComponent.nzSize = 'small';\n    fixture.detectChanges();\n    expect(resultEl.nativeElement.querySelector('.ant-color-picker-trigger').classList).toContain(\n      'ant-color-picker-sm'\n    );\n    testComponent.nzSize = 'large';\n    fixture.detectChanges();\n    expect(resultEl.nativeElement.querySelector('.ant-color-picker-trigger').classList).toContain(\n      'ant-color-picker-lg'\n    );\n  });\n\n  it('color-picker nzDisabled', () => {\n    testComponent.nzDisabled = true;\n    fixture.detectChanges();\n    expect(resultEl.nativeElement.classList).toContain('ant-color-picker-disabled');\n  });\n\n  it('color-picker nzShowText', () => {\n    testComponent.nzShowText = true;\n    fixture.detectChanges();\n    expect(resultEl.nativeElement.querySelector('.ant-color-picker-trigger-text').innerText).toBe('#1677ff');\n  });\n\n  it('color-picker nzTrigger click', fakeAsync(() => {\n    fixture.detectChanges();\n    const dom = resultEl.nativeElement.querySelector('.ant-color-picker-trigger');\n    dispatchMouseEvent(dom, 'click');\n    waitingForTooltipToggling();\n    expect(!!overlayContainerElement.querySelector('.ant-popover-inner-content')).toBeTrue();\n  }));\n\n  it('color-picker nzTrigger hover', fakeAsync(() => {\n    testComponent.nzTrigger = 'hover';\n    fixture.detectChanges();\n    const dom = resultEl.nativeElement.querySelector('.ant-color-picker-trigger');\n    dispatchMouseEvent(dom, 'mouseenter');\n    waitingForTooltipToggling();\n    expect(!!overlayContainerElement.querySelector('.ant-popover-inner-content')).toBeTrue();\n  }));\n\n  it('color-picker nzOpen', () => {\n    testComponent.nzOpen = true;\n    fixture.detectChanges();\n    expect(!!overlayContainerElement.querySelector('.ant-popover-inner-content')).toBeTrue();\n  });\n\n  it('color-picker nzAllowClear', fakeAsync(() => {\n    testComponent.nzAllowClear = true;\n    fixture.detectChanges();\n    const dom = resultEl.nativeElement.querySelector('.ant-color-picker-trigger');\n    dispatchMouseEvent(dom, 'click');\n    waitingForTooltipToggling();\n    expect(!!overlayContainerElement.querySelector('.ant-color-picker-clear')).toBeTrue();\n  }));\n\n  it('color-picker nzTitle', fakeAsync(() => {\n    fixture.detectChanges();\n    const dom = resultEl.nativeElement.querySelector('.ant-color-picker-trigger');\n    dispatchMouseEvent(dom, 'click');\n    waitingForTooltipToggling();\n    expect(overlayContainerElement.querySelector('.ant-color-picker-title-content')?.textContent?.trim()).toBe(\n      'Color Picker'\n    );\n  }));\n\n  it('color-picker nzFlipFlop', () => {\n    testComponent.isFlipFlop = true;\n    fixture.detectChanges();\n    expect(!!resultEl.nativeElement.querySelector('button')).toBeTrue();\n  });\n\n  it('color-picker nzFormat', fakeAsync(() => {\n    fixture.detectChanges();\n    const dom = resultEl.nativeElement.querySelector('.ant-color-picker-trigger');\n    dispatchMouseEvent(dom, 'click');\n    waitingForTooltipToggling();\n    expect(!!overlayContainerElement.querySelector('.ant-color-picker-hex-input')).toBeTrue();\n    testComponent.nzFormat = 'hsb';\n    fixture.detectChanges();\n    waitingForTooltipToggling();\n    expect(!!overlayContainerElement.querySelector('.ant-color-picker-hsb-input')).toBeTrue();\n    testComponent.nzFormat = 'rgb';\n    fixture.detectChanges();\n    waitingForTooltipToggling();\n    expect(!!overlayContainerElement.querySelector('.ant-color-picker-rgb-input')).toBeTrue();\n  }));\n\n  it('color-picker nzOnOpenChange', fakeAsync(() => {\n    fixture.detectChanges();\n    const dom = resultEl.nativeElement.querySelector('.ant-color-picker-trigger');\n    dispatchMouseEvent(dom, 'click');\n    waitingForTooltipToggling();\n    expect(testComponent.openChange).toBeTrue();\n  }));\n\n  it('color-picker nzOnClear', fakeAsync(() => {\n    testComponent.nzAllowClear = true;\n    fixture.detectChanges();\n    const dom = resultEl.nativeElement.querySelector('.ant-color-picker-trigger');\n    dispatchMouseEvent(dom, 'click');\n    waitingForTooltipToggling();\n    const clear = overlayContainerElement.querySelector('.ant-color-picker-clear');\n    if (clear) {\n      dispatchMouseEvent(clear, 'click');\n      fixture.detectChanges();\n      waitingForTooltipToggling();\n      const colorDom = resultEl.nativeElement.querySelector('.ant-color-picker-color-block-inner');\n      expect(colorDom.style.backgroundColor).toBe('rgba(22, 119, 255, 0)');\n      discardPeriodicTasks();\n    }\n  }));\n\n  it('color-picker nzOnChange', fakeAsync(() => {\n    fixture.detectChanges();\n    const dom = resultEl.nativeElement.querySelector('.ant-color-picker-trigger');\n    dispatchMouseEvent(dom, 'click');\n    waitingForTooltipToggling();\n    const select = overlayContainerElement.querySelector('nz-select') as Element;\n    dispatchMouseEvent(select, 'click');\n    waitingForTooltipToggling();\n    const item = overlayContainerElement.querySelectorAll('nz-option-item')[1];\n    dispatchMouseEvent(item, 'click');\n    waitingForTooltipToggling();\n    expect(testComponent.colorChange?.format).toBe('hsb');\n    expect(testComponent.colorChange?.color.toHsbString()).toBe('hsb(215, 91%, 100%)');\n    discardPeriodicTasks();\n  }));\n\n  it('color-picker disableAlpha', fakeAsync(() => {\n    testComponent.nzAlphaDisabled = true;\n    fixture.detectChanges();\n    const dom = resultEl.nativeElement.querySelector('.ant-color-picker-trigger');\n    dispatchMouseEvent(dom, 'click');\n    waitingForTooltipToggling();\n    const alphaSlider = overlayContainerElement.querySelector('.ant-color-picker-slider-alpha') as Element;\n    expect(alphaSlider).toBeFalsy();\n    discardPeriodicTasks();\n  }));\n\n  it('nz-color-format disableAlpha', fakeAsync(() => {\n    testComponent.nzAlphaDisabled = true;\n    fixture.detectChanges();\n    const dom = resultEl.nativeElement.querySelector('.ant-color-picker-trigger');\n    dispatchMouseEvent(dom, 'click');\n    waitingForTooltipToggling();\n    const select = overlayContainerElement.querySelector('nz-select') as Element;\n    dispatchMouseEvent(select, 'click');\n    waitingForTooltipToggling();\n    const items = overlayContainerElement.querySelectorAll('nz-option-item');\n    items.forEach(item => {\n      dispatchMouseEvent(item, 'click');\n      waitingForTooltipToggling();\n      const alphaInputElement = overlayContainerElement.querySelector('.ant-color-picker-alpha-input') as Element;\n      expect(alphaInputElement).toBeFalsy();\n    });\n    discardPeriodicTasks();\n  }));\n});\n\n@Component({\n  imports: [NzButtonModule, NzColorPickerModule],\n  template: `\n    <nz-color-picker\n      [nzValue]=\"nzValue\"\n      [nzSize]=\"nzSize\"\n      [nzDefaultValue]=\"nzDefaultValue\"\n      [nzShowText]=\"nzShowText\"\n      [nzDisabled]=\"nzDisabled\"\n      [nzTrigger]=\"nzTrigger\"\n      [nzFormat]=\"nzFormat\"\n      [nzAllowClear]=\"nzAllowClear\"\n      [nzOpen]=\"nzOpen\"\n      [nzDisabledAlpha]=\"nzAlphaDisabled\"\n      (nzOnChange)=\"nzOnChange($event)\"\n      (nzOnFormatChange)=\"nzOnFormatChange($event)\"\n      (nzOnClear)=\"nzOnClear($event)\"\n      (nzOnOpenChange)=\"nzOnOpenChange($event)\"\n      nzTitle=\"Color Picker\"\n      [nzFlipFlop]=\"isFlipFlop ? flipFlop : null\"\n    />\n    <ng-template #flipFlop>\n      <button nz-button nzType=\"primary\">Color</button>\n    </ng-template>\n  `\n})\nexport class NzTestColorPickerComponent {\n  nzFormat: NzColorPickerFormatType | null = null;\n  nzValue = '';\n  nzSize: NzSizeLDSType = 'default';\n  nzDefaultValue = '';\n  nzTrigger: NzColorPickerTriggerType = 'click';\n  nzShowText: boolean = false;\n  nzAllowClear: boolean = false;\n  nzDisabled: boolean = false;\n  nzAlphaDisabled: boolean = false;\n  nzOpen: boolean = false;\n\n  isFlipFlop = false;\n\n  isClear = false;\n  openChange = false;\n  colorChange: { color: NzColor; format: string } | null = null;\n  formatChange: NzColorPickerFormatType | null = null;\n  nzOnChange(value: { color: NzColor; format: string }): void {\n    this.colorChange = value;\n  }\n  nzOnFormatChange(value: NzColorPickerFormatType): void {\n    this.formatChange = value;\n  }\n  nzOnClear(value: boolean): void {\n    this.isClear = value;\n  }\n  nzOnOpenChange(value: boolean): void {\n    this.openChange = value;\n  }\n}\n\ndescribe('nz-color-picker form', () => {\n  let fixture: ComponentFixture<NzTestColorPickerFormComponent>;\n  let component: NzTestColorPickerFormComponent;\n  let resultEl: DebugElement;\n\n  beforeEach(fakeAsync(() => {\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations()]\n    });\n    fixture = TestBed.createComponent(NzTestColorPickerFormComponent);\n    fixture.detectChanges();\n    component = fixture.componentInstance;\n    resultEl = fixture.debugElement.query(By.directive(NzColorPickerComponent));\n  }));\n\n  it('color-picker form base', fakeAsync(() => {\n    fixture.detectChanges();\n    expect(resultEl.nativeElement.querySelector('.ant-color-picker-color-block-inner').style.backgroundColor).toBe(\n      'rgb(255, 102, 0)'\n    );\n  }));\n\n  it('color-picker form disable', fakeAsync(() => {\n    component.disable();\n    fixture.detectChanges();\n    expect(resultEl.nativeElement.classList).toContain('ant-color-picker-disabled');\n    component.enable();\n    fixture.detectChanges();\n    expect(resultEl.nativeElement.classList).not.toContain('ant-color-picker-disabled');\n  }));\n});\n\ndescribe('nz-color-picker with presets', () => {\n  let fixture: ComponentFixture<NzTestColorPickerPresetsComponent>;\n  let testComponent: NzTestColorPickerPresetsComponent;\n  let resultEl: DebugElement;\n  let overlayContainer: OverlayContainer;\n  let overlayContainerElement: HTMLElement;\n\n  function waitingForTooltipToggling(): void {\n    fixture.detectChanges();\n    tick(500);\n    fixture.detectChanges();\n  }\n\n  beforeEach(fakeAsync(() => {\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), provideZoneChangeDetection()]\n    });\n    fixture = TestBed.createComponent(NzTestColorPickerPresetsComponent);\n    fixture.detectChanges();\n    testComponent = fixture.componentInstance;\n    resultEl = fixture.debugElement.query(By.directive(NzColorPickerComponent));\n  }));\n\n  beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n    overlayContainer = oc;\n    overlayContainerElement = oc.getContainerElement();\n  }));\n\n  afterEach(() => {\n    overlayContainer.ngOnDestroy();\n  });\n\n  it('should render presets when provided', fakeAsync(() => {\n    const trigger = resultEl.nativeElement.querySelector('.ant-color-picker-trigger');\n    dispatchMouseEvent(trigger, 'click');\n    waitingForTooltipToggling();\n\n    const presetWrapper = overlayContainerElement.querySelector('.ant-color-picker-presets-wrapper');\n    expect(presetWrapper).toBeTruthy();\n\n    const collapseItems = overlayContainerElement.querySelectorAll('.ant-collapse-item');\n    expect(collapseItems.length).toBe(2);\n  }));\n\n  it('should not render presets when null', fakeAsync(() => {\n    testComponent.presets = null;\n    fixture.detectChanges();\n\n    const trigger = resultEl.nativeElement.querySelector('.ant-color-picker-trigger');\n    dispatchMouseEvent(trigger, 'click');\n    waitingForTooltipToggling();\n\n    const presetWrapper = overlayContainerElement.querySelector('.ant-color-picker-presets-wrapper');\n    expect(presetWrapper).toBeFalsy();\n  }));\n\n  it('should handle preset color selection', fakeAsync(() => {\n    spyOn(testComponent, 'onColorChange');\n\n    const trigger = resultEl.nativeElement.querySelector('.ant-color-picker-trigger');\n    dispatchMouseEvent(trigger, 'click');\n    waitingForTooltipToggling();\n\n    const firstPresetColor = overlayContainerElement.querySelector(\n      '.ant-color-picker-presets-items .ant-color-picker-color-block'\n    );\n    expect(firstPresetColor).toBeTruthy();\n\n    dispatchMouseEvent(firstPresetColor as Element, 'click');\n    fixture.detectChanges();\n    tick(0);\n    fixture.detectChanges();\n\n    expect(testComponent.onColorChange).toHaveBeenCalled();\n  }));\n\n  it('should toggle preset groups', fakeAsync(() => {\n    const trigger = resultEl.nativeElement.querySelector('.ant-color-picker-trigger');\n    dispatchMouseEvent(trigger, 'click');\n    waitingForTooltipToggling();\n\n    const collapseItems = overlayContainerElement.querySelectorAll('.ant-collapse-item');\n    const secondPanel = collapseItems[1] as HTMLElement;\n\n    // Initially, second group should be collapsed (no active class)\n    expect(secondPanel.classList.contains('ant-collapse-item-active')).toBeFalse();\n\n    // Find and click the collapse header to toggle\n    const collapseHeader = secondPanel.querySelector('.ant-collapse-header');\n    if (collapseHeader) {\n      dispatchMouseEvent(collapseHeader, 'click');\n      fixture.detectChanges();\n      tick(300); // Wait for collapse animation\n      fixture.detectChanges();\n    }\n  }));\n});\n\n@Component({\n  imports: [NzColorPickerModule, NzFormModule, ReactiveFormsModule],\n  template: `\n    <form nz-form [formGroup]=\"validateForm\">\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"4\">color</nz-form-label>\n        <nz-form-control [nzSpan]=\"16\">\n          <nz-color-picker formControlName=\"colorPicker\" nzShowText />\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `\n})\nexport class NzTestColorPickerFormComponent {\n  validateForm = new FormGroup({\n    colorPicker: new FormControl('#ff6600')\n  });\n\n  disable(): void {\n    this.validateForm.disable();\n  }\n\n  enable(): void {\n    this.validateForm.enable();\n  }\n}\n\n@Component({\n  imports: [NzColorPickerModule],\n  template: ` <nz-color-picker [nzPresets]=\"presets\" nzValue=\"#1677ff\" (nzOnChange)=\"onColorChange($event)\" /> `\n})\nexport class NzTestColorPickerPresetsComponent {\n  presets: NzPresetColor[] | null = [\n    {\n      label: 'Basic Colors',\n      colors: ['#ff0000', '#00ff00', '#0000ff'],\n      defaultOpen: true,\n      key: 'basic'\n    },\n    {\n      label: 'Advanced Colors',\n      colors: ['#ffff00', '#ff00ff', '#00ffff'],\n      defaultOpen: false,\n      key: 'advanced'\n    }\n  ];\n\n  onColorChange(event: { color: NzColor; format: string }): void {\n    console.log('Color changed:', event);\n  }\n}\n\ndescribe('nz-color-picker form size', () => {\n  let fixture: ComponentFixture<NzTestColorPickerFormSizeComponent>;\n  let colorPickerElement: HTMLElement;\n  let formSizeSignal: WritableSignal<NzSizeLDSType | undefined>;\n\n  beforeEach(() => {\n    formSizeSignal = signal<NzSizeLDSType | undefined>(undefined);\n  });\n\n  afterEach(() => {\n    TestBed.resetTestingModule();\n  });\n\n  it('should apply size from NZ_FORM_SIZE signal', () => {\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), { provide: NZ_FORM_SIZE, useValue: formSizeSignal }]\n    });\n    fixture = TestBed.createComponent(NzTestColorPickerFormSizeComponent);\n    colorPickerElement = fixture.debugElement.query(By.directive(NzColorPickerComponent)).nativeElement;\n    fixture.detectChanges();\n\n    formSizeSignal.set('large');\n    fixture.detectChanges();\n\n    const trigger = colorPickerElement.querySelector('.ant-color-picker-trigger');\n    expect(trigger?.classList).toContain('ant-color-picker-lg');\n  });\n\n  it('should apply small size from NZ_FORM_SIZE signal', () => {\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), { provide: NZ_FORM_SIZE, useValue: formSizeSignal }]\n    });\n    fixture = TestBed.createComponent(NzTestColorPickerFormSizeComponent);\n    colorPickerElement = fixture.debugElement.query(By.directive(NzColorPickerComponent)).nativeElement;\n    fixture.detectChanges();\n\n    formSizeSignal.set('small');\n    fixture.detectChanges();\n\n    const trigger = colorPickerElement.querySelector('.ant-color-picker-trigger');\n    expect(trigger?.classList).toContain('ant-color-picker-sm');\n  });\n\n  it('should prioritize NZ_FORM_SIZE over nzSize input', () => {\n    formSizeSignal.set('large');\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), { provide: NZ_FORM_SIZE, useValue: formSizeSignal }]\n    });\n    fixture = TestBed.createComponent(NzTestColorPickerFormSizeComponent);\n    colorPickerElement = fixture.debugElement.query(By.directive(NzColorPickerComponent)).nativeElement;\n    fixture.componentInstance.size = 'small';\n    fixture.detectChanges();\n\n    const trigger = colorPickerElement.querySelector('.ant-color-picker-trigger');\n    expect(trigger?.classList).toContain('ant-color-picker-lg');\n    expect(trigger?.classList).not.toContain('ant-color-picker-sm');\n  });\n\n  it('should use nzSize input when NZ_FORM_SIZE is not provided', () => {\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations()]\n    });\n    fixture = TestBed.createComponent(NzTestColorPickerFormSizeComponent);\n    colorPickerElement = fixture.debugElement.query(By.directive(NzColorPickerComponent)).nativeElement;\n    fixture.componentInstance.size = 'large';\n    fixture.detectChanges();\n\n    const trigger = colorPickerElement.querySelector('.ant-color-picker-trigger');\n    expect(trigger?.classList).toContain('ant-color-picker-lg');\n  });\n\n  it('should update size when NZ_FORM_SIZE signal changes', () => {\n    formSizeSignal.set('small');\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), { provide: NZ_FORM_SIZE, useValue: formSizeSignal }]\n    });\n    fixture = TestBed.createComponent(NzTestColorPickerFormSizeComponent);\n    colorPickerElement = fixture.debugElement.query(By.directive(NzColorPickerComponent)).nativeElement;\n    fixture.detectChanges();\n\n    let trigger = colorPickerElement.querySelector('.ant-color-picker-trigger');\n    expect(trigger?.classList).toContain('ant-color-picker-sm');\n\n    formSizeSignal.set('large');\n    fixture.detectChanges();\n\n    trigger = colorPickerElement.querySelector('.ant-color-picker-trigger');\n    expect(trigger?.classList).toContain('ant-color-picker-lg');\n    expect(trigger?.classList).not.toContain('ant-color-picker-sm');\n  });\n\n  it('should apply default size when NZ_FORM_SIZE is undefined', () => {\n    formSizeSignal.set(undefined);\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), { provide: NZ_FORM_SIZE, useValue: formSizeSignal }]\n    });\n    fixture = TestBed.createComponent(NzTestColorPickerFormSizeComponent);\n    colorPickerElement = fixture.debugElement.query(By.directive(NzColorPickerComponent)).nativeElement;\n    fixture.detectChanges();\n\n    const trigger = colorPickerElement.querySelector('.ant-color-picker-trigger');\n    expect(trigger?.classList).not.toContain('ant-color-picker-lg');\n    expect(trigger?.classList).not.toContain('ant-color-picker-sm');\n  });\n});\n\n@Component({\n  imports: [NzColorPickerModule],\n  template: `<nz-color-picker [nzSize]=\"size\" />`\n})\nexport class NzTestColorPickerFormSizeComponent {\n  size: NzSizeLDSType = 'default';\n}\n"
  },
  {
    "path": "components/color-picker/color-picker.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  computed,\n  DestroyRef,\n  EventEmitter,\n  forwardRef,\n  inject,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  signal,\n  SimpleChanges,\n  TemplateRef\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, FormBuilder, NG_VALUE_ACCESSOR } from '@angular/forms';\n\nimport { NZ_FORM_SIZE } from 'ng-zorro-antd/core/form';\nimport { NzStringTemplateOutletDirective } from 'ng-zorro-antd/core/outlet';\nimport { NzSafeAny, NzSizeLDSType } from 'ng-zorro-antd/core/types';\nimport { NzPopoverDirective } from 'ng-zorro-antd/popover';\n\nimport { NzColorBlockComponent } from './color-block.component';\nimport { NzColorFormatComponent } from './color-format.component';\nimport { NgAntdColorPickerModule } from './src/ng-antd-color-picker.module';\nimport { defaultColor, generateColor } from './src/util/util';\nimport { NzColor, NzColorPickerFormatType, NzColorPickerTriggerType, NzPresetColor } from './typings';\n\n@Component({\n  selector: 'nz-color-picker',\n  exportAs: 'nzColorPicker',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  imports: [\n    NgAntdColorPickerModule,\n    NzPopoverDirective,\n    NzColorBlockComponent,\n    NzColorFormatComponent,\n    NgTemplateOutlet,\n    NzStringTemplateOutletDirective\n  ],\n  template: `\n    <div\n      [class.ant-color-picker-trigger]=\"!nzFlipFlop\"\n      [class.ant-color-picker-sm]=\"finalSize() === 'small'\"\n      [class.ant-color-picker-lg]=\"finalSize() === 'large'\"\n      nz-popover\n      [nzPopoverContent]=\"colorPicker\"\n      [nzPopoverTrigger]=\"!nzDisabled ? nzTrigger : null\"\n      [nzPopoverVisible]=\"nzOpen\"\n      (nzPopoverVisibleChange)=\"nzOnOpenChange.emit($event)\"\n    >\n      @if (!nzFlipFlop) {\n        <nz-color-block [nzColor]=\"blockColor\" [nzSize]=\"finalSize()\" />\n      } @else {\n        <ng-template [ngTemplateOutlet]=\"nzFlipFlop\" />\n      }\n      @if (nzShowText && !!showText && !nzFlipFlop) {\n        <div class=\"ant-color-picker-trigger-text\">\n          {{ showText }}\n        </div>\n      }\n    </div>\n    <ng-template #colorPicker>\n      <ng-antd-color-picker\n        [value]=\"blockColor\"\n        [defaultValue]=\"nzDefaultValue\"\n        [disabled]=\"nzDisabled\"\n        [panelRenderHeader]=\"nzPanelRenderHeader\"\n        [panelRenderFooter]=\"nzPanelRenderFooter\"\n        [disabledAlpha]=\"nzDisabledAlpha\"\n        [presets]=\"nzPresets\"\n        (nzOnChange)=\"colorChange($event)\"\n      />\n    </ng-template>\n    <ng-template #nzPanelRenderHeader>\n      @if (nzTitle || nzAllowClear) {\n        <div class=\"ant-color-picker-title\">\n          <div class=\"ant-color-picker-title-content\">\n            <ng-template [nzStringTemplateOutlet]=\"nzTitle\">{{ nzTitle }}</ng-template>\n          </div>\n          @if (nzAllowClear) {\n            <div class=\"ant-color-picker-clear\" (click)=\"clearColorHandle()\"></div>\n          }\n        </div>\n      }\n    </ng-template>\n    <ng-template #nzPanelRenderFooter>\n      <nz-color-format\n        [colorValue]=\"blockColor\"\n        [clearColor]=\"clearColor\"\n        [format]=\"nzFormat\"\n        [nzDisabledAlpha]=\"nzDisabledAlpha\"\n        (formatChange)=\"formatChange($event)\"\n        (nzOnFormatChange)=\"nzOnFormatChange.emit($event)\"\n      />\n    </ng-template>\n  `,\n  host: {\n    class: 'ant-color-picker-inline',\n    '[class.ant-color-picker-disabled]': `nzDisabled`\n  },\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => NzColorPickerComponent),\n      multi: true\n    }\n  ]\n})\nexport class NzColorPickerComponent implements OnInit, OnChanges, ControlValueAccessor {\n  private cdr = inject(ChangeDetectorRef);\n  private destroyRef = inject(DestroyRef);\n  private formBuilder = inject(FormBuilder);\n\n  private readonly formSize = inject(NZ_FORM_SIZE, { optional: true });\n\n  @Input() nzFormat: NzColorPickerFormatType | null = null;\n  @Input() nzValue: string | NzColor = '';\n  @Input() nzSize: NzSizeLDSType = 'default';\n  @Input() nzDefaultValue: string | NzColor = '';\n  @Input() nzTrigger: NzColorPickerTriggerType = 'click';\n  @Input() nzTitle: TemplateRef<void> | string = '';\n  @Input() nzFlipFlop: TemplateRef<void> | null = null;\n  @Input({ transform: booleanAttribute }) nzShowText: boolean = false;\n  @Input({ transform: booleanAttribute }) nzOpen: boolean = false;\n  @Input({ transform: booleanAttribute }) nzAllowClear: boolean = false;\n  @Input({ transform: booleanAttribute }) nzDisabled: boolean = false;\n  @Input({ transform: booleanAttribute }) nzDisabledAlpha: boolean = false;\n  @Input() nzPresets: NzPresetColor[] | null = null;\n  @Output() readonly nzOnChange = new EventEmitter<{ color: NzColor; format: string }>();\n  @Output() readonly nzOnFormatChange = new EventEmitter<NzColorPickerFormatType>();\n  @Output() readonly nzOnClear = new EventEmitter<boolean>();\n  @Output() readonly nzOnOpenChange = new EventEmitter<boolean>();\n\n  private isNzDisableFirstChange: boolean = true;\n  blockColor: string = '';\n  clearColor: boolean = false;\n  showText: string = defaultColor.toHexString();\n  formControl = this.formBuilder.control('');\n  private readonly size = signal(this.nzSize);\n\n  protected readonly finalSize = computed(() => this.formSize?.() || this.size());\n\n  onChange: (value: string) => void = () => {};\n\n  writeValue(value: string): void {\n    this.nzValue = value;\n    this.getBlockColor();\n    this.formControl.patchValue(value);\n  }\n\n  registerOnChange(fn: NzSafeAny): void {\n    this.onChange = fn;\n  }\n\n  registerOnTouched(): void {}\n\n  setDisabledState(isDisabled: boolean): void {\n    this.nzDisabled = (this.isNzDisableFirstChange && this.nzDisabled) || isDisabled;\n    this.isNzDisableFirstChange = false;\n    this.cdr.markForCheck();\n  }\n\n  ngOnInit(): void {\n    this.getBlockColor();\n    this.formControl.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(value => {\n      if (value) {\n        let color = value;\n        if (this.nzFormat === 'hex') {\n          color =\n            generateColor(value).getAlpha() < 1\n              ? generateColor(value).toHex8String()\n              : generateColor(value).toHexString();\n        } else if (this.nzFormat === 'hsb') {\n          color = generateColor(value).toHsbString();\n        } else if (this.nzFormat === 'rgb') {\n          color = generateColor(value).toRgbString();\n        }\n        this.showText = color;\n        this.onChange(color);\n        this.cdr.markForCheck();\n      }\n    });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzValue, nzDefaultValue, nzSize } = changes;\n    if (nzValue || nzDefaultValue) {\n      this.getBlockColor();\n    }\n    if (nzSize) {\n      this.size.set(nzSize.currentValue);\n    }\n  }\n\n  clearColorHandle(): void {\n    this.clearColor = true;\n    this.nzOnClear.emit(true);\n    this.cdr.markForCheck();\n  }\n\n  getBlockColor(): void {\n    if (this.nzValue) {\n      this.blockColor = generateColor(this.nzValue).toRgbString();\n    } else if (this.nzDefaultValue) {\n      this.blockColor = generateColor(this.nzDefaultValue).toRgbString();\n    } else {\n      this.blockColor = defaultColor.toHexString();\n    }\n  }\n\n  colorChange(value: { color: NzColor }): void {\n    this.blockColor = value.color.getAlpha() < 1 ? value.color.toHex8String() : value.color.toHexString();\n    this.clearColor = false;\n    this.nzOnChange.emit({ color: value.color, format: this.nzFormat ?? 'hex' });\n    this.cdr.markForCheck();\n  }\n\n  formatChange(value: { color: string; format: NzColorPickerFormatType }): void {\n    this.nzValue = value.color;\n    this.clearColor = false;\n    this.getBlockColor();\n    this.nzOnChange.emit({ color: generateColor(value.color), format: value.format });\n    this.formControl.patchValue(value.color);\n    this.cdr.markForCheck();\n  }\n}\n"
  },
  {
    "path": "components/color-picker/color-picker.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzColorBlockComponent } from './color-block.component';\nimport { NzColorFormatComponent } from './color-format.component';\nimport { NzColorPickerComponent } from './color-picker.component';\n\n@NgModule({\n  imports: [NzColorPickerComponent, NzColorBlockComponent, NzColorFormatComponent],\n  exports: [NzColorPickerComponent, NzColorBlockComponent]\n})\nexport class NzColorPickerModule {}\n"
  },
  {
    "path": "components/color-picker/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n最简单的用法。\n\n## en-US\n\nThe simplest usage.\n"
  },
  {
    "path": "components/color-picker/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzColorPickerModule } from 'ng-zorro-antd/color-picker';\n\n@Component({\n  selector: 'nz-demo-color-picker-basic',\n  imports: [NzColorPickerModule],\n  template: `<nz-color-picker />`\n})\nexport class NzDemoColorPickerBasicComponent {}\n"
  },
  {
    "path": "components/color-picker/demo/block.md",
    "content": "---\norder: 10\ntitle:\n  zh-CN: 色彩块\n  en-US: Color Block\n---\n\n## zh-CN\n\n最简单的用法。\n\n## en-US\n\nColor Block.\n"
  },
  {
    "path": "components/color-picker/demo/block.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzColorPickerModule } from 'ng-zorro-antd/color-picker';\n\n@Component({\n  selector: 'nz-demo-color-picker-block',\n  imports: [NzColorPickerModule],\n  template: `\n    <nz-color-block nzSize=\"small\" />\n    <nz-color-block />\n    <nz-color-block nzSize=\"large\" />\n  `,\n  styles: `\n    nz-color-block {\n      margin-right: 12px;\n    }\n  `\n})\nexport class NzDemoColorPickerBlockComponent {}\n"
  },
  {
    "path": "components/color-picker/demo/clear.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 清除颜色\n  en-US: Clear Color\n---\n\n## zh-CN\n\n清除已选择的颜色。\n\n## en-US\n\nClear Color.\n"
  },
  {
    "path": "components/color-picker/demo/clear.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzColorPickerModule } from 'ng-zorro-antd/color-picker';\n\n@Component({\n  selector: 'nz-demo-color-picker-clear',\n  imports: [NzColorPickerModule],\n  template: `<nz-color-picker nzAllowClear nzTitle=\"Allow Clear\" />`\n})\nexport class NzDemoColorPickerClearComponent {}\n"
  },
  {
    "path": "components/color-picker/demo/disable-alpha.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 禁用透明度\n  en-US: Disabled Alpha\n---\n\n## zh-CN\n\n禁用颜色透明度。\n\n## en-US\n\nDisabled color alpha.\n"
  },
  {
    "path": "components/color-picker/demo/disable-alpha.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzColorPickerModule } from 'ng-zorro-antd/color-picker';\n\n@Component({\n  selector: 'nz-demo-color-picker-disable-alpha',\n  imports: [NzColorPickerModule],\n  template: `<nz-color-picker nzDisabledAlpha />`\n})\nexport class NzDemoColorPickerDisableAlphaComponent {}\n"
  },
  {
    "path": "components/color-picker/demo/disable.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 禁用\n  en-US: Disabled\n---\n\n## zh-CN\n\n设置为禁用状态。\n\n## en-US\n\nSet to disabled state.\n"
  },
  {
    "path": "components/color-picker/demo/disable.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzColorPickerModule } from 'ng-zorro-antd/color-picker';\n\n@Component({\n  selector: 'nz-demo-color-picker-disable',\n  imports: [NzColorPickerModule],\n  template: `<nz-color-picker nzDisabled nzShowText />`\n})\nexport class NzDemoColorPickerDisableComponent {}\n"
  },
  {
    "path": "components/color-picker/demo/flip-flop.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 自定义触发器\n  en-US: Custom Trigger\n---\n\n## zh-CN\n\n自定义颜色面板的触发器。\n\n## en-US\n\nTriggers for customizing color panels.\n"
  },
  {
    "path": "components/color-picker/demo/flip-flop.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzColorPickerModule } from 'ng-zorro-antd/color-picker';\n\n@Component({\n  selector: 'nz-demo-color-picker-flip-flop',\n  imports: [FormsModule, NzButtonModule, NzColorPickerModule],\n  template: `\n    <nz-color-picker [nzFlipFlop]=\"flipFlop\" [(ngModel)]=\"color\" />\n    <ng-template #flipFlop>\n      <button nz-button nzType=\"primary\" [style.background-color]=\"color\">Color</button>\n    </ng-template>\n  `,\n  styles: `\n    button {\n      border: none;\n    }\n  `\n})\nexport class NzDemoColorPickerFlipFlopComponent {\n  color = '#1677ff';\n}\n"
  },
  {
    "path": "components/color-picker/demo/format.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 颜色编码\n  en-US: Color Format\n---\n\n## zh-CN\n\n编码格式，支持 `HEX`、`HSB`、`RGB`。\n\n## en-US\n\nEncoding formats, support `HEX`, `HSB`, `RGB`.\n"
  },
  {
    "path": "components/color-picker/demo/format.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzColorPickerModule } from 'ng-zorro-antd/color-picker';\n\n@Component({\n  selector: 'nz-demo-color-picker-format',\n  imports: [FormsModule, NzColorPickerModule],\n  template: `\n    <div class=\"format\"> <nz-color-picker nzFormat=\"hex\" [(ngModel)]=\"hex\" /> HEX: {{ hex }} </div>\n    <div class=\"format\"> <nz-color-picker nzFormat=\"hsb\" [(ngModel)]=\"hsb\" /> HSB: {{ hsb }} </div>\n    <div class=\"format\"> <nz-color-picker nzFormat=\"rgb\" [(ngModel)]=\"rgb\" /> RGB: {{ rgb }} </div>\n  `,\n  styles: `\n    .format {\n      display: flex;\n      align-items: center;\n      margin-bottom: 12px;\n    }\n\n    nz-color-picker {\n      margin-right: 8px;\n    }\n  `\n})\nexport class NzDemoColorPickerFormatComponent {\n  hex: string = '#1677ff';\n  hsb: string = 'hsb(215, 91%, 100%)';\n  rgb: string = 'rgb(22, 119, 255)';\n}\n"
  },
  {
    "path": "components/color-picker/demo/presets.md",
    "content": "---\norder: 10\ntitle:\n  zh-CN: 预设颜色\n  en-US: Presets\n---\n\n## zh-CN\n\n使用 `nzPresets` 属性可以预设一些颜色，方便用户快速选择。每个预设组可以设置标签、颜色列表、默认展开状态和唯一键值。\n\n## en-US\n\nUse `nzPresets` property to preset some colors for users to choose from quickly. Each preset group can have a label, color list, default open state, and unique key.\n"
  },
  {
    "path": "components/color-picker/demo/presets.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzColorPickerModule, NzPresetColor } from 'ng-zorro-antd/color-picker';\n\n@Component({\n  selector: 'nz-demo-color-picker-presets',\n  imports: [NzColorPickerModule],\n  template: `\n    <div style=\"display: flex; flex-direction: column; gap: 16px;\">\n      <div>\n        <h4>Basic Presets</h4>\n        <nz-color-picker [nzPresets]=\"basicPresets\" nzValue=\"#1677ff\" />\n      </div>\n\n      <div>\n        <h4>Multiple Preset Groups</h4>\n        <nz-color-picker [nzPresets]=\"multiplePresets\" nzValue=\"#52c41a\" />\n      </div>\n\n      <div>\n        <h4>Custom Preset with Collapsed State</h4>\n        <nz-color-picker [nzPresets]=\"customPresets\" nzValue=\"#722ed1\" />\n      </div>\n    </div>\n  `\n})\nexport class NzDemoColorPickerPresetsComponent {\n  basicPresets: NzPresetColor[] = [\n    {\n      label: 'Recommended',\n      colors: [\n        '#000000',\n        '#000000E0',\n        '#000000A6',\n        '#00000073',\n        '#00000040',\n        '#00000026',\n        '#0000001A',\n        '#00000012',\n        '#0000000A',\n        '#00000005'\n      ]\n    },\n    {\n      label: 'Recent',\n      colors: [\n        '#F5222D',\n        '#FA8C16',\n        '#FADB14',\n        '#8BBB11',\n        '#52C41A',\n        '#13A8A8',\n        '#1677FF',\n        '#2F54EB',\n        '#722ED1',\n        '#EB2F96'\n      ]\n    }\n  ];\n\n  multiplePresets: NzPresetColor[] = [\n    {\n      label: 'Primary Colors',\n      colors: ['#1677ff', '#52c41a', '#faad14', '#f5222d', '#722ed1'],\n      key: 'primary'\n    },\n    {\n      label: 'Secondary Colors',\n      colors: ['#13c2c2', '#eb2f96', '#fa541c', '#a0d911', '#2f54eb'],\n      key: 'secondary'\n    },\n    {\n      label: 'Neutral Colors',\n      colors: ['#000000', '#434343', '#666666', '#999999', '#cccccc'],\n      key: 'neutral'\n    }\n  ];\n\n  customPresets: NzPresetColor[] = [\n    {\n      label: 'Brand Colors',\n      colors: ['#1677ff', '#69c0ff', '#bae7ff', '#e6f7ff'],\n      defaultOpen: true,\n      key: 'brand'\n    },\n    {\n      label: 'Success Colors',\n      colors: ['#52c41a', '#95de64', '#b7eb8f', '#d9f7be'],\n      defaultOpen: false,\n      key: 'success'\n    },\n    {\n      label: 'Warning Colors',\n      colors: ['#faad14', '#ffc53d', '#ffd666', '#ffe58f'],\n      defaultOpen: false,\n      key: 'warning'\n    },\n    {\n      label: 'Error Colors',\n      colors: ['#f5222d', '#ff4d4f', '#ff7875', '#ffa39e'],\n      defaultOpen: false,\n      key: 'error'\n    }\n  ];\n}\n"
  },
  {
    "path": "components/color-picker/demo/show-text.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 显示颜色文本\n  en-US: Show Color Text\n---\n\n## zh-CN\n\n渲染触发器的默认文本, `nzShowText` 为 `true` 时生效。\n\n## en-US\n\nThe default text of the rendering trigger, effective when `nzShowText` is `true`.\n"
  },
  {
    "path": "components/color-picker/demo/show-text.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzColorPickerModule } from 'ng-zorro-antd/color-picker';\n\n@Component({\n  selector: 'nz-demo-color-picker-show-text',\n  imports: [NzColorPickerModule],\n  template: `<nz-color-picker nzShowText />`\n})\nexport class NzDemoColorPickerShowTextComponent {}\n"
  },
  {
    "path": "components/color-picker/demo/size.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 触发器尺寸大小\n  en-US: Trigger size\n---\n\n## zh-CN\n\n触发器有大、中、小三种尺寸\n\n## en-US\n\nThe trigger has three sizes: large, medium and small.\n"
  },
  {
    "path": "components/color-picker/demo/size.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzColorPickerModule } from 'ng-zorro-antd/color-picker';\n\n@Component({\n  selector: 'nz-demo-color-picker-size',\n  imports: [NzColorPickerModule],\n  template: `\n    <nz-color-picker nzSize=\"large\" />\n    <br />\n    <br />\n    <nz-color-picker />\n    <br />\n    <br />\n    <nz-color-picker nzSize=\"small\" />\n  `\n})\nexport class NzDemoColorPickerSizeComponent {}\n"
  },
  {
    "path": "components/color-picker/demo/trigger.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 自定义触发事件\n  en-US: Custom Trigger Event\n---\n\n## zh-CN\n\n自定义颜色面板的触发事件，提供 `click` 和 `hover` 两个选项。\n\n## en-US\n\nTriggers event for customizing color panels, provide options `click` and `hover`.\n"
  },
  {
    "path": "components/color-picker/demo/trigger.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzColorPickerModule } from 'ng-zorro-antd/color-picker';\n\n@Component({\n  selector: 'nz-demo-color-picker-trigger',\n  imports: [NzColorPickerModule],\n  template: `<nz-color-picker nzTrigger=\"hover\" />`\n})\nexport class NzDemoColorPickerTriggerComponent {}\n"
  },
  {
    "path": "components/color-picker/demo/use.md",
    "content": "---\norder: 12\ntitle:\n  zh-CN: 结合表单使用\n  en-US: Use with forms\n---\n\n## zh-CN\n\n`<nz-color-picker formControlName=\"color\"></nz-color-picker>`\n\n## en-US\n\n`<nz-color-picker formControlName=\"color\"></nz-color-picker>`\n"
  },
  {
    "path": "components/color-picker/demo/use.ts",
    "content": "import { Component, inject } from '@angular/core';\nimport { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzColorPickerModule } from 'ng-zorro-antd/color-picker';\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-color-picker-use',\n  imports: [ReactiveFormsModule, NzButtonModule, NzColorPickerModule, NzFormModule, NzInputModule],\n  template: `\n    <form nz-form [formGroup]=\"validateForm\" (ngSubmit)=\"submitForm()\">\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"4\">name</nz-form-label>\n        <nz-form-control [nzSpan]=\"16\">\n          <input nz-input formControlName=\"username\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"4\">color</nz-form-label>\n        <nz-form-control [nzSpan]=\"16\">\n          <nz-color-picker formControlName=\"colorPicker\" nzShowText />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-control>\n          <button nz-button nzType=\"primary\">submit</button>\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `\n})\nexport class NzDemoColorPickerUseComponent {\n  private formBuilder = inject(FormBuilder);\n  validateForm = this.formBuilder.group({\n    username: ['color-picker', [Validators.required]],\n    colorPicker: ['#1677ff']\n  });\n\n  submitForm(): void {\n    console.log(this.validateForm.value);\n  }\n}\n"
  },
  {
    "path": "components/color-picker/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Entry\ntitle: ColorPicker\ntag: 16.2.0\ncover: 'https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*PpY4RYNM8UcAAAAAAAAAAAAADrJ8AQ/original'\ndescription: Used for color selection.\n---\n\n## When To Use\n\nUsed when the user needs to customize the color selection.\n\n## API\n\n### nz-color-picker\n\n| Parameter            | Description                           | Type                                               | Default     | Version |\n| -------------------- | ------------------------------------- | -------------------------------------------------- | ----------- | ------- |\n| `[nzFormat]`         | Format of color                       | `'rgb' \\| 'hex' \\| 'hsb'`                          | `'hex'`     |\n| `[nzValue]`          | Value of color                        | `string \\| NzColor`                                | -           |\n| `[nzSize]`           | Setting the trigger size              | `'large' \\| 'small' \\| 'default'`                  | `'default'` |\n| `[nzDefaultValue]`   | Default value of color                | `string \\| NzColor`                                | `false`     |\n| `[nzAllowClear]`     | Allow clearing color selected         | `boolean`                                          | `false`     |\n| `[nzTrigger]`        | ColorPicker trigger mode              | `'hover' \\| 'click'`                               | `'click'`   |\n| `[nzShowText]`       | Show color text                       | `boolean`                                          | `false`     |\n| `[nzOpen]`           | Whether to show popups                | `boolean`                                          | `false`     |\n| `[nzDisabled]`       | Disable ColorPicker                   | `boolean`                                          | `false`     |\n| `[nzDisabledAlpha]`  | Disable Alpha                         | `boolean`                                          | `false`     |\n| `[nzTitle]`          | Setting the title of the color picker | `TemplateRef<void> \\| string`                      | -           |\n| `[nzPresets]`        | Preset colors                         | `NzColorPickerPresetsItem[]`                       | -           | 21.0.0  |\n| `(nzOnChange)`       | Callback when value is changed        | `EventEmitter<{ color: NzColor; format: string }>` | -           |\n| `(nzOnClear)`        | Called when clear                     | `EventEmitter<boolean>`                            | -           |\n| `(nzOnFormatChange)` | Callback when `format` is changed     | `EventEmitter<'rgb'｜'hex'｜'hsb'>`                | -           |\n| `(nzOnOpenChange)`   | Callback for opening the color panel  | `EventEmitter<boolean>`                            | -           |\n\n### nz-color-block\n\n| Parameter     | Description                            | Type                              | Default     |\n| ------------- | -------------------------------------- | --------------------------------- | ----------- |\n| `[nzColor]`   | Module colors                          | `string`                          | `'#1677ff'` |\n| `[nzSize]`    | Color block size                       | `'large' \\| 'small' \\| 'default'` | `'default'` |\n| `[nzOnClick]` | Callbacks for clicking on color blocks | `EventEmitter<void>`              | -           |\n\n### NzColor\n\n| Parameter     | Description                                                                       | Type                                                    | Default |\n| ------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------- | ------- |\n| `toHex`       | Convert to `hex` format characters, the return type like: `1677ff`                | `() => string`                                          | -       |\n| `toHexString` | Convert to `hex` format color string, the return type like: `#1677ff`             | `() => string`                                          | -       |\n| `toHsb`       | Convert to `hsb` object                                                           | `() => ({ h: number, s: number, b: number, a number })` | -       |\n| `toHsbString` | Convert to `hsb` format color string, the return type like: `hsb(215, 91%, 100%)` | `() => string`                                          | -       |\n| `toRgb`       | Convert to `rgb` object                                                           | `() => ({ r: number, g: number, b: number, a number })` | -       |\n| `toRgbString` | Convert to `rgb` format color string, the return type like: `rgb(22, 119, 255)`   | `() => string`                                          | -       |\n\n## FAQ\n\n### Q: The overlay layer element does not follow the scroll position when scrolling\n\nBy default, the overlay layer element uses body as the scroll container. If using another scroll container, add\nthe [CdkScrollable](https://material.angular.dev/cdk/scrolling/api#CdkScrollable) directive to the custom scroll\ncontainer element.\nNote: You need to import the `CdkScrollable` directive or `ScrollingModule` module from `@angular/cdk/scrolling`.\n"
  },
  {
    "path": "components/color-picker/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 颜色选择器\ntype: 数据录入\ntitle: ColorPicker\ntag: 16.2.0\ncover: 'https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*PpY4RYNM8UcAAAAAAAAAAAAADrJ8AQ/original'\ndescription: 用于颜色选择。\n---\n\n## 何时使用\n\n当用户需要自定义颜色选择的时候使用。\n\n## API\n\n### nz-color-picker\n\n| 参数                 | 说明                 | 类型                                               | 默认值      | 版本   |\n| -------------------- | -------------------- | -------------------------------------------------- | ----------- | ------ |\n| `[nzFormat]`         | 颜色格式             | `'rgb' \\| 'hex' \\| 'hsb'`                          | `'hex'`     |\n| `[nzValue]`          | 颜色的值             | `string \\| NzColor`                                | -           |\n| `[nzSize]`           | 设置触发器大小       | `'large' \\| 'small' \\| 'default'`                  | `'default'` |\n| `[nzDefaultValue]`   | 颜色默认的值         | `string \\| NzColor`                                | -           |\n| `[nzAllowClear]`     | 允许清除选择的颜色   | `boolean`                                          | `false`     |\n| `[nzTrigger]`        | 颜色选择器的触发模式 | `'hover' \\| 'click'`                               | `'click'`   |\n| `[nzShowText]`       | 显示颜色文本         | `boolean`                                          | `false`     |\n| `[nzOpen]`           | 是否显示弹出窗口     | `boolean`                                          | `false`     |\n| `[nzDisabled]`       | 禁用颜色选择器       | `boolean`                                          | `false`     |\n| `[nzDisabledAlpha]`  | 禁用透明度           | `boolean`                                          | `false`     |\n| `[nzTitle]`          | 设置颜色选择器的标题 | `TemplateRef<void> \\| string`                      | -           |\n| `[nzPresets]`        | 预设的颜色           | `NzColorPickerPresetsItem[]`                       | -           | 21.0.0 |\n| `(nzOnChange)`       | 颜色变化的回调       | `EventEmitter<{ color: NzColor; format: string }>` | -           |\n| `(nzOnClear)`        | 清除的回调           | `EventEmitter<boolean>`                            | -           |\n| `(nzOnFormatChange)` | 颜色格式变化的回调   | `EventEmitter<'rgb'｜'hex'｜'hsb'>`                | -           |\n| `(nzOnOpenChange)`   | 打开颜色面板的回调   | `EventEmitter<boolean>`                            | -           |\n\n### nz-color-block\n\n| 参数          | 说明             | 类型                              | 默认值      |\n| ------------- | ---------------- | --------------------------------- | ----------- |\n| `[nzColor]`   | 模块的颜色       | `string`                          | `'#1677ff'` |\n| `[nzSize]`    | 色彩块的大小     | `'large' \\| 'small' \\| 'default'` | `'default'` |\n| `[nzOnClick]` | 点击色彩块的回调 | `EventEmitter<void>`              | -           |\n\n### NzColor\n\n| 参数          | 说明                                                           | 类型                                                    | 默认值 |\n| ------------- | -------------------------------------------------------------- | ------------------------------------------------------- | ------ |\n| `toHex`       | 转换成 `hex` 格式字符，返回格式如：`1677ff`                    | `() => string`                                          | -      |\n| `toHexString` | 转换成 `hex` 格式颜色字符串，返回格式如：`#1677ff`             | `() => string`                                          | -      |\n| `toHsb`       | 转换成 `hsb` 对象                                              | `() => ({ h: number, s: number, b: number, a number })` | -      |\n| `toHsbString` | 转换成 `hsb` 格式颜色字符串，返回格式如：`hsb(215, 91%, 100%)` | `() => string`                                          | -      |\n| `toRgb`       | 转换成 `rgb` 对象                                              | `() => ({ r: number, g: number, b: number, a number })` | -      |\n| `toRgbString` | 转换成 `rgb` 格式颜色字符串，返回格式如：`rgb(22, 119, 255)`   | `() => string`                                          | -      |\n\n## FAQ\n\n### Q：滚动时浮层元素没有跟随滚动位置\n\n默认情况下，浮层元素使用 `body` 作为滚动容器，如果使用了其他滚动容器，在自定义滚动容器元素上添加 [CdkScrollable](https://material.angular.dev/cdk/scrolling/api#CdkScrollable) 指令。\n注意：您需要从 `@angular/cdk/scrolling` 导入 `CdkScrollable` 指令或 `ScrollingModule` 模块。\n"
  },
  {
    "path": "components/color-picker/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/color-picker/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/color-picker/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './typings';\nexport * from './color-picker.component';\nexport * from './color-block.component';\nexport * from './color-picker.module';\n"
  },
  {
    "path": "components/color-picker/src/components/gradient.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';\n\nimport { Color } from '../interfaces/color';\nimport { HsbaColorType } from '../interfaces/type';\nimport { generateColor } from '../util/util';\n\n@Directive({\n  selector: 'color-gradient',\n  host: {\n    class: 'ant-color-picker-gradient',\n    '[style.background]': `'linear-gradient(' + direction + ', ' + gradientColors + ')'`\n  }\n})\nexport class GradientDirective implements OnInit, OnChanges {\n  @Input() colors: Color[] | string[] = [];\n  @Input() direction: string = 'to right';\n  @Input() type: HsbaColorType = 'hue';\n\n  gradientColors: string = '';\n\n  ngOnInit(): void {\n    this.useMemo();\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { colors, type } = changes;\n    if (colors || type) {\n      this.useMemo();\n    }\n  }\n\n  useMemo(): void {\n    this.gradientColors = this.colors\n      .map((color, idx) => {\n        const result = generateColor(color);\n        if (this.type === 'alpha' && idx === this.colors.length - 1) {\n          result.setAlpha(1);\n        }\n        return result.toRgbString();\n      })\n      .join(',');\n  }\n}\n"
  },
  {
    "path": "components/color-picker/src/components/handler.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, Input } from '@angular/core';\n\ntype HandlerSize = 'default' | 'small';\n\n@Directive({\n  selector: 'color-handler',\n  host: {\n    class: 'ant-color-picker-handler',\n    '[style.background-color]': 'color',\n    '[class.ant-color-picker-handler-sm]': `size === 'small'`\n  }\n})\nexport class HandlerDirective {\n  @Input() color: string | null = null;\n  @Input() size: HandlerSize = 'default';\n}\n"
  },
  {
    "path": "components/color-picker/src/components/picker.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  AfterViewInit,\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DOCUMENT,\n  ElementRef,\n  EventEmitter,\n  inject,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  SimpleChanges,\n  ViewChild\n} from '@angular/core';\n\nimport { HandlerDirective } from './handler.directive';\nimport { Color } from '../interfaces/color';\nimport { HsbaColorType, TransformOffset } from '../interfaces/type';\nimport { calculateColor, calculateOffset } from '../util/util';\n\ntype EventType = MouseEvent | TouchEvent;\n\ntype EventHandle = (e: EventType) => void;\n\nfunction getPosition(e: EventType): { pageX: number; pageY: number } {\n  const obj = 'touches' in e ? e.touches[0] : e;\n  const scrollXOffset = document.documentElement.scrollLeft || document.body.scrollLeft || window.pageXOffset;\n  const scrollYOffset = document.documentElement.scrollTop || document.body.scrollTop || window.pageYOffset;\n  return { pageX: obj.pageX - scrollXOffset, pageY: obj.pageY - scrollYOffset };\n}\n\n@Component({\n  // eslint-disable-next-line @angular-eslint/component-selector\n  selector: 'color-picker',\n  imports: [HandlerDirective],\n  template: `\n    <div class=\"ant-color-picker-palette\">\n      <div #transform class=\"ant-color-picker-transform\" [style.left.px]=\"offsetValue.x\" [style.top.px]=\"offsetValue.y\">\n        <color-handler [color]=\"toRgbString()\" />\n      </div>\n      <div class=\"ant-color-picker-saturation\" [style.background-color]=\"toHsb()\"></div>\n    </div>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    class: 'ant-color-picker-select',\n    '(mousedown)': 'dragStartHandle($event)',\n    '(touchstart)': 'dragStartHandle($event)'\n  }\n})\nexport class PickerComponent implements OnInit, AfterViewInit, OnChanges {\n  private document = inject(DOCUMENT);\n  private cdr = inject(ChangeDetectorRef);\n  containerRef = inject<ElementRef<HTMLDivElement>>(ElementRef);\n\n  @ViewChild('transform', { static: true }) transformRef!: ElementRef<HTMLDivElement>;\n\n  @Input() color: Color | null = null;\n  @Output() readonly nzOnChange = new EventEmitter<Color>();\n  @Output() readonly nzOnChangeComplete = new EventEmitter<HsbaColorType>();\n  @Input({ transform: booleanAttribute }) disabled: boolean = false;\n\n  offsetValue: TransformOffset = { x: 0, y: 0 };\n  dragRef: boolean = false;\n\n  mouseMoveRef: (e: MouseEvent | TouchEvent) => void = () => null;\n  mouseUpRef: (e: MouseEvent | TouchEvent) => void = () => null;\n\n  toRgbString(): string {\n    return this.color?.toRgbString() as string;\n  }\n\n  toHsb(): string {\n    return `hsl(${this.color?.toHsb().h},100%, 50%)`;\n  }\n\n  ngOnInit(): void {\n    this.document.removeEventListener('mousemove', this.mouseMoveRef);\n    this.document.removeEventListener('mouseup', this.mouseUpRef);\n    this.document.removeEventListener('touchmove', this.mouseMoveRef);\n    this.document.removeEventListener('touchend', this.mouseUpRef);\n    this.mouseMoveRef = () => null;\n    this.mouseUpRef = () => null;\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { color } = changes;\n\n    if (color) {\n      if (!this.dragRef && this.containerRef && this.transformRef) {\n        const calcOffset = calculateOffset(\n          this.containerRef.nativeElement,\n          this.transformRef.nativeElement,\n          this.color\n        );\n        if (calcOffset) {\n          this.offsetValue = calcOffset;\n          this.cdr.detectChanges();\n        }\n      }\n    }\n  }\n\n  ngAfterViewInit(): void {\n    if (!this.dragRef && this.containerRef && this.transformRef) {\n      const calcOffset = calculateOffset(this.containerRef.nativeElement, this.transformRef.nativeElement, this.color);\n      if (calcOffset) {\n        this.offsetValue = calcOffset;\n        this.cdr.detectChanges();\n      }\n    }\n  }\n\n  dragStartHandle(e: MouseEvent | TouchEvent): void {\n    this.onDragStart(e);\n  }\n\n  updateOffset: EventHandle = (e: EventType, direction: 'x' | 'y' = 'y') => {\n    const { pageX, pageY } = getPosition(e);\n    const {\n      x: rectX,\n      y: rectY,\n      width,\n      height\n    } = this.containerRef?.nativeElement?.getBoundingClientRect() || { x: 0, y: 0, width: 0, height: 0 };\n    const { width: targetWidth, height: targetHeight } = this.transformRef?.nativeElement?.getBoundingClientRect() || {\n      width: 0,\n      height: 0\n    };\n\n    const centerOffsetX = targetWidth / 2;\n    const centerOffsetY = targetHeight / 2;\n\n    const offsetX = Math.max(0, Math.min(pageX - rectX, width)) - centerOffsetX;\n    const offsetY = Math.max(0, Math.min(pageY - rectY, height)) - centerOffsetY;\n\n    const calcOffset = {\n      x: offsetX,\n      y: direction === 'x' ? this.offsetValue.y : offsetY\n    };\n    // Exclusion of boundary cases\n    if ((targetWidth === 0 && targetHeight === 0) || targetWidth !== targetHeight) {\n      return;\n    }\n    this.offsetValue = calcOffset;\n    this.nzOnChange.emit(\n      calculateColor(calcOffset, this.containerRef.nativeElement, this.transformRef.nativeElement, this.color)\n    );\n    this.cdr.detectChanges();\n  };\n\n  onDragMove: EventHandle = (e: EventType) => {\n    e.preventDefault();\n    this.updateOffset(e);\n  };\n\n  onDragStop: EventHandle = (e: EventType) => {\n    e.preventDefault();\n    this.dragRef = false;\n    this.document.removeEventListener('mousemove', this.onDragMove);\n    this.document.removeEventListener('mouseup', this.mouseUpRef);\n    this.document.removeEventListener('touchmove', this.mouseMoveRef);\n    this.document.removeEventListener('touchend', this.mouseUpRef);\n    this.mouseMoveRef = () => null;\n    this.mouseUpRef = () => null;\n    this.nzOnChangeComplete?.emit();\n  };\n\n  onDragStart: EventHandle = (e: EventType) => {\n    if (this.disabled) {\n      return;\n    }\n    this.updateOffset(e);\n    this.dragRef = true;\n    this.document.addEventListener('mousemove', this.onDragMove);\n    this.document.addEventListener('mouseup', this.onDragStop);\n    this.document.addEventListener('touchmove', this.onDragMove);\n    this.document.addEventListener('touchend', this.onDragStop);\n    this.mouseMoveRef = this.onDragMove;\n    this.mouseUpRef = this.onDragStop;\n    this.cdr.markForCheck();\n  };\n}\n"
  },
  {
    "path": "components/color-picker/src/components/slider.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  AfterViewInit,\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DOCUMENT,\n  ElementRef,\n  EventEmitter,\n  inject,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  SimpleChanges,\n  ViewChild\n} from '@angular/core';\n\nimport { GradientDirective } from './gradient.directive';\nimport { HandlerDirective } from './handler.directive';\nimport { Color } from '../interfaces/color';\nimport { HsbaColorType, TransformOffset } from '../interfaces/type';\nimport { calculateColor, calculateOffset } from '../util/util';\n\ntype EventType = MouseEvent | TouchEvent;\n\ntype EventHandle = (e: EventType) => void;\n\nfunction getPosition(e: EventType): { pageX: number; pageY: number } {\n  const obj = 'touches' in e ? e.touches[0] : e;\n  const scrollXOffset = document.documentElement.scrollLeft || document.body.scrollLeft || window.pageXOffset;\n  const scrollYOffset = document.documentElement.scrollTop || document.body.scrollTop || window.pageYOffset;\n  return { pageX: obj.pageX - scrollXOffset, pageY: obj.pageY - scrollYOffset };\n}\n\n@Component({\n  // eslint-disable-next-line @angular-eslint/component-selector\n  selector: 'color-slider',\n  imports: [GradientDirective, HandlerDirective],\n  template: `\n    <div class=\"ant-color-picker-palette\">\n      <div #transform class=\"ant-color-picker-transform\" [style.left.px]=\"offsetValue.x\" [style.top.px]=\"offsetValue.y\">\n        <color-handler size=\"small\" [color]=\"value\" />\n      </div>\n      <color-gradient [colors]=\"gradientColors\" [direction]=\"direction\" [type]=\"type\" />\n    </div>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    class: 'ant-color-picker-slider',\n    '[class]': `'ant-color-picker-slider-' + type`,\n    '(mousedown)': `dragStartHandle($event)`,\n    '(touchstart)': `dragStartHandle($event)`\n  }\n})\nexport class SliderComponent implements OnInit, AfterViewInit, OnChanges {\n  private document = inject(DOCUMENT);\n  private cdr = inject(ChangeDetectorRef);\n  containerRef = inject<ElementRef<HTMLDivElement>>(ElementRef);\n\n  @ViewChild('transform', { static: true }) transformRef!: ElementRef<HTMLDivElement>;\n\n  @Input() gradientColors: string[] = [];\n  @Input() direction: string = 'to right';\n  @Input() type: HsbaColorType = 'hue';\n  @Input() color: Color | null = null;\n  @Input() value: string | null = null;\n  @Input({ transform: booleanAttribute }) disabled: boolean = false;\n  @Output() readonly nzOnChange = new EventEmitter<Color>();\n  @Output() readonly nzOnChangeComplete = new EventEmitter<HsbaColorType>();\n\n  offsetValue: TransformOffset = { x: 0, y: 0 };\n  dragRef: boolean = false;\n  mouseMoveRef: (e: MouseEvent | TouchEvent) => void = () => null;\n  mouseUpRef: (e: MouseEvent | TouchEvent) => void = () => null;\n\n  ngOnInit(): void {\n    this.document.removeEventListener('mousemove', this.mouseMoveRef);\n    this.document.removeEventListener('mouseup', this.mouseUpRef);\n    this.document.removeEventListener('touchmove', this.mouseMoveRef);\n    this.document.removeEventListener('touchend', this.mouseUpRef);\n    this.mouseMoveRef = () => null;\n    this.mouseUpRef = () => null;\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { color } = changes;\n\n    if (color) {\n      if (!this.dragRef && this.containerRef && this.transformRef) {\n        const calcOffset = calculateOffset(\n          this.containerRef.nativeElement,\n          this.transformRef.nativeElement,\n          this.color,\n          this.type\n        );\n        if (calcOffset) {\n          this.offsetValue = calcOffset;\n          this.cdr.detectChanges();\n        }\n      }\n    }\n  }\n\n  ngAfterViewInit(): void {\n    if (!this.dragRef && this.containerRef && this.transformRef) {\n      const calcOffset = calculateOffset(\n        this.containerRef.nativeElement,\n        this.transformRef.nativeElement,\n        this.color,\n        this.type\n      );\n      if (calcOffset) {\n        this.offsetValue = calcOffset;\n        this.cdr.detectChanges();\n      }\n    }\n  }\n\n  dragStartHandle(e: MouseEvent | TouchEvent): void {\n    this.onDragStart(e);\n  }\n\n  updateOffset: EventHandle = (e: EventType, direction: 'x' | 'y' = 'x') => {\n    const { pageX, pageY } = getPosition(e);\n    const {\n      x: rectX,\n      y: rectY,\n      width,\n      height\n    } = this.containerRef?.nativeElement?.getBoundingClientRect() || { x: 0, y: 0, width: 0, height: 0 };\n    const { width: targetWidth, height: targetHeight } = this.transformRef?.nativeElement?.getBoundingClientRect() || {\n      width: 0,\n      height: 0\n    };\n\n    const centerOffsetX = targetWidth / 2;\n    const centerOffsetY = targetHeight / 2;\n\n    const offsetX = Math.max(0, Math.min(pageX - rectX, width)) - centerOffsetX;\n    const offsetY = Math.max(0, Math.min(pageY - rectY, height)) - centerOffsetY;\n\n    const calcOffset = {\n      x: offsetX,\n      y: direction === 'x' ? this.offsetValue.y : offsetY\n    };\n\n    // Exclusion of boundary cases\n    if ((targetWidth === 0 && targetHeight === 0) || targetWidth !== targetHeight) {\n      return;\n    }\n\n    this.offsetValue = calcOffset;\n    this.nzOnChange.emit(\n      calculateColor(\n        calcOffset,\n        this.containerRef.nativeElement,\n        this.transformRef.nativeElement,\n        this.color,\n        this.type\n      )\n    );\n    this.cdr.detectChanges();\n  };\n\n  onDragMove: EventHandle = (e: EventType) => {\n    e.preventDefault();\n    this.updateOffset(e);\n  };\n\n  onDragStop: EventHandle = (e: EventType) => {\n    e.preventDefault();\n    this.dragRef = false;\n    this.document.removeEventListener('mousemove', this.onDragMove);\n    this.document.removeEventListener('mouseup', this.mouseUpRef);\n    this.document.removeEventListener('touchmove', this.mouseMoveRef);\n    this.document.removeEventListener('touchend', this.mouseUpRef);\n    this.mouseMoveRef = () => null;\n    this.mouseUpRef = () => null;\n    this.nzOnChangeComplete?.emit(this.type);\n  };\n\n  onDragStart: EventHandle = (e: EventType) => {\n    if (this.disabled) {\n      return;\n    }\n    this.updateOffset(e);\n    this.dragRef = true;\n    this.document.addEventListener('mousemove', this.onDragMove);\n    this.document.addEventListener('mouseup', this.onDragStop);\n    this.document.addEventListener('touchmove', this.onDragMove);\n    this.document.addEventListener('touchend', this.onDragStop);\n    this.mouseMoveRef = this.onDragMove;\n    this.mouseUpRef = this.onDragStop;\n    this.cdr.markForCheck();\n  };\n}\n"
  },
  {
    "path": "components/color-picker/src/interfaces/color.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ColorInput, HSVA, Numberify, TinyColor } from '@ctrl/tinycolor';\n\nimport type { ColorGenInput, HSB, HSBA } from './type';\n\nexport const getRoundNumber = (value: number): number => Math.round(Number(value || 0));\n\nconst convertHsb2Hsv = (color: ColorGenInput): ColorInput => {\n  if (color && typeof color === 'object' && 'h' in color && 'b' in color) {\n    const { b, ...resets } = color as HSB;\n    return {\n      ...resets,\n      v: b\n    };\n  }\n  if (typeof color === 'string' && /hsb/.test(color)) {\n    return color.replace(/hsb/, 'hsv');\n  }\n  return color as ColorInput;\n};\n\nexport class Color extends TinyColor {\n  constructor(color: ColorGenInput) {\n    super(convertHsb2Hsv(color));\n  }\n\n  toHsbString(): string {\n    const hsb = this.toHsb();\n    const saturation = getRoundNumber(hsb.s * 100);\n    const lightness = getRoundNumber(hsb.b * 100);\n    const hue = getRoundNumber(hsb.h);\n    const alpha = hsb.a;\n    const hsbString = `hsb(${hue}, ${saturation}%, ${lightness}%)`;\n    const hsbaString = `hsba(${hue}, ${saturation}%, ${lightness}%, ${alpha.toFixed(alpha === 0 ? 0 : 2)})`;\n    return alpha === 1 ? hsbString : hsbaString;\n  }\n\n  toHsb(): Numberify<HSBA> {\n    let hsv = this.toHsv();\n    if (typeof this.originalInput === 'object' && this.originalInput) {\n      if ('h' in this.originalInput) {\n        hsv = this.originalInput as Numberify<HSVA>;\n      }\n    }\n\n    const { v: _, ...resets } = hsv;\n    return {\n      ...resets,\n      b: hsv.v\n    };\n  }\n}\n"
  },
  {
    "path": "components/color-picker/src/interfaces/type.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport type { Color } from './color';\n\nexport interface HSB {\n  h: number | string;\n  s: number | string;\n  b: number | string;\n}\n\nexport interface RGB {\n  r: number | string;\n  g: number | string;\n  b: number | string;\n}\n\nexport interface HSBA extends HSB {\n  a: number;\n}\n\nexport interface RGBA extends RGB {\n  a: number;\n}\n\nexport type ColorGenInput<T = Color> = string | number | RGB | RGBA | HSB | HSBA | T;\n\nexport type HsbaColorType = 'hue' | 'alpha';\n\nexport interface TransformOffset {\n  x: number;\n  y: number;\n}\n\nexport interface BaseColorPickerProps {\n  color?: Color;\n  prefixCls?: string;\n  disabled?: boolean;\n  onChange?: (color: Color, type?: HsbaColorType) => void;\n  onChangeComplete?: (type?: HsbaColorType) => void;\n}\n\nexport type ColorValue = ColorGenInput | undefined;\n\nexport interface ColorPickerProps extends BaseColorPickerProps {\n  value?: ColorGenInput;\n  defaultValue?: ColorGenInput;\n  className?: string;\n  // style?: CSSProperties;\n  style?: string;\n  /** Get panel element  */\n  panelRender?: (panel: Element) => Element;\n  /** Disabled alpha selection */\n  disabledAlpha?: boolean;\n}\n"
  },
  {
    "path": "components/color-picker/src/ng-antd-color-block.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, DebugElement, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { NgAntdColorBlockComponent } from './ng-antd-color-block.component';\n\ndescribe('NgxColorBlockComponent', () => {\n  let component: NzxTestColorBlockComponent;\n  let fixture: ComponentFixture<NzxTestColorBlockComponent>;\n  let resultEl: DebugElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzxTestColorBlockComponent);\n    fixture.detectChanges();\n    component = fixture.componentInstance;\n    resultEl = fixture.debugElement.query(By.directive(NgAntdColorBlockComponent));\n  });\n\n  it('color-block color', () => {\n    component.color = '#ff6600';\n    fixture.detectChanges();\n    expect(resultEl.nativeElement.querySelector('.ant-color-picker-color-block-inner').style.backgroundColor).toBe(\n      'rgb(255, 102, 0)'\n    );\n  });\n\n  it('color-block click', () => {\n    fixture.detectChanges();\n    resultEl.nativeElement.click();\n    expect(component.isClick).toBeTrue();\n  });\n});\n\n@Component({\n  imports: [NgAntdColorBlockComponent],\n  template: `<ng-antd-color-block [color]=\"color\" (nzOnClick)=\"clickHandle()\" />`\n})\nexport class NzxTestColorBlockComponent {\n  color = '#1677ff';\n  isClick: boolean = false;\n\n  clickHandle(): void {\n    this.isClick = true;\n  }\n}\n"
  },
  {
    "path": "components/color-picker/src/ng-antd-color-block.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';\n\nimport type { Color } from './interfaces/color';\nimport { defaultColor, generateColor } from './util/util';\n\n@Component({\n  // eslint-disable-next-line @angular-eslint/component-selector\n  selector: 'ng-antd-color-block',\n  template: `<div class=\"ant-color-picker-color-block-inner\" [style.background-color]=\"color\"></div>`,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    class: 'ant-color-picker-color-block ant-color-picker-presets-color',\n    '[class.ant-color-picker-presets-color-checked]': 'isChecked',\n    '[class.ant-color-picker-presets-color-bright]': 'isBright',\n    '(click)': 'nzOnClick.emit()'\n  }\n})\nexport class NgAntdColorBlockComponent {\n  @Input() color: string = defaultColor.toHsbString();\n  @Input() value: Color | null = null;\n  @Output() readonly nzOnClick = new EventEmitter<void>();\n\n  get isChecked(): boolean {\n    if (!this.value) {\n      return false;\n    }\n    const current = generateColor(this.value).toHexString();\n    const colorPreset = generateColor(this.color).toHexString();\n    return current === colorPreset;\n  }\n\n  get isBright(): boolean {\n    const { r, g, b, a } = generateColor(this.color).toRgb();\n    if (a !== undefined && a <= 0.5) return true;\n    const brightness = r * 0.299 + g * 0.587 + b * 0.114;\n    return brightness > 192;\n  }\n}\n"
  },
  {
    "path": "components/color-picker/src/ng-antd-color-picker.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, DebugElement, provideZoneChangeDetection, ViewEncapsulation } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { NzPresetColor } from '../typings';\nimport { Color } from './interfaces/color';\nimport { HsbaColorType } from './interfaces/type';\nimport { NgAntdColorPickerComponent } from './ng-antd-color-picker.component';\n\ndescribe('NgxColorPickerComponent', () => {\n  let component: NzxTestColorPickerComponent;\n  let fixture: ComponentFixture<NzxTestColorPickerComponent>;\n  let resultEl: DebugElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection(), provideNoopAnimations()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzxTestColorPickerComponent);\n    component = fixture.componentInstance;\n    fixture.detectChanges();\n    resultEl = fixture.debugElement.query(By.directive(NgAntdColorPickerComponent));\n  });\n\n  it('color-picker basic', () => {\n    fixture.detectChanges();\n    expect(resultEl.nativeElement.querySelector('.ant-color-picker-color-block-inner').style.backgroundColor).toBe(\n      'rgb(22, 119, 255)'\n    );\n  });\n\n  it('color-picker defaultValue', () => {\n    component.defaultValue = '#ff6600';\n    fixture.detectChanges();\n    expect(resultEl.nativeElement.querySelector('.ant-color-picker-color-block-inner').style.backgroundColor).toBe(\n      'rgb(255, 102, 0)'\n    );\n  });\n\n  it('color-picker disabled', () => {\n    component.disabled = true;\n    fixture.detectChanges();\n    expect(resultEl.nativeElement.querySelector('.ant-color-picker-panel').classList).toContain(\n      'ant-color-picker-panel-disabled'\n    );\n  });\n\n  it('color-picker disabledAlpha', () => {\n    component.disabledAlpha = true;\n    fixture.detectChanges();\n    expect(resultEl.nativeElement.querySelector('.ant-color-picker-slider-group').classList).toContain(\n      'ant-color-picker-slider-group-disabled-alpha'\n    );\n  });\n\n  it('color-picker input color', () => {\n    component.value = '#ff6600';\n    fixture.detectChanges();\n    const dom = fixture.debugElement.nativeElement.querySelector('.ant-color-picker-palette');\n    const handleWrapper = dom.firstChild;\n    expect(dom.firstChild.style.top).toBe(`-${handleWrapper.clientWidth / 2}px`);\n    expect(dom.firstChild.style.left).toBe(`${dom.clientWidth - handleWrapper.clientWidth / 2}px`);\n    expect(resultEl.nativeElement.querySelector('.ant-color-picker-color-block-inner').style.backgroundColor).toBe(\n      'rgb(255, 102, 0)'\n    );\n  });\n\n  it('color-picker slide select', () => {\n    fixture.detectChanges();\n    const element = fixture.debugElement.nativeElement.querySelector('.ant-color-picker-select');\n    const dom = fixture.debugElement.nativeElement.querySelector('.ant-color-picker-palette');\n    const handleWrapper = dom.firstChild;\n    const { x, y } = {\n      x: element.offsetLeft + element.clientWidth + handleWrapper.clientWidth / 2,\n      y: element.offsetTop - handleWrapper.clientWidth / 2\n    };\n    const event = new MouseEvent('mousedown', { clientX: x, clientY: y });\n    const event1 = new MouseEvent('mouseup');\n    element.dispatchEvent(event);\n    element.dispatchEvent(event1);\n\n    expect(dom.firstChild.style.top).toBe(`-${handleWrapper.clientWidth / 2}px`);\n    expect(dom.firstChild.style.left).toBe(`${dom.clientWidth - handleWrapper.clientWidth / 2}px`);\n    expect(resultEl.nativeElement.querySelector('.ant-color-picker-color-block-inner').style.backgroundColor).toBe(\n      'rgb(0, 106, 255)'\n    );\n    expect(component.changeColor?.toRgbString()).toBe('rgb(0, 106, 255)');\n    expect(component.complete).toBe(null);\n  });\n\n  it('color-picker slide hue', () => {\n    fixture.detectChanges();\n    const element = fixture.debugElement.nativeElement.querySelector('.ant-color-picker-slider-hue');\n    const { x, y } = {\n      x: element.offsetLeft + 230,\n      y: element.offsetTop + 4\n    };\n    const event = new MouseEvent('mousedown', { clientX: x, clientY: y });\n    const closeEvent = new MouseEvent('mouseup');\n    element.dispatchEvent(event);\n    element.dispatchEvent(closeEvent);\n    expect(resultEl.nativeElement.querySelector('.ant-color-picker-color-block-inner').style.backgroundColor).toBe(\n      'rgb(255, 22, 22)'\n    );\n    expect(component.changeColor?.toRgbString()).toBe('rgb(255, 22, 22)');\n    expect(component.complete).toBe('hue');\n  });\n\n  it('color-picker slide alpha', () => {\n    fixture.detectChanges();\n    const element = fixture.debugElement.nativeElement.querySelector('.ant-color-picker-slider-alpha');\n    const { x, y } = {\n      x: element.offsetLeft - 6,\n      y: element.offsetTop + 4\n    };\n    const event = new MouseEvent('mousedown', { clientX: x, clientY: y });\n    const closeEvent = new MouseEvent('mouseup');\n    element.dispatchEvent(event);\n    element.dispatchEvent(closeEvent);\n    expect(resultEl.nativeElement.querySelector('.ant-color-picker-color-block-inner').style.backgroundColor).toBe(\n      'rgba(22, 119, 255, 0)'\n    );\n    expect(component.changeColor?.toRgbString()).toBe('rgba(22, 119, 255, 0)');\n    expect(component.complete).toBe('alpha');\n  });\n\n  it('color-picker ngTemplateOutlet', () => {\n    fixture.detectChanges();\n    expect(resultEl.nativeElement.querySelector('.ant-color-picker-header').innerText).toBe('Color Picker Header');\n    expect(resultEl.nativeElement.querySelector('.ant-color-picker-footer').innerText).toBe('Color Picker Footer');\n  });\n\n  it('color-picker presets render and clicking a preset updates color and emits change', () => {\n    component.presets = [\n      { label: 'Recent', colors: ['rgb(255, 0, 0)', '#00ff00'], defaultOpen: true, key: 'recent' },\n      { label: 'Favorites', colors: ['#0000ff'], key: 'fav' }\n    ];\n    fixture.detectChanges();\n\n    const hostEl = resultEl.nativeElement as HTMLElement;\n\n    const items = hostEl.querySelectorAll('.ant-color-picker-presets .ant-collapse-item');\n    expect(items.length).toBe(2);\n\n    const presetBlocks = hostEl.querySelectorAll('.ant-color-picker-presets .ant-color-picker-color-block');\n    expect(presetBlocks.length).toBe(3);\n\n    const firstPreset = hostEl.querySelector('.ant-color-picker-presets .ant-color-picker-color-block') as HTMLElement;\n    firstPreset.dispatchEvent(new MouseEvent('click', { bubbles: true }));\n    fixture.detectChanges();\n\n    expect(component.changeColor?.toRgbString()).toBe('rgb(255, 0, 0)');\n    expect(component.complete).toBe(null);\n\n    const preview = hostEl.querySelector('.ant-color-picker-color-block-inner') as HTMLElement;\n    expect(preview.style.backgroundColor).toBe('rgb(255, 0, 0)');\n  });\n});\n\n@Component({\n  imports: [NgAntdColorPickerComponent],\n  template: `\n    <ng-antd-color-picker\n      [value]=\"value\"\n      [defaultValue]=\"defaultValue\"\n      [disabled]=\"disabled\"\n      [disabledAlpha]=\"disabledAlpha\"\n      [presets]=\"presets\"\n      [panelRenderHeader]=\"title\"\n      [panelRenderFooter]=\"footer\"\n      (nzOnChange)=\"onChange($event)\"\n      (nzOnChangeComplete)=\"onChangeComplete($event)\"\n    />\n    <ng-template #title>\n      <div class=\"ant-color-picker-header\">Color Picker Header</div>\n    </ng-template>\n    <ng-template #footer>\n      <div class=\"ant-color-picker-footer\">Color Picker Footer</div>\n    </ng-template>\n  `,\n  encapsulation: ViewEncapsulation.None,\n  styles: `\n    @import '../../style/testing.less';\n    @import '../style/entry.less';\n  `\n})\nexport class NzxTestColorPickerComponent {\n  value = '';\n  defaultValue = '';\n  disabled = false;\n  disabledAlpha = false;\n  presets: NzPresetColor[] = [];\n\n  changeColor: Color | null = null;\n  complete: HsbaColorType | null = null;\n\n  onChange(value: { color: Color; type?: HsbaColorType }): void {\n    this.changeColor = value.color;\n    this.complete = value?.type || null;\n  }\n\n  onChangeComplete(value: HsbaColorType): void {\n    this.complete = value;\n  }\n}\n"
  },
  {
    "path": "components/color-picker/src/ng-antd-color-picker.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  EventEmitter,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  SimpleChanges,\n  TemplateRef,\n  booleanAttribute,\n  inject\n} from '@angular/core';\n\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\n\nimport { NzPresetColor } from '../typings';\nimport { PickerComponent } from './components/picker.component';\nimport { SliderComponent } from './components/slider.component';\nimport { Color } from './interfaces/color';\nimport { ColorGenInput, ColorValue, HsbaColorType } from './interfaces/type';\nimport { NgAntdColorBlockComponent } from './ng-antd-color-block.component';\nimport { NgAntdColorPresetComponent } from './ng-antd-color-preset.component';\nimport { defaultColor, generateColor } from './util/util';\n\n@Component({\n  // eslint-disable-next-line @angular-eslint/component-selector\n  selector: 'ng-antd-color-picker',\n  imports: [\n    PickerComponent,\n    SliderComponent,\n    NgAntdColorBlockComponent,\n    NgTemplateOutlet,\n    NgAntdColorPresetComponent,\n    NzDividerModule\n  ],\n  template: `\n    <div class=\"ant-color-picker-inner-content\">\n      <div class=\"ant-color-picker-panel\" [class.ant-color-picker-panel-disabled]=\"disabled\">\n        @if (panelRenderHeader) {\n          <ng-template [ngTemplateOutlet]=\"panelRenderHeader\" />\n        }\n        <color-picker\n          [color]=\"colorValue\"\n          (nzOnChange)=\"handleChange($event)\"\n          [disabled]=\"disabled\"\n          (nzOnChangeComplete)=\"nzOnChangeComplete.emit($event)\"\n        />\n        <div class=\"ant-color-picker-slider-container\">\n          <div\n            class=\"ant-color-picker-slider-group\"\n            [class.ant-color-picker-slider-group-disabled-alpha]=\"disabledAlpha\"\n          >\n            <color-slider\n              [color]=\"colorValue\"\n              [value]=\"'hsl(' + colorValue?.toHsb()?.h + ',100%, 50%)'\"\n              [gradientColors]=\"hueColor\"\n              (nzOnChange)=\"handleChange($event, 'hue')\"\n              [disabled]=\"disabled\"\n              (nzOnChangeComplete)=\"nzOnChangeComplete.emit($event)\"\n            />\n            @if (!disabledAlpha) {\n              <color-slider\n                type=\"alpha\"\n                [color]=\"colorValue\"\n                [value]=\"toRgbString\"\n                [gradientColors]=\"gradientColors\"\n                (nzOnChange)=\"handleChange($event, 'alpha')\"\n                [disabled]=\"disabled\"\n                (nzOnChangeComplete)=\"nzOnChangeComplete.emit($event)\"\n              />\n            }\n          </div>\n          <ng-antd-color-block [color]=\"toRgbString\" />\n        </div>\n      </div>\n      @if (panelRenderFooter) {\n        <ng-template [ngTemplateOutlet]=\"panelRenderFooter\" />\n      }\n      @if (presets && presets.length > 0) {\n        <nz-divider nzSize=\"small\" />\n        <ng-antd-color-preset [value]=\"colorValue\" [presets]=\"presets\" (presetSelect)=\"handleChange($event)\" />\n      }\n    </div>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    class: 'ant-color-picker-inner'\n  }\n})\nexport class NgAntdColorPickerComponent implements OnInit, OnChanges {\n  private cdr = inject(ChangeDetectorRef);\n\n  @Input() value: string = '';\n  @Input() defaultValue: ColorValue;\n  @Output() readonly nzOnChange = new EventEmitter<{ color: Color; type?: HsbaColorType }>();\n  @Output() readonly nzOnChangeComplete = new EventEmitter<HsbaColorType>();\n  @Input() panelRenderHeader: TemplateRef<void> | null = null;\n  @Input() panelRenderFooter: TemplateRef<void> | null = null;\n  @Input({ transform: booleanAttribute }) disabledAlpha: boolean = false;\n  @Input({ transform: booleanAttribute }) disabled: boolean = false;\n  @Input() presets: NzPresetColor[] | null = null;\n\n  colorValue: Color | null = null;\n  alphaColor: string = '';\n\n  hueColor: string[] = [\n    'rgb(255, 0, 0) 0%',\n    'rgb(255, 255, 0) 17%',\n    'rgb(0, 255, 0) 33%',\n    'rgb(0, 255, 255) 50%',\n    'rgb(0, 0, 255) 67%',\n    'rgb(255, 0, 255) 83%',\n    'rgb(255, 0, 0) 100%'\n  ];\n\n  gradientColors: string[] = ['rgba(255, 0, 4, 0) 0%', this.alphaColor];\n\n  toRgbString: string = this.colorValue?.toRgbString() || '';\n\n  ngOnInit(): void {\n    this.setColorValue(this.value);\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { value, defaultValue } = changes;\n    if (value || defaultValue) {\n      this.setColorValue(this.value);\n    }\n  }\n\n  hasValue(value: ColorValue): boolean {\n    return !!value;\n  }\n\n  setColorValue(color: ColorValue): void {\n    let mergeState;\n    if (this.hasValue(color)) {\n      mergeState = color;\n    } else if (this.hasValue(this.defaultValue)) {\n      mergeState = this.defaultValue;\n    } else {\n      mergeState = defaultColor;\n    }\n    this.colorValue = generateColor(mergeState as ColorGenInput);\n    this.setAlphaColor(this.colorValue);\n    this.toRgbString = this.colorValue?.toRgbString() || '';\n    this.cdr.detectChanges();\n  }\n\n  setAlphaColor(colorValue: Color): void {\n    const rgb = generateColor(colorValue.toRgbString());\n    this.alphaColor = rgb.toRgbString();\n    this.gradientColors = ['rgba(255, 0, 4, 0) 0%', this.alphaColor];\n    this.cdr.markForCheck();\n  }\n\n  handleChange(color: Color, type?: HsbaColorType): void {\n    this.setColorValue(color);\n    this.nzOnChange.emit({ color, type });\n  }\n}\n"
  },
  {
    "path": "components/color-picker/src/ng-antd-color-picker.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NgAntdColorBlockComponent } from './ng-antd-color-block.component';\nimport { NgAntdColorPickerComponent } from './ng-antd-color-picker.component';\nimport { NgAntdColorPresetComponent } from './ng-antd-color-preset.component';\n\n@NgModule({\n  imports: [NgAntdColorPickerComponent, NgAntdColorBlockComponent, NgAntdColorPresetComponent],\n  exports: [NgAntdColorPickerComponent, NgAntdColorBlockComponent, NgAntdColorPresetComponent]\n})\nexport class NgAntdColorPickerModule {}\n"
  },
  {
    "path": "components/color-picker/src/ng-antd-color-preset.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { dispatchMouseEvent } from 'ng-zorro-antd/core/testing';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NgAntdColorPresetComponent } from './ng-antd-color-preset.component';\n\ndescribe('ng-antd-color-preset', () => {\n  let fixture: ComponentFixture<NgAntdColorPresetComponent>;\n  let component: NgAntdColorPresetComponent;\n\n  beforeEach(async () => {\n    await TestBed.configureTestingModule({\n      providers: [provideNoopAnimations()],\n      imports: [NgAntdColorPresetComponent]\n    }).compileComponents();\n\n    fixture = TestBed.createComponent(NgAntdColorPresetComponent);\n    component = fixture.componentInstance;\n  });\n\n  it('should render collapse panels and colors according to presets', () => {\n    component.presets = [\n      {\n        label: 'Recent',\n        colors: ['#ff0000', '#00ff00'],\n        defaultOpen: true\n      },\n      {\n        label: 'Favorites',\n        colors: ['#0000ff'],\n        defaultOpen: false\n      }\n    ];\n    fixture.detectChanges();\n\n    const host = fixture.nativeElement as HTMLElement;\n    const items = host.querySelectorAll('.ant-collapse-item');\n    expect(items.length).toBe(2);\n\n    const colors = host.querySelectorAll('.ant-color-picker-color-block');\n    expect(colors.length).toBe(3);\n\n    const headers = host.querySelectorAll('.ant-collapse-header');\n    expect(headers[0]?.textContent).toContain('Recent');\n    expect(headers[1]?.textContent).toContain('Favorites');\n  });\n\n  it('should respect defaultOpen state', () => {\n    component.presets = [\n      {\n        label: 'Recent',\n        colors: ['#ff0000', '#00ff00'],\n        defaultOpen: true\n      },\n      {\n        label: 'Favorites',\n        colors: ['#0000ff'],\n        defaultOpen: false\n      }\n    ];\n    fixture.detectChanges();\n\n    const host = fixture.nativeElement as HTMLElement;\n    const items = host.querySelectorAll('.ant-collapse-item');\n    const first = items[0] as HTMLElement;\n    const second = items[1] as HTMLElement;\n\n    expect(first.classList.contains('ant-collapse-item-active')).toBeTrue();\n\n    expect(second.classList.contains('ant-collapse-item-active')).toBeFalse();\n  });\n\n  it('should toggle panel active state when header clicked', fakeAsync(() => {\n    component.presets = [\n      {\n        label: 'Recent',\n        colors: ['#ff0000', '#00ff00'],\n        defaultOpen: true\n      },\n      {\n        label: 'Favorites',\n        colors: ['#0000ff'],\n        defaultOpen: false\n      }\n    ];\n    fixture.detectChanges();\n\n    const host = fixture.nativeElement as HTMLElement;\n    const items = host.querySelectorAll('.ant-collapse-item');\n    const second = items[1] as HTMLElement;\n\n    const header = second.querySelector('.ant-collapse-header') as HTMLElement;\n    dispatchMouseEvent(header, 'click');\n    fixture.detectChanges();\n    tick(0);\n    fixture.detectChanges();\n\n    expect(second.classList.contains('ant-collapse-item-active')).toBeTrue();\n  }));\n\n  it('should emit presetSelect with NzColor when a color is clicked', () => {\n    component.presets = [\n      {\n        label: 'Recent',\n        colors: ['#ff0000', '#00ff00'],\n        defaultOpen: true\n      },\n      {\n        label: 'Favorites',\n        colors: ['#0000ff'],\n        defaultOpen: false\n      }\n    ];\n    fixture.detectChanges();\n\n    let emitted: NzSafeAny = null;\n    const sub = component.presetSelect.subscribe(v => (emitted = v));\n\n    const host = fixture.nativeElement as HTMLElement;\n    const firstColor = host.querySelector('.ant-color-picker-color-block') as HTMLElement;\n    dispatchMouseEvent(firstColor, 'click');\n    fixture.detectChanges();\n\n    expect(emitted).toBeTruthy();\n    expect(typeof emitted.toRgbString).toBe('function');\n    expect(emitted.toRgbString()).toBe('rgb(255, 0, 0)');\n\n    sub.unsubscribe();\n  });\n\n  it('should add checked class to the selected preset color', () => {\n    component.presets = [\n      {\n        label: 'Recent',\n        colors: ['#ff0000', '#00ff00'],\n        defaultOpen: true\n      }\n    ];\n    // Select second color '#00ff00'\n    component.value = '#00ff00' as NzSafeAny;\n    fixture.detectChanges();\n\n    const host = fixture.nativeElement as HTMLElement;\n    const blocks = host.querySelectorAll('.ant-color-picker-color-block');\n    expect(blocks.length).toBe(2);\n\n    const checked = host.querySelectorAll('.ant-color-picker-presets-color-checked');\n    expect(checked.length).toBe(1);\n    // The second block should be checked\n    expect(blocks[1].classList.contains('ant-color-picker-presets-color-checked')).toBeTrue();\n  });\n\n  it('should add bright class for bright preset colors (e.g., white)', () => {\n    component.presets = [\n      {\n        label: 'Bright',\n        colors: ['#ffffff'],\n        defaultOpen: true\n      },\n      {\n        label: 'Dark',\n        colors: ['#000000'],\n        defaultOpen: true\n      }\n    ];\n    // Select white to also trigger checked\n    component.value = '#ffffff' as NzSafeAny;\n    fixture.detectChanges();\n\n    const host = fixture.nativeElement as HTMLElement;\n    const blocks = host.querySelectorAll('.ant-color-picker-color-block');\n    expect(blocks.length).toBe(2);\n\n    const first = blocks[0] as HTMLElement; // white\n    expect(first.classList.contains('ant-color-picker-presets-color-bright')).toBeTrue();\n    expect(first.classList.contains('ant-color-picker-presets-color-checked')).toBeTrue();\n\n    const second = blocks[1] as HTMLElement; // black\n    expect(second.classList.contains('ant-color-picker-presets-color-bright')).toBeFalse();\n  });\n\n  it('should render base presets color class on each color block', () => {\n    component.presets = [{ label: 'Group', colors: ['#111111', '#222222', '#333333'], defaultOpen: true }];\n    fixture.detectChanges();\n\n    const host = fixture.nativeElement as HTMLElement;\n    const blocks = host.querySelectorAll('.ant-color-picker-color-block');\n    expect(blocks.length).toBe(3);\n    blocks.forEach(block => {\n      expect(block.classList.contains('ant-color-picker-presets-color')).toBeTrue();\n    });\n  });\n});\n"
  },
  {
    "path": "components/color-picker/src/ng-antd-color-preset.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  EventEmitter,\n  inject,\n  Input,\n  OnInit,\n  Output\n} from '@angular/core';\n\nimport { NzCollapseModule } from 'ng-zorro-antd/collapse';\n\nimport { NzColor, NzPresetColor } from '../typings';\nimport type { Color } from './interfaces/color';\nimport { NgAntdColorBlockComponent } from './ng-antd-color-block.component';\nimport { generateColor } from './util/util';\n\n@Component({\n  // eslint-disable-next-line @angular-eslint/component-selector\n  selector: 'ng-antd-color-preset',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  imports: [NzCollapseModule, NgAntdColorBlockComponent],\n  template: `\n    <div class=\"ant-color-picker-presets\">\n      <nz-collapse nzGhost>\n        @for (preset of presets; track preset.key || $index) {\n          <nz-collapse-panel\n            [nzActive]=\"openPresets.has($index)\"\n            (nzActiveChange)=\"onPanelActiveChange($index, $event)\"\n            [nzHeader]=\"preset.label\"\n          >\n            <div class=\"ant-color-picker-presets-items\">\n              @for (color of preset.colors; track $index) {\n                <ng-antd-color-block\n                  [value]=\"value\"\n                  [color]=\"getColorString(color)\"\n                  (nzOnClick)=\"selectPresetColor(color)\"\n                />\n              }\n            </div>\n          </nz-collapse-panel>\n        }\n      </nz-collapse>\n    </div>\n  `,\n  host: {\n    class: 'ant-color-picker-presets-wrapper'\n  }\n})\nexport class NgAntdColorPresetComponent implements OnInit {\n  private cdr = inject(ChangeDetectorRef);\n  protected openPresets = new Set<string | number>();\n\n  @Input() presets: NzPresetColor[] = [];\n  @Input() value: Color | null = null;\n  @Output() readonly presetSelect = new EventEmitter<NzColor>();\n\n  ngOnInit(): void {\n    this.presets.forEach((preset, index) => {\n      if (preset.defaultOpen) {\n        this.openPresets.add(index);\n      }\n    });\n  }\n\n  onPanelActiveChange(index: number, active: boolean): void {\n    if (active) {\n      this.openPresets.add(index);\n    } else {\n      this.openPresets.delete(index);\n    }\n    this.cdr.markForCheck();\n  }\n\n  selectPresetColor(color: string | NzColor): void {\n    const colorInstance = typeof color === 'string' ? generateColor(color) : color;\n    this.presetSelect.emit(colorInstance);\n  }\n\n  getColorString(color: string | NzColor): string {\n    if (typeof color === 'string') {\n      return color;\n    }\n    return color.toRgbString();\n  }\n}\n"
  },
  {
    "path": "components/color-picker/src/util/util.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Color } from '../interfaces/color';\nimport type { ColorGenInput, HsbaColorType, TransformOffset } from '../interfaces/type';\n\nexport const generateColor = (color: ColorGenInput): Color => {\n  if (color instanceof Color) {\n    return color;\n  }\n  return new Color(color);\n};\n\nexport const defaultColor = generateColor('#1677ff');\n\nexport function calculateColor(\n  offset: TransformOffset,\n  containerRef: HTMLDivElement,\n  targetRef: HTMLDivElement,\n  color?: Color | null,\n  type?: HsbaColorType\n): Color {\n  const { width, height } = containerRef.getBoundingClientRect();\n  const { width: targetWidth, height: targetHeight } = targetRef.getBoundingClientRect();\n  const centerOffsetX = targetWidth / 2;\n  const centerOffsetY = targetHeight / 2;\n  const saturation = (offset.x + centerOffsetX) / width;\n  const bright = 1 - (offset.y + centerOffsetY) / height;\n  const hsb = color?.toHsb() || { a: 0, h: 0, s: 0, b: 0 };\n  const alphaOffset = saturation;\n  const hueOffset = ((offset.x + centerOffsetX) / width) * 360;\n\n  if (type) {\n    switch (type) {\n      case 'hue':\n        return generateColor({\n          ...hsb,\n          h: hueOffset <= 0 ? 0 : hueOffset\n        });\n      case 'alpha':\n        return generateColor({\n          ...hsb,\n          a: alphaOffset <= 0 ? 0 : alphaOffset\n        });\n    }\n  }\n\n  return generateColor({\n    h: hsb.h,\n    s: saturation <= 0 ? 0 : saturation,\n    b: bright >= 1 ? 1 : bright,\n    a: hsb.a\n  });\n}\n\nexport const calculateOffset = (\n  containerRef: HTMLDivElement,\n  targetRef: HTMLDivElement,\n  color?: Color | null,\n  type?: HsbaColorType\n): TransformOffset | null => {\n  const { width, height } = containerRef.getBoundingClientRect();\n  const { width: targetWidth, height: targetHeight } = targetRef.getBoundingClientRect();\n  const centerOffsetX = targetWidth / 2;\n  const centerOffsetY = targetHeight / 2;\n  const hsb = color?.toHsb() || { a: 0, h: 0, s: 0, b: 0 };\n\n  // Exclusion of boundary cases\n  if ((targetWidth === 0 && targetHeight === 0) || targetWidth !== targetHeight) {\n    return null;\n  }\n\n  if (type) {\n    switch (type) {\n      case 'hue':\n        return {\n          x: (hsb.h / 360) * width - centerOffsetX,\n          y: -centerOffsetY / 3\n        };\n      case 'alpha':\n        return {\n          x: hsb.a * width - centerOffsetX,\n          y: -centerOffsetY / 3\n        };\n    }\n  }\n  return {\n    x: hsb.s * width - centerOffsetX,\n    y: (1 - hsb.b) * height - centerOffsetY\n  };\n};\n"
  },
  {
    "path": "components/color-picker/style/entry.less",
    "content": "@import './index.less';\n"
  },
  {
    "path": "components/color-picker/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@color-picker-prefix-cls: ~'@{ant-prefix}-color-picker';\n\n.@{color-picker-prefix-cls} {\n  &-inner {\n    display: block;\n\n    &-content {\n      display: flex;\n      flex-direction: column;\n      width: 234px;\n    }\n  }\n\n  &-panel {\n    user-select: none;\n\n    &-disabled {\n      cursor: not-allowed;\n    }\n  }\n\n  &-gradient {\n    position: absolute;\n    inset: 0;\n  }\n\n  &-palette {\n    position: relative;\n    display: block;\n  }\n\n  &-select {\n    display: block;\n    margin-bottom: @margin-sm;\n\n    .@{color-picker-prefix-cls}-palette {\n      min-height: 160px;\n      overflow: hidden;\n      border-radius: @border-radius-base;\n\n      & > .@{color-picker-prefix-cls}-gradient {\n        border-top-left-radius: 5px;\n      }\n    }\n  }\n\n  &-saturation {\n    position: absolute;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    background-image: linear-gradient(0deg, #000, transparent), linear-gradient(90deg, #fff, hsla(0deg, 0%, 100%, 0));\n    border-radius: inherit;\n  }\n\n  &-transform {\n    position: absolute;\n    z-index: 1;\n  }\n\n  &-handler {\n    display: block;\n    box-sizing: border-box;\n    width: 16px;\n    height: 16px;\n    border: @border-width-base solid #fff;\n    border-radius: 50%;\n\n    &-sm {\n      width: 12px;\n      height: 12px;\n    }\n  }\n\n  &-slider {\n    display: block;\n    border-radius: @border-radius-base;\n\n    .@{color-picker-prefix-cls}-palette {\n      height: 8px;\n    }\n\n    .@{color-picker-prefix-cls}-gradient {\n      border-radius: @border-radius-base;\n    }\n\n    &-hue {\n      margin-bottom: @margin-sm;\n    }\n\n    &-alpha {\n      background-image: conic-gradient(\n        rgba(0, 0, 0, 0.06) 0 25%,\n        transparent 0 50%,\n        rgba(0, 0, 0, 0.06) 0 75%,\n        transparent 0\n      );\n      background-size: 8px 8px;\n    }\n  }\n\n  &-trigger {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    min-width: 32px;\n    height: 32px;\n    padding: 3px;\n    border: @border-width-base solid @border-color-split;\n    border-radius: @border-radius-base;\n    cursor: pointer;\n    transition: all 0.2s;\n\n    &:hover {\n      border-color: @primary-color;\n    }\n\n    &-text {\n      margin: 0 @margin-xss 0 @margin-xs;\n      font-size: @font-size-base;\n    }\n  }\n\n  &-sm {\n    min-width: 24px;\n    height: 24px;\n  }\n\n  &-lg {\n    min-width: 40px;\n    height: 40px;\n\n    .@{color-picker-prefix-cls}-trigger-text {\n      font-size: @font-size-lg;\n    }\n  }\n\n  &-color-block {\n    position: relative;\n    display: block;\n    width: 24px;\n    height: 24px;\n    overflow: hidden;\n    background-size: 50% 50%;\n    border-radius: @border-radius-base;\n\n    &-inner {\n      box-sizing: border-box;\n      width: 100%;\n      height: 100%;\n      border: @border-width-base solid @border-color-split;\n    }\n  }\n\n  &-slider-container {\n    display: flex;\n    gap: @margin-sm;\n    margin-bottom: @margin-sm;\n\n    .@{color-picker-prefix-cls}-slider-group {\n      flex: 1;\n\n      &-disabled-alpha {\n        display: flex;\n        align-items: center;\n\n        .@{color-picker-prefix-cls}-slider {\n          margin-bottom: 0;\n        }\n      }\n    }\n  }\n\n  &-title {\n    display: flex;\n\n    &-content {\n      flex: 1;\n      margin-bottom: @margin-xs;\n    }\n\n    .@{color-picker-prefix-cls}-clear {\n      flex: 0 0 18px;\n      margin-left: @margin-xs;\n    }\n  }\n\n  &-clear {\n    position: relative;\n    width: 18px;\n    height: 18px;\n    margin-bottom: @margin-xs;\n    overflow: hidden;\n    border: @border-width-base solid @border-color-split;\n    border-radius: @border-radius-base;\n    cursor: pointer;\n\n    &::after {\n      position: absolute;\n      top: 0;\n      display: block;\n      width: 40px;\n      height: 2px;\n      background-color: #f5222d;\n      transform: rotate(-45deg);\n      transform-origin: right;\n      content: '';\n      inset-inline-end: 1px;\n    }\n  }\n\n  &-input-container {\n    display: flex;\n    margin-bottom: @margin-sm;\n\n    .ant-select {\n      font-size: 12px;\n    }\n\n    .ant-input {\n      font-size: 12px;\n    }\n\n    .ant-input-number {\n      width: auto;\n      font-size: 12px;\n    }\n\n    .ant-input-number-sm input {\n      padding: 0 0 0 4px;\n    }\n\n    .ant-select-selector {\n      padding: 0;\n    }\n\n    .@{color-picker-prefix-cls}-format-select {\n      width: auto;\n    }\n\n    .@{color-picker-prefix-cls}-input {\n      flex: 1;\n\n      .@{color-picker-prefix-cls}-hex-input {\n        margin-right: @margin-xss;\n        padding: 0;\n      }\n\n      .@{color-picker-prefix-cls}-hsb-input {\n        display: flex;\n        gap: 4px;\n        align-items: center;\n      }\n\n      .@{color-picker-prefix-cls}-rgb-input {\n        display: flex;\n        gap: 4px;\n        align-items: center;\n      }\n    }\n\n    .@{color-picker-prefix-cls}-steppers {\n      flex: 1;\n    }\n\n    .@{color-picker-prefix-cls}-alpha-input {\n      flex: 0 0 44px;\n      margin-left: @margin-xss;\n    }\n  }\n\n  &-disabled {\n    color: @disabled-color;\n    background: @disabled-bg;\n    cursor: not-allowed;\n\n    .@{color-picker-prefix-cls}-trigger {\n      cursor: not-allowed;\n\n      &:hover {\n        border-color: @border-color-split;\n      }\n    }\n  }\n\n  &-inline {\n    display: inline-block;\n\n    .@{color-picker-prefix-cls}-color-block {\n      width: 24px;\n      height: 24px;\n      margin: 0;\n    }\n\n    &-lg {\n      .@{color-picker-prefix-cls}-color-block {\n        width: 32px;\n        height: 32px;\n      }\n    }\n\n    &-sm {\n      .@{color-picker-prefix-cls}-color-block {\n        width: 16px;\n        height: 16px;\n      }\n    }\n  }\n\n  &-presets {\n    &-wrapper {\n      max-height: 200px;\n      overflow-y: auto;\n\n      .ant-collapse {\n        display: flex;\n        flex-direction: column;\n        gap: @margin-xss;\n\n        .ant-collapse-header {\n          padding: 0 !important;\n          font-size: 12px;\n        }\n      }\n    }\n\n    &-items {\n      display: flex;\n      flex-wrap: wrap;\n      gap: @margin-xs;\n      padding: @padding-xs 0;\n    }\n\n    // Preset color block extra styles\n    &-color {\n      position: relative;\n    }\n\n    // Show a tick on selected preset - full overlay, centered\n    &-color-checked::after {\n      position: absolute;\n      top: 50%;\n      display: table;\n      box-sizing: border-box;\n      width: calc(120px / 13);\n      height: calc(192px / 13);\n      border: 2px solid #fff;\n      border-top: 0;\n      transform: translate(-50%, -60%) rotate(45deg);\n      content: '';\n      pointer-events: none;\n      border-inline-start: 0;\n      inset-inline-start: 46.5%;\n    }\n\n    // For bright backgrounds, use dark tick for contrast\n    &-color-bright&-color-checked::after,\n    &-color-checked&-color-bright::after {\n      border-color: rgba(0, 0, 0, 0.88);\n    }\n  }\n}\n"
  },
  {
    "path": "components/color-picker/typings.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { TemplateRef } from '@angular/core';\n\nimport { Color } from './src/interfaces/color';\n\nexport type NzColorPickerFormatType = 'rgb' | 'hex' | 'hsb';\n\nexport type NzColorPickerTriggerType = 'click' | 'hover';\n\nexport interface ValidForm {\n  isFormat: NzColorPickerFormatType | null;\n  hex: string | null;\n  hsbH: number;\n  hsbS: number;\n  hsbB: number;\n  rgbR: number;\n  rgbG: number;\n  rgbB: number;\n  roundA: number;\n}\n\nexport type ValidFormKey = keyof ValidForm;\n\nexport interface NzColor extends Color {}\n\nexport interface NzPresetColor {\n  label: TemplateRef<void> | string;\n  colors: Array<string | NzColor>;\n  defaultOpen?: boolean;\n  key?: string | number;\n}\n"
  },
  {
    "path": "components/comment/comment-cells.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { CdkPortalOutlet, TemplatePortal } from '@angular/cdk/portal';\nimport {\n  AfterViewInit,\n  ChangeDetectionStrategy,\n  Component,\n  Directive,\n  inject,\n  Input,\n  OnDestroy,\n  OnInit,\n  TemplateRef,\n  ViewChild,\n  ViewContainerRef,\n  ViewEncapsulation\n} from '@angular/core';\n\n@Directive({\n  selector: 'nz-avatar[nz-comment-avatar]',\n  exportAs: 'nzCommentAvatar'\n})\nexport class NzCommentAvatarDirective {}\n\n@Directive({\n  selector: 'nz-comment-content, [nz-comment-content]',\n  exportAs: 'nzCommentContent',\n  host: { class: 'ant-comment-content-detail' }\n})\nexport class NzCommentContentDirective {}\n\n@Directive({\n  selector: '[nzCommentActionHost]',\n  exportAs: 'nzCommentActionHost'\n})\nexport class NzCommentActionHostDirective extends CdkPortalOutlet implements OnInit, OnDestroy, AfterViewInit {\n  @Input() nzCommentActionHost?: TemplatePortal | null;\n\n  override ngOnInit(): void {\n    super.ngOnInit();\n  }\n\n  override ngOnDestroy(): void {\n    super.ngOnDestroy();\n  }\n\n  ngAfterViewInit(): void {\n    this.attach(this.nzCommentActionHost);\n  }\n}\n\n@Component({\n  selector: 'nz-comment-action',\n  exportAs: 'nzCommentAction',\n  template: '<ng-template><ng-content /></ng-template>',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class NzCommentActionComponent implements OnInit {\n  @ViewChild(TemplateRef, { static: true }) implicitContent!: TemplateRef<void>;\n  private viewContainerRef = inject(ViewContainerRef);\n  private contentPortal: TemplatePortal | null = null;\n\n  get content(): TemplatePortal | null {\n    return this.contentPortal;\n  }\n\n  ngOnInit(): void {\n    this.contentPortal = new TemplatePortal(this.implicitContent, this.viewContainerRef);\n  }\n}\n"
  },
  {
    "path": "components/comment/comment.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ContentChildren,\n  DestroyRef,\n  inject,\n  Input,\n  OnInit,\n  QueryList,\n  TemplateRef,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\n\nimport { NzCommentActionComponent as CommentAction, NzCommentActionHostDirective } from './comment-cells';\n\n@Component({\n  selector: 'nz-comment',\n  exportAs: 'nzComment',\n  template: `\n    <div class=\"ant-comment-inner\">\n      <div class=\"ant-comment-avatar\">\n        <ng-content select=\"nz-avatar[nz-comment-avatar]\" />\n      </div>\n      <div class=\"ant-comment-content\">\n        <div class=\"ant-comment-content-author\">\n          @if (nzAuthor) {\n            <span class=\"ant-comment-content-author-name\">\n              <ng-container *nzStringTemplateOutlet=\"nzAuthor\">{{ nzAuthor }}</ng-container>\n            </span>\n          }\n          @if (nzDatetime) {\n            <span class=\"ant-comment-content-author-time\">\n              <ng-container *nzStringTemplateOutlet=\"nzDatetime\">{{ nzDatetime }}</ng-container>\n            </span>\n          }\n        </div>\n        <ng-content select=\"nz-comment-content\" />\n        @if (actions?.length) {\n          <ul class=\"ant-comment-actions\">\n            @for (action of actions; track action) {\n              <li>\n                <span><ng-template [nzCommentActionHost]=\"action.content\" /></span>\n              </li>\n            }\n          </ul>\n        }\n      </div>\n    </div>\n    <div class=\"ant-comment-nested\">\n      <ng-content />\n    </div>\n  `,\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    '[class.ant-comment]': `true`,\n    '[class.ant-comment-rtl]': `dir === \"rtl\"`\n  },\n  imports: [NzOutletModule, NzCommentActionHostDirective]\n})\nexport class NzCommentComponent implements OnInit {\n  private destroyRef = inject(DestroyRef);\n  private cdr = inject(ChangeDetectorRef);\n  private directionality = inject(Directionality);\n\n  @Input() nzAuthor?: string | TemplateRef<void>;\n  @Input() nzDatetime?: string | TemplateRef<void>;\n  dir: Direction = 'ltr';\n\n  @ContentChildren(CommentAction) actions!: QueryList<CommentAction>;\n\n  ngOnInit(): void {\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n      this.dir = direction;\n      this.cdr.detectChanges();\n    });\n\n    this.dir = this.directionality.value;\n  }\n}\n"
  },
  {
    "path": "components/comment/comment.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport {\n  NzCommentActionComponent,\n  NzCommentActionHostDirective,\n  NzCommentAvatarDirective,\n  NzCommentContentDirective\n} from './comment-cells';\nimport { NzCommentComponent } from './comment.component';\n\nconst NZ_COMMENT_CELLS = [\n  NzCommentAvatarDirective,\n  NzCommentContentDirective,\n  NzCommentActionComponent,\n  NzCommentActionHostDirective\n];\n\n@NgModule({\n  imports: [NzCommentComponent, ...NZ_COMMENT_CELLS],\n  exports: [NzCommentComponent, ...NZ_COMMENT_CELLS]\n})\nexport class NzCommentModule {}\n"
  },
  {
    "path": "components/comment/comment.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport { Component, NO_ERRORS_SCHEMA, provideZoneChangeDetection, ViewChild } from '@angular/core';\nimport { fakeAsync, TestBed, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzCommentComponent } from './comment.component';\nimport { NzDemoCommentBasicComponent } from './demo/basic';\nimport { NzDemoCommentEditorComponent } from './demo/editor';\nimport { NzDemoCommentListComponent } from './demo/list';\nimport { NzDemoCommentNestedComponent } from './demo/nested';\n\ndescribe('comment', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideZoneChangeDetection()],\n      schemas: [NO_ERRORS_SCHEMA]\n    });\n  });\n\n  describe('default', () => {\n    it('should basic work', () => {\n      const fixture = TestBed.createComponent(NzDemoCommentBasicComponent);\n      const component = fixture.componentInstance;\n      const comment = fixture.debugElement.query(By.directive(NzCommentComponent));\n      fixture.detectChanges();\n\n      expect(comment.nativeElement.classList).toContain('ant-comment');\n      expect(comment.nativeElement.querySelector('nz-avatar[nz-comment-avatar]')).toBeTruthy();\n      expect(comment.nativeElement.querySelector('nz-comment-content')).toBeTruthy();\n      expect(comment.nativeElement.querySelector('.ant-comment-content-author-name')).toBeTruthy();\n      expect(comment.nativeElement.querySelector('.ant-comment-content-author-time')).toBeTruthy();\n      expect(comment.nativeElement.querySelector('.ant-comment-content-author-name').innerText).toBe('Han Solo');\n      expect(comment.nativeElement.querySelector('.ant-comment-content-author-time').innerText).toBe(component.time);\n    });\n\n    it('should actions work', () => {\n      const fixture = TestBed.createComponent(NzDemoCommentBasicComponent);\n      const component = fixture.componentInstance;\n      const comment = fixture.debugElement.query(By.directive(NzCommentComponent));\n      fixture.detectChanges();\n\n      expect(component.likes).toBe(0);\n      expect(component.dislikes).toBe(0);\n      expect(comment.nativeElement.classList).toContain('ant-comment');\n      expect(comment.nativeElement.querySelectorAll('.ant-comment-actions li>span').length).toBe(3);\n      expect(comment.nativeElement.querySelector('.ant-comment-actions li>span .like').innerText).toBe(\n        component.likes.toString()\n      );\n      expect(comment.nativeElement.querySelector('.ant-comment-actions li>span .dislike').innerText).toBe(\n        component.dislikes.toString()\n      );\n\n      component.like();\n      fixture.detectChanges();\n\n      expect(component.likes).toBe(1);\n      expect(component.dislikes).toBe(0);\n      expect(comment.nativeElement.querySelector('.ant-comment-actions li>span .like').innerText).toBe(\n        component.likes.toString()\n      );\n      expect(comment.nativeElement.querySelector('.ant-comment-actions li>span .dislike').innerText).toBe(\n        component.dislikes.toString()\n      );\n\n      component.dislike();\n      fixture.detectChanges();\n\n      expect(component.likes).toBe(0);\n      expect(component.dislikes).toBe(1);\n      expect(comment.nativeElement.querySelector('.ant-comment-actions li>span .like').innerText).toBe(\n        component.likes.toString()\n      );\n      expect(comment.nativeElement.querySelector('.ant-comment-actions li>span .dislike').innerText).toBe(\n        component.dislikes.toString()\n      );\n    });\n\n    it('should list work', () => {\n      const fixture = TestBed.createComponent(NzDemoCommentListComponent);\n      const component = fixture.componentInstance;\n      fixture.detectChanges();\n      let comments = fixture.debugElement.queryAll(By.directive(NzCommentComponent));\n      fixture.detectChanges();\n      expect(component.data.length === comments.length).toBeTruthy();\n\n      component.data.forEach((e, i) => {\n        const comment = comments[i];\n        expect(comment.nativeElement.querySelector('nz-avatar[nz-comment-avatar]')).toBeTruthy();\n        expect(comment.nativeElement.querySelector('.ant-comment-content-author-name').innerText).toBe(e.author);\n        expect(comment.nativeElement.querySelector('.ant-comment-content-detail p').innerText).toBe(e.content);\n        expect(comment.nativeElement.querySelector('.ant-comment-content-author-time').innerText).toBe(e.datetime);\n      });\n\n      component.data = [{ ...component.data[0] }];\n      fixture.detectChanges();\n      comments = fixture.debugElement.queryAll(By.directive(NzCommentComponent));\n      expect(component.data.length === comments.length).toBeTruthy();\n    });\n\n    it('should editor work', fakeAsync(() => {\n      const fixture = TestBed.createComponent(NzDemoCommentEditorComponent);\n      const component = fixture.componentInstance;\n      fixture.detectChanges();\n      expect(fixture.debugElement.query(By.css('nz-comment .ant-comment-content-detail textarea'))).toBeTruthy();\n      let comments = fixture.debugElement.queryAll(By.css('nz-list nz-comment'));\n      expect(component.data.length).toBe(0);\n      expect(component.data.length === comments.length).toBeTruthy();\n\n      component.inputValue = 'Test Comment 0';\n      component.handleSubmit();\n      tick(1000);\n      fixture.detectChanges();\n\n      component.inputValue = 'Test Comment 1';\n      component.handleSubmit();\n      tick(1000);\n      fixture.detectChanges();\n\n      comments = fixture.debugElement.queryAll(By.css('nz-list nz-comment'));\n\n      component.data.forEach((e, i) => {\n        const comment = comments[i];\n        expect(comment.nativeElement.querySelector('nz-avatar[nz-comment-avatar]')).toBeTruthy();\n        expect(comment.nativeElement.querySelector('.ant-comment-content-author-name').innerText).toBe(e.author);\n        expect(comment.nativeElement.querySelector('.ant-comment-content-detail p').innerText).toBe(e.content);\n        expect(comment.nativeElement.querySelector('.ant-comment-content-author-time').innerText).toBe(e.displayTime);\n      });\n    }));\n\n    it('should nested work', () => {\n      const fixture = TestBed.createComponent(NzDemoCommentNestedComponent);\n      fixture.detectChanges();\n\n      const rootComment = fixture.debugElement.query(By.directive(NzCommentComponent));\n      expect(rootComment.nativeElement).toBeTruthy();\n\n      const levelTwoComment = rootComment.query(By.directive(NzCommentComponent));\n      expect(levelTwoComment.nativeElement).toBeTruthy();\n\n      const levelThreeComments = levelTwoComment.queryAll(By.directive(NzCommentComponent));\n      expect(levelThreeComments.length).toBe(2);\n    });\n  });\n\n  describe('RTL', () => {\n    it('should className correct on dir change', () => {\n      const fixture = TestBed.createComponent(NzTestCommentRtlComponent);\n      const comment = fixture.debugElement.query(By.directive(NzCommentComponent));\n      fixture.detectChanges();\n      expect(comment.nativeElement.classList).toContain('ant-comment-rtl');\n\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n      expect(comment.nativeElement.classList).not.toContain('ant-comment-rtl');\n    });\n  });\n});\n\n@Component({\n  imports: [BidiModule, NzDemoCommentBasicComponent],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-demo-comment-basic />\n    </div>\n  `\n})\nexport class NzTestCommentRtlComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n}\n"
  },
  {
    "path": "components/comment/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本评论\n  en-US: Basic comment\n---\n\n## zh-CN\n\n一个基本的评论组件，带有作者、头像、时间和操作。\n\n## en-US\n\nA basic comment with author, avatar, time and actions.\n"
  },
  {
    "path": "components/comment/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { formatDistance } from 'date-fns';\n\nimport { NzAvatarModule } from 'ng-zorro-antd/avatar';\nimport { NzCommentModule } from 'ng-zorro-antd/comment';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzTooltipModule } from 'ng-zorro-antd/tooltip';\n\n@Component({\n  selector: 'nz-demo-comment-basic',\n  imports: [NzAvatarModule, NzCommentModule, NzIconModule, NzTooltipModule],\n  template: `\n    <nz-comment nzAuthor=\"Han Solo\" [nzDatetime]=\"time\">\n      <nz-avatar nz-comment-avatar nzIcon=\"user\" nzSrc=\"//zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png\" />\n      <nz-comment-content>\n        <p>\n          We supply a series of design principles, practical patterns and high quality design resources(Sketch and\n          Axure), to help people create their product prototypes beautifully and efficiently.\n        </p>\n      </nz-comment-content>\n      <nz-comment-action>\n        <nz-icon\n          nz-tooltip\n          nzTooltipTitle=\"Like\"\n          nzType=\"like\"\n          [nzTheme]=\"likes > 0 ? 'twotone' : 'outline'\"\n          (click)=\"like()\"\n        />\n        <span class=\"count like\">{{ likes }}</span>\n      </nz-comment-action>\n      <nz-comment-action>\n        <nz-icon\n          nz-tooltip\n          nzTooltipTitle=\"Dislike\"\n          nzType=\"dislike\"\n          [nzTheme]=\"dislikes > 0 ? 'twotone' : 'outline'\"\n          (click)=\"dislike()\"\n        />\n        <span class=\"count dislike\">{{ dislikes }}</span>\n      </nz-comment-action>\n      <nz-comment-action>Reply to</nz-comment-action>\n    </nz-comment>\n  `,\n  styles: `\n    .count {\n      padding-left: 8px;\n      cursor: auto;\n    }\n    .ant-comment-rtl .count {\n      padding-right: 8px;\n      padding-left: 0;\n    }\n  `\n})\nexport class NzDemoCommentBasicComponent {\n  likes = 0;\n  dislikes = 0;\n  time = formatDistance(new Date(), new Date());\n\n  like(): void {\n    this.likes = 1;\n    this.dislikes = 0;\n  }\n\n  dislike(): void {\n    this.likes = 0;\n    this.dislikes = 1;\n  }\n}\n"
  },
  {
    "path": "components/comment/demo/editor.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 回复框\n  en-US: Reply Editor\n---\n\n## zh-CN\n\n评论编辑器组件提供了相同样式的封装以支持自定义评论编辑器。\n\n## en-US\n\nComment can be used as editor, user can customize the editor component.\n"
  },
  {
    "path": "components/comment/demo/editor.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { formatDistance } from 'date-fns';\n\nimport { NzAvatarModule } from 'ng-zorro-antd/avatar';\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzCommentModule } from 'ng-zorro-antd/comment';\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzListModule } from 'ng-zorro-antd/list';\n\ninterface User {\n  author: string;\n  avatar: string;\n}\n\ninterface Data extends User {\n  content: string;\n  datetime: Date;\n  displayTime: string;\n}\n\n@Component({\n  selector: 'nz-demo-comment-editor',\n  imports: [FormsModule, NzAvatarModule, NzButtonModule, NzCommentModule, NzFormModule, NzInputModule, NzListModule],\n  template: `\n    @if (data.length) {\n      <nz-list [nzDataSource]=\"data\" [nzRenderItem]=\"item\" nzItemLayout=\"horizontal\">\n        <ng-template #item let-item>\n          <nz-comment [nzAuthor]=\"item.author\" [nzDatetime]=\"item.displayTime\">\n            <nz-avatar nz-comment-avatar nzIcon=\"user\" [nzSrc]=\"item.avatar\" />\n            <nz-comment-content>\n              <p>{{ item.content }}</p>\n            </nz-comment-content>\n          </nz-comment>\n        </ng-template>\n      </nz-list>\n    }\n\n    <nz-comment>\n      <nz-avatar nz-comment-avatar nzIcon=\"user\" [nzSrc]=\"user.avatar\" />\n      <nz-comment-content>\n        <nz-form-item>\n          <textarea [(ngModel)]=\"inputValue\" nz-input rows=\"4\"></textarea>\n        </nz-form-item>\n        <nz-form-item>\n          <button nz-button nzType=\"primary\" [nzLoading]=\"submitting\" [disabled]=\"!inputValue\" (click)=\"handleSubmit()\">\n            Add Comment\n          </button>\n        </nz-form-item>\n      </nz-comment-content>\n    </nz-comment>\n  `\n})\nexport class NzDemoCommentEditorComponent {\n  data: Data[] = [];\n  submitting = false;\n  user: User = {\n    author: 'Han Solo',\n    avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png'\n  };\n  inputValue = '';\n\n  handleSubmit(): void {\n    this.submitting = true;\n    const content = this.inputValue;\n    this.inputValue = '';\n    setTimeout(() => {\n      this.submitting = false;\n      this.data = [\n        ...this.data,\n        {\n          ...this.user,\n          content,\n          datetime: new Date(),\n          displayTime: formatDistance(new Date(), new Date())\n        }\n      ].map(e => ({\n        ...e,\n        displayTime: formatDistance(new Date(), e.datetime)\n      }));\n    }, 800);\n  }\n}\n"
  },
  {
    "path": "components/comment/demo/list.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 配合列表组件\n  en-US: Usage with list\n---\n\n## zh-CN\n\n配合 `nz-list` 组件展现评论列表。\n\n## en-US\n\nDisplaying a series of comments using the `nz-list` Component.\n"
  },
  {
    "path": "components/comment/demo/list.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { addDays, formatDistance } from 'date-fns';\n\nimport { NzAvatarModule } from 'ng-zorro-antd/avatar';\nimport { NzCommentModule } from 'ng-zorro-antd/comment';\nimport { NzListModule } from 'ng-zorro-antd/list';\n\n@Component({\n  selector: 'nz-demo-comment-list',\n  imports: [NzAvatarModule, NzCommentModule, NzListModule],\n  template: `\n    <nz-list [nzDataSource]=\"data\" [nzRenderItem]=\"item\" nzItemLayout=\"horizontal\">\n      <ng-template #item let-item>\n        <nz-comment [nzAuthor]=\"item.author\" [nzDatetime]=\"item.datetime\">\n          <nz-avatar nz-comment-avatar nzIcon=\"user\" [nzSrc]=\"item.avatar\" />\n          <nz-comment-content>\n            <p>{{ item.content }}</p>\n          </nz-comment-content>\n          <nz-comment-action>Reply to</nz-comment-action>\n        </nz-comment>\n      </ng-template>\n    </nz-list>\n  `\n})\nexport class NzDemoCommentListComponent {\n  data = [\n    {\n      author: 'Han Solo',\n      avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',\n      content:\n        'We supply a series of design principles, practical patterns and high quality design resources' +\n        '(Sketch and Axure), to help people create their product prototypes beautifully and efficiently.',\n      datetime: formatDistance(new Date(), addDays(new Date(), 1))\n    },\n    {\n      author: 'Han Solo',\n      avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',\n      content:\n        'We supply a series of design principles, practical patterns and high quality design resources' +\n        '(Sketch and Axure), to help people create their product prototypes beautifully and efficiently.',\n      datetime: formatDistance(new Date(), addDays(new Date(), 2))\n    }\n  ];\n}\n"
  },
  {
    "path": "components/comment/demo/nested.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 嵌套评论\n  en-US: Nested comments\n---\n\n## zh-CN\n\n评论可以嵌套。\n\n## en-US\n\nComments can be nested.\n"
  },
  {
    "path": "components/comment/demo/nested.ts",
    "content": "import { NgTemplateOutlet } from '@angular/common';\nimport { Component } from '@angular/core';\n\nimport { NzAvatarModule } from 'ng-zorro-antd/avatar';\nimport { NzCommentModule } from 'ng-zorro-antd/comment';\n\n@Component({\n  selector: 'nz-demo-comment-nested',\n  imports: [NgTemplateOutlet, NzAvatarModule, NzCommentModule],\n  template: `\n    <ng-template #commentTemplateRef let-comment=\"comment\">\n      <nz-comment [nzAuthor]=\"comment.author\">\n        <nz-avatar nz-comment-avatar nzIcon=\"user\" [nzSrc]=\"comment.avatar\" />\n        <nz-comment-content>\n          <p>{{ comment.content }}</p>\n        </nz-comment-content>\n        <nz-comment-action>Reply to</nz-comment-action>\n        @if (comment.children && comment.children.length) {\n          @for (child of comment.children; track child) {\n            <ng-template [ngTemplateOutlet]=\"commentTemplateRef\" [ngTemplateOutletContext]=\"{ comment: child }\" />\n          }\n        }\n      </nz-comment>\n    </ng-template>\n\n    <ng-template [ngTemplateOutlet]=\"commentTemplateRef\" [ngTemplateOutletContext]=\"{ comment: data }\" />\n  `\n})\nexport class NzDemoCommentNestedComponent {\n  data = {\n    author: 'Han Solo',\n    avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',\n    content:\n      'We supply a series of design principles, practical patterns and high quality design resources' +\n      '(Sketch and Axure), to help people create their product prototypes beautifully and efficiently.',\n    children: [\n      {\n        author: 'Han Solo',\n        avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',\n        content:\n          'We supply a series of design principles, practical patterns and high quality design resources' +\n          '(Sketch and Axure), to help people create their product prototypes beautifully and efficiently.',\n        children: [\n          {\n            author: 'Han Solo',\n            avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',\n            content:\n              'We supply a series of design principles, practical patterns and high quality design resources' +\n              '(Sketch and Axure), to help people create their product prototypes beautifully and efficiently.'\n          },\n          {\n            author: 'Han Solo',\n            avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',\n            content:\n              'We supply a series of design principles, practical patterns and high quality design resources' +\n              '(Sketch and Axure), to help people create their product prototypes beautifully and efficiently.'\n          }\n        ]\n      }\n    ]\n  };\n}\n"
  },
  {
    "path": "components/comment/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Display\ntitle: Comment\ncols: 1\ncover: 'https://gw.alipayobjects.com/zos/alicdn/ILhxpGzBO/Comment.svg'\ndescription: A comment displays user feedback and discussion to website content.\n---\n\n## When To Use\n\nComments can be used to enable discussions on an entity such as a page, blog post, issue or other.\n\n## API\n\n### nz-comment\n\n| Property       | Description                                            | Type                          | Default |\n| -------------- | ------------------------------------------------------ | ----------------------------- | ------- |\n| `[nzAuthor]`   | The element to display as the comment author           | `string \\| TemplateRef<void>` | -       |\n| `[nzDatetime]` | A datetime element containing the time to be displayed | `string \\| TemplateRef<void>` | -       |\n\n### [nz-comment-avatar]\n\nThe element to display as the comment avatar.\n\n### nz-comment-content\n\nThe main content of the comment.\n\n### nz-comment-action\n\nThe element items rendered below the comment content.\n"
  },
  {
    "path": "components/comment/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ntype: 数据展示\ntitle: Comment\nsubtitle: 评论\ncols: 1\ncover: 'https://gw.alipayobjects.com/zos/alicdn/ILhxpGzBO/Comment.svg'\ndescription: 对网站内容的反馈、评价和讨论。\n---\n\n## 何时使用\n\n评论组件可用于对事物的讨论，例如页面、博客文章、问题等等。\n\n## API\n\n### nz-comment\n\n| Property       | Description    | Type                          | Default |\n| -------------- | -------------- | ----------------------------- | ------- |\n| `[nzAuthor]`   | 显示评论的作者 | `string \\| TemplateRef<void>` | -       |\n| `[nzDatetime]` | 展示时间描述   | `string \\| TemplateRef<void>` | -       |\n\n### [nz-comment-avatar]\n\n要显示为评论头像的元素。\n\n### nz-comment-content\n\n评论的主要内容。\n\n### nz-comment-action\n\n在评论内容下面呈现的操作项。\n"
  },
  {
    "path": "components/comment/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/comment/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/comment/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './comment.module';\nexport * from './comment.component';\nexport * from './comment-cells';\n"
  },
  {
    "path": "components/comment/style/entry.less",
    "content": "@import './index.less';\n@import \"./patch\";"
  },
  {
    "path": "components/comment/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@comment-prefix-cls: ~'@{ant-prefix}-comment';\n\n.@{comment-prefix-cls} {\n  position: relative;\n  background-color: @comment-bg;\n\n  &-inner {\n    display: flex;\n    padding: @comment-padding-base;\n  }\n\n  &-avatar {\n    position: relative;\n    flex-shrink: 0;\n    margin-right: @margin-sm;\n    cursor: pointer;\n\n    img {\n      width: 32px;\n      height: 32px;\n      border-radius: 50%;\n    }\n  }\n\n  &-content {\n    position: relative;\n    flex: 1 1 auto;\n    min-width: 1px;\n    font-size: @comment-font-size-base;\n    word-wrap: break-word;\n\n    &-author {\n      display: flex;\n      flex-wrap: wrap;\n      justify-content: flex-start;\n      margin-bottom: @margin-xss;\n      font-size: @comment-font-size-base;\n\n      & > a,\n      & > span {\n        padding-right: @padding-xs;\n        font-size: @comment-font-size-sm;\n        line-height: 18px;\n      }\n\n      &-name {\n        color: @comment-author-name-color;\n        font-size: @comment-font-size-base;\n        transition: color 0.3s;\n\n        > * {\n          color: @comment-author-name-color;\n\n          &:hover {\n            color: @comment-author-name-color;\n          }\n        }\n      }\n\n      &-time {\n        color: @comment-author-time-color;\n        white-space: nowrap;\n        cursor: auto;\n      }\n    }\n\n    &-detail p {\n      margin-bottom: @comment-content-detail-p-margin-bottom;\n      white-space: pre-wrap;\n    }\n  }\n\n  &-actions {\n    margin-top: @comment-actions-margin-top;\n    margin-bottom: @comment-actions-margin-bottom;\n    padding-left: 0;\n\n    > li {\n      display: inline-block;\n      color: @comment-action-color;\n\n      > span {\n        margin-right: 10px;\n        color: @comment-action-color;\n        font-size: @comment-font-size-sm;\n        cursor: pointer;\n        transition: color 0.3s;\n        user-select: none;\n\n        &:hover {\n          color: @comment-action-hover-color;\n        }\n      }\n    }\n  }\n\n  &-nested {\n    margin-left: @comment-nest-indent;\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/comment/style/patch.less",
    "content": "nz-comment {\n  display: block;\n}\n\nnz-comment-content {\n  display: block;\n}\n"
  },
  {
    "path": "components/comment/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@comment-prefix-cls: ~'@{ant-prefix}-comment';\n\n.@{comment-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &-avatar {\n    .@{comment-prefix-cls}-rtl & {\n      margin-right: 0;\n      margin-left: 12px;\n    }\n  }\n\n  &-content {\n    &-author {\n      & > a,\n      & > span {\n        .@{comment-prefix-cls}-rtl & {\n          padding-right: 0;\n          padding-left: 8px;\n        }\n      }\n    }\n  }\n\n  &-actions {\n    .@{comment-prefix-cls}-rtl & {\n      padding-right: 0;\n    }\n\n    > li {\n      > span {\n        .@{comment-prefix-cls}-rtl & {\n          margin-right: 0;\n          margin-left: 10px;\n        }\n      }\n    }\n  }\n\n  &-nested {\n    .@{comment-prefix-cls}-rtl & {\n      margin-right: @comment-nest-indent;\n      margin-left: 0;\n    }\n  }\n}\n"
  },
  {
    "path": "components/components.less",
    "content": "@import './icon/style/entry.less';\n@import './affix/style/entry.less';\n@import './alert/style/entry.less';\n@import './anchor/style/entry.less';\n@import './avatar/style/entry.less';\n@import './badge/style/entry.less';\n@import './breadcrumb/style/entry.less';\n@import './button/style/entry.less';\n@import './card/style/entry.less';\n@import './carousel/style/entry.less';\n@import './checkbox/style/entry.less';\n@import './collapse/style/entry.less';\n@import './comment/style/entry.less';\n@import './date-picker/style/entry.less';\n@import './descriptions/style/entry.less';\n@import './divider/style/entry.less';\n@import './drawer/style/entry.less';\n@import './dropdown/style/entry.less';\n@import './empty/style/entry.less';\n@import './grid/style/entry.less';\n@import './flex/style/entry.less';\n@import './input/style/entry.less';\n@import './input-number/style/entry.less';\n@import './layout/style/entry.less';\n@import './form/style/entry.less';\n@import './list/style/entry.less';\n@import './menu/style/entry.less';\n@import './mention/style/entry.less';\n@import './message/style/entry.less';\n@import './modal/style/entry.less';\n@import './notification/style/entry.less';\n@import './page-header/style/entry.less';\n@import './pagination/style/entry.less';\n@import './popconfirm/style/entry.less';\n@import './popover/style/entry.less';\n@import './progress/style/entry.less';\n@import './radio/style/entry.less';\n@import './rate/style/entry.less';\n@import './select/style/entry.less';\n@import './segmented/style/entry.less';\n@import './skeleton/style/entry.less';\n@import './slider/style/entry.less';\n@import './spin/style/entry.less';\n@import './splitter/style/entry.less';\n@import './statistic/style/entry.less';\n@import './steps/style/entry.less';\n@import './switch/style/entry.less';\n@import './table/style/entry.less';\n@import './tabs/style/entry.less';\n@import './tag/style/entry.less';\n@import './time-picker/style/entry.less';\n@import './timeline/style/entry.less';\n@import './tooltip/style/entry.less';\n@import './transfer/style/entry.less';\n@import './typography/style/entry.less';\n@import './upload/style/entry.less';\n@import './auto-complete/style/entry.less';\n@import './cascader/style/entry.less';\n@import './tree-view/style/entry.less';\n@import './tree/style/entry.less';\n@import './tree-select/style/entry.less';\n@import './calendar/style/entry.less';\n@import './result/style/entry.less';\n@import './space/style/entry.less';\n@import './image/style/entry.less';\n@import './cron-expression/style/entry.less';\n@import './qr-code/style/entry.less';\n@import './color-picker/style/entry.less';\n@import './hash-code/style/entry.less';\n@import './float-button/style/entry.less';\n@import './check-list/style/entry.less';\n"
  },
  {
    "path": "components/core/animation/animation-consts.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport class AnimationDuration {\n  static SLOW = '0.3s'; // Modal\n  static BASE = '0.2s';\n  static FAST = '0.1s'; // Tooltip\n}\n\nexport class AnimationCurves {\n  static EASE_BASE_OUT = 'cubic-bezier(0.7, 0.3, 0.1, 1)';\n  static EASE_BASE_IN = 'cubic-bezier(0.9, 0, 0.3, 0.7)';\n  static EASE_OUT = 'cubic-bezier(0.215, 0.61, 0.355, 1)';\n  static EASE_IN = 'cubic-bezier(0.55, 0.055, 0.675, 0.19)';\n  static EASE_IN_OUT = 'cubic-bezier(0.645, 0.045, 0.355, 1)';\n  static EASE_OUT_BACK = 'cubic-bezier(0.12, 0.4, 0.29, 1.46)';\n  static EASE_IN_BACK = 'cubic-bezier(0.71, -0.46, 0.88, 0.6)';\n  static EASE_IN_OUT_BACK = 'cubic-bezier(0.71, -0.46, 0.29, 1.46)';\n  static EASE_OUT_CIRC = 'cubic-bezier(0.08, 0.82, 0.17, 1)';\n  static EASE_IN_CIRC = 'cubic-bezier(0.6, 0.04, 0.98, 0.34)';\n  static EASE_IN_OUT_CIRC = 'cubic-bezier(0.78, 0.14, 0.15, 0.86)';\n  static EASE_OUT_QUINT = 'cubic-bezier(0.23, 1, 0.32, 1)';\n  static EASE_IN_QUINT = 'cubic-bezier(0.755, 0.05, 0.855, 0.06)';\n  static EASE_IN_OUT_QUINT = 'cubic-bezier(0.86, 0, 0.07, 1)';\n}\n"
  },
  {
    "path": "components/core/animation/collapse.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { coerceCssPixelValue } from '@angular/cdk/coercion';\nimport { AnimationCallbackEvent, Directive, effect, ElementRef, inject, Injectable, input } from '@angular/core';\nimport { Subject } from 'rxjs';\nimport { debounceTime, take } from 'rxjs/operators';\n\nimport { requestAnimationFrame } from 'ng-zorro-antd/core/polyfill';\n\nimport { isAnimationEnabled, NzNoAnimationDirective } from './no-animation';\n\nconst COLLAPSE_MOTION_CLASS = 'ant-motion-collapse';\n\n@Directive({\n  // eslint-disable-next-line @angular-eslint/directive-selector\n  selector: '[animation-collapse]',\n  host: {\n    '(transitionend)': 'onTransitionEnd($event)'\n  }\n})\nexport class NzAnimationCollapseDirective {\n  private readonly elementRef = inject<ElementRef<HTMLElement>>(ElementRef);\n  private readonly noAnimation = inject(NzNoAnimationDirective, { optional: true, host: true });\n  private readonly animationEnabled = isAnimationEnabled(() => !this.noAnimation?.nzNoAnimation());\n\n  readonly open = input<boolean>(false);\n  readonly leavedClassName = input<string>('');\n  private firstRender = true;\n\n  constructor() {\n    effect(() => {\n      const open = this.open();\n      // should skip the first rendering\n      const animationEnabled = this.animationEnabled() && !this.firstRender;\n      const element = this.elementRef.nativeElement;\n      const leavedClassName = this.leavedClassName();\n\n      if (open && leavedClassName) {\n        element.classList.remove(leavedClassName);\n      }\n\n      if (animationEnabled) {\n        /**\n         * | open  | animation stage | height | opacity |\n         * | ----  | --------------- | ------ | ------- |\n         * | true  | before          | 0            | 1 |\n         * | true  | active          | scrollHeight | 1 |\n         * | true  | end             | auto         | 1 |\n         * | false | before          | scrollHeight | 0 |\n         * | false | active          | 0            | 0 |\n         * | false | end             | 0            | 0 |\n         */\n        element.classList.add(COLLAPSE_MOTION_CLASS);\n\n        if (open) {\n          // Wait for next frame to get correct scrollHeight after removing hidden class\n          requestAnimationFrame(() => {\n            const scrollHeight = this.getActualScrollHeight(element);\n            element.style.height = coerceCssPixelValue(scrollHeight);\n            element.style.opacity = '1';\n          });\n        } else {\n          // Used for setting height to actual height when transition start\n          const scrollHeight = this.getActualScrollHeight(element);\n          element.style.height = coerceCssPixelValue(scrollHeight);\n          requestAnimationFrame(() => {\n            element.style.height = coerceCssPixelValue(0);\n            element.style.opacity = '0';\n          });\n        }\n      } else {\n        if (open) {\n          element.style.height = 'auto';\n          element.style.opacity = '1';\n        } else {\n          element.style.height = coerceCssPixelValue(0);\n          element.style.opacity = '0';\n          if (leavedClassName) {\n            element.classList.add(leavedClassName);\n          }\n        }\n      }\n\n      this.firstRender = false;\n    });\n  }\n\n  // Calculate height by summing up direct children's offsetHeight\n  // This naturally excludes collapsed nested submenus since they have height: 0\n  private getActualScrollHeight(element: HTMLElement): number {\n    return Array.from(element.children).reduce((acc, child) => acc + (child as HTMLElement).offsetHeight, 0);\n  }\n\n  protected onTransitionEnd(event: TransitionEvent): void {\n    if (!this.animationEnabled() || event.target !== this.elementRef.nativeElement) {\n      return;\n    }\n\n    // set height to auto after transition end, so that it's height can be changed along with content\n    if (this.open()) {\n      this.elementRef.nativeElement.style.height = 'auto';\n    } else if (this.leavedClassName()) {\n      this.elementRef.nativeElement.classList.add(this.leavedClassName());\n    }\n\n    this.elementRef.nativeElement.classList.remove(COLLAPSE_MOTION_CLASS);\n  }\n}\n\n@Injectable()\nexport class NzAnimationTreeCollapseService {\n  firstRender = true;\n  virtualScroll = false;\n\n  readonly animationDone$ = new Subject<void>();\n\n  constructor() {\n    this.animationDone$.pipe(debounceTime(50), take(1)).subscribe(() => {\n      this.firstRender = false;\n    });\n  }\n}\n\n@Directive({\n  // eslint-disable-next-line @angular-eslint/directive-selector\n  selector: '[animation-tree-collapse]',\n  host: {\n    '(animate.enter)': 'onAnimationEnter($event)',\n    '(animate.leave)': 'onAnimationLeave($event)'\n  }\n})\nexport class NzAnimationTreeCollapseDirective {\n  private readonly treeCollapseService = inject(NzAnimationTreeCollapseService, { optional: true });\n  private readonly noAnimation = inject(NzNoAnimationDirective, { optional: true, host: true });\n  // should disable animation in virtual scrolling\n  private readonly animationEnabled = isAnimationEnabled(\n    () => !this.noAnimation?.nzNoAnimation() && !(this.treeCollapseService?.virtualScroll ?? false)\n  );\n\n  private get firstRender(): boolean {\n    return this.treeCollapseService?.firstRender ?? false;\n  }\n\n  protected onAnimationEnter(event: AnimationCallbackEvent): void {\n    if (!this.animationEnabled() || this.firstRender) {\n      this.treeCollapseService?.animationDone$.next();\n      event.animationComplete();\n      return;\n    }\n\n    const element = event.target as HTMLElement;\n    element.style.height = coerceCssPixelValue(0);\n    element.style.opacity = '0';\n    element.classList.add(COLLAPSE_MOTION_CLASS);\n\n    const onTransitionEnd = (e: TransitionEvent): void => {\n      // Only handle height transition to avoid premature cleanup\n      if (e.propertyName !== 'height') {\n        return;\n      }\n      element.removeEventListener('transitionend', onTransitionEnd);\n      element.style.height = 'auto';\n      element.classList.remove(COLLAPSE_MOTION_CLASS);\n      event.animationComplete();\n    };\n\n    requestAnimationFrame(() => {\n      element.style.height = coerceCssPixelValue(element.scrollHeight);\n      element.style.opacity = '1';\n    });\n\n    element.addEventListener('transitionend', onTransitionEnd);\n  }\n\n  protected onAnimationLeave(event: AnimationCallbackEvent): void {\n    if (!this.animationEnabled()) {\n      event.animationComplete();\n      return;\n    }\n\n    const element = event.target as HTMLElement;\n    element.style.height = coerceCssPixelValue(element.scrollHeight);\n    element.style.opacity = '1';\n    element.classList.add(COLLAPSE_MOTION_CLASS);\n\n    const onTransitionEnd = (e: TransitionEvent): void => {\n      // Only handle height transition to avoid premature cleanup\n      if (e.propertyName !== 'height') {\n        return;\n      }\n      element.removeEventListener('transitionend', onTransitionEnd);\n      event.animationComplete();\n    };\n\n    requestAnimationFrame(() => {\n      element.style.height = coerceCssPixelValue(0);\n      element.style.opacity = '0';\n      element.style.marginBottom = '0';\n    });\n\n    element.addEventListener('transitionend', onTransitionEnd);\n  }\n}\n"
  },
  {
    "path": "components/core/animation/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/core/animation/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/core/animation/no-animation.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ANIMATION_MODULE_TYPE, Component, signal } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport {\n  isAnimationEnabled,\n  NZ_NO_ANIMATION_CLASS,\n  NzNoAnimationDirective,\n  provideNzNoAnimation,\n  withAnimationCheck\n} from './no-animation';\n\n@Component({\n  template: `<div #element [nzNoAnimation]=\"noAnimation()\" data-testid=\"test-element\"></div>`,\n  imports: [NzNoAnimationDirective]\n})\nclass TestComponent {\n  noAnimation = signal(false);\n  animationClass = withAnimationCheck(() => 'animation-class');\n  animationEnabled = isAnimationEnabled(() => !this.noAnimation());\n}\n\ndescribe('NzNoAnimationDirective', () => {\n  let fixture: ComponentFixture<TestComponent>;\n  let component: TestComponent;\n\n  describe('without NoopAnimations', () => {\n    beforeEach(() => {\n      TestBed.configureTestingModule({});\n      fixture = TestBed.createComponent(TestComponent);\n      component = fixture.componentInstance;\n      fixture.detectChanges();\n    });\n\n    it('should not add animation disabled class when nzNoAnimation is false', () => {\n      const element = fixture.nativeElement.querySelector('[data-testid=\"test-element\"]');\n      expect(element.classList.contains(NZ_NO_ANIMATION_CLASS)).toBeFalse();\n    });\n\n    it('should add animation disabled class when nzNoAnimation is true', async () => {\n      component.noAnimation.set(true);\n      await fixture.whenStable();\n      const element = fixture.nativeElement.querySelector('[data-testid=\"test-element\"]');\n      expect(element.classList.contains(NZ_NO_ANIMATION_CLASS)).toBeTrue();\n    });\n  });\n\n  describe('with NoopAnimations', () => {\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        providers: [provideNoopAnimations()]\n      });\n      fixture = TestBed.createComponent(TestComponent);\n      component = fixture.componentInstance;\n      fixture.detectChanges();\n    });\n\n    it('should add animation disabled class even when nzNoAnimation is false', () => {\n      const element = fixture.nativeElement.querySelector('[data-testid=\"test-element\"]');\n      expect(element.classList.contains(NZ_NO_ANIMATION_CLASS)).toBeTrue();\n    });\n\n    it('should keep animation disabled class when nzNoAnimation is true', async () => {\n      component.noAnimation.set(true);\n      await fixture.whenStable();\n      const element = fixture.nativeElement.querySelector('[data-testid=\"test-element\"]');\n      expect(element.classList.contains(NZ_NO_ANIMATION_CLASS)).toBeTrue();\n    });\n  });\n});\n\ndescribe('provideNzNoAnimation', () => {\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [provideNzNoAnimation()]\n    });\n  });\n\n  it('should provide NoopAnimations animation type', () => {\n    const animationType = TestBed.inject(ANIMATION_MODULE_TYPE);\n    expect(animationType).toBe('NoopAnimations');\n  });\n\n  it('should disable animations globally when used', () => {\n    const fixture = TestBed.createComponent(TestComponent);\n    fixture.detectChanges();\n\n    const element = fixture.nativeElement.querySelector('[data-testid=\"test-element\"]');\n    expect(element.classList.contains(NZ_NO_ANIMATION_CLASS)).toBeTrue();\n  });\n});\n\ndescribe('isAnimationEnabled', () => {\n  it('should return passed getter when animations are enabled', () => {\n    const fixture = TestBed.createComponent(TestComponent);\n    expect(fixture.componentInstance.animationEnabled()).toBe(true);\n\n    fixture.componentInstance.noAnimation.set(true);\n    expect(fixture.componentInstance.animationEnabled()).toBe(false);\n  });\n\n  it('should return false with provideNoopAnimations', async () => {\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations()]\n    });\n    const fixture = TestBed.createComponent(TestComponent);\n    expect(fixture.componentInstance.animationEnabled()).toBe(false);\n  });\n\n  it('should return false with provideNzNoAnimation', async () => {\n    TestBed.configureTestingModule({\n      providers: [provideNzNoAnimation()]\n    });\n    const fixture = TestBed.createComponent(TestComponent);\n    expect(fixture.componentInstance.animationEnabled()).toBe(false);\n  });\n\n  describe('injection context validation', () => {\n    it('should throw error when called outside injection context in dev mode', () => {\n      const originalDevMode = (globalThis as { ngDevMode?: boolean }).ngDevMode;\n      (globalThis as { ngDevMode?: boolean }).ngDevMode = true;\n\n      expect(() => {\n        isAnimationEnabled(() => true);\n      }).toThrow();\n\n      (globalThis as { ngDevMode?: boolean }).ngDevMode = originalDevMode;\n    });\n  });\n});\n\ndescribe('withAnimationCheck', () => {\n  it('should return dynamic class when animations are enabled', () => {\n    const fixture = TestBed.createComponent(TestComponent);\n    fixture.detectChanges();\n\n    expect(fixture.componentInstance.animationClass()).toBe('animation-class');\n  });\n\n  it('should return no-animation class with provideNoopAnimations', () => {\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations()]\n    });\n    const fixture = TestBed.createComponent(TestComponent);\n    fixture.detectChanges();\n\n    expect(fixture.componentInstance.animationClass()).toBe(NZ_NO_ANIMATION_CLASS);\n  });\n\n  it('should return no-animation class with provideNzNoAnimation', () => {\n    TestBed.configureTestingModule({\n      providers: [provideNzNoAnimation()]\n    });\n    const fixture = TestBed.createComponent(TestComponent);\n    fixture.detectChanges();\n\n    expect(fixture.componentInstance.animationClass()).toBe(NZ_NO_ANIMATION_CLASS);\n  });\n\n  describe('injection context validation', () => {\n    it('should throw error when called outside injection context in dev mode', () => {\n      const originalDevMode = (globalThis as { ngDevMode?: boolean }).ngDevMode;\n      (globalThis as { ngDevMode?: boolean }).ngDevMode = true;\n\n      expect(() => {\n        withAnimationCheck(() => 'test-class');\n      }).toThrow();\n\n      (globalThis as { ngDevMode?: boolean }).ngDevMode = originalDevMode;\n    });\n  });\n});\n"
  },
  {
    "path": "components/core/animation/no-animation.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ANIMATION_MODULE_TYPE,\n  assertInInjectionContext,\n  booleanAttribute,\n  computed,\n  Directive,\n  inject,\n  input,\n  NgModule,\n  Provider,\n  signal,\n  Signal\n} from '@angular/core';\n\nexport const NZ_NO_ANIMATION_CLASS = 'nz-animate-disabled';\n\n@Directive({\n  selector: '[nzNoAnimation]',\n  exportAs: 'nzNoAnimation',\n  host: {\n    [`[class.${NZ_NO_ANIMATION_CLASS}]`]: `nzNoAnimation() || animationType === 'NoopAnimations'`\n  }\n})\nexport class NzNoAnimationDirective {\n  readonly animationType = inject(ANIMATION_MODULE_TYPE, { optional: true });\n  readonly nzNoAnimation = input(false, { transform: booleanAttribute });\n}\n\n/**\n * @deprecated Will be removed in v23, please use {@link NzNoAnimationDirective} instead.\n */\n@NgModule({\n  imports: [NzNoAnimationDirective],\n  exports: [NzNoAnimationDirective]\n})\nexport class NzNoAnimationModule {}\n\n/**\n * Returns the set of dependency-injection providers to disable animations in a context.\n */\nexport function provideNzNoAnimation(): Provider[] {\n  return [\n    {\n      provide: ANIMATION_MODULE_TYPE,\n      useValue: 'NoopAnimations'\n    }\n  ];\n}\n\nfunction _internalAnimationEnabled(): boolean {\n  return inject(ANIMATION_MODULE_TYPE, { optional: true }) !== 'NoopAnimations';\n}\n\n/**\n * If the current animation mode is `NoopAnimations`, returns the false as a signal.\n * Otherwise, returns the result of the provided getter as a computed signal.\n * @param getter A function that returns the outer logic for whether animations are enabled.\n */\nexport function isAnimationEnabled(getter: () => boolean): Signal<boolean> {\n  if (typeof ngDevMode !== 'undefined' && ngDevMode) {\n    assertInInjectionContext(isAnimationEnabled);\n  }\n\n  return _internalAnimationEnabled() ? computed(getter) : signal(false);\n}\n\n/**\n * If the current animation mode is `NoopAnimations`, returns the no-animation class as a signal.\n * Otherwise, returns the result of the provided class name getter as a computed signal.\n * @param classNameGetter A function that returns the class name string.\n */\nexport function withAnimationCheck(classNameGetter: () => string): Signal<string> {\n  if (typeof ngDevMode !== 'undefined' && ngDevMode) {\n    assertInInjectionContext(withAnimationCheck);\n  }\n\n  return _internalAnimationEnabled() ? computed(classNameGetter) : signal(NZ_NO_ANIMATION_CLASS);\n}\n"
  },
  {
    "path": "components/core/animation/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './animation-consts';\nexport * from './collapse';\nexport * from './slide';\nexport * from './no-animation';\n"
  },
  {
    "path": "components/core/animation/slide.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport type { Signal } from '@angular/core';\n\nimport { withAnimationCheck } from './no-animation';\n\nexport const SLIDE_ANIMATION_CLASS = {\n  enter: 'ant-slide-up-enter ant-slide-up-enter-active',\n  leave: 'ant-slide-up-leave ant-slide-up-leave-active'\n};\n\nexport const slideAnimationEnter = (): Signal<string> => withAnimationCheck(() => SLIDE_ANIMATION_CLASS.enter);\n\nexport const slideAnimationLeave = (): Signal<string> => withAnimationCheck(() => SLIDE_ANIMATION_CLASS.leave);\n"
  },
  {
    "path": "components/core/color/color.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nexport const statusColors = ['success', 'processing', 'error', 'default', 'warning'] as const;\n\nexport const presetColors = [\n  'pink',\n  'red',\n  'yellow',\n  'orange',\n  'cyan',\n  'green',\n  'blue',\n  'purple',\n  'geekblue',\n  'magenta',\n  'volcano',\n  'gold',\n  'lime'\n] as const;\n\nexport type NzPresetColor = (typeof presetColors)[number];\nexport type NzStatusColor = (typeof statusColors)[number];\n\nexport function isPresetColor(color: string): color is NzPresetColor {\n  return presetColors.indexOf(color as NzSafeAny) !== -1;\n}\n\nexport function isStatusColor(color: string): color is NzPresetColor {\n  return statusColors.indexOf(color as NzSafeAny) !== -1;\n}\n"
  },
  {
    "path": "components/core/color/generate.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\n/**\n * Sync from @ant-design/colors(https://github.com/ant-design/ant-design-colors)\n */\n\nimport { rgbToHsv, rgbToHex, inputToRGB } from '@ctrl/tinycolor';\n\nconst hueStep = 2; // 色相阶梯\nconst saturationStep = 0.16; // 饱和度阶梯，浅色部分\nconst saturationStep2 = 0.05; // 饱和度阶梯，深色部分\nconst brightnessStep1 = 0.05; // 亮度阶梯，浅色部分\nconst brightnessStep2 = 0.15; // 亮度阶梯，深色部分\nconst lightColorCount = 5; // 浅色数量，主色上\nconst darkColorCount = 4; // 深色数量，主色下\n// 暗色主题颜色映射关系表\nconst darkColorMap = [\n  { index: 7, opacity: 0.15 },\n  { index: 6, opacity: 0.25 },\n  { index: 5, opacity: 0.3 },\n  { index: 5, opacity: 0.45 },\n  { index: 5, opacity: 0.65 },\n  { index: 5, opacity: 0.85 },\n  { index: 4, opacity: 0.9 },\n  { index: 3, opacity: 0.95 },\n  { index: 2, opacity: 0.97 },\n  { index: 1, opacity: 0.98 }\n];\n\ninterface HsvObject {\n  h: number;\n  s: number;\n  v: number;\n}\n\ninterface RgbObject {\n  r: number;\n  g: number;\n  b: number;\n}\n\n// Wrapper function ported from TinyColor.prototype.toHsv\n// Keep it here because of `hsv.h * 360`\nfunction toHsv({ r, g, b }: RgbObject): HsvObject {\n  const hsv = rgbToHsv(r, g, b);\n  return { h: hsv.h * 360, s: hsv.s, v: hsv.v };\n}\n\n// Wrapper function ported from TinyColor.prototype.toHexString\n// Keep it here because of the prefix `#`\nfunction toHex({ r, g, b }: RgbObject): string {\n  return `#${rgbToHex(r, g, b, false)}`;\n}\n\n// Wrapper function ported from TinyColor.prototype.mix, not treeshakable.\n// Amount in range [0, 1]\n// Assume color1 & color2 has no alpha, since the following src code did so.\nfunction mix(rgb1: RgbObject, rgb2: RgbObject, amount: number): RgbObject {\n  const p = amount / 100;\n  const rgb = {\n    r: (rgb2.r - rgb1.r) * p + rgb1.r,\n    g: (rgb2.g - rgb1.g) * p + rgb1.g,\n    b: (rgb2.b - rgb1.b) * p + rgb1.b\n  };\n  return rgb;\n}\n\nfunction getHue(hsv: HsvObject, i: number, light?: boolean): number {\n  let hue: number;\n  // 根据色相不同，色相转向不同\n  if (Math.round(hsv.h) >= 60 && Math.round(hsv.h) <= 240) {\n    hue = light ? Math.round(hsv.h) - hueStep * i : Math.round(hsv.h) + hueStep * i;\n  } else {\n    hue = light ? Math.round(hsv.h) + hueStep * i : Math.round(hsv.h) - hueStep * i;\n  }\n  if (hue < 0) {\n    hue += 360;\n  } else if (hue >= 360) {\n    hue -= 360;\n  }\n  return hue;\n}\n\nfunction getSaturation(hsv: HsvObject, i: number, light?: boolean): number {\n  // grey color don't change saturation\n  if (hsv.h === 0 && hsv.s === 0) {\n    return hsv.s;\n  }\n  let saturation: number;\n  if (light) {\n    saturation = hsv.s - saturationStep * i;\n  } else if (i === darkColorCount) {\n    saturation = hsv.s + saturationStep;\n  } else {\n    saturation = hsv.s + saturationStep2 * i;\n  }\n  // 边界值修正\n  if (saturation > 1) {\n    saturation = 1;\n  }\n  // 第一格的 s 限制在 0.06-0.1 之间\n  if (light && i === lightColorCount && saturation > 0.1) {\n    saturation = 0.1;\n  }\n  if (saturation < 0.06) {\n    saturation = 0.06;\n  }\n  return Number(saturation.toFixed(2));\n}\n\nfunction getValue(hsv: HsvObject, i: number, light?: boolean): number {\n  let value: number;\n  if (light) {\n    value = hsv.v + brightnessStep1 * i;\n  } else {\n    value = hsv.v - brightnessStep2 * i;\n  }\n  if (value > 1) {\n    value = 1;\n  }\n  return Number(value.toFixed(2));\n}\n\ninterface Opts {\n  theme?: 'dark' | 'default';\n  backgroundColor?: string;\n}\n\nexport function generate(color: string, opts: Opts = {}): string[] {\n  const patterns: string[] = [];\n  const pColor = inputToRGB(color);\n  for (let i = lightColorCount; i > 0; i -= 1) {\n    const hsv = toHsv(pColor);\n    const colorString: string = toHex(\n      inputToRGB({\n        h: getHue(hsv, i, true),\n        s: getSaturation(hsv, i, true),\n        v: getValue(hsv, i, true)\n      })\n    );\n    patterns.push(colorString);\n  }\n  patterns.push(toHex(pColor));\n  for (let i = 1; i <= darkColorCount; i += 1) {\n    const hsv = toHsv(pColor);\n    const colorString: string = toHex(\n      inputToRGB({\n        h: getHue(hsv, i),\n        s: getSaturation(hsv, i),\n        v: getValue(hsv, i)\n      })\n    );\n    patterns.push(colorString);\n  }\n\n  // dark theme patterns\n  if (opts.theme === 'dark') {\n    return darkColorMap.map(({ index, opacity }) => {\n      const darkColorString: string = toHex(\n        mix(inputToRGB(opts.backgroundColor || '#141414'), inputToRGB(patterns[index]), opacity * 100)\n      );\n      return darkColorString;\n    });\n  }\n  return patterns;\n}\n"
  },
  {
    "path": "components/core/color/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/core/color/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/core/color/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './color';\nexport * from './generate';\n"
  },
  {
    "path": "components/core/config/config.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  CSP_NONCE,\n  DestroyRef,\n  Injectable,\n  afterNextRender,\n  assertInInjectionContext,\n  inject,\n  Signal,\n  computed,\n  WritableSignal,\n  signal,\n  InputSignalWithTransform,\n  InputSignal\n} from '@angular/core';\nimport { SIGNAL } from '@angular/core/primitives/signals';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Observable, Subject, Subscription } from 'rxjs';\nimport { filter, map } from 'rxjs/operators';\n\nimport { NZ_CONFIG, NzConfig, NzConfigKey } from './config';\nimport { registerTheme } from './css-variables';\n\nfunction isDefined<T>(value?: T): value is Exclude<T, undefined> {\n  return value !== undefined;\n}\n\nconst defaultPrefixCls = 'ant';\n\n@Injectable({\n  providedIn: 'root'\n})\nexport class NzConfigService {\n  private configUpdated$ = new Subject<keyof NzConfig>();\n\n  /**\n   * Sharing config signals for all components, used for {@link withConfigFactory}\n   * @internal\n   * @todo use nested signal to refactor the whole config service\n   */\n  private readonly _configMap = new Map<NzConfigKey, WritableSignal<NzConfig[NzConfigKey]>>();\n\n  /** Global config holding property. */\n  private readonly config: NzConfig = inject(NZ_CONFIG, { optional: true }) || {};\n\n  private readonly cspNonce: string | null = inject(CSP_NONCE, { optional: true });\n\n  constructor() {\n    if (this.config.theme) {\n      // If theme is set with NZ_CONFIG, register theme to make sure css variables work\n      registerTheme(this.getConfig().prefixCls?.prefixCls || defaultPrefixCls, this.config.theme, this.cspNonce);\n    }\n  }\n\n  private _getConfigValue<T extends NzConfigKey>(componentName: T): WritableSignal<NzConfig[T]> {\n    let configValue = this._configMap.get(componentName) as WritableSignal<NzConfig[T]>;\n    if (configValue) {\n      return configValue;\n    }\n\n    configValue = signal(this.config[componentName]);\n    this._configMap.set(componentName, configValue);\n    return configValue;\n  }\n\n  getConfig(): NzConfig {\n    return this.config;\n  }\n\n  getConfigForComponent<T extends NzConfigKey>(componentName: T): NzConfig[T] {\n    return this.config[componentName];\n  }\n\n  getConfigChangeEventForComponent(componentName: NzConfigKey): Observable<void> {\n    return this.configUpdated$.pipe(\n      filter(n => n === componentName),\n      map(() => undefined)\n    );\n  }\n\n  set<T extends NzConfigKey>(componentName: T, value: NzConfig[T]): void {\n    this.config[componentName] = { ...this.config[componentName], ...value };\n    this._configMap.get(componentName)?.set(this.config[componentName]);\n    if (componentName === 'theme' && this.config.theme) {\n      registerTheme(this.getConfig().prefixCls?.prefixCls || defaultPrefixCls, this.config.theme, this.cspNonce);\n    }\n    this.configUpdated$.next(componentName);\n  }\n}\n\n/**\n * Subscribes to configuration change events for a specific NZ component after the next render cycle.\n *\n * This utility is intended for use within Angular injection contexts and handles automatic\n * unsubscription via `DestroyRef`. It returns a cleanup function that can be manually called\n * to unsubscribe early if needed.\n *\n * @param componentName - The name of the component (as defined in `NzConfigKey`) to listen for config changes.\n * @param callback - A function to invoke when the component's configuration changes.\n * @returns A cleanup function that destroys the post-render effect and unsubscribes from the config event.\n *\n * @throws If called outside of an Angular injection context (in dev mode).\n */\nexport function onConfigChangeEventForComponent(componentName: NzConfigKey, callback: () => void): () => void {\n  if (typeof ngDevMode !== 'undefined' && ngDevMode) {\n    assertInInjectionContext(onConfigChangeEventForComponent);\n  }\n\n  const destroyRef = inject(DestroyRef);\n  const nzConfigService = inject(NzConfigService);\n  let subscription: Subscription | null = null;\n\n  const ref = afterNextRender(() => {\n    subscription = nzConfigService\n      .getConfigChangeEventForComponent(componentName)\n      .pipe(takeUntilDestroyed(destroyRef))\n      .subscribe(callback);\n  });\n\n  return () => {\n    ref.destroy();\n    subscription?.unsubscribe();\n  };\n}\n\n/**\n * This decorator is used to decorate class field. If a class field is decorated and unassigned, it would try to load default value from `NZ_CONFIG`\n *\n * @note that the class must have `_nzModuleName`({@link NzConfigKey}) property.\n * @example\n * ```ts\n * class ExampleComponent {\n *   private readonly _nzModuleName: NzConfigKey = 'button';\n *   @WithConfig() size: string = 'default';\n * }\n * ```\n */\nexport function WithConfig<This, Value>() {\n  return function (_value: undefined, context: ClassFieldDecoratorContext<This, Value>) {\n    context.addInitializer(function () {\n      const nzConfigService = inject(NzConfigService);\n      const originalValue = this[context.name as keyof This];\n\n      let value: Value;\n      let assignedByUser = false;\n\n      Object.defineProperty(this, context.name, {\n        get: () => {\n          const configValue = nzConfigService.getConfigForComponent(\n            this['_nzModuleName' as keyof This] as NzConfigKey\n          )?.[context.name as keyof NzConfig[NzConfigKey]];\n\n          if (assignedByUser) {\n            return value;\n          }\n\n          if (isDefined(configValue)) {\n            return configValue;\n          }\n\n          return originalValue;\n        },\n        set: (newValue: Value) => {\n          // if the newValue is undefined, we also consider it as not assigned by user\n          assignedByUser = isDefined(newValue);\n          value = newValue;\n        },\n        enumerable: true,\n        configurable: true\n      });\n    });\n  };\n}\n\n/**\n * Generate a `withConfig` function for a specific component, which would try to load default value from `NZ_CONFIG`\n * if the `input` property is not assigned by user.\n *\n * @param componentName The name of component (as defined in {@link NzConfigKey}) to listen for config changes.\n * @example\n * ```ts\n * const withConfig = withConfigFactory('button');\n *\n * class ExampleComponent {\n *   readonly nzSize = input<NzButtonSize>('default');\n *   protected readonly size = withConfig('nzSize', this.nzSize);\n * }\n * ```\n */\nexport function withConfigFactory<T extends NzConfigKey>(componentName: T) {\n  /**\n   * @param name The name of input property.\n   * @param inputSignal The input signal.\n   * @param defaultValue The default value.\n   */\n  return <N extends keyof NonNullable<NzConfig[T]>, V = NonNullable<NzConfig[T]>[N]>(\n    name: N,\n    inputSignal: InputSignal<V | undefined> | InputSignalWithTransform<V | undefined, unknown>,\n    defaultValue: V\n  ): Signal<V> => {\n    const configValueSignal = inject(NzConfigService)['_getConfigValue'](componentName);\n\n    return computed<V>(() => {\n      const configValue = configValueSignal()?.[name] as V | undefined;\n      const inputValue = inputSignal();\n      // if the version of the inputSignal is 0 or the inputValue is undefined, we consider it as not assigned by user\n      const assignedByUser = inputSignal[SIGNAL].version > 0 && isDefined(inputValue);\n\n      if (assignedByUser) {\n        return inputValue;\n      }\n\n      if (isDefined(configValue)) {\n        return configValue;\n      }\n\n      return defaultValue;\n    });\n  };\n}\n"
  },
  {
    "path": "components/core/config/config.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, ElementRef, inject, input, Input, inputBinding, signal } from '@angular/core';\nimport { TestBed } from '@angular/core/testing';\n\nimport { NzButtonSize } from 'ng-zorro-antd/button';\n\nimport { NzConfigKey, provideNzConfig } from './config';\nimport { NzConfigService, withConfigFactory, WithConfig } from './config.service';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'button';\nconst withConfig = withConfigFactory(NZ_CONFIG_MODULE_NAME);\n\n@Component({\n  selector: 'nz-with-config',\n  template: ``\n})\nclass NzWithConfigTestComponent {\n  readonly elementRef = inject(ElementRef);\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  @Input() @WithConfig() nzSize: NzButtonSize = 'default';\n}\n\n@Component({\n  selector: 'nz-with-config-signal',\n  template: ``\n})\nclass NzWithConfigSignalTestComponent {\n  readonly elementRef = inject(ElementRef);\n\n  readonly nzSize = input<NzButtonSize>();\n  readonly innerSize = withConfig('nzSize', this.nzSize, 'default');\n}\n\ndescribe('nz global config', () => {\n  const size = signal<NzButtonSize | undefined>(undefined);\n\n  // resign to unassigned value\n  afterEach(() => {\n    size.set(undefined);\n  });\n\n  describe('@WithConfig', () => {\n    it('should render with in-component props', async () => {\n      const fixture = TestBed.createComponent(NzWithConfigTestComponent, {\n        bindings: [inputBinding('nzSize', size)]\n      });\n      const component = fixture.debugElement.componentInstance as NzWithConfigTestComponent;\n      await fixture.whenStable();\n\n      fixture.detectChanges();\n      expect(component.nzSize).toBe('default');\n\n      size.set('large');\n      fixture.detectChanges();\n      expect(component.nzSize).toBe('large');\n    });\n\n    describe('with config', () => {\n      beforeEach(() => {\n        TestBed.configureTestingModule({\n          providers: [\n            provideNzConfig({\n              button: {\n                nzSize: 'large'\n              }\n            })\n          ]\n        });\n      });\n\n      it('should static config work', async () => {\n        const fixture = TestBed.createComponent(NzWithConfigTestComponent, {\n          bindings: [inputBinding('nzSize', size)]\n        });\n        const component = fixture.debugElement.componentInstance as NzWithConfigTestComponent;\n        await fixture.whenStable();\n\n        fixture.detectChanges();\n        expect(component.nzSize).toBe('large');\n\n        size.set('default');\n        fixture.detectChanges();\n        expect(component.nzSize).toBe('default');\n      });\n\n      it('should dynamic config work', async () => {\n        const fixture = TestBed.createComponent(NzWithConfigTestComponent, {\n          bindings: [inputBinding('nzSize', size)]\n        });\n        const component = fixture.debugElement.componentInstance as NzWithConfigTestComponent;\n        const nzConfigService = TestBed.inject(NzConfigService);\n        await fixture.whenStable();\n\n        fixture.detectChanges();\n        expect(component.nzSize).toBe('large');\n\n        nzConfigService.set('button', { nzSize: 'small' });\n        fixture.detectChanges();\n        expect(component.nzSize).toBe('small');\n\n        size.set('default');\n        fixture.detectChanges();\n        expect(component.nzSize).toBe('default');\n      });\n    });\n  });\n\n  describe('withConfig signal', () => {\n    it('should render with in-component props', async () => {\n      const fixture = TestBed.createComponent(NzWithConfigSignalTestComponent, {\n        bindings: [inputBinding('nzSize', size)]\n      });\n      const component = fixture.debugElement.componentInstance as NzWithConfigSignalTestComponent;\n      await fixture.whenStable();\n\n      fixture.detectChanges();\n      expect(component.nzSize()).toBeUndefined();\n      expect(component.innerSize()).toBe('default');\n\n      size.set('large');\n      fixture.detectChanges();\n      expect(component.nzSize()).toBe('large');\n      expect(component.innerSize()).toBe('large');\n    });\n\n    describe('with config', () => {\n      beforeEach(() => {\n        TestBed.configureTestingModule({\n          providers: [\n            provideNzConfig({\n              button: {\n                nzSize: 'large'\n              }\n            })\n          ]\n        });\n      });\n\n      it('should static config work', async () => {\n        const fixture = TestBed.createComponent(NzWithConfigSignalTestComponent, {\n          bindings: [inputBinding('nzSize', size)]\n        });\n        const component = fixture.debugElement.componentInstance as NzWithConfigSignalTestComponent;\n        await fixture.whenStable();\n\n        fixture.detectChanges();\n        expect(component.nzSize()).toBeUndefined();\n        expect(component.innerSize()).toBe('large');\n\n        size.set('default');\n        fixture.detectChanges();\n        expect(component.nzSize()).toBe('default');\n        expect(component.innerSize()).toBe('default');\n      });\n\n      it('should dynamic config work', async () => {\n        const fixture = TestBed.createComponent(NzWithConfigSignalTestComponent, {\n          bindings: [inputBinding('nzSize', size)]\n        });\n        const component = fixture.debugElement.componentInstance as NzWithConfigSignalTestComponent;\n        const nzConfigService = TestBed.inject(NzConfigService);\n        await fixture.whenStable();\n\n        fixture.detectChanges();\n        expect(component.nzSize()).toBeUndefined();\n        expect(component.innerSize()).toBe('large');\n\n        nzConfigService.set('button', { nzSize: 'small' });\n        fixture.detectChanges();\n        expect(component.nzSize()).toBeUndefined();\n        expect(component.innerSize()).toBe('small');\n\n        size.set('default');\n        fixture.detectChanges();\n        expect(component.nzSize()).toBe('default');\n        expect(component.innerSize()).toBe('default');\n      });\n    });\n  });\n\n  describe('theme config', () => {\n    let nzConfigService: NzConfigService;\n\n    beforeEach(() => {\n      nzConfigService = TestBed.inject(NzConfigService);\n    });\n\n    function getComputedStylePropertyValue(property: string): string {\n      return getComputedStyle(document.documentElement).getPropertyValue(property).trim();\n    }\n\n    it('should dynamic theme colors config work', () => {\n      nzConfigService.set('theme', { primaryColor: '#0000FF' });\n      expect(getComputedStylePropertyValue('--ant-primary-color')).toEqual('rgb(0, 0, 255)');\n    });\n\n    it('should dynamic theme colors config with custom prefix work', () => {\n      nzConfigService.set('prefixCls', { prefixCls: 'custom-variable' });\n      nzConfigService.set('theme', { primaryColor: '#0000FF' });\n      expect(getComputedStylePropertyValue('--custom-variable-primary-color')).toEqual('rgb(0, 0, 255)');\n    });\n  });\n});\n"
  },
  {
    "path": "components/core/config/config.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction } from '@angular/cdk/bidi';\nimport { EnvironmentProviders, InjectionToken, makeEnvironmentProviders, TemplateRef, Type } from '@angular/core';\nimport { SafeUrl } from '@angular/platform-browser';\n\nimport { ThemeType } from '@ant-design/icons-angular';\n\nimport { NzBreakpointEnum } from 'ng-zorro-antd/core/services';\nimport {\n  NzSafeAny,\n  NzShapeSCType,\n  NzSizeDSType,\n  NzSizeLDSType,\n  NzSizeMDSType,\n  NzTSType,\n  NzVariant\n} from 'ng-zorro-antd/core/types';\n\ninterface MonacoEnvironment {\n  globalAPI?: boolean;\n  baseUrl?: string;\n  getWorker?(workerId: string, label: string): Promise<Worker> | Worker;\n  getWorkerUrl?(workerId: string, label: string): string;\n}\n\nexport interface NzConfig {\n  affix?: AffixConfig;\n  select?: SelectConfig;\n  alert?: AlertConfig;\n  anchor?: AnchorConfig;\n  avatar?: AvatarConfig;\n  floatButton?: FloatButtonConfig;\n  badge?: BadgeConfig;\n  button?: ButtonConfig;\n  card?: CardConfig;\n  carousel?: CarouselConfig;\n  cascader?: CascaderConfig;\n  codeEditor?: CodeEditorConfig;\n  collapse?: CollapseConfig;\n  collapsePanel?: CollapsePanelConfig;\n  datePicker?: DatePickerConfig;\n  descriptions?: DescriptionsConfig;\n  drawer?: DrawerConfig;\n  dropdown?: DropdownConfig;\n  empty?: EmptyConfig;\n  filterTrigger?: FilterTriggerConfig;\n  form?: FormConfig;\n  icon?: IconConfig;\n  message?: MessageConfig;\n  modal?: ModalConfig;\n  notification?: NotificationConfig;\n  pageHeader?: PageHeaderConfig;\n  pagination?: PaginationConfig;\n  progress?: ProgressConfig;\n  rate?: RateConfig;\n  segmented?: SegmentedConfig;\n  space?: SpaceConfig;\n  spin?: SpinConfig;\n  switch?: SwitchConfig;\n  table?: TableConfig;\n  tabs?: TabsConfig;\n  timePicker?: TimePickerConfig;\n  tree?: TreeConfig;\n  treeSelect?: TreeSelectConfig;\n  typography?: TypographyConfig;\n  image?: ImageConfig;\n  popconfirm?: PopConfirmConfig;\n  popover?: PopoverConfig;\n  imageExperimental?: ImageExperimentalConfig;\n  theme?: Theme;\n  prefixCls?: PrefixCls;\n}\n\nexport interface PrefixCls {\n  prefixCls?: string;\n  iconPrefixCls?: string;\n}\n\nexport interface Theme {\n  primaryColor?: string;\n  infoColor?: string;\n  successColor?: string;\n  processingColor?: string;\n  errorColor?: string;\n  warningColor?: string;\n  [key: string]: string | undefined;\n}\n\nexport interface SelectConfig {\n  nzVariant?: NzVariant;\n  nzSuffixIcon?: TemplateRef<NzSafeAny> | string | null;\n  nzBackdrop?: boolean;\n  nzOptionHeightPx?: number;\n}\n\nexport interface AffixConfig {\n  nzOffsetBottom?: number;\n  nzOffsetTop?: number;\n}\n\nexport interface AlertConfig {\n  nzCloseable?: boolean;\n  nzShowIcon?: boolean;\n}\n\nexport interface AvatarConfig {\n  nzShape?: NzShapeSCType;\n  nzSize?: NzSizeLDSType | number;\n  nzGap?: number;\n}\n\nexport interface AnchorConfig {\n  nzBounds?: number;\n  nzOffsetBottom?: number;\n  nzOffsetTop?: number;\n  nzShowInkInFixed?: boolean;\n}\n\nexport interface BadgeConfig {\n  nzColor?: number;\n  nzOverflowCount?: number;\n  nzShowZero?: number;\n}\n\nexport interface ButtonConfig {\n  nzSize?: 'large' | 'default' | 'small';\n}\n\nexport interface CodeEditorConfig {\n  assetsRoot?: string | SafeUrl;\n  extraConfig?: NzSafeAny;\n  defaultEditorOption?: NzSafeAny;\n  useStaticLoading?: boolean;\n  monacoEnvironment?: MonacoEnvironment;\n\n  onLoad?(): void;\n\n  onFirstEditorInit?(): void;\n\n  onInit?(): void;\n}\n\nexport interface CardConfig {\n  nzSize?: NzSizeDSType;\n  nzHoverable?: boolean;\n  nzBordered?: boolean;\n}\n\nexport interface CarouselConfig {\n  nzAutoPlay?: boolean;\n  nzAutoPlaySpeed?: boolean;\n  nzDots?: boolean;\n  nzEffect?: 'scrollx' | 'fade' | string;\n  nzEnableSwipe?: boolean;\n  nzVertical?: boolean;\n  nzLoop?: boolean;\n}\n\nexport interface CascaderConfig {\n  nzSize?: string;\n  nzBackdrop?: boolean;\n  nzVariant?: NzVariant;\n}\n\nexport interface CollapseConfig {\n  nzAccordion?: boolean;\n  nzBordered?: boolean;\n  nzGhost?: boolean;\n}\n\nexport interface CollapsePanelConfig {\n  nzShowArrow?: boolean;\n}\n\nexport interface DatePickerConfig {\n  nzSeparator?: string;\n  nzSuffixIcon?: string | TemplateRef<NzSafeAny>;\n  nzBackdrop?: boolean;\n  nzVariant?: NzVariant;\n}\n\nexport interface DescriptionsConfig {\n  nzBordered?: boolean;\n  nzColumn?: Partial<Record<NzBreakpointEnum, number>> | number;\n  nzSize?: 'default' | 'middle' | 'small';\n  nzColon?: boolean;\n}\n\nexport interface DrawerConfig {\n  nzMask?: boolean;\n  nzMaskClosable?: boolean;\n  nzCloseOnNavigation?: boolean;\n  nzDirection?: Direction;\n}\n\nexport interface DropdownConfig {\n  nzBackdrop?: boolean;\n}\n\nexport interface EmptyConfig {\n  nzDefaultEmptyContent?: Type<NzSafeAny> | TemplateRef<string> | string | undefined;\n}\n\nexport interface FilterTriggerConfig {\n  nzBackdrop?: boolean;\n}\n\nexport interface FloatButtonConfig {\n  nzVisibilityHeight?: number;\n}\n\nexport interface FormConfig {\n  nzNoColon?: boolean;\n  nzAutoTips?: Record<string, Record<string, string>>;\n  nzTooltipIcon?: string | { type: string; theme: ThemeType };\n}\n\nexport interface IconConfig {\n  nzTheme?: 'fill' | 'outline' | 'twotone';\n  nzTwotoneColor?: string;\n}\n\nexport interface MessageConfig {\n  nzAnimate?: boolean;\n  nzDuration?: number;\n  nzMaxStack?: number;\n  nzPauseOnHover?: boolean;\n  nzTop?: number | string;\n  nzDirection?: Direction;\n}\n\nexport interface ModalConfig {\n  nzMask?: boolean;\n  nzMaskClosable?: boolean;\n  nzCloseOnNavigation?: boolean;\n  nzDirection?: Direction;\n}\n\nexport interface NotificationConfig extends MessageConfig {\n  nzTop?: string | number;\n  nzBottom?: string | number;\n  nzPlacement?: 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight' | 'top' | 'bottom';\n}\n\nexport interface PageHeaderConfig {\n  nzGhost: boolean;\n}\n\nexport interface PaginationConfig {\n  nzSize?: 'default' | 'small';\n  nzPageSizeOptions?: number[];\n  nzShowSizeChanger?: boolean;\n  nzShowQuickJumper?: boolean;\n  nzSimple?: boolean;\n}\n\nexport interface ProgressConfig {\n  nzGapDegree?: number;\n  nzGapPosition?: 'top' | 'right' | 'bottom' | 'left';\n  nzShowInfo?: boolean;\n  nzStrokeSwitch?: number;\n  nzStrokeWidth?: number;\n  nzSize?: 'default' | 'small';\n  nzStrokeLinecap?: 'round' | 'square';\n  nzStrokeColor?: string;\n}\n\nexport interface RateConfig {\n  nzAllowClear?: boolean;\n  nzAllowHalf?: boolean;\n}\n\nexport interface SegmentedConfig {\n  nzSize?: NzSizeLDSType;\n}\n\nexport interface SpaceConfig {\n  nzSize?: 'small' | 'middle' | 'large' | number | Array<'small' | 'middle' | 'large' | number>;\n}\n\nexport interface SpinConfig {\n  nzIndicator?: TemplateRef<NzSafeAny>;\n}\n\nexport interface SwitchConfig {\n  nzSize: NzSizeDSType;\n}\n\nexport interface TableConfig {\n  nzBordered?: boolean;\n  nzSize?: NzSizeMDSType;\n  nzShowQuickJumper?: boolean;\n  nzLoadingIndicator?: TemplateRef<NzSafeAny>;\n  nzShowSizeChanger?: boolean;\n  nzSimple?: boolean;\n  nzHideOnSinglePage?: boolean;\n  /**\n   * @see {@link NzTableSortOrder}\n   */\n  nzSortDirections?: Array<string | 'ascend' | 'descend' | null>;\n}\n\nexport interface TabsConfig {\n  nzAnimated?:\n    | boolean\n    | {\n        inkBar: boolean;\n        tabPane: boolean;\n      };\n  nzSize?: NzSizeLDSType;\n  nzType?: 'line' | 'card';\n  nzTabBarGutter?: number;\n  nzShowPagination?: boolean;\n}\n\nexport interface TimePickerConfig {\n  nzAllowEmpty?: boolean;\n  nzClearText?: string;\n  nzNowText?: string;\n  nzOkText?: string;\n  nzFormat?: string;\n  nzHourStep?: number;\n  nzMinuteStep?: number;\n  nzSecondStep?: number;\n  nzPopupClassName?: string;\n  nzUse12Hours?: string;\n  nzSuffixIcon?: string | TemplateRef<NzSafeAny>;\n  nzBackdrop?: boolean;\n  nzVariant?: NzVariant;\n}\n\nexport interface TreeConfig {\n  nzBlockNode?: boolean;\n  nzShowIcon?: boolean;\n  nzHideUnMatched?: boolean;\n}\n\nexport interface TreeSelectConfig {\n  nzShowIcon?: string;\n  nzShowLine?: boolean;\n  nzDropdownMatchSelectWidth?: boolean;\n  nzHideUnMatched?: boolean;\n  nzSize?: 'large' | 'small' | 'default';\n  nzBackdrop?: boolean;\n  nzVariant?: NzVariant;\n}\n\nexport interface TypographyConfig {\n  nzEllipsisRows?: number;\n  nzCopyTooltips?: [NzTSType, NzTSType] | null;\n  nzCopyIcons: [NzTSType, NzTSType];\n  nzEditTooltip?: null | NzTSType;\n  nzEditIcon: NzTSType;\n}\n\nexport interface ImageConfig {\n  nzFallback?: string;\n  nzPlaceholder?: string;\n  nzDisablePreview?: string;\n  nzCloseOnNavigation?: boolean;\n  nzDirection?: Direction;\n  nzScaleStep?: number;\n}\n\nexport interface ImageExperimentalConfig {\n  nzFallback?: string;\n  nzPlaceholder?: string;\n  nzDisablePreview?: string;\n  nzCloseOnNavigation?: boolean;\n  nzDirection?: Direction;\n  nzAutoSrcset?: boolean;\n  nzSrcLoader?(params: { src: string; width: number }): string;\n}\n\nexport interface PopConfirmConfig {\n  nzPopconfirmBackdrop?: boolean;\n  nzAutofocus?: null | 'ok' | 'cancel';\n}\n\nexport interface PopoverConfig {\n  nzPopoverBackdrop?: boolean;\n}\n\nexport type NzConfigKey = keyof NzConfig;\n\n/**\n * User should provide an object implements this interface to set global configurations.\n */\nexport const NZ_CONFIG = new InjectionToken<NzConfig>(typeof ngDevMode !== 'undefined' && ngDevMode ? 'nz-config' : '');\n\nexport function provideNzConfig(config: NzConfig): EnvironmentProviders {\n  return makeEnvironmentProviders([{ provide: NZ_CONFIG, useValue: config }]);\n}\n"
  },
  {
    "path": "components/core/config/css-variables.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\n/**\n * Sync from @ant-design/colors(https://github.com/ant-design/ant-design-colors)\n */\nimport { TinyColor } from '@ctrl/tinycolor';\n\nimport { generate } from 'ng-zorro-antd/core/color';\nimport { warn } from 'ng-zorro-antd/core/logger';\nimport { canUseDom, updateCSS } from 'ng-zorro-antd/core/util';\n\nimport { Theme } from './config';\n\nconst dynamicStyleMark = `-ant-${Date.now()}-${Math.random()}`;\n\nexport function getStyle(globalPrefixCls: string, theme: Theme): string {\n  const variables: Record<string, string> = {};\n\n  const formatColor = (color: TinyColor, updater?: (cloneColor: TinyColor) => TinyColor | undefined): string => {\n    let clone = color.clone();\n    clone = updater?.(clone) || clone;\n    return clone.toRgbString();\n  };\n\n  const fillColor = (colorVal: string, type: string): void => {\n    const baseColor = new TinyColor(colorVal);\n    const colorPalettes = generate(baseColor.toRgbString());\n\n    variables[`${type}-color`] = formatColor(baseColor);\n    variables[`${type}-color-disabled`] = colorPalettes[1];\n    variables[`${type}-color-hover`] = colorPalettes[4];\n    variables[`${type}-color-active`] = colorPalettes[7];\n    variables[`${type}-color-outline`] = baseColor.clone().setAlpha(0.2).toRgbString();\n    variables[`${type}-color-deprecated-bg`] = colorPalettes[1];\n    variables[`${type}-color-deprecated-border`] = colorPalettes[3];\n  };\n\n  // ================ Primary Color ================\n  if (theme.primaryColor) {\n    fillColor(theme.primaryColor, 'primary');\n\n    const primaryColor = new TinyColor(theme.primaryColor);\n    const primaryColors = generate(primaryColor.toRgbString());\n\n    // Legacy - We should use semantic naming standard\n    primaryColors.forEach((color, index) => {\n      variables[`primary-${index + 1}`] = color;\n    });\n    // Deprecated\n    variables['primary-color-deprecated-l-35'] = formatColor(primaryColor, c => c.lighten(35));\n    variables['primary-color-deprecated-l-20'] = formatColor(primaryColor, c => c.lighten(20));\n    variables['primary-color-deprecated-t-20'] = formatColor(primaryColor, c => c.tint(20));\n    variables['primary-color-deprecated-t-50'] = formatColor(primaryColor, c => c.tint(50));\n    variables['primary-color-deprecated-f-12'] = formatColor(primaryColor, c => c.setAlpha(c.getAlpha() * 0.12));\n\n    const primaryActiveColor = new TinyColor(primaryColors[0]);\n    variables['primary-color-active-deprecated-f-30'] = formatColor(primaryActiveColor, c =>\n      c.setAlpha(c.getAlpha() * 0.3)\n    );\n    variables['primary-color-active-deprecated-d-02'] = formatColor(primaryActiveColor, c => c.darken(2));\n  }\n\n  // ================ Success Color ================\n  if (theme.successColor) {\n    fillColor(theme.successColor, 'success');\n  }\n\n  // ================ Warning Color ================\n  if (theme.warningColor) {\n    fillColor(theme.warningColor, 'warning');\n  }\n\n  // ================= Error Color =================\n  if (theme.errorColor) {\n    fillColor(theme.errorColor, 'error');\n  }\n\n  // ================= Info Color ==================\n  if (theme.infoColor) {\n    fillColor(theme.infoColor, 'info');\n  }\n\n  // Convert to css variables\n  const cssList = Object.keys(variables).map(key => `--${globalPrefixCls}-${key}: ${variables[key]};`);\n\n  return `\n  :root {\n    ${cssList.join('\\n')}\n  }\n  `.trim();\n}\n\nexport function registerTheme(globalPrefixCls: string, theme: Theme, cspNonce: string | null | undefined): void {\n  const style = getStyle(globalPrefixCls, theme);\n\n  if (canUseDom()) {\n    updateCSS(style, `${dynamicStyleMark}-dynamic-theme`, { cspNonce });\n  } else {\n    warn(`NzConfigService: SSR do not support dynamic theme with css variables.`);\n  }\n}\n"
  },
  {
    "path": "components/core/config/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/core/config/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/core/config/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './config.service';\nexport * from './config';\nexport * from './css-variables';\n"
  },
  {
    "path": "components/core/element-patch/element-patch.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, ElementRef, inject } from '@angular/core';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\n/**\n * A patch directive to select the element of a component.\n */\n@Directive({\n  selector: '[nzElement], [nz-element]',\n  exportAs: 'nzElement'\n})\nexport class NzElementPatchDirective {\n  public elementRef = inject(ElementRef<HTMLElement>);\n  get nativeElement(): NzSafeAny {\n    return this.elementRef.nativeElement;\n  }\n}\n"
  },
  {
    "path": "components/core/element-patch/element-patch.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzElementPatchDirective } from './element-patch.directive';\n\n/**\n * @deprecated Will be removed in v23, please use {@link NzElementPatchDirective} instead.\n */\n@NgModule({\n  imports: [NzElementPatchDirective],\n  exports: [NzElementPatchDirective]\n})\nexport class NzElementPatchModule {}\n"
  },
  {
    "path": "components/core/element-patch/element-patch.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, ViewChild } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\n\nimport { NzElementPatchDirective } from './element-patch.directive';\n\ndescribe('nz-element', () => {\n  let fixture: ComponentFixture<NzTestElementPatchComponent>;\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzTestElementPatchComponent);\n    fixture.detectChanges();\n  });\n\n  it('should getters work', () => {\n    const element = fixture.componentInstance.element.nativeElement as HTMLButtonElement;\n    expect(element.tagName).toBe('BUTTON');\n  });\n});\n\n@Component({\n  imports: [NzElementPatchDirective],\n  template: `<button nz-element>Action</button> `\n})\nexport class NzTestElementPatchComponent {\n  @ViewChild(NzElementPatchDirective) element!: NzElementPatchDirective;\n}\n"
  },
  {
    "path": "components/core/element-patch/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/core/element-patch/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/core/element-patch/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './element-patch.directive';\nexport * from './element-patch.module';\n"
  },
  {
    "path": "components/core/environments/environment.test.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport const environment = {\n  isTestMode: true\n};\n"
  },
  {
    "path": "components/core/environments/environment.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport const environment = {\n  isTestMode: false\n};\n"
  },
  {
    "path": "components/core/environments/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/core/environments/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/core/environments/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './environment';\n"
  },
  {
    "path": "components/core/form/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/core/form/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/core/form/nz-form-item-feedback-icon.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  inject,\n  Input,\n  OnChanges,\n  SimpleChanges,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { NzValidateStatus } from 'ng-zorro-antd/core/types';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nconst iconTypeMap = {\n  error: 'close-circle-fill',\n  validating: 'loading',\n  success: 'check-circle-fill',\n  warning: 'exclamation-circle-fill'\n} as const;\n\n@Component({\n  selector: 'nz-form-item-feedback-icon',\n  exportAs: 'nzFormFeedbackIcon',\n  imports: [NzIconModule],\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    @if (iconType) {\n      <nz-icon [nzType]=\"iconType\" />\n    }\n  `,\n  host: {\n    class: 'ant-form-item-feedback-icon',\n    '[class.ant-form-item-feedback-icon-error]': 'status===\"error\"',\n    '[class.ant-form-item-feedback-icon-warning]': 'status===\"warning\"',\n    '[class.ant-form-item-feedback-icon-success]': 'status===\"success\"',\n    '[class.ant-form-item-feedback-icon-validating]': 'status===\"validating\"'\n  }\n})\nexport class NzFormItemFeedbackIconComponent implements OnChanges {\n  public cdr = inject(ChangeDetectorRef);\n  @Input() status: NzValidateStatus = '';\n\n  iconType: (typeof iconTypeMap)[keyof typeof iconTypeMap] | null = null;\n\n  ngOnChanges(_changes: SimpleChanges): void {\n    this.updateIcon();\n  }\n\n  updateIcon(): void {\n    this.iconType = this.status ? iconTypeMap[this.status] : null;\n    this.cdr.markForCheck();\n  }\n}\n"
  },
  {
    "path": "components/core/form/nz-form-item-feedback-icon.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { DebugElement, SimpleChange } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { NzValidateStatus } from 'ng-zorro-antd/core/types';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzFormItemFeedbackIconComponent } from './nz-form-item-feedback-icon.component';\n\ndescribe('nz-form-item-feedback-icon', () => {\n  let fixture: ComponentFixture<NzFormItemFeedbackIconComponent>;\n  let component: NzFormItemFeedbackIconComponent;\n  let feedback: DebugElement;\n  let firstChange = true;\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), provideNzIconsTesting()]\n    });\n    fixture = TestBed.createComponent(NzFormItemFeedbackIconComponent);\n    component = fixture.componentInstance;\n    feedback = fixture.debugElement;\n    fixture.detectChanges();\n  });\n\n  function changeStatus(status: NzValidateStatus): void {\n    const previousStatus: NzValidateStatus = component.status;\n    component.status = status;\n    component.ngOnChanges({ status: new SimpleChange(previousStatus, status, firstChange) });\n    firstChange = false;\n    fixture.detectChanges();\n  }\n\n  it('should className correct', () => {\n    changeStatus('');\n    expect(fixture.nativeElement.classList).toContain('ant-form-item-feedback-icon');\n\n    changeStatus('success');\n    expect(fixture.nativeElement.classList).toContain('ant-form-item-feedback-icon-success');\n    expect(fixture.nativeElement.querySelector('.anticon-check-circle-fill')).toBeTruthy();\n\n    changeStatus('error');\n    expect(feedback.nativeElement.classList).toContain('ant-form-item-feedback-icon-error');\n    expect(feedback.nativeElement.querySelector('.anticon-close-circle-fill')).toBeTruthy();\n\n    changeStatus('warning');\n    expect(feedback.nativeElement.classList).toContain('ant-form-item-feedback-icon-warning');\n    expect(feedback.nativeElement.querySelector('.anticon-exclamation-circle-fill')).toBeTruthy();\n\n    changeStatus('validating');\n    expect(feedback.nativeElement.classList).toContain('ant-form-item-feedback-icon-validating');\n    expect(feedback.nativeElement.querySelector('.anticon-loading')).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "components/core/form/nz-form-no-status.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Injectable } from '@angular/core';\nimport { BehaviorSubject } from 'rxjs';\n\n// Used in input-group/input-number-group to make sure components in addon work well\n/**\n * @deprecated Will be removed in v22.0.0. This service will be removed along with input-group/input-number-group.\n */\n@Injectable()\nexport class NzFormNoStatusService {\n  noFormStatus = new BehaviorSubject<boolean>(false);\n}\n"
  },
  {
    "path": "components/core/form/nz-form-size.token.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { InjectionToken, type Signal } from '@angular/core';\n\nimport type { NzSizeLDSType } from 'ng-zorro-antd/core/types';\n\nexport const NZ_FORM_SIZE = new InjectionToken<Signal<NzSizeLDSType | undefined>>(\n  typeof ngDevMode !== 'undefined' && ngDevMode ? 'nz-form-size' : ''\n);\n"
  },
  {
    "path": "components/core/form/nz-form-status.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Injectable } from '@angular/core';\nimport { ReplaySubject } from 'rxjs';\n\nimport { NzValidateStatus } from 'ng-zorro-antd/core/types';\n\n@Injectable()\nexport class NzFormStatusService {\n  formStatusChanges = new ReplaySubject<{ status: NzValidateStatus; hasFeedback: boolean }>(1);\n}\n"
  },
  {
    "path": "components/core/form/nz-form-variant.token.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { InjectionToken, type Signal } from '@angular/core';\n\nimport type { NzVariant } from 'ng-zorro-antd/core/types';\n\nexport const NZ_FORM_VARIANT = new InjectionToken<Signal<NzVariant>>(\n  typeof ngDevMode !== 'undefined' && ngDevMode ? 'nz-form-variant' : ''\n);\n"
  },
  {
    "path": "components/core/form/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './nz-form-item-feedback-icon.component';\nexport * from './nz-form-no-status.service';\nexport * from './nz-form-size.token';\nexport * from './nz-form-status.service';\nexport * from './nz-form-variant.token';\n"
  },
  {
    "path": "components/core/highlight/highlight.pipe.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzHighlightPipe } from './highlight.pipe';\n\ndescribe('NzHighlightPipe', () => {\n  let pipe: NzHighlightPipe;\n\n  beforeEach(() => {\n    pipe = new NzHighlightPipe();\n  });\n\n  it('should return highlight tag', () => {\n    expect(pipe.transform('Ant Design of Angular', 'Angular')).toEqual('Ant Design of <span>Angular</span>');\n    expect(pipe.transform('Ant Design of Angular', 'Ant')).toEqual('<span>Ant</span> Design of Angular');\n  });\n\n  it('should highlight when there is a new value', () => {\n    expect(pipe.transform('Ant Design of Angular', 'Angular')).toEqual('Ant Design of <span>Angular</span>');\n    expect(pipe.transform('ng-zorro-antd', 'ng')).toEqual('<span>ng</span>-zorro-antd');\n  });\n\n  it('should renter origin value when highlight value is falsely', () => {\n    expect(pipe.transform('Ant Design of Angular', '')).toEqual('Ant Design of Angular');\n  });\n\n  it('should flags work', () => {\n    expect(pipe.transform('Ant Design of Angular', 'a', 'ig')).toEqual(\n      '<span>A</span>nt Design of <span>A</span>ngul<span>a</span>r'\n    );\n  });\n\n  it('should class work', () => {\n    expect(pipe.transform('Ant Design of Angular', 'Angular', '', 'highlight')).toEqual(\n      'Ant Design of <span class=\"highlight\">Angular</span>'\n    );\n  });\n\n  it('should escapes regex keyword', () => {\n    expect(\n      pipe.transform(\n        'Escapes of characters (\\\\, *, +, ?, |, {, [, (,), ^, $, ., #, and white space)',\n        '(\\\\, *, +, ?, |, {, [, (,), ^, $, ., #, and white space)'\n      )\n    ).toEqual('Escapes of characters <span>(\\\\, *, +, ?, |, {, [, (,), ^, $, ., #, and white space)</span>');\n  });\n\n  it('should encode HTML tags', () => {\n    expect(pipe.transform('<script>alert(\"hello\")</script>', '<script>alert(\"he')).toEqual(\n      '<span>&lt;script&gt;alert(&#34;he</span>llo&#34;)&lt;/script&gt;'\n    );\n  });\n\n  it('should highlight HTML entities', () => {\n    expect(pipe.transform('abc<>&\"¢¥~®™Abc', 'a', 'igm')).toEqual(\n      '<span>a</span>bc&lt;&gt;&amp;&#34;&#162;&#165;~&#174;&#8482;<span>A</span>bc'\n    );\n    expect(pipe.transform('<>&\"¢¥~®™', '>', 'igm')).toEqual(\n      '&lt;<span>&gt;</span>&amp;&#34;&#162;&#165;~&#174;&#8482;'\n    );\n    expect(pipe.transform('&forall;&nabla;&#8364;&#x20AC;', '&', 'g')).toEqual(\n      '<span>&amp;</span>forall;<span>&amp;</span>nabla;<span>&amp;</span>#8364;<span>&amp;</span>#x20AC;'\n    );\n    expect(pipe.transform('e😀m😁o😂j🤣i', '😂j', 'g')).toEqual(\n      'e&#128512;m&#128513;o<span>&#128514;j</span>&#129315;i'\n    );\n  });\n});\n"
  },
  {
    "path": "components/core/highlight/highlight.pipe.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Pipe, PipeTransform } from '@angular/core';\n\nimport { encodeEntities } from 'ng-zorro-antd/core/util';\n\n@Pipe({\n  name: 'nzHighlight'\n})\nexport class NzHighlightPipe implements PipeTransform {\n  private UNIQUE_WRAPPERS: [string, string] = ['##==-open_tag-==##', '##==-close_tag-==##'];\n\n  transform(value: string, highlightValue: string, flags?: string, klass?: string): string | null {\n    if (!highlightValue) {\n      return value;\n    }\n\n    // Escapes regex keyword to interpret these characters literally\n    const searchValue = new RegExp(highlightValue.replace(/([.*+?^=!:${}()|[\\]/\\\\])/g, '\\\\$&'), flags);\n    const wrapValue = value.replace(searchValue, `${this.UNIQUE_WRAPPERS[0]}$&${this.UNIQUE_WRAPPERS[1]}`);\n    return encodeEntities(wrapValue)\n      .replace(new RegExp(this.UNIQUE_WRAPPERS[0], 'g'), klass ? `<span class=\"${klass}\">` : '<span>')\n      .replace(new RegExp(this.UNIQUE_WRAPPERS[1], 'g'), '</span>');\n  }\n}\n"
  },
  {
    "path": "components/core/highlight/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/core/highlight/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/core/highlight/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './highlight.pipe';\n"
  },
  {
    "path": "components/core/logger/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/core/logger/logger.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { isDevMode } from '@angular/core';\n\nimport { environment } from 'ng-zorro-antd/core/environments';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nconst record: Record<string, boolean> = {};\n\nexport const PREFIX = '[NG-ZORRO]:';\n\nfunction notRecorded(...args: NzSafeAny[]): boolean {\n  const asRecord = args.reduce((acc, c) => acc + c.toString(), '');\n\n  if (record[asRecord]) {\n    return false;\n  } else {\n    record[asRecord] = true;\n    return true;\n  }\n}\n\nfunction consoleCommonBehavior(consoleFunc: (...args: NzSafeAny) => void, ...args: NzSafeAny[]): void {\n  if (environment.isTestMode || (isDevMode() && notRecorded(...args))) {\n    consoleFunc(...args);\n  }\n}\n\n// Warning should only be printed in dev mode and only once.\nexport const warn = (...args: NzSafeAny[]): void =>\n  consoleCommonBehavior((...arg: NzSafeAny[]) => console.warn(PREFIX, ...arg), ...args);\n\n// eslint-disable-next-line @typescript-eslint/explicit-function-return-type\nexport const warnDeprecation = (...args: NzSafeAny[]) => {\n  if (!environment.isTestMode) {\n    const stack = new Error().stack;\n    return consoleCommonBehavior((...arg: NzSafeAny[]) => console.warn(PREFIX, 'deprecated:', ...arg, stack), ...args);\n  } else {\n    return () => {};\n  }\n};\n\n// Log should only be printed in dev mode.\nexport const log = (...args: NzSafeAny[]): void => {\n  if (isDevMode()) {\n    console.log(PREFIX, ...args);\n  }\n};\n"
  },
  {
    "path": "components/core/logger/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/core/logger/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './logger';\n"
  },
  {
    "path": "components/core/outlet/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/core/outlet/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/core/outlet/outlet.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzStringTemplateOutletDirective } from './string-template-outlet.directive';\n\n@NgModule({\n  imports: [NzStringTemplateOutletDirective],\n  exports: [NzStringTemplateOutletDirective]\n})\nexport class NzOutletModule {}\n"
  },
  {
    "path": "components/core/outlet/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport { NzOutletModule } from './outlet.module';\nexport { NzStringTemplateOutletDirective } from './string-template-outlet.directive';\n"
  },
  {
    "path": "components/core/outlet/string-template-outlet.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  Directive,\n  EmbeddedViewRef,\n  inject,\n  Input,\n  OnChanges,\n  SimpleChange,\n  SimpleChanges,\n  TemplateRef,\n  ViewContainerRef\n} from '@angular/core';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { isTemplateRef } from 'ng-zorro-antd/core/util';\n\n@Directive({\n  selector: '[nzStringTemplateOutlet]',\n  exportAs: 'nzStringTemplateOutlet'\n})\nexport class NzStringTemplateOutletDirective<_T = unknown> implements OnChanges {\n  private viewContainer = inject(ViewContainerRef);\n  private templateRef = inject(TemplateRef<NzSafeAny>);\n\n  private embeddedViewRef: EmbeddedViewRef<NzSafeAny> | null = null;\n  private context = new NzStringTemplateOutletContext();\n  @Input() nzStringTemplateOutletContext: NzSafeAny | null = null;\n  @Input() nzStringTemplateOutlet: NzSafeAny | TemplateRef<NzSafeAny> = null;\n\n  static ngTemplateContextGuard<T>(\n    _dir: NzStringTemplateOutletDirective<T>,\n    _ctx: NzSafeAny\n  ): _ctx is NzStringTemplateOutletContext {\n    return true;\n  }\n\n  private recreateView(): void {\n    this.viewContainer.clear();\n    if (isTemplateRef(this.nzStringTemplateOutlet)) {\n      this.embeddedViewRef = this.viewContainer.createEmbeddedView(\n        this.nzStringTemplateOutlet,\n        this.nzStringTemplateOutletContext\n      );\n    } else {\n      this.embeddedViewRef = this.viewContainer.createEmbeddedView(this.templateRef, this.context);\n    }\n  }\n\n  private updateContext(): void {\n    const newCtx = isTemplateRef(this.nzStringTemplateOutlet) ? this.nzStringTemplateOutletContext : this.context;\n    const oldCtx = this.embeddedViewRef!.context as NzSafeAny;\n    if (newCtx) {\n      for (const propName of Object.keys(newCtx)) {\n        oldCtx[propName] = newCtx[propName];\n      }\n    }\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzStringTemplateOutletContext, nzStringTemplateOutlet } = changes;\n    const shouldRecreateView = (): boolean => {\n      let shouldOutletRecreate = false;\n      if (nzStringTemplateOutlet) {\n        shouldOutletRecreate =\n          nzStringTemplateOutlet.firstChange ||\n          isTemplateRef(nzStringTemplateOutlet.previousValue) ||\n          isTemplateRef(nzStringTemplateOutlet.currentValue);\n      }\n      const hasContextShapeChanged = (ctxChange: SimpleChange): boolean => {\n        const prevCtxKeys = Object.keys(ctxChange.previousValue || {});\n        const currCtxKeys = Object.keys(ctxChange.currentValue || {});\n        if (prevCtxKeys.length === currCtxKeys.length) {\n          for (const propName of currCtxKeys) {\n            if (prevCtxKeys.indexOf(propName) === -1) {\n              return true;\n            }\n          }\n          return false;\n        } else {\n          return true;\n        }\n      };\n      const shouldContextRecreate =\n        nzStringTemplateOutletContext && hasContextShapeChanged(nzStringTemplateOutletContext);\n      return shouldContextRecreate || shouldOutletRecreate;\n    };\n\n    if (nzStringTemplateOutlet) {\n      this.context.$implicit = nzStringTemplateOutlet.currentValue;\n    }\n\n    const recreateView = shouldRecreateView();\n    if (recreateView) {\n      /** recreate view when context shape or outlet change **/\n      this.recreateView();\n    } else {\n      /** update context **/\n      this.updateContext();\n    }\n  }\n}\n\nexport class NzStringTemplateOutletContext {\n  public $implicit: NzSafeAny;\n}\n"
  },
  {
    "path": "components/core/outlet/string-template-outlet.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, provideZoneChangeDetection, TemplateRef, ViewChild } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzOutletModule } from './outlet.module';\nimport { NzStringTemplateOutletDirective } from './string-template-outlet.directive';\n\ndescribe('string template outlet', () => {\n  let fixture: ComponentFixture<StringTemplateOutletTestComponent>;\n  let component: StringTemplateOutletTestComponent;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(StringTemplateOutletTestComponent);\n    component = fixture.componentInstance;\n    fixture.detectChanges();\n  });\n\n  describe('null', () => {\n    it('should no error when null', () => {\n      expect(fixture.nativeElement.innerText).toBe('TargetText');\n    });\n  });\n\n  describe('outlet change', () => {\n    it('should work when switch between null and string', () => {\n      component.stringTemplateOutlet = 'String Testing';\n      fixture.detectChanges();\n      expect(fixture.nativeElement.innerText).toBe('TargetText String Testing');\n      component.stringTemplateOutlet = null;\n      fixture.detectChanges();\n      expect(fixture.nativeElement.innerText).toBe('TargetText');\n    });\n\n    it('should work when switch between null and template', () => {\n      component.stringTemplateOutlet = component.stringTpl;\n      fixture.detectChanges();\n      expect(fixture.nativeElement.innerText).toBe('TargetText The data is');\n      component.stringTemplateOutlet = null;\n      fixture.detectChanges();\n      expect(fixture.nativeElement.innerText).toBe('TargetText');\n    });\n\n    it('should work when switch between string', () => {\n      component.stringTemplateOutlet = 'String Testing';\n      fixture.detectChanges();\n      expect(fixture.nativeElement.innerText).toBe('TargetText String Testing');\n      component.stringTemplateOutlet = 'String String';\n      fixture.detectChanges();\n      expect(fixture.nativeElement.innerText).toBe('TargetText String String');\n    });\n\n    it('should work when switch between string and template', () => {\n      component.stringTemplateOutlet = 'String Testing';\n      fixture.detectChanges();\n      expect(fixture.nativeElement.innerText).toBe('TargetText String Testing');\n      component.stringTemplateOutlet = component.stringTpl;\n      fixture.detectChanges();\n      expect(fixture.nativeElement.innerText).toBe('TargetText The data is');\n      component.stringTemplateOutlet = 'String Testing';\n      fixture.detectChanges();\n      expect(fixture.nativeElement.innerText).toBe('TargetText String Testing');\n    });\n\n    it('should work when switch between template', () => {\n      component.stringTemplateOutlet = component.stringTpl;\n      fixture.detectChanges();\n      expect(fixture.nativeElement.innerText).toBe('TargetText The data is');\n      component.stringTemplateOutlet = component.emptyTpl;\n      fixture.detectChanges();\n      expect(fixture.nativeElement.innerText).toBe('TargetText Empty Template');\n    });\n  });\n\n  describe('context shape change', () => {\n    it('should work when context shape change', () => {\n      component.stringTemplateOutlet = component.dataTimeTpl;\n      const spyOnUpdateContext = spyOn(\n        component.nzStringTemplateOutletDirective as NzSafeAny,\n        'updateContext'\n      ).and.callThrough();\n      const spyOnRecreateView = spyOn(\n        component.nzStringTemplateOutletDirective as NzSafeAny,\n        'recreateView'\n      ).and.callThrough();\n      fixture.detectChanges();\n      expect(fixture.nativeElement.innerText).toBe('TargetText The data is , The time is');\n      component.context = { $implicit: 'data', time: 'time' };\n      fixture.detectChanges();\n      expect(spyOnUpdateContext).toHaveBeenCalledTimes(0);\n      expect(spyOnRecreateView).toHaveBeenCalledTimes(2);\n      expect(fixture.nativeElement.innerText).toBe('TargetText The data is data, The time is time');\n    });\n  });\n\n  describe('context data change', () => {\n    it('should work when context implicit change', () => {\n      component.stringTemplateOutlet = component.stringTpl;\n      const spyOnUpdateContext = spyOn(\n        component.nzStringTemplateOutletDirective as NzSafeAny,\n        'updateContext'\n      ).and.callThrough();\n      const spyOnRecreateView = spyOn(\n        component.nzStringTemplateOutletDirective as NzSafeAny,\n        'recreateView'\n      ).and.callThrough();\n      fixture.detectChanges();\n      expect(fixture.nativeElement.innerText).toBe('TargetText The data is');\n      component.context = { $implicit: 'data' };\n      fixture.detectChanges();\n      expect(spyOnUpdateContext).toHaveBeenCalledTimes(1);\n      expect(spyOnRecreateView).toHaveBeenCalledTimes(1);\n      expect(fixture.nativeElement.innerText).toBe('TargetText The data is data');\n    });\n  });\n});\n\n@Component({\n  imports: [NzOutletModule],\n  template: `\n    TargetText\n    <ng-container *nzStringTemplateOutlet=\"stringTemplateOutlet; context: context; let stringTemplateOutlet\">\n      {{ stringTemplateOutlet }}\n    </ng-container>\n    <ng-template #stringTpl let-data>The data is {{ data }}</ng-template>\n    <ng-template #emptyTpl>Empty Template</ng-template>\n    <ng-template #dataTimeTpl let-data let-time=\"time\">The data is {{ data }}, The time is {{ time }}</ng-template>\n  `\n})\nexport class StringTemplateOutletTestComponent {\n  @ViewChild('stringTpl') stringTpl!: TemplateRef<NzSafeAny>;\n  @ViewChild('emptyTpl') emptyTpl!: TemplateRef<NzSafeAny>;\n  @ViewChild('dataTimeTpl') dataTimeTpl!: TemplateRef<NzSafeAny>;\n  @ViewChild(NzStringTemplateOutletDirective) nzStringTemplateOutletDirective!: NzStringTemplateOutletDirective;\n  stringTemplateOutlet: TemplateRef<NzSafeAny> | string | null = null;\n  context: NzSafeAny = { $implicit: '' };\n}\n"
  },
  {
    "path": "components/core/overlay/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/core/overlay/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/core/overlay/nz-connected-overlay.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  CdkConnectedOverlay,\n  CdkOverlayOrigin,\n  ConnectedOverlayPositionChange,\n  FlexibleConnectedPositionStrategyOrigin\n} from '@angular/cdk/overlay';\nimport { Directive, ElementRef, Input, booleanAttribute, inject } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { getPlacementName } from './overlay-position';\n\n/** Equivalent of `DOMRect` without some of the properties we don't care about. */\ntype Dimensions = Omit<DOMRect, 'x' | 'y' | 'toJSON'>;\n\n@Directive({\n  selector: '[cdkConnectedOverlay][nzConnectedOverlay]',\n  exportAs: 'nzConnectedOverlay'\n})\nexport class NzConnectedOverlayDirective {\n  private readonly cdkConnectedOverlay = inject(CdkConnectedOverlay);\n  @Input({ transform: booleanAttribute }) nzArrowPointAtCenter: boolean = false;\n\n  constructor() {\n    this.cdkConnectedOverlay.backdropClass = 'nz-overlay-transparent-backdrop';\n\n    this.cdkConnectedOverlay.positionChange.pipe(takeUntilDestroyed()).subscribe(position => {\n      if (this.nzArrowPointAtCenter) {\n        this.updateArrowPosition(position);\n      }\n    });\n  }\n\n  private updateArrowPosition(position: ConnectedOverlayPositionChange): void {\n    const originRect = this.getOriginRect();\n    const placement = getPlacementName(position);\n\n    let offsetX: number | undefined = 0;\n    let offsetY: number | undefined = 0;\n\n    if (placement === 'topLeft' || placement === 'bottomLeft') {\n      offsetX = originRect.width / 2 - 14;\n    } else if (placement === 'topRight' || placement === 'bottomRight') {\n      offsetX = -(originRect.width / 2 - 14);\n    } else if (placement === 'leftTop' || placement === 'rightTop') {\n      offsetY = originRect.height / 2 - 10;\n    } else if (placement === 'leftBottom' || placement === 'rightBottom') {\n      offsetY = -(originRect.height / 2 - 10);\n    }\n\n    if (this.cdkConnectedOverlay.offsetX !== offsetX || this.cdkConnectedOverlay.offsetY !== offsetY) {\n      this.cdkConnectedOverlay.offsetY = offsetY;\n      this.cdkConnectedOverlay.offsetX = offsetX;\n      this.cdkConnectedOverlay.overlayRef.updatePosition();\n    }\n  }\n\n  private getFlexibleConnectedPositionStrategyOrigin(): FlexibleConnectedPositionStrategyOrigin {\n    if (this.cdkConnectedOverlay.origin instanceof CdkOverlayOrigin) {\n      return this.cdkConnectedOverlay.origin.elementRef;\n    } else {\n      return this.cdkConnectedOverlay.origin;\n    }\n  }\n\n  private getOriginRect(): Dimensions {\n    const origin = this.getFlexibleConnectedPositionStrategyOrigin();\n\n    if (origin instanceof ElementRef) {\n      return origin.nativeElement.getBoundingClientRect();\n    }\n\n    // Check for Element so SVG elements are also supported.\n    if (origin instanceof Element) {\n      return origin.getBoundingClientRect();\n    }\n\n    const width = origin.width || 0;\n    const height = origin.height || 0;\n\n    // If the origin is a point, return a client rect as if it was a 0x0 element at the point.\n    return {\n      top: origin.y,\n      bottom: origin.y + height,\n      left: origin.x,\n      right: origin.x + width,\n      height,\n      width\n    };\n  }\n}\n"
  },
  {
    "path": "components/core/overlay/nz-overlay.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzConnectedOverlayDirective } from './nz-connected-overlay';\n\n@NgModule({\n  imports: [NzConnectedOverlayDirective],\n  exports: [NzConnectedOverlayDirective]\n})\nexport class NzOverlayModule {}\n"
  },
  {
    "path": "components/core/overlay/overlay-position.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ConnectedOverlayPositionChange, ConnectionPositionPair } from '@angular/cdk/overlay';\n\nexport const POSITION_MAP = {\n  top: new ConnectionPositionPair({ originX: 'center', originY: 'top' }, { overlayX: 'center', overlayY: 'bottom' }),\n  topCenter: new ConnectionPositionPair(\n    { originX: 'center', originY: 'top' },\n    { overlayX: 'center', overlayY: 'bottom' }\n  ),\n  topLeft: new ConnectionPositionPair({ originX: 'start', originY: 'top' }, { overlayX: 'start', overlayY: 'bottom' }),\n  topRight: new ConnectionPositionPair({ originX: 'end', originY: 'top' }, { overlayX: 'end', overlayY: 'bottom' }),\n  right: new ConnectionPositionPair({ originX: 'end', originY: 'center' }, { overlayX: 'start', overlayY: 'center' }),\n  rightTop: new ConnectionPositionPair({ originX: 'end', originY: 'top' }, { overlayX: 'start', overlayY: 'top' }),\n  rightBottom: new ConnectionPositionPair(\n    { originX: 'end', originY: 'bottom' },\n    { overlayX: 'start', overlayY: 'bottom' }\n  ),\n  bottom: new ConnectionPositionPair({ originX: 'center', originY: 'bottom' }, { overlayX: 'center', overlayY: 'top' }),\n  bottomCenter: new ConnectionPositionPair(\n    { originX: 'center', originY: 'bottom' },\n    { overlayX: 'center', overlayY: 'top' }\n  ),\n  bottomLeft: new ConnectionPositionPair(\n    { originX: 'start', originY: 'bottom' },\n    { overlayX: 'start', overlayY: 'top' }\n  ),\n  bottomRight: new ConnectionPositionPair({ originX: 'end', originY: 'bottom' }, { overlayX: 'end', overlayY: 'top' }),\n  left: new ConnectionPositionPair({ originX: 'start', originY: 'center' }, { overlayX: 'end', overlayY: 'center' }),\n  leftTop: new ConnectionPositionPair({ originX: 'start', originY: 'top' }, { overlayX: 'end', overlayY: 'top' }),\n  leftBottom: new ConnectionPositionPair(\n    { originX: 'start', originY: 'bottom' },\n    { overlayX: 'end', overlayY: 'bottom' }\n  )\n};\nexport type POSITION_TYPE = keyof typeof POSITION_MAP;\nexport type POSITION_TYPE_HORIZONTAL = Extract<\n  POSITION_TYPE,\n  'bottomLeft' | 'bottomCenter' | 'bottomRight' | 'topLeft' | 'topCenter' | 'topRight'\n>;\n\n/**\n * @internal\n * @param offset offset in pixels which should not be less than 0.\n * The default value is `12`, which means `(arrow-size / 2) + 4`\n */\nconst positionOffsetMapFactory = (offset: number = 12): Record<string, [number, number]> => ({\n  top: [0, -offset],\n  topCenter: [0, -offset],\n  topLeft: [0, -offset],\n  topRight: [0, -offset],\n  right: [offset, 0],\n  rightTop: [offset, 0],\n  rightBottom: [offset, 0],\n  bottom: [0, offset],\n  bottomCenter: [0, offset],\n  bottomLeft: [0, offset],\n  bottomRight: [0, offset],\n  left: [-offset, 0],\n  leftTop: [-offset, 0],\n  leftBottom: [-offset, 0]\n});\n\nexport const TOOLTIP_OFFSET_MAP = positionOffsetMapFactory();\n\nexport const DEFAULT_TOOLTIP_POSITIONS = [\n  setConnectedPositionOffset(POSITION_MAP.top, TOOLTIP_OFFSET_MAP.top),\n  setConnectedPositionOffset(POSITION_MAP.right, TOOLTIP_OFFSET_MAP.right),\n  setConnectedPositionOffset(POSITION_MAP.bottom, TOOLTIP_OFFSET_MAP.bottom),\n  setConnectedPositionOffset(POSITION_MAP.left, TOOLTIP_OFFSET_MAP.left)\n];\n\nexport const DEFAULT_CASCADER_POSITIONS = [\n  POSITION_MAP.bottomLeft,\n  POSITION_MAP.bottomRight,\n  POSITION_MAP.topLeft,\n  POSITION_MAP.topRight\n];\n\nexport const DEFAULT_MENTION_TOP_POSITIONS = [\n  new ConnectionPositionPair({ originX: 'start', originY: 'bottom' }, { overlayX: 'start', overlayY: 'bottom' }),\n  new ConnectionPositionPair({ originX: 'start', originY: 'bottom' }, { overlayX: 'end', overlayY: 'bottom' })\n];\n\nexport const DEFAULT_MENTION_BOTTOM_POSITIONS = [\n  POSITION_MAP.bottomLeft,\n  new ConnectionPositionPair({ originX: 'start', originY: 'bottom' }, { overlayX: 'end', overlayY: 'top' })\n];\n\nexport function getPlacementName(position: ConnectedOverlayPositionChange): string | undefined {\n  for (const placement in POSITION_MAP) {\n    if (\n      position.connectionPair.originX === POSITION_MAP[placement as POSITION_TYPE].originX &&\n      position.connectionPair.originY === POSITION_MAP[placement as POSITION_TYPE].originY &&\n      position.connectionPair.overlayX === POSITION_MAP[placement as POSITION_TYPE].overlayX &&\n      position.connectionPair.overlayY === POSITION_MAP[placement as POSITION_TYPE].overlayY\n    ) {\n      return placement;\n    }\n  }\n  return undefined;\n}\n\nexport const DATE_PICKER_POSITION_MAP = {\n  bottomLeft: new ConnectionPositionPair(\n    { originX: 'start', originY: 'bottom' },\n    { overlayX: 'start', overlayY: 'top' },\n    undefined,\n    2\n  ),\n  topLeft: new ConnectionPositionPair(\n    { originX: 'start', originY: 'top' },\n    { overlayX: 'start', overlayY: 'bottom' },\n    undefined,\n    -2\n  ),\n  bottomRight: new ConnectionPositionPair(\n    { originX: 'end', originY: 'bottom' },\n    { overlayX: 'end', overlayY: 'top' },\n    undefined,\n    2\n  ),\n  topRight: new ConnectionPositionPair(\n    { originX: 'end', originY: 'top' },\n    { overlayX: 'end', overlayY: 'bottom' },\n    undefined,\n    -2\n  )\n};\n\nexport const DEFAULT_DATE_PICKER_POSITIONS = [\n  DATE_PICKER_POSITION_MAP.bottomLeft,\n  DATE_PICKER_POSITION_MAP.topLeft,\n  DATE_PICKER_POSITION_MAP.bottomRight,\n  DATE_PICKER_POSITION_MAP.topRight\n];\n\nexport function normalizeConnectedPositionOffset(offset: number | [number, number]): [number, number] {\n  return Array.isArray(offset) ? offset : [offset, offset];\n}\n\nexport function setConnectedPositionOffset(\n  position: ConnectionPositionPair,\n  offset: number | [number, number]\n): ConnectionPositionPair {\n  const [offsetX, offsetY] = normalizeConnectedPositionOffset(offset);\n  // return new object\n  return {\n    ...position,\n    offsetX: offsetX,\n    offsetY: offsetY\n  };\n}\n"
  },
  {
    "path": "components/core/overlay/overlay-z-index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { OverlayRef } from '@angular/cdk/overlay';\n\nexport function overlayZIndexSetter(overlayRef: OverlayRef, zIndex?: number): void {\n  if (!zIndex) return;\n\n  (overlayRef['_host'] as HTMLElement).style.zIndex = `${zIndex}`;\n}\n"
  },
  {
    "path": "components/core/overlay/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './nz-connected-overlay';\nexport * from './nz-overlay.module';\nexport * from './overlay-position';\nexport * from './overlay-z-index';\n"
  },
  {
    "path": "components/core/pipe/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/core/pipe/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/core/pipe/nz-pipe.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzTimeRangePipe } from './time-range.pipe';\n\n@NgModule({\n  imports: [NzTimeRangePipe],\n  exports: [NzTimeRangePipe]\n})\nexport class NzPipesModule {}\n"
  },
  {
    "path": "components/core/pipe/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './nz-pipe.module';\nexport * from './time-range.pipe';\n"
  },
  {
    "path": "components/core/pipe/time-range.pipe.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Pipe, PipeTransform } from '@angular/core';\n\nimport { timeUnits } from 'ng-zorro-antd/core/time';\nimport { padStart } from 'ng-zorro-antd/core/util';\n\n@Pipe({\n  name: 'nzTimeRange'\n})\nexport class NzTimeRangePipe implements PipeTransform {\n  transform(value: string | number, format: string = 'HH:mm:ss'): string {\n    let duration = Number(value || 0);\n\n    return timeUnits.reduce((current, [name, unit]) => {\n      if (current.indexOf(name) !== -1) {\n        const v = Math.floor(duration / unit);\n        duration -= v * unit;\n        return current.replace(new RegExp(`${name}+`, 'g'), (match: string) =>\n          padStart(v.toString(), match.length, '0')\n        );\n      }\n      return current;\n    }, format);\n  }\n}\n"
  },
  {
    "path": "components/core/pipe/time-range.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\n\nimport { NzPipesModule } from 'ng-zorro-antd/core/pipe';\n\n@Component({\n  imports: [NzPipesModule],\n  template: ` {{ diff | nzTimeRange: format }} `\n})\nexport class NzTestTimeRangeComponent {\n  diff = 1000 * 60 * 60 * 24 * 2 + 1000 * 30;\n  format = 'HH:mm:ss';\n}\n\ndescribe('nzTimeRange', () => {\n  let fixture: ComponentFixture<NzTestTimeRangeComponent>;\n  let testComponent: NzTestTimeRangeComponent;\n  let element: HTMLElement;\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzTestTimeRangeComponent);\n    testComponent = fixture.debugElement.componentInstance;\n    element = fixture.debugElement.nativeElement;\n  });\n\n  it('should render time correctly with different formats', async () => {\n    await fixture.whenStable();\n    expect(element.innerText).toBe('48:00:30');\n\n    testComponent.format = 'HH:mm';\n    fixture.changeDetectorRef.markForCheck();\n    await fixture.whenStable();\n    expect(element.innerText).toBe('48:00');\n\n    testComponent.format = 'D 天 H 时 m 分 s 秒';\n    fixture.changeDetectorRef.markForCheck();\n    await fixture.whenStable();\n    expect(element.innerText).toBe('2 天 0 时 0 分 30 秒');\n  });\n\n  it('should render time correctly with different values', async () => {\n    testComponent.diff = 0;\n    fixture.changeDetectorRef.markForCheck();\n    await fixture.whenStable();\n    expect(element.innerText).toBe('00:00:00');\n\n    testComponent.diff = -1000 * 60 * 60 * 24 * 2 + 1000 * 30;\n    fixture.changeDetectorRef.markForCheck();\n    await fixture.whenStable();\n    expect(element.innerText).toBe('-48:00:30');\n  });\n});\n"
  },
  {
    "path": "components/core/polyfill/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/core/polyfill/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/core/polyfill/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './request-animation';\n"
  },
  {
    "path": "components/core/polyfill/request-animation.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\n// Note: This falls back to `setTimeout` if `requestAnimationFrame` is\n// unintentionally called on the server, but ideally, we should never attempt\n// to call `requestAnimationFrame` on the server — all invocations should be\n// wrapped with isBrowser.\nexport const requestAnimationFrame =\n  typeof globalThis.requestAnimationFrame === 'function' ? globalThis.requestAnimationFrame : globalThis.setTimeout;\n\nexport const cancelAnimationFrame =\n  typeof globalThis.requestAnimationFrame === 'function' ? globalThis.cancelAnimationFrame : globalThis.clearTimeout;\n"
  },
  {
    "path": "components/core/render/after-next-render.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { InjectionToken, Injector, afterNextRender, inject } from '@angular/core';\nimport { Observable } from 'rxjs';\n\n/**\n * An injection token representing `afterNextRender` as an observable rather\n * than a callback-based API has been added. This might be necessary in code\n * where streams of data are already being used and we need to wait until\n * the change detection ends before performing any tasks.\n */\nexport const NZ_AFTER_NEXT_RENDER$ = new InjectionToken<Observable<void>>(\n  typeof ngDevMode !== 'undefined' && ngDevMode ? 'nz-after-next-render' : '',\n  {\n    providedIn: 'root',\n    factory: () => {\n      const injector = inject(Injector);\n\n      return new Observable<void>(subscriber => {\n        const ref = afterNextRender(\n          () => {\n            subscriber.next();\n            subscriber.complete();\n          },\n          { injector }\n        );\n\n        return () => ref.destroy();\n      });\n    }\n  }\n);\n"
  },
  {
    "path": "components/core/render/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/core/render/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/core/render/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './after-next-render';\n"
  },
  {
    "path": "components/core/services/breakpoint.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { MediaMatcher } from '@angular/cdk/layout';\nimport { inject, Injectable } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Observable } from 'rxjs';\nimport { distinctUntilChanged, map, startWith } from 'rxjs/operators';\n\nimport { NzResizeService } from './resize';\n\nexport enum NzBreakpointEnum {\n  xxl = 'xxl',\n  xl = 'xl',\n  lg = 'lg',\n  md = 'md',\n  sm = 'sm',\n  xs = 'xs'\n}\n\nexport type BreakpointMap = Record<NzBreakpointEnum, string>;\nexport type BreakpointBooleanMap = Record<NzBreakpointEnum, boolean>;\nexport type NzBreakpointKey = keyof typeof NzBreakpointEnum;\n\nexport const gridResponsiveMap: BreakpointMap = {\n  xs: '(max-width: 575px)',\n  sm: '(min-width: 576px)',\n  md: '(min-width: 768px)',\n  lg: '(min-width: 992px)',\n  xl: '(min-width: 1200px)',\n  xxl: '(min-width: 1600px)'\n};\n\nexport const siderResponsiveMap: BreakpointMap = {\n  xs: '(max-width: 479.98px)',\n  sm: '(max-width: 575.98px)',\n  md: '(max-width: 767.98px)',\n  lg: '(max-width: 991.98px)',\n  xl: '(max-width: 1199.98px)',\n  xxl: '(max-width: 1599.98px)'\n};\n\n@Injectable({\n  providedIn: 'root'\n})\nexport class NzBreakpointService {\n  private resizeService = inject(NzResizeService);\n  private mediaMatcher = inject(MediaMatcher);\n\n  constructor() {\n    this.resizeService\n      .connect()\n      .pipe(takeUntilDestroyed())\n      .subscribe(() => {});\n  }\n\n  subscribe(breakpointMap: BreakpointMap): Observable<NzBreakpointEnum>;\n  subscribe(breakpointMap: BreakpointMap, fullMap: true): Observable<BreakpointBooleanMap>;\n  subscribe(breakpointMap: BreakpointMap, fullMap?: true): Observable<NzBreakpointEnum | BreakpointBooleanMap> {\n    if (fullMap) {\n      // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n      const get = () => this.matchMedia(breakpointMap, true);\n      return this.resizeService.connect().pipe(\n        map(get),\n        startWith(get()),\n        distinctUntilChanged(\n          (x: [NzBreakpointEnum, BreakpointBooleanMap], y: [NzBreakpointEnum, BreakpointBooleanMap]) => x[0] === y[0]\n        ),\n        map(x => x[1])\n      );\n    } else {\n      // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n      const get = () => this.matchMedia(breakpointMap);\n      return this.resizeService.connect().pipe(map(get), startWith(get()), distinctUntilChanged());\n    }\n  }\n\n  private matchMedia(breakpointMap: BreakpointMap): NzBreakpointEnum;\n  private matchMedia(breakpointMap: BreakpointMap, fullMap: true): [NzBreakpointEnum, BreakpointBooleanMap];\n  private matchMedia(\n    breakpointMap: BreakpointMap,\n    fullMap?: true\n  ): NzBreakpointEnum | [NzBreakpointEnum, BreakpointBooleanMap] {\n    let bp = NzBreakpointEnum.md;\n\n    const breakpointBooleanMap: Partial<BreakpointBooleanMap> = {};\n\n    Object.keys(breakpointMap).map(breakpoint => {\n      const castBP = breakpoint as NzBreakpointEnum;\n      const matched = this.mediaMatcher.matchMedia(gridResponsiveMap[castBP]).matches;\n\n      breakpointBooleanMap[breakpoint as NzBreakpointEnum] = matched;\n\n      if (matched) {\n        bp = castBP;\n      }\n    });\n\n    if (fullMap) {\n      return [bp, breakpointBooleanMap as BreakpointBooleanMap];\n    } else {\n      return bp;\n    }\n  }\n}\n"
  },
  {
    "path": "components/core/services/destroy.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { of } from 'rxjs';\nimport { delay, finalize, takeUntil } from 'rxjs/operators';\n\nimport { NzDestroyService } from './destroy';\n\ndescribe('NzDestroy service', () => {\n  let destroyService: NzDestroyService;\n  const initObservable = of('done');\n\n  beforeEach(() => {\n    destroyService = new NzDestroyService();\n  });\n\n  it('should subscribe work normal', () => {\n    let result = 'initial';\n\n    initObservable.pipe(takeUntil(destroyService)).subscribe(value => {\n      result = value;\n    });\n\n    expect(result).toBe('done');\n  });\n\n  it('should complete work normal', () => {\n    let result = 'initial';\n\n    initObservable\n      .pipe(\n        delay(1000),\n        takeUntil(destroyService),\n        finalize(() => {\n          result = 'done';\n        })\n      )\n      .subscribe();\n\n    destroyService.ngOnDestroy();\n\n    expect(result).toBe('done');\n  });\n});\n"
  },
  {
    "path": "components/core/services/destroy.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Injectable, OnDestroy } from '@angular/core';\nimport { Subject } from 'rxjs';\n\n@Injectable()\nexport class NzDestroyService extends Subject<void> implements OnDestroy {\n  ngOnDestroy(): void {\n    this.next();\n    this.complete();\n  }\n}\n"
  },
  {
    "path": "components/core/services/drag.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, inject } from '@angular/core';\nimport { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';\nimport { Subject, Subscription } from 'rxjs';\n\nimport { createMouseEvent, createTouchEvent, dispatchMouseEvent, dispatchTouchEvent } from 'ng-zorro-antd/core/testing';\n\nimport { NzDragService } from './drag';\n\n@Component({\n  template: ''\n})\nexport class NzTestDragServiceComponent {\n  public nzDragService = inject(NzDragService);\n  drag$ = new Subject<void>();\n  complete$ = new Subject<void>();\n\n  drag(event: MouseEvent | TouchEvent): void {\n    this.nzDragService.requestDraggingSequence(event).subscribe({\n      next: () => this.drag$.next(),\n      complete: () => this.complete$.next()\n    });\n  }\n}\n\ndescribe('drag service', () => {\n  let fixture: ComponentFixture<NzTestDragServiceComponent>;\n  let component: NzTestDragServiceComponent;\n\n  let completed = false;\n  let dragged = false;\n  let drag_: Subscription;\n  let complete_: Subscription;\n\n  describe('basics', () => {\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestDragServiceComponent);\n      component = fixture.debugElement.componentInstance;\n    });\n\n    beforeEach(() => {\n      completed = false;\n      dragged = false;\n\n      complete_ = component.complete$.subscribe(() => (completed = true));\n      drag_ = component.drag$.subscribe(() => (dragged = true));\n    });\n\n    afterEach(() => {\n      if (drag_) {\n        drag_.unsubscribe();\n      }\n\n      if (complete_) {\n        complete_.unsubscribe();\n      }\n    });\n\n    it('should mousedown work', fakeAsync(() => {\n      component.drag(createMouseEvent('mousedown', 0, 0));\n      dispatchMouseEvent(document, 'mousemove', 100, 0);\n\n      tickMilliseconds(fixture, 20);\n      expect(dragged).toBeTruthy();\n\n      dispatchMouseEvent(document, 'mouseup');\n      expect(completed).toBeTruthy();\n    }));\n\n    it('should touchdown work', fakeAsync(() => {\n      component.drag(createTouchEvent('touchdown') as TouchEvent);\n      dispatchTouchEvent(document, 'touchmove', 100, 0);\n\n      tickMilliseconds(fixture, 20);\n      expect(dragged).toBeTruthy();\n\n      dispatchTouchEvent(document, 'touchend');\n      expect(completed).toBeTruthy();\n    }));\n\n    it('should close previous drag sequence', () => {\n      component.drag(createMouseEvent('mousedown', 0, 0));\n      component.drag(createMouseEvent('mousedown', 0, 0));\n\n      expect(completed).toBeTruthy();\n      expect(dragged).toBeFalsy();\n    });\n\n    it('should threshold work', fakeAsync(() => {\n      component.drag(createMouseEvent('mousedown', 0, 0));\n      dispatchMouseEvent(document, 'mousemove', 4, 0);\n\n      tickMilliseconds(fixture, 20);\n      expect(dragged).toBeFalsy();\n\n      dispatchMouseEvent(document, 'mouseup');\n      expect(completed).toBeTruthy();\n    }));\n  });\n});\n\nfunction tickMilliseconds<T>(fixture: ComponentFixture<T>, seconds: number = 1): void {\n  fixture.detectChanges();\n  tick(seconds);\n  fixture.detectChanges();\n}\n"
  },
  {
    "path": "components/core/services/drag.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { inject, Injectable, RendererFactory2 } from '@angular/core';\nimport { Observable, Subject } from 'rxjs';\nimport { filter, finalize, map } from 'rxjs/operators';\n\nimport { getEventPosition, isTouchEvent } from 'ng-zorro-antd/core/util';\n\ninterface Point {\n  x: number;\n  y: number;\n}\n\ntype Delta = Point;\n\ninterface HandlerItem {\n  handler?(e: Event): void;\n\n  teardown(): void;\n}\n\nfunction getPagePosition(event: MouseEvent | TouchEvent): Point {\n  const e = getEventPosition(event);\n  return {\n    x: e.pageX,\n    y: e.pageY\n  };\n}\n\n/**\n * This module provide a global dragging service to other components.\n */\n@Injectable({\n  providedIn: 'root'\n})\nexport class NzDragService {\n  private draggingThreshold = 5;\n  private currentDraggingSequence: Subject<MouseEvent | Touch> | null = null;\n  private currentStartingPoint: Point | null = null;\n  private handleRegistry = new Set<HandlerItem>();\n  private renderer = inject(RendererFactory2).createRenderer(null, null);\n\n  requestDraggingSequence(event: MouseEvent | TouchEvent): Observable<Delta> {\n    if (!this.handleRegistry.size) {\n      this.registerDraggingHandler(isTouchEvent(event));\n    }\n\n    // Complete last dragging sequence if a new target is dragged.\n    if (this.currentDraggingSequence) {\n      this.currentDraggingSequence.complete();\n    }\n\n    this.currentStartingPoint = getPagePosition(event);\n    this.currentDraggingSequence = new Subject<MouseEvent | Touch>();\n\n    return this.currentDraggingSequence.pipe(\n      map((e: MouseEvent | Touch) => ({\n        x: e.pageX - this.currentStartingPoint!.x,\n        y: e.pageY - this.currentStartingPoint!.y\n      })),\n      filter((e: Delta) => Math.abs(e.x) > this.draggingThreshold || Math.abs(e.y) > this.draggingThreshold),\n      finalize(() => this.teardownDraggingSequence())\n    );\n  }\n\n  private registerDraggingHandler(isTouch: boolean): void {\n    if (isTouch) {\n      this.handleRegistry.add({\n        teardown: this.renderer.listen('document', 'touchmove', (e: TouchEvent) => {\n          if (this.currentDraggingSequence) {\n            this.currentDraggingSequence.next(e.touches[0] || e.changedTouches[0]);\n          }\n        })\n      });\n      this.handleRegistry.add({\n        teardown: this.renderer.listen('document', 'touchend', () => {\n          if (this.currentDraggingSequence) {\n            this.currentDraggingSequence.complete();\n          }\n        })\n      });\n    } else {\n      this.handleRegistry.add({\n        teardown: this.renderer.listen('document', 'mousemove', e => {\n          if (this.currentDraggingSequence) {\n            this.currentDraggingSequence.next(e);\n          }\n        })\n      });\n      this.handleRegistry.add({\n        teardown: this.renderer.listen('document', 'mouseup', () => {\n          if (this.currentDraggingSequence) {\n            this.currentDraggingSequence.complete();\n          }\n        })\n      });\n    }\n  }\n\n  private teardownDraggingSequence(): void {\n    this.currentDraggingSequence = null;\n  }\n}\n"
  },
  {
    "path": "components/core/services/image-preload.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Platform } from '@angular/cdk/platform';\nimport { DOCUMENT, inject, Injectable } from '@angular/core';\n\ninterface PreloadOption {\n  src: string;\n  srcset?: string;\n}\n\nexport type PreloadDisposeHandle = () => void;\n\n@Injectable({\n  providedIn: 'root'\n})\nexport class ImagePreloadService {\n  private counter = new Map<string, number>();\n  private linkRefs = new Map<string, HTMLLinkElement>();\n  private document: Document = inject(DOCUMENT);\n  private platform: Platform = inject(Platform);\n\n  addPreload(option: PreloadOption): PreloadDisposeHandle {\n    if (this.platform.isBrowser) {\n      return () => void 0;\n    }\n    const uniqueKey = `${option.src}${option.srcset}`;\n    let currentCount = this.counter.get(uniqueKey) || 0;\n    currentCount++;\n    this.counter.set(uniqueKey, currentCount);\n    if (!this.linkRefs.has(uniqueKey)) {\n      const linkNode = this.appendPreloadLink(option);\n      this.linkRefs.set(uniqueKey, linkNode);\n    }\n    return () => {\n      if (this.counter.has(uniqueKey)) {\n        let count = this.counter.get(uniqueKey)!;\n        count--;\n        if (count === 0) {\n          const linkNode = this.linkRefs.get(uniqueKey)!;\n          this.removePreloadLink(linkNode);\n          this.counter.delete(uniqueKey);\n          this.linkRefs.delete(uniqueKey);\n        } else {\n          this.counter.set(uniqueKey, count);\n        }\n      }\n    };\n  }\n\n  private appendPreloadLink(option: PreloadOption): HTMLLinkElement {\n    const linkNode = this.document.createElement('link') as HTMLLinkElement;\n    linkNode.setAttribute('rel', 'preload');\n    linkNode.setAttribute('as', 'image');\n    linkNode.setAttribute('href', option.src);\n\n    if (option.srcset) {\n      linkNode.setAttribute('imagesrcset', option.srcset);\n    }\n    this.document.head.appendChild(linkNode);\n    return linkNode;\n  }\n\n  private removePreloadLink(linkNode: HTMLLinkElement): void {\n    if (this.document.head.contains(linkNode)) {\n      this.document.head.removeChild(linkNode);\n    }\n  }\n}\n"
  },
  {
    "path": "components/core/services/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/core/services/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/core/services/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './resize';\nexport * from './singleton';\nexport * from './drag';\nexport * from './scroll';\nexport * from './breakpoint';\nexport * from './destroy';\nexport * from './image-preload';\n"
  },
  {
    "path": "components/core/services/resize.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { DestroyRef, inject, Injectable, NgZone, RendererFactory2 } from '@angular/core';\nimport { Observable, Subject } from 'rxjs';\nimport { auditTime, finalize } from 'rxjs/operators';\n\nconst NOOP = (): void => {};\n\n@Injectable({\n  providedIn: 'root'\n})\nexport class NzResizeService {\n  private ngZone = inject(NgZone);\n  private destroyRef = inject(DestroyRef);\n  private readonly resizeSource$ = new Subject<void>();\n\n  private listeners = 0;\n\n  private renderer = inject(RendererFactory2).createRenderer(null, null);\n\n  private disposeHandle = NOOP;\n\n  private handler = (): void => {\n    this.ngZone.run(() => {\n      this.resizeSource$.next();\n    });\n  };\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      // Caretaker note: the `handler` is an instance property (it's not defined on the class prototype).\n      this.handler = NOOP;\n    });\n  }\n\n  connect(): Observable<void> {\n    this.registerListener();\n\n    return this.resizeSource$.pipe(\n      auditTime(16),\n      finalize(() => this.unregisterListener())\n    );\n  }\n\n  disconnet(): void {\n    this.unregisterListener();\n  }\n\n  private registerListener(): void {\n    if (this.listeners === 0) {\n      this.ngZone.runOutsideAngular(() => {\n        this.disposeHandle = this.renderer.listen('window', 'resize', this.handler);\n      });\n    }\n\n    this.listeners += 1;\n  }\n\n  private unregisterListener(): void {\n    this.listeners -= 1;\n\n    if (this.listeners === 0) {\n      this.disposeHandle();\n      this.disposeHandle = NOOP;\n    }\n  }\n}\n"
  },
  {
    "path": "components/core/services/scroll.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { PlatformLocation } from '@angular/common';\nimport { ApplicationRef, DOCUMENT, NgZone } from '@angular/core';\nimport { fakeAsync, TestBed, tick } from '@angular/core/testing';\n\nimport { MockNgZone } from 'ng-zorro-antd/core/testing';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzScrollService } from './scroll';\n\ndescribe('NzScrollService', () => {\n  const TOP = 10;\n  let document: MockDocument;\n  let scrollService: NzScrollService;\n  let ngZone: MockNgZone;\n\n  class MockDocument {\n    body = new MockElement();\n    documentElement = new MockDocumentElement();\n  }\n\n  class MockDocumentElement {\n    scrollTop = jasmine.createSpy('scrollTop');\n  }\n\n  class MockElement {\n    scrollTop = jasmine.createSpy('scrollTop');\n  }\n\n  class MockPlatformLocation {\n    hash!: string;\n  }\n\n  beforeEach(() => {\n    spyOn(window, 'scrollBy');\n  });\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [\n        NzScrollService,\n        { provide: DOCUMENT, useClass: MockDocument },\n        { provide: PlatformLocation, useClass: MockPlatformLocation },\n        { provide: NgZone, useClass: MockNgZone }\n      ]\n    });\n\n    document = TestBed.inject<MockDocument>(DOCUMENT);\n    scrollService = TestBed.inject(NzScrollService);\n    ngZone = TestBed.inject(NgZone) as MockNgZone;\n  });\n\n  describe('#setScrollTop', () => {\n    it(`should scroll to window ${TOP} x`, () => {\n      scrollService.setScrollTop(window, TOP);\n      expect(document.body.scrollTop).toBe(TOP);\n      scrollService.setScrollTop(window, 0);\n    });\n\n    it(`should scroll to dom element ${TOP} x`, () => {\n      const el: Element = new MockElement() as NzSafeAny;\n      scrollService.setScrollTop(el, TOP);\n      expect(el.scrollTop).toBe(TOP);\n      scrollService.setScrollTop(el, 0);\n    });\n  });\n\n  describe('#getOffset', () => {\n    it(`should be working`, () => {\n      const ret = scrollService.getOffset({\n        ownerDocument: {\n          documentElement: {\n            clientTop: 1,\n            clientLeft: 1\n          }\n        },\n        getClientRects: () => [0],\n        getBoundingClientRect: () => ({ top: 10, left: 10, width: 100, height: 100 })\n      } as NzSafeAny);\n      expect(ret.left).toBe(9);\n      expect(ret.top).toBe(9);\n    });\n\n    it(`should be return 0 when is no getClientRects`, () => {\n      const ret = scrollService.getOffset({ getClientRects: () => [] } as NzSafeAny);\n      expect(ret.left).toBe(0);\n      expect(ret.top).toBe(0);\n    });\n\n    it(`should be return element top when element is not size`, () => {\n      const ret = scrollService.getOffset({\n        getClientRects: () => [0],\n        getBoundingClientRect: () => ({ top: 1, left: 1 })\n      } as NzSafeAny);\n      expect(ret.left).toBe(1);\n      expect(ret.top).toBe(1);\n    });\n  });\n\n  describe('#getScroll', () => {\n    it('should be return scrollTop when target is window', () => {\n      const mockWin: NzSafeAny = { pageYOffset: 10 };\n      mockWin.window = mockWin;\n      expect(scrollService.getScroll(mockWin)).toBe(10);\n    });\n    it('should be return scrollTop when target is html element', () => {\n      const mockEl: NzSafeAny = { scrollTop: 10 };\n      expect(scrollService.getScroll(mockEl)).toBe(10);\n    });\n  });\n\n  describe('change detection behavior', () => {\n    // The `requestAnimationFrame` is mocked as `setTimeout(fn, 16)`.\n    const tickAnimationFrame = (): void => tick(16);\n\n    it('should not trigger change detection when calling `scrollTo`', fakeAsync(() => {\n      const appRef = TestBed.inject(ApplicationRef);\n      spyOn(appRef, 'tick');\n\n      scrollService.scrollTo();\n\n      tickAnimationFrame();\n\n      expect(appRef.tick).not.toHaveBeenCalled();\n    }));\n\n    it('should call the custom callback within the Angular zone', fakeAsync(() => {\n      let callbackCalled = false;\n      spyOn(ngZone, 'run').and.callThrough();\n\n      scrollService.scrollTo(undefined, undefined, {\n        duration: 0,\n        callback: () => {\n          callbackCalled = true;\n        }\n      });\n\n      tickAnimationFrame();\n\n      expect(ngZone.run).toHaveBeenCalled();\n      expect(callbackCalled).toBeTrue();\n    }));\n  });\n});\n"
  },
  {
    "path": "components/core/services/scroll.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { DOCUMENT, inject, Injectable, NgZone } from '@angular/core';\n\nimport { requestAnimationFrame } from 'ng-zorro-antd/core/polyfill';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nexport type EasyingFn = (t: number, b: number, c: number, d: number) => number;\n\nfunction easeInOutCubic(t: number, b: number, c: number, d: number): number {\n  const cc = c - b;\n  let tt = t / (d / 2);\n  if (tt < 1) {\n    return (cc / 2) * tt * tt * tt + b;\n  } else {\n    return (cc / 2) * ((tt -= 2) * tt * tt + 2) + b;\n  }\n}\n\nexport interface NzScrollToOptions {\n  /** Scroll container, default as window */\n  easing?: EasyingFn;\n  /** Scroll end callback */\n  callback?(): void;\n  /** Animation duration, default as 450 */\n  duration?: number;\n}\n\n@Injectable({\n  providedIn: 'root'\n})\nexport class NzScrollService {\n  private doc: Document = inject(DOCUMENT);\n  private ngZone = inject(NgZone);\n\n  /** Set the position of the scroll bar of `el`. */\n  setScrollTop(el: Element | Window, topValue: number = 0): void {\n    if (el === window) {\n      this.doc.body.scrollTop = topValue;\n      this.doc.documentElement!.scrollTop = topValue;\n    } else {\n      (el as Element).scrollTop = topValue;\n    }\n  }\n\n  /** Get position of `el` against window. */\n  getOffset(el: Element): { top: number; left: number } {\n    const ret = {\n      top: 0,\n      left: 0\n    };\n    if (!el || !el.getClientRects().length) {\n      return ret;\n    }\n\n    const rect = el.getBoundingClientRect();\n    if (rect.width || rect.height) {\n      const doc = el.ownerDocument!.documentElement;\n      ret.top = rect.top - doc!.clientTop;\n      ret.left = rect.left - doc!.clientLeft;\n    } else {\n      ret.top = rect.top;\n      ret.left = rect.left;\n    }\n\n    return ret;\n  }\n\n  /** Get the position of the scroll bar of `el`. */\n  // TODO: remove '| Window' as the fallback already happens here\n  getScroll(target?: Element | HTMLElement | Window | Document | null, top: boolean = true): number {\n    if (typeof window === 'undefined') {\n      return 0;\n    }\n    const method = top ? 'scrollTop' : 'scrollLeft';\n    let result = 0;\n    if (this.isWindow(target)) {\n      result = (target as Window)[top ? 'pageYOffset' : 'pageXOffset'];\n    } else if (target instanceof Document) {\n      result = target.documentElement[method];\n    } else if (target) {\n      result = (target as HTMLElement)[method];\n    }\n    if (target && !this.isWindow(target) && typeof result !== 'number') {\n      result = ((target as HTMLElement).ownerDocument || (target as Document)).documentElement[method];\n    }\n    return result;\n  }\n\n  isWindow(obj: NzSafeAny): boolean {\n    return obj !== null && obj !== undefined && obj === obj.window;\n  }\n\n  /**\n   * Scroll `el` to some position with animation.\n   *\n   * @param containerEl container, `window` by default\n   * @param y Scroll to `top`, 0 by default\n   * @param options Scroll animation options\n   */\n  scrollTo(\n    containerEl?: Element | HTMLElement | Window | Document | null,\n    y: number = 0,\n    options: NzScrollToOptions = {}\n  ): void {\n    const target = containerEl ? containerEl : window;\n    const scrollTop = this.getScroll(target);\n    const startTime = Date.now();\n    const { easing, callback, duration = 450 } = options;\n    const frameFunc = (): void => {\n      const timestamp = Date.now();\n      const time = timestamp - startTime;\n      const nextScrollTop = (easing || easeInOutCubic)(time > duration ? duration : time, scrollTop, y, duration);\n      if (this.isWindow(target)) {\n        (target as Window).scrollTo(window.pageXOffset, nextScrollTop);\n      } else if (target instanceof HTMLDocument || target.constructor.name === 'HTMLDocument') {\n        (target as HTMLDocument).documentElement.scrollTop = nextScrollTop;\n      } else {\n        (target as HTMLElement).scrollTop = nextScrollTop;\n      }\n      if (time < duration) {\n        requestAnimationFrame(frameFunc);\n      } else if (typeof callback === 'function') {\n        // Caretaker note: the `frameFunc` is called within the `<root>` zone, but we have to re-enter\n        // the Angular zone when calling custom callback to be backwards-compatible.\n        this.ngZone.run(callback);\n      }\n    };\n    // Caretaker note: the `requestAnimationFrame` triggers change detection, but updating a `scrollTop` property or\n    // calling `window.scrollTo` doesn't require Angular to run `ApplicationRef.tick()`.\n    this.ngZone.runOutsideAngular(() => requestAnimationFrame(frameFunc));\n  }\n}\n"
  },
  {
    "path": "components/core/services/singleton.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Injectable } from '@angular/core';\n\nimport { environment } from 'ng-zorro-antd/core/environments';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\ninterface SingletonRegistryItem {\n  target: NzSafeAny;\n}\n\n/**\n * When running in test, singletons should not be destroyed. So we keep references of singletons\n * in this global variable.\n */\nconst testSingleRegistry = new Map<string, SingletonRegistryItem>();\n\n/**\n * Some singletons should have life cycle that is same to Angular's. This service make sure that\n * those singletons get destroyed in HMR.\n */\n@Injectable({\n  providedIn: 'root'\n})\nexport class NzSingletonService {\n  private get singletonRegistry(): Map<string, SingletonRegistryItem> {\n    return environment.isTestMode ? testSingleRegistry : this._singletonRegistry;\n  }\n\n  /**\n   * This registry is used to register singleton in dev mode.\n   * So that singletons get destroyed when hot module reload happens.\n   *\n   * This works in prod mode too but with no specific effect.\n   */\n  private _singletonRegistry = new Map<string, SingletonRegistryItem>();\n\n  registerSingletonWithKey(key: string, target: NzSafeAny): void {\n    const alreadyHave = this.singletonRegistry.has(key);\n    const item: SingletonRegistryItem = alreadyHave ? this.singletonRegistry.get(key)! : this.withNewTarget(target);\n\n    if (!alreadyHave) {\n      this.singletonRegistry.set(key, item);\n    }\n  }\n\n  unregisterSingletonWithKey(key: string): void {\n    if (this.singletonRegistry.has(key)) {\n      this.singletonRegistry.delete(key);\n    }\n  }\n\n  getSingletonWithKey<T>(key: string): T | null {\n    return this.singletonRegistry.has(key) ? (this.singletonRegistry.get(key)!.target as T) : null;\n  }\n\n  private withNewTarget(target: NzSafeAny): SingletonRegistryItem {\n    return {\n      target\n    };\n  }\n}\n"
  },
  {
    "path": "components/core/testing/directionality.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { EnvironmentProviders, makeEnvironmentProviders, signal } from '@angular/core';\nimport { Subject } from 'rxjs';\n\nclass MockDirectionality {\n  value = 'ltr';\n  change = new Subject();\n  valueSignal = signal('ltr');\n}\n\nexport function provideMockDirectionality(): EnvironmentProviders {\n  return makeEnvironmentProviders([{ provide: Directionality, useClass: MockDirectionality }]);\n}\n"
  },
  {
    "path": "components/core/testing/dispatch-events.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { createFakeEvent, createKeyboardEvent, createMouseEvent, createTouchEvent } from './event-objects';\n\n/** Utility to dispatch any event on a Node. */\nexport function dispatchEvent(node: Node | Window, event: Event): Event {\n  node.dispatchEvent(event);\n  return event;\n}\n\n/** Shorthand to dispatch a fake event on a specified node. */\nexport function dispatchFakeEvent(node: Node | Window, type: string, canBubble?: boolean): Event {\n  return dispatchEvent(node, createFakeEvent(type, canBubble));\n}\n\n/** Shorthand to dispatch a keyboard event with a specified key code. */\nexport function dispatchKeyboardEvent(node: Node, type: string, keyCode: number, target?: Element): KeyboardEvent {\n  return dispatchEvent(node, createKeyboardEvent(type, keyCode, target)) as KeyboardEvent;\n}\n\n/** Shorthand to dispatch a mouse event on the specified coordinates. */\nexport function dispatchMouseEvent(\n  node: Node,\n  type: string,\n  x: number = 0,\n  y: number = 0,\n  event: MouseEvent = createMouseEvent(type, x, y)\n): MouseEvent {\n  return dispatchEvent(node, event) as MouseEvent;\n}\n\n/** Shorthand to dispatch a touch event on the specified coordinates. */\nexport function dispatchTouchEvent(node: Node, type: string, x: number = 0, y: number = 0): TouchEvent {\n  return dispatchEvent(node, createTouchEvent(type, x, y)) as TouchEvent;\n}\n"
  },
  {
    "path": "components/core/testing/event-objects.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\n/** Creates a browser MouseEvent with the specified options. */\nexport function createMouseEvent(type: string, x: number = 0, y: number = 0, button: number = 0): MouseEvent {\n  const event = document.createEvent('MouseEvent');\n\n  event.initMouseEvent(\n    type,\n    true /* canBubble */,\n    false /* cancelable */,\n    window /* view */,\n    0 /* detail */,\n    x /* screenX */,\n    y /* screenY */,\n    x /* clientX */,\n    y /* clientY */,\n    false /* ctrlKey */,\n    false /* altKey */,\n    false /* shiftKey */,\n    false /* metaKey */,\n    button /* button */,\n    null /* relatedTarget */\n  );\n\n  // `initMouseEvent` doesn't allow us to pass the `buttons` and\n  // defaults it to 0 which looks like a fake event.\n  Object.defineProperty(event, 'buttons', { get: () => 1 });\n\n  return event;\n}\n\n/** Creates a browser TouchEvent with the specified pointer coordinates. */\nexport function createTouchEvent(type: string, pageX: number = 0, pageY: number = 0): UIEvent {\n  // In favor of creating events that work for most of the browsers, the event is created\n  // as a basic UI Event. The necessary details for the event will be set manually.\n  const event = new UIEvent(type, { detail: 0, view: window });\n  const touchDetails = { pageX, pageY, clientX: pageX, clientY: pageY };\n\n  // Most of the browsers don't have a \"initTouchEvent\" method that can be used to define\n  // the touch details.\n  Object.defineProperties(event, {\n    touches: { value: [touchDetails] },\n    targetTouches: { value: [touchDetails] },\n    changedTouches: { value: [touchDetails] }\n  });\n\n  return event;\n}\n\n/** Dispatches a keydown event from an element. */\nexport function createKeyboardEvent(\n  type: string,\n  keyCode: number,\n  target?: Element,\n  key?: string,\n  ctrlKey?: boolean,\n  metaKey?: boolean,\n  shiftKey?: boolean\n): KeyboardEvent {\n  const event = document.createEvent('KeyboardEvent') as NzSafeAny;\n\n  // Firefox does not support `initKeyboardEvent`, but supports `initKeyEvent`.\n  if (event.initKeyEvent) {\n    event.initKeyEvent(type, true, true, window, 0, 0, 0, 0, 0, keyCode);\n  } else {\n    event.initKeyboardEvent(type, true, true, window, 0, key, 0, '', false);\n  }\n\n  // Webkit Browsers don't set the keyCode when calling the init function.\n  // See related bug https://bugs.webkit.org/show_bug.cgi?id=16735\n  Object.defineProperties(event, {\n    keyCode: { get: () => keyCode },\n    key: { get: () => key },\n    target: { get: () => target },\n    ctrlKey: { get: () => ctrlKey },\n    metaKey: { get: () => metaKey },\n    shiftKey: { get: () => shiftKey }\n  });\n\n  return event;\n}\n\n/** Creates a fake event object with any desired event type. */\nexport function createFakeEvent(type: string, canBubble: boolean = true, cancelable: boolean = true): Event {\n  const event = document.createEvent('Event');\n  event.initEvent(type, canBubble, cancelable);\n  return event;\n}\n"
  },
  {
    "path": "components/core/testing/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/core/testing/mock-ng-zone.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { EventEmitter, Injectable, NgZone } from '@angular/core';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\n/**\n * Mock synchronous NgZone implementation that can be used\n * to flush out `onStable` subscriptions in tests.\n *\n * via: https://github.com/angular/angular/blob/master/packages/core/testing/src/ng_zone_mock.ts\n *\n * @docs-private\n */\n@Injectable()\nexport class MockNgZone extends NgZone {\n  override onStable = new EventEmitter<NzSafeAny>(false);\n\n  constructor() {\n    super({ enableLongStackTrace: false });\n  }\n\n  override run(fn: () => NzSafeAny): NzSafeAny {\n    return fn();\n  }\n\n  override runOutsideAngular(fn: () => NzSafeAny): NzSafeAny {\n    return fn();\n  }\n\n  simulateZoneExit(): void {\n    this.onStable.emit(null);\n  }\n}\n"
  },
  {
    "path": "components/core/testing/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/core/testing/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './directionality';\nexport * from './dispatch-events';\nexport * from './event-objects';\nexport * from './mock-ng-zone';\nexport * from './type-in-element';\nexport * from './zoneless-helpers';\n"
  },
  {
    "path": "components/core/testing/type-in-element.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { dispatchFakeEvent } from './dispatch-events';\n\n/**\n * Focuses an input, sets its value and dispatches\n * the `input` event, simulating the user typing.\n *\n * @param value Value to be set on the input.\n * @param element Element onto which to set the value.\n */\nexport function typeInElement(value: string, element: HTMLInputElement | HTMLTextAreaElement): void {\n  element.focus();\n  element.value = value;\n  dispatchFakeEvent(element, 'input');\n}\n"
  },
  {
    "path": "components/core/testing/zoneless-helpers.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport type { ComponentFixture } from '@angular/core/testing';\n\nexport function sleep(ms: number): Promise<void> {\n  return new Promise(resolve => setTimeout(resolve, ms));\n}\n\nexport async function updateNonSignalsInput<T>(fixture: ComponentFixture<T>, ms?: number): Promise<void> {\n  fixture.changeDetectorRef.markForCheck();\n  if (typeof ms === 'number') {\n    await sleep(ms);\n  }\n  await fixture.whenStable();\n}\n"
  },
  {
    "path": "components/core/time/candy-date.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport differenceInCalendarMonths from 'date-fns/differenceInCalendarMonths';\n\nimport { CandyDate, normalizeRangeValue, SingleValue } from './candy-date';\n\ndescribe('candy-date coverage supplements', () => {\n  const date = new CandyDate('2018-5-5 12:12:12');\n\n  it('support getTime', () => expect(date.getTime()).toBe(date.nativeDate.getTime()));\n\n  it('support getMilliseconds', () => expect(date.getMilliseconds()).toBe(date.nativeDate.getMilliseconds()));\n\n  it('support isSame', () => {\n    expect(date.isSame(new CandyDate('2018'), 'year')).toBeTruthy();\n\n    expect(date.isSameMonth(new CandyDate('2018-5-5 12:00:00'))).toBeTruthy();\n\n    expect(date.isSame(new CandyDate('2018-5-5 12:00:00'), 'hour')).toBeTruthy();\n    expect(date.isSameHour(new CandyDate('2019-5-5 12:00:00'))).toBeFalsy();\n\n    expect(date.isSame(new CandyDate('2018-5-5 12:12:00'), 'minute')).toBeTruthy();\n    expect(date.isSameMinute(new CandyDate('2019-5-5 12:12:00'))).toBeFalsy();\n\n    expect(date.isSame(new CandyDate('2018-5-5 12:12:12'), 'second')).toBeTruthy();\n    expect(date.isSameSecond(new CandyDate('2019-5-5 12:12:12'))).toBeFalsy();\n  });\n\n  it('support isBefore', () => {\n    expect(date.isBeforeYear(null)).toBeFalsy();\n\n    expect(date.isBeforeYear(new CandyDate('2100'))).toBeTruthy();\n\n    expect(date.isBeforeMonth(new CandyDate('2100-5-5 12:12:12'))).toBeTruthy();\n    expect(date.isBeforeMonth(new CandyDate('2018-6-5 12:12:12'))).toBeTruthy();\n\n    expect(date.isBeforeDay(new CandyDate('2018-6-5 12:12:12'))).toBeTruthy();\n  });\n\n  it('should throw error while putting invalid date input', () => {\n    const errorMessage = 'The input date type is not supported (\"Date\" is now recommended)';\n    expect(() => new CandyDate({} as any)).toThrowError(errorMessage); // eslint-disable-line @typescript-eslint/no-explicit-any\n  });\n\n  it('should normalizeRangeValue work', () => {\n    const randomDay = new CandyDate('2020-09-17');\n    const now = new Date();\n    let result: SingleValue[];\n    result = normalizeRangeValue([null, randomDay], false);\n    expect(result[0]!.getMonth()).toEqual(7);\n    expect(result[1]!.getMonth()).toEqual(8);\n\n    result = normalizeRangeValue([randomDay, null], false);\n    expect(result[0]!.getMonth()).toEqual(8);\n    expect(result[1]!.getMonth()).toEqual(9);\n\n    result = normalizeRangeValue([randomDay, null], true);\n    expect(result[0]!.getMonth()).toEqual(8);\n    expect(result[1]!.getMonth()).toEqual(8);\n\n    result = normalizeRangeValue([null, null], false);\n    expect(result[0]!.getMonth()).toEqual(now.getMonth());\n    expect(differenceInCalendarMonths(result[1]!.nativeDate, now)).toEqual(1);\n\n    result = normalizeRangeValue([null, null], true);\n    expect(result[0]!.getMonth()).toEqual(now.getMonth());\n    expect(result[1]!.getMonth()).toEqual(now.getMonth());\n\n    result = normalizeRangeValue([randomDay, new CandyDate()], false, 'month', 'left');\n    expect(result[0]!.getMonth()).toEqual(randomDay.getMonth());\n    expect(differenceInCalendarMonths(result[1]!.nativeDate, randomDay.nativeDate)).toEqual(1);\n\n    result = normalizeRangeValue([randomDay, new CandyDate()], false, 'month', 'right');\n    expect(result[1]!.getMonth()).toEqual(now.getMonth());\n    expect(differenceInCalendarMonths(result[0]!.nativeDate, now)).toEqual(-1);\n\n    result = normalizeRangeValue([new CandyDate(), new CandyDate()], false, 'month', 'left');\n    expect(result[0]!.getMonth()).toEqual(now.getMonth());\n    expect(differenceInCalendarMonths(result[1]!.nativeDate, now)).toEqual(1);\n\n    result = normalizeRangeValue([new CandyDate(), new CandyDate()], false, 'month', 'right');\n    expect(result[0]!.getMonth()).toEqual(now.getMonth());\n    expect(differenceInCalendarMonths(result[1]!.nativeDate, now)).toEqual(1);\n\n    result = normalizeRangeValue([new CandyDate(), new CandyDate()], true);\n    expect(result[0]!.getMonth()).toEqual(now.getMonth());\n    expect(result[1]!.getMonth()).toEqual(now.getMonth());\n\n    result = normalizeRangeValue([new CandyDate(), new CandyDate()], false, 'year');\n    expect(result[0]!.getYear()).toEqual(now.getFullYear());\n    expect(result[1]!.getYear()).toEqual(now.getFullYear() + 1);\n\n    result = normalizeRangeValue([new CandyDate(), new CandyDate()], true, 'year');\n    expect(result[0]!.getYear()).toEqual(now.getFullYear());\n    expect(result[1]!.getYear()).toEqual(now.getFullYear());\n  });\n}); // /candy-date coverage supplements\n"
  },
  {
    "path": "components/core/time/candy-date.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  addMonths,\n  addYears,\n  differenceInCalendarDays,\n  differenceInCalendarMonths,\n  differenceInCalendarYears,\n  differenceInCalendarQuarters,\n  differenceInHours,\n  differenceInMinutes,\n  differenceInSeconds,\n  isFirstDayOfMonth,\n  isLastDayOfMonth,\n  isSameDay,\n  isSameHour,\n  isSameMinute,\n  isSameMonth,\n  isSameSecond,\n  isSameYear,\n  isSameQuarter,\n  isToday,\n  isValid,\n  setDay,\n  setMonth,\n  setYear,\n  startOfMonth,\n  startOfWeek,\n  getQuarter,\n  setQuarter\n} from 'date-fns';\n\nimport { warn } from 'ng-zorro-antd/core/logger';\nimport { IndexableObject, NzSafeAny } from 'ng-zorro-antd/core/types';\n\nexport type CandyDateMode = 'decade' | 'year' | 'quarter' | 'month' | 'day' | 'hour' | 'minute' | 'second';\nexport type NormalizedMode = 'decade' | 'year' | 'month';\nexport type WeekDayIndex = 0 | 1 | 2 | 3 | 4 | 5 | 6;\nexport type CandyDateType = CandyDate | Date | null;\nexport type SingleValue = CandyDate | null;\nexport type CompatibleValue = SingleValue | SingleValue[];\n\nexport function wrongSortOrder(rangeValue: SingleValue[]): boolean {\n  const [start, end] = rangeValue;\n  return !!start && !!end && end.isBeforeDay(start);\n}\n\nexport function normalizeRangeValue(\n  value: SingleValue[],\n  hasTimePicker: boolean,\n  type: NormalizedMode = 'month',\n  activePart: 'left' | 'right' = 'left'\n): CandyDate[] {\n  const [start, end] = value;\n  let newStart: CandyDate = start || new CandyDate();\n  let newEnd: CandyDate = end || (hasTimePicker ? newStart : newStart.add(1, type));\n\n  if (start && !end) {\n    newStart = start;\n    newEnd = hasTimePicker ? start : start.add(1, type);\n  } else if (!start && end) {\n    newStart = hasTimePicker ? end : end.add(-1, type);\n    newEnd = end;\n  } else if (start && end && !hasTimePicker) {\n    if (start.isSame(end, type)) {\n      newEnd = newStart.add(1, type);\n    } else {\n      if (activePart === 'left') {\n        newEnd = newStart.add(1, type);\n      } else {\n        newStart = newEnd.add(-1, type);\n      }\n    }\n  }\n  return [newStart, newEnd];\n}\n\nexport function cloneDate(value: CompatibleValue): CompatibleValue {\n  if (Array.isArray(value)) {\n    return value.map(v => (v instanceof CandyDate ? v.clone() : null));\n  } else {\n    return value instanceof CandyDate ? value.clone() : null;\n  }\n}\n\n/**\n * Wrapping kind APIs for date operating and unify\n * NOTE: every new API return new CandyDate object without side effects to the former Date object\n * NOTE: most APIs are based on local time other than customized locale id (this needs tobe support in future)\n * TODO: support format() against to angular's core API\n */\nexport class CandyDate implements IndexableObject {\n  nativeDate: Date;\n  // locale: string; // Custom specified locale ID\n\n  constructor(date?: Date | string | number) {\n    if (date) {\n      if (date instanceof Date) {\n        this.nativeDate = date;\n      } else if (typeof date === 'string' || typeof date === 'number') {\n        warn('The string type is not recommended for date-picker, use \"Date\" type');\n        this.nativeDate = new Date(date);\n      } else {\n        throw new Error('The input date type is not supported (\"Date\" is now recommended)');\n      }\n    } else {\n      this.nativeDate = new Date();\n    }\n  }\n\n  calendarStart(options?: { weekStartsOn: WeekDayIndex | undefined }): CandyDate {\n    return new CandyDate(startOfWeek(startOfMonth(this.nativeDate), options));\n  }\n\n  // ---------------------------------------------------------------------\n  // | Native shortcuts\n  // -----------------------------------------------------------------------------\\\n\n  getYear(): number {\n    return this.nativeDate.getFullYear();\n  }\n\n  getMonth(): number {\n    return this.nativeDate.getMonth();\n  }\n\n  getDay(): number {\n    return this.nativeDate.getDay();\n  }\n\n  getTime(): number {\n    return this.nativeDate.getTime();\n  }\n\n  getDate(): number {\n    return this.nativeDate.getDate();\n  }\n\n  getHours(): number {\n    return this.nativeDate.getHours();\n  }\n\n  getMinutes(): number {\n    return this.nativeDate.getMinutes();\n  }\n\n  getSeconds(): number {\n    return this.nativeDate.getSeconds();\n  }\n\n  getMilliseconds(): number {\n    return this.nativeDate.getMilliseconds();\n  }\n\n  // ---------------------------------------------------------------------\n  // | New implementing APIs\n  // ---------------------------------------------------------------------\n\n  clone(): CandyDate {\n    return new CandyDate(new Date(this.nativeDate));\n  }\n\n  setHms(hour: number, minute: number, second: number): CandyDate {\n    const newDate = new Date(this.nativeDate.setHours(hour, minute, second));\n    return new CandyDate(newDate);\n  }\n\n  setYear(year: number): CandyDate {\n    return new CandyDate(setYear(this.nativeDate, year));\n  }\n\n  addYears(amount: number): CandyDate {\n    return new CandyDate(addYears(this.nativeDate, amount));\n  }\n\n  // NOTE: month starts from 0\n  // NOTE: Don't use the native API for month manipulation as it not restrict the date when it overflows, eg. (new Date('2018-7-31')).setMonth(1) will be date of 2018-3-03 instead of 2018-2-28\n  setMonth(month: number): CandyDate {\n    return new CandyDate(setMonth(this.nativeDate, month));\n  }\n\n  addMonths(amount: number): CandyDate {\n    return new CandyDate(addMonths(this.nativeDate, amount));\n  }\n\n  setDay(day: number, options?: { weekStartsOn: WeekDayIndex }): CandyDate {\n    return new CandyDate(setDay(this.nativeDate, day, options));\n  }\n\n  setDate(amount: number): CandyDate {\n    const date = new Date(this.nativeDate);\n    date.setDate(amount);\n    return new CandyDate(date);\n  }\n\n  getQuarter(): number {\n    return getQuarter(this.nativeDate);\n  }\n\n  setQuarter(quarter: number): CandyDate {\n    return new CandyDate(setQuarter(this.nativeDate, quarter));\n  }\n\n  addDays(amount: number): CandyDate {\n    return this.setDate(this.getDate() + amount);\n  }\n\n  add(amount: number, mode: NormalizedMode): CandyDate {\n    switch (mode) {\n      case 'decade':\n        return this.addYears(amount * 10);\n      case 'year':\n        return this.addYears(amount);\n      case 'month':\n        return this.addMonths(amount);\n      default:\n        return this.addMonths(amount);\n    }\n  }\n\n  isSame(date: CandyDateType, grain: CandyDateMode = 'day'): boolean {\n    let fn;\n    switch (grain) {\n      case 'decade':\n        fn = (pre: Date, next: Date) => Math.abs(pre.getFullYear() - next.getFullYear()) < 11;\n        break;\n      case 'year':\n        fn = isSameYear;\n        break;\n      case 'quarter':\n        fn = isSameQuarter;\n        break;\n      case 'month':\n        fn = isSameMonth;\n        break;\n      case 'day':\n        fn = isSameDay;\n        break;\n      case 'hour':\n        fn = isSameHour;\n        break;\n      case 'minute':\n        fn = isSameMinute;\n        break;\n      case 'second':\n        fn = isSameSecond;\n        break;\n      default:\n        fn = isSameDay;\n        break;\n    }\n    return fn(this.nativeDate, this.toNativeDate(date));\n  }\n\n  isSameYear(date: CandyDateType): boolean {\n    return this.isSame(date, 'year');\n  }\n  isSameQuarter(date: CandyDateType): boolean {\n    return this.isSame(date, 'quarter');\n  }\n\n  isSameMonth(date: CandyDateType): boolean {\n    return this.isSame(date, 'month');\n  }\n\n  isSameDay(date: CandyDateType): boolean {\n    return this.isSame(date, 'day');\n  }\n\n  isSameHour(date: CandyDateType): boolean {\n    return this.isSame(date, 'hour');\n  }\n\n  isSameMinute(date: CandyDateType): boolean {\n    return this.isSame(date, 'minute');\n  }\n\n  isSameSecond(date: CandyDateType): boolean {\n    return this.isSame(date, 'second');\n  }\n\n  isBefore(date: CandyDateType, grain: CandyDateMode = 'day'): boolean {\n    if (date === null) {\n      return false;\n    }\n    let fn;\n    switch (grain) {\n      case 'year':\n        fn = differenceInCalendarYears;\n        break;\n      case 'quarter':\n        fn = differenceInCalendarQuarters;\n        break;\n      case 'month':\n        fn = differenceInCalendarMonths;\n        break;\n      case 'day':\n        fn = differenceInCalendarDays;\n        break;\n      case 'hour':\n        fn = differenceInHours;\n        break;\n      case 'minute':\n        fn = differenceInMinutes;\n        break;\n      case 'second':\n        fn = differenceInSeconds;\n        break;\n      default:\n        fn = differenceInCalendarDays;\n        break;\n    }\n    return fn(this.nativeDate, this.toNativeDate(date)) < 0;\n  }\n\n  isBeforeYear(date: CandyDateType): boolean {\n    return this.isBefore(date, 'year');\n  }\n\n  isBeforeQuarter(date: CandyDateType): boolean {\n    return this.isBefore(date, 'quarter');\n  }\n\n  isBeforeMonth(date: CandyDateType): boolean {\n    return this.isBefore(date, 'month');\n  }\n\n  isBeforeDay(date: CandyDateType): boolean {\n    return this.isBefore(date, 'day');\n  }\n\n  // Equal to today accurate to \"day\"\n  isToday(): boolean {\n    return isToday(this.nativeDate);\n  }\n\n  isValid(): boolean {\n    return isValid(this.nativeDate);\n  }\n\n  isFirstDayOfMonth(): boolean {\n    return isFirstDayOfMonth(this.nativeDate);\n  }\n\n  isLastDayOfMonth(): boolean {\n    return isLastDayOfMonth(this.nativeDate);\n  }\n\n  private toNativeDate(date: NzSafeAny): Date {\n    return date instanceof CandyDate ? date.nativeDate : date;\n  }\n}\n"
  },
  {
    "path": "components/core/time/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/core/time/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/core/time/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './candy-date';\nexport * from './time';\nexport { NgTimeParser as ɵNgTimeParser } from './time-parser';\nexport type { TimeResult as ɵTimeResult } from './time-parser';\n"
  },
  {
    "path": "components/core/time/time-parser.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { registerLocaleData } from '@angular/common';\nimport zh from '@angular/common/locales/zh';\nimport { LOCALE_ID } from '@angular/core';\nimport { TestBed } from '@angular/core/testing';\n\nimport { NgTimeParser, TimeResult } from './time-parser';\n\ndescribe('Parse time with angular format', () => {\n  let localeId: string;\n  let parser: NgTimeParser;\n  let result: TimeResult | null;\n  let time: Date;\n\n  describe('default locale', () => {\n    beforeEach(() => {\n      localeId = TestBed.inject(LOCALE_ID);\n    });\n\n    it('should parse hh:mm:ss a', () => {\n      parser = new NgTimeParser('hh:mm:ss a', localeId);\n      result = parser.getTimeResult('12:30:22 AM');\n      expect(result?.hour).toBe(12);\n      expect(result?.minute).toBe(30);\n      expect(result?.second).toBe(22);\n      expect(result?.period).toBe(0);\n\n      result = parser.getTimeResult('12:30:22 PM');\n      expect(result?.period).toBe(1);\n\n      time = parser.toDate('12:30:22 PM');\n      expect(time.getHours()).toBe(12);\n      expect(time.getMinutes()).toBe(30);\n      expect(time.getSeconds()).toBe(22);\n\n      time = parser.toDate('05:30:22 PM');\n      expect(time.getHours()).toBe(17);\n    });\n\n    it('should parse hh:mm:ss aaaaa', () => {\n      parser = new NgTimeParser('hh:mm:ss aaaaa', localeId);\n      result = parser.getTimeResult('12:30:22 a');\n      expect(result?.hour).toBe(12);\n      expect(result?.minute).toBe(30);\n      expect(result?.second).toBe(22);\n      expect(result?.period).toBe(0);\n\n      result = parser.getTimeResult('12:30:22 p');\n      expect(result?.period).toBe(1);\n    });\n\n    it('should parse mm(ss) HH', () => {\n      parser = new NgTimeParser('mm(ss) HH', localeId);\n      result = parser.getTimeResult('30(22) 12');\n      expect(result?.period).toBe(null);\n\n      time = parser.toDate('30(22) 12');\n      expect(time.getHours()).toBe(12);\n      expect(time.getMinutes()).toBe(30);\n      expect(time.getSeconds()).toBe(22);\n    });\n\n    it('should parse ss + mm', () => {\n      parser = new NgTimeParser('ss + mm', localeId);\n      time = parser.toDate('10 + 42');\n      const now = new Date();\n      expect(time.getHours()).toBe(now.getHours());\n      expect(time.getMinutes()).toBe(42);\n      expect(time.getSeconds()).toBe(10);\n    });\n  });\n\n  describe('zh locale', () => {\n    registerLocaleData(zh);\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        providers: [{ provide: LOCALE_ID, useValue: 'zh-CN' }]\n      });\n      localeId = TestBed.inject(LOCALE_ID);\n    });\n\n    it('should parse hh:mm:ss a', () => {\n      parser = new NgTimeParser('hh:mm:ss a', localeId);\n      result = parser.getTimeResult('04:45:22 上午');\n      expect(result?.hour).toBe(4);\n      expect(result?.minute).toBe(45);\n      expect(result?.second).toBe(22);\n      expect(result?.period).toBe(0);\n\n      time = parser.toDate('04:45:22 下午');\n      expect(time.getHours()).toBe(16);\n    });\n  });\n});\n"
  },
  {
    "path": "components/core/time/time-parser.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\n// from https://github.com/hsuanxyz/ng-time-parser\nimport { FormStyle, getLocaleDayPeriods, TranslationWidth } from '@angular/common';\n\nimport { isNotNil } from 'ng-zorro-antd/core/util';\n\nexport interface TimeResult {\n  hour: number | null;\n  minute: number | null;\n  second: number | null;\n  period: number | null;\n}\n\nexport class NgTimeParser {\n  regex: RegExp = null!;\n  matchMap: Record<string, null | number> = {\n    hour: null,\n    minute: null,\n    second: null,\n    periodNarrow: null,\n    periodWide: null,\n    periodAbbreviated: null\n  };\n\n  constructor(\n    private format: string,\n    private localeId: string\n  ) {\n    this.genRegexp();\n  }\n\n  toDate(str: string): Date {\n    const result = this.getTimeResult(str);\n    const time = new Date();\n\n    if (isNotNil(result?.hour)) {\n      time.setHours(result!.hour);\n    }\n\n    if (isNotNil(result?.minute)) {\n      time.setMinutes(result!.minute);\n    }\n\n    if (isNotNil(result?.second)) {\n      time.setSeconds(result!.second);\n    }\n\n    if (result?.period === 1 && time.getHours() < 12) {\n      time.setHours(time.getHours() + 12);\n    }\n\n    return time;\n  }\n\n  getTimeResult(str: string): TimeResult | null {\n    const match = this.regex.exec(str);\n    let period = null;\n    if (match) {\n      if (isNotNil(this.matchMap.periodNarrow)) {\n        period = getLocaleDayPeriods(this.localeId, FormStyle.Format, TranslationWidth.Narrow).indexOf(\n          match[this.matchMap.periodNarrow + 1]\n        );\n      }\n      if (isNotNil(this.matchMap.periodWide)) {\n        period = getLocaleDayPeriods(this.localeId, FormStyle.Format, TranslationWidth.Wide).indexOf(\n          match[this.matchMap.periodWide + 1]\n        );\n      }\n      if (isNotNil(this.matchMap.periodAbbreviated)) {\n        period = getLocaleDayPeriods(this.localeId, FormStyle.Format, TranslationWidth.Abbreviated).indexOf(\n          match[this.matchMap.periodAbbreviated + 1]\n        );\n      }\n      return {\n        hour: isNotNil(this.matchMap.hour) ? Number.parseInt(match[this.matchMap.hour + 1], 10) : null,\n        minute: isNotNil(this.matchMap.minute) ? Number.parseInt(match[this.matchMap.minute + 1], 10) : null,\n        second: isNotNil(this.matchMap.second) ? Number.parseInt(match[this.matchMap.second + 1], 10) : null,\n        period\n      };\n    } else {\n      return null;\n    }\n  }\n\n  genRegexp(): void {\n    let regexStr = this.format.replace(/([.*+?^=!:${}()|[\\]/\\\\])/g, '\\\\$&');\n    const hourRegex = /h{1,2}/i;\n    const minuteRegex = /m{1,2}/;\n    const secondRegex = /s{1,2}/;\n    const periodNarrow = /aaaaa/;\n    const periodWide = /aaaa/;\n    const periodAbbreviated = /a{1,3}/;\n\n    const hourMatch = hourRegex.exec(this.format);\n    const minuteMatch = minuteRegex.exec(this.format);\n    const secondMatch = secondRegex.exec(this.format);\n    const periodNarrowMatch = periodNarrow.exec(this.format);\n    let periodWideMatch: null | RegExpExecArray = null;\n    let periodAbbreviatedMatch: null | RegExpExecArray = null;\n    if (!periodNarrowMatch) {\n      periodWideMatch = periodWide.exec(this.format);\n    }\n    if (!periodWideMatch && !periodNarrowMatch) {\n      periodAbbreviatedMatch = periodAbbreviated.exec(this.format);\n    }\n\n    const matchs = [hourMatch, minuteMatch, secondMatch, periodNarrowMatch, periodWideMatch, periodAbbreviatedMatch]\n      .filter(m => !!m)\n      .sort((a, b) => a!.index - b!.index);\n\n    matchs.forEach((match, index) => {\n      switch (match) {\n        case hourMatch:\n          this.matchMap.hour = index;\n          regexStr = regexStr.replace(hourRegex, '(\\\\d{1,2})');\n          break;\n        case minuteMatch:\n          this.matchMap.minute = index;\n          regexStr = regexStr.replace(minuteRegex, '(\\\\d{1,2})');\n          break;\n        case secondMatch:\n          this.matchMap.second = index;\n          regexStr = regexStr.replace(secondRegex, '(\\\\d{1,2})');\n          break;\n        case periodNarrowMatch: {\n          this.matchMap.periodNarrow = index;\n          const periodsNarrow = getLocaleDayPeriods(this.localeId, FormStyle.Format, TranslationWidth.Narrow).join('|');\n          regexStr = regexStr.replace(periodNarrow, `(${periodsNarrow})`);\n          break;\n        }\n        case periodWideMatch: {\n          this.matchMap.periodWide = index;\n          const periodsWide = getLocaleDayPeriods(this.localeId, FormStyle.Format, TranslationWidth.Wide).join('|');\n          regexStr = regexStr.replace(periodWide, `(${periodsWide})`);\n          break;\n        }\n        case periodAbbreviatedMatch: {\n          this.matchMap.periodAbbreviated = index;\n          const periodsAbbreviated = getLocaleDayPeriods(\n            this.localeId,\n            FormStyle.Format,\n            TranslationWidth.Abbreviated\n          ).join('|');\n          regexStr = regexStr.replace(periodAbbreviated, `(${periodsAbbreviated})`);\n          break;\n        }\n      }\n    });\n\n    this.regex = new RegExp(regexStr);\n  }\n}\n"
  },
  {
    "path": "components/core/time/time.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport const timeUnits: Array<[string, number]> = [\n  ['Y', 1000 * 60 * 60 * 24 * 365], // years\n  ['M', 1000 * 60 * 60 * 24 * 30], // months\n  ['D', 1000 * 60 * 60 * 24], // days\n  ['H', 1000 * 60 * 60], // hours\n  ['m', 1000 * 60], // minutes\n  ['s', 1000], // seconds\n  ['S', 1] // million seconds\n];\n"
  },
  {
    "path": "components/core/trans-button/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/core/trans-button/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/core/trans-button/nz-trans-button.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive } from '@angular/core';\n\n@Directive({\n  selector: 'button[nz-trans-button]',\n  host: {\n    '[style.border]': '\"0\"',\n    '[style.background]': '\"transparent\"',\n    '[style.padding]': '\"0\"',\n    '[style.line-height]': '\"inherit\"'\n  }\n})\nexport class NzTransButtonDirective {}\n"
  },
  {
    "path": "components/core/trans-button/nz-trans-button.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzTransButtonDirective } from './nz-trans-button.directive';\n\n@NgModule({\n  imports: [NzTransButtonDirective],\n  exports: [NzTransButtonDirective]\n})\nexport class NzTransButtonModule {}\n"
  },
  {
    "path": "components/core/trans-button/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport { NzTransButtonModule } from './nz-trans-button.module';\nexport { NzTransButtonDirective } from './nz-trans-button.directive';\n"
  },
  {
    "path": "components/core/transition-patch/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/core/transition-patch/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/core/transition-patch/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport { NzTransitionPatchModule as ɵNzTransitionPatchModule } from './transition-patch.module';\nexport { NzTransitionPatchDirective as ɵNzTransitionPatchDirective } from './transition-patch.directive';\n"
  },
  {
    "path": "components/core/transition-patch/transition-patch.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { AfterViewInit, Directive, ElementRef, inject, Input, OnChanges, Renderer2 } from '@angular/core';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\n/**\n * hack the bug\n * angular router change with unexpected transition trigger after calling applicationRef.attachView\n * https://github.com/angular/angular/issues/34718\n */\n@Directive({\n  selector:\n    '[nz-button], [nz-icon], nz-icon, [nz-menu-item], [nz-submenu], nz-select-top-control, nz-select-placeholder, nz-input-group'\n})\nexport class NzTransitionPatchDirective implements AfterViewInit, OnChanges {\n  private elementRef = inject(ElementRef<HTMLElement>);\n  private renderer = inject(Renderer2);\n  @Input() hidden: NzSafeAny = null;\n  setHiddenAttribute(): void {\n    if (this.hidden) {\n      if (typeof this.hidden === 'string') {\n        this.renderer.setAttribute(this.elementRef.nativeElement, 'hidden', this.hidden);\n      } else {\n        this.renderer.setAttribute(this.elementRef.nativeElement, 'hidden', '');\n      }\n    } else {\n      this.renderer.removeAttribute(this.elementRef.nativeElement, 'hidden');\n    }\n  }\n\n  constructor() {\n    this.renderer.setAttribute(this.elementRef.nativeElement, 'hidden', '');\n  }\n\n  ngOnChanges(): void {\n    this.setHiddenAttribute();\n  }\n\n  ngAfterViewInit(): void {\n    this.setHiddenAttribute();\n  }\n}\n"
  },
  {
    "path": "components/core/transition-patch/transition-patch.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzTransitionPatchDirective } from './transition-patch.directive';\n\n@NgModule({\n  imports: [NzTransitionPatchDirective],\n  exports: [NzTransitionPatchDirective]\n})\nexport class NzTransitionPatchModule {}\n"
  },
  {
    "path": "components/core/transition-patch/transition-patch.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component } from '@angular/core';\nimport { TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\n\nimport { NzTransitionPatchDirective } from './transition-patch.directive';\nimport { NzTransitionPatchModule } from './transition-patch.module';\n\ndescribe('transition-patch', () => {\n  it('should visible after afterViewInit', () => {\n    const fixture = TestBed.createComponent(TestTransitionPatchComponent);\n    const buttonElement = fixture.debugElement.query(By.directive(NzTransitionPatchDirective)).nativeElement;\n    expect(buttonElement.getAttribute('hidden')).toBeFalsy();\n  });\n\n  it('should hidden after afterViewInit', () => {\n    const fixture = TestBed.createComponent(TestTransitionPatchHiddenComponent);\n    const buttonElement = fixture.debugElement.query(By.directive(NzTransitionPatchDirective)).nativeElement;\n    expect(buttonElement.getAttribute('hidden')).toBeFalsy();\n  });\n\n  it('should restore after afterViewInit', () => {\n    const fixture = TestBed.createComponent(TestTransitionPatchRestoreComponent);\n    fixture.detectChanges();\n    const buttonElement = fixture.debugElement.query(By.directive(NzTransitionPatchDirective)).nativeElement;\n    expect(buttonElement.getAttribute('hidden')).toBe('abc');\n  });\n\n  it('should work if hidden binding', () => {\n    const fixture = TestBed.createComponent(TestTransitionPatchHiddenBindingComponent);\n    const component = fixture.componentInstance;\n    const buttonElement = fixture.debugElement.query(By.directive(NzTransitionPatchDirective)).nativeElement;\n    expect(buttonElement.getAttribute('hidden')).toBeFalsy();\n    component.hidden = true;\n    fixture.detectChanges();\n    expect(buttonElement.getAttribute('hidden')).toBe('');\n  });\n\n  it('should work if hidden binding with undefined', () => {\n    const fixture = TestBed.createComponent(TestTransitionPatchHiddenBindingComponent);\n    const component = fixture.componentInstance;\n    const buttonElement = fixture.debugElement.query(By.directive(NzTransitionPatchDirective)).nativeElement;\n    expect(buttonElement.getAttribute('hidden')).toBeFalsy();\n    component.hidden = undefined;\n    fixture.detectChanges();\n    expect(buttonElement.hasAttribute('hidden')).toBeFalse();\n  });\n});\n\n@Component({\n  imports: [NzButtonModule, NzTransitionPatchModule],\n  template: `<button nz-button></button>`\n})\nexport class TestTransitionPatchComponent {}\n\n@Component({\n  imports: [NzButtonModule, NzTransitionPatchModule],\n  template: `<button nz-button hidden></button>`\n})\nexport class TestTransitionPatchHiddenComponent {}\n\n@Component({\n  imports: [NzButtonModule, NzTransitionPatchModule],\n  template: `<button nz-button hidden=\"abc\"></button>`\n})\nexport class TestTransitionPatchRestoreComponent {}\n\n@Component({\n  imports: [NzButtonModule, NzTransitionPatchModule],\n  template: `<button nz-button [hidden]=\"hidden\"></button>`\n})\nexport class TestTransitionPatchHiddenBindingComponent {\n  hidden?: boolean = false;\n}\n"
  },
  {
    "path": "components/core/tree/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/core/tree/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/core/tree/nz-tree-base-node.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzTreeNodeBaseComponent } from './nz-tree-base.definitions';\nimport { NzTreeBaseService } from './nz-tree-base.service';\n\nexport type NzTreeNodeKey = string | number;\n\nexport interface FlattenNode {\n  parent: FlattenNode | null;\n  children: FlattenNode[];\n  pos: string;\n  data: NzTreeNode;\n  isStart: boolean[];\n  isEnd: boolean[];\n}\n\nexport interface NzTreeNodeOptions {\n  title: string;\n  key: string;\n  icon?: string;\n  isLeaf?: boolean;\n  checked?: boolean;\n  selected?: boolean;\n  selectable?: boolean;\n  disabled?: boolean;\n  disableCheckbox?: boolean;\n  expanded?: boolean;\n  children?: NzTreeNodeOptions[];\n\n  [key: string]: NzSafeAny;\n}\n\nexport class NzTreeNode {\n  private _title: string = '';\n  key!: string;\n  level: number = 0;\n  origin!: NzTreeNodeOptions;\n  // Parent Node\n  parentNode: NzTreeNode | null = null;\n  private _icon: string = '';\n  private _children: NzTreeNode[] = [];\n  private _isLeaf: boolean = false;\n  private _isChecked: boolean = false;\n  private _isSelectable: boolean = false;\n  private _isDisabled: boolean = false;\n  private _isDisableCheckbox: boolean = false;\n  private _isExpanded: boolean = false;\n  private _isHalfChecked: boolean = false;\n  private _isSelected: boolean = false;\n  private _isLoading: boolean = false;\n  canHide: boolean = false;\n  isMatched: boolean = false;\n\n  service: NzTreeBaseService | null = null;\n  component!: NzTreeNodeBaseComponent;\n\n  /** New added in Tree for easy data access */\n  isStart?: boolean[];\n  isEnd?: boolean[];\n\n  get treeService(): NzTreeBaseService | null {\n    return this.service || (this.parentNode && this.parentNode.treeService);\n  }\n\n  /**\n   * Init nzTreeNode\n   *\n   * @param option option user's input\n   * @param parent parent node\n   * @param service base nzTreeService\n   */\n  constructor(\n    option: NzTreeNodeOptions | NzTreeNode,\n    parent: NzTreeNode | null = null,\n    service: NzTreeBaseService | null = null\n  ) {\n    if (option instanceof NzTreeNode) {\n      return option;\n    }\n    this.service = service || null;\n    this.origin = option;\n    this.key = option.key;\n    this.parentNode = parent;\n    this._title = option.title || '---';\n    this._icon = option.icon || '';\n    this._isLeaf = option.isLeaf || false;\n    this._children = [];\n    // option params\n    this._isChecked = option.checked || false;\n    this._isSelectable = option.disabled || option.selectable !== false;\n    this._isDisabled = option.disabled || false;\n    this._isDisableCheckbox = option.disableCheckbox || false;\n    this._isExpanded = option.isLeaf ? false : option.expanded || false;\n    this._isHalfChecked = false;\n    this._isSelected = (!option.disabled && option.selected) || false;\n    this._isLoading = false;\n    this.isMatched = false;\n\n    /**\n     * parent's checked status will affect children while initializing\n     */\n    if (parent) {\n      this.level = parent.level + 1;\n    } else {\n      this.level = 0;\n    }\n\n    const s = this.treeService;\n\n    /**\n     * post process of current treeNode\n     */\n    s?.treeNodePostProcessor?.(this);\n\n    /**\n     * instantiate children tree nodes\n     */\n    if (typeof option.children !== 'undefined' && option.children !== null) {\n      option.children.forEach(nodeOptions => {\n        if (\n          s &&\n          !s.isCheckStrictly &&\n          option.checked &&\n          !option.disabled &&\n          !nodeOptions.disabled &&\n          !nodeOptions.disableCheckbox\n        ) {\n          nodeOptions.checked = option.checked;\n        }\n        this._children.push(new NzTreeNode(nodeOptions, this));\n      });\n    }\n  }\n\n  /**\n   * auto generate\n   * get\n   * set\n   */\n  get title(): string {\n    return this._title;\n  }\n\n  set title(value: string) {\n    this._title = value;\n    this.update();\n  }\n\n  get icon(): string {\n    return this._icon;\n  }\n\n  set icon(value: string) {\n    this._icon = value;\n    this.update();\n  }\n\n  get children(): NzTreeNode[] {\n    return this._children;\n  }\n\n  set children(value: NzTreeNode[]) {\n    this._children = value;\n    this.update();\n  }\n\n  get isLeaf(): boolean {\n    return this._isLeaf;\n  }\n\n  set isLeaf(value: boolean) {\n    this._isLeaf = value;\n    this.update();\n  }\n\n  get isChecked(): boolean {\n    return this._isChecked;\n  }\n\n  set isChecked(value: boolean) {\n    this._isChecked = value;\n    this.origin.checked = value;\n    this.afterValueChange('isChecked');\n  }\n\n  get isHalfChecked(): boolean {\n    return this._isHalfChecked;\n  }\n\n  set isHalfChecked(value: boolean) {\n    this._isHalfChecked = value;\n    this.afterValueChange('isHalfChecked');\n  }\n\n  get isSelectable(): boolean {\n    return this._isSelectable;\n  }\n\n  set isSelectable(value: boolean) {\n    this._isSelectable = value;\n    this.update();\n  }\n\n  get isDisabled(): boolean {\n    return this._isDisabled;\n  }\n\n  set isDisabled(value: boolean) {\n    this._isDisabled = value;\n    this.update();\n  }\n\n  get isDisableCheckbox(): boolean {\n    return this._isDisableCheckbox;\n  }\n\n  set isDisableCheckbox(value: boolean) {\n    this._isDisableCheckbox = value;\n    this.update();\n  }\n\n  get isExpanded(): boolean {\n    return this._isExpanded;\n  }\n\n  set isExpanded(value: boolean) {\n    this._isExpanded = value;\n    this.origin.expanded = value;\n    this.afterValueChange('isExpanded');\n    this.afterValueChange('reRender');\n  }\n\n  get isSelected(): boolean {\n    return this._isSelected;\n  }\n\n  set isSelected(value: boolean) {\n    this._isSelected = value;\n    this.origin.selected = value;\n    this.afterValueChange('isSelected');\n  }\n\n  get isLoading(): boolean {\n    return this._isLoading;\n  }\n\n  set isLoading(value: boolean) {\n    this._isLoading = value;\n    this.update();\n  }\n\n  public setSyncChecked(checked: boolean = false, halfChecked: boolean = false): void {\n    this.setChecked(checked, halfChecked);\n    if (this.treeService && !this.treeService.isCheckStrictly) {\n      this.treeService.conduct(this);\n    }\n  }\n\n  public setChecked(checked: boolean = false, halfChecked: boolean = false): void {\n    this.origin.checked = checked;\n    this.isChecked = checked;\n    this.isHalfChecked = halfChecked;\n  }\n\n  public setExpanded(value: boolean): void {\n    this._isExpanded = value;\n    this.origin.expanded = value;\n    this.afterValueChange('isExpanded');\n  }\n\n  public getParentNode(): NzTreeNode | null {\n    return this.parentNode;\n  }\n\n  public getChildren(): NzTreeNode[] {\n    return this.children;\n  }\n\n  /**\n   * Support appending child nodes by position. Leaf node cannot be appended.\n   */\n  public addChildren(children: NzSafeAny[], childPos: number = -1): void {\n    if (!this.isLeaf) {\n      children.forEach(node => {\n        const refreshLevel = (n: NzTreeNode): void => {\n          n.getChildren().forEach(c => {\n            c.level = c.getParentNode()!.level + 1;\n            // flush origin\n            c.origin.level = c.level;\n            refreshLevel(c);\n          });\n        };\n        let child = node;\n        if (child instanceof NzTreeNode) {\n          child.parentNode = this;\n        } else {\n          child = new NzTreeNode(node, this);\n        }\n        child.level = this.level + 1;\n        child.origin.level = child.level;\n        refreshLevel(child);\n        try {\n          childPos === -1 ? this.children.push(child) : this.children.splice(childPos, 0, child);\n          // flush origin\n        } catch {\n          // noop\n        }\n      });\n      this.origin.children = this.getChildren().map(v => v.origin);\n      // remove loading state\n      this.isLoading = false;\n    }\n    this.afterValueChange('addChildren');\n    this.afterValueChange('reRender');\n  }\n\n  public clearChildren(): void {\n    // refresh checked state\n    this.afterValueChange('clearChildren');\n    this.children = [];\n    this.origin.children = [];\n    this.afterValueChange('reRender');\n  }\n\n  public remove(): void {\n    const parentNode = this.getParentNode();\n    if (parentNode) {\n      parentNode.children = parentNode.getChildren().filter(v => v.key !== this.key);\n      parentNode.origin.children = parentNode.origin.children!.filter(v => v.key !== this.key);\n      this.afterValueChange('remove');\n      this.afterValueChange('reRender');\n    }\n  }\n\n  public afterValueChange(key: string): void {\n    if (this.treeService) {\n      switch (key) {\n        case 'isChecked':\n          this.treeService.setCheckedNodeList(this);\n          break;\n        case 'isHalfChecked':\n          this.treeService.setHalfCheckedNodeList(this);\n          break;\n        case 'isExpanded':\n          this.treeService.setExpandedNodeList(this);\n          break;\n        case 'isSelected':\n          this.treeService.setNodeActive(this);\n          break;\n        case 'clearChildren':\n          this.treeService.afterRemove(this.getChildren());\n          break;\n        case 'remove':\n          this.treeService.afterRemove([this]);\n          break;\n        case 'reRender':\n          this.treeService.flattenTreeData(\n            this.treeService.rootNodes,\n            this.treeService.getExpandedNodeList().map(v => v.key!)\n          );\n          break;\n      }\n    }\n    this.update();\n  }\n\n  public update(): void {\n    if (this.component) {\n      this.component.markForCheck();\n    }\n  }\n}\n"
  },
  {
    "path": "components/core/tree/nz-tree-base-util.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { FlattenNode, NzTreeNode, NzTreeNodeKey } from './nz-tree-base-node';\n\nexport function isCheckDisabled(node: NzTreeNode): boolean {\n  const { isDisabled, isDisableCheckbox } = node;\n  return !!(isDisabled || isDisableCheckbox);\n}\n\nexport function isInArray(needle: NzSafeAny, haystack: NzSafeAny[]): boolean {\n  return haystack.length > 0 && haystack.indexOf(needle) > -1;\n}\n\nexport function getPosition(level: string | number, index: number): string {\n  return `${level}-${index}`;\n}\n\nexport function getKey(key: NzTreeNodeKey, pos: string): NzTreeNodeKey {\n  if (key !== null && key !== undefined) {\n    return key;\n  }\n  return pos;\n}\n\n/**\n * Flat nest tree data into flatten list. This is used for virtual list render.\n *\n * @param treeNodeList Origin data node list\n * @param expandedKeys\n * need expanded keys, provides `true` means all expanded (used in `rc-tree-select`).\n */\nexport function flattenTreeData(\n  treeNodeList: NzTreeNode[] = [],\n  expandedKeys: NzTreeNodeKey[] | true = []\n): FlattenNode[] {\n  const expandedKeySet = new Set(expandedKeys === true ? [] : expandedKeys);\n  const flattenList: FlattenNode[] = [];\n\n  function dig(list: NzTreeNode[], parent: FlattenNode | null = null): FlattenNode[] {\n    return list.map((treeNode, index) => {\n      const pos: string = getPosition(parent ? parent.pos : '0', index);\n      const mergedKey = getKey(treeNode.key, pos);\n      treeNode.isStart = [...(parent ? parent.isStart : []), index === 0];\n      treeNode.isEnd = [...(parent ? parent.isEnd : []), index === list.length - 1];\n      // Add FlattenDataNode into list\n      // TODO: only need data here.\n      const flattenNode: FlattenNode = {\n        parent,\n        pos,\n        children: [],\n        data: treeNode,\n        isStart: [...(parent ? parent.isStart : []), index === 0],\n        isEnd: [...(parent ? parent.isEnd : []), index === list.length - 1]\n      };\n\n      flattenList.push(flattenNode);\n\n      // Loop treeNode children\n      if (expandedKeys === true || expandedKeySet.has(mergedKey) || treeNode.isExpanded) {\n        flattenNode.children = dig(treeNode.children || [], flattenNode);\n      } else {\n        flattenNode.children = [];\n      }\n\n      return flattenNode;\n    });\n  }\n\n  dig(treeNodeList);\n  return flattenList;\n}\n"
  },
  {
    "path": "components/core/tree/nz-tree-base.definitions.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzTreeNode } from './nz-tree-base-node';\n\nexport interface NzFormatEmitEvent {\n  eventName: string;\n  node?: NzTreeNode | null;\n  event?: MouseEvent | DragEvent | null;\n  dragNode?: NzTreeNode;\n  selectedKeys?: NzTreeNode[];\n  checkedKeys?: NzTreeNode[];\n  matchedKeys?: NzTreeNode[];\n  nodes?: NzTreeNode[];\n  keys?: string[];\n}\n\nexport interface NzFormatBeforeDropEvent {\n  dragNode: NzTreeNode;\n  node: NzTreeNode;\n  pos: number;\n}\n\nexport interface NzTreeNodeBaseComponent {\n  markForCheck(): void;\n}\n"
  },
  {
    "path": "components/core/tree/nz-tree-base.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Injectable } from '@angular/core';\nimport { BehaviorSubject } from 'rxjs';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzTreeNode, NzTreeNodeKey } from './nz-tree-base-node';\nimport { flattenTreeData, isCheckDisabled, isInArray } from './nz-tree-base-util';\nimport { NzFormatEmitEvent } from './nz-tree-base.definitions';\n\n@Injectable()\nexport class NzTreeBaseService {\n  DRAG_SIDE_RANGE = 0.25;\n  DRAG_MIN_GAP = 2;\n\n  isCheckStrictly: boolean = false;\n  isMultiple: boolean = false;\n  selectedNode!: NzTreeNode;\n  rootNodes: NzTreeNode[] = [];\n  flattenNodes$ = new BehaviorSubject<NzTreeNode[]>([]);\n  selectedNodeList: NzTreeNode[] = [];\n  expandedNodeList: NzTreeNode[] = [];\n  checkedNodeList: NzTreeNode[] = [];\n  halfCheckedNodeList: NzTreeNode[] = [];\n  matchedNodeList: NzTreeNode[] = [];\n  /**\n   * handle to post process a tree node when it's instantiating, note that its children haven't been initiated yet\n   */\n  treeNodePostProcessor?: (node: NzTreeNode) => void;\n\n  /**\n   * reset tree nodes will clear default node list\n   */\n  initTree(nzNodes: NzTreeNode[]): void {\n    this.rootNodes = nzNodes;\n    this.expandedNodeList = [];\n    this.selectedNodeList = [];\n    this.halfCheckedNodeList = [];\n    this.checkedNodeList = [];\n    this.matchedNodeList = [];\n  }\n\n  flattenTreeData(nzNodes: NzTreeNode[], expandedKeys: NzTreeNodeKey[] | true = []): void {\n    this.flattenNodes$.next(flattenTreeData(nzNodes, expandedKeys).map(item => item.data));\n  }\n\n  getSelectedNode(): NzTreeNode | null {\n    return this.selectedNode;\n  }\n\n  /**\n   * get some list\n   */\n  getSelectedNodeList(): NzTreeNode[] {\n    return this.conductNodeState('select');\n  }\n\n  /**\n   * get checked node keys\n   */\n  getCheckedNodeKeys(): NzTreeNodeKey[] {\n    const keys: NzTreeNodeKey[] = [];\n    const checkedNodes = this.getCheckedNodeList();\n\n    const calc = (nodes: NzTreeNode[]): void => {\n      nodes.forEach(node => {\n        keys.push(node.key);\n        if (node.children.length < 1) return;\n        calc(node.children);\n      });\n    };\n\n    calc(checkedNodes);\n\n    return keys;\n  }\n\n  /**\n   * return checked nodes\n   */\n  getCheckedNodeList(): NzTreeNode[] {\n    return this.conductNodeState('check');\n  }\n\n  getHalfCheckedNodeList(): NzTreeNode[] {\n    return this.conductNodeState('halfCheck');\n  }\n\n  /**\n   * return expanded nodes\n   */\n  getExpandedNodeList(): NzTreeNode[] {\n    return this.conductNodeState('expand');\n  }\n\n  /**\n   * return search matched nodes\n   */\n  getMatchedNodeList(): NzTreeNode[] {\n    return this.conductNodeState('match');\n  }\n\n  isArrayOfNzTreeNode(value: NzSafeAny[]): boolean {\n    return value.every(item => item instanceof NzTreeNode);\n  }\n\n  /**\n   * set drag node\n   */\n  setSelectedNode(node: NzTreeNode): void {\n    this.selectedNode = node;\n  }\n\n  /**\n   * set node selected status\n   */\n  setNodeActive(node: NzTreeNode): void {\n    if (!this.isMultiple && node.isSelected) {\n      this.selectedNodeList.forEach(n => {\n        if (node.key !== n.key) {\n          // reset other nodes\n          n.isSelected = false;\n        }\n      });\n      // single mode: remove pre node\n      this.selectedNodeList = [];\n    }\n    this.setSelectedNodeList(node, this.isMultiple);\n  }\n\n  /**\n   * add or remove node to selectedNodeList\n   */\n  setSelectedNodeList(node: NzTreeNode, isMultiple: boolean = false): void {\n    const index = this.getIndexOfArray(this.selectedNodeList, node.key);\n    if (isMultiple) {\n      if (node.isSelected && index === -1) {\n        this.selectedNodeList.push(node);\n      }\n    } else {\n      if (node.isSelected && index === -1) {\n        this.selectedNodeList = [node];\n      }\n    }\n    if (!node.isSelected) {\n      this.selectedNodeList = this.selectedNodeList.filter(n => n.key !== node.key);\n    }\n  }\n\n  /**\n   * merge checked nodes\n   */\n  setHalfCheckedNodeList(node: NzTreeNode): void {\n    const index = this.getIndexOfArray(this.halfCheckedNodeList, node.key);\n    if (node.isHalfChecked && index === -1) {\n      this.halfCheckedNodeList.push(node);\n    } else if (!node.isHalfChecked && index > -1) {\n      this.halfCheckedNodeList = this.halfCheckedNodeList.filter(n => node.key !== n.key);\n    }\n  }\n\n  setCheckedNodeList(node: NzTreeNode): void {\n    const index = this.getIndexOfArray(this.checkedNodeList, node.key);\n    if (node.isChecked && index === -1) {\n      this.checkedNodeList.push(node);\n    } else if (!node.isChecked && index > -1) {\n      this.checkedNodeList = this.checkedNodeList.filter(n => node.key !== n.key);\n    }\n  }\n\n  /**\n   * conduct checked/selected/expanded keys\n   */\n  conductNodeState(type: string = 'check'): NzTreeNode[] {\n    let resultNodesList: NzTreeNode[] = [];\n    switch (type) {\n      case 'select':\n        resultNodesList = this.selectedNodeList;\n        break;\n      case 'expand':\n        resultNodesList = this.expandedNodeList;\n        break;\n      case 'match':\n        resultNodesList = this.matchedNodeList;\n        break;\n      case 'check': {\n        resultNodesList = this.checkedNodeList;\n        const isIgnore = (node: NzTreeNode): boolean => {\n          const parentNode = node.getParentNode();\n          if (parentNode) {\n            if (this.checkedNodeList.findIndex(n => n.key === parentNode.key) > -1) {\n              return true;\n            } else {\n              return isIgnore(parentNode);\n            }\n          }\n          return false;\n        };\n        // merge checked\n        if (!this.isCheckStrictly) {\n          resultNodesList = this.checkedNodeList.filter(n => !isIgnore(n));\n        }\n        break;\n      }\n      case 'halfCheck':\n        if (!this.isCheckStrictly) {\n          resultNodesList = this.halfCheckedNodeList;\n        }\n        break;\n    }\n    return resultNodesList;\n  }\n\n  /**\n   * set expanded nodes\n   */\n  setExpandedNodeList(node: NzTreeNode): void {\n    if (node.isLeaf) {\n      return;\n    }\n    const index = this.getIndexOfArray(this.expandedNodeList, node.key);\n    if (node.isExpanded && index === -1) {\n      this.expandedNodeList.push(node);\n    } else if (!node.isExpanded && index > -1) {\n      this.expandedNodeList.splice(index, 1);\n    }\n  }\n\n  setMatchedNodeList(node: NzTreeNode): void {\n    const index = this.getIndexOfArray(this.matchedNodeList, node.key);\n    if (node.isMatched && index === -1) {\n      this.matchedNodeList.push(node);\n    } else if (!node.isMatched && index > -1) {\n      this.matchedNodeList.splice(index, 1);\n    }\n  }\n\n  /**\n   * check state\n   *\n   * @param isCheckStrictly\n   */\n  refreshCheckState(isCheckStrictly: boolean = false): void {\n    if (isCheckStrictly) {\n      return;\n    }\n    this.checkedNodeList.forEach(node => {\n      this.conduct(node, isCheckStrictly);\n    });\n  }\n\n  // reset other node checked state based current node\n  conduct(node: NzTreeNode, isCheckStrictly: boolean = false): void {\n    const isChecked = node.isChecked;\n    if (node && !isCheckStrictly) {\n      this.conductUp(node);\n      this.conductDown(node, isChecked);\n    }\n  }\n\n  /**\n   * 1、children half checked\n   * 2、children all checked, parent checked\n   * 3、no children checked\n   */\n  conductUp(node: NzTreeNode): void {\n    const parentNode = node.getParentNode();\n    if (parentNode) {\n      if (!isCheckDisabled(parentNode)) {\n        if (parentNode.children.every(child => isCheckDisabled(child) || (!child.isHalfChecked && child.isChecked))) {\n          parentNode.isChecked = true;\n          parentNode.isHalfChecked = false;\n        } else if (parentNode.children.some(child => child.isHalfChecked || child.isChecked)) {\n          parentNode.isChecked = false;\n          parentNode.isHalfChecked = true;\n        } else {\n          parentNode.isChecked = false;\n          parentNode.isHalfChecked = false;\n        }\n      }\n      this.setCheckedNodeList(parentNode);\n      this.setHalfCheckedNodeList(parentNode);\n      this.conductUp(parentNode);\n    }\n  }\n\n  /**\n   * reset child check state\n   */\n  conductDown(node: NzTreeNode, value: boolean): void {\n    if (!isCheckDisabled(node)) {\n      node.isChecked = value;\n      node.isHalfChecked = false;\n      this.setCheckedNodeList(node);\n      this.setHalfCheckedNodeList(node);\n      node.children.forEach(n => {\n        this.conductDown(n, value);\n      });\n    }\n  }\n\n  /**\n   * flush after delete node\n   */\n  afterRemove(nodes: NzTreeNode[]): void {\n    // to reset selectedNodeList & expandedNodeList\n    const loopNode = (node: NzTreeNode): void => {\n      // remove selected node\n      this.selectedNodeList = this.selectedNodeList.filter(n => n.key !== node.key);\n      // remove expanded node\n      this.expandedNodeList = this.expandedNodeList.filter(n => n.key !== node.key);\n      // remove checked node\n      this.checkedNodeList = this.checkedNodeList.filter(n => n.key !== node.key);\n      if (node.children) {\n        node.children.forEach(child => {\n          loopNode(child);\n        });\n      }\n    };\n    nodes.forEach(n => {\n      loopNode(n);\n    });\n    this.refreshCheckState(this.isCheckStrictly);\n  }\n\n  /**\n   * drag event\n   */\n  refreshDragNode(node: NzTreeNode): void {\n    if (node.children.length === 0) {\n      // until root\n      this.conductUp(node);\n    } else {\n      node.children.forEach(child => {\n        this.refreshDragNode(child);\n      });\n    }\n  }\n\n  // reset node level\n  resetNodeLevel(node: NzTreeNode): void {\n    const parentNode = node.getParentNode();\n    if (parentNode) {\n      node.level = parentNode.level + 1;\n    } else {\n      node.level = 0;\n    }\n    for (const child of node.children) {\n      this.resetNodeLevel(child);\n    }\n  }\n\n  calcDropPosition(event: DragEvent): number {\n    const { clientY } = event;\n    // to fix firefox undefined\n    const { top, bottom, height } = (event.target as Element).getBoundingClientRect();\n    const des = Math.max(height * this.DRAG_SIDE_RANGE, this.DRAG_MIN_GAP);\n\n    if (clientY <= top + des) {\n      return -1;\n    } else if (clientY >= bottom - des) {\n      return 1;\n    }\n\n    return 0;\n  }\n\n  /**\n   * drop\n   * 0: inner -1: pre 1: next\n   */\n  dropAndApply(targetNode: NzTreeNode, dragPos: number = -1): void {\n    if (!targetNode || dragPos > 1) {\n      return;\n    }\n    const treeService = targetNode.treeService;\n    const targetParent = targetNode.getParentNode();\n    const isSelectedRootNode = this.selectedNode.getParentNode();\n    // remove the dragNode\n    if (isSelectedRootNode) {\n      isSelectedRootNode.children = isSelectedRootNode.children.filter(n => n.key !== this.selectedNode.key);\n    } else {\n      this.rootNodes = this.rootNodes.filter(n => n.key !== this.selectedNode.key);\n    }\n    switch (dragPos) {\n      case 0:\n        targetNode.addChildren([this.selectedNode]);\n        this.resetNodeLevel(targetNode);\n        break;\n      case -1:\n      case 1: {\n        const tIndex = dragPos === 1 ? 1 : 0;\n        if (targetParent) {\n          targetParent.addChildren([this.selectedNode], targetParent.children.indexOf(targetNode) + tIndex);\n          const parentNode = this.selectedNode.getParentNode();\n          if (parentNode) {\n            this.resetNodeLevel(parentNode);\n          }\n        } else {\n          const targetIndex = this.rootNodes.indexOf(targetNode) + tIndex;\n          // Insert root node.\n          this.rootNodes.splice(targetIndex, 0, this.selectedNode);\n          this.rootNodes[targetIndex].parentNode = null;\n          this.resetNodeLevel(this.rootNodes[targetIndex]);\n        }\n        break;\n      }\n    }\n    // flush all nodes\n    this.rootNodes.forEach(child => {\n      if (!child.treeService) {\n        child.service = treeService;\n      }\n      this.refreshDragNode(child);\n    });\n  }\n\n  /**\n   * emit Structure\n   * eventName\n   * node\n   * event: MouseEvent / DragEvent\n   * dragNode\n   */\n  formatEvent(eventName: string, node: NzTreeNode | null, event: MouseEvent | DragEvent | null): NzFormatEmitEvent {\n    const emitStructure: NzFormatEmitEvent = {\n      eventName,\n      node,\n      event\n    };\n    switch (eventName) {\n      case 'dragstart':\n      case 'dragenter':\n      case 'dragover':\n      case 'dragleave':\n      case 'drop':\n      case 'dragend':\n        Object.assign(emitStructure, { dragNode: this.getSelectedNode() });\n        break;\n      case 'click':\n      case 'dblclick':\n        Object.assign(emitStructure, { selectedKeys: this.selectedNodeList });\n        Object.assign(emitStructure, { nodes: this.selectedNodeList });\n        Object.assign(emitStructure, { keys: this.selectedNodeList.map(n => n.key) });\n        break;\n      case 'check': {\n        const checkedNodeList = this.getCheckedNodeList();\n        Object.assign(emitStructure, { checkedKeys: checkedNodeList });\n        Object.assign(emitStructure, { nodes: checkedNodeList });\n        Object.assign(emitStructure, { keys: checkedNodeList.map(n => n.key) });\n        break;\n      }\n      case 'search':\n        Object.assign(emitStructure, { matchedKeys: this.getMatchedNodeList() });\n        Object.assign(emitStructure, { nodes: this.getMatchedNodeList() });\n        Object.assign(emitStructure, { keys: this.getMatchedNodeList().map(n => n.key) });\n        break;\n      case 'expand':\n        Object.assign(emitStructure, { nodes: this.expandedNodeList });\n        Object.assign(emitStructure, { keys: this.expandedNodeList.map(n => n.key) });\n        break;\n    }\n    return emitStructure;\n  }\n\n  /**\n   * New functions for flatten nodes\n   */\n\n  getIndexOfArray(list: NzTreeNode[], key: string): number {\n    return list.findIndex(v => v.key === key);\n  }\n\n  /**\n   * Render by nzCheckedKeys\n   * When keys equals null, just render with checkStrictly\n   *\n   * @param keys\n   * @param checkStrictly\n   */\n  conductCheck(keys: NzTreeNodeKey[] | null, checkStrictly: boolean): void {\n    this.checkedNodeList = [];\n    this.halfCheckedNodeList = [];\n    const calc = (nodes: NzTreeNode[]): void => {\n      nodes.forEach(node => {\n        if (keys === null) {\n          // render tree if no default checked keys found\n          node.isChecked = !!node.origin.checked;\n        } else {\n          if (isInArray(node.key, keys || [])) {\n            node.isChecked = true;\n            node.isHalfChecked = false;\n          } else {\n            node.isChecked = false;\n            node.isHalfChecked = false;\n          }\n        }\n        if (node.children.length > 0) {\n          calc(node.children);\n        }\n      });\n    };\n    calc(this.rootNodes);\n    this.refreshCheckState(checkStrictly);\n  }\n\n  conductExpandedKeys(keys: NzTreeNodeKey[] | true = []): void {\n    const expandedKeySet = new Set(keys === true ? [] : keys);\n    this.expandedNodeList = [];\n    const calc = (nodes: NzTreeNode[]): void => {\n      nodes.forEach(node => {\n        node.setExpanded(keys === true || expandedKeySet.has(node.key) || node.isExpanded === true);\n        if (node.isExpanded) {\n          this.setExpandedNodeList(node);\n        }\n        if (node.children.length > 0) {\n          calc(node.children);\n        }\n      });\n    };\n    calc(this.rootNodes);\n  }\n\n  conductSelectedKeys(keys: NzTreeNodeKey[], isMulti: boolean): void {\n    this.selectedNodeList.forEach(node => (node.isSelected = false));\n    this.selectedNodeList = [];\n    const calc = (nodes: NzTreeNode[]): boolean =>\n      nodes.every(node => {\n        if (isInArray(node.key, keys)) {\n          node.isSelected = true;\n          this.setSelectedNodeList(node);\n          if (!isMulti) {\n            // if not support multi select\n            return false;\n          }\n        } else {\n          node.isSelected = false;\n        }\n        if (node.children.length > 0) {\n          // Recursion\n          return calc(node.children);\n        }\n        return true;\n      });\n    calc(this.rootNodes);\n  }\n\n  /**\n   * Expand parent nodes by child node\n   *\n   * @param node\n   */\n  expandNodeAllParentBySearch(node: NzTreeNode): void {\n    const calc = (n: NzTreeNode | null): void => {\n      if (n) {\n        n.canHide = false;\n        n.setExpanded(true);\n        this.setExpandedNodeList(n);\n        if (n.getParentNode()) {\n          return calc(n.getParentNode());\n        }\n      }\n    };\n    calc(node.getParentNode());\n  }\n}\n"
  },
  {
    "path": "components/core/tree/nz-tree-base.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzTreeNode } from './nz-tree-base-node';\nimport { NzTreeBaseService } from './nz-tree-base.service';\n\nexport class NzTreeBase {\n  constructor(public nzTreeService: NzTreeBaseService) {}\n\n  /**\n   * Coerces a value({@link any[]}) to a TreeNodes({@link NzTreeNode[]})\n   */\n  coerceTreeNodes(value: NzSafeAny[]): NzTreeNode[] {\n    let nodes: NzTreeNode[] = [];\n    if (!this.nzTreeService.isArrayOfNzTreeNode(value)) {\n      // has not been new NzTreeNode\n      nodes = value.map(item => new NzTreeNode(item, null, this.nzTreeService));\n    } else {\n      nodes = value.map((item: NzTreeNode) => {\n        item.service = this.nzTreeService;\n        return item;\n      });\n    }\n    return nodes;\n  }\n\n  /**\n   * Get all nodes({@link NzTreeNode})\n   */\n  getTreeNodes(): NzTreeNode[] {\n    return this.nzTreeService.rootNodes;\n  }\n\n  /**\n   * Get {@link NzTreeNode} with key\n   */\n  getTreeNodeByKey(key: string): NzTreeNode | null {\n    // flat tree nodes\n    const nodes: NzTreeNode[] = [];\n    const getNode = (node: NzTreeNode): void => {\n      nodes.push(node);\n      node.getChildren().forEach(n => {\n        getNode(n);\n      });\n    };\n    this.getTreeNodes().forEach(n => {\n      getNode(n);\n    });\n    return nodes.find(n => n.key === key) || null;\n  }\n\n  /**\n   * Get checked nodes(merged)\n   */\n  getCheckedNodeList(): NzTreeNode[] {\n    return this.nzTreeService.getCheckedNodeList();\n  }\n\n  /**\n   * Get selected nodes\n   */\n  getSelectedNodeList(): NzTreeNode[] {\n    return this.nzTreeService.getSelectedNodeList();\n  }\n\n  /**\n   * Get half checked nodes\n   */\n  getHalfCheckedNodeList(): NzTreeNode[] {\n    return this.nzTreeService.getHalfCheckedNodeList();\n  }\n\n  /**\n   * Get expanded nodes\n   */\n  getExpandedNodeList(): NzTreeNode[] {\n    return this.nzTreeService.getExpandedNodeList();\n  }\n\n  /**\n   * Get matched nodes(if nzSearchValue is not null)\n   */\n  getMatchedNodeList(): NzTreeNode[] {\n    return this.nzTreeService.getMatchedNodeList();\n  }\n}\n"
  },
  {
    "path": "components/core/tree/nz-tree-service.resolver.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { InjectionToken } from '@angular/core';\n\nimport { NzTreeBaseService } from './nz-tree-base.service';\n\nexport const NzTreeHigherOrderServiceToken = new InjectionToken<NzTreeBaseService>(\n  typeof ngDevMode !== 'undefined' && ngDevMode ? 'nz-tree-higher-order' : ''\n);\n"
  },
  {
    "path": "components/core/tree/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './nz-tree-base-node';\nexport * from './nz-tree-base.definitions';\nexport * from './nz-tree-base.service';\nexport * from './nz-tree-service.resolver';\nexport * from './nz-tree-base';\nexport * from './nz-tree-base-util';\n"
  },
  {
    "path": "components/core/types/any.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type NzSafeAny = any;\n"
  },
  {
    "path": "components/core/types/common-wrap.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzSafeAny } from './any';\n\n// Define a property that can also returned by called function\nexport type FunctionProp<T> = (...args: NzSafeAny[]) => T;\n"
  },
  {
    "path": "components/core/types/compare-with.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzSafeAny } from './any';\n\nexport type CompareWith = (o1: NzSafeAny, o2: NzSafeAny) => boolean;\n"
  },
  {
    "path": "components/core/types/control-value-accessor.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzSafeAny } from './any';\n\nexport type OnTouchedType = () => NzSafeAny;\nexport type OnChangeType = (value: NzSafeAny) => void;\n"
  },
  {
    "path": "components/core/types/convert-input.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport type BooleanInput = boolean | string | undefined | null;\nexport type NumberInput = number | string | undefined | null;\n"
  },
  {
    "path": "components/core/types/direction.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport type NzDirectionVHType = 'vertical' | 'horizontal';\nexport type NzFourDirectionType = 'top' | 'bottom' | 'left' | 'right';\nexport type NzPlacement = 'bottomLeft' | 'bottomRight' | 'topLeft' | 'topRight';\n"
  },
  {
    "path": "components/core/types/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/core/types/indexable.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzSafeAny } from './any';\n\nexport interface IndexableObject {\n  [key: string]: NzSafeAny;\n}\n"
  },
  {
    "path": "components/core/types/input-observable.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { SimpleChange } from '@angular/core';\nimport { Observable } from 'rxjs';\n\nexport interface InputObservable {\n  getInputObservable<K extends keyof this>(changeType: K): Observable<SimpleChange>;\n}\n"
  },
  {
    "path": "components/core/types/ng-class.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzSafeAny } from './any';\n\nexport type NgClassType = string | string[] | NgClassInterface;\n\nexport interface NgClassInterface {\n  [klass: string]: NzSafeAny;\n}\n\nexport interface NgStyleInterface {\n  [klass: string]: NzSafeAny;\n}\n"
  },
  {
    "path": "components/core/types/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/core/types/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './common-wrap';\nexport * from './direction';\nexport * from './indexable';\nexport * from './ng-class';\nexport * from './size';\nexport * from './template';\nexport * from './shape';\nexport * from './compare-with';\nexport * from './any';\nexport * from './control-value-accessor';\nexport * from './convert-input';\nexport * from './input-observable';\nexport * from './type';\nexport * from './status';\nexport * from './variant';\n"
  },
  {
    "path": "components/core/types/shape.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport type NzShapeSCType = 'square' | 'circle';\n"
  },
  {
    "path": "components/core/types/size.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\n// TODO: replace other size with this type.\nexport type NzSizeLDSType = 'large' | 'default' | 'small';\nexport type NzSizeLMSType = 'large' | 'middle' | 'small';\nexport type NzSizeMDSType = 'middle' | 'default' | 'small';\nexport type NzSizeDSType = 'default' | 'small';\n"
  },
  {
    "path": "components/core/types/status.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport type NzStatus = '' | 'error' | 'warning';\nexport type NzValidateStatus = '' | 'success' | 'warning' | 'error' | 'validating';\n"
  },
  {
    "path": "components/core/types/template.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { TemplateRef } from '@angular/core';\n\n/**\n * A joined type of string and `TemplateRef<void>`.\n */\nexport type NzTSType = string | TemplateRef<void>;\n"
  },
  {
    "path": "components/core/types/type.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport const tuple = <T extends string[]>(...args: T): T => args;\n"
  },
  {
    "path": "components/core/types/variant.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport type NzVariant = 'outlined' | 'filled' | 'borderless' | 'underlined';\n"
  },
  {
    "path": "components/core/util/array.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport function toArray<T>(value: T | T[]): T[] {\n  let ret: T[];\n  if (value == null) {\n    ret = [];\n  } else if (!Array.isArray(value)) {\n    ret = [value];\n  } else {\n    ret = value;\n  }\n  return ret;\n}\n\nexport function arraysEqual<T>(array1: T[], array2: T[]): boolean {\n  if (!array1 || !array2 || array1.length !== array2.length) {\n    return false;\n  }\n\n  const len = array1.length;\n  for (let i = 0; i < len; i++) {\n    if (array1[i] !== array2[i]) {\n      return false;\n    }\n  }\n  return true;\n}\n\nexport function shallowCopyArray<T>(source: T[]): T[] {\n  return source.slice();\n}\n"
  },
  {
    "path": "components/core/util/can-use-dom.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\n/**\n * Sync from rc-util [https://github.com/react-component/util]\n */\nexport function canUseDom(): boolean {\n  return !!(typeof window !== 'undefined' && window.document && window.document.createElement);\n}\n"
  },
  {
    "path": "components/core/util/check.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { TemplateRef } from '@angular/core';\n\nimport { IndexableObject, NzSafeAny } from 'ng-zorro-antd/core/types';\n\nexport function isNotNil<T>(value: T): value is NonNullable<T> {\n  return typeof value !== 'undefined' && value !== null;\n}\n\nexport function isNil(value: unknown): value is null | undefined {\n  return typeof value === 'undefined' || value === null;\n}\n\n/**\n * Examine if two objects are shallowly equaled.\n */\nexport function shallowEqual(objA?: IndexableObject, objB?: IndexableObject): boolean {\n  if (objA === objB) {\n    return true;\n  }\n\n  if (typeof objA !== 'object' || !objA || typeof objB !== 'object' || !objB) {\n    return false;\n  }\n\n  const keysA = Object.keys(objA);\n  const keysB = Object.keys(objB);\n\n  if (keysA.length !== keysB.length) {\n    return false;\n  }\n\n  const bHasOwnProperty = Object.prototype.hasOwnProperty.bind(objB);\n\n  // eslint-disable-next-line @typescript-eslint/prefer-for-of\n  for (let idx = 0; idx < keysA.length; idx++) {\n    const key = keysA[idx];\n    if (!bHasOwnProperty(key)) {\n      return false;\n    }\n    if (objA[key] !== objB[key]) {\n      return false;\n    }\n  }\n\n  return true;\n}\n\nexport function isNonEmptyString(value: NzSafeAny): boolean {\n  return typeof value === 'string' && value !== '';\n}\n\nexport function isTemplateRef<T>(value: TemplateRef<T> | NzSafeAny): value is TemplateRef<T> {\n  return value instanceof TemplateRef;\n}\n"
  },
  {
    "path": "components/core/util/class-name.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { generateClassName, getClassListFromValue } from './class-name';\n\ndescribe('class-name utils', () => {\n  describe('generateClassName', () => {\n    it('should generate className with prefix and suffix', () => {\n      expect(generateClassName('ant', 'button')).toBe('ant-button');\n      expect(generateClassName('nz', 'alert')).toBe('nz-alert');\n    });\n\n    it('should handle empty strings', () => {\n      expect(generateClassName('', 'suffix')).toBe('-suffix');\n      expect(generateClassName('prefix', '')).toBe('prefix-');\n      expect(generateClassName('', '')).toBe('-');\n    });\n\n    it('should handle special characters', () => {\n      expect(generateClassName('ant-design', 'button-primary')).toBe('ant-design-button-primary');\n      expect(generateClassName('nz_component', 'test_case')).toBe('nz_component-test_case');\n    });\n\n    it('should handle numbers', () => {\n      expect(generateClassName('prefix', '123')).toBe('prefix-123');\n      expect(generateClassName('v1', 'alpha')).toBe('v1-alpha');\n    });\n  });\n\n  describe('getClassListFromValue', () => {\n    it('should return array when input is an array', () => {\n      const input = ['class1', 'class2', 'class3'];\n      expect(getClassListFromValue(input)).toEqual(['class1', 'class2', 'class3']);\n    });\n\n    it('should split string by whitespace', () => {\n      expect(getClassListFromValue('class1 class2 class3')).toEqual(['class1', 'class2', 'class3']);\n      expect(getClassListFromValue('single')).toEqual(['single']);\n    });\n\n    it('should handle multiple spaces', () => {\n      expect(getClassListFromValue('class1  class2   class3')).toEqual(['class1', 'class2', 'class3']);\n      expect(getClassListFromValue('class1    class2')).toEqual(['class1', 'class2']);\n    });\n\n    it('should trim leading and trailing spaces', () => {\n      expect(getClassListFromValue('  class1 class2  ')).toEqual(['class1', 'class2']);\n      expect(getClassListFromValue('   single   ')).toEqual(['single']);\n    });\n\n    it('should handle tabs and newlines', () => {\n      expect(getClassListFromValue('class1\\tclass2\\nclass3')).toEqual(['class1', 'class2', 'class3']);\n      expect(getClassListFromValue('class1\\n\\nclass2')).toEqual(['class1', 'class2']);\n    });\n\n    it('should handle empty string', () => {\n      expect(getClassListFromValue('')).toEqual([]);\n      expect(getClassListFromValue('   ')).toEqual([]);\n    });\n\n    it('should handle empty array', () => {\n      expect(getClassListFromValue([])).toEqual([]);\n    });\n\n    it('should handle array with empty strings', () => {\n      const input = ['', 'class1', ''];\n      expect(getClassListFromValue(input)).toEqual(['class1']);\n    });\n\n    it('should handle mixed whitespace characters', () => {\n      expect(getClassListFromValue('class1\\r\\nclass2\\t\\tclass3   class4')).toEqual([\n        'class1',\n        'class2',\n        'class3',\n        'class4'\n      ]);\n    });\n\n    it('should preserve class names with special characters', () => {\n      expect(getClassListFromValue('ant-btn ant-btn-primary ant-btn-lg')).toEqual([\n        'ant-btn',\n        'ant-btn-primary',\n        'ant-btn-lg'\n      ]);\n      expect(getClassListFromValue('class_1 class-2 class.3')).toEqual(['class_1', 'class-2', 'class.3']);\n    });\n  });\n});\n"
  },
  {
    "path": "components/core/util/class-name.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport function generateClassName(prefix: string, suffix: string): string {\n  return `${prefix}-${suffix}`;\n}\n\nexport function getClassListFromValue(value: string | string[]): string[] | null {\n  let classList: string[] | null = Array.isArray(value) ? value.filter(Boolean) : null;\n  if (typeof value === 'string') {\n    classList = value.trim().split(/\\s+/).filter(Boolean);\n  }\n  return classList;\n}\n"
  },
  {
    "path": "components/core/util/convert.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { coerceBooleanProperty, coerceCssPixelValue, coerceNumberProperty } from '@angular/cdk/coercion';\nimport { numberAttribute } from '@angular/core';\n\nimport { warn } from 'ng-zorro-antd/core/logger';\nimport { FunctionProp, NzSafeAny } from 'ng-zorro-antd/core/types';\n\nexport function toBoolean(value: unknown): boolean {\n  return coerceBooleanProperty(value);\n}\n\nexport function numberAttributeWithZeroFallback(value: unknown): number {\n  return numberAttribute(value, 0);\n}\n\nexport function numberAttributeWithOneFallback(value: unknown): number {\n  return numberAttribute(value, 1);\n}\n\nexport function numberAttributeWithInfinityFallback(value: unknown): number {\n  return numberAttribute(value, Infinity);\n}\n\nexport function toNumber(value: number | string): number;\nexport function toNumber<D>(value: number | string, fallback: D): number | D;\nexport function toNumber(value: number | string, fallbackValue: number = 0): number {\n  return coerceNumberProperty(value, fallbackValue);\n}\n\nexport function toCssPixel(value: number | string): string {\n  return coerceCssPixelValue(value);\n}\n\nexport function toCssPixelNumber(value: number | string): number {\n  return toNumber(typeof value === 'string' ? value.replace('px', '') : value);\n}\n\n// eslint-disable  no-invalid-this\n\n/**\n * Get the function-property type's value\n */\nexport function valueFunctionProp<T>(prop: FunctionProp<T> | T, ...args: NzSafeAny[]): T {\n  return typeof prop === 'function' ? (prop as FunctionProp<T>)(...args) : prop;\n}\n\nfunction propDecoratorFactory<T, D>(\n  name: string,\n  fallback: (v: T) => D\n): (target: NzSafeAny, propName: string) => void {\n  function propDecorator(\n    target: NzSafeAny,\n    propName: string,\n    originalDescriptor?: TypedPropertyDescriptor<NzSafeAny>\n  ): NzSafeAny {\n    const privatePropName = `$$__zorroPropDecorator__${propName}`;\n\n    if (Object.prototype.hasOwnProperty.call(target, privatePropName)) {\n      warn(`The prop \"${privatePropName}\" is already exist, it will be overrided by ${name} decorator.`);\n    }\n\n    Object.defineProperty(target, privatePropName, {\n      configurable: true,\n      writable: true\n    });\n\n    return {\n      get(): string {\n        return originalDescriptor && originalDescriptor.get\n          ? originalDescriptor.get.bind(this)()\n          : this[privatePropName];\n      },\n      set(value: T): void {\n        if (originalDescriptor && originalDescriptor.set) {\n          originalDescriptor.set.bind(this)(fallback(value));\n        }\n        this[privatePropName] = fallback(value);\n      }\n    };\n  }\n\n  return propDecorator;\n}\n\n/**\n * @deprecated Use input transform instead: `@Input({ transform })`\n *\n * Input decorator that handle a prop to do get/set automatically with toBoolean\n *\n * Why not using @InputBoolean alone without @Input? AOT needs @Input to be visible\n *\n * @howToUse\n * ```\n * @Input() @InputBoolean() visible: boolean = false;\n *\n * // Act as below:\n * // @Input()\n * // get visible() { return this.__visible; }\n * // set visible(value) { this.__visible = value; }\n * // __visible = false;\n * ```\n */\nexport function InputBoolean(): NzSafeAny {\n  return propDecoratorFactory('InputBoolean', toBoolean);\n}\n\n/**\n * @deprecated Use input transform instead: `@Input({ transform })`\n */\nexport function InputCssPixel(): NzSafeAny {\n  return propDecoratorFactory('InputCssPixel', toCssPixel);\n}\n\n/**\n * @deprecated Use input transform instead: `@Input({ transform })`\n */\nexport function InputNumber(fallbackValue?: NzSafeAny): NzSafeAny {\n  return propDecoratorFactory('InputNumber', (value: string | number) => toNumber(value, fallbackValue));\n}\n"
  },
  {
    "path": "components/core/util/dom.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\n/**\n * This module provides utility functions to query DOM information or\n * set properties.\n */\n\nimport { Observable } from 'rxjs';\n\n/**\n * Silent an event by stopping and preventing it.\n */\nexport function silentEvent(e: Event): void {\n  e.stopPropagation();\n  e.preventDefault();\n}\n\nexport function getElementOffset(elem: HTMLElement): { top: number; left: number } {\n  if (!elem.getClientRects().length) {\n    return { top: 0, left: 0 };\n  }\n\n  const rect = elem.getBoundingClientRect();\n  const win = elem.ownerDocument!.defaultView;\n  return {\n    top: rect.top + win!.pageYOffset,\n    left: rect.left + win!.pageXOffset\n  };\n}\n\n/**\n * Investigate if an event is a `TouchEvent`.\n */\nexport function isTouchEvent(event: MouseEvent | TouchEvent): event is TouchEvent {\n  return event.type.startsWith('touch');\n}\n\nexport function getEventPosition(event: MouseEvent | TouchEvent): MouseEvent | Touch {\n  return isTouchEvent(event) ? event.touches[0] || event.changedTouches[0] : event;\n}\n\nexport interface MouseTouchObserverConfig {\n  end: string;\n  move: string;\n  pluckKey: string[];\n  start: string;\n\n  end$?: Observable<Event>;\n  moveResolved$?: Observable<number>;\n  startPlucked$?: Observable<number>;\n\n  filter?(e: Event): boolean;\n}\n"
  },
  {
    "path": "components/core/util/dynamic-css.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\n/**\n * Sync from rc-util [https://github.com/react-component/util]\n */\nimport { canUseDom } from './can-use-dom';\n\nconst MARK_KEY = `rc-util-key` as NzSafeAny;\n\nfunction getMark({ mark }: Options = {}): string {\n  if (mark) {\n    return mark.startsWith('data-') ? mark : `data-${mark}`;\n  }\n  return MARK_KEY;\n}\n\ninterface Options {\n  attachTo?: Element;\n  cspNonce?: string | null;\n  prepend?: boolean;\n  mark?: string;\n}\n\nfunction getContainer(option: Options): HTMLElement | Element {\n  if (option.attachTo) {\n    return option.attachTo;\n  }\n\n  const head = document.querySelector('head');\n  return head || document.body;\n}\n\nexport function injectCSS(css: string, options: Options = {}): HTMLStyleElement | null {\n  if (!canUseDom()) {\n    return null;\n  }\n\n  const styleNode = document.createElement('style');\n  if (options.cspNonce) {\n    styleNode.nonce = options.cspNonce;\n  }\n  styleNode.innerHTML = css;\n\n  const container = getContainer(options);\n  const { firstChild } = container;\n\n  if (options.prepend && container.prepend) {\n    // Use `prepend` first\n    container.prepend(styleNode);\n  } else if (options.prepend && firstChild) {\n    // Fallback to `insertBefore` like IE not support `prepend`\n    container.insertBefore(styleNode, firstChild);\n  } else {\n    container.appendChild(styleNode);\n  }\n\n  return styleNode;\n}\n\nconst containerCache = new Map<Element, Node & ParentNode>();\n\nfunction findExistNode(key: string, option: Options = {}): HTMLStyleElement {\n  const container = getContainer(option);\n\n  return Array.from(containerCache.get(container)?.children || []).find(\n    node => node.tagName === 'STYLE' && node.getAttribute(getMark(option)) === key\n  ) as HTMLStyleElement;\n}\n\nexport function removeCSS(key: string, option: Options = {}): void {\n  const existNode = findExistNode(key, option);\n\n  existNode?.parentNode?.removeChild(existNode);\n}\n\nexport function updateCSS(css: string, key: string, options: Options = {}): HTMLStyleElement | null {\n  const container = getContainer(options);\n\n  // Get real parent\n  if (!containerCache.has(container)) {\n    const placeholderStyle = injectCSS('', options);\n    // @ts-ignore\n    const { parentNode } = placeholderStyle;\n    containerCache.set(container, parentNode);\n    parentNode.removeChild(placeholderStyle);\n  }\n\n  const existNode = findExistNode(key, options);\n\n  if (existNode) {\n    if (options.cspNonce && existNode.nonce !== options.cspNonce) {\n      existNode.nonce = options.cspNonce;\n    }\n\n    if (existNode.innerHTML !== css) {\n      existNode.innerHTML = css;\n    }\n\n    return existNode;\n  }\n\n  const newNode = injectCSS(css, options);\n  newNode?.setAttribute(getMark(options), key);\n  return newNode;\n}\n"
  },
  {
    "path": "components/core/util/encode-entities.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nconst SURROGATE_PAIR_REGEXP = /[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]/g;\n// ! to ~ is the ASCII range.\nconst NON_ALPHANUMERIC_REGEXP = /([^#-~ |!])/g;\n\n/**\n * Escapes all potentially dangerous characters, so that the\n * resulting string can be safely inserted into attribute or\n * element text.\n */\nexport function encodeEntities(value: string): string {\n  return value\n    .replace(/&/g, '&amp;')\n    .replace(SURROGATE_PAIR_REGEXP, (match: string) => {\n      const hi = match.charCodeAt(0);\n      const low = match.charCodeAt(1);\n      return `&#${(hi - 0xd800) * 0x400 + (low - 0xdc00) + 0x10000};`;\n    })\n    .replace(NON_ALPHANUMERIC_REGEXP, (match: string) => `&#${match.charCodeAt(0)};`)\n    .replace(/</g, '&lt;')\n    .replace(/>/g, '&gt;');\n}\n"
  },
  {
    "path": "components/core/util/ensure-in-bounds.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport function ensureInBounds(value: number, boundValue: number): number {\n  return value ? (value < boundValue ? value : boundValue) : boundValue;\n}\n"
  },
  {
    "path": "components/core/util/focus.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport interface InputFocusOptions extends FocusOptions {\n  cursor?: 'start' | 'end' | 'all';\n}\n\nexport function triggerFocus(element: HTMLInputElement | HTMLTextAreaElement, option?: InputFocusOptions): void {\n  element.focus(option);\n\n  // Selection content\n  const { cursor } = option || {};\n  if (cursor) {\n    const len = element.value.length;\n\n    switch (cursor) {\n      case 'start':\n        element.setSelectionRange(0, 0);\n        break;\n\n      case 'end':\n        element.setSelectionRange(len, len);\n        break;\n\n      default:\n        element.setSelectionRange(0, len);\n    }\n  }\n}\n"
  },
  {
    "path": "components/core/util/from-event-outside-angular.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, inject, NgZone, provideZoneChangeDetection } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { TestBed } from '@angular/core/testing';\nimport { fromEvent } from 'rxjs';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { fromEventOutsideAngular } from './from-event-outside-angular';\n\n@Component({\n  template: ``\n})\nclass TestComponent {\n  readonly recorder: NzSafeAny[] = [];\n\n  constructor() {\n    const ngZone = inject(NgZone);\n\n    ngZone.run(() => {\n      fromEvent(document, 'click')\n        .pipe(takeUntilDestroyed())\n        .subscribe(() => {\n          this.recorder.push(['fromEvent in zone: ', NgZone.isInAngularZone()]);\n        });\n\n      fromEventOutsideAngular(document, 'click')\n        .pipe(takeUntilDestroyed())\n        .subscribe(() => {\n          this.recorder.push(['fromEventOutsideAngular in zone: ', NgZone.isInAngularZone()]);\n        });\n    });\n  }\n}\n\ndescribe('fromEventOutsideAngular', () => {\n  it('should add event listener outside of the Angular zone', () => {\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n    const fixture = TestBed.createComponent(TestComponent);\n    document.body.click();\n    expect(fixture.componentInstance.recorder).toEqual([\n      ['fromEvent in zone: ', true],\n      ['fromEventOutsideAngular in zone: ', false]\n    ]);\n  });\n});\n"
  },
  {
    "path": "components/core/util/from-event-outside-angular.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { EMPTY, fromEvent, Observable } from 'rxjs';\n\n// This would be exposed in the global environment whenever `zone.js` is\n// included in the `polyfills` configuration property. Starting from Angular 17,\n// users can opt-in to use zoneless change detection.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ndeclare const Zone: any;\n\nfunction runOutsideAngular<T>(fn: () => T): T {\n  // The function that does the same job as `NgZone.runOutsideAngular`.\n  // The difference is that we don't need to rely on the `NgZone` service,\n  // allowing `fromEventOutsideAngular` to function without requiring an explicit\n  // injection context (where we might otherwise call `inject(NgZone)`).\n  return typeof Zone !== 'undefined' ? Zone.root.run(fn) : fn();\n}\n\n/**\n * This function replaces `runOutsideAngular` with `fromEvent`, introducing a\n * lot of boilerplate where we need to inject the `NgZone` service and then subscribe\n * to `fromEvent` within the `runOutsideAngular` callback.\n */\nexport function fromEventOutsideAngular<TEvent extends Event>(\n  target: EventTarget | null | undefined,\n  name: string,\n  options?: boolean | AddEventListenerOptions\n): Observable<TEvent> {\n  // Allow the event target to be nullable to avoid requiring callers to check\n  // if the target exists. We simply complete the observable immediately,\n  // as this might potentially be used within a `switchMap`.\n  if (!target) {\n    return EMPTY;\n  }\n\n  return new Observable<TEvent>(subscriber => {\n    // Note that we're wrapping fromEvent with an observable because `fromEvent`\n    // is eager and only calls `addEventListener` when a new subscriber comes in.\n    // Therefore, we're wrapping the subscription with `runOutsideAngular` to ensure\n    // that `addEventListener` is also called outside of Angular when there's a subscriber.\n    return runOutsideAngular(() =>\n      // Casting because the inferred overload is incorrect :(\n      fromEvent<TEvent>(target, name, options as AddEventListenerOptions).subscribe(subscriber)\n    );\n  });\n}\n"
  },
  {
    "path": "components/core/util/getMentions.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport function getRegExp(prefix: string | string[]): RegExp {\n  const prefixArray = Array.isArray(prefix) ? prefix : [prefix];\n  let prefixToken = prefixArray.join('').replace(/(\\$|\\^)/g, '\\\\$1');\n\n  if (prefixArray.length > 1) {\n    prefixToken = `[${prefixToken}]`;\n  }\n\n  return new RegExp(`(\\\\s|^)(${prefixToken})[^\\\\s]*`, 'g');\n}\n\nexport function getMentions(value: string, prefix: string | string[] = '@'): string[] {\n  if (typeof value !== 'string') {\n    return [];\n  }\n  const regex = getRegExp(prefix);\n  const mentions = value.match(regex);\n  return mentions !== null ? mentions.map(e => e.trim()) : [];\n}\n"
  },
  {
    "path": "components/core/util/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/core/util/is-promise.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nexport function isPromise<T>(obj: NzSafeAny): obj is Promise<T> {\n  return !!obj && typeof obj.then === 'function' && typeof obj.catch === 'function';\n}\n"
  },
  {
    "path": "components/core/util/measure-scrollbar.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nlet scrollbarVerticalSize: number;\nlet scrollbarHorizontalSize: number;\n\n// Measure scrollbar width for padding body during modal show/hide\nconst scrollbarMeasure = {\n  position: 'absolute',\n  top: '-9999px',\n  width: '50px',\n  height: '50px'\n};\n\nexport function measureScrollbar(direction: 'vertical' | 'horizontal' = 'vertical', prefix: string = 'ant'): number {\n  if (typeof document === 'undefined' || typeof window === 'undefined') {\n    return 0;\n  }\n  const isVertical = direction === 'vertical';\n  if (isVertical && scrollbarVerticalSize) {\n    return scrollbarVerticalSize;\n  } else if (!isVertical && scrollbarHorizontalSize) {\n    return scrollbarHorizontalSize;\n  }\n  const scrollDiv = document.createElement('div');\n  Object.keys(scrollbarMeasure).forEach(scrollProp => {\n    // @ts-ignore\n    scrollDiv.style[scrollProp] = scrollbarMeasure[scrollProp];\n  });\n  // apply hide scrollbar className ahead\n  scrollDiv.className = `${prefix}-hide-scrollbar scroll-div-append-to-body`;\n  // Append related overflow style\n  if (isVertical) {\n    scrollDiv.style.overflowY = 'scroll';\n  } else {\n    scrollDiv.style.overflowX = 'scroll';\n  }\n  document.body.appendChild(scrollDiv);\n  let size = 0;\n  if (isVertical) {\n    size = scrollDiv.offsetWidth - scrollDiv.clientWidth;\n    scrollbarVerticalSize = size;\n  } else {\n    size = scrollDiv.offsetHeight - scrollDiv.clientHeight;\n    scrollbarHorizontalSize = size;\n  }\n\n  document.body.removeChild(scrollDiv);\n  return size;\n}\n"
  },
  {
    "path": "components/core/util/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/core/util/number.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nexport function getPercent(min: number, max: number, value: number): number {\n  return ((value - min) / (max - min)) * 100;\n}\n\nexport function getPrecision(num: number): number {\n  const numStr = num.toString();\n  const dotIndex = numStr.indexOf('.');\n  return dotIndex >= 0 ? numStr.length - dotIndex - 1 : 0;\n}\n\nexport function ensureNumberInRange(num: number, min: number, max: number): number {\n  if (isNaN(num) || num < min) {\n    return min;\n  } else if (num > max) {\n    return max;\n  } else {\n    return num;\n  }\n}\n\nexport function isNumberFinite(value: NzSafeAny): boolean {\n  return typeof value === 'number' && isFinite(value);\n}\n\nexport function toDecimal(value: number, decimal: number): number {\n  return Math.round(value * Math.pow(10, decimal)) / Math.pow(10, decimal);\n}\n\nexport function sum(input: number[], initial: number = 0): number {\n  return input.reduce((previous: number, current: number) => previous + current, initial);\n}\n"
  },
  {
    "path": "components/core/util/observable.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { isObservable, Observable, of } from 'rxjs';\n\nimport { isPromise } from './is-promise';\n\nexport function wrapIntoObservable<T>(value: T | Promise<T> | Observable<T>): Observable<T> {\n  if (isObservable(value)) {\n    return value;\n  }\n\n  if (isPromise(value)) {\n    // Not using `from()` because it includes support for many input types\n    // (iterables, async generators, observables, etc.),\n    // which increases bundle size. We're only handling Promises here, so a\n    // minimal wrapper is used instead.\n    return new Observable<T>(subscriber => {\n      // Use `Promise.resolve()` to wrap promise-like instances.\n      Promise.resolve(value)\n        .then(result => {\n          subscriber.next(result);\n          subscriber.complete();\n        })\n        .catch(error => subscriber.error(error));\n    });\n  }\n\n  return of(value);\n}\n"
  },
  {
    "path": "components/core/util/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './array';\nexport * from './check';\nexport * from './convert';\nexport * from './dom';\nexport * from './getMentions';\nexport * from './string';\nexport * from './is-promise';\nexport * from './number';\nexport * from './scroll-into-view-if-needed';\nexport * from './textarea-caret-position';\nexport * from './style';\nexport * from './text-measure';\nexport * from './measure-scrollbar';\nexport * from './ensure-in-bounds';\nexport * from './tick';\nexport * from './observable';\nexport * from './can-use-dom';\nexport * from './dynamic-css';\nexport * from './status-util';\nexport * from './from-event-outside-angular';\nexport * from './variant-utils';\nexport * from './encode-entities';\nexport * from './class-name';\nexport * from './focus';\n"
  },
  {
    "path": "components/core/util/scroll-into-view-if-needed.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nexport function scrollIntoView(node: HTMLElement): void {\n  const nodeAsAny = node as NzSafeAny;\n  if (nodeAsAny.scrollIntoViewIfNeeded) {\n    nodeAsAny.scrollIntoViewIfNeeded(false);\n    return;\n  }\n  if (node.scrollIntoView) {\n    node.scrollIntoView(false);\n    return;\n  }\n}\n"
  },
  {
    "path": "components/core/util/status-util.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgClassInterface, NzValidateStatus } from 'ng-zorro-antd/core/types';\n\nexport function getStatusClassNames(\n  prefixCls: string,\n  status?: NzValidateStatus,\n  hasFeedback?: boolean\n): NgClassInterface {\n  return {\n    [`${prefixCls}-status-success`]: status === 'success',\n    [`${prefixCls}-status-warning`]: status === 'warning',\n    [`${prefixCls}-status-error`]: status === 'error',\n    [`${prefixCls}-status-validating`]: status === 'validating',\n    [`${prefixCls}-has-feedback`]: hasFeedback\n  };\n}\n"
  },
  {
    "path": "components/core/util/string.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\n/**\n * Much like lodash.\n */\nexport function padStart(toPad: string, length: number, element: string): string {\n  if (toPad.length > length) {\n    return toPad;\n  }\n\n  const joined = `${getRepeatedElement(length, element)}${toPad}`;\n  return joined.slice(joined.length - length, joined.length);\n}\n\nexport function padEnd(toPad: string, length: number, element: string): string {\n  const joined = `${toPad}${getRepeatedElement(length, element)}`;\n  return joined.slice(0, length);\n}\n\nexport function getRepeatedElement(length: number, element: string): string {\n  return Array(length).fill(element).join('');\n}\n"
  },
  {
    "path": "components/core/util/style.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgStyleInterface } from 'ng-zorro-antd/core/types';\n\nexport function isStyleSupport(styleName: string | string[]): boolean {\n  if (typeof window !== 'undefined' && window.document && window.document.documentElement) {\n    const styleNameList = Array.isArray(styleName) ? styleName : [styleName];\n    const { documentElement } = window.document;\n\n    return styleNameList.some(name => name in documentElement.style);\n  }\n  return false;\n}\n\nexport function getStyleAsText(styles?: NgStyleInterface): string {\n  if (!styles) {\n    return '';\n  }\n\n  return Object.keys(styles)\n    .map(key => {\n      const val = styles[key];\n      return `${key}:${typeof val === 'string' ? val : `${val}px`}`;\n    })\n    .join(';');\n}\n"
  },
  {
    "path": "components/core/util/text-measure.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nexport interface MeasureResult {\n  finished: boolean;\n  node: Node | null;\n}\n\n// We only handle element & text node.\nconst ELEMENT_NODE = 1;\nconst TEXT_NODE = 3;\nconst COMMENT_NODE = 8;\n\nlet ellipsisContainer: HTMLParagraphElement;\n\nconst wrapperStyle = {\n  padding: '0',\n  margin: '0',\n  display: 'inline',\n  lineHeight: 'inherit'\n};\n\nexport function pxToNumber(value: string | null): number {\n  if (!value) {\n    return 0;\n  }\n\n  const match = value.match(/^\\d*(\\.\\d*)?/);\n\n  return match ? Number(match[0]) : 0;\n}\n\nfunction styleToObject(style: CSSStyleDeclaration): Record<string, string> {\n  // There are some different behavior between Firefox & Chrome.\n  // We have to handle this ourself.\n  const styles: Record<string, string> = {};\n  const styleNames: string[] = Array.prototype.slice.apply(style);\n  for (const name of styleNames) {\n    styles[name] = style.getPropertyValue(name);\n  }\n  return styles;\n}\n\nfunction mergeChildren(children: Node[]): Node[] {\n  const childList: Node[] = [];\n\n  children.forEach((child: Node) => {\n    const prevChild = childList[childList.length - 1];\n    if (prevChild && child.nodeType === TEXT_NODE && prevChild.nodeType === TEXT_NODE) {\n      (prevChild as Text).data += (child as Text).data;\n    } else {\n      childList.push(child);\n    }\n  });\n\n  return childList;\n}\n\nexport function measure(\n  originEle: HTMLElement,\n  rows: number,\n  contentNodes: Node[],\n  fixedContent: HTMLElement[],\n  ellipsisStr: string,\n  suffixStr: string = ''\n): { contentNodes: Node[]; text: string; ellipsis: boolean } {\n  if (!ellipsisContainer) {\n    ellipsisContainer = document.createElement('div');\n    ellipsisContainer.setAttribute('aria-hidden', 'true');\n    document.body.appendChild(ellipsisContainer);\n  }\n\n  // Get origin style\n  const originStyle = window.getComputedStyle(originEle);\n  const originCSS = styleToObject(originStyle);\n  const lineHeight = pxToNumber(originStyle.lineHeight);\n  const maxHeight = Math.round(\n    lineHeight * (rows + 1) + pxToNumber(originStyle.paddingTop) + pxToNumber(originStyle.paddingBottom)\n  );\n  // Set shadow\n  for (const [name, value] of Object.entries(originCSS)) {\n    // setAttribute('style', ...) is not allowed when strict CSP is in place.\n    ellipsisContainer.style.setProperty(name, value);\n  }\n  ellipsisContainer.style.position = 'fixed';\n  ellipsisContainer.style.left = '0';\n  ellipsisContainer.style.height = 'auto';\n  ellipsisContainer.style.minHeight = 'auto';\n  ellipsisContainer.style.maxHeight = 'auto';\n  ellipsisContainer.style.top = '-999999px';\n  ellipsisContainer.style.zIndex = '-1000';\n\n  // clean up css overflow\n  ellipsisContainer.style.textOverflow = 'clip';\n  ellipsisContainer.style.whiteSpace = 'normal';\n  (ellipsisContainer.style as NzSafeAny).webkitLineClamp = 'none';\n\n  const contentList = mergeChildren(contentNodes);\n  const container = document.createElement('div');\n  const contentContainer = document.createElement('span');\n  const suffixContainer = document.createTextNode(suffixStr);\n  const fixedContainer = document.createElement('span');\n\n  // Add styles in container\n  Object.assign(container.style, wrapperStyle);\n  Object.assign(contentContainer.style, wrapperStyle);\n  Object.assign(fixedContainer.style, wrapperStyle);\n\n  contentList.forEach(n => {\n    contentContainer.appendChild(n);\n  });\n\n  contentContainer.appendChild(suffixContainer);\n\n  fixedContent.forEach(node => {\n    fixedContainer.appendChild(node.cloneNode(true));\n  });\n  container.appendChild(contentContainer);\n  container.appendChild(fixedContainer);\n\n  // Render in the fake container\n  ellipsisContainer.appendChild(container);\n\n  // Check if ellipsis in measure div is height enough for content\n  function inRange(): boolean {\n    return ellipsisContainer.offsetHeight < maxHeight;\n  }\n\n  if (inRange()) {\n    const text = ellipsisContainer.innerHTML;\n    ellipsisContainer.removeChild(container);\n    return { contentNodes, text, ellipsis: false };\n  }\n\n  // We should clone the childNode since they're controlled by React and we can't reuse it without warning\n  const childNodes: ChildNode[] = Array.prototype.slice\n    .apply(ellipsisContainer.childNodes[0].childNodes[0].cloneNode(true).childNodes)\n    .filter(({ nodeType }: ChildNode) => nodeType !== COMMENT_NODE);\n  const fixedNodes: ChildNode[] = Array.prototype.slice.apply(\n    ellipsisContainer.childNodes[0].childNodes[1].cloneNode(true).childNodes\n  );\n  ellipsisContainer.removeChild(container);\n\n  // ========================= Find match ellipsis content =========================\n  ellipsisContainer.innerHTML = '';\n\n  // Create origin content holder\n  const ellipsisContentHolder = document.createElement('span');\n  ellipsisContainer.appendChild(ellipsisContentHolder);\n  const ellipsisTextNode = document.createTextNode(ellipsisStr + suffixStr);\n  ellipsisContentHolder.appendChild(ellipsisTextNode);\n\n  fixedNodes.forEach(childNode => {\n    ellipsisContainer.appendChild(childNode);\n  });\n\n  // Append before fixed nodes\n  function appendChildNode(node: ChildNode): void {\n    ellipsisContentHolder.insertBefore(node, ellipsisTextNode);\n  }\n\n  // Get maximum text\n  function measureText(\n    textNode: Text,\n    fullText: string,\n    startLoc: number = 0,\n    endLoc: number = fullText.length,\n    lastSuccessLoc: number = 0\n  ): MeasureResult {\n    const midLoc = Math.floor((startLoc + endLoc) / 2);\n    textNode.textContent = fullText.slice(0, midLoc);\n\n    if (startLoc >= endLoc - 1) {\n      // Loop when step is small\n      for (let step = endLoc; step >= startLoc; step -= 1) {\n        const currentStepText = fullText.slice(0, step);\n        textNode.textContent = currentStepText;\n\n        if (inRange() || !currentStepText) {\n          return step === fullText.length\n            ? {\n                finished: false,\n                node: document.createTextNode(fullText)\n              }\n            : {\n                finished: true,\n                node: document.createTextNode(currentStepText)\n              };\n        }\n      }\n    }\n    if (inRange()) {\n      return measureText(textNode, fullText, midLoc, endLoc, midLoc);\n    } else {\n      return measureText(textNode, fullText, startLoc, midLoc, lastSuccessLoc);\n    }\n  }\n\n  function measureNode(childNode: ChildNode, index: number): MeasureResult {\n    const type = childNode.nodeType;\n\n    if (type === ELEMENT_NODE) {\n      // We don't split element, it will keep if whole element can be displayed.\n      // appendChildNode(childNode);\n      if (inRange()) {\n        return {\n          finished: false,\n          node: contentList[index]\n        };\n      }\n\n      // Clean up if can not pull in\n      ellipsisContentHolder.removeChild(childNode);\n      return {\n        finished: true,\n        node: null\n      };\n    } else if (type === TEXT_NODE) {\n      const fullText = childNode.textContent || '';\n      const textNode = document.createTextNode(fullText);\n      appendChildNode(textNode);\n      return measureText(textNode, fullText);\n    }\n\n    // Not handle other type of content\n    // PS: This code should not be attached after react 16\n    return {\n      finished: false,\n      node: null\n    };\n  }\n\n  const ellipsisNodes: Node[] = [];\n  childNodes.some((childNode, index) => {\n    const { finished, node } = measureNode(childNode, index);\n    if (node) {\n      ellipsisNodes.push(node);\n    }\n    return finished;\n  });\n  const result = {\n    contentNodes: ellipsisNodes,\n    text: ellipsisContainer.innerHTML,\n    ellipsis: true\n  };\n  while (ellipsisContainer.firstChild) {\n    ellipsisContainer.removeChild(ellipsisContainer.firstChild);\n  }\n  return result;\n}\n"
  },
  {
    "path": "components/core/util/text-mesure.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { pxToNumber } from './text-measure';\n\ndescribe('pxToNumber', () => {\n  it('should return 0 when value is null', () => {\n    expect(pxToNumber(null)).toBe(0);\n  });\n});\n"
  },
  {
    "path": "components/core/util/textarea-caret-position.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\n// from https://github.com/component/textarea-caret-position\n\n// We'll copy the properties below into the mirror div.\n// Note that some browsers, such as Firefox, do not concatenate properties\n// into their shorthand (e.g. padding-top, padding-bottom etc. -> padding),\n// so we have to list every single property explicitly.\nexport const properties = [\n  'direction', // RTL support\n  'boxSizing',\n  'width', // on Chrome and IE, exclude the scrollbar, so the mirror div wraps exactly as the textarea does\n  'height',\n  'overflowX',\n  'overflowY', // copy the scrollbar for IE\n\n  'borderTopWidth',\n  'borderRightWidth',\n  'borderBottomWidth',\n  'borderLeftWidth',\n  'borderStyle',\n\n  'paddingTop',\n  'paddingRight',\n  'paddingBottom',\n  'paddingLeft',\n\n  // https://developer.mozilla.org/en-US/docs/Web/CSS/font\n  'fontStyle',\n  'fontVariant',\n  'fontWeight',\n  'fontStretch',\n  'fontSize',\n  'fontSizeAdjust',\n  'lineHeight',\n  'fontFamily',\n\n  'textAlign',\n  'textTransform',\n  'textIndent',\n  'textDecoration', // might not make a difference, but better be safe\n\n  'letterSpacing',\n  'wordSpacing',\n\n  'tabSize',\n  'MozTabSize'\n];\n\nconst isBrowser = typeof window !== 'undefined';\n\nconst isFirefox = isBrowser && (window as NzSafeAny).mozInnerScreenX != null;\n\nconst _parseInt = (str: string): number => parseInt(str, 10);\n\nexport interface Coordinates {\n  top: number;\n  left: number;\n  height: number;\n}\n\nexport function getCaretCoordinates(\n  element: HTMLInputElement | HTMLTextAreaElement,\n  position: number,\n  options?: { debug?: boolean }\n): Coordinates {\n  if (!isBrowser) {\n    throw new Error('textarea-caret-position#getCaretCoordinates should only be called in a browser');\n  }\n\n  const debug = (options && options.debug) || false;\n  if (debug) {\n    const el = document.querySelector('#input-textarea-caret-position-mirror-div');\n    if (el) {\n      el.parentNode!.removeChild(el);\n    }\n  }\n\n  // The mirror div will replicate the textarea's style\n  const div = document.createElement('div');\n  div.id = 'input-textarea-caret-position-mirror-div';\n  document.body.appendChild(div);\n\n  const style = div.style;\n\n  const computed = window.getComputedStyle ? window.getComputedStyle(element) : (element as NzSafeAny).currentStyle; // currentStyle for IE < 9\n  const isInput = element.nodeName === 'INPUT';\n\n  // Default textarea styles\n  style.whiteSpace = 'pre-wrap';\n  if (!isInput) {\n    style.wordWrap = 'break-word'; // only for textarea-s\n  }\n\n  // Position off-screen\n  style.position = 'absolute'; // required to return coordinates properly\n  if (!debug) {\n    style.visibility = 'hidden';\n  } // not 'display: none' because we want rendering\n\n  // Transfer the element's properties to the div\n  properties.forEach((prop: string) => {\n    if (isInput && prop === 'lineHeight') {\n      // Special case for <input>s because text is rendered centered and line height may be != height\n      style.lineHeight = computed.height;\n    } else {\n      // @ts-ignore\n      style[prop] = computed[prop];\n    }\n  });\n\n  if (isFirefox) {\n    // Firefox lies about the overflow property for textareas: https://bugzilla.mozilla.org/show_bug.cgi?id=984275\n    if (element.scrollHeight > _parseInt(computed.height)) {\n      style.overflowY = 'scroll';\n    }\n  } else {\n    style.overflow = 'hidden'; // for Chrome to not render a scrollbar; IE keeps overflowY = 'scroll'\n  }\n\n  div.textContent = element.value.substring(0, position);\n  // The second special handling for input type=\"text\" vs textarea:\n  // spaces need to be replaced with non-breaking spaces - http://stackoverflow.com/a/13402035/1269037\n  if (isInput) {\n    div.textContent = div.textContent.replace(/\\s/g, '\\u00a0');\n  }\n\n  const span = document.createElement('span');\n  // Wrapping must be replicated *exactly*, including when a long word gets\n  // onto the next line, with whitespace at the end of the line before (#7).\n  // The  *only* reliable way to do that is to copy the *entire* rest of the\n  // textarea's content into the <span> created at the caret position.\n  // For inputs, just '.' would be enough, but no need to bother.\n  span.textContent = element.value.substring(position) || '.'; // || because a completely empty faux span doesn't render at all\n  div.appendChild(span);\n\n  const coordinates = {\n    top: span.offsetTop + _parseInt(computed.borderTopWidth),\n    left: span.offsetLeft + _parseInt(computed.borderLeftWidth),\n    height: _parseInt(computed.lineHeight)\n  };\n\n  if (debug) {\n    span.style.backgroundColor = '#eee';\n    createDebugEle(element, coordinates);\n  } else {\n    document.body.removeChild(div);\n  }\n\n  return coordinates;\n}\n\nexport function createDebugEle(element: HTMLInputElement | HTMLTextAreaElement, coordinates: Coordinates): void {\n  const fontSize = getComputedStyle(element).getPropertyValue('font-size');\n  const rect: HTMLSpanElement = (document.querySelector('#DEBUG') as HTMLSpanElement) || document.createElement('div');\n  document.body.appendChild(rect);\n  rect.id = 'DEBUG';\n  rect.style.position = 'absolute';\n  rect.style.backgroundColor = 'red';\n  rect.style.height = fontSize;\n  rect.style.width = '1px';\n  rect.style.top = `${\n    element.getBoundingClientRect().top - element.scrollTop + window.pageYOffset + coordinates.top\n  }px`;\n  rect.style.left = `${\n    element.getBoundingClientRect().left - element.scrollLeft + window.pageXOffset + coordinates.left\n  }px`;\n}\n"
  },
  {
    "path": "components/core/util/tick.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Observable, Subject } from 'rxjs';\nimport { take } from 'rxjs/operators';\n\nexport function inNextTick(): Observable<void> {\n  const timer = new Subject<void>();\n  Promise.resolve().then(() => timer.next());\n  return timer.pipe(take(1));\n}\n"
  },
  {
    "path": "components/core/util/variant-utils.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgClassInterface, NzVariant } from 'ng-zorro-antd/core/types';\n\nexport function getVariantClassNames(prefixCls: string, variant?: NzVariant, borderless?: boolean): NgClassInterface {\n  return {\n    [`${prefixCls}-borderless`]: variant === 'borderless' || (variant === 'outlined' && borderless),\n    [`${prefixCls}-filled`]: variant === 'filled',\n    [`${prefixCls}-underlined`]: variant === 'underlined'\n  };\n}\n"
  },
  {
    "path": "components/core/wave/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/core/wave/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/core/wave/nz-wave-renderer.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Platform } from '@angular/cdk/platform';\nimport { NgZone } from '@angular/core';\n\nexport class NzWaveRenderer {\n  private waveTransitionDuration = 400;\n  private styleForPseudo: HTMLStyleElement | null = null;\n  private extraNode: HTMLDivElement | null = null;\n  private lastTime = 0;\n  clickHandler: (event: MouseEvent) => void;\n  get waveAttributeName(): string {\n    return this.insertExtraNode ? 'ant-click-animating' : 'ant-click-animating-without-extra-node';\n  }\n\n  constructor(\n    private triggerElement: HTMLElement,\n    private ngZone: NgZone,\n    private insertExtraNode: boolean,\n    private platform: Platform,\n    private cspNonce?: string | null\n  ) {\n    this.clickHandler = this.onClick.bind(this);\n    this.bindTriggerEvent();\n  }\n\n  onClick = (event: MouseEvent): void => {\n    if (\n      !this.triggerElement ||\n      !this.triggerElement.getAttribute ||\n      this.triggerElement.getAttribute('disabled') ||\n      (event.target as HTMLElement).tagName === 'INPUT' ||\n      this.triggerElement.className.indexOf('disabled') >= 0\n    ) {\n      return;\n    }\n    this.fadeOutWave();\n  };\n\n  bindTriggerEvent(): void {\n    if (this.platform.isBrowser) {\n      this.ngZone.runOutsideAngular(() => {\n        this.removeTriggerEvent();\n        if (this.triggerElement) {\n          this.triggerElement.addEventListener('click', this.clickHandler, true);\n        }\n      });\n    }\n  }\n\n  removeTriggerEvent(): void {\n    if (this.triggerElement) {\n      this.triggerElement.removeEventListener('click', this.clickHandler, true);\n    }\n  }\n\n  removeStyleAndExtraNode(): void {\n    if (this.styleForPseudo && document.body.contains(this.styleForPseudo)) {\n      document.body.removeChild(this.styleForPseudo);\n      this.styleForPseudo = null;\n    }\n    if (this.insertExtraNode && this.triggerElement.contains(this.extraNode)) {\n      this.triggerElement.removeChild(this.extraNode as Node);\n    }\n  }\n\n  destroy(): void {\n    this.removeTriggerEvent();\n    this.removeStyleAndExtraNode();\n  }\n\n  private fadeOutWave(): void {\n    const node = this.triggerElement;\n    const waveColor = this.getWaveColor(node);\n    node.setAttribute(this.waveAttributeName, 'true');\n    if (Date.now() < this.lastTime + this.waveTransitionDuration) {\n      return;\n    }\n\n    if (this.isValidColor(waveColor)) {\n      if (!this.styleForPseudo) {\n        this.styleForPseudo = document.createElement('style');\n        if (this.cspNonce) {\n          this.styleForPseudo.nonce = this.cspNonce;\n        }\n      }\n\n      this.styleForPseudo.innerHTML = `\n      [ant-click-animating-without-extra-node='true']::after, .ant-click-animating-node {\n        --antd-wave-shadow-color: ${waveColor};\n      }`;\n      document.body.appendChild(this.styleForPseudo);\n    }\n\n    if (this.insertExtraNode) {\n      if (!this.extraNode) {\n        this.extraNode = document.createElement('div');\n      }\n      this.extraNode.className = 'ant-click-animating-node';\n      node.appendChild(this.extraNode);\n    }\n\n    this.lastTime = Date.now();\n\n    this.runTimeoutOutsideZone(() => {\n      node.removeAttribute(this.waveAttributeName);\n      this.removeStyleAndExtraNode();\n    }, this.waveTransitionDuration);\n  }\n\n  private isValidColor(color: string): boolean {\n    return (\n      !!color &&\n      color !== '#ffffff' &&\n      color !== 'rgb(255, 255, 255)' &&\n      this.isNotGrey(color) &&\n      !/rgba\\(\\d*, \\d*, \\d*, 0\\)/.test(color) &&\n      color !== 'transparent'\n    );\n  }\n\n  private isNotGrey(color: string): boolean {\n    const match = color.match(/rgba?\\((\\d*), (\\d*), (\\d*)(, [.\\d]*)?\\)/);\n    if (match && match[1] && match[2] && match[3]) {\n      return !(match[1] === match[2] && match[2] === match[3]);\n    }\n    return true;\n  }\n\n  private getWaveColor(node: HTMLElement): string {\n    const nodeStyle = getComputedStyle(node);\n    return (\n      nodeStyle.getPropertyValue('border-top-color') || // Firefox Compatible\n      nodeStyle.getPropertyValue('border-color') ||\n      nodeStyle.getPropertyValue('background-color')\n    );\n  }\n\n  private runTimeoutOutsideZone(fn: () => void, delay: number): void {\n    this.ngZone.runOutsideAngular(() => setTimeout(fn, delay));\n  }\n}\n"
  },
  {
    "path": "components/core/wave/nz-wave.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Platform } from '@angular/cdk/platform';\nimport {\n  ANIMATION_MODULE_TYPE,\n  CSP_NONCE,\n  Directive,\n  ElementRef,\n  EnvironmentProviders,\n  InjectionToken,\n  Input,\n  NgZone,\n  OnDestroy,\n  OnInit,\n  inject,\n  makeEnvironmentProviders\n} from '@angular/core';\n\nimport { NzWaveRenderer } from './nz-wave-renderer';\n\nexport interface NzWaveConfig {\n  disabled?: boolean;\n}\n\nexport const NZ_WAVE_GLOBAL_DEFAULT_CONFIG: NzWaveConfig = {\n  disabled: false\n};\n\nexport const NZ_WAVE_GLOBAL_CONFIG = new InjectionToken<NzWaveConfig>(\n  typeof ngDevMode !== 'undefined' && ngDevMode ? 'nz-wave-global-options' : ''\n);\n\nexport function provideNzWave(config: NzWaveConfig): EnvironmentProviders {\n  return makeEnvironmentProviders([{ provide: NZ_WAVE_GLOBAL_CONFIG, useValue: config }]);\n}\n\n@Directive({\n  selector: '[nz-wave],button[nz-button]:not([nzType=\"link\"]):not([nzType=\"text\"])',\n  exportAs: 'nzWave'\n})\nexport class NzWaveDirective implements OnInit, OnDestroy {\n  @Input() nzWaveExtraNode = false;\n\n  private waveRenderer?: NzWaveRenderer;\n  private waveDisabled: boolean = false;\n\n  get disabled(): boolean {\n    return this.waveDisabled;\n  }\n\n  get rendererRef(): NzWaveRenderer | undefined {\n    return this.waveRenderer;\n  }\n\n  private cspNonce = inject(CSP_NONCE, { optional: true });\n  private platform = inject(Platform);\n  private config = inject(NZ_WAVE_GLOBAL_CONFIG, { optional: true });\n  private animationType = inject(ANIMATION_MODULE_TYPE, { optional: true });\n  private ngZone = inject(NgZone);\n  private elementRef = inject(ElementRef<HTMLElement>);\n\n  constructor() {\n    this.waveDisabled = this.isConfigDisabled();\n  }\n\n  isConfigDisabled(): boolean {\n    let disabled = false;\n    if (this.config && typeof this.config.disabled === 'boolean') {\n      disabled = this.config.disabled;\n    }\n    if (this.animationType === 'NoopAnimations') {\n      disabled = true;\n    }\n    return disabled;\n  }\n\n  ngOnDestroy(): void {\n    if (this.waveRenderer) {\n      this.waveRenderer.destroy();\n    }\n  }\n\n  ngOnInit(): void {\n    this.renderWaveIfEnabled();\n  }\n\n  renderWaveIfEnabled(): void {\n    if (!this.waveDisabled && this.elementRef.nativeElement) {\n      this.waveRenderer = new NzWaveRenderer(\n        this.elementRef.nativeElement,\n        this.ngZone,\n        this.nzWaveExtraNode,\n        this.platform,\n        this.cspNonce\n      );\n    }\n  }\n\n  disable(): void {\n    this.waveDisabled = true;\n    if (this.waveRenderer) {\n      this.waveRenderer.removeTriggerEvent();\n      this.waveRenderer.removeStyleAndExtraNode();\n    }\n  }\n\n  enable(): void {\n    // config priority\n    this.waveDisabled = this.isConfigDisabled() || false;\n    if (this.waveRenderer) {\n      this.waveRenderer.bindTriggerEvent();\n    }\n  }\n}\n"
  },
  {
    "path": "components/core/wave/nz-wave.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NZ_WAVE_GLOBAL_DEFAULT_CONFIG, NzWaveDirective, provideNzWave } from './nz-wave.directive';\n\n@NgModule({\n  imports: [NzWaveDirective],\n  exports: [NzWaveDirective],\n  providers: [provideNzWave(NZ_WAVE_GLOBAL_DEFAULT_CONFIG)]\n})\nexport class NzWaveModule {}\n"
  },
  {
    "path": "components/core/wave/nz-wave.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, ElementRef, provideZoneChangeDetection, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { dispatchMouseEvent } from 'ng-zorro-antd/core/testing';\n\nimport { NzWaveDirective } from './nz-wave.directive';\nimport { NzWaveModule } from './nz-wave.module';\n\nconst WAVE_ATTRIBUTE_NAME = 'ant-click-animating-without-extra-node';\nconst WAVE_ATTRIBUTE_NAME_EXTRA_NODE = 'ant-click-animating';\nconst EXTRA_NODE_CLASS_NAME = '.ant-click-animating-node';\n\ndescribe('nz-wave basic', () => {\n  let fixture: ComponentFixture<WaveContainerWithButtonComponent>;\n  let waveTarget: HTMLElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(WaveContainerWithButtonComponent);\n    fixture.detectChanges();\n    waveTarget = fixture.componentInstance.trigger.nativeElement;\n  });\n\n  it('should create wave on click', () => {\n    dispatchMouseEvent(waveTarget, 'click');\n    expect(waveTarget.hasAttribute(WAVE_ATTRIBUTE_NAME)).toBe(true);\n    expect(document.body.querySelector('style') !== null).toBe(true);\n  });\n\n  it('should remove wave when transition end', fakeAsync(() => {\n    dispatchMouseEvent(waveTarget, 'click');\n    expect(waveTarget.hasAttribute(WAVE_ATTRIBUTE_NAME)).toBe(true);\n    expect(document.body.querySelector('style') !== null).toBe(true);\n    tick(500);\n    expect(waveTarget.hasAttribute(WAVE_ATTRIBUTE_NAME)).toBe(false);\n    expect(document.body.querySelector('style') !== null).toBe(false);\n  }));\n\n  it('should throttling when clicks', () => {\n    dispatchMouseEvent(waveTarget, 'click');\n    fixture.detectChanges();\n    dispatchMouseEvent(waveTarget, 'click');\n    fixture.detectChanges();\n    dispatchMouseEvent(waveTarget, 'click');\n    fixture.detectChanges();\n    expect(document.body.querySelectorAll('style').length).toBe(1);\n  });\n\n  it('should not create wave on click when disabled', () => {\n    fixture.componentInstance.disabled = true;\n    fixture.detectChanges();\n    dispatchMouseEvent(waveTarget, 'click');\n    fixture.detectChanges();\n    expect(waveTarget.hasAttribute(WAVE_ATTRIBUTE_NAME)).toBe(false);\n    expect(document.body.querySelector('style') !== null).toBe(false);\n  });\n\n  it('should not create wave on click when has disabled class', () => {\n    fixture.componentInstance.disabledClass = true;\n    fixture.detectChanges();\n    dispatchMouseEvent(waveTarget, 'click');\n    expect(waveTarget.hasAttribute(WAVE_ATTRIBUTE_NAME)).toBe(false);\n    expect(document.body.querySelector('style') !== null).toBe(false);\n  });\n\n  it('should not create wave style on click when invalid color', () => {\n    fixture.componentInstance.borderColor = '#ffffff';\n    fixture.detectChanges();\n    dispatchMouseEvent(waveTarget, 'click');\n    expect(document.body.querySelector('style') !== null).toBe(false);\n  });\n\n  it('should priority use border-color color', () => {\n    fixture.componentInstance.borderColor = 'rgb(255, 255, 0)';\n    fixture.componentInstance.backgroundColor = 'rgb(255, 0, 0)';\n    fixture.detectChanges();\n    dispatchMouseEvent(waveTarget, 'click');\n    const style: string = document.body.querySelector('style')!.innerText;\n    expect(style.includes(fixture.componentInstance.borderColor)).toBe(true);\n  });\n\n  it('should not create wave style on click when grey color', () => {\n    fixture.componentInstance.borderColor = '#eee';\n    fixture.detectChanges();\n    dispatchMouseEvent(waveTarget, 'click');\n    expect(document.body.querySelector('style') !== null).toBe(false);\n  });\n\n  it('should destroy', () => {\n    dispatchMouseEvent(waveTarget, 'click');\n    expect(waveTarget.hasAttribute(WAVE_ATTRIBUTE_NAME)).toBe(true);\n    expect(document.body.querySelector('style') !== null).toBe(true);\n\n    fixture.componentInstance.isDestroyed = true;\n    fixture.detectChanges();\n\n    expect(document.body.querySelector('style') !== null).toBe(false);\n  });\n});\n\ndescribe('nz-wave extra', () => {\n  let fixture: ComponentFixture<WaveContainerWithExtraNodeComponent>;\n  let waveTarget: HTMLElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(WaveContainerWithExtraNodeComponent);\n    fixture.detectChanges();\n    waveTarget = fixture.componentInstance.trigger.nativeElement;\n  });\n\n  it('should create wave on click', () => {\n    dispatchMouseEvent(waveTarget, 'click');\n    expect(waveTarget.hasAttribute(WAVE_ATTRIBUTE_NAME_EXTRA_NODE)).toBe(true);\n    expect(document.body.querySelector('style') !== null).toBe(true);\n    expect(waveTarget.querySelector(EXTRA_NODE_CLASS_NAME) !== null).toBe(true);\n  });\n\n  it('should remove wave when transition end', fakeAsync(() => {\n    dispatchMouseEvent(waveTarget, 'click');\n    expect(document.body.querySelector('style') !== null).toBe(true);\n    expect(waveTarget.querySelector(EXTRA_NODE_CLASS_NAME) !== null).toBe(true);\n    tick(500);\n    expect(document.body.querySelector('style') !== null).toBe(false);\n    expect(waveTarget.querySelector(EXTRA_NODE_CLASS_NAME) !== null).toBe(false);\n  }));\n\n  it('should not create wave on click when has disabled class', () => {\n    fixture.componentInstance.disabledClass = true;\n    fixture.detectChanges();\n    dispatchMouseEvent(waveTarget, 'click');\n    expect(waveTarget.hasAttribute(WAVE_ATTRIBUTE_NAME_EXTRA_NODE)).toBe(false);\n    expect(document.body.querySelector('style') !== null).toBe(false);\n    expect(waveTarget.querySelector(EXTRA_NODE_CLASS_NAME) !== null).toBe(false);\n  });\n\n  it('should not create wave style on click when invalid color', () => {\n    fixture.componentInstance.borderColor = '#ffffff';\n    fixture.detectChanges();\n    dispatchMouseEvent(waveTarget, 'click');\n    expect(document.body.querySelector('style') !== null).toBe(false);\n  });\n\n  it('should priority use border-color color', () => {\n    fixture.componentInstance.borderColor = 'rgb(255, 255, 0)';\n    fixture.componentInstance.backgroundColor = 'rgb(255, 0, 0)';\n    fixture.detectChanges();\n    dispatchMouseEvent(waveTarget, 'click');\n    const style: string = document.body.querySelector('style')!.innerText;\n    expect(style.includes(fixture.componentInstance.borderColor)).toBe(true);\n  });\n\n  it('should not create wave style on click when grey color', () => {\n    fixture.componentInstance.borderColor = '#eee';\n    fixture.detectChanges();\n    dispatchMouseEvent(waveTarget, 'click');\n    expect(document.body.querySelector('style') !== null).toBe(false);\n  });\n\n  it('should destroy', () => {\n    dispatchMouseEvent(waveTarget, 'click');\n    expect(waveTarget.hasAttribute(WAVE_ATTRIBUTE_NAME_EXTRA_NODE)).toBe(true);\n    expect(document.body.querySelector('style') !== null).toBe(true);\n    expect(waveTarget.querySelector(EXTRA_NODE_CLASS_NAME) !== null).toBe(true);\n\n    fixture.componentInstance.isDestroyed = true;\n    fixture.detectChanges();\n\n    expect(document.body.querySelector('style') !== null).toBe(false);\n    expect(waveTarget.querySelector(EXTRA_NODE_CLASS_NAME) !== null).toBe(false);\n  });\n});\n\ndescribe('nz-wave noAnimation', () => {\n  let fixture: ComponentFixture<WaveContainerWithButtonComponent>;\n  let waveRef: NzWaveDirective;\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(WaveContainerWithButtonComponent);\n    fixture.detectChanges();\n    waveRef = fixture.componentInstance.wave;\n  });\n\n  it('should disable by NoopAnimationsModule ', () => {\n    expect(waveRef.disabled).toBe(true);\n    expect(waveRef.rendererRef).toBeFalsy();\n  });\n\n  it('should config priority', () => {\n    waveRef.enable();\n    expect(waveRef.disabled).toBe(true);\n    expect(waveRef.rendererRef).toBeFalsy();\n  });\n});\n\ndescribe('nz-wave disable/enable', () => {\n  let fixture: ComponentFixture<WaveContainerWithButtonComponent>;\n  let waveTarget: HTMLElement;\n  let waveRef: NzWaveDirective;\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(WaveContainerWithButtonComponent);\n    fixture.detectChanges();\n    waveTarget = fixture.componentInstance.trigger.nativeElement;\n    waveRef = fixture.componentInstance.wave;\n  });\n\n  it('should enable work', () => {\n    waveRef.enable();\n    expect(waveRef.disabled).toBe(false);\n    expect(waveRef.rendererRef).toBeTruthy();\n    dispatchMouseEvent(waveTarget, 'click');\n    expect(waveTarget.hasAttribute(WAVE_ATTRIBUTE_NAME)).toBe(true);\n    expect(document.body.querySelector('style') !== null).toBe(true);\n  });\n\n  it('should disable work', () => {\n    waveRef.disable();\n    expect(waveRef.disabled).toBe(true);\n    dispatchMouseEvent(waveTarget, 'click');\n    expect(waveTarget.hasAttribute(WAVE_ATTRIBUTE_NAME)).toBe(false);\n    expect(document.body.querySelector('style') === null).toBe(true);\n  });\n});\n\n@Component({\n  imports: [NzWaveModule],\n  template: `\n    @if (!isDestroyed) {\n      <button\n        #trigger\n        nz-wave\n        [attr.disabled]=\"disabled || null\"\n        [class.disabled]=\"disabledClass\"\n        [style.border-color]=\"borderColor\"\n        [style.background-color]=\"backgroundColor\"\n      >\n        Button\n      </button>\n    }\n  `\n})\nclass WaveContainerWithButtonComponent {\n  disabled = false;\n  disabledClass = false;\n  isDestroyed = false;\n  borderColor = 'rgb(0,255,0)';\n  backgroundColor = 'rgb(255,255,255)';\n  @ViewChild('trigger', { static: false }) trigger!: ElementRef<HTMLElement>;\n  @ViewChild(NzWaveDirective, { static: false }) wave!: NzWaveDirective;\n}\n\n@Component({\n  imports: [NzWaveModule],\n  template: `\n    @if (!isDestroyed) {\n      <div\n        #trigger\n        nz-wave\n        [nzWaveExtraNode]=\"true\"\n        [class.disabled]=\"disabledClass\"\n        [style.border-color]=\"borderColor\"\n        [style.background-color]=\"backgroundColor\"\n      >\n        <button>Button</button>\n      </div>\n    }\n  `\n})\nclass WaveContainerWithExtraNodeComponent {\n  disabledClass = false;\n  isDestroyed = false;\n  borderColor = 'rgb(0,255,0)';\n  backgroundColor = 'rgb(255,255,255)';\n  @ViewChild('trigger', { static: false }) trigger!: ElementRef<HTMLElement>;\n  @ViewChild(NzWaveDirective, { static: false }) wave!: NzWaveDirective;\n}\n"
  },
  {
    "path": "components/core/wave/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './nz-wave-renderer';\nexport * from './nz-wave.directive';\nexport * from './nz-wave.module';\n"
  },
  {
    "path": "components/cron-expression/cron-expression-input.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  EventEmitter,\n  Input,\n  Output,\n  ViewEncapsulation,\n  booleanAttribute\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\nimport { CronChangeType, TimeType } from './typings';\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-cron-expression-input',\n  exportAs: 'nzCronExpressionInput',\n  template: `\n    <div class=\"ant-cron-expression-input\">\n      <input\n        nz-input\n        [(ngModel)]=\"value\"\n        [name]=\"label\"\n        [disabled]=\"disabled\"\n        (focus)=\"focusInputEffect($event)\"\n        (blur)=\"blurInputEffect()\"\n        (ngModelChange)=\"setValue()\"\n      />\n    </div>\n  `,\n  imports: [NzInputModule, FormsModule]\n})\nexport class NzCronExpressionInputComponent {\n  @Input() value: string = '0';\n  @Input() label: TimeType = 'second';\n  @Input({ transform: booleanAttribute }) disabled: boolean = false;\n  @Output() readonly focusEffect = new EventEmitter<TimeType>();\n  @Output() readonly blurEffect = new EventEmitter<void>();\n  @Output() readonly getValue = new EventEmitter<CronChangeType>();\n\n  focusInputEffect(event: FocusEvent): void {\n    this.focusEffect.emit(this.label);\n    (event.target as HTMLInputElement).select();\n  }\n\n  blurInputEffect(): void {\n    this.blurEffect.emit();\n  }\n\n  setValue(): void {\n    this.getValue.emit({ label: this.label, value: this.value });\n  }\n}\n"
  },
  {
    "path": "components/cron-expression/cron-expression-label.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, ViewEncapsulation, ChangeDetectionStrategy, Input } from '@angular/core';\n\nimport { NzCronExpressionLabelI18n } from 'ng-zorro-antd/i18n';\n\nimport { TimeType } from './typings';\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-cron-expression-label',\n  exportAs: 'nzCronExpressionLabel',\n  template: `\n    <div class=\"ant-cron-expression-label\" [class.ant-cron-expression-label-foucs]=\"labelFocus === type\">\n      <label>\n        {{ locale[type] }}\n      </label>\n    </div>\n  `\n})\nexport class NzCronExpressionLabelComponent {\n  @Input() type: TimeType = 'second';\n  @Input() locale!: NzCronExpressionLabelI18n;\n  @Input() labelFocus: string | null = null;\n}\n"
  },
  {
    "path": "components/cron-expression/cron-expression-preview.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { DatePipe, NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  EventEmitter,\n  Input,\n  Output,\n  TemplateRef,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject\n} from '@angular/core';\n\nimport { NzCronExpressionCronErrorI18n } from 'ng-zorro-antd/i18n';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-cron-expression-preview',\n  exportAs: 'nzCronExpressionPreview',\n  template: `\n    <div class=\"ant-collapse ant-collapse-borderless ant-cron-expression-preview\">\n      <div class=\"ant-cron-expression-preview-dateTime\" [class.ant-cron-expression-preview-dateTime-center]=\"!isExpand\">\n        @if (visible) {\n          @if (!nzSemantic) {\n            {{ TimeList[0] | date: 'yyyy-MM-dd HH:mm:ss' }}\n          } @else {\n            <ng-template [ngTemplateOutlet]=\"nzSemantic\" />\n          }\n        } @else {\n          {{ locale.cronError }}\n        }\n      </div>\n      @if (visible && !isExpand) {\n        <div class=\"ant-cron-expression-preview-content\">\n          <ul class=\"ant-cron-expression-preview-list\">\n            @for (item of TimeList; track item) {\n              <li>\n                {{ item | date: 'yyyy-MM-dd HH:mm:ss' }}\n              </li>\n            }\n            <li><a (click)=\"loadMorePreview.emit()\">···</a></li>\n          </ul>\n        </div>\n      }\n\n      <ul class=\"ant-cron-expression-preview-icon\">\n        @if (isExpand) {\n          <li><nz-icon nzType=\"down\" nzTheme=\"outline\" (click)=\"setExpand()\" /></li>\n        } @else {\n          <li><nz-icon nzType=\"up\" nzTheme=\"outline\" (click)=\"setExpand()\" /></li>\n        }\n      </ul>\n    </div>\n  `,\n  imports: [NgTemplateOutlet, DatePipe, NzIconModule]\n})\nexport class NzCronExpressionPreviewComponent {\n  private cdr = inject(ChangeDetectorRef);\n  @Input() TimeList: Date[] = [];\n  @Input({ transform: booleanAttribute }) visible: boolean = true;\n  @Input() locale!: NzCronExpressionCronErrorI18n;\n  @Input() nzSemantic: TemplateRef<void> | null = null;\n  @Output() readonly loadMorePreview = new EventEmitter<void>();\n\n  isExpand: boolean = true;\n\n  setExpand(): void {\n    this.isExpand = !this.isExpand;\n    this.cdr.markForCheck();\n  }\n}\n"
  },
  {
    "path": "components/cron-expression/cron-expression.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DestroyRef,\n  forwardRef,\n  inject,\n  Input,\n  OnChanges,\n  OnInit,\n  SimpleChanges,\n  TemplateRef,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport {\n  AbstractControl,\n  AsyncValidator,\n  ControlValueAccessor,\n  FormBuilder,\n  FormControl,\n  FormGroup,\n  NG_ASYNC_VALIDATORS,\n  NG_VALUE_ACCESSOR,\n  ValidationErrors,\n  ValidatorFn,\n  Validators\n} from '@angular/forms';\nimport { Observable, of } from 'rxjs';\n\nimport { CronExpression, parseExpression } from 'cron-parser';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { NzCronExpressionI18nInterface, NzI18nService } from 'ng-zorro-antd/i18n';\n\nimport { NzCronExpressionInputComponent } from './cron-expression-input.component';\nimport { NzCronExpressionLabelComponent } from './cron-expression-label.component';\nimport { NzCronExpressionPreviewComponent } from './cron-expression-preview.component';\nimport { Cron, CronChangeType, CronValue, NzCronExpressionSize, NzCronExpressionType, TimeType } from './typings';\n\nfunction labelsOfType(type: NzCronExpressionType): TimeType[] {\n  if (type === 'spring') {\n    return ['second', 'minute', 'hour', 'day', 'month', 'week'];\n  }\n  return ['minute', 'hour', 'day', 'month', 'week'];\n}\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-cron-expression',\n  exportAs: 'nzCronExpression',\n  template: `\n    <div class=\"ant-cron-expression\">\n      <div class=\"ant-cron-expression-content\">\n        <div\n          class=\"ant-input ant-cron-expression-input-group\"\n          [class.ant-input-lg]=\"nzSize === 'large'\"\n          [class.ant-input-sm]=\"nzSize === 'small'\"\n          [class.ant-input-borderless]=\"nzBorderless\"\n          [class.ant-cron-expression-input-group-focus]=\"focus && !nzBorderless\"\n          [class.ant-input-status-error]=\"!validateForm.valid && !nzBorderless\"\n          [class.ant-cron-expression-input-group-error-focus]=\"!validateForm.valid && focus && !nzBorderless\"\n          [class.ant-input-disabled]=\"nzDisabled\"\n        >\n          @for (label of labels; track label) {\n            <nz-cron-expression-input\n              [value]=\"this.validateForm.controls[label].value\"\n              [label]=\"label\"\n              [disabled]=\"nzDisabled\"\n              (focusEffect)=\"focusEffect($event)\"\n              (blurEffect)=\"blurEffect()\"\n              (getValue)=\"getValue($event)\"\n            />\n          }\n        </div>\n        <div\n          class=\"ant-cron-expression-label-group\"\n          [class.ant-input-lg]=\"nzSize === 'large'\"\n          [class.ant-cron-expression-label-group-default]=\"nzSize === 'default'\"\n          [class.ant-input-sm]=\"nzSize === 'small'\"\n        >\n          @for (label of labels; track label) {\n            <nz-cron-expression-label [type]=\"label\" [labelFocus]=\"labelFocus\" [locale]=\"locale\" />\n          }\n        </div>\n        @if (!nzCollapseDisable) {\n          <nz-cron-expression-preview\n            [TimeList]=\"nextTimeList\"\n            [visible]=\"validateForm.valid\"\n            [locale]=\"locale\"\n            [nzSemantic]=\"nzSemantic\"\n            (loadMorePreview)=\"loadMorePreview()\"\n          />\n        }\n      </div>\n      @if (nzExtra) {\n        <div class=\"ant-cron-expression-map\">\n          <ng-template [ngTemplateOutlet]=\"nzExtra\" />\n        </div>\n      }\n    </div>\n  `,\n  providers: [\n    {\n      provide: NG_ASYNC_VALIDATORS,\n      useExisting: forwardRef(() => NzCronExpressionComponent),\n      multi: true\n    },\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => NzCronExpressionComponent),\n      multi: true\n    }\n  ],\n  imports: [\n    NzCronExpressionInputComponent,\n    NzCronExpressionLabelComponent,\n    NzCronExpressionPreviewComponent,\n    NgTemplateOutlet\n  ]\n})\nexport class NzCronExpressionComponent implements OnInit, OnChanges, ControlValueAccessor, AsyncValidator {\n  private formBuilder = inject(FormBuilder);\n  private cdr = inject(ChangeDetectorRef);\n  private i18n = inject(NzI18nService);\n  private destroyRef = inject(DestroyRef);\n\n  @Input() nzSize: NzCronExpressionSize = 'default';\n  @Input() nzType: NzCronExpressionType = 'linux';\n  @Input({ transform: booleanAttribute }) nzCollapseDisable: boolean = false;\n  @Input() nzExtra?: TemplateRef<void> | null = null;\n  @Input() nzSemantic: TemplateRef<void> | null = null;\n  @Input({ transform: booleanAttribute }) nzBorderless = false;\n  @Input({ transform: booleanAttribute }) nzDisabled = false;\n\n  locale!: NzCronExpressionI18nInterface;\n  focus: boolean = false;\n  labelFocus: TimeType | null = null;\n  labels: TimeType[] = labelsOfType(this.nzType);\n  interval!: CronExpression<false>;\n  nextTimeList: Date[] = [];\n  private isNzDisableFirstChange: boolean = true;\n\n  validateForm: FormGroup<Record<TimeType, FormControl<CronValue>>>;\n\n  onChange: NzSafeAny = () => {};\n  onTouch: () => void = () => null;\n\n  convertFormat(value: string): void {\n    const values = value.split(' ');\n    const valueObject = this.labels.reduce((obj, label, idx) => {\n      obj[label] = values[idx];\n      return obj;\n    }, {} as Cron);\n    this.validateForm.patchValue(valueObject);\n  }\n\n  writeValue(value: string | null): void {\n    if (value) {\n      this.convertFormat(value);\n    }\n  }\n\n  registerOnChange(fn: NzSafeAny): void {\n    this.onChange = fn;\n  }\n\n  registerOnTouched(fn: NzSafeAny): void {\n    this.onTouch = fn;\n  }\n\n  validate(): Observable<ValidationErrors | null> {\n    if (this.validateForm.valid) {\n      return of(null);\n    } else {\n      return of({ error: true });\n    }\n  }\n\n  setDisabledState(isDisabled: boolean): void {\n    this.nzDisabled = (this.isNzDisableFirstChange && this.nzDisabled) || isDisabled;\n    this.isNzDisableFirstChange = false;\n    this.cdr.markForCheck();\n  }\n\n  constructor() {\n    this.validateForm = this.formBuilder.nonNullable.group(\n      {\n        second: ['0', Validators.required],\n        minute: ['*', Validators.required],\n        hour: ['*', Validators.required],\n        day: ['*', Validators.required],\n        month: ['*', Validators.required],\n        week: ['*', Validators.required]\n      },\n      { validators: this.checkValid }\n    );\n  }\n\n  ngOnInit(): void {\n    this.i18n.localeChange.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      this.locale = this.i18n.getLocaleData('CronExpression');\n      this.cdr.markForCheck();\n    });\n    this.cronFormType();\n    this.previewDate(this.validateForm.value);\n\n    this.validateForm.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(value => {\n      this.onChange(Object.values(value).join(' '));\n      this.previewDate(value);\n      this.cdr.markForCheck();\n    });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzType } = changes;\n\n    if (nzType) {\n      this.labels = labelsOfType(this.nzType);\n      this.cronFormType();\n    }\n  }\n\n  cronFormType(): void {\n    if (this.nzType === 'spring') {\n      this.validateForm.controls.second.enable();\n    } else {\n      this.validateForm.controls.second.disable();\n    }\n  }\n\n  previewDate(value: Cron): void {\n    try {\n      this.interval = parseExpression(Object.values(value).join(' '));\n      this.nextTimeList = [\n        this.interval.next().toDate(),\n        this.interval.next().toDate(),\n        this.interval.next().toDate(),\n        this.interval.next().toDate(),\n        this.interval.next().toDate()\n      ];\n    } catch {\n      return;\n    }\n  }\n\n  loadMorePreview(): void {\n    this.nextTimeList = [\n      ...this.nextTimeList,\n      this.interval.next().toDate(),\n      this.interval.next().toDate(),\n      this.interval.next().toDate(),\n      this.interval.next().toDate(),\n      this.interval.next().toDate()\n    ];\n    this.cdr.markForCheck();\n  }\n\n  focusEffect(value: TimeType): void {\n    this.focus = true;\n    this.labelFocus = value;\n    this.cdr.markForCheck();\n  }\n\n  blurEffect(): void {\n    this.focus = false;\n    this.labelFocus = null;\n    this.cdr.markForCheck();\n  }\n\n  getValue(item: CronChangeType): void {\n    this.validateForm.controls[item.label].patchValue(item.value);\n    this.cdr.markForCheck();\n  }\n\n  checkValid: ValidatorFn = (control: AbstractControl): ValidationErrors | null => {\n    if (control.value) {\n      try {\n        const cron: string[] = [];\n        this.labels.forEach(label => cron.push(control.value[label]));\n        parseExpression(cron.join(' '));\n      } catch {\n        return { error: true };\n      }\n    }\n    return null;\n  };\n}\n"
  },
  {
    "path": "components/cron-expression/cron-expression.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzCronExpressionInputComponent } from './cron-expression-input.component';\nimport { NzCronExpressionLabelComponent } from './cron-expression-label.component';\nimport { NzCronExpressionPreviewComponent } from './cron-expression-preview.component';\nimport { NzCronExpressionComponent } from './cron-expression.component';\n\n@NgModule({\n  imports: [\n    NzCronExpressionComponent,\n    NzCronExpressionLabelComponent,\n    NzCronExpressionInputComponent,\n    NzCronExpressionPreviewComponent\n  ],\n  exports: [NzCronExpressionComponent]\n})\nexport class NzCronExpressionModule {}\n"
  },
  {
    "path": "components/cron-expression/cron-expression.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, DebugElement, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, fakeAsync, flush, TestBed } from '@angular/core/testing';\nimport { FormControl, ReactiveFormsModule } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzCronExpressionComponent } from 'ng-zorro-antd/cron-expression/cron-expression.component';\nimport { NzCronExpressionModule } from 'ng-zorro-antd/cron-expression/cron-expression.module';\nimport { NzCronExpressionSize } from 'ng-zorro-antd/cron-expression/typings';\n\ndescribe('cron-expression', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  describe('basic', () => {\n    let fixture: ComponentFixture<NzTestCronExpressionComponent>;\n    let testComponent: NzTestCronExpressionComponent;\n    let resultEl: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCronExpressionComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n      resultEl = fixture.debugElement.query(By.directive(NzCronExpressionComponent));\n    });\n\n    it('cron-expression basic', () => {\n      fixture.detectChanges();\n      expect(resultEl.nativeElement.querySelector('.ant-cron-expression-input-group').classList).toContain('ant-input');\n    });\n\n    it('cron-expression nzSize', () => {\n      testComponent.nzSize = 'small';\n      fixture.detectChanges();\n      expect(resultEl.nativeElement.querySelector('.ant-cron-expression-input-group').classList).toContain(\n        'ant-input-sm'\n      );\n      testComponent.nzSize = 'large';\n      fixture.detectChanges();\n      expect(resultEl.nativeElement.querySelector('.ant-cron-expression-input-group').classList).toContain(\n        'ant-input-lg'\n      );\n    });\n\n    it('cron-expression nzDisabled', () => {\n      testComponent.nzDisabled = true;\n      fixture.detectChanges();\n      expect(resultEl.nativeElement.querySelector('.ant-cron-expression-input-group').classList).toContain(\n        'ant-input-disabled'\n      );\n    });\n\n    it('cron-expression nzBorderless', () => {\n      testComponent.nzBorderless = true;\n      fixture.detectChanges();\n      expect(resultEl.nativeElement.querySelector('.ant-cron-expression-input-group').classList).toContain(\n        'ant-input-borderless'\n      );\n    });\n\n    it('cron-expression nzCollapseDisable', () => {\n      expect(resultEl.nativeElement.querySelector('nz-cron-expression-preview')).not.toBe(null);\n      testComponent.nzCollapseDisable = true;\n      fixture.detectChanges();\n      expect(resultEl.nativeElement.querySelector('nz-cron-expression-preview')).toBe(null);\n    });\n\n    it('cron-expression nzExtra', () => {\n      fixture.detectChanges();\n      expect(resultEl.nativeElement.querySelector('.ant-cron-expression-map')).not.toBe(null);\n    });\n\n    it('cron-expression nzSemantic', () => {\n      fixture.detectChanges();\n      expect(resultEl.nativeElement.querySelector('.ant-cron-expression-preview-dateTime').innerText).toBe('Test');\n    });\n  });\n\n  describe('type', () => {\n    let fixture: ComponentFixture<NzTestCronExpressionTypeComponent>;\n    let resultEl: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCronExpressionTypeComponent);\n      fixture.detectChanges();\n      resultEl = fixture.debugElement.query(By.directive(NzCronExpressionComponent));\n    });\n\n    it('cron-expression type', () => {\n      fixture.detectChanges();\n      expect(resultEl.nativeElement.querySelectorAll('nz-cron-expression-input').length).toBe(6);\n      expect(resultEl.nativeElement.querySelectorAll('nz-cron-expression-label').length).toBe(6);\n\n      fixture.componentRef.instance.nzType = 'linux';\n      fixture.detectChanges();\n      expect(resultEl.nativeElement.querySelectorAll('nz-cron-expression-input').length).toBe(5);\n      expect(resultEl.nativeElement.querySelectorAll('nz-cron-expression-label').length).toBe(5);\n    });\n  });\n\n  describe('form', () => {\n    let fixture: ComponentFixture<NzTestCronExpressionFormComponent>;\n    let testComponent: NzTestCronExpressionFormComponent;\n    let resultEl: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCronExpressionFormComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n      resultEl = fixture.debugElement.query(By.directive(NzCronExpressionComponent));\n    });\n\n    it('cron-expression form', fakeAsync(() => {\n      flush();\n      expect(resultEl.nativeElement.querySelector('.ant-cron-expression-input-group').classList).not.toContain(\n        'ant-input-disabled'\n      );\n      testComponent.disable();\n      fixture.detectChanges();\n      flush();\n      expect(resultEl.nativeElement.querySelector('.ant-cron-expression-input-group').classList).toContain(\n        'ant-input-disabled'\n      );\n    }));\n  });\n});\n\n@Component({\n  imports: [NzButtonModule, NzCronExpressionModule],\n  template: `\n    <nz-cron-expression\n      [nzSize]=\"nzSize\"\n      [nzCollapseDisable]=\"nzCollapseDisable\"\n      [nzDisabled]=\"nzDisabled\"\n      [nzBorderless]=\"nzBorderless\"\n      [nzExtra]=\"shortcuts\"\n      [nzSemantic]=\"semanticTemplate\"\n    />\n    <ng-template #shortcuts>\n      <button nz-button nzType=\"primary\">Test</button>\n    </ng-template>\n    <ng-template #semanticTemplate>Test</ng-template>\n  `\n})\nexport class NzTestCronExpressionComponent {\n  nzSize: NzCronExpressionSize = 'default';\n  nzDisabled = false;\n  nzBorderless = false;\n  nzCollapseDisable = false;\n}\n\n@Component({\n  imports: [NzCronExpressionModule],\n  template: `<nz-cron-expression [nzType]=\"nzType\" />`\n})\nexport class NzTestCronExpressionTypeComponent {\n  nzType: 'linux' | 'spring' = 'spring';\n}\n\n@Component({\n  imports: [ReactiveFormsModule, NzCronExpressionModule],\n  template: `<nz-cron-expression [formControl]=\"formControl\" />`\n})\nexport class NzTestCronExpressionFormComponent {\n  formControl = new FormControl('1 1 1 * *');\n\n  disable(): void {\n    this.formControl.disable();\n  }\n}\n"
  },
  {
    "path": "components/cron-expression/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n最简单的用法。\n\n## en-US\n\nThe simplest usage.\n"
  },
  {
    "path": "components/cron-expression/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCronExpressionModule } from 'ng-zorro-antd/cron-expression';\n\n@Component({\n  selector: 'nz-demo-cron-expression-basic',\n  imports: [NzCronExpressionModule],\n  template: `\n    <nz-cron-expression />\n    <br />\n    <br />\n    <nz-cron-expression nzDisabled />\n  `\n})\nexport class NzDemoCronExpressionBasicComponent {}\n"
  },
  {
    "path": "components/cron-expression/demo/borderless.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 无边框\n  en-US: Borderless\n---\n\n## zh-CN\n\n没有边框\n\n## en-US\n\nNo bezel.\n"
  },
  {
    "path": "components/cron-expression/demo/borderless.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCronExpressionModule } from 'ng-zorro-antd/cron-expression';\n\n@Component({\n  selector: 'nz-demo-cron-expression-borderless',\n  imports: [NzCronExpressionModule],\n  template: `<nz-cron-expression nzBorderless />`\n})\nexport class NzDemoCronExpressionBorderlessComponent {}\n"
  },
  {
    "path": "components/cron-expression/demo/collapse.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 隐藏折叠面板\n  en-US: Hide Collapse\n---\n\n## zh-CN\n\n`[nzCollapseDisable]=\"true\"`\n\n## en-US\n\n`[nzCollapseDisable]=\"true\"`\n"
  },
  {
    "path": "components/cron-expression/demo/collapse.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCronExpressionModule } from 'ng-zorro-antd/cron-expression';\n\n@Component({\n  selector: 'nz-demo-cron-expression-collapse',\n  imports: [NzCronExpressionModule],\n  template: `<nz-cron-expression [nzCollapseDisable]=\"true\" />`\n})\nexport class NzDemoCronExpressionCollapseComponent {}\n"
  },
  {
    "path": "components/cron-expression/demo/semantic.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 自定义渲染 cron 时间\n  en-US: Custom rendering cron time\n---\n\n## zh-CN\n\n自定义渲染下次执行时间\n\n## en-US\n\nCustom rendering next execution time.\n"
  },
  {
    "path": "components/cron-expression/demo/semantic.ts",
    "content": "import { DatePipe } from '@angular/common';\nimport { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { parseExpression } from 'cron-parser';\n\nimport { NzCronExpressionModule } from 'ng-zorro-antd/cron-expression';\n\n@Component({\n  selector: 'nz-demo-cron-expression-semantic',\n  imports: [FormsModule, NzCronExpressionModule, DatePipe],\n  template: `\n    <nz-cron-expression [nzSemantic]=\"semanticTemplate\" [ngModel]=\"value\" (ngModelChange)=\"getValue($event)\" />\n    <ng-template #semanticTemplate>Next Time: {{ semantic | date: 'yyyy-MM-dd HH:mm:ss' }}</ng-template>\n  `\n})\nexport class NzDemoCronExpressionSemanticComponent {\n  value: string = '10 * * * *';\n  semantic?: Date;\n\n  getValue(value: string): void {\n    try {\n      const interval = parseExpression(value);\n      this.semantic = interval.next().toDate();\n    } catch {\n      return;\n    }\n  }\n}\n"
  },
  {
    "path": "components/cron-expression/demo/shortcuts.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 额外节点\n  en-US: Extra Node\n---\n\n## zh-CN\n\n你可以通过 nzExtra 来指定右侧的内容。\n\n## en-US\n\nYou can use nzExtra to specify the content on the right.\n"
  },
  {
    "path": "components/cron-expression/demo/shortcuts.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzCronExpressionModule } from 'ng-zorro-antd/cron-expression';\nimport { NzDropdownModule } from 'ng-zorro-antd/dropdown';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-demo-cron-expression-shortcuts',\n  imports: [FormsModule, NzButtonModule, NzCronExpressionModule, NzDropdownModule, NzIconModule],\n  template: `\n    <nz-cron-expression [nzExtra]=\"shortcuts\" [(ngModel)]=\"value\" (ngModelChange)=\"getValue($event)\" />\n    <ng-template #shortcuts>\n      <button nz-button nz-dropdown [nzDropdownMenu]=\"menu\">\n        Shortcuts\n        <nz-icon nzType=\"down\" />\n      </button>\n      <nz-dropdown-menu #menu=\"nzDropdownMenu\">\n        <ul nz-menu nzSelectable>\n          @for (item of options; track item.value) {\n            <li nz-menu-item [value]=\"item.value\" (click)=\"setValue(item.value)\">{{ item.label }}</li>\n          }\n        </ul>\n      </nz-dropdown-menu>\n    </ng-template>\n    <p>cron: {{ cron }} </p>\n  `\n})\nexport class NzDemoCronExpressionShortcutsComponent {\n  value: string = '1 1 * * *';\n  cron: string = '';\n  options = [\n    {\n      label: 'Every hour',\n      value: '0 0-23/1 * * *'\n    },\n    {\n      label: 'Every day at eight',\n      value: '0 8 * * *'\n    },\n    {\n      label: 'Every Friday',\n      value: '0 0 * * 5'\n    }\n  ];\n\n  setValue(value: string): void {\n    this.value = value;\n  }\n\n  getValue(value: string): void {\n    this.cron = value;\n  }\n}\n"
  },
  {
    "path": "components/cron-expression/demo/size.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 三种大小\n  en-US: Three sizes of Input\n---\n\n## zh-CN\n\n我们为 `nz-cron-expression` 输入框定义了三种尺寸（大、默认、小），高度分别为 `40px`、`32px` 和 `24px`。\n\n## en-US\n\nThere are three sizes of an CronExpression box: `large` (40px)、`default` (32px) and `small` (24px).\n"
  },
  {
    "path": "components/cron-expression/demo/size.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCronExpressionModule } from 'ng-zorro-antd/cron-expression';\n\n@Component({\n  selector: 'nz-demo-cron-expression-size',\n  imports: [NzCronExpressionModule],\n  template: `\n    <div class=\"example-cron-expression\">\n      <nz-cron-expression nzSize=\"small\" />\n      <nz-cron-expression nzSize=\"default\" />\n      <nz-cron-expression nzSize=\"large\" />\n    </div>\n  `,\n  styles: `\n    .example-cron-expression nz-cron-expression {\n      margin: 0 8px 8px 0;\n    }\n  `\n})\nexport class NzDemoCronExpressionSizeComponent {}\n"
  },
  {
    "path": "components/cron-expression/demo/type.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 两种规则类型\n  en-US: Two rule types\n---\n\n## zh-CN\n\n我们为 `nz-cron-expression` 输入框定义了两种规则类型（五段式， 六段式），分别为: `nzType=\"linux\"`、`nzType=\"spring\"`。\n\n## en-US\n\nThere are two rule types of an CronExpression box: `nzType=\"linux\"` (five-segment) and`nzType=\"spring\"` (six-segment).\n"
  },
  {
    "path": "components/cron-expression/demo/type.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCronExpressionModule } from 'ng-zorro-antd/cron-expression';\n\n@Component({\n  selector: 'nz-demo-cron-expression-type',\n  imports: [NzCronExpressionModule],\n  template: `\n    <div class=\"example-cron-expression\">\n      <nz-cron-expression nzType=\"linux\" />\n      <nz-cron-expression nzType=\"spring\" />\n    </div>\n  `,\n  styles: `\n    .example-cron-expression nz-cron-expression {\n      margin: 0 8px 8px 0;\n    }\n  `\n})\nexport class NzDemoCronExpressionTypeComponent {}\n"
  },
  {
    "path": "components/cron-expression/demo/use.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 结合表单使用\n  en-US: Basic\n---\n\n## zh-CN\n\n`<nz-cron-expression formControlName=\"cron\"></nz-cron-expression>`\n\n## en-US\n\n`<nz-cron-expression formControlName=\"cron\"></nz-cron-expression>`\n"
  },
  {
    "path": "components/cron-expression/demo/use.ts",
    "content": "import { Component, inject } from '@angular/core';\nimport { FormBuilder, FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzCronExpressionModule } from 'ng-zorro-antd/cron-expression';\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-cron-expression-use',\n  imports: [ReactiveFormsModule, NzButtonModule, NzCronExpressionModule, NzFormModule, NzInputModule],\n  template: `\n    <form nz-form nzLayout=\"vertical\" [formGroup]=\"validateForm\" (ngSubmit)=\"submitForm()\">\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"6\">name</nz-form-label>\n        <nz-form-control [nzSpan]=\"14\">\n          <input nz-input formControlName=\"username\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"6\">nz-cron-linux</nz-form-label>\n        <nz-form-control [nzSpan]=\"14\">\n          <nz-cron-expression formControlName=\"cronLinux\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"6\">nz-cron-spring</nz-form-label>\n        <nz-form-control [nzSpan]=\"14\">\n          <nz-cron-expression formControlName=\"cronSpring\" nzType=\"spring\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-control>\n          <button nz-button nzType=\"primary\" [disabled]=\"!validateForm.valid\">submit</button>\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `\n})\nexport class NzDemoCronExpressionUseComponent {\n  private fb = inject(FormBuilder);\n  validateForm: FormGroup<{\n    username: FormControl<string | null>;\n    cronLinux: FormControl<string | null>;\n    cronSpring: FormControl<string | null>;\n  }> = this.fb.group({\n    username: ['cron-expression', [Validators.required]],\n    cronLinux: ['* 1 * * *', [Validators.required]],\n    cronSpring: ['0 * 1 * * *', [Validators.required]]\n  });\n\n  submitForm(): void {\n    console.log(this.validateForm.value);\n  }\n}\n"
  },
  {
    "path": "components/cron-expression/doc/index.en-US.md",
    "content": "---\ncategory: Components\nsubtitle: cron form\ntype: Data Entry\ntitle: Cron Expression\ncols: 1\nexperimental: true\ndescription: Display and edit cron expression.\n---\n\n## When To Use\n\nWhen you want to use cron expression in Angular.\n\n## API\n\nInstall `cron-parser` in your project first:\n\n```sh\nnpm install cron-parser\n```\n\n### nz-cron-expression\n\n| Parameter             | Description                          | Type                          | Default   |\n| --------------------- | ------------------------------------ | ----------------------------- | --------- |\n| `[nzType]`            | Cron rule type                       | `'linux'｜'spring'`           | `linux`   |\n| `[nzDisabled]`        | Disable                              | `boolean`                     | `false`   |\n| `[nzBorderless]`      | Whether to hide the border           | `boolean`                     | `false`   |\n| `[nzSize]`            | The size of the input box.           | `'large'｜'small'｜'default'` | `default` |\n| `[nzCollapseDisable]` | Hide collapse                        | `boolean`                     | `false`   |\n| `[nzExtra]`           | Render the content on the right      | `TemplateRef<void>`           | -         |\n| `[nzSemantic]`        | Custom rendering next execution time | `TemplateRef<void>`           | -         |\n\n## Note\n\n### Supported format\n\n```text\n*    *    *    *    *    *\n┬    ┬    ┬    ┬    ┬    ┬\n│    │    │    │    │    |\n│    │    │    │    │    └ day of week (0 - 7, 1L - 7L) (0 or 7 is Sun)\n│    │    │    │    └───── month (1 - 12)\n│    │    │    └────────── day of month (1 - 31, L)\n│    │    └─────────────── hour (0 - 23)\n│    └──────────────────── minute (0 - 59)\n└───────────────────────── second (0 - 59, optional)\n```\n"
  },
  {
    "path": "components/cron-expression/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: cron 表单\ntype: 数据录入\ntitle: Cron Expression\ncols: 1\nexperimental: true\ndescription: 显示和编辑 cron 表达式。\n---\n\n## 何时使用\n\n需要在表单中使用 cron 格式验证时使用。\n\n## API\n\n别忘记先安装 cron-parser：\n\n```sh\nnpm install cron-parser\n```\n\n### nz-cron-expression\n\n| 参数                  | 说明                   | 类型                          | 默认值    |\n| --------------------- | ---------------------- | ----------------------------- | --------- |\n| `[nzType]`            | cron 规则类型          | `'linux'｜'spring'`           | `linux`   |\n| `[nzSize]`            | 设置输入框大小         | `'large'｜'small'｜'default'` | `default` |\n| `[nzDisabled]`        | 禁用                   | `boolean`                     | `false`   |\n| `[nzBorderless]`      | 是否隐藏边框           | `boolean`                     | `false`   |\n| `[nzCollapseDisable]` | 隐藏折叠面板           | `boolean`                     | `false`   |\n| `[nzExtra]`           | 自定义渲染右侧的内容   | `TemplateRef<void>`           | -         |\n| `[nzSemantic]`        | 自定义渲染下次执行时间 | `TemplateRef<void>`           | -         |\n\n## 注意\n\n### 支持格式\n\n```text\n*    *    *    *    *    *\n┬    ┬    ┬    ┬    ┬    ┬\n│    │    │    │    │    |\n│    │    │    │    │    └ day of week (0 - 7, 1L - 7L) (0 or 7 is Sun)\n│    │    │    │    └───── month (1 - 12)\n│    │    │    └────────── day of month (1 - 31, L)\n│    │    └─────────────── hour (0 - 23)\n│    └──────────────────── minute (0 - 59)\n└───────────────────────── second (0 - 59, optional)\n```\n"
  },
  {
    "path": "components/cron-expression/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/cron-expression/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/cron-expression/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './typings';\nexport * from './cron-expression.component';\nexport * from './cron-expression.module';\n"
  },
  {
    "path": "components/cron-expression/style/entry.less",
    "content": "@import './index.less';"
  },
  {
    "path": "components/cron-expression/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@cron-expression-prefix-cls: ~'@{ant-prefix}-cron-expression';\n\n.@{cron-expression-prefix-cls} {\n  display: flex;\n  flex-wrap: nowrap;\n\n  &-content{\n    width: 100%;\n\n    .@{cron-expression-prefix-cls}-input-group-error-focus {\n      box-shadow: 0 0 0 @outline-width @error-color-outline;\n    }\n  }\n\n  nz-cron-expression-input{\n    width: 20%;\n  }\n\n  &-input-group {\n    display: flex;\n    flex-wrap: nowrap;\n    align-items: center;\n\n    input {\n      width: 100%;\n      padding: 0;\n      border: none !important;\n      border-radius: 0;\n      outline: none;\n      box-shadow: none !important;\n    }\n  }\n\n  &-input-group-focus {\n    border-color: @primary-color;\n    outline: 0;\n    box-shadow: 0 0 0 @outline-width @primary-color-outline;\n  }\n\n  nz-cron-expression-label {\n    width: 20%;\n  }\n\n  &-label-group {\n    display: flex;\n    flex-wrap: nowrap;\n    justify-content: space-around;\n    width: 100%;\n    padding-top: 0 !important;\n    padding-bottom: 0 !important;\n\n    &-default {\n      padding: 0 @padding-sm;\n    }\n  }\n\n  &-label-foucs {\n    color: @primary-color;\n  }\n\n  &-map {\n    margin-left: @margin-sm;\n  }\n\n  &-preview {\n    display: flex;\n    padding: @padding-sm;\n\n    &-dateTime {\n      display: flex;\n      flex: 1 1 auto;\n      align-items: center;\n\n      &-center {\n        justify-content: center;\n      }\n    }\n\n    &-content {\n      display: flex;\n      flex: 0 0 220px;\n      align-items: center;\n      padding-left: @padding-md;\n    }\n\n    &-list, &-icon {\n      margin: 0;\n      padding: 0;\n      list-style: none;\n\n      li {\n        margin: 0;\n        padding: 0;\n        list-style: none;\n      }\n    }\n\n    &-list {\n      height: 132px;\n      overflow-y: scroll;\n    }\n\n    &-icon {\n      display: flex;\n      flex: 0 0 16px;\n      justify-content: center;\n    }\n  }\n\n  &-error {\n    color: @error-color;\n  }\n}"
  },
  {
    "path": "components/cron-expression/typings.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport type TimeType = keyof Cron;\n\nexport interface Cron {\n  second?: CronValue;\n  minute?: CronValue;\n  hour?: CronValue;\n  day?: CronValue;\n  month?: CronValue;\n  week?: CronValue;\n}\n\nexport type CronValue = '*' | `${number}` | `${number}-${number}` | `${number}/${number}` | string;\n\nexport interface CronChangeType {\n  label: TimeType;\n  value: CronValue;\n}\n\nexport type NzCronExpressionSize = 'large' | 'default' | 'small';\nexport type NzCronExpressionType = 'linux' | 'spring';\n"
  },
  {
    "path": "components/date-picker/calendar-footer.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  EventEmitter,\n  Input,\n  OnChanges,\n  Output,\n  SimpleChanges,\n  TemplateRef,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject\n} from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzStringTemplateOutletDirective } from 'ng-zorro-antd/core/outlet';\nimport { CandyDate } from 'ng-zorro-antd/core/time';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { DateHelperService, NzCalendarI18nInterface } from 'ng-zorro-antd/i18n';\n\nimport { transCompatFormat } from './lib/util';\nimport { PREFIX_CLASS } from './util';\n\n@Component({\n  // eslint-disable-next-line @angular-eslint/component-selector\n  selector: 'calendar-footer',\n  imports: [NgTemplateOutlet, NzButtonModule, NzStringTemplateOutletDirective],\n  template: `\n    <div class=\"{{ prefixCls }}-footer\">\n      @if (extraFooter) {\n        <div class=\"{{ prefixCls }}-footer-extra\">\n          <ng-template [nzStringTemplateOutlet]=\"extraFooter\">{{ extraFooter }}</ng-template>\n        </div>\n      }\n\n      @if (showToday) {\n        <a\n          class=\"{{ prefixCls }}-today-btn {{ isTodayDisabled ? prefixCls + '-today-btn-disabled' : '' }}\"\n          role=\"button\"\n          (click)=\"isTodayDisabled ? null : onClickToday()\"\n          title=\"{{ todayTitle }}\"\n        >\n          {{ locale.today }}\n        </a>\n      }\n\n      @if (hasTimePicker || rangeQuickSelector) {\n        <ul class=\"{{ prefixCls }}-ranges\">\n          <ng-container *ngTemplateOutlet=\"rangeQuickSelector\" />\n          @if (showNow) {\n            <li class=\"{{ prefixCls }}-now\">\n              <a class=\"{{ prefixCls }}-now-btn\" (click)=\"isTodayDisabled ? null : onClickToday()\">\n                {{ locale.now }}\n              </a>\n            </li>\n          }\n\n          @if (hasTimePicker) {\n            <li class=\"{{ prefixCls }}-ok\">\n              <button\n                nz-button\n                type=\"button\"\n                nzType=\"primary\"\n                nzSize=\"small\"\n                [disabled]=\"okDisabled\"\n                (click)=\"okDisabled ? null : clickOk.emit()\"\n              >\n                {{ locale.ok }}\n              </button>\n            </li>\n          }\n        </ul>\n      }\n    </div>\n  `,\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class CalendarFooterComponent implements OnChanges {\n  private dateHelper = inject(DateHelperService);\n  @Input() locale!: NzCalendarI18nInterface;\n  @Input({ transform: booleanAttribute }) showToday: boolean = false;\n  @Input({ transform: booleanAttribute }) showNow: boolean = false;\n  @Input({ transform: booleanAttribute }) hasTimePicker: boolean = false;\n  @Input({ transform: booleanAttribute }) isRange: boolean = false;\n\n  @Input({ transform: booleanAttribute }) okDisabled: boolean = false;\n  @Input() disabledDate?: (d: Date) => boolean;\n  @Input() extraFooter?: TemplateRef<void> | string;\n  @Input() rangeQuickSelector: TemplateRef<NzSafeAny> | null = null;\n\n  @Output() readonly clickOk = new EventEmitter<void>();\n  @Output() readonly clickToday = new EventEmitter<CandyDate>();\n\n  prefixCls: string = PREFIX_CLASS;\n  isTodayDisabled: boolean = false;\n  todayTitle: string = '';\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const now: Date = new Date();\n    if (changes.disabledDate) {\n      this.isTodayDisabled = !!(this.disabledDate && this.disabledDate(now));\n    }\n    if (changes.locale) {\n      // NOTE: Compat for DatePipe formatting rules\n      const dateFormat: string = transCompatFormat(this.locale.dateFormat);\n      this.todayTitle = this.dateHelper.format(now, dateFormat);\n    }\n  }\n\n  onClickToday(): void {\n    const now: CandyDate = new CandyDate();\n    this.clickToday.emit(now.clone()); // To prevent the \"now\" being modified from outside, we use clone\n  }\n}\n"
  },
  {
    "path": "components/date-picker/date-picker.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ESCAPE } from '@angular/cdk/keycodes';\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport { registerLocaleData } from '@angular/common';\nimport zh from '@angular/common/locales/zh';\nimport {\n  ApplicationRef,\n  Component,\n  DebugElement,\n  inject,\n  provideZoneChangeDetection,\n  signal,\n  TemplateRef,\n  ViewChild,\n  WritableSignal\n} from '@angular/core';\nimport { ComponentFixture, fakeAsync, flush, TestBed, inject as testingInject, tick } from '@angular/core/testing';\nimport { FormBuilder, FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport isEqual from 'date-fns/isEqual';\nimport isSameDay from 'date-fns/isSameDay';\nimport { enUS } from 'date-fns/locale';\n\nimport { NZ_FORM_SIZE, NZ_FORM_VARIANT } from 'ng-zorro-antd/core/form';\nimport {\n  dispatchFakeEvent,\n  dispatchKeyboardEvent,\n  dispatchMouseEvent,\n  typeInElement\n} from 'ng-zorro-antd/core/testing';\nimport {\n  NgStyleInterface,\n  NzSafeAny,\n  NzSizeLDSType,\n  NzStatus,\n  NzVariant,\n  type NzPlacement\n} from 'ng-zorro-antd/core/types';\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NZ_DATE_LOCALE, NzI18nService } from 'ng-zorro-antd/i18n';\nimport en_US from 'ng-zorro-antd/i18n/languages/en_US';\nimport { NZ_SPACE_COMPACT_SIZE } from 'ng-zorro-antd/space';\n\nimport { NzDatePickerComponent, NzDatePickerSizeType } from './date-picker.component';\nimport { NzDatePickerModule } from './date-picker.module';\nimport { CompatibleDate, NzPanelChangeType } from './standard-types';\nimport { ENTER_EVENT, getPickerAbstract, getPickerInput } from './testing/util';\nimport { PREFIX_CLASS } from './util';\n\nregisterLocaleData(zh);\n\ndescribe('NzDatePickerComponent', () => {\n  let fixture: ComponentFixture<NzTestDatePickerComponent>;\n  let fixtureInstance: NzTestDatePickerComponent;\n  let debugElement: DebugElement;\n  let overlayContainer: OverlayContainer;\n  let overlayContainerElement: HTMLElement;\n  let i18nService: NzI18nService;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzTestDatePickerComponent);\n    fixtureInstance = fixture.componentInstance;\n    debugElement = fixture.debugElement;\n  });\n\n  beforeEach(\n    testingInject([OverlayContainer, NzI18nService], (oc: OverlayContainer, i18n: NzI18nService) => {\n      overlayContainer = oc;\n      overlayContainerElement = oc.getContainerElement();\n      i18nService = i18n;\n    })\n  );\n\n  afterEach(() => {\n    overlayContainer.ngOnDestroy();\n  });\n\n  describe('general api testing', () => {\n    beforeEach(() => (fixtureInstance.useSuite = 1));\n\n    it('should open by click and close by click at outside', fakeAsync(() => {\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(getPickerContainer()).not.toBeNull();\n\n      triggerInputBlur();\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).toBeNull();\n    }));\n\n    it('should open and close method work', fakeAsync(() => {\n      fixture.detectChanges();\n      fixtureInstance.datePicker.open();\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).not.toBeNull();\n\n      fixtureInstance.datePicker.close();\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).toBeNull();\n    }));\n\n    it('should focus on the trigger after a click outside', fakeAsync(() => {\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      triggerInputBlur();\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(document.activeElement).toEqual(getPickerInput(fixture.debugElement));\n    }));\n\n    it('should open on enter', fakeAsync(() => {\n      fixture.detectChanges();\n      getPickerInput(fixture.debugElement).dispatchEvent(ENTER_EVENT);\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).toBeNull();\n\n      getPickerInput(fixture.debugElement).focus();\n      getPickerInput(fixture.debugElement).dispatchEvent(ENTER_EVENT);\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).not.toBeNull();\n    }));\n\n    it('should open by click and focus on inner calendar input', fakeAsync(() => {\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(document.activeElement).toEqual(getPickerInput(fixture.debugElement));\n    }));\n\n    it('should open by click, focus on inner calendar input, and submit on enter', fakeAsync(() => {\n      fixtureInstance.nzValue = new Date();\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(document.activeElement).toEqual(getPickerInput(fixture.debugElement));\n      getPickerInput(fixture.debugElement).dispatchEvent(ENTER_EVENT);\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).toBeNull();\n    }));\n\n    it('should not submit with invalid input', fakeAsync(() => {\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      const input = getPickerInput(fixture.debugElement) as HTMLInputElement;\n      input.value = 'invalid input';\n      fixture.detectChanges();\n      input.dispatchEvent(ENTER_EVENT);\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).not.toBeNull();\n    }));\n\n    it('should have focus when opened programmatically', fakeAsync(() => {\n      fixture.detectChanges();\n      openPickerByCode();\n      expect(document.activeElement).toEqual(getPickerInput(fixture.debugElement));\n    }));\n\n    it('should open by click and close by tab', fakeAsync(() => {\n      const nzOnChange = spyOn(fixtureInstance, 'nzOnChange');\n      fixtureInstance.useSuite = 5;\n\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(getPickerContainer()).not.toBeNull();\n\n      typeInElement('2021-04-12', getPickerInput(fixture.debugElement));\n      fixture.detectChanges();\n\n      triggerInputBlur();\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      const result = (nzOnChange.calls.allArgs()[0] as Date[])[0];\n      expect(isSameDay(new Date('2021-04-12'), result)).toBeTruthy();\n      expect(getPickerContainer()).toBeNull();\n    }));\n\n    it(\"should not send onChangeEvent if value doesn't change\", fakeAsync(() => {\n      const nzOnChange = spyOn(fixtureInstance, 'nzOnChange');\n      fixtureInstance.useSuite = 5;\n      fixtureInstance.firstValue = new Date('2021-04-12');\n      fixture.detectChanges();\n\n      openPickerByClickTrigger();\n      expect(getPickerContainer()).not.toBeNull();\n      typeInElement('2021-04-12', getPickerInput(fixture.debugElement));\n      fixture.detectChanges();\n\n      triggerInputBlur();\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      expect(nzOnChange).not.toHaveBeenCalled();\n      expect(getPickerContainer()).toBeNull();\n    }));\n\n    it('should support changing language at runtime', fakeAsync(() => {\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement).placeholder).toBe('请选择日期');\n      i18nService.setLocale(en_US);\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement).placeholder).toBe('Select date');\n\n      openPickerByClickTrigger();\n      expect(queryFromOverlay(`.${PREFIX_CLASS}-content th`).textContent).toContain('Su');\n    }));\n\n    /* Issue https://github.com/NG-ZORRO/ng-zorro-antd/issues/1539 */\n    it('should be able to open after closed by \"Escape\" key', fakeAsync(() => {\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(getPickerContainer()).not.toBeNull();\n\n      dispatchKeyboardEvent(document.body, 'keydown', ESCAPE);\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).toBeNull();\n\n      openPickerByClickTrigger();\n      expect(getPickerContainer()).not.toBeNull();\n    }));\n\n    it('should prevent default on the mousedown event when mouse down in date picker', fakeAsync(() => {\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      const event = new MouseEvent('mousedown');\n      spyOn(event, 'preventDefault').and.callThrough();\n      fixture.nativeElement.querySelector(`.${PREFIX_CLASS}`).dispatchEvent(event);\n\n      expect(event.preventDefault).toHaveBeenCalled();\n    }));\n\n    it('should execute default on the mousedown event when mouse down in date picker input', fakeAsync(() => {\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      const event = new MouseEvent('mousedown');\n      spyOn(event, 'preventDefault').and.callThrough();\n      fixture.nativeElement.querySelector(`.${PREFIX_CLASS} input`).dispatchEvent(event);\n\n      expect(event.preventDefault).not.toHaveBeenCalled();\n    }));\n\n    it('should support nzAllowClear and work properly', fakeAsync(() => {\n      const clearBtnSelector = By.css(`.${PREFIX_CLASS}-clear`);\n      const initial = (fixtureInstance.nzValue = new Date());\n      fixtureInstance.nzAllowClear = false;\n      fixture.detectChanges();\n      expect(debugElement.query(clearBtnSelector)).toBeFalsy();\n\n      fixtureInstance.nzAllowClear = true;\n      tick(500);\n      fixture.detectChanges();\n      expect(fixtureInstance.nzValue).toBe(initial);\n      expect(debugElement.query(clearBtnSelector)).toBeDefined();\n\n      const nzOnChange = spyOn(fixtureInstance, 'nzOnChange');\n      debugElement.query(clearBtnSelector).nativeElement.click();\n      fixture.detectChanges();\n      expect(fixtureInstance.nzValue).toBe(initial);\n      expect(nzOnChange).toHaveBeenCalledWith(null);\n      expect(debugElement.query(clearBtnSelector)).toBeFalsy();\n    }));\n\n    it('should support nzAutoFocus', () => {\n      fixtureInstance.nzAutoFocus = true;\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement) === document.activeElement).toBeTruthy();\n    });\n\n    it('should support nzDisabled', fakeAsync(() => {\n      fixtureInstance.useSuite = 4;\n      fixtureInstance.nzDisabled = true;\n      fixtureInstance.nzAllowClear = true; // Make sure picker clear button shown up\n      fixtureInstance.nzValue = new Date();\n      fixtureInstance.control = new FormControl(new Date());\n      fixture.detectChanges();\n      flush();\n\n      const datePickerElement = fixture.debugElement.query(By.directive(NzDatePickerComponent)).nativeElement;\n      const inputElement = fixture.debugElement.query(By.css('input')).nativeElement as HTMLInputElement;\n\n      expect(datePickerElement.classList).toContain('ant-picker-disabled');\n      expect(inputElement.disabled).toBeTruthy();\n      openPickerByClickTrigger();\n      expect(getPickerContainer()).toBeNull();\n\n      fixtureInstance.control.enable();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(datePickerElement.classList).not.toContain('ant-picker-disabled');\n      expect(inputElement.disabled).toBeFalsy();\n      openPickerByClickTrigger();\n      expect(getPickerContainer()).not.toBeNull();\n\n      dispatchKeyboardEvent(document.body, 'keydown', ESCAPE);\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      fixtureInstance.control.disable();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(datePickerElement.classList).toContain('ant-picker-disabled');\n      expect(inputElement.disabled).toBeTruthy();\n      openPickerByClickTrigger();\n      expect(getPickerContainer()).toBeNull();\n    }));\n\n    it('should mark the control touched when user loseFocus of datePicker', fakeAsync(() => {\n      fixtureInstance.useSuite = 4;\n      fixtureInstance.control = new FormControl<Date | null>(null);\n      fixture.detectChanges();\n      flush();\n      const datePickerElement = fixture.debugElement.query(By.directive(NzDatePickerComponent)).nativeElement;\n      openPickerByClickTrigger();\n      expect(datePickerElement.classList).toContain('ng-untouched');\n      triggerInputBlur();\n      fixture.detectChanges();\n      flush();\n      expect(datePickerElement.classList).toContain('ng-touched');\n      expect(fixtureInstance.control.touched).toBeTruthy();\n    }));\n\n    it('should support nzInputReadOnly', fakeAsync(() => {\n      fixtureInstance.nzInputReadOnly = true;\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement).readOnly).toBeTruthy();\n\n      fixtureInstance.nzInputReadOnly = false;\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement).readOnly).not.toBeTruthy();\n    }));\n\n    it('should support nzOpen if assigned', fakeAsync(() => {\n      fixtureInstance.useSuite = 2;\n\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).toBeNull();\n      fixtureInstance.nzOpen = true;\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).not.toBeNull();\n\n      fixtureInstance.nzOpen = false;\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).toBeNull();\n    }));\n\n    it('should support nzFormat', fakeAsync(() => {\n      fixtureInstance.nzFormat = 'dd.MM.yyyy';\n      fixtureInstance.nzValue = new Date('2020-03-04');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      const input = getPickerInput(fixture.debugElement);\n      expect(input.value).toBe('04.03.2020');\n      dispatchMouseEvent(queryFromOverlay('.ant-picker-cell')!, 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(input.value).toBe('24.02.2020');\n    }));\n\n    it('should rerender input value when nzFormat changed', fakeAsync(() => {\n      fixtureInstance.nzFormat = 'dd.MM.yyyy';\n      fixtureInstance.nzValue = new Date('2025-05-23');\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      const input = getPickerInput(fixture.debugElement);\n      expect(input.value).toBe('23.05.2025');\n      const nzOnChange = spyOn(fixtureInstance, 'nzOnChange');\n      fixtureInstance.nzFormat = 'dd/MM/yyyy';\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(input.value).toBe('23/05/2025');\n      expect(nzOnChange).not.toHaveBeenCalled();\n    }));\n\n    it('should support nzDisabledDate', fakeAsync(() => {\n      fixture.detectChanges();\n      const compareDate = new Date('2018-11-15 00:00:00');\n      fixtureInstance.nzValue = new Date('2018-11-11 12:12:12');\n      fixtureInstance.nzDisabledDate = (current: Date) => isSameDay(current, compareDate);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      const disabledCell = queryFromOverlay(`tbody tr td.${PREFIX_CLASS}-cell-disabled div`);\n      expect(disabledCell.textContent!.trim()).toBe('15');\n      const input = getPickerInput(fixture.debugElement);\n      const submit = (date: string): void => {\n        input.value = date;\n        fixture.detectChanges();\n        input.dispatchEvent(ENTER_EVENT);\n        fixture.detectChanges();\n        tick(500);\n        fixture.detectChanges();\n      };\n      // Should fail to submit a disabled date\n      submit('2018-11-15');\n      expect(getPickerContainer()).not.toBeNull();\n      // But it should be fine to submit an enabled date\n      submit('2018-11-11');\n      expect(getPickerContainer()).toBeNull();\n    }));\n\n    // #5633\n    it('should support disable year and month right', fakeAsync(() => {\n      fixture.detectChanges();\n      fixtureInstance.nzValue = new Date(2020, 0, 1);\n      fixtureInstance.nzDisabledDate = (date: Date): boolean =>\n        date >= new Date(2019, 0, 1) && date < new Date(2019, 0, 2);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      dispatchMouseEvent(queryFromOverlay('.ant-picker-header-year-btn'), 'click');\n      fixture.detectChanges();\n\n      const year2019 = getFirstCell();\n      expect(year2019.textContent!.trim()).toBe('2019');\n      expect(year2019.classList).not.toContain('ant-picker-cell-disabled');\n\n      dispatchMouseEvent(year2019, 'click');\n      fixture.detectChanges();\n      dispatchMouseEvent(queryFromOverlay('.ant-picker-header-month-btn'), 'click');\n      fixture.detectChanges();\n\n      const january = getFirstCell();\n      expect(january.textContent!.trim()).toContain('1');\n      expect(january.classList).not.toContain('ant-picker-cell-disabled');\n    }));\n\n    it('should support nzLocale', () => {\n      const featureKey = 'TEST_PLACEHOLDER';\n      fixtureInstance.nzLocale = { lang: { placeholder: featureKey } };\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement).getAttribute('placeholder')).toBe(featureKey);\n    });\n\n    it('should support nzPlaceHolder', () => {\n      const featureKey = (fixtureInstance.nzPlaceHolder = 'TEST_PLACEHOLDER');\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement).getAttribute('placeholder')).toBe(featureKey);\n    });\n\n    it('should support nzPopupStyle', fakeAsync(() => {\n      fixtureInstance.nzPopupStyle = { color: 'red' };\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(queryFromOverlay(`.${PREFIX_CLASS}-dropdown`).style.color).toBe('red');\n    }));\n\n    it('should support nzDropdownClassName', fakeAsync(() => {\n      const keyCls = (fixtureInstance.nzDropdownClassName = 'my-test-class');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(queryFromOverlay(`.${PREFIX_CLASS}-dropdown`).classList.contains(keyCls)).toBeTruthy();\n    }));\n\n    it('should support nzSize', () => {\n      fixtureInstance.nzSize = 'large';\n      fixture.detectChanges();\n      expect(getPickerAbstract(fixture.debugElement).classList.contains(`${PREFIX_CLASS}-large`)).toBeTruthy();\n\n      fixtureInstance.nzSize = 'small';\n      fixture.detectChanges();\n      expect(getPickerAbstract(fixture.debugElement).classList.contains(`${PREFIX_CLASS}-small`)).toBeTruthy();\n    });\n\n    it('should support nzOnOpenChange', fakeAsync(() => {\n      const nzOnOpenChange = spyOn(fixtureInstance, 'nzOnOpenChange');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(nzOnOpenChange).toHaveBeenCalledWith(true);\n\n      triggerInputBlur();\n      fixture.detectChanges();\n      flush();\n      expect(nzOnOpenChange).toHaveBeenCalledWith(false);\n      expect(nzOnOpenChange).toHaveBeenCalledTimes(2);\n    }));\n\n    it('should not emit nzOnOpenChange second time when input clicked twice', fakeAsync(() => {\n      const nzOnOpenChange = spyOn(fixtureInstance, 'nzOnOpenChange');\n\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      expect(nzOnOpenChange).toHaveBeenCalledWith(true);\n      expect(nzOnOpenChange).toHaveBeenCalledTimes(1);\n    }));\n\n    it('should not emit nzOnOpenChange when nzOpen is false and input is clicked', fakeAsync(() => {\n      const nzOnOpenChange = spyOn(fixtureInstance, 'nzOnOpenChange');\n      fixtureInstance.useSuite = 2;\n      fixtureInstance.nzOpen = false;\n\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      expect(nzOnOpenChange).not.toHaveBeenCalledWith(true);\n    }));\n\n    it('should support nzValue', fakeAsync(() => {\n      fixtureInstance.nzDefaultPickerValue = new Date('2015-09-17');\n      fixtureInstance.nzValue = new Date('2018-11-11');\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(getSelectedDayCell().textContent!.trim()).toBe('11');\n    }));\n\n    it('should support nzOnChange', fakeAsync(() => {\n      fixtureInstance.nzValue = new Date('2018-11-11');\n      const nzOnChange = spyOn(fixtureInstance, 'nzOnChange');\n      const nzOnCalendarChange = spyOn(fixtureInstance, 'nzOnCalendarChange');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      const cell = getFirstCell(); // Use the first cell\n      const cellText = cell.textContent!.trim();\n      dispatchMouseEvent(cell, 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(nzOnChange).toHaveBeenCalled();\n      expect(nzOnCalendarChange).not.toHaveBeenCalled();\n      const result = (nzOnChange.calls.allArgs()[0] as Date[])[0];\n      expect(result.getDate()).toBe(+cellText);\n    }));\n\n    it('should support nzDefaultPickerValue', fakeAsync(() => {\n      fixture.detectChanges();\n      fixtureInstance.nzDefaultPickerValue = new Date('2015-09-17');\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(queryFromOverlay('.ant-picker-header-year-btn').textContent!.indexOf('2015') > -1).toBeTruthy();\n      expect(queryFromOverlay('.ant-picker-header-month-btn').textContent!.indexOf('9') > -1).toBeTruthy();\n    }));\n\n    it('should support custom suffixIcon', fakeAsync(() => {\n      fixtureInstance.nzSuffixIcon = 'clock-circle';\n      fixture.detectChanges();\n      expect(debugElement.query(By.css(`.anticon-clock-circle`))).toBeDefined();\n    }));\n\n    describe('should support nzVariant', () => {\n      it('borderless', () => {\n        fixture.detectChanges();\n        expect(debugElement.query(By.css(`.ant-picker-borderless`))).toBeNull();\n        fixtureInstance.nzVariant = 'borderless';\n        fixture.detectChanges();\n        expect(debugElement.query(By.css(`.ant-picker-borderless`))).toBeDefined();\n      });\n\n      it('filled', () => {\n        fixture.detectChanges();\n        expect(debugElement.query(By.css(`.ant-picker-filled`))).toBeNull();\n        fixtureInstance.nzVariant = 'filled';\n        fixture.detectChanges();\n        expect(debugElement.query(By.css(`.ant-picker-filled`))).toBeDefined();\n      });\n\n      it('underlined', () => {\n        fixture.detectChanges();\n        expect(debugElement.query(By.css(`.ant-picker-underlined`))).toBeNull();\n        fixtureInstance.nzVariant = 'underlined';\n        fixture.detectChanges();\n        expect(debugElement.query(By.css(`.ant-picker-underlined`))).toBeDefined();\n      });\n    });\n\n    it('should support nzInline', fakeAsync(() => {\n      const nzOnChange = spyOn(fixtureInstance, 'nzOnChange');\n      fixtureInstance.nzInline = true;\n      fixture.detectChanges();\n      overlayContainerElement = debugElement.nativeElement as HTMLLIElement;\n      const cell = getFirstCell(); // Use the first cell\n      const cellText = cell.textContent!.trim();\n      dispatchMouseEvent(cell, 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(nzOnChange).toHaveBeenCalled();\n      const result = (nzOnChange.calls.allArgs()[0] as Date[])[0];\n      expect(result.getDate()).toBe(+cellText);\n    }));\n\n    it('should not run change detection when inline mode is enabled and the `date-range-popup` is clicked', () => {\n      fixtureInstance.nzInline = true;\n      fixture.detectChanges();\n\n      const appRef = TestBed.inject(ApplicationRef);\n      const event = new MouseEvent('mousedown');\n\n      spyOn(appRef, 'tick');\n      spyOn(event, 'preventDefault').and.callThrough();\n\n      debugElement.nativeElement.querySelector('date-range-popup').dispatchEvent(event);\n\n      expect(appRef.tick).not.toHaveBeenCalled();\n      expect(event.preventDefault).toHaveBeenCalled();\n    });\n\n    it('should support nzBackdrop', fakeAsync(() => {\n      fixtureInstance.nzBackdrop = true;\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      const boundingBox = overlayContainerElement.children[0];\n      expect(boundingBox.children[0].classList).toContain('cdk-overlay-backdrop');\n    }));\n\n    // TODO: why this works well locally but fails on CI?\n    xit('should support nzPlacement', fakeAsync(() => {\n      fixtureInstance.nzPlacement = 'bottomLeft';\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      let element = queryFromOverlay('.ant-picker-dropdown');\n      expect(element.classList.contains('ant-picker-dropdown-placement-bottomLeft')).toBe(true);\n      expect(element.classList.contains('ant-picker-dropdown-placement-topLeft')).toBe(false);\n      expect(element.classList.contains('ant-picker-dropdown-placement-bottomRight')).toBe(false);\n      expect(element.classList.contains('ant-picker-dropdown-placement-topRight')).toBe(false);\n      triggerInputBlur();\n      fixture.detectChanges();\n      tick(500);\n\n      fixtureInstance.nzPlacement = 'bottomRight';\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      element = queryFromOverlay('.ant-picker-dropdown');\n      expect(element.classList.contains('ant-picker-dropdown-placement-bottomLeft')).toBe(false);\n      expect(element.classList.contains('ant-picker-dropdown-placement-topLeft')).toBe(false);\n      expect(element.classList.contains('ant-picker-dropdown-placement-bottomRight')).toBe(true);\n      expect(element.classList.contains('ant-picker-dropdown-placement-topRight')).toBe(false);\n\n      fixtureInstance.nzPlacement = 'topLeft';\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      element = queryFromOverlay('.ant-picker-dropdown');\n      expect(element.classList.contains('ant-picker-dropdown-placement-bottomLeft')).toBe(false);\n      expect(element.classList.contains('ant-picker-dropdown-placement-topLeft')).toBe(true);\n      expect(element.classList.contains('ant-picker-dropdown-placement-bottomRight')).toBe(false);\n      expect(element.classList.contains('ant-picker-dropdown-placement-topRight')).toBe(false);\n\n      fixtureInstance.nzPlacement = 'topRight';\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      element = queryFromOverlay('.ant-picker-dropdown');\n      expect(element.classList.contains('ant-picker-dropdown-placement-bottomLeft')).toBe(false);\n      expect(element.classList.contains('ant-picker-dropdown-placement-topLeft')).toBe(false);\n      expect(element.classList.contains('ant-picker-dropdown-placement-bottomRight')).toBe(false);\n      expect(element.classList.contains('ant-picker-dropdown-placement-topRight')).toBe(true);\n\n      triggerInputBlur();\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n    }));\n\n    it('should support nzShowWeekNumber', fakeAsync(() => {\n      fixtureInstance.nzShowWeekNumber = true;\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(queryFromOverlay('.ant-picker-week-panel-row .ant-picker-cell-week')).toBeDefined();\n      fixtureInstance.nzShowWeekNumber = false;\n      fixture.detectChanges();\n      tick(500);\n      openPickerByClickTrigger();\n      expect(queryFromOverlay('.ant-picker-week-panel-row .ant-picker-cell-week')).toBeNull();\n    }));\n  });\n\n  describe('panel switch and move forward/afterward', () => {\n    beforeEach(() => (fixtureInstance.useSuite = 1));\n\n    it('should support date panel changes on click month', fakeAsync(() => {\n      fixtureInstance.nzValue = new Date('2018-11-11');\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      // Click month\n      dispatchMouseEvent(queryFromOverlay('.ant-picker-header-month-btn'), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      dispatchMouseEvent(getFirstCell(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      // click 2018-01-01\n      dispatchMouseEvent(getFirstCell(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement).value).toBe('2018-01-01');\n    }));\n\n    it('should support date panel changes', fakeAsync(() => {\n      fixtureInstance.nzValue = new Date('2018-11-11');\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      // Click previous year button\n      dispatchMouseEvent(getSuperPreBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-header-year-btn').textContent!.indexOf('2017') > -1).toBeTruthy();\n      // Click next year button * 2\n      dispatchMouseEvent(getSuperNextBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      dispatchMouseEvent(getSuperNextBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-header-year-btn').textContent!.indexOf('2019') > -1).toBeTruthy();\n      // Click previous month button\n      dispatchMouseEvent(getPreBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-header-month-btn').textContent!.indexOf('10') > -1).toBeTruthy();\n      // Click next month button * 2\n      dispatchMouseEvent(getNextBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      dispatchMouseEvent(getNextBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-header-month-btn').textContent!.indexOf('12') > -1).toBeTruthy();\n    }));\n\n    it('should support month panel changes', fakeAsync(() => {\n      fixtureInstance.nzValue = new Date('2018-11-11');\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      // Click month select to show month panel\n      dispatchMouseEvent(queryFromOverlay('.ant-picker-header-month-btn'), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-month-panel')).toBeDefined();\n      expect(queryFromOverlay('.ant-picker-header-month-btn').textContent!.indexOf('2018') > -1).toBeTruthy();\n      // Goto previous year\n      dispatchMouseEvent(getSuperPreBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-header-month-btn').textContent!.indexOf('2017') > -1).toBeTruthy();\n      // Goto next year * 2\n      dispatchMouseEvent(getSuperNextBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      dispatchMouseEvent(getSuperNextBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-header-month-btn').textContent!.indexOf('2019') > -1).toBeTruthy();\n      // Click to choose a year to change panel\n      dispatchMouseEvent(queryFromOverlay('td.ant-picker-cell'), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-date-panel')).toBeTruthy();\n    }));\n\n    it('should support year panel changes', fakeAsync(() => {\n      fixtureInstance.nzValue = new Date('2018-11-11');\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      // Click year select to show year panel\n      dispatchMouseEvent(queryFromOverlay('.ant-picker-header-year-btn'), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-year-panel')).toBeDefined();\n      expect(queryFromOverlay('.ant-picker-header-year-btn').textContent!.indexOf('2010') > -1).toBeTruthy();\n      expect(queryFromOverlay('.ant-picker-header-year-btn').textContent!.indexOf('2019') > -1).toBeTruthy();\n      // Coverage for last/next cell\n      dispatchMouseEvent(getSuperPreBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      dispatchMouseEvent(getSuperNextBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      // Goto previous decade\n      dispatchMouseEvent(getSuperPreBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-header-year-btn').textContent!.indexOf('2000') > -1).toBeTruthy();\n      expect(queryFromOverlay('.ant-picker-header-year-btn').textContent!.indexOf('2009') > -1).toBeTruthy();\n      // Goto next decade * 2\n      dispatchMouseEvent(getSuperNextBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      dispatchMouseEvent(getSuperNextBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-header-year-btn').textContent!.indexOf('2020') > -1).toBeTruthy();\n      expect(queryFromOverlay('.ant-picker-header-year-btn').textContent!.indexOf('2029') > -1).toBeTruthy();\n      // Click to choose a year to change panel\n      dispatchMouseEvent(queryFromOverlay('td.ant-picker-cell'), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-header .ant-picker-year-panel')).toBeFalsy();\n    }));\n\n    it('should support decade panel changes', fakeAsync(() => {\n      fixtureInstance.nzValue = new Date('2018-11-11');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      // Click to show decade panel\n      dispatchMouseEvent(queryFromOverlay('.ant-picker-header-year-btn'), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      dispatchMouseEvent(queryFromOverlay('.ant-picker-header-year-btn'), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-decade-panel')).toBeDefined();\n      // Coverage for last/next cell\n      dispatchMouseEvent(getSuperNextBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      dispatchMouseEvent(getSuperPreBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      // Goto previous century\n      dispatchMouseEvent(getSuperPreBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-header-decade-btn').textContent!.indexOf('1900') > -1).toBeTruthy();\n      expect(queryFromOverlay('.ant-picker-header-decade-btn').textContent!.indexOf('1999') > -1).toBeTruthy();\n      // Goto next century * 2\n      dispatchMouseEvent(getSuperNextBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      dispatchMouseEvent(getSuperNextBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-header-decade-btn').textContent!.indexOf('2100') > -1).toBeTruthy();\n      expect(queryFromOverlay('.ant-picker-header-decade-btn').textContent!.indexOf('2199') > -1).toBeTruthy();\n      // Click to choose a decade to change panel\n      dispatchMouseEvent(queryFromOverlay('td.ant-picker-cell'), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-year-panel')).toBeDefined();\n    }));\n  }); // /panel switch and move forward/afterward\n\n  describe('specified date picker testing', () => {\n    beforeEach(() => (fixtureInstance.useSuite = 1));\n\n    it('should support nzDateRender', fakeAsync(() => {\n      fixtureInstance.nzDateRender = fixtureInstance.tplDateRender;\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(queryFromOverlay('.test-first-day').textContent!.trim()).toBe('1');\n    }));\n\n    it('should support nzDateRender with typeof function', fakeAsync(() => {\n      const featureKey = 'TEST_FIRST_DAY';\n      fixtureInstance.nzDateRender = (d: Date) => (d.getDate() === 1 ? featureKey : d.getDate());\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(overlayContainerElement.textContent!.indexOf(featureKey) > -1).toBeTruthy();\n    }));\n\n    it('should support nzShowTime', fakeAsync(() => {\n      fixtureInstance.nzValue = new Date('2018-11-11 11:22:33');\n      fixtureInstance.nzShowTime = '' as NzSafeAny;\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      flush();\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-ok')).toBeDefined();\n      expect(queryFromOverlay('.ant-picker-time-panel')).toBeDefined();\n      expect(\n        queryFromOverlay('.ant-picker-time-panel-cell-selected .ant-picker-time-panel-cell-inner').textContent!.trim()\n      ).toBe('11');\n\n      // Click to choose an hour\n      dispatchMouseEvent(queryFromOverlay('.ant-picker-time-panel-cell:first-child'), 'click');\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement).value).toBe('2018-11-11 00:22:33');\n    }));\n\n    it('should support nzShowTime.nzDefaultOpenValue', fakeAsync(() => {\n      fixtureInstance.nzValue = null;\n      fixtureInstance.nzShowTime = { nzDefaultOpenValue: new Date(0, 0, 0, 0, 1, 2) };\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      dispatchMouseEvent(getFirstCell(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement).value).toContain('00:01:02');\n\n      const listOfSelectedLi = overlayContainerElement.querySelectorAll(\n        '.ant-picker-time-panel-cell-selected .ant-picker-time-panel-cell-inner'\n      );\n      expect(listOfSelectedLi[0].textContent!.trim()).toBe('00');\n      expect(listOfSelectedLi[1].textContent!.trim()).toBe('01');\n      expect(listOfSelectedLi[2].textContent!.trim()).toBe('02');\n    }));\n\n    it('should not reset time', fakeAsync(() => {\n      fixtureInstance.nzValue = new Date('2019-08-02 13:03:33');\n      fixtureInstance.nzShowTime = true;\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      dispatchMouseEvent(getFirstCell(), 'click');\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement).value).toBe('2019-07-29 13:03:33');\n    }));\n\n    it('should support nzShowTime.nzFormat', fakeAsync(() => {\n      fixtureInstance.nzShowTime = { nzFormat: 'HH:mm' };\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(overlayContainerElement.querySelectorAll('.ant-picker-time-panel-column').length).toBe(2);\n    }));\n\n    it('should support nzDisabledTime and nzShowTime.nzHideDisabledOptions', fakeAsync(() => {\n      fixtureInstance.nzShowTime = true;\n      fixtureInstance.nzDisabledTime = () => ({\n        nzDisabledHours: () => [0, 1, 2],\n        nzDisabledMinutes: () => [0, 1],\n        nzDisabledSeconds: () => [0]\n      });\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      expect(\n        queryFromOverlay('.ant-picker-time-panel-column li:nth-child(3)').classList.contains(\n          'ant-picker-time-panel-cell-disabled'\n        )\n      ).toBeTruthy();\n      expect(\n        queryFromOverlay('.ant-picker-time-panel-column:nth-child(2) li:nth-child(2)').classList.contains(\n          'ant-picker-time-panel-cell-disabled'\n        )\n      ).toBeTruthy();\n      expect(\n        queryFromOverlay('.ant-picker-time-panel-column:nth-child(3) li:nth-child(1)').classList.contains(\n          'ant-picker-time-panel-cell-disabled'\n        )\n      ).toBeTruthy();\n\n      // Use nzHideDisabledOptions to hide disabled times\n      fixtureInstance.nzShowTime = { nzHideDisabledOptions: true };\n      fixture.detectChanges();\n      expect(+queryFromOverlay('.ant-picker-time-panel-column:nth-child(1) li:first-child').textContent!.trim()).toBe(\n        3\n      );\n      expect(+queryFromOverlay('.ant-picker-time-panel-column:nth-child(2) li:first-child').textContent!.trim()).toBe(\n        2\n      );\n      expect(+queryFromOverlay('.ant-picker-time-panel-column:nth-child(3) li:first-child').textContent!.trim()).toBe(\n        1\n      );\n    }));\n\n    it('should nzDisabledTime invalid input not emit', fakeAsync(() => {\n      fixtureInstance.nzShowTime = true;\n      fixtureInstance.nzDisabledTime = () => ({\n        nzDisabledHours: () => [0, 1, 2],\n        nzDisabledMinutes: () => [0, 1],\n        nzDisabledSeconds: () => [0]\n      });\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      // input disabled value\n      const input = getPickerInput(fixture.debugElement);\n      typeInElement('2020-03-14 00:00:00', input);\n      fixture.detectChanges();\n      input.dispatchEvent(ENTER_EVENT);\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).not.toBeNull();\n\n      triggerInputBlur();\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement).value).toBe('');\n    }));\n\n    it('should support updating the nzDisabledTime state when the current time changes', fakeAsync(() => {\n      fixtureInstance.nzShowTime = true;\n      fixtureInstance.nzDisabledTime = (current: Date) => ({\n        nzDisabledHours: () => {\n          if (current) {\n            if (current.getMonth() === 2) {\n              return [0, 1, 2];\n            } else {\n              return [4, 5, 6];\n            }\n          } else {\n            return [7, 8, 9];\n          }\n        },\n        nzDisabledMinutes: () => [],\n        nzDisabledSeconds: () => []\n      });\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      // input disabled value\n      const input = getPickerInput(fixture.debugElement);\n      typeInElement('2020-03-14 00:00:00', input);\n      fixture.detectChanges();\n      expect(\n        queryFromOverlay('.ant-picker-time-panel-column li:nth-child(3)').classList.contains(\n          'ant-picker-time-panel-cell-disabled'\n        )\n      ).toBeTruthy();\n\n      // input disabled value\n      typeInElement('2020-04-14 00:00:00', input);\n      fixture.detectChanges();\n      expect(\n        queryFromOverlay('.ant-picker-time-panel-column li:nth-child(5)').classList.contains(\n          'ant-picker-time-panel-cell-disabled'\n        )\n      ).toBeTruthy();\n    }));\n\n    it('should support nzRenderExtraFooter', fakeAsync(() => {\n      fixtureInstance.nzRenderExtraFooter = () => fixtureInstance.tplExtraFooter;\n      fixture.detectChanges();\n\n      openPickerByClickTrigger();\n      expect(overlayContainerElement.textContent!.indexOf('TEST_EXTRA_FOOTER') > -1).toBeTruthy();\n\n      fixtureInstance.nzRenderExtraFooter = 'TEST_EXTRA_FOOTER_STRING';\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent!.indexOf(fixtureInstance.nzRenderExtraFooter) > -1).toBeTruthy();\n    }));\n\n    it('should support nzShowToday', fakeAsync(() => {\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(overlayContainerElement.querySelector('.ant-picker-footer')).toBeDefined();\n\n      fixtureInstance.nzShowToday = true;\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-picker-today-btn')).toBeDefined();\n\n      // Click today button\n      const nzOnChange = spyOn(fixtureInstance, 'nzOnChange');\n      dispatchMouseEvent(queryFromOverlay('.ant-picker-today-btn'), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      const result = (nzOnChange.calls.allArgs()[0] as Date[])[0];\n      expect(isSameDay(new Date(), result)).toBeTruthy();\n      expect(queryFromOverlay('.ant-picker-container')).toBeFalsy(); // Should be closed\n    }));\n\n    it('should support nzShowNow', fakeAsync(() => {\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(overlayContainerElement.querySelector('.ant-picker-footer')).toBeDefined();\n\n      fixtureInstance.nzShowTime = true;\n\n      fixtureInstance.nzShowNow = false;\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-picker-now-btn')).toBeNull();\n\n      fixtureInstance.nzShowNow = true;\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-picker-now-btn')).toBeDefined();\n\n      // Click now button\n      const nzOnChange = spyOn(fixtureInstance, 'nzOnChange');\n      dispatchMouseEvent(queryFromOverlay('.ant-picker-now-btn'), 'click');\n      fixture.detectChanges();\n\n      // Click ok button\n      dispatchMouseEvent(overlayContainerElement.querySelector('.ant-picker-ok > button')!, 'click');\n      const result = (nzOnChange.calls.allArgs()[0] as Date[])[0];\n      expect(isEqual(new Date(), result)).toBeTruthy();\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-container')).toBeFalsy(); // Should be closed\n    }));\n\n    it('should support nzMode', fakeAsync(() => {\n      fixtureInstance.nzValue = new Date('2020-12-01');\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement).placeholder).toEqual('请选择日期');\n\n      fixtureInstance.nzMode = 'month';\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement).placeholder).toEqual('请选择月份');\n      expect(getPickerInput(fixture.debugElement).value).toEqual('2020-12');\n\n      openPickerByClickTrigger();\n      expect(overlayContainerElement.querySelector('.ant-picker-month-panel')).toBeDefined();\n    }));\n\n    it('should support nzOnPanelChange', fakeAsync(() => {\n      fixtureInstance.nzValue = new Date('2020-12-01');\n      spyOn(fixtureInstance, 'nzOnPanelChange');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      // Click header to month panel\n      dispatchMouseEvent(overlayContainerElement.querySelector('.ant-picker-header-month-btn')!, 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(fixtureInstance.nzOnPanelChange).toHaveBeenCalledWith({ mode: 'month', date: new Date('2020-12-01') });\n    }));\n\n    it('should support nzOnPanelChange when next button is clicked', fakeAsync(() => {\n      fixtureInstance.nzValue = new Date('2020-11-01');\n      spyOn(fixtureInstance, 'nzOnPanelChange');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      dispatchMouseEvent(getNextBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(fixtureInstance.nzOnPanelChange).toHaveBeenCalledWith({ mode: 'date', date: new Date('2020-12-01') });\n    }));\n\n    it('should support nzOnPanelChange when super next button is clicked', fakeAsync(() => {\n      fixtureInstance.nzValue = new Date('2020-11-01');\n      spyOn(fixtureInstance, 'nzOnPanelChange');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      dispatchMouseEvent(getSuperNextBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(fixtureInstance.nzOnPanelChange).toHaveBeenCalledWith({ mode: 'date', date: new Date('2021-11-01') });\n    }));\n\n    it('should support nzOnPanelChange when previous button is clicked', fakeAsync(() => {\n      fixtureInstance.nzValue = new Date('2020-11-01 11:22:33');\n      spyOn(fixtureInstance, 'nzOnPanelChange');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      dispatchMouseEvent(getPreBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(fixtureInstance.nzOnPanelChange).toHaveBeenCalledWith({\n        mode: 'date',\n        date: new Date('2020-10-01 11:22:33')\n      });\n    }));\n\n    it('should support nzOnPanelChange when super previous button is clicked', fakeAsync(() => {\n      fixtureInstance.nzValue = new Date('2020-11-01 11:22:33');\n      spyOn(fixtureInstance, 'nzOnPanelChange');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      dispatchMouseEvent(getSuperPreBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(fixtureInstance.nzOnPanelChange).toHaveBeenCalledWith({\n        mode: 'date',\n        date: new Date('2019-11-01 11:22:33')\n      });\n    }));\n\n    it('should support nzOnOk', fakeAsync(() => {\n      spyOn(fixtureInstance, 'nzOnOk');\n      fixtureInstance.nzValue = new Date('2018-11-11 11:22:33');\n      fixtureInstance.nzShowTime = true;\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      // Click ok button\n      dispatchMouseEvent(overlayContainerElement.querySelector('.ant-picker-ok > button')!, 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(fixtureInstance.nzOnOk).toHaveBeenCalledWith(fixtureInstance.nzValue);\n    }));\n\n    it('should custom input date', fakeAsync(() => {\n      const nzOnChange = spyOn(fixtureInstance, 'nzOnChange');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      const input = getPickerInput(fixture.debugElement);\n\n      // Wrong input support\n      typeInElement('wrong', input);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      // expect(input.classList.contains('ant-calendar-input-invalid')).toBeTruthy();\n\n      // Correct input\n      input.value = '2018-11-22';\n      input.dispatchEvent(ENTER_EVENT);\n      // dispatchKeyboardEvent(input, 'keyup', ENTER); // Not working?\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(nzOnChange).toHaveBeenCalled();\n      const result = (nzOnChange.calls.allArgs()[0] as Date[])[0];\n      expect(result.getDate()).toBe(22);\n    }));\n\n    // #6070\n    it('should reset after input invalid value and close panel', fakeAsync(() => {\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      const input = getPickerInput(fixture.debugElement);\n\n      // Wrong input support\n      typeInElement('wrong', input);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n\n      triggerInputBlur();\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(input.value).toBe('');\n    }));\n  }); // /specified date picker testing\n\n  function getPreBtn(): HTMLElement {\n    return queryFromOverlay(`.${PREFIX_CLASS}-header-prev-btn`);\n  }\n\n  function getNextBtn(): HTMLElement {\n    return queryFromOverlay(`.${PREFIX_CLASS}-header-next-btn`);\n  }\n\n  function getSuperPreBtn(): HTMLElement {\n    return queryFromOverlay(`.${PREFIX_CLASS}-header-super-prev-btn`);\n  }\n\n  function getSuperNextBtn(): HTMLElement {\n    return queryFromOverlay(`.${PREFIX_CLASS}-header-super-next-btn`);\n  }\n\n  describe('ngModel value accessors', () => {\n    beforeEach(() => (fixtureInstance.useSuite = 3));\n\n    it('should specified date provide by \"modelValue\" be chosen', fakeAsync(() => {\n      fixtureInstance.modelValue = new Date('2018-11-11');\n      fixture.detectChanges();\n      flush(); // Wait writeValue() tobe done\n      fixture.detectChanges();\n      expect(getSelectedDayCell().textContent!.trim()).toBe('11');\n\n      // Click the first cell to change ngModel\n      const cell = getFirstCell();\n      const cellText = cell.textContent!.trim();\n      dispatchMouseEvent(cell, 'click');\n      fixture.detectChanges();\n      expect(fixtureInstance.modelValue.getDate()).toBe(+cellText);\n    }));\n  });\n\n  describe('formControl', () => {\n    beforeEach(() => (fixtureInstance.useSuite = 4));\n\n    it('should formControl init work', fakeAsync(() => {\n      fixtureInstance.control = new FormControl(new Date('2020-04-08'));\n      fixture.detectChanges();\n      flush(); // Wait writeValue() tobe done\n      fixture.detectChanges();\n      const datePickerElement = fixture.debugElement.query(By.directive(NzDatePickerComponent)).nativeElement;\n      const inputElement = fixture.debugElement.query(By.css('input')).nativeElement as HTMLInputElement;\n\n      expect(datePickerElement.classList).not.toContain('ant-picker-disabled');\n      expect(inputElement.disabled).toBeFalsy();\n      expect(getPickerInput(fixture.debugElement).value!.trim()).toBe('2020-04-08');\n    }));\n\n    it('should disabled work', fakeAsync(() => {\n      fixtureInstance.control = new FormControl({ value: new Date('2020-04-24'), disabled: true });\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement).getAttribute('disabled')).not.toBeNull();\n    }));\n  });\n\n  function getPickerContainer(): HTMLElement {\n    return queryFromOverlay(`.${PREFIX_CLASS}-panel-container`) as HTMLElement;\n  }\n\n  function getSelectedDayCell(): HTMLElement {\n    return queryFromOverlay(`.${PREFIX_CLASS}-body tr td.ant-picker-cell-selected div`) as HTMLElement;\n  }\n\n  function getFirstCell(): HTMLElement {\n    return queryFromOverlay(`.${PREFIX_CLASS}-body tr td`) as HTMLElement;\n  }\n\n  function queryFromOverlay(selector: string): HTMLElement {\n    return overlayContainerElement.querySelector(selector) as HTMLElement;\n  }\n\n  function openPickerByClickTrigger(): void {\n    dispatchMouseEvent(getPickerInput(fixture.debugElement), 'click');\n    fixture.detectChanges();\n    tick(500);\n    fixture.detectChanges();\n  }\n\n  function openPickerByCode(): void {\n    fixtureInstance.datePicker.open();\n    fixture.detectChanges();\n    tick(500);\n    fixture.detectChanges();\n  }\n\n  function triggerInputBlur(): void {\n    dispatchFakeEvent(getPickerInput(fixture.debugElement), 'focusout');\n  }\n});\n\ndescribe('date-fns testing', () => {\n  let fixture: ComponentFixture<NzTestDatePickerComponent>;\n  let fixtureInstance: NzTestDatePickerComponent;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), provideZoneChangeDetection(), { provide: NZ_DATE_LOCALE, useValue: enUS }]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzTestDatePickerComponent);\n    fixtureInstance = fixture.componentInstance;\n    fixtureInstance.useSuite = 1;\n  });\n\n  it('should parse input value with nzFormat', fakeAsync(() => {\n    const nzOnChange = spyOn(fixtureInstance, 'nzOnChange');\n    fixtureInstance.nzFormat = 'dd.MM.yyyy';\n    fixture.detectChanges();\n    dispatchMouseEvent(getPickerInput(fixture.debugElement), 'click');\n    fixture.detectChanges();\n    tick(500);\n    fixture.detectChanges();\n    const input = getPickerInput(fixture.debugElement);\n    expect(input).not.toBeNull();\n    typeInElement('25.10.2019', input);\n    fixture.detectChanges();\n    input.dispatchEvent(ENTER_EVENT);\n    fixture.detectChanges();\n    flush();\n    expect(nzOnChange).toHaveBeenCalled();\n    const result = (nzOnChange.calls.allArgs()[0] as Date[])[0];\n    expect(result.getFullYear()).toBe(2019);\n    expect(result.getMonth() + 1).toBe(10);\n    expect(result.getDate()).toBe(25);\n  }));\n});\n\ndescribe('date-picker status', () => {\n  let fixture: ComponentFixture<NzTestDatePickerStatusComponent>;\n  let fixtureInstance: NzTestDatePickerStatusComponent;\n  let datePickerElement!: HTMLElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzTestDatePickerStatusComponent);\n    fixtureInstance = fixture.componentInstance;\n    datePickerElement = fixture.debugElement.query(By.directive(NzDatePickerComponent)).nativeElement;\n    fixture.detectChanges();\n  });\n\n  it('should classname correct', () => {\n    expect(datePickerElement.classList).toContain('ant-picker-status-error');\n\n    fixtureInstance.status = 'warning';\n    fixture.detectChanges();\n    expect(datePickerElement.classList).toContain('ant-picker-status-warning');\n\n    fixtureInstance.status = '';\n    fixture.detectChanges();\n    expect(datePickerElement.classList).not.toContain('ant-picker-status-warning');\n  });\n});\n\ndescribe('in form', () => {\n  let fixture: ComponentFixture<NzTestDatePickerInFormComponent>;\n  let datePickerElement!: HTMLElement;\n  let formGroup: FormGroup<{\n    demo: FormControl<Date | null>;\n  }>;\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzTestDatePickerInFormComponent);\n    datePickerElement = fixture.debugElement.query(By.directive(NzDatePickerComponent)).nativeElement;\n    formGroup = fixture.componentInstance.validateForm;\n    fixture.detectChanges();\n  });\n\n  it('should classname correct', () => {\n    expect(datePickerElement.classList).not.toContain('ant-picker-status-error');\n    expect(datePickerElement.querySelector('nz-form-item-feedback-icon')).toBeNull();\n\n    formGroup.get('demo')!.markAsDirty();\n    formGroup.get('demo')!.setValue(null);\n    formGroup.get('demo')!.updateValueAndValidity();\n    fixture.detectChanges();\n    expect(datePickerElement.classList).toContain('ant-picker-status-error');\n    expect(datePickerElement.querySelector('nz-form-item-feedback-icon')).toBeTruthy();\n    expect(datePickerElement!.querySelector('nz-form-item-feedback-icon')!.className).toContain(\n      'ant-form-item-feedback-icon-error'\n    );\n\n    formGroup.get('demo')!.markAsDirty();\n    formGroup.get('demo')!.setValue(new Date());\n    formGroup.get('demo')!.updateValueAndValidity();\n    fixture.detectChanges();\n    // show success\n    expect(datePickerElement.classList).toContain('ant-picker-status-success');\n    expect(datePickerElement.querySelector('nz-form-item-feedback-icon')).toBeTruthy();\n    expect(datePickerElement.querySelector('nz-form-item-feedback-icon')!.className).toContain(\n      'ant-form-item-feedback-icon-success'\n    );\n  });\n});\n\ndescribe('finalSize', () => {\n  let fixture: ComponentFixture<TestDatePickerFinalSizeComponent>;\n  let datePickerElement: HTMLElement;\n  let compactSizeSignal: WritableSignal<NzSizeLDSType>;\n  let formSizeSignal: WritableSignal<NzSizeLDSType | undefined>;\n\n  beforeEach(() => {\n    compactSizeSignal = signal<NzSizeLDSType>('large');\n    formSizeSignal = signal<NzSizeLDSType>('default');\n  });\n  afterEach(() => {\n    TestBed.resetTestingModule();\n  });\n  it('should set correctly the size from the formSize signal', () => {\n    TestBed.configureTestingModule({\n      providers: [\n        { provide: NZ_FORM_SIZE, useValue: formSizeSignal },\n        { provide: NZ_SPACE_COMPACT_SIZE, useValue: compactSizeSignal }\n      ]\n    });\n    fixture = TestBed.createComponent(TestDatePickerFinalSizeComponent);\n    datePickerElement = fixture.debugElement.query(By.directive(NzDatePickerComponent)).nativeElement;\n    fixture.detectChanges();\n    formSizeSignal.set('large');\n    fixture.detectChanges();\n    expect(datePickerElement.classList).toContain('ant-picker-large');\n  });\n  it('should set correctly the size from the compactSize signal', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_SPACE_COMPACT_SIZE, useValue: compactSizeSignal }]\n    });\n    fixture = TestBed.createComponent(TestDatePickerFinalSizeComponent);\n    datePickerElement = fixture.debugElement.query(By.directive(NzDatePickerComponent)).nativeElement;\n    fixture.detectChanges();\n    expect(datePickerElement.classList).toContain('ant-picker-large');\n  });\n  it('should set correctly the size from the component input', () => {\n    fixture = TestBed.createComponent(TestDatePickerFinalSizeComponent);\n    datePickerElement = fixture.debugElement.query(By.directive(NzDatePickerComponent)).nativeElement;\n    fixture.componentInstance.size = 'large';\n    fixture.detectChanges();\n    expect(datePickerElement.classList).toContain('ant-picker-large');\n  });\n});\n\ndescribe('finalVariant', () => {\n  let fixture: ComponentFixture<TestDatePickerFinalVariantComponent>;\n  let datePickerElement: HTMLElement;\n  let formVariantSignal: WritableSignal<NzVariant>;\n\n  beforeEach(() => {\n    formVariantSignal = signal<NzVariant>('outlined');\n  });\n\n  afterEach(() => {\n    TestBed.resetTestingModule();\n  });\n\n  it('should use formVariant when nzVariant is not set (undefined by default)', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_FORM_VARIANT, useValue: formVariantSignal }]\n    });\n    fixture = TestBed.createComponent(TestDatePickerFinalVariantComponent);\n    datePickerElement = fixture.debugElement.query(By.directive(NzDatePickerComponent)).nativeElement;\n    fixture.detectChanges();\n    formVariantSignal.set('filled');\n    fixture.detectChanges();\n    expect(datePickerElement.classList).toContain('ant-picker-filled');\n  });\n\n  it('should use nzVariant over formVariant when nzVariant is explicitly set', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_FORM_VARIANT, useValue: formVariantSignal }]\n    });\n    fixture = TestBed.createComponent(TestDatePickerFinalVariantComponent);\n    datePickerElement = fixture.debugElement.query(By.directive(NzDatePickerComponent)).nativeElement;\n    fixture.componentInstance.variant.set('borderless');\n    fixture.detectChanges();\n    formVariantSignal.set('filled');\n    fixture.detectChanges();\n    expect(datePickerElement.classList).toContain('ant-picker-borderless');\n    expect(datePickerElement.classList).not.toContain('ant-picker-filled');\n  });\n\n  it('should use nzVariant outlined over formVariant when explicitly set', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_FORM_VARIANT, useValue: formVariantSignal }]\n    });\n    fixture = TestBed.createComponent(TestDatePickerFinalVariantComponent);\n    datePickerElement = fixture.debugElement.query(By.directive(NzDatePickerComponent)).nativeElement;\n    fixture.componentInstance.variant.set('outlined');\n    fixture.detectChanges();\n    formVariantSignal.set('filled');\n    fixture.detectChanges();\n    expect(datePickerElement.classList).not.toContain('ant-picker-filled');\n  });\n\n  it('should use nzVariant when no formVariant is provided', () => {\n    fixture = TestBed.createComponent(TestDatePickerFinalVariantComponent);\n    datePickerElement = fixture.debugElement.query(By.directive(NzDatePickerComponent)).nativeElement;\n    fixture.componentInstance.variant.set('filled');\n    fixture.detectChanges();\n    expect(datePickerElement.classList).toContain('ant-picker-filled');\n  });\n\n  it('should default to outlined when neither nzVariant nor formVariant is set', () => {\n    fixture = TestBed.createComponent(TestDatePickerFinalVariantComponent);\n    datePickerElement = fixture.debugElement.query(By.directive(NzDatePickerComponent)).nativeElement;\n    fixture.detectChanges();\n    expect(datePickerElement.classList).not.toContain('ant-picker-filled');\n    expect(datePickerElement.classList).not.toContain('ant-picker-borderless');\n    expect(datePickerElement.classList).not.toContain('ant-picker-underlined');\n  });\n});\n\n@Component({\n  imports: [ReactiveFormsModule, FormsModule, NzDatePickerModule],\n  template: `\n    @switch (useSuite) {\n      @case (1) {\n        <nz-date-picker\n          [nzAllowClear]=\"nzAllowClear\"\n          [nzAutoFocus]=\"nzAutoFocus\"\n          [nzDisabled]=\"nzDisabled\"\n          [nzInputReadOnly]=\"nzInputReadOnly\"\n          [nzDisabledDate]=\"nzDisabledDate\"\n          [nzFormat]=\"nzFormat\"\n          [nzLocale]=\"nzLocale\"\n          [nzPlaceHolder]=\"nzPlaceHolder\"\n          [nzPopupStyle]=\"nzPopupStyle\"\n          [nzDropdownClassName]=\"nzDropdownClassName\"\n          [nzSize]=\"nzSize\"\n          (nzOnOpenChange)=\"nzOnOpenChange($event)\"\n          [ngModel]=\"nzValue\"\n          (ngModelChange)=\"nzOnChange($event)\"\n          [nzDefaultPickerValue]=\"nzDefaultPickerValue\"\n          [nzDateRender]=\"nzDateRender\"\n          [nzDisabledTime]=\"nzDisabledTime\"\n          [nzRenderExtraFooter]=\"nzRenderExtraFooter\"\n          [nzShowToday]=\"nzShowToday\"\n          [nzShowNow]=\"nzShowNow\"\n          [nzMode]=\"nzMode\"\n          (nzOnPanelChange)=\"nzOnPanelChange($event)\"\n          (nzOnCalendarChange)=\"nzOnCalendarChange($event)\"\n          [nzShowTime]=\"nzShowTime\"\n          (nzOnOk)=\"nzOnOk($event)\"\n          [nzSuffixIcon]=\"nzSuffixIcon\"\n          [nzVariant]=\"nzVariant\"\n          [nzInline]=\"nzInline\"\n          [nzBackdrop]=\"nzBackdrop\"\n          [nzPlacement]=\"nzPlacement\"\n          [nzShowWeekNumber]=\"nzShowWeekNumber\"\n        />\n      }\n      @case (2) {\n        <nz-date-picker [nzOpen]=\"nzOpen\" (nzOnOpenChange)=\"nzOnOpenChange($event)\" />\n      }\n      @case (3) {\n        <nz-date-picker nzOpen [(ngModel)]=\"modelValue\" />\n      }\n      @case (4) {\n        <nz-date-picker [formControl]=\"control\" [nzDisabled]=\"nzDisabled\" />\n      }\n      @case (5) {\n        <ng-container>\n          <nz-date-picker [ngModel]=\"firstValue\" (ngModelChange)=\"nzOnChange($event)\" />\n          <nz-date-picker [ngModel]=\"secondValue\" />\n        </ng-container>\n      }\n    }\n    <ng-template #tplDateRender let-current>\n      <div [class.test-first-day]=\"current.getDate() === 1\">{{ current.getDate() }}</div>\n    </ng-template>\n    <ng-template #tplExtraFooter>TEST_EXTRA_FOOTER</ng-template>\n  `\n})\nclass NzTestDatePickerComponent {\n  useSuite!: 1 | 2 | 3 | 4 | 5;\n  @ViewChild('tplDateRender', { static: true }) tplDateRender!: TemplateRef<Date>;\n  @ViewChild('tplExtraFooter', { static: true }) tplExtraFooter!: TemplateRef<void>;\n  @ViewChild(NzDatePickerComponent, { static: false }) datePicker!: NzDatePickerComponent;\n  // --- Suite 1\n  nzAllowClear: boolean = false;\n  nzAutoFocus: boolean = false;\n  nzDisabled: boolean = false;\n  nzInputReadOnly: boolean = false;\n  nzFormat!: string;\n  nzDisabledDate!: (d: Date) => boolean;\n  nzLocale: NzSafeAny;\n  nzPlaceHolder!: string;\n  nzPopupStyle!: NgStyleInterface;\n  nzDropdownClassName!: string;\n  nzSize!: NzDatePickerSizeType;\n\n  nzOnChange(_: Date | null): void {}\n\n  nzOnCalendarChange(_: Array<Date | null>): void {}\n\n  nzOnOpenChange(_: boolean): void {}\n\n  nzValue: Date | null = null;\n  nzDefaultPickerValue: Date | null = null;\n  nzDateRender: NzSafeAny;\n  nzShowTime: boolean | object = false;\n  nzDisabledTime: NzSafeAny;\n  nzRenderExtraFooter!: string | (() => TemplateRef<void> | string);\n  nzShowToday = false;\n  nzShowNow = false;\n  nzMode: string = 'date';\n  nzSuffixIcon!: string;\n  nzVariant: NzVariant = 'outlined';\n  nzInline = false;\n  nzBackdrop = false;\n  nzPlacement: NzPlacement = 'bottomLeft';\n  nzShowWeekNumber = false;\n\n  // nzRanges;\n  nzOnPanelChange(_: NzPanelChangeType): void {}\n\n  nzOnOk(_: CompatibleDate | null): void {}\n\n  // --- Suite 2\n  nzOpen: boolean = false;\n\n  // --- Suite 3\n  modelValue!: Date;\n\n  // --- Suite 4\n  control!: FormControl<Date | null>;\n\n  // --- Suite 5\n  firstValue!: Date;\n  secondValue!: Date;\n}\n\n@Component({\n  imports: [NzDatePickerModule],\n  template: `<nz-date-picker [nzStatus]=\"status\" />`\n})\nclass NzTestDatePickerStatusComponent {\n  status: NzStatus = 'error';\n}\n\n@Component({\n  imports: [ReactiveFormsModule, NzFormModule, NzDatePickerModule],\n  template: `\n    <form nz-form [formGroup]=\"validateForm\">\n      <nz-form-item>\n        <nz-form-control nzHasFeedback>\n          <nz-date-picker formControlName=\"demo\" />\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `\n})\nclass NzTestDatePickerInFormComponent {\n  private fb = inject(FormBuilder);\n  validateForm = this.fb.group({\n    demo: this.fb.control<Date | null>(null, Validators.required)\n  });\n}\n\n@Component({\n  imports: [NzDatePickerModule],\n  template: `<nz-date-picker [nzSize]=\"size\" />`\n})\nexport class TestDatePickerFinalSizeComponent {\n  size: NzDatePickerSizeType = 'default';\n}\n\n@Component({\n  imports: [NzDatePickerModule],\n  template: `<nz-date-picker [nzVariant]=\"variant()\" />`\n})\nexport class TestDatePickerFinalVariantComponent {\n  readonly variant = signal<NzVariant | undefined>(undefined);\n}\n"
  },
  {
    "path": "components/date-picker/date-picker.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { ESCAPE } from '@angular/cdk/keycodes';\nimport {\n  CdkConnectedOverlay,\n  ConnectedOverlayPositionChange,\n  ConnectionPositionPair,\n  OriginConnectionPosition\n} from '@angular/cdk/overlay';\nimport { Platform } from '@angular/cdk/platform';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterViewInit,\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  computed,\n  DestroyRef,\n  DOCUMENT,\n  ElementRef,\n  EventEmitter,\n  forwardRef,\n  inject,\n  input,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  QueryList,\n  Renderer2,\n  signal,\n  SimpleChanges,\n  TemplateRef,\n  ViewChild,\n  ViewChildren,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { of } from 'rxjs';\nimport { distinctUntilChanged, map, withLatestFrom } from 'rxjs/operators';\n\nimport { NzResizeObserver } from 'ng-zorro-antd/cdk/resize-observer';\nimport { slideAnimationEnter, slideAnimationLeave } from 'ng-zorro-antd/core/animation';\nimport { NzConfigKey, NzConfigService, WithConfig } from 'ng-zorro-antd/core/config';\nimport {\n  NZ_FORM_SIZE,\n  NZ_FORM_VARIANT,\n  NzFormItemFeedbackIconComponent,\n  NzFormNoStatusService,\n  NzFormStatusService\n} from 'ng-zorro-antd/core/form';\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { DATE_PICKER_POSITION_MAP, DEFAULT_DATE_PICKER_POSITIONS, NzOverlayModule } from 'ng-zorro-antd/core/overlay';\nimport { CandyDate, cloneDate, CompatibleValue, wrongSortOrder } from 'ng-zorro-antd/core/time';\nimport {\n  BooleanInput,\n  FunctionProp,\n  NgClassInterface,\n  NzSafeAny,\n  NzSizeLDSType,\n  NzStatus,\n  NzValidateStatus,\n  NzVariant,\n  OnChangeType,\n  OnTouchedType,\n  type NzPlacement\n} from 'ng-zorro-antd/core/types';\nimport {\n  fromEventOutsideAngular,\n  generateClassName,\n  getStatusClassNames,\n  toBoolean,\n  valueFunctionProp\n} from 'ng-zorro-antd/core/util';\nimport {\n  DateHelperService,\n  NzDatePickerI18nInterface,\n  NzDatePickerLangI18nInterface,\n  NzI18nService\n} from 'ng-zorro-antd/i18n';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NZ_SPACE_COMPACT_ITEM_TYPE, NZ_SPACE_COMPACT_SIZE, NzSpaceCompactItemDirective } from 'ng-zorro-antd/space';\n\nimport { DatePickerService } from './date-picker.service';\nimport { DateRangePopupComponent } from './date-range-popup.component';\nimport {\n  CompatibleDate,\n  DisabledTimeFn,\n  NzDateMode,\n  NzPanelChangeType,\n  PresetRanges,\n  RangePartType,\n  SupportTimeOptions\n} from './standard-types';\nimport { PREFIX_CLASS } from './util';\n\nconst POPUP_STYLE_PATCH = { position: 'relative' }; // Aim to override antd's style to support overlay's position strategy (position:absolute will cause it not working because the overlay can't get the height/width of it's content)\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'datePicker';\n\nexport type NzDatePickerSizeType = 'large' | 'default' | 'small';\n\n/**\n * The base picker for all common APIs\n */\n@Component({\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  selector: 'nz-date-picker,nz-week-picker,nz-month-picker,nz-quarter-picker,nz-year-picker,nz-range-picker',\n  exportAs: 'nzDatePicker',\n  template: `\n    @if (!nzInline()) {\n      @if (!isRange) {\n        <div class=\"{{ prefixCls }}-input\">\n          <input\n            #pickerInput\n            [attr.id]=\"nzId\"\n            [class.ant-input-disabled]=\"nzDisabled\"\n            [disabled]=\"nzDisabled\"\n            [readOnly]=\"nzInputReadOnly\"\n            [(ngModel)]=\"inputValue\"\n            placeholder=\"{{ getPlaceholder() }}\"\n            [size]=\"inputSize\"\n            autocomplete=\"off\"\n            (focus)=\"onFocus($event)\"\n            (focusout)=\"onFocusout($event)\"\n            (ngModelChange)=\"onInputChange($event)\"\n            (keyup.enter)=\"onKeyupEnter($event)\"\n          />\n          <ng-container *ngTemplateOutlet=\"tplRightRest\" />\n        </div>\n      } @else {\n        <div class=\"{{ prefixCls }}-input\">\n          <ng-container *ngTemplateOutlet=\"tplRangeInput; context: { partType: 'left' }\" />\n        </div>\n        <div #separatorElement class=\"{{ prefixCls }}-range-separator\">\n          <span class=\"{{ prefixCls }}-separator\">\n            <ng-container *nzStringTemplateOutlet=\"nzSeparator; let separator\">\n              @if (nzSeparator) {\n                {{ nzSeparator }}\n              } @else {\n                <nz-icon nzType=\"swap-right\" nzTheme=\"outline\" />\n              }\n            </ng-container>\n          </span>\n        </div>\n        <div class=\"{{ prefixCls }}-input\">\n          <ng-container *ngTemplateOutlet=\"tplRangeInput; context: { partType: 'right' }\" />\n        </div>\n        <ng-container *ngTemplateOutlet=\"tplRightRest\" />\n      }\n    } @else {\n      <ng-template [ngTemplateOutlet]=\"inlineMode\" />\n    }\n    <!-- Input for Range ONLY -->\n    <ng-template #tplRangeInput let-partType=\"partType\">\n      <input\n        #rangePickerInput\n        [attr.id]=\"nzId\"\n        [disabled]=\"nzDisabled\"\n        [readOnly]=\"nzInputReadOnly\"\n        [size]=\"inputSize\"\n        autocomplete=\"off\"\n        (click)=\"onClickInputBox($event)\"\n        (focusout)=\"onFocusout($event)\"\n        (focus)=\"onFocus($event, partType)\"\n        (keyup.enter)=\"onKeyupEnter($event)\"\n        [(ngModel)]=\"inputValue[datePickerService.getActiveIndex(partType)]\"\n        (ngModelChange)=\"onInputChange($event)\"\n        placeholder=\"{{ getPlaceholder(partType) }}\"\n      />\n    </ng-template>\n\n    <!-- Right operator icons -->\n    <ng-template #tplRightRest>\n      <div class=\"{{ prefixCls }}-active-bar\" [style]=\"activeBarStyle\"></div>\n      @if (showClear) {\n        <span class=\"{{ prefixCls }}-clear\" (click)=\"onClickClear($event)\">\n          <nz-icon nzType=\"close-circle\" nzTheme=\"fill\" />\n        </span>\n      }\n\n      <span class=\"{{ prefixCls }}-suffix\">\n        <ng-container *nzStringTemplateOutlet=\"nzSuffixIcon; let suffixIcon\">\n          <nz-icon [nzType]=\"suffixIcon\" />\n        </ng-container>\n        @if (hasFeedback && !!status) {\n          <nz-form-item-feedback-icon [status]=\"status\" />\n        }\n      </span>\n    </ng-template>\n\n    <ng-template #inlineMode>\n      <div\n        [class]=\"dropdownClass()\"\n        [class.ant-picker-dropdown-range]=\"!nzInline() && isRange\"\n        [class.ant-picker-active-left]=\"datePickerService.activeInput === 'left'\"\n        [class.ant-picker-active-right]=\"datePickerService.activeInput === 'right'\"\n        [style]=\"nzPopupStyle\"\n        [animate.enter]=\"$any(!nzInline() && datepickerAnimationEnter())\"\n        [animate.leave]=\"$any(!nzInline() && datepickerAnimationLeave())\"\n      >\n        <date-range-popup\n          [isRange]=\"isRange\"\n          [inline]=\"nzInline()\"\n          [defaultPickerValue]=\"nzDefaultPickerValue\"\n          [showWeek]=\"nzShowWeekNumber || nzMode === 'week'\"\n          [panelMode]=\"panelMode\"\n          (panelModeChange)=\"onPanelModeChange($event)\"\n          (calendarChange)=\"onCalendarChange($event)\"\n          [locale]=\"nzLocale?.lang!\"\n          [showToday]=\"nzMode === 'date' && nzShowToday && !isRange && !nzShowTime\"\n          [showNow]=\"nzMode === 'date' && nzShowNow && !isRange && !!nzShowTime\"\n          [showTime]=\"nzShowTime\"\n          [dateRender]=\"nzDateRender\"\n          [disabledDate]=\"nzDisabledDate\"\n          [disabledTime]=\"nzDisabledTime\"\n          [extraFooter]=\"extraFooter\"\n          [ranges]=\"nzRanges\"\n          [dir]=\"dir()\"\n          [format]=\"nzFormat\"\n          (resultOk)=\"onResultOk()\"\n        />\n      </div>\n    </ng-template>\n\n    <!-- Overlay -->\n    <ng-template\n      cdkConnectedOverlay\n      nzConnectedOverlay\n      cdkConnectedOverlayTransformOriginOn=\".{{ prefixCls }}-dropdown\"\n      [cdkConnectedOverlayHasBackdrop]=\"nzBackdrop\"\n      [cdkConnectedOverlayOrigin]=\"origin\"\n      [cdkConnectedOverlayOpen]=\"realOpenState\"\n      [cdkConnectedOverlayPositions]=\"overlayPositions\"\n      (positionChange)=\"onPositionChange($event)\"\n      (detach)=\"close()\"\n      (overlayKeydown)=\"onOverlayKeydown($event)\"\n    >\n      <ng-container *ngTemplateOutlet=\"inlineMode\" />\n    </ng-template>\n  `,\n  host: {\n    '[class.ant-picker]': `true`,\n    '[class.ant-picker-range]': `isRange`,\n    '[class.ant-picker-large]': `finalSize() === 'large'`,\n    '[class.ant-picker-small]': `finalSize() === 'small'`,\n    '[class.ant-picker-disabled]': `nzDisabled`,\n    '[class.ant-picker-rtl]': `dir() === 'rtl'`,\n    '[class.ant-picker-borderless]': `finalVariant() === 'borderless'`,\n    '[class.ant-picker-filled]': `finalVariant() === 'filled'`,\n    '[class.ant-picker-underlined]': `finalVariant() === 'underlined'`,\n    '[class.ant-picker-inline]': `nzInline()`,\n    '(click)': 'onClickInputBox($event)'\n  },\n  hostDirectives: [NzSpaceCompactItemDirective],\n  providers: [\n    DatePickerService,\n    { provide: NZ_SPACE_COMPACT_ITEM_TYPE, useValue: 'picker' },\n    {\n      provide: NG_VALUE_ACCESSOR,\n      multi: true,\n      useExisting: forwardRef(() => NzDatePickerComponent)\n    }\n  ],\n  imports: [\n    FormsModule,\n    NgTemplateOutlet,\n    NzOutletModule,\n    NzIconModule,\n    NzFormItemFeedbackIconComponent,\n    DateRangePopupComponent,\n    CdkConnectedOverlay,\n    NzOverlayModule\n  ]\n})\nexport class NzDatePickerComponent implements OnInit, OnChanges, AfterViewInit, ControlValueAccessor {\n  public nzConfigService = inject(NzConfigService);\n  public datePickerService = inject(DatePickerService);\n  protected i18n = inject(NzI18nService);\n  protected cdr = inject(ChangeDetectorRef);\n  private renderer = inject(Renderer2);\n  private elementRef = inject(ElementRef<HTMLElement>);\n  private dateHelper = inject(DateHelperService);\n  private nzResizeObserver = inject(NzResizeObserver);\n  private platform = inject(Platform);\n  private destroyRef = inject(DestroyRef);\n  protected readonly dir = inject(Directionality).valueSignal;\n\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  static ngAcceptInputType_nzShowTime: BooleanInput | SupportTimeOptions | null | undefined;\n  static ngAcceptInputType_nzMode: NzDateMode | string;\n\n  isRange: boolean = false; // Indicate whether the value is a range value\n  extraFooter?: TemplateRef<NzSafeAny> | string;\n\n  // status\n  statusCls: NgClassInterface = {};\n  status: NzValidateStatus = '';\n  hasFeedback: boolean = false;\n\n  public panelMode: NzDateMode | NzDateMode[] = 'date';\n  private isCustomPlaceHolder: boolean = false;\n  private isCustomFormat: boolean = false;\n  private showTime: SupportTimeOptions | boolean = false;\n  private isNzDisableFirstChange: boolean = true;\n  // --- Common API\n  readonly nzInline = input(false, { transform: booleanAttribute });\n  @Input({ transform: booleanAttribute }) nzAllowClear: boolean = true;\n  @Input({ transform: booleanAttribute }) nzAutoFocus: boolean = false;\n  @Input({ transform: booleanAttribute }) nzDisabled: boolean = false;\n  @Input({ transform: booleanAttribute }) nzInputReadOnly: boolean = false;\n  @Input({ transform: booleanAttribute }) nzOpen?: boolean;\n  @Input() nzDisabledDate?: (d: Date) => boolean;\n  @Input() nzLocale!: NzDatePickerI18nInterface;\n  @Input() nzPlaceHolder: string | string[] = '';\n  @Input() nzPopupStyle: object = POPUP_STYLE_PATCH;\n  readonly nzDropdownClassName = input<string>();\n  @Input() nzSize: NzDatePickerSizeType = 'default';\n  @Input() nzStatus: NzStatus = '';\n  @Input() nzFormat!: string;\n  @Input() @WithConfig() nzVariant: NzVariant | undefined = undefined;\n  @Input() nzDateRender?: TemplateRef<NzSafeAny> | string | FunctionProp<TemplateRef<Date> | string>;\n  @Input() nzDisabledTime?: DisabledTimeFn;\n  @Input() nzRenderExtraFooter?: TemplateRef<NzSafeAny> | string | FunctionProp<TemplateRef<NzSafeAny> | string>;\n  @Input({ transform: booleanAttribute }) nzShowToday: boolean = true;\n  @Input() nzMode: NzDateMode = 'date';\n  @Input({ transform: booleanAttribute }) nzShowNow: boolean = true;\n  @Input() nzRanges?: PresetRanges;\n  @Input() nzDefaultPickerValue: CompatibleDate | null = null;\n  @Input() @WithConfig() nzSeparator?: string | TemplateRef<NzSafeAny> = undefined;\n  @Input() @WithConfig() nzSuffixIcon: string | TemplateRef<NzSafeAny> = 'calendar';\n  @Input() @WithConfig() nzBackdrop = false;\n  @Input() nzId: string | null = null;\n  @Input() nzPlacement: NzPlacement = 'bottomLeft';\n  @Input({ transform: booleanAttribute }) nzShowWeekNumber: boolean = false;\n\n  @Output() readonly nzOnPanelChange = new EventEmitter<NzPanelChangeType>();\n  @Output() readonly nzOnCalendarChange = new EventEmitter<Array<Date | null>>();\n  @Output() readonly nzOnOk = new EventEmitter<CompatibleDate | null>();\n  @Output() readonly nzOnOpenChange = new EventEmitter<boolean>();\n\n  @Input() get nzShowTime(): SupportTimeOptions | boolean {\n    return this.showTime;\n  }\n\n  set nzShowTime(value: SupportTimeOptions | boolean) {\n    this.showTime = typeof value === 'object' ? value : toBoolean(value);\n  }\n\n  // ------------------------------------------------------------------------\n  // Input API Start\n  // ------------------------------------------------------------------------\n  @ViewChild(CdkConnectedOverlay, { static: false }) cdkConnectedOverlay?: CdkConnectedOverlay;\n  @ViewChild(DateRangePopupComponent, { static: false }) panel!: DateRangePopupComponent;\n  @ViewChild('separatorElement', { static: false }) separatorElement?: ElementRef;\n  @ViewChild('pickerInput', { static: false }) pickerInput?: ElementRef<HTMLInputElement>;\n  @ViewChildren('rangePickerInput') rangePickerInputs?: QueryList<ElementRef<HTMLInputElement>>;\n\n  get origin(): ElementRef {\n    return this.elementRef;\n  }\n\n  inputSize: number = 12;\n  inputWidth?: number;\n  prefixCls = PREFIX_CLASS;\n  inputValue!: NzSafeAny;\n  activeBarStyle: object = {};\n  overlayOpen: boolean = false; // Available when \"nzOpen\" = undefined\n  overlayPositions: ConnectionPositionPair[] = [...DEFAULT_DATE_PICKER_POSITIONS];\n\n  private readonly currentPosition = signal<OriginConnectionPosition>({ originX: 'start', originY: 'bottom' });\n\n  protected readonly datepickerAnimationEnter = slideAnimationEnter();\n  protected readonly datepickerAnimationLeave = slideAnimationLeave();\n\n  protected readonly dropdownClass = computed(() => {\n    const cls: string[] = [];\n    if (!this.nzInline()) {\n      cls.push(this.generateClass('dropdown'));\n\n      const customCls = this.nzDropdownClassName();\n      if (customCls) {\n        cls.push(customCls);\n      }\n\n      const { originX, originY } = this.currentPosition();\n\n      if (originX === 'start' && originY === 'bottom') {\n        cls.push(this.generateClass('dropdown-placement-bottomLeft'));\n      } else if (originX === 'start' && originY === 'top') {\n        cls.push(this.generateClass('dropdown-placement-topLeft'));\n      } else if (originX === 'end' && originY === 'bottom') {\n        cls.push(this.generateClass('dropdown-placement-bottomRight'));\n      } else if (originX === 'end' && originY === 'top') {\n        cls.push(this.generateClass('dropdown-placement-topRight'));\n      }\n\n      if (this.dir() === 'rtl') {\n        cls.push(this.generateClass('dropdown-rtl'));\n      }\n    }\n    return cls;\n  });\n\n  get realOpenState(): boolean {\n    // The value that really decide the open state of overlay\n    return this.isOpenHandledByUser() ? !!this.nzOpen : this.overlayOpen;\n  }\n\n  protected finalSize = computed(() => {\n    if (this.formSize?.()) {\n      return this.formSize();\n    }\n    if (this.compactSize) {\n      return this.compactSize();\n    }\n    return this.size();\n  });\n\n  protected readonly finalVariant = computed(() => this.variant() || this.formVariant?.() || 'outlined');\n\n  private size = signal<NzSizeLDSType>(this.nzSize);\n  private variant = signal<NzVariant | undefined>(this.nzVariant);\n\n  private readonly formSize = inject(NZ_FORM_SIZE, { optional: true });\n  private readonly formVariant = inject(NZ_FORM_VARIANT, { optional: true });\n\n  private compactSize = inject(NZ_SPACE_COMPACT_SIZE, { optional: true });\n  private document: Document = inject(DOCUMENT);\n\n  ngAfterViewInit(): void {\n    if (this.nzAutoFocus) {\n      this.focus();\n    }\n\n    if (this.isRange && this.platform.isBrowser) {\n      this.nzResizeObserver\n        .observe(this.elementRef)\n        .pipe(takeUntilDestroyed(this.destroyRef))\n        .subscribe(() => {\n          this.updateInputWidthAndArrowLeft();\n        });\n    }\n\n    this.datePickerService.inputPartChange$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(partType => {\n      if (partType) {\n        this.datePickerService.activeInput = partType;\n      }\n      this.focus();\n      this.updateInputWidthAndArrowLeft();\n    });\n\n    if (this.platform.isBrowser) {\n      // prevent mousedown event to trigger focusout event when click in date picker\n      // see: https://github.com/NG-ZORRO/ng-zorro-antd/issues/7450\n      fromEventOutsideAngular(this.elementRef.nativeElement, 'mousedown')\n        .pipe(takeUntilDestroyed(this.destroyRef))\n        .subscribe(event => {\n          if ((event.target as HTMLInputElement).tagName.toLowerCase() !== 'input') {\n            event.preventDefault();\n          }\n        });\n    }\n  }\n\n  updateInputWidthAndArrowLeft(): void {\n    this.inputWidth = this.rangePickerInputs?.first?.nativeElement.offsetWidth || 0;\n\n    const baseStyle = { position: 'absolute', width: `${this.inputWidth}px` };\n    this.datePickerService.arrowLeft =\n      this.datePickerService.activeInput === 'left'\n        ? 0\n        : this.inputWidth + this.separatorElement?.nativeElement.offsetWidth || 0;\n\n    if (this.dir() === 'rtl') {\n      this.activeBarStyle = { ...baseStyle, right: `${this.datePickerService.arrowLeft}px` };\n    } else {\n      this.activeBarStyle = { ...baseStyle, left: `${this.datePickerService.arrowLeft}px` };\n    }\n\n    this.cdr.markForCheck();\n  }\n\n  getInput(partType?: RangePartType): HTMLInputElement | undefined {\n    if (this.nzInline()) {\n      return undefined;\n    }\n    return this.isRange\n      ? partType === 'left'\n        ? this.rangePickerInputs?.first.nativeElement\n        : this.rangePickerInputs?.last.nativeElement\n      : this.pickerInput!.nativeElement;\n  }\n\n  focus(): void {\n    const activeInputElement = this.getInput(this.datePickerService.activeInput);\n    if (this.document.activeElement !== activeInputElement) {\n      activeInputElement?.focus();\n    }\n  }\n\n  onFocus(event: FocusEvent, partType?: RangePartType): void {\n    event.preventDefault();\n    if (partType) {\n      this.datePickerService.inputPartChange$.next(partType);\n    }\n    this.renderClass(true);\n  }\n\n  // blur event has not the relatedTarget in IE11, use focusout instead.\n  onFocusout(event: FocusEvent): void {\n    event.preventDefault();\n    this.onTouchedFn();\n    if (!this.elementRef.nativeElement.contains(event.relatedTarget as Node)) {\n      this.checkAndClose();\n    }\n    this.renderClass(false);\n  }\n\n  // Show overlay content\n  open(): void {\n    if (this.nzInline()) {\n      return;\n    }\n    if (!this.realOpenState && !this.nzDisabled) {\n      this.updateInputWidthAndArrowLeft();\n      this.overlayOpen = true;\n      this.nzOnOpenChange.emit(true);\n      this.focus();\n      this.cdr.markForCheck();\n    }\n  }\n\n  close(): void {\n    if (this.nzInline()) {\n      return;\n    }\n    if (this.realOpenState) {\n      this.overlayOpen = false;\n      this.nzOnOpenChange.emit(false);\n    }\n  }\n\n  get showClear(): boolean {\n    return !this.nzDisabled && !this.isEmptyValue(this.datePickerService.value) && this.nzAllowClear;\n  }\n\n  checkAndClose(): void {\n    if (!this.realOpenState) {\n      return;\n    }\n\n    if (this.panel.isAllowed(this.datePickerService.value!, true)) {\n      if (Array.isArray(this.datePickerService.value) && wrongSortOrder(this.datePickerService.value)) {\n        const index = this.datePickerService.getActiveIndex();\n        const value = this.datePickerService.value[index];\n        this.panel.changeValueFromSelect(value!, true);\n        return;\n      }\n      this.updateInputValue();\n      this.datePickerService.emitValue$.next();\n    } else {\n      this.datePickerService.setValue(this.datePickerService.initialValue!);\n      this.close();\n    }\n  }\n\n  onClickInputBox(event: MouseEvent): void {\n    event.stopPropagation();\n    this.focus();\n    if (!this.isOpenHandledByUser()) {\n      this.open();\n    }\n  }\n\n  onOverlayKeydown(event: KeyboardEvent): void {\n    if (event.keyCode === ESCAPE) {\n      this.datePickerService.initValue();\n    }\n  }\n\n  onPositionChange(position: ConnectedOverlayPositionChange): void {\n    this.currentPosition.set(position.connectionPair);\n  }\n\n  onClickClear(event: MouseEvent): void {\n    event.preventDefault();\n    event.stopPropagation();\n\n    this.datePickerService.initValue(true);\n    this.datePickerService.emitValue$.next();\n  }\n\n  updateInputValue(): void {\n    const newValue = this.datePickerService.value;\n    if (this.isRange) {\n      this.inputValue = newValue ? (newValue as CandyDate[]).map(v => this.formatValue(v)) : ['', ''];\n    } else {\n      this.inputValue = this.formatValue(newValue as CandyDate);\n    }\n    this.cdr.markForCheck();\n  }\n\n  formatValue(value: CandyDate): string {\n    return this.dateHelper.format(value && (value as CandyDate).nativeDate, this.nzFormat);\n  }\n\n  onInputChange(value: string, isEnter: boolean = false): void {\n    /**\n     * in IE11 focus/blur will trigger ngModelChange if placeholder changes,\n     * so we forbid IE11 to open panel through input change\n     */\n    if (\n      !this.platform.TRIDENT &&\n      this.document.activeElement === this.getInput(this.datePickerService.activeInput) &&\n      !this.realOpenState\n    ) {\n      this.open();\n      return;\n    }\n\n    const date = this.checkValidDate(value);\n    // Can only change date when it's open\n    if (date && this.realOpenState) {\n      this.panel.changeValueFromSelect(date, isEnter);\n    }\n  }\n\n  onKeyupEnter(event: Event): void {\n    this.onInputChange((event.target as HTMLInputElement).value, true);\n  }\n\n  private checkValidDate(value: string): CandyDate | null {\n    const date = new CandyDate(this.dateHelper.parseDate(value, this.nzFormat));\n\n    if (!date.isValid() || value !== this.dateHelper.format(date.nativeDate, this.nzFormat)) {\n      return null;\n    }\n\n    return date;\n  }\n\n  getPlaceholder(partType?: RangePartType): string {\n    return this.isRange\n      ? this.nzPlaceHolder[this.datePickerService.getActiveIndex(partType!)]\n      : (this.nzPlaceHolder as string);\n  }\n\n  isEmptyValue(value: CompatibleValue): boolean {\n    if (value === null) {\n      return true;\n    } else if (this.isRange) {\n      return !value || !Array.isArray(value) || value.every(val => !val);\n    } else {\n      return !value;\n    }\n  }\n\n  // Whether open state is permanently controlled by user himself\n  isOpenHandledByUser(): boolean {\n    return this.nzOpen !== undefined;\n  }\n\n  private nzFormStatusService = inject(NzFormStatusService, { optional: true });\n  private nzFormNoStatusService = inject(NzFormNoStatusService, { optional: true });\n\n  // ------------------------------------------------------------------------\n  // Input API End\n  // ------------------------------------------------------------------------\n\n  ngOnInit(): void {\n    this.nzFormStatusService?.formStatusChanges\n      .pipe(\n        distinctUntilChanged((pre, cur) => {\n          return pre.status === cur.status && pre.hasFeedback === cur.hasFeedback;\n        }),\n        withLatestFrom(this.nzFormNoStatusService ? this.nzFormNoStatusService.noFormStatus : of(false)),\n        map(([{ status, hasFeedback }, noStatus]) => ({ status: noStatus ? '' : status, hasFeedback })),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(({ status, hasFeedback }) => {\n        this.setStatusStyles(status, hasFeedback);\n      });\n\n    // Subscribe the every locale change if the nzLocale is not handled by user\n    if (!this.nzLocale) {\n      this.i18n.localeChange.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => this.setLocale());\n    }\n\n    // Default value\n    this.datePickerService.isRange = this.isRange;\n    this.datePickerService.initValue(true);\n    this.datePickerService.emitValue$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      const granularityComparison = this.showTime ? 'second' : 'day';\n      const value = this.datePickerService.value;\n      const datePickerPreviousValue = this.datePickerService.initialValue;\n\n      // Check if the value has change for a simple datepicker, let us avoid notify the control for nothing\n      if (\n        !this.isRange &&\n        (value as CandyDate)?.isSame((datePickerPreviousValue as CandyDate)?.nativeDate, granularityComparison)\n      ) {\n        this.onTouchedFn();\n        return this.close();\n      }\n\n      // check if the value has change for a range picker, let us avoid notify the control for nothing\n      if (this.isRange) {\n        const [previousStartDate, previousEndDate] = datePickerPreviousValue as CandyDate[];\n        const [currentStartDate, currentEndDate] = value as CandyDate[];\n        if (\n          previousStartDate?.isSame(currentStartDate?.nativeDate, granularityComparison) &&\n          previousEndDate?.isSame(currentEndDate?.nativeDate, granularityComparison)\n        ) {\n          this.onTouchedFn();\n          return this.close();\n        }\n      }\n\n      this.datePickerService.initialValue = cloneDate(value);\n      if (this.isRange) {\n        const vAsRange = value as CandyDate[];\n        if (vAsRange.length) {\n          this.onChangeFn([vAsRange[0]?.nativeDate ?? null, vAsRange[1]?.nativeDate ?? null]);\n        } else {\n          this.onChangeFn([]);\n        }\n      } else {\n        if (value) {\n          this.onChangeFn((value as CandyDate).nativeDate);\n        } else {\n          this.onChangeFn(null);\n        }\n      }\n      this.onTouchedFn();\n      // When value emitted, overlay will be closed\n      this.close();\n    });\n\n    this.inputValue = this.isRange ? ['', ''] : '';\n    this.setModeAndFormat();\n\n    this.datePickerService.valueChange$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      this.updateInputValue();\n    });\n  }\n\n  ngOnChanges({\n    nzStatus,\n    nzPlacement,\n    nzPopupStyle,\n    nzPlaceHolder,\n    nzLocale,\n    nzFormat,\n    nzRenderExtraFooter,\n    nzMode,\n    nzSize,\n    nzVariant\n  }: SimpleChanges): void {\n    if (nzPopupStyle) {\n      // Always assign the popup style patch\n      this.nzPopupStyle = this.nzPopupStyle ? { ...this.nzPopupStyle, ...POPUP_STYLE_PATCH } : POPUP_STYLE_PATCH;\n    }\n\n    // Mark as customized placeholder by user once nzPlaceHolder assigned at the first time\n    if (nzPlaceHolder?.currentValue) {\n      this.isCustomPlaceHolder = true;\n    }\n\n    if (nzFormat?.currentValue) {\n      this.isCustomFormat = true;\n      this.updateInputValue();\n    }\n\n    if (nzLocale) {\n      // The nzLocale is currently handled by user\n      this.setDefaultPlaceHolder();\n    }\n\n    if (nzRenderExtraFooter) {\n      this.extraFooter = valueFunctionProp(this.nzRenderExtraFooter!);\n    }\n\n    if (nzMode) {\n      this.setDefaultPlaceHolder();\n      this.setModeAndFormat();\n    }\n\n    if (nzStatus) {\n      this.setStatusStyles(this.nzStatus, this.hasFeedback);\n    }\n\n    if (nzPlacement) {\n      this.setPlacement(this.nzPlacement);\n    }\n\n    if (nzSize) {\n      this.size.set(nzSize.currentValue);\n    }\n\n    if (nzVariant) {\n      this.variant.set(nzVariant.currentValue);\n    }\n  }\n\n  setModeAndFormat(): void {\n    const inputFormats: Partial<Record<NzDateMode, string>> = {\n      year: 'yyyy',\n      quarter: 'yyyy-[Q]Q',\n      month: 'yyyy-MM',\n      week: 'YYYY-ww',\n      date: this.nzShowTime ? 'yyyy-MM-dd HH:mm:ss' : 'yyyy-MM-dd'\n    };\n\n    if (!this.nzMode) {\n      this.nzMode = 'date';\n    }\n\n    this.panelMode = this.isRange ? [this.nzMode, this.nzMode] : this.nzMode;\n\n    // Default format when it's empty\n    if (!this.isCustomFormat) {\n      this.nzFormat = inputFormats[this.nzMode as NzDateMode]!;\n    }\n\n    this.inputSize = Math.max(10, this.nzFormat.length) + 2;\n    this.updateInputValue();\n  }\n\n  /**\n   * Triggered when overlayOpen changes (different with realOpenState)\n   *\n   * @param open The overlayOpen in picker component\n   */\n  onOpenChange(open: boolean): void {\n    this.nzOnOpenChange.emit(open);\n  }\n\n  // ------------------------------------------------------------------------\n  // | Control value accessor implements\n  // ------------------------------------------------------------------------\n\n  // NOTE: onChangeFn/onTouchedFn will not be assigned if user not use as ngModel\n  onChangeFn: OnChangeType = () => void 0;\n  onTouchedFn: OnTouchedType = () => void 0;\n\n  writeValue(value: CompatibleDate): void {\n    this.setValue(value);\n    this.cdr.markForCheck();\n  }\n\n  registerOnChange(fn: OnChangeType): void {\n    this.onChangeFn = fn;\n  }\n\n  registerOnTouched(fn: OnTouchedType): void {\n    this.onTouchedFn = fn;\n  }\n\n  setDisabledState(isDisabled: boolean): void {\n    this.nzDisabled = (this.isNzDisableFirstChange && this.nzDisabled) || isDisabled;\n    this.cdr.markForCheck();\n    this.isNzDisableFirstChange = false;\n  }\n\n  // ------------------------------------------------------------------------\n  // | Internal methods\n  // ------------------------------------------------------------------------\n\n  // Reload locale from i18n with side effects\n  private setLocale(): void {\n    this.nzLocale = this.i18n.getLocaleData('DatePicker', {});\n    this.setDefaultPlaceHolder();\n    this.cdr.markForCheck();\n  }\n\n  private setDefaultPlaceHolder(): void {\n    if (!this.isCustomPlaceHolder && this.nzLocale) {\n      const defaultPlaceholder: Partial<Record<NzDateMode, string>> = {\n        year: this.getPropertyOfLocale('yearPlaceholder'),\n        quarter: this.getPropertyOfLocale('quarterPlaceholder'),\n        month: this.getPropertyOfLocale('monthPlaceholder'),\n        week: this.getPropertyOfLocale('weekPlaceholder'),\n        date: this.getPropertyOfLocale('placeholder')\n      };\n\n      const defaultRangePlaceholder: Partial<Record<NzDateMode, string[]>> = {\n        year: this.getPropertyOfLocale('rangeYearPlaceholder'),\n        quarter: this.getPropertyOfLocale('rangeQuarterPlaceholder'),\n        month: this.getPropertyOfLocale('rangeMonthPlaceholder'),\n        week: this.getPropertyOfLocale('rangeWeekPlaceholder'),\n        date: this.getPropertyOfLocale('rangePlaceholder')\n      };\n\n      this.nzPlaceHolder = this.isRange\n        ? defaultRangePlaceholder[this.nzMode as NzDateMode]!\n        : defaultPlaceholder[this.nzMode as NzDateMode]!;\n    }\n  }\n\n  private getPropertyOfLocale<T extends keyof NzDatePickerLangI18nInterface>(\n    type: T\n  ): NzDatePickerLangI18nInterface[T] {\n    return this.nzLocale.lang[type] || this.i18n.getLocaleData(`DatePicker.lang.${type}`);\n  }\n\n  // Safe way of setting value with default\n  private setValue(value: CompatibleDate): void {\n    const newValue = this.datePickerService.makeValue(value);\n    this.datePickerService.setValue(newValue);\n    this.datePickerService.initialValue = cloneDate(newValue);\n    this.cdr.detectChanges();\n  }\n\n  renderClass(value: boolean): void {\n    // TODO: avoid autoFocus cause change after checked error\n    if (value) {\n      this.renderer.addClass(this.elementRef.nativeElement, 'ant-picker-focused');\n    } else {\n      this.renderer.removeClass(this.elementRef.nativeElement, 'ant-picker-focused');\n    }\n  }\n\n  onPanelModeChange(panelChange: NzPanelChangeType): void {\n    this.nzOnPanelChange.emit(panelChange);\n  }\n\n  // Emit nzOnCalendarChange when select date by nz-range-picker\n  onCalendarChange(value: CompatibleValue): void {\n    if (this.isRange && Array.isArray(value)) {\n      const rangeValue = value.filter(x => x instanceof CandyDate).map(x => x!.nativeDate);\n      this.nzOnCalendarChange.emit(rangeValue);\n    }\n  }\n\n  onResultOk(): void {\n    if (this.isRange) {\n      const value = this.datePickerService.value as CandyDate[];\n      if (value.length) {\n        this.nzOnOk.emit([value[0]?.nativeDate || null, value[1]?.nativeDate || null]);\n      } else {\n        this.nzOnOk.emit([]);\n      }\n    } else {\n      if (this.datePickerService.value) {\n        this.nzOnOk.emit((this.datePickerService.value as CandyDate).nativeDate);\n      } else {\n        this.nzOnOk.emit(null);\n      }\n    }\n  }\n\n  // status\n  private setStatusStyles(status: NzValidateStatus, hasFeedback: boolean): void {\n    // set inner status\n    this.status = status;\n    this.hasFeedback = hasFeedback;\n    this.cdr.markForCheck();\n    // render status if nzStatus is set\n    this.statusCls = getStatusClassNames(this.prefixCls, status, hasFeedback);\n    Object.keys(this.statusCls).forEach(status => {\n      if (this.statusCls[status]) {\n        this.renderer.addClass(this.elementRef.nativeElement, status);\n      } else {\n        this.renderer.removeClass(this.elementRef.nativeElement, status);\n      }\n    });\n  }\n\n  private setPlacement(placement: NzPlacement): void {\n    const position: ConnectionPositionPair = DATE_PICKER_POSITION_MAP[placement];\n    this.overlayPositions = [position, ...DEFAULT_DATE_PICKER_POSITIONS];\n    this.currentPosition.set(position);\n  }\n\n  private generateClass(suffix: string): string {\n    return generateClassName(this.prefixCls, suffix);\n  }\n}\n"
  },
  {
    "path": "components/date-picker/date-picker.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { CalendarFooterComponent } from './calendar-footer.component';\nimport { NzDatePickerComponent } from './date-picker.component';\nimport { DateRangePopupComponent } from './date-range-popup.component';\nimport { InnerPopupComponent } from './inner-popup.component';\nimport { NzMonthPickerComponent } from './month-picker.component';\nimport { NzQuarterPickerComponent } from './quarter-picker.component';\nimport { NzRangePickerComponent } from './range-picker.component';\nimport { NzWeekPickerComponent } from './week-picker.component';\nimport { NzYearPickerComponent } from './year-picker.component';\n\n@NgModule({\n  imports: [\n    NzDatePickerComponent,\n    NzMonthPickerComponent,\n    NzYearPickerComponent,\n    NzWeekPickerComponent,\n    NzRangePickerComponent,\n    CalendarFooterComponent,\n    InnerPopupComponent,\n    DateRangePopupComponent,\n    NzQuarterPickerComponent\n  ],\n  exports: [\n    NzDatePickerComponent,\n    NzRangePickerComponent,\n    NzMonthPickerComponent,\n    NzYearPickerComponent,\n    NzWeekPickerComponent,\n    NzQuarterPickerComponent\n  ]\n})\nexport class NzDatePickerModule {}\n"
  },
  {
    "path": "components/date-picker/date-picker.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Injectable, OnDestroy } from '@angular/core';\nimport { ReplaySubject, Subject } from 'rxjs';\n\nimport { CandyDate, cloneDate, CompatibleValue, NormalizedMode, normalizeRangeValue } from 'ng-zorro-antd/core/time';\n\nimport { CompatibleDate, NzDateMode, RangePartType } from './standard-types';\n\n@Injectable()\nexport class DatePickerService implements OnDestroy {\n  initialValue!: CompatibleValue;\n  value!: CompatibleValue;\n  activeDate?: CompatibleValue;\n  activeInput: RangePartType = 'left';\n  arrowLeft: number = 0;\n  isRange = false;\n\n  valueChange$ = new ReplaySubject<CompatibleValue>(1);\n  emitValue$ = new Subject<void>();\n  inputPartChange$ = new Subject<RangePartType | null>();\n\n  initValue(reset: boolean = false): void {\n    if (reset) {\n      this.initialValue = this.isRange ? [] : null;\n    }\n\n    this.setValue(this.initialValue);\n  }\n\n  hasValue(value: CompatibleValue = this.value): boolean {\n    if (Array.isArray(value)) {\n      return !!value[0] || !!value[1];\n    } else {\n      return !!value;\n    }\n  }\n\n  makeValue(value?: CompatibleDate): CompatibleValue {\n    if (this.isRange) {\n      return value ? (value as Date[]).map(val => new CandyDate(val)) : [];\n    } else {\n      return value ? new CandyDate(value as Date) : null;\n    }\n  }\n\n  setActiveDate(value: CompatibleValue, hasTimePicker: boolean = false, mode: NormalizedMode = 'month'): void {\n    const parentPanels: Partial<Record<NzDateMode, NormalizedMode>> = {\n      date: 'month',\n      month: 'year',\n      quarter: 'year',\n      year: 'decade'\n    };\n    if (this.isRange) {\n      this.activeDate = normalizeRangeValue(value as CandyDate[], hasTimePicker, parentPanels[mode], this.activeInput);\n    } else {\n      this.activeDate = cloneDate(value);\n    }\n  }\n\n  setValue(value: CompatibleValue): void {\n    this.value = value;\n    this.valueChange$.next(this.value);\n  }\n\n  getActiveIndex(part: RangePartType = this.activeInput): number {\n    return { left: 0, right: 1 }[part];\n  }\n\n  ngOnDestroy(): void {\n    this.valueChange$.complete();\n    this.emitValue$.complete();\n    this.inputPartChange$.complete();\n  }\n}\n"
  },
  {
    "path": "components/date-picker/date-range-popup.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction } from '@angular/cdk/bidi';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DestroyRef,\n  ElementRef,\n  EventEmitter,\n  inject,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  SimpleChanges,\n  TemplateRef,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { merge } from 'rxjs';\n\nimport {\n  CandyDate,\n  cloneDate,\n  CompatibleValue,\n  NormalizedMode,\n  SingleValue,\n  wrongSortOrder\n} from 'ng-zorro-antd/core/time';\nimport { FunctionProp } from 'ng-zorro-antd/core/types';\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\nimport { NzCalendarI18nInterface } from 'ng-zorro-antd/i18n';\n\nimport { CalendarFooterComponent } from './calendar-footer.component';\nimport { DatePickerService } from './date-picker.service';\nimport { InnerPopupComponent } from './inner-popup.component';\nimport {\n  CompatibleDate,\n  DisabledDateFn,\n  DisabledTimeFn,\n  DisabledTimePartial,\n  NzDateMode,\n  NzPanelChangeType,\n  PresetRanges,\n  RangePartType,\n  SupportTimeOptions\n} from './standard-types';\nimport { getTimeConfig, isAllowedDate, PREFIX_CLASS } from './util';\n\n@Component({\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  // eslint-disable-next-line @angular-eslint/component-selector\n  selector: 'date-range-popup',\n  template: `\n    @if (isRange) {\n      <div class=\"{{ prefixCls }}-range-wrapper {{ prefixCls }}-date-range-wrapper\">\n        <div class=\"{{ prefixCls }}-range-arrow\" [style]=\"arrowPosition\"></div>\n        <div class=\"{{ prefixCls }}-panel-container {{ showWeek ? prefixCls + '-week-number' : '' }}\">\n          <div class=\"{{ prefixCls }}-panels\">\n            @if (hasTimePicker) {\n              <ng-container *ngTemplateOutlet=\"tplInnerPopup; context: { partType: datePickerService.activeInput }\" />\n            } @else {\n              <ng-container *ngTemplateOutlet=\"tplInnerPopup; context: { partType: 'left' }\" />\n              <ng-container *ngTemplateOutlet=\"tplInnerPopup; context: { partType: 'right' }\" />\n            }\n          </div>\n          <ng-container *ngTemplateOutlet=\"tplFooter\" />\n        </div>\n      </div>\n    } @else {\n      <div\n        class=\"{{ prefixCls }}-panel-container {{ showWeek ? prefixCls + '-week-number' : '' }} {{\n          hasTimePicker ? prefixCls + '-time' : ''\n        }} {{ isRange ? prefixCls + '-range' : '' }}\"\n      >\n        <div class=\"{{ prefixCls }}-panel\" [class.ant-picker-panel-rtl]=\"dir === 'rtl'\" tabindex=\"-1\">\n          <!-- Single ONLY -->\n          <ng-container *ngTemplateOutlet=\"tplInnerPopup\" />\n          <ng-container *ngTemplateOutlet=\"tplFooter\" />\n        </div>\n      </div>\n    }\n\n    <ng-template #tplInnerPopup let-partType=\"partType\">\n      <div class=\"{{ prefixCls }}-panel\" [class.ant-picker-panel-rtl]=\"dir === 'rtl'\">\n        <!-- TODO(@wenqi73) [selectedValue] [hoverValue] types-->\n        <inner-popup\n          [showWeek]=\"showWeek\"\n          [endPanelMode]=\"getPanelMode(endPanelMode, partType)\"\n          [partType]=\"partType\"\n          [locale]=\"locale!\"\n          [showTimePicker]=\"hasTimePicker\"\n          [timeOptions]=\"getTimeOptions(partType)\"\n          [panelMode]=\"getPanelMode(panelMode, partType)\"\n          (panelChange)=\"onPanelModeChange($event, partType)\"\n          [activeDate]=\"getActiveDate(partType)\"\n          [value]=\"getValue(partType)\"\n          [disabledDate]=\"disabledDate\"\n          [dateRender]=\"dateRender\"\n          [selectedValue]=\"$any(datePickerService?.value)\"\n          [hoverValue]=\"$any(hoverValue)\"\n          [format]=\"format\"\n          (cellHover)=\"onCellHover($event)\"\n          (selectDate)=\"changeValueFromSelect($event, !showTime)\"\n          (selectTime)=\"onSelectTime($event, partType)\"\n          (headerChange)=\"onActiveDateChange($event, partType)\"\n        />\n      </div>\n    </ng-template>\n\n    <ng-template #tplFooter>\n      @if (hasFooter) {\n        <calendar-footer\n          [locale]=\"locale!\"\n          [isRange]=\"isRange\"\n          [showToday]=\"showToday\"\n          [showNow]=\"showNow\"\n          [hasTimePicker]=\"hasTimePicker\"\n          [okDisabled]=\"!isAllowed($any(datePickerService?.value))\"\n          [extraFooter]=\"extraFooter\"\n          [rangeQuickSelector]=\"ranges ? tplRangeQuickSelector : null\"\n          (clickOk)=\"onClickOk()\"\n          (clickToday)=\"onClickToday($event)\"\n        />\n      }\n    </ng-template>\n\n    <!-- Range ONLY: Range Quick Selector -->\n    <ng-template #tplRangeQuickSelector>\n      @for (name of getObjectKeys(ranges); track name) {\n        <li\n          class=\"{{ prefixCls }}-preset\"\n          (click)=\"onClickPresetRange(ranges![name])\"\n          (mouseenter)=\"onHoverPresetRange(ranges![name])\"\n          (mouseleave)=\"onPresetRangeMouseLeave()\"\n        >\n          <span class=\"ant-tag ant-tag-blue\">{{ name }}</span>\n        </li>\n      }\n    </ng-template>\n  `,\n  imports: [InnerPopupComponent, NgTemplateOutlet, CalendarFooterComponent]\n})\nexport class DateRangePopupComponent implements OnInit, OnChanges {\n  public datePickerService = inject(DatePickerService);\n  public cdr = inject(ChangeDetectorRef);\n  private host = inject(ElementRef<HTMLElement>);\n  private destroyRef = inject(DestroyRef);\n\n  @Input({ transform: booleanAttribute }) isRange!: boolean;\n  @Input({ transform: booleanAttribute }) inline: boolean = false;\n  @Input({ transform: booleanAttribute }) showWeek!: boolean;\n  @Input() locale!: NzCalendarI18nInterface | undefined;\n  @Input() disabledDate?: DisabledDateFn;\n  @Input() disabledTime?: DisabledTimeFn; // This will lead to rebuild time options\n  @Input({ transform: booleanAttribute }) showToday!: boolean;\n  @Input({ transform: booleanAttribute }) showNow!: boolean;\n  @Input() showTime!: SupportTimeOptions | boolean;\n  @Input() extraFooter?: TemplateRef<void> | string;\n  @Input() ranges?: PresetRanges;\n  @Input() dateRender?: string | TemplateRef<Date> | FunctionProp<TemplateRef<Date> | string>;\n  @Input() panelMode!: NzDateMode | NzDateMode[];\n  @Input() defaultPickerValue!: CompatibleDate | undefined | null;\n  @Input() dir: Direction = 'ltr';\n  @Input() format?: string;\n\n  @Output() readonly panelModeChange = new EventEmitter<NzPanelChangeType>();\n  @Output() readonly calendarChange = new EventEmitter<CompatibleValue>();\n  @Output() readonly resultOk = new EventEmitter<void>(); // Emitted when done with date selecting\n\n  prefixCls: string = PREFIX_CLASS;\n  endPanelMode: NzDateMode | NzDateMode[] = 'date';\n  timeOptions: SupportTimeOptions | SupportTimeOptions[] | null = null;\n  hoverValue: SingleValue[] = []; // Range ONLY\n  checkedPartArr: boolean[] = [false, false];\n\n  get hasTimePicker(): boolean {\n    return !!this.showTime;\n  }\n\n  get hasFooter(): boolean {\n    return this.showToday || this.hasTimePicker || !!this.extraFooter || !!this.ranges;\n  }\n\n  get arrowPosition(): { left?: string; right?: string } {\n    return this.dir === 'rtl'\n      ? { right: `${this.datePickerService?.arrowLeft}px` }\n      : { left: `${this.datePickerService?.arrowLeft}px` };\n  }\n\n  ngOnInit(): void {\n    merge(this.datePickerService.valueChange$, this.datePickerService.inputPartChange$)\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(() => {\n        this.updateActiveDate();\n        this.cdr.markForCheck();\n      });\n\n    fromEventOutsideAngular(this.host.nativeElement, 'mousedown')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(event => event.preventDefault());\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    // Parse showTime options\n    if (changes.showTime || changes.disabledTime) {\n      if (this.showTime) {\n        this.buildTimeOptions();\n      }\n    }\n    if (changes.panelMode) {\n      this.endPanelMode = this.panelMode;\n    }\n    if (changes.defaultPickerValue) {\n      this.updateActiveDate();\n    }\n  }\n\n  updateActiveDate(): void {\n    const activeDate = this.datePickerService.hasValue()\n      ? this.datePickerService.value\n      : this.datePickerService.makeValue(this.defaultPickerValue!);\n    this.datePickerService.setActiveDate(\n      activeDate,\n      this.hasTimePicker,\n      this.getPanelMode(this.endPanelMode) as NormalizedMode\n    );\n  }\n\n  onClickOk(): void {\n    const inputIndex = { left: 0, right: 1 }[this.datePickerService.activeInput];\n    const value: CandyDate = this.isRange\n      ? (this.datePickerService.value as CandyDate[])[inputIndex]\n      : (this.datePickerService.value as CandyDate);\n    this.changeValueFromSelect(value);\n    this.resultOk.emit();\n  }\n\n  onClickToday(value: CandyDate): void {\n    this.changeValueFromSelect(value, !this.showTime);\n  }\n\n  onCellHover(value: CandyDate | null): void {\n    if (!this.isRange) {\n      return;\n    }\n    if (value === null) {\n      this.hoverValue = [];\n      return;\n    }\n    const otherInputIndex = { left: 1, right: 0 }[this.datePickerService.activeInput];\n    const base = (this.datePickerService.value as CandyDate[])[otherInputIndex]!;\n    if (base) {\n      if (base.isBeforeDay(value)) {\n        this.hoverValue = [base, value];\n      } else {\n        this.hoverValue = [value, base];\n      }\n    }\n  }\n\n  onPanelModeChange(panelChangeEvent: NzPanelChangeType, partType?: RangePartType): void {\n    if (this.isRange) {\n      const index = this.datePickerService.getActiveIndex(partType);\n      if (index === 0) {\n        this.panelMode = [panelChangeEvent.mode, this.panelMode[1]] as [NzDateMode, NzDateMode];\n      } else {\n        this.panelMode = [this.panelMode[0], panelChangeEvent.mode] as [NzDateMode, NzDateMode];\n      }\n      this.panelModeChange.emit({\n        mode: this.panelMode as [NzDateMode, NzDateMode],\n        date: (this.datePickerService.activeDate as SingleValue[]).map(d => d!.nativeDate) as [Date, Date]\n      });\n    } else {\n      this.panelMode = panelChangeEvent.mode as NzDateMode;\n      this.panelModeChange.emit({ mode: this.panelMode as NzDateMode, date: panelChangeEvent.date as Date });\n    }\n  }\n\n  onActiveDateChange(value: CandyDate, partType: RangePartType): void {\n    if (this.isRange) {\n      const activeDate: SingleValue[] = [];\n      activeDate[this.datePickerService.getActiveIndex(partType)] = value;\n      this.datePickerService.setActiveDate(\n        activeDate,\n        this.hasTimePicker,\n        this.getPanelMode(this.endPanelMode, partType) as NormalizedMode\n      );\n    } else {\n      this.datePickerService.setActiveDate(value);\n    }\n  }\n\n  onSelectTime(value: CandyDate, partType?: RangePartType): void {\n    if (this.isRange) {\n      const newValue = cloneDate(this.datePickerService.value) as SingleValue[];\n      const index = this.datePickerService.getActiveIndex(partType);\n      newValue[index] = this.overrideHms(value, newValue[index]);\n      this.datePickerService.setValue(newValue);\n    } else {\n      const newValue = this.overrideHms(value, this.datePickerService.value as CandyDate);\n      this.datePickerService.setValue(newValue); // If not select a date currently, use today\n    }\n    this.datePickerService.inputPartChange$.next(null);\n    this.buildTimeOptions();\n  }\n\n  changeValueFromSelect(value: CandyDate, emitValue: boolean = true): void {\n    if (this.isRange) {\n      const selectedValue: SingleValue[] = cloneDate(this.datePickerService.value) as CandyDate[];\n      const checkedPart: RangePartType = this.datePickerService.activeInput;\n      let nextPart: RangePartType = checkedPart;\n\n      selectedValue[this.datePickerService.getActiveIndex(checkedPart)] = value;\n      this.checkedPartArr[this.datePickerService.getActiveIndex(checkedPart)] = true;\n      this.hoverValue = selectedValue;\n\n      if (emitValue) {\n        if (this.inline) {\n          // For UE, Should always be reversed, and clear vaue when next part is right\n          nextPart = this.reversedPart(checkedPart);\n          if (nextPart === 'right') {\n            selectedValue[this.datePickerService.getActiveIndex(nextPart)] = null;\n            this.checkedPartArr[this.datePickerService.getActiveIndex(nextPart)] = false;\n          }\n          this.datePickerService.setValue(selectedValue);\n          this.calendarChange.emit(selectedValue);\n          if (this.isBothAllowed(selectedValue) && this.checkedPartArr[0] && this.checkedPartArr[1]) {\n            this.clearHoverValue();\n            this.datePickerService.emitValue$.next();\n          }\n        } else {\n          /**\n           * if sort order is wrong, output in reverse order.\n           */\n          if (wrongSortOrder(selectedValue)) {\n            selectedValue.reverse();\n          }\n          this.datePickerService.setValue(selectedValue);\n          /**\n           * range date usually selected paired,\n           * so we emit the date value only both date is allowed and both part are checked\n           */\n          if (this.isBothAllowed(selectedValue) && this.checkedPartArr[0] && this.checkedPartArr[1]) {\n            this.calendarChange.emit(selectedValue);\n            this.clearHoverValue();\n            this.datePickerService.emitValue$.next();\n          } else if (this.isAllowed(selectedValue)) {\n            nextPart = this.reversedPart(checkedPart);\n            this.calendarChange.emit([value.clone()]);\n          }\n        }\n      } else {\n        this.datePickerService.setValue(selectedValue);\n      }\n      this.datePickerService.inputPartChange$.next(nextPart);\n    } else {\n      this.datePickerService.setValue(value);\n      this.datePickerService.inputPartChange$.next(null);\n\n      if (emitValue && this.isAllowed(value)) {\n        this.datePickerService.emitValue$.next();\n      }\n    }\n\n    this.buildTimeOptions();\n  }\n\n  reversedPart(part: RangePartType): RangePartType {\n    return part === 'left' ? 'right' : 'left';\n  }\n\n  getPanelMode(panelMode: NzDateMode | NzDateMode[], partType?: RangePartType): NzDateMode {\n    if (this.isRange) {\n      return panelMode[this.datePickerService.getActiveIndex(partType)] as NzDateMode;\n    } else {\n      return panelMode as NzDateMode;\n    }\n  }\n\n  // Get single value or part value of a range\n  getValue(partType?: RangePartType): CandyDate {\n    if (this.isRange) {\n      return ((this.datePickerService.value as CandyDate[]) || [])[this.datePickerService.getActiveIndex(partType)];\n    } else {\n      return this.datePickerService.value as CandyDate;\n    }\n  }\n\n  getActiveDate(partType?: RangePartType): CandyDate {\n    if (this.isRange) {\n      return (this.datePickerService.activeDate as CandyDate[])[this.datePickerService.getActiveIndex(partType)];\n    } else {\n      return this.datePickerService.activeDate as CandyDate;\n    }\n  }\n\n  disabledStartTime: DisabledTimeFn = (value: Date | Date[]) => this.disabledTime && this.disabledTime(value, 'start');\n\n  disabledEndTime: DisabledTimeFn = (value: Date | Date[]) => this.disabledTime && this.disabledTime(value, 'end');\n\n  isOneAllowed(selectedValue: SingleValue[]): boolean {\n    const index = this.datePickerService.getActiveIndex();\n    const disabledTimeArr = [this.disabledStartTime, this.disabledEndTime];\n    return isAllowedDate(selectedValue[index]!, this.disabledDate, disabledTimeArr[index]);\n  }\n\n  isBothAllowed(selectedValue: SingleValue[]): boolean {\n    return (\n      isAllowedDate(selectedValue[0]!, this.disabledDate, this.disabledStartTime) &&\n      isAllowedDate(selectedValue[1]!, this.disabledDate, this.disabledEndTime)\n    );\n  }\n\n  isAllowed(value: CompatibleValue, isBoth: boolean = false): boolean {\n    if (this.isRange) {\n      return isBoth ? this.isBothAllowed(value as CandyDate[]) : this.isOneAllowed(value as CandyDate[]);\n    } else {\n      return isAllowedDate(value as CandyDate, this.disabledDate, this.disabledTime);\n    }\n  }\n\n  getTimeOptions(partType?: RangePartType): SupportTimeOptions | null {\n    if (this.showTime && this.timeOptions) {\n      return this.timeOptions instanceof Array\n        ? this.timeOptions[this.datePickerService.getActiveIndex(partType)]\n        : this.timeOptions;\n    }\n    return null;\n  }\n\n  onClickPresetRange(val: PresetRanges[keyof PresetRanges]): void {\n    const value = typeof val === 'function' ? val() : val;\n    if (value) {\n      this.datePickerService.setValue([new CandyDate(value[0]), new CandyDate(value[1])]);\n      this.datePickerService.emitValue$.next();\n    }\n  }\n\n  onPresetRangeMouseLeave(): void {\n    this.clearHoverValue();\n  }\n\n  onHoverPresetRange(val: PresetRanges[keyof PresetRanges]): void {\n    if (typeof val !== 'function') {\n      this.hoverValue = [new CandyDate(val[0]), new CandyDate(val[1])];\n    }\n  }\n\n  getObjectKeys(obj?: PresetRanges): string[] {\n    return obj ? Object.keys(obj) : [];\n  }\n\n  show(partType: RangePartType): boolean {\n    const hide = this.showTime && this.isRange && this.datePickerService.activeInput !== partType;\n    return !hide;\n  }\n\n  private clearHoverValue(): void {\n    this.hoverValue = [];\n  }\n\n  private buildTimeOptions(): void {\n    if (this.showTime) {\n      const showTime = typeof this.showTime === 'object' ? this.showTime : {};\n      if (this.isRange) {\n        const value = this.datePickerService.value as CandyDate[];\n        this.timeOptions = [\n          this.overrideTimeOptions(showTime, value[0], 'start'),\n          this.overrideTimeOptions(showTime, value[1], 'end')\n        ];\n      } else {\n        this.timeOptions = this.overrideTimeOptions(showTime, this.datePickerService.value as CandyDate);\n      }\n    } else {\n      this.timeOptions = null;\n    }\n  }\n\n  private overrideTimeOptions(\n    origin: SupportTimeOptions,\n    value: CandyDate,\n    partial?: DisabledTimePartial\n  ): SupportTimeOptions {\n    let disabledTimeFn;\n    if (partial) {\n      disabledTimeFn = partial === 'start' ? this.disabledStartTime : this.disabledEndTime;\n    } else {\n      disabledTimeFn = this.disabledTime;\n    }\n    return { ...origin, ...getTimeConfig(value, disabledTimeFn) };\n  }\n\n  private overrideHms(newValue: CandyDate | null, oldValue: CandyDate | null): CandyDate {\n    newValue = newValue || new CandyDate();\n    oldValue = oldValue || new CandyDate();\n    return oldValue.setHms(newValue.getHours(), newValue.getMinutes(), newValue.getSeconds());\n  }\n}\n"
  },
  {
    "path": "components/date-picker/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n最简单的用法，在浮层中可以选择或者输入日期。\n\n## en-US\n\nBasic use case. Users can select or input a date in panel.\n"
  },
  {
    "path": "components/date-picker/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { getISOWeek } from 'date-fns';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzDatePickerModule } from 'ng-zorro-antd/date-picker';\nimport { en_US, NzI18nService, zh_CN } from 'ng-zorro-antd/i18n';\n\n@Component({\n  selector: 'nz-demo-date-picker-basic',\n  imports: [FormsModule, NzButtonModule, NzDatePickerModule],\n  template: `\n    <nz-date-picker [(ngModel)]=\"date\" (ngModelChange)=\"onChange($event)\" />\n    <br />\n    <nz-date-picker nzMode=\"week\" [(ngModel)]=\"date\" (ngModelChange)=\"getWeek($event)\" />\n    <br />\n    <nz-date-picker nzMode=\"month\" [(ngModel)]=\"date\" (ngModelChange)=\"onChange($event)\" />\n    <br />\n    <nz-date-picker nzMode=\"quarter\" [(ngModel)]=\"date\" (ngModelChange)=\"onChange($event)\" />\n    <br />\n    <nz-date-picker nzMode=\"year\" [(ngModel)]=\"date\" (ngModelChange)=\"onChange($event)\" />\n    <br />\n    <button nz-button nzType=\"default\" (click)=\"changeLanguage()\">Switch language for all pickers</button>\n  `,\n  styles: `\n    nz-date-picker {\n      margin: 0 8px 12px 0;\n    }\n  `\n})\nexport class NzDemoDatePickerBasicComponent {\n  date = null;\n  isEnglish = false;\n\n  constructor(private i18n: NzI18nService) {}\n\n  onChange(result: Date): void {\n    console.log('onChange: ', result);\n  }\n\n  getWeek(result: Date): void {\n    console.log('week: ', getISOWeek(result));\n  }\n\n  changeLanguage(): void {\n    this.i18n.setLocale(this.isEnglish ? zh_CN : en_US);\n    this.isEnglish = !this.isEnglish;\n  }\n}\n"
  },
  {
    "path": "components/date-picker/demo/date-render.md",
    "content": "---\norder: 11\ntitle:\n  zh-CN: 定制日期单元格\n  en-US: Customized Date Rendering\n---\n\n## zh-CN\n\n使用 `nzDateRender` 可以自定义日期单元格的内容和样式。\n\n## en-US\n\nWe can customize the rendering of date cells in the calendar by providing a `nzDateRender` function to `DatePicker`.\n"
  },
  {
    "path": "components/date-picker/demo/date-render.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDatePickerModule } from 'ng-zorro-antd/date-picker';\n\n@Component({\n  selector: 'nz-demo-date-picker-date-render',\n  imports: [NzDatePickerModule],\n  template: `\n    <nz-date-picker [nzDateRender]=\"tplRender\" />\n    <nz-range-picker [nzDateRender]=\"tplRender\" />\n\n    <ng-template #tplRender let-current>\n      <div class=\"ant-picker-cell-inner\" [class.border]=\"current.getDate() === 1\"> {{ current.getDate() }} </div>\n    </ng-template>\n\n    <br />\n    <nz-date-picker nzMode=\"quarter\" nzFormat=\"yyyy年Q季度\" [nzDateRender]=\"tplQuarterRender\" />\n    <ng-template #tplQuarterRender let-current>\n      <div class=\"ant-picker-cell-inner\">{{ getQuarter(current) }}</div>\n    </ng-template>\n  `,\n  styles: `\n    nz-date-picker,\n    nz-range-picker {\n      margin: 0 8px 12px 0;\n    }\n    .border {\n      border: 1px solid #1890ff;\n      border-radius: 50%;\n    }\n  `\n})\nexport class NzDemoDatePickerDateRenderComponent {\n  getQuarter(date: Date): string {\n    const quarter = Math.floor((date.getMonth() + 3) / 3);\n    const quarterMapper: Record<string, string> = { 1: '一', 2: '二', 3: '三', 4: '四' };\n    return `${quarterMapper[quarter]}季度`;\n  }\n}\n"
  },
  {
    "path": "components/date-picker/demo/disabled-date.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 不可选择日期和时间\n  en-US: Disabled Date & Time\n---\n\n## zh-CN\n\n可用 `nzDisabledDate` 和 `nzDisabledTime` 分别禁止选择部分日期和时间。\n\n## en-US\n\nDisabled part of dates and time by `nzDisabledDate` and `nzDisabledTime` respectively.\n"
  },
  {
    "path": "components/date-picker/demo/disabled-date.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { differenceInCalendarDays, setHours } from 'date-fns';\n\nimport { DisabledTimeFn, DisabledTimePartial, NzDatePickerModule } from 'ng-zorro-antd/date-picker';\n\n@Component({\n  selector: 'nz-demo-date-picker-disabled-date',\n  imports: [NzDatePickerModule],\n  template: `\n    <nz-date-picker\n      nzFormat=\"yyyy-MM-dd HH:mm:ss\"\n      [nzDisabledDate]=\"disabledDate\"\n      [nzDisabledTime]=\"disabledDateTime\"\n      [nzShowTime]=\"{ nzDefaultOpenValue: timeDefaultValue }\"\n    />\n    <br />\n    <nz-date-picker nzMode=\"month\" [nzDisabledDate]=\"disabledDate\" />\n    <br />\n    <nz-date-picker nzMode=\"quarter\" [nzDisabledDate]=\"disabledDate\" />\n    <br />\n    <nz-date-picker nzMode=\"year\" [nzDisabledDate]=\"disabledDate\" />\n    <br />\n    <nz-range-picker\n      [nzDisabledDate]=\"disabledDate\"\n      [nzDisabledTime]=\"disabledRangeTime\"\n      [nzShowTime]=\"{ nzHideDisabledOptions: true, nzDefaultOpenValue: timeDefaultValue }\"\n      nzFormat=\"yyyy-MM-dd HH:mm:ss\"\n    />\n  `,\n  styles: `\n    nz-date-picker,\n    nz-range-picker {\n      margin: 0 8px 12px 0;\n    }\n  `\n})\nexport class NzDemoDatePickerDisabledDateComponent {\n  today = new Date();\n  timeDefaultValue = setHours(new Date(), 0);\n\n  range(start: number, end: number): number[] {\n    const result: number[] = [];\n    for (let i = start; i < end; i++) {\n      result.push(i);\n    }\n    return result;\n  }\n\n  disabledDate = (current: Date): boolean =>\n    // Can not select days before today and today\n    differenceInCalendarDays(current, this.today) > 0;\n\n  disabledDateTime: DisabledTimeFn = () => ({\n    nzDisabledHours: () => this.range(0, 24).splice(4, 20),\n    nzDisabledMinutes: () => this.range(30, 60),\n    nzDisabledSeconds: () => [55, 56]\n  });\n\n  disabledRangeTime: DisabledTimeFn = (_value, type?: DisabledTimePartial) => {\n    if (type === 'start') {\n      return {\n        nzDisabledHours: () => this.range(0, 60).splice(4, 20),\n        nzDisabledMinutes: () => this.range(30, 60),\n        nzDisabledSeconds: () => [55, 56]\n      };\n    }\n    return {\n      nzDisabledHours: () => this.range(0, 60).splice(20, 4),\n      nzDisabledMinutes: () => this.range(0, 31),\n      nzDisabledSeconds: () => [55, 56]\n    };\n  };\n}\n"
  },
  {
    "path": "components/date-picker/demo/disabled.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 禁用\n  en-US: Disabled\n---\n\n## zh-CN\n\n选择框的不可用状态。\n\n## en-US\n\nA disabled state of the `DatePicker`.\n"
  },
  {
    "path": "components/date-picker/demo/disabled.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDatePickerModule } from 'ng-zorro-antd/date-picker';\n\n@Component({\n  selector: 'nz-demo-date-picker-disabled',\n  imports: [NzDatePickerModule],\n  template: `\n    <nz-date-picker nzDisabled />\n    <br />\n    <nz-date-picker nzMode=\"month\" nzDisabled />\n    <br />\n    <nz-range-picker nzDisabled />\n  `,\n  styles: `\n    nz-date-picker,\n    nz-range-picker {\n      margin: 0 8px 12px 0;\n    }\n  `\n})\nexport class NzDemoDatePickerDisabledComponent {}\n"
  },
  {
    "path": "components/date-picker/demo/extra-footer.md",
    "content": "---\norder: 10\ntitle:\n  zh-CN: 额外的页脚\n  en-US: Extra Footer\n---\n\n## zh-CN\n\n在浮层中加入额外的页脚，以满足某些定制信息的需求。\n\n## en-US\n\nRender extra footer in panel for customized requirements.\n"
  },
  {
    "path": "components/date-picker/demo/extra-footer.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDatePickerModule } from 'ng-zorro-antd/date-picker';\n\n@Component({\n  selector: 'nz-demo-date-picker-extra-footer',\n  imports: [NzDatePickerModule],\n  template: `\n    <nz-date-picker [nzRenderExtraFooter]=\"footerRender\" />\n    <br />\n    <nz-date-picker [nzRenderExtraFooter]=\"plainFooter\" nzShowTime />\n    <nz-range-picker [nzRenderExtraFooter]=\"footerRender\" />\n    <nz-range-picker [nzRenderExtraFooter]=\"plainFooter\" nzShowTime />\n    <nz-date-picker nzMode=\"month\" [nzRenderExtraFooter]=\"footerRender\" />\n  `,\n  styles: `\n    nz-date-picker,\n    nz-range-picker {\n      margin: 0 8px 12px 0;\n    }\n  `\n})\nexport class NzDemoDatePickerExtraFooterComponent {\n  plainFooter = 'plain extra footer';\n  footerRender = (): string => 'extra footer';\n}\n"
  },
  {
    "path": "components/date-picker/demo/format.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 日期格式\n  en-US: Date Format\n---\n\n## zh-CN\n\n使用 `nzFormat` 属性，可以自定义日期显示格式。\n\n## en-US\n\nWe can set the date format by `nzFormat`.\n"
  },
  {
    "path": "components/date-picker/demo/format.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDatePickerModule } from 'ng-zorro-antd/date-picker';\n\n@Component({\n  selector: 'nz-demo-date-picker-format',\n  imports: [NzDatePickerModule],\n  template: `\n    <nz-date-picker [nzFormat]=\"dateFormat\" />\n    <br />\n    <nz-date-picker nzMode=\"month\" [nzFormat]=\"monthFormat\" />\n    <br />\n    <nz-date-picker nzMode=\"quarter\" [nzFormat]=\"quarterFormat\" />\n    <br />\n    <nz-range-picker [nzFormat]=\"dateFormat\" />\n  `,\n  styles: `\n    nz-date-picker,\n    nz-range-picker {\n      margin: 0 8px 12px 0;\n    }\n  `\n})\nexport class NzDemoDatePickerFormatComponent {\n  dateFormat = 'yyyy/MM/dd';\n  monthFormat = 'yyyy/MM';\n  quarterFormat = 'yyyy/[Q]Q';\n}\n"
  },
  {
    "path": "components/date-picker/demo/inline.md",
    "content": "---\norder: 13\ntitle:\n  zh-CN: 内联模式\n  en-US: Inline mode\n---\n\n## zh-CN\n\n使用 `nzInline` 属性，可以渲染为内联模式。\n\n## en-US\n\nWe can set the inline mode by `nzInline`.\n"
  },
  {
    "path": "components/date-picker/demo/inline.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { getISOWeek } from 'date-fns';\n\nimport { NzDatePickerModule } from 'ng-zorro-antd/date-picker';\nimport { NzTabsModule } from 'ng-zorro-antd/tabs';\n\n@Component({\n  selector: 'nz-demo-date-picker-inline',\n  imports: [FormsModule, NzDatePickerModule, NzTabsModule],\n  template: `\n    <nz-tabs>\n      <nz-tab nzTitle=\"Default\">\n        <nz-date-picker nzInline [(ngModel)]=\"date\" (ngModelChange)=\"onChange($event)\" />\n      </nz-tab>\n      <nz-tab nzTitle=\"Week\">\n        <nz-date-picker nzInline nzMode=\"week\" [(ngModel)]=\"date\" (ngModelChange)=\"getWeek($event)\" />\n      </nz-tab>\n      <nz-tab nzTitle=\"Month\">\n        <nz-date-picker nzInline nzMode=\"month\" [(ngModel)]=\"date\" (ngModelChange)=\"onChange($event)\" />\n      </nz-tab>\n      <nz-tab nzTitle=\"Quarter\">\n        <nz-date-picker nzInline nzMode=\"quarter\" [(ngModel)]=\"date\" (ngModelChange)=\"onChange($event)\" />\n      </nz-tab>\n      <nz-tab nzTitle=\"Year\">\n        <nz-date-picker nzInline nzMode=\"year\" [(ngModel)]=\"date\" (ngModelChange)=\"onChange($event)\" />\n      </nz-tab>\n      <nz-tab nzTitle=\"Range\">\n        <nz-range-picker nzInline [(ngModel)]=\"rangeDate\" (ngModelChange)=\"onChange($event)\" />\n      </nz-tab>\n      <nz-tab nzTitle=\"Range Time\">\n        <nz-range-picker nzInline nzShowTime [(ngModel)]=\"rangeDate\" (ngModelChange)=\"onChange($event)\" />\n      </nz-tab>\n      <nz-tab nzTitle=\"Range Week\">\n        <nz-range-picker nzInline nzMode=\"week\" [(ngModel)]=\"rangeDate\" (ngModelChange)=\"onChange($event)\" />\n      </nz-tab>\n      <nz-tab nzTitle=\"Range Month\">\n        <nz-range-picker nzInline nzMode=\"month\" [(ngModel)]=\"rangeDate\" (ngModelChange)=\"onChange($event)\" />\n      </nz-tab>\n      <nz-tab nzTitle=\"Range Quarter\">\n        <nz-range-picker nzInline nzMode=\"quarter\" [(ngModel)]=\"rangeDate\" (ngModelChange)=\"onChange($event)\" />\n      </nz-tab>\n      <nz-tab nzTitle=\"Range Year\">\n        <nz-range-picker nzInline nzMode=\"year\" [(ngModel)]=\"rangeDate\" (ngModelChange)=\"onChange($event)\" />\n      </nz-tab>\n    </nz-tabs>\n  `,\n  styles: `\n    :host ::ng-deep .ant-tabs-tabpane {\n      padding: 24px;\n      overflow: auto;\n    }\n  `\n})\nexport class NzDemoDatePickerInlineComponent {\n  date = null;\n  rangeDate = null;\n\n  onChange(result: Date): void {\n    console.log('onChange: ', result);\n  }\n\n  getWeek(result: Date): void {\n    console.log('week: ', getISOWeek(result));\n  }\n}\n"
  },
  {
    "path": "components/date-picker/demo/placement.md",
    "content": "---\norder: 15\ntitle:\n  zh-CN: 自定义位置\n  en-US: Placement\n---\n\n## zh-CN\n\n可以通过 `nzPlacement` 手动指定弹出的位置。\n\n## en-US\n\nYou can manually specify the position of the popup via `nzPlacement`.\n"
  },
  {
    "path": "components/date-picker/demo/placement.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport type { NzPlacement } from 'ng-zorro-antd/core/types';\nimport { NzDatePickerModule } from 'ng-zorro-antd/date-picker';\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\n\n@Component({\n  selector: 'nz-demo-date-picker-placement',\n  imports: [FormsModule, NzDatePickerModule, NzRadioModule],\n  template: `\n    <nz-radio-group [(ngModel)]=\"placement\">\n      <label nz-radio-button nzValue=\"bottomLeft\">bottomLeft</label>\n      <label nz-radio-button nzValue=\"bottomRight\">bottomRight</label>\n      <label nz-radio-button nzValue=\"topLeft\">topLeft</label>\n      <label nz-radio-button nzValue=\"topRight\">topRight</label>\n    </nz-radio-group>\n    <br />\n    <br />\n    <nz-date-picker [nzPlacement]=\"placement\" />\n    <br />\n    <nz-range-picker [nzPlacement]=\"placement\" />\n  `,\n  styles: `\n    nz-date-picker,\n    nz-range-picker {\n      margin: 0 8px 12px 0;\n    }\n  `\n})\nexport class NzDemoDatePickerPlacementComponent {\n  placement: NzPlacement = 'bottomLeft';\n}\n"
  },
  {
    "path": "components/date-picker/demo/presetted-ranges.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 预设范围\n  en-US: Presetted Ranges\n---\n\n## zh-CN\n\nRangePicker 可以设置常用的 预设范围 提高用户体验。\n\n## en-US\n\nWe can set presetted ranges to RangePicker to improve user experience.\n"
  },
  {
    "path": "components/date-picker/demo/presetted-ranges.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { endOfMonth } from 'date-fns';\n\nimport { NzDatePickerModule } from 'ng-zorro-antd/date-picker';\n\n@Component({\n  selector: 'nz-demo-date-picker-presetted-ranges',\n  imports: [FormsModule, NzDatePickerModule],\n  template: `\n    <nz-range-picker [nzRanges]=\"ranges\" ngModel (ngModelChange)=\"onChange($event)\" />\n    <br />\n    <nz-range-picker\n      [nzRanges]=\"ranges\"\n      nzShowTime\n      nzFormat=\"yyyy/MM/dd HH:mm:ss\"\n      ngModel\n      (ngModelChange)=\"onChange($event)\"\n    />\n  `,\n  styles: `\n    nz-date-picker,\n    nz-range-picker {\n      margin: 0 8px 12px 0;\n    }\n  `\n})\nexport class NzDemoDatePickerPresettedRangesComponent {\n  ranges = { Today: [new Date(), new Date()], 'This Month': [new Date(), endOfMonth(new Date())] };\n\n  onChange(result: Date[]): void {\n    console.log('From: ', result[0], ', to: ', result[1]);\n  }\n}\n"
  },
  {
    "path": "components/date-picker/demo/range-picker.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 范围选择器\n  en-US: Range Picker\n---\n\n## zh-CN\n\n通过设置 `nzMode` 属性，指定范围选择器类型。\n\n## en-US\n\nSet range picker type by `nzMode` prop.\n"
  },
  {
    "path": "components/date-picker/demo/range-picker.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { getISOWeek } from 'date-fns';\n\nimport { NzDatePickerModule } from 'ng-zorro-antd/date-picker';\n\n@Component({\n  selector: 'nz-demo-date-picker-range-picker',\n  imports: [FormsModule, NzDatePickerModule],\n  template: `\n    <nz-range-picker [(ngModel)]=\"date\" (ngModelChange)=\"onChange($event)\" />\n    <br />\n    <nz-range-picker [nzShowTime]=\"true\" [(ngModel)]=\"date\" (ngModelChange)=\"onChange($event)\" />\n    <br />\n    <nz-range-picker nzMode=\"week\" [(ngModel)]=\"date\" (ngModelChange)=\"getWeek($event)\" />\n    <br />\n    <nz-range-picker nzMode=\"month\" [(ngModel)]=\"date\" (ngModelChange)=\"onChange($event)\" />\n    <br />\n    <nz-range-picker nzMode=\"quarter\" [(ngModel)]=\"date\" (ngModelChange)=\"onChange($event)\" />\n    <br />\n    <nz-range-picker nzMode=\"year\" [(ngModel)]=\"date\" (ngModelChange)=\"onChange($event)\" />\n  `,\n  styles: `\n    nz-range-picker {\n      margin: 0 8px 12px 0;\n    }\n  `\n})\nexport class NzDemoDatePickerRangePickerComponent {\n  date = null;\n\n  onChange(result: Date[]): void {\n    console.log('onChange: ', result);\n  }\n\n  getWeek(result: Date[]): void {\n    console.log('week: ', result.map(getISOWeek));\n  }\n}\n"
  },
  {
    "path": "components/date-picker/demo/size.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 三种大小\n  en-US: Three Sizes\n---\n\n## zh-CN\n\n三种大小的输入框，若不设置，则为 `default`。\n\n## en-US\n\nThe input box comes in three sizes. `default` will be used if `nzSize` is omitted.\n"
  },
  {
    "path": "components/date-picker/demo/size.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzDatePickerModule, NzDatePickerSizeType } from 'ng-zorro-antd/date-picker';\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\n\n@Component({\n  selector: 'nz-demo-date-picker-size',\n  imports: [FormsModule, NzDatePickerModule, NzRadioModule],\n  template: `\n    <nz-radio-group [(ngModel)]=\"size\">\n      <label nz-radio-button nzValue=\"large\">large</label>\n      <label nz-radio-button nzValue=\"default\">default</label>\n      <label nz-radio-button nzValue=\"small\">small</label>\n    </nz-radio-group>\n    <br />\n    <br />\n    <nz-date-picker [nzSize]=\"size\" />\n    <br />\n    <nz-date-picker nzMode=\"week\" [nzSize]=\"size\" />\n    <br />\n    <nz-date-picker nzMode=\"month\" [nzSize]=\"size\" />\n    <br />\n    <nz-date-picker nzMode=\"quarter\" [nzSize]=\"size\" />\n    <br />\n    <nz-range-picker [nzSize]=\"size\" />\n  `,\n  styles: `\n    nz-date-picker,\n    nz-range-picker {\n      margin: 0 8px 12px 0;\n    }\n  `\n})\nexport class NzDemoDatePickerSizeComponent {\n  size: NzDatePickerSizeType = 'default';\n}\n"
  },
  {
    "path": "components/date-picker/demo/start-end.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 自定义日期范围选择\n  en-US: Customized Range Picker\n---\n\n## zh-CN\n\n当 `RangePicker` 无法满足业务需求时，可以使用两个 `DatePicker` 实现类似的功能。\n\n> - 通过设置 `nzDisabledDate` 方法，来约束开始和结束日期。\n> - 通过 `open()` 来优化交互。\n\n## en-US\n\nWhen `RangePicker` does not satisfied your requirements, try to implement similar functionality with two `DatePicker`.\n\n> - Use the `nzDisabledDate` property to limit the start and end dates.\n> - Improve user experience with `open()`.\n"
  },
  {
    "path": "components/date-picker/demo/start-end.ts",
    "content": "import { Component, ViewChild } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzDatePickerComponent, NzDatePickerModule } from 'ng-zorro-antd/date-picker';\n\n@Component({\n  selector: 'nz-demo-date-picker-start-end',\n  imports: [FormsModule, NzDatePickerModule],\n  template: `\n    <nz-date-picker\n      [nzDisabledDate]=\"disabledStartDate\"\n      nzShowTime\n      nzFormat=\"yyyy-MM-dd HH:mm:ss\"\n      [(ngModel)]=\"startValue\"\n      nzPlaceHolder=\"Start\"\n      (nzOnOpenChange)=\"handleStartOpenChange($event)\"\n    />\n    <nz-date-picker\n      #endDatePicker\n      [nzDisabledDate]=\"disabledEndDate\"\n      nzShowTime\n      nzFormat=\"yyyy-MM-dd HH:mm:ss\"\n      [(ngModel)]=\"endValue\"\n      nzPlaceHolder=\"End\"\n      (nzOnOpenChange)=\"handleEndOpenChange($event)\"\n    />\n  `,\n  styles: `\n    nz-date-picker {\n      margin: 0 8px 12px 0;\n    }\n  `\n})\nexport class NzDemoDatePickerStartEndComponent {\n  startValue: Date | null = null;\n  endValue: Date | null = null;\n  @ViewChild('endDatePicker') endDatePicker!: NzDatePickerComponent;\n\n  disabledStartDate = (startValue: Date): boolean => {\n    if (!startValue || !this.endValue) {\n      return false;\n    }\n    return startValue.getTime() > this.endValue.getTime();\n  };\n\n  disabledEndDate = (endValue: Date): boolean => {\n    if (!endValue || !this.startValue) {\n      return false;\n    }\n    return endValue.getTime() <= this.startValue.getTime();\n  };\n\n  handleStartOpenChange(open: boolean): void {\n    if (!open) {\n      this.endDatePicker.open();\n    }\n    console.log('handleStartOpenChange', open);\n  }\n\n  handleEndOpenChange(open: boolean): void {\n    console.log('handleEndOpenChange', open);\n  }\n}\n"
  },
  {
    "path": "components/date-picker/demo/status.md",
    "content": "---\norder: 14\ntitle:\n  zh-CN: 自定义状态\n  en-US: Status\n---\n\n## zh-CN\n\n使用 `nzStatus` 为 DatePicker 添加状态，可选 `error` 或者 `warning`。\n\n## en-US\n\nAdd status to DatePicker with `nzStatus`, which could be `error` or `warning`.\n"
  },
  {
    "path": "components/date-picker/demo/status.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDatePickerModule } from 'ng-zorro-antd/date-picker';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\n\n@Component({\n  selector: 'nz-demo-date-picker-status',\n  imports: [NzDatePickerModule, NzSpaceModule],\n  template: `\n    <nz-space nzDirection=\"vertical\" style=\"width: 100%\">\n      <nz-date-picker *nzSpaceItem nzStatus=\"error\" style=\"width: 100%\" />\n      <nz-date-picker *nzSpaceItem nzStatus=\"warning\" style=\"width: 100%\" />\n      <nz-range-picker *nzSpaceItem nzStatus=\"error\" style=\"width: 100%\" />\n      <nz-range-picker *nzSpaceItem nzStatus=\"warning\" style=\"width: 100%\" />\n    </nz-space>\n  `\n})\nexport class NzDemoDatePickerStatusComponent {}\n"
  },
  {
    "path": "components/date-picker/demo/switch.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 切换不同的选择器\n  en-US: Switchable picker\n---\n\n## zh-CN\n\n提供选择器，自由切换不同类型的日期选择器，常用于日期筛选场合。\n\n## en-US\n\nSwitch in different types of pickers by Select.\n"
  },
  {
    "path": "components/date-picker/demo/switch.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzDatePickerModule } from 'ng-zorro-antd/date-picker';\nimport { NzSelectModule } from 'ng-zorro-antd/select';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\n\n@Component({\n  selector: 'nz-demo-date-picker-switch',\n  imports: [FormsModule, NzDatePickerModule, NzSelectModule, NzSpaceModule],\n  template: `\n    <nz-space>\n      <nz-select *nzSpaceItem [(ngModel)]=\"mode\">\n        <nz-option nzValue=\"date\" nzLabel=\"Date\" />\n        <nz-option nzValue=\"week\" nzLabel=\"Week\" />\n        <nz-option nzValue=\"month\" nzLabel=\"Month\" />\n        <nz-option nzValue=\"quarter\" nzLabel=\"Quarter\" />\n        <nz-option nzValue=\"year\" nzLabel=\"Year\" />\n      </nz-select>\n      <nz-date-picker *nzSpaceItem [nzMode]=\"mode\" />\n    </nz-space>\n  `\n})\nexport class NzDemoDatePickerSwitchComponent {\n  mode = 'date';\n}\n"
  },
  {
    "path": "components/date-picker/demo/time.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 日期时间选择\n  en-US: Choose Time\n---\n\n## zh-CN\n\n增加选择时间功能，当 `nzShowTime` 为一个对象时，其属性会传递给内建的 `TimePicker`。\n\n## en-US\n\nThis property provide an additional time selection. When `nzShowTime` is an Object, its properties will be passed on to built-in `TimePicker`.\n"
  },
  {
    "path": "components/date-picker/demo/time.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzDatePickerModule } from 'ng-zorro-antd/date-picker';\n\n@Component({\n  selector: 'nz-demo-date-picker-time',\n  imports: [FormsModule, NzDatePickerModule],\n  template: `\n    <nz-date-picker\n      nzShowTime\n      nzFormat=\"yyyy-MM-dd HH:mm:ss\"\n      ngModel\n      (ngModelChange)=\"onChange($event)\"\n      (nzOnOk)=\"onOk($event)\"\n    />\n    <br />\n    <nz-range-picker\n      [nzShowTime]=\"{ nzFormat: 'HH:mm' }\"\n      nzFormat=\"yyyy-MM-dd HH:mm\"\n      ngModel\n      (ngModelChange)=\"onChange($event)\"\n      (nzOnCalendarChange)=\"onCalendarChange($event)\"\n      (nzOnOk)=\"onOk($event)\"\n    />\n  `,\n  styles: `\n    nz-date-picker,\n    nz-range-picker {\n      margin: 0 8px 12px 0;\n    }\n  `\n})\nexport class NzDemoDatePickerTimeComponent {\n  onChange(result: Date): void {\n    console.log('Selected Time: ', result);\n  }\n\n  onOk(result: Date | Date[] | null): void {\n    console.log('onOk', result);\n  }\n\n  onCalendarChange(result: Array<Date | null>): void {\n    console.log('onCalendarChange', result);\n  }\n}\n"
  },
  {
    "path": "components/date-picker/demo/variant.md",
    "content": "---\norder: 12\nversion: 20.0.0\ntitle:\n  zh-CN: 形态变体\n  en-US: Variants\n---\n\n## zh-CN\n\nDatePicker 形态变体，可选 `outlined` `filled` `borderless` `underlined` 四种形态。\n\n## en-US\n\nVariants of DatePicker, there are four variants: `outlined` `filled` `borderless` and `underlined`.\n"
  },
  {
    "path": "components/date-picker/demo/variant.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDatePickerModule } from 'ng-zorro-antd/date-picker';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\n\n@Component({\n  selector: 'nz-demo-date-picker-variant',\n  imports: [NzDatePickerModule, NzSpaceModule],\n  template: `\n    <nz-space nzDirection=\"vertical\" style=\"width: 100%\">\n      <nz-date-picker *nzSpaceItem nzVariant=\"outlined\" />\n      <nz-date-picker *nzSpaceItem nzVariant=\"filled\" />\n      <nz-date-picker *nzSpaceItem nzVariant=\"borderless\" />\n      <nz-date-picker *nzSpaceItem nzVariant=\"underlined\" />\n    </nz-space>\n  `,\n  styles: `\n    nz-date-picker {\n      margin: 0 8px 12px 0;\n    }\n  `\n})\nexport class NzDemoDatePickerVariantComponent {}\n"
  },
  {
    "path": "components/date-picker/demo/week-number.md",
    "content": "---\norder: 16\ntitle:\n  zh-CN: 显示周数\n  en-US: Week Number\n---\n\n## zh-CN\n\n使用 `nzShowWeekNumber` 显示周数\n\n## en-US\n\nDisplay week numbers with `nzShowWeekNumber`.\n"
  },
  {
    "path": "components/date-picker/demo/week-number.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzDatePickerModule } from 'ng-zorro-antd/date-picker';\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\n\n@Component({\n  selector: 'nz-demo-date-picker-week-number',\n  imports: [FormsModule, NzDatePickerModule, NzRadioModule],\n  template: `\n    <nz-radio-group [(ngModel)]=\"showWeekNumber\">\n      <label nz-radio-button [nzValue]=\"true\">true</label>\n      <label nz-radio-button [nzValue]=\"false\">false</label>\n    </nz-radio-group>\n    <br />\n    <br />\n    <nz-date-picker [nzShowWeekNumber]=\"showWeekNumber\" />\n    <br />\n    <nz-range-picker [nzShowWeekNumber]=\"showWeekNumber\" />\n  `,\n  styles: `\n    nz-date-picker,\n    nz-range-picker {\n      margin: 0 8px 12px 0;\n    }\n  `\n})\nexport class NzDemoDatePickerWeekNumberComponent {\n  showWeekNumber: boolean = false;\n}\n"
  },
  {
    "path": "components/date-picker/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Entry\ntitle: DatePicker\ncover: 'https://gw.alipayobjects.com/zos/alicdn/RT_USzA48/DatePicker.svg'\ndescription: To select or input a date.\n---\n\n## When To Use\n\nBy clicking the input box, you can select a date from a popup calendar.\n\n## API\n\n**Note:** Some of nz-date-picker's locale are coming from [Angular i18n](https://angular.dev/guide/i18n), that should be\nprovided in the file `app.config.ts`.\n\nFor example:\n\n```typescript\nimport { registerLocaleData } from '@angular/common';\nimport en from '@angular/common/locales/en';\n\nregisterLocaleData(en);\n```\n\n**Note:** All input and output date objects\nare [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date), you can manipulate it\nwith [date-fns](https://date-fns.org/).\n\n### Common API\n\nThe following APIs are shared by nz-date-picker, nz-range-picker.\n\n| Property                 | Description                                                                                                                        | Type                                                       | Default                                                                                                    | Global Config | Version |\n| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ------------- | ------- |\n| `[nzId]`                 | input id attribute inside the component                                                                                            | `string`                                                   | -                                                                                                          |\n| `[nzAllowClear]`         | Whether to show clear button                                                                                                       | `boolean`                                                  | `true`                                                                                                     | -             |\n| `[nzAutoFocus]`          | get focus when component mounted                                                                                                   | `boolean`                                                  | `false`                                                                                                    | -             |\n| `[nzBackdrop]`           | whether or not the overlay should attach a backdrop                                                                                | `boolean`                                                  | `false`                                                                                                    |\n| `[nzDefaultPickerValue]` | default picker date                                                                                                                | `Date \\| Date[]`                                           | -                                                                                                          | -             |\n| `[nzDisabled]`           | determine whether the nz-date-picker is disabled                                                                                   | `boolean`                                                  | `false`                                                                                                    | -             |\n| `[nzDisabledDate]`       | specify the date that cannot be selected                                                                                           | `(current: Date) => boolean`                               | -                                                                                                          | -             |\n| `[nzDropdownClassName]`  | to customize the className of the popup calendar                                                                                   | `string`                                                   | -                                                                                                          | -             |\n| `[nzFormat]`             | to set the date format, see `nzFormat special instructions`                                                                        | `string`                                                   | -                                                                                                          |\n| `[nzInputReadOnly]`      | set the readonly attribute of the input tag (avoids virtual keyboard on touch devices)                                             | `boolean`                                                  | `false`                                                                                                    | -             |\n| `[nzLocale]`             | localization configuration                                                                                                         | `object`                                                   | [default](https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json) | -             |\n| `[nzMode]`               | Set picker mode                                                                                                                    | `'date' \\| 'week' \\| 'month' \\| 'quarter'  \\| 'year'`      | `'date'`                                                                                                   |\n| `[nzPlaceHolder]`        | placeholder of date input                                                                                                          | `string \\| string[]`                                       | -                                                                                                          |\n| `[nzPopupStyle]`         | to customize the style of the popup calendar                                                                                       | `object`                                                   | `{}`                                                                                                       | -             |\n| `[nzRenderExtraFooter]`  | render extra footer in panel                                                                                                       | `TemplateRef \\| string \\| (() => TemplateRef \\| string)`   | -                                                                                                          |\n| `[nzSize]`               | determine the size of the input box, the height of `large` and `small`, are 40px and 24px respectively, while default size is 32px | `'large' \\| 'small'`                                       | -                                                                                                          | -             |\n| `[nzStatus]`             | Set validation status                                                                                                              | `'error' \\| 'warning'`                                     | -                                                                                                          |\n| `[nzPlacement]`          | The position where the selection box pops up                                                                                       | `'bottomLeft' \\| 'bottomRight' \\| 'topLeft' \\| 'topRight'` | `'bottomLeft'`                                                                                             |               |\n| `[nzSuffixIcon]`         | the custom suffix icon                                                                                                             | `string \\| TemplateRef`                                    | -                                                                                                          | ✅            |\n| `[nzVariant]`            | Variants of DatePicker                                                                                                             | `'outlined' \\| 'borderless' \\| 'filled' \\| 'underlined'`   | `'outlined'`                                                                                               | ✅            | 20.0.0  |\n| `[nzInline]`             | inline mode                                                                                                                        | `boolean`                                                  | `false`                                                                                                    | -             |\n| `(nzOnOpenChange)`       | a callback emitter, can be executed whether the popup calendar is popped up or closed                                              | `EventEmitter<boolean>`                                    | -                                                                                                          | -             |\n| `(nzOnPanelChange)`      | a callback emitter, can be executed when the panel changes                                                                         | `EventEmitter<NzPanelChangeType>`                          | -                                                                                                          | -             |\n\n### Common Methods\n\n| Name      | Description          |\n| --------- | -------------------- |\n| `open()`  | open calendar panel  |\n| `close()` | close calendar panel |\n\n### nz-date-picker\n\n| Property      | Description | Type   | Default |\n| ------------- | ----------- | ------ | ------- |\n| `[(ngModel)]` | Date        | `Date` | -       |\n\n### nz-date-picker[nzMode=\"date\"]\n\n| Property             | Description                                                                                                        | Type                                                                           | Default                                                                     |\n| -------------------- | ------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------ | --------------------------------------------------------------------------- |\n| `[nzDateRender]`     | custom rendering function for date cells (Not support by month-picker/year-picker)                                 | -                                                                              | `TemplateRef<Date> \\| string \\| ((d: Date) => TemplateRef<Date> \\| string)` |\n| `[nzDisabledTime]`   | to specify the time that cannot be selected                                                                        | `(current: Date) => { nzDisabledHours, nzDisabledMinutes, nzDisabledSeconds }` | -                                                                           |\n| `[nzShowTime]`       | to provide an additional time selection                                                                            | `object \\| boolean`                                                            | [TimePicker Options](/components/time-picker/en#api)                        |\n| `[nzShowToday]`      | whether to show 'Today' button                                                                                     | `boolean`                                                                      | `true`                                                                      |\n| `[nzShowNow]`        | whether to show 'Now' button on panel when `nzShowTime` is set                                                     | `boolean`                                                                      | `true`                                                                      |\n| `[nzShowWeekNumber]` | whether to show the week number on each row (Only supported by date picker. Week picker always shows week numbers) | `boolean`                                                                      | `false`                                                                     |\n| `(nzOnOk)`           | callback when click ok button                                                                                      | `EventEmitter<Date>`                                                           | -                                                                           |\n\n### nz-range-picker\n\n| Property               | Description                                                 | Type                                                               | Default |\n| ---------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------ | ------- |\n| `[(ngModel)]`          | Date                                                        | `Date[]`                                                           | -       |\n| `[nzRanges]`           | preseted ranges for quick selection                         | `{ [ key: string ]: Date[] } \\| { [ key: string ]: () => Date[] }` | -       |\n| `[nzSeparator]`        | separator                                                   | `string \\| TemplateRef`                                            | `'~'`   |\n| `(nzOnCalendarChange)` | The start time or the end time of the range change callback | `EventEmitter<Date[]>`                                             | -       |\n\n### nz-range-picker[nzMode=\"date\"]\n\n| Property             | Description                                                                                                        | Type                                                                                                      | Default                                              |\n| -------------------- | ------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |\n| `[nzShowTime]`       | to provide an additional time selection                                                                            | `object \\| boolean`                                                                                       | [TimePicker Options](/components/time-picker/en#api) |\n| `[nzDisabledTime]`   | to specify the time that cannot be selected                                                                        | `(current: Date, partial: 'start' \\| 'end') => { nzDisabledHours, nzDisabledMinutes, nzDisabledSeconds }` | -                                                    |\n| `[nzShowWeekNumber]` | whether to show the week number on each row (Only supported by date picker. Week picker always shows week numbers) | `boolean`                                                                                                 | `false`                                              |\n| `(nzOnOk)`           | click ok callback                                                                                                  | `EventEmitter<Date[]>`                                                                                    | -                                                    |\n\n> Currently, supported `nz-time-picker` parameters in `nzShowTime` are: `nzFormat`, `nzHourStep`, `nzMinuteStep`,\n> `nzSecondStep`, `nzDisabledHours`, `nzDisabledMinutes`, `nzDisabledSeconds`, `nzHideDisabledOptions`,\n> `nzDefaultOpenValue`, `nzAddOn`\n\n## FAQ\n\n### Why does manual input not take effect after setting `nzFormat=\"dd/MM/yyyy\"`\n\nYou need to use `date-fns`. Date formatting currently supports two methods: `DatePipe` (\ndefault, [syntax reference](https://angular.dev/api/common/DatePipe)) and `date-fns` (\nsee [`How to format a date using date-fns`](/docs/i18n/en#How%20to%20format%20a%20date%20using%20Date-fns)).NG-ZORRO\ntakes the function provided by `date-fns` to implement date deserialization after using it.\n\n### Q: The overlay layer element does not follow the scroll position when scrolling\n\nBy default, the overlay layer element uses body as the scroll container. If using another scroll container, add the [CdkScrollable](https://material.angular.dev/cdk/scrolling/api#CdkScrollable) directive to the custom scroll container element.\nNote: You need to import the `CdkScrollable` directive or `ScrollingModule` module from `@angular/cdk/scrolling`.\n"
  },
  {
    "path": "components/date-picker/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ntype: 数据录入\ntitle: DatePicker\nsubtitle: 日期选择框\ncover: 'https://gw.alipayobjects.com/zos/alicdn/RT_USzA48/DatePicker.svg'\ndescription: 输入或选择日期的控件。\n---\n\n## 何时使用\n\n当用户需要输入一个日期，可以点击标准输入框，弹出日期面板进行选择。\n\n## API\n\n**注意：** nz-date-picker 的部分 locale 来自于 Angular 自身的[国际化支持](https://angular.cn/guide/i18n)\n，需要在 `app.config.ts` 文件中 引入相应的 Angular 语言包。\n例如：\n\n```typescript\nimport { registerLocaleData } from '@angular/common';\nimport zh from '@angular/common/locales/zh';\n\nregisterLocaleData(zh);\n```\n\n**注意：**\n所有输入输出日期对象均为 [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date)\n，你可以通过 [date-fns](https://date-fns.org/) 工具库获得你需要的数据。\n\n### 共同的 API\n\n以下 API 为 nz-date-picker、nz-range-picker 共享的 API。\n\n| 参数                     | 说明                                                          | 类型                                                       | 默认值                                                                                                      | 全局配置 | 版本   |\n| ------------------------ | ------------------------------------------------------------- | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | -------- | ------ |\n| `[nzId]`                 | 组件内部 input 的 id 值                                       | `string`                                                   | -                                                                                                           |\n| `[nzAllowClear]`         | 是否显示清除按钮                                              | `boolean`                                                  | `true`                                                                                                      | -        |\n| `[nzAutoFocus]`          | 自动获取焦点                                                  | `boolean`                                                  | `false`                                                                                                     | -        |\n| `[nzBackdrop]`           | 浮层是否应带有背景板                                          | `boolean`                                                  | `false`                                                                                                     |\n| `[nzDefaultPickerValue]` | 默认面板日期                                                  | `Date \\| Date[]`                                           | -                                                                                                           | -        |\n| `[nzDisabled]`           | 禁用                                                          | `boolean`                                                  | `false`                                                                                                     | -        |\n| `[nzDisabledDate]`       | 不可选择的日期                                                | `(current: Date) => boolean`                               | -                                                                                                           | -        |\n| `[nzDropdownClassName]`  | 额外的弹出日历 className                                      | `string`                                                   | -                                                                                                           | -        |\n| `[nzFormat]`             | 展示的日期格式，见`nzFormat特别说明`                          | `string`                                                   | -                                                                                                           |\n| `[nzInputReadOnly]`      | 为 input 标签设置只读属性（避免在移动设备上触发小键盘）       | `boolean`                                                  | `false`                                                                                                     | -        |\n| `[nzLocale]`             | 国际化配置                                                    | `object`                                                   | [默认配置](https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json) | -        |\n| `[nzMode]`               | 选择模式                                                      | `'date' \\| 'week' \\| 'month' \\| 'quarter'  \\| 'year'`      | `'date'`                                                                                                    |\n| `[nzPlaceHolder]`        | 输入框提示文字                                                | `string \\| string[]`                                       | -                                                                                                           | -        |\n| `[nzPopupStyle]`         | 额外的弹出日历样式                                            | `object`                                                   | `{}`                                                                                                        | -        |\n| `[nzRenderExtraFooter]`  | 在面板中添加额外的页脚                                        | `TemplateRef \\| string \\| (() => TemplateRef \\| string)`   | -                                                                                                           |\n| `[nzSize]`               | 输入框大小，`large` 高度为 40px，`small` 为 24px，默认是 32px | `'large' \\| 'small'`                                       | -                                                                                                           | -        |\n| `[nzStatus]`             | 设置校验状态                                                  | `'error' \\| 'warning'`                                     | -                                                                                                           |\n| `[nzPlacement]`          | 选择框弹出的位置                                              | `'bottomLeft' \\| 'bottomRight' \\| 'topLeft' \\| 'topRight'` | `'bottomLeft'`                                                                                              |          |\n| `[nzSuffixIcon]`         | 自定义的后缀图标                                              | `string \\| TemplateRef`                                    | -                                                                                                           | ✅       |\n| `[nzVariant]`            | 形态变体                                                      | `'outlined' \\| 'borderless' \\| 'filled' \\| 'underlined'`   | `'outlined'`                                                                                                | ✅       | 20.0.0 |\n| `[nzInline]`             | 内联模式                                                      | `boolean`                                                  | `false`                                                                                                     | -        |\n| `(nzOnOpenChange)`       | 弹出日历和关闭日历的回调                                      | `EventEmitter<boolean>`                                    | -                                                                                                           | -        |\n| `(nzOnPanelChange)`      | 改变模式或日期的回调                                          | `EventEmitter<NzPanelChangeType>`                          | -                                                                                                           | -        |\n\n### 共同的方法\n\n| 名称      | 描述         |\n| --------- | ------------ |\n| `open()`  | 打开日历弹层 |\n| `close()` | 关闭日历弹层 |\n\n### nz-date-picker\n\n| 参数          | 说明 | 类型   | 默认值 |\n| ------------- | ---- | ------ | ------ |\n| `[(ngModel)]` | 日期 | `Date` | -      |\n\n### nz-date-picker[nzMode=\"date\"]\n\n| 参数                 | 说明                                                           | 类型                                                                           | 默认值                                               |\n| -------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------ | ---------------------------------------------------- |\n| `[nzDateRender]`     | 自定义日期单元格的内容（month-picker/year-picker 不支持）      | `TemplateRef<Date> \\| string \\| ((d: Date) => TemplateRef<Date> \\| string)`    | -                                                    |\n| `[nzDisabledTime]`   | 不可选择的时间                                                 | `(current: Date) => { nzDisabledHours, nzDisabledMinutes, nzDisabledSeconds }` | -                                                    |\n| `[nzShowTime]`       | 增加时间选择功能                                               | `object \\| boolean`                                                            | [TimePicker Options](/components/time-picker/zh#api) |\n| `[nzShowToday]`      | 是否展示“今天”按钮                                             | `boolean`                                                                      | `true`                                               |\n| `[nzShowNow]`        | 当设定了`nzShowTime`的时候，面板是否显示“此刻”按钮             | `boolean`                                                                      | `true`                                               |\n| `[nzShowWeekNumber]` | 是否在每一行显示周数（仅日期选择器支持。周选择器始终显示周数） | `boolean`                                                                      | `false`                                              |\n| `(nzOnOk)`           | 点击确定按钮的回调                                             | `EventEmitter<Date>`                                                           | -                                                    |\n\n### nz-range-picker\n\n| 参数                   | 说明                   | 类型                                                               | 默认值 |\n| ---------------------- | ---------------------- | ------------------------------------------------------------------ | ------ |\n| `[(ngModel)]`          | 日期                   | `Date[]`                                                           | -      |\n| `[nzRanges]`           | 预设时间范围快捷选择   | `{ [ key: string ]: Date[] } \\| { [ key: string ]: () => Date[] }` | -      |\n| `[nzSeparator]`        | 分隔符                 | `string \\| TemplateRef`                                            | `'~'`  |\n| `(nzOnCalendarChange)` | 待选日期发生变化的回调 | `EventEmitter<Date[]>`                                             | -      |\n\n### nz-range-picker[nzMode=\"date\"]\n\n| 参数                 | 说明                                                           | 类型                                                                                                      | 默认值                                               |\n| -------------------- | -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |\n| `[nzShowTime]`       | 增加时间选择功能                                               | `object \\| boolean`                                                                                       | [TimePicker Options](/components/time-picker/zh#api) |\n| `[nzDisabledTime]`   | 不可选择的时间                                                 | `(current: Date, partial: 'start' \\| 'end') => { nzDisabledHours, nzDisabledMinutes, nzDisabledSeconds }` | -                                                    |\n| `[nzShowWeekNumber]` | 是否在每一行显示周数（仅日期选择器支持。周选择器始终显示周数） | `boolean`                                                                                                 | `false`                                              |\n| `(nzOnOk)`           | 点击确定按钮的回调                                             | `EventEmitter<Date[]>`                                                                                    | -                                                    |\n\n> `nzShowTime` 中当前支持的 `nz-time-picker`\n> 参数有：`nzFormat`, `nzHourStep`, `nzMinuteStep`, `nzSecondStep`, `nzDisabledHours`, `nzDisabledMinutes`, `nzDisabledSeconds`, `nzHideDisabledOptions`, `nzDefaultOpenValue`, `nzAddOn`\n\n## FAQ\n\n### 为何在设置 `nzFormat=\"dd/MM/yyyy\"` 后手动输入不生效\n\n需要引入 `date-fns` 。日期格式化目前同时支持两种方式：`DatePipe`（默认，[语法参考](https://angular.cn/api/common/DatePipe)）\n和 `date-fns`（见[如何使用 `date-fns` 进行日期格式化](/docs/i18n/zh#如何使用Date-fns进行日期格式化)）。当你引入 `date-fns`\n后，NG-ZORRO 会使用它提供的 API 来进行反序列化。\n\n### Q：滚动时浮层元素没有跟随滚动位置\n\n默认情况下，浮层元素使用 `body` 作为滚动容器，如果使用了其他滚动容器，在自定义滚动容器元素上添加 [CdkScrollable](https://material.angular.dev/cdk/scrolling/api#CdkScrollable) 指令。\n注意：您需要从 `@angular/cdk/scrolling` 导入 `CdkScrollable` 指令或 `ScrollingModule` 模块。\n"
  },
  {
    "path": "components/date-picker/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/date-picker/inner-popup.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  Component,\n  EventEmitter,\n  Input,\n  OnChanges,\n  Output,\n  SimpleChanges,\n  TemplateRef,\n  ViewEncapsulation\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { CandyDate } from 'ng-zorro-antd/core/time';\nimport { FunctionProp } from 'ng-zorro-antd/core/types';\nimport { NzCalendarI18nInterface } from 'ng-zorro-antd/i18n';\nimport { NzTimePickerModule } from 'ng-zorro-antd/time-picker';\n\nimport { LibPackerModule } from './lib';\nimport { DisabledDateFn, NzDateMode, NzPanelChangeType, RangePartType, SupportTimeOptions } from './standard-types';\nimport { PREFIX_CLASS } from './util';\n\n@Component({\n  // eslint-disable-next-line @angular-eslint/component-selector\n  selector: 'inner-popup',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    <div (mouseleave)=\"onLeave()\" [class.ant-picker-datetime-panel]=\"showTimePicker\">\n      <div class=\"{{ prefixCls }}-{{ panelMode }}-panel\">\n        @switch (panelMode) {\n          @case ('decade') {\n            <decade-header\n              [(value)]=\"activeDate\"\n              [locale]=\"locale\"\n              [showSuperPreBtn]=\"enablePrevNext('prev', 'decade')\"\n              [showSuperNextBtn]=\"enablePrevNext('next', 'decade')\"\n              [showNextBtn]=\"false\"\n              [showPreBtn]=\"false\"\n              (panelChange)=\"panelChange.emit($event)\"\n              (valueChange)=\"headerChange.emit($event)\"\n            />\n            <div class=\"{{ prefixCls }}-body\">\n              <decade-table\n                [activeDate]=\"activeDate\"\n                [value]=\"value\"\n                [locale]=\"locale\"\n                (valueChange)=\"onChooseDecade($event)\"\n                [disabledDate]=\"disabledDate\"\n              />\n            </div>\n          }\n          @case ('year') {\n            <year-header\n              [(value)]=\"activeDate\"\n              [locale]=\"locale\"\n              [showSuperPreBtn]=\"enablePrevNext('prev', 'year')\"\n              [showSuperNextBtn]=\"enablePrevNext('next', 'year')\"\n              [showNextBtn]=\"false\"\n              [showPreBtn]=\"false\"\n              (panelChange)=\"panelChange.emit($event)\"\n              (valueChange)=\"headerChange.emit($event)\"\n            />\n            <div class=\"{{ prefixCls }}-body\">\n              <year-table\n                [activeDate]=\"activeDate\"\n                [value]=\"value\"\n                [locale]=\"locale\"\n                [disabledDate]=\"disabledDate\"\n                [selectedValue]=\"selectedValue\"\n                [hoverValue]=\"hoverValue\"\n                (valueChange)=\"onChooseYear($event)\"\n                (cellHover)=\"cellHover.emit($event)\"\n              />\n            </div>\n          }\n          @case ('month') {\n            <month-header\n              [(value)]=\"activeDate\"\n              [locale]=\"locale\"\n              [showSuperPreBtn]=\"enablePrevNext('prev', 'month')\"\n              [showSuperNextBtn]=\"enablePrevNext('next', 'month')\"\n              [showNextBtn]=\"false\"\n              [showPreBtn]=\"false\"\n              (panelChange)=\"panelChange.emit($event)\"\n              (valueChange)=\"headerChange.emit($event)\"\n            />\n            <div class=\"{{ prefixCls }}-body\">\n              <month-table\n                [value]=\"value\"\n                [activeDate]=\"activeDate\"\n                [locale]=\"locale\"\n                [disabledDate]=\"disabledDate\"\n                [selectedValue]=\"selectedValue\"\n                [hoverValue]=\"hoverValue\"\n                (valueChange)=\"onChooseMonth($event)\"\n                (cellHover)=\"cellHover.emit($event)\"\n              />\n            </div>\n          }\n          @case ('quarter') {\n            <quarter-header\n              [(value)]=\"activeDate\"\n              [locale]=\"locale\"\n              [showSuperPreBtn]=\"enablePrevNext('prev', 'month')\"\n              [showSuperNextBtn]=\"enablePrevNext('next', 'month')\"\n              [showNextBtn]=\"false\"\n              [showPreBtn]=\"false\"\n              (panelChange)=\"panelChange.emit($event)\"\n              (valueChange)=\"headerChange.emit($event)\"\n            />\n            <div class=\"{{ prefixCls }}-body\">\n              <quarter-table\n                [value]=\"value\"\n                [activeDate]=\"activeDate\"\n                [locale]=\"locale\"\n                [disabledDate]=\"disabledDate\"\n                [selectedValue]=\"selectedValue\"\n                [hoverValue]=\"hoverValue\"\n                (valueChange)=\"onChooseQuarter($event)\"\n                (cellHover)=\"cellHover.emit($event)\"\n                [cellRender]=\"dateRender\"\n              />\n            </div>\n          }\n          @default {\n            <date-header\n              [(value)]=\"activeDate\"\n              [locale]=\"locale\"\n              [showSuperPreBtn]=\"panelMode === 'week' ? enablePrevNext('prev', 'week') : enablePrevNext('prev', 'date')\"\n              [showSuperNextBtn]=\"\n                panelMode === 'week' ? enablePrevNext('next', 'week') : enablePrevNext('next', 'date')\n              \"\n              [showPreBtn]=\"panelMode === 'week' ? enablePrevNext('prev', 'week') : enablePrevNext('prev', 'date')\"\n              [showNextBtn]=\"panelMode === 'week' ? enablePrevNext('next', 'week') : enablePrevNext('next', 'date')\"\n              (panelChange)=\"panelChange.emit($event)\"\n              (valueChange)=\"headerChange.emit($event)\"\n            />\n            <div class=\"{{ prefixCls }}-body\">\n              <date-table\n                [locale]=\"locale\"\n                [showWeek]=\"showWeek\"\n                [value]=\"value\"\n                [activeDate]=\"activeDate\"\n                [disabledDate]=\"disabledDate\"\n                [cellRender]=\"dateRender\"\n                [selectedValue]=\"selectedValue\"\n                [hoverValue]=\"hoverValue\"\n                [canSelectWeek]=\"panelMode === 'week'\"\n                [format]=\"format\"\n                (valueChange)=\"onSelectDate($event)\"\n                (cellHover)=\"cellHover.emit($event)\"\n              />\n            </div>\n          }\n        }\n      </div>\n      @if (showTimePicker && timeOptions) {\n        <nz-time-picker-panel\n          [nzInDatePicker]=\"true\"\n          [ngModel]=\"value?.nativeDate\"\n          (ngModelChange)=\"onSelectTime($event)\"\n          [format]=\"$any(timeOptions.nzFormat)\"\n          [nzHourStep]=\"$any(timeOptions.nzHourStep)\"\n          [nzMinuteStep]=\"$any(timeOptions.nzMinuteStep)\"\n          [nzSecondStep]=\"$any(timeOptions.nzSecondStep)\"\n          [nzDisabledHours]=\"$any(timeOptions.nzDisabledHours)\"\n          [nzDisabledMinutes]=\"$any(timeOptions.nzDisabledMinutes)\"\n          [nzDisabledSeconds]=\"$any(timeOptions.nzDisabledSeconds)\"\n          [nzHideDisabledOptions]=\"!!timeOptions.nzHideDisabledOptions\"\n          [nzDefaultOpenValue]=\"$any(timeOptions.nzDefaultOpenValue)\"\n          [nzUse12Hours]=\"!!timeOptions.nzUse12Hours\"\n          [nzAddOn]=\"$any(timeOptions.nzAddOn)\"\n        />\n      }\n    </div>\n  `,\n  imports: [LibPackerModule, NzTimePickerModule, FormsModule]\n})\nexport class InnerPopupComponent implements OnChanges {\n  @Input() activeDate!: CandyDate;\n  @Input() endPanelMode!: NzDateMode;\n  @Input() panelMode!: NzDateMode;\n  @Input({ transform: booleanAttribute }) showWeek!: boolean;\n  @Input() locale!: NzCalendarI18nInterface;\n  @Input({ transform: booleanAttribute }) showTimePicker!: boolean;\n  @Input() timeOptions!: SupportTimeOptions | null;\n  @Input() disabledDate?: DisabledDateFn;\n  @Input() dateRender?: string | TemplateRef<Date> | FunctionProp<TemplateRef<Date> | string>;\n  @Input() selectedValue!: CandyDate[]; // Range ONLY\n  @Input() hoverValue!: CandyDate[]; // Range ONLY\n  @Input() value!: CandyDate;\n  @Input() partType!: RangePartType;\n  @Input() format?: string;\n\n  @Output() readonly panelChange = new EventEmitter<NzPanelChangeType>();\n  // TODO: name is not proper\n  @Output() readonly headerChange = new EventEmitter<CandyDate>(); // Emitted when user changed the header's value\n  @Output() readonly selectDate = new EventEmitter<CandyDate>(); // Emitted when the date is selected by click the date panel\n  @Output() readonly selectTime = new EventEmitter<CandyDate>();\n  @Output() readonly cellHover = new EventEmitter<CandyDate | null>(); // Emitted when hover on a day by mouse enter\n\n  prefixCls: string = PREFIX_CLASS;\n\n  /**\n   * Hide \"next\" arrow in left panel,\n   * hide \"prev\" arrow in right panel\n   *\n   * @param direction\n   * @param panelMode\n   */\n  enablePrevNext(direction: 'prev' | 'next', panelMode: NzDateMode): boolean {\n    return !(\n      !this.showTimePicker &&\n      panelMode === this.endPanelMode &&\n      ((this.partType === 'left' && direction === 'next') || (this.partType === 'right' && direction === 'prev'))\n    );\n  }\n\n  onLeave(): void {\n    this.cellHover.emit(null);\n  }\n\n  onSelectTime(date: Date): void {\n    this.selectTime.emit(new CandyDate(date));\n  }\n\n  // The value real changed to outside\n  onSelectDate(date: CandyDate | Date): void {\n    const value = date instanceof CandyDate ? date : new CandyDate(date);\n    const timeValue = this.timeOptions && this.timeOptions.nzDefaultOpenValue;\n\n    // Display timeValue when value is null\n    if (!this.value && timeValue) {\n      value.setHms(timeValue.getHours(), timeValue.getMinutes(), timeValue.getSeconds());\n    }\n\n    this.selectDate.emit(value);\n  }\n\n  onChooseMonth(value: CandyDate): void {\n    this.activeDate = this.activeDate.setMonth(value.getMonth());\n    if (this.endPanelMode === 'month') {\n      this.value = value;\n      this.selectDate.emit(value);\n    } else {\n      this.headerChange.emit(value);\n      this.panelChange.emit({ mode: this.endPanelMode, date: value.nativeDate });\n    }\n  }\n\n  onChooseQuarter(value: CandyDate): void {\n    this.activeDate = this.activeDate.setQuarter(value.getQuarter());\n    this.value = value;\n    this.selectDate.emit(value);\n  }\n\n  onChooseYear(value: CandyDate): void {\n    this.activeDate = this.activeDate.setYear(value.getYear());\n    if (this.endPanelMode === 'year') {\n      this.value = value;\n      this.selectDate.emit(value);\n    } else {\n      this.headerChange.emit(value);\n      this.panelChange.emit({ mode: this.endPanelMode, date: value.nativeDate });\n    }\n  }\n\n  onChooseDecade(value: CandyDate): void {\n    this.activeDate = this.activeDate.setYear(value.getYear());\n    if (this.endPanelMode === 'decade') {\n      this.value = value;\n      this.selectDate.emit(value);\n    } else {\n      this.headerChange.emit(value);\n      this.panelChange.emit({ mode: 'year', date: value.nativeDate });\n    }\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    if (changes.activeDate && !changes.activeDate.currentValue) {\n      this.activeDate = new CandyDate();\n    }\n    // New Antd vesion has merged 'date' ant 'time' to one panel,\n    // So there is not 'time' panel\n    if (changes.panelMode && changes.panelMode.currentValue === 'time') {\n      this.panelMode = 'date';\n    }\n  }\n}\n"
  },
  {
    "path": "components/date-picker/month-picker.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport { registerLocaleData } from '@angular/common';\nimport zh from '@angular/common/locales/zh';\nimport { Component, DebugElement, provideZoneChangeDetection, TemplateRef, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, flush, inject, TestBed, tick } from '@angular/core/testing';\nimport { FormsModule } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport isBefore from 'date-fns/isBefore';\n\nimport { dispatchFakeEvent, dispatchMouseEvent } from 'ng-zorro-antd/core/testing';\nimport { NgStyleInterface } from 'ng-zorro-antd/core/types';\nimport { NzDatePickerSizeType } from 'ng-zorro-antd/date-picker/date-picker.component';\nimport { getPickerAbstract, getPickerInput } from 'ng-zorro-antd/date-picker/testing/util';\nimport { PREFIX_CLASS } from 'ng-zorro-antd/date-picker/util';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\nimport { NzDatePickerModule } from './date-picker.module';\n\nregisterLocaleData(zh);\n\ndescribe('month-picker', () => {\n  let fixture: ComponentFixture<NzTestMonthPickerComponent>;\n  let fixtureInstance: NzTestMonthPickerComponent;\n  let debugElement: DebugElement;\n  let overlayContainerElement: HTMLElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzTestMonthPickerComponent);\n    fixtureInstance = fixture.componentInstance;\n    debugElement = fixture.debugElement;\n  });\n\n  beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n    overlayContainerElement = oc.getContainerElement();\n  }));\n\n  describe('general api testing', () => {\n    beforeEach(() => (fixtureInstance.useSuite = 1));\n\n    it('should open by click and close by click at outside', fakeAsync(() => {\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(getPickerContainer()).not.toBeNull();\n\n      dispatchFakeEvent(getPickerInput(fixture.debugElement), 'focusout');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).toBeNull();\n    }));\n\n    it('should support nzAllowClear and work properly', fakeAsync(() => {\n      const clearBtnSelector = By.css(`.${PREFIX_CLASS}-clear`);\n      const initial = (fixtureInstance.nzValue = new Date());\n      fixtureInstance.nzAllowClear = false;\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(debugElement.query(clearBtnSelector)).toBeFalsy();\n\n      fixtureInstance.nzAllowClear = true;\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(fixtureInstance.nzValue).toBe(initial);\n      expect(debugElement.query(clearBtnSelector)).toBeDefined();\n\n      const nzOnChange = spyOn(fixtureInstance, 'nzOnChange');\n      debugElement.query(clearBtnSelector).nativeElement.click();\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(fixtureInstance.nzValue).toBe(initial);\n      expect(nzOnChange).toHaveBeenCalledWith(null);\n      expect(debugElement.query(clearBtnSelector)).toBeFalsy();\n    }));\n\n    it('should support nzAutoFocus', () => {\n      fixtureInstance.nzAutoFocus = true;\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement) === document.activeElement).toBeTruthy();\n    });\n\n    it('should support nzDisabled', fakeAsync(() => {\n      // Make sure picker clear button shown up\n      fixtureInstance.nzAllowClear = true;\n      fixtureInstance.nzValue = new Date();\n\n      fixtureInstance.nzDisabled = true;\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(debugElement.query(By.css('.ant-picker-disabled'))).not.toBeNull();\n      expect(debugElement.query(By.css('.ant-picker-clear'))).toBeNull();\n\n      fixtureInstance.nzDisabled = false;\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(debugElement.query(By.css('.ant-picker-disabled'))).toBeNull();\n      expect(debugElement.query(By.css('.ant-picker-clear'))).not.toBeNull();\n    }));\n\n    it('should support nzOpen if assigned', fakeAsync(() => {\n      fixtureInstance.useSuite = 2;\n\n      fixture.detectChanges();\n      fixture.whenRenderingDone().then(() => {\n        expect(getPickerContainer()).toBeNull();\n\n        fixtureInstance.nzOpen = true;\n        fixture.detectChanges();\n        tick(500);\n        fixture.detectChanges();\n        expect(getPickerContainer()).not.toBeNull();\n\n        fixtureInstance.nzOpen = false;\n        fixture.detectChanges();\n        tick(500);\n        fixture.detectChanges();\n        expect(getPickerContainer()).toBeNull();\n      });\n    }));\n\n    it('should nz-month-picker work', fakeAsync(() => {\n      fixtureInstance.useSuite = 4;\n      fixture.whenRenderingDone().then(() => {\n        tick(500);\n        fixture.detectChanges();\n        expect(getPickerContainer()).not.toBeNull();\n        const pickerInput = getPickerInput(fixture.debugElement);\n        expect(pickerInput).not.toBeNull();\n      });\n    }));\n\n    it('should support nzDisabledDate', fakeAsync(() => {\n      fixture.detectChanges();\n      const compareDate = new Date('2018-11-15 00:00:00');\n      fixtureInstance.nzValue = new Date('2018-11-11 12:12:12');\n      fixtureInstance.nzDisabledDate = (current: Date) => isBefore(current, compareDate);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n\n      openPickerByClickTrigger();\n      const allDisabledCells = overlayContainerElement.querySelectorAll(\n        '.ant-picker-month-panel tr td.ant-picker-cell-disabled'\n      );\n      const disabledCell = allDisabledCells[allDisabledCells.length - 1];\n      expect(disabledCell.textContent).toContain('10');\n    }));\n\n    it('should support nzLocale', () => {\n      const featureKey = 'TEST_PLACEHOLDER';\n      fixtureInstance.nzLocale = { lang: { monthPlaceholder: featureKey } };\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement).getAttribute('placeholder')).toBe(featureKey);\n    });\n\n    it('should support nzPlaceHolder', () => {\n      const featureKey = (fixtureInstance.nzPlaceHolder = 'TEST_PLACEHOLDER');\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement).getAttribute('placeholder')).toBe(featureKey);\n    });\n\n    it('should support nzPopupStyle', fakeAsync(() => {\n      fixtureInstance.nzPopupStyle = { color: 'red' };\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(queryFromOverlay(`.${PREFIX_CLASS}-dropdown`).style.color).toBe('red');\n    }));\n\n    it('should support nzDropdownClassName', fakeAsync(() => {\n      const keyCls = (fixtureInstance.nzDropdownClassName = 'my-test-class');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(queryFromOverlay(`.${PREFIX_CLASS}-dropdown`).classList.contains(keyCls)).toBeTruthy();\n    }));\n\n    it('should support nzSize', () => {\n      fixtureInstance.nzSize = 'large';\n      fixture.detectChanges();\n      expect(getPickerAbstract(fixture.debugElement).classList.contains('ant-picker-large')).toBeTruthy();\n\n      fixtureInstance.nzSize = 'small';\n      fixture.detectChanges();\n      expect(getPickerAbstract(fixture.debugElement).classList.contains('ant-picker-small')).toBeTruthy();\n    });\n\n    it('should support nzOnOpenChange', fakeAsync(() => {\n      const nzOnOpenChange = spyOn(fixtureInstance, 'nzOnOpenChange');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(nzOnOpenChange).toHaveBeenCalledWith(true);\n\n      dispatchFakeEvent(getPickerInput(fixture.debugElement), 'focusout');\n      fixture.detectChanges();\n      flush();\n      expect(nzOnOpenChange).toHaveBeenCalledWith(false);\n      expect(nzOnOpenChange).toHaveBeenCalledTimes(2);\n    }));\n\n    it('should support nzValue', fakeAsync(() => {\n      fixtureInstance.nzValue = new Date('2018-11-22');\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(getSelectedMonthCell().textContent).toContain('11');\n    }));\n\n    it('should support nzOnChange', fakeAsync(() => {\n      fixtureInstance.nzValue = new Date('2018-11');\n      const nzOnChange = spyOn(fixtureInstance, 'nzOnChange');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      const cell = getFirstMonthCell(); // Use the first cell\n      const cellText = cell.textContent!.trim();\n      dispatchMouseEvent(cell, 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(nzOnChange).toHaveBeenCalled();\n      const result = (nzOnChange.calls.allArgs()[0] as Date[])[0];\n      expect(result.getMonth() + 1).toBe(parseInt(cellText, 10));\n    }));\n  }); // /general api testing\n\n  describe('panel switch and move forward/afterward', () => {\n    beforeEach(() => (fixtureInstance.useSuite = 1));\n\n    it('should support year panel changes', fakeAsync(() => {\n      fixtureInstance.nzValue = new Date('2018-11');\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      // Click year select to show year panel\n      dispatchMouseEvent(queryFromOverlay('.ant-picker-header-month-btn'), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-year-panel')).toBeDefined();\n      expect(queryFromOverlay('.ant-picker-header-year-btn').textContent).toContain('2010');\n      expect(queryFromOverlay('.ant-picker-header-year-btn').textContent).toContain('2019');\n      // Goto previous year\n      dispatchMouseEvent(getSuperPreBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-header-year-btn').textContent).toContain('2000');\n      expect(queryFromOverlay('.ant-picker-header-year-btn').textContent).toContain('2009');\n      // Goto next year * 2\n      dispatchMouseEvent(getSuperNextBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      dispatchMouseEvent(getSuperNextBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-header-year-btn').textContent).toContain('2020');\n      expect(queryFromOverlay('.ant-picker-header-year-btn').textContent).toContain('2029');\n    }));\n\n    it('should support decade panel changes', fakeAsync(() => {\n      fixtureInstance.nzValue = new Date('2018-11');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      // Click to show decade panel\n      dispatchMouseEvent(queryFromOverlay('.ant-picker-header-month-btn'), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      dispatchMouseEvent(queryFromOverlay('.ant-picker-header-year-btn'), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-decade-panel')).toBeDefined();\n      // Goto previous decade\n      dispatchMouseEvent(getSuperPreBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-header-decade-btn').textContent).toContain('1900');\n      expect(queryFromOverlay('.ant-picker-header-decade-btn').textContent).toContain('1999');\n      // Goto next decade * 2\n      dispatchMouseEvent(getSuperNextBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      dispatchMouseEvent(getSuperNextBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-header-decade-btn').textContent).toContain('2100');\n      expect(queryFromOverlay('.ant-picker-header-decade-btn').textContent).toContain('2199');\n    }));\n  }); // /panel switch and move forward/afterward\n\n  describe('specified date picker testing', () => {\n    beforeEach(() => (fixtureInstance.useSuite = 1));\n\n    it('should support nzRenderExtraFooter', fakeAsync(() => {\n      fixtureInstance.nzRenderExtraFooter = () => fixtureInstance.tplExtraFooter;\n      fixture.detectChanges();\n\n      openPickerByClickTrigger();\n      expect(overlayContainerElement.textContent!.indexOf('TEST_EXTRA_FOOTER') > -1).toBeTruthy();\n\n      fixtureInstance.nzRenderExtraFooter = 'TEST_EXTRA_FOOTER_STRING';\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent!.indexOf(fixtureInstance.nzRenderExtraFooter) > -1).toBeTruthy();\n    }));\n\n    it('should support selected month active', fakeAsync(() => {\n      fixtureInstance.nzValue = new Date('2019-7-13 15:10:00');\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n\n      openPickerByClickTrigger();\n      const activeMonthElement = overlayContainerElement.querySelector(\n        '.ant-picker-month-panel tr td.ant-picker-cell-selected .ant-picker-cell-inner'\n      );\n      expect(activeMonthElement!.textContent).toContain('7月');\n    }));\n  }); // /specified date picker testing\n\n  describe('ngModel value accessors', () => {\n    beforeEach(() => (fixtureInstance.useSuite = 3));\n\n    it('should specified date provide by \"modelValue\" be chosen', fakeAsync(() => {\n      fixtureInstance.modelValue = new Date('2018-11');\n      fixture.detectChanges();\n      flush(); // Wait writeValue() tobe done\n      fixture.detectChanges();\n      expect(getSelectedMonthCell().textContent).toContain('11');\n\n      // Click the first cell to change ngModel\n      const cell = getFirstMonthCell();\n      const cellText = cell.textContent!.trim();\n      dispatchMouseEvent(cell, 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(fixtureInstance.modelValue.getMonth() + 1).toBe(parseInt(cellText, 10));\n    }));\n  });\n\n  ////////////\n\n  function getSuperPreBtn(): HTMLElement {\n    return queryFromOverlay(`.${PREFIX_CLASS}-header-super-prev-btn`);\n  }\n\n  function getSuperNextBtn(): HTMLElement {\n    return queryFromOverlay(`.${PREFIX_CLASS}-header-super-next-btn`);\n  }\n\n  function getPickerContainer(): HTMLElement {\n    return queryFromOverlay('.ant-picker-panel-container') as HTMLElement;\n  }\n\n  function getSelectedMonthCell(): HTMLElement {\n    return queryFromOverlay('.ant-picker-month-panel td.ant-picker-cell-selected') as HTMLElement;\n  }\n\n  function getFirstMonthCell(): HTMLElement {\n    return queryFromOverlay(\n      '.ant-picker-month-panel td.ant-picker-cell:nth-child(1) .ant-picker-cell-inner'\n    ) as HTMLElement;\n  }\n\n  function queryFromOverlay(selector: string): HTMLElement {\n    return overlayContainerElement.querySelector(selector) as HTMLElement;\n  }\n\n  function openPickerByClickTrigger(): void {\n    dispatchMouseEvent(getPickerInput(fixture.debugElement), 'click');\n    fixture.detectChanges();\n    tick(500);\n    fixture.detectChanges();\n  }\n});\n\n@Component({\n  imports: [FormsModule, NzDatePickerModule, NzInputModule],\n  template: `\n    <ng-template #tplExtraFooter>TEST_EXTRA_FOOTER</ng-template>\n    @switch (useSuite) {\n      @case (1) {\n        <nz-date-picker\n          nzMode=\"month\"\n          [nzAllowClear]=\"nzAllowClear\"\n          [nzAutoFocus]=\"nzAutoFocus\"\n          [nzDisabled]=\"nzDisabled\"\n          [nzDisabledDate]=\"nzDisabledDate\"\n          [nzLocale]=\"nzLocale\"\n          [nzPlaceHolder]=\"nzPlaceHolder\"\n          [nzPopupStyle]=\"nzPopupStyle\"\n          [nzDropdownClassName]=\"nzDropdownClassName\"\n          [nzSize]=\"nzSize\"\n          (nzOnOpenChange)=\"nzOnOpenChange($event)\"\n          [ngModel]=\"nzValue\"\n          (ngModelChange)=\"nzOnChange($event)\"\n          [nzRenderExtraFooter]=\"nzRenderExtraFooter\"\n        />\n      }\n      @case (2) {\n        <nz-date-picker nzMode=\"month\" [nzOpen]=\"nzOpen\" />\n      }\n      @case (3) {\n        <nz-date-picker nzMode=\"month\" nzOpen [(ngModel)]=\"modelValue\" />\n      }\n      @case (4) {\n        <nz-month-picker nzOpen />\n      }\n    }\n  `\n})\nclass NzTestMonthPickerComponent {\n  useSuite!: 1 | 2 | 3 | 4;\n  @ViewChild('tplExtraFooter', { static: true }) tplExtraFooter!: TemplateRef<void>;\n  // --- Suite 1\n  nzAllowClear: boolean = false;\n  nzAutoFocus: boolean = false;\n  nzDisabled: boolean = false;\n  nzDisabledDate!: (d: Date) => boolean;\n  nzLocale: any; // eslint-disable-line @typescript-eslint/no-explicit-any\n  nzPlaceHolder!: string;\n  nzPopupStyle!: NgStyleInterface;\n  nzDropdownClassName!: string;\n  nzSize!: NzDatePickerSizeType;\n\n  nzOnOpenChange(_: boolean): void {}\n\n  nzOnChange(_: Date | null): void {}\n\n  nzValue: Date | null = null;\n\n  nzRenderExtraFooter!: string | (() => TemplateRef<void> | string);\n\n  // --- Suite 2\n  nzOpen: boolean = false;\n\n  // --- Suite 3\n  modelValue!: Date;\n}\n"
  },
  {
    "path": "components/date-picker/month-picker.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, inject } from '@angular/core';\n\nimport { NzDatePickerComponent } from './date-picker.component';\n\n@Directive({\n  selector: 'nz-month-picker',\n  exportAs: 'nzMonthPicker'\n})\nexport class NzMonthPickerComponent {\n  datePicker = inject(NzDatePickerComponent, { host: true });\n\n  constructor() {\n    this.datePicker.nzMode = 'month';\n  }\n}\n"
  },
  {
    "path": "components/date-picker/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/date-picker/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './standard-types';\nexport * from './util';\n\nexport { CalendarFooterComponent as ɵCalendarFooterComponent } from './calendar-footer.component';\nexport { NzDatePickerComponent } from './date-picker.component';\nexport type { NzDatePickerSizeType } from './date-picker.component';\nexport { NzDatePickerModule } from './date-picker.module';\nexport { DatePickerService as ɵDatePickerService } from './date-picker.service';\nexport { DateRangePopupComponent as ɵDateRangePopupComponent } from './date-range-popup.component';\nexport { InnerPopupComponent as ɵInnerPopupComponent } from './inner-popup.component';\nexport { NzMonthPickerComponent } from './month-picker.component';\nexport { NzQuarterPickerComponent } from './quarter-picker.component';\nexport { NzRangePickerComponent } from './range-picker.component';\nexport { NzWeekPickerComponent } from './week-picker.component';\nexport { NzYearPickerComponent } from './year-picker.component';\n\nexport * from './lib/public-api';\n"
  },
  {
    "path": "components/date-picker/quarter-picker.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport { Component, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, fakeAsync, flush, inject, TestBed, tick } from '@angular/core/testing';\nimport { FormsModule } from '@angular/forms';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport isBefore from 'date-fns/isBefore';\n\nimport { dispatchMouseEvent } from 'ng-zorro-antd/core/testing';\nimport { CandyDate } from 'ng-zorro-antd/core/time';\nimport { getPickerInput } from 'ng-zorro-antd/date-picker/testing/util';\nimport { PREFIX_CLASS } from 'ng-zorro-antd/date-picker/util';\n\nimport { NzDatePickerModule } from './date-picker.module';\n\ndescribe('quater-picker', () => {\n  let fixture: ComponentFixture<NzTestQuarterPickerComponent>;\n  let fixtureInstance: NzTestQuarterPickerComponent;\n  let overlayContainer: OverlayContainer;\n  let overlayContainerElement: HTMLElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n    overlayContainer = oc;\n    overlayContainerElement = oc.getContainerElement();\n  }));\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzTestQuarterPickerComponent);\n    fixtureInstance = fixture.componentInstance;\n    // set initial mode\n    fixtureInstance.useSuite = 1;\n    fixture.detectChanges();\n  });\n\n  afterEach(() => {\n    overlayContainer.ngOnDestroy();\n  });\n\n  it('should show quarter panel', fakeAsync(() => {\n    fixtureInstance.nzFormat = undefined; // cover branch\n    fixture.detectChanges();\n    openPickerByClickTrigger();\n    expect(queryFromOverlay('.ant-picker-quarter-panel')).toBeDefined();\n  }));\n\n  it('should change input value when click quarter', fakeAsync(() => {\n    fixtureInstance.nzValue = new Date('2024-04-04');\n    fixture.detectChanges();\n    flush();\n    fixture.detectChanges();\n    openPickerByClickTrigger();\n    dispatchMouseEvent(queryFromOverlay('.ant-picker-cell'), 'click');\n    fixture.detectChanges();\n    tick(500);\n    fixture.detectChanges();\n    expect(getPickerInput(fixture.debugElement).value).toBe('2024-Q1');\n  }));\n\n  it('should specified date provide by \"value\" be chosen', fakeAsync(() => {\n    fixtureInstance.useSuite = 3;\n    fixtureInstance.nzValue = new Date('2024-04-30');\n    fixture.detectChanges();\n    flush(); // Wait writeValue() tobe done\n    fixture.detectChanges();\n    tick(500);\n    fixture.detectChanges();\n    expect(queryFromOverlay('.ant-picker-quarter-panel td.ant-picker-cell-selected').textContent).toContain('Q2');\n\n    // Click the first cell to change ngModel\n    const cell = queryFromOverlay('.ant-picker-quarter-panel td.ant-picker-cell:nth-child(1) .ant-picker-cell-inner');\n    const cellText = cell.textContent!.trim();\n    dispatchMouseEvent(cell, 'click');\n    fixture.detectChanges();\n    tick(500);\n    fixture.detectChanges();\n    expect(`Q${new CandyDate(fixtureInstance.nzValue).setMonth(0).getQuarter().toString()}`).toBe(cellText);\n  }));\n\n  it('should nz-quarter-picker work', fakeAsync(() => {\n    fixtureInstance.useSuite = 2;\n    fixture.whenRenderingDone().then(() => {\n      tick(500);\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      dispatchMouseEvent(queryFromOverlay('.ant-picker-cell'), 'click');\n      tick(500);\n      expect(getPickerContainer()).not.toBeNull();\n      const pickerInput = getPickerInput(fixture.debugElement);\n      expect(pickerInput).not.toBeNull(); //\n    });\n  }));\n\n  it('should nz-range-picker \"nzValue\" work', fakeAsync(() => {\n    fixtureInstance.useSuite = 4;\n    fixtureInstance.nzValue = [new Date('2024-04-30'), new Date('2025-12-30')];\n    fixture.whenRenderingDone().then(() => {\n      tick(500);\n      fixture.detectChanges();\n      const panels = overlayContainerElement.querySelectorAll('.ant-picker-quarter-panel');\n      expect(panels).not.toBeNull();\n      expect(panels.length).toBe(2);\n\n      tick(500);\n      fixture.detectChanges();\n      const firstCell = panels[0].querySelector('td.ant-picker-cell-selected')!;\n      expect(firstCell).not.toBeNull();\n      expect(firstCell.textContent!.trim()).toBe('Q2');\n\n      const secondCell = panels[1].querySelector('td.ant-picker-cell-selected')!;\n      expect(secondCell).not.toBeNull();\n      expect(secondCell.textContent!.trim()).toBe('Q4');\n    });\n  }));\n\n  it('should support year panel changes', fakeAsync(() => {\n    fixtureInstance.useSuite = 3;\n\n    fixtureInstance.nzValue = new Date('2024-04-30');\n    fixture.detectChanges();\n    tick();\n    fixture.detectChanges();\n    openPickerByClickTrigger();\n    // Click year select to show year panel\n    dispatchMouseEvent(queryFromOverlay('.ant-picker-header-quarter-btn'), 'click');\n    fixture.detectChanges();\n    tick(500);\n    fixture.detectChanges();\n    expect(queryFromOverlay('.ant-picker-year-panel')).toBeDefined();\n    expect(queryFromOverlay('.ant-picker-header-year-btn').textContent).toContain('2020');\n    expect(queryFromOverlay('.ant-picker-header-year-btn').textContent).toContain('2029');\n    // Goto previous year\n    dispatchMouseEvent(getSuperPreBtn(), 'click');\n    fixture.detectChanges();\n    tick(500);\n    fixture.detectChanges();\n    expect(queryFromOverlay('.ant-picker-header-year-btn').textContent).toContain('2010');\n    expect(queryFromOverlay('.ant-picker-header-year-btn').textContent).toContain('2019');\n    // Goto next year * 2\n    dispatchMouseEvent(getSuperNextBtn(), 'click');\n    fixture.detectChanges();\n    tick(500);\n    fixture.detectChanges();\n    dispatchMouseEvent(getSuperNextBtn(), 'click');\n    fixture.detectChanges();\n    tick(500);\n    fixture.detectChanges();\n    expect(queryFromOverlay('.ant-picker-header-year-btn').textContent).toContain('2030');\n    expect(queryFromOverlay('.ant-picker-header-year-btn').textContent).toContain('2039');\n  }));\n\n  it('should support nzDisabledDate', fakeAsync(() => {\n    fixtureInstance.useSuite = 1;\n    fixtureInstance.nzValue = null;\n    fixture.detectChanges();\n    const compareDate = new Date('2024-8-01');\n    fixtureInstance.nzValue = new Date('2024-04-01');\n    fixtureInstance.nzDisabledDate = (current: Date) => isBefore(current, compareDate);\n    fixture.detectChanges();\n    flush();\n    fixture.detectChanges();\n\n    openPickerByClickTrigger();\n    const allDisabledCells = overlayContainerElement.querySelectorAll(\n      '.ant-picker-quarter-panel tr td.ant-picker-cell-disabled'\n    );\n    const disabledCell = allDisabledCells[allDisabledCells.length - 1];\n    expect(disabledCell.textContent).toContain('Q2');\n  }));\n\n  it('should support hover date cell style', fakeAsync(() => {\n    fixtureInstance.useSuite = 4;\n    fixture.detectChanges();\n    openPickerByClickTrigger();\n    tick(500);\n    fixture.detectChanges();\n\n    const left = getFirstCell('left'); // Use the first cell\n    dispatchMouseEvent(left, 'click');\n    const rightInNextMonth = queryFromRightPanel('table tr td.ant-picker-cell');\n    dispatchMouseEvent(rightInNextMonth, 'mouseenter');\n    fixture.detectChanges();\n    expect(rightInNextMonth.classList.contains('ant-picker-cell-range-hover-end')).toBeTruthy();\n  }));\n\n  ////////////\n\n  function queryFromRightPanel(selector: string): HTMLElement {\n    return overlayContainerElement\n      .querySelector('.ant-picker-panel:last-child')!\n      .querySelector(selector) as HTMLElement;\n  }\n\n  function getFirstCell(partial: 'left' | 'right'): HTMLElement {\n    const flg = partial === 'left' ? 'first' : 'last';\n    return queryFromOverlay(\n      `.ant-picker-quarter-panel:${flg}-child td:first-child .ant-picker-cell-inner`\n    ) as HTMLElement;\n  }\n\n  function queryFromOverlay(selector: string): HTMLElement {\n    return overlayContainerElement.querySelector(selector) as HTMLElement;\n  }\n\n  function openPickerByClickTrigger(): void {\n    dispatchMouseEvent(getPickerInput(fixture.debugElement), 'click');\n    fixture.detectChanges();\n    tick(500);\n    fixture.detectChanges();\n  }\n\n  function getPickerContainer(): HTMLElement {\n    return queryFromOverlay('.ant-picker-quarter-panel') as HTMLElement;\n  }\n\n  function getSuperPreBtn(): HTMLElement {\n    return queryFromOverlay(`.${PREFIX_CLASS}-header-super-prev-btn`);\n  }\n\n  function getSuperNextBtn(): HTMLElement {\n    return queryFromOverlay(`.${PREFIX_CLASS}-header-super-next-btn`);\n  }\n});\n\n@Component({\n  imports: [NzDatePickerModule, FormsModule],\n  template: `\n    @switch (useSuite) {\n      @case (1) {\n        <nz-date-picker\n          nzMode=\"quarter\"\n          [nzFormat]=\"nzFormat!\"\n          [ngModel]=\"nzValue\"\n          [nzDisabled]=\"nzDisabled\"\n          [nzDisabledDate]=\"nzDisabledDate\"\n        />\n      }\n      @case (2) {\n        <nz-quarter-picker [ngModel]=\"nzValue\" />\n      }\n      @case (3) {\n        <nz-quarter-picker [ngModel]=\"nzValue\" nzOpen />\n      }\n      @case (4) {\n        <nz-range-picker nzMode=\"quarter\" [ngModel]=\"nzValue\" nzOpen />\n      }\n    }\n  `\n})\nexport class NzTestQuarterPickerComponent {\n  useSuite!: 1 | 2 | 3 | 4;\n  nzFormat?: string;\n  nzValue: Date | Date[] | null = null;\n  nzDisabled: boolean = false;\n  nzDisabledDate!: (d: Date) => boolean;\n}\n"
  },
  {
    "path": "components/date-picker/quarter-picker.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, inject } from '@angular/core';\n\nimport { NzDatePickerComponent } from './date-picker.component';\n\n@Directive({\n  selector: 'nz-quarter-picker',\n  exportAs: 'nzQuarterPicker'\n})\nexport class NzQuarterPickerComponent {\n  datePicker = inject(NzDatePickerComponent, { host: true });\n\n  constructor() {\n    this.datePicker.nzMode = 'quarter';\n  }\n}\n"
  },
  {
    "path": "components/date-picker/range-picker.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ESCAPE } from '@angular/cdk/keycodes';\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport { registerLocaleData } from '@angular/common';\nimport zh from '@angular/common/locales/zh';\nimport { Component, DebugElement, provideZoneChangeDetection, TemplateRef, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, flush, inject, TestBed, tick } from '@angular/core/testing';\nimport { FormsModule } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport differenceInDays from 'date-fns/differenceInDays';\nimport isSameDay from 'date-fns/isSameDay';\n\nimport {\n  dispatchFakeEvent,\n  dispatchKeyboardEvent,\n  dispatchMouseEvent,\n  typeInElement\n} from 'ng-zorro-antd/core/testing';\nimport { CandyDate } from 'ng-zorro-antd/core/time';\nimport { NgStyleInterface, NzStatus } from 'ng-zorro-antd/core/types';\nimport { NzDatePickerSizeType } from 'ng-zorro-antd/date-picker/date-picker.component';\nimport { NzRangePickerComponent } from 'ng-zorro-antd/date-picker/range-picker.component';\nimport { CompatibleDate, NzPanelChangeType, RangePartType } from 'ng-zorro-antd/date-picker/standard-types';\nimport {\n  ENTER_EVENT,\n  getPickerAbstract,\n  getPickerInput,\n  getRangePickerRightInput\n} from 'ng-zorro-antd/date-picker/testing/util';\nimport { PREFIX_CLASS } from 'ng-zorro-antd/date-picker/util';\n\nimport { NzDatePickerModule } from './date-picker.module';\n\nregisterLocaleData(zh);\n\ndescribe('range-picker', () => {\n  let fixture: ComponentFixture<NzTestRangePickerComponent>;\n  let fixtureInstance: NzTestRangePickerComponent;\n  let debugElement: DebugElement;\n  let overlayContainer: OverlayContainer;\n  let overlayContainerElement: HTMLElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzTestRangePickerComponent);\n    fixtureInstance = fixture.componentInstance;\n    debugElement = fixture.debugElement;\n  });\n\n  beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n    overlayContainer = oc;\n    overlayContainerElement = oc.getContainerElement();\n  }));\n\n  afterEach(() => {\n    overlayContainer.ngOnDestroy();\n  });\n\n  describe('general api testing', () => {\n    beforeEach(() => (fixtureInstance.useSuite = 1));\n\n    it('should open by click and close by click at outside', fakeAsync(() => {\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(getPickerContainer()).not.toBeNull();\n\n      triggerInputBlur();\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).toBeNull();\n    }));\n\n    it('should nz-range-picker work', fakeAsync(() => {\n      fixtureInstance.useSuite = 5;\n      fixture.whenRenderingDone().then(() => {\n        tick(500);\n        fixture.detectChanges();\n        expect(getPickerContainer()).not.toBeNull();\n        const pickerInput = getPickerInput(fixture.debugElement);\n        expect(pickerInput).not.toBeNull();\n      });\n    }));\n\n    it('should open by click and close by tab', fakeAsync(() => {\n      fixtureInstance.useSuite = 4;\n\n      fixture.detectChanges();\n      expect(getPickerContainer()).toBeNull();\n      openPickerByClickTrigger();\n      expect(getPickerContainer()).not.toBeNull();\n\n      getRangePickerRightInput(fixture.debugElement).focus();\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).not.toBeNull();\n\n      triggerInputBlur();\n      getRegularPickerInput(fixture.debugElement).focus();\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).toBeNull();\n    }));\n\n    it('should focus on the trigger after a click outside', fakeAsync(() => {\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      triggerInputBlur();\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement).matches(':focus-within')).toBeTruthy();\n    }));\n\n    it('should open on enter while focusing', fakeAsync(() => {\n      fixture.detectChanges();\n      getPickerInput(fixture.debugElement).dispatchEvent(ENTER_EVENT);\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).toBeNull();\n\n      getPickerInput(fixture.debugElement).focus();\n      getPickerInput(fixture.debugElement).dispatchEvent(ENTER_EVENT);\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).not.toBeNull();\n    }));\n\n    it('should execute default on the mousedown event when mouse down in date picker input', fakeAsync(() => {\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      const event = new MouseEvent('mousedown');\n      spyOn(event, 'preventDefault').and.callThrough();\n      fixture.nativeElement.querySelector(`.${PREFIX_CLASS}-separator`).dispatchEvent(event);\n\n      expect(event.preventDefault).not.toHaveBeenCalled();\n    }));\n\n    it('should support nzAllowClear and work properly', fakeAsync(() => {\n      const clearBtnSelector = By.css(`.${PREFIX_CLASS}-clear`);\n      const initial = (fixtureInstance.modelValue = [new Date(), new Date()]);\n      fixtureInstance.nzAllowClear = false;\n      fixture.detectChanges();\n      expect(debugElement.query(clearBtnSelector)).toBeNull();\n\n      fixtureInstance.nzAllowClear = true;\n      tick();\n      fixture.detectChanges();\n      expect(fixtureInstance.modelValue).toBe(initial);\n      expect(debugElement.query(clearBtnSelector)).toBeDefined();\n\n      const nzOnChange = spyOn(fixtureInstance, 'modelValueChange');\n      debugElement.query(clearBtnSelector).nativeElement.click();\n      fixture.detectChanges();\n      expect(fixtureInstance.modelValue.length).toBe(0);\n      expect(nzOnChange).toHaveBeenCalledWith([]);\n      expect(debugElement.query(clearBtnSelector)).toBeFalsy();\n    }));\n\n    it('should support clear input value when set default value', fakeAsync(() => {\n      const clearBtnSelector = By.css(`.${PREFIX_CLASS}-clear`);\n      fixtureInstance.modelValue = [new Date(), new Date()];\n      fixtureInstance.nzAllowClear = true;\n      tick();\n      fixture.autoDetectChanges();\n\n      const leftInput = getPickerInput(fixture.debugElement);\n      tick(500);\n      debugElement.query(clearBtnSelector).nativeElement.click();\n      expect(leftInput.attributes.getNamedItem('ng-reflect-model')?.value).toBeUndefined();\n    }));\n\n    it('should support nzAutoFocus', fakeAsync(() => {\n      fixtureInstance.nzAutoFocus = true;\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement) === document.activeElement).toBeTruthy();\n    }));\n\n    it('should support nzDisabled', fakeAsync(() => {\n      // Make sure picker clear button shown up\n      fixtureInstance.nzAllowClear = true;\n      fixtureInstance.modelValue = [new Date(), new Date()];\n\n      fixtureInstance.nzDisabled = true;\n      fixture.detectChanges();\n      expect(debugElement.query(By.css('.ant-picker-disabled'))).not.toBeNull();\n      expect(debugElement.query(By.css('.ant-picker-clear'))).toBeNull();\n\n      fixtureInstance.nzDisabled = false;\n      tick();\n      fixture.detectChanges();\n      expect(debugElement.query(By.css('.ant-picker-disabled'))).toBeNull();\n      expect(debugElement.query(By.css('.ant-picker-clear'))).not.toBeNull();\n    }));\n\n    it('should support nzOpen if assigned', fakeAsync(() => {\n      fixtureInstance.useSuite = 2;\n\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).toBeNull();\n\n      fixtureInstance.nzOpen = true;\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).not.toBeNull();\n\n      fixtureInstance.nzOpen = false;\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).toBeNull();\n    }));\n\n    it('should support nzDisabledDate', fakeAsync(() => {\n      fixture.detectChanges();\n      const compareDate = new Date('2018-11-15 00:00:00');\n      fixtureInstance.modelValue = [new Date('2018-11-11 12:12:12'), null!];\n      fixtureInstance.nzDisabledDate = (current: Date) => isSameDay(current, compareDate);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      const disabledCell = queryFromOverlay('td.ant-picker-cell-disabled .ant-picker-cell-inner');\n      expect(disabledCell.textContent!.trim()).toBe('15');\n    }));\n\n    it('should support nzLocale', () => {\n      const featureKey = 'LEFT_PLACEHOLDER';\n      fixtureInstance.nzLocale = { lang: { rangePlaceholder: [featureKey, 'End'] } };\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement).getAttribute('placeholder')).toBe(featureKey);\n    });\n\n    it('should support nzPlaceHolder', () => {\n      const featureKey = 'RIGHT_PLACEHOLDER';\n      fixtureInstance.nzPlaceHolder = ['Start', featureKey];\n      fixture.detectChanges();\n      expect(getRangePickerRightInput(fixture.debugElement).getAttribute('placeholder')).toBe(featureKey);\n    });\n\n    it('should support nzPopupStyle', fakeAsync(() => {\n      fixtureInstance.nzPopupStyle = { color: 'red' };\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(queryFromOverlay(`.${PREFIX_CLASS}-dropdown`).style.color).toBe('red');\n    }));\n\n    it('should support nzDropdownClassName', fakeAsync(() => {\n      const keyCls = (fixtureInstance.nzDropdownClassName = 'my-test-class');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(queryFromOverlay(`.${PREFIX_CLASS}-dropdown`).classList.contains(keyCls)).toBeTruthy();\n    }));\n\n    it('should support nzSize', () => {\n      fixtureInstance.nzSize = 'large';\n      fixture.detectChanges();\n      expect(getPickerAbstract(fixture.debugElement).classList.contains('ant-picker-large')).toBeTruthy();\n\n      fixtureInstance.nzSize = 'small';\n      fixture.detectChanges();\n      expect(getPickerAbstract(fixture.debugElement).classList.contains('ant-picker-small')).toBeTruthy();\n    });\n\n    it('should support nzOnOpenChange', fakeAsync(() => {\n      const nzOnOpenChange = spyOn(fixtureInstance, 'nzOnOpenChange');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(nzOnOpenChange).toHaveBeenCalledWith(true);\n\n      triggerInputBlur();\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(nzOnOpenChange).toHaveBeenCalledWith(false);\n      expect(nzOnOpenChange).toHaveBeenCalledTimes(2);\n    }));\n\n    it('should support nzValue', fakeAsync(() => {\n      fixtureInstance.nzDefaultPickerValue = [new Date('2012-03-18'), new Date('2019-12-12')];\n      fixtureInstance.modelValue = [new Date('2018-11-11'), new Date('2018-12-11')];\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(getFirstSelectedDayCell().textContent!.trim()).toBe('11');\n    }));\n\n    it('should support nzDefaultPickerValue', fakeAsync(() => {\n      fixtureInstance.nzDefaultPickerValue = [new Date('2012-01-18'), new Date('2019-11-11')];\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(getHeaderMonthBtn().textContent!.indexOf('1') > -1).toBeTruthy();\n      expect(queryFromRightPanel('.ant-picker-header-month-btn').textContent!.indexOf('2') > -1).toBeTruthy();\n    }));\n\n    it('should support string nzSeparator', fakeAsync(() => {\n      fixtureInstance.nzSeparator = '→';\n      fixture.detectChanges();\n      expect(fixture.debugElement.query(By.css(`.ant-picker-range-separator`)).nativeElement.textContent.trim()).toBe(\n        '→'\n      );\n    }));\n\n    it('should support ElementRef nzSeparator', fakeAsync(() => {\n      fixtureInstance.useSuite = 6;\n      fixture.detectChanges();\n      expect(fixture.debugElement.query(By.css(`.ant-picker-range-separator`)).nativeElement.textContent.trim()).toBe(\n        'TEST_SEPARATOR_REF'\n      );\n    }));\n\n    it('should support nzOnCalendarChange', fakeAsync(() => {\n      const nzOnCalendarChange = spyOn(fixtureInstance, 'nzOnCalendarChange');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      const left = getFirstCell('left');\n      const leftText = left.textContent!.trim();\n      dispatchMouseEvent(left, 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(nzOnCalendarChange).toHaveBeenCalled();\n      let result = (nzOnCalendarChange.calls.allArgs()[0] as Date[][])[0];\n      expect((result[0] as Date).getDate()).toBe(+leftText);\n      const right = getFirstCell('right');\n      const rightText = right.textContent!.trim();\n      dispatchMouseEvent(right, 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(nzOnCalendarChange).toHaveBeenCalled();\n      result = (nzOnCalendarChange.calls.allArgs()[1] as Date[][])[0];\n      expect((result[0] as Date).getDate()).toBe(+leftText);\n      expect((result[1] as Date).getDate()).toBe(+rightText);\n    }));\n\n    it('should support nzOnCalendarChange when nzShowTime is true', fakeAsync(() => {\n      const nzOnCalendarChange = spyOn(fixtureInstance, 'nzOnCalendarChange');\n      fixtureInstance.nzShowTime = true;\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      const left = getFirstCell('left');\n      dispatchMouseEvent(left, 'click');\n      fixture.detectChanges();\n      dispatchMouseEvent(queryFromOverlay('.ant-picker-ok > button'), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(nzOnCalendarChange).toHaveBeenCalled();\n    }));\n\n    it('should support nzOnChange', fakeAsync(() => {\n      fixtureInstance.modelValue = [new Date('2018-11-11'), new Date('2018-11-11')];\n      const nzOnChange = spyOn(fixtureInstance, 'modelValueChange');\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      const left = getFirstCell('left'); // Use the first cell\n      const leftText = left.textContent!.trim();\n      dispatchMouseEvent(left, 'click');\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(nzOnChange).not.toHaveBeenCalled();\n      // now the cursor focus on right\n      const right = getFirstCell('right');\n      dispatchMouseEvent(right, 'click');\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      const result = (nzOnChange.calls.allArgs()[0] as Date[][])[0];\n      expect((result[0] as Date).getDate()).toBe(+leftText);\n    }));\n    it('should not call nzOnChange if values do not change', fakeAsync(() => {\n      fixtureInstance.modelValue = [new Date('2018-11-11'), new Date('2018-11-11')];\n      const nzOnChange = spyOn(fixtureInstance, 'modelValueChange');\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      const leftInput = getPickerInput(fixture.debugElement);\n      const rightInput = getRangePickerRightInput(fixture.debugElement);\n      typeInElement('2018-11-11 00:00:00', leftInput);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      typeInElement('2018-11-11 00:00:00', rightInput);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      triggerInputBlur();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(nzOnChange).not.toHaveBeenCalled();\n    }));\n\n    it('should support nzInline', fakeAsync(() => {\n      const nzOnChange = spyOn(fixtureInstance, 'modelValueChange');\n      fixtureInstance.modelValue = [new Date('2018-11-11'), new Date('2018-11-11')];\n      fixtureInstance.nzInline = true;\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      overlayContainerElement = debugElement.nativeElement as HTMLLIElement;\n\n      const left = getFirstCell('left'); // Use the first cell\n      const leftText = left.textContent!.trim();\n      dispatchMouseEvent(left, 'click');\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(nzOnChange).not.toHaveBeenCalled();\n      // now the cursor focus on right\n      const right = getFirstCell('right');\n      dispatchMouseEvent(right, 'click');\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      const result = (nzOnChange.calls.allArgs()[0] as Date[][])[0];\n      expect((result[0] as Date).getDate()).toBe(+leftText);\n    }));\n\n    it('should support correct position for top arrow', fakeAsync(() => {\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      const arrow = queryFromOverlay(`.${PREFIX_CLASS}-range-arrow`) as HTMLElement;\n\n      expect(arrow.style.left).not.toBe('');\n    }));\n\n    it('should support dir rtl for top arrow', fakeAsync(() => {\n      fixture.debugElement.nativeElement.parentElement.setAttribute('dir', 'rtl');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      const arrow = queryFromOverlay(`.${PREFIX_CLASS}-range-arrow`) as HTMLElement;\n\n      expect(arrow.style.right).not.toBe('');\n      fixture.debugElement.nativeElement.parentElement.setAttribute('dir', '');\n    }));\n  }); // /general api testing\n\n  describe('panel switch and move forward/afterward', () => {\n    beforeEach(() => (fixtureInstance.useSuite = 1));\n\n    it('should support date panel changes', fakeAsync(() => {\n      fixtureInstance.modelValue = [new Date('2018-6-11'), new Date('2018-12-12')];\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      // Click previous year button\n      dispatchMouseEvent(getSuperPreBtn('left'), 'click');\n      fixture.detectChanges();\n      expect(getHeaderYearBtn('left').textContent!.indexOf('2017') > -1).toBeTruthy();\n      // Click next year button * 2\n      dispatchMouseEvent(getSuperNextBtn('left'), 'click');\n      fixture.detectChanges();\n      dispatchMouseEvent(getSuperNextBtn('left'), 'click');\n      fixture.detectChanges();\n      expect(getHeaderYearBtn('left').textContent!.indexOf('2019') > -1).toBeTruthy();\n      // Click previous month button\n      dispatchMouseEvent(getPreBtn('left'), 'click');\n      fixture.detectChanges();\n      expect(getHeaderMonthBtn().textContent!.indexOf('5') > -1).toBeTruthy();\n      // Click next month button * 2\n      dispatchMouseEvent(getNextBtn('left'), 'click');\n      fixture.detectChanges();\n      dispatchMouseEvent(getNextBtn('left'), 'click');\n      fixture.detectChanges();\n      expect(getHeaderMonthBtn().textContent!.indexOf('7') > -1).toBeTruthy();\n    }));\n\n    it('should support keep initValue when reopen panel', fakeAsync(() => {\n      fixtureInstance.modelValue = [new Date('2018-6-11'), new Date('2018-12-12')];\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      // Click next year button * 2\n      dispatchMouseEvent(getSuperNextBtn('left'), 'click');\n      fixture.detectChanges();\n      dispatchMouseEvent(getSuperNextBtn('left'), 'click');\n      fixture.detectChanges();\n\n      triggerInputBlur();\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      openPickerByClickTrigger();\n      expect(getHeaderYearBtn('left').textContent!.indexOf('2018') > -1).toBeTruthy();\n    }));\n  }); // /panel switch and move forward/afterward\n\n  describe('specified date picker testing', () => {\n    beforeEach(() => (fixtureInstance.useSuite = 1));\n\n    it('should support nzDateRender', fakeAsync(() => {\n      fixtureInstance.nzDateRender = fixtureInstance.tplDateRender;\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(queryFromOverlay('.test-first-day').textContent!.trim()).toBe('1');\n    }));\n\n    it('should support nzDateRender with typeof function', fakeAsync(() => {\n      const featureKey = 'TEST_FIRST_DAY';\n      fixtureInstance.nzDateRender = (d: CandyDate) => (d.getDate() === 1 ? featureKey : d.getDate());\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(overlayContainerElement.textContent!.indexOf(featureKey) > -1).toBeTruthy();\n    }));\n\n    it('should support nzShowTime', fakeAsync(() => {\n      fixtureInstance.modelValue = [new Date('2018-11-11 11:22:33'), new Date('2018-12-12 11:22:33')];\n      fixtureInstance.nzShowTime = true;\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      flush();\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-ok')).toBeDefined();\n      expect(\n        queryFromOverlay('.ant-picker-panel .ant-picker-time-picker-inner.ant-picker-time-picker-column-3')\n      ).toBeDefined();\n      expect(\n        queryFromOverlay(\n          '.ant-picker-panel .ant-picker-time-panel-cell-selected .ant-picker-time-panel-cell-inner'\n        ).textContent!.trim()\n      ).toBe('11');\n\n      // Click to choose an hour\n      dispatchMouseEvent(\n        queryFromOverlay('.ant-picker-time-panel-column .ant-picker-time-panel-cell:first-child'),\n        'click'\n      );\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement).value).toBe('2018-11-11 00:22:33');\n    }));\n\n    it('should support hover date cell style', fakeAsync(() => {\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      const left = getFirstCell('left'); // Use the first cell\n      dispatchMouseEvent(left, 'click');\n      fixture.detectChanges();\n      const rightInNextMonth = queryFromRightPanel('table tr:nth-child(3) td.ant-picker-cell');\n      dispatchMouseEvent(rightInNextMonth, 'mouseenter');\n      fixture.detectChanges();\n      expect(rightInNextMonth.classList.contains('ant-picker-cell-range-hover-end')).toBeTruthy();\n    }));\n\n    it('should support active part change when select one', fakeAsync(() => {\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      flush();\n      fixture.detectChanges();\n      // Choose left part first\n      dispatchMouseEvent(getFirstCell('left'), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getRangePickerRightInput(fixture.debugElement) === document.activeElement).toBeTruthy();\n\n      triggerInputBlur();\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      // Choose right part first\n      openRightPickerByClickTrigger();\n      flush();\n      fixture.detectChanges();\n      dispatchMouseEvent(getFirstCell('right'), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement) === document.activeElement).toBeTruthy();\n    }));\n\n    it('should support select end date first with time panel', fakeAsync(() => {\n      fixtureInstance.nzShowTime = true;\n      fixture.detectChanges();\n      openRightPickerByClickTrigger();\n      flush();\n      fixture.detectChanges();\n      const okButton = queryFromOverlay('.ant-picker-ok > button');\n      expect(okButton.getAttribute('disabled')).not.toBeNull();\n\n      // Click to choose an hour\n      dispatchMouseEvent(\n        queryFromRightPanel('.ant-picker-time-panel-column .ant-picker-time-panel-cell:first-child'),\n        'click'\n      );\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(okButton.getAttribute('disabled')).toBeNull();\n\n      dispatchMouseEvent(okButton, 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement) === document.activeElement).toBeTruthy();\n    }));\n\n    it('should support nzShowTime.nzFormat', fakeAsync(() => {\n      fixtureInstance.modelValue = [new Date('2018-11-11'), new Date('2018-12-12')];\n      fixtureInstance.nzShowTime = { nzFormat: 'HH:mm' };\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(\n        overlayContainerElement.querySelectorAll('.ant-picker-panel:first-child .ant-picker-time-panel-column').length\n      ).toBe(2);\n    }));\n\n    it('should support nzDisabledTime and nzShowTime.nzHideDisabledOptions', fakeAsync(() => {\n      fixtureInstance.modelValue = [new Date('2018-11-11 11:11:11'), new Date('2018-12-12 12:12:12')];\n      fixtureInstance.nzShowTime = true;\n      fixtureInstance.nzDisabledTime = (_current: Date, partial: 'start' | 'end') =>\n        partial === 'start'\n          ? {\n              nzDisabledHours: () => [0, 1, 2],\n              nzDisabledMinutes: () => [0, 1],\n              nzDisabledSeconds: () => [0]\n            }\n          : {\n              nzDisabledHours: () => [0, 1, 2, 3],\n              nzDisabledMinutes: () => [0, 1, 2],\n              nzDisabledSeconds: () => [0, 1]\n            };\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      // Left time picker\n      expect(\n        queryFromOverlay('.ant-picker-time-panel-column li:nth-child(3)').classList.contains(\n          'ant-picker-time-panel-cell-disabled'\n        )\n      ).toBeTruthy();\n      expect(\n        queryFromOverlay('.ant-picker-time-panel-column:nth-child(2) li:nth-child(2)').classList.contains(\n          'ant-picker-time-panel-cell-disabled'\n        )\n      ).toBeTruthy();\n      expect(\n        queryFromOverlay('.ant-picker-time-panel-column:nth-child(3) li:nth-child(1)').classList.contains(\n          'ant-picker-time-panel-cell-disabled'\n        )\n      ).toBeTruthy();\n\n      // Close left panel\n      triggerInputBlur();\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      // Right time picker\n      openRightPickerByClickTrigger();\n      expect(\n        queryFromRightPanel('.ant-picker-time-panel-column li:nth-child(4)').classList.contains(\n          'ant-picker-time-panel-cell-disabled'\n        )\n      ).toBeTruthy();\n      expect(\n        queryFromRightPanel('.ant-picker-time-panel-column:nth-child(2) li:nth-child(3)').classList.contains(\n          'ant-picker-time-panel-cell-disabled'\n        )\n      ).toBeTruthy();\n      expect(\n        queryFromRightPanel('.ant-picker-time-panel-column:nth-child(3) li:nth-child(2)').classList.contains(\n          'ant-picker-time-panel-cell-disabled'\n        )\n      ).toBeTruthy();\n\n      // Use nzHideDisabledOptions to hide disabled times\n      fixtureInstance.nzShowTime = { nzHideDisabledOptions: true };\n      fixture.detectChanges();\n\n      // Close left panel\n      triggerInputBlur('right');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      // Left time picker\n      expect(+queryFromOverlay('.ant-picker-time-panel-column:nth-child(1) li:first-child').textContent!.trim()).toBe(\n        3\n      );\n      expect(+queryFromOverlay('.ant-picker-time-panel-column:nth-child(2) li:first-child').textContent!.trim()).toBe(\n        2\n      );\n      expect(+queryFromOverlay('.ant-picker-time-panel-column:nth-child(3) li:first-child').textContent!.trim()).toBe(\n        1\n      );\n\n      // Close left panel\n      triggerInputBlur();\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      openRightPickerByClickTrigger();\n      // Right time picker\n      expect(\n        +queryFromRightPanel('.ant-picker-time-panel-column:nth-child(1) li:first-child').textContent!.trim()\n      ).toBe(4);\n      expect(\n        +queryFromRightPanel('.ant-picker-time-panel-column:nth-child(2) li:first-child').textContent!.trim()\n      ).toBe(3);\n      expect(\n        +queryFromRightPanel('.ant-picker-time-panel-column:nth-child(3) li:first-child').textContent!.trim()\n      ).toBe(2);\n    }));\n\n    it('should support nzRenderExtraFooter', fakeAsync(() => {\n      fixtureInstance.nzRenderExtraFooter = () => fixtureInstance.tplExtraFooter;\n      fixture.detectChanges();\n\n      openPickerByClickTrigger();\n      expect(overlayContainerElement.textContent!.indexOf('TEST_EXTRA_FOOTER') > -1).toBeTruthy();\n\n      fixtureInstance.nzRenderExtraFooter = 'TEST_EXTRA_FOOTER_STRING';\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent!.indexOf(fixtureInstance.nzRenderExtraFooter) > -1).toBeTruthy();\n    }));\n\n    it('should support nzOnPanelChange', fakeAsync(() => {\n      fixtureInstance.modelValue = [new Date('2018-10-11 11:22:34'), new Date('2018-11-12 11:22:33')];\n      const spy = spyOn(fixtureInstance, 'nzOnPanelChange');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      // Click header to month panel\n      // Left\n      dispatchMouseEvent(\n        overlayContainerElement.querySelector('.ant-picker-panel .ant-picker-header-month-btn')!,\n        'click'\n      );\n      fixture.detectChanges();\n\n      expect(fixtureInstance.nzOnPanelChange).toHaveBeenCalledWith({\n        mode: ['month', 'date'],\n        date: [new Date('2018-10-11 11:22:34'), new Date('2018-11-11 11:22:34')]\n      });\n\n      spy.calls.reset();\n\n      // Right\n      dispatchMouseEvent(\n        overlayContainerElement.querySelector('.ant-picker-panel:last-child .ant-picker-header-year-btn')!,\n        'click'\n      );\n      fixture.detectChanges();\n      expect(fixtureInstance.nzOnPanelChange).toHaveBeenCalledWith({\n        mode: ['month', 'year'],\n        date: [new Date('2018-10-11 11:22:34'), new Date('2018-11-11 11:22:34')]\n      });\n    }));\n\n    it('should support nzOnPanelChange when click on prev button', fakeAsync(() => {\n      fixtureInstance.modelValue = [new Date('2018-10-11 11:22:34'), new Date('2018-11-12 11:22:33')];\n      spyOn(fixtureInstance, 'nzOnPanelChange');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      dispatchMouseEvent(getPreBtn('left'), 'click');\n      fixture.detectChanges();\n      expect(fixtureInstance.nzOnPanelChange).toHaveBeenCalledWith({\n        mode: ['date', 'date'],\n        date: [new Date('2018-09-11 11:22:34'), new Date('2018-10-11 11:22:34')]\n      });\n    }));\n    it('should support nzOnPanelChange when click on next button', fakeAsync(() => {\n      fixtureInstance.modelValue = [new Date('2018-10-11 11:22:34'), new Date('2018-11-12 11:22:33')];\n      spyOn(fixtureInstance, 'nzOnPanelChange');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      dispatchMouseEvent(getNextBtn('right'), 'click');\n      fixture.detectChanges();\n      expect(fixtureInstance.nzOnPanelChange).toHaveBeenCalledWith({\n        mode: ['date', 'date'],\n        date: [new Date('2018-11-11 11:22:34'), new Date('2018-12-11 11:22:34')]\n      });\n    }));\n    it('should support nzOnPanelChange when click on super prev button', fakeAsync(() => {\n      fixtureInstance.modelValue = [new Date('2018-10-11 11:22:34'), new Date('2018-11-12 11:22:33')];\n      spyOn(fixtureInstance, 'nzOnPanelChange');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      dispatchMouseEvent(getSuperPreBtn('left'), 'click');\n      fixture.detectChanges();\n      expect(fixtureInstance.nzOnPanelChange).toHaveBeenCalledWith({\n        mode: ['date', 'date'],\n        date: [new Date('2017-10-11 11:22:34'), new Date('2017-11-11 11:22:34')]\n      });\n    }));\n    it('should support nzOnPanelChange when click on super next button', fakeAsync(() => {\n      fixtureInstance.modelValue = [new Date('2018-10-11 11:22:34'), new Date('2018-11-12 11:22:33')];\n      spyOn(fixtureInstance, 'nzOnPanelChange');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      dispatchMouseEvent(getSuperNextBtn('left'), 'click');\n      fixture.detectChanges();\n      expect(fixtureInstance.nzOnPanelChange).toHaveBeenCalledWith({\n        mode: ['date', 'date'],\n        date: [new Date('2019-10-11 11:22:34'), new Date('2019-11-11 11:22:34')]\n      });\n    }));\n\n    it('should support nzOnOk', fakeAsync(() => {\n      spyOn(fixtureInstance, 'nzOnOk');\n      fixtureInstance.modelValue = [new Date('2018-11-11 11:22:33'), new Date('2018-12-12 11:22:33')];\n      fixtureInstance.nzShowTime = true;\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      // Click ok button\n      dispatchMouseEvent(overlayContainerElement.querySelector('.ant-picker-ok > button')!, 'click');\n      fixture.detectChanges();\n      tick(500);\n      expect(fixtureInstance.nzOnOk).toHaveBeenCalledWith(fixtureInstance.modelValue);\n    }));\n\n    it('should select date from start to end with side effects', fakeAsync(() => {\n      const initial = (fixtureInstance.modelValue = [new Date('2018-05-15'), new Date('2018-06-15')]);\n      fixtureInstance.nzDisabledDate = (current: Date) => differenceInDays(current, initial[0]) < 0;\n      fixtureInstance.nzShowTime = true;\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      // Click start date\n      const startDate = queryFromOverlay('.ant-picker-panel td.ant-picker-cell-selected');\n      dispatchMouseEvent(startDate, 'click');\n      fixture.detectChanges();\n      expect(startDate.classList.contains('ant-picker-cell-selected')).toBeTruthy();\n    }));\n\n    it('should display expected date when the range values are the same day (include the scenario of timepicker)', fakeAsync(() => {\n      fixtureInstance.modelValue = [new Date('2018-05-15'), new Date('2018-05-15')];\n      fixtureInstance.nzShowTime = true;\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      expect(getHeaderMonthBtn().textContent).toContain('5');\n    }));\n\n    it('should support nzRanges', fakeAsync(() => {\n      const today = new Date();\n      const nzOnChange = spyOn(fixtureInstance, 'modelValueChange');\n      fixtureInstance.nzRanges = { Today: [today, today] };\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(queryFromOverlay('.ant-picker-ranges .ant-picker-preset')).toBeDefined();\n\n      const selector = queryFromOverlay('.ant-picker-ranges li.ant-picker-preset:first-child');\n      dispatchMouseEvent(selector, 'mouseenter');\n      fixture.detectChanges();\n      expect(\n        queryFromOverlay('.ant-picker-panel td.ant-picker-cell-range-hover-start .ant-picker-cell-inner').textContent\n      ).toContain(`${today.getDate()}`);\n\n      // selector = queryFromOverlay('.ant-picker-ranges li.ant-picker-preset:first-child');\n      dispatchMouseEvent(selector, 'mouseleave');\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-panel td.ant-picker-cell-selected')).toBeFalsy();\n\n      // selector = queryFromOverlay('.ant-picker-range-quick-selector > a');\n      dispatchMouseEvent(selector, 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(nzOnChange).toHaveBeenCalled();\n      expect(getPickerContainer()).toBeFalsy();\n    }));\n\n    it('should custom input date range', fakeAsync(() => {\n      const nzOnChange = spyOn(fixtureInstance, 'modelValueChange');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      const leftInput = getPickerInput(fixture.debugElement);\n      const rightInput = getRangePickerRightInput(fixture.debugElement);\n\n      typeInElement('2018-11-11', leftInput);\n      fixture.detectChanges();\n\n      // should focus the other input\n      leftInput.dispatchEvent(ENTER_EVENT);\n      fixture.detectChanges();\n      expect(getRangePickerRightInput(fixture.debugElement) === document.activeElement).toBeTruthy();\n\n      typeInElement('2018-12-12', rightInput);\n      rightInput.dispatchEvent(ENTER_EVENT);\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(nzOnChange).toHaveBeenCalled();\n      const result = (nzOnChange.calls.allArgs()[0] as Date[][])[0];\n      expect(result[0].getDate()).toBe(11);\n      expect(result[1].getDate()).toBe(12);\n    }));\n\n    it('should custom input time range', fakeAsync(() => {\n      const nzOnChange = spyOn(fixtureInstance, 'modelValueChange');\n      fixtureInstance.modelValue = [new Date('2019-11-11 11:22:33'), new Date('2019-12-12 11:22:33')];\n      fixtureInstance.nzShowTime = true;\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      const leftInput = getPickerInput(fixture.debugElement);\n      const rightInput = getRangePickerRightInput(fixture.debugElement);\n      const newDateString = ['2019-09-15 11:08:22', '2020-10-10 11:08:22'];\n      typeInElement(newDateString[0], leftInput);\n      fixture.detectChanges();\n      // should focus the other input\n      leftInput.dispatchEvent(ENTER_EVENT);\n      fixture.detectChanges();\n      typeInElement(newDateString[1], rightInput);\n      fixture.detectChanges();\n      rightInput.dispatchEvent(ENTER_EVENT);\n      fixture.detectChanges();\n      tick(500);\n      expect(nzOnChange).toHaveBeenCalledWith([new Date(newDateString[0]), new Date(newDateString[1])]);\n    }));\n\n    it('if sort order is wrong, output in reverse order', fakeAsync(() => {\n      const nzOnChange = spyOn(fixtureInstance, 'modelValueChange');\n      fixtureInstance.modelValue = [];\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      const leftInput = getPickerInput(fixture.debugElement);\n      const rightInput = getRangePickerRightInput(fixture.debugElement);\n      const newDateString = ['2019-09-15', '2020-10-10'];\n\n      typeInElement(newDateString[1], leftInput);\n      fixture.detectChanges();\n      leftInput.dispatchEvent(ENTER_EVENT);\n      fixture.detectChanges();\n\n      typeInElement(newDateString[0], rightInput);\n      fixture.detectChanges();\n      rightInput.dispatchEvent(ENTER_EVENT);\n      fixture.detectChanges();\n      tick(500);\n      expect(nzOnChange).toHaveBeenCalledWith([new Date(newDateString[0]), new Date(newDateString[1])]);\n    }));\n\n    it('should not change value when click ESC', fakeAsync(() => {\n      fixtureInstance.modelValue = [new Date('2018-09-11'), new Date('2020-09-12')];\n      fixture.detectChanges();\n      tick(); // Wait writeValue() tobe done\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      const leftInput = getPickerInput(fixture.debugElement);\n      const rightInput = getRangePickerRightInput(fixture.debugElement);\n\n      typeInElement('2019-11-05', leftInput);\n      fixture.detectChanges();\n      // TODO: value should be change\n      // expect(getFirstSelectedDayCell().textContent!.trim()).toBe('5');\n      typeInElement('2019-12-08', rightInput);\n      fixture.detectChanges();\n      // expect(getSecondSelectedDayCell().textContent!.trim()).toBe('8');\n      dispatchKeyboardEvent(document.body, 'keydown', ESCAPE);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      // TODO: input value should not be change\n      // expect(leftInput.value).toBe('2018-09-11');\n    }));\n\n    it('should auto sort range value when start is after end', fakeAsync(() => {\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      const leftInput = getPickerInput(fixture.debugElement);\n      const rightInput = getRangePickerRightInput(fixture.debugElement);\n      typeInElement('2019-08-10', leftInput);\n      fixture.detectChanges();\n      // should focus the other input\n      leftInput.dispatchEvent(ENTER_EVENT);\n      fixture.detectChanges();\n      typeInElement('2018-02-06', rightInput);\n      fixture.detectChanges();\n      getRangePickerRightInput(fixture.debugElement).dispatchEvent(ENTER_EVENT);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(leftInput.value).toBe('2018-02-06');\n      expect(rightInput.value).toBe('2019-08-10');\n    }));\n\n    it('should panel date follows the selected date', fakeAsync(() => {\n      fixtureInstance.nzShowTime = true;\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      const leftInput = getPickerInput(fixture.debugElement);\n      typeInElement('2027-09-17 11:08:22', leftInput);\n      fixture.detectChanges();\n      leftInput.dispatchEvent(ENTER_EVENT);\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getHeaderYearBtn('left').textContent).toContain('2027');\n      // panel month will increase 1\n      expect(getHeaderMonthBtn().textContent).toContain('9');\n    }));\n  }); // /specified date picker testing\n\n  describe('ngModel value accessors', () => {\n    beforeEach(() => (fixtureInstance.useSuite = 3));\n\n    it('should specified date provide by \"modelValue\" be chosen', fakeAsync(() => {\n      fixtureInstance.modelValue = [new Date('2018-11-11'), new Date('2018-12-12')];\n      fixture.detectChanges();\n      tick(); // Wait writeValue() tobe done\n      fixture.detectChanges();\n      expect(getFirstSelectedDayCell().textContent!.trim()).toBe('11');\n\n      // Click the first cell to change ngModel\n      const left = getFirstCell('left');\n      const right = getFirstCell('right');\n      const leftText = left.textContent!.trim();\n      dispatchMouseEvent(left, 'click');\n      fixture.detectChanges();\n      dispatchMouseEvent(right, 'click');\n      fixture.detectChanges();\n      expect(fixtureInstance.modelValue[0]!.getDate()).toBe(+leftText);\n    }));\n  });\n\n  describe('week mode', () => {\n    beforeEach(() => {\n      fixtureInstance.useSuite = 1;\n      fixtureInstance.nzMode = 'week';\n    });\n\n    it('should support week row style', fakeAsync(() => {\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      const leftThirdRow = queryFromOverlay('.ant-picker-panel:first-child table tr:nth-child(3)');\n      const leftThirdRowCell = leftThirdRow.querySelector('td.ant-picker-cell')!;\n      dispatchMouseEvent(leftThirdRowCell, 'click');\n      fixture.detectChanges();\n      expect(leftThirdRow.classList.contains('ant-picker-week-panel-row-selected')).toBeTruthy();\n      const rightThirdRowCell = queryFromRightPanel('table tr:nth-child(3) td.ant-picker-cell');\n      dispatchMouseEvent(rightThirdRowCell, 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).toBeNull();\n    }));\n  });\n\n  describe('month mode', () => {\n    beforeEach(() => {\n      fixtureInstance.useSuite = 1;\n      fixtureInstance.nzMode = 'month';\n    });\n\n    it('should support month cell style', fakeAsync(() => {\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      const left = getFirstCell('left'); // Use the first cell\n      dispatchMouseEvent(left, 'click');\n      fixture.detectChanges();\n      const rightThirdRowCell = queryFromRightPanel('table tr:nth-child(3) td.ant-picker-cell');\n      dispatchMouseEvent(rightThirdRowCell, 'mouseenter');\n      fixture.detectChanges();\n      expect(rightThirdRowCell.classList.contains('ant-picker-cell-range-hover-end')).toBeTruthy();\n    }));\n  });\n\n  describe('year mode', () => {\n    beforeEach(() => {\n      fixtureInstance.useSuite = 1;\n      fixtureInstance.nzMode = 'year';\n    });\n\n    it('should support year cell style', fakeAsync(() => {\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      const left = getFirstCell('left');\n      dispatchMouseEvent(left, 'click');\n      fixture.detectChanges();\n      const rightThirdRowCell = queryFromRightPanel('table tr:nth-child(3) td.ant-picker-cell');\n      dispatchMouseEvent(rightThirdRowCell, 'mouseenter');\n      fixture.detectChanges();\n      expect(rightThirdRowCell.classList.contains('ant-picker-cell-range-hover-end')).toBeTruthy();\n    }));\n  });\n\n  describe('status', () => {\n    let fixtureStatus: ComponentFixture<NzTestRangePickerStatusComponent>;\n    let fixtureStatusInstance: NzTestRangePickerStatusComponent;\n    let rangePickerElement!: HTMLElement;\n    beforeEach(() => {\n      fixtureStatus = TestBed.createComponent(NzTestRangePickerStatusComponent);\n      fixtureStatusInstance = fixtureStatus.componentInstance;\n      rangePickerElement = fixtureStatus.debugElement.query(By.directive(NzRangePickerComponent)).nativeElement;\n      fixtureStatus.detectChanges();\n    });\n\n    it('should classname correct', fakeAsync(() => {\n      expect(rangePickerElement.classList).toContain('ant-picker-status-error');\n\n      fixtureStatusInstance.status = 'warning';\n      fixtureStatus.detectChanges();\n      expect(rangePickerElement.classList).toContain('ant-picker-status-warning');\n\n      fixtureStatusInstance.status = '';\n      fixtureStatus.detectChanges();\n      expect(rangePickerElement.classList).not.toContain('ant-picker-status-warning');\n    }));\n  });\n\n  ////////////\n\n  function getCssIndex(part: RangePartType): string {\n    return part === 'left' ? 'first-child' : 'last-child';\n  }\n\n  function getPickerContainer(): HTMLElement {\n    return queryFromOverlay('.ant-picker-panel-container') as HTMLElement;\n  }\n\n  function getFirstSelectedDayCell(): HTMLElement {\n    return queryFromOverlay(\n      '.ant-picker-panel:first-child td.ant-picker-cell-selected .ant-picker-cell-inner'\n    ) as HTMLElement;\n  }\n\n  function getRegularPickerInput(fixtureDebugElement: DebugElement): HTMLInputElement {\n    return fixtureDebugElement.queryAll(By.css(`.${PREFIX_CLASS}-input input`))[2].nativeElement as HTMLInputElement;\n  }\n\n  function getPreBtn(part: RangePartType): HTMLElement {\n    return queryFromOverlay(`.ant-picker-panel:${getCssIndex(part)} .${PREFIX_CLASS}-header-prev-btn`);\n  }\n\n  function getNextBtn(part: RangePartType): HTMLElement {\n    return queryFromOverlay(`.ant-picker-panel:${getCssIndex(part)} .${PREFIX_CLASS}-header-next-btn`);\n  }\n\n  function getSuperPreBtn(part: RangePartType): HTMLElement {\n    return queryFromOverlay(`.ant-picker-panel:${getCssIndex(part)} .${PREFIX_CLASS}-header-super-prev-btn`);\n  }\n\n  function getSuperNextBtn(part: RangePartType): HTMLElement {\n    return queryFromOverlay(`.ant-picker-panel:${getCssIndex(part)} .${PREFIX_CLASS}-header-super-next-btn`);\n  }\n\n  function getHeaderYearBtn(part: RangePartType): HTMLElement {\n    return queryFromOverlay(`.ant-picker-panel .ant-picker-header-year-btn:${getCssIndex(part)}`);\n  }\n\n  function getHeaderMonthBtn(): HTMLElement {\n    return queryFromOverlay(`.ant-picker-panel .ant-picker-header-month-btn`);\n  }\n\n  function getFirstCell(partial: 'left' | 'right'): HTMLElement {\n    const flg = partial === 'left' ? 'first' : 'last';\n    return queryFromOverlay(`.ant-picker-panel:${flg}-child td:first-child .ant-picker-cell-inner`) as HTMLElement;\n  }\n\n  function queryFromOverlay(selector: string): HTMLElement {\n    return overlayContainerElement.querySelector(selector) as HTMLElement;\n  }\n\n  function queryFromRightPanel(selector: string): HTMLElement {\n    return overlayContainerElement\n      .querySelector('.ant-picker-panel:last-child')!\n      .querySelector(selector) as HTMLElement;\n  }\n\n  function openPickerByClickTrigger(): void {\n    dispatchMouseEvent(getPickerInput(fixture.debugElement), 'click');\n    fixture.detectChanges();\n    tick(500);\n    fixture.detectChanges();\n    dispatchFakeEvent(getPickerInput(fixture.debugElement), 'focus');\n    fixture.detectChanges();\n    tick(500);\n    fixture.detectChanges();\n  }\n\n  function openRightPickerByClickTrigger(): void {\n    dispatchMouseEvent(getRangePickerRightInput(fixture.debugElement), 'click');\n    fixture.detectChanges();\n    tick(500);\n    fixture.detectChanges();\n    dispatchFakeEvent(getRangePickerRightInput(fixture.debugElement), 'focus');\n    fixture.detectChanges();\n    tick(500);\n    fixture.detectChanges();\n  }\n\n  function triggerInputBlur(part: 'left' | 'right' = 'left'): void {\n    if (part === 'left') {\n      dispatchFakeEvent(getPickerInput(fixture.debugElement), 'focusout');\n    } else {\n      dispatchFakeEvent(getRangePickerRightInput(fixture.debugElement), 'focusout');\n    }\n  }\n});\n\n@Component({\n  imports: [FormsModule, NzDatePickerModule],\n  template: `\n    <ng-template #tplDateRender let-current>\n      <div [class.test-first-day]=\"current.getDate() === 1\">{{ current.getDate() }}</div>\n    </ng-template>\n    <ng-template #tplExtraFooter>TEST_EXTRA_FOOTER</ng-template>\n    <ng-template #separatorTemplate>TEST_SEPARATOR_REF</ng-template>\n\n    @switch (useSuite) {\n      @case (1) {\n        <nz-range-picker\n          [nzAllowClear]=\"nzAllowClear\"\n          [nzAutoFocus]=\"nzAutoFocus\"\n          [nzDisabled]=\"nzDisabled\"\n          [nzDisabledDate]=\"nzDisabledDate\"\n          [nzLocale]=\"nzLocale\"\n          [nzPlaceHolder]=\"nzPlaceHolder\"\n          [nzPopupStyle]=\"nzPopupStyle\"\n          [nzDropdownClassName]=\"nzDropdownClassName\"\n          [nzSize]=\"nzSize\"\n          [nzSeparator]=\"nzSeparator\"\n          (nzOnOpenChange)=\"nzOnOpenChange($event)\"\n          [(ngModel)]=\"modelValue\"\n          (ngModelChange)=\"modelValueChange($event)\"\n          [nzDateRender]=\"nzDateRender\"\n          [nzDisabledTime]=\"nzDisabledTime\"\n          [nzRenderExtraFooter]=\"nzRenderExtraFooter\"\n          [nzShowToday]=\"nzShowToday\"\n          [nzShowNow]=\"nzShowNow\"\n          [nzMode]=\"nzMode\"\n          [nzRanges]=\"nzRanges\"\n          [nzDefaultPickerValue]=\"nzDefaultPickerValue\"\n          [nzInline]=\"nzInline\"\n          (nzOnPanelChange)=\"nzOnPanelChange($event)\"\n          (nzOnCalendarChange)=\"nzOnCalendarChange($event)\"\n          [nzShowTime]=\"nzShowTime\"\n          (nzOnOk)=\"nzOnOk($event)\"\n        />\n      }\n      @case (2) {\n        <nz-range-picker [nzOpen]=\"nzOpen\" />\n      }\n      @case (3) {\n        <nz-range-picker nzOpen [(ngModel)]=\"modelValue\" />\n      }\n      @case (4) {\n        <nz-range-picker [(ngModel)]=\"modelValue\" />\n        <nz-date-picker [ngModel]=\"singleValue\" />\n      }\n      @case (5) {\n        <nz-range-picker nzOpen />\n      }\n      @case (6) {\n        <nz-range-picker [nzSeparator]=\"separatorTemplate\" />\n      }\n    }\n  `\n})\nclass NzTestRangePickerComponent {\n  useSuite!: 1 | 2 | 3 | 4 | 5 | 6;\n  @ViewChild('tplDateRender', { static: true }) tplDateRender!: TemplateRef<Date>;\n  @ViewChild('tplExtraFooter', { static: true }) tplExtraFooter!: TemplateRef<void>;\n\n  // --- Suite 1\n  nzAllowClear: boolean = false;\n  nzAutoFocus: boolean = false;\n  nzDisabled: boolean = false;\n  nzDisabledDate!: (d: Date) => boolean;\n  nzLocale: any; // eslint-disable-line @typescript-eslint/no-explicit-any\n  nzPlaceHolder!: string[];\n  nzPopupStyle!: NgStyleInterface;\n  nzDropdownClassName!: string;\n  nzSize!: NzDatePickerSizeType;\n\n  nzOnOpenChange(_: boolean): void {}\n\n  modelValue: CompatibleDate = [];\n\n  modelValueChange(_: Date[]): void {}\n\n  nzDefaultPickerValue!: CompatibleDate;\n  nzSeparator!: string;\n  nzInline: boolean = false;\n\n  nzDateRender: any; // eslint-disable-line @typescript-eslint/no-explicit-any\n  nzShowTime: boolean | object = false;\n  nzDisabledTime: any; // eslint-disable-line @typescript-eslint/no-explicit-any\n  nzRenderExtraFooter!: string | (() => TemplateRef<void> | string);\n  nzShowToday = false;\n  nzShowNow = false;\n  nzMode = 'date';\n\n  nzRanges: any; // eslint-disable-line @typescript-eslint/no-explicit-any\n  nzOnPanelChange(_: NzPanelChangeType): void {}\n\n  nzOnCalendarChange(_: Array<Date | null>): void {}\n\n  nzOnOk(_: CompatibleDate | null): void {}\n\n  // --- Suite 2\n  nzOpen: boolean = false;\n\n  // --- Suite 4\n  singleValue!: Date;\n}\n\n@Component({\n  imports: [NzDatePickerModule],\n  template: `<nz-range-picker [nzStatus]=\"status\" />`\n})\nclass NzTestRangePickerStatusComponent {\n  status: NzStatus = 'error';\n}\n"
  },
  {
    "path": "components/date-picker/range-picker.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, inject } from '@angular/core';\n\nimport { NzDatePickerComponent } from './date-picker.component';\n\n@Directive({\n  selector: 'nz-range-picker',\n  exportAs: 'nzRangePicker'\n})\nexport class NzRangePickerComponent {\n  datePicker = inject(NzDatePickerComponent, { host: true });\n\n  constructor() {\n    this.datePicker.isRange = true;\n  }\n}\n"
  },
  {
    "path": "components/date-picker/standard-types.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { TemplateRef } from '@angular/core';\n\nexport type DisabledDateFn = (d: Date) => boolean;\n\nexport type DisabledTimePartial = 'start' | 'end';\n\nexport type NzDateMode = 'decade' | 'year' | 'quarter' | 'month' | 'week' | 'date' | 'time';\n\nexport type RangePartType = 'left' | 'right';\n\nexport type CompatibleDate = Date | Date[];\n\nexport type DisabledTimeFn = (current: Date | Date[], partial?: DisabledTimePartial) => DisabledTimeConfig | undefined;\n\nexport type NzPanelChangeType =\n  | { mode: NzDateMode; date: Date }\n  | {\n      mode: [startMode: NzDateMode, endMode: NzDateMode];\n      date: [startDate: Date, endDate: Date];\n    };\n\nexport interface DisabledTimeConfig {\n  nzDisabledHours(): number[];\n\n  nzDisabledMinutes(hour: number): number[];\n\n  nzDisabledSeconds(hour: number, minute: number): number[];\n}\n\nexport interface SupportTimeOptions {\n  nzFormat?: string;\n  nzHourStep?: number;\n  nzMinuteStep?: number;\n  nzSecondStep?: number;\n\n  nzDisabledHours?(): number[];\n\n  nzDisabledMinutes?(hour: number): number[];\n\n  nzDisabledSeconds?(hour: number, minute: number): number[];\n\n  nzHideDisabledOptions?: boolean;\n  nzDefaultOpenValue?: Date;\n  nzAddOn?: TemplateRef<void>;\n  nzUse12Hours?: boolean;\n}\n\nexport interface PresetRanges {\n  [key: string]: Date[] | (() => Date[]);\n}\n"
  },
  {
    "path": "components/date-picker/style/Calendar.less",
    "content": ".calendarLeftArrow() {\n  height: 100%;\n\n  &::before,\n  &::after {\n    position: relative;\n    top: -1px;\n    display: inline-block;\n    width: 8px;\n    height: 8px;\n    vertical-align: middle;\n    border: 0 solid #aaa;\n    border-width: 1.5px 0 0 1.5px;\n    border-radius: 1px;\n    transform: rotate(-45deg) scale(0.8);\n    transition: all 0.3s;\n    content: '';\n  }\n\n  &:hover::before,\n  &:hover::after {\n    border-color: @text-color;\n  }\n\n  &::after {\n    display: none;\n  }\n}\n\n.calendarLeftDoubleArrow() {\n  .calendarLeftArrow;\n\n  &::after {\n    position: relative;\n    left: -3px;\n    display: inline-block;\n  }\n}\n\n.calendarRightArrow() {\n  .calendarLeftArrow;\n\n  &::before,\n  &::after {\n    transform: rotate(135deg) scale(0.8);\n  }\n}\n\n.calendarRightDoubleArrow() {\n  .calendarRightArrow;\n\n  &::before {\n    position: relative;\n    left: 3px;\n  }\n\n  &::after {\n    display: inline-block;\n  }\n}\n\n.calendarPanelHeader(@calendar-prefix-cls) {\n  height: 40px;\n  line-height: 40px;\n  text-align: center;\n  border-bottom: @border-width-base @border-style-base @border-color-split;\n  user-select: none;\n\n  a:hover {\n    color: @link-hover-color;\n  }\n\n  .@{calendar-prefix-cls}-century-select,\n  .@{calendar-prefix-cls}-decade-select,\n  .@{calendar-prefix-cls}-year-select,\n  .@{calendar-prefix-cls}-month-select {\n    display: inline-block;\n    padding: 0 2px;\n    color: @heading-color;\n    font-weight: 500;\n    line-height: 40px;\n  }\n\n  .@{calendar-prefix-cls}-century-select-arrow,\n  .@{calendar-prefix-cls}-decade-select-arrow,\n  .@{calendar-prefix-cls}-year-select-arrow,\n  .@{calendar-prefix-cls}-month-select-arrow {\n    display: none;\n  }\n\n  .@{calendar-prefix-cls}-prev-century-btn,\n  .@{calendar-prefix-cls}-next-century-btn,\n  .@{calendar-prefix-cls}-prev-decade-btn,\n  .@{calendar-prefix-cls}-next-decade-btn,\n  .@{calendar-prefix-cls}-prev-month-btn,\n  .@{calendar-prefix-cls}-next-month-btn,\n  .@{calendar-prefix-cls}-prev-year-btn,\n  .@{calendar-prefix-cls}-next-year-btn {\n    position: absolute;\n    top: 0;\n    display: inline-block;\n    padding: 0 5px;\n    color: @text-color-secondary;\n    font-size: 16px;\n    font-family: Arial, 'Hiragino Sans GB', 'Microsoft Yahei', 'Microsoft Sans Serif', sans-serif;\n    line-height: 40px;\n  }\n\n  .@{calendar-prefix-cls}-prev-century-btn,\n  .@{calendar-prefix-cls}-prev-decade-btn,\n  .@{calendar-prefix-cls}-prev-year-btn {\n    left: 7px;\n    .calendarLeftDoubleArrow;\n  }\n\n  .@{calendar-prefix-cls}-next-century-btn,\n  .@{calendar-prefix-cls}-next-decade-btn,\n  .@{calendar-prefix-cls}-next-year-btn {\n    right: 7px;\n    .calendarRightDoubleArrow;\n  }\n\n  .@{calendar-prefix-cls}-prev-month-btn {\n    left: 29px;\n    .calendarLeftArrow;\n  }\n\n  .@{calendar-prefix-cls}-next-month-btn {\n    right: 29px;\n    .calendarRightArrow;\n  }\n}\n\n.calendar-selected-cell() {\n  .@{calendar-prefix-cls}-date {\n    color: @text-color-inverse;\n    background: @primary-color;\n    border: @border-width-base @border-style-base transparent;\n\n    &:hover {\n      background: @primary-color;\n    }\n  }\n}\n\n.@{calendar-prefix-cls} {\n  position: relative;\n  width: 280px;\n  font-size: @font-size-base;\n  line-height: @line-height-base;\n  text-align: left;\n  list-style: none;\n  background-color: @component-background;\n  background-clip: padding-box;\n  border: @border-width-base @border-style-base @border-color-inverse;\n  border-radius: @border-radius-base;\n  outline: none;\n  box-shadow: @box-shadow-base;\n\n  &-input-wrap {\n    height: 34px;\n    padding: 6px @control-padding-horizontal - 2px;\n    border-bottom: @border-width-base @border-style-base @border-color-split;\n  }\n\n  &-input {\n    width: 100%;\n    height: 22px;\n    color: @input-color;\n    background: @input-bg;\n    border: 0;\n    outline: 0;\n    cursor: auto;\n    .placeholder;\n  }\n\n  &-week-number {\n    width: 286px;\n\n    &-cell {\n      text-align: center;\n    }\n  }\n\n  &-header {\n    .calendarPanelHeader(@calendar-prefix-cls);\n  }\n\n  &-body {\n    padding: 8px 12px;\n  }\n\n  table {\n    width: 100%;\n    max-width: 100%;\n    background-color: transparent;\n    border-collapse: collapse;\n  }\n\n  table,\n  th,\n  td {\n    text-align: center;\n    border: 0;\n  }\n\n  &-calendar-table {\n    margin-bottom: 0;\n    border-spacing: 0;\n  }\n\n  &-column-header {\n    width: 33px;\n    padding: 6px 0;\n    line-height: 18px;\n    text-align: center;\n    .@{calendar-prefix-cls}-column-header-inner {\n      display: block;\n      font-weight: normal;\n    }\n  }\n\n  &-week-number-header {\n    .@{calendar-prefix-cls}-column-header-inner {\n      display: none;\n    }\n  }\n\n  &-cell {\n    height: 30px;\n    padding: 3px 0;\n  }\n\n  &-date {\n    display: block;\n    width: 24px;\n    height: 24px;\n    margin: 0 auto;\n    padding: 0;\n    color: @text-color;\n    line-height: 22px;\n    text-align: center;\n    background: transparent;\n    border: @border-width-base @border-style-base transparent;\n    border-radius: @border-radius-sm;\n    transition: background 0.3s ease;\n\n    &-panel {\n      position: relative;\n      outline: none;\n    }\n\n    &:hover {\n      background: @item-hover-bg;\n      cursor: pointer;\n    }\n\n    &:active {\n      color: @text-color-inverse;\n      background: @primary-5;\n    }\n  }\n\n  &-today &-date {\n    color: @primary-color;\n    font-weight: bold;\n    border-color: @primary-color;\n  }\n\n  &-selected-day &-date {\n    background: @primary-2;\n  }\n\n  &-last-month-cell &-date,\n  &-next-month-btn-day &-date {\n    &,\n    &:hover {\n      color: @disabled-color;\n      background: transparent;\n      border-color: transparent;\n    }\n  }\n\n  &-disabled-cell &-date {\n    position: relative;\n    width: auto;\n    color: @disabled-color;\n    background: @disabled-bg;\n    border: @border-width-base @border-style-base transparent;\n    border-radius: 0;\n    cursor: not-allowed;\n\n    &:hover {\n      background: @disabled-bg;\n    }\n  }\n\n  &-disabled-cell&-selected-day &-date::before {\n    position: absolute;\n    top: -1px;\n    left: 5px;\n    width: 24px;\n    height: 24px;\n    background: rgba(0, 0, 0, 0.1);\n    border-radius: @border-radius-sm;\n    content: '';\n  }\n\n  &-disabled-cell&-today &-date {\n    position: relative;\n    padding-right: 5px;\n    padding-left: 5px;\n\n    &::before {\n      position: absolute;\n      top: -1px;\n      left: 5px;\n      width: 24px;\n      height: 24px;\n      border: @border-width-base @border-style-base @disabled-color;\n      border-radius: @border-radius-sm;\n      content: ' ';\n    }\n  }\n\n  &-disabled-cell-first-of-row &-date {\n    border-top-left-radius: 4px;\n    border-bottom-left-radius: 4px;\n  }\n\n  &-disabled-cell-last-of-row &-date {\n    border-top-right-radius: 4px;\n    border-bottom-right-radius: 4px;\n  }\n\n  &-footer {\n    padding: 0 12px;\n    line-height: 38px;\n    border-top: @border-width-base @border-style-base @border-color-split;\n\n    &:empty {\n      border-top: 0;\n    }\n\n    &-btn {\n      display: block;\n      text-align: center;\n    }\n\n    &-extra {\n      text-align: left;\n    }\n  }\n\n  .@{calendar-prefix-cls}-today-btn,\n  .@{calendar-prefix-cls}-clear-btn {\n    display: inline-block;\n    margin: 0 0 0 8px;\n    text-align: center;\n\n    &-disabled {\n      color: @disabled-color;\n      cursor: not-allowed;\n    }\n\n    &:only-child {\n      margin: 0;\n    }\n  }\n\n  .@{calendar-prefix-cls}-clear-btn {\n    position: absolute;\n    top: 7px;\n    right: 5px;\n    display: none;\n    width: 20px;\n    height: 20px;\n    margin: 0;\n    overflow: hidden;\n    line-height: 20px;\n    text-align: center;\n    text-indent: -76px;\n  }\n\n  .@{calendar-prefix-cls}-clear-btn::after {\n    display: inline-block;\n    width: 20px;\n    color: @disabled-color;\n    font-size: @font-size-base;\n    line-height: 1;\n    text-indent: 43px;\n    transition: color 0.3s ease;\n  }\n\n  .@{calendar-prefix-cls}-clear-btn:hover::after {\n    color: @text-color-secondary;\n  }\n\n  .@{calendar-prefix-cls}-ok-btn {\n    .btn;\n    .btn-primary;\n    .button-size(@btn-height-sm; @btn-padding-sm; @font-size-base; @border-radius-base);\n\n    line-height: @btn-height-sm - 2px;\n\n    .button-disabled();\n  }\n}\n"
  },
  {
    "path": "components/date-picker/style/DecadePanel.less",
    "content": ".@{calendar-prefix-cls}-decade-panel {\n  position: absolute;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: @zindex-picker-panel;\n  display: flex;\n  flex-direction: column;\n  background: @calendar-bg;\n  border-radius: @border-radius-base;\n  outline: none;\n}\n\n.@{calendar-prefix-cls}-decade-panel-hidden {\n  display: none;\n}\n\n.@{calendar-prefix-cls}-decade-panel-header {\n  position: relative;\n}\n\n.@{calendar-prefix-cls}-decade-panel-body {\n  flex: 1;\n}\n\n.@{calendar-prefix-cls}-decade-panel-footer {\n  border-top: @border-width-base @border-style-base @border-color-split;\n  .@{calendar-prefix-cls}-footer-extra {\n    padding: 0 12px;\n  }\n}\n\n.@{calendar-prefix-cls}-decade-panel-table {\n  width: 100%;\n  height: 100%;\n  table-layout: fixed;\n  border-collapse: separate;\n}\n\n.@{calendar-prefix-cls}-decade-panel-cell {\n  white-space: nowrap;\n  text-align: center;\n}\n\n.@{calendar-prefix-cls}-decade-panel-decade {\n  display: inline-block;\n  height: 24px;\n  margin: 0 auto;\n  padding: 0 6px;\n  color: @text-color;\n  line-height: 24px;\n  text-align: center;\n  background: transparent;\n  border-radius: @border-radius-base;\n  transition: background 0.3s ease;\n\n  &:hover {\n    background: @item-hover-bg;\n    cursor: pointer;\n  }\n}\n\n.@{calendar-prefix-cls}-decade-panel-selected-cell .@{calendar-prefix-cls}-decade-panel-decade {\n  color: @text-color-inverse;\n  background: @primary-color;\n\n  &:hover {\n    color: @text-color-inverse;\n    background: @primary-color;\n  }\n}\n\n.@{calendar-prefix-cls}-decade-panel-last-century-cell,\n.@{calendar-prefix-cls}-decade-panel-next-century-cell {\n  .@{calendar-prefix-cls}-decade-panel-decade {\n    color: @disabled-color;\n    user-select: none;\n  }\n}\n"
  },
  {
    "path": "components/date-picker/style/MonthPanel.less",
    "content": ".@{calendar-prefix-cls}-month-panel {\n  position: absolute;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: @zindex-picker-panel;\n  background: @component-background;\n  border-radius: @border-radius-base;\n  outline: none;\n\n  > div {\n    display: flex;\n    flex-direction: column;\n    // TODO: this is a useless wrapper, and we need to remove it in rc-calendar\n    height: 100%;\n  }\n}\n\n.@{calendar-prefix-cls}-month-panel-hidden {\n  display: none;\n}\n\n.@{calendar-prefix-cls}-month-panel-header {\n  .calendarPanelHeader(~'@{calendar-prefix-cls}-month-panel');\n  position: relative;\n}\n\n.@{calendar-prefix-cls}-month-panel-body {\n  flex: 1;\n}\n\n.@{calendar-prefix-cls}-month-panel-footer {\n  border-top: @border-width-base @border-style-base @border-color-split;\n  .@{calendar-prefix-cls}-footer-extra {\n    padding: 0 12px;\n  }\n}\n\n.@{calendar-prefix-cls}-month-panel-table {\n  width: 100%;\n  height: 100%;\n  table-layout: fixed;\n  border-collapse: separate;\n}\n\n.@{calendar-prefix-cls}-month-panel-selected-cell .@{calendar-prefix-cls}-month-panel-month {\n  color: @text-color-inverse;\n  background: @primary-color;\n\n  &:hover {\n    color: @text-color-inverse;\n    background: @primary-color;\n  }\n}\n\n.@{calendar-prefix-cls}-month-panel-cell {\n  text-align: center;\n\n  &-disabled .@{calendar-prefix-cls}-month-panel-month {\n    &,\n    &:hover {\n      color: @disabled-color;\n      background: @disabled-bg;\n      cursor: not-allowed;\n    }\n  }\n}\n\n.@{calendar-prefix-cls}-month-panel-month {\n  display: inline-block;\n  height: 24px;\n  margin: 0 auto;\n  padding: 0 8px;\n  color: @text-color;\n  line-height: 24px;\n  text-align: center;\n  background: transparent;\n  border-radius: @border-radius-sm;\n  transition: background 0.3s ease;\n\n  &:hover {\n    background: @item-hover-bg;\n    cursor: pointer;\n  }\n}\n"
  },
  {
    "path": "components/date-picker/style/MonthPicker.less",
    "content": ".@{calendar-prefix-cls}-month {\n  .@{calendar-prefix-cls}-month-header-wrap {\n    position: relative;\n    height: 288px;\n  }\n  .@{calendar-prefix-cls}-month-panel,\n  .@{calendar-prefix-cls}-year-panel {\n    top: 0;\n    height: 100%;\n  }\n}\n"
  },
  {
    "path": "components/date-picker/style/Picker.less",
    "content": "@import '../../button/style/mixin';\n\n.@{calendar-prefix-cls}-picker-container {\n  .reset-component;\n\n  position: absolute;\n  z-index: @zindex-picker;\n  font-family: @font-family;\n\n  &.slide-up-enter.slide-up-enter-active&-placement-topLeft,\n  &.slide-up-enter.slide-up-enter-active&-placement-topRight,\n  &.slide-up-appear.slide-up-appear-active&-placement-topLeft,\n  &.slide-up-appear.slide-up-appear-active&-placement-topRight {\n    animation-name: antSlideDownIn;\n  }\n\n  &.slide-up-enter.slide-up-enter-active&-placement-bottomLeft,\n  &.slide-up-enter.slide-up-enter-active&-placement-bottomRight,\n  &.slide-up-appear.slide-up-appear-active&-placement-bottomLeft,\n  &.slide-up-appear.slide-up-appear-active&-placement-bottomRight {\n    animation-name: antSlideUpIn;\n  }\n\n  &.slide-up-leave.slide-up-leave-active&-placement-topLeft,\n  &.slide-up-leave.slide-up-leave-active&-placement-topRight {\n    animation-name: antSlideDownOut;\n  }\n\n  &.slide-up-leave.slide-up-leave-active&-placement-bottomLeft,\n  &.slide-up-leave.slide-up-leave-active&-placement-bottomRight {\n    animation-name: antSlideUpOut;\n  }\n}\n\n.@{calendar-prefix-cls}-picker {\n  .reset-component;\n\n  position: relative;\n  display: inline-block;\n  outline: none;\n  cursor: text;\n  transition: opacity 0.3s;\n\n  &-input {\n    outline: none;\n\n    &.@{ant-prefix}-input {\n      line-height: @line-height-base;\n    }\n  }\n\n  &-input.@{ant-prefix}-input-sm {\n    padding-top: 0;\n    padding-bottom: 0;\n  }\n\n  &:hover &-input:not(.@{ant-prefix}-input-disabled) {\n    border-color: @input-hover-border-color;\n  }\n\n  &:focus &-input:not(.@{ant-prefix}-input-disabled) {\n    .active();\n  }\n\n  &-clear,\n  &-icon {\n    position: absolute;\n    top: 50%;\n    right: @control-padding-horizontal;\n    z-index: 1;\n    width: 14px;\n    height: 14px;\n    margin-top: -7px;\n    font-size: @font-size-sm;\n    line-height: 14px;\n    transition: all 0.3s;\n    user-select: none;\n  }\n\n  &-clear {\n    z-index: 2;\n    color: @disabled-color;\n    font-size: @font-size-base;\n    background: @input-bg;\n    cursor: pointer;\n    opacity: 0;\n    pointer-events: none;\n\n    &:hover {\n      color: @text-color-secondary;\n    }\n  }\n\n  &:hover &-clear {\n    opacity: 1;\n    pointer-events: auto;\n  }\n\n  &-icon {\n    display: inline-block;\n    color: @disabled-color;\n    font-size: @font-size-base;\n    line-height: 1;\n  }\n\n  &-small &-clear,\n  &-small &-icon {\n    right: @control-padding-horizontal-sm;\n  }\n}\n"
  },
  {
    "path": "components/date-picker/style/RangePicker.less",
    "content": "@input-box-height: 34px;\n\n.@{calendar-prefix-cls}-range-picker-input {\n  width: 44%;\n  height: 99%;\n  text-align: center;\n  background-color: transparent;\n  border: 0;\n  outline: 0;\n  .placeholder();\n\n  &[disabled] {\n    cursor: not-allowed;\n  }\n}\n\n.@{calendar-prefix-cls}-range-picker-separator {\n  display: inline-block;\n  min-width: 10px;\n  height: 100%;\n  color: @text-color-secondary;\n  white-space: nowrap;\n  text-align: center;\n  vertical-align: top;\n  pointer-events: none;\n}\n\n.@{calendar-prefix-cls}-range {\n  width: 552px;\n  overflow: hidden;\n\n  .@{calendar-prefix-cls}-date-panel {\n    &::after {\n      display: block;\n      clear: both;\n      height: 0;\n      visibility: hidden;\n      content: '.';\n    }\n  }\n\n  &-part {\n    position: relative;\n    width: 50%;\n  }\n\n  &-left {\n    float: left;\n    .@{calendar-prefix-cls} {\n      &-time-picker-inner {\n        border-right: 1px solid @border-color-split;\n      }\n    }\n  }\n\n  &-right {\n    float: right;\n    .@{calendar-prefix-cls} {\n      &-time-picker-inner {\n        border-left: 1px solid @border-color-split;\n      }\n    }\n  }\n\n  &-middle {\n    position: absolute;\n    left: 50%;\n    z-index: 1;\n    height: @input-box-height;\n    margin: 1px 0 0;\n    padding: 0 200px 0 0;\n    color: @text-color-secondary;\n    line-height: @input-box-height;\n    text-align: center;\n    transform: translateX(-50%);\n    pointer-events: none;\n  }\n\n  &-right .@{calendar-prefix-cls}-date-input-wrap {\n    margin-left: -90px;\n  }\n\n  &.@{calendar-prefix-cls}-time &-middle {\n    padding: 0 10px 0 0;\n    transform: translateX(-50%);\n  }\n\n  .@{calendar-prefix-cls}-today\n    :not(.@{calendar-prefix-cls}-disabled-cell)\n    :not(.@{calendar-prefix-cls}-last-month-cell)\n    :not(.@{calendar-prefix-cls}-next-month-btn-day) {\n    .@{calendar-prefix-cls}-date {\n      color: @primary-color;\n      background: @primary-2;\n      border-color: @primary-color;\n    }\n  }\n\n  .@{calendar-prefix-cls}-selected-start-date,\n  .@{calendar-prefix-cls}-selected-end-date {\n    .calendar-selected-cell;\n  }\n\n  &.@{calendar-prefix-cls}-time &-right .@{calendar-prefix-cls}-date-input-wrap {\n    margin-left: 0;\n  }\n\n  .@{calendar-prefix-cls}-input-wrap {\n    position: relative;\n    height: @input-box-height;\n  }\n\n  .@{calendar-prefix-cls}-input,\n  .@{calendar-timepicker-prefix-cls}-input {\n    .input;\n    height: @input-height-sm;\n    padding-right: 0;\n    padding-left: 0;\n    line-height: @input-height-sm;\n    border: 0;\n    box-shadow: none;\n\n    &:focus {\n      box-shadow: none;\n    }\n  }\n\n  .@{calendar-timepicker-prefix-cls}-icon {\n    display: none;\n  }\n\n  &.@{calendar-prefix-cls}-week-number {\n    width: 574px;\n\n    .@{calendar-prefix-cls}-range-part {\n      width: 286px;\n    }\n  }\n\n  .@{calendar-prefix-cls}-year-panel,\n  .@{calendar-prefix-cls}-month-panel,\n  .@{calendar-prefix-cls}-decade-panel {\n    top: @input-box-height;\n  }\n  .@{calendar-prefix-cls}-month-panel .@{calendar-prefix-cls}-year-panel {\n    top: 0;\n  }\n  .@{calendar-prefix-cls}-decade-panel-table,\n  .@{calendar-prefix-cls}-year-panel-table,\n  .@{calendar-prefix-cls}-month-panel-table {\n    height: 208px;\n  }\n\n  .@{calendar-prefix-cls}-in-range-cell {\n    position: relative;\n    border-radius: 0;\n\n    > div {\n      position: relative;\n      z-index: 1;\n    }\n\n    &::before {\n      position: absolute;\n      top: 4px;\n      right: 0;\n      bottom: 4px;\n      left: 0;\n      display: block;\n      background: @item-active-bg;\n      border: 0;\n      border-radius: 0;\n      content: '';\n    }\n  }\n\n  .@{calendar-prefix-cls}-footer-extra {\n    float: left;\n  }\n\n  // `div` for selector specificity\n  div&-quick-selector {\n    text-align: left;\n\n    > a {\n      margin-right: 8px;\n    }\n  }\n\n  .@{calendar-prefix-cls},\n  .@{calendar-prefix-cls}-month-panel,\n  .@{calendar-prefix-cls}-year-panel,\n  .@{calendar-prefix-cls}-decade-panel {\n    &-header {\n      border-bottom: 0;\n    }\n\n    &-body {\n      border-top: @border-width-base @border-style-base @border-color-split;\n    }\n  }\n\n  &.@{calendar-prefix-cls}-time {\n    .@{calendar-timepicker-prefix-cls} {\n      top: 68px;\n      z-index: 2; // cover .ant-calendar-range .ant-calendar-in-range-cell > div (z-index: 1)\n      width: 100%;\n      height: 207px;\n\n      &-panel {\n        height: 267px;\n        margin-top: -34px;\n      }\n\n      &-inner {\n        height: 100%;\n        padding-top: 40px;\n        background: none;\n      }\n\n      &-combobox {\n        display: inline-block;\n        height: 100%;\n        background-color: @component-background;\n        border-top: @border-width-base @border-style-base @border-color-split;\n      }\n\n      &-select {\n        height: 100%;\n\n        ul {\n          max-height: 100%;\n        }\n      }\n    }\n    .@{calendar-prefix-cls}-footer .@{calendar-prefix-cls}-time-picker-btn {\n      margin-right: 8px;\n    }\n    .@{calendar-prefix-cls}-today-btn {\n      height: 22px;\n      margin: 8px 12px;\n      line-height: 22px;\n    }\n  }\n\n  &-with-ranges.@{calendar-prefix-cls}-time .@{calendar-timepicker-prefix-cls} {\n    height: 233px;\n  }\n}\n\n.@{calendar-prefix-cls}-range.@{calendar-prefix-cls}-show-time-picker {\n  .@{calendar-prefix-cls}-body {\n    border-top-color: transparent;\n  }\n}\n"
  },
  {
    "path": "components/date-picker/style/TimePicker.less",
    "content": ".@{calendar-timepicker-prefix-cls} {\n  position: absolute;\n  top: 40px;\n  width: 100%;\n  background-color: @component-background;\n\n  &-panel {\n    position: absolute;\n    z-index: @zindex-picker;\n    width: 100%;\n  }\n\n  &-inner {\n    position: relative;\n    display: inline-block;\n    width: 100%;\n    overflow: hidden;\n    font-size: @font-size-base;\n    line-height: 1.5;\n    text-align: left;\n    list-style: none;\n    background-color: @component-background;\n    background-clip: padding-box;\n    outline: none;\n  }\n\n  &-combobox {\n    width: 100%;\n  }\n\n  &-column-1,\n  &-column-1 &-select {\n    width: 100%;\n  }\n\n  &-column-2 &-select {\n    width: 50%;\n  }\n\n  &-column-3 &-select {\n    width: 33.33%;\n  }\n\n  &-column-4 &-select {\n    width: 25%;\n  }\n\n  &-input-wrap {\n    display: none;\n  }\n\n  &-select {\n    position: relative; // Fix chrome weird render bug\n    float: left;\n    height: 226px;\n    overflow: hidden;\n    font-size: @font-size-base;\n    border-right: @border-width-base @border-style-base @border-color-split;\n\n    &:hover {\n      overflow-y: auto;\n    }\n\n    &:first-child {\n      margin-left: 0;\n      border-left: 0;\n    }\n\n    &:last-child {\n      border-right: 0;\n    }\n\n    ul {\n      width: 100%;\n      max-height: 206px;\n      margin: 0;\n      padding: 0;\n      list-style: none;\n    }\n\n    li {\n      width: 100%;\n      height: 24px;\n      margin: 0;\n      line-height: 24px;\n      text-align: center;\n      list-style: none;\n      cursor: pointer;\n      transition: all .3s;\n      user-select: none;\n\n      &:last-child::after {\n        display: block;\n        height: 202px;\n        content: '';\n      }\n\n      &:hover {\n        background: @item-hover-bg;\n      }\n\n      &:focus {\n        color: @primary-color;\n        font-weight: 600;\n        outline: none;\n      }\n    }\n\n    li&-option-selected {\n      font-weight: 600;\n      background: @time-picker-selected-bg;\n    }\n\n    li&-option-disabled {\n      color: @btn-disable-color;\n\n      &:hover {\n        background: transparent;\n        cursor: not-allowed;\n      }\n    }\n  }\n}\n\n.@{calendar-prefix-cls}-time {\n  .@{calendar-prefix-cls}-day-select {\n    display: inline-block;\n    padding: 0 2px;\n    color: @heading-color;\n    font-weight: 500;\n    line-height: 34px;\n  }\n\n  .@{calendar-prefix-cls}-footer {\n    position: relative;\n    height: auto;\n\n    &-btn {\n      text-align: right;\n    }\n\n    .@{calendar-prefix-cls}-today-btn {\n      float: left;\n      margin: 0;\n    }\n\n    .@{calendar-prefix-cls}-time-picker-btn {\n      display: inline-block;\n      margin-right: 8px;\n\n      &-disabled {\n        color: @disabled-color;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/date-picker/style/WeekPicker.less",
    "content": ".@{calendar-prefix-cls}-week-number {\n  &-cell {\n    opacity: 0.5;\n  }\n  .@{calendar-prefix-cls}-body tr {\n    cursor: pointer;\n    transition: all 0.3s;\n\n    &:hover {\n      background: @primary-1;\n    }\n    &.@{calendar-prefix-cls}-active-week {\n      font-weight: bold;\n      background: @primary-2;\n    }\n    .@{calendar-prefix-cls}-selected-day .@{calendar-prefix-cls}-date,\n    .@{calendar-prefix-cls}-selected-day:hover .@{calendar-prefix-cls}-date {\n      color: @text-color;\n      background: transparent;\n    }\n  }\n}\n"
  },
  {
    "path": "components/date-picker/style/YearPanel.less",
    "content": ".@{calendar-prefix-cls}-year-panel {\n  position: absolute;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: @zindex-picker-panel;\n  background: @component-background;\n  border-radius: @border-radius-base;\n  outline: none;\n\n  > div {\n    display: flex;\n    flex-direction: column;\n    // TODO: this is a useless wrapper, and we need to remove it in rc-calendar\n    height: 100%;\n  }\n}\n\n.@{calendar-prefix-cls}-year-panel-hidden {\n  display: none;\n}\n\n.@{calendar-prefix-cls}-year-panel-header {\n  .calendarPanelHeader(~'@{calendar-prefix-cls}-year-panel');\n  position: relative;\n}\n\n.@{calendar-prefix-cls}-year-panel-body {\n  flex: 1;\n}\n\n.@{calendar-prefix-cls}-year-panel-footer {\n  border-top: @border-width-base @border-style-base @border-color-split;\n  .@{calendar-prefix-cls}-footer-extra {\n    padding: 0 12px;\n  }\n}\n\n.@{calendar-prefix-cls}-year-panel-table {\n  width: 100%;\n  height: 100%;\n  table-layout: fixed;\n  border-collapse: separate;\n}\n\n.@{calendar-prefix-cls}-year-panel-cell {\n  text-align: center;\n}\n\n.@{calendar-prefix-cls}-year-panel-year {\n  display: inline-block;\n  height: 24px;\n  margin: 0 auto;\n  padding: 0 8px;\n  color: @text-color;\n  line-height: 24px;\n  text-align: center;\n  background: transparent;\n  border-radius: @border-radius-sm;\n  transition: background 0.3s ease;\n\n  &:hover {\n    background: @item-hover-bg;\n    cursor: pointer;\n  }\n}\n\n.@{calendar-prefix-cls}-year-panel-selected-cell .@{calendar-prefix-cls}-year-panel-year {\n  color: @text-color-inverse;\n  background: @primary-color;\n\n  &:hover {\n    color: @text-color-inverse;\n    background: @primary-color;\n  }\n}\n\n.@{calendar-prefix-cls}-year-panel-last-decade-cell,\n.@{calendar-prefix-cls}-year-panel-next-decade-cell {\n  .@{calendar-prefix-cls}-year-panel-year {\n    color: @disabled-color;\n    user-select: none;\n  }\n}\n"
  },
  {
    "path": "components/date-picker/style/entry.less",
    "content": "@import './index.less';\n@import './patch.less';\n// style dependencies\n// deps-lint-skip: input\n@import '../../input/style/entry.less';\n@import '../../time-picker/style/entry.less';\n@import '../../tag/style/entry.less';\n"
  },
  {
    "path": "components/date-picker/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import '../../input/style/mixin';\n@import './status';\n\n@picker-prefix-cls: ~'@{ant-prefix}-picker';\n\n.picker-padding(@input-height, @font-size, @padding-horizontal) {\n  // font height probably 22.0001， So use floor better\n  @font-height: floor(@font-size * @line-height-base) + 2;\n  @padding-top: max(((@input-height - @font-height) / 2), 0);\n  @padding-bottom: max(@input-height - @font-height - @padding-top, 0);\n  padding: @padding-top @padding-horizontal @padding-bottom;\n}\n\n.@{picker-prefix-cls} {\n  @arrow-size: @popover-arrow-width;\n\n  .reset-component();\n  .picker-padding(@input-height-base, @font-size-base, @input-padding-horizontal-base);\n  position: relative;\n  display: inline-flex;\n  align-items: center;\n  background: @picker-bg;\n  border: @border-width-base @border-style-base @select-border-color;\n  border-radius: @control-border-radius;\n  transition:\n    border @animation-duration-slow,\n    box-shadow @animation-duration-slow;\n\n  &:hover,\n  &-focused {\n    .hover();\n  }\n\n  &-focused {\n    .active();\n  }\n\n  &&-disabled {\n    background: @input-disabled-bg;\n    border-color: @select-border-color;\n    cursor: not-allowed;\n  }\n\n  &&-disabled &-suffix {\n    color: @disabled-color;\n  }\n\n  &&-borderless {\n    background-color: transparent;\n    border-color: transparent;\n    box-shadow: none;\n  }\n\n  // filled style\n  &&-filled {\n    background-color: @input-variant-filled-bg;\n    border-color: transparent;\n    box-shadow: none;\n  }\n\n  &&-filled:hover {\n    background-color: @input-variant-filled-hover-bg;\n    border-color: transparent;\n    box-shadow: none;\n  }\n\n  &&-filled:focus,\n  &&-filled&-focused {\n    .active();\n    background-color: transparent;\n    box-shadow: none;\n  }\n\n  &&-filled&-disabled,\n  &&-filled&[disabled] {\n    .disabled();\n  }\n\n  // underlined style\n  &&-underlined,\n  &&-underlined:hover,\n  &&-underlined:focus,\n  &&-underlined&-focused,\n  &&-underlined&-disabled,\n  &&-underlined&[disabled] {\n    background-color: transparent;\n    border-width: 0 0 @border-width-base;\n    border-radius: 0;\n    box-shadow: none;\n  }\n\n  &&-underlined:hover:not(&-focused):not(:focus) {\n    border-color: @input-border-color;\n  }\n\n  // ======================== Input =========================\n  &-input {\n    position: relative;\n    display: inline-flex;\n    align-items: center;\n    width: 100%;\n\n    > input {\n      .input();\n      flex: auto;\n\n      // Fix Firefox flex not correct:\n      // https://github.com/ant-design/ant-design/pull/20023#issuecomment-564389553\n      min-width: 1px;\n      height: auto;\n      padding: 0;\n      background: transparent;\n\n      border: 0;\n\n      &:focus {\n        box-shadow: none;\n      }\n\n      &[disabled] {\n        background: transparent;\n      }\n    }\n\n    &:hover {\n      .@{picker-prefix-cls}-clear {\n        opacity: 1;\n      }\n    }\n\n    &-placeholder {\n      > input {\n        color: @input-placeholder-color;\n      }\n    }\n  }\n\n  // Size\n  &-large {\n    .picker-padding(@input-height-lg, @font-size-lg, @input-padding-horizontal-lg);\n\n    .@{picker-prefix-cls}-input > input {\n      font-size: @font-size-lg;\n    }\n  }\n\n  &-small {\n    .picker-padding(@input-height-sm, @font-size-base, @input-padding-horizontal-sm);\n  }\n\n  &-prefix {\n    flex: 0 0 auto;\n    margin-right: (@padding-xs / 2);\n  }\n\n  &-suffix {\n    display: flex;\n    flex: none;\n    align-self: center;\n    margin-left: (@padding-xs / 2);\n    color: @disabled-color;\n    line-height: 1;\n    pointer-events: none;\n\n    > * {\n      vertical-align: top;\n\n      &:not(:last-child) {\n        margin-right: 8px;\n      }\n    }\n  }\n\n  &-clear {\n    position: absolute;\n    top: 50%;\n    right: 0;\n    color: @disabled-color;\n    line-height: 1;\n    background: @component-background;\n    transform: translateY(-50%);\n    cursor: pointer;\n    opacity: 0;\n    transition:\n      opacity @animation-duration-slow,\n      color @animation-duration-slow;\n\n    > * {\n      vertical-align: top;\n    }\n\n    &:hover {\n      color: @text-color-secondary;\n    }\n  }\n\n  &-separator {\n    position: relative;\n    display: inline-block;\n    width: 1em;\n    height: @font-size-lg;\n    color: @disabled-color;\n    font-size: @font-size-lg;\n    vertical-align: top;\n    cursor: default;\n\n    .@{picker-prefix-cls}-focused & {\n      color: @text-color-secondary;\n    }\n\n    .@{picker-prefix-cls}-range-separator & {\n      .@{picker-prefix-cls}-disabled & {\n        cursor: not-allowed;\n      }\n    }\n  }\n\n  // ======================== Range =========================\n  &-range {\n    position: relative;\n    display: inline-flex;\n\n    // Clear\n    .@{picker-prefix-cls}-clear {\n      right: @input-padding-horizontal-base;\n    }\n\n    &:hover {\n      .@{picker-prefix-cls}-clear {\n        opacity: 1;\n      }\n    }\n\n    // Active bar\n    .@{picker-prefix-cls}-active-bar {\n      bottom: -@border-width-base;\n      height: 2px;\n      margin-left: @input-padding-horizontal-base;\n      background: @primary-color;\n      opacity: 0;\n      transition: all @animation-duration-slow ease-out;\n      pointer-events: none;\n    }\n\n    &.@{picker-prefix-cls}-focused {\n      .@{picker-prefix-cls}-active-bar {\n        opacity: 1;\n      }\n    }\n\n    &-separator {\n      align-items: center;\n      padding: 0 @padding-xs;\n      line-height: 1;\n    }\n\n    &.@{picker-prefix-cls}-small {\n      .@{picker-prefix-cls}-clear {\n        right: @input-padding-horizontal-sm;\n      }\n\n      .@{picker-prefix-cls}-active-bar {\n        margin-left: @input-padding-horizontal-sm;\n      }\n    }\n  }\n\n  // ======================= Dropdown =======================\n  &-dropdown {\n    .reset-component();\n\n    --antd-arrow-background-color: @calendar-bg;\n\n    position: absolute;\n    // Fix incorrect position of picker popup\n    // https://github.com/ant-design/ant-design/issues/35590\n    top: -9999px;\n    left: -9999px;\n    z-index: @zindex-picker;\n\n    &-hidden {\n      display: none;\n    }\n\n    &-placement-bottomLeft,\n    &-placement-bottomRight {\n      .@{picker-prefix-cls}-range-arrow {\n        top: 0;\n        display: block;\n        transform: translateY(-100%);\n      }\n    }\n\n    &-placement-topLeft,\n    &-placement-topRight {\n      .@{picker-prefix-cls}-range-arrow {\n        bottom: 0;\n        display: block;\n        transform: translateY(100%) rotate(180deg);\n      }\n    }\n\n    &.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-topLeft,\n    &.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-topRight,\n    &.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-topLeft,\n    &.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-topRight {\n      animation-name: antSlideDownIn;\n    }\n\n    &.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-bottomLeft,\n    &.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-bottomRight,\n    &.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-bottomLeft,\n    &.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-bottomRight {\n      animation-name: antSlideUpIn;\n    }\n\n    &.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-topLeft,\n    &.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-topRight {\n      animation-name: antSlideDownOut;\n    }\n\n    &.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-bottomLeft,\n    &.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-bottomRight {\n      animation-name: antSlideUpOut;\n    }\n  }\n\n  &-dropdown-range {\n    margin-block: (@arrow-size * 2 / 3);\n\n    &-hidden {\n      display: none;\n    }\n  }\n\n  // Time picker with additional style\n  &-dropdown &-panel > &-time-panel {\n    padding-top: (@padding-xs / 2);\n  }\n\n  // ======================== Ranges ========================\n  &-ranges {\n    margin-bottom: 0;\n    padding: (@padding-xs / 2) @padding-sm;\n    overflow: hidden;\n    line-height: @picker-text-height - 2 * @border-width-base - (@padding-xs / 2);\n    text-align: left;\n    list-style: none;\n\n    > li {\n      display: inline-block;\n    }\n\n    // https://github.com/ant-design/ant-design/issues/23687\n    .@{picker-prefix-cls}-preset > .@{ant-prefix}-tag-blue {\n      color: @primary-color;\n      background: @primary-1;\n      border-color: @primary-3;\n      cursor: pointer;\n    }\n\n    .@{picker-prefix-cls}-ok {\n      float: right;\n      margin-left: @padding-xs;\n    }\n  }\n\n  &-range-wrapper {\n    display: flex;\n  }\n\n  &-range-arrow {\n    position: absolute;\n    z-index: 1;\n    box-sizing: content-box;\n    margin-left: @input-padding-horizontal-base * 1.5;\n    transition: left @animation-duration-slow ease-out;\n    .roundedArrow(@arrow-size, 4px, @arrow-border-radius, var(--antd-arrow-background-color), @popover-arrow-box-shadow);\n  }\n\n  &-panel-container {\n    overflow: hidden;\n    vertical-align: top;\n    background: @calendar-bg;\n    border-radius: @border-radius-base;\n    box-shadow: @box-shadow-base;\n    transition: margin @animation-duration-slow;\n\n    .@{picker-prefix-cls}-panels {\n      display: inline-flex;\n      flex-wrap: nowrap;\n      direction: ltr;\n    }\n\n    .@{picker-prefix-cls}-panel {\n      vertical-align: top;\n      background: transparent;\n      border: none;\n      border-radius: 0;\n\n      .@{picker-prefix-cls}-content,\n      table {\n        text-align: center;\n      }\n    }\n  }\n\n  // ===================== Compact Item Styles =====================\n  .compact-item(@picker-prefix-cls, null, ~'@{picker-prefix-cls}-focused');\n}\n\n@import './panel';\n@import './rtl';\n"
  },
  {
    "path": "components/date-picker/style/panel.less",
    "content": "@picker-cell-inner-cls: ~'@{picker-prefix-cls}-cell-inner';\n\n.@{picker-prefix-cls} {\n  @picker-arrow-size: 7px;\n  @picker-year-month-cell-width: 60px;\n  @picker-panel-width: @picker-panel-cell-width * 7 + @padding-sm * 2 + 4;\n\n  &-panel {\n    display: inline-flex;\n    flex-direction: column;\n    text-align: center;\n    background: @calendar-bg;\n    border: @border-width-base @border-style-base @picker-border-color;\n    border-radius: @border-radius-base;\n    outline: none;\n\n    &-focused {\n      border-color: @primary-color;\n    }\n  }\n\n  // ========================================================\n  // =                     Shared Panel                     =\n  // ========================================================\n  &-decade-panel,\n  &-year-panel,\n  &-quarter-panel,\n  &-month-panel,\n  &-week-panel,\n  &-date-panel,\n  &-time-panel {\n    display: flex;\n    flex-direction: column;\n    width: @picker-panel-width;\n  }\n\n  // ======================= Header =======================\n  &-header {\n    display: flex;\n    padding: 0 @padding-xs;\n    color: @heading-color;\n    border-bottom: @border-width-base @border-style-base @picker-border-color;\n\n    > * {\n      flex: none;\n    }\n\n    button {\n      padding: 0;\n      color: @disabled-color;\n      line-height: @picker-text-height;\n      background: transparent;\n      border: 0;\n      cursor: pointer;\n      transition: color @animation-duration-slow;\n    }\n\n    > button {\n      min-width: 1.6em;\n      font-size: @font-size-base;\n\n      &:hover {\n        color: @text-color;\n      }\n    }\n\n    &-view {\n      flex: auto;\n      font-weight: 500;\n      line-height: @picker-text-height;\n\n      button {\n        color: inherit;\n        font-weight: inherit;\n\n        &:not(:first-child) {\n          margin-left: @padding-xs;\n        }\n\n        &:hover {\n          color: @primary-color;\n        }\n      }\n    }\n  }\n\n  // Arrow button\n  &-prev-icon,\n  &-next-icon,\n  &-super-prev-icon,\n  &-super-next-icon {\n    position: relative;\n    display: inline-block;\n    width: @picker-arrow-size;\n    height: @picker-arrow-size;\n\n    &::before {\n      position: absolute;\n      top: 0;\n      left: 0;\n      display: inline-block;\n      width: @picker-arrow-size;\n      height: @picker-arrow-size;\n      border: 0 solid currentcolor;\n      border-width: 1.5px 0 0 1.5px;\n      content: '';\n    }\n  }\n\n  &-super-prev-icon,\n  &-super-next-icon {\n    &::after {\n      position: absolute;\n      top: ceil((@picker-arrow-size / 2));\n      left: ceil((@picker-arrow-size / 2));\n      display: inline-block;\n      width: @picker-arrow-size;\n      height: @picker-arrow-size;\n      border: 0 solid currentcolor;\n      border-width: 1.5px 0 0 1.5px;\n      content: '';\n    }\n  }\n\n  &-prev-icon,\n  &-super-prev-icon {\n    transform: rotate(-45deg);\n  }\n\n  &-next-icon,\n  &-super-next-icon {\n    transform: rotate(135deg);\n  }\n\n  // ======================== Body ========================\n  &-content {\n    width: 100%;\n    table-layout: fixed;\n    border-collapse: collapse;\n\n    th,\n    td {\n      position: relative;\n      min-width: 24px;\n      font-weight: 400;\n    }\n\n    th {\n      height: 30px;\n      color: @text-color;\n      line-height: 30px;\n    }\n  }\n\n  .picker-cell-inner(@cellClassName) {\n    &::before {\n      position: absolute;\n      top: 50%;\n      right: 0;\n      left: 0;\n      z-index: 1;\n      height: @picker-panel-cell-height;\n      transform: translateY(-50%);\n      transition: all @animation-duration-slow;\n      content: '';\n    }\n\n    // >>> Default\n    .@{cellClassName} {\n      position: relative;\n      z-index: 2;\n      display: inline-block;\n      min-width: @picker-panel-cell-height;\n      height: @picker-panel-cell-height;\n      line-height: @picker-panel-cell-height;\n      border-radius: @border-radius-base;\n      transition: background @animation-duration-slow, border @animation-duration-slow;\n    }\n\n    // >>> Hover\n    &:hover:not(&-in-view),\n    &:hover:not(&-selected):not(&-range-start):not(&-range-end):not(&-range-hover-start):not(&-range-hover-end) {\n      .@{cellClassName} {\n        background: @picker-basic-cell-hover-color;\n      }\n    }\n\n    // >>> Today\n    &-in-view&-today .@{cellClassName} {\n      &::before {\n        position: absolute;\n        top: 0;\n        right: 0;\n        bottom: 0;\n        left: 0;\n        z-index: 1;\n        border: @border-width-base @border-style-base @primary-color;\n        border-radius: @border-radius-base;\n        content: '';\n      }\n    }\n\n    // >>> In Range\n    &-in-view&-in-range {\n      position: relative;\n\n      &::before {\n        background: @picker-basic-cell-active-with-range-color;\n      }\n    }\n\n    // >>> Selected\n    &-in-view&-selected .@{cellClassName},\n    &-in-view&-range-start .@{cellClassName},\n    &-in-view&-range-end .@{cellClassName} {\n      color: @text-color-inverse;\n      background: @primary-color;\n    }\n\n    &-in-view&-range-start:not(&-range-start-single),\n    &-in-view&-range-end:not(&-range-end-single) {\n      &::before {\n        background: @picker-basic-cell-active-with-range-color;\n      }\n    }\n\n    &-in-view&-range-start::before {\n      left: 50%;\n    }\n\n    &-in-view&-range-end::before {\n      right: 50%;\n    }\n\n    // >>> Range Hover\n    &-in-view&-range-hover-start:not(&-in-range):not(&-range-start):not(&-range-end),\n    &-in-view&-range-hover-end:not(&-in-range):not(&-range-start):not(&-range-end),\n    &-in-view&-range-hover-start&-range-start-single,\n    &-in-view&-range-hover-start&-range-start&-range-end&-range-end-near-hover,\n    &-in-view&-range-hover-end&-range-start&-range-end&-range-start-near-hover,\n    &-in-view&-range-hover-end&-range-end-single,\n    &-in-view&-range-hover:not(&-in-range) {\n      &::after {\n        position: absolute;\n        top: 50%;\n        z-index: 0;\n        height: 24px;\n        border-top: @border-width-base dashed @picker-date-hover-range-border-color;\n        border-bottom: @border-width-base dashed @picker-date-hover-range-border-color;\n        transform: translateY(-50%);\n        transition: all @animation-duration-slow;\n        content: '';\n      }\n    }\n\n    // Add space for stash\n    &-range-hover-start::after,\n    &-range-hover-end::after,\n    &-range-hover::after {\n      right: 0;\n      left: 2px;\n    }\n\n    // Hover with in range\n    &-in-view&-in-range&-range-hover::before,\n    &-in-view&-range-start&-range-hover::before,\n    &-in-view&-range-end&-range-hover::before,\n    &-in-view&-range-start:not(&-range-start-single)&-range-hover-start::before,\n    &-in-view&-range-end:not(&-range-end-single)&-range-hover-end::before,\n    .@{picker-prefix-cls}-panel\n      > :not(.@{picker-prefix-cls}-date-panel)\n      &-in-view&-in-range&-range-hover-start::before,\n    .@{picker-prefix-cls}-panel\n      > :not(.@{picker-prefix-cls}-date-panel)\n      &-in-view&-in-range&-range-hover-end::before {\n      background: @picker-date-hover-range-color;\n    }\n\n    // range start border-radius\n    &-in-view&-range-start:not(&-range-start-single):not(&-range-end) .@{cellClassName} {\n      border-radius: @border-radius-base 0 0 @border-radius-base;\n    }\n\n    // range end border-radius\n    &-in-view&-range-end:not(&-range-end-single):not(&-range-start) .@{cellClassName} {\n      border-radius: 0 @border-radius-base @border-radius-base 0;\n    }\n\n    // DatePanel only\n    .@{picker-prefix-cls}-date-panel &-in-view&-in-range&-range-hover-start .@{cellClassName},\n    .@{picker-prefix-cls}-date-panel &-in-view&-in-range&-range-hover-end .@{cellClassName} {\n      &::after {\n        position: absolute;\n        top: 0;\n        bottom: 0;\n        z-index: -1;\n        background: @picker-date-hover-range-color;\n        transition: all @animation-duration-slow;\n        content: '';\n      }\n    }\n\n    .@{picker-prefix-cls}-date-panel\n      &-in-view&-in-range&-range-hover-start\n      .@{cellClassName}::after {\n      right: -5px - @border-width-base;\n      left: 0;\n    }\n\n    .@{picker-prefix-cls}-date-panel &-in-view&-in-range&-range-hover-end .@{cellClassName}::after {\n      right: 0;\n      left: -5px - @border-width-base;\n    }\n\n    // Hover with range start & end\n    &-range-hover&-range-start::after {\n      right: 50%;\n    }\n\n    &-range-hover&-range-end::after {\n      left: 50%;\n    }\n\n    // Edge start\n    tr > &-in-view&-range-hover:first-child::after,\n    tr > &-in-view&-range-hover-end:first-child::after,\n    &-in-view&-start&-range-hover-edge-start&-range-hover-edge-start-near-range::after,\n    &-in-view&-range-hover-edge-start:not(&-range-hover-edge-start-near-range)::after,\n    &-in-view&-range-hover-start::after {\n      left: 6px;\n      border-left: @border-width-base dashed @picker-date-hover-range-border-color;\n      border-top-left-radius: @border-radius-base;\n      border-bottom-left-radius: @border-radius-base;\n    }\n\n    // Edge end\n    tr > &-in-view&-range-hover:last-child::after,\n    tr > &-in-view&-range-hover-start:last-child::after,\n    &-in-view&-end&-range-hover-edge-end&-range-hover-edge-end-near-range::after,\n    &-in-view&-range-hover-edge-end:not(&-range-hover-edge-end-near-range)::after,\n    &-in-view&-range-hover-end::after {\n      right: 6px;\n      border-right: @border-width-base dashed @picker-date-hover-range-border-color;\n      border-top-right-radius: @border-radius-base;\n      border-bottom-right-radius: @border-radius-base;\n    }\n\n    // >>> Disabled\n    &-disabled {\n      color: @disabled-color;\n      pointer-events: none;\n\n      .@{cellClassName} {\n        background: transparent;\n      }\n\n      &::before {\n        background: @picker-basic-cell-disabled-bg;\n      }\n    }\n    &-disabled&-today .@{cellClassName}::before {\n      border-color: @disabled-color;\n    }\n  }\n\n  &-cell {\n    padding: 3px 0;\n    color: @disabled-color;\n    cursor: pointer;\n\n    // In view\n    &-in-view {\n      color: @text-color;\n    }\n\n    .picker-cell-inner(~'@{picker-cell-inner-cls}');\n  }\n\n  &-decade-panel,\n  &-year-panel,\n  &-quarter-panel,\n  &-month-panel {\n    .@{picker-prefix-cls}-content {\n      height: @picker-panel-without-time-cell-height * 4;\n    }\n\n    .@{picker-cell-inner-cls} {\n      padding: 0 @padding-xs;\n    }\n  }\n\n  &-quarter-panel {\n    .@{picker-prefix-cls}-content {\n      height: 56px;\n    }\n  }\n\n  // ======================== Footer ========================\n  &-footer {\n    width: min-content;\n    min-width: 100%;\n    line-height: @picker-text-height - 2 * @border-width-base;\n    text-align: center;\n    border-bottom: @border-width-base @border-style-base transparent;\n\n    .@{picker-prefix-cls}-panel & {\n      border-top: @border-width-base @border-style-base @picker-border-color;\n    }\n\n    &-extra {\n      padding: 0 @padding-sm;\n      line-height: @picker-text-height - 2 * @border-width-base;\n      text-align: left;\n\n      &:not(:last-child) {\n        border-bottom: @border-width-base @border-style-base @picker-border-color;\n      }\n    }\n  }\n\n  &-now {\n    text-align: left;\n  }\n\n  &-today-btn {\n    color: @link-color;\n\n    &:hover {\n      color: @link-hover-color;\n    }\n\n    &:active {\n      color: @link-active-color;\n    }\n\n    &&-disabled {\n      color: @disabled-color;\n      cursor: not-allowed;\n    }\n  }\n\n  // ========================================================\n  // =                       Special                        =\n  // ========================================================\n\n  // ===================== Decade Panel =====================\n  &-decade-panel {\n    .@{picker-cell-inner-cls} {\n      padding: 0 (@padding-xs / 2);\n    }\n\n    .@{picker-prefix-cls}-cell::before {\n      display: none;\n    }\n  }\n\n  // ============= Year & Quarter & Month Panel =============\n  &-year-panel,\n  &-quarter-panel,\n  &-month-panel {\n    @hover-cell-fixed-distance: (\n      (((@picker-panel-width - @padding-xs * 2) / 3) - @picker-year-month-cell-width) / 2\n    );\n\n    .@{picker-prefix-cls}-body {\n      padding: 0 @padding-xs;\n    }\n\n    .@{picker-cell-inner-cls} {\n      width: @picker-year-month-cell-width;\n    }\n\n    .@{picker-prefix-cls}-cell-range-hover-start::after {\n      left: @hover-cell-fixed-distance;\n      border-left: @border-width-base dashed @picker-date-hover-range-border-color;\n      border-radius: @border-radius-base 0 0 @border-radius-base;\n\n      .@{picker-prefix-cls}-panel-rtl & {\n        right: @hover-cell-fixed-distance;\n        border-right: @border-width-base dashed @picker-date-hover-range-border-color;\n        border-radius: 0 @border-radius-base @border-radius-base 0;\n      }\n    }\n    .@{picker-prefix-cls}-cell-range-hover-end::after {\n      right: @hover-cell-fixed-distance;\n      border-right: @border-width-base dashed @picker-date-hover-range-border-color;\n      border-radius: 0 @border-radius-base @border-radius-base 0;\n\n      .@{picker-prefix-cls}-panel-rtl & {\n        left: @hover-cell-fixed-distance;\n        border-left: @border-width-base dashed @picker-date-hover-range-border-color;\n        border-radius: @border-radius-base 0 0 @border-radius-base;\n      }\n    }\n  }\n\n  // ====================== Week Panel ======================\n  &-week-panel {\n    .@{picker-prefix-cls}-body {\n      padding: @padding-xs @padding-sm;\n    }\n\n    // Clear cell style\n    .@{picker-prefix-cls}-cell {\n      &:hover .@{picker-cell-inner-cls},\n      &-selected .@{picker-cell-inner-cls},\n      .@{picker-cell-inner-cls} {\n        background: transparent !important;\n      }\n    }\n\n    &-row {\n      td {\n        transition: background @animation-duration-slow;\n      }\n\n      &:hover td {\n        background: @picker-basic-cell-hover-color;\n      }\n\n      &-selected td,\n      &-selected:hover td {\n        background: @primary-color;\n\n        &.@{picker-prefix-cls}-cell-week {\n          color: fade(@text-color-inverse, 50%);\n        }\n\n        &.@{picker-prefix-cls}-cell-today .@{picker-cell-inner-cls}::before {\n          border-color: @text-color-inverse;\n        }\n\n        .@{picker-cell-inner-cls} {\n          color: @text-color-inverse;\n        }\n      }\n    }\n  }\n\n  // ====================== Date Panel ======================\n  &-date-panel {\n    .@{picker-prefix-cls}-body {\n      padding: @padding-xs @padding-sm;\n    }\n\n    .@{picker-prefix-cls}-content {\n      width: @picker-panel-cell-width * 7;\n\n      th {\n        width: @picker-panel-cell-width;\n      }\n    }\n  }\n\n  // ==================== Datetime Panel ====================\n  &-datetime-panel {\n    display: flex;\n\n    .@{picker-prefix-cls}-time-panel {\n      border-left: @border-width-base @border-style-base @picker-border-color;\n    }\n\n    .@{picker-prefix-cls}-date-panel,\n    .@{picker-prefix-cls}-time-panel {\n      transition: opacity @animation-duration-slow;\n    }\n\n    // Keyboard\n    &-active {\n      .@{picker-prefix-cls}-date-panel,\n      .@{picker-prefix-cls}-time-panel {\n        opacity: 0.3;\n\n        &-active {\n          opacity: 1;\n        }\n      }\n    }\n  }\n\n  // ====================== Time Panel ======================\n  &-time-panel {\n    width: auto;\n    min-width: auto;\n\n    .@{picker-prefix-cls}-content {\n      display: flex;\n      flex: auto;\n      height: @picker-time-panel-column-height;\n    }\n\n    &-column {\n      flex: 1 0 auto;\n      width: @picker-time-panel-column-width;\n      margin: 0;\n      padding: 0;\n      overflow-y: hidden;\n      text-align: left;\n      list-style: none;\n      transition: background @animation-duration-slow;\n\n      &::after {\n        display: block;\n        height: @picker-time-panel-column-height - @picker-time-panel-cell-height;\n        content: '';\n        .@{picker-prefix-cls}-datetime-panel & {\n          height: @picker-time-panel-column-height - @picker-time-panel-cell-height + 2 *\n            @border-width-base;\n        }\n      }\n\n      &:not(:first-child) {\n        border-left: @border-width-base @border-style-base @picker-border-color;\n      }\n\n      &-active {\n        background: @calendar-column-active-bg;\n      }\n\n      &:hover {\n        overflow-y: auto;\n      }\n\n      > li {\n        margin: 0;\n        padding: 0;\n\n        &.@{picker-prefix-cls}-time-panel-cell {\n          .@{picker-prefix-cls}-time-panel-cell-inner {\n            display: block;\n            width: 100%;\n            height: @picker-time-panel-cell-height;\n            margin: 0;\n            padding: 0 0 0 ((@picker-time-panel-column-width - 28px) / 2);\n            color: @text-color;\n            line-height: @picker-time-panel-cell-height;\n            border-radius: 0;\n            cursor: pointer;\n            transition: background @animation-duration-slow;\n\n            &:hover {\n              background: @item-hover-bg;\n            }\n          }\n\n          &-selected {\n            .@{picker-prefix-cls}-time-panel-cell-inner {\n              background: @calendar-item-active-bg;\n            }\n          }\n\n          &-disabled {\n            .@{picker-prefix-cls}-time-panel-cell-inner {\n              color: @disabled-color;\n              background: transparent;\n              cursor: not-allowed;\n            }\n          }\n        }\n      }\n    }\n  }\n}\n\n// Fix IE11 render bug by css hacks\n// https://github.com/ant-design/ant-design/issues/21559\n// https://codepen.io/afc163-1472555193/pen/mdJRaNj?editors=0110\n/* stylelint-disable selector-type-no-unknown,selector-no-vendor-prefix */\n_:-ms-fullscreen,\n:root {\n  .@{picker-prefix-cls}-range-wrapper {\n    .@{picker-prefix-cls}-month-panel .@{picker-prefix-cls}-cell,\n    .@{picker-prefix-cls}-year-panel .@{picker-prefix-cls}-cell {\n      padding: 21px 0;\n    }\n  }\n}\n"
  },
  {
    "path": "components/date-picker/style/patch.less",
    "content": "// inline mode\n.@{picker-prefix-cls}-inline {\n  padding: 0;\n  border: none;\n  .@{picker-prefix-cls} {\n    &-range-arrow {\n      display: none !important;\n    }\n\n    &-dropdown {\n      z-index: auto;\n    }\n  }\n}\n\n// overwrite css in index.less to make sure picker popup is in the right position\n.@{picker-prefix-cls}-dropdown {\n  top: unset;\n  left: unset;\n}\n\n// ensure table is correct width to display week numbers in date mode\n.@{picker-prefix-cls}-panel-container.@{picker-prefix-cls}-week-number .@{picker-prefix-cls}-date-panel .@{picker-prefix-cls}-content {\n  width: 100%;\n\n  th {\n    width: inherit;\n  }\n}\n\n// make arrow in the right position in right direction\n.@{picker-prefix-cls}-range-arrow {\n  margin-right: @input-padding-horizontal-base * 1.5;\n}"
  },
  {
    "path": "components/date-picker/style/rtl.less",
    "content": ".@{picker-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &-suffix {\n    .@{picker-prefix-cls}-rtl & {\n      margin-right: (@padding-xs / 2);\n      margin-left: 0;\n    }\n  }\n\n  &-clear {\n    .@{picker-prefix-cls}-rtl & {\n      right: auto;\n      left: 0;\n    }\n  }\n\n  &-separator {\n    .@{picker-prefix-cls}-rtl & {\n      transform: rotate(180deg);\n    }\n  }\n\n  &-header {\n    &-view {\n      button {\n        &:not(:first-child) {\n          .@{picker-prefix-cls}-panel-rtl & {\n            margin-right: @padding-xs;\n            margin-left: 0;\n          }\n        }\n      }\n    }\n  }\n\n  // ======================== Range =========================\n  &-range {\n    // Clear\n    .@{picker-prefix-cls}-clear {\n      .@{picker-prefix-cls}-rtl& {\n        right: auto;\n        left: @input-padding-horizontal-base;\n      }\n    }\n\n    // Active bar\n    .@{picker-prefix-cls}-active-bar {\n      .@{picker-prefix-cls}-rtl& {\n        margin-right: @input-padding-horizontal-base;\n        margin-left: 0;\n      }\n    }\n\n    &.@{picker-prefix-cls}-small {\n      .@{picker-prefix-cls}-active-bar {\n        .@{picker-prefix-cls}-rtl& {\n          margin-right: @input-padding-horizontal-sm;\n        }\n      }\n    }\n  }\n\n  // ======================== Ranges ========================\n  &-ranges {\n    .@{picker-prefix-cls}-dropdown-rtl & {\n      text-align: right;\n    }\n\n    .@{picker-prefix-cls}-ok {\n      .@{picker-prefix-cls}-dropdown-rtl & {\n        float: left;\n        margin-right: @padding-xs;\n        margin-left: 0;\n      }\n    }\n  }\n\n  // ======================== Panel ========================\n  &-panel {\n    &-rtl {\n      direction: rtl;\n    }\n  }\n\n  &-prev-icon,\n  &-super-prev-icon {\n    .@{picker-prefix-cls}-panel-rtl & {\n      transform: rotate(135deg);\n    }\n  }\n\n  &-next-icon,\n  &-super-next-icon {\n    .@{picker-prefix-cls}-panel-rtl & {\n      transform: rotate(-45deg);\n    }\n  }\n\n  &-cell {\n    .picker-cell-inner(~'@{picker-cell-inner-cls}');\n  }\n\n  // ======================== Body ==========================\n  .picker-cell-inner(@cellClassName) {\n    .@{cellClassName} {\n      position: relative;\n      z-index: 2;\n      display: inline-block;\n      min-width: @picker-panel-cell-height;\n      height: @picker-panel-cell-height;\n      line-height: @picker-panel-cell-height;\n      border-radius: @border-radius-base;\n      transition: background @animation-duration-slow, border @animation-duration-slow;\n    }\n\n    &-in-view&-range-start::before {\n      .@{picker-prefix-cls}-panel-rtl & {\n        right: 50%;\n        left: 0;\n      }\n    }\n\n    &-in-view&-range-end::before {\n      .@{picker-prefix-cls}-panel-rtl & {\n        right: 0;\n        left: 50%;\n      }\n    }\n\n    &-in-view&-range-start&-range-end::before {\n      .@{picker-prefix-cls}-panel-rtl & {\n        right: 50%;\n        left: 50%;\n      }\n    }\n\n    .@{picker-prefix-cls}-date-panel\n      &-in-view&-in-range&-range-hover-start\n      .@{cellClassName}::after {\n      .@{picker-prefix-cls}-panel-rtl & {\n        right: 0;\n        left: -5px - @border-width-base;\n      }\n    }\n\n    .@{picker-prefix-cls}-date-panel &-in-view&-in-range&-range-hover-end .@{cellClassName}::after {\n      .@{picker-prefix-cls}-panel-rtl & {\n        right: -5px - @border-width-base;\n        left: 0;\n      }\n    }\n\n    // Hover with range start & end\n    &-range-hover&-range-start::after {\n      .@{picker-prefix-cls}-panel-rtl & {\n        right: 0;\n        left: 50%;\n      }\n    }\n\n    &-range-hover&-range-end::after {\n      .@{picker-prefix-cls}-panel-rtl & {\n        right: 50%;\n        left: 0;\n      }\n    }\n\n    // range start border-radius\n    &-in-view&-range-start:not(&-range-start-single):not(&-range-end) .@{cellClassName} {\n      .@{picker-prefix-cls}-panel-rtl & {\n        border-radius: 0 @border-radius-base @border-radius-base 0;\n      }\n    }\n\n    // range end border-radius\n    &-in-view&-range-end:not(&-range-end-single):not(&-range-start) .@{cellClassName} {\n      .@{picker-prefix-cls}-panel-rtl & {\n        border-radius: @border-radius-base 0 0 @border-radius-base;\n      }\n    }\n\n    // Edge start\n    tr > &-in-view&-range-hover:not(&-selected):first-child::after,\n    &-in-view&-start&-range-hover-edge-start&-range-hover-edge-start-near-range::after,\n    &-in-view&-range-hover-edge-start:not(&-range-hover-edge-start-near-range)::after,\n    &-in-view&-range-hover-start::after {\n      .@{picker-prefix-cls}-panel-rtl & {\n        right: 6px;\n        left: 0;\n        border-right: @border-width-base dashed @picker-date-hover-range-border-color;\n        border-left: none;\n        border-radius: 0 @border-radius-base @border-radius-base 0;\n      }\n    }\n\n    // Edge end\n    tr > &-in-view&-range-hover:not(&-selected):last-child::after,\n    &-in-view&-end&-range-hover-edge-end&-range-hover-edge-end-near-range::after,\n    &-in-view&-range-hover-edge-end:not(&-range-hover-edge-end-near-range)::after,\n    &-in-view&-range-hover-end::after {\n      .@{picker-prefix-cls}-panel-rtl & {\n        right: 0;\n        left: 6px;\n        border-right: none;\n        border-left: @border-width-base dashed @picker-date-hover-range-border-color;\n        border-radius: @border-radius-base 0 0 @border-radius-base;\n      }\n    }\n\n    tr > &-in-view&-range-hover-start:last-child::after,\n    tr > &-in-view&-range-hover-end:first-child::after,\n    &-in-view&-start&-range-hover-edge-start:not(&-range-hover)::after,\n    &-in-view&-start&-range-hover-end&-range-hover-edge-start:not(&-range-hover)::after,\n    &-in-view&-end&-range-hover-start&-range-hover-edge-end:not(&-range-hover)::after,\n    tr > &-in-view&-start&-range-hover&-range-hover-edge-start:last-child::after,\n    tr > &-in-view&-end&-range-hover&-range-hover-edge-end:first-child::after {\n      .@{picker-prefix-cls}-panel-rtl & {\n        right: 6px;\n        left: 6px;\n        border-right: @border-width-base dashed @picker-date-hover-range-border-color;\n        border-left: @border-width-base dashed @picker-date-hover-range-border-color;\n        border-radius: @border-radius-base;\n      }\n    }\n  }\n\n  // ======================== Footer ========================\n  &-footer {\n    &-extra {\n      .@{picker-prefix-cls}-dropdown-rtl & {\n        direction: rtl;\n        text-align: right;\n      }\n    }\n  }\n\n  // ====================== Time Panel ======================\n  &-time-panel {\n    .@{picker-prefix-cls}-panel-rtl & {\n      direction: ltr;\n    }\n  }\n}\n"
  },
  {
    "path": "components/date-picker/style/status.less",
    "content": "@import '../../input/style/mixin';\n\n@picker-prefix-cls: ~'@{ant-prefix}-picker';\n\n.picker-status-color(\n  @text-color: @input-color;\n  @border-color: @input-border-color;\n  @background-color: @input-bg;\n  @hoverBorderColor: @primary-color-hover;\n  @outlineColor: @primary-color-outline;\n) {\n  &.@{picker-prefix-cls} {\n    &,\n    &:not(.@{picker-prefix-cls}-disabled):hover {\n      background-color: @background-color;\n      border-color: @border-color;\n    }\n\n    &-focused,\n    &:focus {\n      .active(@text-color, @hoverBorderColor, @outlineColor);\n    }\n\n    .@{picker-prefix-cls}-active-bar {\n      background: @hoverBorderColor;\n    }\n  }\n}\n\n.@{picker-prefix-cls} {\n  &-status-error {\n    .picker-status-color(@error-color, @error-color, @input-bg, @error-color-hover, @error-color-outline);\n  }\n\n  &-status-warning {\n    .picker-status-color(@warning-color, @warning-color, @input-bg, @warning-color-hover, @warning-color-outline);\n  }\n}\n"
  },
  {
    "path": "components/date-picker/testing/util.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { DebugElement } from '@angular/core';\nimport { By } from '@angular/platform-browser';\n\nimport { PREFIX_CLASS } from '../util';\n\nexport const ENTER_EVENT = new KeyboardEvent('keyup', { key: 'Enter' });\n\nexport function getPickerAbstract<T = HTMLElement>(debugElement: DebugElement): T {\n  return debugElement.query(By.css(`.${PREFIX_CLASS}`)).nativeElement;\n}\n\nexport function getPickerInput(debugElement: DebugElement): HTMLInputElement {\n  return debugElement.query(By.css(`.${PREFIX_CLASS}-input input`)).nativeElement as HTMLInputElement;\n}\n\nexport function getRangePickerRightInput(debugElement: DebugElement): HTMLInputElement {\n  return debugElement.queryAll(By.css(`.${PREFIX_CLASS}-input input`))[1].nativeElement as HTMLInputElement;\n}\n\nexport function getPickerOkButton(debugElement: DebugElement): HTMLElement {\n  return debugElement.query(By.css(`.${PREFIX_CLASS}-ok`)).nativeElement.querySelector('button') as HTMLElement;\n}\n"
  },
  {
    "path": "components/date-picker/util.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { CandyDate } from 'ng-zorro-antd/core/time';\n\nimport { isAllowedDate } from './util';\n\ndescribe('util.ts coverage supplements', () => {\n  it('should cover untouched branches', () => {\n    const disabledDate = (): boolean => true;\n    expect(isAllowedDate(new CandyDate(), disabledDate)).toBeFalsy();\n\n    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n    const disabledTime = () => ({\n      nzDisabledHours: () => [1],\n      nzDisabledMinutes: () => [2],\n      nzDisabledSeconds: () => [3]\n    });\n    expect(isAllowedDate(new CandyDate('2000-11-11 01:11:11'), undefined, disabledTime)).toBeFalsy();\n    expect(isAllowedDate(new CandyDate('2000-11-11 02:02:11'), undefined, disabledTime)).toBeFalsy();\n    expect(isAllowedDate(new CandyDate('2000-11-11 02:03:03'), undefined, disabledTime)).toBeFalsy();\n  });\n});\n"
  },
  {
    "path": "components/date-picker/util.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { CandyDate } from 'ng-zorro-antd/core/time';\n\nimport { DisabledDateFn, DisabledTimeConfig, DisabledTimeFn } from './standard-types';\n\nexport const PREFIX_CLASS = 'ant-picker';\n\nconst defaultDisabledTime: DisabledTimeConfig = {\n  nzDisabledHours(): number[] {\n    return [];\n  },\n  nzDisabledMinutes(): number[] {\n    return [];\n  },\n  nzDisabledSeconds(): number[] {\n    return [];\n  }\n};\n\nexport function getTimeConfig(value: CandyDate, disabledTime?: DisabledTimeFn): DisabledTimeConfig {\n  let disabledTimeConfig = disabledTime ? disabledTime(value && value.nativeDate) : ({} as DisabledTimeConfig);\n  disabledTimeConfig = {\n    ...defaultDisabledTime,\n    ...disabledTimeConfig\n  };\n  return disabledTimeConfig;\n}\n\nexport function isTimeValidByConfig(value: CandyDate, disabledTimeConfig: DisabledTimeConfig): boolean {\n  let invalidTime = false;\n  if (value) {\n    const hour = value.getHours();\n    const minutes = value.getMinutes();\n    const seconds = value.getSeconds();\n    const disabledHours = disabledTimeConfig.nzDisabledHours();\n    if (disabledHours.indexOf(hour) === -1) {\n      const disabledMinutes = disabledTimeConfig.nzDisabledMinutes(hour);\n      if (disabledMinutes.indexOf(minutes) === -1) {\n        const disabledSeconds = disabledTimeConfig.nzDisabledSeconds(hour, minutes);\n        invalidTime = disabledSeconds.indexOf(seconds) !== -1;\n      } else {\n        invalidTime = true;\n      }\n    } else {\n      invalidTime = true;\n    }\n  }\n  return !invalidTime;\n}\n\nexport function isTimeValid(value: CandyDate, disabledTime: DisabledTimeFn): boolean {\n  const disabledTimeConfig = getTimeConfig(value, disabledTime);\n  return isTimeValidByConfig(value, disabledTimeConfig);\n}\n\nexport function isAllowedDate(value: CandyDate, disabledDate?: DisabledDateFn, disabledTime?: DisabledTimeFn): boolean {\n  if (!value) {\n    return false;\n  }\n  if (disabledDate) {\n    if (disabledDate(value.nativeDate)) {\n      return false;\n    }\n  }\n  if (disabledTime) {\n    if (!isTimeValid(value, disabledTime)) {\n      return false;\n    }\n  }\n  return true;\n}\n"
  },
  {
    "path": "components/date-picker/week-picker.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport { Component, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, fakeAsync, flush, inject, TestBed, tick } from '@angular/core/testing';\nimport { FormsModule } from '@angular/forms';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { dispatchMouseEvent } from 'ng-zorro-antd/core/testing';\nimport { getPickerInput } from 'ng-zorro-antd/date-picker/testing/util';\n\nimport { NzDatePickerModule } from './date-picker.module';\n\ndescribe('week-picker', () => {\n  let fixture: ComponentFixture<NzTestWeekPickerComponent>;\n  let fixtureInstance: NzTestWeekPickerComponent;\n  let overlayContainer: OverlayContainer;\n  let overlayContainerElement: HTMLElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n    overlayContainer = oc;\n    overlayContainerElement = oc.getContainerElement();\n  }));\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzTestWeekPickerComponent);\n    fixtureInstance = fixture.componentInstance;\n    // set initial mode\n    fixtureInstance.useSuite = 1;\n    fixture.detectChanges();\n  });\n\n  afterEach(() => {\n    overlayContainer.ngOnDestroy();\n  });\n\n  it('should show week num', fakeAsync(() => {\n    fixtureInstance.nzFormat = undefined; // cover branch\n    fixture.detectChanges();\n    openPickerByClickTrigger();\n    expect(queryFromOverlay('.ant-picker-week-panel-row .ant-picker-cell-week')).toBeDefined();\n  }));\n\n  it('should change input value when click week', fakeAsync(() => {\n    fixtureInstance.nzValue = new Date('2020-02-25');\n    fixture.detectChanges();\n    flush();\n    fixture.detectChanges();\n    openPickerByClickTrigger();\n    dispatchMouseEvent(queryFromOverlay('.ant-picker-cell'), 'click');\n    fixture.detectChanges();\n    tick(500);\n    fixture.detectChanges();\n    expect(getPickerInput(fixture.debugElement).value).toBe('2020-05');\n  }));\n\n  it('should change panel to week from month', fakeAsync(() => {\n    fixtureInstance.nzValue = new Date('2020-02-25');\n    fixture.detectChanges();\n    openPickerByClickTrigger();\n    dispatchMouseEvent(queryFromOverlay('.ant-picker-header-month-btn'), 'click');\n    fixture.detectChanges();\n    dispatchMouseEvent(queryFromOverlay('.ant-picker-cell'), 'click');\n    fixture.detectChanges();\n    expect(queryFromOverlay('.ant-picker-week-panel')).toBeTruthy();\n  }));\n\n  it('should show week num', fakeAsync(() => {\n    fixtureInstance.useSuite = 2;\n    fixture.whenRenderingDone().then(() => {\n      tick(500);\n      fixture.detectChanges();\n      fixtureInstance.nzFormat = undefined; // cover branch\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(queryFromOverlay('.ant-picker-week-panel-row .ant-picker-cell-week')).toBeDefined();\n    });\n  }));\n\n  ////////////\n\n  function queryFromOverlay(selector: string): HTMLElement {\n    return overlayContainerElement.querySelector(selector) as HTMLElement;\n  }\n\n  function openPickerByClickTrigger(): void {\n    dispatchMouseEvent(getPickerInput(fixture.debugElement), 'click');\n    fixture.detectChanges();\n    tick(500);\n    fixture.detectChanges();\n  }\n});\n\n@Component({\n  imports: [NzDatePickerModule, FormsModule],\n  template: `\n    @switch (useSuite) {\n      @case (1) {\n        <nz-date-picker nzMode=\"week\" [nzFormat]=\"nzFormat!\" [ngModel]=\"nzValue\" />\n      }\n      @case (2) {\n        <nz-week-picker [ngModel]=\"nzValue\" />\n      }\n    }\n  `\n})\nexport class NzTestWeekPickerComponent {\n  useSuite!: 1 | 2;\n  nzFormat?: string;\n  nzValue: Date | null = null;\n}\n"
  },
  {
    "path": "components/date-picker/week-picker.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, inject } from '@angular/core';\n\nimport { NzDatePickerComponent } from './date-picker.component';\n\n@Directive({\n  selector: 'nz-week-picker',\n  exportAs: 'nzWeekPicker'\n})\nexport class NzWeekPickerComponent {\n  datePicker = inject(NzDatePickerComponent, { host: true });\n\n  constructor() {\n    this.datePicker.nzMode = 'week';\n  }\n}\n"
  },
  {
    "path": "components/date-picker/year-picker.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport { Component, DebugElement, provideZoneChangeDetection, TemplateRef, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, flush, inject, TestBed, tick } from '@angular/core/testing';\nimport { FormsModule } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { dispatchFakeEvent, dispatchMouseEvent } from 'ng-zorro-antd/core/testing';\nimport { NgStyleInterface } from 'ng-zorro-antd/core/types';\nimport { NzDatePickerSizeType } from 'ng-zorro-antd/date-picker/date-picker.component';\nimport { getPickerAbstract, getPickerInput } from 'ng-zorro-antd/date-picker/testing/util';\nimport { PREFIX_CLASS } from 'ng-zorro-antd/date-picker/util';\nimport { NzDatePickerI18nInterface, NzDatePickerLangI18nInterface } from 'ng-zorro-antd/i18n';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\nimport { NzDatePickerModule } from './date-picker.module';\n\ndescribe('year-picker', () => {\n  let fixture: ComponentFixture<NzTestYearPickerComponent>;\n  let fixtureInstance: NzTestYearPickerComponent;\n  let debugElement: DebugElement;\n  let overlayContainerElement: HTMLElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzTestYearPickerComponent);\n    fixtureInstance = fixture.componentInstance;\n    debugElement = fixture.debugElement;\n  });\n\n  beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n    overlayContainerElement = oc.getContainerElement();\n  }));\n\n  afterEach(() => {\n    // overlayContainer.ngOnDestroy();\n  });\n\n  describe('general api testing', () => {\n    beforeEach(() => (fixtureInstance.useSuite = 1));\n\n    it('should open by click and close by click at outside', fakeAsync(() => {\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(getPickerContainer()).not.toBeNull();\n\n      dispatchFakeEvent(getPickerInput(fixture.debugElement), 'focusout');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).toBeNull();\n    }));\n\n    it('should support nzAllowClear and work properly', fakeAsync(() => {\n      const clearBtnSelector = By.css(`.${PREFIX_CLASS}-clear`);\n      const initial = (fixtureInstance.nzValue = new Date());\n      fixtureInstance.nzAllowClear = false;\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(debugElement.query(clearBtnSelector)).toBeFalsy();\n\n      fixtureInstance.nzAllowClear = true;\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(fixtureInstance.nzValue).toBe(initial);\n      expect(debugElement.query(clearBtnSelector)).toBeDefined();\n\n      const nzOnChange = spyOn(fixtureInstance, 'nzOnChange');\n      debugElement.query(clearBtnSelector).nativeElement.click();\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(fixtureInstance.nzValue).toBe(initial);\n      expect(nzOnChange).toHaveBeenCalledWith(null);\n      expect(debugElement.query(clearBtnSelector)).toBeFalsy();\n    }));\n\n    it('should support nzAutoFocus', () => {\n      fixtureInstance.nzAutoFocus = true;\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement) === document.activeElement).toBeTruthy();\n    });\n\n    it('should support nzDisabled', fakeAsync(() => {\n      // Make sure picker clear button shown up\n      fixtureInstance.nzAllowClear = true;\n      fixtureInstance.nzValue = new Date();\n\n      fixtureInstance.nzDisabled = true;\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(debugElement.query(By.css('.ant-picker-disabled'))).not.toBeNull();\n      expect(debugElement.query(By.css('.ant-picker-clear'))).toBeNull();\n\n      fixtureInstance.nzDisabled = false;\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(debugElement.query(By.css('.ant-picker-disabled'))).toBeNull();\n      expect(debugElement.query(By.css('.ant-picker-clear'))).not.toBeNull();\n    }));\n\n    it('should support nzOpen if assigned', fakeAsync(() => {\n      fixtureInstance.useSuite = 2;\n\n      fixture.detectChanges();\n      fixture.whenRenderingDone().then(() => {\n        expect(getPickerContainer()).toBeNull();\n\n        fixtureInstance.nzOpen = true;\n        fixture.detectChanges();\n        tick(500);\n        fixture.detectChanges();\n        expect(getPickerContainer()).not.toBeNull();\n\n        fixtureInstance.nzOpen = false;\n        fixture.detectChanges();\n        tick(500);\n        fixture.detectChanges();\n        expect(getPickerContainer()).toBeNull();\n      });\n    }));\n\n    it('should nz-year-picker work', fakeAsync(() => {\n      fixtureInstance.useSuite = 4;\n      fixture.whenRenderingDone().then(() => {\n        tick(500);\n        fixture.detectChanges();\n        expect(getPickerContainer()).not.toBeNull();\n        const pickerInput = getPickerInput(fixture.debugElement);\n        expect(pickerInput).not.toBeNull();\n      });\n    }));\n\n    it('should support nzDisabledDate', fakeAsync(() => {\n      fixture.detectChanges();\n      fixtureInstance.nzValue = new Date('2018-11-11 12:12:12');\n      fixtureInstance.nzDisabledDate = (current: Date) => current.getFullYear() === 2013;\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n\n      openPickerByClickTrigger();\n      const disabledCell = overlayContainerElement.querySelector(\n        '.ant-picker-year-panel tr td.ant-picker-cell-disabled'\n      )!;\n      expect(disabledCell.textContent).toContain('2013');\n    }));\n\n    it('should support nzLocale', () => {\n      const featureKey = 'TEST_PLACEHOLDER';\n      fixtureInstance.nzLocale = {\n        lang: { yearPlaceholder: featureKey } as unknown as NzDatePickerLangI18nInterface,\n        timePickerLocale: {}\n      };\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement).getAttribute('placeholder')).toBe(featureKey);\n    });\n\n    it('should support nzPlaceHolder', () => {\n      const featureKey = 'TEST_PLACEHOLDER';\n      fixtureInstance.nzPlaceHolder = featureKey;\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement).getAttribute('placeholder')).toBe(featureKey);\n    });\n\n    it('should support nzPopupStyle', fakeAsync(() => {\n      fixtureInstance.nzPopupStyle = { color: 'red' };\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(queryFromOverlay(`.${PREFIX_CLASS}-dropdown`).style.color).toBe('red');\n    }));\n\n    it('should support nzDropdownClassName', fakeAsync(() => {\n      const keyCls = (fixtureInstance.nzDropdownClassName = 'my-test-class');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(queryFromOverlay(`.${PREFIX_CLASS}-dropdown`).classList.contains(keyCls)).toBeTruthy();\n    }));\n\n    it('should support nzSize', () => {\n      fixtureInstance.nzSize = 'large';\n      fixture.detectChanges();\n      expect(getPickerAbstract(fixture.debugElement).classList.contains('ant-picker-large')).toBeTruthy();\n\n      fixtureInstance.nzSize = 'small';\n      fixture.detectChanges();\n      expect(getPickerAbstract(fixture.debugElement).classList.contains('ant-picker-small')).toBeTruthy();\n    });\n\n    it('should support nzOnOpenChange', fakeAsync(() => {\n      const nzOnOpenChange = spyOn(fixtureInstance, 'nzOnOpenChange');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(nzOnOpenChange).toHaveBeenCalledWith(true);\n\n      dispatchFakeEvent(getPickerInput(fixture.debugElement), 'focusout');\n      fixture.detectChanges();\n      flush();\n      expect(nzOnOpenChange).toHaveBeenCalledWith(false);\n      expect(nzOnOpenChange).toHaveBeenCalledTimes(2);\n    }));\n    it('should support nzValue', fakeAsync(() => {\n      fixtureInstance.nzValue = new Date('2018-11-22');\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      expect(getSelectedYearCell().textContent).toContain('2018');\n    }));\n\n    it('should support nzOnChange', fakeAsync(() => {\n      fixtureInstance.nzValue = new Date('2018-11');\n      const nzOnChange = spyOn(fixtureInstance, 'nzOnChange');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n\n      const cell = getSecondYearCell(); // Use the second cell\n      const cellText = cell.textContent!.trim();\n      dispatchMouseEvent(cell, 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(nzOnChange).toHaveBeenCalled();\n      const result = (nzOnChange.calls.allArgs()[0] as Date[])[0];\n      expect(result.getFullYear()).toBe(parseInt(cellText, 10));\n    }));\n  }); // /general api testing\n\n  describe('panel switch and move forward/afterward', () => {\n    beforeEach(() => (fixtureInstance.useSuite = 1));\n\n    it('should support decade panel changes', fakeAsync(() => {\n      fixtureInstance.nzValue = new Date('2018-11');\n      fixture.detectChanges();\n      openPickerByClickTrigger();\n      // Click to show decade panel\n      dispatchMouseEvent(queryFromOverlay('.ant-picker-header-year-btn'), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-decade-panel')).toBeDefined();\n      // Goto previous decade\n      dispatchMouseEvent(getSuperPreBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-header-decade-btn').textContent).toContain('1900');\n      expect(queryFromOverlay('.ant-picker-header-decade-btn').textContent).toContain('1999');\n      // Goto next decade * 2\n      dispatchMouseEvent(getSuperNextBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      dispatchMouseEvent(getSuperNextBtn(), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(queryFromOverlay('.ant-picker-header-decade-btn').textContent).toContain('2100');\n      expect(queryFromOverlay('.ant-picker-header-decade-btn').textContent).toContain('2199');\n    }));\n  }); // /panel switch and move forward/afterward\n\n  describe('specified date picker testing', () => {\n    beforeEach(() => (fixtureInstance.useSuite = 1));\n\n    it('should support nzRenderExtraFooter', fakeAsync(() => {\n      fixtureInstance.nzRenderExtraFooter = () => fixtureInstance.tplExtraFooter;\n      fixture.detectChanges();\n\n      openPickerByClickTrigger();\n      expect(overlayContainerElement.textContent!.indexOf('TEST_EXTRA_FOOTER') > -1).toBeTruthy();\n\n      fixtureInstance.nzRenderExtraFooter = 'TEST_EXTRA_FOOTER_STRING';\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent!.indexOf(fixtureInstance.nzRenderExtraFooter) > -1).toBeTruthy();\n    }));\n  }); // /specified date picker testing\n\n  describe('ngModel value accessors', () => {\n    beforeEach(() => (fixtureInstance.useSuite = 3));\n\n    it('should specified date provide by \"modelValue\" be chosen', fakeAsync(() => {\n      fixtureInstance.modelValue = new Date('2018-11');\n      fixture.detectChanges();\n      flush(); // Wait writeValue() tobe done\n      fixture.detectChanges();\n      expect(getSelectedYearCell().textContent).toContain('2018');\n      // Click the first cell to change ngModel\n      const cell = getSecondYearCell();\n      const cellText = cell.textContent!.trim();\n      dispatchMouseEvent(cell, 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(fixtureInstance.modelValue.getFullYear()).toBe(parseInt(cellText, 10));\n    }));\n  });\n\n  ////////////\n\n  function getSuperPreBtn(): HTMLElement {\n    return queryFromOverlay(`.${PREFIX_CLASS}-header-super-prev-btn`);\n  }\n\n  function getSuperNextBtn(): HTMLElement {\n    return queryFromOverlay(`.${PREFIX_CLASS}-header-super-next-btn`);\n  }\n\n  function getPickerContainer(): HTMLElement {\n    return queryFromOverlay('.ant-picker-panel-container') as HTMLElement;\n  }\n\n  function getSelectedYearCell(): HTMLElement {\n    return queryFromOverlay('.ant-picker-year-panel td.ant-picker-cell-selected') as HTMLElement;\n  }\n\n  function getSecondYearCell(): HTMLElement {\n    return queryFromOverlay(\n      '.ant-picker-year-panel td.ant-picker-cell:nth-child(2) .ant-picker-cell-inner'\n    ) as HTMLElement;\n  }\n\n  function queryFromOverlay(selector: string): HTMLElement {\n    return overlayContainerElement.querySelector(selector) as HTMLElement;\n  }\n\n  function openPickerByClickTrigger(): void {\n    dispatchMouseEvent(getPickerInput(fixture.debugElement), 'click');\n    fixture.detectChanges();\n    tick(500);\n    fixture.detectChanges();\n  }\n});\n\n@Component({\n  imports: [FormsModule, NzDatePickerModule, NzInputModule],\n  template: `\n    <ng-template #tplExtraFooter>TEST_EXTRA_FOOTER</ng-template>\n    @switch (useSuite) {\n      @case (1) {\n        <nz-date-picker\n          nzMode=\"year\"\n          [nzAllowClear]=\"nzAllowClear\"\n          [nzAutoFocus]=\"nzAutoFocus\"\n          [nzDisabled]=\"nzDisabled\"\n          [nzDisabledDate]=\"nzDisabledDate\"\n          [nzLocale]=\"nzLocale\"\n          [nzPlaceHolder]=\"nzPlaceHolder\"\n          [nzPopupStyle]=\"nzPopupStyle ?? {}\"\n          [nzDropdownClassName]=\"nzDropdownClassName\"\n          [nzSize]=\"nzSize\"\n          (nzOnOpenChange)=\"nzOnOpenChange($event)\"\n          [ngModel]=\"nzValue\"\n          (ngModelChange)=\"nzOnChange($event)\"\n          [nzRenderExtraFooter]=\"nzRenderExtraFooter\"\n        />\n      }\n      @case (2) {\n        <nz-date-picker nzMode=\"year\" [nzOpen]=\"nzOpen\" />\n      }\n      @case (3) {\n        <nz-date-picker nzMode=\"year\" nzOpen [(ngModel)]=\"modelValue\" />\n      }\n      @case (4) {\n        <nz-year-picker nzOpen [(ngModel)]=\"modelValue\" />\n      }\n    }\n  `\n})\nclass NzTestYearPickerComponent {\n  useSuite?: 1 | 2 | 3 | 4;\n  @ViewChild('tplExtraFooter', { static: true }) tplExtraFooter!: TemplateRef<void>;\n\n  // --- Suite 1\n  nzAllowClear: boolean = false;\n  nzAutoFocus: boolean = false;\n  nzDisabled: boolean = false;\n  nzDisabledDate?: (d: Date) => boolean;\n  nzLocale!: NzDatePickerI18nInterface;\n  nzPlaceHolder!: string;\n  nzPopupStyle?: NgStyleInterface;\n  nzDropdownClassName?: string;\n  nzSize!: NzDatePickerSizeType;\n\n  nzOnOpenChange(_: boolean): void {}\n\n  nzOnChange(_: Date | null): void {}\n\n  nzValue: Date | null = null;\n\n  nzRenderExtraFooter?: string | (() => TemplateRef<void> | string);\n\n  // --- Suite 2\n  nzOpen: boolean = false;\n\n  // --- Suite 3\n  modelValue?: Date;\n}\n"
  },
  {
    "path": "components/date-picker/year-picker.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, inject } from '@angular/core';\n\nimport { NzDatePickerComponent } from './date-picker.component';\n\n@Directive({\n  selector: 'nz-year-picker',\n  exportAs: 'nzYearPicker'\n})\nexport class NzYearPickerComponent {\n  datePicker = inject(NzDatePickerComponent, { host: true });\n\n  constructor() {\n    this.datePicker.nzMode = 'year';\n  }\n}\n"
  },
  {
    "path": "components/descriptions/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n简单的展示。\n\n## en-US\n\nBasic usage.\n"
  },
  {
    "path": "components/descriptions/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDescriptionsModule } from 'ng-zorro-antd/descriptions';\n\n@Component({\n  selector: 'nz-demo-descriptions-basic',\n  imports: [NzDescriptionsModule],\n  template: `\n    <nz-descriptions nzTitle=\"User Info\">\n      <nz-descriptions-item nzTitle=\"UserName\">Zhou Maomao</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Telephone\">18100000000</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Live\">Hangzhou, Zhejiang</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Remark\">Empty</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Address\">\n        No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China\n      </nz-descriptions-item>\n    </nz-descriptions>\n  `\n})\nexport class NzDemoDescriptionsBasicComponent {}\n"
  },
  {
    "path": "components/descriptions/demo/border.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 带边框的\n  en-US: Border\n---\n\n## zh-CN\n\n带边框和背景颜色列表。\n\n## en-US\n\nDescriptions with border and background color.\n"
  },
  {
    "path": "components/descriptions/demo/border.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzBadgeModule } from 'ng-zorro-antd/badge';\nimport { NzDescriptionsModule } from 'ng-zorro-antd/descriptions';\n\n@Component({\n  selector: 'nz-demo-descriptions-border',\n  imports: [NzBadgeModule, NzDescriptionsModule],\n  template: `\n    <nz-descriptions nzTitle=\"User Info\" nzBordered>\n      <nz-descriptions-item nzTitle=\"Product\">Cloud Database</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Billing Mode\">Prepaid</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Automatic Renewal\">YES</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Order Time\">2018-04-24 18:00:00</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Usage Time\" [nzSpan]=\"2\">\n        2018-04-24 18:00:00 To 2019-04-24 18:00:00\n      </nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Status\" [nzSpan]=\"3\">\n        <nz-badge nzStatus=\"processing\" nzText=\"Running\" />\n      </nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Negotiated Amount\">$80.00</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Discount\">$20.00</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Official Receipts\">$60.00</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Config Info\">\n        Data disk type: MongoDB\n        <br />\n        Database version: 3.4\n        <br />\n        Package: dds.mongo.mid\n        <br />\n        Storage space: 10 GB\n        <br />\n        Replication_factor:3\n        <br />\n        Region: East China 1\n        <br />\n      </nz-descriptions-item>\n    </nz-descriptions>\n  `\n})\nexport class NzDemoDescriptionsBorderComponent {}\n"
  },
  {
    "path": "components/descriptions/demo/custom-size.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 自定义尺寸\n  en-US: Custom size\n---\n\n## zh-CN\n\n自定义尺寸，适应在各种容器中展示。\n\n## en-US\n\nCustom sizes to fit in a variety of containers.\n"
  },
  {
    "path": "components/descriptions/demo/custom-size.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzDescriptionsModule, NzDescriptionsSize } from 'ng-zorro-antd/descriptions';\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\n\n@Component({\n  selector: 'nz-demo-descriptions-custom-size',\n  imports: [FormsModule, NzButtonModule, NzDescriptionsModule, NzRadioModule],\n  template: `\n    <nz-radio-group [(ngModel)]=\"size\">\n      <label nz-radio nzValue=\"default\">default</label>\n      <label nz-radio nzValue=\"middle\">middle</label>\n      <label nz-radio nzValue=\"small\">small</label>\n    </nz-radio-group>\n    <br />\n    <br />\n    <nz-descriptions nzTitle=\"Custom Size\" [nzExtra]=\"extraTpl\" nzBordered [nzSize]=\"size\">\n      <nz-descriptions-item nzTitle=\"Product\">Cloud Database</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Billing\">Prepaid</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"time\">18:00:00</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Amount\">$80.00</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Discount\">$20.00</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Official\">$60.00</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Config Info\">\n        Data disk type: MongoDB\n        <br />\n        Database version: 3.4\n        <br />\n        Package: dds.mongo.mid\n        <br />\n        Storage space: 10 GB\n        <br />\n        Replication_factor:3\n        <br />\n        Region: East China 1\n        <br />\n      </nz-descriptions-item>\n    </nz-descriptions>\n    <br />\n    <br />\n    <nz-descriptions nzTitle=\"Custom Size\" [nzSize]=\"size\" [nzExtra]=\"extraTpl\">\n      <nz-descriptions-item nzTitle=\"Product\">Cloud Database</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Billing\">Prepaid</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Time\">18:00:00</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Amount\">$80.00</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Discount\">$20.00</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Official\">$60.00</nz-descriptions-item>\n    </nz-descriptions>\n    <ng-template #extraTpl>\n      <button nz-button nzType=\"primary\">Edit</button>\n    </ng-template>\n  `\n})\nexport class NzDemoDescriptionsCustomSizeComponent {\n  size: NzDescriptionsSize = 'default';\n}\n"
  },
  {
    "path": "components/descriptions/demo/responsive.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 响应式\n  en-US: Responsive\n---\n\n## zh-CN\n\n通过响应式的配置可以实现在小屏幕设备上的完美呈现。\n\n## en-US\n\nResponsive configuration enables perfect presentation on small screen devices.\n"
  },
  {
    "path": "components/descriptions/demo/responsive.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDescriptionsModule } from 'ng-zorro-antd/descriptions';\n\n@Component({\n  selector: 'nz-demo-descriptions-responsive',\n  imports: [NzDescriptionsModule],\n  template: `\n    <nz-descriptions\n      nzTitle=\"Responsive Descriptions\"\n      nzBordered\n      [nzColumn]=\"{ xxl: 4, xl: 3, lg: 3, md: 3, sm: 2, xs: 1 }\"\n    >\n      <nz-descriptions-item nzTitle=\"Product\">Cloud Database</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Billing\">Prepaid</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"time\">18:00:00</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Amount\">$80.00</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Discount\">$20.00</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Official\">$60.00</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Config Info\">\n        Data disk type: MongoDB\n        <br />\n        Database version: 3.4\n        <br />\n        Package: dds.mongo.mid\n        <br />\n        Storage space: 10 GB\n        <br />\n        Replication_factor:3\n        <br />\n        Region: East China 1\n        <br />\n      </nz-descriptions-item>\n    </nz-descriptions>\n  `\n})\nexport class NzDemoDescriptionsResponsiveComponent {}\n"
  },
  {
    "path": "components/descriptions/demo/vertical-border.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 垂直边框\n  en-US: Vertical border\n---\n\n## zh-CN\n\n垂直且带边框。\n\n## en-US\n\nVertical descriptions with border.\n"
  },
  {
    "path": "components/descriptions/demo/vertical-border.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzBadgeModule } from 'ng-zorro-antd/badge';\nimport { NzDescriptionsModule } from 'ng-zorro-antd/descriptions';\n\n@Component({\n  selector: 'nz-demo-descriptions-vertical-border',\n  imports: [NzBadgeModule, NzDescriptionsModule],\n  template: `\n    <nz-descriptions nzTitle=\"User Info\" nzBordered nzLayout=\"vertical\">\n      <nz-descriptions-item nzTitle=\"Product\">Cloud Database</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Billing Mode\">Prepaid</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Automatic Renewal\">YES</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Order Time\">2018-04-24 18:00:00</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Usage Time\" [nzSpan]=\"2\">\n        2018-04-24 18:00:00 To 2019-04-24 18:00:00\n      </nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Status\" [nzSpan]=\"3\">\n        <nz-badge nzStatus=\"processing\" nzText=\"Running\" />\n      </nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Negotiated Amount\">$80.00</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Discount\">$20.00</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Official Receipts\">$60.00</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Config Info\">\n        Data disk type: MongoDB\n        <br />\n        Database version: 3.4\n        <br />\n        Package: dds.mongo.mid\n        <br />\n        Storage space: 10 GB\n        <br />\n        Replication_factor:3\n        <br />\n        Region: East China 1\n        <br />\n      </nz-descriptions-item>\n    </nz-descriptions>\n  `\n})\nexport class NzDemoDescriptionsVerticalBorderComponent {}\n"
  },
  {
    "path": "components/descriptions/demo/vertical.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 垂直\n  en-US: Vertical\n---\n\n## zh-CN\n\n垂直的列表。\n\n## en-US\n\nSimplest Usage.\n"
  },
  {
    "path": "components/descriptions/demo/vertical.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDescriptionsModule } from 'ng-zorro-antd/descriptions';\n\n@Component({\n  selector: 'nz-demo-descriptions-vertical',\n  imports: [NzDescriptionsModule],\n  template: `\n    <nz-descriptions nzTitle=\"User Info\" nzLayout=\"vertical\">\n      <nz-descriptions-item nzTitle=\"UserName\">Zhou Maomao</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Telephone\">1810000000</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Live\">Hangzhou, Zhejiang</nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Address\" [nzSpan]=\"2\">\n        No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China\n      </nz-descriptions-item>\n      <nz-descriptions-item nzTitle=\"Remark\">empty</nz-descriptions-item>\n    </nz-descriptions>\n  `\n})\nexport class NzDemoDescriptionsVerticalComponent {}\n"
  },
  {
    "path": "components/descriptions/descriptions-item.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  Input,\n  OnChanges,\n  OnDestroy,\n  TemplateRef,\n  ViewChild,\n  ViewEncapsulation,\n  numberAttribute\n} from '@angular/core';\nimport { Subject } from 'rxjs';\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-descriptions-item',\n  template: `\n    <ng-template>\n      <ng-content />\n    </ng-template>\n  `,\n  exportAs: 'nzDescriptionsItem'\n})\nexport class NzDescriptionsItemComponent implements OnChanges, OnDestroy {\n  @ViewChild(TemplateRef, { static: true }) content!: TemplateRef<void>;\n\n  @Input({ transform: numberAttribute }) nzSpan = 1;\n  @Input() nzTitle: string | TemplateRef<void> = '';\n\n  readonly inputChange$ = new Subject<void>();\n\n  ngOnChanges(): void {\n    this.inputChange$.next();\n  }\n\n  ngOnDestroy(): void {\n    this.inputChange$.complete();\n  }\n}\n"
  },
  {
    "path": "components/descriptions/descriptions.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterContentInit,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ContentChildren,\n  DestroyRef,\n  Input,\n  OnChanges,\n  OnInit,\n  QueryList,\n  SimpleChanges,\n  TemplateRef,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { merge } from 'rxjs';\nimport { auditTime, startWith, switchMap, tap } from 'rxjs/operators';\n\nimport { NzConfigKey, NzConfigService, WithConfig } from 'ng-zorro-antd/core/config';\nimport { warn } from 'ng-zorro-antd/core/logger';\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzBreakpointEnum, NzBreakpointService, gridResponsiveMap } from 'ng-zorro-antd/core/services';\n\nimport { NzDescriptionsItemComponent } from './descriptions-item.component';\nimport { NzDescriptionsItemRenderProps, NzDescriptionsLayout, NzDescriptionsSize } from './typings';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'descriptions';\nconst defaultColumnMap: Record<NzBreakpointEnum, number> = {\n  xxl: 3,\n  xl: 3,\n  lg: 3,\n  md: 3,\n  sm: 2,\n  xs: 1\n};\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-descriptions',\n  exportAs: 'nzDescriptions',\n  template: `\n    @if (nzTitle || nzExtra) {\n      <div class=\"ant-descriptions-header\">\n        @if (nzTitle) {\n          <div class=\"ant-descriptions-title\">\n            <ng-container *nzStringTemplateOutlet=\"nzTitle\">{{ nzTitle }}</ng-container>\n          </div>\n        }\n        @if (nzExtra) {\n          <div class=\"ant-descriptions-extra\">\n            <ng-container *nzStringTemplateOutlet=\"nzExtra\">{{ nzExtra }}</ng-container>\n          </div>\n        }\n      </div>\n    }\n\n    <div class=\"ant-descriptions-view\">\n      <table>\n        <tbody>\n          @if (nzLayout === 'horizontal') {\n            @for (row of itemMatrix; track row; let i = $index) {\n              <tr class=\"ant-descriptions-row\">\n                @for (item of row; track item; let isLast = $last) {\n                  @if (!nzBordered) {\n                    <td class=\"ant-descriptions-item\" [colSpan]=\"item.span\">\n                      <div class=\"ant-descriptions-item-container\">\n                        <span class=\"ant-descriptions-item-label\" [class.ant-descriptions-item-no-colon]=\"!nzColon\">\n                          <ng-container *nzStringTemplateOutlet=\"item.title\">\n                            {{ item.title }}\n                          </ng-container>\n                        </span>\n                        <span class=\"ant-descriptions-item-content\">\n                          <ng-template [ngTemplateOutlet]=\"item.content\" />\n                        </span>\n                      </div>\n                    </td>\n                  } @else {\n                    <td class=\"ant-descriptions-item-label\">\n                      <ng-container *nzStringTemplateOutlet=\"item.title\">\n                        {{ item.title }}\n                      </ng-container>\n                    </td>\n                    <td class=\"ant-descriptions-item-content\" [colSpan]=\"item.span * 2 - 1\">\n                      <ng-template [ngTemplateOutlet]=\"item.content\" />\n                    </td>\n                  }\n                }\n              </tr>\n            }\n          }\n\n          @if (nzLayout === 'vertical') {\n            @if (!nzBordered) {\n              @for (row of itemMatrix; track row; let i = $index) {\n                <tr class=\"ant-descriptions-row\">\n                  @for (item of row; track item; let isLast = $last) {\n                    <td class=\"ant-descriptions-item\" [colSpan]=\"item.span\">\n                      <div class=\"ant-descriptions-item-container\">\n                        <span class=\"ant-descriptions-item-label\" [class.ant-descriptions-item-no-colon]=\"!nzColon\">\n                          <ng-container *nzStringTemplateOutlet=\"item.title\">\n                            {{ item.title }}\n                          </ng-container>\n                        </span>\n                      </div>\n                    </td>\n                  }\n                </tr>\n                <tr class=\"ant-descriptions-row\">\n                  @for (item of row; track item; let isLast = $last) {\n                    <td class=\"ant-descriptions-item\" [colSpan]=\"item.span\">\n                      <div class=\"ant-descriptions-item-container\">\n                        <span class=\"ant-descriptions-item-content\">\n                          <ng-template [ngTemplateOutlet]=\"item.content\" />\n                        </span>\n                      </div>\n                    </td>\n                  }\n                </tr>\n              }\n            } @else {\n              @for (row of itemMatrix; track row; let i = $index) {\n                <tr class=\"ant-descriptions-row\">\n                  @for (item of row; track item; let isLast = $last) {\n                    <td class=\"ant-descriptions-item-label\" [colSpan]=\"item.span\">\n                      <ng-container *nzStringTemplateOutlet=\"item.title\">\n                        {{ item.title }}\n                      </ng-container>\n                    </td>\n                  }\n                </tr>\n                <tr class=\"ant-descriptions-row\">\n                  @for (item of row; track item; let isLast = $last) {\n                    <td class=\"ant-descriptions-item-content\" [colSpan]=\"item.span\">\n                      <ng-template [ngTemplateOutlet]=\"item.content\" />\n                    </td>\n                  }\n                </tr>\n              }\n            }\n          }\n        </tbody>\n      </table>\n    </div>\n  `,\n  host: {\n    class: 'ant-descriptions',\n    '[class.ant-descriptions-bordered]': 'nzBordered',\n    '[class.ant-descriptions-middle]': 'nzSize === \"middle\"',\n    '[class.ant-descriptions-small]': 'nzSize === \"small\"',\n    '[class.ant-descriptions-rtl]': 'dir === \"rtl\"'\n  },\n  imports: [NzOutletModule, NgTemplateOutlet]\n})\nexport class NzDescriptionsComponent implements OnChanges, AfterContentInit, OnInit {\n  public nzConfigService = inject(NzConfigService);\n  private cdr = inject(ChangeDetectorRef);\n  private breakpointService = inject(NzBreakpointService);\n  private directionality = inject(Directionality);\n  private destroyRef = inject(DestroyRef);\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  @ContentChildren(NzDescriptionsItemComponent) items!: QueryList<NzDescriptionsItemComponent>;\n\n  @Input({ transform: booleanAttribute }) @WithConfig() nzBordered: boolean = false;\n  @Input() nzLayout: NzDescriptionsLayout = 'horizontal';\n  @Input() @WithConfig() nzColumn: number | Record<NzBreakpointEnum, number> = defaultColumnMap;\n  @Input() @WithConfig() nzSize: NzDescriptionsSize = 'default';\n  @Input() nzTitle: string | TemplateRef<void> = '';\n  @Input() nzExtra?: string | TemplateRef<void>;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzColon: boolean = true;\n\n  itemMatrix: NzDescriptionsItemRenderProps[][] = [];\n  realColumn = 3;\n  dir: Direction = 'ltr';\n\n  private breakpoint: NzBreakpointEnum = NzBreakpointEnum.md;\n\n  ngOnInit(): void {\n    this.dir = this.directionality.value;\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((direction: Direction) => {\n      this.dir = direction;\n    });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    if (changes.nzColumn) {\n      this.prepareMatrix();\n    }\n  }\n\n  ngAfterContentInit(): void {\n    const contentChange$ = this.items.changes.pipe(startWith(this.items));\n\n    merge(\n      contentChange$,\n      contentChange$.pipe(switchMap(() => merge(...this.items.map(i => i.inputChange$)).pipe(auditTime(16)))),\n      this.breakpointService.subscribe(gridResponsiveMap).pipe(tap(bp => (this.breakpoint = bp)))\n    )\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(() => {\n        this.prepareMatrix();\n        this.cdr.markForCheck();\n      });\n  }\n\n  /**\n   * Prepare the render matrix according to description items' spans.\n   */\n  private prepareMatrix(): void {\n    if (!this.items) {\n      return;\n    }\n\n    let currentRow: NzDescriptionsItemRenderProps[] = [];\n    let width = 0;\n\n    const column = (this.realColumn = this.getColumn());\n    const items = this.items.toArray();\n    const length = items.length;\n    const matrix: NzDescriptionsItemRenderProps[][] = [];\n    const flushRow = (): void => {\n      matrix.push(currentRow);\n      currentRow = [];\n      width = 0;\n    };\n\n    for (let i = 0; i < length; i++) {\n      const item = items[i];\n      const { nzTitle: title, content, nzSpan: span } = item;\n\n      width += span;\n\n      // If the last item make the row's length exceeds `nzColumn`, the last\n      // item should take all the space left. This logic is implemented in the template.\n      // Warn user about that.\n      if (width >= column) {\n        if (width > column) {\n          warn(`\"nzColumn\" is ${column} but we have row length ${width}`);\n        }\n        currentRow.push({ title, content, span: column - (width - span) });\n        flushRow();\n      } else if (i === length - 1) {\n        currentRow.push({ title, content, span: column - (width - span) });\n        flushRow();\n      } else {\n        currentRow.push({ title, content, span });\n      }\n    }\n\n    this.itemMatrix = matrix;\n  }\n\n  private getColumn(): number {\n    if (typeof this.nzColumn !== 'number') {\n      return this.nzColumn[this.breakpoint];\n    }\n\n    return this.nzColumn;\n  }\n}\n"
  },
  {
    "path": "components/descriptions/descriptions.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzDescriptionsItemComponent } from './descriptions-item.component';\nimport { NzDescriptionsComponent } from './descriptions.component';\n\n@NgModule({\n  imports: [NzDescriptionsComponent, NzDescriptionsItemComponent],\n  exports: [NzDescriptionsComponent, NzDescriptionsItemComponent]\n})\nexport class NzDescriptionsModule {}\n"
  },
  {
    "path": "components/descriptions/descriptions.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport { Component, provideZoneChangeDetection, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { NzDescriptionsComponent } from './descriptions.component';\nimport { NzDescriptionsModule } from './descriptions.module';\n\n// eslint-disable-next-line  @typescript-eslint/no-explicit-any\ndeclare const viewport: any;\n\ndescribe('descriptions', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  describe('with different spans', () => {\n    let testComponent: NzTestDescriptionsComponent;\n    let componentElement: HTMLElement;\n    let fixture: ComponentFixture<NzTestDescriptionsComponent>;\n    let rows;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestDescriptionsComponent);\n      testComponent = fixture.componentInstance;\n      componentElement = fixture.debugElement.nativeElement;\n      fixture.detectChanges();\n    });\n\n    it('should have correct layout', () => {\n      let title = componentElement.querySelector('.ant-descriptions-title');\n      const view = componentElement.querySelector('.ant-descriptions-view');\n\n      expect(title).toBeTruthy();\n      expect(view).toBeTruthy();\n\n      testComponent.title = '';\n      fixture.detectChanges();\n      title = componentElement.querySelector('.ant-descriptions-title');\n      expect(title).toBeFalsy();\n    });\n\n    it('should render spans correctly', () => {\n      const spyOnWarn = spyOn(console, 'warn');\n      spyOnWarn.calls.reset();\n      rows = componentElement.querySelectorAll('.ant-descriptions-row');\n      expect(rows.length).toBe(1);\n\n      testComponent.colspanArray = [1, 1, 1, 2, 3, 1, 5];\n      fixture.detectChanges();\n      rows = componentElement.querySelectorAll('.ant-descriptions-row');\n      expect(rows.length).toBe(3);\n      expect(spyOnWarn).toHaveBeenCalledTimes(2);\n      expect(spyOnWarn).toHaveBeenCalledWith('[NG-ZORRO]:', '\"nzColumn\" is 3 but we have row length 5');\n      expect(spyOnWarn).toHaveBeenCalledWith('[NG-ZORRO]:', '\"nzColumn\" is 3 but we have row length 6');\n\n      testComponent.column = 5;\n      testComponent.colspanArray = [1, 2, 3];\n      fixture.detectChanges();\n      rows = componentElement.querySelectorAll('.ant-descriptions-row');\n      expect(rows.length).toBe(1);\n      expect(spyOnWarn).toHaveBeenCalledTimes(4);\n      expect(spyOnWarn).toHaveBeenCalledWith('[NG-ZORRO]:', '\"nzColumn\" is 5 but we have row length 6');\n\n      testComponent.colspanArray = [1, 2, 2];\n      fixture.detectChanges();\n      rows = componentElement.querySelectorAll('.ant-descriptions-row');\n      expect(rows.length).toBe(1);\n\n      // Should the last fill the rest space.\n      testComponent.colspanArray = [1, 1];\n      fixture.detectChanges();\n      rows = componentElement.querySelectorAll('.ant-descriptions-row');\n      const tds = componentElement.querySelectorAll('.ant-descriptions-item');\n      expect(rows.length).toBe(1);\n      expect((tds[1] as HTMLTableCellElement).colSpan).toBe(4);\n      spyOnWarn.calls.reset();\n    });\n\n    it('should responsive work', fakeAsync(() => {\n      testComponent.column = {\n        xxl: 3,\n        xl: 3,\n        lg: 3,\n        md: 3,\n        sm: 2,\n        xs: 1\n      };\n      testComponent.colspanArray = [1, 1, 1, 2, 3, 1, 5];\n\n      viewport.set(1024, 1024);\n      window.dispatchEvent(new Event('resize'));\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n      rows = componentElement.querySelectorAll('.ant-descriptions-row');\n      expect(rows.length).toBe(3);\n\n      viewport.set(320, 320);\n      window.dispatchEvent(new Event('resize'));\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n\n      rows = componentElement.querySelectorAll('.ant-descriptions-row');\n      expect(rows.length).toBe(7);\n\n      viewport.reset();\n    }));\n\n    // fix #3795\n    it('should change to use content work', fakeAsync(() => {\n      let firstTitle = componentElement.querySelector('.ant-descriptions-item-label') as HTMLSpanElement;\n      expect(firstTitle.innerText).toBe('Item Title 0');\n\n      testComponent.itemTitle = 'Item ';\n      fixture.detectChanges();\n      tick(16);\n      fixture.detectChanges();\n      firstTitle = componentElement.querySelector('.ant-descriptions-item-label') as HTMLSpanElement;\n      expect(firstTitle.innerText).toBe('Item 0');\n    }));\n  });\n\n  describe('RTL', () => {\n    let fixture: ComponentFixture<NzTestDescriptionsRtlComponent>;\n    let componentElement: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestDescriptionsRtlComponent);\n      componentElement = fixture.debugElement.query(By.directive(NzDescriptionsComponent)).nativeElement;\n      fixture.detectChanges();\n    });\n\n    it('should className correct on dir change', fakeAsync(() => {\n      expect(componentElement.classList).toContain('ant-descriptions-rtl');\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n      expect(componentElement.classList).not.toContain('ant-descriptions-rtl');\n    }));\n  });\n});\n\n@Component({\n  imports: [NzDescriptionsModule],\n  selector: 'nz-test-descriptions',\n  template: `\n    <nz-descriptions [nzTitle]=\"title\" [nzBordered]=\"bordered\" [nzColumn]=\"column\">\n      @for (col of colspanArray; track $index) {\n        <nz-descriptions-item [nzTitle]=\"itemTitle + $index\" [nzSpan]=\"col\" />\n      }\n    </nz-descriptions>\n  `\n})\nexport class NzTestDescriptionsComponent {\n  bordered = false;\n  colspanArray: number[] = [1, 1, 1];\n  column: NzDescriptionsComponent['nzColumn'] = 3;\n  title = 'Title';\n  itemTitle = 'Item Title ';\n}\n\n@Component({\n  imports: [BidiModule, NzTestDescriptionsComponent],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-test-descriptions />\n    </div>\n  `\n})\nexport class NzTestDescriptionsRtlComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n}\n"
  },
  {
    "path": "components/descriptions/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Display\ntitle: Descriptions\ncols: 1\ncover: 'https://gw.alipayobjects.com/zos/alicdn/MjtG9_FOI/Descriptions.svg'\ndescription: Display multiple read-only fields in a group.\n---\n\n## When To Use\n\nCommonly displayed on the details page.\n\n## API\n\n### nz-descriptions\n\n| Property       | Description                                                                                                     | Type                               | Default                                         | Global Config |\n| -------------- | --------------------------------------------------------------------------------------------------------------- | ---------------------------------- | ----------------------------------------------- | ------------- |\n| `[nzTitle]`    | Describe the title of the list, displayed at the top                                                            | `string \\| TemplateRef<void>`      | `false`                                         |\n| `[nzExtra]`    | The action area of the description list, placed at the top-right                                                | `string \\| TemplateRef<void>`      | `-`                                             |\n| `[nzBordered]` | Whether to display the border                                                                                   | `boolean`                          | `false`                                         | ✅            |\n| `[nzColumn]`   | The number of `nz-descriptions-item` in a row. It could be a number or a object like `{ xs: 8, sm: 16, md: 24}` | `number \\| object`                 | `{ xxl: 3, xl: 3, lg: 3, md: 3, sm: 2, xs: 1 }` | ✅            |\n| `[nzSize]`     | Set the size of the list. Only works when `nzBordered` is set                                                   | `'default' \\| 'middle' \\| 'small'` | `'default'`                                     | ✅            |\n| `[nzColon]`    | Show colon after title                                                                                          | `boolean`                          | `true`                                          | ✅            |\n| `[nzLayout]`   | Set the layout of the list                                                                                      | `'horizontal' \\| 'vertical'`       | `'horizontal'`                                  |               |\n\n### nz-descriptions-item\n\n| Property    | Description                    | Type      | Default                       |\n| ----------- | ------------------------------ | --------- | ----------------------------- |\n| `[nzTitle]` | Description of the content     | `boolean` | `string \\| TemplateRef<void>` |\n| `[nzSpan]`  | The number of columns included | `number`  | `1`                           |\n"
  },
  {
    "path": "components/descriptions/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ntype: 数据展示\ntitle: Descriptions\nsubtitle: 描述列表\ncols: 1\ncover: 'https://gw.alipayobjects.com/zos/alicdn/MjtG9_FOI/Descriptions.svg'\ndescription: 展示多个只读字段的组合。\n---\n\n## 何时使用\n\n常见于详情页的信息展示。\n\n## API\n\n### nz-descriptions\n\n| 参数           | 说明                                                                                                  | 类型                               | 默认值                                          | 支持全局配置 |\n| -------------- | ----------------------------------------------------------------------------------------------------- | ---------------------------------- | ----------------------------------------------- | ------------ |\n| `[nzTitle]`    | 描述列表的标题，显示在最顶部                                                                          | `string \\| TemplateRef<void>`      | `false`                                         |\n| `[nzExtra]`    | 描述列表的操作区域，显示在右上方                                                                      | `string \\| TemplateRef<void>`      | `-`                                             |\n| `[nzBordered]` | 是否展示边框                                                                                          | `boolean`                          | `false`                                         | ✅           |\n| `[nzColumn]`   | 一行的 `nz-descriptions-item` 的数量，可以写成像素值或支持响应式的对象写法 `{ xs: 8, sm: 16, md: 24}` | `number \\| object`                 | `{ xxl: 3, xl: 3, lg: 3, md: 3, sm: 2, xs: 1 }` | ✅           |\n| `[nzSize]`     | 设置列表的大小（只有设置 `nzBordered` 时生效）                                                        | `'default' \\| 'middle' \\| 'small'` | `'default'`                                     | ✅           |\n| `[nzColon]`    | 在标题后显示冒号                                                                                      | `boolean`                          | `true`                                          | ✅           |\n\n### nz-descriptions-item\n\n| 参数        | 说明         | 类型                          | 默认值 |\n| ----------- | ------------ | ----------------------------- | ------ |\n| `[nzTitle]` | 内容的描述   | `string \\| TemplateRef<void>` | -      |\n| `[nzSpan]`  | 包含列的数量 | `number`                      | `1`    |\n"
  },
  {
    "path": "components/descriptions/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/descriptions/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/descriptions/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport { NzDescriptionsModule } from './descriptions.module';\nexport { NzDescriptionsComponent } from './descriptions.component';\nexport { NzDescriptionsItemComponent } from './descriptions-item.component';\n\nexport * from './typings';\n"
  },
  {
    "path": "components/descriptions/style/entry.less",
    "content": "@import \"./index.less\";\n@import \"./patch\";"
  },
  {
    "path": "components/descriptions/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@descriptions-prefix-cls: ~'@{ant-prefix}-descriptions';\n\n.@{descriptions-prefix-cls} {\n  &-header {\n    display: flex;\n    align-items: center;\n    margin-bottom: @descriptions-title-margin-bottom;\n  }\n\n  &-title {\n    flex: auto;\n    overflow: hidden;\n    color: @heading-color;\n    font-weight: bold;\n    font-size: @font-size-lg;\n    line-height: @line-height-base;\n    white-space: nowrap;\n    text-overflow: ellipsis;\n  }\n\n  &-extra {\n    margin-left: auto;\n    color: @descriptions-extra-color;\n    font-size: @font-size-base;\n  }\n\n  &-view {\n    width: 100%;\n    border-radius: @border-radius-base;\n\n    table {\n      width: 100%;\n      table-layout: fixed;\n    }\n  }\n\n  &-row {\n    > th,\n    > td {\n      padding-bottom: @descriptions-item-padding-bottom;\n    }\n\n    &:last-child {\n      border-bottom: none;\n    }\n  }\n\n  &-item-label {\n    color: @heading-color;\n    font-weight: normal;\n    font-size: @font-size-base;\n    line-height: @line-height-base;\n    text-align: start;\n\n    &::after {\n      & when (@descriptions-item-trailing-colon=true) {\n        content: ':';\n      }\n      & when not (@descriptions-item-trailing-colon=true) {\n        content: ' ';\n      }\n\n      position: relative;\n      top: -0.5px;\n      margin: 0 @descriptions-item-label-colon-margin-right 0\n        @descriptions-item-label-colon-margin-left;\n    }\n\n    &.@{descriptions-prefix-cls}-item-no-colon::after {\n      content: ' ';\n    }\n  }\n\n  &-item-no-label {\n    &::after {\n      margin: 0;\n      content: '';\n    }\n  }\n\n  &-item-content {\n    display: table-cell;\n    flex: 1;\n    color: @text-color;\n    font-size: @font-size-base;\n    line-height: @line-height-base;\n    word-break: break-word;\n    overflow-wrap: break-word;\n  }\n\n  &-item {\n    padding-bottom: 0;\n    vertical-align: top;\n\n    &-container {\n      display: flex;\n\n      .@{descriptions-prefix-cls}-item-label,\n      .@{descriptions-prefix-cls}-item-content {\n        display: inline-flex;\n        align-items: baseline;\n      }\n    }\n  }\n\n  &-middle {\n    .@{descriptions-prefix-cls}-row {\n      > th,\n      > td {\n        padding-bottom: @padding-sm;\n      }\n    }\n  }\n\n  &-small {\n    .@{descriptions-prefix-cls}-row {\n      > th,\n      > td {\n        padding-bottom: @padding-xs;\n      }\n    }\n  }\n\n  &-bordered {\n    .@{descriptions-prefix-cls}-view {\n      border: 1px solid @border-color-split;\n\n      > table {\n        table-layout: auto;\n        border-collapse: collapse;\n      }\n    }\n\n    .@{descriptions-prefix-cls}-item-label,\n    .@{descriptions-prefix-cls}-item-content {\n      padding: @descriptions-default-padding;\n      border-right: 1px solid @border-color-split;\n\n      &:last-child {\n        border-right: none;\n      }\n    }\n\n    .@{descriptions-prefix-cls}-item-label {\n      background-color: @descriptions-bg;\n\n      &::after {\n        display: none;\n      }\n    }\n\n    .@{descriptions-prefix-cls}-row {\n      border-bottom: 1px solid @border-color-split;\n\n      &:last-child {\n        border-bottom: none;\n      }\n    }\n\n    &.@{descriptions-prefix-cls}-middle {\n      .@{descriptions-prefix-cls}-item-label,\n      .@{descriptions-prefix-cls}-item-content {\n        padding: @descriptions-middle-padding;\n      }\n    }\n\n    &.@{descriptions-prefix-cls}-small {\n      .@{descriptions-prefix-cls}-item-label,\n      .@{descriptions-prefix-cls}-item-content {\n        padding: @descriptions-small-padding;\n      }\n    }\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/descriptions/style/patch.less",
    "content": "nz-descriptions {\n  display: block;\n}\n"
  },
  {
    "path": "components/descriptions/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@descriptions-prefix-cls: ~'@{ant-prefix}-descriptions';\n\n.@{descriptions-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &-item-label {\n    &::after {\n      .@{descriptions-prefix-cls}-rtl & {\n        margin: 0 @descriptions-item-label-colon-margin-left 0\n          @descriptions-item-label-colon-margin-right;\n      }\n    }\n  }\n\n  &-bordered {\n    .@{descriptions-prefix-cls}-item-label,\n    .@{descriptions-prefix-cls}-item-content {\n      .@{descriptions-prefix-cls}-rtl& {\n        border-right: none;\n        border-left: 1px solid @border-color-split;\n\n        &:last-child {\n          border-left: none;\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/descriptions/typings.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { TemplateRef } from '@angular/core';\n\nexport type NzDescriptionsSize = 'default' | 'middle' | 'small';\n\nexport type NzDescriptionsLayout = 'horizontal' | 'vertical';\n\nexport interface NzDescriptionsItemRenderProps {\n  title: string | TemplateRef<void>;\n  span: number;\n  content: TemplateRef<void>;\n}\n"
  },
  {
    "path": "components/divider/demo/horizontal.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 水平分割线\n  en-US: Horizontal\n---\n\n## zh-CN\n\n默认为水平分割线，可在中间加入文字。\n\n## en-US\n\nDivider default type is `horizontal`. Support inner text inside Divider.\n"
  },
  {
    "path": "components/divider/demo/horizontal.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-demo-divider-horizontal',\n  imports: [NzDividerModule, NzIconModule],\n  template: `\n    <div>\n      <p>\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae\n        sunt a te dicta? Refert tamen, quo modo.\n      </p>\n      <nz-divider />\n      <p>\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae\n        sunt a te dicta? Refert tamen, quo modo.\n      </p>\n      <nz-divider nzText=\"With Text\" />\n      <p>\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae\n        sunt a te dicta? Refert tamen, quo modo.\n      </p>\n      <nz-divider nzDashed [nzText]=\"text\">\n        <ng-template #text>\n          <nz-icon nzType=\"plus\" />\n          Add\n        </ng-template>\n      </nz-divider>\n\n      <p>\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae\n        sunt a te dicta? Refert tamen, quo modo.\n      </p>\n    </div>\n  `\n})\nexport class NzDemoDividerHorizontalComponent {}\n"
  },
  {
    "path": "components/divider/demo/orientation.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 标题位置\n  en-US: Orientation of title\n---\n\n## zh-CN\n\n修改分割线标题的位置。\n\n## en-US\n\nSet orientation of divider to left or right.\n"
  },
  {
    "path": "components/divider/demo/orientation.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\n\n@Component({\n  selector: 'nz-demo-divider-orientation',\n  imports: [NzDividerModule],\n  template: `\n    <div>\n      <p>\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae\n        sunt a te dicta? Refert tamen, quo modo.\n      </p>\n      <nz-divider nzText=\"Text\" />\n      <p>\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae\n        sunt a te dicta? Refert tamen, quo modo.\n      </p>\n      <nz-divider nzText=\"Left Text\" nzOrientation=\"left\" />\n      <p>\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae\n        sunt a te dicta? Refert tamen, quo modo.\n      </p>\n      <nz-divider nzText=\"Right Text\" nzOrientation=\"right\" />\n      <p>\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae\n        sunt a te dicta? Refert tamen, quo modo.\n      </p>\n    </div>\n  `\n})\nexport class NzDemoDividerOrientationComponent {}\n"
  },
  {
    "path": "components/divider/demo/plain.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 分割文字使用正文样式\n  en-US: Text without heading style\n---\n\n## zh-CN\n\n使用 `nzPlain` 可以设置为更轻量的分割文字样式。\n\n## en-US\n\nYou can use non-heading style of divider text by setting `nzPlain`.\n"
  },
  {
    "path": "components/divider/demo/plain.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\n\n@Component({\n  selector: 'nz-demo-divider-plain',\n  imports: [NzDividerModule],\n  template: `\n    <div>\n      <p>\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae\n        sunt a te dicta? Refert tamen, quo modo.\n      </p>\n      <nz-divider nzPlain nzText=\"Text\" />\n      <p>\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae\n        sunt a te dicta? Refert tamen, quo modo.\n      </p>\n      <nz-divider nzPlain nzText=\"Left Text\" nzOrientation=\"left\" />\n      <p>\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae\n        sunt a te dicta? Refert tamen, quo modo.\n      </p>\n      <nz-divider nzPlain nzText=\"Right Text\" nzOrientation=\"right\" />\n      <p>\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae\n        sunt a te dicta? Refert tamen, quo modo.\n      </p>\n    </div>\n  `\n})\nexport class NzDemoDividerPlainComponent {}\n"
  },
  {
    "path": "components/divider/demo/size.md",
    "content": "---\norder: 5\nversion: 20.2.0\ntitle:\n  zh-CN: 分割线大小\n  en-US: Size\n---\n\n## zh-CN\n\n通过 `nzSize` 设置分割线的大小。\n\n## en-US\n\nDivider support `nzSize` to set the size of Divider.\n"
  },
  {
    "path": "components/divider/demo/size.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-demo-divider-size',\n  imports: [NzDividerModule, NzIconModule],\n  template: `\n    <div>\n      <p>\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae\n        sunt a te dicta? Refert tamen, quo modo.\n      </p>\n      <nz-divider nzSize=\"small\" />\n      <p>\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae\n        sunt a te dicta? Refert tamen, quo modo.\n      </p>\n      <nz-divider nzSize=\"middle\" />\n      <p>\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae\n        sunt a te dicta? Refert tamen, quo modo.\n      </p>\n      <nz-divider nzSize=\"large\" />\n      <p>\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae\n        sunt a te dicta? Refert tamen, quo modo.\n      </p>\n    </div>\n  `\n})\nexport class NzDemoDividerSizeComponent {}\n"
  },
  {
    "path": "components/divider/demo/variant.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 变体\n  en-US: Variant\n---\n\n## zh-CN\n\n分隔线默认为 `solid`（实线）变体。您可以将其更改为 `dashed`（虚线）或 `dotted`（点线）。\n\n## en-US\n\nDivider is of `solid` variant by default. You can change that to either `dashed` or `dotted`.\n"
  },
  {
    "path": "components/divider/demo/variant.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\n\n@Component({\n  selector: 'nz-demo-divider-variant',\n  imports: [NzDividerModule],\n  template: `\n    <div>\n      <p>\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae\n        sunt a te dicta? Refert tamen, quo modo.\n      </p>\n      <nz-divider nzPlain nzText=\"Solid\" nzVariant=\"solid\" />\n      <p>\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae\n        sunt a te dicta? Refert tamen, quo modo.\n      </p>\n      <nz-divider nzPlain nzText=\"Dotted\" nzVariant=\"dotted\" />\n      <p>\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae\n        sunt a te dicta? Refert tamen, quo modo.\n      </p>\n      <nz-divider nzPlain nzText=\"Dashed\" nzVariant=\"dashed\" />\n      <p>\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae\n        sunt a te dicta? Refert tamen, quo modo.\n      </p>\n    </div>\n  `,\n  styles: `\n    nz-divider::after,\n    nz-divider::before {\n      border-color: #7cb305 !important;\n    }\n  `\n})\nexport class NzDemoDividerVariantComponent {}\n"
  },
  {
    "path": "components/divider/demo/vertical.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 垂直分割线\n  en-US: Vertical\n---\n\n## zh-CN\n\n使用 `nzType=\"vertical\"` 设置为行内的垂直分割线。\n\n## en-US\n\nUse `nzType=\"vertical\"` make it vertical.\n"
  },
  {
    "path": "components/divider/demo/vertical.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\n\n@Component({\n  selector: 'nz-demo-divider-vertical',\n  imports: [NzDividerModule],\n  template: `\n    <div>\n      Text\n      <nz-divider nzType=\"vertical\" />\n      <a href=\"#\">Link</a>\n      <nz-divider nzType=\"vertical\" />\n      <a href=\"#\">Link</a>\n    </div>\n  `\n})\nexport class NzDemoDividerVerticalComponent {}\n"
  },
  {
    "path": "components/divider/divider.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  Input,\n  TemplateRef,\n  ViewEncapsulation,\n  booleanAttribute\n} from '@angular/core';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport type { NzSizeLMSType } from 'ng-zorro-antd/core/types';\n\n@Component({\n  selector: 'nz-divider',\n  exportAs: 'nzDivider',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    @if (nzText) {\n      <span class=\"ant-divider-inner-text\">\n        <ng-container *nzStringTemplateOutlet=\"nzText\">{{ nzText }}</ng-container>\n      </span>\n    }\n  `,\n  host: {\n    class: 'ant-divider',\n    '[class.ant-divider-horizontal]': `nzType === 'horizontal'`,\n    '[class.ant-divider-vertical]': `nzType === 'vertical'`,\n    '[class.ant-divider-with-text]': `nzText`,\n    '[class.ant-divider-plain]': `nzPlain`,\n    '[class.ant-divider-with-text-left]': `nzText && nzOrientation === 'left'`,\n    '[class.ant-divider-with-text-right]': `nzText && nzOrientation === 'right'`,\n    '[class.ant-divider-with-text-center]': `nzText && nzOrientation === 'center'`,\n    '[class.ant-divider-dashed]': `nzDashed || nzVariant === 'dashed'`,\n    '[class.ant-divider-dotted]': `nzVariant === 'dotted'`,\n    '[class.ant-divider-sm]': `nzSize === 'small'`,\n    '[class.ant-divider-md]': `nzSize === 'middle'`\n  },\n  imports: [NzOutletModule]\n})\nexport class NzDividerComponent {\n  @Input() nzText?: string | TemplateRef<void>;\n  @Input() nzType: 'horizontal' | 'vertical' = 'horizontal';\n  @Input() nzOrientation: 'left' | 'right' | 'center' = 'center';\n  @Input() nzVariant: 'dashed' | 'dotted' | 'solid' = 'solid';\n  @Input() nzSize: NzSizeLMSType | undefined;\n  @Input({ transform: booleanAttribute }) nzDashed = false;\n  @Input({ transform: booleanAttribute }) nzPlain = false;\n}\n"
  },
  {
    "path": "components/divider/divider.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzDividerComponent } from './divider.component';\n\n@NgModule({\n  imports: [NzDividerComponent],\n  exports: [NzDividerComponent]\n})\nexport class NzDividerModule {}\n"
  },
  {
    "path": "components/divider/divider.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, DebugElement, provideZoneChangeDetection, ViewChild } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzDividerComponent } from './divider.component';\nimport { NzDividerModule } from './divider.module';\n\ndescribe('divider', () => {\n  let fixture: ComponentFixture<TestDividerComponent>;\n  let context: TestDividerComponent;\n  let dl: DebugElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideZoneChangeDetection()]\n    });\n    fixture = TestBed.createComponent(TestDividerComponent);\n    context = fixture.componentInstance;\n    dl = fixture.debugElement;\n    fixture.detectChanges();\n  });\n\n  describe('#nzDashed', () => {\n    for (const value of [true, false]) {\n      it(`[${value}]`, () => {\n        context.nzDashed = value;\n        fixture.detectChanges();\n        expect(dl.query(By.css('.ant-divider-dashed')) != null).toBe(value);\n      });\n    }\n  });\n\n  describe('#nzType', () => {\n    for (const value of ['horizontal', 'vertical'] as const) {\n      it(`[${value}]`, () => {\n        context.nzType = value;\n        fixture.detectChanges();\n        expect(dl.query(By.css(`.ant-divider-${value}`)) != null).toBe(true);\n      });\n    }\n  });\n\n  describe('#nzText', () => {\n    for (const item of [\n      { text: 'with text', ret: true },\n      { text: undefined, ret: false }\n    ]) {\n      it(`[${item.text}]`, () => {\n        context.nzText = item.text;\n        fixture.detectChanges();\n        expect(dl.query(By.css('.ant-divider-inner-text')) != null).toBe(item.ret);\n      });\n    }\n\n    it('should be custom template', () => {\n      const fixture = TestBed.createComponent(TestDividerTextTemplateComponent);\n      fixture.detectChanges();\n      expect(fixture.debugElement.query(By.css('.anticon-plus')) != null).toBe(true);\n    });\n  });\n\n  describe('#nzOrientation', () => {\n    (['center', 'left', 'right'] as const).forEach(type => {\n      it(`with ${type}`, () => {\n        context.nzOrientation = type;\n        fixture.detectChanges();\n        expect(dl.query(By.css(`.ant-divider-with-text-${type}`)) != null).toBe(true);\n      });\n    });\n  });\n\n  describe('#nzVariant', () => {\n    (['dashed', 'dotted'] as const).forEach(type => {\n      it(`with ${type}`, () => {\n        context.comp.nzVariant = type;\n        fixture.detectChanges();\n        expect(dl.query(By.css(`.ant-divider-${type}`)) != null).toBe(true);\n      });\n    });\n\n    it('should have solid as default value for nzVariant', () => {\n      expect(context.comp.nzVariant).toEqual('solid');\n    });\n  });\n\n  describe('#nzPlain', () => {\n    for (const value of [true, false]) {\n      it(`[${value}]`, () => {\n        context.comp.nzPlain = value;\n        fixture.detectChanges();\n        expect(dl.query(By.css('.ant-divider-plain')) != null).toBe(value);\n      });\n    }\n  });\n\n  describe('#nzSize', () => {\n    it('should not have size class by default', () => {\n      fixture.detectChanges();\n      const el = dl.query(By.css('.ant-divider'))!.nativeElement as HTMLElement;\n      expect(el.classList.contains('ant-divider-sm')).toBe(false);\n      expect(el.classList.contains('ant-divider-md')).toBe(false);\n      expect(el.classList.contains('ant-divider-lg')).toBe(false);\n    });\n\n    (['small', 'middle', 'large'] as const).forEach(size => {\n      it(`with ${size}`, () => {\n        context.comp.nzSize = size;\n        fixture.detectChanges();\n        const el = dl.query(By.css('.ant-divider'))!.nativeElement as HTMLElement;\n        expect(el.classList.contains('ant-divider-sm')).toBe(size === 'small');\n        expect(el.classList.contains('ant-divider-md')).toBe(size === 'middle');\n        // Large size does not have a specific class; ensure no lg class is added\n        expect(el.classList.contains('ant-divider-lg')).toBe(false);\n      });\n    });\n  });\n\n  describe('#with text class', () => {\n    it('should have ant-divider-with-text when nzText set', () => {\n      context.nzText = 'text';\n      fixture.detectChanges();\n      expect(dl.query(By.css('.ant-divider-with-text')) != null).toBe(true);\n    });\n\n    it('should not have ant-divider-with-text when nzText removed', () => {\n      context.nzText = undefined;\n      fixture.detectChanges();\n      expect(dl.query(By.css('.ant-divider-with-text')) == null).toBe(true);\n    });\n  });\n});\n\n@Component({\n  imports: [NzDividerModule],\n  template: `\n    <nz-divider #comp [nzDashed]=\"nzDashed\" [nzType]=\"nzType\" [nzText]=\"nzText\" [nzOrientation]=\"nzOrientation\" />\n  `\n})\nclass TestDividerComponent {\n  @ViewChild('comp', { static: false }) comp!: NzDividerComponent;\n  nzDashed = false;\n  nzType: 'vertical' | 'horizontal' = 'horizontal';\n  nzText?: string = 'with text';\n  nzOrientation!: 'left' | 'right' | 'center';\n}\n\n@Component({\n  imports: [NzDividerModule, NzIconModule],\n  template: `\n    <nz-divider nzDashed [nzText]=\"text\">\n      <ng-template #text>\n        <nz-icon nzType=\"plus\" />\n        Add\n      </ng-template>\n    </nz-divider>\n  `\n})\nclass TestDividerTextTemplateComponent {}\n"
  },
  {
    "path": "components/divider/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Layout\ntitle: Divider\ncover: 'https://gw.alipayobjects.com/zos/alicdn/5swjECahe/Divider.svg'\ndescription: A divider line separates different content.\n---\n\n## When To Use\n\n- Divide sections of article.\n- Divide inline text and links such as the operation column of table.\n\n## API\n\n### nz-divider\n\n| Property          | Description                             | Type                              | Default        | Version |\n| ----------------- | --------------------------------------- | --------------------------------- | -------------- | ------- |\n| `[nzDashed]`      | whether line is dashed                  | `boolean`                         | `false`        |\n| `[nzType]`        | direction type of divider               | `'horizontal' \\| 'vertical'`      | `'horizontal'` |\n| `[nzText]`        | inner text of divider                   | `string \\| TemplateRef<void>`     | -              |\n| `[nzPlain]`       | Divider text show as plain style        | `boolean`                         | `false`        |\n| `[nzOrientation]` | inner text orientation                  | `'center' \\| 'left' \\| 'right'`   | `'center'`     |\n| `[nzVariant]`     | Whether line is dashed, dotted or solid | `'dashed' \\| 'dotted' \\| 'solid'` | `'solid'`      |\n| `[nzSize]`        | Divider size                            | `'small' \\| 'middle' \\| 'large'`  | -              | 20.2.0  |\n"
  },
  {
    "path": "components/divider/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ntype: 布局\ntitle: Divider\nsubtitle: 分割线\ncover: 'https://gw.alipayobjects.com/zos/alicdn/5swjECahe/Divider.svg'\ndescription: 区隔内容的分割线。\n---\n\n## 何时使用\n\n- 对不同章节的文本段落进行分割。\n- 对行内文字/链接进行分割，例如表格的操作列。\n\n## API\n\n### nz-divider\n\n| 参数              | 说明                       | 类型                              | 默认值         | 版本   |\n| ----------------- | -------------------------- | --------------------------------- | -------------- | ------ |\n| `[nzDashed]`      | 是否虚线                   | `boolean`                         | `false`        |\n| `[nzType]`        | 水平还是垂直类型           | `'horizontal' \\| 'vertical'`      | `'horizontal'` |\n| `[nzText]`        | 中间文字                   | `string \\| TemplateRef<void>`     | -              |\n| `[nzPlain]`       | 文字是否显示为普通正文样式 | `boolean`                         | `false`        |\n| `[nzOrientation]` | 中间文字方向               | `'center' \\| 'left' \\| 'right'`   | `'center'`     |\n| `[nzVariant]`     | 分割线是虚线、点线还是实线 | `'dashed' \\| 'dotted' \\| 'solid'` | `'solid'`      |\n| `[nzSize]`        | 分割线大小                 | `'small' \\| 'middle' \\| 'large'`  | -              | 20.2.0 |\n"
  },
  {
    "path": "components/divider/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/divider/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/divider/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './divider.component';\nexport * from './divider.module';\n"
  },
  {
    "path": "components/divider/style/entry.less",
    "content": "@import './index.less';\n@import './patch.less';\n"
  },
  {
    "path": "components/divider/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@divider-prefix-cls: ~'@{ant-prefix}-divider';\n\n.@{divider-prefix-cls} {\n  .reset-component();\n\n  border-top: @border-width-base solid @divider-color;\n\n  &-vertical {\n    position: relative;\n    top: -0.06em;\n    display: inline-block;\n    height: 0.9em;\n    margin: 0 @divider-vertical-gutter;\n    vertical-align: middle;\n    border-top: 0;\n    border-left: @border-width-base solid @divider-color;\n  }\n\n  &-horizontal {\n    display: flex;\n    clear: both;\n    width: 100%;\n    min-width: 100%; // Fix https://github.com/ant-design/ant-design/issues/10914\n    margin: 24px 0;\n  }\n\n  &-horizontal&-with-text {\n    display: flex;\n    align-items: center;\n    margin: 16px 0;\n    color: @heading-color;\n    font-weight: 500;\n    font-size: @font-size-lg;\n    white-space: nowrap;\n    text-align: center;\n    border-top: 0;\n    border-top-color: @divider-color;\n\n    &::before,\n    &::after {\n      position: relative;\n      width: 50%;\n      border-top: @border-width-base solid transparent;\n      // Chrome not accept `inherit` in `border-top`\n      border-top-color: inherit;\n      border-bottom: 0;\n      transform: translateY(50%);\n      content: '';\n    }\n  }\n\n  &-horizontal&-with-text-left {\n    &::before {\n      width: @divider-orientation-margin;\n    }\n\n    &::after {\n      width: 100% - @divider-orientation-margin;\n    }\n  }\n\n  &-horizontal&-with-text-right {\n    &::before {\n      width: 100% - @divider-orientation-margin;\n    }\n\n    &::after {\n      width: @divider-orientation-margin;\n    }\n  }\n\n  &-inner-text {\n    display: inline-block;\n    padding: 0 @divider-text-padding;\n  }\n\n  &-dashed {\n    background: none;\n    border-color: @divider-color;\n    border-style: dashed;\n    border-width: @border-width-base 0 0;\n  }\n\n  &-horizontal&-with-text&-dashed {\n    &::before,\n    &::after {\n      border-style: dashed none none;\n    }\n  }\n\n  &-vertical&-dashed {\n    border-width: 0 0 0 @border-width-base;\n  }\n\n  &-plain&-with-text {\n    color: @text-color;\n    font-weight: normal;\n    font-size: @font-size-base;\n  }\n\n  &-horizontal&-with-text-left&-no-default-orientation-margin-left {\n    &::before {\n      width: 0;\n    }\n\n    &::after {\n      width: 100%;\n    }\n\n    .@{divider-prefix-cls}-inner-text {\n      padding-left: 0;\n    }\n  }\n\n  &-horizontal&-with-text-right&-no-default-orientation-margin-right {\n    &::before {\n      width: 100%;\n    }\n\n    &::after {\n      width: 0;\n    }\n\n    .@{divider-prefix-cls}-inner-text {\n      padding-right: 0;\n    }\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/divider/style/patch.less",
    "content": "@import '../../style/themes/index';\n\n.@{divider-prefix-cls} {\n  &-dotted {\n    background: none;\n    border-color: @divider-color;\n    border-style: dotted;\n    border-width: @border-width-base 0 0;\n  }\n\n  &-horizontal&-with-text&-dotted {\n    &::after,\n    &::before {\n      border-style: dotted none none;\n    }\n  }\n\n  &-vertical&-dotted {\n    border-width: 0 0 0 @border-width-base;\n  }\n\n  &-sm {\n    margin-block: @margin-xs;\n  }\n\n  &-md {\n    margin-block: @margin-md;\n  }\n}\n"
  },
  {
    "path": "components/divider/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@divider-prefix-cls: ~'@{ant-prefix}-divider';\n\n.@{divider-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &-horizontal&-with-text-left {\n    &::before {\n      .@{divider-prefix-cls}-rtl& {\n        width: 100% - @divider-orientation-margin;\n      }\n    }\n\n    &::after {\n      .@{divider-prefix-cls}-rtl& {\n        width: @divider-orientation-margin;\n      }\n    }\n  }\n\n  &-horizontal&-with-text-right {\n    &::before {\n      .@{divider-prefix-cls}-rtl& {\n        width: @divider-orientation-margin;\n      }\n    }\n\n    &::after {\n      .@{divider-prefix-cls}-rtl& {\n        width: 100% - @divider-orientation-margin;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/drawer/demo/basic-right.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基础抽屉\n  en-US: Basic\n---\n\n## zh-CN\n\n基础抽屉，点击触发按钮抽屉从右滑出，点击遮罩区关闭\n\n## en-US\n\nBasic drawer.\n"
  },
  {
    "path": "components/drawer/demo/basic-right.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzDrawerModule } from 'ng-zorro-antd/drawer';\n\n@Component({\n  selector: 'nz-demo-drawer-basic-right',\n  imports: [NzButtonModule, NzDrawerModule],\n  template: `\n    <button nz-button nzType=\"primary\" (click)=\"open()\">Open</button>\n    <nz-drawer\n      [nzClosable]=\"false\"\n      [nzVisible]=\"visible\"\n      nzPlacement=\"right\"\n      nzTitle=\"Basic Drawer\"\n      (nzOnClose)=\"close()\"\n    >\n      <ng-container *nzDrawerContent>\n        <p>Some contents...</p>\n        <p>Some contents...</p>\n        <p>Some contents...</p>\n      </ng-container>\n    </nz-drawer>\n  `\n})\nexport class NzDemoDrawerBasicRightComponent {\n  visible = false;\n\n  open(): void {\n    this.visible = true;\n  }\n\n  close(): void {\n    this.visible = false;\n  }\n}\n"
  },
  {
    "path": "components/drawer/demo/extra.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 额外操作\n  en-US: Extra Actions\n---\n\n## zh-CN\n\n在 Ant Design 规范中，操作按钮建议放在抽屉的右上角，可以使用 `nzExtra` 属性来实现。\n\n## en-US\n\nExtra actions should be placed at the corner of the drawer in Ant Design, you can use `nzExtra` prop for that.\n"
  },
  {
    "path": "components/drawer/demo/extra.ts",
    "content": "import { Component, signal } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzDrawerModule } from 'ng-zorro-antd/drawer';\nimport { NzFlexModule } from 'ng-zorro-antd/flex';\n\n@Component({\n  selector: 'nz-demo-drawer-extra',\n  imports: [NzButtonModule, NzDrawerModule, NzFlexModule],\n  template: `\n    <button nz-button nzType=\"primary\" (click)=\"open()\">Open</button>\n    <nz-drawer\n      [nzClosable]=\"false\"\n      nzPlacement=\"right\"\n      nzTitle=\"Basic Drawer\"\n      (nzOnClose)=\"close()\"\n      [nzVisible]=\"visible()\"\n      [nzExtra]=\"extra\"\n    >\n      <ng-container *nzDrawerContent>\n        <p>Some contents...</p>\n        <p>Some contents...</p>\n        <p>Some contents...</p>\n      </ng-container>\n\n      <ng-template #extra>\n        <div nz-flex nzGap=\"small\">\n          <button nz-button nzType=\"primary\" (click)=\"close()\">OK</button>\n          <button nz-button nzType=\"default\" (click)=\"close()\">Cancel</button>\n        </div>\n      </ng-template>\n    </nz-drawer>\n  `\n})\nexport class NzDemoDrawerExtraComponent {\n  readonly visible = signal(false);\n\n  open(): void {\n    this.visible.set(true);\n  }\n\n  close(): void {\n    this.visible.set(false);\n  }\n}\n"
  },
  {
    "path": "components/drawer/demo/from-drawer.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 对象编辑\n  en-US: Edit item in drawer\n---\n\n## zh-CN\n\n用于承载编辑相关操作，需要点击关闭按钮关闭。\n\n## en-US\n\nA drawer containing an editable form which needs to be collapsed by clicking the close button.\n"
  },
  {
    "path": "components/drawer/demo/from-drawer.ts",
    "content": "import { CdkTextareaAutosize } from '@angular/cdk/text-field';\nimport { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzDatePickerModule } from 'ng-zorro-antd/date-picker';\nimport { NzDrawerModule } from 'ng-zorro-antd/drawer';\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\n@Component({\n  selector: 'nz-demo-drawer-from-drawer',\n  imports: [\n    NzButtonModule,\n    NzDrawerModule,\n    NzDatePickerModule,\n    NzFormModule,\n    NzInputModule,\n    NzSelectModule,\n    CdkTextareaAutosize\n  ],\n  template: `\n    <button nz-button nzType=\"primary\" (click)=\"open()\">Create</button>\n    <nz-drawer\n      [nzBodyStyle]=\"{ overflow: 'auto' }\"\n      [nzMaskClosable]=\"false\"\n      [nzWidth]=\"720\"\n      [nzVisible]=\"visible\"\n      nzTitle=\"Create\"\n      [nzFooter]=\"footerTpl\"\n      (nzOnClose)=\"close()\"\n    >\n      <form nz-form *nzDrawerContent>\n        <div nz-row [nzGutter]=\"8\">\n          <div nz-col nzSpan=\"12\">\n            <nz-form-item>\n              <nz-form-label>Name</nz-form-label>\n              <nz-form-control>\n                <input nz-input placeholder=\"please enter user name\" />\n              </nz-form-control>\n            </nz-form-item>\n          </div>\n          <div nz-col nzSpan=\"12\">\n            <nz-form-item>\n              <nz-form-label>Url</nz-form-label>\n              <nz-form-control>\n                <nz-input-wrapper nzAddonBefore=\"http://\" nzAddonAfter=\".com\">\n                  <input type=\"text\" nz-input placeholder=\"please enter url\" />\n                </nz-input-wrapper>\n              </nz-form-control>\n            </nz-form-item>\n          </div>\n        </div>\n        <div nz-row [nzGutter]=\"8\">\n          <div nz-col nzSpan=\"12\">\n            <nz-form-item>\n              <nz-form-label>Owner</nz-form-label>\n              <nz-form-control>\n                <nz-select nzPlaceHolder=\"Please select an owner\" />\n              </nz-form-control>\n            </nz-form-item>\n          </div>\n          <div nz-col nzSpan=\"12\">\n            <nz-form-item>\n              <nz-form-label>Type</nz-form-label>\n              <nz-form-control>\n                <nz-select nzPlaceHolder=\"Please choose the type\" />\n              </nz-form-control>\n            </nz-form-item>\n          </div>\n        </div>\n        <div nz-row [nzGutter]=\"8\">\n          <div nz-col nzSpan=\"12\">\n            <nz-form-item>\n              <nz-form-label>Approver</nz-form-label>\n              <nz-form-control>\n                <nz-select nzPlaceHolder=\"Please choose the approver\" />\n              </nz-form-control>\n            </nz-form-item>\n          </div>\n          <div nz-col nzSpan=\"12\">\n            <nz-form-item>\n              <nz-form-label>DateTime</nz-form-label>\n              <nz-form-control>\n                <nz-range-picker />\n              </nz-form-control>\n            </nz-form-item>\n          </div>\n        </div>\n        <div nz-row [nzGutter]=\"8\">\n          <div nz-col nzSpan=\"24\">\n            <nz-form-item>\n              <nz-form-label>Description</nz-form-label>\n              <nz-form-control>\n                <textarea\n                  nz-input\n                  placeholder=\"please enter url description\"\n                  cdkTextareaAutosize\n                  cdkAutosizeMinRows=\"4\"\n                  cdkAutosizeMaxRows=\"4\"\n                ></textarea>\n              </nz-form-control>\n            </nz-form-item>\n          </div>\n        </div>\n      </form>\n\n      <ng-template #footerTpl>\n        <div style=\"float: right\">\n          <button nz-button style=\"margin-right: 8px;\" (click)=\"close()\">Cancel</button>\n          <button nz-button nzType=\"primary\" (click)=\"close()\">Submit</button>\n        </div>\n      </ng-template>\n    </nz-drawer>\n  `\n})\nexport class NzDemoDrawerFromDrawerComponent {\n  visible = false;\n\n  open(): void {\n    this.visible = true;\n  }\n\n  close(): void {\n    this.visible = false;\n  }\n}\n"
  },
  {
    "path": "components/drawer/demo/multi-level-drawer.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 多层抽屉\n  en-US: Multi-level drawer\n---\n\n## zh-CN\n\n在抽屉内打开新的抽屉，用以解决多分支任务的复杂状况。\n\n## en-US\n\nOpen a new drawer on top of an existing drawer to handle multi branch tasks\n"
  },
  {
    "path": "components/drawer/demo/multi-level-drawer.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzDrawerModule } from 'ng-zorro-antd/drawer';\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzListModule } from 'ng-zorro-antd/list';\nimport { NzTagModule } from 'ng-zorro-antd/tag';\n\n@Component({\n  selector: 'nz-demo-drawer-multi-level-drawer',\n  imports: [NzButtonModule, NzDrawerModule, NzFormModule, NzInputModule, NzListModule, NzTagModule],\n  template: `\n    <button nz-button nzType=\"primary\" (click)=\"open()\">New Cookbook</button>\n    <nz-drawer\n      [nzClosable]=\"false\"\n      [nzOffsetX]=\"childrenVisible ? 180 : 0\"\n      [nzWidth]=\"320\"\n      [nzVisible]=\"visible\"\n      nzTitle=\"Cookbook\"\n      (nzOnClose)=\"close()\"\n    >\n      <form *nzDrawerContent nz-form>\n        <div nz-row>\n          <div nz-col nzSpan=\"24\">\n            <nz-form-item>\n              <nz-form-label>Name</nz-form-label>\n              <nz-form-control>\n                <input nz-input placeholder=\"please enter cookbook name\" />\n              </nz-form-control>\n            </nz-form-item>\n          </div>\n        </div>\n        <div nz-row>\n          <div nz-col nzSpan=\"24\">\n            <nz-form-item>\n              <nz-form-label>Food</nz-form-label>\n              <nz-form-control>\n                <nz-tag>potato</nz-tag>\n                <nz-tag>eggplant</nz-tag>\n                <nz-tag (click)=\"openChildren()\">+</nz-tag>\n              </nz-form-control>\n            </nz-form-item>\n          </div>\n        </div>\n      </form>\n      <nz-drawer [nzClosable]=\"false\" [nzVisible]=\"childrenVisible\" nzTitle=\"Food\" (nzOnClose)=\"closeChildren()\">\n        <nz-list *nzDrawerContent [nzDataSource]=\"vegetables\" [nzRenderItem]=\"item\">\n          <ng-template #item let-item>\n            <nz-list-item [nzContent]=\"item\" />\n          </ng-template>\n        </nz-list>\n      </nz-drawer>\n    </nz-drawer>\n  `\n})\nexport class NzDemoDrawerMultiLevelDrawerComponent {\n  visible = false;\n  childrenVisible = false;\n\n  vegetables = ['asparagus', 'bamboo', 'potato', 'carrot', 'cilantro', 'potato', 'eggplant'];\n\n  open(): void {\n    this.visible = true;\n  }\n\n  close(): void {\n    this.visible = false;\n  }\n\n  openChildren(): void {\n    this.childrenVisible = true;\n  }\n\n  closeChildren(): void {\n    this.childrenVisible = false;\n  }\n}\n"
  },
  {
    "path": "components/drawer/demo/placement.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 自定义位置\n  en-US: Custom Placement\n---\n\n## zh-CN\n\n自定义位置，点击触发按钮抽屉从相应的位置滑出，点击遮罩区关闭\n\n## en-US\n\nBasic drawer.\n"
  },
  {
    "path": "components/drawer/demo/placement.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzDrawerModule, NzDrawerPlacement } from 'ng-zorro-antd/drawer';\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\n\n@Component({\n  selector: 'nz-demo-drawer-placement',\n  imports: [FormsModule, NzButtonModule, NzDrawerModule, NzRadioModule],\n  template: `\n    <nz-radio-group [(ngModel)]=\"placement\">\n      <label nz-radio nzValue=\"top\">top</label>\n      <label nz-radio nzValue=\"right\">right</label>\n      <label nz-radio nzValue=\"bottom\">bottom</label>\n      <label nz-radio nzValue=\"left\">left</label>\n    </nz-radio-group>\n    <button nz-button nzType=\"primary\" (click)=\"open()\">Open</button>\n    <nz-drawer\n      [nzClosable]=\"false\"\n      [nzVisible]=\"visible\"\n      [nzPlacement]=\"placement\"\n      nzTitle=\"Basic Drawer\"\n      (nzOnClose)=\"close()\"\n    >\n      <ng-container *nzDrawerContent>\n        <p>Some contents...</p>\n        <p>Some contents...</p>\n        <p>Some contents...</p>\n      </ng-container>\n    </nz-drawer>\n  `\n})\nexport class NzDemoDrawerPlacementComponent {\n  visible = false;\n  placement: NzDrawerPlacement = 'left';\n  open(): void {\n    this.visible = true;\n  }\n\n  close(): void {\n    this.visible = false;\n  }\n}\n"
  },
  {
    "path": "components/drawer/demo/service.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 服务方式创建\n  en-US: Drawer's service\n---\n\n## zh-CN\n\nDrawer 的 service 用法，示例中演示了用户自定义模板、自定义component。\n\n## en-US\n\nUsage of Drawer's service, examples demonstrate user-defined templates, custom components.\n"
  },
  {
    "path": "components/drawer/demo/service.ts",
    "content": "import { Component, TemplateRef, ViewChild, inject } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\nimport { NZ_DRAWER_DATA, NzDrawerModule, NzDrawerRef, NzDrawerService } from 'ng-zorro-antd/drawer';\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-drawer-service',\n  imports: [FormsModule, NzButtonModule, NzDrawerModule, NzFormModule, NzInputModule],\n  template: `\n    <ng-template #drawerTemplate let-data let-drawerRef=\"drawerRef\">\n      value: {{ data?.value }}\n      <br />\n      <br />\n      <button nz-button nzType=\"primary\" (click)=\"drawerRef.close()\">close</button>\n    </ng-template>\n    <div nz-form>\n      <nz-form-item>\n        <input nz-input [(ngModel)]=\"value\" />\n      </nz-form-item>\n    </div>\n    <button nz-button nzType=\"primary\" (click)=\"openTemplate()\">Use Template</button>\n    &nbsp;\n    <button nz-button nzType=\"primary\" (click)=\"openComponent()\">Use Component</button>\n  `\n})\nexport class NzDemoDrawerServiceComponent {\n  @ViewChild('drawerTemplate', { static: false }) drawerTemplate?: TemplateRef<{\n    $implicit: { value: string };\n    drawerRef: NzDrawerRef<string>;\n  }>;\n  value = 'ng';\n\n  constructor(private drawerService: NzDrawerService) {}\n\n  openTemplate(): void {\n    const drawerRef = this.drawerService.create({\n      nzTitle: 'Template',\n      nzFooter: 'Footer',\n      nzExtra: 'Extra',\n      nzContent: this.drawerTemplate,\n      nzContentParams: {\n        value: this.value\n      }\n    });\n\n    drawerRef.afterOpen.subscribe(() => {\n      console.log('Drawer(Template) open');\n    });\n\n    drawerRef.afterClose.subscribe(() => {\n      console.log('Drawer(Template) close');\n    });\n  }\n\n  openComponent(): void {\n    const drawerRef = this.drawerService.create<NzDrawerCustomComponent, { value: string }, string>({\n      nzTitle: 'Component',\n      nzFooter: 'Footer',\n      nzExtra: 'Extra',\n      nzContent: NzDrawerCustomComponent,\n      nzContentParams: {\n        value: this.value\n      },\n      nzData: {\n        value: 'Ng Zorro'\n      }\n    });\n\n    drawerRef.afterOpen.subscribe(() => {\n      console.log('Drawer(Component) open');\n    });\n\n    drawerRef.afterClose.subscribe(data => {\n      console.log(data);\n      if (typeof data === 'string') {\n        this.value = data;\n      }\n    });\n  }\n}\n\n@Component({\n  selector: 'nz-drawer-custom-component',\n  imports: [FormsModule, NzButtonModule, NzDividerModule, NzInputModule],\n  template: `\n    <div>\n      <input nz-input [(ngModel)]=\"nzData.value\" />\n      <nz-divider />\n      <button nzType=\"primary\" (click)=\"close()\" nz-button>Confirm</button>\n    </div>\n  `\n})\nexport class NzDrawerCustomComponent {\n  // @Input() value = '';\n  nzData: { value: string } = inject(NZ_DRAWER_DATA);\n\n  constructor(private drawerRef: NzDrawerRef<string>) {}\n\n  close(): void {\n    this.drawerRef.close(this.nzData);\n  }\n}\n"
  },
  {
    "path": "components/drawer/demo/size.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 预设宽度\n  en-US: Preset size\n---\n\n## zh-CN\n\n抽屉的默认宽度为 `378px`，另外还提供一个大号抽屉 `736px`，可以用 `size` 属性来设置。\n\n## en-US\n\nThe default width (or height) of Drawer is `378px`, and there is a presetted large size `736px`.\n"
  },
  {
    "path": "components/drawer/demo/size.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzDrawerModule } from 'ng-zorro-antd/drawer';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\n\n@Component({\n  selector: 'nz-demo-drawer-size',\n  imports: [NzButtonModule, NzDrawerModule, NzSpaceModule],\n  template: `\n    <nz-space>\n      <button *nzSpaceItem nz-button nzType=\"primary\" (click)=\"showDefault()\">Open Default Size (378px)</button>\n      <button *nzSpaceItem nz-button nzType=\"primary\" (click)=\"showLarge()\">Open Large Size (736px)</button>\n    </nz-space>\n    <nz-drawer\n      [nzSize]=\"size\"\n      [nzVisible]=\"visible\"\n      nzPlacement=\"right\"\n      [nzTitle]=\"title\"\n      [nzExtra]=\"extra\"\n      (nzOnClose)=\"close()\"\n    >\n      <ng-container *nzDrawerContent>\n        <p>Some contents...</p>\n        <p>Some contents...</p>\n        <p>Some contents...</p>\n      </ng-container>\n    </nz-drawer>\n    <ng-template #extra>\n      <button nz-button nzType=\"default\" (click)=\"close()\">Cancel</button>\n      &nbsp;\n      <button nz-button nzType=\"primary\" (click)=\"close()\">OK</button>\n    </ng-template>\n  `\n})\nexport class NzDemoDrawerSizeComponent {\n  visible = false;\n  size: 'large' | 'default' = 'default';\n\n  get title(): string {\n    return `${this.size} Drawer`;\n  }\n\n  showDefault(): void {\n    this.size = 'default';\n    this.open();\n  }\n\n  showLarge(): void {\n    this.size = 'large';\n    this.open();\n  }\n\n  open(): void {\n    this.visible = true;\n  }\n\n  close(): void {\n    this.visible = false;\n  }\n}\n"
  },
  {
    "path": "components/drawer/demo/user-profile.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 信息预览抽屉\n  en-US: Preview drawer\n---\n\n## zh-CN\n\n需要快速预览对象概要时使用，点击遮罩区关闭。\n\n## en-US\n\nUse when you need to quickly preview the outline of the object. Such as list item preview.\n"
  },
  {
    "path": "components/drawer/demo/user-profile.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzDescriptionsModule } from 'ng-zorro-antd/descriptions';\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\nimport { NzDrawerModule } from 'ng-zorro-antd/drawer';\nimport { NzListModule } from 'ng-zorro-antd/list';\n\n@Component({\n  selector: 'nz-demo-drawer-user-profile',\n  imports: [NzButtonModule, NzDescriptionsModule, NzDividerModule, NzDrawerModule, NzListModule],\n  template: `\n    <nz-list [nzDataSource]=\"data\" [nzRenderItem]=\"item\" nzItemLayout=\"horizontal\">\n      <ng-template #item let-item>\n        <nz-list-item [nzActions]=\"[viewAction]\">\n          <ng-template #viewAction>\n            <a (click)=\"open()\">View Profile</a>\n          </ng-template>\n          <nz-list-item-meta\n            [nzTitle]=\"nzTitle\"\n            nzAvatar=\"https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png\"\n            nzDescription=\"Progresser AFX\"\n          >\n            <ng-template #nzTitle>\n              <a href=\"https://ng.ant.design\">{{ item.name }}</a>\n            </ng-template>\n          </nz-list-item-meta>\n        </nz-list-item>\n      </ng-template>\n    </nz-list>\n    <nz-drawer [nzVisible]=\"visible\" [nzWidth]=\"640\" [nzClosable]=\"false\" (nzOnClose)=\"close()\">\n      <ng-container *nzDrawerContent>\n        <p class=\"title\">User Profile</p>\n        <nz-descriptions [nzColumn]=\"2\" nzTitle=\"Personal\">\n          <nz-descriptions-item nzTitle=\"Full Name\" [nzSpan]=\"1\">Lily</nz-descriptions-item>\n          <nz-descriptions-item nzTitle=\"Account\" [nzSpan]=\"1\">AntDesign&#64;example.com</nz-descriptions-item>\n          <nz-descriptions-item nzTitle=\"City\" [nzSpan]=\"1\">HangZhou</nz-descriptions-item>\n          <nz-descriptions-item nzTitle=\"Country\" [nzSpan]=\"1\">China🇨🇳</nz-descriptions-item>\n          <nz-descriptions-item nzTitle=\"Birthday\" [nzSpan]=\"1\">February 2,1900</nz-descriptions-item>\n          <nz-descriptions-item nzTitle=\"Website\" [nzSpan]=\"1\">-</nz-descriptions-item>\n          <nz-descriptions-item nzTitle=\"Message\" [nzSpan]=\"2\">\n            Make things as simple as possible but no simpler.\n          </nz-descriptions-item>\n        </nz-descriptions>\n        <nz-divider />\n        <nz-descriptions [nzColumn]=\"2\" nzTitle=\"Company\">\n          <nz-descriptions-item nzTitle=\"Position\" [nzSpan]=\"1\">Programmer</nz-descriptions-item>\n          <nz-descriptions-item nzTitle=\"Responsibilities\" [nzSpan]=\"1\">Coding</nz-descriptions-item>\n          <nz-descriptions-item nzTitle=\"Department\" [nzSpan]=\"1\">AFX</nz-descriptions-item>\n          <nz-descriptions-item nzTitle=\"Supervisor\" [nzSpan]=\"1\">Lin</nz-descriptions-item>\n          <nz-descriptions-item nzTitle=\"Skills\" [nzSpan]=\"2\">\n            C / C + +, data structures, software engineering, operating systems, computer networks, databases, compiler\n            theory, computer architecture, Microcomputer Principle and Interface Technology, Computer English, Java,\n            ASP, etc.\n          </nz-descriptions-item>\n        </nz-descriptions>\n        <nz-divider />\n        <nz-descriptions [nzColumn]=\"2\" nzTitle=\"Contacts\">\n          <nz-descriptions-item nzTitle=\"Email\" [nzSpan]=\"1\">AntDesign&#64;example.com</nz-descriptions-item>\n          <nz-descriptions-item nzTitle=\"Phone Number\" [nzSpan]=\"1\">+86 181 0000 0000</nz-descriptions-item>\n          <nz-descriptions-item nzTitle=\"Github\" [nzSpan]=\"2\">\n            <a href=\"https://github.com/NG-ZORRO/ng-zorro-antd\" target=\"_blank\">github.com/NG-ZORRO/ng-zorro-antd</a>\n          </nz-descriptions-item>\n        </nz-descriptions>\n      </ng-container>\n    </nz-drawer>\n  `,\n  styles: `\n    .title {\n      font-size: 16px;\n      color: rgba(0, 0, 0, 0.85);\n      line-height: 24px;\n      display: block;\n      margin-bottom: 24px;\n    }\n  `\n})\nexport class NzDemoDrawerUserProfileComponent {\n  data = [\n    {\n      name: 'Lily'\n    },\n    {\n      name: 'Lily'\n    }\n  ];\n\n  visible = false;\n\n  open(): void {\n    this.visible = true;\n  }\n\n  close(): void {\n    this.visible = false;\n  }\n}\n"
  },
  {
    "path": "components/drawer/doc/index.en-US.md",
    "content": "---\ntype: Feedback\ncategory: Components\ntitle: Drawer\ncover: 'https://gw.alipayobjects.com/zos/alicdn/7z8NJQhFb/Drawer.svg'\ndescription: A panel that slides out from the edge of the screen.\n---\n\nA Drawer is a panel that is typically overlaid on top of a page and slides in from the side. It contains a set of\ninformation or actions. Since that user can interact with the Drawer without leaving the current page, tasks can be\nachieved more efficient within the same context.\n\n## When To Use\n\n- Use a Form to create or edit a set of information.\n- Processing subtasks. When subtasks are too heavy for Popover and we still want to keep the subtasks in the context of\n  the main task, Drawer comes very handy.\n- When a same Form is needed in multiple places.\n\n## API\n\n### nz-drawer\n\n| Props                   | Description                                                                                                                                                                                 | Type                                     | Default     | Global Config |\n| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- | ----------- | ------------- |\n| `[nzClosable]`          | Whether a close (x) button is visible on top left of the Drawer dialog or not.                                                                                                              | `boolean`                                | `true`      |\n| `[nzCloseIcon]`         | Custom close icon                                                                                                                                                                           | `string \\| TemplateRef<void> \\| null`    | `'close'`   |\n| `[nzExtra]`             | Extra actions area at corner.                                                                                                                                                               | `string \\| TemplateRef<void> \\| null`    | -           |\n| `[nzMask]`              | Whether to show mask or not.                                                                                                                                                                | `boolean`                                | `true`      | ✅            |\n| `[nzMaskClosable]`      | Clicking on the mask (area outside the Drawer) to close the Drawer or not.                                                                                                                  | `boolean`                                | `true`      | ✅            |\n| `[nzCloseOnNavigation]` | Whether to close the drawer when the user goes backwards/forwards in history. Note that this usually doesn't include clicking on links (unless the user is using the HashLocationStrategy). | `boolean`                                | `true`      | ✅            |\n| `[nzKeyboard]`          | Whether support press esc to close                                                                                                                                                          | `boolean`                                | `true`      |\n| `[nzMaskStyle]`         | Style for Drawer's mask element.                                                                                                                                                            | `object`                                 | `{}`        |\n| `[nzBodyStyle]`         | Body style for drawer body element. Such as height, padding etc.                                                                                                                            | `object`                                 | `{}`        |\n| `[nzTitle]`             | The title for Drawer.                                                                                                                                                                       | `string \\| TemplateRef<void>`            | -           |\n| `[nzFooter]`            | The footer for Drawer.                                                                                                                                                                      | `string \\| TemplateRef<void>`            | -           |\n| `[nzVisible]`           | Whether the Drawer dialog is visible or not, you can use `[(nzVisible)]` two-way binding                                                                                                    | `boolean`                                | `false`     |\n| `[nzPlacement]`         | The placement of the Drawer.                                                                                                                                                                | `'top' \\| 'right' \\| 'bottom' \\| 'left'` | `'right'`   |\n| `[nzSize]`              | Preset size of drawer, default `378px` and large `736px`.                                                                                                                                   | `'default' \\| 'large'`                   | `'default'` |\n| `[nzWidth]`             | Width of the Drawer dialog, only when placement is `'right'` or `'left'`, having a higher priority than `nzSize`.                                                                           | `number \\| string`                       | -           |\n| `[nzHeight]`            | Height of the Drawer dialog, only when placement is `'top'` or `'bottom'`, having a higher priority than `nzSize`.                                                                          | `number \\| string`                       | -           |\n| `[nzOffsetX]`           | The X coordinate offset(px), only when placement is `'right'` or `'left'`.                                                                                                                  | `number`                                 | `0`         |\n| `[nzOffsetY]`           | The Y coordinate offset(px), only when placement is `'top'` or `'bottom'`.                                                                                                                  | `number`                                 | `0`         |\n| `[nzWrapClassName]`     | The class name of the container of the Drawer dialog.                                                                                                                                       | `string`                                 | -           |\n| `[nzZIndex]`            | The `z-index` of the Drawer.                                                                                                                                                                | `number`                                 | `1000`      |\n| `(nzOnClose)`           | Specify a callback that will be called when a user clicks mask, close button or Cancel button.                                                                                              | `EventEmitter<MouseEvent>`               | -           |\n\n### NzDrawerService\n\n| Method          | Description               | Params                  | Return              |\n| --------------- | ------------------------- | ----------------------- | ------------------- |\n| create<T, D, R> | create and open an Drawer | `NzDrawerOptions<T, D>` | `NzDrawerRef<T, R>` |\n\n### NzDrawerOptions\n\n| Params              | Description                                                                                                                                                                                                    | Type                                                               | Default     | Global Config |\n| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ | ----------- | ------------- |\n| nzContent           | The drawer body content.                                                                                                                                                                                       | `TemplateRef<{ $implicit: D, drawerRef: NzDrawerRef }> \\| Type<T>` | -           |\n| nzContentParams     | Deprecated: Use NzData instead. The component inputs the param / The Template context                                                                                                                          | `D`                                                                | -           |\n| nzData              | Will be a template variable when nzContent is TemplateRef. <br /> object, will be the value of the injection token NZ_DRAWER_DATA when nzContent is a component                                                | `D`                                                                | -           |\n| nzClosable          | Whether a close (x) button is visible on top left of the Drawer dialog or not.                                                                                                                                 | `boolean`                                                          | `true`      |\n| nzCloseIcon         | Custom close icon                                                                                                                                                                                              | `string \\| TemplateRef<void> \\| null`                              | `'close'`   |\n| nzExtra             | Extra actions area at corner.                                                                                                                                                                                  | `string \\| TemplateRef<void> \\| null`                              | -           |\n| nzOnCancel          | Execute when click on the mask or the upper cancel button, This function returns a promise, which is automatically closed when the execution is complete or the promise ends (return false to prevent closing) | `() => Promise<any>`                                               | -           |\n| nzMaskClosable      | Clicking on the mask (area outside the Drawer) to close the Drawer or not.                                                                                                                                     | `boolean`                                                          | `true`      | ✅            |\n| nzCloseOnNavigation | Whether to close the drawer when the user goes backwards/forwards in history. Note that this usually doesn't include clicking on links (unless the user is using the HashLocationStrategy).                    | `boolean`                                                          | `true`      | ✅            |\n| nzMask              | Whether to show mask or not.                                                                                                                                                                                   | `boolean`                                                          | `true`      | ✅            |\n| nzDirection         | Direction of the text in the modal                                                                                                                                                                             | `'ltr' \\| 'rtl'`                                                   | -           | ✅            |\n| nzKeyboard          | Whether support press esc to close                                                                                                                                                                             | `boolean`                                                          | `true`      |\n| nzMaskStyle         | Style for Drawer's mask element.                                                                                                                                                                               | `object`                                                           | `{}`        |\n| nzBodyStyle         | Body style for modal body element. Such as height, padding etc.                                                                                                                                                | `object`                                                           | `{}`        |\n| nzTitle             | The title for Drawer.                                                                                                                                                                                          | `string \\| TemplateRef<void>`                                      | -           |\n| nzFooter            | The footer for Drawer.                                                                                                                                                                                         | `string \\| TemplateRef<void>`                                      | -           |\n| nzSize              | Preset size of drawer, default `378px` and large `736px`.                                                                                                                                                      | `'default' \\| 'large'`                                             | `'default'` |\n| nzWidth             | Width of the Drawer dialog, only when placement is `'right'` or `'left'`, having a higher priority than `nzSize`.                                                                                              | `number \\| string`                                                 | -           |\n| nzHeight            | Height of the Drawer dialog, only when placement is `'top'` or `'bottom'`, having a higher priority than `nzSize`.                                                                                             | `number \\| string`                                                 | -           |\n| nzWrapClassName     | The class name of the container of the Drawer dialog.                                                                                                                                                          | `string`                                                           | -           |\n| nzZIndex            | The `z-index` of the Drawer.                                                                                                                                                                                   | `number`                                                           | `1000`      |\n| nzPlacement         | The placement of the Drawer.                                                                                                                                                                                   | `'top' \\| 'right' \\| 'bottom' \\| 'left'`                           | `'right'`   |\n| nzOffsetX           | The X coordinate offset(px).                                                                                                                                                                                   | `number`                                                           | `0`         |\n| nzOffsetY           | The Y coordinate offset(px), only when placement is `'top'` or `'bottom'`.                                                                                                                                     | `number`                                                           | `0`         |\n\n### NZ_DRAWER_DATA\n\nNZ_DRAWER_DATA injection token is used to retrieve nzData in the custom component. The drawer created by the service\nmethod NzDrawerService.create() inject a NZ_DRAWER_DATA token (if nzContent is used as Component) to retrieve the\nparameters that have used to the 'nzContent component'\n\n### NzDrawerRef\n\n#### Methods\n\n| Name                   | Description                                                               | Type                            |\n| ---------------------- | ------------------------------------------------------------------------- | ------------------------------- |\n| close                  | close the drawer.                                                         | `(result?: R) => void`          |\n| open                   | open the drawer.                                                          | `() => void`                    |\n| getContentComponent    | Returns the instance when `nzContent` is the component.                   | `() => T \\| null`               |\n| getContentComponentRef | Returns the reference of the component when `nzContent` is the component. | `() => ComponentRef<T> \\| null` |\n\n#### Property\n\n| Name            | Description                                                                     | Type                                     |\n| --------------- | ------------------------------------------------------------------------------- | ---------------------------------------- |\n| afterOpen       | Callback called after open.                                                     | `Observable<void>`                       |\n| afterClose      | Callback called after close.                                                    | `Observable<R>`                          |\n| nzCloseIcon     | Custom close icon                                                               | `string \\| TemplateRef<void> \\| null`    |\n| nzClosable      | Whether a close (x) button is visible on top right of the Drawer dialog or not. | `boolean`                                |\n| nzMaskClosable  | Clicking on the mask (area outside the Drawer) to close the Drawer or not.      | `boolean`                                |\n| nzMask          | Whether to show mask or not.                                                    | `boolean`                                |\n| nzKeyboard      | Whether support press esc to close                                              | `boolean`                                |\n| nzMaskStyle     | Style for Drawer's mask element.                                                | `object`                                 |\n| nzBodyStyle     | Body style for modal body element. Such as height, padding etc.                 | `object`                                 |\n| nzTitle         | The title for Drawer.                                                           | `string \\| TemplateRef<void>`            |\n| nzFooter        | The footer for Drawer.                                                          | `string \\| TemplateRef<void>`            |\n| nzWidth         | Width of the Drawer dialog.                                                     | `number \\| string`                       |\n| nzHeight        | Height of the Drawer dialog, only when placement is `'top'` or `'bottom'`.      | `number \\| string`                       |\n| nzWrapClassName | The class name of the container of the Drawer dialog.                           | `string`                                 |\n| nzZIndex        | The `z-index` of the Drawer.                                                    | `number`                                 |\n| nzPlacement     | The placement of the Drawer.                                                    | `'top' \\| 'right' \\| 'bottom' \\| 'left'` |\n| nzOffsetX       | The X coordinate offset(px).                                                    | `number`                                 |\n| nzOffsetY       | The Y coordinate offset(px), only when placement is `'top'` or `'bottom'`.      | `number`                                 |\n"
  },
  {
    "path": "components/drawer/doc/index.zh-CN.md",
    "content": "---\ntype: 反馈\ncategory: Components\nsubtitle: 抽屉\ntitle: Drawer\ncover: 'https://gw.alipayobjects.com/zos/alicdn/7z8NJQhFb/Drawer.svg'\ndescription: 屏幕边缘滑出的浮层面板。\n---\n\n抽屉从父窗体边缘滑入，覆盖住部分父窗体内容。用户在抽屉内操作时不必离开当前任务，操作完成后，可以平滑地回到到原任务。\n\n## 何时使用\n\n- 当需要一个附加的面板来控制父窗体内容，这个面板在需要时呼出。比如，控制界面展示样式，往界面中添加内容。\n- 当需要在当前任务流中插入临时任务，创建或预览附加内容。比如展示协议条款，创建子对象。\n\n## API\n\n### nz-drawer\n\n| 参数                    | 说明                                                                                                         | 类型                                     | 默认值      | 全局配置 |\n| ----------------------- | ------------------------------------------------------------------------------------------------------------ | ---------------------------------------- | ----------- | -------- |\n| `[nzClosable]`          | 是否显示左上角的关闭按钮                                                                                     | `boolean`                                | `true`      |\n| `[nzCloseIcon]`         | 自定义关闭图标                                                                                               | `string \\| TemplateRef<void> \\| null`    | `'close'`   |\n| `[nzExtra]`             | 抽屉右上角的操作区域                                                                                         | `string \\| TemplateRef<void> \\| null`    | -           |\n| `[nzMaskClosable]`      | 点击蒙层是否允许关闭                                                                                         | `boolean`                                | `true`      | ✅       |\n| `[nzMask]`              | 是否展示遮罩                                                                                                 | `boolean`                                | `true`      | ✅       |\n| `[nzCloseOnNavigation]` | 当用户在历史中前进/后退时是否关闭抽屉组件。注意，这通常不包括点击链接（除非用户使用 HashLocationStrategy）。 | `boolean`                                | `true`      | ✅       |\n| `[nzMaskStyle]`         | 遮罩样式                                                                                                     | `object`                                 | `{}`        |\n| `[nzKeyboard]`          | 是否支持键盘 esc 关闭                                                                                        | `boolean`                                | `true`      |\n| `[nzBodyStyle]`         | Drawer body 样式                                                                                             | `object`                                 | `{}`        |\n| `[nzTitle]`             | 标题                                                                                                         | `string \\| TemplateRef<void>`            | -           |\n| `[nzFooter]`            | 抽屉的页脚                                                                                                   | `string \\| TemplateRef<void>`            | -           |\n| `[nzVisible]`           | Drawer 是否可见，可以使用 `[(nzVisible)]` 双向绑定                                                           | `boolean`                                | -           |\n| `[nzPlacement]`         | 抽屉的方向                                                                                                   | `'top' \\| 'right' \\| 'bottom' \\| 'left'` | `'right'`   |\n| `[nzSize]`              | 预设抽屉宽度（或高度），default `378px` 和 large `736px`                                                     | `'default' \\| 'large'`                   | `'default'` |\n| `[nzWidth]`             | 宽度, 只在方向为 `'right'`或`'left'` 时生效，优先级高于 `nzSize`                                             | `number \\| string`                       | -           |\n| `[nzHeight]`            | 高度, 只在方向为 `'top'`或`'bottom'` 时生效，优先级高于 `nzSize`                                             | `number \\| string`                       | -           |\n| `[nzOffsetX]`           | x 坐标移量(px), 只在方向为 `'right'`或`'left'` 时生效                                                        | `number`                                 | `0`         |\n| `[nzOffsetY]`           | y 坐标移量(px), 高度, 只在方向为 `'top'`或`'bottom'` 时生效                                                  | `number`                                 | `0`         |\n| `[nzWrapClassName]`     | 对话框外层容器的类名                                                                                         | `string`                                 | -           |\n| `[nzZIndex]`            | 设置 Drawer 的 `z-index`                                                                                     | `number`                                 | `1000`      |\n| `(nzOnClose)`           | 点击遮罩层或右上角叉的回调                                                                                   | `EventEmitter<MouseEvent>`               | -           |\n\n### NzDrawerService\n\n| 方法名          | 说明                  | 参数                    | 返回                |\n| --------------- | --------------------- | ----------------------- | ------------------- |\n| create<T, D, R> | 创建并打开一个 Drawer | `NzDrawerOptions<T, D>` | `NzDrawerRef<T, R>` |\n\n### NzDrawerOptions\n\n| 参数                | 说明                                                                                                                   | 类型                                                               | 默认值      | 全局配置 |\n| ------------------- | ---------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ | ----------- | -------- |\n| nzContent           | Drawer body 的内容                                                                                                     | `TemplateRef<{ $implicit: D, drawerRef: NzDrawerRef }> \\| Type<T>` | -           |\n| nzContentParams     | 内容组件的输入参数 / Template 的 context                                                                               | `D`                                                                | -           |\n| nzOnCancel          | 点击遮罩层或右上角叉时执行,该函数可返回 promise 待执行完毕或 promise 结束时，将自动关闭对话框（返回 false 可阻止关闭） | `() => Promise<any>`                                               | -           |\n| nzClosable          | 是否显示左上角的关闭按钮                                                                                               | `boolean`                                                          | `true`      |\n| nzCloseIcon         | 自定义关闭图标                                                                                                         | `string \\| TemplateRef<void> \\| null`                              | `'close'`   |\n| nzExtra             | 抽屉右上角的操作区域                                                                                                   | `string \\| TemplateRef<void> \\| null`                              | -           |\n| nzMaskClosable      | 点击蒙层是否允许关闭                                                                                                   | `boolean`                                                          | `true`      | ✅       |\n| nzMask              | 是否展示遮罩                                                                                                           | `boolean`                                                          | `true`      | ✅       |\n| nzCloseOnNavigation | 当用户在历史中前进/后退时是否关闭抽屉组件。注意，这通常不包括点击链接（除非用户使用 HashLocationStrategy）。           | `boolean`                                                          | `true`      | ✅       |\n| nzDirection         | 文字方向                                                                                                               | `'ltr' \\| 'rtl'`                                                   | -           | ✅       |\n| nzKeyboard          | 是否支持键盘 esc 关闭                                                                                                  | `boolean`                                                          | `true`      |\n| nzMaskStyle         | 遮罩样式                                                                                                               | `object`                                                           | `{}`        |\n| nzBodyStyle         | Modal body 样式                                                                                                        | `object`                                                           | `{}`        |\n| nzTitle             | 标题                                                                                                                   | `string \\| TemplateRef<void>`                                      | -           |\n| nzFooter            | 页脚                                                                                                                   | `string \\| TemplateRef<void>`                                      | -           |\n| nzSize              | 预设抽屉宽度（或高度），default `378px` 和 large `736px`                                                               | `'default' \\| 'large'`                                             | `'default'` |\n| nzWidth             | 宽度, 只在方向为 `'right'`或`'left'` 时生效，优先级高于 `nzSize`                                                       | `number \\| string`                                                 | -           |\n| nzHeight            | 高度, 只在方向为 `'top'`或`'bottom'` 时生效，优先级高于 `nzSize`                                                       | `number \\| string`                                                 | -           |\n| nzWrapClassName     | 对话框外层容器的类名                                                                                                   | `string`                                                           | -           |\n| nzZIndex            | 设置 Drawer 的 `z-index`                                                                                               | `number`                                                           | `1000`      |\n| nzPlacement         | 抽屉的方向                                                                                                             | `'top' \\| 'right' \\| 'bottom' \\| 'left'`                           | `'right'`   |\n| nzOffsetX           | x 坐标移量(px)                                                                                                         | `number`                                                           | `0`         |\n| nzOffsetY           | y 坐标移量(px), 高度, 只在方向为 `'top'`或`'bottom'` 时生效                                                            | `number`                                                           | `0`         |\n\n### NzDrawerRef\n\n#### 方法\n\n| 名称                | 说明                                | 类型                   |\n| ------------------- | ----------------------------------- | ---------------------- |\n| close               | 关闭 Drawer                         | `(result?: R) => void` |\n| open                | 打开 Drawer                         | `() => void`           |\n| getContentComponent | 返回 `nzContent` 为组件时的组件实例 | `() => T \\| null`      |\n\n#### 属性\n\n| 名称            | 说明                                                        | 类型                                     |\n| --------------- | ----------------------------------------------------------- | ---------------------------------------- |\n| afterOpen       | 打开之后的回调                                              | `Observable<void>`                       |\n| afterClose      | 关闭之后的回调                                              | `Observable<R>`                          |\n| nzClosable      | 是否显示右上角的关闭按钮                                    | `boolean`                                |\n| nzCloseIcon     | 自定义关闭图标                                              | `string \\| TemplateRef<void> \\| null`    |\n| nzMaskClosable  | 点击蒙层是否允许关闭                                        | `boolean`                                |\n| nzMask          | 是否展示遮罩                                                | `boolean`                                |\n| nzMaskStyle     | 遮罩样式                                                    | `object`                                 |\n| nzKeyboard      | 是否支持键盘 esc 关闭                                       | `boolean`                                |\n| nzBodyStyle     | Modal body 样式                                             | `object`                                 |\n| nzTitle         | 标题                                                        | `string \\| TemplateRef<void>`            |\n| nzWidth         | 宽度                                                        | `number \\| string`                       |\n| nzHeight        | 高度, 只在方向为 `'top'`或`'bottom'` 时生效                 | `number \\| string`                       |\n| nzWrapClassName | 对话框外层容器的类名                                        | `string`                                 |\n| nzZIndex        | 设置 Drawer 的 `z-index`                                    | `number`                                 |\n| nzPlacement     | 抽屉的方向                                                  | `'top' \\| 'right' \\| 'bottom' \\| 'left'` |\n| nzOffsetX       | x 坐标移量(px)                                              | `number`                                 |\n| nzOffsetY       | y 坐标移量(px), 高度, 只在方向为 `'top'`或`'bottom'` 时生效 | `number`                                 |\n"
  },
  {
    "path": "components/drawer/drawer-content.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, inject, TemplateRef } from '@angular/core';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\n@Directive({\n  selector: '[nzDrawerContent]',\n  exportAs: 'nzDrawerContent'\n})\nexport class NzDrawerContentDirective {\n  public templateRef = inject(TemplateRef<NzSafeAny>);\n}\n"
  },
  {
    "path": "components/drawer/drawer-options.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction } from '@angular/cdk/bidi';\nimport { InjectionToken, TemplateRef, Type } from '@angular/core';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzDrawerRef } from './drawer-ref';\n\nexport const DRAWER_DEFAULT_SIZE = 378;\nexport const DRAWER_LARGE_SIZE = 736;\nexport type NzDrawerPlacement = 'left' | 'right' | 'top' | 'bottom';\nexport type NzDrawerSize = 'default' | 'large';\n\nexport interface NzDrawerOptionsOfComponent<T = NzSafeAny, D = NzSafeAny> {\n  nzClosable?: boolean;\n  nzMaskClosable?: boolean;\n  nzCloseOnNavigation?: boolean;\n  nzDirection?: Direction;\n  nzMask?: boolean;\n  nzKeyboard?: boolean;\n  nzNoAnimation?: boolean;\n  nzTitle?: string | TemplateRef<{}>;\n  nzExtra?: string | TemplateRef<{}>;\n  nzFooter?: string | TemplateRef<{}>;\n  nzContent?: TemplateRef<{ $implicit: D; drawerRef: NzDrawerRef }> | Type<T>;\n  /**@Deprecated**/\n  nzContentParams?: Partial<T & D>;\n  nzData?: D;\n  nzMaskStyle?: object;\n  nzBodyStyle?: object;\n  nzWrapClassName?: string;\n  nzSize?: NzDrawerSize;\n  nzWidth?: number | string;\n  nzHeight?: number | string;\n  nzPlacement?: NzDrawerPlacement;\n  nzZIndex?: number;\n  nzOffsetX?: number;\n  nzOffsetY?: number;\n}\n\nexport interface NzDrawerOptions<T = NzSafeAny, D = NzSafeAny> extends NzDrawerOptionsOfComponent<T, D> {\n  nzOnCancel?(): Promise<NzSafeAny>;\n}\n\nexport const NZ_DRAWER_DATA = new InjectionToken<NzSafeAny>(\n  typeof ngDevMode !== 'undefined' && ngDevMode ? 'nz-drawer-data' : ''\n);\n"
  },
  {
    "path": "components/drawer/drawer-ref.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ComponentRef, TemplateRef } from '@angular/core';\nimport { Observable } from 'rxjs';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzDrawerPlacement } from './drawer-options';\n\nexport abstract class NzDrawerRef<T = NzSafeAny, R = NzSafeAny> {\n  abstract afterClose: Observable<R | undefined>;\n  abstract afterOpen: Observable<void>;\n  abstract close(result?: R): void;\n  abstract open(): void;\n  abstract getContentComponent(): T | null;\n  abstract getContentComponentRef(): Readonly<ComponentRef<T>> | null;\n\n  abstract nzClosable?: boolean;\n  abstract nzNoAnimation?: boolean;\n  abstract nzMaskClosable?: boolean;\n  abstract nzKeyboard?: boolean;\n  abstract nzMask?: boolean;\n  abstract nzTitle?: string | TemplateRef<{}>;\n  abstract nzPlacement?: NzDrawerPlacement;\n  abstract nzMaskStyle?: object;\n  abstract nzBodyStyle?: object;\n  abstract nzWrapClassName?: string;\n  abstract nzWidth?: number | string;\n  abstract nzHeight?: number | string;\n  abstract nzZIndex?: number | string;\n  abstract nzOffsetX?: number | string;\n  abstract nzOffsetY?: number | string;\n}\n"
  },
  {
    "path": "components/drawer/drawer.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { FocusTrap, FocusTrapFactory } from '@angular/cdk/a11y';\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport { ESCAPE } from '@angular/cdk/keycodes';\nimport {\n  CdkScrollable,\n  createBlockScrollStrategy,\n  createGlobalPositionStrategy,\n  createOverlayRef,\n  OverlayKeyboardDispatcher,\n  OverlayRef\n} from '@angular/cdk/overlay';\nimport { CdkPortalOutlet, ComponentPortal, PortalModule, TemplatePortal } from '@angular/cdk/portal';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterViewInit,\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ComponentRef,\n  ContentChild,\n  DestroyRef,\n  DOCUMENT,\n  EventEmitter,\n  inject,\n  Injector,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  Renderer2,\n  SimpleChanges,\n  TemplateRef,\n  Type,\n  ViewChild,\n  ViewContainerRef\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Observable, Subject } from 'rxjs';\n\nimport { NzNoAnimationDirective, withAnimationCheck } from 'ng-zorro-antd/core/animation';\nimport { NzConfigKey, WithConfig } from 'ng-zorro-antd/core/config';\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { overlayZIndexSetter } from 'ng-zorro-antd/core/overlay';\nimport { NgStyleInterface, NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { isTemplateRef, toCssPixel } from 'ng-zorro-antd/core/util';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nimport { NzDrawerContentDirective } from './drawer-content.directive';\nimport {\n  DRAWER_DEFAULT_SIZE,\n  DRAWER_LARGE_SIZE,\n  NZ_DRAWER_DATA,\n  NzDrawerOptionsOfComponent,\n  NzDrawerPlacement,\n  NzDrawerSize\n} from './drawer-options';\nimport { NzDrawerRef } from './drawer-ref';\n\nexport const DRAWER_ANIMATE_DURATION = 300;\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'drawer';\n\n@Component({\n  selector: 'nz-drawer',\n  exportAs: 'nzDrawer',\n  template: `\n    <ng-template #drawerTemplate>\n      <div\n        class=\"ant-drawer\"\n        [nzNoAnimation]=\"nzNoAnimation\"\n        [class.ant-drawer-rtl]=\"dir === 'rtl'\"\n        [class.ant-drawer-open]=\"isOpen\"\n        [class.no-mask]=\"!nzMask\"\n        [class.ant-drawer-top]=\"nzPlacement === 'top'\"\n        [class.ant-drawer-bottom]=\"nzPlacement === 'bottom'\"\n        [class.ant-drawer-right]=\"nzPlacement === 'right'\"\n        [class.ant-drawer-left]=\"nzPlacement === 'left'\"\n        [style.transform]=\"offsetTransform\"\n        [style.transition]=\"placementChanging ? 'none' : null\"\n        [style.zIndex]=\"nzZIndex\"\n      >\n        @if (nzMask && isOpen) {\n          <div\n            class=\"ant-drawer-mask\"\n            [animate.enter]=\"maskAnimationEnter()\"\n            [animate.leave]=\"maskAnimationLeave()\"\n            (click)=\"maskClick()\"\n            [style]=\"nzMaskStyle\"\n          ></div>\n        }\n        <div\n          class=\"ant-drawer-content-wrapper {{ nzWrapClassName }}\"\n          [style.width]=\"width\"\n          [style.height]=\"height\"\n          [style.transform]=\"transform\"\n          [style.transition]=\"placementChanging ? 'none' : null\"\n        >\n          <div class=\"ant-drawer-content\">\n            <div class=\"ant-drawer-wrapper-body\" [style.height]=\"isLeftOrRight ? '100%' : null\">\n              @if (nzTitle || nzClosable) {\n                <div class=\"ant-drawer-header\" [class.ant-drawer-header-close-only]=\"!nzTitle\">\n                  <div class=\"ant-drawer-header-title\">\n                    @if (nzClosable) {\n                      <button (click)=\"closeClick()\" aria-label=\"Close\" class=\"ant-drawer-close\">\n                        <ng-container *nzStringTemplateOutlet=\"nzCloseIcon; let closeIcon\">\n                          <nz-icon [nzType]=\"closeIcon\" />\n                        </ng-container>\n                      </button>\n                    }\n\n                    @if (nzTitle) {\n                      <div class=\"ant-drawer-title\">\n                        <ng-container *nzStringTemplateOutlet=\"nzTitle\">{{ nzTitle }}</ng-container>\n                      </div>\n                    }\n                  </div>\n                  @if (nzExtra) {\n                    <div class=\"ant-drawer-extra\">\n                      <ng-container *nzStringTemplateOutlet=\"nzExtra\">{{ nzExtra }}</ng-container>\n                    </div>\n                  }\n                </div>\n              }\n              <div class=\"ant-drawer-body\" [style]=\"nzBodyStyle\" cdkScrollable>\n                <ng-template cdkPortalOutlet />\n                @if (nzContent) {\n                  @if (isTemplateRef(nzContent)) {\n                    <ng-container *ngTemplateOutlet=\"nzContent; context: templateContext\" />\n                  }\n                } @else if (contentFromContentChild && (isOpen || inAnimation)) {\n                  <ng-template [ngTemplateOutlet]=\"contentFromContentChild\" />\n                }\n              </div>\n              @if (nzFooter) {\n                <div class=\"ant-drawer-footer\">\n                  <ng-container *nzStringTemplateOutlet=\"nzFooter\">{{ nzFooter }}</ng-container>\n                </div>\n              }\n            </div>\n          </div>\n        </div>\n      </div>\n    </ng-template>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  imports: [NzNoAnimationDirective, NzOutletModule, NzIconModule, PortalModule, NgTemplateOutlet, CdkScrollable]\n})\nexport class NzDrawerComponent<T extends {} = NzSafeAny, R = NzSafeAny, D extends Partial<T> = NzSafeAny>\n  extends NzDrawerRef<T, R>\n  implements OnInit, AfterViewInit, OnChanges, NzDrawerOptionsOfComponent\n{\n  private cdr = inject(ChangeDetectorRef);\n  private renderer = inject(Renderer2);\n  private injector = inject(Injector);\n  private changeDetectorRef = inject(ChangeDetectorRef);\n  private focusTrapFactory = inject(FocusTrapFactory);\n  private viewContainerRef = inject(ViewContainerRef);\n  private overlayKeyboardDispatcher = inject(OverlayKeyboardDispatcher);\n  private directionality = inject(Directionality);\n  private destroyRef = inject(DestroyRef);\n  private document = inject(DOCUMENT);\n\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  @Input() nzContent!: TemplateRef<{ $implicit: D; drawerRef: NzDrawerRef<R> }> | Type<T>;\n  @Input() nzCloseIcon: string | TemplateRef<void> = 'close';\n  @Input({ transform: booleanAttribute }) nzClosable: boolean = true;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzMaskClosable: boolean = true;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzMask: boolean = true;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzCloseOnNavigation: boolean = true;\n  @Input({ transform: booleanAttribute }) nzNoAnimation = false;\n  @Input({ transform: booleanAttribute }) nzKeyboard: boolean = true;\n  @Input() nzTitle?: string | TemplateRef<{}>;\n  @Input() nzExtra?: string | TemplateRef<{}>;\n  @Input() nzFooter?: string | TemplateRef<{}>;\n  @Input() nzPlacement: NzDrawerPlacement = 'right';\n  @Input() nzSize: NzDrawerSize = 'default';\n  @Input() nzMaskStyle: NgStyleInterface = {};\n  @Input() nzBodyStyle: NgStyleInterface = {};\n  @Input() nzWrapClassName?: string;\n  @Input() nzWidth?: number | string;\n  @Input() nzHeight?: number | string;\n  @Input() nzZIndex = 1000;\n  @Input() nzOffsetX = 0;\n  @Input() nzOffsetY = 0;\n  private componentInstance: T | null = null;\n  private componentRef: ComponentRef<T> | null = null;\n\n  @Input({ transform: booleanAttribute })\n  set nzVisible(value: boolean) {\n    this.isOpen = value;\n  }\n\n  get nzVisible(): boolean {\n    return this.isOpen;\n  }\n\n  @Output() readonly nzOnViewInit = new EventEmitter<void>();\n  @Output() readonly nzOnClose = new EventEmitter<MouseEvent>();\n  @Output() readonly nzVisibleChange = new EventEmitter<boolean>();\n\n  @ViewChild('drawerTemplate', { static: true }) drawerTemplate!: TemplateRef<void>;\n  @ViewChild(CdkPortalOutlet, { static: false }) bodyPortalOutlet?: CdkPortalOutlet;\n  @ContentChild(NzDrawerContentDirective, { static: true, read: TemplateRef })\n  contentFromContentChild?: TemplateRef<NzSafeAny>;\n\n  previouslyFocusedElement?: HTMLElement;\n  placementChanging = false;\n  placementChangeTimeoutId?: ReturnType<typeof setTimeout>;\n  nzContentParams?: NzSafeAny; // only service\n  nzData?: D;\n  overlayRef?: OverlayRef | null;\n  portal?: TemplatePortal;\n  focusTrap?: FocusTrap;\n  isOpen = false;\n  inAnimation = false;\n  templateContext: { $implicit: D | undefined; drawerRef: NzDrawerRef<R> } = {\n    $implicit: undefined,\n    drawerRef: this as NzDrawerRef<R>\n  };\n  protected isTemplateRef = isTemplateRef;\n  protected readonly maskAnimationEnter = withAnimationCheck(() => 'ant-drawer-mask-motion-enter');\n  protected readonly maskAnimationLeave = withAnimationCheck(() => 'ant-drawer-mask-motion-leave');\n\n  get offsetTransform(): string | null {\n    if (!this.isOpen || this.nzOffsetX + this.nzOffsetY === 0) {\n      return null;\n    }\n    switch (this.nzPlacement) {\n      case 'left':\n        return `translateX(${this.nzOffsetX}px)`;\n      case 'right':\n        return `translateX(-${this.nzOffsetX}px)`;\n      case 'top':\n        return `translateY(${this.nzOffsetY}px)`;\n      case 'bottom':\n        return `translateY(-${this.nzOffsetY}px)`;\n    }\n  }\n\n  get transform(): string | null {\n    if (this.isOpen) {\n      return null;\n    }\n\n    switch (this.nzPlacement) {\n      case 'left':\n        return `translateX(-100%)`;\n      case 'right':\n        return `translateX(100%)`;\n      case 'top':\n        return `translateY(-100%)`;\n      case 'bottom':\n        return `translateY(100%)`;\n    }\n  }\n\n  get width(): string | null {\n    if (this.isLeftOrRight) {\n      const defaultWidth = this.nzSize === 'large' ? DRAWER_LARGE_SIZE : DRAWER_DEFAULT_SIZE;\n      return this.nzWidth === undefined ? toCssPixel(defaultWidth) : toCssPixel(this.nzWidth);\n    }\n    return null;\n  }\n\n  get height(): string | null {\n    if (!this.isLeftOrRight) {\n      const defaultHeight = this.nzSize === 'large' ? DRAWER_LARGE_SIZE : DRAWER_DEFAULT_SIZE;\n      return this.nzHeight === undefined ? toCssPixel(defaultHeight) : toCssPixel(this.nzHeight);\n    }\n    return null;\n  }\n\n  get isLeftOrRight(): boolean {\n    return this.nzPlacement === 'left' || this.nzPlacement === 'right';\n  }\n\n  nzAfterOpen = new Subject<void>();\n  nzAfterClose = new Subject<R | undefined>();\n\n  get afterOpen(): Observable<void> {\n    return this.nzAfterOpen.asObservable();\n  }\n\n  get afterClose(): Observable<R | undefined> {\n    return this.nzAfterClose.asObservable();\n  }\n\n  get isNzContentTemplateRef(): boolean {\n    return isTemplateRef(this.nzContent);\n  }\n\n  // from service config\n  @WithConfig() nzDirection?: Direction = undefined;\n\n  dir: Direction = 'ltr';\n\n  constructor() {\n    super();\n    this.destroyRef.onDestroy(() => {\n      clearTimeout(this.placementChangeTimeoutId);\n      this.disposeOverlay();\n    });\n  }\n\n  ngOnInit(): void {\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n      this.dir = direction;\n      this.cdr.detectChanges();\n    });\n    this.dir = this.nzDirection || this.directionality.value;\n\n    this.attachOverlay();\n    this.updateOverlayStyle();\n    this.updateBodyOverflow();\n    this.templateContext = { $implicit: this.nzData || this.nzContentParams, drawerRef: this as NzDrawerRef<R> };\n    this.changeDetectorRef.detectChanges();\n  }\n\n  ngAfterViewInit(): void {\n    this.attachBodyContent();\n    // The `setTimeout` triggers change detection. There's no sense to schedule the DOM timer if anyone is\n    // listening to the `nzOnViewInit` event inside the template, for instance `<nz-drawer (nzOnViewInit)=\"...\">`.\n    if (this.nzOnViewInit.observers.length) {\n      setTimeout(() => {\n        this.nzOnViewInit.emit();\n      });\n    }\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzPlacement, nzVisible } = changes;\n    if (nzVisible) {\n      const value = changes.nzVisible.currentValue;\n      if (value) {\n        this.open();\n      } else {\n        this.close();\n      }\n    }\n    if (nzPlacement && !nzPlacement.isFirstChange()) {\n      this.triggerPlacementChangeCycleOnce();\n    }\n  }\n\n  private getAnimationDuration(): number {\n    return this.nzNoAnimation ? 0 : DRAWER_ANIMATE_DURATION;\n  }\n\n  // Disable the transition animation temporarily when the placement changing\n  private triggerPlacementChangeCycleOnce(): void {\n    if (!this.nzNoAnimation) {\n      this.placementChanging = true;\n      this.changeDetectorRef.markForCheck();\n      clearTimeout(this.placementChangeTimeoutId);\n      this.placementChangeTimeoutId = setTimeout(() => {\n        this.placementChanging = false;\n        this.changeDetectorRef.markForCheck();\n      }, this.getAnimationDuration());\n    }\n  }\n\n  close(result?: R): void {\n    this.isOpen = false;\n    this.inAnimation = true;\n    this.nzVisibleChange.emit(false);\n    this.updateOverlayStyle();\n    this.overlayKeyboardDispatcher.remove(this.overlayRef!);\n    this.changeDetectorRef.detectChanges();\n    setTimeout(() => {\n      this.updateBodyOverflow();\n      this.restoreFocus();\n      this.inAnimation = false;\n      this.nzAfterClose.next(result);\n      this.nzAfterClose.complete();\n      this.componentInstance = null;\n      this.componentRef = null;\n    }, this.getAnimationDuration());\n  }\n\n  open(): void {\n    this.attachOverlay();\n    this.isOpen = true;\n    this.inAnimation = true;\n    this.nzVisibleChange.emit(true);\n    this.overlayKeyboardDispatcher.add(this.overlayRef!);\n    this.updateOverlayStyle();\n    this.updateBodyOverflow();\n    this.savePreviouslyFocusedElement();\n    this.trapFocus();\n    this.changeDetectorRef.detectChanges();\n    setTimeout(() => {\n      this.inAnimation = false;\n      this.changeDetectorRef.detectChanges();\n      this.nzAfterOpen.next();\n    }, this.getAnimationDuration());\n  }\n\n  getContentComponent(): T | null {\n    return this.componentInstance;\n  }\n\n  override getContentComponentRef(): ComponentRef<T> | null {\n    return this.componentRef;\n  }\n\n  closeClick(): void {\n    this.nzOnClose.emit();\n  }\n\n  maskClick(): void {\n    if (this.nzMaskClosable && this.nzMask) {\n      this.nzOnClose.emit();\n    }\n  }\n\n  private attachBodyContent(): void {\n    this.bodyPortalOutlet!.dispose();\n\n    if (this.nzContent instanceof Type) {\n      const childInjector = Injector.create({\n        parent: this.injector,\n        providers: [\n          { provide: NzDrawerRef, useValue: this },\n          { provide: NZ_DRAWER_DATA, useValue: this.nzData }\n        ]\n      });\n      const componentPortal = new ComponentPortal<T>(this.nzContent, null, childInjector);\n      this.componentRef = this.bodyPortalOutlet!.attachComponentPortal(componentPortal);\n\n      this.componentInstance = this.componentRef.instance;\n      /**TODO\n       * When nzContentParam will be remove in the next major version, we have to remove the following line\n       * **/\n      Object.assign(this.componentRef.instance!, this.nzData || this.nzContentParams);\n      this.componentRef.changeDetectorRef.detectChanges();\n    }\n  }\n\n  private attachOverlay(): void {\n    if (!this.overlayRef) {\n      this.portal = new TemplatePortal(this.drawerTemplate, this.viewContainerRef);\n      this.overlayRef = createOverlayRef(this.injector, {\n        disposeOnNavigation: this.nzCloseOnNavigation,\n        positionStrategy: createGlobalPositionStrategy(this.injector),\n        scrollStrategy: createBlockScrollStrategy(this.injector)\n      });\n\n      overlayZIndexSetter(this.overlayRef, this.nzZIndex);\n    }\n\n    if (this.overlayRef && !this.overlayRef.hasAttached()) {\n      this.overlayRef.attach(this.portal);\n      this.overlayRef!.keydownEvents()\n        .pipe(takeUntilDestroyed(this.destroyRef))\n        .subscribe((event: KeyboardEvent) => {\n          if (event.keyCode === ESCAPE && this.isOpen && this.nzKeyboard) {\n            this.nzOnClose.emit();\n          }\n        });\n      this.overlayRef\n        .detachments()\n        .pipe(takeUntilDestroyed(this.destroyRef))\n        .subscribe(() => {\n          this.close();\n          this.disposeOverlay();\n        });\n    }\n  }\n\n  private disposeOverlay(): void {\n    this.overlayRef?.dispose();\n    this.overlayRef = null;\n  }\n\n  private updateOverlayStyle(): void {\n    if (this.overlayRef && this.overlayRef.overlayElement) {\n      this.renderer.setStyle(this.overlayRef.overlayElement, 'pointer-events', this.isOpen ? 'auto' : 'none');\n    }\n  }\n\n  private updateBodyOverflow(): void {\n    if (this.overlayRef) {\n      if (this.isOpen) {\n        this.overlayRef.getConfig().scrollStrategy!.enable();\n      } else {\n        this.overlayRef.getConfig().scrollStrategy!.disable();\n      }\n    }\n  }\n\n  savePreviouslyFocusedElement(): void {\n    if (this.document && !this.previouslyFocusedElement) {\n      this.previouslyFocusedElement = this.document.activeElement as HTMLElement;\n      this.previouslyFocusedElement?.blur();\n    }\n  }\n\n  private trapFocus(): void {\n    if (!this.focusTrap && this.overlayRef && this.overlayRef.overlayElement) {\n      this.focusTrap = this.focusTrapFactory.create(this.overlayRef!.overlayElement);\n      this.focusTrap.focusInitialElement();\n    }\n  }\n\n  private restoreFocus(): void {\n    if (this.previouslyFocusedElement) {\n      this.previouslyFocusedElement.focus();\n      this.previouslyFocusedElement = undefined;\n    }\n    if (this.focusTrap) {\n      this.focusTrap.destroy();\n    }\n  }\n}\n"
  },
  {
    "path": "components/drawer/drawer.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzDrawerContentDirective } from './drawer-content.directive';\nimport { NzDrawerComponent } from './drawer.component';\nimport { NzDrawerService } from './drawer.service';\n\n@NgModule({\n  imports: [NzDrawerComponent, NzDrawerContentDirective],\n  providers: [NzDrawerService],\n  exports: [NzDrawerComponent, NzDrawerContentDirective]\n})\nexport class NzDrawerModule {}\n"
  },
  {
    "path": "components/drawer/drawer.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { createOverlayRef, OverlayRef } from '@angular/cdk/overlay';\nimport { ComponentPortal } from '@angular/cdk/portal';\nimport { inject, Injectable, Injector } from '@angular/core';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzDrawerOptions, NzDrawerOptionsOfComponent } from './drawer-options';\nimport { NzDrawerRef } from './drawer-ref';\nimport { NzDrawerComponent } from './drawer.component';\n\nexport class DrawerBuilderForService<T extends {}, R> {\n  private drawerRef: NzDrawerComponent<T, R> | null;\n  private unsubscribe$ = new Subject<void>();\n\n  constructor(\n    private overlayRef: OverlayRef,\n    private options: NzDrawerOptions\n  ) {\n    /** pick {@link NzDrawerOptions.nzOnCancel} and omit this option */\n    const { nzOnCancel, ...componentOption } = this.options;\n    this.drawerRef = this.overlayRef.attach(new ComponentPortal(NzDrawerComponent)).instance;\n    this.updateOptions(componentOption);\n    // Prevent repeatedly open drawer when tap focus element.\n    this.drawerRef.savePreviouslyFocusedElement();\n    this.drawerRef.nzOnViewInit.pipe(takeUntil(this.unsubscribe$)).subscribe(() => {\n      this.drawerRef!.open();\n    });\n    this.drawerRef.nzOnClose.subscribe(() => {\n      if (nzOnCancel) {\n        nzOnCancel().then(canClose => {\n          if (canClose !== false) {\n            this.drawerRef!.close();\n          }\n        });\n      } else {\n        this.drawerRef!.close();\n      }\n    });\n\n    this.drawerRef.afterClose.pipe(takeUntil(this.unsubscribe$)).subscribe(() => {\n      this.overlayRef.dispose();\n      this.drawerRef = null;\n      this.unsubscribe$.next();\n      this.unsubscribe$.complete();\n    });\n  }\n\n  getInstance(): NzDrawerRef<T, R> {\n    return this.drawerRef!;\n  }\n\n  updateOptions(options: NzDrawerOptionsOfComponent): void {\n    Object.assign(this.drawerRef!, options);\n  }\n}\n\n@Injectable()\nexport class NzDrawerService {\n  private injector = inject(Injector);\n\n  create<T extends {} = NzSafeAny, D = undefined, R = NzSafeAny>(\n    options: NzDrawerOptions<T, D extends undefined ? {} : D>\n  ): NzDrawerRef<T, R> {\n    return new DrawerBuilderForService<T, R>(createOverlayRef(this.injector), options).getInstance();\n  }\n}\n"
  },
  {
    "path": "components/drawer/drawer.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport { ESCAPE } from '@angular/cdk/keycodes';\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport { Component, Input, TemplateRef, ViewChild, inject, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, TestBed, fakeAsync, inject as testingInject, tick } from '@angular/core/testing';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { provideNzNoAnimation } from 'ng-zorro-antd/core/animation';\nimport { dispatchKeyboardEvent } from 'ng-zorro-antd/core/testing';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NZ_DRAWER_DATA, NzDrawerPlacement } from './drawer-options';\nimport { NzDrawerRef } from './drawer-ref';\nimport { NzDrawerComponent } from './drawer.component';\nimport { NzDrawerModule } from './drawer.module';\nimport { NzDrawerService } from './drawer.service';\n\ndescribe('NzDrawerComponent', () => {\n  describe('default', () => {\n    let component: NzTestDrawerComponent;\n    let fixture: ComponentFixture<NzTestDrawerComponent>;\n    let overlayContainer: OverlayContainer;\n    let overlayContainerElement: HTMLElement;\n    let forceScrollElement: HTMLElement;\n\n    beforeEach(() => {\n      // todo: use zoneless\n      TestBed.configureTestingModule({\n        providers: [provideNzNoAnimation(), provideNzIconsTesting(), provideZoneChangeDetection()]\n      });\n    });\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestDrawerComponent);\n      component = fixture.componentInstance;\n      fixture.detectChanges();\n    });\n\n    beforeEach(\n      testingInject([OverlayContainer], (oc: OverlayContainer) => {\n        overlayContainer = oc;\n        overlayContainerElement = oc.getContainerElement();\n        forceScrollElement = document.createElement('div');\n        document.body.appendChild(forceScrollElement);\n        forceScrollElement.style.width = '100px';\n        forceScrollElement.style.height = '3000px';\n        forceScrollElement.style.background = 'rebeccapurple';\n      })\n    );\n\n    afterEach(() => {\n      component.close();\n      document.body.removeChild(forceScrollElement);\n      window.scroll(0, 0);\n      overlayContainer.ngOnDestroy();\n    });\n\n    it('should open work', () => {\n      expect(component.triggerVisible).toHaveBeenCalledTimes(1);\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(component.drawerComponent.nzVisible).toBe(true);\n      expect(component.triggerVisible).toHaveBeenCalledTimes(2);\n      expect(component.triggerVisible).toHaveBeenCalledWith(true);\n    });\n\n    it('should close work', () => {\n      expect(component.triggerVisible).toHaveBeenCalledTimes(1);\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(component.triggerVisible).toHaveBeenCalledTimes(2);\n      expect(component.triggerVisible).toHaveBeenCalledWith(true);\n      component.close();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(false);\n      expect(component.drawerComponent.nzVisible).toBe(false);\n      expect(component.triggerVisible).toHaveBeenCalledTimes(3);\n      expect(component.triggerVisible).toHaveBeenCalledWith(false);\n    });\n\n    it('should block scroll', fakeAsync(() => {\n      expect(document.documentElement!.classList).not.toContain('cdk-global-scrollblock');\n      component.open();\n      tick(300);\n      fixture.detectChanges();\n      expect(document.documentElement!.classList).toContain('cdk-global-scrollblock');\n      component.close();\n      fixture.detectChanges();\n      tick(300);\n      fixture.detectChanges();\n      expect(document.documentElement!.classList).not.toContain('cdk-global-scrollblock');\n    }));\n\n    it('should hied close button', () => {\n      component.closable = false;\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(overlayContainerElement.querySelector('.ant-drawer .ant-drawer-close')).toBe(null);\n    });\n\n    it('should open work', () => {\n      expect(component.triggerVisible).toHaveBeenCalledTimes(1);\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(component.drawerComponent.nzVisible).toBe(true);\n      expect(component.triggerVisible).toHaveBeenCalledTimes(2);\n      expect(component.triggerVisible).toHaveBeenCalledWith(true);\n    });\n\n    it('should close work', () => {\n      expect(component.triggerVisible).toHaveBeenCalledTimes(1);\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(component.triggerVisible).toHaveBeenCalledTimes(2);\n      expect(component.triggerVisible).toHaveBeenCalledWith(true);\n      component.close();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(false);\n      expect(component.drawerComponent.nzVisible).toBe(false);\n      expect(component.triggerVisible).toHaveBeenCalledTimes(3);\n      expect(component.triggerVisible).toHaveBeenCalledWith(false);\n    });\n\n    it('should closable', () => {\n      expect(component.triggerVisible).toHaveBeenCalledTimes(1);\n      component.closable = true;\n      component.open();\n      fixture.detectChanges();\n      expect(component.triggerVisible).toHaveBeenCalledTimes(2);\n      expect(component.triggerVisible).toHaveBeenCalledWith(true);\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      (overlayContainerElement.querySelector('.ant-drawer .ant-drawer-close') as HTMLElement).click();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(false);\n      expect(component.triggerVisible).toHaveBeenCalledTimes(3);\n      expect(component.triggerVisible).toHaveBeenCalledWith(false);\n    });\n\n    it('should set close icon work', () => {\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer .anticon-close')).toBeDefined();\n\n      component.closeIcon = 'close-circle';\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer .anticon-close')).toBeNull();\n      expect(overlayContainerElement.querySelector('.ant-drawer .anticon-close-circle')).toBeDefined();\n\n      component.closeIcon = component.closeIconTemplateRef;\n      fixture.detectChanges();\n\n      expect(overlayContainerElement.querySelector('.ant-drawer .anticon-close')).toBeNull();\n      expect(overlayContainerElement.querySelector('.ant-drawer .anticon-close-circle')).toBeNull();\n      expect(overlayContainerElement.querySelector('.ant-drawer .anticon-close-square')).toBeDefined();\n    });\n\n    it('should not close when click mask', () => {\n      expect(component.triggerVisible).toHaveBeenCalledTimes(1);\n      component.maskClosable = false;\n      component.open();\n      fixture.detectChanges();\n      expect(component.triggerVisible).toHaveBeenCalledTimes(2);\n      expect(component.triggerVisible).toHaveBeenCalledWith(true);\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      (overlayContainerElement.querySelector('.ant-drawer .ant-drawer-mask') as HTMLElement).click();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(component.triggerVisible).toHaveBeenCalledTimes(2);\n    });\n\n    it('should be closed when ESC keydown', () => {\n      expect(component.triggerVisible).toHaveBeenCalledTimes(1);\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(component.triggerVisible).toHaveBeenCalledTimes(2);\n      expect(component.triggerVisible).toHaveBeenCalledWith(true);\n      dispatchKeyboardEvent(document.body, 'keydown', ESCAPE);\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(false);\n      expect(component.triggerVisible).toHaveBeenCalledTimes(3);\n      expect(component.triggerVisible).toHaveBeenCalledWith(false);\n    });\n\n    it('should disabled ESC keydown', () => {\n      expect(component.triggerVisible).toHaveBeenCalledTimes(1);\n      component.open();\n      component.drawerComponent.nzKeyboard = false;\n      fixture.detectChanges();\n      expect(component.triggerVisible).toHaveBeenCalledTimes(2);\n      expect(component.triggerVisible).toHaveBeenCalledWith(true);\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      dispatchKeyboardEvent(document.body, 'keydown', ESCAPE);\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(component.triggerVisible).toHaveBeenCalledTimes(2);\n      component.close();\n      fixture.detectChanges();\n    });\n\n    it('should close when click mask', () => {\n      expect(component.triggerVisible).toHaveBeenCalledTimes(1);\n      component.maskClosable = true;\n      component.open();\n      fixture.detectChanges();\n      expect(component.triggerVisible).toHaveBeenCalledTimes(2);\n      expect(component.triggerVisible).toHaveBeenCalledWith(true);\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      (overlayContainerElement.querySelector('.ant-drawer .ant-drawer-mask') as HTMLElement).click();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(false);\n      expect(component.triggerVisible).toHaveBeenCalledTimes(3);\n      expect(component.triggerVisible).toHaveBeenCalledWith(false);\n    });\n\n    it('should not show mask', () => {\n      component.showMask = false;\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('no-mask')).toBe(true);\n      expect(overlayContainerElement.querySelector('.ant-drawer .ant-drawer-mask')).toBe(null);\n      component.showMask = true;\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('no-mask')).toBe(false);\n    });\n\n    it('should set nzMaskStyle & nzBodyStyle', () => {\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect((overlayContainerElement.querySelector('.ant-drawer .ant-drawer-mask') as HTMLElement).style.color).toBe(\n        'gray'\n      );\n      expect((overlayContainerElement.querySelector('.ant-drawer .ant-drawer-body') as HTMLElement).style.color).toBe(\n        'gray'\n      );\n    });\n\n    it('should not render title', () => {\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(overlayContainerElement.querySelector('.ant-drawer .ant-drawer-title')).toBe(null);\n    });\n\n    it('should render header when is no title but is closeable', () => {\n      component.closable = true;\n      component.open();\n      fixture.detectChanges();\n\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(overlayContainerElement.querySelector('.ant-drawer-header-close-only')).toBeTruthy();\n      expect(overlayContainerElement.querySelector('.ant-drawer .ant-drawer-title')).toBe(null);\n    });\n\n    it('should not render title even with nzExtra', () => {\n      component.extra = 'test';\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(overlayContainerElement.querySelector('.ant-drawer .ant-drawer-title')).toBe(null);\n    });\n\n    it('should support string extra', () => {\n      component.closable = true;\n      component.extra = component.stringTitle;\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(\n        (overlayContainerElement.querySelector('.ant-drawer .ant-drawer-extra') as HTMLElement).innerText.trim()\n      ).toBe('test');\n    });\n\n    it('should support TemplateRef extra', () => {\n      component.closable = true;\n      component.extra = component.titleTemplateRef;\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(overlayContainerElement.querySelector('.ant-drawer .ant-drawer-extra .custom-title')).not.toBe(null);\n    });\n\n    it('should support string title', () => {\n      component.title = component.stringTitle;\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(\n        (overlayContainerElement.querySelector('.ant-drawer .ant-drawer-title') as HTMLElement).innerText.trim()\n      ).toBe('test');\n    });\n\n    it('should support TemplateRef title', () => {\n      component.title = component.titleTemplateRef;\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(overlayContainerElement.querySelector('.ant-drawer .ant-drawer-title .custom-title')).not.toBe(null);\n    });\n\n    it('should support string footer', () => {\n      component.footer = 'test';\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(\n        (overlayContainerElement.querySelector('.ant-drawer .ant-drawer-footer') as HTMLElement).innerText.trim()\n      ).toBe('test');\n    });\n\n    it('should support TemplateRef footer', () => {\n      component.footer = component.templateFooter;\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(overlayContainerElement.querySelector('.ant-drawer .ant-drawer-footer .custom-footer')).not.toBe(null);\n    });\n\n    it('should support custom width', () => {\n      component.width = '500px';\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(\n        (\n          overlayContainerElement.querySelector('.ant-drawer .ant-drawer-content') as HTMLElement\n        ).getBoundingClientRect().width\n      ).toBe(500);\n    });\n\n    it('should support custom number type width', () => {\n      component.width = 520;\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(\n        (\n          overlayContainerElement.querySelector('.ant-drawer .ant-drawer-content') as HTMLElement\n        ).getBoundingClientRect().width\n      ).toBe(520);\n    });\n\n    it('should support custom height', () => {\n      component.height = '500px';\n      component.placement = 'top';\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(\n        (\n          overlayContainerElement.querySelector('.ant-drawer .ant-drawer-content-wrapper') as HTMLElement\n        ).getBoundingClientRect().height\n      ).toBe(500);\n      component.placement = 'left';\n      fixture.detectChanges();\n    });\n\n    it('should support custom number type height', () => {\n      component.height = 520;\n      component.placement = 'top';\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(\n        (\n          overlayContainerElement.querySelector('.ant-drawer .ant-drawer-content-wrapper') as HTMLElement\n        ).getBoundingClientRect().height\n      ).toBe(520);\n      component.placement = 'left';\n      fixture.detectChanges();\n    });\n\n    it('should support large size width', () => {\n      component.size = 'large';\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(\n        (\n          overlayContainerElement.querySelector('.ant-drawer .ant-drawer-content') as HTMLElement\n        ).getBoundingClientRect().width\n      ).toBe(736);\n    });\n\n    it('should custom width priority higher than size', () => {\n      component.size = 'large';\n      component.width = 520;\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(\n        (\n          overlayContainerElement.querySelector('.ant-drawer .ant-drawer-content') as HTMLElement\n        ).getBoundingClientRect().width\n      ).toBe(520);\n    });\n\n    it('should support large size height', () => {\n      component.size = 'large';\n      component.placement = 'top';\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(\n        (\n          overlayContainerElement.querySelector('.ant-drawer .ant-drawer-content-wrapper') as HTMLElement\n        ).getBoundingClientRect().height\n      ).toBe(736);\n      component.placement = 'left';\n      fixture.detectChanges();\n    });\n\n    it('should custom height priority higher than size', () => {\n      component.size = 'large';\n      component.height = 520;\n      component.placement = 'top';\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(\n        (\n          overlayContainerElement.querySelector('.ant-drawer .ant-drawer-content-wrapper') as HTMLElement\n        ).getBoundingClientRect().height\n      ).toBe(520);\n      component.placement = 'left';\n      fixture.detectChanges();\n    });\n\n    it('should nzWrapClassName work', () => {\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(\n        (\n          overlayContainerElement.querySelector('.ant-drawer .ant-drawer-content-wrapper') as HTMLElement\n        ).classList.contains('test-class')\n      ).toBe(true);\n    });\n\n    it('should nzZIndex work', () => {\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).style.zIndex).toBe('1001');\n    });\n\n    it('should nzPlacement work', () => {\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect(\n        (overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-left')\n      ).toBe(true);\n      expect(\n        (overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-bottom')\n      ).toBe(false);\n      expect(\n        (overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-top')\n      ).toBe(false);\n      component.placement = 'right';\n      fixture.detectChanges();\n      component.close();\n      fixture.detectChanges();\n      component.open();\n      expect(\n        (overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-left')\n      ).toBe(false);\n      expect(\n        (overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-right')\n      ).toBe(true);\n      expect(\n        (overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-bottom')\n      ).toBe(false);\n      expect(\n        (overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-top')\n      ).toBe(false);\n      component.placement = 'top';\n      fixture.detectChanges();\n      component.close();\n      fixture.detectChanges();\n      component.open();\n      expect(\n        (overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-left')\n      ).toBe(false);\n      expect(\n        (overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-right')\n      ).toBe(false);\n      expect(\n        (overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-bottom')\n      ).toBe(false);\n      expect(\n        (overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-top')\n      ).toBe(true);\n      component.placement = 'bottom';\n      fixture.detectChanges();\n      component.close();\n      fixture.detectChanges();\n      component.open();\n      expect(\n        (overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-left')\n      ).toBe(false);\n      expect(\n        (overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-right')\n      ).toBe(false);\n      expect(\n        (overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-bottom')\n      ).toBe(true);\n      expect(\n        (overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-top')\n      ).toBe(false);\n      component.close();\n      fixture.detectChanges();\n      component.placement = 'Invalid' as unknown as NzDrawerPlacement;\n      fixture.detectChanges();\n      component.open();\n      expect(\n        (overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-left')\n      ).toBe(false);\n      expect(\n        (overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-right')\n      ).toBe(false);\n      expect(\n        (overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-bottom')\n      ).toBe(false);\n      expect(\n        (overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).classList.contains('ant-drawer-top')\n      ).toBe(false);\n      component.close();\n      fixture.detectChanges();\n    });\n\n    it('should disable the transition when the placement changing', fakeAsync(() => {\n      component.open();\n      tick(300);\n      fixture.detectChanges();\n      expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).style.transition).toBe('');\n      component.placement = 'top';\n      fixture.detectChanges();\n      expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).style.transition).toBe('none');\n      expect(\n        (overlayContainerElement.querySelector('.ant-drawer-content-wrapper') as HTMLElement).style.transition\n      ).toBe('none');\n      component.placement = 'right';\n      fixture.detectChanges();\n      component.close();\n      fixture.detectChanges();\n      tick(300);\n      fixture.detectChanges();\n      expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).style.transition).toBe('');\n    }));\n\n    it('should ignore set transition when `noAnimation` is `true` ', fakeAsync(() => {\n      component.noAnimation = true;\n      fixture.detectChanges();\n      component.open();\n      tick(300);\n      fixture.detectChanges();\n      expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).style.transition).toBe('');\n      component.placement = 'top';\n      fixture.detectChanges();\n      expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).style.transition).toBe('');\n      expect(\n        (overlayContainerElement.querySelector('.ant-drawer-content-wrapper') as HTMLElement).style.transition\n      ).toBe('');\n      fixture.detectChanges();\n      component.close();\n      component.placement = 'right';\n      component.noAnimation = false;\n      fixture.detectChanges();\n      tick(300);\n      fixture.detectChanges();\n    }));\n\n    it('should nzOffsetX work', () => {\n      component.open();\n      component.placement = 'left';\n      component.width = '300px';\n      component.offsetX = 100;\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).style.transform).toBe(\n        'translateX(100px)'\n      );\n      fixture.detectChanges();\n      component.placement = 'right';\n      component.offsetX = 100;\n      fixture.detectChanges();\n      expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).style.transform).toBe(\n        'translateX(-100px)'\n      );\n      component.close();\n      fixture.detectChanges();\n    });\n\n    it('should nzOffsetY work', () => {\n      component.open();\n      component.placement = 'top';\n      component.height = '300px';\n      component.offsetY = 100;\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-open')).toBe(true);\n      expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).style.transform).toBe(\n        'translateY(100px)'\n      );\n      fixture.detectChanges();\n      component.placement = 'bottom';\n      component.offsetY = 100;\n      fixture.detectChanges();\n      expect((overlayContainerElement.querySelector('.ant-drawer') as HTMLElement).style.transform).toBe(\n        'translateY(-100px)'\n      );\n      component.close();\n      fixture.detectChanges();\n    });\n\n    it('should allow scroll', () => {\n      component.placement = 'right';\n      component.open();\n      fixture.detectChanges();\n      expect(\n        (overlayContainerElement.querySelector('.ant-drawer .ant-drawer-wrapper-body') as HTMLElement).style.height\n      ).toBe('100%');\n    });\n  });\n  describe('RTL', () => {\n    let component: NzTestDrawerRtlComponent;\n    let fixture: ComponentFixture<NzTestDrawerRtlComponent>;\n    let overlayContainerElement: HTMLElement;\n\n    beforeEach(() => {\n      // todo: use zoneless\n      TestBed.configureTestingModule({\n        providers: [provideNzNoAnimation(), provideNzIconsTesting(), provideZoneChangeDetection()]\n      });\n    });\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestDrawerRtlComponent);\n      component = fixture.componentInstance;\n      fixture.detectChanges();\n    });\n\n    beforeEach(\n      testingInject([OverlayContainer], (oc: OverlayContainer) => {\n        overlayContainerElement = oc.getContainerElement();\n      })\n    );\n\n    it('should className correct on dir change', () => {\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-rtl')).toBe(true);\n\n      fixture.componentInstance.direction = 'ltr';\n      component.close();\n      fixture.detectChanges();\n      component.open();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-drawer')!.classList.contains('ant-drawer-rtl')).toBe(false);\n    });\n  });\n  describe('animation', () => {\n    beforeEach(() => {\n      // todo: use zoneless\n      TestBed.configureTestingModule({\n        providers: [provideNzIconsTesting(), provideZoneChangeDetection()]\n      });\n    });\n\n    it('should get correct mask animation class', () => {\n      const fixture = TestBed.createComponent(NzDrawerComponent);\n      expect(fixture.componentInstance['maskAnimationEnter']()).toBe('ant-drawer-mask-motion-enter');\n      expect(fixture.componentInstance['maskAnimationLeave']()).toBe('ant-drawer-mask-motion-leave');\n    });\n  });\n});\n\ndescribe('NzDrawerService', () => {\n  let component: NzTestDrawerWithServiceComponent;\n  let fixture: ComponentFixture<NzTestDrawerWithServiceComponent>;\n  let overlayContainer: OverlayContainer;\n  let drawerService: NzDrawerService;\n  let overlayContainerElement: HTMLElement;\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [NzDrawerService, provideNzNoAnimation()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzTestDrawerWithServiceComponent);\n    component = fixture.componentInstance;\n    fixture.detectChanges();\n  });\n\n  beforeEach(\n    testingInject([OverlayContainer, NzDrawerService], (oc: OverlayContainer, ds: NzDrawerService) => {\n      overlayContainer = oc;\n      drawerService = ds;\n      overlayContainerElement = oc.getContainerElement();\n    })\n  );\n\n  afterEach(() => {\n    overlayContainer.ngOnDestroy();\n  });\n\n  it('should create template content drawer', fakeAsync(() => {\n    component.openTemplate();\n    fixture.detectChanges();\n    tick(300);\n    expect(component.templateDrawerRef?.getContentComponent()).toBeNull();\n    expect(component.templateDrawerRef?.getContentComponentRef()).toBeNull();\n    expect(component.templateOpenSpy).toHaveBeenCalled();\n    fixture.detectChanges();\n    (overlayContainerElement.querySelector('.ant-drawer .ant-drawer-mask') as HTMLElement).click();\n    tick(300);\n    expect(component.templateCloseSpy).toHaveBeenCalled();\n    fixture.detectChanges();\n  }));\n\n  it('should create component content drawer', fakeAsync(() => {\n    const openSpy = jasmine.createSpy('afterOpen spy');\n    const closeSpy = jasmine.createSpy('afterClose spy').and.returnValue(1);\n    const drawerRef = drawerService.create({\n      nzTitle: 'Service',\n      nzFooter: 'Footer',\n      nzContent: NzDrawerCustomComponent,\n      nzContentParams: { value: 1 }\n    });\n    drawerRef.afterOpen.subscribe(openSpy);\n    drawerRef.afterClose.subscribe(closeSpy);\n    fixture.detectChanges();\n    expect(openSpy).not.toHaveBeenCalled();\n    expect(drawerRef.getContentComponent()).not.toBeNull();\n    expect(drawerRef.getContentComponentRef()).not.toBeNull();\n    tick(300);\n    expect(openSpy).toHaveBeenCalled();\n    (overlayContainerElement.querySelector('.ant-drawer .close-btn') as HTMLElement).click();\n    fixture.detectChanges();\n    tick(300);\n    expect(closeSpy).toHaveBeenCalled();\n    fixture.detectChanges();\n    expect(drawerRef.getContentComponent()).toBeNull();\n    expect(drawerRef.getContentComponentRef()).toBeNull();\n  }));\n\n  it('should create a component drawer and use nzData instead of nzContentParams', fakeAsync(() => {\n    const openSpy = jasmine.createSpy('afterOpen spy');\n    const closeSpy = jasmine.createSpy('afterClose spy').and.returnValue(2);\n    const drawerRef = drawerService.create({\n      nzTitle: 'Service',\n      nzFooter: 'Footer',\n      nzContent: NzDrawerCustomComponent,\n      nzContentParams: { value: 1 },\n      nzData: { value: 2 }\n    });\n    drawerRef.afterOpen.subscribe(openSpy);\n    drawerRef.afterClose.subscribe(closeSpy);\n    fixture.detectChanges();\n    expect(openSpy).not.toHaveBeenCalled();\n    expect(drawerRef.getContentComponent()).not.toBeNull();\n    expect(drawerRef.getContentComponentRef()).not.toBeNull();\n    tick(300);\n    expect(openSpy).toHaveBeenCalled();\n    (overlayContainerElement.querySelector('.ant-drawer .close-btn') as HTMLElement).click();\n    fixture.detectChanges();\n    tick(300);\n    expect(closeSpy).toHaveBeenCalled();\n    fixture.detectChanges();\n    expect(drawerRef.getContentComponent()).toBeNull();\n    expect(drawerRef.getContentComponentRef()).toBeNull();\n  }));\n\n  it('should `nzOnCancel` work', fakeAsync(() => {\n    let canClose = false;\n    const openSpy = jasmine.createSpy('afterOpen spy');\n    const closeSpy = jasmine.createSpy('afterClose spy').and.returnValue(1);\n    const drawerRef = drawerService.create({\n      nzTitle: 'Service nzOnCancel',\n      nzContent: NzDrawerCustomComponent,\n      nzOnCancel: () => Promise.resolve(canClose)\n    });\n    drawerRef.afterOpen.subscribe(openSpy);\n    drawerRef.afterClose.subscribe(closeSpy);\n    fixture.detectChanges();\n    expect(openSpy).not.toHaveBeenCalled();\n    tick(300);\n    expect(openSpy).toHaveBeenCalled();\n    (overlayContainerElement.querySelector('.ant-drawer .ant-drawer-close') as HTMLElement).click();\n    fixture.detectChanges();\n    tick(300);\n    expect(closeSpy).not.toHaveBeenCalled();\n    fixture.detectChanges();\n    canClose = true;\n    (overlayContainerElement.querySelector('.ant-drawer .ant-drawer-close') as HTMLElement).click();\n    fixture.detectChanges();\n    tick(300);\n    expect(closeSpy).toHaveBeenCalled();\n  }));\n});\n\n@Component({\n  imports: [NzDrawerModule, NzIconModule],\n  template: `\n    <button (click)=\"open()\">Open</button>\n    <ng-template #closeIconTemplate>\n      <nz-icon nzType=\"close-square\" nzTheme=\"outline\" />\n    </ng-template>\n    <ng-template #titleTemplate>\n      <span class=\"custom-title\">title</span>\n      <button class=\"close-btn\"></button>\n    </ng-template>\n    <ng-template #customFooter>\n      <span class=\"custom-footer\">footer</span>\n      <button>Submit</button>\n    </ng-template>\n    <nz-drawer\n      [nzMaskStyle]=\"{ color: 'gray' }\"\n      [nzBodyStyle]=\"{ color: 'gray' }\"\n      [nzMaskClosable]=\"maskClosable\"\n      nzWrapClassName=\"test-class\"\n      [nzZIndex]=\"1001\"\n      [nzCloseIcon]=\"closeIcon\"\n      [nzClosable]=\"closable\"\n      [nzMask]=\"showMask\"\n      [nzVisible]=\"visible\"\n      [nzSize]=\"size\"\n      [nzWidth]=\"width\"\n      [nzHeight]=\"height\"\n      [nzPlacement]=\"placement\"\n      [nzNoAnimation]=\"noAnimation\"\n      [nzTitle]=\"title\"\n      [nzExtra]=\"extra\"\n      [nzFooter]=\"footer\"\n      [nzOffsetX]=\"offsetX\"\n      [nzOffsetY]=\"offsetY\"\n      (nzOnClose)=\"close()\"\n      (nzVisibleChange)=\"triggerVisible($event)\"\n    >\n      <ng-container *nzDrawerContent>\n        <p>Some contents...</p>\n        <p>Some contents...</p>\n        <p>Some contents...</p>\n      </ng-container>\n    </nz-drawer>\n  `\n})\nclass NzTestDrawerComponent {\n  visible = false;\n  closable = true;\n  maskClosable = true;\n  showMask = true;\n  title: string | TemplateRef<{}> = '';\n  extra: string | TemplateRef<{}> = '';\n  footer: string | TemplateRef<{}> = '';\n  stringTitle = 'test';\n  size: 'large' | 'default' = 'default';\n  width?: string | number;\n  height?: string | number;\n  placement: NzDrawerPlacement = 'left';\n  noAnimation = false;\n  closeIcon!: TemplateRef<void> | string;\n  offsetX = 0;\n  offsetY = 0;\n  triggerVisible = jasmine.createSpy('visibleChange');\n\n  @ViewChild('titleTemplate', { static: false }) titleTemplateRef!: TemplateRef<{}>;\n  @ViewChild('closeIconTemplate', { static: false }) closeIconTemplateRef!: TemplateRef<void>;\n  @ViewChild('customFooter', { static: false }) templateFooter!: TemplateRef<{}>;\n  @ViewChild(NzDrawerComponent, { static: false }) drawerComponent!: NzDrawerComponent;\n\n  open(): void {\n    this.visible = true;\n  }\n\n  close(): void {\n    this.visible = false;\n  }\n}\n\n@Component({\n  template: `\n    <ng-template #drawerTemplate>\n      <span>Template</span>\n    </ng-template>\n  `\n})\nclass NzTestDrawerWithServiceComponent {\n  @ViewChild('drawerTemplate', { static: false }) drawerTemplate!: TemplateRef<{\n    $implicit: number;\n    drawerRef: NzDrawerRef;\n  }>;\n  templateOpenSpy = jasmine.createSpy('template afterOpen spy');\n  templateCloseSpy = jasmine.createSpy('template afterClose spy');\n  templateDrawerRef?: NzDrawerRef;\n\n  constructor(private drawerService: NzDrawerService) {}\n\n  openTemplate(): void {\n    this.templateDrawerRef = this.drawerService.create({\n      nzTitle: 'Service',\n      nzContent: this.drawerTemplate\n    });\n\n    this.templateDrawerRef.afterOpen.subscribe(this.templateOpenSpy);\n    this.templateDrawerRef.afterClose.subscribe(this.templateCloseSpy);\n  }\n}\n\n@Component({\n  imports: [NzButtonModule],\n  template: `\n    <div>\n      <p>Custom Component</p>\n      <button class=\"close-btn\" (click)=\"close()\" nz-button>Close</button>\n    </div>\n  `\n})\nexport class NzDrawerCustomComponent {\n  @Input() value: NzSafeAny;\n  nzData: { value: string } = inject(NZ_DRAWER_DATA);\n\n  constructor(private drawerRef: NzDrawerRef) {}\n\n  close(): void {\n    this.drawerRef.close(this.value);\n  }\n}\n\n@Component({\n  imports: [BidiModule, NzDrawerModule],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-drawer [nzVisible]=\"visible\" (nzOnClose)=\"close()\">\n        <ng-container *nzDrawerContent>\n          <p>Some contents...</p>\n          <p>Some contents...</p>\n          <p>Some contents...</p>\n        </ng-container>\n      </nz-drawer>\n    </div>\n  `\n})\nexport class NzTestDrawerRtlComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n  visible = false;\n\n  open(): void {\n    this.visible = true;\n  }\n\n  close(): void {\n    this.visible = false;\n  }\n}\n"
  },
  {
    "path": "components/drawer/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/drawer/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/drawer/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './drawer-content.directive';\nexport * from './drawer-options';\nexport * from './drawer-ref';\nexport * from './drawer.component';\nexport * from './drawer.module';\nexport * from './drawer.service';\n"
  },
  {
    "path": "components/drawer/style/animation.less",
    "content": "@import '../../style/core/motion/fade';\n@import (reference) '../../style/themes/index';\n\n.fade-motion('drawer-mask', @ease-in-out, @animation-duration-slow);\n"
  },
  {
    "path": "components/drawer/style/customize.less",
    "content": "@import './index.less';\n\n.popover-customize-bg(@drawer-prefix-cls, @popover-background);\n"
  },
  {
    "path": "components/drawer/style/drawer.less",
    "content": "@import '../../style/themes/index';\n\n@drawer-prefix-cls: ~'@{ant-prefix}-drawer';\n\n.@{drawer-prefix-cls} {\n  position: fixed;\n  inset: 0;\n  z-index: @zindex-modal;\n  pointer-events: none;\n\n  &-inline {\n    position: absolute;\n  }\n\n  // ====================== Mask ======================\n  &-mask {\n    position: absolute;\n    inset: 0;\n    z-index: @zindex-modal;\n    background: @modal-mask-bg;\n    pointer-events: auto;\n  }\n\n  // ==================== Content =====================\n  &-content-wrapper {\n    position: absolute;\n    z-index: @zindex-modal;\n    transition: all @animation-duration-slow;\n\n    &-hidden {\n      display: none;\n    }\n\n    // Placement\n    .@{drawer-prefix-cls}-left > & {\n      top: 0;\n      bottom: 0;\n      left: 0;\n      box-shadow: @shadow-1-right;\n    }\n\n    .@{drawer-prefix-cls}-right > & {\n      top: 0;\n      right: 0;\n      bottom: 0;\n      box-shadow: @shadow-1-left;\n    }\n\n    .@{drawer-prefix-cls}-top > & {\n      top: 0;\n      right: 0;\n      left: 0;\n      box-shadow: @shadow-1-down;\n    }\n\n    .@{drawer-prefix-cls}-bottom > & {\n      right: 0;\n      bottom: 0;\n      left: 0;\n      box-shadow: @shadow-1-up;\n    }\n  }\n\n  &-content {\n    width: 100%;\n    height: 100%;\n    overflow: auto;\n    background: @drawer-bg;\n    pointer-events: auto;\n  }\n\n  // ===================== Panel ======================\n  &-wrapper-body {\n    display: flex;\n    flex-direction: column;\n    width: 100%;\n    height: 100%;\n  }\n\n  // Header\n  &-header {\n    display: flex;\n    flex: 0;\n    align-items: center;\n    padding: @drawer-header-padding;\n    font-size: @drawer-title-font-size;\n    line-height: @drawer-title-line-height;\n    border-bottom: @border-width-base @border-style-base @border-color-split;\n\n    &-title {\n      display: flex;\n      flex: 1;\n      align-items: center;\n      min-width: 0;\n      min-height: 0;\n    }\n  }\n\n  &-extra {\n    flex: none;\n  }\n\n  &-close {\n    display: inline-block;\n    margin-right: 12px;\n    color: @modal-close-color;\n    font-weight: 700;\n    font-size: @font-size-lg;\n    font-style: normal;\n    line-height: 1;\n    text-align: center;\n    text-transform: none;\n    text-decoration: none;\n    background: transparent;\n    border: 0;\n    outline: 0;\n    cursor: pointer;\n    transition: color @animation-duration-slow;\n    text-rendering: auto;\n\n    &:focus,\n    &:hover {\n      color: @icon-color-hover;\n      text-decoration: none;\n    }\n  }\n\n  &-title {\n    flex: 1;\n    margin: 0;\n    color: @heading-color;\n    font-weight: 500;\n    font-size: @drawer-title-font-size;\n    line-height: @drawer-title-line-height;\n  }\n\n  // Body\n  &-body {\n    flex: 1;\n    min-width: 0;\n    min-height: 0;\n    padding: @drawer-body-padding;\n    overflow: auto;\n  }\n\n  // Footer\n  &-footer {\n    flex-shrink: 0;\n    padding: @drawer-footer-padding-vertical @drawer-footer-padding-horizontal;\n    border-top: @border-width-base @border-style-base @border-color-split;\n  }\n}\n"
  },
  {
    "path": "components/drawer/style/entry.less",
    "content": "@import './index.less';\n@import './patch.less';\n"
  },
  {
    "path": "components/drawer/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import './drawer';\n@import './motion';\n@import './animation';\n@import './rtl';\n\n.popover-customize-bg(@drawer-prefix-cls, @popover-background);\n"
  },
  {
    "path": "components/drawer/style/motion.less",
    "content": "@import (reference) '../../style/themes/index';\n\n@drawer-prefix-cls: ~'@{ant-prefix}-drawer';\n\n.panel-motion {\n  &-enter,\n  &-appear,\n  &-leave {\n    &-start {\n      transition: none;\n    }\n\n    &-active {\n      transition: all @animation-duration-slow;\n    }\n  }\n}\n\n.@{drawer-prefix-cls} {\n  // ======================== Mask ========================\n  &-mask-motion {\n    &-enter,\n    &-appear,\n    &-leave {\n      &-active {\n        transition: all @animation-duration-slow;\n      }\n    }\n\n    &-enter,\n    &-appear {\n      opacity: 0;\n\n      &-active {\n        opacity: 1;\n      }\n    }\n\n    &-leave {\n      opacity: 1;\n\n      &-active {\n        opacity: 0;\n      }\n    }\n  }\n\n  // ======================= Panel ========================\n  &-panel-motion {\n    // Left\n    &-left {\n      .panel-motion();\n\n      &-enter,\n      &-appear {\n        &-start {\n          transform: translateX(-100%) !important;\n        }\n\n        &-active {\n          transform: translateX(0);\n        }\n      }\n\n      &-leave {\n        transform: translateX(0);\n\n        &-active {\n          transform: translateX(-100%);\n        }\n      }\n    }\n\n    // Right\n    &-right {\n      .panel-motion();\n\n      &-enter,\n      &-appear {\n        &-start {\n          transform: translateX(100%) !important;\n        }\n\n        &-active {\n          transform: translateX(0);\n        }\n      }\n\n      &-leave {\n        transform: translateX(0);\n\n        &-active {\n          transform: translateX(100%);\n        }\n      }\n    }\n\n    // Top\n    &-top {\n      .panel-motion();\n\n      &-enter,\n      &-appear {\n        &-start {\n          transform: translateY(-100%) !important;\n        }\n\n        &-active {\n          transform: translateY(0);\n        }\n      }\n\n      &-leave {\n        transform: translateY(0);\n\n        &-active {\n          transform: translateY(-100%);\n        }\n      }\n    }\n\n    // Bottom\n    &-bottom {\n      .panel-motion();\n\n      &-enter,\n      &-appear {\n        &-start {\n          transform: translateY(100%) !important;\n        }\n\n        &-active {\n          transform: translateY(0);\n        }\n      }\n\n      &-leave {\n        transform: translateY(0);\n\n        &-active {\n          transform: translateY(100%);\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/drawer/style/patch.less",
    "content": ".@{drawer-prefix-cls} {\n  // Fix the issue of the drawer content shadow when the drawer is closed\n  &:not(.@{drawer-prefix-cls}-open) {\n    .@{drawer-prefix-cls}-content-wrapper {\n      box-shadow: none;\n    }\n  }\n}\n"
  },
  {
    "path": "components/drawer/style/rtl.less",
    "content": "@import '../../style/themes/index';\n\n@drawer-prefix-cls: ~'@{ant-prefix}-drawer';\n\n.@{drawer-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &-close {\n    .@{drawer-prefix-cls}-rtl & {\n      margin-right: 0;\n      margin-left: 12px;\n    }\n  }\n}\n"
  },
  {
    "path": "components/dropdown/context-menu.service.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\n@NgModule()\nexport class NzContextMenuServiceModule {}\n"
  },
  {
    "path": "components/dropdown/context-menu.service.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ESCAPE } from '@angular/cdk/keycodes';\nimport { OverlayContainer, ScrollDispatcher } from '@angular/cdk/overlay';\nimport { Component, Provider, Type, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, inject, TestBed, tick } from '@angular/core/testing';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\nimport { Subject } from 'rxjs';\n\nimport { createKeyboardEvent, createMouseEvent, dispatchEvent } from 'ng-zorro-antd/core/testing';\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\n\nimport { NzContextMenuService } from './context-menu.service';\nimport { NzDropdownMenuComponent } from './dropdown-menu.component';\nimport { NzDropdownModule } from './dropdown.module';\n\ndescribe('context-menu', () => {\n  let overlayContainer: OverlayContainer;\n  let overlayContainerElement: HTMLElement;\n\n  function createComponent<T>(component: Type<T>, providers: Provider[] = []): ComponentFixture<T> {\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), ...providers]\n    });\n\n    inject([OverlayContainer], (oc: OverlayContainer) => {\n      overlayContainer = oc;\n      overlayContainerElement = oc.getContainerElement();\n    })();\n\n    return TestBed.createComponent<T>(component);\n  }\n\n  afterEach(inject([OverlayContainer], (currentOverlayContainer: OverlayContainer) => {\n    currentOverlayContainer.ngOnDestroy();\n    overlayContainer.ngOnDestroy();\n  }));\n\n  it('should create dropdown', fakeAsync(() => {\n    const fixture = createComponent(NzTestDropdownContextMenuComponent);\n    fixture.detectChanges();\n    expect(overlayContainerElement.textContent).toBe('');\n    fixture.detectChanges();\n    expect(() => {\n      const fakeEvent = createMouseEvent('contextmenu', 300, 300);\n      const component = fixture.componentInstance;\n      const viewRef = component.nzContextMenuService.create(fakeEvent, component.nzDropdownMenuComponent);\n      expect(viewRef).toBeTruthy();\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent).toContain('1st menu item');\n    }).not.toThrowError();\n  }));\n\n  it('should only one dropdown exist', fakeAsync(() => {\n    const fixture = createComponent(NzTestDropdownContextMenuComponent);\n    fixture.detectChanges();\n    expect(overlayContainerElement.textContent).toBe('');\n    fixture.detectChanges();\n    expect(() => {\n      let fakeEvent = createMouseEvent('contextmenu', 0, 0);\n      const component = fixture.componentInstance;\n      component.nzContextMenuService.create(fakeEvent, component.nzDropdownMenuComponent);\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent).toContain('1st menu item');\n      fakeEvent = createMouseEvent('contextmenu', window.innerWidth, window.innerHeight);\n      component.nzContextMenuService.create(fakeEvent, component.nzDropdownMenuComponent);\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent).toContain('1st menu item');\n    }).not.toThrowError();\n  }));\n\n  it('should dropdown close when scroll', fakeAsync(() => {\n    const scrolledSubject = new Subject<void>();\n    const fixture = createComponent(NzTestDropdownContextMenuComponent, [\n      { provide: ScrollDispatcher, useFactory: () => ({ scrolled: () => scrolledSubject }) }\n    ]);\n    fixture.detectChanges();\n    expect(overlayContainerElement.textContent).toBe('');\n    expect(() => {\n      const fakeEvent = createMouseEvent('contextmenu', 0, 0);\n      const component = fixture.componentInstance;\n      component.nzContextMenuService.create(fakeEvent, component.nzDropdownMenuComponent);\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent).toContain('1st menu item');\n      scrolledSubject.next();\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent).toBe('');\n    }).not.toThrowError();\n  }));\n\n  it('should backdrop work with click', fakeAsync(() => {\n    const fixture = createComponent(NzTestDropdownContextMenuComponent);\n    fixture.detectChanges();\n    expect(overlayContainerElement.textContent).toBe('');\n    fixture.detectChanges();\n    expect(() => {\n      const fakeEvent = createMouseEvent('contextmenu', 300, 300);\n      const component = fixture.componentInstance;\n      component.nzContextMenuService.create(fakeEvent, component.nzDropdownMenuComponent);\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent).toContain('1st menu item');\n      document.body.click();\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent).toBe('');\n    }).not.toThrowError();\n  }));\n\n  it('should backdrop work with keyboard event ESCAPE', fakeAsync(() => {\n    const fixture = createComponent(NzTestDropdownContextMenuComponent);\n    const keyboardEvent = createKeyboardEvent('keydown', ESCAPE, undefined, 'Escape');\n    fixture.detectChanges();\n    expect(overlayContainerElement.textContent).toBe('');\n    fixture.detectChanges();\n    expect(() => {\n      const fakeEvent = createMouseEvent('contextmenu', 300, 300);\n      const component = fixture.componentInstance;\n      component.nzContextMenuService.create(fakeEvent, component.nzDropdownMenuComponent);\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent).toContain('1st menu item');\n      dispatchEvent(document.body, keyboardEvent);\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent).toBe('');\n    }).not.toThrowError();\n  }));\n\n  it('should not call the method close if the overlay is clicked inside', async () => {\n    const fixture = createComponent(NzTestDropdownContextMenuComponent);\n    fixture.detectChanges();\n    const fakeEvent = createMouseEvent('contextmenu', 300, 300);\n    const component = fixture.componentInstance;\n    component.nzContextMenuService.create(fakeEvent, component.nzDropdownMenuComponent);\n    fixture.detectChanges();\n    await fixture.whenStable();\n    fixture.detectChanges();\n    const closeSpy = spyOn(component.nzContextMenuService, 'close');\n    overlayContainerElement.querySelector('ul')!.click();\n    expect(closeSpy).toHaveBeenCalledTimes(0);\n    document.body.click();\n    expect(closeSpy).toHaveBeenCalledTimes(1);\n  });\n});\n\n@Component({\n  imports: [NzDropdownModule, NzMenuModule],\n  template: `\n    <nz-dropdown-menu>\n      <ul nz-menu>\n        <li nz-menu-item>1st menu item</li>\n        <li nz-menu-item>2nd menu item</li>\n        <li nz-menu-item>3rd menu item</li>\n      </ul>\n    </nz-dropdown-menu>\n  `\n})\nexport class NzTestDropdownContextMenuComponent {\n  @ViewChild(NzDropdownMenuComponent, { static: true }) nzDropdownMenuComponent!: NzDropdownMenuComponent;\n\n  constructor(public nzContextMenuService: NzContextMenuService) {}\n}\n"
  },
  {
    "path": "components/dropdown/context-menu.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ConnectionPositionPair,\n  createCloseScrollStrategy,\n  createFlexibleConnectedPositionStrategy,\n  createOverlayRef,\n  OverlayRef\n} from '@angular/cdk/overlay';\nimport { TemplatePortal } from '@angular/cdk/portal';\nimport { EmbeddedViewRef, inject, Injectable, Injector, NgZone } from '@angular/core';\nimport { merge, Subscription } from 'rxjs';\nimport { filter, first } from 'rxjs/operators';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\n\nimport { NzContextMenuServiceModule } from './context-menu.service.module';\nimport { NzDropdownMenuComponent } from './dropdown-menu.component';\n\nconst LIST_OF_POSITIONS = [\n  new ConnectionPositionPair({ originX: 'start', originY: 'top' }, { overlayX: 'start', overlayY: 'top' }),\n  new ConnectionPositionPair({ originX: 'start', originY: 'top' }, { overlayX: 'start', overlayY: 'bottom' }),\n  new ConnectionPositionPair({ originX: 'start', originY: 'top' }, { overlayX: 'end', overlayY: 'bottom' }),\n  new ConnectionPositionPair({ originX: 'start', originY: 'top' }, { overlayX: 'end', overlayY: 'top' })\n];\n\n@Injectable({\n  providedIn: NzContextMenuServiceModule\n})\nexport class NzContextMenuService {\n  private ngZone = inject(NgZone);\n  private injector = inject(Injector);\n  private overlayRef: OverlayRef | null = null;\n  private closeSubscription = Subscription.EMPTY;\n\n  create(\n    $event: MouseEvent | { x: number; y: number },\n    nzDropdownMenuComponent: NzDropdownMenuComponent\n  ): EmbeddedViewRef<NzSafeAny> {\n    this.close(true);\n    const { x, y } = $event;\n    if ($event instanceof MouseEvent) {\n      $event.preventDefault();\n    }\n\n    this.overlayRef = createOverlayRef(this.injector, {\n      positionStrategy: createFlexibleConnectedPositionStrategy(this.injector, { x, y })\n        .withPositions(LIST_OF_POSITIONS)\n        .withTransformOriginOn('.ant-dropdown'),\n      disposeOnNavigation: true,\n      scrollStrategy: createCloseScrollStrategy(this.injector)\n    });\n\n    this.closeSubscription = new Subscription();\n\n    this.closeSubscription.add(nzDropdownMenuComponent.descendantMenuItemClick$.subscribe(() => this.close()));\n\n    this.closeSubscription.add(\n      merge(\n        fromEventOutsideAngular<MouseEvent>(document, 'click').pipe(\n          filter(event => !!this.overlayRef && !this.overlayRef.overlayElement.contains(event.target as HTMLElement)),\n          /** handle firefox contextmenu event **/\n          filter(event => event.button !== 2)\n        ),\n        fromEventOutsideAngular<KeyboardEvent>(document, 'keydown').pipe(filter(event => event.key === 'Escape'))\n      )\n        .pipe(first())\n        .subscribe(() => this.ngZone.run(() => this.close()))\n    );\n\n    return this.overlayRef.attach(\n      new TemplatePortal(nzDropdownMenuComponent.templateRef, nzDropdownMenuComponent.viewContainerRef)\n    );\n  }\n\n  close(clear: boolean = false): void {\n    if (this.overlayRef) {\n      this.overlayRef.detach();\n      if (clear) {\n        this.overlayRef.dispose();\n      }\n      this.overlayRef = null;\n      this.closeSubscription.unsubscribe();\n    }\n  }\n}\n"
  },
  {
    "path": "components/dropdown/demo/arrow.md",
    "content": "---\norder: 9\nversion: 20.2.0\ntitle:\n  zh-CN: 箭头\n  en-US: Arrow\n---\n\n## zh-CN\n\n可以展示一个箭头\n\n## en-US\n\nYou could display an arrow\n"
  },
  {
    "path": "components/dropdown/demo/arrow.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzDropdownModule, NzPlacementType } from 'ng-zorro-antd/dropdown';\nimport { NzFlexModule } from 'ng-zorro-antd/flex';\n\n@Component({\n  selector: 'nz-demo-dropdown-arrow',\n  imports: [NzDropdownModule, NzButtonModule, NzFlexModule],\n  template: `\n    <div nz-flex [nzGap]=\"8\" nzWrap=\"wrap\">\n      @for (position of listOfPosition; track position) {\n        <button nz-button nz-dropdown [nzDropdownMenu]=\"menu\" [nzPlacement]=\"position\" nzArrow>{{ position }}</button>\n        <nz-dropdown-menu #menu=\"nzDropdownMenu\">\n          <ul nz-menu>\n            <li nz-menu-item>1st menu item length</li>\n            <li nz-menu-item>2nd menu item length</li>\n            <li nz-menu-item>3rd menu item length</li>\n          </ul>\n        </nz-dropdown-menu>\n      }\n    </div>\n  `\n})\nexport class NzDemoDropdownArrowComponent {\n  listOfPosition: NzPlacementType[] = ['bottomLeft', 'bottomCenter', 'bottomRight', 'topLeft', 'topCenter', 'topRight'];\n}\n"
  },
  {
    "path": "components/dropdown/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n最简单的下拉菜单。\n\n## en-US\n\nThe most basic dropdown menu.\n"
  },
  {
    "path": "components/dropdown/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDropdownModule } from 'ng-zorro-antd/dropdown';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-demo-dropdown-basic',\n  imports: [NzDropdownModule, NzIconModule],\n  template: `\n    <a nz-dropdown [nzDropdownMenu]=\"menu\">\n      Hover me\n      <nz-icon nzType=\"down\" />\n    </a>\n    <nz-dropdown-menu #menu=\"nzDropdownMenu\">\n      <ul nz-menu nzSelectable>\n        <li nz-menu-item>1st menu item</li>\n        <li nz-menu-item>2nd menu item</li>\n        <li nz-menu-item>3rd menu item</li>\n        <li nz-menu-item nzDanger>4th danger item</li>\n      </ul>\n    </nz-dropdown-menu>\n  `\n})\nexport class NzDemoDropdownBasicComponent {}\n"
  },
  {
    "path": "components/dropdown/demo/context-menu.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 右键菜单\n  en-US: Context Menu\n---\n\n## zh-CN\n\n在区域内任意右击触发。\n\n## en-US\n\nTrigger `dropdown` with contextmenu.\n"
  },
  {
    "path": "components/dropdown/demo/context-menu.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzContextMenuService, NzDropdownMenuComponent, NzDropdownModule } from 'ng-zorro-antd/dropdown';\n\n@Component({\n  selector: 'nz-demo-dropdown-context-menu',\n  imports: [NzDropdownModule],\n  template: `\n    <div class=\"context-area\" (contextmenu)=\"contextMenu($event, menu)\">Right Click on here</div>\n    <nz-dropdown-menu #menu=\"nzDropdownMenu\">\n      <ul nz-menu>\n        <li nz-menu-item>1st menu item</li>\n        <li nz-menu-item>2nd menu item</li>\n        <li nz-menu-item nzDisabled>disabled menu item</li>\n        <li nz-submenu nzTitle=\"sub menu\">\n          <ul>\n            <li nz-menu-item>3rd menu item</li>\n            <li nz-menu-item>4th menu item</li>\n          </ul>\n        </li>\n        <li nz-submenu nzDisabled nzTitle=\"disabled sub menu\">\n          <ul>\n            <li nz-menu-item>3rd menu item</li>\n            <li nz-menu-item>4th menu item</li>\n          </ul>\n        </li>\n      </ul>\n    </nz-dropdown-menu>\n  `,\n  styles: `\n    .context-area {\n      background: #f7f7f7;\n      color: #777;\n      text-align: center;\n      height: 200px;\n      line-height: 200px;\n    }\n  `\n})\nexport class NzDemoDropdownContextMenuComponent {\n  contextMenu($event: MouseEvent, menu: NzDropdownMenuComponent): void {\n    this.nzContextMenuService.create($event, menu);\n  }\n\n  constructor(private nzContextMenuService: NzContextMenuService) {}\n}\n"
  },
  {
    "path": "components/dropdown/demo/dropdown-button.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 带下拉框的按钮\n  en-US: Button with dropdown menu\n---\n\n## zh-CN\n\n左边是按钮，右边是额外的相关功能菜单。\n\n## en-US\n\nA button is on the left, and a related functional menu is on the right.\n"
  },
  {
    "path": "components/dropdown/demo/dropdown-button.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzDropdownModule } from 'ng-zorro-antd/dropdown';\nimport { NzFlexModule } from 'ng-zorro-antd/flex';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\n\n@Component({\n  selector: 'nz-demo-dropdown-dropdown-button',\n  imports: [NzButtonModule, NzDropdownModule, NzFlexModule, NzIconModule, NzSpaceModule],\n  template: `\n    <div nz-flex nzGap=\"small\" nzWrap=\"wrap\">\n      <nz-space-compact>\n        <button nz-button (click)=\"log()\">Dropdown</button>\n        <button nz-button nz-dropdown [nzDropdownMenu]=\"menu\" nzPlacement=\"bottomRight\">\n          <nz-icon nzType=\"ellipsis\" />\n        </button>\n      </nz-space-compact>\n      <nz-space-compact>\n        <button nz-button (click)=\"log()\">Dropdown</button>\n        <button nz-button nz-dropdown [nzDropdownMenu]=\"menu\" nzPlacement=\"bottomRight\">\n          <nz-icon nzType=\"user\" />\n        </button>\n      </nz-space-compact>\n      <nz-space-compact>\n        <button nz-button disabled>Dropdown</button>\n        <button nz-button disabled nz-dropdown [nzDropdownMenu]=\"menu\" nzDisabled nzPlacement=\"bottomRight\">\n          <nz-icon nzType=\"ellipsis\" />\n        </button>\n      </nz-space-compact>\n      <button nz-button nz-dropdown [nzDropdownMenu]=\"menu\">\n        Button\n        <nz-icon nzType=\"down\" />\n      </button>\n    </div>\n    <nz-dropdown-menu #menu=\"nzDropdownMenu\">\n      <ul nz-menu>\n        <li nz-menu-item>menu 1st menu item</li>\n        <li nz-menu-item>menu 2nd menu item</li>\n        <li nz-menu-item>menu 3rd menu item</li>\n      </ul>\n    </nz-dropdown-menu>\n  `\n})\nexport class NzDemoDropdownDropdownButtonComponent {\n  log(): void {\n    console.log('click dropdown button');\n  }\n}\n"
  },
  {
    "path": "components/dropdown/demo/event.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 触发事件\n  en-US: Click event\n---\n\n## zh-CN\n\n点击菜单项后会触发事件，用户可以自由添加各种事件进行不同的操作。\n\n## en-US\n\nAn event will be triggered when you click menu items, in which you can make different operations by adding events to item.\n"
  },
  {
    "path": "components/dropdown/demo/event.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDropdownModule } from 'ng-zorro-antd/dropdown';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-demo-dropdown-event',\n  imports: [NzDropdownModule, NzIconModule],\n  template: `\n    <a nz-dropdown [nzDropdownMenu]=\"menu\">\n      Hover me, Click menu item\n      <nz-icon nzType=\"down\" />\n    </a>\n    <nz-dropdown-menu #menu=\"nzDropdownMenu\">\n      <ul nz-menu>\n        <li nz-menu-item (click)=\"log('1st menu item')\">1st menu item</li>\n        <li nz-menu-item (click)=\"log('2nd menu item')\">2nd menu item</li>\n        <li nz-menu-item (click)=\"log('3rd menu item')\">3rd menu item</li>\n      </ul>\n    </nz-dropdown-menu>\n  `\n})\nexport class NzDemoDropdownEventComponent {\n  log(data: string): void {\n    console.log(data);\n  }\n}\n"
  },
  {
    "path": "components/dropdown/demo/item.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 其他元素\n  en-US: Other elements\n---\n\n## zh-CN\n\n分割线和不可用菜单项。\n\n## en-US\n\nDivider and disabled menu item.\n"
  },
  {
    "path": "components/dropdown/demo/item.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDropdownModule } from 'ng-zorro-antd/dropdown';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-demo-dropdown-item',\n  imports: [NzDropdownModule, NzIconModule],\n  template: `\n    <a nz-dropdown [nzDropdownMenu]=\"menu\">\n      Hover me\n      <nz-icon nzType=\"down\" />\n    </a>\n    <nz-dropdown-menu #menu=\"nzDropdownMenu\">\n      <ul nz-menu>\n        <li nz-menu-item>1st menu item</li>\n        <li nz-menu-item>2nd menu item</li>\n        <li nz-menu-divider></li>\n        <li nz-menu-item nzDisabled>3rd menu item（disabled）</li>\n      </ul>\n    </nz-dropdown-menu>\n  `\n})\nexport class NzDemoDropdownItemComponent {}\n"
  },
  {
    "path": "components/dropdown/demo/overlay-visible.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 菜单隐藏方式\n  en-US: The way of hiding menu.\n---\n\n## zh-CN\n\n默认是点击关闭菜单，可以关闭此功能。\n\n## en-US\n\nThe default is to close the menu when you click on menu items, this feature can be turned off.\n"
  },
  {
    "path": "components/dropdown/demo/overlay-visible.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDropdownModule } from 'ng-zorro-antd/dropdown';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-demo-dropdown-overlay-visible',\n  imports: [NzDropdownModule, NzIconModule],\n  template: `\n    <a nz-dropdown [nzDropdownMenu]=\"menu\" [nzClickHide]=\"false\" [(nzVisible)]=\"visible\">\n      Hover me\n      <nz-icon nzType=\"down\" />\n    </a>\n    <nz-dropdown-menu #menu=\"nzDropdownMenu\">\n      <ul nz-menu>\n        <li nz-menu-item>Clicking me will not close the menu.</li>\n        <li nz-menu-item>Clicking me will not close the menu also.</li>\n        <li nz-menu-item (click)=\"visible = false\">Clicking me will close the menu</li>\n      </ul>\n    </nz-dropdown-menu>\n  `\n})\nexport class NzDemoDropdownOverlayVisibleComponent {\n  visible = false;\n}\n"
  },
  {
    "path": "components/dropdown/demo/placement.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 弹出位置\n  en-US: Placement\n---\n\n## zh-CN\n\n支持 6 个弹出位置。\n\n## en-US\n\nSupport 6 placements.\n"
  },
  {
    "path": "components/dropdown/demo/placement.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzDropdownModule, NzPlacementType } from 'ng-zorro-antd/dropdown';\n\n@Component({\n  selector: 'nz-demo-dropdown-placement',\n  imports: [NzDropdownModule, NzButtonModule],\n  template: `\n    <div>\n      @for (position of listOfPosition; track position) {\n        <button nz-button nz-dropdown [nzDropdownMenu]=\"menu\" [nzPlacement]=\"position\">{{ position }}</button>\n        <nz-dropdown-menu #menu=\"nzDropdownMenu\">\n          <ul nz-menu>\n            <li nz-menu-item>1st menu item length</li>\n            <li nz-menu-item>2nd menu item length</li>\n            <li nz-menu-item>3rd menu item length</li>\n          </ul>\n        </nz-dropdown-menu>\n      }\n    </div>\n  `,\n  styles: `\n    [nz-button] {\n      margin-right: 8px;\n      margin-bottom: 8px;\n    }\n  `\n})\nexport class NzDemoDropdownPlacementComponent {\n  listOfPosition: NzPlacementType[] = ['bottomLeft', 'bottomCenter', 'bottomRight', 'topLeft', 'topCenter', 'topRight'];\n}\n"
  },
  {
    "path": "components/dropdown/demo/sub-menu.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 多级菜单\n  en-US: Cascading menu\n---\n\n## zh-CN\n\n传入的菜单里有多个层级。\n\n## en-US\n\nThe menu has multiple levels.\n"
  },
  {
    "path": "components/dropdown/demo/sub-menu.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDropdownModule } from 'ng-zorro-antd/dropdown';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-demo-dropdown-sub-menu',\n  imports: [NzDropdownModule, NzIconModule],\n  template: `\n    <a nz-dropdown [nzDropdownMenu]=\"menu\" (nzVisibleChange)=\"change($event)\">\n      Cascading menu\n      <nz-icon nzType=\"down\" />\n    </a>\n    <nz-dropdown-menu #menu=\"nzDropdownMenu\">\n      <ul nz-menu>\n        <li nz-menu-item>1st menu item</li>\n        <li nz-menu-item>2nd menu item</li>\n        <li nz-submenu nzTitle=\"sub menu\">\n          <ul>\n            <li nz-menu-item>3rd menu item</li>\n            <li nz-menu-item>4th menu item</li>\n          </ul>\n        </li>\n        <li nz-submenu nzDisabled nzTitle=\"disabled sub menu\">\n          <ul>\n            <li nz-menu-item>3rd menu item</li>\n            <li nz-menu-item>4th menu item</li>\n          </ul>\n        </li>\n      </ul>\n    </nz-dropdown-menu>\n  `\n})\nexport class NzDemoDropdownSubMenuComponent {\n  change(value: boolean): void {\n    console.log(value);\n  }\n}\n"
  },
  {
    "path": "components/dropdown/demo/trigger.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 触发方式\n  en-US: Trigger mode\n---\n\n## zh-CN\n\n默认是移入触发菜单，可以点击触发。\n\n## en-US\n\nThe default trigger mode is `hover`, you can change it to `click`.\n"
  },
  {
    "path": "components/dropdown/demo/trigger.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDropdownModule } from 'ng-zorro-antd/dropdown';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-demo-dropdown-trigger',\n  imports: [NzDropdownModule, NzIconModule],\n  template: `\n    <a nz-dropdown nzTrigger=\"click\" [nzDropdownMenu]=\"menu\">\n      Click me\n      <nz-icon nzType=\"down\" />\n    </a>\n    <nz-dropdown-menu #menu=\"nzDropdownMenu\">\n      <ul nz-menu>\n        <li nz-menu-item>1st menu item</li>\n        <li nz-menu-item>2nd menu item</li>\n        <li nz-menu-divider></li>\n        <li nz-menu-item nzDisabled>disabled menu item</li>\n        <li nz-submenu nzTitle=\"sub menu\">\n          <ul>\n            <li nz-menu-item>3rd menu item</li>\n            <li nz-menu-item>4th menu item</li>\n          </ul>\n        </li>\n        <li nz-submenu nzDisabled nzTitle=\"disabled sub menu\">\n          <ul>\n            <li nz-menu-item>3rd menu item</li>\n            <li nz-menu-item>4th menu item</li>\n          </ul>\n        </li>\n      </ul>\n    </nz-dropdown-menu>\n  `\n})\nexport class NzDemoDropdownTriggerComponent {}\n"
  },
  {
    "path": "components/dropdown/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Navigation\ntitle: Dropdown\ncover: 'https://gw.alipayobjects.com/zos/alicdn/eedWN59yJ/Dropdown.svg'\ndescription: A dropdown list.\n---\n\n## When To Use\n\nIf there are too many operations to display, you can wrap them in a `Dropdown`. By clicking/hovering on the trigger, a dropdown menu should appear, which allows you to choose one option and execute relevant actions.\n\n## API\n\n### [nz-dropdown]\n\n| Property               | Description                                                                                       | Type                                                                                        | Default        | Version |\n| ---------------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | -------------- | ------- |\n| `[nzDropdownMenu]`     | Dropdown menu                                                                                     | `NzDropdownMenuComponent`                                                                   | -              |\n| `[nzDisabled]`         | whether the dropdown menu is disabled                                                             | `boolean`                                                                                   | -              |\n| `[nzPlacement]`        | placement of pop menu                                                                             | `'bottomLeft' \\| 'bottomCenter' \\| 'bottomRight' \\| 'topLeft' \\| 'topCenter' \\| 'topRight'` | `'bottomLeft'` |\n| `[nzTrigger]`          | the trigger mode which executes the drop-down action                                              | `'click' \\| 'hover'`                                                                        | `'hover'`      |\n| `[nzClickHide]`        | whether hide menu when click                                                                      | `boolean`                                                                                   | `true`         |\n| `[nzVisible]`          | whether the dropdown menu is visible, double binding                                              | `boolean`                                                                                   | -              |\n| `[nzOverlayClassName]` | Class name of the dropdown root element                                                           | `string`                                                                                    | -              |\n| `[nzOverlayStyle]`     | Style of the dropdown root element                                                                | `object`                                                                                    | -              |\n| `(nzVisibleChange)`    | a callback function takes an argument: `nzVisible`, is executed when the visible state is changed | `EventEmitter<boolean>`                                                                     | -              |\n| `[nzArrow]`            | Whether the dropdown arrow should be visible                                                      | `boolean`                                                                                   | `false`        | 20.2.0  |\n\nYou should use [nz-menu](/components/menu/en) in `nz-dropdown`. The menu items and dividers are also available by using `nz-menu-item` and `nz-menu-divider`.\n\n> Note: `[nz-menu]` of `nz-dropdown` is unselectable by default, you can make it selectable via `<ul nz-menu nzSelectable>`.\n>\n> The `nzMode` of `[nz-menu]` inside `nz-dropdown-menu` can only be the default value `vertical`.\n\n### nz-dropdown-menu\n\nWrap Dropdown Menu and pass to `[nz-dropdown]` and `NzContextMenuService`, you can export it via Template Syntax `nzDropdownMenu`\n\n> Note：Every `[nz-dropdown]` should pass independent `nz-dropdown-menu`.\n\n```html\n<a nz-dropdown [nzDropdownMenu]=\"menu\">Hover me</a>\n<nz-dropdown-menu #menu=\"nzDropdownMenu\">\n  <ul nz-menu>\n    <li nz-menu-item>1st menu item</li>\n    <li nz-menu-item>2nd menu item</li>\n    <li nz-menu-item>3rd menu item</li>\n  </ul>\n</nz-dropdown-menu>\n```\n\n### NzContextMenuService\n\nCreate dropdown with contextmenu, the detail can be found in the example above\n\n| Property | Description     | Arguments                                                                   | Return Value           |\n| -------- | --------------- | --------------------------------------------------------------------------- | ---------------------- |\n| create   | create dropdown | `($event:MouseEvent \\| {x:number, y:number}, menu:NzDropdownMenuComponent)` | `EmbeddedViewRef<any>` |\n| close    | close dropdown  | -                                                                           | -                      |\n\n## FAQ\n\n### Q: The overlay layer element does not follow the scroll position when scrolling\n\nBy default, the overlay layer element uses body as the scroll container. If using another scroll container, add the [CdkScrollable](https://material.angular.dev/cdk/scrolling/api#CdkScrollable) directive to the custom scroll container element.\nNote: You need to import the `CdkScrollable` directive or `ScrollingModule` module from `@angular/cdk/scrolling`.\n"
  },
  {
    "path": "components/dropdown/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 下拉菜单\ntype: 导航\ntitle: Dropdown\ncover: 'https://gw.alipayobjects.com/zos/alicdn/eedWN59yJ/Dropdown.svg'\ndescription: 向下弹出的列表。\n---\n\n## 何时使用\n\n当页面上的操作命令过多时，用此组件可以收纳操作元素。点击或移入触点，会出现一个下拉菜单。可在列表中进行选择，并执行相应的命令。\n\n## API\n\n### [nz-dropdown]\n\n| 参数                   | 说明                                     | 类型                                                                                        | 默认值         | 版本   |\n| ---------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------- | -------------- | ------ |\n| `[nzDropdownMenu]`     | Dropdown 下拉菜单组件                    | `NzDropdownMenuComponent`                                                                   | -              |\n| `[nzDisabled]`         | 菜单是否禁用                             | `boolean`                                                                                   | -              |\n| `[nzPlacement]`        | 菜单弹出位置                             | `'bottomLeft' \\| 'bottomCenter' \\| 'bottomRight' \\| 'topLeft' \\| 'topCenter' \\| 'topRight'` | `'bottomLeft'` |\n| `[nzTrigger]`          | 触发下拉的行为                           | `'click' \\| 'hover'`                                                                        | `'hover'`      |\n| `[nzClickHide]`        | 点击后是否隐藏菜单                       | `boolean`                                                                                   | `true`         |\n| `[nzVisible]`          | 菜单是否显示，可双向绑定                 | `boolean`                                                                                   | -              |\n| `[nzOverlayClassName]` | 下拉根元素的类名称                       | `string`                                                                                    | -              |\n| `[nzOverlayStyle]`     | 下拉根元素的样式                         | `object`                                                                                    | -              |\n| `(nzVisibleChange)`    | 菜单显示状态改变时调用，参数为 nzVisible | `EventEmitter<boolean>`                                                                     | -              |\n| `[nzArrow]`            | 下拉框箭头是否显示                       | `boolean`                                                                                   | `false`        | 20.2.0 |\n\n菜单使用 [nz-menu](/components/menu/zh)，还包括菜单项 `[nz-menu-item]`，分割线 `[nz-menu-divider]`。\n\n> 注意：`nz-dropdown` 下的 `[nz-menu]` 默认不可选中。如果需要菜单可选中，可以指定 `<ul nz-menu nzSelectable>`.\n>\n> `nz-dropdown-menu` 内 `[nz-menu]` 的 `nzMode` 只可以是默认值 `vertical`。\n\n### nz-dropdown-menu\n\n用于包裹菜单项，可以通过 `nzDropdownMenu` 模板变量导出后传入 `[nz-dropdown]` 和 `NzContextMenuService`。\n\n> 注意：每个 `nz-dropdown-menu` 只能作为一个 `[nz-dropdown]` 的输入项\n\n```html\n<a nz-dropdown [nzDropdownMenu]=\"menu\">Hover me</a>\n<nz-dropdown-menu #menu=\"nzDropdownMenu\">\n  <ul nz-menu>\n    <li nz-menu-item>1st menu item</li>\n    <li nz-menu-item>2nd menu item</li>\n    <li nz-menu-item>3rd menu item</li>\n  </ul>\n</nz-dropdown-menu>\n```\n\n### NzContextMenuService\n\n用于右键弹出下拉菜单，具体参见示例\n\n| 方法/属性 | 说明         | 参数                                                                        | 返回                   |\n| --------- | ------------ | --------------------------------------------------------------------------- | ---------------------- |\n| create    | 创建右键菜单 | `($event:MouseEvent \\| {x:number, y:number}, menu:NzDropdownMenuComponent)` | `EmbeddedViewRef<any>` |\n| close     | 关闭右键菜单 | -                                                                           | -                      |\n\n## FAQ\n\n### Q：滚动时浮层元素没有跟随滚动位置\n\n默认情况下，浮层元素使用 `body` 作为滚动容器，如果使用了其他滚动容器，在自定义滚动容器元素上添加 [CdkScrollable](https://material.angular.dev/cdk/scrolling/api#CdkScrollable) 指令。\n注意：您需要从 `@angular/cdk/scrolling` 导入 `CdkScrollable` 指令或 `ScrollingModule` 模块。\n"
  },
  {
    "path": "components/dropdown/dropdown-a.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive } from '@angular/core';\n\n@Directive({\n  selector: 'a[nz-dropdown]',\n  host: {\n    class: 'ant-dropdown-link'\n  }\n})\nexport class NzDropdownADirective {}\n"
  },
  {
    "path": "components/dropdown/dropdown-menu.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport {\n  AfterContentInit,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DestroyRef,\n  ElementRef,\n  EventEmitter,\n  OnInit,\n  Renderer2,\n  TemplateRef,\n  ViewChild,\n  ViewContainerRef,\n  ViewEncapsulation,\n  inject,\n  type AnimationCallbackEvent\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { BehaviorSubject } from 'rxjs';\n\nimport { NzNoAnimationDirective, slideAnimationEnter, slideAnimationLeave } from 'ng-zorro-antd/core/animation';\nimport { IndexableObject, NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { MenuService, NzIsMenuInsideDropdownToken } from 'ng-zorro-antd/menu';\n\nexport type NzPlacementType = 'bottomLeft' | 'bottomCenter' | 'bottomRight' | 'topLeft' | 'topCenter' | 'topRight';\n\n@Component({\n  selector: `nz-dropdown-menu`,\n  exportAs: `nzDropdownMenu`,\n  providers: [\n    MenuService,\n    /** menu is inside dropdown-menu component **/\n    {\n      provide: NzIsMenuInsideDropdownToken,\n      useValue: true\n    }\n  ],\n  template: `\n    <ng-template>\n      <div\n        class=\"ant-dropdown\"\n        [class.ant-dropdown-rtl]=\"dir === 'rtl'\"\n        [class.ant-dropdown-show-arrow]=\"nzArrow\"\n        [class.ant-dropdown-placement-bottomLeft]=\"placement === 'bottomLeft'\"\n        [class.ant-dropdown-placement-bottomRight]=\"placement === 'bottomRight'\"\n        [class.ant-dropdown-placement-bottom]=\"placement === 'bottom'\"\n        [class.ant-dropdown-placement-topLeft]=\"placement === 'topLeft'\"\n        [class.ant-dropdown-placement-topRight]=\"placement === 'topRight'\"\n        [class.ant-dropdown-placement-top]=\"placement === 'top'\"\n        [class]=\"nzOverlayClassName\"\n        [style]=\"nzOverlayStyle\"\n        [animate.enter]=\"dropdownAnimationEnter()\"\n        [animate.leave]=\"dropdownAnimationLeave()\"\n        (animate.leave)=\"onAnimationEvent($event)\"\n        [nzNoAnimation]=\"!!noAnimation?.nzNoAnimation?.()\"\n        (mouseenter)=\"setMouseState(true)\"\n        (mouseleave)=\"setMouseState(false)\"\n      >\n        @if (nzArrow) {\n          <div class=\"ant-dropdown-arrow\"></div>\n        }\n        <ng-content />\n      </div>\n    </ng-template>\n  `,\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  imports: [NzNoAnimationDirective]\n})\nexport class NzDropdownMenuComponent implements AfterContentInit, OnInit {\n  private cdr = inject(ChangeDetectorRef);\n  private elementRef = inject(ElementRef);\n  private renderer = inject(Renderer2);\n  public viewContainerRef = inject(ViewContainerRef);\n  private directionality = inject(Directionality);\n  private destroyRef = inject(DestroyRef);\n  noAnimation = inject(NzNoAnimationDirective, { host: true, optional: true });\n  public nzMenuService = inject(MenuService);\n\n  isChildSubMenuOpen$ = this.nzMenuService.isChildSubMenuOpen$;\n  descendantMenuItemClick$ = this.nzMenuService.descendantMenuItemClick$;\n  mouseState$ = new BehaviorSubject<boolean>(false);\n  animationStateChange$ = new EventEmitter<AnimationCallbackEvent>();\n  @ViewChild(TemplateRef, { static: true }) templateRef!: TemplateRef<NzSafeAny>;\n\n  nzOverlayClassName: string = '';\n  nzOverlayStyle: IndexableObject = {};\n  nzArrow: boolean = false;\n  placement: NzPlacementType | 'bottom' | 'top' = 'bottomLeft';\n  dir: Direction = 'ltr';\n\n  protected readonly dropdownAnimationEnter = slideAnimationEnter();\n  protected readonly dropdownAnimationLeave = slideAnimationLeave();\n\n  onAnimationEvent(event: AnimationCallbackEvent): void {\n    const element = event.target as HTMLElement;\n    const onAnimationEnd = (): void => {\n      element.removeEventListener('animationend', onAnimationEnd);\n      this.animationStateChange$.emit(event);\n    };\n    element.addEventListener('animationend', onAnimationEnd);\n  }\n\n  setMouseState(visible: boolean): void {\n    this.mouseState$.next(visible);\n  }\n\n  setValue<T extends keyof NzDropdownMenuComponent>(key: T, value: this[T]): void {\n    this[key] = value;\n    this.cdr.markForCheck();\n  }\n\n  ngOnInit(): void {\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n      this.dir = direction;\n      this.cdr.detectChanges();\n    });\n\n    this.dir = this.directionality.value;\n  }\n\n  ngAfterContentInit(): void {\n    this.renderer.removeChild(this.renderer.parentNode(this.elementRef.nativeElement), this.elementRef.nativeElement);\n  }\n}\n"
  },
  {
    "path": "components/dropdown/dropdown.directive.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ESCAPE } from '@angular/cdk/keycodes';\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport { Component } from '@angular/core';\nimport { ComponentFixture, fakeAsync, inject, TestBed, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { dispatchFakeEvent, dispatchKeyboardEvent } from 'ng-zorro-antd/core/testing';\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\n\nimport { NzPlacementType } from './dropdown-menu.component';\nimport { NzDropdownDirective } from './dropdown.directive';\nimport { NzDropdownModule } from './dropdown.module';\n\ndescribe('dropdown', () => {\n  let overlayContainer: OverlayContainer;\n  let overlayContainerElement: HTMLElement;\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations()]\n    });\n  });\n\n  beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n    overlayContainer = oc;\n    overlayContainerElement = oc.getContainerElement();\n  }));\n\n  afterEach(inject([OverlayContainer], (currentOverlayContainer: OverlayContainer) => {\n    currentOverlayContainer.ngOnDestroy();\n    overlayContainer.ngOnDestroy();\n  }));\n\n  // TODO: why this works well with ChromeHeadless but fails with ChromeHeadlessCI?\n  xdescribe('placement and arrow', () => {\n    let fixture: ComponentFixture<NzTestDropdownArrowComponent>;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestDropdownArrowComponent);\n      fixture.componentInstance.arrow = true;\n    });\n\n    it('should render arrow when nzArrow is true and apply placement classes', fakeAsync(() => {\n      fixture.componentInstance.placement = 'bottomLeft';\n      fixture.detectChanges();\n      const dropdownElement = fixture.debugElement.query(By.directive(NzDropdownDirective)).nativeElement;\n      dispatchFakeEvent(dropdownElement, 'mouseenter');\n      tick(1000);\n      fixture.detectChanges();\n      const dropdown = overlayContainerElement.querySelector('.ant-dropdown') as HTMLElement;\n      expect(dropdown).not.toBeNull();\n      expect(dropdown.classList).toContain('ant-dropdown-show-arrow');\n      expect(dropdown.classList).toContain('ant-dropdown-placement-bottomLeft');\n      expect(dropdown.querySelector('.ant-dropdown-arrow')).not.toBeNull();\n\n      // Change placement while open should update placement class\n      fixture.componentInstance.placement = 'topRight';\n      fixture.detectChanges();\n      tick(0);\n      fixture.detectChanges();\n      expect(dropdown.classList.contains('ant-dropdown-placement-topRight')).toBeTrue();\n    }));\n\n    it('should map center placements to top/bottom classes', fakeAsync(() => {\n      fixture.componentInstance.placement = 'bottomCenter';\n      fixture.detectChanges();\n      const dropdownElement = fixture.debugElement.query(By.directive(NzDropdownDirective)).nativeElement;\n      dispatchFakeEvent(dropdownElement, 'mouseenter');\n      tick(1000);\n      fixture.detectChanges();\n      const dropdown = overlayContainerElement.querySelector('.ant-dropdown') as HTMLElement;\n      expect(dropdown).not.toBeNull();\n      expect(dropdown.classList.contains('ant-dropdown-show-arrow')).toBeTrue();\n      const isBottomFamily =\n        dropdown.classList.contains('ant-dropdown-placement-bottom') ||\n        dropdown.classList.contains('ant-dropdown-placement-bottomLeft') ||\n        dropdown.classList.contains('ant-dropdown-placement-bottomRight');\n      expect(isBottomFamily).toBeTrue();\n\n      // Switch to topCenter\n      fixture.componentInstance.placement = 'topCenter';\n      fixture.detectChanges();\n      tick(0);\n      fixture.detectChanges();\n      const isTopFamily =\n        dropdown.classList.contains('ant-dropdown-placement-top') ||\n        dropdown.classList.contains('ant-dropdown-placement-topLeft') ||\n        dropdown.classList.contains('ant-dropdown-placement-topRight');\n      expect(isTopFamily).toBeTrue();\n    }));\n  });\n\n  it('should hover correct', fakeAsync(() => {\n    const fixture = TestBed.createComponent(NzTestDropdownComponent);\n    fixture.componentInstance.trigger = 'hover';\n    fixture.detectChanges();\n    expect(overlayContainerElement.textContent).toBe('');\n    expect(() => {\n      const dropdownElement = fixture.debugElement.query(By.directive(NzDropdownDirective)).nativeElement;\n      dispatchFakeEvent(dropdownElement, 'mouseenter');\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent).toContain('1st menu item');\n    }).not.toThrowError();\n  }));\n\n  it('should click correct', fakeAsync(() => {\n    const fixture = TestBed.createComponent(NzTestDropdownComponent);\n    fixture.componentInstance.trigger = 'click';\n    fixture.detectChanges();\n    expect(overlayContainerElement.textContent).toBe('');\n    expect(() => {\n      const dropdownElement = fixture.debugElement.query(By.directive(NzDropdownDirective)).nativeElement;\n      dispatchFakeEvent(dropdownElement, 'click');\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent).toContain('1st menu item');\n    }).not.toThrowError();\n  }));\n\n  it('should disabled work', fakeAsync(() => {\n    const fixture = TestBed.createComponent(NzTestDropdownComponent);\n    fixture.componentInstance.disabled = true;\n    fixture.detectChanges();\n    expect(overlayContainerElement.textContent).toBe('');\n    expect(() => {\n      const dropdownElement = fixture.debugElement.query(By.directive(NzDropdownDirective)).nativeElement;\n      dispatchFakeEvent(dropdownElement, 'mouseenter');\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent).toBe('');\n    }).not.toThrowError();\n  }));\n\n  describe('when nzBackdrop=true', () => {\n    let fixture: ComponentFixture<NzTestDropdownComponent>;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestDropdownComponent);\n      fixture.componentInstance.backdrop = true;\n    });\n\n    it('should disappear if invisible backdrop clicked if nzTrigger=click', fakeAsync(() => {\n      fixture.componentInstance.trigger = 'click';\n      fixture.detectChanges();\n\n      expect(() => {\n        const dropdownElement = fixture.debugElement.query(By.directive(NzDropdownDirective)).nativeElement;\n        dispatchFakeEvent(dropdownElement, 'click');\n\n        tick(1000);\n        fixture.detectChanges();\n\n        const backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop');\n        expect(backdrop).not.toBeNull();\n\n        dispatchFakeEvent(backdrop as Element, 'click');\n        tick(1000);\n        fixture.detectChanges();\n\n        expect(overlayContainerElement.querySelector('.cdk-overlay-backdrop')).toBeNull();\n      }).not.toThrowError();\n    }));\n  });\n\n  it('should disappear if Escape pressed', fakeAsync(() => {\n    const fixture = TestBed.createComponent(NzTestDropdownComponent);\n    fixture.componentInstance.trigger = 'click';\n    fixture.componentInstance.backdrop = true;\n    fixture.detectChanges();\n\n    expect(() => {\n      const dropdownElement = fixture.debugElement.query(By.directive(NzDropdownDirective)).nativeElement;\n\n      dispatchFakeEvent(dropdownElement, 'click');\n      tick(1000);\n      fixture.detectChanges();\n\n      const backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop');\n      expect(backdrop).not.toBeNull();\n\n      dispatchKeyboardEvent(document.body, 'keydown', ESCAPE);\n      tick(1000);\n      fixture.detectChanges();\n\n      const nullBackdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop');\n      expect(nullBackdrop).toBeNull();\n    }).not.toThrowError();\n  }));\n\n  it('should nzOverlayClassName and nzOverlayStyle work', fakeAsync(() => {\n    const fixture = TestBed.createComponent(NzTestDropdownComponent);\n    fixture.detectChanges();\n    expect(() => {\n      const dropdownElement = fixture.debugElement.query(By.directive(NzDropdownDirective)).nativeElement;\n      dispatchFakeEvent(dropdownElement, 'mouseenter');\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-dropdown')!.classList).toContain('custom-class');\n      expect(overlayContainerElement.querySelector<HTMLElement>('.ant-dropdown')!.style.color).toBe('rgb(0, 0, 0)');\n    }).not.toThrowError();\n  }));\n\n  it('should nzVisible & nzClickHide work', fakeAsync(() => {\n    const fixture = TestBed.createComponent(NzTestDropdownVisibleComponent);\n    fixture.detectChanges();\n    expect(fixture.componentInstance.triggerVisible).toHaveBeenCalledTimes(0);\n    const dropdownElement = fixture.debugElement.query(By.directive(NzDropdownDirective)).nativeElement;\n    dispatchFakeEvent(dropdownElement, 'mouseenter');\n    fixture.detectChanges();\n    tick(1000);\n    fixture.detectChanges();\n    expect(fixture.componentInstance.triggerVisible).toHaveBeenCalledTimes(1);\n    expect(fixture.componentInstance.triggerVisible).toHaveBeenCalledWith(true);\n    expect(overlayContainerElement.textContent).toContain('Clicking me will not close the menu.');\n    dispatchFakeEvent(overlayContainerElement.querySelector('.first-menu')!, 'click');\n    fixture.detectChanges();\n    tick(1000);\n    fixture.detectChanges();\n    expect(fixture.componentInstance.triggerVisible).toHaveBeenCalledTimes(1);\n    expect(fixture.componentInstance.triggerVisible).toHaveBeenCalledWith(true);\n    expect(overlayContainerElement.textContent).toContain('Clicking me will not close the menu.');\n    dispatchFakeEvent(overlayContainerElement.querySelector('.second-menu')!, 'click');\n    fixture.detectChanges();\n    tick(1000);\n    fixture.detectChanges();\n    expect(fixture.componentInstance.triggerVisible).toHaveBeenCalledTimes(1);\n    expect(overlayContainerElement.textContent).toContain('Clicking me will not close the menu.');\n    dispatchFakeEvent(overlayContainerElement.querySelector('.close-menu')!, 'click');\n    fixture.detectChanges();\n    tick(2000);\n    fixture.detectChanges();\n    expect(fixture.componentInstance.triggerVisible).toHaveBeenCalledTimes(1);\n  }));\n});\n\n@Component({\n  imports: [NzDropdownModule, NzMenuModule],\n  template: `\n    <a\n      nz-dropdown\n      [nzDropdownMenu]=\"menu\"\n      [nzTrigger]=\"trigger\"\n      [nzDisabled]=\"disabled\"\n      [nzPlacement]=\"placement\"\n      [nzBackdrop]=\"backdrop\"\n      [nzOverlayClassName]=\"className\"\n      [nzOverlayStyle]=\"overlayStyle\"\n    >\n      Trigger\n    </a>\n    <nz-dropdown-menu #menu=\"nzDropdownMenu\">\n      <ul nz-menu>\n        <li nz-menu-item>1st menu item</li>\n        <li nz-menu-item>2nd menu item</li>\n        <li nz-menu-item>3rd menu item</li>\n      </ul>\n    </nz-dropdown-menu>\n  `\n})\nexport class NzTestDropdownComponent {\n  backdrop = false;\n  trigger: 'click' | 'hover' = 'hover';\n  placement: NzPlacementType = 'bottomLeft';\n  disabled = false;\n  className = 'custom-class';\n  overlayStyle = { color: '#000' };\n}\n\n@Component({\n  imports: [NzDropdownModule, NzMenuModule],\n  template: `\n    <a\n      nz-dropdown\n      [nzDropdownMenu]=\"menu\"\n      [nzClickHide]=\"false\"\n      [(nzVisible)]=\"visible\"\n      (nzVisibleChange)=\"triggerVisible($event)\"\n    >\n      Hover me\n    </a>\n    <nz-dropdown-menu #menu=\"nzDropdownMenu\">\n      <ul nz-menu>\n        <li nz-menu-item class=\"first-menu\">Clicking me will not close the menu.</li>\n        <li nz-menu-item class=\"second-menu\">Clicking me will not close the menu also.</li>\n        <li nz-menu-item (click)=\"visible = false\" class=\"close-menu\">Clicking me will close the menu</li>\n      </ul>\n    </nz-dropdown-menu>\n  `\n})\nexport class NzTestDropdownVisibleComponent {\n  visible = false;\n  triggerVisible = jasmine.createSpy('visibleChange');\n}\n\n@Component({\n  imports: [NzDropdownModule, NzMenuModule],\n  template: `\n    <a nz-dropdown [nzDropdownMenu]=\"menu\" [nzArrow]=\"arrow\" [nzPlacement]=\"placement\" nzTrigger=\"hover\"> Trigger </a>\n    <nz-dropdown-menu #menu=\"nzDropdownMenu\">\n      <ul nz-menu>\n        <li nz-menu-item>1st menu item</li>\n      </ul>\n    </nz-dropdown-menu>\n  `\n})\nexport class NzTestDropdownArrowComponent {\n  arrow = false;\n  placement: NzPlacementType = 'bottomLeft';\n}\n"
  },
  {
    "path": "components/dropdown/dropdown.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ESCAPE, hasModifierKey } from '@angular/cdk/keycodes';\nimport {\n  createFlexibleConnectedPositionStrategy,\n  createOverlayRef,\n  createRepositionScrollStrategy,\n  OverlayRef\n} from '@angular/cdk/overlay';\nimport { Platform } from '@angular/cdk/platform';\nimport { TemplatePortal } from '@angular/cdk/portal';\nimport {\n  AfterViewInit,\n  booleanAttribute,\n  DestroyRef,\n  Directive,\n  ElementRef,\n  EventEmitter,\n  inject,\n  Injector,\n  Input,\n  OnChanges,\n  Output,\n  Renderer2,\n  SimpleChanges,\n  ViewContainerRef,\n  type AnimationCallbackEvent\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { BehaviorSubject, combineLatest, EMPTY, fromEvent, merge, Subject } from 'rxjs';\nimport { auditTime, distinctUntilChanged, filter, map, switchMap } from 'rxjs/operators';\n\nimport { NzConfigKey, NzConfigService, WithConfig } from 'ng-zorro-antd/core/config';\nimport {\n  getPlacementName,\n  POSITION_MAP,\n  POSITION_TYPE,\n  setConnectedPositionOffset,\n  TOOLTIP_OFFSET_MAP\n} from 'ng-zorro-antd/core/overlay';\nimport { IndexableObject } from 'ng-zorro-antd/core/types';\n\nimport { NzDropdownMenuComponent, NzPlacementType } from './dropdown-menu.component';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'dropdown';\n\nconst listOfPositions: POSITION_TYPE[] = ['bottomLeft', 'bottomRight', 'topRight', 'topLeft'];\n\nconst normalizePlacementForClass = (p: NzPlacementType): NzDropdownMenuComponent['placement'] => {\n  // Map center placements to generic top/bottom classes for styling\n  if (p === 'topCenter') {\n    return 'top';\n  }\n  if (p === 'bottomCenter') {\n    return 'bottom';\n  }\n  return p as NzDropdownMenuComponent['placement'];\n};\n\n@Directive({\n  selector: '[nz-dropdown]',\n  exportAs: 'nzDropdown',\n  host: {\n    class: 'ant-dropdown-trigger'\n  }\n})\nexport class NzDropdownDirective implements AfterViewInit, OnChanges {\n  public readonly nzConfigService = inject(NzConfigService);\n  private renderer = inject(Renderer2);\n  private viewContainerRef = inject(ViewContainerRef);\n  private platform = inject(Platform);\n  private destroyRef = inject(DestroyRef);\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n  public elementRef = inject(ElementRef);\n  private injector = inject(Injector);\n\n  private portal?: TemplatePortal;\n  private overlayRef: OverlayRef | null = null;\n\n  private inputVisible$ = new BehaviorSubject<boolean>(false);\n  private nzTrigger$ = new BehaviorSubject<'click' | 'hover'>('hover');\n  private overlayClose$ = new Subject<boolean>();\n  @Input() nzDropdownMenu: NzDropdownMenuComponent | null = null;\n  @Input() nzTrigger: 'click' | 'hover' = 'hover';\n  @Input() nzMatchWidthElement: ElementRef | null = null;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzBackdrop = false;\n  @Input({ transform: booleanAttribute }) nzClickHide = true;\n  @Input({ transform: booleanAttribute }) nzDisabled = false;\n  @Input({ transform: booleanAttribute }) nzVisible = false;\n  @Input({ transform: booleanAttribute }) nzArrow = false;\n  @Input() nzOverlayClassName: string = '';\n  @Input() nzOverlayStyle: IndexableObject = {};\n  @Input() nzPlacement: NzPlacementType = 'bottomLeft';\n  @Output() readonly nzVisibleChange = new EventEmitter<boolean>();\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      this.overlayRef?.dispose();\n      this.overlayRef = null;\n    });\n  }\n\n  setDropdownMenuValue<T extends keyof NzDropdownMenuComponent>(key: T, value: NzDropdownMenuComponent[T]): void {\n    this.nzDropdownMenu?.setValue(key, value);\n  }\n\n  ngAfterViewInit(): void {\n    if (this.nzDropdownMenu) {\n      const nativeElement: HTMLElement = this.elementRef.nativeElement;\n      /** host mouse state **/\n      const hostMouseState$ = merge(\n        fromEvent(nativeElement, 'mouseenter').pipe(map(() => true)),\n        fromEvent(nativeElement, 'mouseleave').pipe(map(() => false))\n      );\n      /** menu mouse state **/\n      const menuMouseState$ = this.nzDropdownMenu.mouseState$;\n      /** merged mouse state **/\n      const mergedMouseState$ = merge(menuMouseState$, hostMouseState$);\n      /** host click state **/\n      const hostClickState$ = fromEvent(nativeElement, 'click').pipe(map(() => !this.nzVisible));\n      /** visible state switch by nzTrigger **/\n      const visibleStateByTrigger$ = this.nzTrigger$.pipe(\n        switchMap(trigger => {\n          if (trigger === 'hover') {\n            return mergedMouseState$;\n          } else if (trigger === 'click') {\n            return hostClickState$;\n          } else {\n            return EMPTY;\n          }\n        })\n      );\n      const descendantMenuItemClick$ = this.nzDropdownMenu.descendantMenuItemClick$.pipe(\n        filter(() => this.nzClickHide),\n        map(() => false)\n      );\n      const domTriggerVisible$ = merge(visibleStateByTrigger$, descendantMenuItemClick$, this.overlayClose$).pipe(\n        filter(() => !this.nzDisabled)\n      );\n      const visible$ = merge(this.inputVisible$, domTriggerVisible$);\n      combineLatest([visible$, this.nzDropdownMenu.isChildSubMenuOpen$])\n        .pipe(\n          map(([visible, sub]) => visible || sub),\n          auditTime(150),\n          distinctUntilChanged(),\n          filter(() => this.platform.isBrowser),\n          takeUntilDestroyed(this.destroyRef)\n        )\n        .subscribe(visible => {\n          const element = this.nzMatchWidthElement ? this.nzMatchWidthElement.nativeElement : nativeElement;\n          const triggerWidth = element.getBoundingClientRect().width;\n          if (this.nzVisible !== visible) {\n            this.nzVisibleChange.emit(visible);\n          }\n          this.nzVisible = visible;\n\n          if (visible) {\n            const positionStrategy = createFlexibleConnectedPositionStrategy(\n              this.injector,\n              this.elementRef.nativeElement\n            )\n              .withLockedPosition()\n              .withTransformOriginOn('.ant-dropdown');\n\n            // Listen for placement changes to update the menu classes (arrow position)\n            positionStrategy.positionChanges\n              .pipe(\n                filter(() => Boolean(this.overlayRef)),\n                map(change => getPlacementName(change) as NzPlacementType | undefined),\n                takeUntilDestroyed(this.destroyRef)\n              )\n              .subscribe(placement => {\n                if (placement) {\n                  this.setDropdownMenuValue('placement', normalizePlacementForClass(placement));\n                }\n              });\n\n            /** set up overlayRef **/\n            if (!this.overlayRef) {\n              /** new overlay **/\n              this.overlayRef = createOverlayRef(this.injector, {\n                positionStrategy,\n                minWidth: triggerWidth,\n                disposeOnNavigation: true,\n                hasBackdrop: this.nzBackdrop && this.nzTrigger === 'click',\n                scrollStrategy: createRepositionScrollStrategy(this.injector)\n              });\n              merge(\n                this.overlayRef.backdropClick(),\n                this.overlayRef.detachments(),\n                this.overlayRef\n                  .outsidePointerEvents()\n                  .pipe(filter(e => !this.elementRef.nativeElement.contains(e.target))),\n                this.overlayRef.keydownEvents().pipe(filter(e => e.keyCode === ESCAPE && !hasModifierKey(e)))\n              )\n                .pipe(takeUntilDestroyed(this.destroyRef))\n                .subscribe(() => {\n                  this.overlayClose$.next(false);\n                });\n            } else {\n              /** update overlay config **/\n              const overlayConfig = this.overlayRef.getConfig();\n              overlayConfig.minWidth = triggerWidth;\n            }\n            /** open dropdown with animation **/\n            const positions = [this.nzPlacement, ...listOfPositions].map(position => {\n              return this.nzArrow\n                ? setConnectedPositionOffset(POSITION_MAP[position], TOOLTIP_OFFSET_MAP[position])\n                : POSITION_MAP[position];\n            });\n            positionStrategy.withPositions(positions);\n            /** reset portal if needed **/\n            if (!this.portal || this.portal.templateRef !== this.nzDropdownMenu!.templateRef) {\n              this.portal = new TemplatePortal(this.nzDropdownMenu!.templateRef, this.viewContainerRef);\n            }\n            // Initialize arrow and placement on open\n            this.setDropdownMenuValue('nzArrow', this.nzArrow);\n            this.setDropdownMenuValue('placement', normalizePlacementForClass(this.nzPlacement));\n            this.overlayRef.attach(this.portal);\n          } else {\n            /** detach overlayRef if needed **/\n            this.overlayRef?.detach();\n          }\n        });\n\n      this.nzDropdownMenu!.animationStateChange$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(\n        (event: AnimationCallbackEvent) => {\n          this.overlayRef?.dispose();\n          this.overlayRef = null;\n          event.animationComplete();\n        }\n      );\n    }\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzVisible, nzDisabled, nzOverlayClassName, nzOverlayStyle, nzTrigger, nzArrow, nzPlacement } = changes;\n    if (nzTrigger) {\n      this.nzTrigger$.next(this.nzTrigger);\n    }\n    if (nzVisible) {\n      this.inputVisible$.next(this.nzVisible);\n    }\n    if (nzDisabled) {\n      const nativeElement = this.elementRef.nativeElement;\n      if (this.nzDisabled) {\n        this.renderer.setAttribute(nativeElement, 'disabled', '');\n        this.inputVisible$.next(false);\n      } else {\n        this.renderer.removeAttribute(nativeElement, 'disabled');\n      }\n    }\n    if (nzOverlayClassName) {\n      this.setDropdownMenuValue('nzOverlayClassName', this.nzOverlayClassName);\n    }\n    if (nzOverlayStyle) {\n      this.setDropdownMenuValue('nzOverlayStyle', this.nzOverlayStyle);\n    }\n    if (nzArrow) {\n      this.setDropdownMenuValue('nzArrow', this.nzArrow);\n    }\n    if (nzPlacement) {\n      this.setDropdownMenuValue('placement', normalizePlacementForClass(this.nzPlacement));\n    }\n  }\n}\n"
  },
  {
    "path": "components/dropdown/dropdown.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\n\nimport { NzContextMenuServiceModule } from './context-menu.service.module';\nimport { NzDropdownADirective } from './dropdown-a.directive';\nimport { NzDropdownMenuComponent } from './dropdown-menu.component';\nimport { NzDropdownDirective } from './dropdown.directive';\n\n@NgModule({\n  imports: [NzDropdownDirective, NzDropdownADirective, NzDropdownMenuComponent, NzContextMenuServiceModule],\n  exports: [NzMenuModule, NzDropdownDirective, NzDropdownADirective, NzDropdownMenuComponent]\n})\nexport class NzDropdownModule {}\n\n/**\n * @deprecated Use {@link NzDropdownModule} instead.\n * This will be removed in v22.0.0.\n */\nexport const NzDropDownModule = NzDropdownModule;\n"
  },
  {
    "path": "components/dropdown/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/dropdown/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/dropdown/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './dropdown.directive';\nexport * from './dropdown.module';\nexport * from './dropdown-a.directive';\nexport * from './dropdown-menu.component';\nexport * from './context-menu.service';\nexport * from './context-menu.service.module';\n"
  },
  {
    "path": "components/dropdown/style/entry.less",
    "content": "@import './index.less';\n@import './patch.less';\n// style dependencies\n@import '../../button/style/entry.less';\n"
  },
  {
    "path": "components/dropdown/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import './status';\n\n@dropdown-prefix-cls: ~'@{ant-prefix}-dropdown';\n\n.@{dropdown-prefix-cls} {\n  .reset-component();\n\n  --antd-arrow-background-color: @dropdown-menu-bg;\n\n  position: absolute;\n  top: -9999px;\n  left: -9999px;\n  z-index: @zindex-dropdown;\n  display: block;\n\n  &::before {\n    position: absolute;\n    inset-block: calc(@popover-arrow-width / 2 - @popover-distance);\n    z-index: -9999;\n    opacity: 0.0001;\n    content: '';\n  }\n\n  &-wrap {\n    position: relative;\n\n    .@{ant-prefix}-btn > .@{iconfont-css-prefix}-down {\n      font-size: 10px;\n    }\n\n    .@{iconfont-css-prefix}-down::before {\n      transition: transform @animation-duration-base;\n    }\n  }\n\n  &-wrap-open {\n    .@{iconfont-css-prefix}-down::before {\n      transform: rotate(180deg);\n    }\n  }\n\n  &-hidden,\n  &-menu-hidden,\n  &-menu-submenu-hidden {\n    display: none;\n  }\n\n  // Arrow Style\n  .placementArrow(@popover-arrow-width, 4px, @arrow-border-radius, var(--antd-arrow-background-color), @popover-arrow-box-shadow);\n\n  &-menu {\n    position: relative;\n    margin: 0;\n    padding: @dropdown-edge-child-vertical-padding 0;\n    text-align: left;\n    list-style-type: none;\n    background-color: @dropdown-menu-bg;\n    background-clip: padding-box;\n    border-radius: @border-radius-base;\n    outline: none;\n    box-shadow: @box-shadow-base;\n\n    &-item-group-title {\n      padding: 5px @control-padding-horizontal;\n      color: @text-color-secondary;\n      transition: all @animation-duration-slow;\n    }\n\n    &-submenu-popup {\n      position: absolute;\n      z-index: @zindex-dropdown;\n      background: transparent;\n      box-shadow: none;\n      transform-origin: 0 0;\n\n      ul,\n      li {\n        list-style: none;\n      }\n\n      ul {\n        margin-right: 0.3em;\n        margin-left: 0.3em;\n      }\n    }\n\n    // ======================= Item Content =======================\n    &-item {\n      position: relative;\n      display: flex;\n      align-items: center;\n    }\n\n    &-item-icon {\n      min-width: 12px;\n      margin-right: 8px;\n      font-size: @font-size-sm;\n    }\n\n    &-title-content {\n      flex: auto;\n\n      > a {\n        color: inherit;\n        transition: all @animation-duration-slow;\n\n        &:hover {\n          color: inherit;\n        }\n\n        &::after {\n          position: absolute;\n          top: 0;\n          right: 0;\n          bottom: 0;\n          left: 0;\n          content: '';\n        }\n      }\n    }\n\n    // =========================== Item ===========================\n    &-item,\n    &-submenu-title {\n      clear: both;\n      margin: 0;\n      padding: @dropdown-vertical-padding @control-padding-horizontal;\n      color: @text-color;\n      font-weight: normal;\n      font-size: @dropdown-font-size;\n      line-height: @dropdown-line-height;\n      cursor: pointer;\n      transition: all @animation-duration-slow;\n\n      &:first-child {\n        & when (@dropdown-edge-child-vertical-padding = 0) {\n          border-radius: @border-radius-base @border-radius-base 0 0;\n        }\n      }\n\n      &:last-child {\n        & when (@dropdown-edge-child-vertical-padding = 0) {\n          border-radius: 0 0 @border-radius-base @border-radius-base;\n        }\n      }\n\n      &-selected {\n        color: @dropdown-selected-color;\n        background-color: @dropdown-selected-bg;\n      }\n\n      &:hover,\n      &&-active {\n        background-color: @item-hover-bg;\n      }\n\n      &&-disabled {\n        color: @disabled-color;\n        cursor: not-allowed;\n\n        &:hover {\n          color: @disabled-color;\n          background-color: @dropdown-menu-submenu-disabled-bg;\n          cursor: not-allowed;\n        }\n\n        a {\n          pointer-events: none;\n        }\n      }\n\n      &-divider {\n        height: 1px;\n        margin: 4px 0;\n        overflow: hidden;\n        line-height: 0;\n        background-color: @border-color-split;\n      }\n\n      .@{dropdown-prefix-cls}-menu-submenu-expand-icon {\n        position: absolute;\n        right: @padding-xs;\n\n        .@{dropdown-prefix-cls}-menu-submenu-arrow-icon {\n          margin-right: 0 !important;\n          color: @text-color-secondary;\n          font-size: 10px;\n          font-style: normal;\n        }\n      }\n    }\n\n    &-item-group-list {\n      margin: 0 8px;\n      padding: 0;\n      list-style: none;\n    }\n\n    &-submenu-title {\n      padding-right: @control-padding-horizontal + @font-size-sm;\n    }\n\n    &-submenu-vertical {\n      position: relative;\n    }\n\n    &-submenu-vertical > & {\n      position: absolute;\n      top: 0;\n      left: 100%;\n      min-width: 100%;\n      margin-left: 4px;\n      transform-origin: 0 0;\n    }\n\n    &-submenu&-submenu-disabled .@{dropdown-prefix-cls}-menu-submenu-title {\n      &,\n      .@{dropdown-prefix-cls}-menu-submenu-arrow-icon {\n        color: @disabled-color;\n        background-color: @dropdown-menu-submenu-disabled-bg;\n        cursor: not-allowed;\n      }\n    }\n\n    // https://github.com/ant-design/ant-design/issues/19264\n    &-submenu-selected &-submenu-title {\n      color: @primary-color;\n    }\n  }\n\n  &.@{ant-prefix}-slide-down-enter.@{ant-prefix}-slide-down-enter-active&-placement-bottomLeft,\n  &.@{ant-prefix}-slide-down-appear.@{ant-prefix}-slide-down-appear-active&-placement-bottomLeft,\n  &.@{ant-prefix}-slide-down-enter.@{ant-prefix}-slide-down-enter-active&-placement-bottom,\n  &.@{ant-prefix}-slide-down-appear.@{ant-prefix}-slide-down-appear-active&-placement-bottom,\n  &.@{ant-prefix}-slide-down-enter.@{ant-prefix}-slide-down-enter-active&-placement-bottomRight,\n  &.@{ant-prefix}-slide-down-appear.@{ant-prefix}-slide-down-appear-active&-placement-bottomRight {\n    animation-name: antSlideUpIn;\n  }\n\n  &.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-topLeft,\n  &.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-topLeft,\n  &.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-top,\n  &.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-top,\n  &.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-topRight,\n  &.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-topRight {\n    animation-name: antSlideDownIn;\n  }\n\n  &.@{ant-prefix}-slide-down-leave.@{ant-prefix}-slide-down-leave-active&-placement-bottomLeft,\n  &.@{ant-prefix}-slide-down-leave.@{ant-prefix}-slide-down-leave-active&-placement-bottom,\n  &.@{ant-prefix}-slide-down-leave.@{ant-prefix}-slide-down-leave-active&-placement-bottomRight {\n    animation-name: antSlideUpOut;\n  }\n\n  &.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-topLeft,\n  &.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-top,\n  &.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-topRight {\n    animation-name: antSlideDownOut;\n  }\n}\n\n.@{dropdown-prefix-cls}-trigger,\n.@{dropdown-prefix-cls}-link,\n.@{dropdown-prefix-cls}-button {\n  > .@{iconfont-css-prefix}.@{iconfont-css-prefix}-down {\n    font-size: 10px;\n    vertical-align: baseline;\n  }\n}\n\n.@{dropdown-prefix-cls}-button {\n  white-space: nowrap;\n\n  &.@{ant-prefix}-btn-group > .@{ant-prefix}-btn {\n    &-loading,\n    &-loading + .@{ant-prefix}-btn {\n      cursor: default;\n      pointer-events: none;\n    }\n\n    &-loading + .@{ant-prefix}-btn::before {\n      display: block;\n    }\n\n    &:last-child:not(:first-child):not(.@{ant-prefix}-btn-icon-only) {\n      padding-right: @padding-xs;\n      padding-left: @padding-xs;\n    }\n  }\n}\n\n// https://github.com/ant-design/ant-design/issues/4903\n.@{dropdown-prefix-cls}-menu-dark {\n  &,\n  .@{dropdown-prefix-cls}-menu {\n    background: @menu-dark-bg;\n  }\n  .@{dropdown-prefix-cls}-menu-item,\n  .@{dropdown-prefix-cls}-menu-submenu-title,\n  .@{dropdown-prefix-cls}-menu-item > a,\n  .@{dropdown-prefix-cls}-menu-item > .@{iconfont-css-prefix} + span > a {\n    color: @text-color-secondary-dark;\n    .@{dropdown-prefix-cls}-menu-submenu-arrow::after {\n      color: @text-color-secondary-dark;\n    }\n\n    &:hover {\n      color: @text-color-inverse;\n      background: transparent;\n    }\n  }\n  .@{dropdown-prefix-cls}-menu-item-selected {\n    &,\n    &:hover,\n    > a {\n      color: @text-color-inverse;\n      background: @primary-color;\n    }\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/dropdown/style/patch.less",
    "content": ".ant-dropdown-menu {\n  & > ul {\n    margin: 0;\n    padding: 0;\n    list-style: inherit;\n  }\n}\n\n.ant-dropdown {\n  position: relative;\n  inset: 0;\n\n  &:not(:has(.ant-dropdown-arrow)) {\n    margin-block: calc(@popover-distance - @popover-arrow-width / 2)\n  }\n}\n\n.@{dropdown-prefix-cls} {\n  &-menu {\n    &-item,\n    &-submenu-title {\n      .@{dropdown-prefix-cls}-menu-submenu-arrow {\n        .@{dropdown-prefix-cls}-rtl & {\n          transform: rotate(180deg);\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/dropdown/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@dropdown-prefix-cls: ~'@{ant-prefix}-dropdown';\n\n.@{dropdown-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &::before {\n    .@{dropdown-prefix-cls}-rtl& {\n      right: -7px;\n      left: 0;\n    }\n  }\n\n  &-menu {\n    &&-rtl {\n      direction: rtl;\n      text-align: right;\n    }\n\n    &-item-group-title {\n      .@{dropdown-prefix-cls}-rtl &,\n      .@{dropdown-prefix-cls}-menu-submenu-rtl & {\n        direction: rtl;\n        text-align: right;\n      }\n    }\n\n    &-submenu-popup {\n      &.@{dropdown-prefix-cls}-menu-submenu-rtl {\n        transform-origin: 100% 0;\n      }\n\n      ul,\n      li {\n        .@{dropdown-prefix-cls}-rtl & {\n          text-align: right;\n        }\n      }\n    }\n\n    &-item,\n    &-submenu-title {\n      .@{dropdown-prefix-cls}-rtl & {\n        text-align: right;\n      }\n\n      > .@{iconfont-css-prefix}:first-child,\n      > span > .@{iconfont-css-prefix}:first-child {\n        .@{dropdown-prefix-cls}-rtl & {\n          margin-right: 0;\n          margin-left: 8px;\n        }\n      }\n\n      .@{dropdown-prefix-cls}-menu-submenu-expand-icon {\n        .@{dropdown-prefix-cls}-rtl & {\n          right: auto;\n          left: @padding-xs;\n        }\n\n        .@{dropdown-prefix-cls}-menu-submenu-arrow-icon {\n          .@{dropdown-prefix-cls}-rtl & {\n            margin-left: 0 !important;\n            transform: scaleX(-1);\n          }\n        }\n      }\n    }\n\n    &-submenu-title {\n      .@{dropdown-prefix-cls}-rtl & {\n        padding-right: @control-padding-horizontal;\n        padding-left: @control-padding-horizontal + @font-size-sm;\n      }\n    }\n\n    &-submenu-vertical > & {\n      .@{dropdown-prefix-cls}-rtl & {\n        right: 100%;\n        left: 0;\n        margin-right: 4px;\n        margin-left: 0;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/dropdown/style/status.less",
    "content": "@import (reference) '../../style/themes/index';\n\n@dropdown-prefix-cls: ~'@{ant-prefix}-dropdown';\n\n.@{dropdown-prefix-cls}-menu-item {\n  &&-danger {\n    color: @error-color;\n\n    &:hover {\n      color: @text-color-inverse;\n      background-color: @error-color;\n    }\n  }\n}\n"
  },
  {
    "path": "components/empty/config.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\n/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { InjectionToken, TemplateRef, Type } from '@angular/core';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nexport type NzEmptySize = 'normal' | 'small' | '';\n\nexport type NzEmptyCustomContent = Type<NzSafeAny> | TemplateRef<NzSafeAny> | string | null;\n\nexport const NZ_EMPTY_COMPONENT_NAME = new InjectionToken<string>(\n  typeof ngDevMode !== 'undefined' && ngDevMode ? 'nz-empty-component-name' : ''\n);\n"
  },
  {
    "path": "components/empty/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n简单的展示。\n\n## en-US\n\nSimplest usage.\n"
  },
  {
    "path": "components/empty/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzEmptyModule } from 'ng-zorro-antd/empty';\n\n@Component({\n  selector: 'nz-demo-empty-basic',\n  imports: [NzEmptyModule],\n  template: `<nz-empty />`\n})\nexport class NzDemoEmptyBasicComponent {}\n"
  },
  {
    "path": "components/empty/demo/config.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 全局化配置\n  en-US: Default Config\n---\n\n## zh-CN\n\n自定义全局组件的 Empty 样式。\n\n## en-US\n\nUse `NzEmptyService` set global Empty style.\n"
  },
  {
    "path": "components/empty/demo/config.ts",
    "content": "import { Component, TemplateRef, ViewChild } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCascaderModule } from 'ng-zorro-antd/cascader';\nimport { NzConfigService } from 'ng-zorro-antd/core/config';\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\nimport { NzEmptyModule } from 'ng-zorro-antd/empty';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzListModule } from 'ng-zorro-antd/list';\nimport { NzSelectModule } from 'ng-zorro-antd/select';\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\nimport { NzTableModule } from 'ng-zorro-antd/table';\nimport { NzTransferModule } from 'ng-zorro-antd/transfer';\nimport { NzTreeSelectModule } from 'ng-zorro-antd/tree-select';\n\n@Component({\n  selector: 'nz-demo-empty-config',\n  imports: [\n    FormsModule,\n    NzCascaderModule,\n    NzDividerModule,\n    NzEmptyModule,\n    NzIconModule,\n    NzListModule,\n    NzSelectModule,\n    NzSwitchModule,\n    NzTableModule,\n    NzTransferModule,\n    NzTreeSelectModule\n  ],\n  template: `\n    <nz-switch\n      nzUnCheckedChildren=\"default\"\n      nzCheckedChildren=\"customize\"\n      [(ngModel)]=\"customize\"\n      (ngModelChange)=\"onConfigChange()\"\n    />\n\n    <nz-divider />\n\n    <h3>Select</h3>\n    <nz-select style=\"width: 200px\" />\n\n    <h3>TreeSelect</h3>\n    <nz-tree-select style=\"width: 200px;\" />\n\n    <h3>Cascader</h3>\n    <nz-cascader style=\"width: 200px;\" [nzShowSearch]=\"true\" [nzOptions]=\"[]\" />\n\n    <h3>Transfer</h3>\n    <nz-transfer />\n\n    <h3>Table</h3>\n    <nz-table [nzData]=\"[]\">\n      <thead>\n        <tr>\n          <th>Title</th>\n          <th>Age</th>\n        </tr>\n      </thead>\n      <tbody></tbody>\n    </nz-table>\n\n    <h3>List</h3>\n    <nz-list [nzDataSource]=\"[]\" />\n\n    <ng-template #customTpl let-name>\n      <div style=\"text-align: center;\">\n        <nz-icon nzType=\"smile\" style=\"font-size: 20px;\" />\n        <p>Data Not Found in {{ name }}</p>\n      </div>\n    </ng-template>\n  `,\n  styles: `\n    h3 {\n      font-size: inherit;\n      margin: 16px 0 8px 0;\n    }\n  `\n})\nexport class NzDemoEmptyConfigComponent {\n  @ViewChild('customTpl', { static: false }) customTpl?: TemplateRef<any>; // eslint-disable-line @typescript-eslint/no-explicit-any\n\n  customize = false;\n\n  constructor(private nzConfigService: NzConfigService) {}\n\n  onConfigChange(): void {\n    if (this.customize) {\n      this.nzConfigService.set('empty', { nzDefaultEmptyContent: this.customTpl });\n    } else {\n      this.nzConfigService.set('empty', { nzDefaultEmptyContent: undefined });\n    }\n  }\n}\n"
  },
  {
    "path": "components/empty/demo/customize.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 自定义\n  en-US: Customize\n---\n\n## zh-CN\n\n自定义图片、描述、附属内容。\n\n## en-US\n\nCustomize image, description and extra content.\n"
  },
  {
    "path": "components/empty/demo/customize.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzEmptyModule } from 'ng-zorro-antd/empty';\n\n@Component({\n  selector: 'nz-demo-empty-customize',\n  imports: [NzButtonModule, NzEmptyModule],\n  template: `\n    <nz-empty\n      nzNotFoundImage=\"https://gw.alipayobjects.com/zos/antfincdn/ZHrcdLPrvN/empty.svg\"\n      [nzNotFoundContent]=\"contentTpl\"\n      [nzNotFoundFooter]=\"footerTpl\"\n    >\n      <ng-template #contentTpl>\n        <span>\n          Customize\n          <a href=\"#API\">Description</a>\n        </span>\n      </ng-template>\n      <ng-template #footerTpl>\n        <button nz-button nzType=\"primary\" (click)=\"onClick()\">Create Now</button>\n      </ng-template>\n    </nz-empty>\n  `\n})\nexport class NzDemoEmptyCustomizeComponent {\n  onClick(): void {\n    console.log('clicked');\n  }\n}\n"
  },
  {
    "path": "components/empty/demo/description.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 无描述\n  en-US: No description\n---\n\n## zh-CN\n\n无描述展示。\n\n## en-US\n\nSimplest Usage with no description.\n"
  },
  {
    "path": "components/empty/demo/description.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzEmptyModule } from 'ng-zorro-antd/empty';\n\n@Component({\n  selector: 'nz-demo-empty-description',\n  imports: [NzEmptyModule],\n  template: `<nz-empty [nzNotFoundContent]=\"null\" />`\n})\nexport class NzDemoEmptyDescriptionComponent {}\n"
  },
  {
    "path": "components/empty/demo/simple.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 选择图片\n  en-US: Chose image\n---\n\n## zh-CN\n\n可以通过设置 `nzNotFoundImage` 为 `simple` 选择另一种风格的图片。\n\n## en-US\n\nYou can choose another style of `image` by setting `simple` to `nzNotFoundImage`.\n"
  },
  {
    "path": "components/empty/demo/simple.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzEmptyModule } from 'ng-zorro-antd/empty';\n\n@Component({\n  selector: 'nz-demo-empty-simple',\n  imports: [NzEmptyModule],\n  template: `<nz-empty nzNotFoundImage=\"simple\" />`\n})\nexport class NzDemoEmptySimpleComponent {}\n"
  },
  {
    "path": "components/empty/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Display\ntitle: Empty\ncols: 1\ncover: 'https://gw.alipayobjects.com/zos/alicdn/MNbKfLBVb/Empty.svg'\ndescription: Empty state placeholder.\n---\n\n## When To Use\n\nWhen there is no data provided, display for friendly tips.\n\n## API\n\n### nz-empty\n\n| Property              | Description                                                   | Type                                  | Default |\n| --------------------- | ------------------------------------------------------------- | ------------------------------------- | ------- |\n| `[nzNotFoundImage]`   | Customize image. Will tread as image url when string provided | `string \\| TemplateRef<void>`         | -       |\n| `[nzNotFoundContent]` | Custom description                                            | `string \\| TemplateRef<void> \\| null` | -       |\n| `[nzNotFoundFooter]`  | Custom Footer                                                 | `string \\| TemplateRef<void>`         | -       |\n\n### `NZ_CONFIG`\n\nThe `nzEmpty` interface has properties as follows:\n\n| Properties              | Description                                                                                             | Type                                                      |\n| ----------------------- | ------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- |\n| `nzDefaultEmptyContent` | User default empty component. You can restore the system default empty content by providing `undefined` | `Type<any> \\| TemplateRef<string> \\| string \\| undefined` |\n\n### InjectionToken\n\n| Token                     | Description                                                                                         | Parameters |\n| ------------------------- | --------------------------------------------------------------------------------------------------- | ---------- |\n| `NZ_EMPTY_COMPONENT_NAME` | Would be injected to `NZ_DEFAULT_EMPTY_CONTENT`, telling that component its parent component's name | `string`   |\n\n### Global Customizable Empty Content\n\nYou may notice or used some inputs like `nzNotFoundContent` in some components. Now they would use `Empty` component. So you can provide `nzDefaultEmptyContent` to customize them.\n\n```ts\n{\n  provide: NZ_CONFIG,\n  useValue: {\n    empty: {\n      nzDefaultEmptyContent\n    }\n  }\n}\n```\n"
  },
  {
    "path": "components/empty/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ntype: 数据展示\nsubtitle: 空状态\ntitle: Empty\ncols: 1\ncover: 'https://gw.alipayobjects.com/zos/alicdn/MNbKfLBVb/Empty.svg'\ndescription: 空状态时的展示占位图。\n---\n\n## 何时使用\n\n当目前没有数据时，用于显式的用户提示。\n\n## API\n\n### nz-empty\n\n| 参数                  | 说明                                           | 类型                                  | 默认值 |\n| --------------------- | ---------------------------------------------- | ------------------------------------- | ------ |\n| `[nzNotFoundImage]`   | 设置显示图片，为 `string` 时表示自定义图片地址 | `string \\| TemplateRef<void>`         | -      |\n| `[nzNotFoundContent]` | 自定义描述内容                                 | `string \\| TemplateRef<void> \\| null` | -      |\n| `[nzNotFoundFooter]`  | 设置自定义 footer                              | `string \\| TemplateRef<void>`         | -      |\n\n### `NZ_CONFIG`\n\n`nzEmpty` 接口有如下字段：\n\n| 参数                    | 说明                                                                | 类型                                                      |\n| ----------------------- | ------------------------------------------------------------------- | --------------------------------------------------------- |\n| `nzDefaultEmptyContent` | 用户自定义的全局空组件，可通过 `undefined` 来取消自定义的全局空组件 | `Type<any> \\| TemplateRef<string> \\| string \\| undefined` |\n\n### InjectionToken\n\n| Token                     | 说明                                                             | 参数     |\n| ------------------------- | ---------------------------------------------------------------- | -------- |\n| `NZ_EMPTY_COMPONENT_NAME` | 将会被注入到用户的全局自定义空组件中，告诉该组件其所在组件的名称 | `string` |\n\n### 全局自定义空组件\n\n你或许知道或者用过一些类似 `nzNotFoundContent` 的属性来自定义组件数据为空时的内容，现在它们都会使用 `Empty` 组件。你可以通过在 `NZ_CONFIG` 中提供 `{ empty: { nzDefaultEmptyContent: something } }` 来定义一个自定义的全局空组件。\n\n```ts\n{\n  provide: NZ_CONFIG,\n  useValue: {\n    empty: {\n      nzDefaultEmptyContent\n    }\n  }\n}\n```\n"
  },
  {
    "path": "components/empty/embed-empty.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ComponentPortal, Portal, PortalModule } from '@angular/cdk/portal';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  inject,\n  Injector,\n  Input,\n  OnChanges,\n  OnInit,\n  SimpleChanges,\n  TemplateRef,\n  Type,\n  ViewContainerRef,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { NzConfigService, onConfigChangeEventForComponent } from 'ng-zorro-antd/core/config';\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NZ_EMPTY_COMPONENT_NAME, NzEmptyCustomContent, NzEmptySize } from './config';\nimport { NzEmptyComponent } from './empty.component';\n\nfunction getEmptySize(componentName: string): NzEmptySize {\n  switch (componentName) {\n    case 'table':\n    case 'list':\n      return 'normal';\n    case 'select':\n    case 'tree-select':\n    case 'cascader':\n    case 'transfer':\n      return 'small';\n    default:\n      return '';\n  }\n}\n\ntype NzEmptyContentType = 'component' | 'template' | 'string';\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-embed-empty',\n  exportAs: 'nzEmbedEmpty',\n  template: `\n    @if (content) {\n      @if (contentType === 'template' || contentType === 'string') {\n        <ng-container *nzStringTemplateOutlet=\"content; context: { $implicit: this.nzComponentName }\">{{\n          content\n        }}</ng-container>\n      } @else {\n        <ng-template [cdkPortalOutlet]=\"contentPortal\" />\n      }\n    } @else {\n      @if (specificContent !== null) {\n        @switch (size) {\n          @case ('normal') {\n            <nz-empty class=\"ant-empty-normal\" nzNotFoundImage=\"simple\" />\n          }\n          @case ('small') {\n            <nz-empty class=\"ant-empty-small\" nzNotFoundImage=\"simple\" />\n          }\n          @default {\n            <nz-empty />\n          }\n        }\n      }\n    }\n  `,\n  imports: [NzEmptyComponent, PortalModule, NzOutletModule]\n})\nexport class NzEmbedEmptyComponent implements OnChanges, OnInit {\n  private configService = inject(NzConfigService);\n  private viewContainerRef = inject(ViewContainerRef);\n  private cdr = inject(ChangeDetectorRef);\n  private injector = inject(Injector);\n\n  @Input() nzComponentName?: string;\n  @Input() specificContent?: NzEmptyCustomContent;\n\n  content?: NzEmptyCustomContent;\n  contentType: NzEmptyContentType = 'string';\n  contentPortal?: Portal<NzSafeAny>;\n  size: NzEmptySize = '';\n\n  constructor() {\n    onConfigChangeEventForComponent('empty', () => {\n      this.content = this.specificContent || this.getUserDefaultEmptyContent();\n      this.renderEmpty();\n    });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    if (changes.nzComponentName) {\n      this.size = getEmptySize(changes.nzComponentName.currentValue);\n    }\n\n    if (changes.specificContent && !changes.specificContent.isFirstChange()) {\n      this.content = changes.specificContent.currentValue;\n      this.renderEmpty();\n    }\n  }\n\n  ngOnInit(): void {\n    this.content = this.specificContent || this.getUserDefaultEmptyContent();\n    this.renderEmpty();\n  }\n\n  private renderEmpty(): void {\n    const content = this.content;\n\n    if (typeof content === 'string') {\n      this.contentType = 'string';\n    } else if (content instanceof TemplateRef) {\n      this.contentType = 'template';\n      this.contentPortal = undefined;\n    } else if (content instanceof Type) {\n      const injector = Injector.create({\n        parent: this.injector,\n        providers: [{ provide: NZ_EMPTY_COMPONENT_NAME, useValue: this.nzComponentName }]\n      });\n      this.contentType = 'component';\n      this.contentPortal = new ComponentPortal(content, this.viewContainerRef, injector);\n    } else {\n      this.contentType = 'string';\n      this.contentPortal = undefined;\n    }\n\n    this.cdr.detectChanges();\n  }\n\n  private getUserDefaultEmptyContent(): Type<NzSafeAny> | TemplateRef<string> | string | undefined {\n    return (this.configService.getConfigForComponent('empty') || {}).nzDefaultEmptyContent;\n  }\n}\n"
  },
  {
    "path": "components/empty/empty.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DestroyRef,\n  inject,\n  Input,\n  OnChanges,\n  OnInit,\n  SimpleChanges,\n  TemplateRef,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzEmptyI18nInterface, NzI18nService } from 'ng-zorro-antd/i18n';\n\nimport { NzEmptyDefaultComponent } from './partial/default';\nimport { NzEmptySimpleComponent } from './partial/simple';\n\nconst NzEmptyDefaultImages = ['default', 'simple'] as const;\ntype NzEmptyNotFoundImageType = (typeof NzEmptyDefaultImages)[number] | null | string | TemplateRef<void>;\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-empty',\n  exportAs: 'nzEmpty',\n  template: `\n    <div class=\"ant-empty-image\">\n      @if (!isImageBuildIn) {\n        <ng-container *nzStringTemplateOutlet=\"nzNotFoundImage\">\n          <img [src]=\"nzNotFoundImage\" [alt]=\"isContentString ? nzNotFoundContent : 'empty'\" />\n        </ng-container>\n      } @else {\n        @if (nzNotFoundImage === 'simple') {\n          <nz-empty-simple />\n        } @else {\n          <nz-empty-default />\n        }\n      }\n    </div>\n    @if (nzNotFoundContent !== null) {\n      <p class=\"ant-empty-description\">\n        <ng-container *nzStringTemplateOutlet=\"nzNotFoundContent\">\n          {{ isContentString ? nzNotFoundContent : locale['description'] }}\n        </ng-container>\n      </p>\n    }\n\n    @if (nzNotFoundFooter) {\n      <div class=\"ant-empty-footer\">\n        <ng-container *nzStringTemplateOutlet=\"nzNotFoundFooter\">\n          {{ nzNotFoundFooter }}\n        </ng-container>\n      </div>\n    }\n  `,\n  host: {\n    class: 'ant-empty'\n  },\n  imports: [NzOutletModule, NzEmptyDefaultComponent, NzEmptySimpleComponent]\n})\nexport class NzEmptyComponent implements OnChanges, OnInit {\n  private i18n = inject(NzI18nService);\n  private cdr = inject(ChangeDetectorRef);\n  private destroyRef = inject(DestroyRef);\n\n  @Input() nzNotFoundImage: NzEmptyNotFoundImageType = 'default';\n  @Input() nzNotFoundContent?: string | TemplateRef<void> | null;\n  @Input() nzNotFoundFooter?: string | TemplateRef<void>;\n\n  isContentString = false;\n  isImageBuildIn = true;\n  locale!: NzEmptyI18nInterface;\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzNotFoundContent, nzNotFoundImage } = changes;\n\n    if (nzNotFoundContent) {\n      const content = nzNotFoundContent.currentValue;\n      this.isContentString = typeof content === 'string';\n    }\n\n    if (nzNotFoundImage) {\n      const image = nzNotFoundImage.currentValue || 'default';\n      this.isImageBuildIn = NzEmptyDefaultImages.findIndex(i => i === image) > -1;\n    }\n  }\n\n  ngOnInit(): void {\n    this.i18n.localeChange.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      this.locale = this.i18n.getLocaleData('Empty');\n      this.cdr.markForCheck();\n    });\n  }\n}\n"
  },
  {
    "path": "components/empty/empty.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzEmbedEmptyComponent } from './embed-empty.component';\nimport { NzEmptyComponent } from './empty.component';\nimport { NzEmptyDefaultComponent } from './partial/default';\nimport { NzEmptySimpleComponent } from './partial/simple';\n\n@NgModule({\n  imports: [NzEmptyComponent, NzEmbedEmptyComponent, NzEmptyDefaultComponent, NzEmptySimpleComponent],\n  exports: [NzEmptyComponent, NzEmbedEmptyComponent]\n})\nexport class NzEmptyModule {}\n"
  },
  {
    "path": "components/empty/empty.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, DebugElement, TemplateRef, ViewChild, inject, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { NZ_CONFIG, NzConfigService } from 'ng-zorro-antd/core/config';\nimport { NzI18nService } from 'ng-zorro-antd/i18n';\nimport en_US from 'ng-zorro-antd/i18n/languages/en_US';\nimport { NzListModule } from 'ng-zorro-antd/list';\n\nimport { NZ_EMPTY_COMPONENT_NAME } from './config';\nimport { NzEmbedEmptyComponent } from './embed-empty.component';\nimport { NzEmptyComponent } from './empty.component';\nimport { NzEmptyModule } from './empty.module';\n\ndescribe('empty', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  describe('basic', () => {\n    let fixture: ComponentFixture<NzEmptyTestBasicComponent>;\n    let testComponent: NzEmptyTestBasicComponent;\n    let emptyComponent: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzEmptyTestBasicComponent);\n      testComponent = fixture.debugElement.componentInstance;\n      emptyComponent = fixture.debugElement.query(By.directive(NzEmptyComponent));\n\n      fixture.detectChanges();\n    });\n\n    it('should render image, description on default situation', () => {\n      expect(emptyComponent.nativeElement.classList.contains('ant-empty')).toBe(true);\n\n      const imageEl = emptyComponent.nativeElement.firstChild;\n\n      expect(imageEl.tagName).toBe('DIV');\n      expect(imageEl.classList.contains('ant-empty-image')).toBe(true);\n      expect(imageEl.firstElementChild.tagName).toBe('NZ-EMPTY-DEFAULT');\n\n      const contentEl = emptyComponent.nativeElement.lastElementChild;\n      expect(contentEl.tagName).toBe('P');\n      expect(contentEl.innerText.trim()).toBe('暂无数据');\n    });\n\n    it('should render image, content and footer as template', () => {\n      testComponent.image = testComponent.imageTpl;\n      testComponent.content = testComponent.contentTpl;\n      testComponent.footer = testComponent.footerTpl;\n\n      fixture.detectChanges();\n\n      expect(emptyComponent.nativeElement.classList.contains('ant-empty')).toBe(true);\n\n      const imageEl = emptyComponent.nativeElement.firstChild;\n      expect(imageEl.tagName).toBe('DIV');\n      expect(imageEl.classList.contains('ant-empty-image')).toBe(true);\n      expect(imageEl.innerText).toBe('Image');\n\n      const contentEl = emptyComponent.nativeElement.querySelector('.ant-empty-description');\n      expect(contentEl).not.toBeFalsy();\n      expect(contentEl.tagName).toBe('P');\n      expect(contentEl.innerText).toBe('Content');\n\n      const footerEl = emptyComponent.nativeElement.lastElementChild;\n      expect(footerEl.tagName).toBe('DIV');\n      expect(footerEl.classList.contains('ant-empty-footer')).toBe(true);\n      expect(footerEl.innerText).toBe('Footer');\n    });\n\n    it('should render image, content and footer as string and change `alt`', () => {\n      testComponent.image = 'https://ng.ant.design/assets/img/logo.svg';\n      testComponent.content = 'zorro icon';\n      testComponent.footer = 'Footer';\n      fixture.detectChanges();\n\n      expect(emptyComponent.nativeElement.classList.contains('ant-empty')).toBe(true);\n\n      const imageEl = emptyComponent.nativeElement.firstChild;\n      expect(imageEl.tagName).toBe('DIV');\n      expect(imageEl.classList.contains('ant-empty-image')).toBe(true);\n      expect(imageEl.firstElementChild.tagName).toBe('IMG');\n      expect(imageEl.firstElementChild.getAttribute('alt')).toBe('zorro icon');\n      expect(imageEl.firstElementChild.src).toContain('ng.ant.design');\n\n      const contentEl = emptyComponent.nativeElement.querySelector('.ant-empty-description');\n      expect(contentEl).not.toBeFalsy();\n      expect(contentEl.tagName).toBe('P');\n      expect(contentEl.innerText).toBe('zorro icon');\n\n      const footerEl = emptyComponent.nativeElement.lastElementChild;\n      expect(footerEl.tagName).toBe('DIV');\n      expect(footerEl.classList.contains('ant-empty-footer')).toBe(true);\n      expect(footerEl.innerText).toBe('Footer');\n    });\n\n    it('should render empty string as content', () => {\n      testComponent.content = '';\n      fixture.detectChanges();\n\n      const contentEl = emptyComponent.nativeElement.querySelector('.ant-empty-description');\n      expect(contentEl).not.toBeFalsy();\n      expect(contentEl.tagName).toBe('P');\n      expect(contentEl.innerText).toBe('');\n    });\n\n    it('i18n', () => {\n      const contentEl = emptyComponent.nativeElement.lastElementChild;\n      expect(contentEl.innerText.trim()).toBe('暂无数据');\n\n      TestBed.inject(NzI18nService).setLocale(en_US);\n      fixture.detectChanges();\n      expect(contentEl.innerText.trim()).toBe('No Data');\n    });\n  });\n\n  /**\n   * Config default empty content via `NzEmptyService`'s `setDefaultEmptyContent` method.\n   */\n  describe('embed', () => {\n    let fixture: ComponentFixture<NzEmptyTestServiceComponent>;\n    let testComponent: NzEmptyTestServiceComponent;\n    let embedComponent: DebugElement;\n    let emptyComponent: DebugElement;\n\n    describe('service method', () => {\n      beforeEach(() => {\n        fixture = TestBed.createComponent(NzEmptyTestServiceComponent);\n        testComponent = fixture.debugElement.componentInstance;\n      });\n\n      it(\"should components' prop has priority\", fakeAsync(() => {\n        const refresh = (): void => {\n          fixture.detectChanges();\n          tick();\n          fixture.detectChanges();\n\n          embedComponent = fixture.debugElement.query(By.directive(NzEmbedEmptyComponent));\n          emptyComponent = fixture.debugElement.query(By.directive(NzEmptyComponent));\n        };\n\n        refresh();\n\n        // Default.\n        expect(embedComponent).toBeTruthy();\n        expect(emptyComponent).toBeTruthy();\n        expect(emptyComponent.nativeElement.classList.contains('ant-empty')).toBe(true);\n        expect(emptyComponent.nativeElement.classList.contains('ant-empty-normal')).toBe(true);\n        const imageEl = emptyComponent.nativeElement.firstChild;\n        expect(imageEl.tagName).toBe('DIV');\n        expect(imageEl.classList.contains('ant-empty-image')).toBe(true);\n        expect(imageEl.firstElementChild.tagName).toBe('NZ-EMPTY-SIMPLE');\n\n        // Prop.\n        testComponent.noResult = 'list';\n        refresh();\n        expect(embedComponent).toBeTruthy();\n        expect(emptyComponent).toBeFalsy();\n        expect(embedComponent.nativeElement.innerText).toBe('list');\n\n        // Null.\n        testComponent.noResult = null!;\n        refresh();\n        expect(embedComponent).toBeTruthy();\n        expect(emptyComponent).toBeFalsy();\n        expect(embedComponent.nativeElement.innerText).toBe('');\n      }));\n\n      it('should support string, template and component', fakeAsync(() => {\n        const refresh = (): void => {\n          fixture.detectChanges();\n          tick();\n          fixture.detectChanges();\n\n          embedComponent = fixture.debugElement.query(By.directive(NzEmbedEmptyComponent));\n          emptyComponent = fixture.debugElement.query(By.directive(NzEmptyComponent));\n        };\n\n        // String.\n        testComponent.configService.set('empty', { nzDefaultEmptyContent: 'empty' });\n        refresh();\n        expect(embedComponent).toBeTruthy();\n        expect(emptyComponent).toBeFalsy();\n        expect(embedComponent.nativeElement.innerText).toBe('empty');\n\n        // Template.\n        testComponent.changeToTemplate();\n        refresh();\n        expect(embedComponent).toBeTruthy();\n        expect(emptyComponent).toBeFalsy();\n        const divEl = embedComponent.nativeElement.firstElementChild;\n        expect(divEl).toBeTruthy();\n        expect(divEl.tagName).toBe('DIV');\n        expect(divEl.innerText).toBe('I am in template list');\n\n        // FIXME: This is not supported yet, see https://github.com/angular/angular/issues/15634.\n        // Component.\n        // testComponent.changeToComponent();\n        // refresh();\n        // expect(embedComponent).toBeTruthy();\n        // expect(emptyComponent).toBeFalsy();\n        // const componentEl = embedComponent.nativeElement.nextSibling;\n        // expect(componentEl).toBeTruthy();\n        // expect(componentEl.tagName).toBe('NZ-EMPTY-TEST-CUSTOM');\n        // expect(componentEl.innerText).toBe(`I'm in component list`);\n\n        // Reset.\n        testComponent.reset();\n        refresh();\n        expect(embedComponent).toBeTruthy();\n        expect(emptyComponent).toBeTruthy();\n        expect(emptyComponent.nativeElement.classList.contains('ant-empty')).toBe(true);\n        expect(emptyComponent.nativeElement.classList.contains('ant-empty-normal')).toBe(true);\n        const imageEl = emptyComponent.nativeElement.firstChild;\n        expect(imageEl.tagName).toBe('DIV');\n        expect(imageEl.classList.contains('ant-empty-image')).toBe(true);\n        expect(imageEl.firstElementChild.tagName).toBe('NZ-EMPTY-SIMPLE');\n      }));\n    });\n\n    /**\n     * Config default empty content via injection.\n     */\n    describe('service injection', () => {\n      beforeEach(() => {\n        TestBed.configureTestingModule({\n          providers: [\n            {\n              provide: NZ_CONFIG,\n              useValue: {\n                empty: {\n                  nzDefaultEmptyContent: NzEmptyTestCustomComponent\n                }\n              }\n            }\n          ]\n        });\n        fixture = TestBed.createComponent(NzEmptyTestServiceComponent);\n        testComponent = fixture.debugElement.componentInstance;\n      });\n\n      it('should support injection', fakeAsync(() => {\n        const refresh = (): void => {\n          fixture.detectChanges();\n          tick(100);\n          fixture.detectChanges();\n\n          embedComponent = fixture.debugElement.query(By.directive(NzEmbedEmptyComponent));\n          emptyComponent = fixture.debugElement.query(By.directive(NzEmptyComponent));\n        };\n\n        refresh();\n\n        // Component.\n        expect(embedComponent).toBeTruthy();\n        expect(emptyComponent).toBeFalsy();\n        const componentEl = embedComponent.nativeElement.firstElementChild;\n        expect(componentEl).toBeTruthy();\n        expect(componentEl.tagName).toBe('NZ-EMPTY-TEST-CUSTOM');\n        expect(componentEl.innerText).toBe(`I'm in component list`);\n      }));\n    });\n  });\n});\n\n@Component({\n  imports: [NzEmptyModule],\n  template: `\n    <nz-empty [nzNotFoundImage]=\"image\" [nzNotFoundContent]=\"content\" [nzNotFoundFooter]=\"footer\">\n      <ng-template #imageTpl>Image</ng-template>\n      <ng-template #contentTpl>Content</ng-template>\n      <ng-template #footerTpl>Footer</ng-template>\n    </nz-empty>\n  `\n})\nexport class NzEmptyTestBasicComponent {\n  @ViewChild('imageTpl', { static: false }) imageTpl!: TemplateRef<void>;\n  @ViewChild('contentTpl', { static: false }) contentTpl!: TemplateRef<void>;\n  @ViewChild('footerTpl', { static: false }) footerTpl!: TemplateRef<void>;\n\n  image!: TemplateRef<void> | string;\n  content?: TemplateRef<void> | string;\n  footer?: TemplateRef<void> | string;\n}\n\n@Component({\n  imports: [NzListModule],\n  template: `\n    <nz-list [nzDataSource]=\"[]\" [nzNoResult]=\"noResult\" />\n    <ng-template #tpl let-component>\n      <div>I am in template {{ component }}</div>\n    </ng-template>\n  `\n})\nexport class NzEmptyTestServiceComponent {\n  @ViewChild('tpl', { static: false }) template!: TemplateRef<string>;\n\n  noResult!: string;\n\n  constructor(public configService: NzConfigService) {}\n\n  reset(): void {\n    this.configService.set('empty', { nzDefaultEmptyContent: undefined });\n  }\n\n  changeToTemplate(): void {\n    this.configService.set('empty', { nzDefaultEmptyContent: this.template });\n  }\n}\n\n@Component({\n  selector: 'nz-empty-test-custom',\n  template: `<div>I'm in component {{ name }}</div>`\n})\nexport class NzEmptyTestCustomComponent {\n  name = inject(NZ_EMPTY_COMPONENT_NAME);\n}\n"
  },
  {
    "path": "components/empty/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/empty/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/empty/partial/default.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-empty-default',\n  exportAs: 'nzEmptyDefault',\n  template: `\n    <svg\n      class=\"ant-empty-img-default\"\n      width=\"184\"\n      height=\"152\"\n      viewBox=\"0 0 184 152\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n    >\n      <g fill=\"none\" fill-rule=\"evenodd\">\n        <g transform=\"translate(24 31.67)\">\n          <ellipse class=\"ant-empty-img-default-ellipse\" cx=\"67.797\" cy=\"106.89\" rx=\"67.797\" ry=\"12.668\" />\n          <path\n            class=\"ant-empty-img-default-path-1\"\n            d=\"M122.034 69.674L98.109 40.229c-1.148-1.386-2.826-2.225-4.593-2.225h-51.44c-1.766 0-3.444.839-4.592 2.225L13.56 69.674v15.383h108.475V69.674z\"\n          />\n          <path\n            class=\"ant-empty-img-default-path-2\"\n            d=\"M101.537 86.214L80.63 61.102c-1.001-1.207-2.507-1.867-4.048-1.867H31.724c-1.54 0-3.047.66-4.048 1.867L6.769 86.214v13.792h94.768V86.214z\"\n            transform=\"translate(13.56)\"\n          />\n          <path\n            class=\"ant-empty-img-default-path-3\"\n            d=\"M33.83 0h67.933a4 4 0 0 1 4 4v93.344a4 4 0 0 1-4 4H33.83a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4z\"\n          />\n          <path\n            class=\"ant-empty-img-default-path-4\"\n            d=\"M42.678 9.953h50.237a2 2 0 0 1 2 2V36.91a2 2 0 0 1-2 2H42.678a2 2 0 0 1-2-2V11.953a2 2 0 0 1 2-2zM42.94 49.767h49.713a2.262 2.262 0 1 1 0 4.524H42.94a2.262 2.262 0 0 1 0-4.524zM42.94 61.53h49.713a2.262 2.262 0 1 1 0 4.525H42.94a2.262 2.262 0 0 1 0-4.525zM121.813 105.032c-.775 3.071-3.497 5.36-6.735 5.36H20.515c-3.238 0-5.96-2.29-6.734-5.36a7.309 7.309 0 0 1-.222-1.79V69.675h26.318c2.907 0 5.25 2.448 5.25 5.42v.04c0 2.971 2.37 5.37 5.277 5.37h34.785c2.907 0 5.277-2.421 5.277-5.393V75.1c0-2.972 2.343-5.426 5.25-5.426h26.318v33.569c0 .617-.077 1.216-.221 1.789z\"\n          />\n        </g>\n        <path\n          class=\"ant-empty-img-default-path-5\"\n          d=\"M149.121 33.292l-6.83 2.65a1 1 0 0 1-1.317-1.23l1.937-6.207c-2.589-2.944-4.109-6.534-4.109-10.408C138.802 8.102 148.92 0 161.402 0 173.881 0 184 8.102 184 18.097c0 9.995-10.118 18.097-22.599 18.097-4.528 0-8.744-1.066-12.28-2.902z\"\n        />\n        <g class=\"ant-empty-img-default-g\" transform=\"translate(149.65 15.383)\">\n          <ellipse cx=\"20.654\" cy=\"3.167\" rx=\"2.849\" ry=\"2.815\" />\n          <path d=\"M5.698 5.63H0L2.898.704zM9.259.704h4.985V5.63H9.259z\" />\n        </g>\n      </g>\n    </svg>\n  `\n})\nexport class NzEmptyDefaultComponent {}\n"
  },
  {
    "path": "components/empty/partial/simple.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-empty-simple',\n  exportAs: 'nzEmptySimple',\n  template: `\n    <svg class=\"ant-empty-img-simple\" width=\"64\" height=\"41\" viewBox=\"0 0 64 41\" xmlns=\"http://www.w3.org/2000/svg\">\n      <g transform=\"translate(0 1)\" fill=\"none\" fill-rule=\"evenodd\">\n        <ellipse class=\"ant-empty-img-simple-ellipse\" cx=\"32\" cy=\"33\" rx=\"32\" ry=\"7\" />\n        <g class=\"ant-empty-img-simple-g\" fill-rule=\"nonzero\">\n          <path\n            d=\"M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z\"\n          />\n          <path\n            d=\"M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z\"\n            class=\"ant-empty-img-simple-path\"\n          />\n        </g>\n      </g>\n    </svg>\n  `\n})\nexport class NzEmptySimpleComponent {}\n"
  },
  {
    "path": "components/empty/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './embed-empty.component';\nexport * from './empty.component';\nexport * from './empty.module';\nexport * from './config';\nexport { NzEmptySimpleComponent } from './partial/simple';\nexport { NzEmptyDefaultComponent } from './partial/default';\n"
  },
  {
    "path": "components/empty/style/entry.less",
    "content": "@import './index.less';\n@import \"./patch\";\n"
  },
  {
    "path": "components/empty/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@empty-prefix-cls: ~'@{ant-prefix}-empty';\n@empty-img-prefix-cls: ~'@{ant-prefix}-empty-img';\n\n.@{empty-prefix-cls} {\n  margin: 0 8px;\n  font-size: @empty-font-size;\n  line-height: @line-height-base;\n  text-align: center;\n\n  &-image {\n    height: 100px;\n    margin-bottom: 8px;\n\n    img {\n      height: 100%;\n    }\n\n    svg {\n      height: 100%;\n      margin: auto;\n    }\n  }\n\n  &-footer {\n    margin-top: 16px;\n  }\n\n  // antd internal empty style\n  &-normal {\n    margin: 32px 0;\n    color: @disabled-color;\n\n    .@{empty-prefix-cls}-image {\n      height: 40px;\n    }\n  }\n\n  &-small {\n    margin: 8px 0;\n    color: @disabled-color;\n\n    .@{empty-prefix-cls}-image {\n      height: 35px;\n    }\n  }\n}\n\n.@{empty-img-prefix-cls}-default {\n  // not support the definition because the less variables have no meaning\n  & when (@theme = dark) {\n    &-ellipse {\n      fill: @white;\n      fill-opacity: 0.08;\n    }\n\n    &-path {\n      &-1 {\n        fill: #262626;\n      }\n\n      &-2 {\n        fill: url('#linearGradient-1');\n      }\n\n      &-3 {\n        fill: #595959;\n      }\n\n      &-4 {\n        fill: #434343;\n      }\n\n      &-5 {\n        fill: #595959;\n      }\n    }\n\n    &-g {\n      fill: #434343;\n    }\n  }\n  & when not (@theme = dark) {\n    &-ellipse {\n      fill: #f5f5f5;\n      fill-opacity: 0.8;\n    }\n\n    &-path {\n      &-1 {\n        fill: #aeb8c2;\n      }\n\n      &-2 {\n        fill: url('#linearGradient-1');\n      }\n\n      &-3 {\n        fill: #f5f5f7;\n      }\n\n      &-4 {\n        fill: #dce0e6;\n      }\n\n      &-5 {\n        fill: #dce0e6;\n      }\n    }\n\n    &-g {\n      fill: @white;\n    }\n  }\n}\n\n.@{empty-img-prefix-cls}-simple {\n  // not support the definition because the less variables have no meaning\n  & when (@theme = dark) {\n    &-ellipse {\n      fill: @white;\n      fill-opacity: 0.08;\n    }\n\n    &-g {\n      stroke: #434343;\n    }\n\n    &-path {\n      fill: #262626;\n      stroke: #434343;\n    }\n  }\n  & when not (@theme = dark) {\n    &-ellipse {\n      fill: #f5f5f5;\n    }\n\n    &-g {\n      stroke: #d9d9d9;\n    }\n\n    &-path {\n      fill: #fafafa;\n    }\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/empty/style/patch.less",
    "content": "nz-empty {\n  display: block;\n}\n"
  },
  {
    "path": "components/empty/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@empty-prefix-cls: ~'@{ant-prefix}-empty';\n\n.@{empty-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n}\n"
  },
  {
    "path": "components/experimental/image/image-loader.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { isNil } from 'ng-zorro-antd/core/util';\n\nimport { NzImageSrcLoader } from './typings';\nimport { normalizeSrc } from './utils';\n\nexport const defaultImageSrcLoader: NzImageSrcLoader = ({ src }) => {\n  return src;\n};\n\n/**\n * AliObjectsLoader return format\n * {domain}/{src}?x-oss-process=image/resize,w_{width}\n */\nexport function createAliObjectsLoader(domain: string): NzImageSrcLoader {\n  return ({ src, width }) => {\n    const params = isNil(width) ? '' : `?x-oss-process=image/resize,w_${width}`;\n    return `${domain}/${normalizeSrc(src)}${params}`;\n  };\n}\n\n/**\n * ImgixLoader return format\n * {domain}/{src}?format=auto&fit=max&w={width}\n */\nexport function createImgixLoader(domain: string): NzImageSrcLoader {\n  return ({ src, width }) => {\n    const params = isNil(width) ? '' : `&fit=max&w=${width}`;\n    return `${domain}/${normalizeSrc(src)}?format=auto${params}`;\n  };\n}\n\n/**\n * CloudinaryLoader return format\n * {domain}/c_limit,q_auto,w_{width}/{src}\n */\nexport function createCloudinaryLoader(domain: string): NzImageSrcLoader {\n  return ({ src, width }) => {\n    const params = isNil(width) ? '' : `,w_${width}`;\n    return `${domain}/c_limit,q_auto${params}/${normalizeSrc(src)}`;\n  };\n}\n"
  },
  {
    "path": "components/experimental/image/image.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ElementRef,\n  Input,\n  OnChanges,\n  OnInit,\n  SimpleChanges,\n  ViewChild,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject,\n  DestroyRef\n} from '@angular/core';\n\nimport { NzConfigKey, onConfigChangeEventForComponent, WithConfig } from 'ng-zorro-antd/core/config';\nimport { warn } from 'ng-zorro-antd/core/logger';\nimport { ImagePreloadService, PreloadDisposeHandle } from 'ng-zorro-antd/core/services';\nimport { NzImageDirective } from 'ng-zorro-antd/image';\n\nimport { defaultImageSrcLoader } from './image-loader';\nimport { NzImageSrcLoader } from './typings';\nimport { isFixedSize } from './utils';\n\nexport const NZ_CONFIG_MODULE_NAME: NzConfigKey = 'imageExperimental';\nconst sizeBreakpoints = [16, 32, 48, 64, 96, 128, 256, 384, 640, 750, 828, 1080, 1200, 1920, 2048, 3840];\n\n@Component({\n  selector: 'nz-image',\n  exportAs: 'nzImage',\n  template: `\n    <img\n      #imageRef\n      nz-image\n      [nzSrc]=\"src\"\n      [nzSrcset]=\"srcset\"\n      [nzDisablePreview]=\"nzDisablePreview\"\n      [nzFallback]=\"nzFallback\"\n      [nzPlaceholder]=\"nzPlaceholder\"\n      [attr.width]=\"width\"\n      [attr.height]=\"height\"\n      [attr.srcset]=\"srcset\"\n      [attr.alt]=\"nzAlt || null\"\n    />\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  imports: [NzImageDirective]\n})\nexport class NzImageViewComponent implements OnInit, OnChanges {\n  private cdr = inject(ChangeDetectorRef);\n  private imagePreloadService = inject(ImagePreloadService);\n  private destroyRef = inject(DestroyRef);\n\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  @Input() nzSrc: string = '';\n  @Input() nzAlt: string = '';\n  @Input() nzWidth: string | number = 'auto';\n  @Input() nzHeight: string | number = 'auto';\n  @Input() @WithConfig() nzSrcLoader: NzImageSrcLoader = defaultImageSrcLoader;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzAutoSrcset: boolean = false;\n  @Input({ transform: booleanAttribute }) nzPriority: boolean = false;\n  @Input() @WithConfig() nzFallback: string | null = null;\n  @Input() @WithConfig() nzPlaceholder: string | null = null;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzDisablePreview: boolean = false;\n  @ViewChild('imageRef') imageRef!: ElementRef<HTMLImageElement>;\n\n  src = '';\n\n  width: string | number = 'auto';\n  height: string | number = 'auto';\n  srcset = '';\n\n  private reloadDisposeHandler: PreloadDisposeHandle = () => void 0;\n\n  constructor() {\n    onConfigChangeEventForComponent(NZ_CONFIG_MODULE_NAME, () => {\n      this.composeImageAttrs();\n      this.cdr.markForCheck();\n    });\n\n    this.destroyRef.onDestroy(() => {\n      this.reloadDisposeHandler();\n    });\n  }\n\n  ngOnInit(): void {\n    if (this.nzPriority) {\n      this.preload();\n    }\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzLoader, nzSrc, nzOptimize } = changes;\n\n    if (nzSrc || nzLoader || nzOptimize) {\n      this.composeImageAttrs();\n    }\n  }\n\n  private preload(): void {\n    this.reloadDisposeHandler = this.imagePreloadService.addPreload({\n      src: this.src,\n      srcset: this.srcset\n    });\n  }\n\n  private optimizable(): boolean {\n    if (this.nzAutoSrcset) {\n      if (!isFixedSize(this.nzWidth) || !isFixedSize(this.nzHeight)) {\n        warn(\n          `When using \"nzAutoSrcset\" you should use a fixed size width and height, for more information please refer to CLS (https://web.dev/cls/) performance metrics`\n        );\n        return false;\n      }\n      if (this.nzSrc.endsWith('.svg')) {\n        warn(`SVG does not need to be optimized`);\n        return false;\n      }\n      if (this.nzSrc.startsWith('data:')) {\n        warn(`Data URLs cannot be optimized`);\n        return false;\n      }\n      return true;\n    }\n    return false;\n  }\n\n  private composeImageAttrs(): void {\n    const loader = this.getLoader();\n    if (!this.optimizable()) {\n      this.src = loader({ src: this.nzSrc });\n      this.width = this.nzWidth;\n      this.height = this.nzHeight;\n      return;\n    }\n    this.width = typeof this.nzWidth === 'number' ? this.nzWidth : parseInt(this.nzWidth, 10);\n    this.height = typeof this.nzHeight === 'number' ? this.nzHeight : parseInt(this.nzHeight, 10);\n    const widths = this.convertWidths(this.width, sizeBreakpoints);\n    this.src = loader({ src: this.nzSrc, width: widths[0] });\n    this.srcset = widths\n      .map(\n        (w, i) =>\n          `${loader({\n            src: this.nzSrc,\n            width: w\n          })} ${i + 1}x`\n      )\n      .join(', ');\n  }\n\n  private getLoader(): NzImageSrcLoader {\n    return this.nzSrcLoader || defaultImageSrcLoader;\n  }\n\n  private convertWidths(width: number, optimizeSizes: number[]): number[] {\n    const allSizes = [...optimizeSizes].sort((a, b) => a - b);\n    return [\n      ...new Set(\n        // 2x scale is sufficient\n        // https://blog.twitter.com/engineering/en_us/topics/infrastructure/2019/capping-image-fidelity-on-ultra-high-resolution-devices.html\n        [width, width * 2].map(w => allSizes.find(p => p >= w) || w)\n      )\n    ];\n  }\n}\n"
  },
  {
    "path": "components/experimental/image/image.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzImageViewComponent } from './image.component';\n\n@NgModule({\n  imports: [NzImageViewComponent],\n  exports: [NzImageViewComponent]\n})\nexport class NzImageModule {}\n"
  },
  {
    "path": "components/experimental/image/image.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, DebugElement } from '@angular/core';\nimport { ComponentFixture, fakeAsync, TestBed } from '@angular/core/testing';\n\nimport {\n  createAliObjectsLoader,\n  createCloudinaryLoader,\n  createImgixLoader,\n  defaultImageSrcLoader,\n  isFixedSize,\n  normalizeSrc,\n  NzImageModule,\n  NzImageSrcLoader\n} from 'ng-zorro-antd/experimental/image';\nimport { NzImageService } from 'ng-zorro-antd/image';\n\ndescribe('Experimental', () => {\n  let fixture: ComponentFixture<TestImageExperimentalBaseComponent>;\n  let context: TestImageExperimentalBaseComponent;\n  let debugElement: DebugElement;\n\n  beforeEach(fakeAsync(() => {\n    TestBed.configureTestingModule({\n      providers: [NzImageService]\n    });\n  }));\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(TestImageExperimentalBaseComponent);\n    context = fixture.componentInstance;\n    debugElement = fixture.debugElement;\n  });\n\n  it('should be no srcset attribute by default', () => {\n    const _src = 'test.jpg';\n    const _encode = encodeURIComponent(_src);\n    context.src = _src;\n    fixture.detectChanges();\n    const image = debugElement.nativeElement.querySelector('img') as HTMLImageElement;\n    expect(image.src).toContain(_encode);\n    expect(image.srcset).toBe('');\n  });\n\n  it('should nzAutoSrcset work', () => {\n    const _src = 'test.jpg';\n    const _encode = encodeURIComponent(_src);\n    context.src = _src;\n    context.autoSrc = true;\n    fixture.detectChanges();\n    const image = debugElement.nativeElement.querySelector('img') as HTMLImageElement;\n    expect(image.src).toContain(_encode);\n    expect(image.srcset).toBe(`${_encode} 1x, ${_encode} 2x`);\n  });\n\n  it('should nzSrcLoader work', () => {\n    const _src = 'test.jpg';\n    const _width = 100;\n    const _loader: NzImageSrcLoader = ({ src, width }) => `${src}?w=${width}`;\n    context.src = _src;\n    context.width = _width;\n    context.autoSrc = true;\n    context.loader = _loader;\n    fixture.detectChanges();\n    const image = debugElement.nativeElement.querySelector('img') as HTMLImageElement;\n    expect(image.src).toContain(`${_src}`);\n    expect(image.srcset).toBe(`${_src}?w=128 1x, ${_src}?w=256 2x`);\n  });\n});\n\ndescribe('Utils', () => {\n  describe('isFixedSize', () => {\n    it('should allow px unit', () => {\n      expect(isFixedSize('12px')).toBe(true);\n      expect(isFixedSize('px')).toBe(false);\n      expect(isFixedSize('')).toBe(false);\n    });\n    it('should allow number', () => {\n      expect(isFixedSize('12')).toBe(true);\n      expect(isFixedSize(12)).toBe(true);\n    });\n  });\n\n  describe('normalizeSrc', () => {\n    it('should normalize src', () => {\n      expect(normalizeSrc('/image.jpg')).toBe('image.jpg');\n      expect(normalizeSrc('image.jpg')).toBe('image.jpg');\n    });\n  });\n});\n\ndescribe('NzSrcLoader', () => {\n  const src = 'test.jpg';\n  const width = 100;\n\n  it('#aliObjectsLoader', () => {\n    const aliObjectsLoader = createAliObjectsLoader('https://zos.alipayobjects.com/rmsportal');\n    expect(\n      aliObjectsLoader({\n        src,\n        width\n      })\n    ).toBe(`https://zos.alipayobjects.com/rmsportal/${src}?x-oss-process=image/resize,w_${width}`);\n    expect(aliObjectsLoader({ src })).toBe(`https://zos.alipayobjects.com/rmsportal/${src}`);\n  });\n\n  it('#imgixLoader', () => {\n    const imgixLoader = createImgixLoader('https://static.imgix.net');\n    expect(imgixLoader({ src, width })).toBe(`https://static.imgix.net/${src}?format=auto&fit=max&w=${width}`);\n    expect(imgixLoader({ src })).toBe(`https://static.imgix.net/${src}?format=auto`);\n  });\n\n  it('#cloudinaryLoader', () => {\n    const cloudinaryLoader = createCloudinaryLoader('https://res.cloudinary.com/demo/image/upload');\n    expect(\n      cloudinaryLoader({\n        src,\n        width\n      })\n    ).toBe(`https://res.cloudinary.com/demo/image/upload/c_limit,q_auto,w_${width}/${src}`);\n    expect(cloudinaryLoader({ src })).toBe(`https://res.cloudinary.com/demo/image/upload/c_limit,q_auto/${src}`);\n  });\n});\n\n@Component({\n  imports: [NzImageModule],\n  template: `\n    <nz-image\n      [nzSrc]=\"src\"\n      [nzAutoSrcset]=\"autoSrc\"\n      [nzSrcLoader]=\"loader\"\n      [nzWidth]=\"width\"\n      nzHeight=\"200\"\n      nzAlt=\"test\"\n    />\n  `\n})\nexport class TestImageExperimentalBaseComponent {\n  src = '';\n  autoSrc = false;\n  loader = defaultImageSrcLoader;\n  width = 200;\n}\n"
  },
  {
    "path": "components/experimental/image/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/experimental/image/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/experimental/image/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './image.component';\nexport * from './image-loader';\nexport * from './image.module';\nexport * from './typings';\nexport * from './utils';\n"
  },
  {
    "path": "components/experimental/image/typings.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport type NzImageSrcLoader = (params: { src: string; width?: number }) => string;\n"
  },
  {
    "path": "components/experimental/image/utils.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport function isFixedSize(size: number | string): boolean {\n  return typeof size === 'number' || /^(\\d)+(px)?$/.test(size);\n}\n\nexport function normalizeSrc(src: string): string {\n  return src[0] === '/' ? src.slice(1) : src;\n}\n"
  },
  {
    "path": "components/experimental-image/demo/auto-srcset.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 自动填充 srcset\n  en-US: Auto Srcset\n---\n\n## zh-CN\n\n使用 `nzAutoSrcset` 时要求必须定义图片尺寸(`nzWidth`、`nzHeight`)，配合 Loader 为不同的像素密度自动生成 [srcset](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/srcset)。\n\n## en-US\n\nUsing `nzAutoSrcset` requires to specify the image size (`nzWidth`, `nzHeight`), with the Loader automatically generating [srcset](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/srcset) for different pixel densities.\n"
  },
  {
    "path": "components/experimental-image/demo/auto-srcset.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { createAliObjectsLoader, NzImageModule as NzExperimentalImageModule } from 'ng-zorro-antd/experimental/image';\nimport { NzImageModule } from 'ng-zorro-antd/image';\n\n@Component({\n  selector: 'nz-demo-experimental-image-auto-srcset',\n  imports: [NzImageModule, NzExperimentalImageModule],\n  template: `<nz-image [nzSrc]=\"src\" nzWidth=\"200\" nzHeight=\"200\" [nzSrcLoader]=\"loader\" nzAutoSrcset />`\n})\nexport class NzDemoExperimentalImageAutoSrcsetComponent {\n  src = 'jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png';\n  loader = createAliObjectsLoader('https://zos.alipayobjects.com/rmsportal');\n}\n"
  },
  {
    "path": "components/experimental-image/demo/preloading.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 优先加载\n  en-US: Priority\n---\n\n## zh-CN\n\n设置 `nzPriority` 将会在服务端渲染(SSR) 时添加 `<link rel=\"preload\">` 标签，浏览器会将其视为高优先级资源加载。你可以在 [MDN - Preloading](https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content)、[web.dev - Preloading responsive images](https://web.dev/preload-responsive-images/) 了解更多。\n\n需要注意的是，通常只需要为首屏图片设置 `nzPriority` 因此在循环生成的模版中只需要为靠前的子项添加即可，例如：\n\n```html\n@for (product of products; track product)\n<nz-image [nzPriority]=\"$index <= 8\"></nz-image>\n}\n```\n\n## en-US\n\nSetting `nzPriority` will add the `<link rel=\"preload\">` tag when rendering server-side (SSR), and browsers will treat it as a high priority resource to load. You can see this in [MDN - Preloading](https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content), [web.dev - Preloading responsive images](https://web.dev/preload-responsive-images/) to learn more.\n\nNote: usually we only need to set `nzPriority` for the first screen images, so you only need to add it for the first few items in the cyclically generated template, e.g.\n\n```html\n@for (product of products; track product)\n<nz-image [nzPriority]=\"$index <= 8\"></nz-image>\n}\n```\n"
  },
  {
    "path": "components/experimental-image/demo/preloading.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzImageModule as NzExperimentalImageModule } from 'ng-zorro-antd/experimental/image';\nimport { NzImageModule } from 'ng-zorro-antd/image';\n\n@Component({\n  selector: 'nz-demo-experimental-image-preloading',\n  imports: [NzImageModule, NzExperimentalImageModule],\n  template: `<nz-image [nzSrc]=\"src\" nzWidth=\"200\" nzHeight=\"200\" nzPriority />`\n})\nexport class NzDemoExperimentalImagePreloadingComponent {\n  src = 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png';\n}\n"
  },
  {
    "path": "components/experimental-image/demo/src-loader.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 使用 Src Loader\n  en-US: Use Src Loader\n---\n\n## zh-CN\n\n自定义 `nzSrcLoader` 用于解析图片 URLs, 也可以使用内置的图片 CND 提供商的 Loaders。\n<br/>\n我们建议始终指定图片的尺寸(`nzWidth`、`nzHeight`)，不仅可以帮助提高网页体验的关键指标 [CLS](https://web.dev/cls/)，还可以配合 Loader 利用图片 CND 对图片进行优化处理提高加载速度。\n<br/>\n如果希望在不同的环境下使用不同的 Loader 时你可以像下面这样做：\n\n```ts\nimport { environment } from 'environments/environment';\n\nimport { NzConfig, provideNzConfig } from 'ng-zorro-antd/core/config';\nimport { aliObjectsLoader, defaultImageSrcLoader } from 'ng-zorro-antd/experimental/image';\n\nconst nzConfig: NzConfig = {\n  imageExperimental: {\n    nzSrcLoader: environment.production ? aliObjectsLoader : defaultImageSrcLoader\n  }\n};\n\nexport const appConfig: ApplicationConfig = {\n  providers: [provideNzConfig(nzConfig)]\n};\n```\n\n## en-US\n\nCustom `nzSrcLoader` is used to resolve image URLs, or you can also use the built-in image CND provider's Loaders.\n<br/>\nWe recommend always specifying the image size (`nzWidth`, `nzHeight`), which can help improve the key metrics of the web experience [CLS](https://web.dev/cls/), and can also be used with the Loader to optimize the images using the image CND to improve the loading speed.\n<br/>\nIf you want to use a different Loader in a different environment you can do the following.\n\n```ts\nimport { environment } from 'environments/environment';\n\nimport { NzConfig, provideNzConfig } from 'ng-zorro-antd/core/config';\nimport { createAliObjectsLoader, defaultImageSrcLoader } from 'ng-zorro-antd/experimental/image';\n\nconst nzConfig: NzConfig = {\n  imageExperimental: {\n    nzSrcLoader: environment.production\n      ? createAliObjectsLoader('https://zos.alipayobjects.com/rmsportal')\n      : defaultImageSrcLoader\n  }\n};\n\nexport const appConfig: ApplicationConfig = {\n  providers: [provideNzConfig(nzConfig)]\n};\n```\n"
  },
  {
    "path": "components/experimental-image/demo/src-loader.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { createAliObjectsLoader, NzImageModule as NzExperimentalImageModule } from 'ng-zorro-antd/experimental/image';\nimport { NzImageModule } from 'ng-zorro-antd/image';\n\n@Component({\n  selector: 'nz-demo-experimental-image-src-loader',\n  imports: [NzImageModule, NzExperimentalImageModule],\n  template: `<nz-image [nzSrc]=\"src\" nzWidth=\"200\" nzHeight=\"200\" [nzSrcLoader]=\"loader\" />`\n})\nexport class NzDemoExperimentalImageSrcLoaderComponent {\n  src = 'jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png';\n  loader = createAliObjectsLoader('https://zos.alipayobjects.com/rmsportal');\n}\n"
  },
  {
    "path": "components/experimental-image/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Display\ntitle: Image\ncols: 1\nexperimental: true\ndescription: Experimental image component.\n---\n\n## When To Use\n\n- When you need the browser to prioritize image loading (needs to be handled in SSR).\n- When you need to optimize for HD displays (e.g. retina screens).\n- When using image CDN.\n- More in [Image documentation](/components/image/en)\n- Next steps\n  - Add [sizes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-sizes) attribute and responsive support.\n\n## API\n\n### nz-image\n\n| Property       | Description                                                                                               | Type               | Default                 | Global Config |\n| -------------- | --------------------------------------------------------------------------------------------------------- | ------------------ | ----------------------- | ------------- |\n| `nzSrc`        | URL                                                                                                       | `string`           | -                       |               |\n| `nzAlt`        | Alt                                                                                                       | `string`           | -                       |               |\n| `nzWidth`      | Width                                                                                                     | `number\\|string`   | `auto`                  |               |\n| `nzHeight`     | Height                                                                                                    | `number\\|string`   | `auto`                  |               |\n| `nzAutoSrcset` | Whether to optimize image loading                                                                         | `boolean`          | `false`                 | ✅            |\n| `nzSrcLoader`  | Loader                                                                                                    | `NzImageSrcLoader` | `defaultImageSrcLoader` | ✅            |\n| `nzPriority`   | Whether to add [preload](https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content) (only SSR) | `boolean`          | `false`                 | ✅            |\n\n### NzImageSrcLoader\n\n```ts\nexport type NzImageSrcLoader = (params: { src: string; width: number }) => string;\n```\n\n## Note\n\n### nzSrcLoader\n\nUsing `nzSrcLoader` helps you to fill in key information about the requested image, such as `src` and `width`, which defaults to\n\n```ts\nexport const defaultImageSrcLoader: NzImageSrcLoader = ({ src }) => {\n  return src;\n};\n```\n\nBuilt-in image CND creation method\n\n```ts\n/**\n * AliObjectsLoader return format\n * {domain}/{src}?x-oss-process=image/resize,w_{width}\n */\nexport function createAliObjectsLoader(domain: string): NzImageSrcLoader;\n\n/**\n * ImgixLoader return format\n * {domain}/{src}?format=auto&fit=max&w={width}\n */\nexport function createImgixLoader(domain: string): NzImageSrcLoader;\n\n/**\n * CloudinaryLoader return format\n * {domain}/c_limit,q_auto,w_{width}/{src}\n */\nexport function createCloudinaryLoader(domain: string): NzImageSrcLoader;\n```\n\n### Responsive images and preloaded images\n\nUsing responsive images can help web pages display well on different devices. Preloading images can help you load images faster, for more information please refer to.\n\n- [preloading responsive images](https://web.dev/preload-responsive-images/)\n- [next.js image component and image optimization](https://nextjs.org/docs/basic-features/image-optimization)\n"
  },
  {
    "path": "components/experimental-image/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 图片\ntype: 数据展示\ntitle: Image\ncols: 1\nexperimental: true\ndescription: 实验性的图片组件。\n---\n\n## 何时使用\n\n- 需要浏览器优先加载图片时（需要在 SSR 下处理）。\n- 需要对高清显示器（如视网膜屏）优化时。\n- 使用图片 CDN 服务时。\n- 以及 [Image documentation](/components/image/zh) 中的功能\n- 下一步计划\n  - 添加 [sizes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-sizes) 属性及响应式的支持\n\n## API\n\n### nz-image\n\n| 参数           | 说明                                                                                     | 类型               | 默认值                  | 支持全局配置 |\n| -------------- | ---------------------------------------------------------------------------------------- | ------------------ | ----------------------- | ------------ |\n| `nzSrc`        | url                                                                                      | `string`           | -                       |              |\n| `nzAlt`        | alt                                                                                      | `string`           | -                       |              |\n| `nzWidth`      | 宽度                                                                                     | `number\\|string`   | `auto`                  |              |\n| `nzHeight`     | 高度                                                                                     | `number\\|string`   | `auto`                  |              |\n| `nzAutoSrcset` | 是否优化图片加载                                                                         | `boolean`          | `false`                 | ✅           |\n| `nzSrcLoader`  | 加载器                                                                                   | `NzImageSrcLoader` | `defaultImageSrcLoader` | ✅           |\n| `nzPriority`   | 是否添加 [preload](https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content) | `boolean`          | `false`                 |              |\n\n### NzImageSrcLoader\n\n```ts\nexport type NzImageSrcLoader = (params: { src: string; width: number }) => string;\n```\n\n## 注意\n\n### nzSrcLoader\n\n使用 `nzSrcLoader` 可以帮助你填充请求图片的关键信息，例如 `src` 和 `srcset`，默认为：\n\n```ts\nexport const defaultImageSrcLoader: NzImageSrcLoader = ({ src }) => {\n  return src;\n};\n```\n\n内置的图片 CND 创建方法\n\n```ts\n/**\n * AliObjectsLoader return format\n * {domain}/{src}?x-oss-process=image/resize,w_{width}\n */\nexport function createAliObjectsLoader(domain: string): NzImageSrcLoader;\n\n/**\n * ImgixLoader return format\n * {domain}/{src}?format=auto&fit=max&w={width}\n */\nexport function createImgixLoader(domain: string): NzImageSrcLoader;\n\n/**\n * CloudinaryLoader return format\n * {domain}/c_limit,q_auto,w_{width}/{src}\n */\nexport function createCloudinaryLoader(domain: string): NzImageSrcLoader;\n```\n\n### 响应式图片和预加载图片\n\n使用响应式图片可以帮助网页在不同的设备上显示良好的效果，预加载图片可以帮助你更快地加载图片，更多信息请参考：\n\n- [preloading responsive images](https://web.dev/preload-responsive-images/)\n- [next.js image component and image optimization](https://nextjs.org/docs/basic-features/image-optimization)\n"
  },
  {
    "path": "components/flex/demo/align.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 对齐方式\n  en-US: Align\n---\n\n## zh-CN\n\n设置对齐方式。\n\n## en-US\n\nSet align.\n"
  },
  {
    "path": "components/flex/demo/align.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzAlign, NzFlexModule, NzJustify } from 'ng-zorro-antd/flex';\nimport { NzSegmentedModule } from 'ng-zorro-antd/segmented';\n\n@Component({\n  selector: 'nz-demo-flex-align',\n  imports: [FormsModule, NzButtonModule, NzFlexModule, NzSegmentedModule],\n  template: `\n    <div class=\"segment-wrapper\">\n      <span>Select justify:</span>\n      <nz-segmented [nzOptions]=\"justifySegment\" [(ngModel)]=\"selectedJustification\" />\n    </div>\n\n    <div class=\"segment-wrapper\">\n      <span>Select align:</span>\n      <nz-segmented [nzOptions]=\"alignSegment\" [(ngModel)]=\"selectedLAlignment\" />\n    </div>\n\n    <div class=\"btn-wrappers\" nz-flex [nzJustify]=\"selectedJustification\" [nzAlign]=\"selectedLAlignment\">\n      <button nz-button nzType=\"primary\">Primary</button>\n      <button nz-button nzType=\"primary\">Primary</button>\n      <button nz-button nzType=\"primary\">Primary</button>\n      <button nz-button nzType=\"primary\">Primary</button>\n    </div>\n  `,\n  styles: `\n    .segment-wrapper {\n      display: flex;\n      align-items: center;\n      gap: 1rem;\n\n      margin-block-end: 1rem;\n    }\n\n    .btn-wrappers {\n      block-size: 10rem;\n      border: 1px solid var(--ant-primary-6);\n    }\n  `\n})\nexport class NzDemoFlexAlignComponent {\n  public justifySegment: NzJustify[] = [\n    'flex-start',\n    'center',\n    'flex-end',\n    'space-between',\n    'space-around',\n    'space-evenly'\n  ];\n  public alignSegment: NzAlign[] = ['flex-start', 'center', 'flex-end'];\n  public selectedJustification: NzJustify = 'flex-start';\n  public selectedLAlignment: NzAlign = 'flex-start';\n}\n"
  },
  {
    "path": "components/flex/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本布局\n  en-US: Basic\n---\n\n## zh-CN\n\n最简单的用法。\n\n## en-US\n\nThe basic usage.\n"
  },
  {
    "path": "components/flex/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzFlexModule } from 'ng-zorro-antd/flex';\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\n\n@Component({\n  selector: 'nz-demo-flex-basic',\n  imports: [FormsModule, NzFlexModule, NzRadioModule],\n  template: `\n    <nz-radio-group [(ngModel)]=\"isVertical\">\n      <label nz-radio [nzValue]=\"false\">horizontal</label>\n      <label nz-radio [nzValue]=\"true\">vertical</label>\n    </nz-radio-group>\n\n    <div nz-flex [nzVertical]=\"isVertical\">\n      <div class=\"flex-item\"></div>\n      <div class=\"flex-item even\"></div>\n      <div class=\"flex-item\"></div>\n      <div class=\"flex-item even\"></div>\n    </div>\n  `,\n  styles: `\n    nz-radio-group {\n      margin-block-end: 1rem;\n    }\n\n    .flex-item {\n      inline-size: 25%;\n      block-size: 54px;\n      background-color: var(--ant-primary-6);\n    }\n\n    .even {\n      background-color: var(--ant-primary-5);\n    }\n  `\n})\nexport class NzDemoFlexBasicComponent {\n  isVertical = false;\n}\n"
  },
  {
    "path": "components/flex/demo/combination.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 组合使用\n  en-US: Combination\n---\n\n## zh-CN\n\n嵌套使用，可以实现更复杂的布局。\n\n## en-US\n\nNesting can achieve more complex layouts.\n"
  },
  {
    "path": "components/flex/demo/combination.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzFlexModule } from 'ng-zorro-antd/flex';\n\n@Component({\n  selector: 'nz-demo-flex-combination',\n  imports: [NzFlexModule],\n  template: `\n    <div class=\"combination-wrapper\" nz-flex [nzGap]=\"80\">\n      <img\n        alt=\"Angular\"\n        width=\"150\"\n        height=\"150\"\n        src=\"https://img.alicdn.com/tfs/TB1g.mWZAL0gK0jSZFtXXXQCXXa-200-200.svg\"\n      />\n\n      <div nz-flex [nzVertical]=\"true\" nzGap=\"large\">\n        <h2> Ant Design of Angular </h2>\n\n        <h3>\n          An enterprise-class Angular UI component library based on Ant Design, all components are open source and free\n          to use under MIT license.\n        </h3>\n      </div>\n    </div>\n  `,\n  styles: `\n    .combination-wrapper {\n      inline-size: 40rem;\n      padding: 2rem;\n      border: 1px solid #f0f0f0;\n      border-radius: 2px;\n    }\n  `\n})\nexport class NzDemoFlexCombinationComponent {}\n"
  },
  {
    "path": "components/flex/demo/gap.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 设置间隙\n  en-US: Gap\n---\n\n## zh-CN\n\n使用 `gap` 设置元素之间的间距，预设了 `small`、`middle`、`large` 三种尺寸，也可以自定义间距。\n\n## en-US\n\nSet the `gap` between elements, which has three preset sizes: `small`, `middle`, `large`, You can also customize the gap size.\n"
  },
  {
    "path": "components/flex/demo/gap.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzFlexModule } from 'ng-zorro-antd/flex';\nimport { NzSegmentedModule } from 'ng-zorro-antd/segmented';\nimport { NzSliderModule } from 'ng-zorro-antd/slider';\n\n@Component({\n  selector: 'nz-demo-flex-gap',\n  imports: [FormsModule, NzButtonModule, NzFlexModule, NzSegmentedModule, NzSliderModule],\n  template: `\n    <div class=\"segment-wrapper\">\n      <span>Select gap:</span>\n      <nz-segmented [nzOptions]=\"gapSegment\" [(ngModel)]=\"selectedGap\" />\n    </div>\n    @if (selectedGap === 'custom') {\n      <nz-slider [nzMin]=\"0\" [nzMax]=\"100\" [(ngModel)]=\"customGapValue\" />\n    }\n    <div nz-flex [nzGap]=\"selectedGap === 'custom' ? customGapValue : selectedGap\">\n      <button nz-button nzType=\"primary\">Primary</button>\n      <button nz-button nzType=\"dashed\">Dashed</button>\n      <button nz-button nzType=\"default\">Default</button>\n      <button nz-button nzType=\"link\">Link</button>\n    </div>\n  `,\n  styles: `\n    .segment-wrapper {\n      display: flex;\n      align-items: center;\n      gap: 1rem;\n\n      margin-block-end: 1rem;\n    }\n  `\n})\nexport class NzDemoFlexGapComponent {\n  public gapSegment: string[] = ['small', 'middle', 'large', 'custom'];\n  public selectedGap = 'small';\n  public customGapValue = 0;\n}\n"
  },
  {
    "path": "components/flex/demo/wrap.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 自动换行\n  en-US: Wrap\n---\n\n## zh-CN\n\n自动换行。\n\n## en-US\n\nWrap line.\n"
  },
  {
    "path": "components/flex/demo/wrap.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzFlexModule, NzWrap } from 'ng-zorro-antd/flex';\nimport { NzSegmentedModule } from 'ng-zorro-antd/segmented';\n\n@Component({\n  selector: 'nz-demo-flex-wrap',\n  imports: [FormsModule, NzButtonModule, NzFlexModule, NzSegmentedModule],\n  template: `\n    <div class=\"segment-wrapper\">\n      <span>Select wrap:</span>\n      <nz-segmented [nzOptions]=\"wrapSegment\" [(ngModel)]=\"selectedWrap\" />\n    </div>\n    <div class=\"btn-wrapper\" nz-flex nzGap=\"middle\" [nzWrap]=\"selectedWrap\">\n      @for (_ of array; track _) {\n        <button style=\"width: 100px\" nz-button nzType=\"primary\">Button {{ _ }}</button>\n      }\n    </div>\n  `,\n  styles: `\n    .segment-wrapper {\n      display: flex;\n      align-items: center;\n      gap: 1rem;\n\n      margin-block-end: 1rem;\n    }\n\n    .btn-wrapper {\n      overflow: auto;\n      padding-block: 10px;\n    }\n  `\n})\nexport class NzDemoFlexWrapComponent {\n  wrapSegment: NzWrap[] = ['wrap', 'wrap-reverse', 'nowrap'];\n  selectedWrap: NzWrap = 'wrap';\n  array = Array.from({ length: 20 }, (_, index) => index + 1);\n}\n"
  },
  {
    "path": "components/flex/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Layout\ncols: 1\ntitle: Flex\ncover: 'https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*SMzgSJZE_AwAAAAAAAAAAAAADrJ8AQ/original'\ntag: 17.1.0\ndescription: A flex layout container for alignment.\n---\n\n## When To Use\n\n- Good for setting spacing between elements.\n- Suitable for setting various horizontal and vertical alignments.\n\n### Difference with Space component\n\n- Space is used to set the spacing between inline elements. It will add a wrapper element for each child element for\n  inline alignment. Suitable for equidistant arrangement of multiple child elements in rows and columns.\n- Flex is used to set the layout of block-level elements. It does not add a wrapper element. Suitable for layout of\n  child elements in vertical or horizontal direction, and provides more flexibility and control.\n\n## API\n\n### [nz-flex]\n\n| Property       | Description                                                                | Type                                                                                          | Default    |\n| -------------- | -------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | ---------- |\n| `[nzVertical]` | Is direction of the flex vertical, use `flex-direction: column`            | `boolean`                                                                                     | `false`    |\n| `[nzJustify]`  | Sets the alignment of elements in the direction of the main axis           | reference [justify-content](https://developer.mozilla.org/en-US/docs/Web/CSS/justify-content) | `'normal'` |\n| `[nzAlign]`    | Sets the alignment of elements in the direction of the cross axis          | reference [align-items](https://developer.mozilla.org/en-US/docs/Web/CSS/align-items)         | `'normal'` |\n| `[nzGap]`      | Sets the gap between items                                                 | `'small' \\| 'middle' \\| 'large' \\| number \\| string`                                          | `0`        |\n| `[nzWrap]`     | Set whether the element is displayed in a single line or in multiple lines | reference [flex-wrap](https://developer.mozilla.org/en-US/docs/Web/CSS/flex-wrap)             | `'nowrap'` |\n| `[nzFlex]`     | Flex CSS shorthand properties                                              | reference [flex](https://developer.mozilla.org/en-US/docs/Web/CSS/flex)                       | `'unset'`  |\n"
  },
  {
    "path": "components/flex/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 弹性布局\ntype: 布局\ncols: 1\ntitle: Flex\ncover: 'https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*SMzgSJZE_AwAAAAAAAAAAAAADrJ8AQ/original'\ntag: 17.1.0\ndescription: 用于对齐的弹性布局容器。\n---\n\n## 何时使用\n\n- 适合设置元素之间的间距。\n- 适合设置各种水平、垂直对齐方式。\n\n### 与 Space 组件的区别\n\n- Space 为内联元素提供间距，其本身会为每一个子元素添加包裹元素用于内联对齐。适用于行、列中多个子元素的等距排列。\n- Flex 为块级元素提供间距，其本身不会添加包裹元素。适用于垂直或水平方向上的子元素布局，并提供了更多的灵活性和控制能力。\n\n## API\n\n### [nz-flex]\n\n| 参数           | 说明                                                                                                                     | 类型                                                 | 默认值     |\n| -------------- | ------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------- | ---------- |\n| `[nzVertical]` | 使用 `flex-direction: column`描述flex的垂直方向                                                                          | `boolean`                                            | `false`    |\n| `[nzJustify]`  | 设置元素在主轴方向上的对齐方式，参照 [justify-content](https://developer.mozilla.org/zh-CN/docs/Web/CSS/justify-content) | `NzJustify`                                          | `'normal'` |\n| `[nzAlign]`    | 设置元素在交叉轴方向上的对齐方式，参照 [align-items](https://developer.mozilla.org/zh-CN/docs/Web/CSS/align-items)       | `NzAlign`                                            | `'normal'` |\n| `[nzGap]`      | 设置项目的间隙                                                                                                           | `'small' \\| 'middle' \\| 'large' \\| number \\| string` | `0`        |\n| `[nzWrap]`     | 指定 flex 元素单行显示还是多行显示，参照 [flex-wrap](https://developer.mozilla.org/zh-CN/docs/Web/CSS/flex-wrap)         | `NzWrap`                                             | `'nowrap'` |\n| `[nzFlex]`     | flex css简写属性，参照 [flex](https://developer.mozilla.org/zh-CN/docs/Web/CSS/flex)                                     | `NzFlex`                                             | `'unset'`  |\n"
  },
  {
    "path": "components/flex/flex.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzFlexDirective } from './nz-flex.directive';\n\n@NgModule({\n  imports: [NzFlexDirective],\n  exports: [NzFlexDirective]\n})\nexport class NzFlexModule {}\n"
  },
  {
    "path": "components/flex/flex.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport {\n  NzAlign,\n  NzCustomGap,\n  NzFlex,\n  NzFlexBasis,\n  NzFlexGrow,\n  NzFlexShrink,\n  NzGap,\n  NzJustify,\n  NzWrap\n} from 'ng-zorro-antd/flex';\nimport { NzFlexModule } from 'ng-zorro-antd/flex/flex.module';\nimport { NzFlexDirective } from 'ng-zorro-antd/flex/nz-flex.directive';\n\ndescribe('flex', () => {\n  let fixture: ComponentFixture<TestFlexComponent>;\n  let component: TestFlexComponent;\n  let element: HTMLElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(TestFlexComponent);\n    element = fixture.debugElement.query(By.directive(NzFlexDirective)).nativeElement;\n    component = fixture.componentInstance;\n    fixture.detectChanges();\n  });\n\n  it('should apply className', () => {\n    expect(element.className).toContain('ant-flex');\n  });\n\n  it('should have correct direction', () => {\n    component.isVertical = false;\n    fixture.detectChanges();\n    expect(element.className).not.toContain('vertical');\n    component.isVertical = true;\n    fixture.detectChanges();\n    expect(element.className).toContain('vertical');\n  });\n\n  it('should have correct justification value', () => {\n    const listOfJustifications: NzJustify[] = [\n      'flex-start',\n      'center',\n      'flex-end',\n      'space-between',\n      'space-around',\n      'space-evenly',\n      'start',\n      'end',\n      'right',\n      'left',\n      'stretch',\n      'normal'\n    ];\n    listOfJustifications.forEach(justification => {\n      component.justify = justification;\n      fixture.detectChanges();\n      expect(element.className).toContain(justification);\n    });\n  });\n\n  it('should have correct alignment value', () => {\n    const listOfAlignments: NzAlign[] = ['flex-start', 'center', 'flex-end', 'start', 'end', 'stretch', 'normal'];\n    listOfAlignments.forEach(alignment => {\n      component.align = alignment;\n      fixture.detectChanges();\n      expect(element.className).toContain(alignment);\n    });\n  });\n\n  it('should have correct gap value', () => {\n    const listOfGaps: NzGap[] = ['small', 'middle', 'large', 10, 20, 30, 40];\n    listOfGaps.forEach(gap => {\n      component.gap = gap;\n      fixture.detectChanges();\n      let gapValue: string;\n      switch (gap) {\n        case 'small':\n          gapValue = '8px';\n          break;\n        case 'middle':\n          gapValue = '16px';\n          break;\n        case 'large':\n          gapValue = '24px';\n          break;\n        default:\n          gapValue = `${gap}px`;\n      }\n\n      expect(getComputedStyle(element).getPropertyValue('gap')).toEqual(gapValue);\n    });\n\n    component.gap = '10rem';\n    fixture.detectChanges();\n    expect(getComputedStyle(element).getPropertyValue('gap')).toEqual(`${10 * 16}px`);\n  });\n\n  it('should have correct wrap value', () => {\n    const listOfWraps: NzWrap[] = ['wrap', 'nowrap', 'wrap-reverse'];\n    listOfWraps.forEach(wrap => {\n      component.wrap = wrap;\n      fixture.detectChanges();\n      expect(element.className).toContain(`flex-wrap-${wrap}`);\n    });\n  });\n\n  it('should have correct flex value', () => {\n    const listOfFlexes: NzFlex[] = ['0 0 auto', '1 1 100%', '0 1 50px'];\n    listOfFlexes.forEach(flex => {\n      component.flex = flex;\n      fixture.detectChanges();\n      expect(getComputedStyle(element).getPropertyValue('flex')).toEqual(flex);\n    });\n\n    component.flex = '1 0 50rem';\n    fixture.detectChanges();\n    expect(getComputedStyle(element).getPropertyValue('flex')).toEqual('1 0 800px');\n  });\n\n  it('should have initial value for nzVertical', () => {\n    expect(element.className).not.toContain('vertical');\n  });\n\n  it('should have initial value for justification', () => {\n    expect(element.className).toContain('normal');\n  });\n\n  it('should have initial value for alignment', () => {\n    expect(element.className).toContain('normal');\n  });\n\n  it('should have initial value for gap', () => {\n    expect(getComputedStyle(element).getPropertyValue('gap')).toEqual('0px');\n  });\n\n  it('should have initial value for wrap', () => {\n    expect(element.className).toContain('nowrap');\n  });\n\n  it('should have initial value for flex', () => {\n    expect(getComputedStyle(element).getPropertyValue('--flex')).toEqual('');\n  });\n});\n\n@Component({\n  imports: [NzFlexModule],\n  template: `\n    <div\n      nz-flex\n      [nzVertical]=\"isVertical\"\n      [nzJustify]=\"justify\"\n      [nzAlign]=\"align\"\n      [nzGap]=\"gap\"\n      [nzWrap]=\"wrap\"\n      [nzFlex]=\"flex\"\n    >\n      <div></div>\n      <div></div>\n      <div></div>\n    </div>\n  `\n})\nexport class TestFlexComponent {\n  isVertical = false;\n  justify: NzJustify = 'normal';\n  align: NzAlign = 'normal';\n  gap: 'small' | 'middle' | 'large' | NzCustomGap = 0;\n  wrap: 'wrap' | 'nowrap' | 'wrap-reverse' = 'nowrap';\n  flex: `${NzFlexShrink} ${NzFlexGrow} ${NzFlexBasis}` | 'unset' = 'unset';\n}\n"
  },
  {
    "path": "components/flex/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/flex/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/flex/nz-flex.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, Input, booleanAttribute } from '@angular/core';\n\nimport { NzAlign, NzFlex, NzGap, NzJustify, NzWrap } from './typings';\n\n@Directive({\n  selector: '[nz-flex],nz-flex',\n  exportAs: 'nzFlex',\n  host: {\n    class: 'ant-flex',\n    '[class.ant-flex-vertical]': `nzVertical`,\n    '[class.ant-flex-justify-flex-start]': `nzJustify === 'flex-start'`,\n    '[class.ant-flex-justify-center]': `nzJustify === 'center'`,\n    '[class.ant-flex-justify-flex-end]': `nzJustify === 'flex-end'`,\n    '[class.ant-flex-justify-space-between]': `nzJustify === 'space-between'`,\n    '[class.ant-flex-justify-space-around]': `nzJustify === 'space-around'`,\n    '[class.ant-flex-justify-space-evenly]': `nzJustify === 'space-evenly'`,\n    '[class.ant-flex-justify-start]': `nzJustify === 'start'`,\n    '[class.ant-flex-justify-end]': `nzJustify === 'end'`,\n    '[class.ant-flex-justify-right]': `nzJustify === 'right'`,\n    '[class.ant-flex-justify-left]': `nzJustify === 'left'`,\n    '[class.ant-flex-justify-stretch]': `nzJustify === 'stretch'`,\n    '[class.ant-flex-justify-normal]': `nzJustify === 'normal'`,\n    '[class.ant-flex-align-flex-start]': `nzAlign === 'flex-start'`,\n    '[class.ant-flex-align-center]': `nzAlign === 'center'`,\n    '[class.ant-flex-align-flex-end]': `nzAlign === 'flex-end'`,\n    '[class.ant-flex-align-space-between]': `nzAlign === 'space-between'`,\n    '[class.ant-flex-align-space-around]': `nzAlign === 'space-around'`,\n    '[class.ant-flex-align-space-evenly]': `nzAlign === 'space-evenly'`,\n    '[class.ant-flex-align-start]': `nzAlign === 'start'`,\n    '[class.ant-flex-align-end]': `nzAlign === 'end'`,\n    '[class.ant-flex-align-right]': `nzAlign === 'right'`,\n    '[class.ant-flex-align-left]': `nzAlign === 'left'`,\n    '[class.ant-flex-align-stretch]': `nzAlign === 'stretch'`,\n    '[class.ant-flex-align-normal]': `nzAlign === 'normal'`,\n    '[class.ant-flex-wrap-wrap]': `nzWrap === 'wrap'`,\n    '[class.ant-flex-wrap-wrap-reverse]': `nzWrap === 'wrap-reverse'`,\n    '[class.ant-flex-wrap-nowrap]': `nzWrap === 'nowrap'`,\n    '[style.gap]': `gap`,\n    '[style.flex]': `nzFlex`\n  }\n})\nexport class NzFlexDirective {\n  @Input({ transform: booleanAttribute }) nzVertical: boolean = false;\n  @Input() nzJustify: NzJustify = 'normal';\n  @Input() nzAlign: NzAlign = 'normal';\n  @Input() nzGap: NzGap = 0;\n  @Input() nzWrap: NzWrap = 'nowrap';\n  @Input() nzFlex: NzFlex = 'unset';\n\n  protected get gap(): string {\n    switch (this.nzGap) {\n      case 'small':\n        return '8px';\n      case 'middle':\n        return '16px';\n      case 'large':\n        return '24px';\n      default:\n        if (typeof this.nzGap === 'number') {\n          return `${this.nzGap}px`;\n        }\n        return this.nzGap;\n    }\n  }\n}\n"
  },
  {
    "path": "components/flex/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './nz-flex.directive';\nexport * from './typings';\nexport * from './flex.module';\n"
  },
  {
    "path": "components/flex/style/entry.less",
    "content": "@import './index.less';\n"
  },
  {
    "path": "components/flex/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@flex-prefix-cls: ~'@{ant-prefix}-flex';\n\n.@{flex-prefix-cls} {\n  display: flex;\n\n  &-vertical {\n    flex-direction: column;\n  }\n\n  &-justify {\n    &-flex-start {\n      justify-content: flex-start;\n    }\n\n    &-center {\n      justify-content: center;\n    }\n\n    &-flex-end {\n      justify-content: flex-end;\n    }\n\n    &-space-between {\n      justify-content: space-between;\n    }\n\n    &-space-around {\n      justify-content: space-around;\n    }\n\n    &-space-evenly {\n      justify-content: space-evenly;\n    }\n\n    &-start {\n      justify-content: start;\n    }\n\n    &-end {\n      justify-content: end;\n    }\n\n    &-right {\n      justify-content: right;\n    }\n\n    &-left {\n      justify-content: left;\n    }\n\n    &-stretch {\n      justify-content: stretch;\n    }\n\n    &-normal {\n      justify-content: normal;\n    }\n  }\n\n  &-align {\n    &-flex-start {\n      align-items: flex-start;\n    }\n\n    &-center {\n      align-items: center;\n    }\n\n    &-flex-end {\n      align-items: flex-end;\n    }\n\n    &-start {\n      align-items: start;\n    }\n\n    &-end {\n      align-items: end;\n    }\n\n    &-stretch {\n      align-items: stretch;\n    }\n\n    &-normal {\n      align-items: normal;\n    }\n  }\n\n  &-wrap {\n    &-wrap {\n      flex-wrap: wrap;\n    }\n\n    &-nowrap {\n      flex-wrap: nowrap;\n    }\n\n    &-wrap-reverse {\n      flex-wrap: wrap-reverse;\n    }\n  }\n}\n"
  },
  {
    "path": "components/flex/typings.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport type NzJustify =\n  | 'flex-start'\n  | 'center'\n  | 'flex-end'\n  | 'space-between'\n  | 'space-around'\n  | 'space-evenly'\n  | 'start'\n  | 'end'\n  | 'right'\n  | 'left'\n  | 'stretch'\n  | 'normal';\n\nexport type NzAlign =\n  | 'flex-start'\n  | 'center'\n  | 'flex-end'\n  | 'space-between'\n  | 'space-around'\n  | 'space-evenly'\n  | 'start'\n  | 'end'\n  | 'right'\n  | 'left'\n  | 'stretch'\n  | 'normal';\n\nexport type NzGap = 'small' | 'middle' | 'large' | NzCustomGap;\nexport type NzCustomGap = number | string;\n\nexport type NzWrap = 'wrap' | 'nowrap' | 'wrap-reverse';\n\nexport type NzFlex = `${NzFlexShrink} ${NzFlexGrow} ${NzFlexBasis}` | 'unset';\nexport type NzFlexShrink = number;\nexport type NzFlexGrow = number;\nexport type NzFlexBasis = string;\n"
  },
  {
    "path": "components/float-button/demo/badge.md",
    "content": "---\norder: 10\nversion: 20.4.0\ntitle:\n  zh-CN: 徽标数\n  en-US: Badge\n---\n\n## zh-CN\n\n右上角附带圆形徽标数字的悬浮按钮。\n\n## en-US\n\nFloatButton with Badge.\n"
  },
  {
    "path": "components/float-button/demo/badge.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzFloatButtonModule } from 'ng-zorro-antd/float-button';\n\n@Component({\n  selector: 'nz-demo-float-button-badge',\n  imports: [NzFloatButtonModule],\n  template: `\n    <div class=\"group\">\n      <nz-float-button nzShape=\"circle\" [nzBadge]=\"{ nzDot: true }\" style=\"inset-inline-end: 164px\" />\n      <nz-float-button-group nzShape=\"circle\" style=\"inset-inline-end: 94px\">\n        <nz-float-button [nzBadge]=\"{ nzCount: 5, nzColor: 'blue' }\" />\n        <nz-float-button [nzBadge]=\"{ nzCount: 5 }\" />\n      </nz-float-button-group>\n      <nz-float-button-group nzShape=\"circle\">\n        <nz-float-button [nzBadge]=\"{ nzCount: 12 }\" nzIcon=\"question-circle\" />\n        <nz-float-button [nzBadge]=\"{ nzCount: 123, nzOverflowCount: 999 }\" />\n        <nz-float-button-top [nzVisibilityHeight]=\"0\" [nzBadge]=\"{ nzDot: true }\" />\n      </nz-float-button-group>\n    </div>\n  `,\n  styles: `\n    .group {\n      height: 300px;\n      position: relative;\n    }\n    nz-float-button-group {\n      position: absolute;\n    }\n    nz-float-button {\n      position: absolute;\n    }\n  `\n})\nexport class NzDemoFloatButtonBadgeComponent {}\n"
  },
  {
    "path": "components/float-button/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n最简单的用法。\n\n## en-US\n\nThe most basic usage.\n"
  },
  {
    "path": "components/float-button/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzFloatButtonModule } from 'ng-zorro-antd/float-button';\n\n@Component({\n  selector: 'nz-demo-float-button-basic',\n  imports: [NzFloatButtonModule],\n  template: `\n    <div class=\"basic\">\n      <nz-float-button />\n    </div>\n  `,\n  styles: `\n    .basic {\n      height: 300px;\n      position: relative;\n    }\n    nz-float-button {\n      position: absolute;\n    }\n  `\n})\nexport class NzDemoFloatButtonBasicComponent {}\n"
  },
  {
    "path": "components/float-button/demo/description.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 描述\n  en-US: Description\n---\n\n## zh-CN\n\n可以通过 `nzDescription` 设置文字内容。\n\n> 仅当 `shape` 属性为 `square` 时支持。由于空间较小，推荐使用比较精简的双数文字。\n\n## en-US\n\nSetting `nzDescription` prop to show FloatButton with description.\n\n> supported only when `shape` is `square`. Due to narrow space for text, short sentence is recommended.\n"
  },
  {
    "path": "components/float-button/demo/description.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzFloatButtonModule } from 'ng-zorro-antd/float-button';\n\n@Component({\n  selector: 'nz-demo-float-button-description',\n  imports: [NzFloatButtonModule],\n  template: `\n    <div class=\"description\">\n      <nz-float-button nzIcon=\"file-text\" nzDescription=\"HELP\" nzShape=\"square\" style=\"right: 24px\" />\n      <nz-float-button nzDescription=\"HELP\" nzShape=\"square\" style=\"right: 94px\" />\n    </div>\n  `,\n  styles: `\n    .description {\n      height: 300px;\n      position: relative;\n    }\n    nz-float-button {\n      position: absolute;\n    }\n  `\n})\nexport class NzDemoFloatButtonDescriptionComponent {}\n"
  },
  {
    "path": "components/float-button/demo/group-menu.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 菜单模式\n  en-US: Menu mode\n---\n\n## zh-CN\n\n设置 `nzTrigger` 属性即可开启菜单模式。提供 `hover` 和 `click` 两种触发方式。\n\n## en-US\n\nOpen menu mode with `nzTrigger`, which could be `hover` or `click`.\n"
  },
  {
    "path": "components/float-button/demo/group-menu.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzFloatButtonModule } from 'ng-zorro-antd/float-button';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-demo-float-button-group-menu',\n  imports: [NzFloatButtonModule, NzIconModule],\n  template: `\n    <div class=\"menu\">\n      <nz-float-button-group\n        nzIcon=\"customer-service\"\n        nzType=\"primary\"\n        nzTrigger=\"click\"\n        style=\"right: 24px\"\n        (nzOnOpenChange)=\"openChange($event)\"\n      >\n        <nz-float-button />\n        <nz-float-button nzIcon=\"comment\" />\n      </nz-float-button-group>\n      <nz-float-button-group\n        nzIcon=\"customer-service\"\n        nzType=\"primary\"\n        nzTrigger=\"hover\"\n        style=\"right: 94px\"\n        (nzOnOpenChange)=\"openChange($event)\"\n      >\n        <nz-float-button />\n        <nz-float-button nzIcon=\"comment\" />\n      </nz-float-button-group>\n    </div>\n  `,\n  styles: `\n    .menu {\n      height: 300px;\n      position: relative;\n    }\n    nz-float-button-group {\n      position: absolute;\n    }\n  `\n})\nexport class NzDemoFloatButtonGroupMenuComponent {\n  openChange(status: boolean): void {\n    console.log(status);\n  }\n}\n"
  },
  {
    "path": "components/float-button/demo/group-placement.md",
    "content": "---\norder: 8\nversion: 20.1.0\ntitle:\n  zh-CN: 弹出方向\n  en-US: Placement\n---\n\n## zh-CN\n\n自定义弹出位置，提供了四个预设值：`top`、`right`、`bottom`、`left`，默认值为 `top`。\n\n## en-US\n\nCustomize animation placement, providing four preset placement: `top`, `right`, `bottom`, `left`, the `top` position by default.\n"
  },
  {
    "path": "components/float-button/demo/group-placement.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzFloatButtonModule } from 'ng-zorro-antd/float-button';\n\n@Component({\n  selector: 'nz-demo-float-button-group-placement',\n  imports: [NzFloatButtonModule],\n  template: `\n    <div class=\"container\">\n      <div class=\"anchor\">\n        <nz-float-button-group\n          class=\"up\"\n          nzIcon=\"up\"\n          nzType=\"primary\"\n          nzTrigger=\"click\"\n          (nzOnOpenChange)=\"openChange($event)\"\n          nzPlacement=\"top\"\n        >\n          <nz-float-button />\n          <nz-float-button nzIcon=\"comment\" />\n        </nz-float-button-group>\n        <nz-float-button-group\n          class=\"down\"\n          nzIcon=\"down\"\n          nzType=\"primary\"\n          nzTrigger=\"click\"\n          (nzOnOpenChange)=\"openChange($event)\"\n          nzPlacement=\"bottom\"\n        >\n          <nz-float-button />\n          <nz-float-button nzIcon=\"comment\" />\n        </nz-float-button-group>\n        <nz-float-button-group\n          class=\"left\"\n          nzIcon=\"left\"\n          nzType=\"primary\"\n          nzTrigger=\"click\"\n          (nzOnOpenChange)=\"openChange($event)\"\n          nzPlacement=\"left\"\n        >\n          <nz-float-button />\n          <nz-float-button nzIcon=\"comment\" />\n        </nz-float-button-group>\n        <nz-float-button-group\n          class=\"right\"\n          nzIcon=\"right\"\n          nzType=\"primary\"\n          nzTrigger=\"click\"\n          (nzOnOpenChange)=\"openChange($event)\"\n          nzPlacement=\"right\"\n        >\n          <nz-float-button />\n          <nz-float-button nzIcon=\"comment\" />\n        </nz-float-button-group>\n      </div>\n    </div>\n  `,\n  styles: `\n    .container {\n      display: flex;\n      height: 300px;\n      justify-content: center;\n      align-items: center;\n\n      .anchor {\n        height: 100px;\n        width: 100px;\n        position: relative;\n\n        .up {\n          inset-inline-end: 30px;\n          bottom: 80px;\n        }\n        .down {\n          inset-inline-end: 30px;\n          bottom: -20px;\n        }\n        .left {\n          inset-inline-end: 80px;\n          bottom: 30px;\n        }\n        .right {\n          inset-inline-end: -20px;\n          bottom: 30px;\n        }\n      }\n      nz-float-button-group {\n        position: absolute;\n      }\n    }\n  `\n})\nexport class NzDemoFloatButtonGroupPlacementComponent {\n  openChange(status: boolean): void {\n    console.log(status);\n  }\n}\n"
  },
  {
    "path": "components/float-button/demo/group.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 浮动按钮组\n  en-US: FloatButton Group\n---\n\n## zh-CN\n\n按钮组合使用时，推荐使用 `nz-float-button-group`，并通过设置 `nzShape` 属性改变悬浮按钮组的形状。\n\n## en-US\n\nWhen multiple buttons are used together, `nz-float-button-group` is recommended. By setting `nzShape` of FloatButtonGroup, you can change the shape of group.\n"
  },
  {
    "path": "components/float-button/demo/group.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzFloatButtonModule } from 'ng-zorro-antd/float-button';\n\n@Component({\n  selector: 'nz-demo-float-button-group',\n  imports: [NzFloatButtonModule],\n  template: `\n    <div class=\"group\">\n      <nz-float-button-group nzShape=\"circle\" style=\"right: 24px\">\n        <nz-float-button nzIcon=\"question-circle\" />\n        <nz-float-button />\n        <nz-float-button-top [nzVisibilityHeight]=\"600\" />\n        <nz-float-button nzIcon=\"customer-service\" />\n      </nz-float-button-group>\n      <nz-float-button-group nzShape=\"square\" style=\"right: 94px\">\n        <nz-float-button nzIcon=\"question-circle\" />\n        <nz-float-button />\n        <nz-float-button-top [nzVisibilityHeight]=\"600\" />\n        <nz-float-button nzIcon=\"customer-service\" />\n      </nz-float-button-group>\n    </div>\n  `,\n  styles: `\n    .group {\n      height: 300px;\n      position: relative;\n    }\n    nz-float-button-group {\n      position: absolute;\n    }\n  `\n})\nexport class NzDemoFloatButtonGroupComponent {}\n"
  },
  {
    "path": "components/float-button/demo/open.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 受控模式\n  en-US: Controlled mode\n---\n\n## zh-CN\n\n设置 `nzOpen` 属性控制 `nz-float-button-group` 是否展开\n\n## en-US\n\nSet the `nzOpen` property to control whether `nz-float-button-group` is expanded.\n"
  },
  {
    "path": "components/float-button/demo/open.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzFloatButtonModule } from 'ng-zorro-antd/float-button';\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\n\n@Component({\n  selector: 'nz-demo-float-button-open',\n  imports: [FormsModule, NzFloatButtonModule, NzSwitchModule],\n  template: `\n    <div class=\"open\">\n      <nz-float-button-group\n        nzIcon=\"customer-service\"\n        [nzOpen]=\"isOpen\"\n        nzType=\"primary\"\n        nzTrigger=\"hover\"\n        style=\"right: 24px\"\n      >\n        <nz-float-button />\n        <nz-float-button nzIcon=\"comment\" />\n      </nz-float-button-group>\n      <nz-switch [(ngModel)]=\"isOpen\" />\n    </div>\n  `,\n  styles: `\n    .open {\n      height: 300px;\n      position: relative;\n    }\n    nz-float-button-group,\n    nz-float-button {\n      position: absolute;\n    }\n  `\n})\nexport class NzDemoFloatButtonOpenComponent {\n  isOpen: boolean = true;\n}\n"
  },
  {
    "path": "components/float-button/demo/shape.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 形状\n  en-US: Shape\n---\n\n## zh-CN\n\n通过 `nsShape` 设置不同的形状。\n\n## en-US\n\nChange the shape of the FloatButton with `nsShape`.\n"
  },
  {
    "path": "components/float-button/demo/shape.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzFloatButtonModule } from 'ng-zorro-antd/float-button';\n\n@Component({\n  selector: 'nz-demo-float-button-shape',\n  imports: [NzFloatButtonModule],\n  template: `\n    <div class=\"shape\">\n      <nz-float-button nzShape=\"circle\" style=\"right: 94px\" nzType=\"primary\" nzIcon=\"customer-service\" />\n      <nz-float-button nzShape=\"square\" style=\"right: 24px\" nzType=\"primary\" nzIcon=\"customer-service\" />\n    </div>\n  `,\n  styles: `\n    .shape {\n      height: 300px;\n      position: relative;\n    }\n    nz-float-button {\n      position: absolute;\n    }\n  `\n})\nexport class NzDemoFloatButtonShapeComponent {}\n"
  },
  {
    "path": "components/float-button/demo/tooltip.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 含有气泡卡片的悬浮按钮\n  en-US: FloatButton with tooltip\n---\n\n## zh-CN\n\n添加 `nz-tooltip` 指令，即可开启气泡卡片。\n\n## en-US\n\nAdding the `tooltip` directive shows the FloatButton with a tooltip.\n"
  },
  {
    "path": "components/float-button/demo/tooltip.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzFloatButtonModule } from 'ng-zorro-antd/float-button';\nimport { NzTooltipDirective } from 'ng-zorro-antd/tooltip';\n\n@Component({\n  selector: 'nz-demo-float-button-tooltip',\n  imports: [NzFloatButtonModule, NzTooltipDirective],\n  template: `\n    <div class=\"tooltip\">\n      <nz-float-button\n        style=\"bottom: 108px\"\n        nz-tooltip\n        nzTooltipTitle=\"Documents\"\n        nzTooltipPlacement=\"top\"\n        nzTooltipColor=\"blue\"\n      />\n      <nz-float-button nz-tooltip [nzTooltipTitle]=\"titleTemplate\" />\n      <ng-template #titleTemplate>\n        <div>Documents</div>\n      </ng-template>\n    </div>\n  `,\n  styles: `\n    .tooltip {\n      height: 300px;\n      position: relative;\n    }\n    nz-float-button {\n      position: absolute;\n    }\n  `\n})\nexport class NzDemoFloatButtonTooltipComponent {}\n"
  },
  {
    "path": "components/float-button/demo/top.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 返回顶部\n  en-US: Back Top\n---\n\n## zh-CN\n\n返回页面顶部的操作按钮。\n\n## en-US\n\nSet the `nzOpen` property to control whether `nz-float-button-group` is expanded.\n"
  },
  {
    "path": "components/float-button/demo/top.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzFloatButtonModule } from 'ng-zorro-antd/float-button';\n\n@Component({\n  selector: 'nz-demo-float-button-top',\n  imports: [NzFloatButtonModule],\n  template: `\n    <nz-float-button-top />\n    Scroll down to see the back to top button on the bottom right\n  `\n})\nexport class NzDemoFloatButtonTopComponent {}\n"
  },
  {
    "path": "components/float-button/demo/type.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 类型\n  en-US: Type\n---\n\n## zh-CN\n\n通过 `nzType` 改变悬浮按钮的类型。\n\n## en-US\n\nChange the type of the FloatButton with `nzType`.\n"
  },
  {
    "path": "components/float-button/demo/type.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzFloatButtonModule } from 'ng-zorro-antd/float-button';\n\n@Component({\n  selector: 'nz-demo-float-button-type',\n  imports: [NzFloatButtonModule],\n  template: `\n    <div class=\"type\">\n      <nz-float-button nzType=\"primary\" style=\"right: 24px\" nzIcon=\"question-circle\" />\n      <nz-float-button nzType=\"default\" style=\"right: 94px\" nzIcon=\"question-circle\" />\n    </div>\n  `,\n  styles: `\n    .type {\n      height: 300px;\n      position: relative;\n    }\n    nz-float-button {\n      position: absolute;\n    }\n  `\n})\nexport class NzDemoFloatButtonTypeComponent {}\n"
  },
  {
    "path": "components/float-button/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: General\ntitle: FloatButton\ncover: 'https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*HS-wTIIwu0kAAAAAAAAAAAAADrJ8AQ/original'\ntag: 19.0.0\ndescription: A button that floats at the top of the page.\n---\n\n## When To Use\n\n- For global functionality on the site.\n- Buttons that can be seen wherever you browse.\n\n## API\n\n### Common API\n\n| Property          | Description                               | Type                                  | Default     | Version |\n| ----------------- | ----------------------------------------- | ------------------------------------- | ----------- | ------- |\n| `[nzIcon]`        | Set the icon component of button          | `string \\| TemplateRef<void> \\| null` | -           |\n| `[nzDescription]` | Text and other content                    | `string \\| TemplateRef<void> \\| null` | -           |\n| `[nzType]`        | Button type                               | `'default' \\| 'primary'`              | `'default'` |\n| `[nzShape]`       | Button shape                              | `'circle' \\| 'square'`                | `'circle'`  |\n| `[nzHref]`        | The target of hyperlink                   | `string`                              | -           |\n| `[nzTarget]`      | Specifies where to display the linked URL | `string`                              | -           |\n| `[nzBadge]`       | badge                                     | `NzFloatButtonBadge`                  | -           | 20.4.0  |\n| `(nzOnClick)`     | Callback of `click` event                 | `EventEmitter<boolean>`               | -           |\n\n### nz-float-button-group\n\n| Property           | Description                                   | Type                                     | Default |\n| ------------------ | --------------------------------------------- | ---------------------------------------- | ------- |\n| `[nzTrigger]`      | Which action can trigger menu open/close      | `'click' \\| 'hover'`                     | -       |\n| `[nzPlacement]`    | Customize menu animation placement            | `'top' \\| 'right' \\| 'bottom' \\| 'left'` | `'top'` |\n| `[nzOpen]`         | Whether the menu is visible or not            | `boolean`                                | -       |\n| `(nzOnOpenChange)` | Callback executed when active menu is changed | `EventEmitter<boolean>`                  | -       |\n\n### nz-float-button-top\n\n| Property               | Description                                                                               | Type                | Default  | Global Config |\n| ---------------------- | ----------------------------------------------------------------------------------------- | ------------------- | -------- | ------------- |\n| `[nzVisibilityHeight]` | The `nz-float-button-top` button will not show until the scroll height reaches this value | `number`            | `400`    | ✅            |\n| `[nzTarget]`           | Specifies the scrollable area dom node                                                    | `string \\| Element` | `window` | -             |\n| `[nzDuration]`         | Duration of scrolling to top (ms)                                                         | `number`            | `450`    | -             |\n\n### Interfaces\n\n#### NzFloatButtonBadge\n\n```ts\n// omit nzShowDot, nzTitle, nzStatus, nzText from the props of NzBadge\nexport interface NzFloatButtonBadge {\n  nzDot?: boolean;\n  nzCount?: number | TemplateRef<void>;\n  nzShowZero?: boolean;\n  nzOverflowCount?: number;\n  nzColor?: string;\n  nzOffset?: [number, number];\n  nzSize?: 'default' | 'small';\n}\n```\n"
  },
  {
    "path": "components/float-button/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 悬浮按钮\ntype: 通用\ntitle: FloatButton\ncover: 'https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*HS-wTIIwu0kAAAAAAAAAAAAADrJ8AQ/original'\ntag: 19.0.0\ndescription: 悬浮于页面上方的按钮。\n---\n\n## 何时使用\n\n- 用于网站上的全局功能；\n- 无论浏览到何处都可以看见的按钮。\n\n## API\n\n### 共同的 API\n\n| 参数              | 说明                                                  | 类型                                  | 默认值      | 版本   |\n| ----------------- | ----------------------------------------------------- | ------------------------------------- | ----------- | ------ |\n| `[nzIcon]`        | 自定义图标                                            | `string \\| TemplateRef<void> \\| null` | -           |\n| `[nzDescription]` | 文字及其它内容                                        | `string \\| TemplateRef<void> \\| null` | -           |\n| `[nzType]`        | 按钮类型                                              | `'default' \\| 'primary'`              | `'default'` |\n| `[nzShape]`       | 按钮形状                                              | `'circle' \\| 'square'`                | `'circle'`  |\n| `[nzHref]`        | 点击跳转的地址，指定此参数 button 的行为和 a 链接一致 | `string`                              | -           |\n| `[nzTarget]`      | 相当于 a 标签的 target 属性，`nzHref` 存在时生效      | `string`                              | -           |\n| `[nzBadge]`       | 徽标数                                                | `NzFloatButtonBadge`                  | -           | 20.4.0 |\n| `(nzOnClick)`     | 点击按钮时的回调                                      | `EventEmitter<boolean>`               | -           |\n\n### nz-float-button-group\n\n| 参数               | 说明                             | 类型                                     | 默认值  |\n| ------------------ | -------------------------------- | ---------------------------------------- | ------- |\n| `[nzTrigger]`      | 触发方式（有触发方式为菜单模式） | `'click' \\| 'hover'`                     | -       |\n| `[nzPlacement]`    | 自定义菜单弹出位置               | `'top' \\| 'right' \\| 'bottom' \\| 'left'` | `'top'` |\n| `[nzOpen]`         | 受控展开                         | `boolean`                                | -       |\n| `(nzOnOpenChange)` | 展开收起时的回调                 | `EventEmitter<boolean>`                  | -       |\n\n### nz-float-button-top\n\n| 参数                   | 说明                                                          | 类型                | 默认值   | 全局配置 |\n| ---------------------- | ------------------------------------------------------------- | ------------------- | -------- | -------- |\n| `[nzVisibilityHeight]` | 滚动高度达到此值时才出现 `nz-float-button-top`                | `number`            | `400`    | ✅       |\n| `[nzTarget]`           | 设置需要监听其滚动事件的元素，值为一个返回对应 DOM 元素的函数 | `string \\| Element` | `window` | -        |\n| `[nzDuration]`         | 回到顶部所需时间（毫秒）                                      | `number`            | `450`    | -        |\n\n### Interfaces\n\n#### NzFloatButtonBadge\n\n```ts\n// NzBadge 组件属性中移除 nzShowDot, nzTitle, nzStatus, nzText\nexport interface NzFloatButtonBadge {\n  nzDot?: boolean;\n  nzCount?: number | TemplateRef<void>;\n  nzShowZero?: boolean;\n  nzOverflowCount?: number;\n  nzColor?: string;\n  nzOffset?: [number, number];\n  nzSize?: 'default' | 'small';\n}\n```\n"
  },
  {
    "path": "components/float-button/float-button-content.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, input, TemplateRef } from '@angular/core';\n\nimport { NzBadgeComponent } from 'ng-zorro-antd/badge';\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzShapeSCType } from 'ng-zorro-antd/core/types';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nimport { NzFloatButtonBadge } from './typings';\n\n@Component({\n  selector: 'nz-float-button-content',\n  exportAs: 'nzFloatButtonContent',\n  imports: [NzIconModule, NzOutletModule, NzBadgeComponent, NgTemplateOutlet],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    @if (nzBadge()) {\n      <nz-badge\n        [nzDot]=\"nzBadge()?.nzDot\"\n        [nzShowDot]=\"nzBadge()?.nzDot\"\n        [nzCount]=\"nzBadge()?.nzCount\"\n        [nzShowZero]=\"nzBadge()?.nzShowZero\"\n        [nzOverflowCount]=\"nzBadge()?.nzOverflowCount!\"\n        [nzColor]=\"nzBadge()?.nzColor\"\n        [nzOffset]=\"nzBadge()?.nzOffset\"\n        [nzSize]=\"nzBadge()?.nzSize || 'default'\"\n      >\n        <ng-container *ngTemplateOutlet=\"button\" />\n      </nz-badge>\n    } @else {\n      <ng-container *ngTemplateOutlet=\"button\" />\n    }\n    <ng-template #button>\n      <div class=\"ant-float-btn-body\">\n        <div class=\"ant-float-btn-content\">\n          @if (nzDescription() || nzIcon()) {\n            @if (nzIcon()) {\n              <div class=\"ant-float-btn-icon\">\n                <ng-container *nzStringTemplateOutlet=\"nzIcon(); let icon\">\n                  <nz-icon [nzType]=\"icon\" nzTheme=\"outline\" />\n                </ng-container>\n              </div>\n            }\n            @if (nzDescription() && nzShape() === 'square') {\n              <div class=\"ant-float-btn-description\">\n                <ng-container *nzStringTemplateOutlet=\"nzDescription()\">\n                  {{ nzDescription() }}\n                </ng-container>\n              </div>\n            }\n          } @else {\n            <div class=\"ant-float-btn-icon\">\n              <nz-icon nzType=\"file-text\" nzTheme=\"outline\" />\n            </div>\n          }\n        </div>\n      </div>\n    </ng-template>\n  `\n})\nexport class NzFloatButtonContentComponent {\n  readonly nzBadge = input<NzFloatButtonBadge | null>(null);\n  readonly nzIcon = input<string | TemplateRef<void> | null>(null);\n  readonly nzDescription = input<string | TemplateRef<void> | null>(null);\n  readonly nzShape = input<NzShapeSCType>('circle');\n}\n"
  },
  {
    "path": "components/float-button/float-button-group.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Direction } from '@angular/cdk/bidi';\nimport { Component, DebugElement, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { NzFourDirectionType, NzShapeSCType } from 'ng-zorro-antd/core/types';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzFloatButtonGroupComponent } from './float-button-group.component';\nimport { NzFloatButtonModule } from './float-button.module';\n\ndescribe('nz-float-button-group', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideZoneChangeDetection()]\n    });\n  });\n\n  describe('basic', () => {\n    let fixture: ComponentFixture<NzTestFloatButtonGroupBasicComponent>;\n    let testComponent: NzTestFloatButtonGroupBasicComponent;\n    let resultEl: DebugElement;\n    let groupComponent: NzFloatButtonGroupComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestFloatButtonGroupBasicComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n      resultEl = fixture.debugElement.query(By.directive(NzFloatButtonGroupComponent));\n      groupComponent = resultEl.componentInstance;\n    });\n\n    it('basic', () => {\n      fixture.detectChanges();\n      expect(resultEl.nativeElement.classList).toContain('ant-float-btn-group-circle');\n    });\n\n    it('nzShape', () => {\n      testComponent.nzShape = 'square';\n      fixture.detectChanges();\n      expect(resultEl.nativeElement.classList).toContain('ant-float-btn-group-square');\n      const innerButtons = [\n        ...groupComponent.nzFloatButtonComponents(),\n        ...groupComponent.nzFloatButtonTopComponents()\n      ];\n      innerButtons.forEach(btn => {\n        expect(btn.shape()).toBe('square');\n      });\n    });\n\n    it('nzTrigger hover', () => {\n      testComponent.nzTrigger = 'hover';\n      fixture.detectChanges();\n      resultEl.nativeElement.getElementsByClassName('ant-float-btn')[0].dispatchEvent(new MouseEvent('mouseover'));\n      fixture.detectChanges();\n      expect(resultEl.nativeElement.getElementsByClassName('anticon')[0].getAttribute('nztype') === 'close').toBe(true);\n      expect(testComponent.isClick).toBe(true);\n      resultEl.nativeElement.dispatchEvent(new MouseEvent('mouseleave'));\n      fixture.detectChanges();\n      expect(resultEl.nativeElement.getElementsByClassName('anticon')[0].getAttribute('nztype') === 'close').toBe(\n        false\n      );\n      expect(testComponent.isClick).toBe(false);\n    });\n\n    it('nzTrigger click', () => {\n      testComponent.nzTrigger = 'click';\n      fixture.detectChanges();\n      resultEl.nativeElement.getElementsByClassName('ant-btn')[0].dispatchEvent(new MouseEvent('click'));\n      fixture.detectChanges();\n      expect(resultEl.nativeElement.getElementsByClassName('anticon')[0].getAttribute('nztype') === 'close').toBe(true);\n      expect(testComponent.isClick).toBe(true);\n      resultEl.nativeElement.getElementsByClassName('ant-btn')[0].dispatchEvent(new MouseEvent('click'));\n      fixture.detectChanges();\n      expect(resultEl.nativeElement.getElementsByClassName('anticon')[0].getAttribute('nztype') === 'close').toBe(\n        false\n      );\n      expect(testComponent.isClick).toBe(false);\n    });\n\n    it('nzOpen true', () => {\n      testComponent.nzOpen = true;\n      testComponent.nzTrigger = 'click';\n      fixture.detectChanges();\n      resultEl.nativeElement.getElementsByClassName('ant-btn')[0].dispatchEvent(new MouseEvent('click'));\n      fixture.detectChanges();\n      expect(resultEl.nativeElement.getElementsByClassName('anticon')[0].getAttribute('nztype') === 'close').toBe(true);\n    });\n\n    it('nzOpen false', () => {\n      testComponent.nzOpen = false;\n      testComponent.nzTrigger = 'click';\n      fixture.detectChanges();\n      resultEl.nativeElement.getElementsByClassName('ant-btn')[0].dispatchEvent(new MouseEvent('click'));\n      fixture.detectChanges();\n      expect(resultEl.nativeElement.getElementsByClassName('anticon')[0].getAttribute('nztype') === 'close').toBe(\n        false\n      );\n    });\n\n    describe('float-button-group placement', () => {\n      it('should set correct class for nzPlacement top', () => {\n        testComponent.nzTrigger = 'click';\n        testComponent.nzPlacement = 'top';\n        fixture.detectChanges();\n        expect(resultEl.nativeElement.classList).toContain('ant-float-btn-group-top');\n        // is not menu mode\n        testComponent.nzTrigger = null;\n        fixture.detectChanges();\n        expect(resultEl.nativeElement.classList).not.toContain('ant-float-btn-group-top');\n      });\n\n      it('should set correct class for nzPlacement bottom', () => {\n        testComponent.nzTrigger = 'click';\n        testComponent.nzPlacement = 'bottom';\n        fixture.detectChanges();\n        expect(resultEl.nativeElement.classList).toContain('ant-float-btn-group-bottom');\n        // is not menu mode\n        testComponent.nzTrigger = null;\n        fixture.detectChanges();\n        expect(resultEl.nativeElement.classList).not.toContain('ant-float-btn-group-bottom');\n      });\n\n      it('should set correct class for nzPlacement left', () => {\n        testComponent.nzTrigger = 'click';\n        testComponent.nzPlacement = 'left';\n        fixture.detectChanges();\n        expect(resultEl.nativeElement.classList).toContain('ant-float-btn-group-left');\n        // is not menu mode\n        testComponent.nzTrigger = null;\n        fixture.detectChanges();\n        expect(resultEl.nativeElement.classList).not.toContain('ant-float-btn-group-left');\n      });\n\n      it('should set correct class for nzPlacement right', () => {\n        testComponent.nzTrigger = 'click';\n        testComponent.nzPlacement = 'right';\n        fixture.detectChanges();\n        expect(resultEl.nativeElement.classList).toContain('ant-float-btn-group-right');\n        // is not menu mode\n        testComponent.nzTrigger = null;\n        fixture.detectChanges();\n        expect(resultEl.nativeElement.classList).not.toContain('ant-float-btn-group-right');\n      });\n\n      it('should get correct animation class according to nzPlacement', () => {\n        fixture.detectChanges();\n        // @ts-ignore\n        const { enterAnimation, leaveAnimation } = groupComponent;\n        expect(enterAnimation()).toBe('ant-float-btn-enter-top');\n        expect(leaveAnimation()).toBe('ant-float-btn-leave-top');\n        testComponent.nzPlacement = 'right';\n        fixture.detectChanges();\n        expect(enterAnimation()).toBe('ant-float-btn-enter-right');\n        expect(leaveAnimation()).toBe('ant-float-btn-leave-right');\n      });\n    });\n  });\n\n  describe('RTL', () => {\n    let fixture: ComponentFixture<NzTestFloatButtonRtlComponent>;\n    let resultEl: DebugElement;\n    let groupComponent: NzFloatButtonGroupComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestFloatButtonRtlComponent);\n      resultEl = fixture.debugElement.query(By.directive(NzFloatButtonGroupComponent));\n      groupComponent = resultEl.componentInstance;\n    });\n\n    it('rtl', () => {\n      fixture.detectChanges();\n      // @ts-ignore\n      expect(groupComponent.dir()).toBe('rtl');\n      expect(resultEl.nativeElement.classList).toContain('ant-float-btn-group-rtl');\n    });\n  });\n});\n\n@Component({\n  selector: 'nz-test-basic-float-button-group',\n  imports: [NzFloatButtonModule, NzIconModule],\n  template: `\n    <nz-float-button-group\n      nzIcon=\"question-circle\"\n      [nzShape]=\"nzShape\"\n      [nzTrigger]=\"nzTrigger\"\n      [nzOpen]=\"nzOpen\"\n      [nzPlacement]=\"nzPlacement\"\n      (nzOnOpenChange)=\"onClick($event)\"\n    />\n  `\n})\nexport class NzTestFloatButtonGroupBasicComponent {\n  nzShape: NzShapeSCType = 'circle';\n  nzTrigger: 'click' | 'hover' | null = null;\n  nzOpen: boolean | null = null;\n  nzPlacement: NzFourDirectionType = 'top';\n\n  isClick: boolean = false;\n\n  onClick(value: boolean): void {\n    this.isClick = value;\n  }\n}\n\n@Component({\n  imports: [BidiModule, NzFloatButtonModule],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-float-button-group />\n    </div>\n  `\n})\nexport class NzTestFloatButtonRtlComponent {\n  direction: Direction = 'rtl';\n}\n"
  },
  {
    "path": "components/float-button/float-button-group.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  computed,\n  contentChildren,\n  effect,\n  inject,\n  input,\n  linkedSignal,\n  output,\n  TemplateRef\n} from '@angular/core';\n\nimport { withAnimationCheck } from 'ng-zorro-antd/core/animation';\nimport { NzFourDirectionType, NzShapeSCType } from 'ng-zorro-antd/core/types';\nimport { generateClassName } from 'ng-zorro-antd/core/util';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nimport { NzFloatButtonTopComponent } from './float-button-top.component';\nimport { NzFloatButtonComponent } from './float-button.component';\nimport { NzFloatButtonType } from './typings';\n\nconst CLASS_NAME = 'ant-float-btn-group';\n\n@Component({\n  selector: 'nz-float-button-group',\n  exportAs: 'nzFloatButtonGroup',\n  imports: [NzFloatButtonComponent, NzIconModule, NgTemplateOutlet],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    @if (!isMenuMode()) {\n      <ng-container *ngTemplateOutlet=\"menu\" />\n    } @else {\n      @if (open()) {\n        <div class=\"ant-float-btn-group-wrap\" [animate.enter]=\"enterAnimation()\" [animate.leave]=\"leaveAnimation()\">\n          <ng-container *ngTemplateOutlet=\"menu\" />\n        </div>\n      }\n      <nz-float-button\n        class=\"ant-float-btn-group-trigger\"\n        [nzType]=\"nzType()\"\n        [nzIcon]=\"open() ? close : nzIcon()\"\n        [nzShape]=\"nzShape()\"\n        [nzDescription]=\"open() ? null : nzDescription()\"\n        (nzOnClick)=\"open() ? clickCloseMenu() : clickOpenMenu()\"\n        (mouseover)=\"hoverOpenMenu()\"\n      />\n    }\n    <ng-template #menu><ng-content /></ng-template>\n    <ng-template #close>\n      <nz-icon nzType=\"close\" nzTheme=\"outline\" />\n    </ng-template>\n  `,\n  host: {\n    '[class]': 'class()',\n    '(mouseleave)': 'hoverCloseMenu()'\n  }\n})\nexport class NzFloatButtonGroupComponent {\n  readonly nzFloatButtonComponents = contentChildren(NzFloatButtonComponent);\n  readonly nzFloatButtonTopComponents = contentChildren(NzFloatButtonTopComponent);\n\n  readonly nzHref = input<string | null>(null);\n  readonly nzTarget = input<string | null>(null);\n  readonly nzType = input<NzFloatButtonType>('default');\n  readonly nzIcon = input<string | TemplateRef<void> | null>(null);\n  readonly nzDescription = input<string | TemplateRef<void> | null>(null);\n  readonly nzShape = input<NzShapeSCType>('circle');\n  readonly nzTrigger = input<'click' | 'hover' | null>(null);\n  readonly nzOpen = input<boolean | null>(null);\n  readonly nzPlacement = input<NzFourDirectionType>('top');\n  readonly nzOnOpenChange = output<boolean>();\n\n  protected readonly dir = inject(Directionality).valueSignal;\n  protected readonly open = linkedSignal<boolean>(() => !!this.nzOpen());\n  protected readonly isMenuMode = computed(\n    () => !!this.nzTrigger() && ['click', 'hover'].includes(this.nzTrigger() as string)\n  );\n  protected readonly isControlledMode = computed(() => this.nzOpen() !== null);\n  protected readonly class = computed<string[]>(() => {\n    const shape = this.nzShape();\n    const dir = this.dir();\n    const classes = [CLASS_NAME, this.generateClass(shape)];\n    if (!this.isMenuMode()) {\n      classes.push(this.generateClass(`${shape}-shadow`));\n    } else {\n      classes.push(this.generateClass(this.nzPlacement()));\n    }\n    if (dir === 'rtl') {\n      classes.push(this.generateClass(dir));\n    }\n    return classes;\n  });\n  protected readonly enterAnimation = withAnimationCheck(() => `ant-float-btn-enter-${this.nzPlacement()}`);\n  protected readonly leaveAnimation = withAnimationCheck(() => `ant-float-btn-leave-${this.nzPlacement()}`);\n\n  constructor() {\n    effect(() => {\n      if (this.nzFloatButtonComponents()) {\n        this.nzFloatButtonComponents().forEach(item => {\n          item.shape.set(this.nzShape());\n        });\n      }\n      if (this.nzFloatButtonTopComponents()) {\n        this.nzFloatButtonTopComponents().forEach(item => {\n          item.shape.set(this.nzShape());\n        });\n      }\n    });\n  }\n\n  clickOpenMenu(): void {\n    this.handleEvent('click', true);\n  }\n\n  hoverOpenMenu(): void {\n    this.handleEvent('hover', true);\n  }\n\n  clickCloseMenu(): void {\n    this.handleEvent('click', false);\n  }\n\n  hoverCloseMenu(): void {\n    this.handleEvent('hover', false);\n  }\n\n  private handleEvent(type: 'click' | 'hover', isOpen: boolean): void {\n    if (this.nzTrigger() !== type || this.isControlledMode() || this.open() === isOpen) {\n      return;\n    }\n    this.open.set(isOpen);\n    this.nzOnOpenChange.emit(isOpen);\n  }\n\n  private generateClass(suffix: string): string {\n    return generateClassName(CLASS_NAME, suffix);\n  }\n}\n"
  },
  {
    "path": "components/float-button/float-button-top.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Direction } from '@angular/cdk/bidi';\nimport { Component, DebugElement, ViewChild } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { provideNzNoAnimation } from 'ng-zorro-antd/core/animation';\nimport { provideNzConfig } from 'ng-zorro-antd/core/config';\nimport { NzScrollService } from 'ng-zorro-antd/core/services';\nimport { sleep, updateNonSignalsInput } from 'ng-zorro-antd/core/testing';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzFloatButtonTopComponent } from './float-button-top.component';\nimport { NzFloatButtonModule } from './float-button.module';\n\nconst defaultVisibilityHeight = 500;\n\ndescribe('nz-float-button-top', () => {\n  describe('basic', () => {\n    let scrollService: MockNzScrollService;\n    let fixture: ComponentFixture<TestFloatButtonTopComponent>;\n    let debugElement: DebugElement;\n    let component: NzFloatButtonTopComponent;\n    let componentObject: NzFloatButtonTopPageObject;\n\n    class NzFloatButtonTopPageObject {\n      scrollTo(el: Element | Window, scrollTop: number): void {\n        scrollService.mockTopOffset = scrollTop;\n        el.dispatchEvent(new Event('scroll'));\n      }\n\n      clickBackTop(): void {\n        this.backTopButton().nativeElement.click();\n      }\n\n      backTopButton(): DebugElement {\n        return debugElement.query(By.css('.ant-float-btn-top .ant-float-btn-inner'));\n      }\n    }\n\n    async function scrollTo(el: Element | Window, scrollTop: number): Promise<void> {\n      componentObject.scrollTo(el, scrollTop);\n      await sleep(50);\n      await fixture.whenStable();\n    }\n\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        providers: [\n          provideNzNoAnimation(),\n          {\n            provide: NzScrollService,\n            useClass: MockNzScrollService\n          },\n          provideNzConfig({\n            floatButton: {\n              nzVisibilityHeight: 999\n            }\n          })\n        ]\n      });\n\n      fixture = TestBed.createComponent(TestFloatButtonTopComponent);\n      component = fixture.componentInstance.floatButtonTopComponent;\n      componentObject = new NzFloatButtonTopPageObject();\n      debugElement = fixture.debugElement;\n      scrollService = TestBed.inject(NzScrollService) as NzSafeAny;\n    });\n\n    describe('[default]', () => {\n      it(`should not show when scroll is below ${defaultVisibilityHeight}`, async () => {\n        componentObject.scrollTo(window, defaultVisibilityHeight - 1);\n        await fixture.whenStable();\n\n        expect(componentObject.backTopButton()).toBeFalsy();\n      });\n\n      it(`should not show when scroll is at ${defaultVisibilityHeight}`, async () => {\n        componentObject.scrollTo(window, defaultVisibilityHeight);\n        await fixture.whenStable();\n\n        expect(componentObject.backTopButton()).toBeFalsy();\n      });\n\n      describe(`when scrolled at least ${defaultVisibilityHeight + 1}`, () => {\n        beforeEach(async () => {\n          await scrollTo(window, defaultVisibilityHeight + 1);\n        });\n\n        it(`should show back to top button`, () => {\n          expect(componentObject.backTopButton()).toBeTruthy();\n        });\n\n        it(`should show default template`, () => {\n          expect(debugElement.query(By.css('.ant-float-btn-content')) === null).toBe(false);\n        });\n\n        it(`should scroll to top when button is clicked`, async () => {\n          componentObject.clickBackTop();\n          await fixture.whenStable();\n          expect(scrollService.getScroll()).toEqual(0);\n        });\n      });\n    });\n\n    describe('[nzVisibilityHeight]', () => {\n      it(`should not show when scroll is below ${defaultVisibilityHeight}`, async () => {\n        await scrollTo(window, defaultVisibilityHeight - 1);\n        expect(componentObject.backTopButton()).toBeFalsy();\n      });\n\n      it(`should not show when scroll is at ${defaultVisibilityHeight}`, async () => {\n        await scrollTo(window, defaultVisibilityHeight);\n        expect(componentObject.backTopButton()).toBeFalsy();\n      });\n\n      it(`when scrolled at least ${defaultVisibilityHeight + 1}`, async () => {\n        await scrollTo(window, defaultVisibilityHeight + 1);\n        expect(componentObject.backTopButton()).toBeTruthy();\n      });\n\n      it('should display when change nzVisibilityHeight less than default', async () => {\n        await scrollTo(window, defaultVisibilityHeight + 1);\n\n        expect(componentObject.backTopButton()).toBeTruthy();\n        fixture.componentInstance.customVisibilityHeight = defaultVisibilityHeight - 100;\n        await updateNonSignalsInput(fixture);\n\n        expect(componentObject.backTopButton()).toBeTruthy();\n      });\n\n      it('should display when change nzVisibilityHeight greater than default', async () => {\n        await scrollTo(window, defaultVisibilityHeight + 1);\n\n        expect(componentObject.backTopButton()).toBeTruthy();\n        fixture.componentInstance.customVisibilityHeight = defaultVisibilityHeight + 100;\n        await updateNonSignalsInput(fixture);\n\n        expect(componentObject.backTopButton()).toBeFalsy();\n      });\n\n      it('should use config value (999) if nzVisibilityHeight is not assigned by user', async () => {\n        await scrollTo(window, defaultVisibilityHeight + 1);\n\n        // @ts-ignore\n        fixture.componentInstance.customVisibilityHeight = undefined;\n        await updateNonSignalsInput(fixture);\n\n        expect(componentObject.backTopButton()).toBeFalsy();\n        expect(component['visibilityHeight']()).toBe(999);\n      });\n    });\n\n    it(`should emit event on nzClick`, async () => {\n      await scrollTo(window, defaultVisibilityHeight + 1);\n\n      componentObject.clickBackTop();\n      expect(fixture.componentInstance.handleClick).toHaveBeenCalledWith(true);\n    });\n\n    describe('[nzTarget]', () => {\n      let fakeTarget: HTMLElement;\n\n      beforeEach(async () => {\n        fakeTarget = debugElement.query(By.css('#fakeTarget')).nativeElement;\n        fixture.componentInstance.setTarget(fakeTarget);\n        await fixture.whenStable();\n      });\n\n      it('window scroll does not show the button', async () => {\n        await scrollTo(window, defaultVisibilityHeight + 1);\n        expect(componentObject.backTopButton()).toBeFalsy();\n      });\n\n      it('element scroll shows the button', async () => {\n        await scrollTo(fakeTarget, defaultVisibilityHeight + 1);\n        expect(componentObject.backTopButton()).toBeTruthy();\n      });\n\n      it('element (use string id) scroll shows the button', async () => {\n        fixture.componentInstance.setTarget('#fakeTarget');\n        await updateNonSignalsInput(fixture);\n        await scrollTo(fakeTarget, defaultVisibilityHeight + 1);\n        expect(componentObject.backTopButton()).toBeTruthy();\n      });\n    });\n\n    describe('[nzIcon]', () => {\n      it('should custom template work', async () => {\n        fixture.componentInstance.useCustomIconTemplate = true;\n        await scrollTo(window, defaultVisibilityHeight + 1);\n        expect(debugElement.query(By.css('.custom-icon'))).toBeTruthy();\n      });\n    });\n  });\n\n  describe('rtl', () => {\n    it('rtl', async () => {\n      const fixture = TestBed.createComponent(TestFloatButtonTopRtlComponent);\n      await fixture.whenStable();\n      const resultEl = fixture.debugElement.query(By.directive(NzFloatButtonTopComponent));\n      expect(resultEl.nativeElement.classList).toContain('ant-float-btn-rtl');\n    });\n  });\n\n  describe('animation', () => {\n    it('should have correct animation classes', () => {\n      const fixture = TestBed.createComponent(NzFloatButtonTopComponent);\n      const component = fixture.componentInstance;\n\n      expect(component['fadeAnimationEnter']()).toBe('ant-float-btn-top-motion-enter');\n      expect(component['fadeAnimationLeave']()).toBe('ant-float-btn-top-motion-leave');\n    });\n  });\n});\n\nclass MockNzScrollService {\n  mockTopOffset: number = 0;\n\n  getScroll(): number {\n    return this.mockTopOffset;\n  }\n\n  scrollTo(_containerEl: Element | Window, targetTopValue: number = 0): void {\n    this.mockTopOffset = targetTopValue;\n  }\n}\n\n@Component({\n  selector: 'test-float-button-top',\n  imports: [NzFloatButtonModule],\n  template: `\n    <nz-float-button-top\n      [nzTarget]=\"target\"\n      [nzVisibilityHeight]=\"customVisibilityHeight\"\n      [nzIcon]=\"useCustomIconTemplate ? customIcon : null\"\n      (nzOnClick)=\"handleClick($event)\"\n    />\n    <div id=\"fakeTarget\"></div>\n    <ng-template #customIcon>\n      <div class=\"custom-icon\"></div>\n    </ng-template>\n  `\n})\nclass TestFloatButtonTopComponent {\n  @ViewChild(NzFloatButtonTopComponent, { static: true })\n  floatButtonTopComponent!: NzFloatButtonTopComponent;\n\n  target!: HTMLElement | string;\n  customVisibilityHeight = defaultVisibilityHeight;\n  useCustomIconTemplate = false;\n  handleClick = jasmine.createSpy('click');\n\n  setTarget(target: HTMLElement | string): void {\n    this.target = target;\n  }\n}\n\n@Component({\n  selector: 'test-float-button-top-rtl',\n  imports: [BidiModule, NzFloatButtonModule],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-float-button-top />\n    </div>\n  `\n})\nexport class TestFloatButtonTopRtlComponent {\n  direction: Direction = 'rtl';\n}\n"
  },
  {
    "path": "components/float-button/float-button-top.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { normalizePassiveListenerOptions, Platform } from '@angular/cdk/platform';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  computed,\n  DestroyRef,\n  DOCUMENT,\n  effect,\n  ElementRef,\n  inject,\n  input,\n  linkedSignal,\n  NgZone,\n  numberAttribute,\n  OnInit,\n  output,\n  signal,\n  TemplateRef,\n  untracked,\n  viewChild,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Subject, Subscription } from 'rxjs';\nimport { debounceTime, takeUntil } from 'rxjs/operators';\n\nimport { withAnimationCheck } from 'ng-zorro-antd/core/animation';\nimport { withConfigFactory } from 'ng-zorro-antd/core/config';\nimport { NzScrollService } from 'ng-zorro-antd/core/services';\nimport { NzShapeSCType } from 'ng-zorro-antd/core/types';\nimport { fromEventOutsideAngular, generateClassName } from 'ng-zorro-antd/core/util';\n\nimport { NzFloatButtonComponent } from './float-button.component';\nimport { NzFloatButtonBadge, NzFloatButtonType } from './typings';\n\nconst withConfig = withConfigFactory('floatButton');\nconst CLASS_NAME = 'ant-float-btn';\n\nconst passiveEventListenerOptions = normalizePassiveListenerOptions({ passive: true });\n\n@Component({\n  selector: 'nz-float-button-top',\n  exportAs: 'nzFloatButtonTop',\n  imports: [NzFloatButtonComponent],\n  template: `\n    @if (visible()) {\n      <nz-float-button\n        #backTop\n        [nzIcon]=\"nzIcon() || 'vertical-align-top'\"\n        [nzDescription]=\"nzDescription()\"\n        [nzHref]=\"nzHref()\"\n        [nzType]=\"nzType()\"\n        [nzShape]=\"shape()\"\n        [nzBadge]=\"nzBadge()\"\n        [animate.enter]=\"fadeAnimationEnter()\"\n        [animate.leave]=\"fadeAnimationLeave()\"\n      />\n    }\n  `,\n  host: {\n    '[class]': 'class()'\n  },\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None\n})\nexport class NzFloatButtonTopComponent implements OnInit {\n  private readonly scrollSrv = inject(NzScrollService);\n  private readonly platform = inject(Platform);\n  private readonly ngZone = inject(NgZone);\n  private readonly directionality = inject(Directionality);\n  private readonly destroyRef = inject(DestroyRef);\n  private readonly document = inject(DOCUMENT);\n\n  readonly backTop = viewChild('backTop', { read: ElementRef });\n\n  readonly nzVisibilityHeight = input<number>();\n  readonly nzHref = input<string | null>(null);\n  readonly nzType = input<NzFloatButtonType>('default');\n  readonly nzShape = input<NzShapeSCType>('circle');\n  readonly nzIcon = input<string | TemplateRef<void> | null>(null);\n  readonly nzDescription = input<TemplateRef<void> | null>(null);\n  readonly nzTemplate = input<TemplateRef<void> | null>(null);\n  readonly nzTarget = input<string | HTMLElement | null>(null);\n  readonly nzDuration = input(450, { transform: numberAttribute });\n  readonly nzBadge = input<NzFloatButtonBadge | null>(null);\n  readonly nzOnClick = output<boolean>();\n\n  protected readonly visible = signal<boolean>(false);\n  // compact global config\n  private readonly visibilityHeight = withConfig('nzVisibilityHeight', this.nzVisibilityHeight, 400);\n  readonly shape = linkedSignal(() => this.nzShape());\n  protected readonly class = computed<string[]>(() => {\n    const dir = this.directionality.valueSignal();\n    const classes = [CLASS_NAME, `${CLASS_NAME}-top`, this.generateClass(this.shape())];\n    if (dir === 'rtl') {\n      classes.push(this.generateClass(dir));\n    }\n    return classes;\n  });\n\n  protected readonly fadeAnimationEnter = withAnimationCheck(() => `${CLASS_NAME}-top-motion-enter`);\n  protected readonly fadeAnimationLeave = withAnimationCheck(() => `${CLASS_NAME}-top-motion-leave`);\n\n  private target?: HTMLElement | null = null;\n  private backTopClickSubscription = Subscription.EMPTY;\n  private scrollListenerDestroy$ = new Subject<void>();\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      this.scrollListenerDestroy$.next();\n      this.scrollListenerDestroy$.complete();\n    });\n\n    effect(() => {\n      const target = this.nzTarget();\n      if (target) {\n        this.target = typeof target === 'string' ? this.document.querySelector(target) : target;\n        this.registerScrollEvent();\n      }\n    });\n\n    effect(onCleanup => {\n      const backTop = this.backTop();\n      if (backTop) {\n        this.backTopClickSubscription.unsubscribe();\n        this.backTopClickSubscription = fromEventOutsideAngular(backTop.nativeElement, 'click')\n          .pipe(takeUntilDestroyed(this.destroyRef))\n          .subscribe(() => {\n            this.scrollSrv.scrollTo(this.getTarget(), 0, { duration: this.nzDuration() });\n            this.ngZone.run(() => this.nzOnClick.emit(true));\n          });\n      }\n      return onCleanup(() => {\n        this.backTopClickSubscription.unsubscribe();\n      });\n    });\n\n    effect(() => {\n      this.visibilityHeight();\n      untracked(() => this.handleScroll());\n    });\n  }\n\n  ngOnInit(): void {\n    this.registerScrollEvent();\n  }\n\n  private getTarget(): HTMLElement | Window {\n    return this.target || window;\n  }\n\n  private handleScroll(): void {\n    if (\n      !this.platform.isBrowser ||\n      this.visible() === this.scrollSrv.getScroll(this.getTarget()) > this.visibilityHeight()\n    ) {\n      return;\n    }\n    this.visible.update(v => !v);\n  }\n\n  private registerScrollEvent(): void {\n    if (!this.platform.isBrowser) {\n      return;\n    }\n    this.scrollListenerDestroy$.next();\n    this.handleScroll();\n    fromEventOutsideAngular(this.getTarget(), 'scroll', passiveEventListenerOptions as AddEventListenerOptions)\n      .pipe(debounceTime(50), takeUntil(this.scrollListenerDestroy$))\n      .subscribe(() => this.handleScroll());\n  }\n\n  private generateClass(suffix: string): string {\n    return generateClassName(CLASS_NAME, suffix);\n  }\n}\n"
  },
  {
    "path": "components/float-button/float-button.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport { Component, DebugElement, provideZoneChangeDetection, TemplateRef, ViewChild } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { NzShapeSCType } from 'ng-zorro-antd/core/types';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzFloatButtonComponent } from './float-button.component';\nimport { NzFloatButtonModule } from './float-button.module';\nimport { NzFloatButtonBadge, NzFloatButtonType } from './typings';\n\ndescribe('float-button', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideNoopAnimations(), provideZoneChangeDetection()]\n    });\n  });\n\n  describe('basic', () => {\n    let fixture: ComponentFixture<NzTestFloatButtonBasicComponent>;\n    let testComponent: NzTestFloatButtonBasicComponent;\n    let resultEl: DebugElement;\n    let floatButtonComponent: NzFloatButtonComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestFloatButtonBasicComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n      resultEl = fixture.debugElement.query(By.directive(NzFloatButtonComponent));\n      floatButtonComponent = resultEl.componentInstance;\n    });\n\n    it('nzType', () => {\n      testComponent.nzType = 'primary';\n      fixture.detectChanges();\n      const view = resultEl.nativeElement.querySelector('.ant-float-btn > .ant-btn-primary');\n      expect(view.tagName).toBe('BUTTON');\n    });\n\n    it('nzShape', () => {\n      testComponent.nzShape = 'square';\n      fixture.detectChanges();\n      expect(resultEl.nativeElement.classList).toContain('ant-float-btn-square');\n    });\n\n    it('nzHref && nzTarget', () => {\n      testComponent.nzTarget = '_blank';\n      testComponent.nzHref = 'https://ng.ant.design/';\n      fixture.detectChanges();\n      const view = resultEl.nativeElement.querySelector('.ant-float-btn > .ant-btn');\n      expect(view.getAttribute('href') === 'https://ng.ant.design/').toBe(true);\n      expect(view.getAttribute('target') === '_blank').toBe(true);\n    });\n\n    it('nzIcon', () => {\n      testComponent.nzIcon = testComponent.icon;\n      fixture.detectChanges();\n      const view = resultEl.nativeElement.getElementsByClassName('anticon-question-circle')[0];\n      expect(view.getAttribute('nztype') === 'question-circle').toBe(true);\n    });\n\n    it('should nzIcon support passing nzType string only', () => {\n      testComponent.nzIcon = 'file-search';\n      fixture.detectChanges();\n      const view = resultEl.nativeElement.querySelector('nz-icon');\n      expect(view.classList).toContain('anticon-file-search');\n    });\n\n    it('nzOnClick', () => {\n      resultEl.nativeElement.getElementsByClassName('ant-btn')[0].dispatchEvent(new MouseEvent('click'));\n      fixture.detectChanges();\n      expect(testComponent.isClick).toBe(true);\n    });\n\n    it('nzBadge', () => {\n      expect(resultEl.nativeElement.querySelector('.ant-badge')).toBeNull();\n      expect(floatButtonComponent.nzBadge()).toBeNull();\n      testComponent.nzBadge = { nzCount: 5 };\n      fixture.detectChanges();\n      expect(floatButtonComponent.nzBadge()).toEqual({\n        nzCount: 5\n      });\n      expect(resultEl.nativeElement.querySelector('.ant-badge')).toBeTruthy();\n    });\n  });\n\n  describe('RTL', () => {\n    let fixture: ComponentFixture<NzTestFloatButtonRtlComponent>;\n    let resultEl: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestFloatButtonRtlComponent);\n      resultEl = fixture.debugElement.query(By.directive(NzFloatButtonComponent));\n    });\n\n    it('rtl', () => {\n      fixture.detectChanges();\n      expect(resultEl.nativeElement.classList).toContain('ant-float-btn-rtl');\n    });\n  });\n});\n\n@Component({\n  selector: 'nz-test-basic-float-button',\n  imports: [NzFloatButtonModule, NzIconModule],\n  template: `\n    <nz-float-button\n      [nzIcon]=\"nzIcon\"\n      [nzDescription]=\"nzDescription\"\n      [nzHref]=\"nzHref\"\n      [nzTarget]=\"nzTarget\"\n      [nzType]=\"nzType\"\n      [nzShape]=\"nzShape\"\n      [nzBadge]=\"nzBadge\"\n      (nzOnClick)=\"onClick($event)\"\n    />\n    <ng-template #icon>\n      <nz-icon nzType=\"question-circle\" nzTheme=\"outline\" />\n    </ng-template>\n    <ng-template #description>HELP</ng-template>\n  `\n})\nexport class NzTestFloatButtonBasicComponent {\n  nzHref: string | null = null;\n  nzTarget: string | null = null;\n  nzType: NzFloatButtonType = 'default';\n  nzShape: NzShapeSCType = 'circle';\n  nzIcon: string | TemplateRef<void> | null = null;\n  nzDescription: TemplateRef<void> | null = null;\n  nzBadge: NzFloatButtonBadge | null = null;\n\n  @ViewChild('icon', { static: false }) icon!: TemplateRef<void>;\n  @ViewChild('description', { static: false }) description!: TemplateRef<void>;\n\n  isClick: boolean = false;\n\n  onClick(value: boolean): void {\n    this.isClick = value;\n  }\n}\n\n@Component({\n  imports: [BidiModule, NzFloatButtonModule],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-float-button />\n    </div>\n  `\n})\nexport class NzTestFloatButtonRtlComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n}\n"
  },
  {
    "path": "components/float-button/float-button.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  computed,\n  inject,\n  input,\n  linkedSignal,\n  output,\n  TemplateRef\n} from '@angular/core';\n\nimport { NzBadgeModule } from 'ng-zorro-antd/badge';\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzShapeSCType } from 'ng-zorro-antd/core/types';\nimport { generateClassName } from 'ng-zorro-antd/core/util';\n\nimport { NzFloatButtonContentComponent } from './float-button-content.component';\nimport { NzFloatButtonBadge, NzFloatButtonType } from './typings';\n\nconst CLASS_NAME = 'ant-float-btn';\n\n@Component({\n  selector: 'nz-float-button',\n  exportAs: 'nzFloatButton',\n  imports: [NzButtonModule, NzFloatButtonContentComponent, NzBadgeModule, NgTemplateOutlet],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    @if (!!nzHref()) {\n      <a\n        [target]=\"nzTarget()\"\n        [href]=\"nzHref()\"\n        nz-button\n        [nzType]=\"nzType()\"\n        [class.ant-float-btn-default]=\"nzType() === 'default'\"\n        class=\"ant-float-btn-inner\"\n        (click)=\"nzOnClick.emit(true)\"\n      >\n        <ng-container *ngTemplateOutlet=\"contentTemplate\" />\n      </a>\n    } @else {\n      <button\n        nz-button\n        [nzType]=\"nzType()\"\n        [class.ant-float-btn-default]=\"nzType() === 'default'\"\n        class=\"ant-float-btn-inner\"\n        (click)=\"nzOnClick.emit(true)\"\n      >\n        <ng-container *ngTemplateOutlet=\"contentTemplate\" />\n      </button>\n    }\n    <ng-template #contentTemplate>\n      <nz-float-button-content\n        [nzBadge]=\"nzBadge()\"\n        [nzIcon]=\"nzIcon()\"\n        [nzDescription]=\"nzDescription()\"\n        [nzShape]=\"shape()\"\n      />\n    </ng-template>\n  `,\n  host: {\n    '[class]': 'class()'\n  }\n})\nexport class NzFloatButtonComponent {\n  readonly nzHref = input<string | null>(null);\n  readonly nzTarget = input<string | null>(null);\n  readonly nzType = input<NzFloatButtonType>('default');\n  readonly nzIcon = input<string | TemplateRef<void> | null>(null);\n  readonly nzDescription = input<string | TemplateRef<void> | null>(null);\n  readonly nzShape = input<NzShapeSCType>('circle');\n  readonly nzBadge = input<NzFloatButtonBadge | null>(null);\n  readonly nzOnClick = output<boolean>();\n\n  readonly shape = linkedSignal(() => this.nzShape());\n  protected readonly dir = inject(Directionality).valueSignal;\n  protected readonly class = computed<string[]>(() => {\n    const dir = this.dir();\n    const classes = [CLASS_NAME, this.generateClass(this.shape())];\n    if (dir === 'rtl') {\n      classes.push(this.generateClass(dir));\n    }\n    return classes;\n  });\n\n  private generateClass(suffix: string): string {\n    return generateClassName(CLASS_NAME, suffix);\n  }\n}\n"
  },
  {
    "path": "components/float-button/float-button.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzFloatButtonContentComponent } from './float-button-content.component';\nimport { NzFloatButtonGroupComponent } from './float-button-group.component';\nimport { NzFloatButtonTopComponent } from './float-button-top.component';\nimport { NzFloatButtonComponent } from './float-button.component';\n\n@NgModule({\n  exports: [\n    NzFloatButtonComponent,\n    NzFloatButtonGroupComponent,\n    NzFloatButtonTopComponent,\n    NzFloatButtonContentComponent\n  ],\n  imports: [\n    NzFloatButtonComponent,\n    NzFloatButtonGroupComponent,\n    NzFloatButtonTopComponent,\n    NzFloatButtonContentComponent\n  ]\n})\nexport class NzFloatButtonModule {}\n"
  },
  {
    "path": "components/float-button/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/float-button/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/float-button/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './float-button.component';\nexport * from './float-button-content.component';\nexport * from './float-button-group.component';\nexport * from './float-button-top.component';\nexport * from './float-button.module';\nexport * from './typings';\n"
  },
  {
    "path": "components/float-button/style/animation.less",
    "content": "/* stylelint-disable less/no-duplicate-variables */\n@import '../../style/themes/index';\n@import '../../style/core/motion/fade';\n\n@float-btn-prefix-cls: ~'@{ant-prefix}-float-btn';\n@animation-duration: @animation-duration-slow;\n@slide-distance: 40px;\n\n.animation(@direction, @type) {\n  &-@{type}-@{direction} {\n    animation: ~\"@{type}-@{direction}\" @animation-duration @ease-in-out;\n  }\n}\n\n.keyframes(@name; @from-opacity; @to-opacity; @from-transform; @to-transform) {\n  @keyframes @name {\n    from {\n      transform: @from-transform;\n      opacity: @from-opacity;\n    }\n\n    to {\n      transform: @to-transform;\n      opacity: @to-opacity;\n    }\n  }\n}\n\n.@{float-btn-prefix-cls} {\n  // animation class\n  .animation(top, enter);\n  .animation(top, leave);\n  .animation(bottom, enter);\n  .animation(bottom, leave);\n  .animation(left, enter);\n  .animation(left, leave);\n  .animation(right, enter);\n  .animation(right, leave);\n\n  // keyframes\n  .keyframes(enter-top; 0; 1; translateY(@slide-distance); translateY(0));\n  .keyframes(leave-top; 1; 0; translateY(0); translateY(@slide-distance));\n  .keyframes(enter-bottom; 0; 1; translateY(-@slide-distance); translateY(0));\n  .keyframes(leave-bottom; 1; 0; translateY(0); translateY(-@slide-distance));\n  .keyframes(enter-left; 0; 1; translateX(@slide-distance); translateX(0));\n  .keyframes(leave-left; 1; 0; translateX(0); translateX(@slide-distance));\n  .keyframes(enter-right; 0; 1; translateX(-@slide-distance); translateX(0));\n  .keyframes(leave-right; 1; 0; translateX(0); translateX(-@slide-distance));\n\n  &-top {\n    .fade-motion('float-btn-top', linear);\n  }\n}"
  },
  {
    "path": "components/float-button/style/entry.less",
    "content": "@import './index.less';\n@import './animation.less';"
  },
  {
    "path": "components/float-button/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@float-btn-prefix-cls: ~'@{ant-prefix}-float-btn';\n@float-btn-group-prefix-cls: ~'@{ant-prefix}-float-btn-group';\n\n// patch variables\n@badge-offset: @padding-xss * 1.5;\n@dot-offset-in-circle: 5.6px;\n@dot-offset-in-square: 1px;\n@float-button-size: 40px;\n@float-button-body-size: @float-button-size - (@padding-xss * 2);\n@float-button-body-padding: @padding-xss;\n@float-button-inset-inline-end: 24px;\n@float-button-inset-block-end: @float-button-inset-inline-end * 2;\n@float-button-icon-size: @font-size-sm * 1.5;\n\n.@{float-btn-prefix-cls} {\n  position: fixed;\n  bottom: @float-button-inset-block-end;\n  z-index: 99;\n  display: block;\n  align-items: center;\n  justify-content: center;\n  width: @float-button-size;\n  height: @float-button-size;\n  border: none;\n  box-shadow: @shadow-2;\n  cursor: pointer;\n  inset-inline-end: @float-button-inset-inline-end;\n\n  &-pure {\n    position: relative;\n    inset: auto;\n  }\n\n  &:empty {\n    display: none;\n  }\n\n  .@{ant-prefix}-badge {\n    width: 100%;\n    height: 100%;\n\n    .@{ant-prefix}-badge-count {\n      top: -@badge-offset;\n      transform: translate(0, 0);\n      transform-origin: center;\n      inset-inline-end: -@badge-offset;\n    }\n  }\n\n  &-body {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    width: 100%;\n    height: 100%;\n    transition: all 0.2s;\n\n    .@{float-btn-prefix-cls}-content {\n      display: flex;\n      flex-direction: column;\n      align-items: center;\n      justify-content: center;\n      min-height: @float-button-size;\n      padding: @float-button-body-padding / 2 @float-button-body-padding;\n      overflow: hidden;\n      text-align: center;\n\n      .@{float-btn-prefix-cls}-icon {\n        width: @float-button-icon-size;\n        margin: auto;\n        font-size: @float-button-icon-size;\n        line-height: 1;\n        text-align: center;\n      }\n    }\n  }\n}\n\n.@{float-btn-prefix-cls}-inner {\n  display: block;\n  width: 100%;\n  height: 100%;\n  margin: 0;\n  padding: 0;\n  list-style: none;\n  border: none;\n}\n\n.@{float-btn-prefix-cls}-rtl {\n  direction: rtl;\n}\n\n.@{float-btn-prefix-cls}-circle {\n  height: @float-button-size;\n  border-radius: 50%;\n\n  .@{ant-prefix}-badge {\n    .@{ant-prefix}-badge-dot {\n      top: @dot-offset-in-circle;\n      inset-inline-end: @dot-offset-in-circle;\n    }\n  }\n\n  .ant-float-btn-inner, .@{float-btn-prefix-cls}-body {\n    border-radius: 50%;\n  }\n}\n\n.@{float-btn-prefix-cls}-square {\n  height: auto;\n  min-height: @float-button-size;\n  border-radius: @border-radius-base;\n\n  .@{ant-prefix}-badge {\n    .@{ant-prefix}-badge-dot {\n      top: @dot-offset-in-square;\n      inset-inline-end: @dot-offset-in-square;\n    }\n  }\n\n  .@{float-btn-prefix-cls}-body {\n    height: auto;\n    border-radius: @border-radius-base;\n  }\n}\n\n.@{float-btn-prefix-cls}-default {\n  background-color: @component-background;\n  transition: background-color 0.2s;\n\n  .@{float-btn-prefix-cls}-body {\n    background-color: @component-background;\n    transition: background-color 0.2s;\n\n    &:hover {\n      color: @text-color;\n      background-color: @background-color-base;\n    }\n\n    .@{float-btn-prefix-cls}-content {\n      .@{float-btn-prefix-cls}-icon {\n        color: @text-color;\n      }\n\n      .@{float-btn-prefix-cls}-description {\n        display: flex;\n        align-items: center;\n        color: @text-color;\n        font-size: @font-size-sm;\n        line-height: @line-height-base;\n      }\n    }\n  }\n\n  &:focus {\n    color: @text-color;\n  }\n}\n\n.@{float-btn-prefix-cls}-top {\n  padding: 0 !important;\n}\n\n.@{float-btn-group-prefix-cls} {\n  position: fixed;\n  bottom: @float-button-inset-block-end;\n  z-index: 99;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  box-sizing: border-box;\n  min-width: @float-button-size;\n  height: auto;\n  min-height: @float-button-size;\n  margin: 0;\n  padding: 0;\n  color: @text-color;\n  font-size: @font-size-base;\n  font-family: @font-family;\n  line-height: @line-height-base;\n  list-style: none;\n  border: none;\n  border-radius: @border-radius-base;\n  box-shadow: none;\n  inset-inline-end: @float-button-inset-inline-end;\n\n  &-wrap {\n    position: absolute;\n    z-index: -1;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n  }\n\n  &&-rtl {\n    direction: rtl;\n  }\n\n  .@{float-btn-prefix-cls} {\n    position: static;\n  }\n}\n\n.@{float-btn-group-prefix-cls}-top > .@{float-btn-group-prefix-cls}-wrap {\n  top: auto;\n  bottom: calc(@float-button-size + @margin-md);\n  flex-direction: column;\n\n  &::after {\n    position: absolute;\n    bottom: -@margin-md;\n    width: 100%;\n    height: @margin-md;\n    content: '';\n  }\n}\n.@{float-btn-group-prefix-cls}-bottom > .@{float-btn-group-prefix-cls}-wrap {\n  top: calc(@float-button-size + @margin-md);\n  bottom: auto;\n  flex-direction: column;\n\n  &::after {\n    position: absolute;\n    top: -@margin-md;\n    width: 100%;\n    height: @margin-md;\n    content: '';\n  }\n}\n.@{float-btn-group-prefix-cls}-left > .@{float-btn-group-prefix-cls}-wrap {\n  right: calc(@float-button-size + @margin-md);\n  left: auto;\n  flex-direction: row;\n\n  &::after {\n    position: absolute;\n    right: -@margin-md;\n    width: @margin-md;\n    height: 100%;\n    content: '';\n  }\n}\n.@{float-btn-group-prefix-cls}-right > .@{float-btn-group-prefix-cls}-wrap {\n  right: auto;\n  left: calc(@float-button-size + @margin-md);\n  flex-direction: row;\n\n  &::after {\n    position: absolute;\n    left: -@margin-md;\n    width: @margin-md;\n    height: 100%;\n    content: '';\n  }\n}\n\n.@{float-btn-group-prefix-cls}-circle {\n  gap: @margin-md;\n\n  .@{float-btn-group-prefix-cls}-wrap {\n    gap: @margin-md;\n  }\n\n  .@{float-btn-prefix-cls}-body {\n    width: @float-button-size;\n    height: @float-button-size;\n  }\n}\n\n.@{float-btn-group-prefix-cls}-square {\n  .@{float-btn-prefix-cls}-square {\n    padding: 0;\n    border-radius: 0;\n\n    &.@{float-btn-group-prefix-cls}-trigger {\n      border-radius: @border-radius-base;\n    }\n\n    &:first-child {\n      border-start-start-radius: @border-radius-base;\n      border-start-end-radius: @border-radius-base;\n    }\n\n    &:last-child {\n      border-end-start-radius: @border-radius-base;\n      border-end-end-radius: @border-radius-base;\n    }\n\n    &:not(:last-child) {\n      border-bottom: 1px solid @border-color-base;\n    }\n\n    .@{ant-prefix}-badge {\n      .@{ant-prefix}-badge-count {\n        top: -(@float-button-body-padding + @badge-offset);\n        inset-inline-end: -(@float-button-body-padding + @badge-offset);\n      }\n    }\n  }\n\n  .@{float-btn-group-prefix-cls}-wrap {\n    border-radius: @border-radius-base;\n    box-shadow: @shadow-2;\n\n    .@{float-btn-prefix-cls}-square {\n      padding: @float-button-body-padding;\n      border-radius: 0;\n      box-shadow: none;\n\n      .@{float-btn-prefix-cls}-body {\n        width: @float-button-body-size;\n        height: @float-button-body-size;\n      }\n    }\n  }\n}\n\n.@{float-btn-group-prefix-cls}-top > .@{float-btn-group-prefix-cls}-wrap, .@{float-btn-group-prefix-cls}-bottom > .@{float-btn-group-prefix-cls}-wrap {\n  > .@{float-btn-prefix-cls}-square {\n    &:first-child {\n      border-start-start-radius: @border-radius-base;\n      border-start-end-radius: @border-radius-base;\n    }\n\n    &:last-child {\n      border-end-start-radius: @border-radius-base;\n      border-end-end-radius: @border-radius-base;\n    }\n\n    &:not(:last-child) {\n      border-bottom: 1px solid @border-color-base;\n    }\n  }\n}\n\n.@{float-btn-group-prefix-cls}-left > .@{float-btn-group-prefix-cls}-wrap, .@{float-btn-group-prefix-cls}-right > .@{float-btn-group-prefix-cls}-wrap {\n  > .@{float-btn-prefix-cls}-square {\n    &:first-child {\n      border-start-start-radius: @border-radius-base;\n      border-end-start-radius: @border-radius-base;\n    }\n\n    &:last-child {\n      border-start-end-radius: @border-radius-base;\n      border-end-end-radius: @border-radius-base;\n    }\n\n    &:not(:last-child) {\n      border-inline-end: 1px solid @border-color-base;\n      border-bottom: none;\n    }\n  }\n}\n\n.@{float-btn-group-prefix-cls}-circle-shadow {\n  box-shadow: none;\n}\n\n.@{float-btn-group-prefix-cls}-square-shadow {\n  box-shadow: @shadow-2;\n\n  .@{float-btn-prefix-cls}-square {\n    padding: @float-button-body-padding;\n    box-shadow: none;\n    .@{float-btn-prefix-cls}-body {\n      width: @float-button-body-size;\n      height: @float-button-body-size;\n    }\n  }\n}\n"
  },
  {
    "path": "components/float-button/typings.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { TemplateRef } from '@angular/core';\n\nimport { NzSizeDSType } from 'ng-zorro-antd/core/types';\n\nexport type NzFloatButtonType = 'primary' | 'default';\n\n// omit nzShowDot, nzTitle, nzStatus, nzText\nexport interface NzFloatButtonBadgeProps {\n  nzShowZero: boolean;\n  nzDot: boolean;\n  nzOverflowCount: number;\n  nzColor: string;\n  nzCount: number | TemplateRef<void>;\n  nzOffset: [number, number];\n  nzSize: NzSizeDSType;\n}\n\nexport type NzFloatButtonBadge = Partial<NzFloatButtonBadgeProps>;\n"
  },
  {
    "path": "components/form/demo/advanced-search.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 高级搜索\n  en-US: Advanced search\n---\n\n## zh-CN\n\n三列栅格式的表单排列方式，常用于数据表格的高级搜索。\n\n有部分定制的样式代码，由于输入标签长度不确定，需要根据具体情况自行调整。\n\n## en-US\n\nThree columns layout is often used for advanced searching of data table.\n\nBecause the width of label is not fixed, you may need to adjust it by customizing its style.\n"
  },
  {
    "path": "components/form/demo/advanced-search.ts",
    "content": "import { Component, inject, OnInit } from '@angular/core';\nimport { FormControl, FormRecord, NonNullableFormBuilder, ReactiveFormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-form-advanced-search',\n  imports: [ReactiveFormsModule, NzButtonModule, NzFormModule, NzIconModule, NzInputModule],\n  template: `\n    <form nz-form [formGroup]=\"validateForm\" class=\"ant-advanced-search-form\">\n      <div nz-row [nzGutter]=\"24\">\n        @for (control of controlArray; track control) {\n          <div nz-col [nzSpan]=\"8\" [hidden]=\"!control.show\">\n            <nz-form-item>\n              <nz-form-label [nzFor]=\"'field' + control.index\">Field {{ control.index }}</nz-form-label>\n              <nz-form-control>\n                <input\n                  nz-input\n                  placeholder=\"placeholder\"\n                  [formControlName]=\"'field' + control.index\"\n                  [attr.id]=\"'field' + control.index\"\n                />\n              </nz-form-control>\n            </nz-form-item>\n          </div>\n        }\n      </div>\n      <div nz-row>\n        <div nz-col [nzSpan]=\"24\" class=\"search-area\">\n          <button nz-button nzType=\"primary\">Search</button>\n          <button nz-button (click)=\"resetForm()\">Clear</button>\n          <a class=\"collapse\" (click)=\"toggleCollapse()\">\n            Collapse\n            <nz-icon [nzType]=\"isCollapse ? 'down' : 'up'\" />\n          </a>\n        </div>\n      </div>\n    </form>\n    <div class=\"search-result-list\">Search Result List</div>\n  `,\n  styles: `\n    .ant-advanced-search-form {\n      padding: 24px;\n      background: #fbfbfb;\n      border: 1px solid #d9d9d9;\n      border-radius: 6px;\n    }\n\n    .search-result-list {\n      margin-top: 16px;\n      border: 1px dashed #e9e9e9;\n      border-radius: 6px;\n      background-color: #fafafa;\n      min-height: 200px;\n      text-align: center;\n      padding-top: 80px;\n    }\n\n    [nz-form-label] {\n      overflow: visible;\n    }\n\n    button {\n      margin-left: 8px;\n    }\n\n    .collapse {\n      margin-left: 8px;\n      font-size: 12px;\n    }\n\n    .search-area {\n      text-align: right;\n    }\n  `\n})\nexport class NzDemoFormAdvancedSearchComponent implements OnInit {\n  private fb = inject(NonNullableFormBuilder);\n  validateForm: FormRecord<FormControl<string>> = this.fb.record({});\n  controlArray: Array<{ index: number; show: boolean }> = [];\n  isCollapse = true;\n\n  toggleCollapse(): void {\n    this.isCollapse = !this.isCollapse;\n    this.controlArray.forEach((c, index) => {\n      c.show = this.isCollapse ? index < 6 : true;\n    });\n  }\n\n  resetForm(): void {\n    this.validateForm.reset();\n  }\n\n  ngOnInit(): void {\n    for (let i = 0; i < 10; i++) {\n      this.controlArray.push({ index: i, show: i < 6 });\n      this.validateForm.addControl(`field${i}`, this.fb.control(''));\n    }\n  }\n}\n"
  },
  {
    "path": "components/form/demo/auto-tips.md",
    "content": "---\norder: 11\ntitle:\n  zh-CN: 自动提示\n  en-US: Auto tips\n---\n\n## zh-CN\n\n让提示变得更简单。  \n需要预先自定义 `Validators` 和提供 `nzAutoTips`，它们优先级如下：\n\n- `Validators` > `nzAutoTips`\n- 通过 `@Input` 设置 `nzAutoTips`\n- 通过全局配置设置 `nzAutoTips`\n\n另外，你可以使用 `nzDisableAutoTips` 去禁用它。\n\n> 使用当前的语言环境(`zh-cn`,`en`...)作为 `nzAutoTips` 的 `key` 去查找提示，如果没找到会再用 `default` 查找一次。\n\n## en-US\n\nMake tips to be easy.  \nNeed to customize `Validators` and provide `nzAutoTips` in advance, the priority is as follows:\n\n- `Validators` > `nzAutoTips`\n- Via `@Input` set `nzAutoTips`\n- Via global config set `nzAutoTips`\n\nIn addition, you can use `nzDisableAutoTips` to disable it.\n\n> Via the current locale (`zh-cn`, `en`...) is used as the `key` of `nzAutoTips` to search for tips. If it is not found, it will be searched again with `default`.\n"
  },
  {
    "path": "components/form/demo/auto-tips.ts",
    "content": "import { Component, inject, OnDestroy, OnInit } from '@angular/core';\nimport {\n  AbstractControl,\n  NonNullableFormBuilder,\n  ReactiveFormsModule,\n  ValidationErrors,\n  ValidatorFn,\n  Validators\n} from '@angular/forms';\nimport { Observable, Observer, Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-form-auto-tips',\n  imports: [ReactiveFormsModule, NzButtonModule, NzFormModule, NzInputModule],\n  template: `\n    <form nz-form [nzAutoTips]=\"autoTips\" [formGroup]=\"validateForm\" (ngSubmit)=\"submitForm()\">\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"7\" nzRequired>Username</nz-form-label>\n        <nz-form-control [nzSpan]=\"12\" nzValidatingTip=\"Validating...\">\n          <input nz-input formControlName=\"username\" placeholder=\"async validate try to write JasonWood\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"7\" nzRequired>Mobile</nz-form-label>\n        <nz-form-control [nzSpan]=\"12\">\n          <input nz-input formControlName=\"mobile\" placeholder=\"mobile\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"7\" nzRequired>E-mail</nz-form-label>\n        <nz-form-control [nzSpan]=\"12\">\n          <input nz-input formControlName=\"email\" placeholder=\"email\" type=\"email\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"7\" nzRequired>Password</nz-form-label>\n        <nz-form-control [nzSpan]=\"12\" nzDisableAutoTips nzErrorTip=\"Please input your password!\">\n          <input nz-input type=\"password\" formControlName=\"password\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"7\" nzRequired>Confirm Password</nz-form-label>\n        <nz-form-control [nzSpan]=\"12\" nzDisableAutoTips [nzErrorTip]=\"passwordErrorTpl\">\n          <input nz-input type=\"password\" formControlName=\"confirm\" placeholder=\"confirm your password\" />\n          <ng-template #passwordErrorTpl let-control>\n            @if (control.errors?.['required']) {\n              Please confirm your password!\n            }\n            @if (control.errors?.['confirm']) {\n              Password is inconsistent!\n            }\n          </ng-template>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-control [nzOffset]=\"7\" [nzSpan]=\"12\">\n          <button nz-button nzType=\"primary\">Submit</button>\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `,\n  styles: `\n    [nz-form] {\n      max-width: 600px;\n    }\n  `\n})\nexport class NzDemoFormAutoTipsComponent implements OnInit, OnDestroy {\n  private fb = inject(NonNullableFormBuilder);\n  private destroy$ = new Subject<void>();\n  validateForm = this.fb.group({\n    username: this.fb.control(\n      '',\n      [MyValidators.required, MyValidators.maxLength(12), MyValidators.minLength(6)],\n      [this.usernameAsyncValidator]\n    ),\n    mobile: this.fb.control('', [MyValidators.required, MyValidators.mobile]),\n    email: this.fb.control('', [MyValidators.required, MyValidators.email]),\n    password: this.fb.control('', [MyValidators.required]),\n    confirm: this.fb.control('', [this.confirmValidator])\n  });\n\n  // current locale is key of the nzAutoTips\n  // if it is not found, it will be searched again with `default`\n  autoTips: Record<string, Record<string, string>> = {\n    'zh-cn': {\n      required: '必填项'\n    },\n    en: {\n      required: 'Input is required'\n    },\n    default: {\n      email: '邮箱格式不正确/The input is not valid email'\n    }\n  };\n\n  ngOnInit(): void {\n    this.validateForm.controls.password.valueChanges.pipe(takeUntil(this.destroy$)).subscribe(() => {\n      this.validateForm.controls.confirm.updateValueAndValidity();\n    });\n  }\n\n  ngOnDestroy(): void {\n    this.destroy$.next();\n    this.destroy$.complete();\n  }\n\n  submitForm(): void {\n    if (this.validateForm.valid) {\n      console.log('submit', this.validateForm.value);\n    } else {\n      Object.values(this.validateForm.controls).forEach(control => {\n        if (control.invalid) {\n          control.markAsDirty();\n          control.updateValueAndValidity({ onlySelf: true });\n        }\n      });\n    }\n  }\n\n  usernameAsyncValidator(control: AbstractControl): Observable<ValidationErrors | null> {\n    return new Observable((observer: Observer<MyValidationErrors | null>) => {\n      setTimeout(() => {\n        if (control.value === 'JasonWood') {\n          observer.next({\n            duplicated: { 'zh-cn': `用户名已存在`, en: `The username is redundant!` }\n          });\n        } else {\n          observer.next(null);\n        }\n        observer.complete();\n      }, 1000);\n    });\n  }\n\n  confirmValidator(control: AbstractControl): ValidationErrors | null {\n    if (!control.value) {\n      return { error: true, required: true };\n    } else if (control.value !== this.validateForm.controls.password.value) {\n      return { confirm: true, error: true };\n    }\n    return {};\n  }\n}\n\n// current locale is key of the MyErrorsOptions\nexport type MyErrorsOptions = { 'zh-cn': string; en: string } & Record<string, NzSafeAny>;\nexport type MyValidationErrors = Record<string, MyErrorsOptions>;\n\nexport class MyValidators extends Validators {\n  static override minLength(minLength: number): ValidatorFn {\n    return (control: AbstractControl): MyValidationErrors | null => {\n      if (Validators.minLength(minLength)(control) === null) {\n        return null;\n      }\n      return { minlength: { 'zh-cn': `最小长度为 ${minLength}`, en: `MinLength is ${minLength}` } };\n    };\n  }\n\n  static override maxLength(maxLength: number): ValidatorFn {\n    return (control: AbstractControl): MyValidationErrors | null => {\n      if (Validators.maxLength(maxLength)(control) === null) {\n        return null;\n      }\n      return { maxlength: { 'zh-cn': `最大长度为 ${maxLength}`, en: `MaxLength is ${maxLength}` } };\n    };\n  }\n\n  static mobile(control: AbstractControl): MyValidationErrors | null {\n    const value = control.value;\n\n    if (isEmptyInputValue(value)) {\n      return null;\n    }\n\n    return isMobile(value)\n      ? null\n      : { mobile: { 'zh-cn': `手机号码格式不正确`, en: `Mobile phone number is not valid` } };\n  }\n}\n\nfunction isEmptyInputValue(value: NzSafeAny): boolean {\n  return value == null || value.length === 0;\n}\n\nfunction isMobile(value: string): boolean {\n  return typeof value === 'string' && /(^1\\d{10}$)/.test(value);\n}\n"
  },
  {
    "path": "components/form/demo/coordinated.md",
    "content": "---\norder: 12\ntitle:\n  zh-CN: 表单联动\n  en-US: Coordinated Controls\n---\n\n## zh-CN\n\n使用 `setValue` 来动态设置其他控件的值。\n\n## en-US\n\nUse `setValue` to set other control's value programmaticly.\n"
  },
  {
    "path": "components/form/demo/coordinated.ts",
    "content": "import { Component, inject, OnDestroy, OnInit } from '@angular/core';\nimport { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\ntype Gender = 'male' | 'female';\n\n@Component({\n  selector: 'nz-demo-form-coordinated',\n  imports: [ReactiveFormsModule, NzButtonModule, NzFormModule, NzInputModule, NzSelectModule],\n  template: `\n    <form nz-form [formGroup]=\"validateForm\" (ngSubmit)=\"submitForm()\">\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"5\" nzRequired nzFor=\"note\">Note</nz-form-label>\n        <nz-form-control [nzSpan]=\"12\" nzErrorTip=\"Please input your username!\">\n          <input id=\"note\" type=\"text\" nz-input formControlName=\"note\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"5\" nzFor=\"gender\" nzRequired>Gender</nz-form-label>\n        <nz-form-control [nzSpan]=\"12\" nzErrorTip=\"Please select your gender!\">\n          <nz-select id=\"gender\" formControlName=\"gender\" nzPlaceHolder=\"Select a option and change input text above\">\n            <nz-option nzValue=\"male\" nzLabel=\"male\" />\n            <nz-option nzValue=\"female\" nzLabel=\"female\" />\n          </nz-select>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-control [nzSpan]=\"12\" [nzOffset]=\"5\">\n          <button nz-button nzType=\"primary\">Submit</button>\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `,\n  styles: `\n    [nz-form] {\n      max-width: 600px;\n    }\n  `\n})\nexport class NzDemoFormCoordinatedComponent implements OnInit, OnDestroy {\n  private fb = inject(FormBuilder);\n  private destroy$ = new Subject<void>();\n  validateForm = this.fb.group({\n    note: this.fb.control<string | null>(null, Validators.required),\n    gender: this.fb.control<Gender | null>(null, Validators.required)\n  });\n\n  ngOnInit(): void {\n    this.validateForm.controls.gender.valueChanges.pipe(takeUntil(this.destroy$)).subscribe(value => {\n      this.genderChange(value);\n    });\n  }\n\n  ngOnDestroy(): void {\n    this.destroy$.next();\n    this.destroy$.complete();\n  }\n\n  submitForm(): void {\n    if (this.validateForm.valid) {\n      console.log('submit', this.validateForm.value);\n    } else {\n      Object.values(this.validateForm.controls).forEach(control => {\n        if (control.invalid) {\n          control.markAsDirty();\n          control.updateValueAndValidity({ onlySelf: true });\n        }\n      });\n    }\n  }\n\n  genderChange(value: Gender | null): void {\n    this.validateForm.controls.note.setValue(value === 'male' ? 'Hi, man!' : 'Hi, lady!');\n  }\n}\n"
  },
  {
    "path": "components/form/demo/dynamic-form-item.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 动态增减表单项\n  en-US: Dynamic Form Item\n---\n\n## zh-CN\n\n动态增加、减少表单项。\n\n## en-US\n\nAdd or remove form items dynamically.\n"
  },
  {
    "path": "components/form/demo/dynamic-form-item.ts",
    "content": "import { Component, inject, OnInit } from '@angular/core';\nimport { FormArray, NonNullableFormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-form-dynamic-form-item',\n  imports: [ReactiveFormsModule, NzButtonModule, NzFormModule, NzIconModule, NzInputModule],\n  template: `\n    <form nz-form [formGroup]=\"validateForm\" (ngSubmit)=\"submitForm()\">\n      <ng-container formArrayName=\"names\">\n        @for (control of listOfControl.controls; track control) {\n          <nz-form-item>\n            @if ($first) {\n              <nz-form-label [nzXs]=\"24\" [nzSm]=\"4\" [nzFor]=\"'passenger' + $index\"> Passengers </nz-form-label>\n            }\n            <nz-form-control\n              [nzXs]=\"24\"\n              [nzSm]=\"20\"\n              [nzOffset]=\"$first ? 0 : 4\"\n              nzErrorTip=\"Please input passenger's name or delete this field.\"\n            >\n              <input\n                class=\"passenger-input\"\n                nz-input\n                placeholder=\"placeholder\"\n                [attr.id]=\"'passenger' + $index\"\n                [formControlName]=\"$index\"\n              />\n              @if ($count > 1) {\n                <nz-icon nzType=\"minus-circle-o\" class=\"dynamic-delete-button\" (click)=\"removeField($index, $event)\" />\n              }\n            </nz-form-control>\n          </nz-form-item>\n        }\n\n        <nz-form-item>\n          <nz-form-control [nzXs]=\"{ span: 24, offset: 0 }\" [nzSm]=\"{ span: 20, offset: 4 }\">\n            <button nz-button nzType=\"dashed\" class=\"add-button\" (click)=\"addField($event)\">\n              <nz-icon nzType=\"plus\" />\n              Add field\n            </button>\n          </nz-form-control>\n        </nz-form-item>\n        <nz-form-item>\n          <nz-form-control [nzXs]=\"{ span: 24, offset: 0 }\" [nzSm]=\"{ span: 20, offset: 4 }\">\n            <button nz-button nzType=\"dashed\" class=\"add-button\" (click)=\"addHeadField($event)\">\n              <nz-icon nzType=\"plus\" />\n              Add field at head\n            </button>\n          </nz-form-control>\n        </nz-form-item>\n        <nz-form-item>\n          <nz-form-control [nzXs]=\"{ span: 24, offset: 0 }\" [nzSm]=\"{ span: 20, offset: 4 }\">\n            <button nz-button nzType=\"primary\">Submit</button>\n          </nz-form-control>\n        </nz-form-item>\n      </ng-container>\n    </form>\n  `,\n  styles: `\n    .dynamic-delete-button {\n      cursor: pointer;\n      position: relative;\n      top: 4px;\n      font-size: 24px;\n      color: #999;\n      transition: all 0.3s;\n    }\n\n    .dynamic-delete-button:hover {\n      color: #777;\n    }\n\n    .passenger-input {\n      width: 60%;\n      margin-right: 8px;\n    }\n\n    [nz-form] {\n      max-width: 600px;\n    }\n\n    .add-button {\n      width: 60%;\n    }\n  `\n})\nexport class NzDemoFormDynamicFormItemComponent implements OnInit {\n  private fb = inject(NonNullableFormBuilder);\n  validateForm = this.fb.group({\n    names: this.fb.array([])\n  });\n  listOfControl = this.validateForm.get('names') as FormArray;\n\n  addField(e?: MouseEvent): void {\n    e?.preventDefault();\n    this.listOfControl.push(this.fb.control('', Validators.required));\n  }\n\n  addHeadField(e?: MouseEvent): void {\n    e?.preventDefault();\n    this.listOfControl.insert(0, this.fb.control('The head item', Validators.required));\n  }\n\n  removeField(index: number, e: MouseEvent): void {\n    e.preventDefault();\n    this.listOfControl.removeAt(index);\n  }\n\n  submitForm(): void {\n    if (this.validateForm.valid) {\n      console.log('submit', this.validateForm.value);\n    } else {\n      Object.values(this.listOfControl.controls).forEach(control => {\n        if (control.invalid) {\n          control.markAsDirty();\n          control.updateValueAndValidity({ onlySelf: true });\n        }\n      });\n    }\n  }\n\n  ngOnInit(): void {\n    this.addField();\n  }\n}\n"
  },
  {
    "path": "components/form/demo/dynamic-rule.md",
    "content": "---\norder: 13\ntitle:\n  zh-CN: 动态校验规则\n  en-US: Dynamic Rules\n---\n\n## zh-CN\n\n根据不同情况执行不同的校验规则。\n\n## en-US\n\nPerform different check rules according to different situations.\n"
  },
  {
    "path": "components/form/demo/dynamic-rule.ts",
    "content": "import { Component, inject, OnDestroy, OnInit } from '@angular/core';\nimport { NonNullableFormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzCheckboxModule } from 'ng-zorro-antd/checkbox';\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-form-dynamic-rule',\n  imports: [ReactiveFormsModule, NzButtonModule, NzCheckboxModule, NzFormModule, NzInputModule],\n  template: `\n    <form nz-form [formGroup]=\"validateForm\" (ngSubmit)=\"submitForm()\">\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"4\" nzRequired nzFor=\"name\">Name</nz-form-label>\n        <nz-form-control [nzSpan]=\"8\" nzErrorTip=\"Please input your name\">\n          <input type=\"text\" nz-input formControlName=\"name\" placeholder=\"Please input your name\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"4\" nzFor=\"nickname\" [nzRequired]=\"validateForm.controls.required.value\">\n          Nickname\n        </nz-form-label>\n        <nz-form-control [nzSpan]=\"8\" nzErrorTip=\"Please input your nickname\">\n          <input type=\"text\" nz-input formControlName=\"nickname\" placeholder=\"Please input your nickname\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-control [nzSpan]=\"8\" [nzOffset]=\"4\">\n          <label nz-checkbox formControlName=\"required\">Nickname is required</label>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-control [nzSpan]=\"8\" [nzOffset]=\"4\">\n          <button nz-button nzType=\"primary\">Check</button>\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `\n})\nexport class NzDemoFormDynamicRuleComponent implements OnInit, OnDestroy {\n  private fb = inject(NonNullableFormBuilder);\n  private destroy$ = new Subject<void>();\n  validateForm = this.fb.group({\n    name: this.fb.control('', [Validators.required]),\n    nickname: this.fb.control(''),\n    required: this.fb.control(false)\n  });\n\n  ngOnInit(): void {\n    this.validateForm.controls.required.valueChanges.pipe(takeUntil(this.destroy$)).subscribe(value => {\n      this.requiredChange(value);\n    });\n  }\n\n  ngOnDestroy(): void {\n    this.destroy$.next();\n    this.destroy$.complete();\n  }\n\n  submitForm(): void {\n    if (this.validateForm.valid) {\n      console.log('submit', this.validateForm.value);\n    } else {\n      Object.values(this.validateForm.controls).forEach(control => {\n        if (control.invalid) {\n          control.markAsDirty();\n          control.updateValueAndValidity({ onlySelf: true });\n        }\n      });\n    }\n  }\n\n  requiredChange(required: boolean): void {\n    if (!required) {\n      this.validateForm.controls.nickname.clearValidators();\n      this.validateForm.controls.nickname.markAsPristine();\n    } else {\n      this.validateForm.controls.nickname.setValidators(Validators.required);\n      this.validateForm.controls.nickname.markAsDirty();\n    }\n    this.validateForm.controls.nickname.updateValueAndValidity();\n  }\n}\n"
  },
  {
    "path": "components/form/demo/horizontal-login.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 内联登录栏\n  en-US: Inline Login Form\n---\n\n## zh-CN\n\n内联登录栏，常用在顶部导航栏中。\n\n## en-US\n\nInline login form is often used in navigation bar.\n"
  },
  {
    "path": "components/form/demo/horizontal-login.ts",
    "content": "import { Component, inject } from '@angular/core';\nimport { NonNullableFormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-form-horizontal-login',\n  imports: [ReactiveFormsModule, NzButtonModule, NzFormModule, NzInputModule],\n  template: `\n    <form nz-form nzLayout=\"inline\" [formGroup]=\"validateForm\" (ngSubmit)=\"submitForm()\">\n      <nz-form-item>\n        <nz-form-control nzErrorTip=\"Please input your username!\">\n          <nz-input-wrapper>\n            <nz-icon nzInputPrefix nzType=\"user\" />\n            <input formControlName=\"username\" nz-input placeholder=\"username\" />\n          </nz-input-wrapper>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-control nzErrorTip=\"Please input your Password!\">\n          <nz-input-password>\n            <nz-icon nzInputPrefix nzType=\"lock\" />\n            <input formControlName=\"password\" nz-input placeholder=\"Password\" />\n          </nz-input-password>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-control>\n          <button nz-button nzType=\"primary\" [disabled]=\"!validateForm.valid\">Log in</button>\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `\n})\nexport class NzDemoFormHorizontalLoginComponent {\n  private fb = inject(NonNullableFormBuilder);\n  validateForm = this.fb.group({\n    username: this.fb.control('', [Validators.required]),\n    password: this.fb.control('', [Validators.required]),\n    remember: this.fb.control(true)\n  });\n\n  submitForm(): void {\n    console.log('submit', this.validateForm.value);\n  }\n}\n"
  },
  {
    "path": "components/form/demo/label-align.md",
    "content": "---\norder: 15\ntitle:\n  zh-CN: 表单标签文本对齐方式\n  en-US: Text align of form label\n---\n\n## zh-CN\n\n表单标签文本对齐方式。\n\n## en-US\n\ntext align of form label.\n"
  },
  {
    "path": "components/form/demo/label-align.ts",
    "content": "import { Component, inject } from '@angular/core';\nimport { NonNullableFormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';\n\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-form-label-align',\n  imports: [ReactiveFormsModule, NzFormModule, NzInputModule],\n  template: `\n    <form nz-form [formGroup]=\"validateForm\" (ngSubmit)=\"submitForm()\">\n      <nz-form-item>\n        <nz-form-label nzRequired nzLabelAlign=\"left\" nzSpan=\"4\">Left-aligned text label</nz-form-label>\n        <nz-form-control nzErrorTip=\"Please input your username!\" nzSpan=\"8\">\n          <input formControlName=\"username\" nz-input placeholder=\"username\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label nzRequired nzLabelAlign=\"right\" nzSpan=\"4\">Right-aligned text label</nz-form-label>\n        <nz-form-control nzErrorTip=\"Please input your Password!\" nzSpan=\"8\">\n          <input formControlName=\"password\" nz-input type=\"password\" placeholder=\"Password\" />\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `\n})\nexport class NzDemoFormLabelAlignComponent {\n  private fb = inject(NonNullableFormBuilder);\n  validateForm = this.fb.group({\n    username: this.fb.control('', [Validators.required]),\n    password: this.fb.control('', [Validators.required]),\n    remember: this.fb.control(true)\n  });\n\n  submitForm(): void {\n    console.log('submit', this.validateForm.value);\n  }\n}\n"
  },
  {
    "path": "components/form/demo/label-wrap.md",
    "content": "---\norder: 14\ntitle:\n  zh-CN: 表单标签可换行\n  en-US: Label can wrap\n---\n\n## zh-CN\n\n使用 `nzLabelWrap` 可以开启 `label` 换行。\n\n## en-US\n\nTurn on `nzLabelWrap` to wrap label if text is long.\n"
  },
  {
    "path": "components/form/demo/label-wrap.ts",
    "content": "import { Component, inject } from '@angular/core';\nimport { NonNullableFormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-form-label-wrap',\n  imports: [ReactiveFormsModule, NzButtonModule, NzFormModule, NzInputModule],\n  template: `\n    <form nz-form [formGroup]=\"validateForm\" nzNoColon nzLabelAlign=\"left\" (ngSubmit)=\"submitForm()\">\n      <nz-form-item>\n        <nz-form-label nzRequired nzFor=\"user\" nzSpan=\"3\"> Normal text label </nz-form-label>\n        <nz-form-control nzErrorTip=\"Please input your username!\" nzSpan=\"8\">\n          <input formControlName=\"username\" nz-input id=\"user\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label nzRequired nzFor=\"label-wrap-password\" nzSpan=\"3\" nzLabelWrap>\n          Long text label Long text label\n        </nz-form-label>\n        <nz-form-control nzErrorTip=\"Please input your Password!\" nzSpan=\"8\">\n          <input formControlName=\"password\" nz-input type=\"password\" id=\"label-wrap-password\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-control nzSpan=\"12\" style=\"text-align: center\">\n          <button nz-button nzType=\"primary\">Log in</button>\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `\n})\nexport class NzDemoFormLabelWrapComponent {\n  private fb = inject(NonNullableFormBuilder);\n  validateForm = this.fb.group({\n    username: this.fb.control('', [Validators.required]),\n    password: this.fb.control('', [Validators.required]),\n    remember: this.fb.control(true)\n  });\n\n  submitForm(): void {\n    console.log('submit', this.validateForm.value);\n  }\n}\n"
  },
  {
    "path": "components/form/demo/layout.md",
    "content": "---\norder: 12\ntitle:\n  zh-CN: 表单布局\n  en-US: Form Layout\n---\n\n## zh-CN\n\n表单有三种布局。\n\n## en-US\n\nThere are three layout for form: `horizontal`, `vertical`, `inline`.\n"
  },
  {
    "path": "components/form/demo/layout.ts",
    "content": "import { Component, inject } from '@angular/core';\nimport { NonNullableFormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzFormLayoutType, NzFormModule } from 'ng-zorro-antd/form';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\n\n@Component({\n  selector: 'nz-demo-form-layout',\n  imports: [ReactiveFormsModule, NzButtonModule, NzFormModule, NzInputModule, NzRadioModule],\n  template: `\n    <form\n      nz-form\n      [nzLayout]=\"validateForm.controls.formLayout.value\"\n      [formGroup]=\"validateForm\"\n      (ngSubmit)=\"submitForm()\"\n    >\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"isHorizontal ? 4 : null\">Form Layout</nz-form-label>\n        <nz-form-control [nzSpan]=\"isHorizontal ? 14 : null\">\n          <nz-radio-group formControlName=\"formLayout\">\n            <label nz-radio-button nzValue=\"horizontal\">Horizontal</label>\n            <label nz-radio-button nzValue=\"vertical\">Vertical</label>\n            <label nz-radio-button nzValue=\"inline\">Inline</label>\n          </nz-radio-group>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"isHorizontal ? 4 : null\">Field A</nz-form-label>\n        <nz-form-control [nzSpan]=\"isHorizontal ? 14 : null\" nzErrorTip=\"Please input your username!\">\n          <input nz-input formControlName=\"fieldA\" placeholder=\"input placeholder\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"isHorizontal ? 4 : null\">Field B</nz-form-label>\n        <nz-form-control [nzSpan]=\"isHorizontal ? 14 : null\" nzErrorTip=\"Please input your Password!\">\n          <input nz-input formControlName=\"filedB\" placeholder=\"input placeholder\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-control [nzSpan]=\"isHorizontal ? 14 : null\" [nzOffset]=\"isHorizontal ? 4 : null\">\n          <button nz-button nzType=\"primary\">Submit</button>\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `,\n  styles: `\n    [nz-form]:not(.ant-form-inline):not(.ant-form-vertical) {\n      max-width: 600px;\n    }\n  `\n})\nexport class NzDemoFormLayoutComponent {\n  private fb = inject(NonNullableFormBuilder);\n  validateForm = this.fb.group({\n    formLayout: this.fb.control<NzFormLayoutType>('horizontal'),\n    fieldA: this.fb.control('', [Validators.required]),\n    filedB: this.fb.control('', [Validators.required])\n  });\n\n  submitForm(): void {\n    if (this.validateForm.valid) {\n      console.log('submit', this.validateForm.value);\n    } else {\n      Object.values(this.validateForm.controls).forEach(control => {\n        if (control.invalid) {\n          control.markAsDirty();\n          control.updateValueAndValidity({ onlySelf: true });\n        }\n      });\n    }\n  }\n\n  get isHorizontal(): boolean {\n    return this.validateForm.controls.formLayout.value === 'horizontal';\n  }\n}\n"
  },
  {
    "path": "components/form/demo/normal-login.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 登录框\n  en-US: Login Form\n---\n\n## zh-CN\n\n普通的登录框，可以容纳更多的元素。\n\n## en-US\n\nNormal login form which can contain more elements.\n"
  },
  {
    "path": "components/form/demo/normal-login.ts",
    "content": "import { Component, inject } from '@angular/core';\nimport { NonNullableFormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzCheckboxModule } from 'ng-zorro-antd/checkbox';\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-form-normal-login',\n  imports: [ReactiveFormsModule, NzButtonModule, NzCheckboxModule, NzFormModule, NzInputModule],\n  template: `\n    <form nz-form [formGroup]=\"validateForm\" class=\"login-form\" (ngSubmit)=\"submitForm()\">\n      <nz-form-item>\n        <nz-form-control nzErrorTip=\"Please input your username!\">\n          <nz-input-wrapper>\n            <nz-icon nzInputPrefix nzType=\"user\" />\n            <input type=\"text\" nz-input formControlName=\"username\" placeholder=\"Username\" />\n          </nz-input-wrapper>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-control nzErrorTip=\"Please input your Password!\">\n          <nz-input-password>\n            <nz-icon nzInputPrefix nzType=\"lock\" />\n            <input nz-input formControlName=\"password\" placeholder=\"Password\" />\n          </nz-input-password>\n        </nz-form-control>\n      </nz-form-item>\n      <div nz-row class=\"login-form-margin\">\n        <div nz-col [nzSpan]=\"12\">\n          <label nz-checkbox formControlName=\"remember\">\n            <span>Remember me</span>\n          </label>\n        </div>\n        <div nz-col [nzSpan]=\"12\">\n          <a class=\"login-form-forgot\">Forgot password</a>\n        </div>\n      </div>\n      <button nz-button class=\"login-form-button login-form-margin\" nzType=\"primary\">Log in</button>\n      Or\n      <a>register now!</a>\n    </form>\n  `,\n  styles: `\n    .login-form {\n      max-width: 300px;\n    }\n\n    .login-form-margin {\n      margin-bottom: 16px;\n    }\n\n    .login-form-forgot {\n      float: right;\n    }\n\n    .login-form-button {\n      width: 100%;\n    }\n  `\n})\nexport class NzDemoFormNormalLoginComponent {\n  private fb = inject(NonNullableFormBuilder);\n  validateForm = this.fb.group({\n    username: this.fb.control('', [Validators.required]),\n    password: this.fb.control('', [Validators.required]),\n    remember: this.fb.control(true)\n  });\n\n  submitForm(): void {\n    if (this.validateForm.valid) {\n      console.log('submit', this.validateForm.value);\n    } else {\n      Object.values(this.validateForm.controls).forEach(control => {\n        if (control.invalid) {\n          control.markAsDirty();\n          control.updateValueAndValidity({ onlySelf: true });\n        }\n      });\n    }\n  }\n}\n"
  },
  {
    "path": "components/form/demo/register.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 注册新用户\n  en-US: Registration\n---\n\n## zh-CN\n\n用户填写必须的信息以注册新用户。\n\n## en-US\n\nFill in this form to create a new account for you.\n"
  },
  {
    "path": "components/form/demo/register.ts",
    "content": "import { Component, inject, OnDestroy, OnInit } from '@angular/core';\nimport {\n  AbstractControl,\n  NonNullableFormBuilder,\n  ReactiveFormsModule,\n  ValidationErrors,\n  Validators\n} from '@angular/forms';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzCheckboxModule } from 'ng-zorro-antd/checkbox';\nimport { NzFormModule, NzFormTooltipIcon } from 'ng-zorro-antd/form';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\n@Component({\n  selector: 'nz-demo-form-register',\n  imports: [ReactiveFormsModule, NzButtonModule, NzCheckboxModule, NzFormModule, NzInputModule, NzSelectModule],\n  template: `\n    <form nz-form [formGroup]=\"validateForm\" (ngSubmit)=\"submitForm()\">\n      <nz-form-item>\n        <nz-form-label [nzSm]=\"6\" [nzXs]=\"24\" nzRequired nzFor=\"email\">E-mail</nz-form-label>\n        <nz-form-control [nzSm]=\"14\" [nzXs]=\"24\" nzErrorTip=\"The input is not valid E-mail!\">\n          <input nz-input formControlName=\"email\" id=\"email\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSm]=\"6\" [nzXs]=\"24\" nzFor=\"password\" nzRequired>Password</nz-form-label>\n        <nz-form-control [nzSm]=\"14\" [nzXs]=\"24\" nzErrorTip=\"Please input your password!\">\n          <input nz-input type=\"password\" id=\"password\" formControlName=\"password\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSm]=\"6\" [nzXs]=\"24\" nzFor=\"checkPassword\" nzRequired>Confirm Password</nz-form-label>\n        <nz-form-control [nzSm]=\"14\" [nzXs]=\"24\" [nzErrorTip]=\"errorTpl\">\n          <input nz-input type=\"password\" formControlName=\"checkPassword\" id=\"checkPassword\" />\n          <ng-template #errorTpl let-control>\n            @if (control.errors?.['required']) {\n              Please confirm your password!\n            }\n            @if (control.errors?.['confirm']) {\n              Two passwords that you enter is inconsistent!\n            }\n          </ng-template>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label\n          [nzSm]=\"6\"\n          [nzXs]=\"24\"\n          nzFor=\"nickname\"\n          nzRequired\n          nzTooltipTitle=\"What do you want other to call you\"\n        >\n          <span>Nickname</span>\n        </nz-form-label>\n        <nz-form-control [nzSm]=\"14\" [nzXs]=\"24\" nzErrorTip=\"Please input your nickname!\">\n          <input nz-input id=\"nickname\" formControlName=\"nickname\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSm]=\"6\" [nzXs]=\"24\" nzFor=\"phoneNumber\" nzRequired>Phone Number</nz-form-label>\n        <nz-form-control\n          [nzSm]=\"14\"\n          [nzXs]=\"24\"\n          [nzValidateStatus]=\"validateForm.controls['phoneNumber']\"\n          nzErrorTip=\"Please input your phone number!\"\n        >\n          <nz-input-wrapper>\n            <nz-select nzInputAddonBefore formControlName=\"phoneNumberPrefix\" class=\"phone-select\">\n              <nz-option nzLabel=\"+86\" nzValue=\"+86\" />\n              <nz-option nzLabel=\"+87\" nzValue=\"+87\" />\n            </nz-select>\n            <input formControlName=\"phoneNumber\" id=\"'phoneNumber'\" nz-input />\n          </nz-input-wrapper>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSm]=\"6\" [nzXs]=\"24\" nzFor=\"website\" nzRequired>Website</nz-form-label>\n        <nz-form-control [nzSm]=\"14\" [nzXs]=\"24\" nzErrorTip=\"Please input website!\">\n          <input nz-input id=\"website\" formControlName=\"website\" placeholder=\"website\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label\n          [nzSm]=\"6\"\n          [nzXs]=\"24\"\n          nzFor=\"captcha\"\n          nzRequired\n          nzTooltipTitle=\"Please click 'Get captcha'\"\n          [nzTooltipIcon]=\"captchaTooltipIcon\"\n        >\n          Captcha\n        </nz-form-label>\n        <nz-form-control\n          [nzSm]=\"14\"\n          [nzXs]=\"24\"\n          nzErrorTip=\"Please input the captcha you got!\"\n          nzExtra=\"We must make sure that your are a human.\"\n        >\n          <div nz-row [nzGutter]=\"8\">\n            <div nz-col [nzSpan]=\"12\">\n              <input nz-input formControlName=\"captcha\" id=\"captcha\" />\n            </div>\n            <div nz-col [nzSpan]=\"12\">\n              <button nz-button (click)=\"getCaptcha($event)\">Get captcha</button>\n            </div>\n          </div>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item nz-row class=\"register-area\">\n        <nz-form-control [nzSpan]=\"14\" [nzOffset]=\"6\">\n          <label nz-checkbox formControlName=\"agree\">\n            <span>\n              I have read the\n              <a>agreement</a>\n            </span>\n          </label>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item nz-row class=\"register-area\">\n        <nz-form-control [nzSpan]=\"14\" [nzOffset]=\"6\">\n          <button nz-button nzType=\"primary\">Register</button>\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `,\n  styles: `\n    [nz-form] {\n      max-width: 600px;\n    }\n\n    .ant-select.ant-select-in-form-item.phone-select {\n      width: 80px;\n    }\n\n    .register-area {\n      margin-bottom: 8px;\n    }\n  `\n})\nexport class NzDemoFormRegisterComponent implements OnInit, OnDestroy {\n  private fb = inject(NonNullableFormBuilder);\n  private destroy$ = new Subject<void>();\n  validateForm = this.fb.group({\n    email: this.fb.control('', [Validators.email, Validators.required]),\n    password: this.fb.control('', [Validators.required]),\n    checkPassword: this.fb.control('', [Validators.required, this.confirmationValidator]),\n    nickname: this.fb.control('', [Validators.required]),\n    phoneNumberPrefix: this.fb.control<'+86' | '+87'>('+86'),\n    phoneNumber: this.fb.control('', [Validators.required]),\n    website: this.fb.control('', [Validators.required]),\n    captcha: this.fb.control('', [Validators.required]),\n    agree: this.fb.control(false)\n  });\n  captchaTooltipIcon: NzFormTooltipIcon = {\n    type: 'info-circle',\n    theme: 'twotone'\n  };\n\n  ngOnInit(): void {\n    this.validateForm.controls.password.valueChanges.pipe(takeUntil(this.destroy$)).subscribe(() => {\n      this.validateForm.controls.checkPassword.updateValueAndValidity();\n    });\n  }\n\n  ngOnDestroy(): void {\n    this.destroy$.next();\n    this.destroy$.complete();\n  }\n\n  submitForm(): void {\n    if (this.validateForm.valid) {\n      console.log('submit', this.validateForm.value);\n    } else {\n      Object.values(this.validateForm.controls).forEach(control => {\n        if (control.invalid) {\n          control.markAsDirty();\n          control.updateValueAndValidity({ onlySelf: true });\n        }\n      });\n    }\n  }\n\n  confirmationValidator(control: AbstractControl): ValidationErrors | null {\n    if (!control.value) {\n      return { required: true };\n    } else if (control.value !== control.parent!.value.password) {\n      return { confirm: true, error: true };\n    }\n    return {};\n  }\n\n  getCaptcha(e: MouseEvent): void {\n    e.preventDefault();\n  }\n}\n"
  },
  {
    "path": "components/form/demo/required-style.md",
    "content": "---\norder: 16\nversion: 20.4.0\ntitle:\n  zh-CN: 必选样式\n  en-US: Required style\n---\n\n## zh-CN\n\n通过 `nzRequiredMark` 切换必选与可选样式。\n\n## en-US\n\nSwitch required or optional style with `nzRequiredMark`.\n"
  },
  {
    "path": "components/form/demo/required-style.ts",
    "content": "import { NgTemplateOutlet } from '@angular/common';\nimport { Component, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzFormModule, type NzRequiredMark } from 'ng-zorro-antd/form';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\nimport { NzTagModule } from 'ng-zorro-antd/tag';\n\n@Component({\n  selector: 'nz-demo-form-required-style',\n  imports: [FormsModule, NzFormModule, NzRadioModule, NzInputModule, NgTemplateOutlet, NzTagModule],\n  template: `\n    <form nz-form [nzRequiredMark]=\"requiredMarkStyle()\">\n      <nz-radio-group [(ngModel)]=\"requiredMarkStyle\" name=\"requiredMarkStyle\">\n        <label nz-radio-button [nzValue]=\"true\">Default</label>\n        <label nz-radio-button nzValue=\"optional\">Optional</label>\n        <label nz-radio-button [nzValue]=\"false\">Hidden</label>\n        <label nz-radio-button [nzValue]=\"customRequiredMark\">Custom</label>\n      </nz-radio-group>\n      <nz-form-item>\n        <nz-form-label nzFor=\"fieldA\" nzRequired>Field A</nz-form-label>\n        <nz-form-control>\n          <input type=\"text\" nz-input id=\"fieldA\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label nzFor=\"fieldB\">Field B</nz-form-label>\n        <nz-form-control>\n          <input type=\"text\" nz-input id=\"fieldB\" />\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n\n    <ng-template #customRequiredMark let-label let-required=\"required\">\n      @if (required) {\n        <nz-tag nzColor=\"red\">Required</nz-tag>\n      } @else {\n        <nz-tag nzColor=\"orange\">Optional</nz-tag>\n      }\n      <ng-container *ngTemplateOutlet=\"label\" />\n    </ng-template>\n  `,\n  styles: `\n    nz-radio-group {\n      margin-bottom: 16px;\n    }\n    [nz-form] {\n      max-width: 600px;\n    }\n  `\n})\nexport class NzDemoFormRequiredStyleComponent {\n  readonly requiredMarkStyle = signal<NzRequiredMark>('optional');\n}\n"
  },
  {
    "path": "components/form/demo/size.md",
    "content": "---\norder: 16\nversion: 21.1.0\ntitle:\n  zh-CN: 表单尺寸\n  en-US: Form size\n---\n\n## zh-CN\n\n设置表单组件尺寸，仅对 antd 组件有效。\n\n## en-US\n\nSet component size, only works for antd components.\n"
  },
  {
    "path": "components/form/demo/size.ts",
    "content": "import { Component, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzCascaderModule } from 'ng-zorro-antd/cascader';\nimport { NzColorPickerModule } from 'ng-zorro-antd/color-picker';\nimport type { NzSizeLDSType } from 'ng-zorro-antd/core/types';\nimport { NzDatePickerModule } from 'ng-zorro-antd/date-picker';\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzInputNumberModule } from 'ng-zorro-antd/input-number';\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\nimport { NzSelectModule } from 'ng-zorro-antd/select';\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\nimport { NzTimePickerModule } from 'ng-zorro-antd/time-picker';\nimport { NzTreeSelectModule } from 'ng-zorro-antd/tree-select';\n\n@Component({\n  selector: 'nz-demo-form-size',\n  imports: [\n    FormsModule,\n    NzFormModule,\n    NzRadioModule,\n    NzInputModule,\n    NzInputNumberModule,\n    NzCascaderModule,\n    NzSelectModule,\n    NzTreeSelectModule,\n    NzDatePickerModule,\n    NzButtonModule,\n    NzTimePickerModule,\n    NzSwitchModule,\n    NzColorPickerModule\n  ],\n  template: `\n    <form nz-form [nzSize]=\"size()\">\n      <nz-form-item>\n        <nz-form-label>Size</nz-form-label>\n        <nz-form-control>\n          <nz-radio-group name=\"size\" [(ngModel)]=\"size\">\n            <label nz-radio-button nzValue=\"small\">Small</label>\n            <label nz-radio-button nzValue=\"default\">Default</label>\n            <label nz-radio-button nzValue=\"large\">Large</label>\n          </nz-radio-group>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label>Input</nz-form-label>\n        <nz-form-control>\n          <input nz-input />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label>Input Number</nz-form-label>\n        <nz-form-control>\n          <nz-input-number />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label>Cascader</nz-form-label>\n        <nz-form-control>\n          <nz-cascader [nzOptions]=\"[]\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label>Select</nz-form-label>\n        <nz-form-control>\n          <nz-select [nzOptions]=\"[]\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label>Tree Select</nz-form-label>\n        <nz-form-control>\n          <nz-tree-select [nzExpandedKeys]=\"expandKeys\" nzShowSearch nzPlaceHolder=\"Please select\" [nzNodes]=\"nodes\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label>Date Picker</nz-form-label>\n        <nz-form-control>\n          <nz-date-picker />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label>Time Picker</nz-form-label>\n        <nz-form-control>\n          <nz-time-picker />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label>Switch</nz-form-label>\n        <nz-form-control>\n          <nz-switch />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label>Color Picker</nz-form-label>\n        <nz-color-picker />\n      </nz-form-item>\n      <button nz-button nzType=\"primary\">Button</button>\n    </form>\n  `\n})\nexport class NzDemoFormSizeComponent {\n  readonly size = signal<NzSizeLDSType>('default');\n\n  expandKeys = ['100', '1001'];\n\n  readonly nodes = [\n    {\n      title: 'parent 1',\n      key: '100',\n      children: [\n        {\n          title: 'parent 1-0',\n          key: '1001',\n          children: [\n            { title: 'leaf 1-0-0', key: '10010', isLeaf: true },\n            { title: 'leaf 1-0-1', key: '10011', isLeaf: true }\n          ]\n        },\n        {\n          title: 'parent 1-1',\n          key: '1002',\n          children: [{ title: 'leaf 1-1-0', key: '10020', isLeaf: true }]\n        }\n      ]\n    }\n  ];\n}\n"
  },
  {
    "path": "components/form/demo/time-related-controls.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 时间类控件\n  en-US: Time-related Controls\n---\n\n## zh-CN\n\n时间类组件的输入和输出类型均为 `Date` 类型，可以通过 [date-fns](https://date-fns.org/) 工具库进行进一步的处理。\n\n## en-US\n\nAll the types of input and output in time-related components are `Date`. You can use [date-fns](https://date-fns.org/) to handle it.\n"
  },
  {
    "path": "components/form/demo/time-related-controls.ts",
    "content": "import { Component, inject } from '@angular/core';\nimport { FormBuilder, ReactiveFormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzDatePickerModule } from 'ng-zorro-antd/date-picker';\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzTimePickerModule } from 'ng-zorro-antd/time-picker';\n\n@Component({\n  selector: 'nz-demo-form-time-related-controls',\n  imports: [ReactiveFormsModule, NzButtonModule, NzDatePickerModule, NzFormModule, NzTimePickerModule],\n  template: `\n    <form nz-form [formGroup]=\"validateForm\" (ngSubmit)=\"submitForm()\">\n      <nz-form-item>\n        <nz-form-label [nzSm]=\"8\" [nzXs]=\"24\" nzRequired>DatePicker</nz-form-label>\n        <nz-form-control [nzSm]=\"16\" [nzXs]=\"24\">\n          <nz-date-picker formControlName=\"datePicker\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSm]=\"8\" [nzXs]=\"24\" nzRequired>DatePicker[ShowTime]</nz-form-label>\n        <nz-form-control [nzSm]=\"16\" [nzXs]=\"24\">\n          <nz-date-picker nzShowTime formControlName=\"datePickerTime\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSm]=\"8\" [nzXs]=\"24\" nzRequired>MonthPicker</nz-form-label>\n        <nz-form-control [nzSm]=\"16\" [nzXs]=\"24\">\n          <nz-date-picker nzMode=\"month\" formControlName=\"monthPicker\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSm]=\"8\" [nzXs]=\"24\" nzRequired>RangePicker</nz-form-label>\n        <nz-form-control [nzSm]=\"16\" [nzXs]=\"24\">\n          <nz-range-picker formControlName=\"rangePicker\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSm]=\"8\" [nzXs]=\"24\" nzRequired>RangePicker[showTime]</nz-form-label>\n        <nz-form-control [nzSm]=\"16\" [nzXs]=\"24\">\n          <nz-range-picker nzShowTime formControlName=\"rangePickerTime\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSm]=\"8\" [nzXs]=\"24\" nzRequired>TimePicker</nz-form-label>\n        <nz-form-control [nzSm]=\"16\" [nzXs]=\"24\">\n          <nz-time-picker formControlName=\"timePicker\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-control [nzXs]=\"{ span: 24, offset: 0 }\" [nzSm]=\"{ span: 16, offset: 8 }\">\n          <button nz-button nzType=\"primary\">Submit</button>\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `,\n  styles: `\n    form {\n      max-width: 600px;\n    }\n  `\n})\nexport class NzDemoFormTimeRelatedControlsComponent {\n  private fb = inject(FormBuilder);\n  validateForm = this.fb.group({\n    datePicker: this.fb.control<Date | null>(null),\n    datePickerTime: this.fb.control<Date | null>(null),\n    monthPicker: this.fb.control<Date | null>(null),\n    rangePicker: this.fb.control<[Date, Date] | null>(null),\n    rangePickerTime: this.fb.control<[Date, Date] | null>(null),\n    timePicker: this.fb.control<Date | null>(null)\n  });\n\n  submitForm(): void {\n    console.log(this.validateForm.value);\n  }\n}\n"
  },
  {
    "path": "components/form/demo/validate-reactive.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 响应式表单验证\n  en-US: Reactive Forms Validation\n---\n\n## zh-CN\n\n我们在 `nz-form-control` 上 提供了 `nzValidateStatus` `nzHasFeedback` 等属性，当使用[响应式表单](https://angular.cn/guide/forms/reactive-forms)时，可以自己定义校验的时机和内容。\n\n1. `nzValidateStatus`: 校验状态，默认自动从 `nz-form-control` 中的 `NgControl` 获得校验状态，也可以手动指定为特定的 `NgControl`。\n2. `nzHasFeedback`：用于给输入框添加反馈图标。\n3. `nzSuccessTip` `nzWarningTip` `nzErrorTip` `nzValidatingTip`：设置不同状态校验文案。\n   > 当同一种状态下存在多种提示情况时，`nzSuccessTip` `nzWarningTip` `nzErrorTip` `nzValidatingTip` 均支持传入 `TemplateRef<{ $implicit: FormControl }` 类型，可以通过[模板变量](https://www.angular.cn/guide/template-syntax)导出 `FormControl` 后用于切换不同的提示信息。\n   > 当 FormControl.status 为 `INVALID` 并且错误包含 `{warning：true}` 时，`nz-form-control` 显示警告状态。\n\n## en-US\n\nWe provide properties like `nzValidateStatus` `nzHasFeedback` in `nz-form-control` to customize your own validate status and message, when using [reactive forms](https://angular.dev/guide/forms/reactive-forms).\n\n1. `nzValidateStatus`: validate status of form components, the default status comes from the `NgControl` in `nz-form-control`, you can set other `NgControl` to it.\n2. `nzHasFeedback`: display feed icon of input control\n3. `nzSuccessTip` `nzWarningTip` `nzErrorTip` `nzValidatingTip`：display validate message。\n   > When there are multiple tips in the same state, `nzSuccessTip` `nzWarningTip` `nzErrorTip` `nzValidatingTip` supports the passing `TemplateRef<{ $implicit: FormControl }` type, which can be used to switch tips after exporting `FormControl` via the [template syntax](https://angular.dev/guide/templates).\n   > When the FormControl.status is `INVALID`, and the errors contains `{warning:true}` , the `nz-form-control` display with warning status.\n"
  },
  {
    "path": "components/form/demo/validate-reactive.ts",
    "content": "import { Component, inject, OnDestroy, OnInit } from '@angular/core';\nimport {\n  AbstractControl,\n  NonNullableFormBuilder,\n  ReactiveFormsModule,\n  ValidationErrors,\n  Validators\n} from '@angular/forms';\nimport { Observable, Observer, Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-form-validate-reactive',\n  imports: [ReactiveFormsModule, NzButtonModule, NzFormModule, NzInputModule],\n  template: `\n    <form nz-form [formGroup]=\"validateForm\" (ngSubmit)=\"submitForm()\">\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"7\" nzRequired>Username</nz-form-label>\n        <nz-form-control [nzSpan]=\"12\" nzHasFeedback nzValidatingTip=\"Validating...\" [nzErrorTip]=\"userErrorTpl\">\n          <input nz-input formControlName=\"userName\" placeholder=\"async validate try to write JasonWood\" />\n          <ng-template #userErrorTpl let-control>\n            @if (control.errors?.['required']) {\n              Please input your username!\n            }\n            @if (control.errors?.['duplicated']) {\n              The username is redundant!\n            }\n          </ng-template>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"7\" nzRequired>E-mail</nz-form-label>\n        <nz-form-control [nzSpan]=\"12\" nzHasFeedback [nzErrorTip]=\"emailErrorTpl\">\n          <input nz-input formControlName=\"email\" placeholder=\"email\" type=\"email\" />\n          <ng-template #emailErrorTpl let-control>\n            @if (control.errors?.['email']) {\n              The input is not valid E-mail!\n            }\n            @if (control.errors?.['required']) {\n              Please input your E-mail!\n            }\n          </ng-template>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"7\" nzRequired>Password</nz-form-label>\n        <nz-form-control [nzSpan]=\"12\" nzHasFeedback nzErrorTip=\"Please input your password!\">\n          <input nz-input type=\"password\" formControlName=\"password\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"7\" nzRequired>Confirm Password</nz-form-label>\n        <nz-form-control [nzSpan]=\"12\" nzHasFeedback [nzErrorTip]=\"passwordErrorTpl\">\n          <input nz-input type=\"password\" formControlName=\"confirm\" placeholder=\"confirm your password\" />\n          <ng-template #passwordErrorTpl let-control>\n            @if (control.errors?.['required']) {\n              Please confirm your password!\n            }\n            @if (control.errors?.['confirm']) {\n              Password is inconsistent!\n            }\n          </ng-template>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"7\" nzRequired>Comment</nz-form-label>\n        <nz-form-control [nzSpan]=\"12\" nzHasFeedback nzErrorTip=\"Please write something here!\">\n          <nz-textarea-count [nzMaxCharacterCount]=\"2000\">\n            <textarea formControlName=\"comment\" nz-input rows=\"2\" placeholder=\"write any thing\"></textarea>\n          </nz-textarea-count>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-control [nzOffset]=\"7\" [nzSpan]=\"12\">\n          <button nz-button nzType=\"primary\" [disabled]=\"!validateForm.valid\">Submit</button>\n          <button nz-button (click)=\"resetForm($event)\">Reset</button>\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `,\n  styles: `\n    [nz-form] {\n      max-width: 600px;\n    }\n\n    button {\n      margin-left: 8px;\n    }\n  `\n})\nexport class NzDemoFormValidateReactiveComponent implements OnInit, OnDestroy {\n  private fb = inject(NonNullableFormBuilder);\n  private destroy$ = new Subject<void>();\n  validateForm = this.fb.group({\n    userName: this.fb.control('', [Validators.required], [this.userNameAsyncValidator]),\n    email: this.fb.control('', [Validators.email, Validators.required]),\n    password: this.fb.control('', [Validators.required]),\n    confirm: this.fb.control('', [this.confirmValidator]),\n    comment: this.fb.control('', [Validators.required])\n  });\n\n  ngOnInit(): void {\n    this.validateForm.controls.password.valueChanges.pipe(takeUntil(this.destroy$)).subscribe(() => {\n      this.validateForm.controls.confirm.updateValueAndValidity();\n    });\n  }\n\n  ngOnDestroy(): void {\n    this.destroy$.next();\n    this.destroy$.complete();\n  }\n\n  submitForm(): void {\n    console.log('submit', this.validateForm.value);\n  }\n\n  resetForm(e: MouseEvent): void {\n    e.preventDefault();\n    this.validateForm.reset();\n  }\n\n  userNameAsyncValidator(control: AbstractControl): Observable<ValidationErrors | null> {\n    return new Observable((observer: Observer<ValidationErrors | null>) => {\n      setTimeout(() => {\n        if (control.value === 'JasonWood') {\n          // you have to return `{error: true}` to mark it as an error event\n          observer.next({ error: true, duplicated: true });\n        } else {\n          observer.next(null);\n        }\n        observer.complete();\n      }, 1000);\n    });\n  }\n\n  confirmValidator(control: AbstractControl): ValidationErrors | null {\n    if (!control.value) {\n      return { error: true, required: true };\n    } else if (control.value !== control.parent!.value.password) {\n      return { confirm: true, error: true };\n    }\n    return {};\n  }\n}\n"
  },
  {
    "path": "components/form/demo/validate-static.md",
    "content": "---\norder: 11\ntitle:\n  zh-CN: 手动指定表单状态\n  en-US: Manual Set Validation Status\n---\n\n## zh-CN\n\n用户可以在通过 `nz-form-control` 的 `nzValidateStatus` 属性直接设定表单的状态。\n\n1. `nzValidateStatus`: 校验状态，可选 'success', 'warning', 'error', 'validating'。\n2. `nzHasFeedback`：用于给输入框添加反馈图标。\n3. `nzSuccessTip` `nzWarningTip` `nzErrorTip` `nzValidatingTip`：设置不同状态校验文案。\n\n## en-US\n\nYou can set the form status directly via the `nzValidateStatus` on `nz-form-control`.\n\n1. `nzValidateStatus`: validate status of form components which could be 'success', 'warning', 'error', 'validating'.\n2. `nzHasFeedback`: display feed icon of input control\n3. `nzSuccessTip` `nzWarningTip` `nzErrorTip` `nzValidatingTip`：display validate message。\n"
  },
  {
    "path": "components/form/demo/validate-static.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzDatePickerModule } from 'ng-zorro-antd/date-picker';\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzInputNumberModule } from 'ng-zorro-antd/input-number';\nimport { NzSelectModule } from 'ng-zorro-antd/select';\nimport { NzTimePickerModule } from 'ng-zorro-antd/time-picker';\n\n@Component({\n  selector: 'nz-demo-form-validate-static',\n  imports: [\n    FormsModule,\n    NzDatePickerModule,\n    NzFormModule,\n    NzInputModule,\n    NzInputNumberModule,\n    NzSelectModule,\n    NzTimePickerModule\n  ],\n  template: `\n    <form nz-form>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"5\">Fail</nz-form-label>\n        <nz-form-control\n          nzValidateStatus=\"error\"\n          [nzSpan]=\"12\"\n          nzErrorTip=\"Should be combination of numbers & alphabets\"\n        >\n          <input nz-input ngModel=\"unavailable choice\" name=\"errorValid\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"5\">Warning</nz-form-label>\n        <nz-form-control nzValidateStatus=\"warning\" [nzSpan]=\"12\">\n          <input nz-input ngModel=\"Warning\" name=\"warningValid\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"5\">Validating</nz-form-label>\n        <nz-form-control\n          [nzSpan]=\"12\"\n          nzValidateStatus=\"validating\"\n          nzHasFeedback\n          nzValidatingTip=\"I'm validating the content\"\n        >\n          <input nz-input ngModel=\"The content is being validated\" name=\"validating\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"5\">Success</nz-form-label>\n        <nz-form-control [nzSpan]=\"12\" nzValidateStatus=\"success\" nzHasFeedback>\n          <input nz-input ngModel=\"The content\" name=\"successValid\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"5\">Warning</nz-form-label>\n        <nz-form-control\n          [nzSpan]=\"12\"\n          nzValidateStatus=\"warning\"\n          nzHasFeedback\n          nzWarningTip=\"Should be combination of numbers & alphabets\"\n        >\n          <input nz-input ngModel=\"Warning\" name=\"warningHighValid\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"5\">Fail</nz-form-label>\n        <nz-form-control\n          [nzSpan]=\"12\"\n          nzValidateStatus=\"error\"\n          nzHasFeedback\n          nzErrorTip=\"Should be combination of numbers & alphabets\"\n        >\n          <input nz-input ngModel=\"unavailable choice\" name=\"invalidValid\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"5\">Success</nz-form-label>\n        <nz-form-control [nzSpan]=\"12\" nzValidateStatus=\"success\" nzHasFeedback>\n          <nz-date-picker name=\"date-picker-success\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"5\">Warning</nz-form-label>\n        <nz-form-control [nzSpan]=\"12\" nzValidateStatus=\"warning\" nzHasFeedback>\n          <nz-time-picker name=\"time-picker-warning\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"5\">Error</nz-form-label>\n        <nz-form-control [nzSpan]=\"12\" nzValidateStatus=\"error\" nzHasFeedback>\n          <nz-select name=\"select-error\" ngModel=\"Option 1\">\n            <nz-option nzValue=\"Option 1\" nzLabel=\"Option 1\" />\n            <nz-option nzValue=\"Option 2\" nzLabel=\"Option 2\" />\n          </nz-select>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"5\">Validating</nz-form-label>\n        <nz-form-control [nzSpan]=\"12\" nzValidateStatus=\"validating\" nzHasFeedback>\n          <nz-select name=\"select-validate\" ngModel=\"Option 2\">\n            <nz-option nzValue=\"Option 1\" nzLabel=\"Option 1\" />\n            <nz-option nzValue=\"Option 2\" nzLabel=\"Option 2\" />\n          </nz-select>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"5\">Success</nz-form-label>\n        <nz-form-control [nzSpan]=\"12\" nzValidateStatus=\"success\" nzHasFeedback>\n          <nz-input-number name=\"inputnumber-success\" style=\"width:100%\" />\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `,\n  styles: `\n    [nz-form] {\n      max-width: 600px;\n    }\n\n    nz-date-picker ::ng-deep .ant-calendar-picker {\n      width: 100%;\n    }\n\n    nz-date-picker,\n    nz-time-picker {\n      width: 100%;\n    }\n  `\n})\nexport class NzDemoFormValidateStaticComponent {}\n"
  },
  {
    "path": "components/form/demo/validate-template.md",
    "content": "---\norder: 10\ntitle:\n  zh-CN: 模板驱动表单验证\n  en-US: Template-driven Forms Validation\n---\n\n## zh-CN\n\n当使用[模板驱动表单](https://angular.cn/guide/forms/template-driven-forms)时，模板可以根据模板设定自动进行校验。\n\n1. `nzHasFeedback`：用于给输入框添加反馈图标。\n2. `nzSuccessTip` `nzWarningTip` `nzErrorTip` `nzValidatingTip`：设置不同状态校验文案。\n   > 当同一种状态下存在多种提示情况时，`nzSuccessTip` `nzWarningTip` `nzErrorTip` `nzValidatingTip` 均支持传入 `TemplateRef<{ $implicit: NgModel }` 类型，可以通过[模板变量](https://www.angular.cn/guide/template-syntax)导出 `NgModel` 后用于切换不同的提示信息。\n\n## en-US\n\nWhen using [template-driven forms](https://angular.dev/guide/forms/template-driven-forms), the form could change its status via the template setting.\n\n1. `nzHasFeedback`: display feed icon of input control\n2. `nzSuccessTip` `nzWarningTip` `nzErrorTip` `nzValidatingTip`: display validate message。\n   > When there are multiple tips in the same state, `nzSuccessTip` `nzWarningTip` `nzErrorTip` `nzValidatingTip` supports the passing `TemplateRef<{ $implicit: NgModel }` type, which can be used to switch tips after exporting `NgModel` via the [template syntax](https://angular.dev/guide/templates).\n"
  },
  {
    "path": "components/form/demo/validate-template.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-form-validate-template',\n  imports: [FormsModule, NzFormModule, NzInputModule, NzInputModule],\n  template: `\n    <form nz-form>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"5\">Required</nz-form-label>\n        <nz-form-control nzHasFeedback [nzSpan]=\"12\" nzErrorTip=\"Input is required\">\n          <input nz-input ngModel=\"Required Input\" name=\"required\" required />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"5\">MaxLength</nz-form-label>\n        <nz-form-control nzHasFeedback [nzSpan]=\"12\" nzErrorTip=\"MaxLength is 6\">\n          <input nz-input ngModel=\"MaxLength is 6\" name=\"maxlength\" maxlength=\"6\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"5\">MinLength</nz-form-label>\n        <nz-form-control nzHasFeedback [nzSpan]=\"12\" nzErrorTip=\"MinLength is 6\">\n          <input nz-input ngModel=\"MinLength is 6\" name=\"minlength\" minlength=\"6\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"5\">Email</nz-form-label>\n        <nz-form-control nzHasFeedback [nzSpan]=\"12\" nzErrorTip=\"Email is not valid\">\n          <input nz-input ngModel=\"Input Email\" name=\"email\" email />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"5\">Pattern</nz-form-label>\n        <nz-form-control nzHasFeedback [nzSpan]=\"12\" nzErrorTip=\"Pattern not match\">\n          <input nz-input ngModel=\"Match pattern\" name=\"pattern\" pattern=\".{3,}\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label [nzSpan]=\"5\">Mix</nz-form-label>\n        <nz-form-control nzHasFeedback [nzSpan]=\"12\" [nzErrorTip]=\"combineTpl\">\n          <input\n            nz-input\n            ngModel=\"MaxLength is 12 and MinLength is 6\"\n            name=\"mix\"\n            minlength=\"6\"\n            maxlength=\"12\"\n            required\n          />\n          <ng-template #combineTpl let-control>\n            @if (control.errors?.['maxlength']) {\n              MaxLength is 12\n            }\n            @if (control.errors?.['minlength']) {\n              MinLength is 6\n            }\n            @if (control.errors?.['required']) {\n              Input is required\n            }\n          </ng-template>\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `,\n  styles: `\n    [nz-form] {\n      max-width: 600px;\n    }\n  `\n})\nexport class NzDemoFormValidateTemplateComponent {}\n"
  },
  {
    "path": "components/form/demo/variant.md",
    "content": "---\norder: 18\ntitle:\n  zh-CN: 表单变体\n  en-US: Form variants\n---\n\n## zh-CN\n\n改变表单内所有组件的变体，可选 `outlined` `filled` `borderless` `underlined` 四种形态。\n\n## en-US\n\nChange the variant of all components in the form, options include: `outlined` `filled` `borderless` and `underlined`.\n"
  },
  {
    "path": "components/form/demo/variant.ts",
    "content": "import { Component, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCascaderModule } from 'ng-zorro-antd/cascader';\nimport type { NzVariant } from 'ng-zorro-antd/core/types';\nimport { NzDatePickerModule } from 'ng-zorro-antd/date-picker';\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzInputNumberModule } from 'ng-zorro-antd/input-number';\nimport { NzMentionModule } from 'ng-zorro-antd/mention';\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\nimport { NzSelectModule } from 'ng-zorro-antd/select';\nimport { NzTimePickerModule } from 'ng-zorro-antd/time-picker';\nimport { NzTreeSelectModule } from 'ng-zorro-antd/tree-select';\n\n@Component({\n  selector: 'nz-demo-form-variant',\n  imports: [\n    NzFormModule,\n    NzRadioModule,\n    FormsModule,\n    NzInputModule,\n    NzInputNumberModule,\n    NzSelectModule,\n    NzCascaderModule,\n    NzDatePickerModule,\n    NzTimePickerModule,\n    NzTreeSelectModule,\n    NzMentionModule\n  ],\n  template: `\n    <form nz-form [nzVariant]=\"variant()\">\n      <nz-form-item>\n        <nz-form-label>Form variant</nz-form-label>\n        <nz-radio-group [(ngModel)]=\"variant\" name=\"variant\">\n          <label nz-radio-button nzValue=\"outlined\">Outlined</label>\n          <label nz-radio-button nzValue=\"filled\">Filled</label>\n          <label nz-radio-button nzValue=\"borderless\">Borderless</label>\n          <label nz-radio-button nzValue=\"underlined\">Underlined</label>\n        </nz-radio-group>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label>Input</nz-form-label>\n        <nz-form-control>\n          <input placeholder=\"Please type something\" nz-input />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label>InputNumber</nz-form-label>\n        <nz-form-control>\n          <nz-input-number nzPlaceHolder=\"Please enter a number\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label>Select</nz-form-label>\n        <nz-form-control>\n          <nz-select nzPlaceHolder=\"Please select\">\n            <nz-option nzValue=\"Marie\" nzLabel=\"Marie\" />\n            <nz-option nzValue=\"John\" nzLabel=\"John\" />\n            <nz-option nzValue=\"Jill\" nzLabel=\"Jill\" />\n          </nz-select>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label>Cascader</nz-form-label>\n        <nz-form-control>\n          <nz-cascader />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label>DatePicker</nz-form-label>\n        <nz-form-control>\n          <nz-date-picker />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item\n        ><nz-form-label>TimePicker</nz-form-label>\n        <nz-form-control>\n          <nz-time-picker />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label>Tree Select</nz-form-label>\n        <nz-form-control>\n          <nz-tree-select [nzExpandedKeys]=\"expandKeys\" [nzNodes]=\"nodes\" nzPlaceHolder=\"Please select\" />\n        </nz-form-control>\n      </nz-form-item>\n\n      <nz-form-item>\n        <nz-form-label>Mention</nz-form-label>\n        <nz-form-control>\n          <nz-mention [nzSuggestions]=\"suggestions\">\n            <textarea rows=\"1\" placeholder=\"Input here\" nzMentionTrigger nz-input></textarea>\n          </nz-mention>\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `\n})\nexport class NzDemoFormVariantComponent {\n  readonly variant = signal<NzVariant>('outlined');\n\n  expandKeys = ['100', '1001'];\n  suggestions = ['afc163', 'benjycui', 'yiminghe', 'RaoHai', '中文', 'にほんご'];\n\n  readonly nodes = [\n    {\n      title: 'parent 1',\n      key: '100',\n      children: [\n        {\n          title: 'parent 1-0',\n          key: '1001',\n          children: [\n            { title: 'leaf 1-0-0', key: '10010', isLeaf: true },\n            { title: 'leaf 1-0-1', key: '10011', isLeaf: true }\n          ]\n        },\n        {\n          title: 'parent 1-1',\n          key: '1002',\n          children: [{ title: 'leaf 1-1-0', key: '10020', isLeaf: true }]\n        }\n      ]\n    }\n  ];\n}\n"
  },
  {
    "path": "components/form/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Entry\ncols: 1\ntitle: Form\ncover: 'https://gw.alipayobjects.com/zos/alicdn/ORmcdeaoO/Form.svg'\ndescription: High-performance form component with data domain management. Includes data entry, validation, and corresponding styles.\n---\n\n## When To Use\n\n- When you need to create an instance or collect information.\n- When you need to validate fields in certain rules.\n\n> Form is totally based on [Angular Forms](https://angular.dev/guide/forms), you can\n> use [reactive forms](https://angular.dev/guide/forms/reactive-forms)\n> or [template-driven-forms](https://angular.dev/guide/forms/template-driven-forms).\n> Please make sure you have read the official form document before using the component.\n\n## Form\n\nYou can align the controls of a `form` using the `layout` prop：\n\n- `horizontal`：to horizontally align the `label`s and controls of the fields. (Default)\n- `vertical`：to vertically align the `label`s and controls of the fields.\n- `inline`：to render form fields in one line.\n\n### nz-form-item\n\nUsed to separate the item in forms, contains label(optional) and control field.\n\n### nz-form-label\n\nThe label of the form item, optional.\n\n### nz-form-control\n\nA form consists of one or more form fields whose type includes input, textarea, checkbox, radio, select, tag, and more.\n\n```html\n<form nz-form>\n  <nz-form-item>\n    <nz-form-label [nzSpan]=\"6\" nzFor=\"email\">E-mail</nz-form-label>\n    <nz-form-control [nzSpan]=\"14\">\n      <input nz-input name=\"email\" type=\"email\" id=\"email\" />\n    </nz-form-control>\n  </nz-form-item>\n</form>\n```\n\n## API\n\n### [nz-form]\n\n| Property              | Description                                                                                             | Type                                                     | Default Value                                   | Global Config | Version |\n| --------------------- | ------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | ----------------------------------------------- | ------------- | ------- |\n| `[nzLayout]`          | Form layout                                                                                             | `'horizontal' \\| 'vertical' \\| 'inline'`                 | `'horizontal'`                                  |               |         |\n| `[nzAutoTips]`        | Set default props `[nzAutoTips]` value of `nz-form-control`, please refer to the example: **Auto tips** | `Record<string, Record<string, string>>`                 | `{}`                                            | ✅            |         |\n| `[nzDisableAutoTips]` | Set default props `[nzDisableAutoTip]` value of `nz-form-control`                                       | `boolean`                                                | `false`                                         | ✅            |         |\n| `[nzNoColon]`         | Set default props `[nzNoColon]` value of `nz-form-label`                                                | `boolean`                                                | `false`                                         | ✅            |         |\n| `[nzTooltipIcon]`     | Set default props `[nzTooltipIcon]` value of `nz-form-label`                                            | `string \\| { type: string; theme: ThemeType }`           | `{ type: 'question-circle', theme: 'outline' }` | ✅            |         |\n| `[nzLabelAlign]`      | Set default props `[nzLabelAlign]` value of `nz-form-label`                                             | `'left' \\| 'right'`                                      | `'right'`                                       |               |         |\n| `[nzLabelWrap]`       | Set default props `[nzLabelWrap]` value of `nz-form-label`                                              | `boolean`                                                | `false`                                         |               |         |\n| `[nzRequiredMark]`    | Required mark style. Can use required mark or optional mark.                                            | `NzRequiredMark`                                         | `true`                                          |               | 20.4.0  |\n| `[nzSize]`            | Set field component size                                                                                | `small` \\| `default` \\| `large`                          |                                                 | -             | 21.1.0  |\n| `[nzVariant]`         | Set form variant                                                                                        | `'outlined' \\| 'filled' \\| 'borderless' \\| 'underlined'` | `'outlined'`                                    |               |         |\n\n### nz-form-item\n\nUsed to separate the item in forms, contains label(optional) and control field.\n\n> All api in [nz-row](/components/grid/en) can be used in `nz-form-item`.\n\n### nz-form-label\n\nThe label of the form item, optional.\n\n> All api in [nz-col](/components/grid/en) can be used in `nz-form-label`.\n\n| Property           | Description                                  | Type                          | Default Value |\n| ------------------ | -------------------------------------------- | ----------------------------- | ------------- |\n| `[nzRequired]`     | add required style to current item           | `boolean`                     | `false`       |\n| `[nzNoColon]`      | whether to not display `:` after label text. | `boolean`                     | `false`       |\n| `[nzFor]`          | The `for` property of `label`                | `string`                      | -             |\n| `[nzTooltipTitle]` | Set tooltip info                             | `string \\| TemplateRef<void>` | -             |\n| `[nzTooltipIcon]`  | Set icon of tooltip info                     | `string \\| NzFormTooltipIcon` | -             |\n| `[nzLabelAlign]`   | The text align of label                      | `'left' \\| 'right'`           | `'right'`     |\n| `[nzLabelWrap]`    | whether label can be wrap                    | `boolean`                     | `false`       |\n\n### nz-form-control\n\n> Note：Due to the lack of partial Observable in [Angular Form](https://github.com/angular/angular/issues/10887), you\n> have to notify `nz-form-control` to update its status with `updateValueAndValidity` when you update form status using\n> methods like `markAsDirty`.\n\nA form consists of one or more form fields whose type includes input, textarea, checkbox, radio, select, tag, and more.\n\n> All api in [nz-col](/components/grid/en) can be used in `nz-form-control`.\n\n| Property              | Description                                                                                                                                                | Type                                                                          | Default Value                                         |\n| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------- |\n| `[nzValidateStatus]`  | Will generate status based on the input `FormControl`, `NgModel` or string, the default value is the first `FormControl` or `NgModel` in `nz-form-control` | `'success' \\| 'warning' \\| 'error' \\| 'validating' \\| FormControl \\| NgModel` | first `FormControl` or `NgModel` in `nz-form-control` |\n| `[nzHasFeedback]`     | Used with `nzValidateStatus`, this option specifies the validation status icon. Recommended to be used only with `Input`.                                  | `boolean`                                                                     | `false`                                               |\n| `[nzExtra]`           | The extra prompt message                                                                                                                                   | `string \\| TemplateRef<void>`                                                 | -                                                     |\n| `[nzSuccessTip]`      | Tip display when validate success                                                                                                                          | `string \\| TemplateRef<{ $implicit: FormControl \\| NgModel }>`                | -                                                     |\n| `[nzWarningTip]`      | Tip display when validate warning                                                                                                                          | `string \\| TemplateRef<{ $implicit: FormControl \\| NgModel }>`                | -                                                     |\n| `[nzErrorTip]`        | Tip display when validate error                                                                                                                            | `string \\| TemplateRef<{ $implicit: FormControl \\| NgModel }>`                | -                                                     |\n| `[nzValidatingTip]`   | Tip display when validating                                                                                                                                | `string \\| TemplateRef<{ $implicit: FormControl \\| NgModel }>`                | -                                                     |\n| `[nzAutoTips]`        | The object of the tips, please refer to the example: **Auto tips**                                                                                         | `Record<string, string \\| Record<string, string>>`                            | -                                                     |\n| `[nzDisableAutoTips]` | Disable Auto Tips                                                                                                                                          | `boolean`                                                                     | -                                                     |\n\n### nz-form-split\n\nThe split icon of `-`\n\n### nz-form-text\n\nText in `nz-form-control`\n"
  },
  {
    "path": "components/form/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 表单\ntype: 数据录入\ncols: 1\ntitle: Form\ncover: 'https://gw.alipayobjects.com/zos/alicdn/ORmcdeaoO/Form.svg'\ndescription: 高性能表单控件，自带数据域管理。包含数据录入、校验以及对应样式。\n---\n\n## 何时使用\n\n- 用于创建一个实体或收集信息。\n- 需要对输入的数据类型进行校验时。\n\n> 该组件需要与 [Angular 表单](https://angular.cn/guide/forms)\n> 结合使用，根据需要可以自由选择 [响应式表单](https://angular.cn/guide/forms/reactive-forms)\n> 或 [模板驱动表单](https://angular.cn/guide/forms/template-driven-forms)。\n> 使用该组件前请确保您已经阅读并掌握了 [Angular 表单](https://angular.cn/guide/forms) 的使用方式。\n\n## 表单\n\n我们提供了以下三种排列方式：\n\n- 水平排列：标签和表单控件水平排列；（默认）\n- 垂直排列：标签和表单控件上下垂直排列；\n- 行内排列：表单项水平行内排列。\n\n### 表单项 nz-form-item\n\n表单项用于区分表单中不同的区域，包含表单域和表单标签(可选)。\n\n### 表单标签 nz-form-label\n\n用于标示当前表单项的内容，可选。\n\n### 表单域 nz-form-control\n\n表单一定会包含表单域，表单域可以是输入控件，标准表单域，标签，下拉菜单，文本域等。\n\n```html\n<form nz-form>\n  <nz-form-item>\n    <nz-form-label [nzSpan]=\"6\" nzFor=\"email\">E-mail</nz-form-label>\n    <nz-form-control [nzSpan]=\"14\">\n      <input nz-input name=\"email\" type=\"email\" id=\"email\" />\n    </nz-form-control>\n  </nz-form-item>\n</form>\n```\n\n## API\n\n### [nz-form]\n\n| 参数                  | 说明                                                                                | 类型                                                     | 默认值                                          | 全局配置 | 版本   |\n| --------------------- | ----------------------------------------------------------------------------------- | -------------------------------------------------------- | ----------------------------------------------- | -------- | ------ |\n| `[nzLayout]`          | 表单布局                                                                            | `'horizontal' \\| 'vertical' \\| 'inline'`                 | `'horizontal'`                                  |          |        |\n| `[nzAutoTips]`        | 配置 `nz-form-control` 的 `[nzAutoTips]` 的默认值, 具体用法请参考示例：**自动提示** | `Record<string, Record<string, string>>`                 | `{}`                                            | ✅       |        |\n| `[nzDisableAutoTips]` | 配置 `nz-form-control` 的 `[nzDisableAutoTips]` 的默认值                            | `boolean`                                                | `false`                                         | ✅       |        |\n| `[nzNoColon]`         | 配置 `nz-form-label` 的 `[nzNoColon]` 的默认值                                      | `boolean`                                                | `false`                                         | ✅       |        |\n| `[nzTooltipIcon]`     | 配置 `nz-form-label` 的 `[nzTooltipIcon]` 的默认值                                  | `string \\| { type: string; theme: ThemeType }`           | `{ type: 'question-circle', theme: 'outline' }` | ✅       |        |\n| `[nzLabelAlign]`      | 配置 `nz-form-label` 的 `[nzLabelAlign]` 的默认值                                   | `'left' \\| 'right'`                                      | `'right'`                                       |          |        |\n| `[nzLabelWrap]`       | 配置 `nz-form-label` 的 `[nzLabelWrap]` 的默认值                                    | `boolean`                                                | `false`                                         |          |        |\n| `[nzRequiredMark]`    | 必填标记样式。可使用必填标记或可选标记。                                            | `NzRequiredMark`                                         | `true`                                          |          | 20.4.0 |\n| `[nzSize]`            | 设置字段组件的尺寸                                                                  | `small` \\| `default` \\| `large`                          | -                                               |          | 21.1.0 |\n| `[nzVariant]`         | 设置表单样式                                                                        | `'outlined' \\| 'filled' \\| 'borderless' \\| 'underlined'` | `'outlined'`                                    |          |        |\n\n### nz-form-item\n\n表单项用于区分表单中不同的区域，包含表单域和表单标签(可选)。\n\n> 所有 [nz-row](/components/grid/zh) 的参数在 `nz-form-item` 上均可直接使用。\n\n### nz-form-label\n\n用于标示当前表单项的内容，可选。\n\n> 所有 [nz-col](/components/grid/zh) 的参数在 `nz-form-label` 上均可直接使用。\n\n| 参数               | 说明                         | 类型                          | 默认值    |\n| ------------------ | ---------------------------- | ----------------------------- | --------- |\n| `[nzRequired]`     | 当前项是否为必填，仅影响样式 | `boolean`                     | `false`   |\n| `[nzNoColon]`      | 是否不显示 label 后面的冒号  | `boolean`                     | `false`   |\n| `[nzFor]`          | label 标签的 for 属性        | `string`                      | -         |\n| `[nzTooltipTitle]` | 配置提示信息                 | `string \\| TemplateRef<void>` | -         |\n| `[nzTooltipIcon]`  | 配置提示信息的图标           | `string \\| NzFormTooltipIcon` | -         |\n| `[nzLabelAlign]`   | 标签文本对齐方式             | `'left' \\| 'right'`           | `'right'` |\n| `[nzLabelWrap]`    | label 标签的文本换行方式     | `boolean`                     | `false`   |\n\n### nz-form-control\n\n> 注意：由于 Angular Form 目前提供的[状态变更订阅](https://github.com/angular/angular/issues/10887)不完整。手动更改表单状态时，例如\n> `markAsDirty` 后，需要执行 `updateValueAndValidity` 通知 `nz-form-control` 进行状态变更。\n\n表单一定会包含表单域，表单域可以是输入控件，标准表单域，标签，下拉菜单，文本域等。\n\n> 所有 [nz-col](/components/grid/zh) 的参数在 `nz-form-control` 上均可直接使用。\n\n| 参数                  | 说明                                                                                                                                                       | 类型                                                                          | 默认值                                                      |\n| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------- |\n| `[nzValidateStatus]`  | 会根据传入的 `FormControl` 或 `NgModel` 自动生成校验状态，也可以直接指定状态，不传入时默认值为 `nz-form-control` 中包裹的第一个 `FormControl` 或 `NgModel` | `'success' \\| 'warning' \\| 'error' \\| 'validating' \\| FormControl \\| NgModel` | `nz-form-control` 中包裹的第一个 `FormControl` 或 `NgModel` |\n| `[nzHasFeedback]`     | 配合 `nzValidateStatus` 属性使用，展示校验状态图标                                                                                                         | `boolean`                                                                     | `false`                                                     |\n| `[nzExtra]`           | 用于显示表单额外提示信息                                                                                                                                   | `string \\| TemplateRef<void>`                                                 | -                                                           |\n| `[nzSuccessTip]`      | 校验状态 success 时提示信息                                                                                                                                | `string \\| TemplateRef<{ $implicit: FormControl \\| NgModel }>`                | -                                                           |\n| `[nzWarningTip]`      | 校验状态 warning 时提示信息                                                                                                                                | `string \\| TemplateRef<{ $implicit: FormControl \\| NgModel }>`                | -                                                           |\n| `[nzErrorTip]`        | 校验状态 error 时提示信息                                                                                                                                  | `string \\| TemplateRef<{ $implicit: FormControl \\| NgModel }>`                | -                                                           |\n| `[nzValidatingTip]`   | 正在校验时提示信息                                                                                                                                         | `string \\| TemplateRef<{ $implicit: FormControl \\| NgModel }>`                | -                                                           |\n| `[nzAutoTips]`        | 配置提示的对象, 具体用法请参考示例：**自动提示**                                                                                                           | `Record<string, Record<string, string>>`                                      | -                                                           |\n| `[nzDisableAutoTips]` | 禁用自动提示                                                                                                                                               | `boolean`                                                                     | -                                                           |\n\n### nz-form-split\n\n用于显示分隔符 `-`\n\n### nz-form-text\n\n在 `nz-form-control` 中直接显示文本\n"
  },
  {
    "path": "components/form/form-control.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  AfterContentInit,\n  AnimationCallbackEvent,\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ContentChild,\n  DestroyRef,\n  inject,\n  Input,\n  OnChanges,\n  OnInit,\n  SimpleChanges,\n  TemplateRef,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { AbstractControl, FormControlDirective, FormControlName, NgControl, NgModel } from '@angular/forms';\nimport { Observable, Subscription } from 'rxjs';\nimport { filter, startWith, tap } from 'rxjs/operators';\n\nimport { isAnimationEnabled, NzNoAnimationDirective, withAnimationCheck } from 'ng-zorro-antd/core/animation';\nimport { NzFormStatusService } from 'ng-zorro-antd/core/form';\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { toBoolean } from 'ng-zorro-antd/core/util';\nimport { NzI18nService } from 'ng-zorro-antd/i18n';\n\nimport { NzFormControlStatusType, NzFormItemComponent } from './form-item.component';\nimport { NzFormDirective } from './form.directive';\n\n@Component({\n  selector: 'nz-form-control',\n  exportAs: 'nzFormControl',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    <div class=\"ant-form-item-control-input\">\n      <div class=\"ant-form-item-control-input-content\">\n        <ng-content />\n      </div>\n    </div>\n    @if (innerTip) {\n      <div\n        [animate.enter]=\"nzValidateAnimationEnter()\"\n        [animate.leave]=\"nzValidateAnimationLeave()\"\n        (animate.leave)=\"onAnimationLeave($event)\"\n        class=\"ant-form-item-explain ant-form-item-explain-connected\"\n      >\n        <div role=\"alert\" [class]=\"['ant-form-item-explain-' + status]\">\n          <ng-container *nzStringTemplateOutlet=\"innerTip; context: { $implicit: validateControl }\">{{\n            innerTip\n          }}</ng-container>\n        </div>\n      </div>\n    }\n\n    @if (nzExtra) {\n      <div class=\"ant-form-item-extra\">\n        <ng-container *nzStringTemplateOutlet=\"nzExtra\">{{ nzExtra }}</ng-container>\n      </div>\n    }\n  `,\n  providers: [NzFormStatusService],\n  host: {\n    class: 'ant-form-item-control'\n  },\n  imports: [NzOutletModule]\n})\nexport class NzFormControlComponent implements OnChanges, OnInit, AfterContentInit {\n  private cdr = inject(ChangeDetectorRef);\n  public i18n = inject(NzI18nService);\n  private nzFormStatusService = inject(NzFormStatusService);\n  private destroyRef = inject(DestroyRef);\n\n  private _hasFeedback = false;\n  private validateChanges: Subscription = Subscription.EMPTY;\n  private validateString: string | null = null;\n  private localeId!: string;\n  private autoErrorTip?: string;\n\n  private get disableAutoTips(): boolean {\n    return this.nzDisableAutoTips !== undefined\n      ? toBoolean(this.nzDisableAutoTips)\n      : !!this.nzFormDirective?.nzDisableAutoTips;\n  }\n\n  private readonly noAnimation = inject(NzNoAnimationDirective, { optional: true, host: true });\n  private readonly animationEnabled = isAnimationEnabled(() => !this.noAnimation?.nzNoAnimation());\n  protected readonly nzValidateAnimationEnter = withAnimationCheck(() => 'ant-form-validate_animation-enter');\n  protected readonly nzValidateAnimationLeave = withAnimationCheck(() => 'ant-form-validate_animation-leave');\n\n  status: NzFormControlStatusType = '';\n  validateControl: AbstractControl | NgModel | null = null;\n  innerTip: string | TemplateRef<{ $implicit: AbstractControl | NgModel }> | null = null;\n\n  @ContentChild(NgControl, { static: false }) defaultValidateControl?: FormControlName | FormControlDirective;\n  @Input() nzSuccessTip?: string | TemplateRef<{ $implicit: AbstractControl | NgModel }>;\n  @Input() nzWarningTip?: string | TemplateRef<{ $implicit: AbstractControl | NgModel }>;\n  @Input() nzErrorTip?: string | TemplateRef<{ $implicit: AbstractControl | NgModel }>;\n  @Input() nzValidatingTip?: string | TemplateRef<{ $implicit: AbstractControl | NgModel }>;\n  @Input() nzExtra?: string | TemplateRef<void>;\n  @Input() nzAutoTips: Record<string, Record<string, string>> = {};\n  @Input({ transform: booleanAttribute }) nzDisableAutoTips?: boolean;\n\n  @Input({ transform: booleanAttribute })\n  set nzHasFeedback(value: boolean) {\n    this._hasFeedback = value;\n    this.nzFormStatusService.formStatusChanges.next({ status: this.status, hasFeedback: this._hasFeedback });\n    if (this.nzFormItemComponent) {\n      this.nzFormItemComponent.setHasFeedback(this._hasFeedback);\n    }\n  }\n\n  get nzHasFeedback(): boolean {\n    return this._hasFeedback;\n  }\n\n  @Input()\n  set nzValidateStatus(value: string | AbstractControl | FormControlName | NgModel) {\n    if (value instanceof AbstractControl || value instanceof NgModel) {\n      this.validateControl = value;\n      this.validateString = null;\n      this.watchControl();\n    } else if (value instanceof FormControlName) {\n      this.validateControl = value.control;\n      this.validateString = null;\n      this.watchControl();\n    } else {\n      this.validateString = value;\n      this.validateControl = null;\n      this.setStatus();\n    }\n  }\n\n  private watchControl(): void {\n    this.validateChanges.unsubscribe();\n    /** miss detect https://github.com/angular/angular/issues/10887 **/\n    if (this.validateControl && this.validateControl.statusChanges) {\n      this.validateChanges = (this.validateControl.statusChanges as Observable<NzSafeAny>)\n        .pipe(startWith(null), takeUntilDestroyed(this.destroyRef))\n        .subscribe(() => {\n          if (!this.disableAutoTips) {\n            this.updateAutoErrorTip();\n          }\n          this.setStatus();\n          this.cdr.markForCheck();\n        });\n    }\n  }\n\n  private setStatus(): void {\n    this.status = this.getControlStatus(this.validateString);\n    this.innerTip = this.getInnerTip(this.status);\n    this.nzFormStatusService.formStatusChanges.next({ status: this.status, hasFeedback: this.nzHasFeedback });\n    if (this.nzFormItemComponent) {\n      this.nzFormItemComponent.setWithHelpViaTips(!!this.innerTip);\n      this.nzFormItemComponent.setStatus(this.status);\n    }\n  }\n\n  private getControlStatus(validateString: string | null): NzFormControlStatusType {\n    let status: NzFormControlStatusType;\n\n    if (validateString === 'warning' || this.validateControlStatus('INVALID', 'warning')) {\n      status = 'warning';\n    } else if (validateString === 'error' || this.validateControlStatus('INVALID')) {\n      status = 'error';\n    } else if (\n      validateString === 'validating' ||\n      validateString === 'pending' ||\n      this.validateControlStatus('PENDING')\n    ) {\n      status = 'validating';\n    } else if (validateString === 'success' || this.validateControlStatus('VALID')) {\n      status = 'success';\n    } else {\n      status = '';\n    }\n\n    return status;\n  }\n\n  private validateControlStatus(validStatus: string, statusType?: NzFormControlStatusType): boolean {\n    if (!this.validateControl) {\n      return false;\n    } else {\n      const { dirty, touched, status } = this.validateControl;\n      return (\n        (!!dirty || !!touched) && (statusType ? this.validateControl.hasError(statusType) : status === validStatus)\n      );\n    }\n  }\n\n  private getInnerTip(\n    status: NzFormControlStatusType\n  ): string | TemplateRef<{ $implicit: AbstractControl | NgModel }> | null {\n    switch (status) {\n      case 'error':\n        return (!this.disableAutoTips && this.autoErrorTip) || this.nzErrorTip || null;\n      case 'validating':\n        return this.nzValidatingTip || null;\n      case 'success':\n        return this.nzSuccessTip || null;\n      case 'warning':\n        return this.nzWarningTip || null;\n      default:\n        return null;\n    }\n  }\n\n  private updateAutoErrorTip(): void {\n    if (this.validateControl) {\n      const errors = this.validateControl.errors || {};\n      let autoErrorTip = '';\n      for (const key in errors) {\n        if (errors.hasOwnProperty(key)) {\n          autoErrorTip =\n            errors[key]?.[this.localeId] ??\n            this.nzAutoTips?.[this.localeId]?.[key] ??\n            this.nzAutoTips.default?.[key] ??\n            this.nzFormDirective?.nzAutoTips?.[this.localeId]?.[key] ??\n            this.nzFormDirective?.nzAutoTips.default?.[key];\n        }\n        if (autoErrorTip) {\n          break;\n        }\n      }\n      this.autoErrorTip = autoErrorTip;\n    }\n  }\n\n  private subscribeAutoTips(observable?: Observable<NzSafeAny>): void {\n    observable?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      if (!this.disableAutoTips) {\n        this.updateAutoErrorTip();\n        this.setStatus();\n        this.cdr.markForCheck();\n      }\n    });\n  }\n\n  private nzFormItemComponent = inject(NzFormItemComponent, { host: true, optional: true });\n  private nzFormDirective = inject(NzFormDirective, { optional: true });\n\n  constructor() {\n    this.subscribeAutoTips(this.i18n.localeChange.pipe(tap(locale => (this.localeId = locale.locale))));\n    this.subscribeAutoTips(this.nzFormDirective?.getInputObservable('nzAutoTips'));\n    this.subscribeAutoTips(\n      this.nzFormDirective\n        ?.getInputObservable('nzDisableAutoTips')\n        .pipe(filter(() => this.nzDisableAutoTips === undefined))\n    );\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzDisableAutoTips, nzAutoTips, nzSuccessTip, nzWarningTip, nzErrorTip, nzValidatingTip } = changes;\n\n    if (nzDisableAutoTips || nzAutoTips) {\n      this.updateAutoErrorTip();\n      this.setStatus();\n    } else if (nzSuccessTip || nzWarningTip || nzErrorTip || nzValidatingTip) {\n      this.setStatus();\n    }\n  }\n\n  ngOnInit(): void {\n    this.setStatus();\n  }\n\n  ngAfterContentInit(): void {\n    if (!this.validateControl && !this.validateString) {\n      if (this.defaultValidateControl instanceof FormControlDirective) {\n        this.nzValidateStatus = this.defaultValidateControl.control;\n      } else {\n        this.nzValidateStatus = this.defaultValidateControl!;\n      }\n    }\n  }\n\n  protected onAnimationLeave(event: AnimationCallbackEvent): void {\n    if (!this.animationEnabled()) {\n      return event.animationComplete();\n    }\n\n    const element = event.target as HTMLElement;\n    const onTransitionEnd = (): void => {\n      element.removeEventListener('transitionend', onTransitionEnd);\n      event.animationComplete();\n    };\n    element.addEventListener('transitionend', onTransitionEnd);\n  }\n}\n"
  },
  {
    "path": "components/form/form-control.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { AnimationCallbackEvent, Component, DebugElement, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';\nimport {\n  AbstractControl,\n  FormBuilder,\n  FormControl,\n  FormGroup,\n  ReactiveFormsModule,\n  ValidatorFn,\n  Validators\n} from '@angular/forms';\nimport { By } from '@angular/platform-browser';\n\nimport { provideNzNoAnimation } from 'ng-zorro-antd/core/animation';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { en_US, NzI18nService } from 'ng-zorro-antd/i18n';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\nimport { NzFormControlComponent } from './form-control.component';\nimport { NzFormItemComponent } from './form-item.component';\nimport { NzFormModule } from './form.module';\n\nconst statusMap = {\n  warning: 'ant-form-item-has-warning',\n  validating: 'ant-form-item-is-validating',\n  pending: 'ant-form-item-is-validating',\n  error: 'ant-form-item-has-error',\n  success: 'ant-form-item-has-success'\n};\n\ndescribe('form-control', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  describe('static status', () => {\n    let fixture: ComponentFixture<NzTestStaticFormControlComponent>;\n    let testComponent: NzTestStaticFormControlComponent;\n    let formItem: DebugElement;\n    let formControl: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestStaticFormControlComponent);\n      testComponent = fixture.componentInstance;\n      formItem = fixture.debugElement.query(By.directive(NzFormItemComponent));\n      formControl = fixture.debugElement.query(By.directive(NzFormControlComponent));\n    });\n\n    it('should className correct', () => {\n      expect(formControl.nativeElement.classList).toContain('ant-form-item-control');\n    });\n\n    it('should status work', () => {\n      const statusList: Array<keyof typeof statusMap> = ['warning', 'validating', 'pending', 'error', 'success'];\n      statusList.forEach(status => {\n        testComponent.status = status;\n        fixture.detectChanges();\n        expect(formItem.nativeElement.classList).toContain(statusMap[status]);\n      });\n    });\n\n    it('should get correct form validate animation class', () => {\n      expect(formControl.componentInstance.nzValidateAnimationEnter()).toBe('ant-form-validate_animation-enter');\n      expect(formControl.componentInstance.nzValidateAnimationLeave()).toBe('ant-form-validate_animation-leave');\n    });\n  });\n\n  describe('reactive status', () => {\n    let fixture: ComponentFixture<NzTestReactiveFormControlComponent>;\n    let formGroup: FormGroup<{\n      input: FormControl<string | null>;\n      input2: FormControl<string | null>;\n      input3: FormControl<string | null>;\n    }>;\n    let formItems: DebugElement[];\n    let formControls: DebugElement[];\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestReactiveFormControlComponent);\n      formGroup = fixture.componentInstance.formGroup;\n      formItems = fixture.debugElement.queryAll(By.directive(NzFormItemComponent));\n      formControls = fixture.debugElement.queryAll(By.directive(NzFormControlComponent));\n    });\n\n    it('should init status correct', () => {\n      expect(formItems[0].nativeElement.classList).toContain('ant-form-item');\n      expect(formItems[1].nativeElement.classList).toContain('ant-form-item');\n      expect(formControls[0].nativeElement.classList).toContain('ant-form-item-control');\n      expect(formControls[1].nativeElement.classList).toContain('ant-form-item-control');\n    });\n\n    it('should valid work', () => {\n      formGroup.get('input')!.markAsDirty();\n      formGroup.get('input2')!.markAsDirty();\n      formGroup.get('input')!.setValue('123');\n      formGroup.get('input2')!.setValue('123');\n      formGroup.get('input')!.updateValueAndValidity();\n      formGroup.get('input2')!.updateValueAndValidity();\n\n      fixture.detectChanges();\n\n      expect(formItems[0].nativeElement.classList).toContain(statusMap.success);\n      expect(formItems[1].nativeElement.classList).toContain(statusMap.success);\n    });\n\n    it('should invalid work', () => {\n      formGroup.get('input')!.markAsDirty();\n      formGroup.get('input2')!.markAsDirty();\n      formGroup.get('input')!.setValue('');\n      formGroup.get('input2')!.setValue('');\n      formGroup.get('input')!.updateValueAndValidity();\n      formGroup.get('input2')!.updateValueAndValidity();\n\n      fixture.detectChanges();\n\n      expect(formItems[0].nativeElement.classList).toContain(statusMap.error);\n      expect(formItems[1].nativeElement.classList).toContain(statusMap.error);\n    });\n\n    it('should dirty work', () => {\n      formGroup.get('input')!.markAsDirty();\n      formGroup.get('input2')!.markAsDirty();\n      formGroup.get('input')!.updateValueAndValidity();\n      formGroup.get('input2')!.updateValueAndValidity();\n\n      fixture.detectChanges();\n\n      expect(formItems[0].nativeElement.classList).toContain(statusMap.error);\n      expect(formItems[1].nativeElement.classList).toContain(statusMap.error);\n\n      formGroup.get('input')!.markAsPristine();\n      formGroup.get('input2')!.markAsPristine();\n      formGroup.get('input')!.updateValueAndValidity();\n      formGroup.get('input2')!.updateValueAndValidity();\n\n      fixture.detectChanges();\n\n      expect(formItems[0].nativeElement.classList).not.toContain(statusMap.error);\n      expect(formItems[1].nativeElement.classList).not.toContain(statusMap.error);\n    });\n\n    it('should pending work', () => {\n      formGroup.get('input')!.markAsPending();\n      formGroup.get('input2')!.markAsPending();\n      formGroup.get('input')!.updateValueAndValidity();\n      formGroup.get('input2')!.updateValueAndValidity();\n\n      fixture.detectChanges();\n\n      expect(formItems[0].nativeElement.classList).not.toContain(statusMap.error);\n      expect(formItems[1].nativeElement.classList).not.toContain(statusMap.error);\n    });\n  });\n\n  describe('reactive init status', () => {\n    let fixture: ComponentFixture<NzTestReactiveFormControlInitStatusComponent>;\n    let testComponent: NzTestReactiveFormControlInitStatusComponent;\n    let formItem: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestReactiveFormControlInitStatusComponent);\n      fixture.detectChanges();\n      testComponent = fixture.componentInstance;\n      formItem = fixture.debugElement.query(By.directive(NzFormItemComponent));\n    });\n\n    it('should init status correct', () => {\n      expect(formItem.nativeElement.classList).toContain(statusMap.error);\n    });\n\n    it('should warning status work', () => {\n      testComponent.formGroup.get('input')!.setErrors({ warning: true });\n      fixture.detectChanges();\n\n      expect(formItem.nativeElement.classList).toContain(statusMap.warning);\n    });\n  });\n\n  describe('auto tips', () => {\n    let fixture: ComponentFixture<NzTestReactiveFormAutoTipsComponent>;\n    let testComponent: NzTestReactiveFormAutoTipsComponent;\n    let formGroup: FormGroup<{\n      username: FormControl<string | null>;\n      mobile: FormControl<string | null>;\n      email: FormControl<string | null>;\n      password: FormControl<string | null>;\n      confirmPassword: FormControl<string | null>;\n    }>;\n    let formControls: DebugElement[];\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestReactiveFormAutoTipsComponent);\n      testComponent = fixture.componentInstance;\n      formGroup = testComponent.formGroup;\n      formControls = fixture.debugElement.queryAll(By.directive(NzFormControlComponent));\n    });\n\n    it('should default work ', () => {\n      formGroup.get('username')!.markAsDirty();\n      formGroup.get('mobile')!.markAsDirty();\n      formGroup.get('email')!.markAsDirty();\n      formGroup.get('password')!.markAsDirty();\n      formGroup.get('confirmPassword')!.markAsDirty();\n      formGroup.get('username')!.updateValueAndValidity();\n      formGroup.get('mobile')!.updateValueAndValidity();\n      formGroup.get('email')!.updateValueAndValidity();\n      formGroup.get('password')!.updateValueAndValidity();\n      formGroup.get('confirmPassword')!.updateValueAndValidity();\n\n      fixture.detectChanges();\n\n      expect(formControls[0].nativeElement.querySelector('.ant-form-item-explain').textContent).toEqual('必填项');\n      expect(formControls[1].nativeElement.querySelector('.ant-form-item-explain').textContent).toEqual('必填项');\n      expect(formControls[2].nativeElement.querySelector('.ant-form-item-explain').textContent).toEqual(\n        '请输入邮箱/Input is required'\n      );\n      expect(formControls[3].nativeElement.querySelector('.ant-form-item-explain').textContent).toEqual('必填项');\n\n      fixture.detectChanges();\n\n      formGroup.get('username')!.setValue('12345');\n      formGroup.get('mobile')!.setValue('12345');\n      formGroup.get('email')!.setValue('12345');\n\n      fixture.detectChanges();\n\n      expect(formControls[0].nativeElement.querySelector('.ant-form-item-explain').textContent).toEqual(`最小长度为 6`);\n      expect(formControls[1].nativeElement.querySelector('.ant-form-item-explain').textContent).toEqual(\n        '手机号码格式不正确'\n      );\n      expect(formControls[2].nativeElement.querySelector('.ant-form-item-explain').textContent).toEqual(\n        '请输入正确的邮箱'\n      );\n\n      fixture.detectChanges();\n\n      testComponent.formAutoTips = {\n        'zh-cn': {\n          required: '请输入',\n          email: '邮箱格式不正确'\n        },\n        en: {\n          required: 'Input is required',\n          email: 'The input is not valid email'\n        }\n      };\n      fixture.detectChanges();\n\n      formGroup.get('username')!.setValue('');\n      formGroup.get('mobile')!.setValue('');\n      formGroup.get('email')!.setValue('');\n\n      fixture.detectChanges();\n\n      expect(formControls[0].nativeElement.querySelector('.ant-form-item-explain').textContent).toEqual('请输入');\n      expect(formControls[1].nativeElement.querySelector('.ant-form-item-explain').textContent).toEqual('请输入');\n      expect(formControls[2].nativeElement.querySelector('.ant-form-item-explain').textContent).toEqual(\n        '请输入邮箱/Input is required'\n      );\n      expect(formControls[3].nativeElement.querySelector('.ant-form-item-explain').textContent).toEqual('请输入');\n\n      fixture.detectChanges();\n\n      testComponent.showConfirmPassword = true;\n      fixture.detectChanges();\n\n      formGroup.get('username')!.setValue('');\n      formGroup.get('mobile')!.setValue('');\n      formGroup.get('email')!.setValue('');\n      fixture.detectChanges();\n\n      formControls = fixture.debugElement.queryAll(By.directive(NzFormControlComponent));\n\n      expect(formControls[0].nativeElement.querySelector('.ant-form-item-explain').textContent).toEqual('请输入');\n      expect(formControls[1].nativeElement.querySelector('.ant-form-item-explain').textContent).toEqual('请输入');\n      expect(formControls[2].nativeElement.querySelector('.ant-form-item-explain').textContent).toEqual(\n        '请输入邮箱/Input is required'\n      );\n      expect(formControls[3].nativeElement.querySelector('.ant-form-item-explain').textContent).toEqual('请输入');\n      expect(formControls[4].nativeElement.querySelector('.ant-form-item-explain').textContent).toEqual('请输入');\n    });\n\n    it('should i18n work ', () => {\n      formGroup.get('username')!.markAsDirty();\n      formGroup.get('mobile')!.markAsDirty();\n      formGroup.get('email')!.markAsDirty();\n      formGroup.get('username')!.updateValueAndValidity();\n      formGroup.get('mobile')!.updateValueAndValidity();\n      formGroup.get('email')!.updateValueAndValidity();\n\n      fixture.detectChanges();\n\n      testComponent.i18n.setLocale(en_US);\n      fixture.detectChanges();\n\n      formGroup.get('username')!.setValue('');\n      formGroup.get('mobile')!.setValue('');\n      formGroup.get('email')!.setValue('');\n      fixture.detectChanges();\n\n      expect(formControls[0].nativeElement.querySelector('.ant-form-item-explain').textContent).toEqual(\n        'Input is required'\n      );\n      expect(formControls[1].nativeElement.querySelector('.ant-form-item-explain').textContent).toEqual(\n        'Input is required'\n      );\n      expect(formControls[2].nativeElement.querySelector('.ant-form-item-explain').textContent).toEqual(\n        '请输入邮箱/Input is required'\n      );\n\n      formGroup.get('username')!.setValue('12345');\n      formGroup.get('mobile')!.setValue('12345');\n      formGroup.get('email')!.setValue('12345');\n\n      fixture.detectChanges();\n\n      expect(formControls[0].nativeElement.querySelector('.ant-form-item-explain').textContent).toEqual(\n        `MinLength is 6`\n      );\n      expect(formControls[1].nativeElement.querySelector('.ant-form-item-explain').textContent).toEqual(\n        'Mobile phone number is not valid'\n      );\n      expect(formControls[2].nativeElement.querySelector('.ant-form-item-explain').textContent).toEqual(\n        'Please input valid email'\n      );\n    });\n\n    it('should nzDisableAutoTips work ', fakeAsync(() => {\n      formGroup.get('username')!.markAsDirty();\n      formGroup.get('mobile')!.markAsDirty();\n      formGroup.get('email')!.markAsDirty();\n      formGroup.get('password')!.markAsDirty();\n      formGroup.get('username')!.updateValueAndValidity();\n      formGroup.get('mobile')!.updateValueAndValidity();\n      formGroup.get('email')!.updateValueAndValidity();\n      formGroup.get('password')!.updateValueAndValidity();\n\n      fixture.detectChanges();\n\n      testComponent.passwordDisableAutoTips = true;\n      fixture.detectChanges();\n\n      formGroup.get('password')!.updateValueAndValidity();\n      fixture.detectChanges();\n\n      expect(formControls[3].nativeElement.querySelector('.ant-form-item-explain').textContent).toEqual(\n        'Please input your password!'\n      );\n\n      testComponent.formDisableAutoTips = true;\n      fixture.detectChanges();\n\n      formGroup.get('username')!.setValue('12345');\n      formGroup.get('mobile')!.setValue('12345');\n      formGroup.get('email')!.setValue('12345');\n\n      fixture.detectChanges();\n      tick(300 + 50);\n      fixture.detectChanges();\n\n      expect(formControls[0].nativeElement.querySelector('.ant-form-item-explain')).toBeNull();\n      expect(formControls[1].nativeElement.querySelector('.ant-form-item-explain')).toBeNull();\n      expect(formControls[2].nativeElement.querySelector('.ant-form-item-explain')).toBeNull();\n    }));\n\n    it('should nzErrorTip change work', () => {\n      testComponent.passwordDisableAutoTips = true;\n\n      formGroup.get('password')!.markAsDirty();\n      formGroup.get('password')!.updateValueAndValidity();\n\n      fixture.detectChanges();\n\n      expect(formControls[3].nativeElement.querySelector('.ant-form-item-explain').textContent).toEqual(\n        'Please input your password!'\n      );\n\n      const passwordErrorTip = '请输入密码';\n      testComponent.passwordErrorTip = passwordErrorTip;\n\n      fixture.detectChanges();\n\n      expect(formControls[3].nativeElement.querySelector('.ant-form-item-explain').textContent).toEqual(\n        passwordErrorTip\n      );\n    });\n  });\n\n  describe('NoopAnimations', () => {\n    let fixture: ComponentFixture<NzTestNoopAnimationsFormControlComponent>;\n    let formGroup: FormGroup<{ input: FormControl<string | null> }>;\n    let formControl: DebugElement;\n\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        providers: [provideZoneChangeDetection(), provideNzNoAnimation()]\n      });\n      fixture = TestBed.createComponent(NzTestNoopAnimationsFormControlComponent);\n      formGroup = fixture.componentInstance.formGroup;\n      formControl = fixture.debugElement.query(By.directive(NzFormControlComponent));\n    });\n\n    it('should call animationComplete immediately when animations are disabled', () => {\n      formGroup.get('input')!.markAsDirty();\n      formGroup.get('input')!.updateValueAndValidity();\n      fixture.detectChanges();\n\n      expect(formControl.nativeElement.querySelector('.ant-form-item-explain')).not.toBeNull();\n\n      const mockEvent: AnimationCallbackEvent = {\n        target: formControl.nativeElement.querySelector('.ant-form-item-explain'),\n        animationComplete: jasmine.createSpy('animationComplete')\n      };\n\n      formControl.componentInstance.onAnimationLeave(mockEvent);\n\n      expect(mockEvent.animationComplete).toHaveBeenCalled();\n    });\n\n    it('should return nz-animate-disabled class when animations are disabled', () => {\n      expect(formControl.componentInstance.nzValidateAnimationEnter()).toBe('nz-animate-disabled');\n      expect(formControl.componentInstance.nzValidateAnimationLeave()).toBe('nz-animate-disabled');\n    });\n  });\n});\n\n@Component({\n  imports: [NzFormModule],\n  template: `\n    <nz-form-item>\n      <nz-form-control [nzHasFeedback]=\"hasFeedback\" [nzValidateStatus]=\"status\" />\n    </nz-form-item>\n  `\n})\nexport class NzTestStaticFormControlComponent {\n  hasFeedback = false;\n  status = 'success';\n}\n\n@Component({\n  imports: [ReactiveFormsModule, NzFormModule],\n  template: `\n    <form [formGroup]=\"formGroup\">\n      <nz-form-item>\n        <nz-form-control>\n          <input formControlName=\"input\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-control [nzValidateStatus]=\"validateStatus\">\n          <input formControlName=\"input3\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-control>\n        <input formControlName=\"input2\" />\n      </nz-form-control>\n    </form>\n  `\n})\nexport class NzTestReactiveFormControlComponent {\n  formGroup: FormGroup<{\n    input: FormControl<string | null>;\n    input2: FormControl<string | null>;\n    input3: FormControl<string | null>;\n  }>;\n  validateStatus: FormControl<string | null>;\n\n  constructor(private formBuilder: FormBuilder) {\n    this.formGroup = this.formBuilder.group({\n      input: this.formBuilder.control('', [Validators.required]),\n      input2: this.formBuilder.control('', [Validators.required]),\n      input3: this.formBuilder.control('', [Validators.required])\n    });\n    this.validateStatus = this.formGroup.controls.input2;\n  }\n}\n\n/** https://github.com/NG-ZORRO/ng-zorro-antd/issues/1170 **/\n@Component({\n  imports: [ReactiveFormsModule, NzFormModule],\n  template: `\n    <form [formGroup]=\"formGroup\">\n      <nz-form-item>\n        <nz-form-control>\n          <input formControlName=\"input\" />\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `\n})\nexport class NzTestReactiveFormControlInitStatusComponent {\n  formGroup: FormGroup;\n\n  constructor(private formBuilder: FormBuilder) {\n    this.formGroup = this.formBuilder.group({\n      input: ['', [Validators.required]]\n    });\n    this.formGroup.controls.input.markAsDirty();\n  }\n}\n\n@Component({\n  imports: [ReactiveFormsModule, NzFormModule, NzInputModule],\n  template: `\n    <form [formGroup]=\"formGroup\" nz-form [nzAutoTips]=\"formAutoTips\" [nzDisableAutoTips]=\"formDisableAutoTips\">\n      <nz-form-item>\n        <nz-form-control #control>\n          <input nz-input formControlName=\"username\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-control>\n          <input nz-input formControlName=\"mobile\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-control [nzAutoTips]=\"emailAutoTips\">\n          <input nz-input formControlName=\"email\" type=\"email\" />\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-control [nzDisableAutoTips]=\"passwordDisableAutoTips\" [nzErrorTip]=\"passwordErrorTip\">\n          <input nz-input type=\"password\" formControlName=\"password\" />\n        </nz-form-control>\n      </nz-form-item>\n      @if (showConfirmPassword) {\n        <nz-form-item>\n          <nz-form-control>\n            <input nz-input type=\"password\" formControlName=\"confirmPassword\" />\n          </nz-form-control>\n        </nz-form-item>\n      }\n    </form>\n  `\n})\nexport class NzTestReactiveFormAutoTipsComponent {\n  formGroup: FormGroup<{\n    username: FormControl<string | null>;\n    mobile: FormControl<string | null>;\n    email: FormControl<string | null>;\n    password: FormControl<string | null>;\n    confirmPassword: FormControl<string | null>;\n  }>;\n\n  showConfirmPassword = false;\n\n  formDisableAutoTips = false;\n  passwordDisableAutoTips = false;\n  passwordErrorTip = 'Please input your password!';\n\n  formAutoTips = {\n    'zh-cn': {\n      required: '必填项',\n      email: '邮箱格式不正确'\n    },\n    en: {\n      required: 'Input is required',\n      email: 'The input is not valid email'\n    }\n  };\n  emailAutoTips = {\n    'zh-cn': {\n      email: '请输入正确的邮箱'\n    },\n    en: {\n      email: 'Please input valid email'\n    },\n    default: {\n      required: '请输入邮箱/Input is required'\n    }\n  };\n\n  constructor(\n    private formBuilder: FormBuilder,\n    public i18n: NzI18nService\n  ) {\n    const { required, minLength, email, mobile } = MyValidators;\n    this.formGroup = this.formBuilder.group({\n      username: ['', [required, minLength(6)]],\n      mobile: ['', [required, mobile]],\n      email: ['', [required, email]],\n      password: ['', [required]],\n      confirmPassword: ['', [required]]\n    });\n  }\n}\n\nexport type MyErrorsOptions = { 'zh-cn': string; en: string } & Record<string, NzSafeAny>;\nexport type MyValidationErrors = Record<string, MyErrorsOptions>;\n\nexport class MyValidators extends Validators {\n  static override minLength(minLength: number): ValidatorFn {\n    return (control: AbstractControl): MyValidationErrors | null => {\n      if (Validators.minLength(minLength)(control) === null) {\n        return null;\n      }\n      return { minlength: { 'zh-cn': `最小长度为 ${minLength}`, en: `MinLength is ${minLength}` } };\n    };\n  }\n\n  static mobile(control: AbstractControl): MyValidationErrors | null {\n    const value = control.value;\n\n    if (isEmptyInputValue(value)) {\n      return null;\n    }\n\n    return isMobile(value)\n      ? null\n      : { mobile: { 'zh-cn': `手机号码格式不正确`, en: `Mobile phone number is not valid` } };\n  }\n}\n\nfunction isEmptyInputValue(value: NzSafeAny): boolean {\n  return value == null || value.length === 0;\n}\n\nfunction isMobile(value: string): boolean {\n  return typeof value === 'string' && /(^1\\d{10}$)/.test(value);\n}\n\n@Component({\n  imports: [ReactiveFormsModule, NzFormModule],\n  template: `\n    <form [formGroup]=\"formGroup\">\n      <nz-form-item>\n        <nz-form-control nzErrorTip=\"This field is required\">\n          <input formControlName=\"input\" />\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `\n})\nexport class NzTestNoopAnimationsFormControlComponent {\n  formGroup: FormGroup<{ input: FormControl<string | null> }>;\n\n  constructor(private formBuilder: FormBuilder) {\n    this.formGroup = this.formBuilder.group({\n      input: this.formBuilder.control('', [Validators.required])\n    });\n  }\n}\n"
  },
  {
    "path": "components/form/form-item.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, inject, ViewEncapsulation } from '@angular/core';\n\nexport type NzFormControlStatusType = 'success' | 'error' | 'warning' | 'validating' | '';\n\n/** should add nz-row directive to host, track https://github.com/angular/angular/issues/8785 **/\n@Component({\n  selector: 'nz-form-item',\n  exportAs: 'nzFormItem',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  host: {\n    class: 'ant-form-item',\n    '[class.ant-form-item-has-success]': 'status === \"success\"',\n    '[class.ant-form-item-has-warning]': 'status === \"warning\"',\n    '[class.ant-form-item-has-error]': 'status === \"error\"',\n    '[class.ant-form-item-is-validating]': 'status === \"validating\"',\n    '[class.ant-form-item-has-feedback]': 'hasFeedback && status',\n    '[class.ant-form-item-with-help]': 'withHelpClass'\n  },\n  template: `<ng-content />`\n})\nexport class NzFormItemComponent {\n  private cdr = inject(ChangeDetectorRef);\n\n  status: NzFormControlStatusType = '';\n  hasFeedback = false;\n  withHelpClass = false;\n\n  setWithHelpViaTips(value: boolean): void {\n    this.withHelpClass = value;\n    this.cdr.markForCheck();\n  }\n\n  setStatus(status: NzFormControlStatusType): void {\n    this.status = status;\n    this.cdr.markForCheck();\n  }\n\n  setHasFeedback(hasFeedback: boolean): void {\n    this.hasFeedback = hasFeedback;\n    this.cdr.markForCheck();\n  }\n}\n"
  },
  {
    "path": "components/form/form-item.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { TestBed } from '@angular/core/testing';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { NzFormItemComponent } from './form-item.component';\n\ndescribe('nz-form-item', () => {\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations()]\n    });\n  });\n\n  it('should className correct', () => {\n    const fixture = TestBed.createComponent(NzFormItemComponent);\n    expect(fixture.nativeElement.classList).toContain('ant-form-item');\n  });\n});\n"
  },
  {
    "path": "components/form/form-label.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  Input,\n  ViewEncapsulation,\n  booleanAttribute,\n  computed,\n  inject\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { filter } from 'rxjs/operators';\n\nimport { ThemeType } from '@ant-design/icons-angular';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzTSType } from 'ng-zorro-antd/core/types';\nimport { isTemplateRef } from 'ng-zorro-antd/core/util';\nimport { NzI18nModule } from 'ng-zorro-antd/i18n';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzTooltipDirective } from 'ng-zorro-antd/tooltip';\n\nimport { DefaultTooltipIcon, NzFormDirective, NzLabelAlignType } from './form.directive';\n\nexport interface NzFormTooltipIcon {\n  type: NzTSType;\n  theme: ThemeType;\n}\n\nfunction toTooltipIcon(value: string | NzFormTooltipIcon): Required<NzFormTooltipIcon> {\n  const icon = typeof value === 'string' ? { type: value } : value;\n  return { ...DefaultTooltipIcon, ...icon };\n}\n\n@Component({\n  selector: 'nz-form-label',\n  exportAs: 'nzFormLabel',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    <label\n      [attr.for]=\"nzFor\"\n      [class.ant-form-item-no-colon]=\"nzNoColon\"\n      [class.ant-form-item-required]=\"nzRequired\"\n      [class.ant-form-item-required-mark-optional]=\"nzRequiredMark?.() === 'optional' || isNzRequiredMarkTemplate()\"\n      [class.ant-form-item-required-mark-hidden]=\"nzRequiredMark?.() === false\"\n    >\n      <ng-template #labelTemplate>\n        <ng-content />\n        @if (nzTooltipTitle) {\n          <span class=\"ant-form-item-tooltip\" nz-tooltip [nzTooltipTitle]=\"nzTooltipTitle\">\n            <ng-container *nzStringTemplateOutlet=\"tooltipIcon.type; let tooltipIconType\">\n              <nz-icon [nzType]=\"tooltipIconType\" [nzTheme]=\"tooltipIcon.theme\" />\n            </ng-container>\n          </span>\n        }\n        @if (nzRequiredMark?.() === 'optional' && !nzRequired) {\n          <span class=\"ant-form-item-optional\">{{ 'Form.optional' | nzI18n }}</span>\n        }\n      </ng-template>\n\n      @if (isNzRequiredMarkTemplate()) {\n        <ng-container\n          *ngTemplateOutlet=\"$any(nzRequiredMark!()); context: { required: nzRequired, $implicit: labelTemplate }\"\n        />\n      } @else {\n        <ng-container *ngTemplateOutlet=\"labelTemplate\" />\n      }\n    </label>\n  `,\n  host: {\n    class: 'ant-form-item-label',\n    '[class.ant-form-item-label-left]': `nzLabelAlign === 'left'`,\n    '[class.ant-form-item-label-wrap]': `nzLabelWrap`\n  },\n  imports: [NzOutletModule, NzTooltipDirective, NzIconModule, NgTemplateOutlet, NzI18nModule]\n})\nexport class NzFormLabelComponent {\n  private cdr = inject(ChangeDetectorRef);\n\n  @Input() nzFor?: string;\n  @Input({ transform: booleanAttribute }) nzRequired = false;\n  @Input({ transform: booleanAttribute })\n  set nzNoColon(value: boolean) {\n    this.noColon = value;\n  }\n  get nzNoColon(): boolean {\n    return this.noColon !== 'default' ? this.noColon : !!this.nzFormDirective?.nzNoColon;\n  }\n\n  private noColon: boolean | 'default' = 'default';\n\n  @Input() nzTooltipTitle?: NzTSType;\n  @Input()\n  set nzTooltipIcon(value: string | NzFormTooltipIcon) {\n    this._tooltipIcon = toTooltipIcon(value);\n  }\n  // due to 'get' and 'set' accessor must have the same type, so it was renamed to `tooltipIcon`\n  get tooltipIcon(): NzFormTooltipIcon {\n    return this._tooltipIcon !== 'default'\n      ? this._tooltipIcon\n      : toTooltipIcon(this.nzFormDirective?.nzTooltipIcon || DefaultTooltipIcon);\n  }\n  private _tooltipIcon: NzFormTooltipIcon | 'default' = 'default';\n\n  @Input()\n  set nzLabelAlign(value: NzLabelAlignType) {\n    this.labelAlign = value;\n  }\n\n  get nzLabelAlign(): NzLabelAlignType {\n    return this.labelAlign !== 'default' ? this.labelAlign : this.nzFormDirective?.nzLabelAlign || 'right';\n  }\n\n  private labelAlign: NzLabelAlignType | 'default' = 'default';\n\n  @Input({ transform: booleanAttribute })\n  set nzLabelWrap(value: boolean) {\n    this.labelWrap = value;\n  }\n\n  get nzLabelWrap(): boolean {\n    return this.labelWrap !== 'default' ? this.labelWrap : !!this.nzFormDirective?.nzLabelWrap;\n  }\n\n  private labelWrap: boolean | 'default' = 'default';\n\n  private nzFormDirective = inject(NzFormDirective, { skipSelf: true, optional: true });\n\n  protected readonly nzRequiredMark = this.nzFormDirective?.nzRequiredMark;\n\n  protected readonly isNzRequiredMarkTemplate = computed(() => isTemplateRef(this.nzRequiredMark?.()));\n\n  constructor() {\n    if (this.nzFormDirective) {\n      this.nzFormDirective\n        .getInputObservable('nzNoColon')\n        .pipe(\n          filter(() => this.noColon === 'default'),\n          takeUntilDestroyed()\n        )\n        .subscribe(() => this.cdr.markForCheck());\n\n      this.nzFormDirective\n        .getInputObservable('nzTooltipIcon')\n        .pipe(\n          filter(() => this._tooltipIcon === 'default'),\n          takeUntilDestroyed()\n        )\n        .subscribe(() => this.cdr.markForCheck());\n\n      this.nzFormDirective\n        .getInputObservable('nzLabelAlign')\n        .pipe(\n          filter(() => this.labelAlign === 'default'),\n          takeUntilDestroyed()\n        )\n        .subscribe(() => this.cdr.markForCheck());\n\n      this.nzFormDirective\n        .getInputObservable('nzLabelWrap')\n        .pipe(\n          filter(() => this.labelWrap === 'default'),\n          takeUntilDestroyed()\n        )\n        .subscribe(() => this.cdr.markForCheck());\n    }\n  }\n}\n"
  },
  {
    "path": "components/form/form-label.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterViewInit,\n  Component,\n  DebugElement,\n  provideZoneChangeDetection,\n  TemplateRef,\n  ViewChild\n} from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { NzLabelAlignType } from 'ng-zorro-antd/form/form.directive';\nimport { NzFormModule } from 'ng-zorro-antd/form/form.module';\nimport { en_US, NzI18nService } from 'ng-zorro-antd/i18n';\n\nimport { NzFormLabelComponent, NzFormTooltipIcon } from './form-label.component';\nimport { NzRequiredMark } from './types';\n\ndescribe('form-label', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection(), provideNoopAnimations()]\n    });\n  });\n\n  describe('default', () => {\n    let fixture: ComponentFixture<NzTestFormLabelComponent>;\n    let testComponent: NzTestFormLabelComponent;\n    let label: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestFormLabelComponent);\n      testComponent = fixture.componentInstance;\n      fixture.detectChanges();\n      label = fixture.debugElement.query(By.directive(NzFormLabelComponent));\n    });\n\n    it('should className correct', () => {\n      expect(label.nativeElement.classList).toContain('ant-form-item-label');\n    });\n\n    it('should label for work', () => {\n      expect(label.nativeElement.querySelector('label').attributes.getNamedItem('for').value).toBe('test');\n    });\n\n    it('should required work', () => {\n      expect(label.nativeElement.querySelector('label').classList).not.toContain('ant-form-item-required');\n\n      testComponent.required = true;\n      fixture.detectChanges();\n\n      expect(label.nativeElement.querySelector('label').classList).toContain('ant-form-item-required');\n    });\n\n    it('should no colon work', () => {\n      expect(label.nativeElement.querySelector('label').classList).not.toContain('ant-form-item-no-colon');\n\n      testComponent.noColon = true;\n      fixture.detectChanges();\n\n      expect(label.nativeElement.querySelector('label').classList).toContain('ant-form-item-no-colon');\n    });\n\n    it('should tooltip work', () => {\n      expect(label.nativeElement.querySelector('.ant-form-item-tooltip')).toBeNull();\n\n      testComponent.tooltipTitle = 'tooltip';\n      fixture.detectChanges();\n\n      expect(label.nativeElement.querySelector('.ant-form-item-tooltip')).toBeDefined();\n      expect(label.nativeElement.querySelector('.anticon-question-circle')).toBeDefined();\n\n      testComponent.tooltipIcon = 'info-circle';\n      fixture.detectChanges();\n\n      expect(label.nativeElement.querySelector('.ant-form-item-tooltip')).toBeDefined();\n      expect(label.nativeElement.querySelector('.anticon-info-circle')).toBeDefined();\n    });\n\n    it('should label align work', () => {\n      expect(label.nativeElement.classList).not.toContain('ant-form-item-label-left');\n\n      testComponent.align = 'left';\n      fixture.detectChanges();\n\n      expect(label.nativeElement.classList).toContain('ant-form-item-label-left');\n    });\n\n    it('should label wrap work', () => {\n      expect(label.nativeElement.classList).not.toContain('ant-form-item-label-wrap');\n\n      testComponent.labelWrap = true;\n      fixture.detectChanges();\n\n      expect(label.nativeElement.classList).toContain('ant-form-item-label-wrap');\n    });\n  });\n\n  describe('with form required mark integration', () => {\n    let fixture: ComponentFixture<NzTestFormLabelRequiredMarkComponent>;\n    let testComponent: NzTestFormLabelRequiredMarkComponent;\n    let labels: DebugElement[];\n    let i18nService: NzI18nService;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestFormLabelRequiredMarkComponent);\n      testComponent = fixture.componentInstance;\n      i18nService = TestBed.inject(NzI18nService);\n      i18nService.setLocale(en_US);\n      fixture.detectChanges();\n      labels = fixture.debugElement.queryAll(By.directive(NzFormLabelComponent));\n    });\n\n    it('should inherit required mark from form directive when using boolean true', () => {\n      const requiredLabel = labels.find(l => l.nativeElement.classList.contains('required-label'));\n      const optionalLabel = labels.find(l => l.nativeElement.classList.contains('optional-label'));\n\n      expect(requiredLabel?.nativeElement.querySelector('label').classList).toContain('ant-form-item-required');\n      expect(requiredLabel?.nativeElement.querySelector('label').classList).not.toContain(\n        'ant-form-item-required-mark-optional'\n      );\n      expect(optionalLabel?.nativeElement.querySelector('label').classList).not.toContain('ant-form-item-required');\n    });\n\n    it('should show optional styling when form nzRequiredMark is false', () => {\n      testComponent.requiredMark = false;\n      fixture.detectChanges();\n\n      const requiredLabel = labels.find(l => l.nativeElement.classList.contains('required-label'));\n      const optionalLabel = labels.find(l => l.nativeElement.classList.contains('optional-label'));\n\n      expect(requiredLabel?.nativeElement.querySelector('label').classList).toContain('ant-form-item-required');\n      expect(requiredLabel?.nativeElement.querySelector('label').classList).toContain(\n        'ant-form-item-required-mark-hidden'\n      );\n      expect(optionalLabel?.nativeElement.querySelector('label').classList).not.toContain('ant-form-item-required');\n      expect(optionalLabel?.nativeElement.querySelector('label').classList).toContain(\n        'ant-form-item-required-mark-hidden'\n      );\n    });\n\n    it('should show optional styling when form nzRequiredMark is \"optional\"', () => {\n      testComponent.requiredMark = 'optional';\n      fixture.detectChanges();\n\n      const requiredLabel = labels.find(l => l.nativeElement.classList.contains('required-label'));\n      const optionalLabel = labels.find(l => l.nativeElement.classList.contains('optional-label'));\n\n      expect(requiredLabel?.nativeElement.querySelector('label').classList).toContain('ant-form-item-required');\n      expect(requiredLabel?.nativeElement.querySelector('label').classList).toContain(\n        'ant-form-item-required-mark-optional'\n      );\n      expect(optionalLabel?.nativeElement.querySelector('label').classList).not.toContain('ant-form-item-required');\n    });\n\n    it('should show optional text when nzRequiredMark is \"optional\" and field is not required', () => {\n      testComponent.requiredMark = 'optional';\n      fixture.detectChanges();\n\n      const requiredLabel = labels.find(l => l.nativeElement.classList.contains('required-label'));\n      const optionalLabel = labels.find(l => l.nativeElement.classList.contains('optional-label'));\n\n      // Required label should NOT show (optional) text\n      expect(requiredLabel?.nativeElement.querySelector('.ant-form-item-optional')).toBeNull();\n\n      // Optional label should show (optional) text\n      expect(optionalLabel?.nativeElement.querySelector('.ant-form-item-optional')).toBeTruthy();\n      expect(optionalLabel?.nativeElement.querySelector('.ant-form-item-optional').textContent?.trim()).toBe(\n        '(optional)'\n      );\n    });\n\n    it('should NOT show optional text when nzRequiredMark is false', () => {\n      testComponent.requiredMark = false;\n      fixture.detectChanges();\n\n      const requiredLabel = labels.find(l => l.nativeElement.classList.contains('required-label'));\n      const optionalLabel = labels.find(l => l.nativeElement.classList.contains('optional-label'));\n\n      expect(requiredLabel?.nativeElement.querySelector('.ant-form-item-optional')).toBeNull();\n      expect(optionalLabel?.nativeElement.querySelector('.ant-form-item-optional')).toBeNull();\n    });\n\n    it('should NOT show optional text when nzRequiredMark is true', () => {\n      testComponent.requiredMark = true;\n      fixture.detectChanges();\n\n      const requiredLabel = labels.find(l => l.nativeElement.classList.contains('required-label'));\n      const optionalLabel = labels.find(l => l.nativeElement.classList.contains('optional-label'));\n\n      expect(requiredLabel?.nativeElement.querySelector('.ant-form-item-optional')).toBeNull();\n      expect(optionalLabel?.nativeElement.querySelector('.ant-form-item-optional')).toBeNull();\n    });\n\n    it('should use custom template when provided', () => {\n      testComponent.useCustomTemplate = true;\n      fixture.detectChanges();\n\n      const requiredLabel = labels.find(l => l.nativeElement.classList.contains('required-label'));\n      const optionalLabel = labels.find(l => l.nativeElement.classList.contains('optional-label'));\n\n      expect(requiredLabel?.nativeElement.querySelector('.custom-required')).toBeTruthy();\n      expect(requiredLabel?.nativeElement.querySelector('.custom-required').textContent?.trim()).toBe('REQUIRED');\n      expect(optionalLabel?.nativeElement.querySelector('.custom-optional')).toBeTruthy();\n      expect(optionalLabel?.nativeElement.querySelector('.custom-optional').textContent?.trim()).toBe('OPTIONAL');\n\n      expect(requiredLabel?.nativeElement.querySelector('.label-content')).toBeTruthy();\n      expect(optionalLabel?.nativeElement.querySelector('.label-content')).toBeTruthy();\n    });\n\n    it('should handle template context correctly with required and optional labels', () => {\n      testComponent.useCustomTemplate = true;\n      fixture.detectChanges();\n\n      const requiredLabelElement = fixture.debugElement.query(By.css('.required-label'));\n      const optionalLabelElement = fixture.debugElement.query(By.css('.optional-label'));\n\n      const requiredCustom = requiredLabelElement.nativeElement.querySelector('.custom-required');\n      const optionalCustom = optionalLabelElement.nativeElement.querySelector('.custom-optional');\n\n      expect(requiredCustom).toBeTruthy();\n      expect(optionalCustom).toBeTruthy();\n      expect(requiredCustom.textContent?.trim()).toBe('REQUIRED');\n      expect(optionalCustom.textContent?.trim()).toBe('OPTIONAL');\n    });\n  });\n});\n\n@Component({\n  imports: [NzFormModule],\n  template: `\n    <nz-form-label\n      [nzFor]=\"forValue\"\n      [nzNoColon]=\"noColon\"\n      [nzRequired]=\"required\"\n      [nzTooltipTitle]=\"tooltipTitle\"\n      [nzTooltipIcon]=\"tooltipIcon\"\n      [nzLabelAlign]=\"align\"\n      [nzLabelWrap]=\"labelWrap\"\n    />\n  `\n})\nexport class NzTestFormLabelComponent {\n  forValue = 'test';\n  required = false;\n  noColon = false;\n  tooltipTitle?: string;\n  tooltipIcon!: string | NzFormTooltipIcon;\n  align: NzLabelAlignType = 'right';\n  labelWrap = false;\n}\n\n@Component({\n  imports: [NzFormModule, NgTemplateOutlet],\n  template: `\n    <form nz-form [nzRequiredMark]=\"useCustomTemplate ? customRequiredMarkTemplate : requiredMark\">\n      <nz-form-item>\n        <nz-form-label class=\"required-label\" nzRequired>\n          <span class=\"label-content\">Required Field</span>\n        </nz-form-label>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label class=\"optional-label\">\n          <span class=\"label-content\">Optional Field</span>\n        </nz-form-label>\n      </nz-form-item>\n    </form>\n\n    <ng-template #customRequiredMarkTemplate let-label let-required=\"required\">\n      @if (required) {\n        <span class=\"custom-required\">REQUIRED</span>\n      } @else {\n        <span class=\"custom-optional\">OPTIONAL</span>\n      }\n      <ng-container *ngTemplateOutlet=\"label\" />\n    </ng-template>\n  `\n})\nexport class NzTestFormLabelRequiredMarkComponent implements AfterViewInit {\n  requiredMark: NzRequiredMark = true;\n  useCustomTemplate = false;\n\n  @ViewChild('customRequiredMarkTemplate', { static: true })\n  customRequiredMarkTemplate!: TemplateRef<{ $implicit: TemplateRef<void>; required: boolean }>;\n\n  ngAfterViewInit(): void {\n    if (this.useCustomTemplate) {\n      this.requiredMark = this.customRequiredMarkTemplate;\n    }\n  }\n}\n"
  },
  {
    "path": "components/form/form-split.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';\n\n@Component({\n  selector: 'nz-form-split',\n  exportAs: 'nzFormSplit',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `<ng-content />`,\n  host: {\n    class: 'ant-form-split'\n  }\n})\nexport class NzFormSplitComponent {}\n"
  },
  {
    "path": "components/form/form-split.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { TestBed } from '@angular/core/testing';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { NzFormSplitComponent } from './form-split.component';\n\ndescribe('nz-form-split', () => {\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations()]\n    });\n  });\n\n  it('should className correct', () => {\n    const fixture = TestBed.createComponent(NzFormSplitComponent);\n    expect(fixture.nativeElement.classList).toContain('ant-form-split');\n  });\n});\n"
  },
  {
    "path": "components/form/form-text.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';\n\n@Component({\n  selector: 'nz-form-text',\n  exportAs: 'nzFormText',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `<ng-content />`,\n  host: {\n    class: 'ant-form-text'\n  }\n})\nexport class NzFormTextComponent {}\n"
  },
  {
    "path": "components/form/form-text.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { TestBed } from '@angular/core/testing';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { NzFormTextComponent } from 'ng-zorro-antd/form/form-text.component';\n\ndescribe('nz-form-text', () => {\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations()]\n    });\n  });\n\n  it('should className correct', () => {\n    const fixture = TestBed.createComponent(NzFormTextComponent);\n    expect(fixture.nativeElement.classList).toContain('ant-form-text');\n  });\n});\n"
  },
  {
    "path": "components/form/form.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport {\n  booleanAttribute,\n  DestroyRef,\n  Directive,\n  inject,\n  Input,\n  input,\n  OnChanges,\n  SimpleChange,\n  SimpleChanges\n} from '@angular/core';\nimport { Observable, Subject } from 'rxjs';\nimport { filter, map } from 'rxjs/operators';\n\nimport { ThemeType } from '@ant-design/icons-angular';\n\nimport { NzConfigKey, WithConfig } from 'ng-zorro-antd/core/config';\nimport { NZ_FORM_SIZE, NZ_FORM_VARIANT } from 'ng-zorro-antd/core/form';\nimport { InputObservable, type NzSizeLDSType, type NzVariant } from 'ng-zorro-antd/core/types';\n\nimport type { NzRequiredMark } from './types';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'form';\n\nexport type NzFormLayoutType = 'horizontal' | 'vertical' | 'inline';\n\nexport type NzLabelAlignType = 'left' | 'right';\n\nexport const DefaultTooltipIcon = {\n  type: 'question-circle',\n  theme: 'outline'\n} as const;\n\n@Directive({\n  selector: '[nz-form]',\n  exportAs: 'nzForm',\n  host: {\n    class: 'ant-form',\n    '[class.ant-form-horizontal]': `nzLayout === 'horizontal'`,\n    '[class.ant-form-vertical]': `nzLayout === 'vertical'`,\n    '[class.ant-form-inline]': `nzLayout === 'inline'`,\n    '[class.ant-form-rtl]': `dir() === 'rtl'`,\n    '[class.ant-form-small]': `nzSize() === 'small'`,\n    '[class.ant-form-large]': `nzSize() === 'large'`\n  },\n  providers: [\n    { provide: NZ_FORM_SIZE, useFactory: () => inject(NzFormDirective).nzSize },\n    {\n      provide: NZ_FORM_VARIANT,\n      useFactory: () => inject(NzFormDirective).nzVariant\n    }\n  ]\n})\nexport class NzFormDirective implements OnChanges, InputObservable {\n  private destroyRef = inject(DestroyRef);\n\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  @Input() nzLayout: NzFormLayoutType = 'horizontal';\n  @Input({ transform: booleanAttribute }) @WithConfig() nzNoColon: boolean = false;\n  @Input() @WithConfig() nzAutoTips: Record<string, Record<string, string>> = {};\n  @Input({ transform: booleanAttribute }) nzDisableAutoTips = false;\n  @Input() @WithConfig() nzTooltipIcon: string | { type: string; theme: ThemeType } = DefaultTooltipIcon;\n  @Input() nzLabelAlign: NzLabelAlignType = 'right';\n  @Input({ transform: booleanAttribute }) @WithConfig() nzLabelWrap: boolean = false;\n\n  readonly nzSize = input<NzSizeLDSType>();\n  readonly nzVariant = input<NzVariant>('outlined');\n\n  readonly nzRequiredMark = input<NzRequiredMark>(true);\n\n  dir = inject(Directionality).valueSignal;\n  private inputChanges$ = new Subject<SimpleChanges>();\n\n  getInputObservable<K extends keyof this>(changeType: K): Observable<SimpleChange> {\n    return this.inputChanges$.pipe(\n      filter(changes => changeType in changes),\n      map(value => value[changeType as string])\n    );\n  }\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      this.inputChanges$.complete();\n    });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    this.inputChanges$.next(changes);\n  }\n}\n"
  },
  {
    "path": "components/form/form.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzGridModule } from 'ng-zorro-antd/grid';\n\nimport { NzFormControlComponent } from './form-control.component';\nimport { NzFormItemComponent } from './form-item.component';\nimport { NzFormLabelComponent } from './form-label.component';\nimport { NzFormSplitComponent } from './form-split.component';\nimport { NzFormTextComponent } from './form-text.component';\nimport { NzFormDirective } from './form.directive';\n\n@NgModule({\n  imports: [\n    NzFormDirective,\n    NzFormItemComponent,\n    NzFormLabelComponent,\n    NzFormControlComponent,\n    NzFormTextComponent,\n    NzFormSplitComponent\n  ],\n  exports: [\n    NzGridModule,\n    NzFormDirective,\n    NzFormItemComponent,\n    NzFormLabelComponent,\n    NzFormControlComponent,\n    NzFormTextComponent,\n    NzFormSplitComponent\n  ]\n})\nexport class NzFormModule {}\n"
  },
  {
    "path": "components/form/form.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterViewInit,\n  Component,\n  DebugElement,\n  provideZoneChangeDetection,\n  TemplateRef,\n  ViewChild\n} from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { NzFormModule } from 'ng-zorro-antd/form/form.module';\n\nimport { NzFormDirective, NzFormLayoutType } from './form.directive';\nimport { NzRequiredMark } from './types';\n\ndescribe('form', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection(), provideNoopAnimations()]\n    });\n  });\n\n  describe('default', () => {\n    let fixture: ComponentFixture<NzTestFormDirectiveComponent>;\n    let testComponent: NzTestFormDirectiveComponent;\n    let form: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestFormDirectiveComponent);\n      testComponent = fixture.componentInstance;\n      form = fixture.debugElement.query(By.directive(NzFormDirective));\n    });\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n      expect(form.nativeElement.classList).toContain('ant-form');\n      expect(form.nativeElement.classList).toContain('ant-form-horizontal');\n    });\n\n    it('should layout work', () => {\n      testComponent.layout = 'vertical';\n\n      fixture.detectChanges();\n\n      expect(form.nativeElement.classList).toContain('ant-form-vertical');\n      expect(form.nativeElement.classList).not.toContain('ant-form-horizontal');\n\n      testComponent.layout = 'inline';\n\n      fixture.detectChanges();\n\n      expect(form.nativeElement.classList).not.toContain('ant-form-vertical');\n      expect(form.nativeElement.classList).not.toContain('ant-form-horizontal');\n      expect(form.nativeElement.classList).toContain('ant-form-inline');\n    });\n  });\n\n  describe('label integrate', () => {\n    let fixture: ComponentFixture<NzTestFormLabelIntegrateComponent>;\n    let testComponent: NzTestFormLabelIntegrateComponent;\n    let form: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestFormLabelIntegrateComponent);\n      testComponent = fixture.componentInstance;\n      form = fixture.debugElement.query(By.directive(NzFormDirective));\n    });\n\n    afterEach(() => {\n      testComponent.defaultNoColon = false;\n      testComponent.noColon = false;\n      testComponent.testPriority = false;\n    });\n\n    it('should set default `NoColon` value', () => {\n      const labels = (form.nativeElement as HTMLElement).querySelectorAll<HTMLLabelElement>(\n        '.ant-form-item-label label'\n      );\n      labels.forEach(label => expect(label.classList).not.toContain('ant-form-item-no-colon'));\n\n      testComponent.defaultNoColon = true;\n\n      fixture.detectChanges();\n\n      labels.forEach(label => expect(label.classList).toContain('ant-form-item-no-colon'));\n    });\n\n    it('should label have high priority', () => {\n      const labels = (form.nativeElement as HTMLElement).querySelectorAll<HTMLLabelElement>(\n        '.ant-form-item-label label'\n      );\n      labels.forEach(label => expect(label.classList).not.toContain('ant-form-item-no-colon'));\n\n      testComponent.defaultNoColon = true;\n\n      fixture.detectChanges();\n\n      labels.forEach(label => expect(label.classList).toContain('ant-form-item-no-colon'));\n      testComponent.testPriority = true;\n\n      fixture.detectChanges();\n\n      labels.forEach(label => expect(label.classList).toContain('ant-form-item-no-colon'));\n      labels.forEach(label => {\n        if (label.innerText === 'TEST_PRIORITY') {\n          expect(label.classList).not.toContain('ant-form-item-no-colon');\n        } else {\n          expect(label.classList).toContain('ant-form-item-no-colon');\n        }\n      });\n\n      testComponent.defaultNoColon = false;\n      testComponent.noColon = true;\n\n      fixture.detectChanges();\n\n      labels.forEach(label => {\n        if (label.innerText === 'TEST_PRIORITY') {\n          expect(label.classList).toContain('ant-form-item-no-colon');\n        } else {\n          expect(label.classList).not.toContain('ant-form-item-no-colon');\n        }\n      });\n    });\n  });\n\n  describe('required mark', () => {\n    let fixture: ComponentFixture<NzTestFormRequiredMarkComponent>;\n    let testComponent: NzTestFormRequiredMarkComponent;\n    let form: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestFormRequiredMarkComponent);\n      testComponent = fixture.componentInstance;\n      form = fixture.debugElement.query(By.directive(NzFormDirective));\n      fixture.detectChanges();\n    });\n\n    it('should handle boolean required mark (default: true)', () => {\n      const requiredLabel = form.nativeElement.querySelector('.required-label label');\n      const optionalLabel = form.nativeElement.querySelector('.optional-label label');\n\n      expect(requiredLabel.classList).toContain('ant-form-item-required');\n      expect(requiredLabel.classList).not.toContain('ant-form-item-required-mark-optional');\n      expect(optionalLabel.classList).not.toContain('ant-form-item-required');\n    });\n\n    it('should handle boolean required mark (false)', () => {\n      testComponent.requiredMark = false;\n      fixture.detectChanges();\n\n      const requiredLabel = form.nativeElement.querySelector('.required-label label');\n      const optionalLabel = form.nativeElement.querySelector('.optional-label label');\n\n      expect(requiredLabel.classList).toContain('ant-form-item-required');\n      expect(requiredLabel.classList).toContain('ant-form-item-required-mark-hidden');\n      expect(optionalLabel.classList).not.toContain('ant-form-item-required');\n      expect(optionalLabel.classList).toContain('ant-form-item-required-mark-hidden');\n    });\n\n    it('should handle optional required mark', () => {\n      testComponent.requiredMark = 'optional';\n      fixture.detectChanges();\n\n      const requiredLabel = form.nativeElement.querySelector('.required-label label');\n      const optionalLabel = form.nativeElement.querySelector('.optional-label label');\n\n      expect(requiredLabel.classList).toContain('ant-form-item-required');\n      expect(requiredLabel.classList).toContain('ant-form-item-required-mark-optional');\n      expect(optionalLabel.classList).not.toContain('ant-form-item-required');\n    });\n\n    it('should handle custom template required mark', () => {\n      testComponent.useCustomTemplate = true;\n      fixture.detectChanges();\n\n      const requiredLabel = form.nativeElement.querySelector('.required-label');\n      const optionalLabel = form.nativeElement.querySelector('.optional-label');\n\n      expect(requiredLabel.querySelector('.custom-required')).toBeTruthy();\n      expect(requiredLabel.querySelector('.custom-required').textContent?.trim()).toBe('REQUIRED');\n      expect(optionalLabel.querySelector('.custom-optional')).toBeTruthy();\n      expect(optionalLabel.querySelector('.custom-optional').textContent?.trim()).toBe('OPTIONAL');\n    });\n\n    it('should propagate required mark from form directive to labels', () => {\n      const formDirective = form.injector.get(NzFormDirective);\n      expect(formDirective.nzRequiredMark()).toBe(true);\n\n      testComponent.requiredMark = 'optional';\n      fixture.detectChanges();\n\n      expect(formDirective.nzRequiredMark()).toBe('optional');\n    });\n\n    it('should handle template context correctly', () => {\n      testComponent.useCustomTemplate = true;\n      fixture.detectChanges();\n\n      const customTemplateElement = form.nativeElement.querySelector('.custom-required');\n      expect(customTemplateElement).toBeTruthy();\n\n      const labelContent = form.nativeElement.querySelector('.required-label .label-content');\n      expect(labelContent).toBeTruthy();\n      expect(labelContent.textContent?.trim()).toBe('Required Field');\n    });\n  });\n});\n\n@Component({\n  imports: [NzFormModule],\n  template: `<form nz-form [nzLayout]=\"layout\"></form>`\n})\nexport class NzTestFormDirectiveComponent {\n  layout: NzFormLayoutType = 'horizontal';\n}\n\n@Component({\n  imports: [NzFormModule],\n  template: `\n    <form nz-form [nzNoColon]=\"defaultNoColon\">\n      <nz-form-item>\n        <nz-form-label>Label</nz-form-label>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label>Label</nz-form-label>\n      </nz-form-item>\n      @if (testPriority) {\n        <nz-form-item>\n          <nz-form-label [nzNoColon]=\"noColon\">TEST_PRIORITY</nz-form-label>\n        </nz-form-item>\n      }\n    </form>\n  `\n})\nexport class NzTestFormLabelIntegrateComponent {\n  defaultNoColon = false;\n  testPriority = false;\n  noColon = false;\n}\n\n@Component({\n  imports: [NzFormModule, NgTemplateOutlet],\n  template: `\n    <form nz-form [nzRequiredMark]=\"useCustomTemplate ? customRequiredMarkTemplate : requiredMark\">\n      <nz-form-item class=\"required-label\">\n        <nz-form-label nzRequired>\n          <span class=\"label-content\">Required Field</span>\n        </nz-form-label>\n      </nz-form-item>\n      <nz-form-item class=\"optional-label\">\n        <nz-form-label>\n          <span class=\"label-content\">Optional Field</span>\n        </nz-form-label>\n      </nz-form-item>\n    </form>\n\n    <ng-template #customRequiredMarkTemplate let-label let-required=\"required\">\n      @if (required) {\n        <span class=\"custom-required\">REQUIRED</span>\n      } @else {\n        <span class=\"custom-optional\">OPTIONAL</span>\n      }\n      <ng-container *ngTemplateOutlet=\"label\" />\n    </ng-template>\n  `\n})\nexport class NzTestFormRequiredMarkComponent implements AfterViewInit {\n  requiredMark: NzRequiredMark = true;\n  useCustomTemplate = false;\n\n  @ViewChild('customRequiredMarkTemplate', { static: true })\n  customRequiredMarkTemplate!: TemplateRef<{ $implicit: TemplateRef<void>; required: boolean }>;\n\n  ngAfterViewInit(): void {\n    if (this.useCustomTemplate) {\n      this.requiredMark = this.customRequiredMarkTemplate;\n    }\n  }\n}\n"
  },
  {
    "path": "components/form/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/form/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/form/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './form-control.component';\nexport * from './form-item.component';\nexport * from './form-label.component';\nexport * from './form-split.component';\nexport * from './form-text.component';\nexport * from './form.directive';\nexport * from './form.module';\nexport * from './types';\n"
  },
  {
    "path": "components/form/style/animation.less",
    "content": "@import (reference) '../../style/themes/index';\n\n// ================================================================\n// =                    Form Validate Animation                   =\n// ================================================================\n\n@form-prefix-cls: ~'@{ant-prefix}-form';\n\n@animation-duration: @animation-duration-slow;\n@animate-distance: -5px;\n\n.animation(@type) {\n  &-@{type} {\n    animation: ~\"@{type}\" @animation-duration @ease-in-out;\n  }\n}\n\n.keyframes(@name; @from-opacity; @to-opacity; @from-transform; @to-transform) {\n  @keyframes @name {\n    from {\n      transform: @from-transform;\n      opacity: @from-opacity;\n    }\n\n    to {\n      transform: @to-transform;\n      opacity: @to-opacity;\n    }\n  }\n}\n\n.@{form-prefix-cls}-validate_animation {\n  .animation(enter);\n  .animation(leave);\n\n  .keyframes(enter; 0; 1; translateY(@animate-distance); translateY(0));\n  .keyframes(leave; 1; 0; translateY(0); translateY(@animate-distance));\n}\n"
  },
  {
    "path": "components/form/style/components.less",
    "content": "@import (reference) '../../style/themes/index';\n\n@form-prefix-cls: ~'@{ant-prefix}-form';\n@form-item-prefix-cls: ~'@{form-prefix-cls}-item';\n\n// ================================================================\n// =                      Children Component                      =\n// ================================================================\n// FIXME: useless, remove in v5\n.@{form-item-prefix-cls} {\n  .@{ant-prefix}-input-number {\n    + .@{form-prefix-cls}-text {\n      margin-left: 8px;\n    }\n  }\n}\n"
  },
  {
    "path": "components/form/style/entry.less",
    "content": "@import './index.less';\n// style dependencies\n@import '../../grid/style/entry.less';\n@import './patch';\n"
  },
  {
    "path": "components/form/style/horizontal.less",
    "content": "@import (reference) '../../style/themes/index';\n\n@form-prefix-cls: ~'@{ant-prefix}-form';\n@form-item-prefix-cls: ~'@{form-prefix-cls}-item';\n\n.@{form-prefix-cls}-horizontal {\n  .@{form-item-prefix-cls}-label {\n    flex-grow: 0;\n  }\n  .@{form-item-prefix-cls}-control {\n    flex: 1 1 0;\n    // https://github.com/ant-design/ant-design/issues/32777\n    // https://github.com/ant-design/ant-design/issues/33773\n    min-width: 0;\n  }\n  // https://github.com/ant-design/ant-design/issues/32980\n  // https://github.com/ant-design/ant-design/issues/34903\n  .@{form-item-prefix-cls}-label[class$='-24'] + .@{form-item-prefix-cls}-control,\n  .@{form-item-prefix-cls}-label[class*='-24 '] + .@{form-item-prefix-cls}-control {\n    min-width: unset;\n  }\n}\n"
  },
  {
    "path": "components/form/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import '../../input/style/mixin';\n@import '../../button/style/mixin';\n@import '../../grid/style/mixin';\n@import './animation';\n@import './components';\n@import './inline';\n@import './horizontal';\n@import './vertical';\n@import './status';\n@import './mixin';\n\n@form-prefix-cls: ~'@{ant-prefix}-form';\n@form-item-prefix-cls: ~'@{form-prefix-cls}-item';\n@form-font-height: ceil(@font-size-base * @line-height-base);\n\n.@{form-prefix-cls} {\n  .reset-component();\n  .reset-form();\n\n  .@{form-prefix-cls}-text {\n    display: inline-block;\n    padding-right: 8px;\n  }\n\n  // ================================================================\n  // =                             Size                             =\n  // ================================================================\n  .formSize(@input-height) {\n    .@{form-item-prefix-cls}-label > label {\n      height: @input-height;\n    }\n\n    .@{form-item-prefix-cls}-control-input {\n      min-height: @input-height;\n    }\n  }\n\n  &-small {\n    .formSize(@input-height-sm);\n  }\n\n  &-large {\n    .formSize(@input-height-lg);\n  }\n}\n\n.explainAndExtraDistance(@num) when (@num >= 0) {\n  padding-top: floor(@num);\n}\n\n.explainAndExtraDistance(@num) when (@num < 0) {\n  margin-top: ceil(@num);\n  margin-bottom: ceil(@num);\n}\n\n// ================================================================\n// =                             Item                             =\n// ================================================================\n.@{form-item-prefix-cls} {\n  .reset-component();\n\n  margin-bottom: @form-item-margin-bottom;\n  vertical-align: top;\n\n  &-with-help {\n    transition: none;\n  }\n\n  &-hidden,\n  &-hidden.@{ant-prefix}-row {\n    // https://github.com/ant-design/ant-design/issues/26141\n    display: none;\n  }\n\n  // ==============================================================\n  // =                            Label                           =\n  // ==============================================================\n  &-label {\n    display: inline-block;\n    flex-grow: 0;\n    overflow: hidden;\n    white-space: nowrap;\n    text-align: right;\n    vertical-align: middle;\n\n    &-left {\n      text-align: left;\n    }\n\n    &-wrap {\n      overflow: unset;\n      line-height: (@line-height-base - 0.25em);\n      white-space: unset;\n    }\n\n    > label {\n      position: relative;\n      display: inline-flex;\n      align-items: center;\n      max-width: 100%;\n      height: @form-item-label-height;\n      color: @label-color;\n      font-size: @form-item-label-font-size;\n\n      > .@{iconfont-css-prefix} {\n        font-size: @form-item-label-font-size;\n        vertical-align: top;\n      }\n\n      // Required mark\n      &.@{form-item-prefix-cls}-required:not(.@{form-item-prefix-cls}-required-mark-optional):not(\n          .@{form-item-prefix-cls}-required-mark-hidden\n        )::before {\n        display: inline-block;\n        margin-right: 4px;\n        color: @label-required-color;\n        font-size: @form-item-label-font-size;\n        font-family: SimSun, sans-serif;\n        line-height: 1;\n        content: '*';\n\n        .@{form-prefix-cls}-hide-required-mark & {\n          display: none;\n        }\n      }\n\n      // Optional mark\n      .@{form-item-prefix-cls}-optional {\n        display: inline-block;\n        margin-left: @margin-xss;\n        color: @text-color-secondary;\n\n        .@{form-prefix-cls}-hide-required-mark & {\n          display: none;\n        }\n      }\n\n      // Optional mark\n      .@{form-item-prefix-cls}-tooltip {\n        color: @text-color-secondary;\n        cursor: help;\n        writing-mode: horizontal-tb;\n        margin-inline-start: @margin-xss;\n      }\n\n      &::after {\n        & when (@form-item-trailing-colon=true) {\n          content: ':';\n        }\n        & when not (@form-item-trailing-colon=true) {\n          content: ' ';\n        }\n\n        position: relative;\n        top: -0.5px;\n        margin: 0 @form-item-label-colon-margin-right 0 @form-item-label-colon-margin-left;\n      }\n\n      &.@{form-item-prefix-cls}-no-colon::after {\n        content: ' ';\n      }\n    }\n  }\n\n  // ==============================================================\n  // =                            Input                           =\n  // ==============================================================\n  &-control {\n    display: flex;\n    flex-direction: column;\n    flex-grow: 1;\n\n    &:first-child:not([class^=~\"'@{ant-prefix}-col-'\"]):not([class*=~\"' @{ant-prefix}-col-'\"]) {\n      width: 100%;\n    }\n  }\n\n  &-control-input {\n    position: relative;\n    display: flex;\n    align-items: center;\n    min-height: @input-height-base;\n\n    &-content {\n      flex: auto;\n      max-width: 100%;\n    }\n  }\n\n  // ==============================================================\n  // =                           Explain                          =\n  // ==============================================================\n  &-explain,\n  &-extra {\n    clear: both;\n    color: @text-color-secondary;\n    font-size: @font-size-base;\n    line-height: @line-height-base;\n    transition: color 0.3s @ease-out; // sync input color transition\n    .explainAndExtraDistance((@form-item-margin-bottom - @form-font-height) / 2);\n  }\n\n  &-explain-connected {\n    width: 100%;\n  }\n\n  &-extra {\n    min-height: @form-item-margin-bottom;\n  }\n\n  &-with-help &-explain {\n    height: auto;\n    // min-height: @form-item-margin-bottom;\n    opacity: 1;\n  }\n\n  // ==============================================================\n  // =                        Feedback Icon                       =\n  // ==============================================================\n  &-feedback-icon {\n    font-size: @font-size-base;\n    text-align: center;\n    visibility: visible;\n    animation: zoomIn 0.3s @ease-out-back;\n    pointer-events: none;\n\n    &-success {\n      color: @success-color;\n    }\n\n    &-error {\n      color: @error-color;\n    }\n\n    &-warning {\n      color: @warning-color;\n    }\n\n    &-validating {\n      color: @primary-color;\n    }\n  }\n}\n\n// >>>>>>>>>> Motion <<<<<<<<<<\n// Explain holder\n.@{ant-prefix}-show-help {\n  transition: opacity @animation-duration-slow @ease-in-out;\n\n  &-appear,\n  &-enter {\n    opacity: 0;\n\n    &-active {\n      opacity: 1;\n    }\n  }\n\n  &-leave {\n    opacity: 1;\n\n    &-active {\n      opacity: 0;\n    }\n  }\n}\n\n// Explain\n.@{ant-prefix}-show-help-item {\n  overflow: hidden;\n  transition:\n    height @animation-duration-slow @ease-in-out,\n    opacity @animation-duration-slow @ease-in-out,\n    transform @animation-duration-slow @ease-in-out !important;\n\n  &-appear,\n  &-enter {\n    transform: translateY(-5px);\n    opacity: 0;\n\n    &-active {\n      transform: translateY(0);\n      opacity: 1;\n    }\n  }\n\n  &-leave {\n    transition:\n      height @animation-duration-base @ease-in-out,\n      opacity @animation-duration-base @ease-in-out,\n      transform @animation-duration-base @ease-in-out !important;\n  }\n\n  &-leave-active {\n    transform: translateY(-5px);\n  }\n}\n\n// need there different zoom animation\n// otherwise won't trigger anim\n@keyframes diffZoomIn1 {\n  0% {\n    transform: scale(0);\n    opacity: 0;\n  }\n\n  100% {\n    transform: scale(1);\n    opacity: 1;\n  }\n}\n\n@keyframes diffZoomIn2 {\n  0% {\n    transform: scale(0);\n    opacity: 0;\n  }\n\n  100% {\n    transform: scale(1);\n    opacity: 1;\n  }\n}\n\n@keyframes diffZoomIn3 {\n  0% {\n    transform: scale(0);\n    opacity: 0;\n  }\n\n  100% {\n    transform: scale(1);\n    opacity: 1;\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/form/style/inline.less",
    "content": "@import (reference) '../../style/themes/index';\n\n@form-prefix-cls: ~'@{ant-prefix}-form';\n@form-item-prefix-cls: ~'@{form-prefix-cls}-item';\n\n.@{form-prefix-cls}-inline {\n  display: flex;\n  flex-wrap: wrap;\n\n  .@{form-prefix-cls}-item {\n    flex: none;\n    flex-wrap: nowrap;\n    margin-right: 16px;\n    margin-bottom: 0;\n\n    &-with-help {\n      margin-bottom: @form-item-margin-bottom;\n    }\n\n    > .@{form-item-prefix-cls}-label,\n    > .@{form-item-prefix-cls}-control {\n      display: inline-block;\n      vertical-align: top;\n    }\n\n    > .@{form-item-prefix-cls}-label {\n      flex: none;\n    }\n\n    .@{form-prefix-cls}-text {\n      display: inline-block;\n    }\n\n    .@{form-item-prefix-cls}-has-feedback {\n      display: inline-block;\n    }\n  }\n}\n"
  },
  {
    "path": "components/form/style/mixin.less",
    "content": "@import '../../input/style/mixin';\n\n.form-control-validation(\n  @text-color: @input-color;\n  @border-color: @input-border-color;\n  @background-color: @input-bg;\n  @hoverBorderColor: @primary-color-hover;\n  @outlineColor: @primary-color-outline;\n) {\n  .@{ant-prefix}-form-item-split {\n    color: @text-color;\n  }\n}\n\n// Reset form styles\n// -----------------------------\n// Based on Bootstrap framework\n.reset-form() {\n  legend {\n    display: block;\n    width: 100%;\n    margin-bottom: 20px;\n    padding: 0;\n    color: @text-color-secondary;\n    font-size: @font-size-lg;\n    line-height: inherit;\n    border: 0;\n    border-bottom: @border-width-base @border-style-base @border-color-base;\n  }\n\n  label {\n    font-size: @font-size-base;\n  }\n\n  input[type='search'] {\n    box-sizing: border-box;\n  }\n\n  // Position radios and checkboxes better\n  input[type='radio'],\n  input[type='checkbox'] {\n    line-height: normal;\n  }\n\n  input[type='file'] {\n    display: block;\n  }\n\n  // Make range inputs behave like textual form controls\n  input[type='range'] {\n    display: block;\n    width: 100%;\n  }\n\n  // Make multiple select elements height not fixed\n  select[multiple],\n  select[size] {\n    height: auto;\n  }\n\n  // Focus for file, radio, and checkbox\n  input[type='file']:focus,\n  input[type='radio']:focus,\n  input[type='checkbox']:focus {\n    outline: thin dotted;\n    outline: 5px auto -webkit-focus-ring-color;\n    outline-offset: -2px;\n  }\n\n  // Adjust output element\n  output {\n    display: block;\n    padding-top: 15px;\n    color: @input-color;\n    font-size: @font-size-base;\n    line-height: @line-height-base;\n  }\n}\n"
  },
  {
    "path": "components/form/style/patch.less",
    "content": "// Since zorro's form-item-margin-bottom doesn't currently animate, we need to fix some of the heights.\n.@{form-item-prefix-cls}{\n  &-explain-connected {\n    height: 0;\n  }\n\n  &-with-help {\n    margin-bottom: 0;\n  }\n\n  &-with-help &-explain {\n    min-height: @form-item-margin-bottom;\n  }\n}\n"
  },
  {
    "path": "components/form/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import '../../input/style/mixin';\n@import '../../button/style/mixin';\n@import '../../grid/style/mixin';\n\n@form-prefix-cls: ~'@{ant-prefix}-form';\n@form-item-prefix-cls: ~'@{form-prefix-cls}-item';\n\n.@{form-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n}\n\n// ================================================================\n// =                             Item                             =\n// ================================================================\n.@{form-item-prefix-cls} {\n  // ==============================================================\n  // =                            Label                           =\n  // ==============================================================\n  &-label {\n    .@{form-prefix-cls}-rtl & {\n      text-align: left;\n    }\n\n    > label {\n      &.@{form-item-prefix-cls}-required::before {\n        .@{form-prefix-cls}-rtl & {\n          margin-right: 0;\n          margin-left: 4px;\n        }\n      }\n\n      &::after {\n        .@{form-prefix-cls}-rtl & {\n          margin: 0 @form-item-label-colon-margin-left 0 @form-item-label-colon-margin-right;\n        }\n      }\n\n      .@{form-item-prefix-cls}-optional {\n        .@{form-prefix-cls}-rtl & {\n          margin-right: @margin-xss;\n          margin-left: 0;\n        }\n      }\n    }\n  }\n\n  // ==============================================================\n  // =                            Input                           =\n  // ==============================================================\n  &-control {\n    .@{ant-prefix}-col-rtl &:first-child {\n      width: 100%;\n    }\n  }\n\n  // status\n  &-has-feedback {\n    .@{ant-prefix}-input {\n      .@{form-prefix-cls}-rtl & {\n        padding-right: @input-padding-horizontal-base;\n        padding-left: 24px;\n      }\n    }\n\n    .@{ant-prefix}-input-affix-wrapper {\n      .@{ant-prefix}-input-suffix {\n        .@{form-prefix-cls}-rtl & {\n          padding-right: @input-padding-horizontal-base;\n          padding-left: 18px;\n        }\n      }\n      .@{ant-prefix}-input {\n        .@{form-prefix-cls}-rtl & {\n          padding: 0;\n        }\n      }\n    }\n\n    .@{ant-prefix}-input-number-affix-wrapper {\n      .@{ant-prefix}-input-number {\n        .@{form-prefix-cls}-rtl & {\n          padding: 0;\n        }\n      }\n    }\n\n    .@{ant-prefix}-input-search:not(.@{ant-prefix}-input-search-enter-button) {\n      .@{ant-prefix}-input-suffix {\n        .@{form-prefix-cls}-rtl & {\n          right: auto;\n          left: 28px;\n        }\n      }\n    }\n\n    .@{ant-prefix}-input-number {\n      .@{form-prefix-cls}-rtl & {\n        padding-left: 18px;\n      }\n    }\n\n    > .@{ant-prefix}-select .@{ant-prefix}-select-arrow,\n    > .@{ant-prefix}-select .@{ant-prefix}-select-clear,\n    :not(.@{ant-prefix}-input-group-addon) > .@{ant-prefix}-select .@{ant-prefix}-select-arrow,\n    :not(.@{ant-prefix}-input-group-addon) > .@{ant-prefix}-select .@{ant-prefix}-select-clear,\n    :not(.@{ant-prefix}-input-number-group-addon)\n      > .@{ant-prefix}-select\n      .@{ant-prefix}-select-arrow,\n    :not(.@{ant-prefix}-input-number-group-addon)\n      > .@{ant-prefix}-select\n      .@{ant-prefix}-select-clear {\n      .@{form-prefix-cls}-rtl & {\n        right: auto;\n        left: 32px;\n      }\n    }\n\n    > .@{ant-prefix}-select .@{ant-prefix}-select-selection-selected-value,\n    :not(.@{ant-prefix}-input-group-addon)\n      > .@{ant-prefix}-select\n      .@{ant-prefix}-select-selection-selected-value,\n    :not(.@{ant-prefix}-input-number-group-addon)\n      > .@{ant-prefix}-select\n      .@{ant-prefix}-select-selection-selected-value {\n      .@{form-prefix-cls}-rtl & {\n        padding-right: 0;\n        padding-left: 42px;\n      }\n    }\n\n    .@{ant-prefix}-cascader-picker {\n      &-arrow {\n        .@{form-prefix-cls}-rtl & {\n          margin-right: 0;\n          margin-left: 19px;\n        }\n      }\n\n      &-clear {\n        .@{form-prefix-cls}-rtl & {\n          right: auto;\n          left: 32px;\n        }\n      }\n    }\n\n    .@{ant-prefix}-picker {\n      .@{form-prefix-cls}-rtl & {\n        padding-right: @input-padding-horizontal-base;\n        padding-left: @input-padding-horizontal-base + @font-size-base * 1.3;\n      }\n\n      &-large {\n        .@{form-prefix-cls}-rtl & {\n          padding-right: @input-padding-horizontal-lg;\n          padding-left: @input-padding-horizontal-lg + @font-size-base * 1.3;\n        }\n      }\n\n      &-small {\n        .@{form-prefix-cls}-rtl & {\n          padding-right: @input-padding-horizontal-sm;\n          padding-left: @input-padding-horizontal-sm + @font-size-base * 1.3;\n        }\n      }\n    }\n\n    &.@{form-item-prefix-cls} {\n      &-has-success,\n      &-has-warning,\n      &-has-error,\n      &-is-validating {\n        // ====================== Icon ======================\n        .@{form-item-prefix-cls}-children-icon {\n          .@{form-prefix-cls}-rtl & {\n            right: auto;\n            left: 0;\n          }\n        }\n      }\n    }\n  }\n}\n\n// inline\n.@{form-prefix-cls}-inline {\n  .@{form-prefix-cls}-item {\n    .@{form-prefix-cls}-rtl& {\n      margin-right: 0;\n      margin-left: 16px;\n    }\n  }\n}\n\n// vertical\n.make-vertical-layout-label() {\n  .@{form-prefix-cls}-rtl& {\n    text-align: right;\n  }\n}\n"
  },
  {
    "path": "components/form/style/status.less",
    "content": "@import (reference) '../../style/themes/index';\n\n@form-prefix-cls: ~'@{ant-prefix}-form';\n@form-item-prefix-cls: ~'@{form-prefix-cls}-item';\n\n.@{form-item-prefix-cls} {\n  // ================================================================\n  // =                            Status                            =\n  // ================================================================\n\n  /* Some non-status related component style is in `components.less` */\n\n  // ========================= Explain =========================\n\n  /* To support leave along ErrorList. We add additional className to handle explain style */\n  &-explain {\n    &-error {\n      color: @error-color;\n    }\n\n    &-warning {\n      color: @warning-color;\n    }\n  }\n\n  &-has-feedback {\n    // ======================== Switch =========================\n    .@{ant-prefix}-switch {\n      margin: 2px 0 4px;\n    }\n  }\n\n  // ======================== Warning ========================\n  &-has-warning {\n    .form-control-validation(@warning-color; @warning-color; @form-warning-input-bg; @warning-color-hover; @warning-color-outline);\n  }\n\n  // ========================= Error =========================\n  &-has-error {\n    .form-control-validation(@error-color; @error-color; @form-error-input-bg; @error-color-hover; @error-color-outline);\n  }\n}\n"
  },
  {
    "path": "components/form/style/vertical.less",
    "content": "@import (reference) '../../style/themes/index';\n\n@form-prefix-cls: ~'@{ant-prefix}-form';\n@form-item-prefix-cls: ~'@{form-prefix-cls}-item';\n\n// ================== Label ==================\n.make-vertical-layout-label() {\n  & when (@form-vertical-label-margin > 0) {\n    margin: @form-vertical-label-margin;\n  }\n  padding: @form-vertical-label-padding;\n  line-height: @line-height-base;\n  white-space: initial;\n  text-align: left;\n\n  > label {\n    margin: 0;\n\n    &::after {\n      display: none;\n    }\n  }\n}\n\n.make-vertical-layout() {\n  .@{form-prefix-cls}-item .@{form-prefix-cls}-item-label {\n    .make-vertical-layout-label();\n  }\n  .@{form-prefix-cls} {\n    .@{form-prefix-cls}-item {\n      flex-wrap: wrap;\n      .@{form-prefix-cls}-item-label,\n      .@{form-prefix-cls}-item-control {\n        flex: 0 0 100%;\n        max-width: 100%;\n      }\n    }\n  }\n}\n\n.@{form-prefix-cls}-vertical {\n  .@{form-item-prefix-cls} {\n    &-row {\n      flex-direction: column;\n    }\n\n    &-label > label {\n      height: auto;\n    }\n\n    .@{form-prefix-cls}-item-control {\n      width: 100%;\n    }\n  }\n}\n\n.@{form-prefix-cls}-vertical .@{form-item-prefix-cls}-label,\n/* when labelCol is 24, it is a vertical form */\n.@{ant-prefix}-col-24.@{form-item-prefix-cls}-label,\n.@{ant-prefix}-col-xl-24.@{form-item-prefix-cls}-label {\n  .make-vertical-layout-label();\n}\n\n@media (max-width: @screen-xs-max) {\n  .make-vertical-layout();\n  .@{ant-prefix}-col-xs-24.@{form-item-prefix-cls}-label {\n    .make-vertical-layout-label();\n  }\n}\n\n@media (max-width: @screen-sm-max) {\n  .@{ant-prefix}-col-sm-24.@{form-item-prefix-cls}-label {\n    .make-vertical-layout-label();\n  }\n}\n\n@media (max-width: @screen-md-max) {\n  .@{ant-prefix}-col-md-24.@{form-item-prefix-cls}-label {\n    .make-vertical-layout-label();\n  }\n}\n\n@media (max-width: @screen-lg-max) {\n  .@{ant-prefix}-col-lg-24.@{form-item-prefix-cls}-label {\n    .make-vertical-layout-label();\n  }\n}\n\n@media (max-width: @screen-xl-max) {\n  .@{ant-prefix}-col-xl-24.@{form-item-prefix-cls}-label {\n    .make-vertical-layout-label();\n  }\n}\n"
  },
  {
    "path": "components/form/types.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { TemplateRef } from '@angular/core';\n\nexport type NzRequiredMark = boolean | 'optional' | TemplateRef<{ $implicit: TemplateRef<void>; required: boolean }>;\n"
  },
  {
    "path": "components/graph/core/minimap.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgZone } from '@angular/core';\n\nimport { drag } from 'd3-drag';\nimport { pointer, select } from 'd3-selection';\nimport { ZoomBehavior, zoomIdentity, ZoomTransform } from 'd3-zoom';\n\nimport { requestAnimationFrame } from 'ng-zorro-antd/core/polyfill';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzZoomTransform } from '../interface';\n\nconst FRAC_VIEWPOINT_AREA = 0.8;\n\nexport class Minimap {\n  private canvas: HTMLCanvasElement;\n  private canvasRect: DOMRect;\n  private canvasBuffer: HTMLCanvasElement;\n  private minimapSvg: SVGSVGElement;\n  private viewpoint: SVGRectElement;\n  private scaleMinimap!: number;\n  private scaleMain!: number;\n  private translate!: [number, number];\n  private viewpointCoord: { x: number; y: number };\n  private minimapSize!: { width: number; height: number };\n\n  private unlisteners: VoidFunction[] = [];\n\n  constructor(\n    private ngZone: NgZone,\n    private svg: SVGSVGElement,\n    private zoomG: SVGGElement,\n    private mainZoom: ZoomBehavior<NzSafeAny, NzSafeAny>,\n    private minimap: HTMLElement,\n    private maxWidth: number,\n    private labelPadding: number\n  ) {\n    const minimapElement = select(minimap);\n    const minimapSvgElement = minimapElement.select('svg');\n    const viewpointElement = minimapSvgElement.select('rect');\n    this.canvas = minimapElement.select('canvas.viewport').node() as HTMLCanvasElement;\n    this.canvasRect = this.canvas.getBoundingClientRect();\n\n    const handleEvent = (event: NzSafeAny): void => {\n      const minimapOffset = this.minimapOffset();\n      const width = Number(viewpointElement.attr('width'));\n      const height = Number(viewpointElement.attr('height'));\n      const clickCoords = pointer(event, minimapSvgElement.node() as NzSafeAny);\n      this.viewpointCoord.x = clickCoords[0] - width / 2 - minimapOffset.x;\n      this.viewpointCoord.y = clickCoords[1] - height / 2 - minimapOffset.y;\n      this.updateViewpoint();\n    };\n    this.viewpointCoord = { x: 0, y: 0 };\n    const subject = drag().subject(Object);\n    const dragEvent = subject.on('drag', handleEvent);\n    viewpointElement.datum(this.viewpointCoord as NzSafeAny).call(dragEvent as NzSafeAny);\n\n    // Make the minimap clickable.\n    minimapSvgElement.on('click', event => {\n      if ((event as Event).defaultPrevented) {\n        // This click was part of a drag event, so suppress it.\n        return;\n      }\n      handleEvent(event);\n    });\n    this.unlisteners.push(() => {\n      subject.on('drag', null);\n      minimapSvgElement.on('click', null);\n    });\n    this.viewpoint = viewpointElement.node() as SVGRectElement;\n    this.minimapSvg = minimapSvgElement.node() as SVGSVGElement;\n    this.canvasBuffer = minimapElement.select('canvas.buffer').node() as HTMLCanvasElement;\n    this.update();\n  }\n\n  destroy(): void {\n    while (this.unlisteners.length) {\n      this.unlisteners.pop()!();\n    }\n  }\n\n  private minimapOffset(): { x: number; y: number } {\n    return {\n      x: (this.canvasRect.width - this.minimapSize.width) / 2,\n      y: (this.canvasRect.height - this.minimapSize.height) / 2\n    };\n  }\n\n  private updateViewpoint(): void {\n    // Update the coordinates of the viewpoint rectangle.\n    select(this.viewpoint).attr('x', this.viewpointCoord.x).attr('y', this.viewpointCoord.y);\n    // Update the translation vector of the main svg to reflect the\n    // new viewpoint.\n    const mainX = (-this.viewpointCoord.x * this.scaleMain) / this.scaleMinimap;\n    const mainY = (-this.viewpointCoord.y * this.scaleMain) / this.scaleMinimap;\n    select(this.svg).call(this.mainZoom.transform, zoomIdentity.translate(mainX, mainY).scale(this.scaleMain));\n  }\n\n  update(): void {\n    let sceneSize = null;\n    try {\n      // Get the size of the entire scene.\n      sceneSize = this.zoomG.getBBox();\n      if (sceneSize.width === 0) {\n        // There is no scene anymore. We have been detached from the dom.\n        return;\n      }\n    } catch {\n      // Firefox produced NS_ERROR_FAILURE if we have been\n      // detached from the dom.\n      return;\n    }\n\n    const svgSelection = select(this.svg);\n    // Read all the style rules in the document and embed them into the svg.\n    // The svg needs to be self-contained, i.e. all the style rules need to be\n    // embedded so the canvas output matches the origin.\n    let stylesText = '';\n\n    for (const k of new Array(document.styleSheets.length).keys()) {\n      try {\n        const cssRules =\n          (document.styleSheets[k] as NzSafeAny).cssRules || (document.styleSheets[k] as NzSafeAny).rules;\n        if (cssRules == null) {\n          continue;\n        }\n        for (const i of new Array(cssRules.length).keys()) {\n          // Remove tf-* selectors from the styles.\n          stylesText += `${cssRules[i].cssText.replace(/ ?tf-[\\w-]+ ?/g, '')}\\n`;\n        }\n      } catch (e: NzSafeAny) {\n        if (e.name !== 'SecurityError') {\n          throw e;\n        }\n      }\n    }\n\n    // Temporarily add the css rules to the main svg.\n    const svgStyle = svgSelection.append('style');\n    svgStyle.text(stylesText);\n\n    // Temporarily remove the zoom/pan transform from the main svg since we\n    // want the minimap to show a zoomed-out and centered view.\n    const zoomGSelection = select(this.zoomG);\n    const zoomTransform = zoomGSelection.attr('transform');\n    zoomGSelection.attr('transform', null);\n\n    // Since we add padding, account for that here.\n    sceneSize.height += this.labelPadding * 2;\n    sceneSize.width += this.labelPadding * 2;\n\n    // Temporarily assign an explicit width/height to the main svg, since\n    // it doesn't have one (uses flex-box), but we need it for the canvas\n    // to work.\n    svgSelection.attr('width', sceneSize.width).attr('height', sceneSize.height);\n\n    // Since the content inside the svg changed (e.g. a node was expanded),\n    // the aspect ratio has also changed. Thus, we need to update the scale\n    // factor of the minimap. The scale factor is determined such that both\n    // the width and height of the minimap are <= maximum specified w/h.\n    this.scaleMinimap = this.maxWidth / Math.max(sceneSize.width, sceneSize.height);\n    this.minimapSize = {\n      width: sceneSize.width * this.scaleMinimap,\n      height: sceneSize.height * this.scaleMinimap\n    };\n\n    const minimapOffset = this.minimapOffset();\n\n    // Update the size of the minimap's svg, the buffer canvas and the\n    // viewpoint rect.\n    select(this.minimapSvg).attr(this.minimapSize as NzSafeAny);\n    select(this.canvasBuffer).attr(this.minimapSize as NzSafeAny);\n\n    if (this.translate != null && this.zoom != null) {\n      // Update the viewpoint rectangle shape since the aspect ratio of the\n      // map has changed.\n      this.ngZone.runOutsideAngular(() => requestAnimationFrame(() => this.zoom()));\n    }\n\n    // Serialize the main svg to a string which will be used as the rendering\n    // content for the canvas.\n    const svgXml = new XMLSerializer().serializeToString(this.svg);\n\n    // Now that the svg is serialized for rendering, remove the temporarily\n    // assigned styles, explicit width and height and bring back the pan/zoom\n    // transform.\n    svgStyle.remove();\n    svgSelection.attr('width', '100%').attr('height', '100%');\n\n    zoomGSelection.attr('transform', zoomTransform);\n\n    const image = document.createElement('img');\n    const onLoad = (): void => {\n      // Draw the svg content onto the buffer canvas.\n      const context = this.canvasBuffer.getContext('2d');\n      context!.clearRect(0, 0, this.canvasBuffer.width, this.canvasBuffer.height);\n\n      context!.drawImage(image, minimapOffset.x, minimapOffset.y, this.minimapSize.width, this.minimapSize.height);\n\n      this.ngZone.runOutsideAngular(() => {\n        requestAnimationFrame(() => {\n          // Hide the old canvas and show the new buffer canvas.\n          select(this.canvasBuffer).style('display', 'block');\n          select(this.canvas).style('display', 'none');\n          // Swap the two canvases.\n          [this.canvas, this.canvasBuffer] = [this.canvasBuffer, this.canvas];\n        });\n      });\n    };\n\n    image.addEventListener('load', onLoad);\n    image.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;\n\n    this.unlisteners.push(() => {\n      image.removeEventListener('load', onLoad);\n    });\n  }\n\n  /**\n   * Handles changes in zooming/panning. Should be called from the main svg\n   * to notify that a zoom/pan was performed, and this minimap will update its\n   * viewpoint rectangle.\n   *\n   * @param transform\n   */\n  zoom(transform?: ZoomTransform | NzZoomTransform): void {\n    if (this.scaleMinimap == null) {\n      // Scene is not ready yet.\n      return;\n    }\n    // Update the new translate and scale params, only if specified.\n    if (transform) {\n      this.translate = [transform.x, transform.y];\n      this.scaleMain = transform.k;\n    }\n\n    // Update the location of the viewpoint rectangle.\n    const svgRect = this.svg.getBoundingClientRect();\n    const minimapOffset = this.minimapOffset();\n    const viewpointSelection = select(this.viewpoint);\n    this.viewpointCoord.x = (-this.translate[0] * this.scaleMinimap) / this.scaleMain;\n    this.viewpointCoord.y = (-this.translate[1] * this.scaleMinimap) / this.scaleMain;\n    const viewpointWidth = (svgRect.width * this.scaleMinimap) / this.scaleMain;\n    const viewpointHeight = (svgRect.height * this.scaleMinimap) / this.scaleMain;\n    viewpointSelection\n      .attr('x', this.viewpointCoord.x + minimapOffset.x)\n      .attr('y', this.viewpointCoord.y + minimapOffset.y)\n      .attr('width', viewpointWidth)\n      .attr('height', viewpointHeight);\n    // Show/hide the minimap depending on the viewpoint area as a fraction of the whole minimap\n    const mapWidth = this.minimapSize.width;\n    const mapHeight = this.minimapSize.height;\n    const x = this.viewpointCoord.x;\n    const y = this.viewpointCoord.y;\n    const w = Math.min(Math.max(0, x + viewpointWidth), mapWidth) - Math.min(Math.max(0, x), mapWidth);\n    const h = Math.min(Math.max(0, y + viewpointHeight), mapHeight) - Math.min(Math.max(0, y), mapHeight);\n    const fracIntersect = (w * h) / (mapWidth * mapHeight);\n    if (fracIntersect < FRAC_VIEWPOINT_AREA) {\n      this.minimap.classList.remove('hidden');\n    } else {\n      this.minimap.classList.add('hidden');\n    }\n  }\n}\n"
  },
  {
    "path": "components/graph/core/utils.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzZoomTransform } from '../interface';\n\n/**\n * Calculate position and scale\n *\n * @param containerEle\n * @param targetEle\n * @param scale: if scale is set, skip calculate scale value\n */\nexport const calculateTransform = (\n  containerEle: SVGSVGElement,\n  targetEle: SVGGElement,\n  scale?: number\n): NzZoomTransform | null => {\n  const containerEleSize = containerEle.getBoundingClientRect();\n  const targetEleSize = targetEle.getBBox();\n  if (!targetEleSize.width) {\n    // There is no g element anymore.\n    return null;\n  }\n\n  // TODO\n  // leave some place when re-scale\n  const scaleUnit = (containerEleSize.width - 48) / containerEleSize.width;\n  const k =\n    scale ||\n    Math.min(containerEleSize.width / targetEleSize.width, containerEleSize.height / targetEleSize.height, 1) *\n      scaleUnit;\n  const x = (containerEleSize.width - targetEleSize.width * k) / 2;\n  const y = (containerEleSize.height - targetEleSize.height * k) / 2;\n  return {\n    x,\n    y,\n    k\n  };\n};\n"
  },
  {
    "path": "components/graph/data-source/base-graph-source.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { SelectionModel } from '@angular/cdk/collections';\n\nexport interface NzGraphBaseSource<T, K> {\n  /** The saved graph nodes data for `expandAll` action. */\n  dataSource: T;\n\n  /** The expansion model */\n  expansionModel: SelectionModel<K>;\n\n  /** Whether the data node is expanded or collapsed. Return true if it's expanded. */\n  isExpanded(dataNode: K): boolean;\n\n  /** Expand or collapse data node */\n  toggle(dataNode: K): void;\n\n  /** Expand one data node */\n  expand(dataNode: K): void;\n\n  /** Collapse one data node */\n  collapse(dataNode: K): void;\n\n  /** Expand all the dataNodes in the tree */\n  expandAll(): void;\n\n  /** Collapse all the dataNodes in the tree */\n  collapseAll(): void;\n}\n"
  },
  {
    "path": "components/graph/data-source/graph-data-source.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { SelectionModel } from '@angular/cdk/collections';\nimport { BehaviorSubject, merge, Observable } from 'rxjs';\nimport { map } from 'rxjs/operators';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzGraphDataDef } from '../interface';\nimport { NzGraphBaseSource } from './base-graph-source';\n\nexport class NzGraphData implements NzGraphBaseSource<NzGraphDataDef, string> {\n  private _data = new BehaviorSubject<NzGraphDataDef>({} as NzGraphDataDef);\n  dataSource!: NzGraphDataDef;\n  /** A selection model with multi-selection to track expansion status. */\n  expansionModel: SelectionModel<string> = new SelectionModel<string>(true);\n\n  /** Toggles one single data node's expanded/collapsed state. */\n  toggle(nodeName: string): void {\n    this.expansionModel.toggle(nodeName);\n  }\n\n  /** Expands one single data node. */\n  expand(nodeName: string): void {\n    const compound = this.dataSource.compound || {};\n    const toBeSelected = this.findParents(compound, nodeName, [nodeName]);\n    this.expansionModel.select(...toBeSelected);\n  }\n\n  /** Collapses one single data node. */\n  collapse(nodeName: string): void {\n    const compound = this.dataSource.compound || {};\n    const toBeDeselected = this.findChildren(compound, nodeName, [nodeName]);\n    this.expansionModel.deselect(...toBeDeselected);\n  }\n\n  /** Whether a given data node is expanded or not. Returns true if the data node is expanded. */\n  isExpanded(nodeName: string): boolean {\n    return this.expansionModel.isSelected(nodeName);\n  }\n\n  /** Collapse all dataNodes in the tree. */\n  collapseAll(): void {\n    this.expansionModel.clear();\n  }\n\n  expandAll(): void {\n    this.expansionModel.select(...Object.keys(this._data.value.compound || {}));\n  }\n\n  setData(data: NzGraphDataDef): void {\n    this.expansionModel?.clear();\n    this.dataSource = data;\n    this._data.next(data);\n  }\n\n  constructor(source?: NzGraphDataDef) {\n    if (source) {\n      this.expansionModel?.clear();\n      this.dataSource = source;\n      this._data.next(source);\n    }\n  }\n\n  connect(): Observable<NzGraphDataDef> {\n    const changes = [this._data, this.expansionModel.changed];\n    return merge(...changes).pipe(map(() => this._data.value));\n  }\n\n  disconnect(): void {\n    // do nothing for now\n  }\n\n  private findParents(data: NzSafeAny, key: string, parents: string[] = []): string[] {\n    const parent = Object.keys(data)\n      .filter(d => d !== key)\n      .find(d => data[d].includes(key));\n    if (!parent) {\n      return parents;\n    } else {\n      return this.findParents(data, parent, [parent, ...parents]);\n    }\n  }\n\n  private findChildren(data: NzSafeAny, key: string, children: string[] = []): string[] {\n    const groupIds = Object.keys(data);\n    const child = (data[key] || []).filter((c: string) => groupIds.includes(c));\n    if (child && child.length > 0) {\n      return child.reduce(\n        (pre: string[], cur: string) =>\n          Array.from(new Set([...pre, ...this.findChildren(data, cur, [...children, cur])])),\n        children\n      );\n    }\n    return children;\n  }\n}\n"
  },
  {
    "path": "components/graph/demo/customized.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 自定义\n  en-US: Custom graph node\n---\n\n## zh-CN\n\n自定义 node 样式。\n\n## en-US\n\nCustom node style of graph.\n"
  },
  {
    "path": "components/graph/demo/customized.ts",
    "content": "import { Component, ViewChild } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport {\n  NzGraphComponent,\n  NzGraphData,\n  NzGraphDataDef,\n  NzGraphModule,\n  NzGraphZoomDirective,\n  NzRankDirection\n} from 'ng-zorro-antd/graph';\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\n\n@Component({\n  selector: 'nz-demo-graph-customized',\n  imports: [FormsModule, NzButtonModule, NzGraphModule, NzRadioModule],\n  template: `\n    <button nz-button nzType=\"default\" (click)=\"expandAll()\">ExpandAll</button>\n    <button nz-button nzType=\"default\" (click)=\"collapseAll()\">CollapseAll</button>\n    <button nz-button nzType=\"primary\" (click)=\"fit()\">Fit</button>\n    <nz-radio-group [(ngModel)]=\"rankDirection\">\n      <label nz-radio-button nzValue=\"LR\">LR</label>\n      <label nz-radio-button nzValue=\"RL\">RL</label>\n      <label nz-radio-button nzValue=\"TB\">TB</label>\n      <label nz-radio-button nzValue=\"BT\">BT</label>\n    </nz-radio-group>\n    <nz-graph\n      nz-graph-zoom\n      [nzGraphData]=\"graphData\"\n      [nzAutoSize]=\"true\"\n      [nzRankDirection]=\"rankDirection\"\n      (nzGraphInitialized)=\"graphInitialized($event)\"\n    >\n      <ng-container *nzGraphNode=\"let node\">\n        <foreignObject x=\"0\" y=\"0\" [attr.width]=\"node.width\" [attr.height]=\"node.height\">\n          <xhtml:div class=\"graph-node leaf-node\" (click)=\"focusNode(node.id || node.name)\">\n            <div class=\"title\">\n              {{ node.name }}\n            </div>\n          </xhtml:div>\n        </foreignObject>\n      </ng-container>\n\n      <ng-container *nzGraphGroupNode=\"let node\">\n        <foreignObject x=\"0\" y=\"0\" [attr.width]=\"node.width\" [attr.height]=\"node.height\">\n          <xhtml:div class=\"graph-node group-node\" (click)=\"focusNode(node.id || node.name)\">\n            <div class=\"title\">\n              {{ node.name }}\n            </div>\n          </xhtml:div>\n        </foreignObject>\n      </ng-container>\n    </nz-graph>\n  `,\n  styles: `\n    nz-radio-group {\n      float: right;\n    }\n\n    button {\n      margin-right: 12px;\n    }\n\n    nz-graph {\n      height: 400px;\n    }\n\n    .graph-node {\n      border: 1px solid #8cc8ff;\n      cursor: pointer;\n      font-size: 12px;\n      height: 100%;\n      line-height: 1.2;\n      border-radius: 0;\n      text-align: center;\n      word-break: break-all;\n      display: block;\n    }\n\n    .group-node {\n      border-width: 4px;\n    }\n\n    .leaf-node {\n      color: #1a90ff;\n      background: rgba(26, 144, 255, 0.15);\n      min-height: 30px;\n      height: fit-content;\n    }\n\n    .title {\n      padding: 4px;\n      word-break: keep-all;\n    }\n  `\n})\nexport class NzDemoGraphCustomizedComponent {\n  @ViewChild(NzGraphComponent, { static: true }) nzGraphComponent!: NzGraphComponent;\n  @ViewChild(NzGraphZoomDirective, { static: true }) zoomController!: NzGraphZoomDirective;\n  zoom = 0.5;\n  testDef: NzGraphDataDef = {\n    nodes: [\n      {\n        id: '0',\n        label: '0'\n      },\n      {\n        id: '1',\n        label: '1'\n      },\n      {\n        id: '2',\n        label: '2'\n      },\n      {\n        id: '3',\n        label: '3'\n      },\n      {\n        id: '4',\n        label: '4'\n      },\n      {\n        id: '5',\n        label: '5'\n      },\n      {\n        id: '6',\n        label: '6'\n      },\n      {\n        id: '7',\n        label: '7'\n      },\n      {\n        id: '8',\n        label: '8'\n      },\n      {\n        id: '9',\n        label: '9'\n      },\n      {\n        id: '10',\n        label: '10'\n      },\n      {\n        id: '11',\n        label: '11'\n      },\n      {\n        id: '12',\n        label: '12'\n      },\n      {\n        id: '13',\n        label: '13'\n      },\n      {\n        id: '14',\n        label: '14'\n      },\n      {\n        id: '15',\n        label: '15'\n      }\n    ],\n    edges: [\n      {\n        v: '0',\n        w: '1'\n      },\n      {\n        v: '0',\n        w: '2'\n      },\n      {\n        v: '0',\n        w: '3'\n      },\n      {\n        v: '0',\n        w: '4'\n      },\n      {\n        v: '0',\n        w: '5'\n      },\n      {\n        v: '0',\n        w: '7'\n      },\n      {\n        v: '0',\n        w: '8'\n      },\n      {\n        v: '0',\n        w: '9'\n      },\n      {\n        v: '0',\n        w: '10'\n      },\n      {\n        v: '0',\n        w: '11'\n      },\n      {\n        v: '0',\n        w: '13'\n      },\n      {\n        v: '0',\n        w: '14'\n      },\n      {\n        v: '0',\n        w: '15'\n      },\n      {\n        v: '2',\n        w: '3'\n      },\n      {\n        v: '4',\n        w: '5'\n      },\n      {\n        v: '4',\n        w: '6'\n      },\n      {\n        v: '5',\n        w: '6'\n      },\n      {\n        v: '7',\n        w: '13'\n      },\n      {\n        v: '8',\n        w: '14'\n      },\n      {\n        v: '9',\n        w: '10'\n      },\n      {\n        v: '10',\n        w: '14'\n      },\n      {\n        v: '10',\n        w: '12'\n      },\n      {\n        v: '11',\n        w: '14'\n      },\n      {\n        v: '12',\n        w: '13'\n      }\n    ],\n    compound: {\n      G0: ['4', '5', '15']\n    }\n  };\n  rankDirection: NzRankDirection = 'TB';\n  graphData = new NzGraphData(this.testDef);\n\n  expand(name: string): void {\n    this.graphData.expand(name);\n  }\n\n  collapse(name: string): void {\n    this.graphData.collapse(name);\n  }\n\n  expandAll(): void {\n    this.graphData.expandAll();\n  }\n\n  collapseAll(): void {\n    this.graphData.collapseAll();\n  }\n\n  fit(): void {\n    this.zoomController?.fitCenter();\n  }\n\n  focusNode(e: string | number): void {\n    this.zoomController?.focus(e);\n  }\n\n  graphInitialized(_ele: NzGraphComponent): void {\n    // Only nz-graph-zoom enabled, you should run `fitCenter` manually\n    this.zoomController?.fitCenter();\n  }\n}\n"
  },
  {
    "path": "components/graph/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Display\ntitle: Graph\ncols: 1\nexperimental: true\ndescription: Render graph.\n---\n\n## When To Use\n\nWhen you want to use graph in Angular.\n\n### Install Dependencies\n\n> The graph depends on d3-drag d3-zoom d3-selection d3-transition d3-shape (may be removed in next major version)\n\n```sh\nnpm install dagre-compound dagre d3-transition d3-zoom d3-selection d3-shape d3-drag @types/d3\n```\n\n### Import Style\n\n```less\n@import 'node_modules/ng-zorro-antd/graph/style/entry.less';\n```\n\n## API\n\n### nz-graph\n\n| Parameter               | Description                                                                      | Type                                 | Default |\n| ----------------------- | -------------------------------------------------------------------------------- | ------------------------------------ | ------- |\n| `[nzGraphData]`         | Data source                                                                      | `NzGraphData(data: NzGraphDataDef?)` | ``      |\n| `[nzRankDirection]`     | Graph Direction                                                                  | `TB` \\| `BT` \\| `LR` \\| `RL`         | `LR`    |\n| `[nzAutoSize]`          | Whether to automatically adjust the height of the node, the default equal height | `boolean`                            | `false` |\n| `[nzGraphLayoutConfig]` | Global config of graph                                                           | `NzGraphLayoutConfig`                | ``      |\n\n#### Methods\n\n| Method        | Description                                                             |\n| ------------- | ----------------------------------------------------------------------- |\n| `fitCenter()` | Move graph to center(use `nz-graph-zoom` instead if zooming is enabled) |\n\n### [nz-graph-zoom]\n\n| Parameter            | Description                | Type                                         | Default |\n| -------------------- | -------------------------- | -------------------------------------------- | ------- |\n| `[(nzZoom)]`         | Default zoom scale         | `number`                                     | `1`     |\n| `[nzMinZoom]`        | Minimum zoom scale         | `number`                                     | `0.1`   |\n| `[nzMaxZoom]`        | Maximum zoom scale         | `number`                                     | `10`    |\n| `(nzTransformEvent)` | Event of zooming           | `() => NzZoomTransform`                      | -       |\n| `(fitCenter)`        | Move graph to center       | `() => void`                                 | `void`  |\n| `(focus)`            | Move target node to center | `(e: SVGGElement, duration: number) => void` | `void`  |\n\n#### NzGraphData\n\n| Method           | Description                   | Type                             |\n| ---------------- | ----------------------------- | -------------------------------- |\n| `setData`        | set data source               | `(data: NzGraphDataDef) => void` |\n| `toggle`         | toggle group node             | `(nodeName: string) => void`     |\n| `expand`         | expand group node             | `(nodeName: string) => void`     |\n| `expandAll`      | expand all group nodes        | `(nodeName: string) => void`     |\n| `collapse`       | collapse group node           | `(nodeName: string) => void`     |\n| `isExpand`       | get if expanded of node       | `(nodeName: string) => boolean`  |\n| `expansionModel` | model of expanded nodes' info | `SelectionModel<string>`         |\n\n### NzGraphLayoutConfig\n\n| Method                | Description         | Type                                                                                                             |\n| --------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------- |\n| `layout`              | graph layout config | `{ nodeSep: number; rankSep: number; edgeSep: number; }`                                                         |\n| `subScene`            | group node config   | `{ paddingTop: number; paddingBottom: number; paddingLeft: number; paddingRight: number; labelHeight: number; }` |\n| `defaultCompoundNode` | group node size     | `{ width: number; height: number; maxLabelWidth: number; }`                                                      |\n| `defaultNode`         | default node size   | `{ width: number; height: number; labelOffset: number; maxLabelWidth: number; }`                                 |\n\n#### NzGraphDataDef\n\n| Parameter  | Description | Type                                                                                                  | Default |\n| ---------- | ----------- | ----------------------------------------------------------------------------------------------------- | ------- |\n| `nodes`    | nodes       | `Array<{ id: number\\|string; label?: string; width?: number; height?: number; [key: string]: any; }>` | `[]`    |\n| `edges`    | edges       | `Array<{ v: number\\|string; w: number\\|string; [key: string]: any; }>`                                | `[]`    |\n| `compound` | group       | `{ [parent: string]: string[]; }`                                                                     | `null`  |\n\n#### NzGraphNode\n\n| Parameter        | Description                  | Type                                 |\n| ---------------- | ---------------------------- | ------------------------------------ |\n| `id`             | id                           | `number\\|string`                     |\n| `label?`         | node content                 | `string`                             |\n| `name`           | node name                    | `number\\|string`                     |\n| `type`           | node type(group: 0, node: 1) | `number`                             |\n| `parentNodeName` | parentNode name              | `string`                             |\n| `coreBox`        | coreBox                      | `{ width: number; height: number; }` |\n| `xOffset`        | x-offset                     | `number`                             |\n| `yOffset`        | y-offset                     | `number`                             |\n| `width`          | width                        | `number`                             |\n| `height`         | height                       | `number`                             |\n| `[key: string]`  | user inputs                  | `any`                                |\n\n#### NzGraphEdge\n\n| Parameter | Description  | Type                               |\n| --------- | ------------ | ---------------------------------- |\n| `id`      | id           | `string`                           |\n| `v`       | source node  | `number\\|string`                   |\n| `w`       | target node  | `number\\|string`                   |\n| `label?`  | edge content | `string`                           |\n| `points`  | points       | `Array<{ x: number; y: number; }>` |\n\n#### NzGraphGroupNode\n\n| Parameter  | Type                                   |\n| ---------- | -------------------------------------- |\n| `expanded` | `boolean`                              |\n| `nodes`    | `Array<NzGraphNode\\|NzGraphGroupNode>` |\n| `edges`    | `NzGraphEdge[]`                        |\n\n### [nzGraphNode]\n\nCustomize the graph node template\n\n```html\n<nz-graph [nzGraphData]=\"data\">\n  <ng-container *nzGraphNode=\"let node\">\n    <span>{{ node.name }} - {{ node.label }}</span>\n  </ng-container>\n</nz-graph>\n```\n\n### [nzGraphGroupNode]\n\nCustomize the graph group-node template\n\n```html\n<nz-graph [nzGraphData]=\"data\">\n  <ng-container *nzGraphGroupNode=\"let node\">\n    <span>{{ node.name }} - {{ node.label }}</span>\n  </ng-container>\n</nz-graph>\n```\n\n### [nzGraphEdge]\n\nCustomize the graph edge template\n\n```html\n<nz-graph [nzGraphData]=\"data\">\n  <ng-container *nzGraphEdge=\"let edge\">\n    <svg:g>\n      <path></path>\n    </svg:g>\n  </ng-container>\n</nz-graph>\n```\n\n### Styling\n\nThe Component styles only contain the necessary positional properties and simple styles, you can customize the style by overriding the following class.\n\n- `.nz-graph` `nz-graph` The `nz-graph` component namespace\n- `.nz-graph-nodes` The class name of container covered all nodes\n  - `.nz-graph-node` The class name of `nz-graph-node`\n  - `.nz-graph-node-expanded` The class name of expanded node\n  - `.nz-graph-group-node` The class name of group node\n  - `.nz-graph-base-node` The class name of leaf(OP) node\n- `.nz-graph-edges` The class name of container covered edges in the target node\n  - `.nz-graph-edge` The class name of edge\n    - `path.nz-graph-edge-line` The class name of svg:path element\n    - `.nz-graph-edge-text` The class name of svg:text element\n\n## More\n\n- [dagre-compound](https://www.npmjs.com/package/dagre-compound): Dagre-based nested layout calculation library\n- [SelectionModel](https://github.com/angular/components/blob/master/src/cdk/collections/selection-model.ts)\n"
  },
  {
    "path": "components/graph/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 流程图\ntype: 数据展示\ntitle: Graph\ncols: 1\nexperimental: true\ndescription: 渲染流程图。\n---\n\n## 何时使用\n\n需要在网页上渲染 Graph 图时使用。\n\n### 安装依赖\n\n> 目前组件依赖 d3-drag d3-zoom d3-selection d3-transition d3-shape 用于绘制相关属性（可能会在之后的版本中逐步替换）\n\n```sh\nnpm install dagre-compound dagre d3-transition d3-zoom d3-selection d3-shape d3-drag @types/d3\n```\n\n### 引入样式\n\n```less\n@import 'node_modules/ng-zorro-antd/graph/style/entry.less';\n```\n\n## API\n\n### nz-graph\n\n| 参数                    | 说明                                 | 类型                                 | 默认值  |\n| ----------------------- | ------------------------------------ | ------------------------------------ | ------- |\n| `[nzGraphData]`         | 数据源                               | `NzGraphData(data: NzGraphDataDef?)` | ``      |\n| `[nzRankDirection]`     | 图方向                               | `TB` \\| `BT` \\| `LR` \\| `RL`         | `LR`    |\n| `[nzAutoSize]`          | 是否根据节点内容自适应高度(默认等高) | `boolean`                            | `false` |\n| `[nzGraphLayoutConfig]` | 全局配置                             | `NzGraphLayoutConfig`                | ``      |\n\n#### 组件方法\n\n| 名称          | 描述                                                       |\n| ------------- | ---------------------------------------------------------- |\n| `fitCenter()` | 居中图并自适应缩放（如使用缩放功能请使用 `nz-graph-zoom`） |\n\n### [nz-graph-zoom]\n\n| 参数                 | 说明               | 类型                                         | 默认值 |\n| -------------------- | ------------------ | -------------------------------------------- | ------ |\n| `[(nzZoom)]`         | 缩放比例           | `number`                                     | `1`    |\n| `[nzMinZoom]`        | 最小缩放           | `number`                                     | `0.1`  |\n| `[nzMaxZoom]`        | 最大缩放           | `number`                                     | `10`   |\n| `(nzTransformEvent)` | 缩放事件           | `() => NzZoomTransform`                      | -      |\n| `(fitCenter)`        | 居中图并自适应缩放 | `() => void`                                 | `void` |\n| `(focus)`            | 居中单个节点       | `(e: SVGGElement, duration: number) => void` | `void` |\n\n#### NzGraphData\n\n| 属性/方法        | 说明                    | 类型                             |\n| ---------------- | ----------------------- | -------------------------------- |\n| `setData`        | 设置数据源              | `(data: NzGraphDataDef) => void` |\n| `toggle`         | 收起/展开 group 节点    | `(nodeName: string) => void`     |\n| `expand`         | 展开 group 节点         | `(nodeName: string) => void`     |\n| `expandAll`      | 展开全部 group 节点     | `(nodeName: string) => void`     |\n| `collapse`       | 收起全部 group 节点     | `(nodeName: string) => void`     |\n| `isExpand`       | 获取 group 节点展开状态 | `(nodeName: string) => boolean`  |\n| `expansionModel` | 展开节点存储对象        | `SelectionModel<string>`         |\n\n### NzGraphLayoutConfig\n\n| 属性                  | 说明            | 类型                                                                                                             |\n| --------------------- | --------------- | ---------------------------------------------------------------------------------------------------------------- |\n| `layout`              | 布局参数        | `{ nodeSep: number; rankSep: number; edgeSep: number; }`                                                         |\n| `subScene`            | group 节点      | `{ paddingTop: number; paddingBottom: number; paddingLeft: number; paddingRight: number; labelHeight: number; }` |\n| `defaultCompoundNode` | group 节点 size | `{ width: number; height: number; maxLabelWidth: number; }`                                                      |\n| `defaultNode`         | 默认节点 size   | `{ width: number; height: number; labelOffset: number; maxLabelWidth: number; }`                                 |\n\n#### NzGraphDataDef\n\n| 属性       | 说明 | 类型                                                                                                  | 默认值 |\n| ---------- | ---- | ----------------------------------------------------------------------------------------------------- | ------ |\n| `nodes`    | 节点 | `Array<{ id: number\\|string; label?: string; width?: number; height?: number; [key: string]: any; }>` | `[]`   |\n| `edges`    | 线   | `Array<{ v: number\\|string; w: number\\|string; [key: string]: any; }>`                                | `[]`   |\n| `compound` | 分组 | `{ [parent: string]: string[]; }`                                                                     | `null` |\n\n#### NzGraphNode\n\n| 属性             | 说明                     | 类型                                 |\n| ---------------- | ------------------------ | ------------------------------------ |\n| `id`             | id                       | `number\\|string`                     |\n| `label?`         | 节点内容                 | `string`                             |\n| `name`           | 节点名称                 | `number\\|string`                     |\n| `type`           | 节点类型(组: 0, 节点: 1) | `number`                             |\n| `parentNodeName` | 父节点名称               | `string`                             |\n| `coreBox`        | 布局高宽                 | `{ width: number; height: number; }` |\n| `xOffset`        | x 偏移                   | `number`                             |\n| `yOffset`        | y 偏移                   | `number`                             |\n| `width`          | 宽度                     | `number`                             |\n| `height`         | 高度                     | `number`                             |\n| `[key: string]`  | 用户输入                 | `any`                                |\n\n#### NzGraphEdge\n\n| 属性     | 说明     | 类型                               |\n| -------- | -------- | ---------------------------------- |\n| `id`     | id       | `string`                           |\n| `v`      | 起始节点 | `number\\|string`                   |\n| `w`      | 目标节点 | `number\\|string`                   |\n| `label?` | 线内容   | `string`                           |\n| `points` | points   | `Array<{ x: number; y: number; }>` |\n\n#### NzGraphGroupNode\n\n| 属性       | 类型                                   |\n| ---------- | -------------------------------------- |\n| `expanded` | `boolean`                              |\n| `nodes`    | `Array<NzGraphNode\\|NzGraphGroupNode>` |\n| `edges`    | `NzGraphEdge[]`                        |\n\n### [nzGraphNode]\n\n自定义叶子节点渲染模板\n\n```html\n<nz-graph [nzGraphData]=\"data\">\n  <ng-container *nzGraphNode=\"let node\">\n    <span>{{ node.name }} - {{ node.label }}</span>\n  </ng-container>\n</nz-graph>\n```\n\n### [nzGraphGroupNode]\n\n自定义组节点渲染模板\n\n```html\n<nz-graph [nzGraphData]=\"data\">\n  <ng-container *nzGraphGroupNode=\"let node\">\n    <span>{{ node.name }} - {{ node.label }}</span>\n  </ng-container>\n</nz-graph>\n```\n\n### [nzGraphEdge]\n\n自定义边渲染模板\n\n```html\n<nz-graph [nzGraphData]=\"data\">\n  <ng-container *nzGraphEdge=\"let edge\">\n    <svg:g>\n      <path></path>\n    </svg:g>\n  </ng-container>\n</nz-graph>\n```\n\n### 样式\n\n组件样式包含了必要的属性和简单的样式，你可以通过覆写下列类名自定义样式。\n\n- `.nz-graph` `nz-graph` 组件命名空间\n- `.nz-graph-nodes` 节点\n  - `.nz-graph-node` 单个节点\n  - `.nz-graph-node-expanded` 展开节点\n  - `.nz-graph-group-node` 组节点\n  - `.nz-graph-base-node` 叶子节点\n- `.nz-graph-edges` 连接线\n  - `.nz-graph-edge` 单条线\n    - `path.nz-graph-edge-line` 线 path 元素\n    - `.nz-graph-edge-text` 线文本元素\n\n## 说明\n\n- [dagre-compound](https://www.npmjs.com/package/dagre-compound): 基于 Dagre 的 嵌套布局计算库\n- [SelectionModel](https://github.com/angular/components/blob/master/src/cdk/collections/selection-model.ts)\n"
  },
  {
    "path": "components/graph/graph-defs.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component } from '@angular/core';\n\n@Component({\n  selector: 'svg:defs[nz-graph-defs]',\n  template: `\n    <svg:marker\n      class=\"nz-graph-edge-marker\"\n      id=\"edge-end-arrow\"\n      viewBox=\"1 0 20 20\"\n      refX=\"8\"\n      refY=\"3.5\"\n      markerWidth=\"10\"\n      markerHeight=\"10\"\n      orient=\"auto\"\n    >\n      <svg:polygon points=\"0 0, 10 3.5, 0 7\" />\n    </svg:marker>\n  `\n})\nexport class NzGraphDefsComponent {}\n"
  },
  {
    "path": "components/graph/graph-edge.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  ElementRef,\n  Injector,\n  Input,\n  OnChanges,\n  OnInit,\n  SimpleChanges,\n  TemplateRef,\n  afterNextRender,\n  inject,\n  ChangeDetectorRef\n} from '@angular/core';\n\nimport { curveBasis, curveLinear, line } from 'd3-shape';\n\nimport { NzGraphEdge, NzGraphEdgeType } from './interface';\n\n@Component({\n  selector: '[nz-graph-edge]',\n  template: `\n    @if (customTemplate) {\n      <ng-container [ngTemplateOutlet]=\"customTemplate\" [ngTemplateOutletContext]=\"{ $implicit: edge }\" />\n    } @else {\n      <svg:g>\n        <path class=\"nz-graph-edge-line\" [attr.marker-end]=\"'url(#edge-end-arrow)'\" />\n        @if (edge.label) {\n          <svg:text class=\"nz-graph-edge-text\" text-anchor=\"middle\" dy=\"10\">\n            <textPath [attr.href]=\"'#' + id\" startOffset=\"50%\">{{ edge.label }}</textPath>\n          </svg:text>\n        }\n      </svg:g>\n    }\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  imports: [NgTemplateOutlet]\n})\nexport class NzGraphEdgeComponent implements OnInit, OnChanges {\n  private injector = inject(Injector);\n  private cdr = inject(ChangeDetectorRef);\n  @Input() edge!: NzGraphEdge;\n  @Input() edgeType?: NzGraphEdgeType | string;\n\n  @Input() customTemplate?: TemplateRef<{\n    $implicit: NzGraphEdge;\n  }>;\n\n  public get id(): string {\n    return this.edge?.id || `${this.edge.v}--${this.edge.w}`;\n  }\n  private el: SVGGElement = inject(ElementRef<SVGGElement>).nativeElement;\n  private path!: SVGPathElement;\n\n  private line = line<{ x: number; y: number }>()\n    .x(d => d.x)\n    .y(d => d.y)\n    .curve(curveLinear);\n\n  ngOnInit(): void {\n    this.initElementStyle();\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { edge, customTemplate, edgeType } = changes;\n\n    if (edge) {\n      afterNextRender(\n        () => {\n          // Update path element if customTemplate set\n          if (customTemplate) {\n            this.initElementStyle();\n          }\n\n          this.setLine();\n          this.cdr.markForCheck();\n        },\n        { injector: this.injector }\n      );\n    }\n\n    if (edgeType) {\n      const type = this.edgeType === NzGraphEdgeType.LINE ? curveLinear : curveBasis;\n      this.line = line<{ x: number; y: number }>()\n        .x(d => d.x)\n        .y(d => d.y)\n        .curve(type);\n    }\n  }\n\n  initElementStyle(): void {\n    this.path = this.el.querySelector('path')!;\n    this.setElementData();\n  }\n\n  setLine(): void {\n    this.setPath(this.line(this.edge.points)!);\n  }\n\n  setPath(d: string): void {\n    this.path.setAttribute('d', d);\n  }\n\n  setElementData(): void {\n    if (!this.path) {\n      return;\n    }\n    this.path.setAttribute('id', this.id);\n    this.path.setAttribute('data-edge', this.id);\n    this.path.setAttribute('data-v', `${this.edge.v}`);\n    this.path.setAttribute('data-w', `${this.edge.w}`);\n  }\n}\n"
  },
  {
    "path": "components/graph/graph-edge.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive } from '@angular/core';\n\n@Directive({\n  selector: '[nzGraphEdge]',\n  exportAs: 'nzGraphEdge'\n})\nexport class NzGraphEdgeDirective {}\n"
  },
  {
    "path": "components/graph/graph-group-node.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive } from '@angular/core';\n\n@Directive({\n  selector: '[nzGraphGroupNode]',\n  exportAs: 'nzGraphGroupNode'\n})\nexport class NzGraphGroupNodeDirective {}\n"
  },
  {
    "path": "components/graph/graph-minimap.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, DestroyRef, ElementRef, inject, NgZone } from '@angular/core';\n\nimport type { ZoomBehavior } from 'd3-zoom';\n\nimport type { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { Minimap } from './core/minimap';\nimport { NzZoomTransform } from './interface';\n\n@Component({\n  selector: 'nz-graph-minimap',\n  template: `\n    <svg>\n      <defs>\n        <filter id=\"minimapDropShadow\" x=\"-20%\" y=\"-20%\" width=\"150%\" height=\"150%\">\n          <feOffset result=\"offOut\" in=\"SourceGraphic\" dx=\"1\" dy=\"1\" />\n          <feColorMatrix\n            result=\"matrixOut\"\n            in=\"offOut\"\n            type=\"matrix\"\n            values=\"0.1 0 0 0 0 0 0.1 0 0 0 0 0 0.1 0 0 0 0 0 0.5 0\"\n          />\n          <feGaussianBlur result=\"blurOut\" in=\"matrixOut\" stdDeviation=\"2\" />\n          <feBlend in=\"SourceGraphic\" in2=\"blurOut\" mode=\"normal\" />\n        </filter>\n      </defs>\n      <rect />\n    </svg>\n    <canvas class=\"viewport\"></canvas>\n    <!-- Additional canvas to use as buffer to avoid flickering between updates -->\n    <canvas class=\"buffer\"></canvas>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    '[class.nz-graph-minimap]': 'true'\n  }\n})\nexport class NzGraphMinimapComponent {\n  private elementRef = inject(ElementRef<HTMLElement>);\n  private ngZone = inject(NgZone);\n  private destroyRef = inject(DestroyRef);\n  minimap?: Minimap;\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      this.minimap?.destroy();\n    });\n  }\n\n  init(containerEle: ElementRef, zoomBehavior: ZoomBehavior<NzSafeAny, NzSafeAny>): void {\n    const svgEle = containerEle.nativeElement.querySelector('svg');\n    const zoomEle = containerEle.nativeElement.querySelector('svg > g');\n    this.minimap = new Minimap(this.ngZone, svgEle, zoomEle, zoomBehavior, this.elementRef.nativeElement, 150, 0);\n  }\n\n  zoom(transform: NzZoomTransform): void {\n    this.minimap?.zoom(transform);\n  }\n\n  update(): void {\n    this.minimap?.update();\n  }\n}\n"
  },
  {
    "path": "components/graph/graph-node.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { coerceCssPixelValue } from '@angular/cdk/coercion';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  DestroyRef,\n  ElementRef,\n  inject,\n  Input,\n  NgZone,\n  OnInit,\n  Renderer2,\n  TemplateRef\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { filter, tap } from 'rxjs/operators';\n\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\n\nimport { NzGraph } from './graph';\nimport { NzGraphGroupNode, NzGraphNode } from './interface';\n\ninterface Info {\n  x: number;\n  y: number;\n  width: number;\n  height: number;\n}\n\nconst translate = (x: number, y: number): string => `translate(${coerceCssPixelValue(x)}, ${coerceCssPixelValue(y)})`;\n\n@Component({\n  selector: '[nz-graph-node]',\n  template: `\n    <svg:g>\n      @if (customTemplate) {\n        <ng-container [ngTemplateOutlet]=\"customTemplate\" [ngTemplateOutletContext]=\"{ $implicit: node }\" />\n      } @else {\n        <svg:rect class=\"nz-graph-node-rect\" [attr.width]=\"node.width\" [attr.height]=\"node.height\" />\n        <svg:text x=\"10\" y=\"20\">{{ node.id || node.name }}</svg:text>\n      }\n    </svg:g>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    '[id]': 'node.id || node.name',\n    '[class.nz-graph-node-expanded]': 'node.expanded',\n    '[class.nz-graph-group-node]': 'node.type === 0',\n    '[class.nz-graph-base-node]': 'node.type === 1'\n  },\n  imports: [NgTemplateOutlet]\n})\nexport class NzGraphNodeComponent implements OnInit {\n  private readonly ngZone = inject(NgZone);\n  private readonly el: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement;\n  private readonly renderer = inject(Renderer2);\n  private readonly graphComponent = inject(NzGraph);\n  private readonly destroyRef = inject(DestroyRef);\n\n  @Input() node!: NzGraphNode | NzGraphGroupNode;\n  @Input() customTemplate?: TemplateRef<{\n    $implicit: NzGraphNode | NzGraphGroupNode;\n  }>;\n\n  private animationInfo: Info | null = null;\n  private initialState = true;\n\n  ngOnInit(): void {\n    fromEventOutsideAngular<MouseEvent>(this.el, 'click')\n      .pipe(\n        tap(event => event.preventDefault()),\n        filter(() => this.graphComponent.nzNodeClick.observers.length > 0),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(() => {\n        // Re-enter the Angular zone and run the change detection only if there are any `nzNodeClick` listeners,\n        // e.g.: `<nz-graph (nzNodeClick)=\"...\"></nz-graph>`.\n        this.ngZone.run(() => this.graphComponent.nzNodeClick.emit(this.node));\n      });\n  }\n\n  async makeAnimation(): Promise<void> {\n    const cur = this.getAnimationInfo();\n    const pre = { ...this.animationInfo } as Info;\n\n    const group = this.el.querySelector('g');\n\n    if (this.initialState) {\n      // Initial state: directly set position without animation\n      this.renderer.setAttribute(this.el, 'transform', translate(cur.x, cur.y));\n      if (group) {\n        this.renderer.setStyle(group, 'width', coerceCssPixelValue(cur.width));\n        this.renderer.setStyle(group, 'height', coerceCssPixelValue(cur.height));\n      }\n      this.initialState = false;\n      this.animationInfo = cur;\n    } else {\n      return new Promise(resolve => {\n        // Animate parent element (transform)\n        const parentAnimation = this.el.animate(\n          [{ transform: translate(pre.x, pre.y) }, { transform: translate(cur.x, cur.y) }],\n          {\n            duration: 150,\n            easing: 'ease-out',\n            fill: 'forwards'\n          }\n        );\n\n        // Animate child g element (width/height) if it exists\n        if (group) {\n          group.animate(\n            [\n              { width: coerceCssPixelValue(pre.width), height: coerceCssPixelValue(pre.height) },\n              { width: coerceCssPixelValue(cur.width), height: coerceCssPixelValue(cur.height) }\n            ],\n            {\n              duration: 150,\n              easing: 'ease-out',\n              fill: 'forwards'\n            }\n          );\n        }\n\n        // Wait for animations to complete\n        parentAnimation.onfinish = () => {\n          // Need this for canvas for now.\n          this.renderer.setAttribute(this.el, 'transform', translate(cur.x, cur.y));\n          if (group) {\n            this.renderer.setStyle(group, 'width', coerceCssPixelValue(cur.width));\n            this.renderer.setStyle(group, 'height', coerceCssPixelValue(cur.height));\n          }\n          resolve();\n        };\n\n        this.animationInfo = cur;\n      });\n    }\n  }\n\n  makeNoAnimation(): void {\n    const cur = this.getAnimationInfo();\n    // Need this for canvas for now.\n    this.renderer.setAttribute(this.el, 'transform', translate(cur.x, cur.y));\n  }\n\n  getAnimationInfo(): Info {\n    const { x, y } = this.nodeTransform();\n    return {\n      width: this.node.width,\n      height: this.node.height,\n      x,\n      y\n    };\n  }\n\n  nodeTransform(): { x: number; y: number } {\n    const x = this.computeCXPositionOfNodeShape() - this.node.width / 2;\n    const y = this.node.y - this.node.height / 2;\n    return { x, y };\n  }\n\n  computeCXPositionOfNodeShape(): number {\n    if ((this.node as NzGraphGroupNode).expanded) {\n      return this.node.x;\n    }\n    return this.node.x - this.node.width / 2 + this.node.coreBox.width / 2;\n  }\n}\n"
  },
  {
    "path": "components/graph/graph-node.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive } from '@angular/core';\n\n@Directive({\n  selector: '[nzGraphNode]',\n  exportAs: 'nzGraphNode'\n})\nexport class NzGraphNodeDirective {}\n"
  },
  {
    "path": "components/graph/graph-zoom.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  afterNextRender,\n  ChangeDetectorRef,\n  DestroyRef,\n  Directive,\n  ElementRef,\n  EventEmitter,\n  inject,\n  Input,\n  Output\n} from '@angular/core';\n\nimport { Selection } from 'd3-selection';\nimport { transition } from 'd3-transition';\nimport { zoom, ZoomBehavior, zoomIdentity, zoomTransform } from 'd3-zoom';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { numberAttributeWithOneFallback } from 'ng-zorro-antd/core/util';\n\nimport { calculateTransform } from './core/utils';\nimport { NzZoomTransform, RelativePositionInfo } from './interface';\n\n@Directive({\n  selector: '[nz-graph-zoom]',\n  exportAs: 'nzGraphZoom'\n})\nexport class NzGraphZoomDirective {\n  private destroyRef = inject(DestroyRef);\n  private cdr = inject(ChangeDetectorRef);\n  private element = inject(ElementRef);\n\n  @Input({ transform: numberAttributeWithOneFallback }) nzZoom?: number;\n  @Input() nzMinZoom = 0.1;\n  @Input() nzMaxZoom = 10;\n\n  @Output() readonly nzTransformEvent = new EventEmitter<NzZoomTransform>();\n  @Output() readonly nzZoomChange = new EventEmitter<number>();\n\n  svgSelection!: Selection<NzSafeAny, NzSafeAny, NzSafeAny, NzSafeAny>;\n  zoomBehavior!: ZoomBehavior<NzSafeAny, NzSafeAny>;\n\n  // TODO\n  // Support svg element only now\n  svgElement!: SVGSVGElement;\n  gZoomElement!: SVGGElement;\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      this.unbind();\n    });\n\n    afterNextRender(() => {\n      this.bind();\n    });\n  }\n\n  bind(): void {\n    this.svgElement = this.element.nativeElement.querySelector('svg') as SVGSVGElement;\n    this.gZoomElement = this.element.nativeElement.querySelector('svg > g') as SVGGElement;\n    const { width, height } = this.element.nativeElement.getBoundingClientRect();\n    this.svgSelection = transition()\n      .selection()\n      .select(() => this.svgElement);\n    this.zoomBehavior = zoom()\n      .extent([\n        [0, 0],\n        [width, height]\n      ])\n      .scaleExtent([this.nzMinZoom, this.nzMaxZoom])\n      .on('zoom', e => {\n        this.zoomed(e);\n      });\n    this.svgSelection.call(this.zoomBehavior, zoomIdentity.translate(0, 0).scale(this.nzZoom || 1));\n    // Init with nzZoom\n    this.reScale(0, this.nzZoom);\n  }\n\n  unbind(): void {\n    // Destroy listener\n    this.svgSelection?.interrupt().selectAll('*').interrupt();\n    if (this.zoomBehavior) {\n      this.zoomBehavior.on('end', null).on('zoom', null);\n    }\n  }\n\n  // Methods\n  fitCenter(duration: number = 0): void {\n    this.reScale(duration);\n  }\n\n  focus(id: NzSafeAny, duration: number = 0): void {\n    // Make sure this node is under SVG container\n    if (!this.svgElement.getElementById(`${id}`)) {\n      return;\n    }\n\n    const node = this.svgElement.getElementById(`${id}`) as SVGGElement;\n    const svgRect = this.svgElement.getBoundingClientRect();\n    const position = this.getRelativePositionInfo(node);\n    const svgTransform = zoomTransform(this.svgElement);\n\n    const centerX = (position.topLeft.x + position.bottomRight.x) / 2;\n    const centerY = (position.topLeft.y + position.bottomRight.y) / 2;\n    const dx = svgRect.left + svgRect.width / 2 - centerX;\n    const dy = svgRect.top + svgRect.height / 2 - centerY;\n\n    this.svgSelection\n      .transition()\n      .duration(duration)\n      .call(this.zoomBehavior.translateBy, dx / svgTransform.k, dy / svgTransform.k);\n  }\n\n  /**\n   * Handle zoom event\n   *\n   * @param transform\n   */\n  private zoomed({ transform }: NzSafeAny): void {\n    const { x, y, k } = transform;\n    // Update g element transform\n    (this.gZoomElement as SVGGElement).setAttribute('transform', `translate(${x}, ${y})scale(${k})`);\n    this.nzZoom = k;\n    this.nzZoomChange.emit(this.nzZoom);\n    this.nzTransformEvent.emit(transform);\n    this.cdr.markForCheck();\n  }\n\n  /**\n   * Scale with zoom and duration\n   *\n   * @param duration\n   * @param scale\n   * @private\n   */\n  private reScale(duration: number, scale?: number): void {\n    const transform = calculateTransform(this.svgElement, this.gZoomElement, scale);\n    if (!transform) {\n      return;\n    }\n    const { x, y, k } = transform;\n    const zTransform = zoomIdentity.translate(x, y).scale(Math.max(k, this.nzMinZoom));\n    this.svgSelection\n      .transition()\n      .duration(duration)\n      .call(this.zoomBehavior.transform, zTransform)\n      .on('end.fitted', () => {\n        this.zoomBehavior.on('end.fitted', null);\n      });\n  }\n\n  private getRelativePositionInfo(node: SVGGElement): RelativePositionInfo {\n    const nodeBox = node.getBBox();\n    const nodeCtm = node.getScreenCTM();\n    let pointTL = this.svgElement.createSVGPoint();\n    let pointBR = this.svgElement.createSVGPoint();\n\n    pointTL.x = nodeBox.x;\n    pointTL.y = nodeBox.y;\n    pointBR.x = nodeBox.x + nodeBox.width;\n    pointBR.y = nodeBox.y + nodeBox.height;\n    pointTL = pointTL.matrixTransform(nodeCtm!);\n    pointBR = pointBR.matrixTransform(nodeCtm!);\n    return {\n      topLeft: pointTL,\n      bottomRight: pointBR\n    };\n  }\n}\n"
  },
  {
    "path": "components/graph/graph.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { isPlatformBrowser, NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterContentChecked,\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ContentChild,\n  DestroyRef,\n  ElementRef,\n  EventEmitter,\n  forwardRef,\n  inject,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  PLATFORM_ID,\n  QueryList,\n  SimpleChanges,\n  TemplateRef,\n  ViewChildren,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Observable, ReplaySubject, Subscription } from 'rxjs';\nimport { take } from 'rxjs/operators';\n\nimport { buildGraph } from 'dagre-compound';\n\nimport { NzNoAnimationDirective } from 'ng-zorro-antd/core/animation';\nimport { cancelAnimationFrame, requestAnimationFrame } from 'ng-zorro-antd/core/polyfill';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { calculateTransform } from './core/utils';\nimport { NzGraphData } from './data-source/graph-data-source';\nimport { NzGraph } from './graph';\nimport { NzGraphDefsComponent } from './graph-defs.component';\nimport { NzGraphEdgeComponent } from './graph-edge.component';\nimport { NzGraphEdgeDirective } from './graph-edge.directive';\nimport { NzGraphGroupNodeDirective } from './graph-group-node.directive';\nimport { NzGraphNodeComponent } from './graph-node.component';\nimport { NzGraphNodeDirective } from './graph-node.directive';\nimport { NzGraphZoomDirective } from './graph-zoom.directive';\nimport {\n  NZ_GRAPH_LAYOUT_SETTING,\n  NzGraphDataDef,\n  NzGraphEdge,\n  NzGraphEdgeDef,\n  NzGraphGroupNode,\n  NzGraphLayoutConfig,\n  NzGraphNode,\n  NzGraphNodeDef,\n  NzGraphOption,\n  NzLayoutSetting,\n  NzRankDirection,\n  nzTypeDefinition\n} from './interface';\n\n/** Checks whether an object is a data source. */\nfunction isDataSource(value: NzSafeAny): value is NzGraphData {\n  // Check if the value is a DataSource by observing if it has a connect function. Cannot\n  // be checked as an `instanceof DataSource` since people could create their own sources\n  // that match the interface, but don't extend DataSource.\n  return value && typeof value.connect === 'function';\n}\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-graph',\n  exportAs: 'nzGraph',\n  providers: [{ provide: NzGraph, useExisting: forwardRef(() => NzGraphComponent) }],\n  template: `\n    <ng-content />\n    <svg width=\"100%\" height=\"100%\">\n      <svg:defs nz-graph-defs />\n      <svg:g [attr.transform]=\"transformStyle\">\n        <ng-container\n          [ngTemplateOutlet]=\"groupTemplate\"\n          [ngTemplateOutletContext]=\"{ renderNode: renderInfo, type: 'root' }\"\n        />\n      </svg:g>\n    </svg>\n\n    <ng-template #groupTemplate let-renderNode=\"renderNode\" let-type=\"type\">\n      <svg:g [attr.transform]=\"type === 'sub' ? subGraphTransform(renderNode) : null\">\n        <svg:g class=\"core\" [attr.transform]=\"coreTransform(renderNode)\">\n          <svg:g class=\"nz-graph-edges\">\n            @for (edge of asNzGraphEdges(renderNode.edges); track edgeTrackByFun(edge)) {\n              <g\n                class=\"nz-graph-edge\"\n                nz-graph-edge\n                [edge]=\"edge\"\n                [edgeType]=\"nzGraphLayoutConfig?.defaultEdge?.type\"\n                [customTemplate]=\"customGraphEdgeTemplate\"\n              />\n            }\n          </svg:g>\n\n          <svg:g class=\"nz-graph-nodes\">\n            @for (node of typedNodes(renderNode.nodes); track node.name) {\n              @if (node.type === 1) {\n                <g class=\"nz-graph-node\" nz-graph-node [node]=\"node\" [customTemplate]=\"nodeTemplate\" />\n              }\n\n              @if (node.type === 0) {\n                <g class=\"nz-graph-node\" nz-graph-node [node]=\"node\" [customTemplate]=\"groupNodeTemplate\" />\n              }\n\n              @if (node.expanded) {\n                <ng-container\n                  [ngTemplateOutlet]=\"groupTemplate\"\n                  [ngTemplateOutletContext]=\"{ renderNode: node, type: 'sub' }\"\n                />\n              }\n            }\n          </svg:g>\n        </svg:g>\n      </svg:g>\n    </ng-template>\n  `,\n  host: {\n    class: 'nz-graph',\n    '[class.nz-graph-auto-size]': 'nzAutoSize'\n  },\n  imports: [NgTemplateOutlet, NzGraphEdgeComponent, NzGraphNodeComponent, NzGraphDefsComponent]\n})\nexport class NzGraphComponent implements OnInit, OnChanges, AfterContentChecked, NzGraph {\n  private readonly cdr = inject(ChangeDetectorRef);\n  private readonly elementRef = inject(ElementRef);\n  private readonly platformId = inject(PLATFORM_ID);\n  private readonly destroyRef = inject(DestroyRef);\n  private readonly noAnimation = inject(NzNoAnimationDirective, { host: true, optional: true });\n  private readonly nzGraphZoom = inject(NzGraphZoomDirective, { optional: true });\n\n  @ViewChildren(NzGraphNodeComponent, { read: ElementRef }) listOfNodeElement!: QueryList<ElementRef>;\n  @ViewChildren(NzGraphNodeComponent) listOfNodeComponent!: QueryList<NzGraphNodeComponent>;\n\n  @ContentChild(NzGraphNodeDirective, { static: true, read: TemplateRef }) nodeTemplate?: TemplateRef<{\n    $implicit: NzGraphNode;\n  }>;\n  @ContentChild(NzGraphGroupNodeDirective, { static: true, read: TemplateRef }) groupNodeTemplate?: TemplateRef<{\n    $implicit: NzGraphGroupNode;\n  }>;\n  @ContentChild(NzGraphEdgeDirective, { static: true, read: TemplateRef }) customGraphEdgeTemplate?: TemplateRef<{\n    $implicit: NzGraphEdge;\n  }>;\n  /**\n   * Provides a stream containing the latest data array to render.\n   * Data source can be an observable of NzGraphData, or a NzGraphData to render.\n   */\n  @Input() nzGraphData!: NzGraphData;\n  @Input() nzRankDirection: NzRankDirection = 'LR';\n  @Input() nzGraphLayoutConfig?: NzGraphLayoutConfig;\n  @Input({ transform: booleanAttribute }) nzAutoSize = false;\n\n  @Output() readonly nzGraphInitialized = new EventEmitter<NzGraphComponent>();\n  @Output() readonly nzGraphRendered = new EventEmitter<NzGraphComponent>();\n  @Output() readonly nzNodeClick = new EventEmitter<NzGraphNode | NzGraphGroupNode>();\n\n  private requestId: number = -1;\n  transformStyle = '';\n  graphRenderedSubject$ = new ReplaySubject<void>(1);\n  renderInfo: NzGraphGroupNode = { labelHeight: 0 } as NzGraphGroupNode;\n  mapOfNodeAttr: Record<string, NzGraphNodeDef> = {};\n  mapOfEdgeAttr: Record<string, NzGraphEdgeDef> = {};\n  zoom = 1;\n\n  private dataSource?: NzGraphData;\n  private layoutSetting: NzLayoutSetting = NZ_GRAPH_LAYOUT_SETTING;\n  private _dataSubscription?: Subscription | null;\n\n  // type guards\n  protected readonly typedNodes = nzTypeDefinition<Array<NzGraphNode | NzGraphGroupNode>>();\n  protected readonly asNzGraphEdges = (data: unknown): NzGraphEdge[] => data as NzGraphEdge[];\n\n  protected readonly edgeTrackByFun = (edge: NzGraphEdge): string => `${edge.v}-${edge.w}`;\n  protected readonly subGraphTransform = (node: NzGraphGroupNode): string => {\n    const x = node.x - node.coreBox.width / 2.0;\n    const y = node.y - node.height / 2.0 + node.paddingTop;\n    return `translate(${x}, ${y})`;\n  };\n  protected readonly coreTransform = (node: NzGraphGroupNode): string =>\n    `translate(0, ${node.parentNodeName ? node.labelHeight : 0})`;\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      if (this.dataSource && typeof this.dataSource.disconnect === 'function') {\n        this.dataSource.disconnect();\n      }\n\n      if (this._dataSubscription) {\n        this._dataSubscription.unsubscribe();\n        this._dataSubscription = null;\n      }\n      cancelAnimationFrame(this.requestId);\n    });\n  }\n\n  ngOnInit(): void {\n    this.graphRenderedSubject$.pipe(take(1), takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      // Only zooming is not set, move graph to center\n      if (!this.nzGraphZoom) {\n        this.fitCenter();\n      }\n      this.nzGraphInitialized.emit(this);\n    });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzAutoFit, nzRankDirection, nzGraphData, nzGraphLayoutConfig } = changes;\n    if (nzGraphLayoutConfig) {\n      this.layoutSetting = this.mergeConfig(nzGraphLayoutConfig.currentValue);\n    }\n\n    if (nzGraphData) {\n      if (this.dataSource !== this.nzGraphData) {\n        this._switchDataSource(this.nzGraphData);\n      }\n    }\n\n    if ((nzAutoFit && !nzAutoFit.firstChange) || (nzRankDirection && !nzRankDirection.firstChange)) {\n      // Render graph\n      if (this.dataSource!.dataSource) {\n        this.drawGraph(this.dataSource!.dataSource, {\n          rankDirection: this.nzRankDirection,\n          expanded: this.dataSource!.expansionModel.selected || []\n        }).then(() => {\n          this.cdr.markForCheck();\n        });\n      }\n    }\n\n    this.cdr.markForCheck();\n  }\n\n  ngAfterContentChecked(): void {\n    if (this.dataSource && !this._dataSubscription) {\n      this.observeRenderChanges();\n    }\n  }\n\n  /**\n   * Move graph to center and scale automatically\n   */\n  fitCenter(): void {\n    const { x, y, k } = calculateTransform(\n      this.elementRef.nativeElement.querySelector('svg'),\n      this.elementRef.nativeElement.querySelector('svg > g')\n    )!;\n    if (k) {\n      this.zoom = k;\n      this.transformStyle = `translate(${x}, ${y})scale(${k})`;\n    }\n    this.cdr.markForCheck();\n  }\n\n  /**\n   * re-Draw graph\n   *\n   * @param data\n   * @param options\n   * @param needResize\n   */\n  drawGraph(data: NzGraphDataDef, options: NzGraphOption, needResize: boolean = false): Promise<void> {\n    if (!isPlatformBrowser(this.platformId)) {\n      return Promise.resolve();\n    }\n\n    const animationEnabled = !this.noAnimation?.nzNoAnimation?.();\n\n    return new Promise(resolve => {\n      this.requestId = requestAnimationFrame(() => {\n        // TODO: Need better performance\n        this.renderInfo = this.buildGraphInfo(data, options);\n        this.cdr.markForCheck();\n        this.requestId = requestAnimationFrame(async () => {\n          await this.drawNodes(animationEnabled);\n          // Update element\n          this.cdr.markForCheck();\n\n          if (needResize) {\n            await this.resizeNodeSize();\n            await this.drawGraph(this.dataSource!.dataSource!, options, false);\n          } else {\n            this.graphRenderedSubject$.next();\n            this.nzGraphRendered.emit(this);\n          }\n\n          resolve();\n        });\n      });\n    });\n  }\n\n  /**\n   * Redraw all nodes\n   *\n   * @param animate\n   */\n  async drawNodes(animate: boolean = true): Promise<void> {\n    if (animate) {\n      return this.makeNodesAnimation();\n    }\n\n    this.listOfNodeComponent.forEach(node => node.makeNoAnimation());\n  }\n\n  private resizeNodeSize(): Promise<void> {\n    return new Promise(resolve => {\n      const dataSource: NzGraphDataDef = this.dataSource!.dataSource!;\n      let scale = this.nzGraphZoom?.nzZoom || this.zoom || 1;\n      this.listOfNodeElement.forEach(nodeEle => {\n        const contentEle = nodeEle.nativeElement;\n        if (contentEle) {\n          let width: number;\n          let height: number;\n          // Check if foreignObject is set\n          const clientRect = contentEle.querySelector('foreignObject > :first-child')?.getBoundingClientRect();\n          if (clientRect) {\n            width = clientRect.width;\n            height = clientRect.height;\n          } else {\n            const bBoxRect = contentEle.getBBox();\n            width = bBoxRect.width;\n            height = bBoxRect.height;\n            // getBBox will return actual value\n            scale = 1;\n          }\n          // Element id type is string\n          const node = dataSource.nodes.find(n => `${n.id}` === nodeEle.nativeElement.id);\n          if (node && width && height) {\n            node.height = height / scale;\n            node.width = width / scale;\n          }\n        }\n      });\n      resolve();\n    });\n  }\n\n  /**\n   * Switch to the provided data source by resetting the data and unsubscribing from the current\n   * render change subscription if one exists. If the data source is null, interpret this by\n   * clearing the node outlet. Otherwise, start listening for new data.\n   */\n  private _switchDataSource(dataSource: NzGraphData): void {\n    if (this.dataSource && typeof this.dataSource.disconnect === 'function') {\n      this.nzGraphData.disconnect();\n    }\n\n    if (this._dataSubscription) {\n      this._dataSubscription.unsubscribe();\n      this._dataSubscription = null;\n    }\n\n    this.dataSource = dataSource;\n    this.observeRenderChanges();\n  }\n\n  /** Set up a subscription for the data provided by the data source. */\n  private observeRenderChanges(): void {\n    let dataStream: Observable<NzGraphDataDef> | undefined;\n    let graphOptions: NzGraphOption = {\n      rankDirection: this.nzRankDirection\n    };\n    if (isDataSource(this.dataSource)) {\n      dataStream = this.dataSource.connect();\n    }\n\n    if (dataStream) {\n      this._dataSubscription = dataStream.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(data => {\n        graphOptions = {\n          rankDirection: this.nzRankDirection,\n          expanded: this.nzGraphData.expansionModel.selected\n        };\n        this.drawGraph(data, graphOptions, this.nzAutoSize).then(() => {\n          this.cdr.detectChanges();\n        });\n      });\n    } else {\n      throw Error(`A valid data source must be provided.`);\n    }\n  }\n\n  /**\n   * Get renderInfo and prepare some data\n   *\n   * @param data\n   * @param options\n   * @private\n   */\n  private buildGraphInfo(data: NzGraphDataDef, options: NzGraphOption): NzGraphGroupNode {\n    this.parseInfo(data);\n    const renderInfo = buildGraph(data, options, this.layoutSetting) as NzGraphGroupNode;\n    const dig = (nodes: Array<NzGraphNode | NzGraphGroupNode>): void => {\n      nodes.forEach(node => {\n        const { x, y } = node;\n        node.xOffset = x;\n        node.yOffset = y;\n        if (node.type === 1 && this.mapOfNodeAttr.hasOwnProperty(node.name)) {\n          Object.assign(node, this.mapOfNodeAttr[node.name]);\n        } else if (node.type === 0) {\n          (node as NzGraphGroupNode).edges.forEach(edge => {\n            if (this.mapOfEdgeAttr.hasOwnProperty(`${edge.v}-${edge.w}`)) {\n              Object.assign(edge, this.mapOfEdgeAttr[`${edge.v}-${edge.w}`]);\n            }\n          });\n          dig(node.nodes);\n        }\n      });\n    };\n    dig(renderInfo.nodes);\n    // Assign data to edges of root graph\n    renderInfo.edges.forEach(edge => {\n      if (this.mapOfEdgeAttr.hasOwnProperty(`${edge.v}-${edge.w}`)) {\n        Object.assign(edge, this.mapOfEdgeAttr[`${edge.v}-${edge.w}`]);\n      }\n    });\n    return renderInfo;\n  }\n\n  /**\n   * Play with animation\n   */\n  private async makeNodesAnimation(): Promise<void> {\n    await Promise.all(this.listOfNodeComponent.map(node => node.makeAnimation()));\n  }\n\n  private parseInfo(data: NzGraphDataDef): void {\n    data.nodes.forEach(n => {\n      this.mapOfNodeAttr[n.id] = n;\n    });\n    data.edges.forEach(e => {\n      this.mapOfEdgeAttr[`${e.v}-${e.w}`] = e;\n    });\n  }\n\n  /**\n   * Merge config with user inputs\n   *\n   * @param config\n   * @private\n   */\n  private mergeConfig(config: NzGraphLayoutConfig): NzLayoutSetting {\n    const graphMeta = config?.layout || {};\n    const subSceneMeta = config?.subScene || {};\n    const defaultNodeMeta = config?.defaultNode || {};\n    const defaultCompoundNodeMeta = config?.defaultCompoundNode || {};\n    const bridge = NZ_GRAPH_LAYOUT_SETTING.nodeSize.bridge;\n\n    const graph: NzLayoutSetting['graph'] = { meta: { ...NZ_GRAPH_LAYOUT_SETTING.graph.meta, ...graphMeta } };\n    const subScene: NzLayoutSetting['subScene'] = {\n      meta: { ...NZ_GRAPH_LAYOUT_SETTING.subScene.meta, ...subSceneMeta }\n    };\n    const nodeSize: NzLayoutSetting['nodeSize'] = {\n      meta: { ...NZ_GRAPH_LAYOUT_SETTING.nodeSize.meta, ...defaultCompoundNodeMeta },\n      node: { ...NZ_GRAPH_LAYOUT_SETTING.nodeSize.node, ...defaultNodeMeta },\n      bridge\n    };\n\n    return { graph, subScene, nodeSize };\n  }\n}\n"
  },
  {
    "path": "components/graph/graph.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzGraphDefsComponent } from './graph-defs.component';\nimport { NzGraphEdgeComponent } from './graph-edge.component';\nimport { NzGraphEdgeDirective } from './graph-edge.directive';\nimport { NzGraphGroupNodeDirective } from './graph-group-node.directive';\nimport { NzGraphMinimapComponent } from './graph-minimap.component';\nimport { NzGraphNodeComponent } from './graph-node.component';\nimport { NzGraphNodeDirective } from './graph-node.directive';\nimport { NzGraphZoomDirective } from './graph-zoom.directive';\nimport { NzGraphComponent } from './graph.component';\n\n@NgModule({\n  imports: [\n    NzGraphComponent,\n    NzGraphMinimapComponent,\n    NzGraphDefsComponent,\n    NzGraphNodeDirective,\n    NzGraphGroupNodeDirective,\n    NzGraphZoomDirective,\n    NzGraphNodeComponent,\n    NzGraphEdgeComponent,\n    NzGraphEdgeDirective\n  ],\n  exports: [\n    NzGraphComponent,\n    NzGraphMinimapComponent,\n    NzGraphDefsComponent,\n    NzGraphNodeDirective,\n    NzGraphGroupNodeDirective,\n    NzGraphZoomDirective,\n    NzGraphNodeComponent,\n    NzGraphEdgeComponent,\n    NzGraphEdgeDirective\n  ]\n})\nexport class NzGraphModule {}\n"
  },
  {
    "path": "components/graph/graph.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { EventEmitter } from '@angular/core';\n\nimport { NzGraphGroupNode, NzGraphNode } from './interface';\n\n/**\n * https://angular.io/errors/NG3003\n * An intermediate interface for {@link NzGraphComponent} & {@link NzGraphNodeComponent}\n */\nexport abstract class NzGraph {\n  abstract nzNodeClick: EventEmitter<NzGraphNode | NzGraphGroupNode>;\n}\n"
  },
  {
    "path": "components/graph/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/graph/interface.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  HierarchyBaseEdgeInfo,\n  HierarchyBaseNodeInfo,\n  HierarchyGraphDef,\n  HierarchyGraphEdgeDef,\n  HierarchyGraphNodeDef,\n  HierarchyGraphNodeInfo,\n  HierarchyGraphOption,\n  LayoutConfig\n} from 'dagre-compound';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nexport enum NzGraphEdgeType {\n  LINE = 'line',\n  CURVE = 'curve'\n}\n\nexport interface NzGraphDataDef extends HierarchyGraphDef {\n  nodes: NzGraphNodeDef[];\n  edges: NzGraphEdgeDef[];\n}\n\nexport interface NzGraphNodeDef extends HierarchyGraphNodeDef {\n  label?: string;\n}\n\nexport interface NzGraphEdgeDef extends HierarchyGraphEdgeDef {\n  label?: string;\n}\n\nexport interface NzGraphOption extends HierarchyGraphOption {}\nexport declare type NzRankDirection = 'TB' | 'BT' | 'LR' | 'RL';\n\nexport interface NzGraphGroupNode extends HierarchyGraphNodeInfo {\n  nodes: Array<NzGraphNode | NzGraphGroupNode>;\n  edges: NzGraphEdge[];\n  [key: string]: NzSafeAny;\n}\n\nexport interface NzGraphNode extends HierarchyBaseNodeInfo {\n  id: NzSafeAny;\n  // TODO\n  name: NzSafeAny;\n  label?: string;\n  [key: string]: NzSafeAny;\n}\n\nexport interface NzGraphEdge extends HierarchyBaseEdgeInfo {\n  id: NzSafeAny;\n  v: NzSafeAny;\n  w: NzSafeAny;\n  label?: string;\n}\n\nexport interface NzLayoutSetting extends LayoutConfig {}\n\nexport interface NzGraphBaseLayout {\n  layout: {\n    nodeSep: number;\n    rankSep: number;\n    edgeSep: number;\n  };\n  subScene: {\n    paddingTop: number;\n    paddingBottom: number;\n    paddingLeft: number;\n    paddingRight: number;\n    labelHeight: number;\n  };\n  defaultCompoundNode: {\n    width: number;\n    height: number;\n    maxLabelWidth: number;\n  };\n  defaultNode: {\n    width: number;\n    height: number;\n    labelOffset: number;\n    maxLabelWidth: number;\n  };\n  defaultEdge: {\n    type: NzGraphEdgeType | string; // Need to support extensions\n  };\n}\n\nexport function nzTypeDefinition<T>(): (item: unknown) => T {\n  return item => item as T;\n}\n\nexport type NzDeepPartial<T> = {\n  [P in keyof T]?: T[P] extends Array<infer U>\n    ? Array<NzDeepPartial<U>>\n    : T[P] extends ReadonlyArray<infer U>\n      ? ReadonlyArray<NzDeepPartial<U>>\n      : NzDeepPartial<T[P]>;\n};\n\nexport type NzGraphLayoutConfig = NzDeepPartial<NzGraphBaseLayout>;\nexport const NZ_GRAPH_LAYOUT_SETTING: NzLayoutSetting = {\n  graph: {\n    meta: {\n      nodeSep: 50,\n      rankSep: 50,\n      edgeSep: 5\n    }\n  },\n  subScene: {\n    meta: {\n      paddingTop: 20,\n      paddingBottom: 20,\n      paddingLeft: 20,\n      paddingRight: 20,\n      labelHeight: 20\n    }\n  },\n  nodeSize: {\n    meta: {\n      width: 50,\n      maxLabelWidth: 0,\n      height: 50\n    },\n    node: {\n      width: 50,\n      height: 50,\n      labelOffset: 10,\n      maxLabelWidth: 40\n    },\n    bridge: {\n      width: 5,\n      height: 5,\n      radius: 2,\n      labelOffset: 0\n    }\n  }\n};\n\n// Zoom interface\n\nexport interface NzZoomTransform {\n  x: number;\n  y: number;\n  k: number;\n}\n\nexport interface RelativePositionInfo {\n  topLeft: { x: number; y: number };\n  bottomRight: { x: number; y: number };\n}\n"
  },
  {
    "path": "components/graph/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/graph/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './interface';\nexport * from './data-source/base-graph-source';\nexport * from './data-source/graph-data-source';\nexport * from './graph.module';\nexport * from './graph.component';\nexport * from './graph-node.directive';\nexport * from './graph-group-node.directive';\nexport * from './graph-zoom.directive';\nexport * from './graph-node.component';\nexport * from './graph-edge.component';\nexport * from './graph-edge.directive';\nexport * from './graph-minimap.component';\nexport * from './graph-defs.component';\n"
  },
  {
    "path": "components/graph/style/entry.less",
    "content": "@import './index.less';\n"
  },
  {
    "path": "components/graph/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@graph-stroke-color: @primary-3;\n@graph-focused-color: @primary-color;\n@graph-stroke-width-base: 1px;\n\n@graph-node-background-color: @primary-1;\n\n@graph-prefix-cls: ~'nz-graph';\n\n.@{graph-prefix-cls} {\n  position: relative;\n  display: block;\n  width: 100%;\n  height: 100%;\n  background-color: @component-background;\n\n  &-nodes {\n    .@{graph-prefix-cls}-node {\n      &-rect {\n        fill: transparent;\n        stroke: @graph-stroke-color;\n        stroke-width: @graph-stroke-width-base;\n\n        &:hover {\n          stroke: @graph-focused-color;\n        }\n      }\n    }\n  }\n\n  &-edges {\n    .@{graph-prefix-cls}-edge {\n      path {\n        fill: none;\n        stroke: @graph-stroke-color;\n        stroke-linecap: butt;\n        stroke-width: @graph-stroke-width-base;\n\n        &:hover {\n          stroke: @graph-focused-color;\n        }\n      }\n\n      &-text {\n        font-size: @font-size-sm;\n        fill: fade(@text-color, 85%);\n      }\n    }\n  }\n\n  &-edge-marker {\n    color: @graph-stroke-color;\n    fill: @graph-stroke-color;\n  }\n\n  &-minimap {\n    position: absolute;\n    right: 0;\n    bottom: 0;\n    z-index: 99;\n    background-color: @component-background;\n    border: @border-width-base @border-style-base @border-color-base;\n    transition: opacity 0.3s linear;\n    pointer-events: auto;\n\n    &.hidden {\n      opacity: 0;\n      pointer-events: none;\n    }\n\n    canvas {\n      border: 1px solid #999;\n    }\n\n    rect {\n      cursor: move;\n      filter: url('#minimapDropShadow');\n      fill: @component-background;\n      stroke: @text-color-secondary;\n      stroke-width: @border-width-base;\n      fill-opacity: 0;\n    }\n\n    svg {\n      position: absolute;\n      width: 100%;\n      height: 100%;\n    }\n\n    .buffer,\n    .viewport {\n      display: block;\n      height: 100%;\n    }\n  }\n}\n"
  },
  {
    "path": "components/grid/col.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport {\n  DestroyRef,\n  Directive,\n  ElementRef,\n  Input,\n  OnChanges,\n  OnInit,\n  Renderer2,\n  SimpleChanges,\n  inject,\n  type AfterViewInit\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { NgClassInterface } from 'ng-zorro-antd/core/types';\nimport { isNotNil } from 'ng-zorro-antd/core/util';\n\nimport { NzRowDirective } from './row.directive';\n\nexport interface EmbeddedProperty {\n  span?: number;\n  pull?: number;\n  push?: number;\n  offset?: number;\n  order?: number;\n}\n\n@Directive({\n  selector: '[nz-col],nz-col,nz-form-control,nz-form-label',\n  exportAs: 'nzCol',\n  host: {\n    '[style.flex]': 'hostFlexStyle'\n  }\n})\nexport class NzColDirective implements OnInit, OnChanges, AfterViewInit {\n  private elementRef = inject(ElementRef);\n  private renderer = inject(Renderer2);\n  private directionality = inject(Directionality);\n  private destroyRef = inject(DestroyRef);\n  private classMap: Record<string, boolean> = {};\n  hostFlexStyle: string | null = null;\n  dir: Direction = 'ltr';\n  @Input() nzFlex: string | number | null = null;\n  @Input() nzSpan: string | number | null = null;\n  @Input() nzOrder: string | number | null = null;\n  @Input() nzOffset: string | number | null = null;\n  @Input() nzPush: string | number | null = null;\n  @Input() nzPull: string | number | null = null;\n  @Input() nzXs: string | number | EmbeddedProperty | null = null;\n  @Input() nzSm: string | number | EmbeddedProperty | null = null;\n  @Input() nzMd: string | number | EmbeddedProperty | null = null;\n  @Input() nzLg: string | number | EmbeddedProperty | null = null;\n  @Input() nzXl: string | number | EmbeddedProperty | null = null;\n  @Input() nzXXl: string | number | EmbeddedProperty | null = null;\n\n  setHostClassMap(): void {\n    const hostClassMap = {\n      ['ant-col']: true,\n      [`ant-col-${this.nzSpan}`]: isNotNil(this.nzSpan),\n      [`ant-col-order-${this.nzOrder}`]: isNotNil(this.nzOrder),\n      [`ant-col-offset-${this.nzOffset}`]: isNotNil(this.nzOffset),\n      [`ant-col-pull-${this.nzPull}`]: isNotNil(this.nzPull),\n      [`ant-col-push-${this.nzPush}`]: isNotNil(this.nzPush),\n      ['ant-col-rtl']: this.dir === 'rtl',\n      ...this.generateClass()\n    };\n    for (const i in this.classMap) {\n      if (this.classMap.hasOwnProperty(i)) {\n        this.renderer.removeClass(this.elementRef.nativeElement, i);\n      }\n    }\n    this.classMap = { ...hostClassMap };\n    for (const i in this.classMap) {\n      if (this.classMap.hasOwnProperty(i) && this.classMap[i]) {\n        this.renderer.addClass(this.elementRef.nativeElement, i);\n      }\n    }\n  }\n\n  setHostFlexStyle(): void {\n    this.hostFlexStyle = this.parseFlex(this.nzFlex);\n  }\n\n  parseFlex(flex: number | string | null): string | null {\n    if (typeof flex === 'number') {\n      return `${flex} ${flex} auto`;\n    } else if (typeof flex === 'string') {\n      if (/^\\d+(\\.\\d+)?(px|em|rem|%)$/.test(flex)) {\n        return `0 0 ${flex}`;\n      }\n    }\n    return flex;\n  }\n\n  generateClass(): object {\n    const listOfSizeInputName: Array<keyof NzColDirective> = ['nzXs', 'nzSm', 'nzMd', 'nzLg', 'nzXl', 'nzXXl'];\n    const listClassMap: NgClassInterface = {};\n    listOfSizeInputName.forEach(name => {\n      const sizeName = name.replace('nz', '').toLowerCase();\n      if (isNotNil(this[name])) {\n        if (typeof this[name] === 'number' || typeof this[name] === 'string') {\n          listClassMap[`ant-col-${sizeName}-${this[name]}`] = true;\n        } else {\n          const embedded = this[name] as EmbeddedProperty;\n          const prefixArray: Array<keyof EmbeddedProperty> = ['span', 'pull', 'push', 'offset', 'order'];\n          prefixArray.forEach(prefix => {\n            const prefixClass = prefix === 'span' ? '-' : `-${prefix}-`;\n            listClassMap[`ant-col-${sizeName}${prefixClass}${embedded[prefix]}`] =\n              embedded && isNotNil(embedded[prefix]);\n          });\n        }\n      }\n    });\n    return listClassMap;\n  }\n\n  nzRowDirective = inject(NzRowDirective, { host: true, optional: true });\n\n  ngOnInit(): void {\n    this.dir = this.directionality.value;\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n      this.dir = direction;\n      this.setHostClassMap();\n    });\n\n    this.setHostClassMap();\n    this.setHostFlexStyle();\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    this.setHostClassMap();\n    const { nzFlex } = changes;\n    if (nzFlex) {\n      this.setHostFlexStyle();\n    }\n  }\n\n  ngAfterViewInit(): void {\n    if (this.nzRowDirective) {\n      this.nzRowDirective.actualGutter$\n        .pipe(takeUntilDestroyed(this.destroyRef))\n        .subscribe(([horizontalGutter, verticalGutter]) => {\n          const renderGutter = (name: string, gutter: number | null): void => {\n            const nativeElement = this.elementRef.nativeElement;\n            if (gutter !== null) {\n              this.renderer.setStyle(nativeElement, name, `${gutter / 2}px`);\n            }\n          };\n          renderGutter('padding-left', horizontalGutter);\n          renderGutter('padding-right', horizontalGutter);\n          renderGutter('padding-top', verticalGutter);\n          renderGutter('padding-bottom', verticalGutter);\n        });\n    }\n  }\n}\n"
  },
  {
    "path": "components/grid/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基础栅格\n  en-US: Basic Grid\n---\n\n## zh-CN\n\n从堆叠到水平排列。\n\n使用单一的一组 `nz-row` 和 `nz-col` 栅格组件，就可以创建一个基本的栅格系统，所有列（`nz-col`）必须放在 `nz-row` 内。\n\n## en-US\n\nFrom the stack to the horizontal arrangement.\n\nYou can create a basic grid system by using a single set of `nz-row` and `nz-col` grid assembly, all of the columns (`nz-col`) must be placed in `nz-row`.\n"
  },
  {
    "path": "components/grid/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzGridModule } from 'ng-zorro-antd/grid';\n\n@Component({\n  selector: 'nz-demo-grid-basic',\n  imports: [NzGridModule],\n  template: `\n    <div nz-row>\n      <div nz-col nzSpan=\"12\">col-12</div>\n      <div nz-col nzSpan=\"12\">col-12</div>\n    </div>\n    <div nz-row>\n      <div nz-col nzSpan=\"8\">col-8</div>\n      <div nz-col nzSpan=\"8\">col-8</div>\n      <div nz-col nzSpan=\"8\">col-8</div>\n    </div>\n    <div nz-row>\n      <div nz-col nzSpan=\"6\">col-6</div>\n      <div nz-col nzSpan=\"6\">col-6</div>\n      <div nz-col nzSpan=\"6\">col-6</div>\n      <div nz-col nzSpan=\"6\">col-6</div>\n    </div>\n  `\n})\nexport class NzDemoGridBasicComponent {}\n"
  },
  {
    "path": "components/grid/demo/flex-align.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 对齐\n  en-US: Alignment\n---\n\n## zh-CN\n\n子元素垂直对齐。\n\n## en-US\n\nChild elements vertically aligned.\n"
  },
  {
    "path": "components/grid/demo/flex-align.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzGridModule } from 'ng-zorro-antd/grid';\n\n@Component({\n  selector: 'nz-demo-grid-flex-align',\n  imports: [NzGridModule],\n  template: `\n    <div>\n      <p>Align Top</p>\n      <div nz-row nzJustify=\"center\" nzAlign=\"top\">\n        <div nz-col nzSpan=\"4\"><p class=\"height-100\">col-4</p></div>\n        <div nz-col nzSpan=\"4\"><p class=\"height-50\">col-4</p></div>\n        <div nz-col nzSpan=\"4\"><p class=\"height-120\">col-4</p></div>\n        <div nz-col nzSpan=\"4\"><p class=\"height-80\">col-4</p></div>\n      </div>\n      <p>Align Center</p>\n      <div nz-row nzJustify=\"space-around\" nzAlign=\"middle\">\n        <div nz-col nzSpan=\"4\"><p class=\"height-100\">col-4</p></div>\n        <div nz-col nzSpan=\"4\"><p class=\"height-50\">col-4</p></div>\n        <div nz-col nzSpan=\"4\"><p class=\"height-120\">col-4</p></div>\n        <div nz-col nzSpan=\"4\"><p class=\"height-80\">col-4</p></div>\n      </div>\n      <p>Align Bottom</p>\n      <div nz-row nzJustify=\"space-between\" nzAlign=\"bottom\">\n        <div nz-col nzSpan=\"4\"><p class=\"height-100\">col-4</p></div>\n        <div nz-col nzSpan=\"4\"><p class=\"height-50\">col-4</p></div>\n        <div nz-col nzSpan=\"4\"><p class=\"height-120\">col-4</p></div>\n        <div nz-col nzSpan=\"4\"><p class=\"height-80\">col-4</p></div>\n      </div>\n    </div>\n  `,\n  styles: `\n    [nz-row] {\n      background-color: rgba(128, 128, 128, 0.08);\n    }\n  `\n})\nexport class NzDemoGridFlexAlignComponent {}\n"
  },
  {
    "path": "components/grid/demo/flex-order.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 排序\n  en-US: Order\n---\n\n## zh-CN\n\n通过 `nzOrder` 来改变元素的排序。\n\n## en-US\n\nTo change the element sort by `nzOrder`.\n"
  },
  {
    "path": "components/grid/demo/flex-order.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzGridModule } from 'ng-zorro-antd/grid';\n\n@Component({\n  selector: 'nz-demo-grid-flex-order',\n  imports: [NzGridModule],\n  template: `\n    <div>\n      <div nz-row>\n        <div nz-col nzSpan=\"6\" nzOrder=\"4\">1 col-order-4</div>\n        <div nz-col nzSpan=\"6\" nzOrder=\"3\">2 col-order-3</div>\n        <div nz-col nzSpan=\"6\" nzOrder=\"2\">3 col-order-2</div>\n        <div nz-col nzSpan=\"6\" nzOrder=\"1\">4 col-order-1</div>\n      </div>\n    </div>\n  `,\n  styles: `\n    [nz-row] {\n      background-color: rgba(128, 128, 128, 0.08);\n    }\n  `\n})\nexport class NzDemoGridFlexOrderComponent {}\n"
  },
  {
    "path": "components/grid/demo/flex-stretch.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: Flex 填充\n  en-US: Flex Stretch\n---\n\n## zh-CN\n\n`nz-col` 提供 `nzFlex` 属性以支持填充。\n\n## en-US\n\n`nz-col` provides `nzFlex` prop to support fill rest.\n"
  },
  {
    "path": "components/grid/demo/flex-stretch.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzGridModule } from 'ng-zorro-antd/grid';\n\n@Component({\n  selector: 'nz-demo-grid-flex-stretch',\n  imports: [NzGridModule],\n  template: `\n    <div>\n      <p>Percentage columns</p>\n      <div nz-row>\n        <div nz-col nzFlex=\"2\">2 / 5</div>\n        <div nz-col nzFlex=\"3\">3 / 5</div>\n      </div>\n      <p>Fill rest</p>\n      <div nz-row>\n        <div nz-col nzFlex=\"100px\">100px</div>\n        <div nz-col nzFlex=\"auto\">Fill Rest</div>\n      </div>\n      <p>Raw flex style</p>\n      <div nz-row>\n        <div nz-col nzFlex=\"1 1 200px\">1 1 200px</div>\n        <div nz-col nzFlex=\"0 1 300px\">0 1 300px</div>\n      </div>\n    </div>\n  `,\n  styles: `\n    [nz-row] {\n      background-color: rgba(128, 128, 128, 0.08);\n    }\n  `\n})\nexport class NzDemoGridFlexStretchComponent {}\n"
  },
  {
    "path": "components/grid/demo/flex.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 排版\n  en-US: Layout\n---\n\n## zh-CN\n\n布局基础。\n\n子元素根据不同的值 `start`、`center`、`end`、`space-between`、`space-around` 和 `space-evenly`，分别定义其在父节点里面的排版方式。\n\n## en-US\n\nChild elements depending on the value of the `start`,` center`, `end`,` space-between`, `space-around`, `space-evenly`, which are defined in its parent node layout mode.\n"
  },
  {
    "path": "components/grid/demo/flex.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzGridModule } from 'ng-zorro-antd/grid';\n\n@Component({\n  selector: 'nz-demo-grid-flex',\n  imports: [NzGridModule],\n  template: `\n    <div>\n      <p>sub-element align left</p>\n      <div nz-row nzJustify=\"start\">\n        <div nz-col nzSpan=\"4\">col-4</div>\n        <div nz-col nzSpan=\"4\">col-4</div>\n        <div nz-col nzSpan=\"4\">col-4</div>\n        <div nz-col nzSpan=\"4\">col-4</div>\n      </div>\n      <p>sub-element align center</p>\n      <div nz-row nzJustify=\"center\">\n        <div nz-col nzSpan=\"4\">col-4</div>\n        <div nz-col nzSpan=\"4\">col-4</div>\n        <div nz-col nzSpan=\"4\">col-4</div>\n        <div nz-col nzSpan=\"4\">col-4</div>\n      </div>\n      <p>sub-element align right</p>\n      <div nz-row nzJustify=\"end\">\n        <div nz-col nzSpan=\"4\">col-4</div>\n        <div nz-col nzSpan=\"4\">col-4</div>\n        <div nz-col nzSpan=\"4\">col-4</div>\n        <div nz-col nzSpan=\"4\">col-4</div>\n      </div>\n      <p>sub-element monospaced arrangement</p>\n      <div nz-row nzJustify=\"space-between\">\n        <div nz-col nzSpan=\"4\">col-4</div>\n        <div nz-col nzSpan=\"4\">col-4</div>\n        <div nz-col nzSpan=\"4\">col-4</div>\n        <div nz-col nzSpan=\"4\">col-4</div>\n      </div>\n      <p>sub-element align full</p>\n      <div nz-row nzJustify=\"space-around\">\n        <div nz-col nzSpan=\"4\">col-4</div>\n        <div nz-col nzSpan=\"4\">col-4</div>\n        <div nz-col nzSpan=\"4\">col-4</div>\n        <div nz-col nzSpan=\"4\">col-4</div>\n      </div>\n      <p>sub-element align evenly</p>\n      <div nz-row nzJustify=\"space-evenly\">\n        <div nz-col nzSpan=\"4\">col-4</div>\n        <div nz-col nzSpan=\"4\">col-4</div>\n        <div nz-col nzSpan=\"4\">col-4</div>\n        <div nz-col nzSpan=\"4\">col-4</div>\n      </div>\n    </div>\n  `,\n  styles: `\n    [nz-row] {\n      background-color: rgba(128, 128, 128, 0.08);\n    }\n  `\n})\nexport class NzDemoGridFlexComponent {}\n"
  },
  {
    "path": "components/grid/demo/gutter.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 区块间隔\n  en-US: Grid Gutter\n---\n\n## zh-CN\n\n栅格常常需要和间隔进行配合，你可以使用 `nz-row` 的 `nzGutter` 属性，我们推荐使用 `(16+8n)px` 作为栅格间隔。(n 是自然数)\n\n如果要支持响应式，可以写成 `{ xs: 8, sm: 16, md: 24, lg: 32, xl: 32, xxl: 32 }`。\n\n## en-US\n\nYou can use the `nzGutter` property of `nzRow` as grid spacing, we recommend set it to `(16 + 8n) px`. (`n` stands for natural number.)\n\nYou can set it to a object like `{ xs: 8, sm: 16, md: 24, lg: 32, xl: 32, xxl: 32 }` for responsive design.\n"
  },
  {
    "path": "components/grid/demo/gutter.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\nimport { NzGridModule } from 'ng-zorro-antd/grid';\n\n@Component({\n  selector: 'nz-demo-grid-gutter',\n  imports: [NzDividerModule, NzGridModule],\n  template: `\n    <nz-divider nzOrientation=\"left\" nzText=\"Horizontal\" />\n    <div nz-row [nzGutter]=\"16\">\n      <div nz-col class=\"gutter-row\" [nzSpan]=\"6\"><div class=\"inner-box\">col-6</div></div>\n      <div nz-col class=\"gutter-row\" [nzSpan]=\"6\"><div class=\"inner-box\">col-6</div></div>\n      <div nz-col class=\"gutter-row\" [nzSpan]=\"6\"><div class=\"inner-box\">col-6</div></div>\n      <div nz-col class=\"gutter-row\" [nzSpan]=\"6\"><div class=\"inner-box\">col-6</div></div>\n    </div>\n    <nz-divider nzOrientation=\"left\" nzText=\"Responsive\" />\n    <div nz-row [nzGutter]=\"{ xs: 8, sm: 16, md: 24, lg: 32 }\">\n      <div nz-col class=\"gutter-row\" [nzSpan]=\"6\"><div class=\"inner-box\">col-6</div></div>\n      <div nz-col class=\"gutter-row\" [nzSpan]=\"6\"><div class=\"inner-box\">col-6</div></div>\n      <div nz-col class=\"gutter-row\" [nzSpan]=\"6\"><div class=\"inner-box\">col-6</div></div>\n      <div nz-col class=\"gutter-row\" [nzSpan]=\"6\"><div class=\"inner-box\">col-6</div></div>\n    </div>\n    <nz-divider nzOrientation=\"left\" nzText=\"Vertical\" />\n    <div nz-row [nzGutter]=\"[16, 24]\">\n      <div nz-col class=\"gutter-row\" [nzSpan]=\"6\"><div class=\"inner-box\">col-6</div></div>\n      <div nz-col class=\"gutter-row\" [nzSpan]=\"6\"><div class=\"inner-box\">col-6</div></div>\n      <div nz-col class=\"gutter-row\" [nzSpan]=\"6\"><div class=\"inner-box\">col-6</div></div>\n      <div nz-col class=\"gutter-row\" [nzSpan]=\"6\"><div class=\"inner-box\">col-6</div></div>\n      <div nz-col class=\"gutter-row\" [nzSpan]=\"6\"><div class=\"inner-box\">col-6</div></div>\n      <div nz-col class=\"gutter-row\" [nzSpan]=\"6\"><div class=\"inner-box\">col-6</div></div>\n      <div nz-col class=\"gutter-row\" [nzSpan]=\"6\"><div class=\"inner-box\">col-6</div></div>\n      <div nz-col class=\"gutter-row\" [nzSpan]=\"6\"><div class=\"inner-box\">col-6</div></div>\n    </div>\n  `,\n  styles: `\n    nz-divider {\n      color: #333;\n      font-weight: normal;\n    }\n    .inner-box {\n      background: #0092ff;\n      padding: 8px 0;\n    }\n  `\n})\nexport class NzDemoGridGutterComponent {}\n"
  },
  {
    "path": "components/grid/demo/offset.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 左右偏移\n  en-US: Column offset\n---\n\n## zh-CN\n\n列偏移。\n\n使用 `nzOffset` 可以将列向右侧偏。例如，`nzOffset=\"4\"` 将元素向右侧偏移了 4 个列（column）的宽度。\n\n## en-US\n\n`nzOffset` can set the column to the right side. For example, using `nzOffset = \"4\"` can set the element shifted to the right four columns width.\n"
  },
  {
    "path": "components/grid/demo/offset.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzGridModule } from 'ng-zorro-antd/grid';\n\n@Component({\n  selector: 'nz-demo-grid-offset',\n  imports: [NzGridModule],\n  template: `\n    <div nz-row>\n      <div nz-col nzSpan=\"8\">col-8</div>\n      <div nz-col nzSpan=\"8\" nzOffset=\"8\">col-8</div>\n    </div>\n    <div nz-row>\n      <div nz-col nzSpan=\"6\" nzOffset=\"6\">col-6 col-offset-6</div>\n      <div nz-col nzSpan=\"6\" nzOffset=\"6\">col-6 col-offset-6</div>\n    </div>\n    <div nz-row>\n      <div nz-col nzSpan=\"12\" nzOffset=\"6\">col-12 col-offset-6</div>\n    </div>\n  `\n})\nexport class NzDemoGridOffsetComponent {}\n"
  },
  {
    "path": "components/grid/demo/playground.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 栅格配置器\n  en-US: Playground\n---\n\n## zh-CN\n\n可以简单配置几种等分栅格和间距。\n\n## en-US\n\nA simple playground for column count and gutter.\n"
  },
  {
    "path": "components/grid/demo/playground.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzGridModule } from 'ng-zorro-antd/grid';\nimport { NzMarks, NzSliderModule } from 'ng-zorro-antd/slider';\n\n@Component({\n  selector: 'nz-demo-grid-playground',\n  imports: [FormsModule, NzGridModule, NzSliderModule],\n  template: `\n    <div class=\"slider-container\">\n      <span>Horizontal Gutter (px):</span>\n      <div class=\"slider\">\n        <nz-slider [nzMarks]=\"marksHGutter\" [nzStep]=\"null\" [nzMin]=\"8\" [nzMax]=\"48\" [(ngModel)]=\"hGutter\" />\n      </div>\n      <span>Vertical Gutter (px):</span>\n      <div class=\"slider\">\n        <nz-slider [nzMarks]=\"marksVGutter\" [nzStep]=\"null\" [nzMin]=\"8\" [nzMax]=\"48\" [(ngModel)]=\"vGutter\" />\n      </div>\n      <span>Column Count:</span>\n      <div class=\"slider\">\n        <nz-slider\n          [nzMarks]=\"marksCount\"\n          [nzStep]=\"null\"\n          [nzMin]=\"2\"\n          [nzMax]=\"12\"\n          [(ngModel)]=\"count\"\n          (ngModelChange)=\"reGenerateArray($event)\"\n        />\n      </div>\n    </div>\n\n    <div class=\"gutter-example\">\n      <div nz-row [nzGutter]=\"[hGutter, vGutter]\">\n        @for (i of array; track $index) {\n          <div nz-col class=\"gutter-row\" [nzSpan]=\"24 / count\">\n            <div class=\"grid-config\">Column</div>\n          </div>\n        }\n\n        @for (i of array; track $index) {\n          <div nz-col class=\"gutter-row\" [nzSpan]=\"24 / count\">\n            <div class=\"grid-config\">Column</div>\n          </div>\n        }\n      </div>\n    </div>\n  `,\n  styles: `\n    .slider {\n      width: 50%;\n    }\n    .slider-container {\n      margin-bottom: 16px;\n    }\n    .grid-config {\n      height: 120px;\n      font-size: 14px;\n      line-height: 120px;\n      background: #0092ff;\n      border-radius: 4px;\n    }\n  `\n})\nexport class NzDemoGridPlaygroundComponent {\n  hGutter = 16;\n  vGutter = 16;\n  count = 4;\n  array = new Array(this.count);\n  marksHGutter: NzMarks = {\n    8: '8',\n    16: '16',\n    24: '24',\n    32: '32',\n    40: '40',\n    48: '48'\n  };\n  marksVGutter: NzMarks = {\n    8: '8',\n    16: '16',\n    24: '24',\n    32: '32',\n    40: '40',\n    48: '48'\n  };\n  marksCount: NzMarks = {\n    2: '2',\n    3: '3',\n    4: '4',\n    6: '6',\n    8: '8',\n    12: '12'\n  };\n  reGenerateArray(count: number): void {\n    this.array = new Array(count);\n  }\n}\n"
  },
  {
    "path": "components/grid/demo/responsive-more.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 其他属性的响应式\n  en-US: More responsive\n---\n\n## zh-CN\n\n`span` `pull` `push` `offset` `order` 属性可以通过内嵌到 `nzXs` `nzSm` `nzMd` `nzLg` `nzXl` `nzXXl` 属性中来使用。\n\n其中 `nzXs=\"6\"` 相当于 `[nzXs]=\"{ span: 6 }\"`。\n\n## en-US\n\n`span` `pull` `push` `offset` `order` property can be embedded into `nzXs` `nzSm` `nzMd` `nzLg` `nzXl` `nzXXl` properties to use,\nwhere `nzXs=\"6\"` is equivalent to `[nzXs]=\"{ span: 6 }\"`.\n"
  },
  {
    "path": "components/grid/demo/responsive-more.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzGridModule } from 'ng-zorro-antd/grid';\n\n@Component({\n  selector: 'nz-demo-grid-responsive-more',\n  imports: [NzGridModule],\n  template: `\n    <div nz-row>\n      <div nz-col [nzXs]=\"{ span: 5, offset: 1 }\" [nzLg]=\"{ span: 6, offset: 2 }\">Col</div>\n      <div nz-col [nzXs]=\"{ span: 11, offset: 1 }\" [nzLg]=\"{ span: 6, offset: 2 }\">Col</div>\n      <div nz-col [nzXs]=\"{ span: 5, offset: 1 }\" [nzLg]=\"{ span: 6, offset: 2 }\">Col</div>\n    </div>\n  `\n})\nexport class NzDemoGridResponsiveMoreComponent {}\n"
  },
  {
    "path": "components/grid/demo/responsive.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 响应式布局\n  en-US: Responsive\n---\n\n## zh-CN\n\n参照 Bootstrap 的 [响应式设计](http://getbootstrap.com/css/#grid-media-queries)，预设五个响应尺寸：`xs` `sm` `md` `lg` `xl` `xxl`。\n\n## en-US\n\nReferring to the Bootstrap [responsive design](http://getbootstrap.com/css/#grid-media-queries), here preset five dimensions: `xs` `sm` `md` `lg` `xl`.\n"
  },
  {
    "path": "components/grid/demo/responsive.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzGridModule } from 'ng-zorro-antd/grid';\n\n@Component({\n  selector: 'nz-demo-grid-responsive',\n  imports: [NzGridModule],\n  template: `\n    <div nz-row>\n      <div nz-col nzXs=\"2\" nzSm=\"4\" nzMd=\"6\" nzLg=\"8\" nzXl=\"10\">Col</div>\n      <div nz-col nzXs=\"20\" nzSm=\"16\" nzMd=\"12\" nzLg=\"8\" nzXl=\"4\">Col</div>\n      <div nz-col nzXs=\"2\" nzSm=\"4\" nzMd=\"6\" nzLg=\"8\" nzXl=\"10\">Col</div>\n    </div>\n  `\n})\nexport class NzDemoGridResponsiveComponent {}\n"
  },
  {
    "path": "components/grid/demo/sort.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 栅格排序\n  en-US: Grid sort\n---\n\n## zh-CN\n\n列排序。\n\n通过使用 `nzPush` 和 `nzPull` 类就可以很容易的改变列（column）的顺序。\n\n## en-US\n\nBy using `nzPush` and `nzPull` class you can easily change column order.\n"
  },
  {
    "path": "components/grid/demo/sort.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzGridModule } from 'ng-zorro-antd/grid';\n\n@Component({\n  selector: 'nz-demo-grid-sort',\n  imports: [NzGridModule],\n  template: `\n    <div nz-row>\n      <div nz-col [nzSpan]=\"18\" [nzPush]=\"6\">col-18 col-push-6</div>\n      <div nz-col [nzSpan]=\"6\" [nzPull]=\"18\">col-6 col-pull-18</div>\n    </div>\n  `\n})\nexport class NzDemoGridSortComponent {}\n"
  },
  {
    "path": "components/grid/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Layout\ncols: 1\ntitle: Grid\ncover: 'https://gw.alipayobjects.com/zos/alicdn/5rWLU27so/Grid.svg'\ndescription: 24 Grids System。\n---\n\n## Design concept\n\n<div class=\"grid-demo\">\n<div class=\"ant-row demo-row\">\n  <div class=\"ant-col-24 demo-col demo-col-1\">\n    100%\n  </div>\n</div>\n<div class=\"ant-row demo-row\">\n  <div class=\"ant-col-6 demo-col demo-col-2\">\n    25%\n  </div>\n  <div class=\"ant-col-6 demo-col demo-col-3\">\n    25%\n  </div>\n  <div class=\"ant-col-6 demo-col demo-col-2\">\n    25%\n  </div>\n  <div class=\"ant-col-6 demo-col demo-col-3\">\n    25%\n  </div>\n</div>\n<div class=\"ant-row demo-row\">\n  <div class=\"ant-col-8 demo-col demo-col-4\">\n    33.33%\n  </div>\n  <div class=\"ant-col-8 demo-col demo-col-5\">\n    33.33%\n  </div>\n  <div class=\"ant-col-8 demo-col demo-col-4\">\n    33.33%\n  </div>\n</div>\n<div class=\"ant-row demo-row\">\n  <div class=\"ant-col-12 demo-col demo-col-1\">\n    50%\n  </div>\n  <div class=\"ant-col-12 demo-col demo-col-3\">\n    50%\n  </div>\n</div>\n<div class=\"ant-row demo-row\">\n  <div class=\"ant-col-16 demo-col demo-col-4\">\n    66.66%\n  </div>\n  <div class=\"ant-col-8 demo-col demo-col-5\">\n    33.33%\n  </div>\n</div>\n</div>\n\nIn most business situations, Ant Design needs to solve a lot of information storage problems within the design area, so based on 12 Grids System, we divided the design area into 24 sections.\n\nWe name the divided area 'box'. We suggest four boxes for horizontal arrangement at most, one at least. Boxes are proportional to the entire screen as shown in the picture above. To ensure a high level of visual comfort, we customize the typography inside of the box based on the box unit.\n\n## Outline\n\nIn the grid system, we define the frame outside the information area based on `row` and `column`, to ensure that every area can have stable arrangement.\n\nFollowing is a brief look at how it works:\n\n- Establish a set of `column` in the horizontal space defined by `row` (abbreviated col)\n- Your content elements should be placed directly in the `col`, and only `col` should be placed directly in `row`\n- The column grid system is a value of 1-24 to represent its range spans. For example, three columns of equal width can be created by `<div nz-col [nzSpan]=\"8\" />`.\n- If the sum of `col` spans in a `row` are more than 24, then the overflowing `col` as a whole will start a new line arrangement.\n\nOur grid systems base on Flex layout to allow the elements within the parent to be aligned horizontally - left, center, right, wide arrangement, and decentralized arrangement. The Grid system also supports vertical alignment - top aligned, vertically centered, bottom-aligned. You can also define the order of elements by using `order`.\n\nLayout uses a 24 grid layout to define the width of each \"box\", but does not rigidly adhere to the grid layout.\n\n## API\n\n### [nz-row]\n\n| Property      | Description                                                                                                                                                                                       | Type                                                                 | Default |\n| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | ------- |\n| `[nzAlign]`   | the vertical alignment                                                                                                                                                                            | `'top' \\| 'middle' \\| 'bottom'`                                      | -       |\n| `[nzGutter]`  | spacing between grids, could be a number or a object like `{ xs: 8, sm: 16, md: 24}`. or you can use array to make horizontal and vertical spacing work at the same time `[horizontal, vertical]` | `string \\| number \\| object \\| [number, number] \\| [object, object]` | `0`     |\n| `[nzJustify]` | horizontal arrangement                                                                                                                                                                            | `'start' \\| 'end' \\| 'center' \\| 'space-around' \\| 'space-between'`  | -       |\n\n### [nz-col]\n\n| Property     | Description                                                                                    | Type               | Default |\n| ------------ | ---------------------------------------------------------------------------------------------- | ------------------ | ------- |\n| `[nzFlex]`   | flex layout style                                                                              | `string \\| number` | -       |\n| `[nzOffset]` | the number of cells to offset Col from the left                                                | `number`           | `0`     |\n| `[nzOrder]`  | raster order                                                                                   | `number`           | `0`     |\n| `[nzPull]`   | the number of cells that raster is moved to the left                                           | `number`           | `0`     |\n| `[nzPush]`   | the number of cells that raster is moved to the right                                          | `number`           | `0`     |\n| `[nzSpan]`   | raster number of cells to occupy, 0 corresponds to `display: none`                             | `number`           | -       |\n| `[nzXs]`     | `<576px` and also default setting, could be a `span` value or an object containing above props | `number \\| object` | -       |\n| `[nzSm]`     | `≥576px`, could be a `span` value or an object containing above props                          | `number \\| object` | -       |\n| `[nzMd]`     | `≥768px`, could be a `span` value or an object containing above props                          | `number \\| object` | -       |\n| `[nzLg]`     | `≥992px`, could be a `span` value or an object containing above props                          | `number \\| object` | -       |\n| `[nzXl]`     | `≥1200px`, could be a `span` value or an object containing above props                         | `number \\| object` | -       |\n| `[nzXXl]`    | `≥1600px`, could be a `span` value or an object containing above props                         | `number \\| object` | -       |\n\nThe breakpoints of responsive grid follow [BootStrap 4 media queries rules](https://getbootstrap.com/docs/4.0/layout/overview/#responsive-breakpoints)(not including `occasionally part`).\n"
  },
  {
    "path": "components/grid/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 栅格\ntype: 布局\ncols: 1\ntitle: Grid\ncover: 'https://gw.alipayobjects.com/zos/alicdn/5rWLU27so/Grid.svg'\ndescription: 24 栅格系统。\n---\n\n## 设计理念\n\n<div class=\"grid-demo\">\n<div class=\"ant-row demo-row\">\n  <div class=\"ant-col-24 demo-col demo-col-1\">\n    100%\n  </div>\n</div>\n<div class=\"ant-row demo-row\">\n  <div class=\"ant-col-6 demo-col demo-col-2\">\n    25%\n  </div>\n  <div class=\"ant-col-6 demo-col demo-col-3\">\n    25%\n  </div>\n  <div class=\"ant-col-6 demo-col demo-col-2\">\n    25%\n  </div>\n  <div class=\"ant-col-6 demo-col demo-col-3\">\n    25%\n  </div>\n</div>\n<div class=\"ant-row demo-row\">\n  <div class=\"ant-col-8 demo-col demo-col-4\">\n    33.33%\n  </div>\n  <div class=\"ant-col-8 demo-col demo-col-5\">\n    33.33%\n  </div>\n  <div class=\"ant-col-8 demo-col demo-col-4\">\n    33.33%\n  </div>\n</div>\n<div class=\"ant-row demo-row\">\n  <div class=\"ant-col-12 demo-col demo-col-1\">\n    50%\n  </div>\n  <div class=\"ant-col-12 demo-col demo-col-3\">\n    50%\n  </div>\n</div>\n<div class=\"ant-row demo-row\">\n  <div class=\"ant-col-16 demo-col demo-col-4\">\n    66.66%\n  </div>\n  <div class=\"ant-col-8 demo-col demo-col-5\">\n    33.33%\n  </div>\n</div>\n</div>\n\n在多数业务情况下，Ant Design 需要在设计区域内解决大量信息收纳的问题，因此在 12 栅格系统的基础上，我们将整个设计建议区域按照 24 等分的原则进行划分。\n\n划分之后的信息区块我们称之为『盒子』。建议横向排列的盒子数量最多四个，最少一个。『盒子』在整个屏幕上占比见上图。设计部分基于盒子的单位定制盒子内部的排版规则，以保证视觉层面的舒适感。\n\n## 概述\n\n布局的栅格化系统，我们是基于行（row）和列（col）来定义信息区块的外部框架，以保证页面的每个区域能够稳健地排布起来。下面简单介绍一下它的工作原理：\n\n- 通过 `row` 在水平方向建立一组 `column`（简写 col）\n- 你的内容应当放置于 `col` 内，并且，只有 `col` 可以作为 `row` 的直接元素\n- 栅格系统中的列是指 1 到 24 的值来表示其跨越的范围。例如，三个等宽的列可以使用 `<div nz-col [nzSpan]=\"8\" />` 来创建\n- 如果一个 `row` 中的 `col` 总和超过 24，那么多余的 `col` 会作为一个整体另起一行排列\n\n我们的栅格化系统基于 Flex 布局，允许子元素在父节点内的水平对齐方式 - 居左、居中、居右、等宽排列、分散排列。子元素与子元素之间，支持顶部对齐、垂直居中对齐、底部对齐的方式。同时，支持使用 order 来定义元素的排列顺序。\n\n布局是基于 24 栅格来定义每一个『盒子』的宽度，但不拘泥于栅格。\n\n## API\n\n### [nz-row]\n\n| 成员          | 说明                                                                                                                                       | 类型                                                                 | 默认值 |\n| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------- | ------ |\n| `[nzAlign]`   | 垂直对齐方式                                                                                                                               | `'top' \\| 'middle' \\| 'bottom'`                                      | -      |\n| `[nzGutter]`  | 栅格间隔，可以写成像素值或支持响应式的对象写法来设置水平间隔 `{ xs: 8, sm: 16, md: 24}`。或者使用数组形式同时设置 `[水平间距, 垂直间距]`。 | `string \\| number \\| object \\| [number, number] \\| [object, object]` | -      |\n| `[nzJustify]` | 水平排列方式                                                                                                                               | `'start' \\| 'end' \\| 'center' \\| 'space-around' \\| 'space-between'`  | -      |\n\n### [nz-col]\n\n| 成员         | 说明                                                     | 类型               | 默认值 |\n| ------------ | -------------------------------------------------------- | ------------------ | ------ |\n| `[nzFlex]`   | flex 布局属性                                            | `string \\| number` | -      |\n| `[nzOffset]` | 栅格左侧的间隔格数，间隔内不可以有栅格                   | `number`           | -      |\n| `[nzOrder]`  | 栅格顺序                                                 | `number`           | -      |\n| `[nzPull]`   | 栅格向左移动格数                                         | `number`           | -      |\n| `[nzPush]`   | 栅格向右移动格数                                         | `number`           | -      |\n| `[nzSpan]`   | 栅格占位格数，为 0 时相当于 `display: none`              | `number`           | -      |\n| `[nzXs]`     | `<576px` 响应式栅格，可为栅格数或一个包含其他属性的对象  | `number \\| object` | -      |\n| `[nzSm]`     | `≥576px` 响应式栅格，可为栅格数或一个包含其他属性的对象  | `number \\| object` | -      |\n| `[nzMd]`     | `≥768px` 响应式栅格，可为栅格数或一个包含其他属性的对象  | `number \\| object` | -      |\n| `[nzLg]`     | `≥992px` 响应式栅格，可为栅格数或一个包含其他属性的对象  | `number \\| object` | -      |\n| `[nzXl]`     | `≥1200px` 响应式栅格，可为栅格数或一个包含其他属性的对象 | `number \\| object` | -      |\n| `[nzXXl]`    | `≥1600px` 响应式栅格，可为栅格数或一个包含其他属性的对象 | `number \\| object` | -      |\n\n响应式栅格的断点扩展自 [BootStrap 4 的规则](https://getbootstrap.com/docs/4.0/layout/overview/#responsive-breakpoints)（不包含链接里 `occasionally` 的部分)。\n"
  },
  {
    "path": "components/grid/grid.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzColDirective } from './col.directive';\nimport { NzRowDirective } from './row.directive';\n\n@NgModule({\n  imports: [NzColDirective, NzRowDirective],\n  exports: [NzColDirective, NzRowDirective]\n})\nexport class NzGridModule {}\n"
  },
  {
    "path": "components/grid/grid.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport { Component, provideZoneChangeDetection, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { EmbeddedProperty, NzColDirective } from './col.directive';\nimport { NzGridModule } from './grid.module';\nimport { NzAlign, NzJustify, NzRowDirective } from './row.directive';\n\ndeclare const viewport: NzSafeAny;\nconst setWindowWidth = (width: number): void => {\n  viewport.set(width);\n  window.dispatchEvent(new Event('resize'));\n  tick(100);\n};\n\ndescribe('grid', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  describe('row', () => {\n    let fixture: ComponentFixture<TestGridComponent>;\n    let component: TestGridComponent;\n    let rowElement: HTMLElement;\n    let colElement: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(TestGridComponent);\n      component = fixture.componentInstance;\n      rowElement = fixture.debugElement.query(By.directive(NzRowDirective)).nativeElement;\n      colElement = fixture.debugElement.query(By.directive(NzColDirective)).nativeElement;\n    });\n\n    it('should apply className', () => {\n      expect(rowElement.className).toBe('ant-row');\n    });\n\n    it('should apply className according to align', () => {\n      const listOfAlign: NzAlign[] = ['top', 'middle', 'bottom'];\n      listOfAlign.forEach(align => {\n        component.align = align;\n        fixture.detectChanges();\n        expect(rowElement.classList).toContain(`ant-row-${align}`);\n      });\n    });\n\n    it('should apply className according to justify', () => {\n      const listOfJustify: NzJustify[] = ['start', 'end', 'center', 'space-around', 'space-between'];\n      listOfJustify.forEach(justify => {\n        component.justify = justify;\n        fixture.detectChanges();\n        expect(rowElement.classList).toContain(`ant-row-${justify}`);\n      });\n    });\n\n    it('should gutter number work', () => {\n      expect(rowElement.style.cssText).toBe('');\n      expect(colElement.style.cssText).toBe('');\n      component.gutter = 16;\n      fixture.detectChanges();\n      expect(rowElement.style.cssText).toBe('margin-left: -8px; margin-right: -8px;');\n      expect(colElement.style.cssText).toBe('padding-left: 8px; padding-right: 8px;');\n    });\n\n    it('should gutter string work', () => {\n      expect(rowElement.style.cssText).toBe('');\n      expect(colElement.style.cssText).toBe('');\n      component.gutter = '16';\n      fixture.detectChanges();\n      expect(rowElement.style.cssText).toBe('margin-left: -8px; margin-right: -8px;');\n      expect(colElement.style.cssText).toBe('padding-left: 8px; padding-right: 8px;');\n    });\n\n    it('should gutter number array work', () => {\n      component.gutter = [16, 16];\n      fixture.detectChanges();\n      expect(rowElement.style.cssText).toBe('margin: -8px;');\n      expect(colElement.style.cssText).toBe('padding: 8px;');\n    });\n\n    it('should gutter responsive work', fakeAsync(() => {\n      component.gutter = { xs: 8, sm: 16, md: 24 };\n      setWindowWidth(480);\n      fixture.detectChanges();\n      expect(rowElement.style.cssText).toBe('margin-left: -4px; margin-right: -4px;');\n      expect(colElement.style.cssText).toBe('padding-left: 4px; padding-right: 4px;');\n      setWindowWidth(600);\n      fixture.detectChanges();\n      expect(rowElement.style.cssText).toBe('margin-left: -8px; margin-right: -8px;');\n      expect(colElement.style.cssText).toBe('padding-left: 8px; padding-right: 8px;');\n      setWindowWidth(800);\n      fixture.detectChanges();\n      expect(rowElement.style.cssText).toBe('margin-left: -12px; margin-right: -12px;');\n      expect(colElement.style.cssText).toBe('padding-left: 12px; padding-right: 12px;');\n    }));\n\n    it('should gutter responsive array work', fakeAsync(() => {\n      component.gutter = [\n        { xs: 8, sm: 16, md: 24 },\n        { xs: 4, sm: 8, md: 12 }\n      ];\n      setWindowWidth(480);\n      fixture.detectChanges();\n      expect(rowElement.style.cssText).toBe('margin: -2px -4px;');\n      expect(colElement.style.cssText).toBe('padding: 2px 4px;');\n      setWindowWidth(600);\n      fixture.detectChanges();\n      expect(rowElement.style.cssText).toBe('margin: -4px -8px;');\n      expect(colElement.style.cssText).toBe('padding: 4px 8px;');\n      setWindowWidth(800);\n      fixture.detectChanges();\n      expect(rowElement.style.cssText).toBe('margin: -6px -12px;');\n      expect(colElement.style.cssText).toBe('padding: 6px 12px;');\n    }));\n  });\n\n  describe('col', () => {\n    let fixture: ComponentFixture<TestColComponent>;\n    let component: TestColComponent;\n    let colElement: HTMLElement;\n    const sizeMatch = (name: string, count: number, size?: string): boolean => {\n      const middle = size ? `-${size}-` : '-';\n      if (name === 'span') {\n        return colElement.classList.contains(`ant-col${middle}${count}`);\n      } else {\n        return colElement.classList.contains(`ant-col${middle}${name}-${count}`);\n      }\n    };\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(TestColComponent);\n      colElement = fixture.debugElement.query(By.directive(NzColDirective)).nativeElement;\n      component = fixture.componentInstance;\n      fixture.detectChanges();\n    });\n\n    it('should apply className', () => {\n      expect(colElement.className).toBe('ant-col');\n    });\n\n    it('should apply style according to flex', () => {\n      component.flex = 1;\n      fixture.detectChanges();\n      expect(colElement.style.cssText).toBe('flex: 1 1 auto;');\n      component.flex = '100px';\n      fixture.detectChanges();\n      expect(colElement.style.cssText).toBe('flex: 0 0 100px;');\n    });\n\n    it('should apply className according to property', () => {\n      const propertySizeMatch = (name: keyof TestColComponent, count: number): boolean => {\n        component[name] = count;\n        fixture.detectChanges();\n        return sizeMatch(name, count);\n      };\n      expect(propertySizeMatch('span', 8)).toBe(true);\n      expect(propertySizeMatch('offset', 8)).toBe(true);\n      expect(propertySizeMatch('order', 8)).toBe(true);\n      expect(propertySizeMatch('pull', 8)).toBe(true);\n      expect(propertySizeMatch('push', 8)).toBe(true);\n      expect(propertySizeMatch('xs', 8)).toBe(true);\n      expect(propertySizeMatch('sm', 8)).toBe(true);\n      expect(propertySizeMatch('md', 8)).toBe(true);\n      expect(propertySizeMatch('lg', 8)).toBe(true);\n      expect(propertySizeMatch('xl', 8)).toBe(true);\n      expect(propertySizeMatch('xxl', 8)).toBe(true);\n    });\n\n    it('should apply className according to responsive size object', () => {\n      const batchSizeMatch = (count: number, size: string): boolean =>\n        sizeMatch('span', count, size) &&\n        sizeMatch('offset', count, size) &&\n        sizeMatch('order', count, size) &&\n        sizeMatch('pull', count, size) &&\n        sizeMatch('push', count, size);\n      component.xs = { span: 1, offset: 1, order: 1, pull: 1, push: 1 };\n      component.sm = { span: 2, offset: 2, order: 2, pull: 2, push: 2 };\n      component.md = { span: 3, offset: 3, order: 3, pull: 3, push: 3 };\n      component.lg = { span: 4, offset: 4, order: 4, pull: 4, push: 4 };\n      component.xl = { span: 5, offset: 5, order: 5, pull: 5, push: 5 };\n      component.xxl = { span: 6, offset: 6, order: 6, pull: 6, push: 6 };\n      fixture.detectChanges();\n      expect(batchSizeMatch(1, 'xs')).toBe(true);\n      expect(batchSizeMatch(2, 'sm')).toBe(true);\n      expect(batchSizeMatch(3, 'md')).toBe(true);\n      expect(batchSizeMatch(4, 'lg')).toBe(true);\n      expect(batchSizeMatch(5, 'xl')).toBe(true);\n      expect(batchSizeMatch(6, 'xxl')).toBe(true);\n      component.xs = { span: 2, offset: 2, order: 2, pull: 2, push: 2 };\n      fixture.detectChanges();\n      expect(batchSizeMatch(1, 'xs')).toBe(false);\n    });\n  });\n\n  describe('RTL', () => {\n    let fixture: ComponentFixture<NzTestGridRtlComponent>;\n    let rowElement: HTMLElement;\n    let colElement: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestGridRtlComponent);\n      rowElement = fixture.debugElement.query(By.directive(NzRowDirective)).nativeElement;\n      colElement = fixture.debugElement.query(By.directive(NzColDirective)).nativeElement;\n      fixture.detectChanges();\n    });\n\n    describe('row', () => {\n      it('should className correct on dir change', () => {\n        expect(rowElement.className).toBe('ant-row ant-row-rtl');\n\n        fixture.componentInstance.direction = 'ltr';\n        fixture.detectChanges();\n\n        expect(rowElement.className).toBe('ant-row');\n      });\n    });\n\n    describe('col', () => {\n      it('should className correct on dir change', () => {\n        expect(colElement.className).toBe('ant-col ant-col-rtl');\n\n        fixture.componentInstance.direction = 'ltr';\n        fixture.detectChanges();\n\n        expect(colElement.className).toBe('ant-col');\n      });\n    });\n  });\n});\n\n@Component({\n  imports: [NzGridModule],\n  template: `\n    <div nz-row [nzGutter]=\"gutter\" [nzJustify]=\"justify\" [nzAlign]=\"align\">\n      <div nz-col></div>\n    </div>\n  `\n})\nexport class TestGridComponent {\n  gutter:\n    | string\n    | number\n    | null\n    | [number, number]\n    | Record<string, number>\n    | [Record<string, number>, Record<string, number>] = null;\n  flex: string | null = null;\n  justify: NzJustify | null = null;\n  align: NzAlign | null = null;\n}\n\n@Component({\n  imports: [NzGridModule],\n  template: `\n    <div nz-row>\n      <div\n        nz-col\n        [nzSpan]=\"span\"\n        [nzFlex]=\"flex\"\n        [nzOffset]=\"offset\"\n        [nzOrder]=\"order\"\n        [nzPull]=\"pull\"\n        [nzPush]=\"push\"\n        [nzXs]=\"xs\"\n        [nzSm]=\"sm\"\n        [nzMd]=\"md\"\n        [nzLg]=\"lg\"\n        [nzXl]=\"xl\"\n        [nzXXl]=\"xxl\"\n      ></div>\n    </div>\n  `\n})\nexport class TestColComponent {\n  span: number | null = null;\n  flex: string | null | number = null;\n  offset: number | null = null;\n  order: number | null = null;\n  pull: number | null = null;\n  push: number | null = null;\n  xs: string | number | EmbeddedProperty | null = null;\n  sm: string | number | EmbeddedProperty | null = null;\n  md: string | number | EmbeddedProperty | null = null;\n  lg: string | number | EmbeddedProperty | null = null;\n  xl: string | number | EmbeddedProperty | null = null;\n  xxl: string | number | EmbeddedProperty | null = null;\n}\n\n@Component({\n  imports: [BidiModule, NzGridModule],\n  template: `\n    <div [dir]=\"direction\">\n      <div nz-row>\n        <div nz-col></div>\n      </div>\n    </div>\n  `\n})\nexport class NzTestGridRtlComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n}\n"
  },
  {
    "path": "components/grid/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/grid/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/grid/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './row.directive';\nexport * from './col.directive';\nexport * from './grid.module';\n"
  },
  {
    "path": "components/grid/row.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport { MediaMatcher } from '@angular/cdk/layout';\nimport { Platform } from '@angular/cdk/platform';\nimport {\n  AfterViewInit,\n  DestroyRef,\n  Directive,\n  ElementRef,\n  inject,\n  Input,\n  OnChanges,\n  OnInit,\n  Renderer2,\n  SimpleChanges\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ReplaySubject } from 'rxjs';\n\nimport { gridResponsiveMap, NzBreakpointKey, NzBreakpointService } from 'ng-zorro-antd/core/services';\nimport { IndexableObject } from 'ng-zorro-antd/core/types';\n\nexport type NzJustify = 'start' | 'end' | 'center' | 'space-around' | 'space-between' | 'space-evenly';\nexport type NzAlign = 'top' | 'middle' | 'bottom';\n\n@Directive({\n  selector: '[nz-row],nz-row,nz-form-item',\n  exportAs: 'nzRow',\n  host: {\n    class: 'ant-row',\n    '[class.ant-row-top]': `nzAlign === 'top'`,\n    '[class.ant-row-middle]': `nzAlign === 'middle'`,\n    '[class.ant-row-bottom]': `nzAlign === 'bottom'`,\n    '[class.ant-row-start]': `nzJustify === 'start'`,\n    '[class.ant-row-end]': `nzJustify === 'end'`,\n    '[class.ant-row-center]': `nzJustify === 'center'`,\n    '[class.ant-row-space-around]': `nzJustify === 'space-around'`,\n    '[class.ant-row-space-between]': `nzJustify === 'space-between'`,\n    '[class.ant-row-space-evenly]': `nzJustify === 'space-evenly'`,\n    '[class.ant-row-rtl]': `dir === \"rtl\"`\n  }\n})\nexport class NzRowDirective implements OnInit, OnChanges, AfterViewInit {\n  private elementRef = inject(ElementRef);\n  private renderer = inject(Renderer2);\n  private mediaMatcher = inject(MediaMatcher);\n  private platform = inject(Platform);\n  private breakpointService = inject(NzBreakpointService);\n  private directionality = inject(Directionality);\n  private destroyRef = inject(DestroyRef);\n  @Input() nzAlign: NzAlign | null = null;\n  @Input() nzJustify: NzJustify | null = null;\n  @Input() nzGutter: string | number | IndexableObject | [number, number] | [IndexableObject, IndexableObject] | null =\n    null;\n\n  readonly actualGutter$ = new ReplaySubject<[number | null, number | null]>(1);\n\n  dir: Direction = 'ltr';\n\n  getGutter(): [number | null, number | null] {\n    const results: [number | null, number | null] = [null, null];\n    const gutter = this.nzGutter || 0;\n    const normalizedGutter = Array.isArray(gutter) ? gutter : [gutter, null];\n    normalizedGutter.forEach((g, index) => {\n      if (typeof g === 'object' && g !== null) {\n        results[index] = null;\n        Object.keys(gridResponsiveMap).map((screen: string) => {\n          const bp = screen as NzBreakpointKey;\n          if (this.mediaMatcher.matchMedia(gridResponsiveMap[bp]).matches && g[bp]) {\n            results[index] = g![bp] as number;\n          }\n        });\n      } else {\n        results[index] = Number(g) || null;\n      }\n    });\n    return results;\n  }\n\n  setGutterStyle(): void {\n    const [horizontalGutter, verticalGutter] = this.getGutter();\n    this.actualGutter$.next([horizontalGutter, verticalGutter]);\n    const renderGutter = (name: string, gutter: number | null): void => {\n      const nativeElement = this.elementRef.nativeElement;\n      if (gutter !== null) {\n        this.renderer.setStyle(nativeElement, name, `-${gutter / 2}px`);\n      }\n    };\n    renderGutter('margin-left', horizontalGutter);\n    renderGutter('margin-right', horizontalGutter);\n    renderGutter('margin-top', verticalGutter);\n    renderGutter('margin-bottom', verticalGutter);\n  }\n\n  ngOnInit(): void {\n    this.dir = this.directionality.value;\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n      this.dir = direction;\n    });\n\n    this.setGutterStyle();\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    if (changes.nzGutter) {\n      this.setGutterStyle();\n    }\n  }\n\n  ngAfterViewInit(): void {\n    if (this.platform.isBrowser) {\n      this.breakpointService\n        .subscribe(gridResponsiveMap)\n        .pipe(takeUntilDestroyed(this.destroyRef))\n        .subscribe(() => {\n          this.setGutterStyle();\n        });\n    }\n  }\n}\n"
  },
  {
    "path": "components/grid/style/entry.less",
    "content": "@import './index.less';\n"
  },
  {
    "path": "components/grid/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import './mixin';\n\n// Grid system\n.@{row-prefix-cls} {\n  display: flex;\n  flex-flow: row wrap;\n  min-width: 0;\n\n  &::before,\n  &::after {\n    display: flex;\n  }\n\n  // No wrap of flex\n  &-no-wrap {\n    flex-wrap: nowrap;\n  }\n}\n\n// x轴原点\n.@{row-prefix-cls}-start {\n  justify-content: flex-start;\n}\n\n// x轴居中\n.@{row-prefix-cls}-center {\n  justify-content: center;\n}\n\n// x轴反方向\n.@{row-prefix-cls}-end {\n  justify-content: flex-end;\n}\n\n// x轴平分\n.@{row-prefix-cls}-space-between {\n  justify-content: space-between;\n}\n\n// x轴有间隔地平分\n.@{row-prefix-cls}-space-around {\n  justify-content: space-around;\n}\n\n// x轴有间隔地均分\n.@{row-prefix-cls}-space-evenly {\n  justify-content: space-evenly;\n}\n\n// 顶部对齐\n.@{row-prefix-cls}-top {\n  align-items: flex-start;\n}\n\n// 居中对齐\n.@{row-prefix-cls}-middle {\n  align-items: center;\n}\n\n// 底部对齐\n.@{row-prefix-cls}-bottom {\n  align-items: flex-end;\n}\n\n.@{col-prefix-cls} {\n  position: relative;\n  max-width: 100%;\n  // Prevent columns from collapsing when empty\n  min-height: 1px;\n}\n\n.make-grid();\n\n// Extra small grid\n//\n// Columns, offsets, pushes, and pulls for extra small devices like\n// smartphones.\n\n.make-grid(-xs);\n\n// Small grid\n//\n// Columns, offsets, pushes, and pulls for the small device range, from phones\n// to tablets.\n\n@media (min-width: @screen-sm-min) {\n  .make-grid(-sm);\n}\n\n// Medium grid\n//\n// Columns, offsets, pushes, and pulls for the desktop device range.\n\n@media (min-width: @screen-md-min) {\n  .make-grid(-md);\n}\n\n// Large grid\n//\n// Columns, offsets, pushes, and pulls for the large desktop device range.\n\n@media (min-width: @screen-lg-min) {\n  .make-grid(-lg);\n}\n\n// Extra Large grid\n//\n// Columns, offsets, pushes, and pulls for the full hd device range.\n\n@media (min-width: @screen-xl-min) {\n  .make-grid(-xl);\n}\n\n// Extra Extra Large grid\n//\n// Columns, offsets, pushes, and pulls for the full hd device range.\n\n@media (min-width: @screen-xxl-min) {\n  .make-grid(-xxl);\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/grid/style/mixin.less",
    "content": "@import '../../style/mixins/index';\n\n@row-prefix-cls: ~'@{ant-prefix}-row';\n@col-prefix-cls: ~'@{ant-prefix}-col';\n\n// mixins for grid system\n// ------------------------\n\n.loop-grid-columns(@index, @class) when (@index > 0) {\n  .@{col-prefix-cls}@{class}-@{index} {\n    display: block;\n    flex: 0 0 percentage((@index / @grid-columns));\n    max-width: percentage((@index / @grid-columns));\n  }\n  .@{col-prefix-cls}@{class}-push-@{index} {\n    left: percentage((@index / @grid-columns));\n  }\n  .@{col-prefix-cls}@{class}-pull-@{index} {\n    right: percentage((@index / @grid-columns));\n  }\n  .@{col-prefix-cls}@{class}-offset-@{index} {\n    margin-left: percentage((@index / @grid-columns));\n  }\n  .@{col-prefix-cls}@{class}-order-@{index} {\n    order: @index;\n  }\n  .loop-grid-columns((@index - 1), @class);\n}\n\n.loop-grid-columns(@index, @class) when (@index = 0) {\n  .@{col-prefix-cls}@{class}-@{index} {\n    display: none;\n  }\n  .@{col-prefix-cls}-push-@{index} {\n    left: auto;\n  }\n  .@{col-prefix-cls}-pull-@{index} {\n    right: auto;\n  }\n  .@{col-prefix-cls}@{class}-push-@{index} {\n    left: auto;\n  }\n  .@{col-prefix-cls}@{class}-pull-@{index} {\n    right: auto;\n  }\n  .@{col-prefix-cls}@{class}-offset-@{index} {\n    margin-left: 0;\n  }\n  .@{col-prefix-cls}@{class}-order-@{index} {\n    order: 0;\n  }\n}\n\n.make-grid(@class: ~'') {\n  .loop-grid-columns(@grid-columns, @class);\n}\n"
  },
  {
    "path": "components/grid/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import './mixin';\n\n.@{row-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n}\n\n// mixin\n.loop-grid-columns(@index, @class) when (@index > 0) {\n  .@{col-prefix-cls}@{class}-push-@{index} {\n    // reset property in RTL direction\n    &.@{col-prefix-cls}-rtl {\n      right: percentage((@index / @grid-columns));\n      left: auto;\n    }\n  }\n\n  .@{col-prefix-cls}@{class}-pull-@{index} {\n    // reset property in RTL direction\n    &.@{col-prefix-cls}-rtl {\n      right: auto;\n      left: percentage((@index / @grid-columns));\n    }\n  }\n\n  .@{col-prefix-cls}@{class}-offset-@{index} {\n    // reset property in RTL direction\n    &.@{col-prefix-cls}-rtl {\n      margin-right: percentage((@index / @grid-columns));\n      margin-left: 0;\n    }\n  }\n}\n\n.loop-grid-columns(@index, @class) when (@index = 0) {\n  .@{col-prefix-cls}-push-@{index} {\n    // reset property in RTL direction\n    &.@{col-prefix-cls}-rtl {\n      right: auto;\n    }\n  }\n\n  .@{col-prefix-cls}-pull-@{index} {\n    &.@{col-prefix-cls}-rtl {\n      left: auto;\n    }\n  }\n\n  .@{col-prefix-cls}@{class}-push-@{index} {\n    &.@{col-prefix-cls}-rtl {\n      right: auto;\n    }\n  }\n\n  .@{col-prefix-cls}@{class}-pull-@{index} {\n    &.@{col-prefix-cls}-rtl {\n      left: auto;\n    }\n  }\n\n  .@{col-prefix-cls}@{class}-offset-@{index} {\n    &.@{col-prefix-cls}-rtl {\n      margin-right: 0;\n    }\n  }\n}\n"
  },
  {
    "path": "components/hash-code/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n最简单的用法。\n\n## en-US\n\nThe simplest usage.\n"
  },
  {
    "path": "components/hash-code/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzHashCodeModule } from 'ng-zorro-antd/hash-code';\n\n@Component({\n  selector: 'nz-demo-hash-code-basic',\n  imports: [NzHashCodeModule],\n  template: `<nz-hash-code [nzValue]=\"value\" />`\n})\nexport class NzDemoHashCodeBasicComponent {\n  value = 'dfb5fe9ef7b99b2b1db102114a6d7d445d992f40a5d575f801c148990199a068';\n}\n"
  },
  {
    "path": "components/hash-code/demo/copy.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 复制\n  en-US: Copy\n---\n\n## zh-CN\n\n点击复制的 icon\n\n## en-US\n\nClick on the copied icon.\n"
  },
  {
    "path": "components/hash-code/demo/copy.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzHashCodeModule } from 'ng-zorro-antd/hash-code';\n\n@Component({\n  selector: 'nz-demo-hash-code-copy',\n  imports: [NzHashCodeModule],\n  template: `<nz-hash-code [nzValue]=\"value\" (nzOnCopy)=\"getCopy($event)\" />`\n})\nexport class NzDemoHashCodeCopyComponent {\n  value = 'dfb5fe9ef7b99b2b1db102114a6d7d445d992f40a5d575f801c148990199a068';\n\n  getCopy(value: string): void {\n    console.log(`hashCode:${value}`);\n  }\n}\n"
  },
  {
    "path": "components/hash-code/demo/logo.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 添加 Logo\n  en-US: Logo\n---\n\n## zh-CN\n\n可设置右上角的标志\n\n## en-US\n\nPossibility to set the logo in the upper right corner.\n"
  },
  {
    "path": "components/hash-code/demo/logo.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzHashCodeModule } from 'ng-zorro-antd/hash-code';\n\n@Component({\n  selector: 'nz-demo-hash-code-logo',\n  imports: [NzHashCodeModule],\n  template: `<nz-hash-code [nzValue]=\"value\" nzLogo=\"Antd\" />`\n})\nexport class NzDemoHashCodeLogoComponent {\n  value = 'dfb5fe9ef7b99b2b1db102114a6d7d445d992f40a5d575f801c148990199a068';\n}\n"
  },
  {
    "path": "components/hash-code/demo/primary.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 更换样式\n  en-US: Style\n---\n\n## zh-CN\n\n更换样式。\n\n## en-US\n\nReplacement of styles.\n"
  },
  {
    "path": "components/hash-code/demo/primary.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzHashCodeModule } from 'ng-zorro-antd/hash-code';\n\n@Component({\n  selector: 'nz-demo-hash-code-primary',\n  imports: [NzHashCodeModule],\n  template: `<nz-hash-code [nzValue]=\"value\" nzType=\"primary\" />`\n})\nexport class NzDemoHashCodePrimaryComponent {\n  value = 'dfb5fe9ef7b99b2b1db102114a6d7d445d992f40a5d575f801c148990199a068';\n}\n"
  },
  {
    "path": "components/hash-code/demo/rect.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 矩形模式\n  en-US: Rect\n---\n\n## zh-CN\n\n同单行模式一样，不会展示原有的 `icon` 和顶部描述内容\n\n## en-US\n\nAs in one-line mode, the original `icon` and top description will not be displayed.\n"
  },
  {
    "path": "components/hash-code/demo/rect.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzHashCodeModule } from 'ng-zorro-antd/hash-code';\n\n@Component({\n  selector: 'nz-demo-hash-code-rect',\n  imports: [NzHashCodeModule],\n  template: `\n    <nz-hash-code [nzValue]=\"value\" nzMode=\"rect\" />\n    <br />\n    <nz-hash-code [nzValue]=\"value\" nzMode=\"rect\" nzType=\"primary\" />\n  `\n})\nexport class NzDemoHashCodeRectComponent {\n  value = 'dfb5fe9ef7b99b2b1db102114a6d7d445d992f40a5d575f801c148990199a068';\n}\n"
  },
  {
    "path": "components/hash-code/demo/single.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 单行模式\n  en-US: Single\n---\n\n## zh-CN\n\n在单行模式下，不会展示原有的 `icon` 和顶部描述内容。\n\n## en-US\n\nIn single-line mode, the original `icon` and top description are not displayed.\n"
  },
  {
    "path": "components/hash-code/demo/single.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzHashCodeModule } from 'ng-zorro-antd/hash-code';\n\n@Component({\n  selector: 'nz-demo-hash-code-single',\n  imports: [NzHashCodeModule],\n  template: `\n    <nz-hash-code [nzValue]=\"value\" nzMode=\"single\" />\n    <br />\n    <nz-hash-code [nzValue]=\"value\" nzMode=\"single\" nzType=\"primary\" />\n  `\n})\nexport class NzDemoHashCodeSingleComponent {\n  value = 'dfb5fe9ef7b99b2b1db102114a6d7d445d992f40a5d575f801c148990199a068';\n}\n"
  },
  {
    "path": "components/hash-code/demo/strip.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 长条模式\n  en-US: Strip\n---\n\n## zh-CN\n\n仅展示一行数据。\n\n## en-US\n\nShow only one row of data.\n"
  },
  {
    "path": "components/hash-code/demo/strip.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzHashCodeModule } from 'ng-zorro-antd/hash-code';\n\n@Component({\n  selector: 'nz-demo-hash-code-strip',\n  imports: [NzHashCodeModule],\n  template: `\n    <nz-hash-code [nzValue]=\"value\" nzMode=\"strip\" />\n    <br />\n    <nz-hash-code [nzValue]=\"value\" nzMode=\"strip\" nzType=\"primary\" />\n  `\n})\nexport class NzDemoHashCodeStripComponent {\n  value = 'dfb5fe9ef7b99b2b1db102114a6d7d445d992f40a5d575f801c148990199a068';\n}\n"
  },
  {
    "path": "components/hash-code/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Featured Components\ntitle: HashCode\ntag: 17.0.0\ncover: 'https://img.alicdn.com/imgextra/i3/O1CN01jn3OGS1qq7Xkq6O6b_!!6000000005546-2-tps-1074-374.png'\ndescription: Display the hash value of blockchain data.\n---\n\n## When To Use\n\nThe hash code component is styled for 64-bit design, and if the data given is less than or more than 64-bit, it may\nbring some differences in presentation.\n\n## API\n\n### nz-hash-code\n\n| Property     | Description                                         | Type                                        | Default      |\n| ------------ | --------------------------------------------------- | ------------------------------------------- | ------------ |\n| `[nzValue]`  | The value of the hash code                          | `string`                                    | -            |\n| `[nzTitle]`  | Description of the content in the upper left corner | `string`                                    | `'HashCode'` |\n| `[nzLogo]`   | Display in the upper right corner                   | `TemplateRef<void> \\| string`               | -            |\n| `[nzMode]`   | Demonstration Mode                                  | `'single' \\| 'double' \\| 'strip' \\| 'rect'` | `'double'`   |\n| `[nzType]`   | style                                               | `'default' \\| 'primary'`                    | `'primary'`  |\n| `(nzOnCopy)` | Clicking the Copy callback                          | `EventEmitter<string>`                      | -            |\n"
  },
  {
    "path": "components/hash-code/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 哈希码\ntype: 特色组件\ntitle: HashCode\ntag: 17.0.0\ncover: 'https://img.alicdn.com/imgextra/i3/O1CN01jn3OGS1qq7Xkq6O6b_!!6000000005546-2-tps-1074-374.png'\ndescription: 展示区块链数据的哈希值。\n---\n\n## 何时使用\n\n哈希码组件是以 64 位设计的样式，如果给出的数据不足或者高于 64 位，可能会带来一些展示上的差异。\n\n## API\n\n### nz-hash-code\n\n| 参数         | 说明             | 类型                                        | 默认值       |\n| ------------ | ---------------- | ------------------------------------------- | ------------ |\n| `[nzValue]`  | 哈希码的值       | `string`                                    | -            |\n| `[nzTitle]`  | 左上角的描述内容 | `string`                                    | `'HashCode'` |\n| `[nzLogo]`   | 右上角的展示     | `TemplateRef<void> \\| string`               | -            |\n| `[nzMode]`   | 展示模式         | `'single' \\| 'double' \\| 'strip' \\| 'rect'` | `'double'`   |\n| `[nzType]`   | 样式             | `'default' \\| 'primary'`                    | `'primary'`  |\n| `(nzOnCopy)` | 点击\"复制\"的回调 | `EventEmitter<string>`                      | -            |\n"
  },
  {
    "path": "components/hash-code/hash-code.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, DebugElement, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { dispatchMouseEvent } from 'ng-zorro-antd/core/testing';\n\nimport { NzHashCodeComponent } from './hash-code.component';\nimport { NzHashCodeModule } from './hash-code.module';\nimport { NzModeType } from './typings';\n\ndescribe('hash-code', () => {\n  let fixture: ComponentFixture<NzTestHashCodeBasicComponent>;\n  let testComponent: NzTestHashCodeBasicComponent;\n  let resultEl: DebugElement;\n\n  function waitingForTooltipToggling(): void {\n    fixture.detectChanges();\n    tick(500);\n    fixture.detectChanges();\n  }\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzTestHashCodeBasicComponent);\n    fixture.detectChanges();\n    testComponent = fixture.componentInstance;\n    resultEl = fixture.debugElement.query(By.directive(NzHashCodeComponent));\n  });\n\n  it('basic', () => {\n    fixture.detectChanges();\n    const dom = resultEl.nativeElement;\n    expect(dom.querySelector('.ant-hash-code-header-title').innerText).toBe('HashCode');\n    expect(dom.querySelectorAll('.ant-hash-code-code-value-block').length).toBe(8);\n    expect(dom.querySelector('.ant-hash-code-header-logo').innerText).toBe('Antd');\n    expect(!!dom.querySelector('.ant-hash-code-texaure')).toBeTrue();\n  });\n\n  it('should value length work', () => {\n    testComponent.value =\n      '683109f0f40ca72a15e05cc20931f8e6683109f0f40ca72a15e05cc20931f8e6683109f0f40ca72a15e05cc20931f8e6683109f0f40ca72a15e05cc20931f8e6';\n    fixture.detectChanges();\n    expect(resultEl.nativeElement.querySelectorAll('.ant-hash-code-code-value-block').length).toBe(8);\n    testComponent.value = '683109f0f40ca72a15e05cc20931f8e6';\n    fixture.detectChanges();\n    expect(resultEl.nativeElement.querySelectorAll('.ant-hash-code-code-value-block').length).toBe(8);\n    testComponent.value = '683109f0f40ca72a';\n    fixture.detectChanges();\n    expect(resultEl.nativeElement.querySelectorAll('.ant-hash-code-code-value-block').length).toBe(4);\n  });\n\n  it('should mode single work', () => {\n    testComponent.mode = 'single';\n    fixture.detectChanges();\n    expect(!!resultEl.nativeElement.querySelector('.ant-hash-code-header')).toBeFalse();\n    expect(!!resultEl.nativeElement.querySelector('.ant-hash-code-header-copy')).toBeTrue();\n    expect(resultEl.nativeElement.classList).toContain('ant-hash-code-single');\n  });\n\n  it('should mode strip work', () => {\n    testComponent.mode = 'strip';\n    fixture.detectChanges();\n    expect(resultEl.nativeElement.classList).toContain('ant-hash-code-strip');\n  });\n\n  it('should rect mode work', () => {\n    testComponent.mode = 'rect';\n    fixture.detectChanges();\n    expect(!!resultEl.nativeElement.querySelector('.ant-hash-code-header')).toBeFalse();\n    expect(!!resultEl.nativeElement.querySelector('.ant-hash-code-header-copy')).toBeTrue();\n    expect(resultEl.nativeElement.classList).toContain('ant-hash-code-rect');\n  });\n\n  it('should type work', () => {\n    testComponent.type = 'primary';\n    fixture.detectChanges();\n    expect(resultEl.nativeElement.classList).toContain('ant-hash-code-primary');\n  });\n\n  it('should copy work', fakeAsync(() => {\n    fixture.detectChanges();\n    const copy = resultEl.nativeElement.querySelector('.ant-hash-code-header-copy');\n    dispatchMouseEvent(copy, 'click');\n    waitingForTooltipToggling();\n    expect(testComponent.copyValue).toBe(testComponent.value);\n  }));\n});\n\n@Component({\n  imports: [NzHashCodeModule],\n  template: `\n    <nz-hash-code\n      [nzValue]=\"value\"\n      [nzTitle]=\"title\"\n      [nzLogo]=\"logo\"\n      [nzMode]=\"mode\"\n      [nzType]=\"type\"\n      (nzOnCopy)=\"onCopy($event)\"\n    />\n  `\n})\nexport class NzTestHashCodeBasicComponent {\n  value = 'dfb5fe9ef7b99b2b1db102114a6d7d445d992f40a5d575f801c148990199a068';\n  title = 'HashCode';\n  logo = 'Antd';\n  mode: NzModeType = 'double';\n  type: 'default' | 'primary' = 'default';\n  copyValue = '';\n\n  onCopy(value: string): void {\n    this.copyValue = value;\n  }\n}\n"
  },
  {
    "path": "components/hash-code/hash-code.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  EventEmitter,\n  inject,\n  Input,\n  OnChanges,\n  Output,\n  SimpleChanges,\n  TemplateRef\n} from '@angular/core';\n\nimport { NzStringTemplateOutletDirective } from 'ng-zorro-antd/core/outlet';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nimport { NzModeType } from './typings';\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  imports: [NzIconModule, NzStringTemplateOutletDirective],\n  selector: 'nz-hash-code',\n  exportAs: 'nzHashCode',\n  template: `\n    @if (nzMode !== 'single' && nzMode !== 'rect') {\n      <div class=\"ant-hash-code-header\">\n        <div class=\"ant-hash-code-header-title\">{{ nzTitle }}</div>\n        <div class=\"ant-hash-code-header-copy\" (click)=\"copyHandle()\">\n          <nz-icon nzType=\"copy\" nzTheme=\"outline\" />\n        </div>\n        <div class=\"ant-hash-code-header-logo\">\n          <ng-template [nzStringTemplateOutlet]=\"nzLogo\">{{ nzLogo }}</ng-template>\n        </div>\n      </div>\n    }\n\n    @if (nzMode === 'single' || nzMode === 'rect') {\n      <div class=\"ant-hash-code-header-copy\" (click)=\"copyHandle()\">\n        <nz-icon nzType=\"copy\" nzTheme=\"outline\" />\n      </div>\n    }\n\n    <div\n      class=\"ant-hash-code-contant\"\n      [class.ant-hash-code-value-default]=\"nzType === 'default'\"\n      [class.ant-hash-code-value-primary]=\"nzType === 'primary'\"\n    >\n      <div\n        class=\"ant-hash-code-code-value\"\n        [style]=\"{ height: nzMode === 'rect' ? '70px' : nzMode === 'single' ? '18px' : '35px' }\"\n      >\n        @if (nzMode === 'double') {\n          @if (hashDataList.length > 8) {\n            @for (v of hashDataList.slice(0, 6); track v) {\n              <div class=\"ant-hash-code-code-value-block\">{{ v }}</div>\n            }\n            <div class=\"ant-hash-code-code-value-block\">····</div>\n            <div class=\"ant-hash-code-code-value-block\">{{ hashDataList[hashDataList.length - 1] }}</div>\n          } @else {\n            @for (v of hashDataList; track v) {\n              <div class=\"ant-hash-code-code-value-block\">{{ v }}</div>\n            }\n          }\n        }\n\n        @if (nzMode === 'single') {\n          <div class=\"ant-hash-code-code-value-block\">{{ hashDataList[0] }}</div>\n          <div class=\"ant-hash-code-code-value-block\">····</div>\n          <div class=\"ant-hash-code-code-value-block\">{{ hashDataList[hashDataList.length - 1] }}</div>\n        }\n\n        @if (nzMode === 'rect' || nzMode === 'strip') {\n          @if (hashDataList.length > 16) {\n            @for (v of hashDataList.slice(0, 14); track v) {\n              <div class=\"ant-hash-code-code-value-block\">{{ v }}</div>\n            }\n            <div class=\"ant-hash-code-code-value-block\">····</div>\n            <div class=\"ant-hash-code-code-value-block\">{{ hashDataList[hashDataList.length - 1] }}</div>\n          } @else {\n            @for (v of hashDataList; track v) {\n              <div class=\"ant-hash-code-code-value-block\">{{ v }}</div>\n            }\n          }\n        }\n      </div>\n      <div\n        class=\"ant-hash-code-texaure\"\n        [class.ant-hash-code-texaure-double]=\"nzMode === 'double'\"\n        [class.ant-hash-code-texaure-single]=\"nzMode === 'single'\"\n        [class.ant-hash-code-texaure-strip]=\"nzMode === 'strip'\"\n        [class.ant-hash-code-texaure-rect]=\"nzMode === 'rect'\"\n      >\n        <svg width=\"545px\" height=\"111px\" viewBox=\"0 0 545 111\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n          <defs>\n            <linearGradient\n              x1=\"15.7162414%\"\n              y1=\"50.0992184%\"\n              x2=\"49.5266564%\"\n              y2=\"50.0234565%\"\n              id=\"linearGradient-2bm6v9icte-1\"\n            >\n              <stop stop-color=\"#A76A00\" offset=\"0%\" />\n              <stop stop-color=\"#F50006\" offset=\"61.2716995%\" />\n              <stop stop-color=\"#DA8500\" offset=\"100%\" />\n            </linearGradient>\n          </defs>\n          <g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n            <g\n              transform=\"translate(-163.000000, -315.000000)\"\n              stroke=\"url(#linearGradient-2bm6v9icte-1)\"\n              stroke-width=\"0.72\"\n            >\n              <g transform=\"translate(163.535712, 316.000000)\" style=\"mix-blend-mode: exclusion;\">\n                <path\n                  d=\"M0,0 C22.68,0 22.68,5.76 45.36,5.76 C68.04,5.76 68.04,0 90.72,0 C113.4,0 113.4,5.76 136.08,5.76 C158.76,5.76 158.76,0 181.44,0 C204.12,0 204.12,5.76 226.8,5.76 C249.48,5.76 249.48,0 272.16,0\"\n                />\n                <path\n                  d=\"M0,28.08 C22.68,28.08 22.68,33.84 45.36,33.84 C68.04,33.84 68.04,28.08 90.72,28.08 C113.4,28.08 113.4,33.84 136.08,33.84 C158.76,33.84 158.76,28.08 181.44,28.08 C204.12,28.08 204.12,33.84 226.8,33.84 C249.48,33.84 249.48,28.08 272.16,28.08\"\n                />\n                <path\n                  d=\"M0,37.44 C22.68,37.44 22.68,43.2 45.36,43.2 C68.04,43.2 68.04,37.44 90.72,37.44 C113.4,37.44 113.4,43.2 136.08,43.2 C158.76,43.2 158.76,37.44 181.44,37.44 C204.12,37.44 204.12,43.2 226.8,43.2 C249.48,43.2 249.48,37.44 272.16,37.44\"\n                />\n                <path\n                  d=\"M0,9.36 C22.68,9.36 22.68,15.12 45.36,15.12 C68.04,15.12 68.04,9.36 90.72,9.36 C113.4,9.36 113.4,15.12 136.08,15.12 C158.76,15.12 158.76,9.36 181.44,9.36 C204.12,9.36 204.12,15.12 226.8,15.12 C249.48,15.12 249.48,9.36 272.16,9.36\"\n                />\n                <path\n                  d=\"M0,18.72 C22.68,18.72 22.68,24.48 45.36,24.48 C68.04,24.48 68.04,18.72 90.72,18.72 C113.4,18.72 113.4,24.48 136.08,24.48 C158.76,24.48 158.76,18.72 181.44,18.72 C204.12,18.72 204.12,24.48 226.8,24.48 C249.48,24.48 249.48,18.72 272.16,18.72\"\n                />\n                <path\n                  d=\"M0,46.8 C22.68,46.8 22.68,52.56 45.36,52.56 C68.04,52.56 68.04,46.8 90.72,46.8 C113.4,46.8 113.4,52.56 136.08,52.56 C158.76,52.56 158.76,46.8 181.44,46.8 C204.12,46.8 204.12,52.56 226.8,52.56 C249.48,52.56 249.48,46.8 272.16,46.8\"\n                />\n              </g>\n              <g transform=\"translate(163.535712, 373.000000)\" style=\"mix-blend-mode: exclusion;\">\n                <path\n                  d=\"M0,0 C22.68,0 22.68,5.76 45.36,5.76 C68.04,5.76 68.04,0 90.72,0 C113.4,0 113.4,5.76 136.08,5.76 C158.76,5.76 158.76,0 181.44,0 C204.12,0 204.12,5.76 226.8,5.76 C249.48,5.76 249.48,0 272.16,0\"\n                />\n                <path\n                  d=\"M0,28.08 C22.68,28.08 22.68,33.84 45.36,33.84 C68.04,33.84 68.04,28.08 90.72,28.08 C113.4,28.08 113.4,33.84 136.08,33.84 C158.76,33.84 158.76,28.08 181.44,28.08 C204.12,28.08 204.12,33.84 226.8,33.84 C249.48,33.84 249.48,28.08 272.16,28.08\"\n                />\n                <path\n                  d=\"M0,37.44 C22.68,37.44 22.68,43.2 45.36,43.2 C68.04,43.2 68.04,37.44 90.72,37.44 C113.4,37.44 113.4,43.2 136.08,43.2 C158.76,43.2 158.76,37.44 181.44,37.44 C204.12,37.44 204.12,43.2 226.8,43.2 C249.48,43.2 249.48,37.44 272.16,37.44\"\n                />\n                <path\n                  d=\"M0,9.36 C22.68,9.36 22.68,15.12 45.36,15.12 C68.04,15.12 68.04,9.36 90.72,9.36 C113.4,9.36 113.4,15.12 136.08,15.12 C158.76,15.12 158.76,9.36 181.44,9.36 C204.12,9.36 204.12,15.12 226.8,15.12 C249.48,15.12 249.48,9.36 272.16,9.36\"\n                />\n                <path\n                  d=\"M0,18.72 C22.68,18.72 22.68,24.48 45.36,24.48 C68.04,24.48 68.04,18.72 90.72,18.72 C113.4,18.72 113.4,24.48 136.08,24.48 C158.76,24.48 158.76,18.72 181.44,18.72 C204.12,18.72 204.12,24.48 226.8,24.48 C249.48,24.48 249.48,18.72 272.16,18.72\"\n                />\n                <path\n                  d=\"M0,46.8 C22.68,46.8 22.68,52.56 45.36,52.56 C68.04,52.56 68.04,46.8 90.72,46.8 C113.4,46.8 113.4,52.56 136.08,52.56 C158.76,52.56 158.76,46.8 181.44,46.8 C204.12,46.8 204.12,52.56 226.8,52.56 C249.48,52.56 249.48,46.8 272.16,46.8\"\n                />\n              </g>\n              <g transform=\"translate(435.535712, 316.000000)\" style=\"mix-blend-mode: exclusion;\">\n                <path\n                  d=\"M0,0 C22.68,0 22.68,5.76 45.36,5.76 C68.04,5.76 68.04,0 90.72,0 C113.4,0 113.4,5.76 136.08,5.76 C158.76,5.76 158.76,0 181.44,0 C204.12,0 204.12,5.76 226.8,5.76 C249.48,5.76 249.48,0 272.16,0\"\n                />\n                <path\n                  d=\"M0,28.08 C22.68,28.08 22.68,33.84 45.36,33.84 C68.04,33.84 68.04,28.08 90.72,28.08 C113.4,28.08 113.4,33.84 136.08,33.84 C158.76,33.84 158.76,28.08 181.44,28.08 C204.12,28.08 204.12,33.84 226.8,33.84 C249.48,33.84 249.48,28.08 272.16,28.08\"\n                />\n                <path\n                  d=\"M0,37.44 C22.68,37.44 22.68,43.2 45.36,43.2 C68.04,43.2 68.04,37.44 90.72,37.44 C113.4,37.44 113.4,43.2 136.08,43.2 C158.76,43.2 158.76,37.44 181.44,37.44 C204.12,37.44 204.12,43.2 226.8,43.2 C249.48,43.2 249.48,37.44 272.16,37.44\"\n                />\n                <path\n                  d=\"M0,9.36 C22.68,9.36 22.68,15.12 45.36,15.12 C68.04,15.12 68.04,9.36 90.72,9.36 C113.4,9.36 113.4,15.12 136.08,15.12 C158.76,15.12 158.76,9.36 181.44,9.36 C204.12,9.36 204.12,15.12 226.8,15.12 C249.48,15.12 249.48,9.36 272.16,9.36\"\n                />\n                <path\n                  d=\"M0,18.72 C22.68,18.72 22.68,24.48 45.36,24.48 C68.04,24.48 68.04,18.72 90.72,18.72 C113.4,18.72 113.4,24.48 136.08,24.48 C158.76,24.48 158.76,18.72 181.44,18.72 C204.12,18.72 204.12,24.48 226.8,24.48 C249.48,24.48 249.48,18.72 272.16,18.72\"\n                />\n                <path\n                  d=\"M0,46.8 C22.68,46.8 22.68,52.56 45.36,52.56 C68.04,52.56 68.04,46.8 90.72,46.8 C113.4,46.8 113.4,52.56 136.08,52.56 C158.76,52.56 158.76,46.8 181.44,46.8 C204.12,46.8 204.12,52.56 226.8,52.56 C249.48,52.56 249.48,46.8 272.16,46.8\"\n                />\n              </g>\n              <g transform=\"translate(435.535712, 373.000000)\" style=\"mix-blend-mode: exclusion;\">\n                <path\n                  d=\"M0,0 C22.68,0 22.68,5.76 45.36,5.76 C68.04,5.76 68.04,0 90.72,0 C113.4,0 113.4,5.76 136.08,5.76 C158.76,5.76 158.76,0 181.44,0 C204.12,0 204.12,5.76 226.8,5.76 C249.48,5.76 249.48,0 272.16,0\"\n                />\n                <path\n                  d=\"M0,28.08 C22.68,28.08 22.68,33.84 45.36,33.84 C68.04,33.84 68.04,28.08 90.72,28.08 C113.4,28.08 113.4,33.84 136.08,33.84 C158.76,33.84 158.76,28.08 181.44,28.08 C204.12,28.08 204.12,33.84 226.8,33.84 C249.48,33.84 249.48,28.08 272.16,28.08\"\n                />\n                <path\n                  d=\"M0,37.44 C22.68,37.44 22.68,43.2 45.36,43.2 C68.04,43.2 68.04,37.44 90.72,37.44 C113.4,37.44 113.4,43.2 136.08,43.2 C158.76,43.2 158.76,37.44 181.44,37.44 C204.12,37.44 204.12,43.2 226.8,43.2 C249.48,43.2 249.48,37.44 272.16,37.44\"\n                />\n                <path\n                  d=\"M0,9.36 C22.68,9.36 22.68,15.12 45.36,15.12 C68.04,15.12 68.04,9.36 90.72,9.36 C113.4,9.36 113.4,15.12 136.08,15.12 C158.76,15.12 158.76,9.36 181.44,9.36 C204.12,9.36 204.12,15.12 226.8,15.12 C249.48,15.12 249.48,9.36 272.16,9.36\"\n                />\n                <path\n                  d=\"M0,18.72 C22.68,18.72 22.68,24.48 45.36,24.48 C68.04,24.48 68.04,18.72 90.72,18.72 C113.4,18.72 113.4,24.48 136.08,24.48 C158.76,24.48 158.76,18.72 181.44,18.72 C204.12,18.72 204.12,24.48 226.8,24.48 C249.48,24.48 249.48,18.72 272.16,18.72\"\n                />\n                <path\n                  d=\"M0,46.8 C22.68,46.8 22.68,52.56 45.36,52.56 C68.04,52.56 68.04,46.8 90.72,46.8 C113.4,46.8 113.4,52.56 136.08,52.56 C158.76,52.56 158.76,46.8 181.44,46.8 C204.12,46.8 204.12,52.56 226.8,52.56 C249.48,52.56 249.48,46.8 272.16,46.8\"\n                />\n              </g>\n            </g>\n          </g>\n        </svg>\n      </div>\n    </div>\n  `,\n  host: {\n    class: 'ant-hash-code',\n    '[class.ant-hash-code-default]': `nzType === 'default'`,\n    '[class.ant-hash-code-primary]': `nzType === 'primary'`,\n    '[class.ant-hash-code-double]': `nzMode === 'double'`,\n    '[class.ant-hash-code-single]': `nzMode === 'single'`,\n    '[class.ant-hash-code-strip]': `nzMode === 'strip'`,\n    '[class.ant-hash-code-rect]': `nzMode === 'rect'`\n  }\n})\nexport class NzHashCodeComponent implements OnChanges {\n  private cdr = inject(ChangeDetectorRef);\n\n  @Input() nzValue: string = '';\n  @Input() nzTitle: string = 'HashCode';\n  @Input() nzLogo: TemplateRef<void> | string = '';\n  @Input() nzMode: NzModeType = 'double';\n  @Input() nzType: 'default' | 'primary' = 'default';\n  @Output() readonly nzOnCopy = new EventEmitter<string>();\n\n  hashDataList: string[] = [];\n\n  copyHandle(): void {\n    this.nzOnCopy.emit(this.nzValue);\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzValue } = changes;\n\n    if (nzValue) {\n      this.setData(this.nzValue);\n    }\n  }\n\n  setData(value: string): void {\n    if (this.nzMode !== 'single') {\n      this.hashDataList = value.match(/.{1,4}/g) as string[];\n    } else {\n      this.hashDataList = value.match(/.{1,8}/g) as string[];\n    }\n    this.cdr.markForCheck();\n  }\n}\n"
  },
  {
    "path": "components/hash-code/hash-code.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzHashCodeComponent } from './hash-code.component';\n\n@NgModule({\n  exports: [NzHashCodeComponent],\n  imports: [NzHashCodeComponent]\n})\nexport class NzHashCodeModule {}\n"
  },
  {
    "path": "components/hash-code/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/hash-code/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/hash-code/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './hash-code.component';\nexport * from './hash-code.module';\nexport * from './typings';\n"
  },
  {
    "path": "components/hash-code/style/entry.less",
    "content": "@import './index.less';"
  },
  {
    "path": "components/hash-code/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@hash-code-prefix-cls: ~'@{ant-prefix}-hash-code';\n\n.@{hash-code-prefix-cls} {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  box-sizing: border-box;\n  margin: 0;\n  padding: 0;\n  color: @text-color;\n  font-size: @font-size-base;\n  line-height: @line-height-base;\n  list-style: none;\n  cursor: pointer;\n}\n\n.@{hash-code-prefix-cls}-header-copy {\n  margin-left: @margin-xs;\n  cursor: pointer;\n  opacity: 0.45;\n}\n\n.@{hash-code-prefix-cls}-header {\n  display: flex;\n  justify-content: left;\n  width: 100%;\n  height: 22px;\n  padding-bottom: @padding-xs;\n\n  .@{hash-code-prefix-cls}-header-title {\n    font-size: @font-size-base;\n    line-height: @line-height-base;\n    text-align: center;\n    opacity: 0.45;\n  }\n\n  .@{hash-code-prefix-cls}-header-logo {\n    display: flex;\n    flex: 1;\n    justify-content: right;\n  }\n}\n\n.@{hash-code-prefix-cls}-double {\n  width: 172px;\n\n  &.ant-hash-code-primary {\n    width: 220px;\n  }\n}\n\n.@{hash-code-prefix-cls}-single {\n  display: flex;\n  flex-direction: row-reverse;\n  width: 236px;\n\n  &.ant-hash-code-primary {\n    width: 284px;\n  }\n\n  .@{hash-code-prefix-cls}-header-copy {\n    margin-top: @margin-xs;\n  }\n}\n\n.@{hash-code-prefix-cls}-strip {\n  width: 350px;\n\n  &.ant-hash-code-primary {\n    width: 398px;\n  }\n}\n\n.@{hash-code-prefix-cls}-rect {\n  display: flex;\n  flex-direction: row-reverse;\n  width: 196px;\n\n  &.ant-hash-code-primary {\n    width: 244px;\n  }\n}\n\n.@{hash-code-prefix-cls}-primary {\n  padding: @padding-lg;\n  background-color: @primary-color;\n  border-radius: 24px;\n\n  .@{hash-code-prefix-cls}-header-copy {\n    opacity: 1;\n  }\n\n  .@{hash-code-prefix-cls}-header-title,\n  .@{hash-code-prefix-cls}-header-copy,\n  .@{hash-code-prefix-cls}-header-logo {\n    color: @text-color-dark;\n  }\n}\n\n.@{hash-code-prefix-cls}-contant {\n  width: 100%;\n  height: 100%;\n}\n\n.@{hash-code-prefix-cls}-code-value {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 0 10px;\n  justify-content: space-between;\n  height: 35px;\n  overflow: hidden;\n}\n\n.@{hash-code-prefix-cls}-code-value-block {\n  height: 16px;\n  font-size: @font-size-base;\n  font-family: Menlo, Monaco, Consolas, 'Courier New', monospace;\n}\n\n.@{hash-code-prefix-cls}-value-primary {\n  .ant-hash-code-code-value-block {\n    color: @text-color-inverse;\n  }\n}\n\n.@{hash-code-prefix-cls}-texaure-double {\n  width: 175px;\n  height: 36px;\n}\n\n.@{hash-code-prefix-cls}-texaure {\n  position: absolute;\n  margin-top: -35px;\n  overflow: hidden;\n}\n\n.@{hash-code-prefix-cls}-texaure-single {\n  width: 210px;\n  height: 28px;\n  margin-top: -21px;\n}\n\n.@{hash-code-prefix-cls}-texaure-strip {\n  width: 350px;\n  height: 36px;\n}\n\n.@{hash-code-prefix-cls}-texaure-rect {\n  width: 175px;\n  height: 72px;\n  margin-top: -71px;\n}\n"
  },
  {
    "path": "components/hash-code/typings.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport type NzModeType = 'single' | 'double' | 'strip' | 'rect';\n"
  },
  {
    "path": "components/i18n/date-config.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { InjectionToken } from '@angular/core';\n\nimport { WeekDayIndex } from 'ng-zorro-antd/core/time';\n\nexport interface NzDateConfig {\n  /** Customize the first day of a week */\n  firstDayOfWeek?: WeekDayIndex;\n}\n\nexport const NZ_DATE_CONFIG = new InjectionToken<NzDateConfig>(\n  typeof ngDevMode !== 'undefined' && ngDevMode ? 'nz-date-config' : ''\n);\n\nexport const NZ_DATE_CONFIG_DEFAULT: NzDateConfig = {\n  firstDayOfWeek: undefined\n};\n\nexport function mergeDateConfig(config: NzDateConfig | null): NzDateConfig {\n  return { ...NZ_DATE_CONFIG_DEFAULT, ...config };\n}\n"
  },
  {
    "path": "components/i18n/date-helper.service.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { TestBed } from '@angular/core/testing';\n\nimport { enUS } from 'date-fns/locale';\n\nimport { NZ_DATE_CONFIG } from './date-config';\nimport { DateHelperByDatePipe, DateHelperService } from './date-helper.service';\nimport en_US from './languages/en_US';\nimport { NzI18nModule } from './nz-i18n.module';\nimport { NZ_DATE_LOCALE, provideNzI18n } from './nz-i18n.token';\n\ndescribe('DateHelperService', () => {\n  let dateHelper: DateHelperService;\n\n  describe('Formatting with DatePipe', () => {\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        imports: [NzI18nModule],\n        providers: [provideNzI18n(en_US)]\n      });\n\n      dateHelper = TestBed.inject(DateHelperService);\n    });\n\n    it('should do formatting by DatePipe', () => {\n      expect(dateHelper instanceof DateHelperByDatePipe).toBeTruthy();\n    });\n\n    it('should do formatting correctly', () => {\n      const date = new Date('2018-12-31 12:11:10');\n      expect(dateHelper.format(date, 'yyyy-MM-dd')).toBe('2018-12-31');\n      expect(dateHelper.format(date, 'ww')).toBe('01');\n    });\n\n    it('should get first day of week with 0 by en_US', () => {\n      expect(dateHelper.getFirstDayOfWeek()).toBe(0);\n    });\n\n    it('should do parseTime correctly', () => {\n      expect(dateHelper.parseTime('14:00', 'HH:mm')?.toTimeString().substr(0, 5)).toBe('14:00');\n      expect(dateHelper.parseTime('4:00', 'H:mm')?.toTimeString().substr(0, 5)).toBe('04:00');\n    });\n\n    it('should do formatting quarter', () => {\n      const date = new Date('2024-04-08 18:18:10');\n      expect(dateHelper.format(date, 'yyyy-Q')).toBe('2024-2');\n      expect(dateHelper.format(date, 'yyyy-QQ')).toBe('2024-02');\n      expect(dateHelper.format(date, 'yyyy-QQQ')).toBe('2024-Q2');\n      expect(dateHelper.format(date, 'yyyy-QQQQ')).toBe('2024-2');\n      expect(dateHelper.format(date, 'yyyy-[Q]Q')).toBe('2024-Q2');\n      expect(dateHelper.format(date, 'yyyy-[QQ]Q')).toBe('2024-QQ2');\n    });\n  });\n\n  describe('Formatting with Data-fns', () => {\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        imports: [NzI18nModule],\n        providers: [{ provide: NZ_DATE_LOCALE, useValue: enUS }]\n      });\n\n      dateHelper = TestBed.inject(DateHelperService);\n    });\n\n    it('should do formatting by Date-fns', () => {\n      expect(dateHelper instanceof DateHelperByDatePipe).toBeFalsy();\n    });\n\n    it('should do formatting correctly', () => {\n      const date = new Date('2018-12-31 12:11:10');\n      expect(dateHelper.format(date, 'yyyy-MM-dd')).toBe('2018-12-31');\n      expect(dateHelper.format(date, 'RRRR-II')).toBe('2019-01'); // ISO week\n    });\n\n    it('should do parseTime correctly', () => {\n      expect(dateHelper.parseTime('14:00', 'HH:mm')?.toTimeString().substr(0, 8)).toBe('14:00:00');\n      expect(dateHelper.parseTime('4:00', 'H:mm')?.toTimeString().substr(0, 8)).toBe('04:00:00');\n    });\n  });\n\n  describe('Custom firstDayOfWeek', () => {\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        imports: [NzI18nModule],\n        providers: [\n          { provide: NZ_DATE_LOCALE, useValue: enUS },\n          { provide: NZ_DATE_CONFIG, useValue: { firstDayOfWeek: 4 } }\n        ]\n      });\n\n      dateHelper = TestBed.inject(DateHelperService);\n    });\n\n    it('should set first day of week to 4', () => {\n      expect(dateHelper.getFirstDayOfWeek()).toBe(4);\n    });\n  });\n});\n"
  },
  {
    "path": "components/i18n/date-helper.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { formatDate } from '@angular/common';\nimport { Injectable, inject } from '@angular/core';\n\nimport { format as fnsFormat, getISOWeek as fnsGetISOWeek, parse as fnsParse, getQuarter } from 'date-fns';\n\nimport { WeekDayIndex, ɵNgTimeParser } from 'ng-zorro-antd/core/time';\n\nimport { NZ_DATE_CONFIG, NzDateConfig, mergeDateConfig } from './date-config';\nimport { NzI18nService } from './nz-i18n.service';\n\nexport function DATE_HELPER_SERVICE_FACTORY(): DateHelperService {\n  const i18n = inject(NzI18nService);\n  return i18n.getDateLocale() ? new DateHelperByDateFns(i18n) : new DateHelperByDatePipe(i18n);\n}\n\n/**\n * Abstract DateHelperService(Token via Class)\n * Compatibility: compact for original usage by default which using DatePipe\n */\n@Injectable({\n  providedIn: 'root',\n  useFactory: DATE_HELPER_SERVICE_FACTORY\n})\nexport abstract class DateHelperService {\n  protected config: NzDateConfig = mergeDateConfig(inject(NZ_DATE_CONFIG, { optional: true }));\n\n  constructor(protected i18n: NzI18nService) {}\n\n  abstract getISOWeek(date: Date): number;\n  abstract getFirstDayOfWeek(): WeekDayIndex;\n  abstract format(date: Date | null, formatStr: string): string;\n  abstract parseDate(text: string, formatStr?: string): Date;\n  abstract parseTime(text: string, formatStr?: string): Date | undefined;\n}\n\n/**\n * DateHelper that handles date formats with date-fns\n */\nexport class DateHelperByDateFns extends DateHelperService {\n  getISOWeek(date: Date): number {\n    return fnsGetISOWeek(date);\n  }\n\n  // Use date-fns's \"weekStartsOn\" to support different locale when \"config.firstDayOfWeek\" is null\n  // https://github.com/date-fns/date-fns/blob/v2.0.0-alpha.27/src/locale/en-US/index.js#L23\n  getFirstDayOfWeek(): WeekDayIndex {\n    let defaultWeekStartsOn: WeekDayIndex;\n    try {\n      defaultWeekStartsOn = this.i18n.getDateLocale().options!.weekStartsOn!;\n    } catch {\n      defaultWeekStartsOn = 1;\n    }\n    return this.config.firstDayOfWeek == null ? defaultWeekStartsOn : this.config.firstDayOfWeek;\n  }\n\n  /**\n   * Format a date\n   *\n   * @see https://date-fns.org/docs/format#description\n   * @param date Date\n   * @param formatStr format string\n   */\n  format(date: Date, formatStr: string): string {\n    return date ? fnsFormat(date, formatStr, { locale: this.i18n.getDateLocale() }) : '';\n  }\n\n  parseDate(text: string, formatStr: string): Date {\n    return fnsParse(text, formatStr, new Date(), {\n      locale: this.i18n.getDateLocale(),\n      weekStartsOn: this.getFirstDayOfWeek()\n    });\n  }\n\n  parseTime(text: string, formatStr: string): Date | undefined {\n    return this.parseDate(text, formatStr);\n  }\n}\n\n/**\n * DateHelper that handles date formats with angular's date-pipe\n *\n * @see https://github.com/NG-ZORRO/ng-zorro-antd/issues/2406 - DatePipe may cause non-standard week bug, see:\n *\n */\nexport class DateHelperByDatePipe extends DateHelperService {\n  getISOWeek(date: Date): number {\n    return +this.format(date, 'w');\n  }\n\n  getFirstDayOfWeek(): WeekDayIndex {\n    if (this.config.firstDayOfWeek === undefined) {\n      const locale = this.i18n.getLocaleId();\n      return locale && ['zh-cn', 'zh-tw'].indexOf(locale.toLowerCase()) > -1 ? 1 : 0;\n    }\n    return this.config.firstDayOfWeek;\n  }\n\n  format(date: Date | null, formatStr: string): string {\n    // angular formatDate does not support the quarter format parameter. This is to be compatible with the quarter format \"Q\" of date-fns.\n    return date ? this.replaceQuarter(formatDate(date, formatStr, this.i18n.getLocaleId())!, date) : '';\n  }\n\n  parseDate(text: string): Date {\n    return new Date(text);\n  }\n\n  parseTime(text: string, formatStr: string): Date {\n    const parser = new ɵNgTimeParser(formatStr, this.i18n.getLocaleId());\n    return parser.toDate(text);\n  }\n\n  private replaceQuarter(dateStr: string, date: Date): string {\n    const quarter = getQuarter(date).toString();\n    const record: Record<string, string> = { Q: quarter, QQ: `0${quarter}`, QQQ: `Q${quarter}` };\n    // Q Pattern format compatible with date-fns (quarter).\n    return (\n      dateStr\n        // Match Q+ outside of brackets, then replace it with the specified quarterly format\n        .replace(/Q+(?![^[]*])/g, match => record[match] ?? quarter)\n        // Match the Q+ surrounded by bracket, then remove bracket.\n        .replace(/\\[(Q+)]/g, '$1')\n    );\n  }\n}\n"
  },
  {
    "path": "components/i18n/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/i18n/languages/ar_EG.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'ar',\n  Pagination: {\n    items_per_page: '/ الصفحة',\n    jump_to: 'الذهاب إلى',\n    jump_to_confirm: 'تأكيد',\n    page: 'الصفحة',\n    prev_page: 'الصفحة السابقة',\n    next_page: 'الصفحة التالية',\n    prev_5: 'خمس صفحات سابقة',\n    next_5: 'خمس صفحات تالية',\n    prev_3: 'ثلاث صفحات سابقة',\n    next_3: 'ثلاث صفحات تالية',\n    page_size: 'مقاس الصفحه'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'اختيار التاريخ',\n      yearPlaceholder: 'اختيار السنة',\n      quarterPlaceholder: 'اختيار الربع',\n      monthPlaceholder: 'اختيار الشهر',\n      weekPlaceholder: 'اختيار الأسبوع',\n      rangePlaceholder: ['البداية', 'النهاية'],\n      rangeYearPlaceholder: ['سنة البداية', 'سنة النهاية'],\n      rangeMonthPlaceholder: ['شهر البداية', 'شهر النهاية'],\n      rangeWeekPlaceholder: ['أسبوع البداية', 'أسبوع النهاية'],\n      locale: 'ar_EG',\n      today: 'اليوم',\n      now: 'الأن',\n      backToToday: 'العودة إلى اليوم',\n      ok: 'تأكيد',\n      clear: 'مسح',\n      month: 'الشهر',\n      year: 'السنة',\n      timeSelect: 'اختيار الوقت',\n      dateSelect: 'اختيار التاريخ',\n      weekSelect: 'اختيار الأسبوع',\n      monthSelect: 'اختيار الشهر',\n      yearSelect: 'اختيار السنة',\n      decadeSelect: 'اختيار العقد',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'الشهر السابق (PageUp)',\n      nextMonth: 'الشهر التالى(PageDown)',\n      previousYear: 'العام السابق (Control + left)',\n      nextYear: 'العام التالى (Control + right)',\n      previousDecade: 'العقد السابق',\n      nextDecade: 'العقد التالى',\n      previousCentury: 'القرن السابق',\n      nextCentury: 'القرن التالى'\n    },\n    timePickerLocale: {\n      placeholder: 'اختيار الوقت'\n    },\n    dateFormat: 'DD-MM-YYYY',\n    monthFormat: 'MM-YYYY',\n    dateTimeFormat: 'DD-MM-YYYY HH:mm:ss',\n    weekFormat: 'wo-YYYY'\n  },\n  TimePicker: {\n    placeholder: 'اختيار الوقت'\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'اختيار التاريخ',\n      yearPlaceholder: 'اختيار السنة',\n      quarterPlaceholder: 'اختيار الربع',\n      monthPlaceholder: 'اختيار الشهر',\n      weekPlaceholder: 'اختيار الأسبوع',\n      rangePlaceholder: ['البداية', 'النهاية'],\n      rangeYearPlaceholder: ['سنة البداية', 'سنة النهاية'],\n      rangeMonthPlaceholder: ['شهر البداية', 'شهر النهاية'],\n      rangeWeekPlaceholder: ['أسبوع البداية', 'أسبوع النهاية'],\n      locale: 'ar_EG',\n      today: 'اليوم',\n      now: 'الأن',\n      backToToday: 'العودة إلى اليوم',\n      ok: 'تأكيد',\n      clear: 'مسح',\n      month: 'الشهر',\n      year: 'السنة',\n      timeSelect: 'اختيار الوقت',\n      dateSelect: 'اختيار التاريخ',\n      weekSelect: 'اختيار الأسبوع',\n      monthSelect: 'اختيار الشهر',\n      yearSelect: 'اختيار السنة',\n      decadeSelect: 'اختيار العقد',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'الشهر السابق (PageUp)',\n      nextMonth: 'الشهر التالى(PageDown)',\n      previousYear: 'العام السابق (Control + left)',\n      nextYear: 'العام التالى (Control + right)',\n      previousDecade: 'العقد السابق',\n      nextDecade: 'العقد التالى',\n      previousCentury: 'القرن السابق',\n      nextCentury: 'القرن التالى'\n    },\n    timePickerLocale: {\n      placeholder: 'اختيار الوقت'\n    },\n    dateFormat: 'DD-MM-YYYY',\n    monthFormat: 'MM-YYYY',\n    dateTimeFormat: 'DD-MM-YYYY HH:mm:ss',\n    weekFormat: 'wo-YYYY'\n  },\n  global: {\n    placeholder: 'يرجى التحديد'\n  },\n  Table: {\n    filterTitle: 'الفلاتر',\n    filterConfirm: 'تأكيد',\n    filterReset: 'إعادة ضبط',\n    selectAll: 'اختيار الكل',\n    selectInvert: 'إلغاء الاختيار',\n    selectionAll: 'حدد جميع البيانات',\n    sortTitle: 'رتب',\n    expand: 'توسيع الصف',\n    collapse: 'طي الصف',\n    triggerDesc: 'ترتيب تنازلي',\n    triggerAsc: 'ترتيب تصاعدي',\n    cancelSort: 'إلغاء الترتيب'\n  },\n  Modal: {\n    okText: 'تأكيد',\n    cancelText: 'إلغاء',\n    justOkText: 'تأكيد'\n  },\n  Popconfirm: {\n    okText: 'تأكيد',\n    cancelText: 'إلغاء'\n  },\n  Transfer: {\n    searchPlaceholder: 'ابحث هنا',\n    itemUnit: 'عنصر',\n    itemsUnit: 'عناصر'\n  },\n  Upload: {\n    uploading: 'جاري الرفع...',\n    removeFile: 'احذف الملف',\n    uploadError: 'مشكلة فى الرفع',\n    previewFile: 'استعرض الملف',\n    downloadFile: 'تحميل الملف'\n  },\n  Empty: {\n    description: 'لا توجد بيانات'\n  },\n  Form: {\n    optional: '(اختياري)'\n  },\n  Icon: {\n    icon: 'أيقونة'\n  },\n  Text: {\n    edit: 'تعديل',\n    copy: 'نسخ',\n    copied: 'نقل',\n    expand: 'وسع'\n  },\n  PageHeader: {\n    back: 'عودة'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/az_AZ.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'az',\n  Pagination: {\n    items_per_page: '/ səhifə',\n    jump_to: 'Get',\n    jump_to_confirm: 'təsdiqlə',\n    page: '',\n    prev_page: 'Əvvəlki Səhifə',\n    next_page: 'Növbəti Səhifə',\n    prev_5: 'Əvvəlki 5 Səhifə',\n    next_5: 'Növbəti 5 Səhifə',\n    prev_3: 'Əvvəlki 3 Səhifə',\n    next_3: 'Növbəti 3 Səhifə',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Tarix seçin',\n      rangePlaceholder: ['Başlama tarixi', 'Bitmə tarixi'],\n      locale: 'az_AZ',\n      today: 'Bugün',\n      now: 'İndi',\n      backToToday: 'Bugünə qayıt',\n      ok: 'Təsdiq',\n      clear: 'Təmizlə',\n      month: 'Ay',\n      year: 'İl',\n      timeSelect: 'vaxtı seç',\n      dateSelect: 'tarixi seç',\n      weekSelect: 'Həftə seç',\n      monthSelect: 'Ay seç',\n      yearSelect: 'il seç',\n      decadeSelect: 'Onillik seçin',\n      yearFormat: 'YYYY',\n      dateFormat: 'D.M.YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D.M.YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Əvvəlki ay (PageUp)',\n      nextMonth: 'Növbəti ay (PageDown)',\n      previousYear: 'Sonuncu il (Control + left)',\n      nextYear: 'Növbəti il (Control + right)',\n      previousDecade: 'Sonuncu onillik',\n      nextDecade: 'Növbəti onillik',\n      previousCentury: 'Sonuncu əsr',\n      nextCentury: 'Növbəti əsr'\n    },\n    timePickerLocale: {\n      placeholder: 'Vaxtı seç'\n    }\n  },\n  TimePicker: {\n    placeholder: 'Vaxtı seç'\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Tarix seçin',\n      rangePlaceholder: ['Başlama tarixi', 'Bitmə tarixi'],\n      locale: 'az_AZ',\n      today: 'Bugün',\n      now: 'İndi',\n      backToToday: 'Bugünə qayıt',\n      ok: 'Təsdiq',\n      clear: 'Təmizlə',\n      month: 'Ay',\n      year: 'İl',\n      timeSelect: 'vaxtı seç',\n      dateSelect: 'tarixi seç',\n      weekSelect: 'Həftə seç',\n      monthSelect: 'Ay seç',\n      yearSelect: 'il seç',\n      decadeSelect: 'Onillik seçin',\n      yearFormat: 'YYYY',\n      dateFormat: 'D.M.YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D.M.YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Əvvəlki ay (PageUp)',\n      nextMonth: 'Növbəti ay (PageDown)',\n      previousYear: 'Sonuncu il (Control + left)',\n      nextYear: 'Növbəti il (Control + right)',\n      previousDecade: 'Sonuncu onillik',\n      nextDecade: 'Növbəti onillik',\n      previousCentury: 'Sonuncu əsr',\n      nextCentury: 'Növbəti əsr'\n    },\n    timePickerLocale: {\n      placeholder: 'Vaxtı seç'\n    }\n  },\n  Table: {\n    filterTitle: 'Filter menyu',\n    filterConfirm: 'Axtar',\n    filterReset: 'Sıfırla',\n    emptyText: 'Məlumat yoxdur',\n    selectAll: 'Cari səhifəni seç',\n    selectInvert: 'Invert current page'\n  },\n  Modal: {\n    okText: 'Bəli',\n    cancelText: 'Ləğv et',\n    justOkText: 'Bəli'\n  },\n  Popconfirm: {\n    okText: 'Bəli',\n    cancelText: 'Ləğv et'\n  },\n  Transfer: {\n    titles: ['', ''],\n    notFoundContent: 'Tapılmadı',\n    searchPlaceholder: 'Burada axtar',\n    itemUnit: 'item',\n    itemsUnit: 'items'\n  },\n  Select: {\n    notFoundContent: 'Tapılmadı'\n  },\n  Upload: {\n    uploading: 'Yüklənir...',\n    removeFile: 'Faylı sil',\n    uploadError: 'Yükləmə xətası',\n    previewFile: 'Fayla önbaxış'\n  },\n  Form: {\n    optional: '(məcburi)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/bg_BG.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'bg',\n  Pagination: {\n    items_per_page: '/ страница',\n    jump_to: 'Към',\n    jump_to_confirm: 'потвърждавам',\n    page: '',\n    prev_page: 'Предишна страница',\n    next_page: 'Следваща страница',\n    prev_5: 'Предишни 5 страници',\n    next_5: 'Следващи 5 страници',\n    prev_3: 'Предишни 3 страници',\n    next_3: 'Следващи 3 страници',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Избор на дата',\n      rangePlaceholder: ['Начална', 'Крайна'],\n      locale: 'bg_BG',\n      today: 'Днес',\n      now: 'Сега',\n      backToToday: 'Към днес',\n      ok: 'Добре',\n      clear: 'Изчистване',\n      month: 'Месец',\n      year: 'Година',\n      timeSelect: 'Избор на час',\n      dateSelect: 'Избор на дата',\n      monthSelect: 'Избор на месец',\n      yearSelect: 'Избор на година',\n      decadeSelect: 'Десетилетие',\n      yearFormat: 'YYYY',\n      dateFormat: 'D M YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D M YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Предишен месец (PageUp)',\n      nextMonth: 'Следващ месец (PageDown)',\n      previousYear: 'Последна година (Control + left)',\n      nextYear: 'Следваща година (Control + right)',\n      previousDecade: 'Предишно десетилетие',\n      nextDecade: 'Следващо десетилетие',\n      previousCentury: 'Последен век',\n      nextCentury: 'Следващ век'\n    },\n    timePickerLocale: {\n      placeholder: 'Избор на час'\n    }\n  },\n  TimePicker: {\n    placeholder: 'Избор на час'\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Избор на дата',\n      rangePlaceholder: ['Начална', 'Крайна'],\n      locale: 'bg_BG',\n      today: 'Днес',\n      now: 'Сега',\n      backToToday: 'Към днес',\n      ok: 'Добре',\n      clear: 'Изчистване',\n      month: 'Месец',\n      year: 'Година',\n      timeSelect: 'Избор на час',\n      dateSelect: 'Избор на дата',\n      monthSelect: 'Избор на месец',\n      yearSelect: 'Избор на година',\n      decadeSelect: 'Десетилетие',\n      yearFormat: 'YYYY',\n      dateFormat: 'D M YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D M YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Предишен месец (PageUp)',\n      nextMonth: 'Следващ месец (PageDown)',\n      previousYear: 'Последна година (Control + left)',\n      nextYear: 'Следваща година (Control + right)',\n      previousDecade: 'Предишно десетилетие',\n      nextDecade: 'Следващо десетилетие',\n      previousCentury: 'Последен век',\n      nextCentury: 'Следващ век'\n    },\n    timePickerLocale: {\n      placeholder: 'Избор на час'\n    }\n  },\n  Table: {\n    filterTitle: 'Филтриране',\n    filterConfirm: 'Добре',\n    filterReset: 'Нулриане',\n    selectAll: 'Избор на текуща страница',\n    selectInvert: 'Обръщане'\n  },\n  Modal: {\n    okText: 'Добре',\n    cancelText: 'Отказ',\n    justOkText: 'Добре'\n  },\n  Popconfirm: {\n    okText: 'Добре',\n    cancelText: 'Отказ'\n  },\n  Transfer: {\n    searchPlaceholder: 'Търсене',\n    itemUnit: 'избор',\n    itemsUnit: 'избори'\n  },\n  Upload: {\n    uploading: 'Качване...',\n    removeFile: 'Премахване',\n    uploadError: 'Грешка при качването',\n    previewFile: 'Преглед',\n    downloadFile: 'Свали файл'\n  },\n  Empty: {\n    description: 'Няма данни'\n  },\n  Form: {\n    optional: '(незадължително)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/bn_BD.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'bn-bd',\n  Pagination: {\n    items_per_page: '/ পৃষ্ঠা',\n    jump_to: 'যাও',\n    jump_to_confirm: 'নিশ্চিত',\n    page: 'পৃষ্ঠা',\n    prev_page: 'আগের পৃষ্ঠা',\n    next_page: 'পরের পৃষ্ঠা',\n    prev_5: 'পূর্ববর্তী ৫ পৃষ্ঠা',\n    next_5: 'পরবর্তী ৫ পৃষ্ঠা',\n    prev_3: 'পূর্ববর্তী ৩ পৃষ্ঠা',\n    next_3: 'পরবর্তী ৩ পৃষ্ঠা',\n    page_size: 'পাতার আকার'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'তারিখ নির্বাচন',\n      yearPlaceholder: 'বছর নির্বাচন',\n      quarterPlaceholder: 'কোয়ার্টার নির্বাচন',\n      monthPlaceholder: 'মাস নির্বাচন',\n      weekPlaceholder: 'সপ্তাহ নির্বাচন',\n      rangePlaceholder: ['শুরুর তারিখ', 'শেষ তারিখ'],\n      rangeYearPlaceholder: ['শুরুর বছর', 'শেষ বছর'],\n      rangeMonthPlaceholder: ['শুরুর মাস', 'শেষ মাস'],\n      rangeWeekPlaceholder: ['শুরুর সপ্তাহ', 'শেষ সপ্তাহ'],\n      locale: 'bn_BD',\n      today: 'আজ',\n      now: 'এখন',\n      backToToday: 'আজকে ফিরে চলুন',\n      ok: 'ওকে',\n      clear: 'পরিস্কার',\n      month: 'মাস',\n      year: 'বছর',\n      timeSelect: 'সময় নির্বাচন',\n      dateSelect: 'তারিখ নির্বাচন',\n      weekSelect: 'সপ্তাহ পছন্দ করুন',\n      monthSelect: 'মাস পছন্দ করুন',\n      yearSelect: 'বছর পছন্দ করুন',\n      decadeSelect: 'একটি দশক পছন্দ করুন',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'গত মাস (PageUp)',\n      nextMonth: 'আগামী মাস (PageDown)',\n      previousYear: 'গত বছর (Control + left)',\n      nextYear: 'আগামী বছর (Control + right)',\n      previousDecade: 'গত দশক',\n      nextDecade: 'পরের দশক',\n      previousCentury: 'গত শতাব্দী',\n      nextCentury: 'পরের শতাব্দী'\n    },\n    timePickerLocale: {\n      placeholder: 'সময় নির্বাচন',\n      rangePlaceholder: ['সময় শুরু', 'শেষ সময়']\n    }\n  },\n  TimePicker: {\n    placeholder: 'সময় নির্বাচন',\n    rangePlaceholder: ['সময় শুরু', 'শেষ সময়']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'তারিখ নির্বাচন',\n      yearPlaceholder: 'বছর নির্বাচন',\n      quarterPlaceholder: 'কোয়ার্টার নির্বাচন',\n      monthPlaceholder: 'মাস নির্বাচন',\n      weekPlaceholder: 'সপ্তাহ নির্বাচন',\n      rangePlaceholder: ['শুরুর তারিখ', 'শেষ তারিখ'],\n      rangeYearPlaceholder: ['শুরুর বছর', 'শেষ বছর'],\n      rangeMonthPlaceholder: ['শুরুর মাস', 'শেষ মাস'],\n      rangeWeekPlaceholder: ['শুরুর সপ্তাহ', 'শেষ সপ্তাহ'],\n      locale: 'bn_BD',\n      today: 'আজ',\n      now: 'এখন',\n      backToToday: 'আজকে ফিরে চলুন',\n      ok: 'ওকে',\n      clear: 'পরিস্কার',\n      month: 'মাস',\n      year: 'বছর',\n      timeSelect: 'সময় নির্বাচন',\n      dateSelect: 'তারিখ নির্বাচন',\n      weekSelect: 'সপ্তাহ পছন্দ করুন',\n      monthSelect: 'মাস পছন্দ করুন',\n      yearSelect: 'বছর পছন্দ করুন',\n      decadeSelect: 'একটি দশক পছন্দ করুন',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'গত মাস (PageUp)',\n      nextMonth: 'আগামী মাস (PageDown)',\n      previousYear: 'গত বছর (Control + left)',\n      nextYear: 'আগামী বছর (Control + right)',\n      previousDecade: 'গত দশক',\n      nextDecade: 'পরের দশক',\n      previousCentury: 'গত শতাব্দী',\n      nextCentury: 'পরের শতাব্দী'\n    },\n    timePickerLocale: {\n      placeholder: 'সময় নির্বাচন',\n      rangePlaceholder: ['সময় শুরু', 'শেষ সময়']\n    }\n  },\n  global: {\n    placeholder: 'অনুগ্রহ করে নির্বাচন করুন'\n  },\n  Table: {\n    filterTitle: 'ফিল্টার মেনু',\n    filterConfirm: 'ঠিক',\n    filterReset: 'রিসেট',\n    filterEmptyText: 'ফিল্টার নেই',\n    emptyText: 'কোনও ডেটা নেই',\n    selectAll: 'বর্তমান পৃষ্ঠা নির্বাচন করুন',\n    selectInvert: 'বর্তমান পৃষ্ঠাটি উল্টে দিন',\n    selectNone: 'সমস্ত ডেটা সাফ করুন',\n    selectionAll: 'সমস্ত ডেটা নির্বাচন করুন',\n    sortTitle: 'সাজান',\n    expand: 'সারি প্রসারিত করুন',\n    collapse: 'সারি সঙ্কুচিত করুন',\n    triggerDesc: 'অবতরণকে সাজানোর জন্য ক্লিক করুন',\n    triggerAsc: 'আরোহী বাছাই করতে ক্লিক করুন',\n    cancelSort: 'বাছাই বাতিল করতে ক্লিক করুন'\n  },\n  Modal: {\n    okText: 'ঠিক',\n    cancelText: 'বাতিল',\n    justOkText: 'ঠিক'\n  },\n  Popconfirm: {\n    okText: 'ঠিক',\n    cancelText: 'বাতিল'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'এখানে অনুসন্ধান',\n    itemUnit: 'আইটেম',\n    itemsUnit: 'আইটেমসমূহ',\n    remove: 'অপসারণ',\n    selectCurrent: 'বর্তমান পৃষ্ঠা নির্বাচন করুন',\n    removeCurrent: 'বর্তমান পৃষ্ঠাটি সরান',\n    selectAll: 'সমস্ত ডেটা নির্বাচন করুন',\n    removeAll: 'সমস্ত ডেটা সরান',\n    selectInvert: 'বর্তমান পৃষ্ঠাটি উল্টে দিন'\n  },\n  Upload: {\n    uploading: 'আপলোড হচ্ছে ...',\n    removeFile: 'ফাইল সরান',\n    uploadError: 'আপলোডে সমস্যা',\n    previewFile: 'ফাইলের পূর্বরূপ',\n    downloadFile: 'ফাইল ডাউনলোড'\n  },\n  Empty: {\n    description: 'কোনও ডেটা নেই'\n  },\n  Form: {\n    optional: '(বাছাইযোগ্য)'\n  },\n  Icon: {\n    icon: 'আইকন'\n  },\n  Text: {\n    edit: 'সম্পাদনা',\n    copy: 'অনুলিপি',\n    copied: 'অনুলিপি হয়েছে',\n    expand: 'বিস্তৃত করা'\n  },\n  PageHeader: {\n    back: 'পেছনে'\n  },\n  Image: {\n    preview: 'পূর্বরূপ'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/by_BY.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'by',\n  Pagination: {\n    items_per_page: '/старонка',\n    jump_to: 'Перайсці',\n    jump_to_confirm: 'Пацвердзіць',\n    page: '',\n    prev_page: 'Назад',\n    next_page: 'Наперад',\n    prev_5: 'Папярэднія 5',\n    next_5: 'Наступныя 5',\n    prev_3: 'Папярэднія 3',\n    next_3: 'Наступныя 3',\n    page_size: 'памер старонкі'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Выберыце дату',\n      yearPlaceholder: 'Выберыце год',\n      quarterPlaceholder: 'Выберыце квартал',\n      monthPlaceholder: 'Выберыце месяц',\n      weekPlaceholder: 'Выберыце тыдзень',\n      rangePlaceholder: ['Пачатковая дата', 'Канчатковая дата'],\n      rangeYearPlaceholder: ['Пачатковы год', 'Год заканчэння'],\n      rangeMonthPlaceholder: ['Пачатковы месяц', 'Канчатковы месяц'],\n      rangeWeekPlaceholder: ['Пачатковы тыдзень', 'Канчатковы тыдзень'],\n      locale: 'by_BY',\n      today: 'Сёння',\n      now: 'Зараз',\n      backToToday: 'Дадзеная дата',\n      ok: 'Ok',\n      clear: 'Ачысціць',\n      month: 'Месяц',\n      year: 'Год',\n      timeSelect: 'Выбраць час',\n      dateSelect: 'Выбраць дату',\n      weekSelect: 'Выбраць тыдзень',\n      monthSelect: 'Выбраць месяц',\n      yearSelect: 'Выбраць год',\n      decadeSelect: 'Выбраць дзесяцігоддзе',\n      yearFormat: 'YYYY',\n      dateFormat: 'D-M-YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D-M-YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Папярэдні месяц (PageUp)',\n      nextMonth: 'Наступны месяц (PageDown)',\n      previousYear: 'Папярэдні год (Control + left)',\n      nextYear: 'Наступны год (Control + right)',\n      previousDecade: 'Папярэдняе дзесяцігоддзе',\n      nextDecade: 'Наступнае дзесяцігоддзе',\n      previousCentury: 'Папярэдні век',\n      nextCentury: 'Наступны век'\n    },\n    timePickerLocale: {\n      placeholder: 'Выберыце час',\n      rangePlaceholder: ['Час пачатку', 'Час заканчэння']\n    }\n  },\n  TimePicker: {\n    placeholder: 'Выберыце час',\n    rangePlaceholder: ['Час пачатку', 'Час заканчэння']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Выберыце дату',\n      yearPlaceholder: 'Выберыце год',\n      quarterPlaceholder: 'Выберыце квартал',\n      monthPlaceholder: 'Выберыце месяц',\n      weekPlaceholder: 'Выберыце тыдзень',\n      rangePlaceholder: ['Пачатковая дата', 'Канчатковая дата'],\n      rangeYearPlaceholder: ['Пачатковы год', 'Год заканчэння'],\n      rangeMonthPlaceholder: ['Пачатковы месяц', 'Канчатковы месяц'],\n      rangeWeekPlaceholder: ['Пачатковы тыдзень', 'Канчатковы тыдзень'],\n      locale: 'by_BY',\n      today: 'Сёння',\n      now: 'Зараз',\n      backToToday: 'Дадзеная дата',\n      ok: 'Ok',\n      clear: 'Ачысціць',\n      month: 'Месяц',\n      year: 'Год',\n      timeSelect: 'Выбраць час',\n      dateSelect: 'Выбраць дату',\n      weekSelect: 'Выбраць тыдзень',\n      monthSelect: 'Выбраць месяц',\n      yearSelect: 'Выбраць год',\n      decadeSelect: 'Выбраць дзесяцігоддзе',\n      yearFormat: 'YYYY',\n      dateFormat: 'D-M-YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D-M-YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Папярэдні месяц (PageUp)',\n      nextMonth: 'Наступны месяц (PageDown)',\n      previousYear: 'Папярэдні год (Control + left)',\n      nextYear: 'Наступны год (Control + right)',\n      previousDecade: 'Папярэдняе дзесяцігоддзе',\n      nextDecade: 'Наступнае дзесяцігоддзе',\n      previousCentury: 'Папярэдні век',\n      nextCentury: 'Наступны век'\n    },\n    timePickerLocale: {\n      placeholder: 'Выберыце час',\n      rangePlaceholder: ['Час пачатку', 'Час заканчэння']\n    }\n  },\n  global: {\n    placeholder: 'Калі ласка выберыце'\n  },\n  Table: {\n    filterTitle: 'Фільтр',\n    filterConfirm: 'OK',\n    filterReset: 'Скінуць',\n    filterEmptyText: 'Без фільтраў',\n    emptyText: 'Няма дадзеных',\n    selectAll: 'Выбраць усе',\n    selectInvert: 'Інвертаваць выбар',\n    selectionAll: 'Выбраць усе дадзеныя',\n    sortTitle: 'Сартаванне',\n    expand: 'Разгарнуць радок',\n    collapse: 'Згарнуць радок',\n    triggerDesc: 'Націсніце для сартавання па змяншэнні',\n    triggerAsc: 'Націсніце для сартавання па ўзросту',\n    cancelSort: 'Націсніце, каб адмяніць сартаванне'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Адмена',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Адмена'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'Пошук',\n    itemUnit: 'элем.',\n    itemsUnit: 'элем.',\n    remove: 'Выдаліць',\n    selectAll: 'Выбраць усе дадзеныя',\n    selectCurrent: 'Вылучыць дадзеную старонку',\n    selectInvert: 'Паказаць у зваротным парадку',\n    removeAll: 'Выдаліць усе дадзеныя',\n    removeCurrent: 'Выдаліць дадзеную старонку'\n  },\n  Upload: {\n    uploading: 'Загрузка...',\n    removeFile: 'Выдаліць файл',\n    uploadError: 'Адбылася памылка пры загрузцы',\n    previewFile: 'Прадпрагляд файла',\n    downloadFile: 'Загрузіць файл'\n  },\n  Form: {\n    optional: '(неабавязковы)'\n  },\n  Empty: {\n    description: 'Няма дадзеных'\n  },\n  Icon: {\n    icon: 'Іконка'\n  },\n  Text: {\n    edit: 'Рэдагаваць',\n    copy: 'Капіяваць',\n    copied: 'Капіяванне завершана',\n    expand: 'Разгарнуць'\n  },\n  PageHeader: {\n    back: 'Назад'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/ca_ES.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'ca',\n  Pagination: {\n    items_per_page: '/ pàgina',\n    jump_to: 'Anar a',\n    jump_to_confirm: 'Confirma',\n    page: '',\n    prev_page: 'Pàgina prèvia',\n    next_page: 'Pàgina següent',\n    prev_5: '5 pàgines prèvies',\n    next_5: '5 pàgines següents',\n    prev_3: '3 pàgines prèvies',\n    next_3: '3 pàgines següents',\n    page_size: 'mida de la pàgina'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Seleccionar data',\n      rangePlaceholder: ['Data inicial', 'Data final'],\n      locale: 'ca_ES',\n      today: 'Avui',\n      now: 'Ara',\n      backToToday: 'Tornar a avui',\n      ok: 'Acceptar',\n      clear: 'Netejar',\n      month: 'Mes',\n      year: 'Any',\n      timeSelect: 'Seleccionar hora',\n      dateSelect: 'Seleccionar data',\n      monthSelect: 'Escollir un mes',\n      yearSelect: 'Escollir un any',\n      decadeSelect: 'Escollir una dècada',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Mes anterior (PageUp)',\n      nextMonth: 'Mes següent (PageDown)',\n      previousYear: 'Any anterior (Control + left)',\n      nextYear: 'Mes següent (Control + right)',\n      previousDecade: 'Dècada anterior',\n      nextDecade: 'Dècada següent',\n      previousCentury: 'Segle anterior',\n      nextCentury: 'Segle següent'\n    },\n    timePickerLocale: {\n      placeholder: 'Seleccionar hora'\n    }\n  },\n  TimePicker: {\n    placeholder: 'Seleccionar hora'\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Seleccionar data',\n      rangePlaceholder: ['Data inicial', 'Data final'],\n      locale: 'ca_ES',\n      today: 'Avui',\n      now: 'Ara',\n      backToToday: 'Tornar a avui',\n      ok: 'Acceptar',\n      clear: 'Netejar',\n      month: 'Mes',\n      year: 'Any',\n      timeSelect: 'Seleccionar hora',\n      dateSelect: 'Seleccionar data',\n      monthSelect: 'Escollir un mes',\n      yearSelect: 'Escollir un any',\n      decadeSelect: 'Escollir una dècada',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Mes anterior (PageUp)',\n      nextMonth: 'Mes següent (PageDown)',\n      previousYear: 'Any anterior (Control + left)',\n      nextYear: 'Mes següent (Control + right)',\n      previousDecade: 'Dècada anterior',\n      nextDecade: 'Dècada següent',\n      previousCentury: 'Segle anterior',\n      nextCentury: 'Segle següent'\n    },\n    timePickerLocale: {\n      placeholder: 'Seleccionar hora'\n    }\n  },\n  global: {\n    placeholder: 'Seleccionar'\n  },\n  Table: {\n    filterTitle: 'Filtrar el menú',\n    filterConfirm: 'D’acord',\n    filterReset: 'Reiniciar',\n    filterEmptyText: 'Sense filtres',\n    selectAll: 'Seleccionar la pàgina actual',\n    selectInvert: 'Invertir la selecció',\n    selectionAll: 'Seleccionar-ho tot',\n    sortTitle: 'Ordenar',\n    expand: 'Ampliar la fila',\n    collapse: 'Plegar la fila',\n    triggerDesc: 'Ordre descendent',\n    triggerAsc: 'Ordre ascendent',\n    cancelSort: 'Desactivar l’ordre'\n  },\n  Modal: {\n    okText: 'D’acord',\n    cancelText: 'Cancel·lar',\n    justOkText: 'D’acord'\n  },\n  Popconfirm: {\n    okText: 'D’acord',\n    cancelText: 'Cancel·lar'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'Cercar',\n    itemUnit: 'ítem',\n    itemsUnit: 'ítems',\n    remove: 'Eliminar',\n    selectCurrent: 'Seleccionar la pàgina actual',\n    removeCurrent: 'Eliminar la selecció',\n    selectAll: 'Seleccionar-ho tot',\n    removeAll: 'Eliminar-ho tot',\n    selectInvert: 'Invertir la selecció'\n  },\n  Upload: {\n    uploading: 'Carregant…',\n    removeFile: 'Eliminar el fitxer',\n    uploadError: 'Error de càrrega',\n    previewFile: 'Vista prèvia del fitxer',\n    downloadFile: 'Baixar el fitxer'\n  },\n  Empty: {\n    description: 'Sense dades'\n  },\n  Form: {\n    optional: '(opcional)'\n  },\n  Icon: {\n    icon: 'icona'\n  },\n  Text: {\n    edit: 'Editar',\n    copy: 'Copiar',\n    copied: 'Copiat',\n    expand: 'Ampliar'\n  },\n  PageHeader: {\n    back: 'Enrere'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/cs_CZ.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'cs',\n  Pagination: {\n    items_per_page: '/ strana',\n    jump_to: 'Přejít',\n    jump_to_confirm: 'potvrdit',\n    page: 'strana',\n    prev_page: 'Předchozí strana',\n    next_page: 'Následující strana',\n    prev_5: 'Předchozích 5 stran',\n    next_5: 'Následujících 5 stran',\n    prev_3: 'Předchozí 3 strany',\n    next_3: 'Následující 3 strany',\n    page_size: 'velikost stránky'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Vybrat datum',\n      yearPlaceholder: 'Vyberte rok',\n      quarterPlaceholder: 'Vyberte čtvrtletí',\n      monthPlaceholder: 'Vyberte měsíc',\n      weekPlaceholder: 'Vyberte týden',\n      rangePlaceholder: ['Od', 'Do'],\n      rangeYearPlaceholder: ['Počáteční rok', 'Koncový rok'],\n      rangeQuarterPlaceholder: ['Počáteční čtvrtletí', 'Koncové čtvrtletí'],\n      rangeMonthPlaceholder: ['Počáteční měsíc', 'Koncový měsíc'],\n      rangeWeekPlaceholder: ['Počáteční týden', 'Koncový týden'],\n      locale: 'cs_CZ',\n      today: 'Dnes',\n      now: 'Nyní',\n      backToToday: 'Zpět na dnešek',\n      ok: 'Ok',\n      clear: 'Vymazat',\n      month: 'Měsíc',\n      year: 'Rok',\n      timeSelect: 'Vybrat čas',\n      dateSelect: 'Vybrat datum',\n      weekSelect: 'Vyberte týden',\n      monthSelect: 'Vyberte měsíc',\n      yearSelect: 'Vyberte rok',\n      decadeSelect: 'Vyberte dekádu',\n      yearFormat: 'YYYY',\n      dateFormat: 'D.M.YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D.M.YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Předchozí měsíc (PageUp)',\n      nextMonth: 'Následující (PageDown)',\n      previousYear: 'Předchozí rok (Control + left)',\n      nextYear: 'Následující rok (Control + right)',\n      previousDecade: 'Předchozí dekáda',\n      nextDecade: 'Následující dekáda',\n      previousCentury: 'Předchozí století',\n      nextCentury: 'Následující století'\n    },\n    timePickerLocale: {\n      placeholder: 'Vybrat čas',\n      rangePlaceholder: ['Počáteční čas', 'Koncový čas']\n    }\n  },\n  TimePicker: {\n    placeholder: 'Vybrat čas',\n    rangePlaceholder: ['Počáteční čas', 'Koncový čas']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Vybrat datum',\n      yearPlaceholder: 'Vyberte rok',\n      quarterPlaceholder: 'Vyberte čtvrtletí',\n      monthPlaceholder: 'Vyberte měsíc',\n      weekPlaceholder: 'Vyberte týden',\n      rangePlaceholder: ['Od', 'Do'],\n      rangeYearPlaceholder: ['Počáteční rok', 'Koncový rok'],\n      rangeMonthPlaceholder: ['Počáteční měsíc', 'Koncový měsíc'],\n      rangeWeekPlaceholder: ['Počáteční týden', 'Koncový týden'],\n      locale: 'cs_CZ',\n      today: 'Dnes',\n      now: 'Nyní',\n      backToToday: 'Zpět na dnešek',\n      ok: 'Ok',\n      clear: 'Vymazat',\n      month: 'Měsíc',\n      year: 'Rok',\n      timeSelect: 'Vybrat čas',\n      dateSelect: 'Vybrat datum',\n      weekSelect: 'Vyberte týden',\n      monthSelect: 'Vyberte měsíc',\n      yearSelect: 'Vyberte rok',\n      decadeSelect: 'Vyberte dekádu',\n      yearFormat: 'YYYY',\n      dateFormat: 'D.M.YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D.M.YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Předchozí měsíc (PageUp)',\n      nextMonth: 'Následující (PageDown)',\n      previousYear: 'Předchozí rok (Control + left)',\n      nextYear: 'Následující rok (Control + right)',\n      previousDecade: 'Předchozí dekáda',\n      nextDecade: 'Následující dekáda',\n      previousCentury: 'Předchozí století',\n      nextCentury: 'Následující století'\n    },\n    timePickerLocale: {\n      placeholder: 'Vybrat čas',\n      rangePlaceholder: ['Počáteční čas', 'Koncový čas']\n    }\n  },\n  global: {\n    placeholder: 'Prosím vyber'\n  },\n  Table: {\n    filterTitle: 'Filtr',\n    filterConfirm: 'Potvrdit',\n    filterReset: 'Obnovit',\n    filterEmptyText: 'Žádné filtry',\n    emptyText: 'Žádná data',\n    selectAll: 'Vybrat všechny řádky na současné stránce',\n    selectInvert: 'Invertovat výběr na současné stránce',\n    selectionAll: 'Vybrat všechny řádky',\n    sortTitle: 'Řadit',\n    expand: 'Rozbalit řádek',\n    collapse: 'Zabalit řádek',\n    triggerDesc: 'Klikni pro sestupné řazení',\n    triggerAsc: 'Klikni pro vzestupné řazení',\n    cancelSort: 'Klikni pro zrušení řazení',\n    filterCheckall: 'Vybrat všechny položky',\n    filterSearchPlaceholder: 'Hledat ve filtrech',\n    selectNone: 'Zrušit výběr všech dat'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Storno',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Storno'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'Vyhledávání',\n    itemUnit: 'položka',\n    itemsUnit: 'položek',\n    remove: 'Odebrat',\n    selectCurrent: 'Vybrat současnou stránku',\n    removeCurrent: 'Odebrat současnou stránku',\n    selectAll: 'Vybrat všechna data',\n    removeAll: 'Odebrat všechna data',\n    selectInvert: 'Invertovat současnou stránku'\n  },\n  Upload: {\n    uploading: 'Nahrávání...',\n    removeFile: 'Odstranit soubor',\n    uploadError: 'Chyba při nahrávání',\n    previewFile: 'Zobrazit soubor',\n    downloadFile: 'Stáhnout soubor'\n  },\n  Empty: {\n    description: 'Žádná data'\n  },\n  Form: {\n    optional: '(nepovinné)'\n  },\n  Icon: {\n    icon: 'ikona'\n  },\n  Text: {\n    edit: 'Upravit',\n    copy: 'Kopírovat',\n    copied: 'Zkopírováno',\n    expand: 'Rozbalit'\n  },\n  PageHeader: {\n    back: 'Zpět'\n  },\n  Image: {\n    preview: 'Náhled'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/da_DK.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'da',\n  DatePicker: {\n    lang: {\n      placeholder: 'Vælg dato',\n      rangePlaceholder: ['Startdato', 'Slutdato'],\n      locale: 'da_DK',\n      today: 'I dag',\n      now: 'Nu',\n      backToToday: 'Gå til i dag',\n      ok: 'Ok',\n      clear: 'Ryd',\n      month: 'Måned',\n      year: 'År',\n      timeSelect: 'Vælg tidspunkt',\n      dateSelect: 'Vælg dato',\n      monthSelect: 'Vælg måned',\n      yearSelect: 'Vælg år',\n      decadeSelect: 'Vælg årti',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Forrige måned (Page Up)',\n      nextMonth: 'Næste måned (Page Down)',\n      previousYear: 'Forrige år (Ctrl-venstre pil)',\n      nextYear: 'Næste år (Ctrl-højre pil)',\n      previousDecade: 'Forrige årti',\n      nextDecade: 'Næste årti',\n      previousCentury: 'Forrige århundrede',\n      nextCentury: 'Næste århundrede'\n    },\n    timePickerLocale: {\n      placeholder: 'Vælg tid',\n      rangePlaceholder: ['Starttidspunkt', 'Sluttidspunkt']\n    }\n  },\n  TimePicker: {\n    placeholder: 'Vælg tid',\n    rangePlaceholder: ['Starttidspunkt', 'Sluttidspunkt']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Vælg dato',\n      rangePlaceholder: ['Startdato', 'Slutdato'],\n      locale: 'da_DK',\n      today: 'I dag',\n      now: 'Nu',\n      backToToday: 'Gå til i dag',\n      ok: 'Ok',\n      clear: 'Ryd',\n      month: 'Måned',\n      year: 'År',\n      timeSelect: 'Vælg tidspunkt',\n      dateSelect: 'Vælg dato',\n      monthSelect: 'Vælg måned',\n      yearSelect: 'Vælg år',\n      decadeSelect: 'Vælg årti',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Forrige måned (Page Up)',\n      nextMonth: 'Næste måned (Page Down)',\n      previousYear: 'Forrige år (Ctrl-venstre pil)',\n      nextYear: 'Næste år (Ctrl-højre pil)',\n      previousDecade: 'Forrige årti',\n      nextDecade: 'Næste årti',\n      previousCentury: 'Forrige århundrede',\n      nextCentury: 'Næste århundrede'\n    },\n    timePickerLocale: {\n      placeholder: 'Vælg tid',\n      rangePlaceholder: ['Starttidspunkt', 'Sluttidspunkt']\n    }\n  },\n  Pagination: {\n    items_per_page: '/ side',\n    jump_to: 'Gå til',\n    jump_to_confirm: 'bekræft',\n    page: 'Side',\n    prev_page: 'Forrige Side',\n    next_page: 'Næste Side',\n    prev_5: 'Forrige 5 Sider',\n    next_5: 'Næste 5 Sider',\n    prev_3: 'Forrige 3 Sider',\n    next_3: 'Næste 3 Sider',\n    page_size: 'sidestørrelse'\n  },\n  Table: {\n    filterTitle: 'Filtermenu',\n    filterConfirm: 'OK',\n    filterReset: 'Nulstil',\n    selectAll: 'Vælg alle',\n    selectInvert: 'Invertér valg',\n    filterEmptyText: 'Ingen filtre',\n    emptyText: 'Ingen data',\n    selectNone: 'Ryd alt data',\n    selectionAll: 'Vælg alt data',\n    sortTitle: 'Sortér',\n    expand: 'Udvid række',\n    collapse: 'Flet række',\n    triggerDesc: 'Klik for at sortere faldende',\n    triggerAsc: 'Klik for at sortere stigende',\n    cancelSort: 'Klik for at annullere sortering'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Afbryd',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Afbryd'\n  },\n  Transfer: {\n    searchPlaceholder: 'Søg her',\n    itemUnit: 'element',\n    itemsUnit: 'elementer'\n  },\n  Upload: {\n    uploading: 'Uploader...',\n    removeFile: 'Fjern fil',\n    uploadError: 'Fejl ved upload',\n    previewFile: 'Forhåndsvisning',\n    downloadFile: 'Download fil'\n  },\n  Empty: {\n    description: 'Ingen data'\n  },\n  Form: {\n    optional: '(valgfrit)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/de_DE.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'de',\n  Pagination: {\n    items_per_page: '/ Seite',\n    jump_to: 'Gehe zu',\n    jump_to_confirm: 'bestätigen',\n    page: 'Seite',\n    prev_page: 'Vorherige Seite',\n    next_page: 'Nächste Seite',\n    prev_5: '5 Seiten zurück',\n    next_5: '5 Seiten vor',\n    prev_3: '3 Seiten zurück',\n    next_3: '3 Seiten vor',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Datum auswählen',\n      yearPlaceholder: 'Jahr auswählen',\n      quarterPlaceholder: 'Quartal auswählen',\n      monthPlaceholder: 'Monat auswählen',\n      weekPlaceholder: 'Woche auswählen',\n      rangePlaceholder: ['Startdatum', 'Enddatum'],\n      rangeYearPlaceholder: ['Startjahr', 'Endjahr'],\n      rangeQuarterPlaceholder: ['Startquartal', 'Endquartal'],\n      rangeMonthPlaceholder: ['Startmonat', 'Endmonat'],\n      rangeWeekPlaceholder: ['Startwoche', 'Endwoche'],\n      locale: 'de_DE',\n      today: 'Heute',\n      now: 'Jetzt',\n      backToToday: 'Zurück zu Heute',\n      ok: 'OK',\n      clear: 'Zurücksetzen',\n      month: 'Monat',\n      year: 'Jahr',\n      timeSelect: 'Zeit wählen',\n      dateSelect: 'Datum wählen',\n      weekSelect: 'Woche wählen',\n      monthSelect: 'Wähle einen Monat',\n      yearSelect: 'Wähle ein Jahr',\n      decadeSelect: 'Wähle ein Jahrzehnt',\n      yearFormat: 'YYYY',\n      dateFormat: 'D.M.YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D.M.YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Vorheriger Monat (PageUp)',\n      nextMonth: 'Nächster Monat (PageDown)',\n      previousYear: 'Vorheriges Jahr (Strg + links)',\n      nextYear: 'Nächstes Jahr (Strg + rechts)',\n      previousDecade: 'Vorheriges Jahrzehnt',\n      nextDecade: 'Nächstes Jahrzehnt',\n      previousCentury: 'Vorheriges Jahrhundert',\n      nextCentury: 'Nächstes Jahrhundert'\n    },\n    timePickerLocale: {\n      placeholder: 'Zeit auswählen',\n      rangePlaceholder: ['Startzeit', 'Endzeit']\n    }\n  },\n  TimePicker: {\n    placeholder: 'Zeit auswählen',\n    rangePlaceholder: ['Startzeit', 'Endzeit']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Datum auswählen',\n      yearPlaceholder: 'Jahr auswählen',\n      quarterPlaceholder: 'Quartal auswählen',\n      monthPlaceholder: 'Monat auswählen',\n      weekPlaceholder: 'Woche auswählen',\n      rangePlaceholder: ['Startdatum', 'Enddatum'],\n      rangeYearPlaceholder: ['Startjahr', 'Endjahr'],\n      rangeMonthPlaceholder: ['Startmonat', 'Endmonat'],\n      rangeWeekPlaceholder: ['Startwoche', 'Endwoche'],\n      locale: 'de_DE',\n      today: 'Heute',\n      now: 'Jetzt',\n      backToToday: 'Zurück zu Heute',\n      ok: 'OK',\n      clear: 'Zurücksetzen',\n      month: 'Monat',\n      year: 'Jahr',\n      timeSelect: 'Zeit wählen',\n      dateSelect: 'Datum wählen',\n      weekSelect: 'Woche wählen',\n      monthSelect: 'Wähle einen Monat',\n      yearSelect: 'Wähle ein Jahr',\n      decadeSelect: 'Wähle ein Jahrzehnt',\n      yearFormat: 'YYYY',\n      dateFormat: 'D.M.YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D.M.YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Vorheriger Monat (PageUp)',\n      nextMonth: 'Nächster Monat (PageDown)',\n      previousYear: 'Vorheriges Jahr (Ctrl + left)',\n      nextYear: 'Nächstes Jahr (Ctrl + right)',\n      previousDecade: 'Vorheriges Jahrzehnt',\n      nextDecade: 'Nächstes Jahrzehnt',\n      previousCentury: 'Vorheriges Jahrhundert',\n      nextCentury: 'Nächstes Jahrhundert'\n    },\n    timePickerLocale: {\n      placeholder: 'Zeit auswählen',\n      rangePlaceholder: ['Startzeit', 'Endzeit']\n    }\n  },\n  global: {\n    placeholder: 'Bitte auswählen'\n  },\n  Table: {\n    filterTitle: 'Filter-Menü',\n    filterConfirm: 'OK',\n    filterReset: 'Zurücksetzen',\n    filterEmptyText: 'Keine Filter',\n    emptyText: 'Keine Daten',\n    selectAll: 'Selektiere Alle',\n    selectInvert: 'Selektion Invertieren',\n    selectionAll: 'Wählen Sie alle Daten aus',\n    sortTitle: 'Sortieren',\n    expand: 'Zeile erweitern',\n    collapse: 'Zeile reduzieren',\n    triggerDesc: 'Klicken zur absteigenden  Sortierung',\n    triggerAsc: 'Klicken zur aufsteigenden Sortierung',\n    cancelSort: 'Klicken zum Abbrechen der Sortierung',\n    filterCheckall: 'Alle Elemente anwählen',\n    filterSearchPlaceholder: 'In Filterung suchen',\n    selectNone: 'Alles löschen'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Abbrechen',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Abbrechen'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'Suchen',\n    itemUnit: 'Eintrag',\n    itemsUnit: 'Einträge',\n    remove: 'Entfernen',\n    selectCurrent: 'Alle auf aktueller Seite auswählen',\n    removeCurrent: 'Auswahl auf aktueller Seite aufheben',\n    selectAll: 'Alle auswählen',\n    removeAll: 'Auswahl aufheben',\n    selectInvert: 'Auswahl umkehren'\n  },\n  Upload: {\n    uploading: 'Hochladen...',\n    removeFile: 'Datei entfernen',\n    uploadError: 'Fehler beim Hochladen',\n    previewFile: 'Dateivorschau',\n    downloadFile: 'Download-Datei'\n  },\n  Empty: {\n    description: 'Keine Daten'\n  },\n  Form: {\n    optional: '(optional)'\n  },\n  Icon: {\n    icon: 'Symbol'\n  },\n  Text: {\n    edit: 'Bearbeiten',\n    copy: 'Kopieren',\n    copied: 'Kopiert',\n    expand: 'Erweitern'\n  },\n  PageHeader: {\n    back: 'Zurück'\n  },\n  Image: {\n    preview: 'Vorschau'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/default.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'en',\n  Pagination: {\n    items_per_page: '/ page',\n    jump_to: 'Go to',\n    jump_to_confirm: 'confirm',\n    page: 'Page',\n    prev_page: 'Previous Page',\n    next_page: 'Next Page',\n    prev_5: 'Previous 5 Pages',\n    next_5: 'Next 5 Pages',\n    prev_3: 'Previous 3 Pages',\n    next_3: 'Next 3 Pages',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Select date',\n      yearPlaceholder: 'Select year',\n      quarterPlaceholder: 'Select quarter',\n      monthPlaceholder: 'Select month',\n      weekPlaceholder: 'Select week',\n      rangePlaceholder: ['Start date', 'End date'],\n      rangeYearPlaceholder: ['Start year', 'End year'],\n      rangeQuarterPlaceholder: ['Start quarter', 'End quarter'],\n      rangeMonthPlaceholder: ['Start month', 'End month'],\n      rangeWeekPlaceholder: ['Start week', 'End week'],\n      locale: 'en_US',\n      today: 'Today',\n      now: 'Now',\n      backToToday: 'Back to today',\n      ok: 'Ok',\n      clear: 'Clear',\n      month: 'Month',\n      year: 'Year',\n      timeSelect: 'select time',\n      dateSelect: 'select date',\n      weekSelect: 'Choose a week',\n      monthSelect: 'Choose a month',\n      yearSelect: 'Choose a year',\n      decadeSelect: 'Choose a decade',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Previous month (PageUp)',\n      nextMonth: 'Next month (PageDown)',\n      previousYear: 'Last year (Control + left)',\n      nextYear: 'Next year (Control + right)',\n      previousDecade: 'Last decade',\n      nextDecade: 'Next decade',\n      previousCentury: 'Last century',\n      nextCentury: 'Next century'\n    },\n    timePickerLocale: {\n      placeholder: 'Select time',\n      rangePlaceholder: ['Start time', 'End time']\n    }\n  },\n  TimePicker: {\n    placeholder: 'Select time',\n    rangePlaceholder: ['Start time', 'End time']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Select date',\n      yearPlaceholder: 'Select year',\n      quarterPlaceholder: 'Select quarter',\n      monthPlaceholder: 'Select month',\n      weekPlaceholder: 'Select week',\n      rangePlaceholder: ['Start date', 'End date'],\n      rangeYearPlaceholder: ['Start year', 'End year'],\n      rangeMonthPlaceholder: ['Start month', 'End month'],\n      rangeWeekPlaceholder: ['Start week', 'End week'],\n      locale: 'en_US',\n      today: 'Today',\n      now: 'Now',\n      backToToday: 'Back to today',\n      ok: 'Ok',\n      clear: 'Clear',\n      month: 'Month',\n      year: 'Year',\n      timeSelect: 'select time',\n      dateSelect: 'select date',\n      weekSelect: 'Choose a week',\n      monthSelect: 'Choose a month',\n      yearSelect: 'Choose a year',\n      decadeSelect: 'Choose a decade',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Previous month (PageUp)',\n      nextMonth: 'Next month (PageDown)',\n      previousYear: 'Last year (Control + left)',\n      nextYear: 'Next year (Control + right)',\n      previousDecade: 'Last decade',\n      nextDecade: 'Next decade',\n      previousCentury: 'Last century',\n      nextCentury: 'Next century'\n    },\n    timePickerLocale: {\n      placeholder: 'Select time',\n      rangePlaceholder: ['Start time', 'End time']\n    }\n  },\n  global: {\n    placeholder: 'Please select'\n  },\n  Table: {\n    filterTitle: 'Filter menu',\n    filterConfirm: 'OK',\n    filterReset: 'Reset',\n    filterEmptyText: 'No filters',\n    emptyText: 'No data',\n    selectAll: 'Select current page',\n    selectInvert: 'Invert current page',\n    selectionAll: 'Select all data',\n    sortTitle: 'Sort',\n    expand: 'Expand row',\n    collapse: 'Collapse row',\n    triggerDesc: 'Click to sort descending',\n    triggerAsc: 'Click to sort ascending',\n    cancelSort: 'Click to cancel sorting',\n    filterCheckall: 'Select all items',\n    filterSearchPlaceholder: 'Search in filters',\n    selectNone: 'Clear all data'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Cancel',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Cancel'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'Search here',\n    itemUnit: 'item',\n    itemsUnit: 'items',\n    remove: 'Remove',\n    selectCurrent: 'Select current page',\n    removeCurrent: 'Remove current page',\n    selectAll: 'Select all data',\n    removeAll: 'Remove all data',\n    selectInvert: 'Invert current page'\n  },\n  Upload: {\n    uploading: 'Uploading...',\n    removeFile: 'Remove file',\n    uploadError: 'Upload error',\n    previewFile: 'Preview file',\n    downloadFile: 'Download file'\n  },\n  Empty: {\n    description: 'No Data'\n  },\n  Form: {\n    optional: '(optional)'\n  },\n  Icon: {\n    icon: 'icon'\n  },\n  Text: {\n    edit: 'Edit',\n    copy: 'Copy',\n    copied: 'Copied',\n    expand: 'Expand'\n  },\n  PageHeader: {\n    back: 'Back'\n  },\n  Image: {\n    preview: 'Preview'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/el_GR.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'el',\n  Pagination: {\n    items_per_page: '/ σελίδα',\n    jump_to: 'Μετάβαση',\n    jump_to_confirm: 'επιβεβαιώνω',\n    page: '',\n    prev_page: 'Προηγούμενη Σελίδα',\n    next_page: 'Επόμενη Σελίδα',\n    prev_5: 'Προηγούμενες 5 Σελίδες',\n    next_5: 'Επόμενες 5 σελίδες',\n    prev_3: 'Προηγούμενες 3 Σελίδες',\n    next_3: 'Επόμενες 3 Σελίδες',\n    page_size: 'Μέγεθος σελίδας'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Επιλέξτε ημερομηνία',\n      yearPlaceholder: 'Επιλέξτε χρονιά',\n      quarterPlaceholder: 'Επιλέξτε τρίμηνο',\n      monthPlaceholder: 'Επιλέξτε μήνα',\n      weekPlaceholder: 'Επιλέξτε εβδομάδα',\n      rangePlaceholder: ['Αρχική ημερομηνία', 'Τελική ημερομηνία'],\n      rangeYearPlaceholder: ['Αρχική χρονιά', 'Τελική χρονιά'],\n      rangeMonthPlaceholder: ['Αρχικός μήνας', 'Τελικός μήνας'],\n      rangeWeekPlaceholder: ['Αρχική εβδομάδα', 'Τελική εβδομάδα'],\n      locale: 'el_GR',\n      today: 'Σήμερα',\n      now: 'Τώρα',\n      backToToday: 'Πίσω στη σημερινή μέρα',\n      ok: 'Ok',\n      clear: 'Καθαρισμός',\n      month: 'Μήνας',\n      year: 'Έτος',\n      timeSelect: 'Επιλογή ώρας',\n      dateSelect: 'Επιλογή ημερομηνίας',\n      weekSelect: 'Επιλογή εβδομάδας',\n      monthSelect: 'Επιλογή μήνα',\n      yearSelect: 'Επιλογή έτους',\n      decadeSelect: 'Επιλογή δεκαετίας',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Προηγούμενος μήνας (PageUp)',\n      nextMonth: 'Επόμενος μήνας (PageDown)',\n      previousYear: 'Προηγούμενο έτος (Control + αριστερά)',\n      nextYear: 'Επόμενο έτος (Control + δεξιά)',\n      previousDecade: 'Προηγούμενη δεκαετία',\n      nextDecade: 'Επόμενη δεκαετία',\n      previousCentury: 'Προηγούμενος αιώνας',\n      nextCentury: 'Επόμενος αιώνας'\n    },\n    timePickerLocale: {\n      placeholder: 'Επιλέξτε ώρα',\n      rangePlaceholder: ['Ώρα έναρξης', 'Ώρα λήξης']\n    }\n  },\n  TimePicker: {\n    placeholder: 'Επιλέξτε ώρα',\n    rangePlaceholder: ['Ώρα έναρξης', 'Ώρα λήξης']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Επιλέξτε ημερομηνία',\n      yearPlaceholder: 'Επιλέξτε χρονιά',\n      quarterPlaceholder: 'Επιλέξτε τρίμηνο',\n      monthPlaceholder: 'Επιλέξτε μήνα',\n      weekPlaceholder: 'Επιλέξτε εβδομάδα',\n      rangePlaceholder: ['Αρχική ημερομηνία', 'Τελική ημερομηνία'],\n      rangeYearPlaceholder: ['Αρχική χρονιά', 'Τελική χρονιά'],\n      rangeMonthPlaceholder: ['Αρχικός μήνας', 'Τελικός μήνας'],\n      rangeWeekPlaceholder: ['Αρχική εβδομάδα', 'Τελική εβδομάδα'],\n      locale: 'el_GR',\n      today: 'Σήμερα',\n      now: 'Τώρα',\n      backToToday: 'Πίσω στη σημερινή μέρα',\n      ok: 'Ok',\n      clear: 'Καθαρισμός',\n      month: 'Μήνας',\n      year: 'Έτος',\n      timeSelect: 'Επιλογή ώρας',\n      dateSelect: 'Επιλογή ημερομηνίας',\n      weekSelect: 'Επιλογή εβδομάδας',\n      monthSelect: 'Επιλογή μήνα',\n      yearSelect: 'Επιλογή έτους',\n      decadeSelect: 'Επιλογή δεκαετίας',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Προηγούμενος μήνας (PageUp)',\n      nextMonth: 'Επόμενος μήνας (PageDown)',\n      previousYear: 'Προηγούμενο έτος (Control + αριστερά)',\n      nextYear: 'Επόμενο έτος (Control + δεξιά)',\n      previousDecade: 'Προηγούμενη δεκαετία',\n      nextDecade: 'Επόμενη δεκαετία',\n      previousCentury: 'Προηγούμενος αιώνας',\n      nextCentury: 'Επόμενος αιώνας'\n    },\n    timePickerLocale: {\n      placeholder: 'Επιλέξτε ώρα',\n      rangePlaceholder: ['Ώρα έναρξης', 'Ώρα λήξης']\n    }\n  },\n  Table: {\n    filterTitle: 'Μενού φίλτρων',\n    filterConfirm: 'ΟΚ',\n    filterReset: 'Επαναφορά',\n    selectAll: 'Επιλογή τρέχουσας σελίδας',\n    selectInvert: 'Αντιστροφή τρέχουσας σελίδας'\n  },\n  Modal: {\n    okText: 'ΟΚ',\n    cancelText: 'Άκυρο',\n    justOkText: 'ΟΚ'\n  },\n  Popconfirm: {\n    okText: 'ΟΚ',\n    cancelText: 'Άκυρο'\n  },\n  Transfer: {\n    searchPlaceholder: 'Αναζήτηση',\n    itemUnit: 'αντικείμενο',\n    itemsUnit: 'αντικείμενα'\n  },\n  Upload: {\n    uploading: 'Μεταφόρτωση...',\n    removeFile: 'Αφαίρεση αρχείου',\n    uploadError: 'Σφάλμα μεταφόρτωσης',\n    previewFile: 'Προεπισκόπηση αρχείου',\n    downloadFile: 'Λήψη αρχείου'\n  },\n  Empty: {\n    description: 'Δεν υπάρχουν δεδομένα'\n  },\n  Form: {\n    optional: '(ανάγκη)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/en_AU.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'en-au',\n  Pagination: {\n    items_per_page: '/ page',\n    jump_to: 'Go to',\n    jump_to_confirm: 'confirm',\n    page: 'Page',\n    prev_page: 'Previous Page',\n    next_page: 'Next Page',\n    prev_5: 'Previous 5 Pages',\n    next_5: 'Next 5 Pages',\n    prev_3: 'Previous 3 Pages',\n    next_3: 'Next 3 Pages',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Select date',\n      yearPlaceholder: 'Select year',\n      quarterPlaceholder: 'Select quarter',\n      monthPlaceholder: 'Select month',\n      weekPlaceholder: 'Select week',\n      rangePlaceholder: ['Start date', 'End date'],\n      rangeYearPlaceholder: ['Start year', 'End year'],\n      rangeMonthPlaceholder: ['Start month', 'End month'],\n      rangeWeekPlaceholder: ['Start week', 'End week'],\n      locale: 'en_AU',\n      today: 'Today',\n      now: 'Now',\n      backToToday: 'Back to today',\n      ok: 'Ok',\n      clear: 'Clear',\n      month: 'Month',\n      year: 'Year',\n      timeSelect: 'select time',\n      dateSelect: 'select date',\n      weekSelect: 'Choose a week',\n      monthSelect: 'Choose a month',\n      yearSelect: 'Choose a year',\n      decadeSelect: 'Choose a decade',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Previous month (PageUp)',\n      nextMonth: 'Next month (PageDown)',\n      previousYear: 'Last year (Control + left)',\n      nextYear: 'Next year (Control + right)',\n      previousDecade: 'Last decade',\n      nextDecade: 'Next decade',\n      previousCentury: 'Last century',\n      nextCentury: 'Next century'\n    },\n    timePickerLocale: {\n      placeholder: 'Select time',\n      rangePlaceholder: ['Start time', 'End time']\n    }\n  },\n  TimePicker: {\n    placeholder: 'Select time',\n    rangePlaceholder: ['Start time', 'End time']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Select date',\n      yearPlaceholder: 'Select year',\n      quarterPlaceholder: 'Select quarter',\n      monthPlaceholder: 'Select month',\n      weekPlaceholder: 'Select week',\n      rangePlaceholder: ['Start date', 'End date'],\n      rangeYearPlaceholder: ['Start year', 'End year'],\n      rangeMonthPlaceholder: ['Start month', 'End month'],\n      rangeWeekPlaceholder: ['Start week', 'End week'],\n      locale: 'en_AU',\n      today: 'Today',\n      now: 'Now',\n      backToToday: 'Back to today',\n      ok: 'Ok',\n      clear: 'Clear',\n      month: 'Month',\n      year: 'Year',\n      timeSelect: 'select time',\n      dateSelect: 'select date',\n      weekSelect: 'Choose a week',\n      monthSelect: 'Choose a month',\n      yearSelect: 'Choose a year',\n      decadeSelect: 'Choose a decade',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Previous month (PageUp)',\n      nextMonth: 'Next month (PageDown)',\n      previousYear: 'Last year (Control + left)',\n      nextYear: 'Next year (Control + right)',\n      previousDecade: 'Last decade',\n      nextDecade: 'Next decade',\n      previousCentury: 'Last century',\n      nextCentury: 'Next century'\n    },\n    timePickerLocale: {\n      placeholder: 'Select time',\n      rangePlaceholder: ['Start time', 'End time']\n    }\n  },\n  global: {\n    placeholder: 'Please select'\n  },\n  Table: {\n    filterTitle: 'Filter menu',\n    filterConfirm: 'OK',\n    filterReset: 'Reset',\n    filterEmptyText: 'No filters',\n    emptyText: 'No data',\n    selectAll: 'Select current page',\n    selectInvert: 'Invert current page',\n    selectionAll: 'Select all data',\n    sortTitle: 'Sort',\n    expand: 'Expand row',\n    collapse: 'Collapse row',\n    triggerDesc: 'Click to sort descending',\n    triggerAsc: 'Click to sort ascending',\n    cancelSort: 'Click to cancel sorting',\n    filterCheckall: 'Select all items',\n    filterSearchPlaceholder: 'Search in filters',\n    selectNone: 'Clear all data'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Cancel',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Cancel'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'Search here',\n    itemUnit: 'item',\n    itemsUnit: 'items',\n    remove: 'Remove',\n    selectCurrent: 'Select current page',\n    removeCurrent: 'Remove current page',\n    selectAll: 'Select all data',\n    removeAll: 'Remove all data',\n    selectInvert: 'Invert current page'\n  },\n  Upload: {\n    uploading: 'Uploading...',\n    removeFile: 'Remove file',\n    uploadError: 'Upload error',\n    previewFile: 'Preview file',\n    downloadFile: 'Download file'\n  },\n  Empty: {\n    description: 'No Data'\n  },\n  Form: {\n    optional: '(optional)'\n  },\n  Icon: {\n    icon: 'icon'\n  },\n  Text: {\n    edit: 'Edit',\n    copy: 'Copy',\n    copied: 'Copied',\n    expand: 'Expand'\n  },\n  PageHeader: {\n    back: 'Back'\n  },\n  Image: {\n    preview: 'Preview'\n  },\n  CronExpression: {\n    cronError: 'Invalid cron expression',\n    second: 'second',\n    minute: 'minute',\n    hour: 'hour',\n    day: 'day',\n    month: 'month',\n    week: 'week'\n  },\n  QRCode: {\n    expired: 'QR code expired',\n    refresh: 'Refresh',\n    scanned: 'Scanned'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/en_GB.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'en-gb',\n  Pagination: {\n    items_per_page: '/ page',\n    jump_to: 'Go to',\n    jump_to_confirm: 'confirm',\n    page: 'Page',\n    prev_page: 'Previous Page',\n    next_page: 'Next Page',\n    prev_5: 'Previous 5 Pages',\n    next_5: 'Next 5 Pages',\n    prev_3: 'Previous 3 Pages',\n    next_3: 'Next 3 Pages',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Select date',\n      yearPlaceholder: 'Select year',\n      quarterPlaceholder: 'Select quarter',\n      monthPlaceholder: 'Select month',\n      weekPlaceholder: 'Select week',\n      rangePlaceholder: ['Start date', 'End date'],\n      rangeYearPlaceholder: ['Start year', 'End year'],\n      rangeMonthPlaceholder: ['Start month', 'End month'],\n      rangeWeekPlaceholder: ['Start week', 'End week'],\n      locale: 'en_GB',\n      today: 'Today',\n      now: 'Now',\n      backToToday: 'Back to today',\n      ok: 'Ok',\n      clear: 'Clear',\n      month: 'Month',\n      year: 'Year',\n      timeSelect: 'Select time',\n      dateSelect: 'Select date',\n      weekSelect: 'Choose a week',\n      monthSelect: 'Choose a month',\n      yearSelect: 'Choose a year',\n      decadeSelect: 'Choose a decade',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Previous month (PageUp)',\n      nextMonth: 'Next month (PageDown)',\n      previousYear: 'Last year (Control + left)',\n      nextYear: 'Next year (Control + right)',\n      previousDecade: 'Last decade',\n      nextDecade: 'Next decade',\n      previousCentury: 'Last century',\n      nextCentury: 'Next century'\n    },\n    timePickerLocale: {\n      placeholder: 'Select time',\n      rangePlaceholder: ['Start time', 'End time']\n    }\n  },\n  TimePicker: {\n    placeholder: 'Select time',\n    rangePlaceholder: ['Start time', 'End time']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Select date',\n      yearPlaceholder: 'Select year',\n      quarterPlaceholder: 'Select quarter',\n      monthPlaceholder: 'Select month',\n      weekPlaceholder: 'Select week',\n      rangePlaceholder: ['Start date', 'End date'],\n      rangeYearPlaceholder: ['Start year', 'End year'],\n      rangeMonthPlaceholder: ['Start month', 'End month'],\n      rangeWeekPlaceholder: ['Start week', 'End week'],\n      locale: 'en_GB',\n      today: 'Today',\n      now: 'Now',\n      backToToday: 'Back to today',\n      ok: 'Ok',\n      clear: 'Clear',\n      month: 'Month',\n      year: 'Year',\n      timeSelect: 'Select time',\n      dateSelect: 'Select date',\n      weekSelect: 'Choose a week',\n      monthSelect: 'Choose a month',\n      yearSelect: 'Choose a year',\n      decadeSelect: 'Choose a decade',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Previous month (PageUp)',\n      nextMonth: 'Next month (PageDown)',\n      previousYear: 'Last year (Control + left)',\n      nextYear: 'Next year (Control + right)',\n      previousDecade: 'Last decade',\n      nextDecade: 'Next decade',\n      previousCentury: 'Last century',\n      nextCentury: 'Next century'\n    },\n    timePickerLocale: {\n      placeholder: 'Select time',\n      rangePlaceholder: ['Start time', 'End time']\n    }\n  },\n  global: {\n    placeholder: 'Please select'\n  },\n  Table: {\n    filterTitle: 'Filter menu',\n    filterConfirm: 'OK',\n    filterReset: 'Reset',\n    filterEmptyText: 'No filters',\n    emptyText: 'No data',\n    selectAll: 'Select current page',\n    selectInvert: 'Invert current page',\n    selectionAll: 'Select all data',\n    sortTitle: 'Sort',\n    expand: 'Expand row',\n    collapse: 'Collapse row',\n    triggerDesc: 'Click to sort descending',\n    triggerAsc: 'Click to sort ascending',\n    cancelSort: 'Click to cancel sorting',\n    selectNone: 'Clear all data'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Cancel',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Cancel'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'Search here',\n    itemUnit: 'item',\n    itemsUnit: 'items',\n    remove: 'Remove',\n    selectCurrent: 'Select current page',\n    removeCurrent: 'Remove current page',\n    selectAll: 'Select all data',\n    removeAll: 'Remove all data',\n    selectInvert: 'Invert current page'\n  },\n  Upload: {\n    uploading: 'Uploading...',\n    removeFile: 'Remove file',\n    uploadError: 'Upload error',\n    previewFile: 'Preview file',\n    downloadFile: 'Download file'\n  },\n  Empty: {\n    description: 'No data'\n  },\n  Form: {\n    optional: '(optional)'\n  },\n  Icon: {\n    icon: 'icon'\n  },\n  Text: {\n    edit: 'Edit',\n    copy: 'Copy',\n    copied: 'Copied',\n    expand: 'Expand'\n  },\n  PageHeader: {\n    back: 'Back'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/en_US.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'en',\n  Pagination: {\n    items_per_page: '/ page',\n    jump_to: 'Go to',\n    jump_to_confirm: 'confirm',\n    page: 'Page',\n    prev_page: 'Previous Page',\n    next_page: 'Next Page',\n    prev_5: 'Previous 5 Pages',\n    next_5: 'Next 5 Pages',\n    prev_3: 'Previous 3 Pages',\n    next_3: 'Next 3 Pages',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Select date',\n      yearPlaceholder: 'Select year',\n      quarterPlaceholder: 'Select quarter',\n      monthPlaceholder: 'Select month',\n      weekPlaceholder: 'Select week',\n      rangePlaceholder: ['Start date', 'End date'],\n      rangeYearPlaceholder: ['Start year', 'End year'],\n      rangeQuarterPlaceholder: ['Start quarter', 'End quarter'],\n      rangeMonthPlaceholder: ['Start month', 'End month'],\n      rangeWeekPlaceholder: ['Start week', 'End week'],\n      locale: 'en_US',\n      today: 'Today',\n      now: 'Now',\n      backToToday: 'Back to today',\n      ok: 'Ok',\n      clear: 'Clear',\n      month: 'Month',\n      year: 'Year',\n      timeSelect: 'select time',\n      dateSelect: 'select date',\n      weekSelect: 'Choose a week',\n      monthSelect: 'Choose a month',\n      yearSelect: 'Choose a year',\n      decadeSelect: 'Choose a decade',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Previous month (PageUp)',\n      nextMonth: 'Next month (PageDown)',\n      previousYear: 'Last year (Control + left)',\n      nextYear: 'Next year (Control + right)',\n      previousDecade: 'Last decade',\n      nextDecade: 'Next decade',\n      previousCentury: 'Last century',\n      nextCentury: 'Next century'\n    },\n    timePickerLocale: {\n      placeholder: 'Select time',\n      rangePlaceholder: ['Start time', 'End time']\n    }\n  },\n  TimePicker: {\n    placeholder: 'Select time',\n    rangePlaceholder: ['Start time', 'End time']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Select date',\n      yearPlaceholder: 'Select year',\n      quarterPlaceholder: 'Select quarter',\n      monthPlaceholder: 'Select month',\n      weekPlaceholder: 'Select week',\n      rangePlaceholder: ['Start date', 'End date'],\n      rangeYearPlaceholder: ['Start year', 'End year'],\n      rangeMonthPlaceholder: ['Start month', 'End month'],\n      rangeWeekPlaceholder: ['Start week', 'End week'],\n      locale: 'en_US',\n      today: 'Today',\n      now: 'Now',\n      backToToday: 'Back to today',\n      ok: 'Ok',\n      clear: 'Clear',\n      month: 'Month',\n      year: 'Year',\n      timeSelect: 'select time',\n      dateSelect: 'select date',\n      weekSelect: 'Choose a week',\n      monthSelect: 'Choose a month',\n      yearSelect: 'Choose a year',\n      decadeSelect: 'Choose a decade',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Previous month (PageUp)',\n      nextMonth: 'Next month (PageDown)',\n      previousYear: 'Last year (Control + left)',\n      nextYear: 'Next year (Control + right)',\n      previousDecade: 'Last decade',\n      nextDecade: 'Next decade',\n      previousCentury: 'Last century',\n      nextCentury: 'Next century'\n    },\n    timePickerLocale: {\n      placeholder: 'Select time',\n      rangePlaceholder: ['Start time', 'End time']\n    }\n  },\n  global: {\n    placeholder: 'Please select'\n  },\n  Table: {\n    filterTitle: 'Filter menu',\n    filterConfirm: 'OK',\n    filterReset: 'Reset',\n    filterEmptyText: 'No filters',\n    emptyText: 'No data',\n    selectAll: 'Select current page',\n    selectInvert: 'Invert current page',\n    selectionAll: 'Select all data',\n    sortTitle: 'Sort',\n    expand: 'Expand row',\n    collapse: 'Collapse row',\n    triggerDesc: 'Click to sort descending',\n    triggerAsc: 'Click to sort ascending',\n    cancelSort: 'Click to cancel sorting',\n    filterCheckall: 'Select all items',\n    filterSearchPlaceholder: 'Search in filters',\n    selectNone: 'Clear all data'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Cancel',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Cancel'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'Search here',\n    itemUnit: 'item',\n    itemsUnit: 'items',\n    remove: 'Remove',\n    selectCurrent: 'Select current page',\n    removeCurrent: 'Remove current page',\n    selectAll: 'Select all data',\n    removeAll: 'Remove all data',\n    selectInvert: 'Invert current page'\n  },\n  Upload: {\n    uploading: 'Uploading...',\n    removeFile: 'Remove file',\n    uploadError: 'Upload error',\n    previewFile: 'Preview file',\n    downloadFile: 'Download file'\n  },\n  Empty: {\n    description: 'No Data'\n  },\n  Form: {\n    optional: '(optional)'\n  },\n  Icon: {\n    icon: 'icon'\n  },\n  Text: {\n    edit: 'Edit',\n    copy: 'Copy',\n    copied: 'Copied',\n    expand: 'Expand'\n  },\n  PageHeader: {\n    back: 'Back'\n  },\n  Image: {\n    preview: 'Preview'\n  },\n  CronExpression: {\n    cronError: 'Invalid cron expression',\n    second: 'second',\n    minute: 'minute',\n    hour: 'hour',\n    day: 'day',\n    month: 'month',\n    week: 'week'\n  },\n  QRCode: {\n    expired: 'QR code expired',\n    refresh: 'Refresh',\n    scanned: 'Scanned'\n  },\n  CheckList: {\n    checkList: 'Check List',\n    checkListFinish: 'You have successfully completed the list!',\n    checkListClose: 'Close',\n    checkListFooter: 'Check list is no longer required',\n    checkListCheck: 'Do you want to close the list?',\n    ok: 'OK',\n    cancel: 'Cancel',\n    checkListCheckOther: 'No longer required to show'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/es_ES.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'es',\n  Pagination: {\n    items_per_page: '/ página',\n    jump_to: 'Ir a',\n    jump_to_confirm: 'confirmar',\n    page: 'Página',\n    prev_page: 'Página anterior',\n    next_page: 'Página siguiente',\n    prev_5: '5 páginas previas',\n    next_5: '5 páginas siguientes',\n    prev_3: '3 páginas previas',\n    next_3: '3 páginas siguientes',\n    page_size: 'tamaño de página'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Seleccionar fecha',\n      yearPlaceholder: 'Seleccionar año',\n      quarterPlaceholder: 'Seleccionar trimestre',\n      monthPlaceholder: 'Seleccionar mes',\n      weekPlaceholder: 'Seleccionar semana',\n      rangePlaceholder: ['Fecha inicial', 'Fecha final'],\n      rangeYearPlaceholder: ['Año inicial', 'Año final'],\n      rangeQuarterPlaceholder: ['Trimestre inicial', 'Trimestre final'],\n      rangeMonthPlaceholder: ['Mes inicial', 'Mes final'],\n      rangeWeekPlaceholder: ['Semana inicial', 'Semana final'],\n      locale: 'es_ES',\n      today: 'Hoy',\n      now: 'Ahora',\n      backToToday: 'Volver a hoy',\n      ok: 'Aceptar',\n      clear: 'Limpiar',\n      month: 'Mes',\n      year: 'Año',\n      timeSelect: 'Seleccionar hora',\n      dateSelect: 'Seleccionar fecha',\n      weekSelect: 'Elegir una semana',\n      monthSelect: 'Elegir un mes',\n      yearSelect: 'Elegir un año',\n      decadeSelect: 'Elegir una década',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Mes anterior (PageUp)',\n      nextMonth: 'Mes siguiente (PageDown)',\n      previousYear: 'Año anterior (Control + left)',\n      nextYear: 'Año siguiente (Control + right)',\n      previousDecade: 'Década anterior',\n      nextDecade: 'Década siguiente',\n      previousCentury: 'Siglo anterior',\n      nextCentury: 'Siglo siguiente'\n    },\n    timePickerLocale: {\n      placeholder: 'Seleccionar hora',\n      rangePlaceholder: ['Hora inicial', 'Hora final']\n    }\n  },\n  TimePicker: {\n    placeholder: 'Seleccionar hora',\n    rangePlaceholder: ['Hora inicial', 'Hora final']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Seleccionar fecha',\n      yearPlaceholder: 'Seleccionar año',\n      quarterPlaceholder: 'Seleccionar trimestre',\n      monthPlaceholder: 'Seleccionar mes',\n      weekPlaceholder: 'Seleccionar semana',\n      rangePlaceholder: ['Fecha inicial', 'Fecha final'],\n      rangeYearPlaceholder: ['Año inicial', 'Año final'],\n      rangeMonthPlaceholder: ['Mes inicial', 'Mes final'],\n      rangeWeekPlaceholder: ['Semana inicial', 'Semana final'],\n      locale: 'es_ES',\n      today: 'Hoy',\n      now: 'Ahora',\n      backToToday: 'Volver a hoy',\n      ok: 'Aceptar',\n      clear: 'Limpiar',\n      month: 'Mes',\n      year: 'Año',\n      timeSelect: 'Seleccionar hora',\n      dateSelect: 'Seleccionar fecha',\n      weekSelect: 'Elegir una semana',\n      monthSelect: 'Elegir un mes',\n      yearSelect: 'Elegir un año',\n      decadeSelect: 'Elegir una década',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Mes anterior (AvPág)',\n      nextMonth: 'Mes siguiente (RePág)',\n      previousYear: 'Año anterior (Control + izquierda)',\n      nextYear: 'Año siguiente (Control + derecha)',\n      previousDecade: 'Década anterior',\n      nextDecade: 'Década siguiente',\n      previousCentury: 'Siglo anterior',\n      nextCentury: 'Siglo siguiente'\n    },\n    timePickerLocale: {\n      placeholder: 'Seleccionar hora',\n      rangePlaceholder: ['Hora inicial', 'Hora final']\n    }\n  },\n  global: {\n    placeholder: 'Seleccione'\n  },\n  Table: {\n    filterTitle: 'Filtrar menú',\n    filterConfirm: 'Aceptar',\n    filterReset: 'Reiniciar',\n    filterEmptyText: 'Sin filtros',\n    emptyText: 'Sin datos',\n    selectAll: 'Seleccionar todo',\n    selectInvert: 'Invertir selección',\n    selectionAll: 'Seleccionar todos los datos',\n    sortTitle: 'Ordenar',\n    expand: 'Expandir fila',\n    collapse: 'Colapsar fila',\n    triggerDesc: 'Click para ordenar descendentemente',\n    triggerAsc: 'Click para ordenar ascendentemenre',\n    cancelSort: 'Click para cancelar ordenación',\n    filterCheckall: 'Seleccionar todos los filtros',\n    filterSearchPlaceholder: 'Buscar en filtros',\n    selectNone: 'Vaciar todo'\n  },\n  Modal: {\n    okText: 'Aceptar',\n    cancelText: 'Cancelar',\n    justOkText: 'Aceptar'\n  },\n  Popconfirm: {\n    okText: 'Aceptar',\n    cancelText: 'Cancelar'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'Buscar aquí',\n    itemUnit: 'elemento',\n    itemsUnit: 'elementos',\n    remove: 'Eliminar',\n    selectCurrent: 'Seleccionar página actual',\n    removeCurrent: 'Eliminar página actual',\n    selectAll: 'Seleccionar todos los datos',\n    removeAll: 'Eliminar todos los datos',\n    selectInvert: 'Invertir página actual'\n  },\n  Upload: {\n    uploading: 'Subiendo...',\n    removeFile: 'Eliminar archivo',\n    uploadError: 'Error al subir el archivo',\n    previewFile: 'Vista previa',\n    downloadFile: 'Descargar archivo'\n  },\n  Empty: {\n    description: 'No hay datos'\n  },\n  Form: {\n    optional: '(opcional)'\n  },\n  Icon: {\n    icon: 'icono'\n  },\n  Text: {\n    edit: 'Editar',\n    copy: 'Copiar',\n    copied: 'Copiado',\n    expand: 'Expandir'\n  },\n  PageHeader: {\n    back: 'Volver'\n  },\n  Image: {\n    preview: 'Previsualización'\n  },\n  CronExpression: {\n    cronError: 'Expresión cron inválida',\n    second: 'segundo',\n    minute: 'minuto',\n    hour: 'hora',\n    day: 'día',\n    month: 'mes',\n    week: 'semana'\n  },\n  QRCode: {\n    expired: 'Código QR expirado',\n    refresh: 'Actualizar',\n    scanned: 'Escaneado'\n  },\n  CheckList: {\n    checkList: 'Lista de tareas',\n    checkListFinish: '¡Has completado la lista correctamente!',\n    checkListClose: 'Cerrar',\n    checkListFooter: 'La lista ya no es necesaria',\n    checkListCheck: '¿Quiere cerrar la lista?',\n    ok: 'OK',\n    cancel: 'Cancelar',\n    checkListCheckOther: 'No mostrar de nuevo'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/et_EE.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'et',\n  Pagination: {\n    items_per_page: '/ leheküljel',\n    jump_to: 'Hüppa',\n    jump_to_confirm: 'Kinnitage',\n    page: '',\n    prev_page: 'Eelmine leht',\n    next_page: 'Järgmine leht',\n    prev_5: 'Eelmised 5 lehekülge',\n    next_5: 'Järgmised 5 lehekülge',\n    prev_3: 'Eelmised 3 lehekülge',\n    next_3: 'Järgmised 3 lehekülge',\n    page_size: 'lehe suurus'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Vali kuupäev',\n      rangePlaceholder: ['Algus kuupäev', 'Lõpu kuupäev'],\n      locale: 'et_EE',\n      today: 'Täna',\n      now: 'Praegu',\n      backToToday: 'Tagasi tänase juurde',\n      ok: 'Ok',\n      clear: 'Tühista',\n      month: 'Kuu',\n      year: 'Aasta',\n      timeSelect: 'Vali aeg',\n      dateSelect: 'Vali kuupäev',\n      monthSelect: 'Vali kuu',\n      yearSelect: 'Vali aasta',\n      decadeSelect: 'Vali dekaad',\n      yearFormat: 'YYYY',\n      dateFormat: 'D.M.YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D.M.YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Eelmine kuu (PageUp)',\n      nextMonth: 'Järgmine kuu (PageDown)',\n      previousYear: 'Eelmine aasta (Control + left)',\n      nextYear: 'Järgmine aasta (Control + right)',\n      previousDecade: 'Eelmine dekaad',\n      nextDecade: 'Järgmine dekaad',\n      previousCentury: 'Eelmine sajand',\n      nextCentury: 'Järgmine sajand'\n    },\n    timePickerLocale: {\n      placeholder: 'Vali aeg'\n    }\n  },\n  TimePicker: {\n    placeholder: 'Vali aeg'\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Vali kuupäev',\n      rangePlaceholder: ['Algus kuupäev', 'Lõpu kuupäev'],\n      locale: 'et_EE',\n      today: 'Täna',\n      now: 'Praegu',\n      backToToday: 'Tagasi tänase juurde',\n      ok: 'Ok',\n      clear: 'Tühista',\n      month: 'Kuu',\n      year: 'Aasta',\n      timeSelect: 'Vali aeg',\n      dateSelect: 'Vali kuupäev',\n      monthSelect: 'Vali kuu',\n      yearSelect: 'Vali aasta',\n      decadeSelect: 'Vali dekaad',\n      yearFormat: 'YYYY',\n      dateFormat: 'D.M.YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D.M.YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Eelmine kuu (PageUp)',\n      nextMonth: 'Järgmine kuu (PageDown)',\n      previousYear: 'Eelmine aasta (Control + left)',\n      nextYear: 'Järgmine aasta (Control + right)',\n      previousDecade: 'Eelmine dekaad',\n      nextDecade: 'Järgmine dekaad',\n      previousCentury: 'Eelmine sajand',\n      nextCentury: 'Järgmine sajand'\n    },\n    timePickerLocale: {\n      placeholder: 'Vali aeg'\n    }\n  },\n  Table: {\n    filterTitle: 'Filtri menüü',\n    filterConfirm: 'OK',\n    filterReset: 'Nulli',\n    selectAll: 'Vali kõik',\n    selectInvert: 'Inverteeri valik',\n    filterEmptyText: 'Filtreid pole',\n    filterCheckall: 'Vali kõik',\n    filterSearchPlaceholder: 'Otsi filtritest',\n    emptyText: 'Andmed puuduvad',\n    selectNone: 'Kustuta kõik andmed',\n    selectionAll: 'Vali kõik andmed',\n    sortTitle: 'Sorteeri',\n    expand: 'Laienda rida',\n    collapse: 'Ahenda rida',\n    triggerDesc: 'Klõpsa kahanevalt sortimiseks',\n    triggerAsc: 'Klõpsa kasvavalt sortimiseks',\n    cancelSort: 'Klõpsa sortimise tühistamiseks'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Tühista',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Tühista'\n  },\n  Transfer: {\n    searchPlaceholder: 'Otsi siit',\n    itemUnit: 'kogus',\n    itemsUnit: 'kogused',\n    titles: ['', ''],\n    remove: 'Eemalda',\n    selectCurrent: 'Vali praegune leht',\n    removeCurrent: 'Eemalda praegune leht',\n    selectAll: 'Vali kõik',\n    removeAll: 'Eemalda kõik andmed',\n    selectInvert: 'Inverteeri valik'\n  },\n  Upload: {\n    uploading: 'Üleslaadimine...',\n    removeFile: 'Eemalda fail',\n    uploadError: 'Üleslaadimise tõrge',\n    previewFile: 'Faili eelvaade',\n    downloadFile: 'Lae fail alla'\n  },\n  Empty: {\n    description: 'Andmed puuduvad'\n  },\n  global: {\n    placeholder: 'Palun vali'\n  },\n  Form: {\n    optional: '(valikuline)'\n  },\n  Icon: {\n    icon: 'ikoon'\n  },\n  Text: {\n    edit: 'Muuda',\n    copy: 'Kopeeri',\n    copied: 'Kopeeritud',\n    expand: 'Laienda'\n  },\n  PageHeader: {\n    back: 'Tagasi'\n  },\n  Image: {\n    preview: 'Eelvaade'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/fa_IR.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'fa',\n  Pagination: {\n    items_per_page: '/ صفحه',\n    jump_to: 'برو به',\n    jump_to_confirm: 'تایید',\n    page: '',\n    prev_page: 'صفحه قبلی',\n    next_page: 'صفحه بعدی',\n    prev_5: '۵ صفحه قبلی',\n    next_5: '۵ صفحه بعدی',\n    prev_3: '۳ صفحه قبلی',\n    next_3: '۳ صفحه بعدی',\n    page_size: 'اندازه صفحه'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'انتخاب تاریخ',\n      yearPlaceholder: 'انتخاب سال',\n      quarterPlaceholder: 'انتخاب فصل',\n      monthPlaceholder: 'انتخاب ماه',\n      weekPlaceholder: 'انتخاب هفته',\n      rangePlaceholder: ['تاریخ شروع', 'تاریخ پایان'],\n      rangeYearPlaceholder: ['سال شروع', 'سال پایان'],\n      rangeQuarterPlaceholder: ['فصل شروع', 'فصل پایان'],\n      rangeMonthPlaceholder: ['ماه شروع', 'ماه پایان'],\n      rangeWeekPlaceholder: ['هفته شروع', 'هفته پایان'],\n      locale: 'fa_IR',\n      today: 'امروز',\n      now: 'اکنون',\n      backToToday: 'بازگشت به روز',\n      ok: 'باشه',\n      clear: 'پاک کردن',\n      month: 'ماه',\n      year: 'سال',\n      timeSelect: 'انتخاب زمان',\n      dateSelect: 'انتخاب تاریخ',\n      weekSelect: 'یک هفته رو انتخاب کنید',\n      monthSelect: 'یک ماه را انتخاب کنید',\n      yearSelect: 'یک سال را انتخاب کنید',\n      decadeSelect: 'یک دهه را انتخاب کنید',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'ماه قبل (PageUp)',\n      nextMonth: 'ماه بعد (PageDown)',\n      previousYear: 'سال قبل (Control + left)',\n      nextYear: 'سال بعد (Control + right)',\n      previousDecade: 'دهه قبل',\n      nextDecade: 'دهه بعد',\n      previousCentury: 'قرن قبل',\n      nextCentury: 'قرن بعد'\n    },\n    timePickerLocale: {\n      placeholder: 'انتخاب زمان',\n      rangePlaceholder: ['زمان شروع', 'زمان پایان']\n    }\n  },\n  TimePicker: {\n    placeholder: 'انتخاب زمان',\n    rangePlaceholder: ['زمان شروع', 'زمان پایان']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'انتخاب تاریخ',\n      yearPlaceholder: 'انتخاب سال',\n      quarterPlaceholder: 'انتخاب فصل',\n      monthPlaceholder: 'انتخاب ماه',\n      weekPlaceholder: 'انتخاب هفته',\n      rangePlaceholder: ['تاریخ شروع', 'تاریخ پایان'],\n      rangeYearPlaceholder: ['سال شروع', 'سال پایان'],\n      rangeMonthPlaceholder: ['ماه شروع', 'ماه پایان'],\n      rangeWeekPlaceholder: ['هفته شروع', 'هفته پایان'],\n      locale: 'fa_IR',\n      today: 'امروز',\n      now: 'اکنون',\n      backToToday: 'بازگشت به روز',\n      ok: 'باشه',\n      clear: 'پاک کردن',\n      month: 'ماه',\n      year: 'سال',\n      timeSelect: 'انتخاب زمان',\n      dateSelect: 'انتخاب تاریخ',\n      weekSelect: 'انتخاب هفته',\n      monthSelect: 'یک ماه را انتخاب کنید',\n      yearSelect: 'یک سال را انتخاب کنید',\n      decadeSelect: 'یک دهه را انتخاب کنید',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'ماه قبل (PageUp)',\n      nextMonth: 'ماه بعد (PageDown)',\n      previousYear: 'سال قبل (Control + left)',\n      nextYear: 'سال بعد (Control + right)',\n      previousDecade: 'دهه قبل',\n      nextDecade: 'دهه بعد',\n      previousCentury: 'قرن قبل',\n      nextCentury: 'قرن بعد'\n    },\n    timePickerLocale: {\n      placeholder: 'انتخاب زمان',\n      rangePlaceholder: ['زمان شروع', 'زمان پایان']\n    }\n  },\n  global: {\n    placeholder: 'لطفا انتخاب کنید'\n  },\n  Table: {\n    filterTitle: 'منوی فیلتر',\n    filterConfirm: 'تایید',\n    filterReset: 'پاک کردن',\n    filterEmptyText: 'بدون فیلتر',\n    emptyText: 'بدون داده',\n    selectAll: 'انتخاب صفحه‌ی کنونی',\n    selectInvert: 'معکوس کردن انتخاب‌ها در صفحه ی کنونی',\n    selectionAll: 'انتخاب همه داده‌ها',\n    sortTitle: 'مرتب سازی',\n    expand: 'باز شدن ردیف',\n    collapse: 'بستن ردیف',\n    triggerDesc: 'ترتیب نزولی',\n    triggerAsc: 'ترتیب صعودی',\n    cancelSort: 'لغوِ ترتیبِ داده شده',\n    filterCheckall: 'انتخاب همه موارد',\n    filterSearchPlaceholder: 'جست‌و‌جو در فیلتر‌ها',\n    selectNone: 'انتخاب هیچکدام'\n  },\n  Modal: {\n    okText: 'تایید',\n    cancelText: 'لغو',\n    justOkText: 'تایید'\n  },\n  Popconfirm: {\n    okText: 'تایید',\n    cancelText: 'لغو'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'جستجو',\n    itemUnit: 'عدد',\n    itemsUnit: 'عدد',\n    remove: 'حذف',\n    selectCurrent: 'انتخاب صفحه فعلی',\n    removeCurrent: 'پاک کردن انتخاب‌های صفحه فعلی',\n    selectAll: 'انتخاب همه',\n    removeAll: 'پاک کردن همه انتخاب‌ها',\n    selectInvert: 'معکوس کردن انتخاب‌ها در صفحه ی کنونی'\n  },\n  Upload: {\n    uploading: 'در حال آپلود...',\n    removeFile: 'حذف فایل',\n    uploadError: 'خطا در آپلود',\n    previewFile: 'مشاهده‌ی فایل',\n    downloadFile: 'دریافت فایل'\n  },\n  Empty: {\n    description: 'داده‌ای موجود نیست'\n  },\n  Form: {\n    optional: '(اختیاری)'\n  },\n  Icon: {\n    icon: 'آیکن'\n  },\n  Text: {\n    edit: 'ویرایش',\n    copy: 'کپی',\n    copied: 'کپی شد',\n    expand: 'توسعه'\n  },\n  PageHeader: {\n    back: 'برگشت'\n  },\n  Image: {\n    preview: 'نمایش'\n  },\n  CronExpression: {\n    cronError: 'Invalid cron expression',\n    second: 'ثانیه',\n    minute: 'دقیقه',\n    hour: 'ساعت',\n    day: 'روز',\n    month: 'ماه',\n    week: 'هفته'\n  },\n  QRCode: {\n    expired: 'کد QR منقضی شده است',\n    refresh: 'تازه کردن',\n    scanned: 'اسکن شده'\n  },\n  CheckList: {\n    checkList: 'چک لیست',\n    checkListFinish: 'چک ‌لیست با موفقیت تکمیل شد',\n    checkListClose: 'بستن',\n    checkListFooter: 'نیازی به نمایش چک ‌لیست نیست',\n    checkListCheck: 'آیا می‌خواهید چک ‌لیست را ببندید؟',\n    ok: 'تایید',\n    cancel: 'لغو',\n    checkListCheckOther: 'دیگر نمایش داده نشود'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/fi_FI.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'fi',\n  Pagination: {\n    items_per_page: '/ sivu',\n    jump_to: 'Mene',\n    jump_to_confirm: 'Potvrdite',\n    page: 'Sivu',\n    prev_page: 'Edellinen sivu',\n    next_page: 'Seuraava sivu',\n    prev_5: 'Edelliset 5 sivua',\n    next_5: 'Seuraavat 5 sivua',\n    prev_3: 'Edelliset 3 sivua',\n    next_3: 'Seuraavat 3 sivua',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Valitse päivä',\n      rangePlaceholder: ['Alkamispäivä', 'Päättymispäivä'],\n      locale: 'fi_FI',\n      today: 'Tänään',\n      now: 'Nyt',\n      backToToday: 'Tämä päivä',\n      ok: 'Ok',\n      clear: 'Tyhjennä',\n      month: 'Kuukausi',\n      year: 'Vuosi',\n      timeSelect: 'Valise aika',\n      dateSelect: 'Valitse päivä',\n      monthSelect: 'Valitse kuukausi',\n      yearSelect: 'Valitse vuosi',\n      decadeSelect: 'Valitse vuosikymmen',\n      yearFormat: 'YYYY',\n      dateFormat: 'D.M.YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D.M.YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Edellinen kuukausi (PageUp)',\n      nextMonth: 'Seuraava kuukausi (PageDown)',\n      previousYear: 'Edellinen vuosi (Control + left)',\n      nextYear: 'Seuraava vuosi (Control + right)',\n      previousDecade: 'Edellinen vuosikymmen',\n      nextDecade: 'Seuraava vuosikymmen',\n      previousCentury: 'Edellinen vuosisata',\n      nextCentury: 'Seuraava vuosisata'\n    },\n    timePickerLocale: {\n      placeholder: 'Valitse aika'\n    }\n  },\n  TimePicker: {\n    placeholder: 'Valitse aika'\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Valitse päivä',\n      rangePlaceholder: ['Alkamispäivä', 'Päättymispäivä'],\n      locale: 'fi_FI',\n      today: 'Tänään',\n      now: 'Nyt',\n      backToToday: 'Tämä päivä',\n      ok: 'Ok',\n      clear: 'Tyhjennä',\n      month: 'Kuukausi',\n      year: 'Vuosi',\n      timeSelect: 'Valise aika',\n      dateSelect: 'Valitse päivä',\n      monthSelect: 'Valitse kuukausi',\n      yearSelect: 'Valitse vuosi',\n      decadeSelect: 'Valitse vuosikymmen',\n      yearFormat: 'YYYY',\n      dateFormat: 'D.M.YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D.M.YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Edellinen kuukausi (PageUp)',\n      nextMonth: 'Seuraava kuukausi (PageDown)',\n      previousYear: 'Edellinen vuosi (Control + left)',\n      nextYear: 'Seuraava vuosi (Control + right)',\n      previousDecade: 'Edellinen vuosikymmen',\n      nextDecade: 'Seuraava vuosikymmen',\n      previousCentury: 'Edellinen vuosisata',\n      nextCentury: 'Seuraava vuosisata'\n    },\n    timePickerLocale: {\n      placeholder: 'Valitse aika'\n    }\n  },\n  Table: {\n    filterTitle: 'Suodatus valikko',\n    filterConfirm: 'OK',\n    filterReset: 'Tyhjennä',\n    selectAll: 'Valitse kaikki',\n    selectInvert: 'Valitse päinvastoin',\n    sortTitle: 'Lajittele',\n    triggerDesc: 'Lajittele laskevasti',\n    triggerAsc: 'Lajittele nousevasti',\n    cancelSort: 'Peruuta lajittelu'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Peruuta',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Peruuta'\n  },\n  Transfer: {\n    searchPlaceholder: 'Etsi täältä',\n    itemUnit: 'kohde',\n    itemsUnit: 'kohdetta'\n  },\n  Upload: {\n    uploading: 'Lähetetään...',\n    removeFile: 'Poista tiedosto',\n    uploadError: 'Virhe lähetyksessä',\n    previewFile: 'Esikatsele tiedostoa',\n    downloadFile: 'Lataa tiedosto'\n  },\n  Empty: {\n    description: 'Ei kohteita'\n  },\n  Form: {\n    optional: '(valinnainen)'\n  },\n  Text: {\n    edit: 'Muokkaa',\n    copy: 'Kopioi',\n    copied: 'Kopioitu',\n    expand: 'Näytä lisää'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/fr_BE.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'fr',\n  Pagination: {\n    items_per_page: '/ page',\n    jump_to: 'Aller à',\n    jump_to_confirm: 'confirmer',\n    page: 'Page',\n    prev_page: 'Page précédente',\n    next_page: 'Page suivante',\n    prev_5: '5 Pages précédentes',\n    next_5: '5 Pages suivantes',\n    prev_3: '3 Pages précédentes',\n    next_3: '3 Pages suivantes',\n    page_size: 'taille de la page'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Sélectionner une date',\n      yearPlaceholder: 'Sélectionner une année',\n      quarterPlaceholder: 'Sélectionner un trimestre',\n      monthPlaceholder: 'Sélectionner un mois',\n      weekPlaceholder: 'Sélectionner une semaine',\n      rangePlaceholder: ['Date de début', 'Date de fin'],\n      rangeYearPlaceholder: ['Année de début', 'Année de fin'],\n      rangeMonthPlaceholder: ['Mois de début', 'Mois de fin'],\n      rangeWeekPlaceholder: ['Semaine de début', 'Semaine de fin'],\n      locale: 'fr_BE',\n      today: \"Aujourd'hui\",\n      now: 'Maintenant',\n      backToToday: \"Aujourd'hui\",\n      ok: 'Ok',\n      clear: 'Rétablir',\n      month: 'Mois',\n      year: 'Année',\n      timeSelect: \"Sélectionner l'heure\",\n      dateSelect: 'Sélectionner la date',\n      weekSelect: 'Choisissez une semaine',\n      monthSelect: 'Choisissez un mois',\n      yearSelect: 'Choisissez une année',\n      decadeSelect: 'Choisissez une décennie',\n      yearFormat: 'YYYY',\n      dateFormat: 'DD/MM/YYYY',\n      dayFormat: 'DD',\n      dateTimeFormat: 'DD/MM/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Mois précédent (PageUp)',\n      nextMonth: 'Mois suivant (PageDown)',\n      previousYear: 'Année précédente (Ctrl + gauche)',\n      nextYear: 'Année prochaine (Ctrl + droite)',\n      previousDecade: 'Décennie précédente',\n      nextDecade: 'Décennie suivante',\n      previousCentury: 'Siècle précédent',\n      nextCentury: 'Siècle suivant'\n    },\n    timePickerLocale: {\n      placeholder: \"Sélectionner l'heure\",\n      rangePlaceholder: ['Heure de début', 'Heure de fin']\n    }\n  },\n  TimePicker: {\n    placeholder: \"Sélectionner l'heure\",\n    rangePlaceholder: ['Heure de début', 'Heure de fin']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Sélectionner une date',\n      yearPlaceholder: 'Sélectionner une année',\n      quarterPlaceholder: 'Sélectionner un trimestre',\n      monthPlaceholder: 'Sélectionner un mois',\n      weekPlaceholder: 'Sélectionner une semaine',\n      rangePlaceholder: ['Date de début', 'Date de fin'],\n      rangeYearPlaceholder: ['Année de début', 'Année de fin'],\n      rangeMonthPlaceholder: ['Mois de début', 'Mois de fin'],\n      rangeWeekPlaceholder: ['Semaine de début', 'Semaine de fin'],\n      locale: 'fr_BE',\n      today: \"Aujourd'hui\",\n      now: 'Maintenant',\n      backToToday: \"Aujourd'hui\",\n      ok: 'Ok',\n      clear: 'Rétablir',\n      month: 'Mois',\n      year: 'Année',\n      timeSelect: \"Sélectionner l'heure\",\n      dateSelect: 'Sélectionner la date',\n      monthSelect: 'Choisissez un mois',\n      yearSelect: 'Choisissez une année',\n      decadeSelect: 'Choisissez une décennie',\n      yearFormat: 'YYYY',\n      dateFormat: 'DD/MM/YYYY',\n      dayFormat: 'DD',\n      dateTimeFormat: 'DD/MM/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Mois précédent (PageUp)',\n      nextMonth: 'Mois suivant (PageDown)',\n      previousYear: 'Année précédente (Ctrl + gauche)',\n      nextYear: 'Année prochaine (Ctrl + droite)',\n      previousDecade: 'Décennie précédente',\n      nextDecade: 'Décennie suivante',\n      previousCentury: 'Siècle précédent',\n      nextCentury: 'Siècle suivant'\n    },\n    timePickerLocale: {\n      placeholder: \"Sélectionner l'heure\",\n      rangePlaceholder: ['Heure de début', 'Heure de fin']\n    }\n  },\n  global: {\n    placeholder: 'Sélectionner'\n  },\n  Table: {\n    filterTitle: 'Filtrer',\n    filterConfirm: 'OK',\n    filterReset: 'Réinitialiser',\n    selectAll: 'Sélectionner la page actuelle',\n    selectInvert: 'Inverser la sélection de la page actuelle',\n    selectionAll: 'Sélectionner toutes les données',\n    sortTitle: 'Trier',\n    expand: 'Développer la ligne',\n    collapse: 'Réduire la ligne',\n    triggerDesc: 'Trier par ordre décroissant',\n    triggerAsc: 'Trier par ordre croissant',\n    cancelSort: 'Annuler le tri',\n    filterEmptyText: 'Aucun filtre',\n    emptyText: 'Aucune donnée',\n    selectNone: 'Désélectionner toutes les données'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Annuler',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Annuler'\n  },\n  Transfer: {\n    searchPlaceholder: 'Rechercher',\n    itemUnit: 'élément',\n    itemsUnit: 'éléments',\n    titles: ['', ''],\n    remove: 'Désélectionner',\n    selectCurrent: 'Sélectionner la page actuelle',\n    removeCurrent: 'Désélectionner la page actuelle',\n    selectAll: 'Sélectionner toutes les données',\n    removeAll: 'Désélectionner toutes les données',\n    selectInvert: 'Inverser la sélection de la page actuelle'\n  },\n  Empty: {\n    description: 'Aucune donnée'\n  },\n  Upload: {\n    uploading: 'Téléchargement...',\n    removeFile: 'Effacer le fichier',\n    uploadError: 'Erreur de téléchargement',\n    previewFile: 'Fichier de prévisualisation',\n    downloadFile: 'Télécharger un fichier'\n  },\n  Form: {\n    optional: '(optionnel)'\n  },\n  Text: {\n    edit: 'Éditer',\n    copy: 'Copier',\n    copied: 'Copie effectuée',\n    expand: 'Développer'\n  },\n  PageHeader: {\n    back: 'Retour'\n  },\n  Icon: {\n    icon: 'icône'\n  },\n  Image: {\n    preview: 'Aperçu'\n  },\n  CronExpression: {\n    cronError: 'Expression CRON invalide',\n    second: 'seconde',\n    minute: 'minute',\n    hour: 'heure',\n    day: 'jour',\n    month: 'mois',\n    week: 'semaine'\n  },\n  QRCode: {\n    expired: 'QR code expiré',\n    refresh: 'Rafraîchir',\n    scanned: 'Scanné'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/fr_CA.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'fr',\n  Pagination: {\n    items_per_page: '/ page',\n    jump_to: 'Aller à',\n    jump_to_confirm: 'confirmer',\n    page: 'Page',\n    prev_page: 'Page précédente',\n    next_page: 'Page suivante',\n    prev_5: '5 Pages précédentes',\n    next_5: '5 Pages suivantes',\n    prev_3: '3 Pages précédentes',\n    next_3: '3 Pages suivantes',\n    page_size: 'taille de la page'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Sélectionner une date',\n      yearPlaceholder: 'Sélectionner une année',\n      quarterPlaceholder: 'Sélectionner un trimestre',\n      monthPlaceholder: 'Sélectionner un mois',\n      weekPlaceholder: 'Sélectionner une semaine',\n      rangePlaceholder: ['Date de début', 'Date de fin'],\n      rangeYearPlaceholder: ['Année de début', 'Année de fin'],\n      rangeMonthPlaceholder: ['Mois de début', 'Mois de fin'],\n      rangeWeekPlaceholder: ['Semaine de début', 'Semaine de fin'],\n      locale: 'fr_CA',\n      today: \"Aujourd'hui\",\n      now: 'Maintenant',\n      backToToday: \"Aujourd'hui\",\n      ok: 'Ok',\n      clear: 'Rétablir',\n      month: 'Mois',\n      year: 'Année',\n      timeSelect: \"Sélectionner l'heure\",\n      dateSelect: 'Sélectionner la date',\n      weekSelect: 'Choisissez une semaine',\n      monthSelect: 'Choisissez un mois',\n      yearSelect: 'Choisissez une année',\n      decadeSelect: 'Choisissez une décennie',\n      yearFormat: 'YYYY',\n      dateFormat: 'DD/MM/YYYY',\n      dayFormat: 'DD',\n      dateTimeFormat: 'DD/MM/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Mois précédent (PageUp)',\n      nextMonth: 'Mois suivant (PageDown)',\n      previousYear: 'Année précédente (Ctrl + gauche)',\n      nextYear: 'Année prochaine (Ctrl + droite)',\n      previousDecade: 'Décennie précédente',\n      nextDecade: 'Décennie suivante',\n      previousCentury: 'Siècle précédent',\n      nextCentury: 'Siècle suivant'\n    },\n    timePickerLocale: {\n      placeholder: \"Sélectionner l'heure\",\n      rangePlaceholder: ['Heure de début', 'Heure de fin']\n    }\n  },\n  TimePicker: {\n    placeholder: \"Sélectionner l'heure\",\n    rangePlaceholder: ['Heure de début', 'Heure de fin']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Sélectionner une date',\n      yearPlaceholder: 'Sélectionner une année',\n      quarterPlaceholder: 'Sélectionner un trimestre',\n      monthPlaceholder: 'Sélectionner un mois',\n      weekPlaceholder: 'Sélectionner une semaine',\n      rangePlaceholder: ['Date de début', 'Date de fin'],\n      rangeYearPlaceholder: ['Année de début', 'Année de fin'],\n      rangeMonthPlaceholder: ['Mois de début', 'Mois de fin'],\n      rangeWeekPlaceholder: ['Semaine de début', 'Semaine de fin'],\n      locale: 'fr_CA',\n      today: \"Aujourd'hui\",\n      now: 'Maintenant',\n      backToToday: \"Aujourd'hui\",\n      ok: 'Ok',\n      clear: 'Rétablir',\n      month: 'Mois',\n      year: 'Année',\n      timeSelect: \"Sélectionner l'heure\",\n      dateSelect: 'Sélectionner la date',\n      monthSelect: 'Choisissez un mois',\n      yearSelect: 'Choisissez une année',\n      decadeSelect: 'Choisissez une décennie',\n      yearFormat: 'YYYY',\n      dateFormat: 'DD/MM/YYYY',\n      dayFormat: 'DD',\n      dateTimeFormat: 'DD/MM/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Mois précédent (PageUp)',\n      nextMonth: 'Mois suivant (PageDown)',\n      previousYear: 'Année précédente (Ctrl + gauche)',\n      nextYear: 'Année prochaine (Ctrl + droite)',\n      previousDecade: 'Décennie précédente',\n      nextDecade: 'Décennie suivante',\n      previousCentury: 'Siècle précédent',\n      nextCentury: 'Siècle suivant'\n    },\n    timePickerLocale: {\n      placeholder: \"Sélectionner l'heure\",\n      rangePlaceholder: ['Heure de début', 'Heure de fin']\n    }\n  },\n  global: {\n    placeholder: 'Sélectionner'\n  },\n  Table: {\n    filterTitle: 'Filtrer',\n    filterConfirm: 'OK',\n    filterReset: 'Réinitialiser',\n    selectAll: 'Sélectionner la page actuelle',\n    selectInvert: 'Inverser la sélection de la page actuelle',\n    selectionAll: 'Sélectionner toutes les données',\n    sortTitle: 'Trier',\n    expand: 'Développer la ligne',\n    collapse: 'Réduire la ligne',\n    triggerDesc: 'Trier par ordre décroissant',\n    triggerAsc: 'Trier par ordre croissant',\n    cancelSort: 'Annuler le tri',\n    filterEmptyText: 'Aucun filtre',\n    emptyText: 'Aucune donnée',\n    selectNone: 'Désélectionner toutes les données'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Annuler',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Annuler'\n  },\n  Transfer: {\n    searchPlaceholder: 'Rechercher',\n    itemUnit: 'élément',\n    itemsUnit: 'éléments',\n    titles: ['', ''],\n    remove: 'Désélectionner',\n    selectCurrent: 'Sélectionner la page actuelle',\n    removeCurrent: 'Désélectionner la page actuelle',\n    selectAll: 'Sélectionner toutes les données',\n    removeAll: 'Désélectionner toutes les données',\n    selectInvert: 'Inverser la sélection de la page actuelle'\n  },\n  Empty: {\n    description: 'Aucune donnée'\n  },\n  Upload: {\n    uploading: 'Téléchargement...',\n    removeFile: 'Effacer le fichier',\n    uploadError: 'Erreur de téléchargement',\n    previewFile: 'Fichier de prévisualisation',\n    downloadFile: 'Télécharger un fichier'\n  },\n  Text: {\n    edit: 'Éditer',\n    copy: 'Copier',\n    copied: 'Copie effectuée',\n    expand: 'Développer'\n  },\n  PageHeader: {\n    back: 'Retour'\n  },\n  Form: {\n    optional: '(optionnel)'\n  },\n  Icon: {\n    icon: 'icône'\n  },\n  Image: {\n    preview: 'Aperçu'\n  },\n  CronExpression: {\n    cronError: 'Expression CRON invalide',\n    second: 'seconde',\n    minute: 'minute',\n    hour: 'heure',\n    day: 'jour',\n    month: 'mois',\n    week: 'semaine'\n  },\n  QRCode: {\n    expired: 'QR code expiré',\n    refresh: 'Rafraîchir',\n    scanned: 'Scanné'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/fr_FR.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'fr',\n  Pagination: {\n    items_per_page: '/ page',\n    jump_to: 'Aller à',\n    jump_to_confirm: 'confirmer',\n    page: 'Page',\n    prev_page: 'Page précédente',\n    next_page: 'Page suivante',\n    prev_5: '5 Pages précédentes',\n    next_5: '5 Pages suivantes',\n    prev_3: '3 Pages précédentes',\n    next_3: '3 Pages suivantes',\n    page_size: 'taille de la page'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Sélectionner une date',\n      yearPlaceholder: 'Sélectionner une année',\n      quarterPlaceholder: 'Sélectionner un trimestre',\n      monthPlaceholder: 'Sélectionner un mois',\n      weekPlaceholder: 'Sélectionner une semaine',\n      rangePlaceholder: ['Date de début', 'Date de fin'],\n      rangeYearPlaceholder: ['Année de début', 'Année de fin'],\n      rangeMonthPlaceholder: ['Mois de début', 'Mois de fin'],\n      rangeWeekPlaceholder: ['Semaine de début', 'Semaine de fin'],\n      locale: 'fr_FR',\n      today: \"Aujourd'hui\",\n      now: 'Maintenant',\n      backToToday: \"Aujourd'hui\",\n      ok: 'Ok',\n      clear: 'Rétablir',\n      month: 'Mois',\n      year: 'Année',\n      timeSelect: \"Sélectionner l'heure\",\n      dateSelect: 'Sélectionner la date',\n      weekSelect: 'Choisissez une semaine',\n      monthSelect: 'Choisissez un mois',\n      yearSelect: 'Choisissez une année',\n      decadeSelect: 'Choisissez une décennie',\n      yearFormat: 'YYYY',\n      dateFormat: 'DD/MM/YYYY',\n      dayFormat: 'DD',\n      dateTimeFormat: 'DD/MM/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Mois précédent (PageUp)',\n      nextMonth: 'Mois suivant (PageDown)',\n      previousYear: 'Année précédente (Ctrl + gauche)',\n      nextYear: 'Année prochaine (Ctrl + droite)',\n      previousDecade: 'Décennie précédente',\n      nextDecade: 'Décennie suivante',\n      previousCentury: 'Siècle précédent',\n      nextCentury: 'Siècle suivant'\n    },\n    timePickerLocale: {\n      placeholder: \"Sélectionner l'heure\",\n      rangePlaceholder: ['Heure de début', 'Heure de fin']\n    }\n  },\n  TimePicker: {\n    placeholder: \"Sélectionner l'heure\",\n    rangePlaceholder: ['Heure de début', 'Heure de fin']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Sélectionner une date',\n      yearPlaceholder: 'Sélectionner une année',\n      quarterPlaceholder: 'Sélectionner un trimestre',\n      monthPlaceholder: 'Sélectionner un mois',\n      weekPlaceholder: 'Sélectionner une semaine',\n      rangePlaceholder: ['Date de début', 'Date de fin'],\n      rangeYearPlaceholder: ['Année de début', 'Année de fin'],\n      rangeMonthPlaceholder: ['Mois de début', 'Mois de fin'],\n      rangeWeekPlaceholder: ['Semaine de début', 'Semaine de fin'],\n      locale: 'fr_FR',\n      today: \"Aujourd'hui\",\n      now: 'Maintenant',\n      backToToday: \"Aujourd'hui\",\n      ok: 'Ok',\n      clear: 'Rétablir',\n      month: 'Mois',\n      year: 'Année',\n      timeSelect: \"Sélectionner l'heure\",\n      dateSelect: 'Sélectionner la date',\n      monthSelect: 'Choisissez un mois',\n      yearSelect: 'Choisissez une année',\n      decadeSelect: 'Choisissez une décennie',\n      yearFormat: 'YYYY',\n      dateFormat: 'DD/MM/YYYY',\n      dayFormat: 'DD',\n      dateTimeFormat: 'DD/MM/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Mois précédent (PageUp)',\n      nextMonth: 'Mois suivant (PageDown)',\n      previousYear: 'Année précédente (Ctrl + gauche)',\n      nextYear: 'Année prochaine (Ctrl + droite)',\n      previousDecade: 'Décennie précédente',\n      nextDecade: 'Décennie suivante',\n      previousCentury: 'Siècle précédent',\n      nextCentury: 'Siècle suivant'\n    },\n    timePickerLocale: {\n      placeholder: \"Sélectionner l'heure\",\n      rangePlaceholder: ['Heure de début', 'Heure de fin']\n    }\n  },\n  global: {\n    placeholder: 'Sélectionner'\n  },\n  Table: {\n    filterTitle: 'Filtrer',\n    filterConfirm: 'OK',\n    filterReset: 'Réinitialiser',\n    selectAll: 'Sélectionner la page actuelle',\n    selectInvert: 'Inverser la sélection de la page actuelle',\n    selectionAll: 'Sélectionner toutes les données',\n    sortTitle: 'Trier',\n    expand: 'Développer la ligne',\n    collapse: 'Réduire la ligne',\n    triggerDesc: 'Trier par ordre décroissant',\n    triggerAsc: 'Trier par ordre croissant',\n    cancelSort: 'Annuler le tri',\n    filterEmptyText: 'Aucun filtre',\n    emptyText: 'Aucune donnée',\n    selectNone: 'Désélectionner toutes les données'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Annuler',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Annuler'\n  },\n  Transfer: {\n    searchPlaceholder: 'Rechercher',\n    itemUnit: 'élément',\n    itemsUnit: 'éléments',\n    titles: ['', ''],\n    remove: 'Désélectionner',\n    selectCurrent: 'Sélectionner la page actuelle',\n    removeCurrent: 'Désélectionner la page actuelle',\n    selectAll: 'Sélectionner toutes les données',\n    removeAll: 'Désélectionner toutes les données',\n    selectInvert: 'Inverser la sélection de la page actuelle'\n  },\n  Empty: {\n    description: 'Aucune donnée'\n  },\n  Upload: {\n    uploading: 'Téléchargement...',\n    removeFile: 'Effacer le fichier',\n    uploadError: 'Erreur de téléchargement',\n    previewFile: 'Fichier de prévisualisation',\n    downloadFile: 'Télécharger un fichier'\n  },\n  Form: {\n    optional: '(optionnel)'\n  },\n  Text: {\n    edit: 'Éditer',\n    copy: 'Copier',\n    copied: 'Copie effectuée',\n    expand: 'Développer'\n  },\n  PageHeader: {\n    back: 'Retour'\n  },\n  Icon: {\n    icon: 'icône'\n  },\n  Image: {\n    preview: 'Aperçu'\n  },\n  CronExpression: {\n    cronError: 'Expression CRON invalide',\n    second: 'seconde',\n    minute: 'minute',\n    hour: 'heure',\n    day: 'jour',\n    month: 'mois',\n    week: 'semaine'\n  },\n  QRCode: {\n    expired: 'QR code expiré',\n    refresh: 'Rafraîchir',\n    scanned: 'Scanné'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/ga_IE.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'ga',\n  Pagination: {\n    items_per_page: '/ leathanach',\n    jump_to: 'Téigh',\n    jump_to_confirm: 'dheimhnigh',\n    page: '',\n    prev_page: 'Leathanach Roimhe Seo',\n    next_page: 'An chéad leathanach eile',\n    prev_5: '5 leathanach roimhe seo',\n    next_5: 'Ar Aghaidh 5 Leathanaigh',\n    prev_3: '3 leathanach roimhe seo',\n    next_3: 'Ar Aghaidh 3 Leathanaigh',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Roghnaigh dáta',\n      yearPlaceholder: 'Roghnaigh bliain',\n      quarterPlaceholder: 'Roghnaigh ráithe',\n      monthPlaceholder: 'Roghnaigh mí',\n      weekPlaceholder: 'Roghnaigh seachtain',\n      rangePlaceholder: ['Dáta tosaigh', 'Dáta deiridh'],\n      rangeYearPlaceholder: ['Tús na bliana', 'Deireadh na bliana'],\n      rangeMonthPlaceholder: ['Tosaigh mhí', 'Deireadh mhí'],\n      rangeWeekPlaceholder: ['Tosaigh an tseachtain', 'Deireadh na seachtaine'],\n      locale: 'ga_IE',\n      today: 'inniu',\n      now: 'anois',\n      backToToday: 'Ar ais inniu',\n      ok: 'ceart go leor',\n      clear: 'soiléir',\n      month: 'mhí',\n      year: 'bhliain',\n      timeSelect: 'roghnaigh am',\n      dateSelect: 'roghnaigh dáta',\n      weekSelect: 'Roghnaigh seachtain',\n      monthSelect: 'Roghnaigh mí',\n      yearSelect: 'Roghnaigh bliain',\n      decadeSelect: 'Roghnaigh deich mbliana',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'An mhí roimhe seo (PageUp)',\n      nextMonth: 'An mhí seo chugainn (PageDown)',\n      previousYear: 'Anuraidh (Control + left)',\n      nextYear: 'An bhliain seo chugainn (Control + right)',\n      previousDecade: 'Le deich mbliana anuas',\n      nextDecade: 'Deich mbliana amach romhainn',\n      previousCentury: 'An chéid seo caite',\n      nextCentury: 'An chéad aois eile'\n    },\n    timePickerLocale: {\n      placeholder: 'Roghnaigh am',\n      rangePlaceholder: ['Am tosaigh', 'Am deiridh']\n    }\n  },\n  TimePicker: {\n    placeholder: 'Roghnaigh am',\n    rangePlaceholder: ['Am tosaigh', 'Am deiridh']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Roghnaigh dáta',\n      yearPlaceholder: 'Roghnaigh bliain',\n      quarterPlaceholder: 'Roghnaigh ráithe',\n      monthPlaceholder: 'Roghnaigh mí',\n      weekPlaceholder: 'Roghnaigh seachtain',\n      rangePlaceholder: ['Dáta tosaigh', 'Dáta deiridh'],\n      rangeYearPlaceholder: ['Tús na bliana', 'Deireadh na bliana'],\n      rangeMonthPlaceholder: ['Tosaigh mhí', 'Deireadh mhí'],\n      rangeWeekPlaceholder: ['Tosaigh an tseachtain', 'Deireadh na seachtaine'],\n      locale: 'ga_IE',\n      today: 'inniu',\n      now: 'anois',\n      backToToday: 'Ar ais inniu',\n      ok: 'ceart go leor',\n      clear: 'soiléir',\n      month: 'mhí',\n      year: 'bhliain',\n      timeSelect: 'roghnaigh am',\n      dateSelect: 'roghnaigh dáta',\n      weekSelect: 'Roghnaigh seachtain',\n      monthSelect: 'Roghnaigh mí',\n      yearSelect: 'Roghnaigh bliain',\n      decadeSelect: 'Roghnaigh deich mbliana',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'An mhí roimhe seo (PageUp)',\n      nextMonth: 'An mhí seo chugainn (PageDown)',\n      previousYear: 'Anuraidh (Control + left)',\n      nextYear: 'An bhliain seo chugainn (Control + right)',\n      previousDecade: 'Le deich mbliana anuas',\n      nextDecade: 'Deich mbliana amach romhainn',\n      previousCentury: 'An chéid seo caite',\n      nextCentury: 'An chéad aois eile'\n    },\n    timePickerLocale: {\n      placeholder: 'Roghnaigh am',\n      rangePlaceholder: ['Am tosaigh', 'Am deiridh']\n    }\n  },\n  global: {\n    placeholder: 'Please select'\n  },\n  Table: {\n    filterTitle: 'Filter menu',\n    filterConfirm: 'OK',\n    filterReset: 'Reset',\n    selectAll: 'Select current page',\n    selectInvert: 'Invert current page',\n    selectionAll: 'Select all data',\n    sortTitle: 'Sort',\n    expand: 'Expand row',\n    collapse: 'Collapse row',\n    triggerDesc: 'Click to sort descending',\n    triggerAsc: 'Click to sort ascending',\n    cancelSort: 'Click to cancel sorting'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Cancel',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Cancel'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'Search here',\n    itemUnit: 'item',\n    itemsUnit: 'items',\n    remove: 'Remove',\n    selectCurrent: 'Select current page',\n    removeCurrent: 'Remove current page',\n    selectAll: 'Select all data',\n    removeAll: 'Remove all data',\n    selectInvert: 'Invert current page'\n  },\n  Upload: {\n    uploading: 'Uploading...',\n    removeFile: 'Remove file',\n    uploadError: 'Upload error',\n    previewFile: 'Preview file',\n    downloadFile: 'Download file'\n  },\n  Empty: {\n    description: 'No Data'\n  },\n  Form: {\n    optional: '(optional)'\n  },\n  Icon: {\n    icon: 'icon'\n  },\n  Text: {\n    edit: 'Edit',\n    copy: 'Copy',\n    copied: 'Copied',\n    expand: 'Expand'\n  },\n  PageHeader: {\n    back: 'Back'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/gl_ES.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'gl',\n  Pagination: {\n    items_per_page: '/ páxina',\n    jump_to: 'Ir a',\n    jump_to_confirm: 'confirmar',\n    page: '',\n    prev_page: 'Páxina anterior',\n    next_page: 'Páxina seguinte',\n    prev_5: '5 páxinas previas',\n    next_5: '5 páxinas seguintes',\n    prev_3: '3 páxinas previas',\n    next_3: '3 páxinas seguintes',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Escolla data',\n      rangePlaceholder: ['Data inicial', 'Data final'],\n      locale: 'gl_ES',\n      today: 'Hoxe',\n      now: 'Agora',\n      backToToday: 'Voltar a hoxe',\n      ok: 'Aceptar',\n      clear: 'Limpar',\n      month: 'Mes',\n      year: 'Ano',\n      timeSelect: 'Seleccionar hora',\n      dateSelect: 'Seleccionar data',\n      monthSelect: 'Elexir un mes',\n      yearSelect: 'Elexir un año',\n      decadeSelect: 'Elexir unha década',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Mes anterior (PageUp)',\n      nextMonth: 'Mes seguinte (PageDown)',\n      previousYear: 'Ano anterior (Control + left)',\n      nextYear: 'Ano seguinte (Control + right)',\n      previousDecade: 'Década anterior',\n      nextDecade: 'Década seguinte',\n      previousCentury: 'Século anterior',\n      nextCentury: 'Século seguinte'\n    },\n    timePickerLocale: {\n      placeholder: 'Escolla hora'\n    }\n  },\n  TimePicker: {\n    placeholder: 'Escolla hora'\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Escolla data',\n      rangePlaceholder: ['Data inicial', 'Data final'],\n      locale: 'gl_ES',\n      today: 'Hoxe',\n      now: 'Agora',\n      backToToday: 'Voltar a hoxe',\n      ok: 'Aceptar',\n      clear: 'Limpar',\n      month: 'Mes',\n      year: 'Ano',\n      timeSelect: 'Seleccionar hora',\n      dateSelect: 'Seleccionar data',\n      monthSelect: 'Elexir un mes',\n      yearSelect: 'Elexir un año',\n      decadeSelect: 'Elexir unha década',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Mes anterior (PageUp)',\n      nextMonth: 'Mes seguinte (PageDown)',\n      previousYear: 'Ano anterior (Control + left)',\n      nextYear: 'Ano seguinte (Control + right)',\n      previousDecade: 'Década anterior',\n      nextDecade: 'Década seguinte',\n      previousCentury: 'Século anterior',\n      nextCentury: 'Século seguinte'\n    },\n    timePickerLocale: {\n      placeholder: 'Escolla hora'\n    }\n  },\n  global: {\n    placeholder: 'Escolla'\n  },\n  Table: {\n    filterTitle: 'Filtrar menú',\n    filterConfirm: 'Aceptar',\n    filterReset: 'Reiniciar',\n    selectAll: 'Seleccionar todo',\n    selectInvert: 'Invertir selección',\n    sortTitle: 'Ordenar'\n  },\n  Modal: {\n    okText: 'Aceptar',\n    cancelText: 'Cancelar',\n    justOkText: 'Aceptar'\n  },\n  Popconfirm: {\n    okText: 'Aceptar',\n    cancelText: 'Cancelar'\n  },\n  Transfer: {\n    searchPlaceholder: 'Buscar aquí',\n    itemUnit: 'elemento',\n    itemsUnit: 'elementos'\n  },\n  Upload: {\n    uploading: 'Subindo...',\n    removeFile: 'Eliminar arquivo',\n    uploadError: 'Error ao subir o arquivo',\n    previewFile: 'Vista previa',\n    downloadFile: 'Descargar arquivo'\n  },\n  Empty: {\n    description: 'Non hai datos'\n  },\n  Form: {\n    optional: '(opcional)'\n  },\n  Icon: {\n    icon: 'icona'\n  },\n  Text: {\n    edit: 'editar',\n    copy: 'copiar',\n    copied: 'copiado',\n    expand: 'expandir'\n  },\n  PageHeader: {\n    back: 'voltar'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/he_IL.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'he',\n  Pagination: {\n    items_per_page: '/ עמוד',\n    jump_to: 'עבור אל',\n    jump_to_confirm: 'אישור',\n    page: '',\n    prev_page: 'העמוד הקודם',\n    next_page: 'העמוד הבא',\n    prev_5: '5 עמודים קודמים',\n    next_5: '5 עמודים הבאים',\n    prev_3: '3 עמודים קודמים',\n    next_3: '3 עמודים הבאים',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'בחר תאריך',\n      yearPlaceholder: 'בחר שנה',\n      quarterPlaceholder: 'בחר רבעון',\n      monthPlaceholder: 'בחר חודש',\n      weekPlaceholder: 'בחר שבוע',\n      rangePlaceholder: ['תאריך התחלה', 'תאריך סיום'],\n      rangeYearPlaceholder: ['שנת התחלה', 'שנת סיום'],\n      rangeQuarterPlaceholder: ['רבעון התחלה', 'רבעון סיום'],\n      rangeMonthPlaceholder: ['חודש התחלה', 'חודש סיום'],\n      rangeWeekPlaceholder: ['שבוע התחלה', 'שבוע סיום'],\n      locale: 'he_IL',\n      today: 'היום',\n      now: 'עכשיו',\n      backToToday: 'חזור להיום',\n      ok: 'אישור',\n      clear: 'איפוס',\n      month: 'חודש',\n      year: 'שנה',\n      timeSelect: 'בחר שעה',\n      dateSelect: 'בחר תאריך',\n      weekSelect: 'בחר שבוע',\n      monthSelect: 'בחר חודש',\n      yearSelect: 'בחר שנה',\n      decadeSelect: 'בחר עשור',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'חודש קודם (PageUp)',\n      nextMonth: 'חודש הבא (PageDown)',\n      previousYear: 'שנה שעברה (Control + left)',\n      nextYear: 'שנה הבאה (Control + right)',\n      previousDecade: 'העשור הקודם',\n      nextDecade: 'העשור הבא',\n      previousCentury: 'המאה הקודמת',\n      nextCentury: 'המאה הבאה'\n    },\n    timePickerLocale: {\n      placeholder: 'בחר שעה',\n      rangePlaceholder: ['שעת התחלה', 'שעת סיום']\n    }\n  },\n  TimePicker: {\n    placeholder: 'בחר שעה',\n    rangePlaceholder: ['שעת התחלה', 'שעת סיום']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'בחר תאריך',\n      yearPlaceholder: 'בחר שנה',\n      quarterPlaceholder: 'בחר רבעון',\n      monthPlaceholder: 'בחר חודש',\n      weekPlaceholder: 'בחר שבוע',\n      rangePlaceholder: ['תאריך התחלה', 'תאריך סיום'],\n      rangeYearPlaceholder: ['שנת התחלה', 'שנת סיום'],\n      rangeMonthPlaceholder: ['חודש התחלה', 'חודש סיום'],\n      rangeWeekPlaceholder: ['שבוע התחלה', 'שבוע סיום'],\n      locale: 'he_IL',\n      today: 'היום',\n      now: 'עכשיו',\n      backToToday: 'חזור להיום',\n      ok: 'אישור',\n      clear: 'איפוס',\n      month: 'חודש',\n      year: 'שנה',\n      timeSelect: 'בחר שעה',\n      dateSelect: 'בחר תאריך',\n      weekSelect: 'בחר שבוע',\n      monthSelect: 'בחר חודש',\n      yearSelect: 'בחר שנה',\n      decadeSelect: 'בחר עשור',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'חודש קודם (PageUp)',\n      nextMonth: 'חודש הבא (PageDown)',\n      previousYear: 'שנה שעברה (Control + left)',\n      nextYear: 'שנה הבאה (Control + right)',\n      previousDecade: 'העשור הקודם',\n      nextDecade: 'העשור הבא',\n      previousCentury: 'המאה הקודמת',\n      nextCentury: 'המאה הבאה'\n    },\n    timePickerLocale: {\n      placeholder: 'בחר שעה',\n      rangePlaceholder: ['שעת התחלה', 'שעת סיום']\n    }\n  },\n  global: {\n    placeholder: 'אנא בחר'\n  },\n  Table: {\n    filterTitle: 'תפריט סינון',\n    filterConfirm: 'אישור',\n    filterReset: 'איפוס',\n    selectAll: 'בחר הכל',\n    selectInvert: 'הפוך בחירה',\n    selectionAll: 'בחר את כל הנתונים',\n    sortTitle: 'מיון',\n    expand: 'הרחב שורה',\n    collapse: 'צמצם שורה',\n    triggerDesc: 'לחץ על מיון לפי סדר יורד',\n    triggerAsc: 'לחץ על מיון לפי סדר עולה',\n    cancelSort: 'לחץ כדי לבטל את המיון'\n  },\n  Modal: {\n    okText: 'אישור',\n    cancelText: 'ביטול',\n    justOkText: 'אישור'\n  },\n  Popconfirm: {\n    okText: 'אישור',\n    cancelText: 'ביטול'\n  },\n  Transfer: {\n    searchPlaceholder: 'חפש כאן',\n    itemUnit: 'פריט',\n    itemsUnit: 'פריטים'\n  },\n  Upload: {\n    uploading: 'מעלה...',\n    removeFile: 'הסר קובץ',\n    uploadError: 'שגיאת העלאה',\n    previewFile: 'הצג קובץ',\n    downloadFile: 'הורד קובץ'\n  },\n  Empty: {\n    description: 'אין מידע'\n  },\n  Form: {\n    optional: '(אופציונלי)'\n  },\n  Icon: {\n    icon: 'סמל'\n  },\n  Text: {\n    edit: 'ערוך',\n    copy: 'העתק',\n    copied: 'הועתק',\n    expand: 'הרחב'\n  },\n  PageHeader: {\n    back: 'חזרה'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/hi_IN.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'hi',\n  Pagination: {\n    items_per_page: '/ पृष्ठ',\n    jump_to: 'इस पर चलें',\n    jump_to_confirm: 'पुष्टि करें',\n    page: '',\n    prev_page: 'पिछला पृष्ठ',\n    next_page: 'अगला पृष्ठ',\n    prev_5: 'पिछले 5 पृष्ठ',\n    next_5: 'अगले 5 पृष्ठ',\n    prev_3: 'पिछले 3 पृष्ठ',\n    next_3: 'अगले 3 पेज',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'तारीख़ चुनें',\n      rangePlaceholder: ['प्रारंभ तिथि', 'समाप्ति तिथि'],\n      locale: 'hi_IN',\n      today: 'आज',\n      now: 'अभी',\n      backToToday: 'आज तक',\n      ok: 'ठीक',\n      clear: 'स्पष्ट',\n      month: 'महीना',\n      year: 'साल',\n      timeSelect: 'समय का चयन करें',\n      dateSelect: 'तारीख़ चुनें',\n      weekSelect: 'एक सप्ताह चुनें',\n      monthSelect: 'एक महीना चुनें',\n      yearSelect: 'एक वर्ष चुनें',\n      decadeSelect: 'एक दशक चुनें',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'पिछला महीना (पेजअप)',\n      nextMonth: 'अगले महीने (पेजडाउन)',\n      previousYear: 'पिछले साल (Ctrl + बाएं)',\n      nextYear: 'अगले साल (Ctrl + दाहिना)',\n      previousDecade: 'पिछला दशक',\n      nextDecade: 'अगले दशक',\n      previousCentury: 'पीछ्ली शताब्दी',\n      nextCentury: 'अगली सदी',\n      yearPlaceholder: 'वर्ष चुनें',\n      quarterPlaceholder: 'तिमाही चुनें',\n      monthPlaceholder: 'महीना चुनिए',\n      weekPlaceholder: 'सप्ताह चुनें',\n      rangeYearPlaceholder: ['आरंभिक वर्ष', 'अंत वर्ष'],\n      rangeMonthPlaceholder: ['आरंभिक महीना', 'अंत महीना'],\n      rangeWeekPlaceholder: ['आरंभिक सप्ताह', 'अंत सप्ताह']\n    },\n    timePickerLocale: {\n      placeholder: 'समय का चयन करें',\n      rangePlaceholder: ['आरंभिक समय', 'अंत समय']\n    }\n  },\n  TimePicker: {\n    placeholder: 'समय का चयन करें',\n    rangePlaceholder: ['आरंभिक समय', 'अंत समय']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'तारीख़ चुनें',\n      rangePlaceholder: ['प्रारंभ तिथि', 'समाप्ति तिथि'],\n      locale: 'hi_IN',\n      today: 'आज',\n      now: 'अभी',\n      backToToday: 'आज तक',\n      ok: 'ठीक',\n      clear: 'स्पष्ट',\n      month: 'महीना',\n      year: 'साल',\n      timeSelect: 'समय का चयन करें',\n      dateSelect: 'तारीख़ चुनें',\n      weekSelect: 'एक सप्ताह चुनें',\n      monthSelect: 'एक महीना चुनें',\n      yearSelect: 'एक वर्ष चुनें',\n      decadeSelect: 'एक दशक चुनें',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'पिछला महीना (पेजअप)',\n      nextMonth: 'अगले महीने (पेजडाउन)',\n      previousYear: 'पिछले साल (Ctrl + बाएं)',\n      nextYear: 'अगले साल (Ctrl + दाहिना)',\n      previousDecade: 'पिछला दशक',\n      nextDecade: 'अगले दशक',\n      previousCentury: 'पीछ्ली शताब्दी',\n      nextCentury: 'अगली सदी',\n      yearPlaceholder: 'वर्ष चुनें',\n      quarterPlaceholder: 'तिमाही चुनें',\n      monthPlaceholder: 'महीना चुनिए',\n      weekPlaceholder: 'सप्ताह चुनें',\n      rangeYearPlaceholder: ['आरंभिक वर्ष', 'अंत वर्ष'],\n      rangeMonthPlaceholder: ['आरंभिक महीना', 'अंत महीना'],\n      rangeWeekPlaceholder: ['आरंभिक सप्ताह', 'अंत सप्ताह']\n    },\n    timePickerLocale: {\n      placeholder: 'समय का चयन करें',\n      rangePlaceholder: ['आरंभिक समय', 'अंत समय']\n    }\n  },\n  global: {\n    placeholder: 'कृपया चुनें'\n  },\n  Table: {\n    filterTitle: 'सूची बंद करें',\n    filterConfirm: 'अच्छी तरह से',\n    filterReset: 'रीसेट',\n    emptyText: 'कोई जानकारी नहीं',\n    selectAll: 'वर्तमान पृष्ठ का चयन करें',\n    selectInvert: 'वर्तमान पृष्ठ घुमाएं',\n    sortTitle: 'द्वारा क्रमबद्ध करें',\n    filterEmptyText: 'कोई फ़िल्टर नहीं',\n    selectNone: 'सभी डेटा साफ़ करें',\n    selectionAll: 'सभी डेटा का चयन करें',\n    expand: 'पंक्ति का विस्तार करें',\n    collapse: 'पंक्ति संक्षिप्त करें',\n    triggerDesc: 'अवरोही क्रमित करने के लिए क्लिक करें',\n    triggerAsc: 'आरोही क्रमित करने के लिए क्लिक करें',\n    cancelSort: 'छँटाई रद्द करने के लिए क्लिक करें'\n  },\n  Modal: {\n    okText: 'अच्छी तरह से',\n    cancelText: 'रद्द करना',\n    justOkText: 'अच्छी तरह से'\n  },\n  Popconfirm: {\n    okText: 'अच्छी तरह से',\n    cancelText: 'रद्द करना'\n  },\n  Transfer: {\n    titles: ['', ''],\n    notFoundContent: 'नहीं मिला',\n    searchPlaceholder: 'यहां खोजें',\n    itemUnit: 'तत्त्व',\n    itemsUnit: 'विषय-वस्तु',\n    remove: 'हटाए',\n    selectCurrent: 'वर्तमान पृष्ठ का चयन करें',\n    removeCurrent: 'वर्तमान पृष्ठ हटाएं',\n    selectAll: 'सभी डेटा का चयन करें',\n    removeAll: 'सभी डेटा हटाएं',\n    selectInvert: 'वर्तमान पृष्ठ को उल्टा करें'\n  },\n  Select: {\n    notFoundContent: 'नहीं मिला'\n  },\n  Upload: {\n    uploading: 'अपलोड हो रहा...',\n    removeFile: 'फ़ाइल निकालें',\n    uploadError: 'अपलोड में त्रुटि',\n    previewFile: 'फ़ाइल पूर्वावलोकन',\n    downloadFile: 'फ़ाइल डाउनलोड करें'\n  },\n  Empty: {\n    description: 'कोई आकड़ा उपलब्ध नहीं है'\n  },\n  Form: {\n    optional: '(वैकल्पिक)'\n  },\n  Icon: {\n    icon: 'आइकन'\n  },\n  Text: {\n    edit: 'संपादित करें',\n    copy: 'प्रतिलिपि',\n    copied: 'कॉपी किया गया',\n    expand: 'विस्तार'\n  },\n  PageHeader: {\n    back: 'वापस'\n  },\n  Image: {\n    preview: 'पूर्वावलोकन'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/hr_HR.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'hr',\n  Pagination: {\n    items_per_page: '/ str',\n    jump_to: 'Idi na',\n    jump_to_confirm: 'potvrdi',\n    page: '',\n    prev_page: 'Prijašnja stranica',\n    next_page: 'Sljedeća stranica',\n    prev_5: 'Prijašnjih 5 stranica',\n    next_5: 'Sljedećih 5 stranica',\n    prev_3: 'Prijašnje 3 stranice',\n    next_3: 'Sljedeće 3 stranice',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Odaberite datum',\n      rangePlaceholder: ['Početni datum', 'Završni datum'],\n      locale: 'hr_HR',\n      today: 'Danas',\n      now: 'Sad',\n      backToToday: 'Natrag na danas',\n      ok: 'Ok',\n      clear: 'Očisti',\n      month: 'Mjesec',\n      year: 'Godina',\n      timeSelect: 'odaberite vrijeme',\n      dateSelect: 'odaberite datum',\n      weekSelect: 'Odaberite tjedan',\n      monthSelect: 'Odaberite mjesec',\n      yearSelect: 'Odaberite godinu',\n      decadeSelect: 'Odaberite desetljeće',\n      yearFormat: 'YYYY',\n      dateFormat: 'D.M.YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D.M.YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Prošli mjesec (PageUp)',\n      nextMonth: 'Sljedeći mjesec (PageDown)',\n      previousYear: 'Prošla godina (Control + left)',\n      nextYear: 'Sljedeća godina (Control + right)',\n      previousDecade: 'Prošlo desetljeće',\n      nextDecade: 'Sljedeće desetljeće',\n      previousCentury: 'Prošlo stoljeće',\n      nextCentury: 'Sljedeće stoljeće',\n      yearPlaceholder: 'Odaberite godinu',\n      quarterPlaceholder: 'Odaberite četvrtinu',\n      monthPlaceholder: 'Odaberite mjesec',\n      weekPlaceholder: 'Odaberite tjedan',\n      rangeYearPlaceholder: ['Početna godina', 'Završna godina'],\n      rangeMonthPlaceholder: ['Početni mjesec', 'Završni mjesec'],\n      rangeWeekPlaceholder: ['Početni tjedan', 'Završni tjedan']\n    },\n    timePickerLocale: {\n      placeholder: 'Odaberite vrijeme',\n      rangePlaceholder: ['Vrijeme početka', 'Vrijeme završetka']\n    }\n  },\n  TimePicker: {\n    placeholder: 'Odaberite vrijeme',\n    rangePlaceholder: ['Vrijeme početka', 'Vrijeme završetka']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Odaberite datum',\n      rangePlaceholder: ['Početni datum', 'Završni datum'],\n      locale: 'hr_HR',\n      today: 'Danas',\n      now: 'Sad',\n      backToToday: 'Natrag na danas',\n      ok: 'Ok',\n      clear: 'Očisti',\n      month: 'Mjesec',\n      year: 'Godina',\n      timeSelect: 'odaberite vrijeme',\n      dateSelect: 'odaberite datum',\n      weekSelect: 'Odaberite tjedan',\n      monthSelect: 'Odaberite mjesec',\n      yearSelect: 'Odaberite godinu',\n      decadeSelect: 'Odaberite desetljeće',\n      yearFormat: 'YYYY',\n      dateFormat: 'D.M.YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D.M.YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Prošli mjesec (PageUp)',\n      nextMonth: 'Sljedeći mjesec (PageDown)',\n      previousYear: 'Prošla godina (Control + left)',\n      nextYear: 'Sljedeća godina (Control + right)',\n      previousDecade: 'Prošlo desetljeće',\n      nextDecade: 'Sljedeće desetljeće',\n      previousCentury: 'Prošlo stoljeće',\n      nextCentury: 'Sljedeće stoljeće',\n      yearPlaceholder: 'Odaberite godinu',\n      quarterPlaceholder: 'Odaberite četvrtinu',\n      monthPlaceholder: 'Odaberite mjesec',\n      weekPlaceholder: 'Odaberite tjedan',\n      rangeYearPlaceholder: ['Početna godina', 'Završna godina'],\n      rangeMonthPlaceholder: ['Početni mjesec', 'Završni mjesec'],\n      rangeWeekPlaceholder: ['Početni tjedan', 'Završni tjedan']\n    },\n    timePickerLocale: {\n      placeholder: 'Odaberite vrijeme',\n      rangePlaceholder: ['Vrijeme početka', 'Vrijeme završetka']\n    }\n  },\n  global: {\n    placeholder: 'Molimo označite'\n  },\n  Table: {\n    filterTitle: 'Filter meni',\n    filterConfirm: 'OK',\n    filterReset: 'Reset',\n    selectAll: 'Označi trenutnu stranicu',\n    selectInvert: 'Invertiraj trenutnu stranicu',\n    sortTitle: 'Sortiraj',\n    filterEmptyText: 'Nema filtera',\n    emptyText: 'Nema podataka',\n    selectionAll: 'Odaberite sve podatke',\n    expand: 'Proširi redak',\n    collapse: 'Sažmi redak',\n    triggerDesc: 'Kliknite za sortiranje silazno',\n    triggerAsc: 'Kliknite za sortiranje uzlazno',\n    cancelSort: 'Kliknite da biste otkazali sortiranje'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Odustani',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Odustani'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'Pretraži ovdje',\n    itemUnit: 'stavka',\n    itemsUnit: 'stavke',\n    remove: 'Ukloniti',\n    selectCurrent: 'Odaberite trenutnu stranicu',\n    removeCurrent: 'Ukloni trenutnu stranicu',\n    selectAll: 'Odaberite sve podatke',\n    removeAll: 'Uklonite sve podatke',\n    selectInvert: 'Obrni trenutnu stranicu'\n  },\n  Upload: {\n    uploading: 'Upload u tijeku...',\n    removeFile: 'Makni datoteku',\n    uploadError: 'Greška kod uploada',\n    previewFile: 'Pogledaj datoteku',\n    downloadFile: 'Preuzmi datoteku'\n  },\n  Form: {\n    optional: '(neobavezno)'\n  },\n  Empty: {\n    description: 'Nema podataka'\n  },\n  Icon: {\n    icon: 'ikona'\n  },\n  Text: {\n    edit: 'Uredi',\n    copy: 'Kopiraj',\n    copied: 'Kopiranje uspješno',\n    expand: 'Proširi'\n  },\n  PageHeader: {\n    back: 'Natrag'\n  },\n  Image: {\n    preview: 'Pregled'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/hu_HU.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'hu',\n  Pagination: {\n    items_per_page: '/ oldal',\n    jump_to: 'Ugrás',\n    jump_to_confirm: 'megerősít',\n    page: '',\n    prev_page: 'Előző oldal',\n    next_page: 'Következő oldal',\n    prev_5: 'Előző 5 oldal',\n    next_5: 'Következő 5 oldal',\n    prev_3: 'Előző 3 oldal',\n    next_3: 'Következő 3 oldal',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Válasszon dátumot',\n      yearPlaceholder: 'Válasszon évet',\n      quarterPlaceholder: 'Válasszon negyedévet',\n      monthPlaceholder: 'Válasszon hónapot',\n      weekPlaceholder: 'Válasszon hetet',\n      rangePlaceholder: ['Kezdő dátum', 'Befejezés dátuma'],\n      rangeYearPlaceholder: ['Kezdő év', 'Befejezés éve'],\n      rangeMonthPlaceholder: ['Kezdő hónap', 'Befejezés hónapja'],\n      rangeWeekPlaceholder: ['Kezdő hét', 'Befejezés hete'],\n      locale: 'hu_HU',\n      today: 'Ma',\n      now: 'Most',\n      backToToday: 'Vissza a mai napra',\n      ok: 'Ok',\n      clear: 'Törlés',\n      month: 'Hónap',\n      year: 'Év',\n      timeSelect: 'Időpont kiválasztása',\n      dateSelect: 'Dátum kiválasztása',\n      weekSelect: 'Hét kiválasztása',\n      monthSelect: 'Hónap kiválasztása',\n      yearSelect: 'Év kiválasztása',\n      decadeSelect: 'Évtized kiválasztása',\n      yearFormat: 'YYYY',\n      dateFormat: 'YYYY/MM/DD',\n      dayFormat: 'DD',\n      dateTimeFormat: 'YYYY/MM/DD HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Előző hónap (PageUp)',\n      nextMonth: 'Következő hónap (PageDown)',\n      previousYear: 'Múlt év (Control + left)',\n      nextYear: 'Jövő év (Control + right)',\n      previousDecade: 'Előző évtized',\n      nextDecade: 'Következő évtized',\n      previousCentury: 'Múlt évszázad',\n      nextCentury: 'Jövő évszázad',\n      rangeQuarterPlaceholder: ['Kezdő negyedév', 'Befejezés negyedéve']\n    },\n    timePickerLocale: {\n      placeholder: 'Válasszon időt',\n      rangePlaceholder: ['Kezdő idő', 'Befejezés ideje']\n    }\n  },\n  TimePicker: {\n    placeholder: 'Válasszon időt',\n    rangePlaceholder: ['Kezdő idő', 'Befejezés ideje']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Válasszon dátumot',\n      yearPlaceholder: 'Válasszon évet',\n      quarterPlaceholder: 'Válasszon negyedévet',\n      monthPlaceholder: 'Válasszon hónapot',\n      weekPlaceholder: 'Válasszon hetet',\n      rangePlaceholder: ['Kezdő dátum', 'Befejezés dátuma'],\n      rangeYearPlaceholder: ['Kezdő év', 'Befejezés éve'],\n      rangeMonthPlaceholder: ['Kezdő hónap', 'Befejezés hónapja'],\n      rangeWeekPlaceholder: ['Kezdő hét', 'Befejezés hete'],\n      locale: 'hu_HU',\n      today: 'Ma',\n      now: 'Most',\n      backToToday: 'Vissza a mai napra',\n      ok: 'Ok',\n      clear: 'Törlés',\n      month: 'Hónap',\n      year: 'Év',\n      timeSelect: 'Időpont kiválasztása',\n      dateSelect: 'Dátum kiválasztása',\n      weekSelect: 'Hét kiválasztása',\n      monthSelect: 'Hónap kiválasztása',\n      yearSelect: 'Év kiválasztása',\n      decadeSelect: 'Évtized kiválasztása',\n      yearFormat: 'YYYY',\n      dateFormat: 'YYYY/MM/DD',\n      dayFormat: 'DD',\n      dateTimeFormat: 'YYYY/MM/DD HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Előző hónap (PageUp)',\n      nextMonth: 'Következő hónap (PageDown)',\n      previousYear: 'Múlt év (Control + left)',\n      nextYear: 'Jövő év (Control + right)',\n      previousDecade: 'Előző évtized',\n      nextDecade: 'Következő évtized',\n      previousCentury: 'Múlt évszázad',\n      nextCentury: 'Jövő évszázad'\n    },\n    timePickerLocale: {\n      placeholder: 'Válasszon időt',\n      rangePlaceholder: ['Kezdő idő', 'Befejezés ideje']\n    }\n  },\n  global: {\n    placeholder: 'Kérlek, válassz'\n  },\n  Table: {\n    filterTitle: 'Szűrők',\n    filterConfirm: 'Alkalmazás',\n    filterReset: 'Visszaállítás',\n    filterEmptyText: 'No filters',\n    emptyText: 'Nincs adat',\n    selectAll: 'Jelenlegi oldal kiválasztása',\n    selectInvert: 'Jelenlegi oldal inverze',\n    selectionAll: 'Összes adat kiválasztása',\n    sortTitle: 'Rendezés',\n    expand: 'Sor kinyitása',\n    collapse: 'Sor becsukása',\n    triggerDesc: 'Kattintson a csökkenő sorrendbe rendezéshez',\n    triggerAsc: 'Kattintson a növekvő sorrendbe rendezéshez',\n    cancelSort: 'Kattintson a rendezés visszavonásához',\n    selectNone: 'Összes visszavonása'\n  },\n  Modal: {\n    okText: 'Alkalmazás',\n    cancelText: 'Visszavonás',\n    justOkText: 'Alkalmazás'\n  },\n  Popconfirm: {\n    okText: 'Alkalmazás',\n    cancelText: 'Visszavonás'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'Keresés',\n    itemUnit: 'elem',\n    itemsUnit: 'elemek',\n    remove: 'Eltávolít',\n    selectCurrent: 'Jelenlegi oldal kiválasztása',\n    removeCurrent: 'Jelenlegi oldal eltávolítása',\n    selectAll: 'Összes adat kiválasztása',\n    removeAll: 'Összes adat eltávolítása',\n    selectInvert: 'Jelenlegi oldal inverze'\n  },\n  Upload: {\n    uploading: 'Feltöltés...',\n    removeFile: 'Fájl eltávolítása',\n    uploadError: 'Feltöltési hiba',\n    previewFile: 'Fájl előnézet',\n    downloadFile: 'Fájl letöltése'\n  },\n  Form: {\n    optional: '(nem kötelező)'\n  },\n  Empty: {\n    description: 'Nincs adat'\n  },\n  Icon: {\n    icon: 'ikon'\n  },\n  Text: {\n    edit: 'Szerkesztés',\n    copy: 'Másolás',\n    copied: 'Másolva',\n    expand: 'Kiterjesztés'\n  },\n  PageHeader: {\n    back: 'Vissza'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/hy_AM.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'hy-am',\n  Pagination: {\n    items_per_page: '/ էջ',\n    jump_to: 'Գնալ',\n    jump_to_confirm: 'հաստատել',\n    page: '',\n    prev_page: 'Նախորդ Էջ',\n    next_page: 'Հաջորդ Էջ',\n    prev_5: 'Նախորդ 5 Էջերը',\n    next_5: 'Հաջորդ 5 Էջերը',\n    prev_3: 'Նախորդ 3 Էջերը',\n    next_3: 'Հաջորդ 3 Էջերը'\n  },\n  DatePicker: {\n    lang: {\n      locale: 'hy-am',\n      placeholder: 'Ընտրեք ամսաթիվը',\n      rangePlaceholder: ['Մեկնարկի ամսաթիվ', 'Ավարտի ամսաթիվը'],\n      today: 'Այսօր',\n      now: 'Հիմա',\n      backToToday: 'Վերադառնալ այսօր',\n      ok: 'Օկ',\n      clear: 'Մաքրել',\n      month: 'Ամիս',\n      year: 'Տարի',\n      timeSelect: 'ընտրեք ժամը',\n      dateSelect: 'ընտրեք ամսաթիվը',\n      weekSelect: 'Ընտրեք շաբաթը',\n      monthSelect: 'Ընտրեք ամիսը',\n      yearSelect: 'Ընտրեք տարին',\n      decadeSelect: 'Ընտրեք տասնամյակը',\n      yearFormat: 'YYYY',\n      dateFormat: 'DD/MM//YYYY',\n      dayFormat: 'DD',\n      dateTimeFormat: 'DD/MM//YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Անցած ամիս (PageUp)',\n      nextMonth: 'Մյուս ամիս (PageDown)',\n      previousYear: 'Անցած տարի (Control + left)',\n      nextYear: 'Մյուս տարի (Control + right)',\n      previousDecade: 'Անցած տասնամյակ',\n      nextDecade: 'Մյուս տասնամյակ',\n      previousCentury: 'Անցած դար',\n      nextCentury: 'Մյուս դար'\n    },\n    timePickerLocale: {\n      placeholder: 'Ընտրեք ժամը'\n    }\n  },\n  TimePicker: {\n    placeholder: 'Ընտրեք ժամը'\n  },\n  Calendar: {\n    lang: {\n      locale: 'hy-am',\n      placeholder: 'Ընտրեք ամսաթիվը',\n      rangePlaceholder: ['Մեկնարկի ամսաթիվ', 'Ավարտի ամսաթիվը'],\n      today: 'Այսօր',\n      now: 'Հիմա',\n      backToToday: 'Վերադառնալ այսօր',\n      ok: 'Օկ',\n      clear: 'Մաքրել',\n      month: 'Ամիս',\n      year: 'Տարի',\n      timeSelect: 'ընտրեք ժամը',\n      dateSelect: 'ընտրեք ամսաթիվը',\n      weekSelect: 'Ընտրեք շաբաթը',\n      monthSelect: 'Ընտրեք ամիսը',\n      yearSelect: 'Ընտրեք տարին',\n      decadeSelect: 'Ընտրեք տասնամյակը',\n      yearFormat: 'YYYY',\n      dateFormat: 'DD/MM//YYYY',\n      dayFormat: 'DD',\n      dateTimeFormat: 'DD/MM//YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Անցած ամիս (PageUp)',\n      nextMonth: 'Մյուս ամիս (PageDown)',\n      previousYear: 'Անցած տարի (Control + left)',\n      nextYear: 'Մյուս տարի (Control + right)',\n      previousDecade: 'Անցած տասնամյակ',\n      nextDecade: 'Մյուս տասնամյակ',\n      previousCentury: 'Անցած դար',\n      nextCentury: 'Մյուս դար'\n    },\n    timePickerLocale: {\n      placeholder: 'Ընտրեք ժամը'\n    }\n  },\n  global: {\n    placeholder: 'Ընտրեք'\n  },\n  Table: {\n    filterTitle: 'ֆիլտրի ընտրացանկ',\n    filterConfirm: 'ֆիլտրել',\n    filterReset: 'Զրոյացնել',\n    selectAll: 'Ընտրեք ընթացիկ էջը',\n    selectInvert: 'Փոխարկել ընթացիկ էջը',\n    sortTitle: 'Տեսակավորել',\n    expand: 'Ընդլայնեք տողը',\n    collapse: 'Կրճատել տողը'\n  },\n  Modal: {\n    okText: 'Օկ',\n    cancelText: 'Չեղարկել',\n    justOkText: 'Օկ'\n  },\n  Popconfirm: {\n    okText: 'Հաստատել',\n    cancelText: 'Մերժել'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'Որոնեք այստեղ',\n    itemUnit: 'պարագան',\n    itemsUnit: 'պարագաները'\n  },\n  Upload: {\n    uploading: 'Ներբեռնում...',\n    removeFile: 'Հեռացնել ֆայլը',\n    uploadError: 'Ներբեռնման սխալ',\n    previewFile: 'Դիտել ֆայլը',\n    downloadFile: 'Ներբեռնել ֆայլը'\n  },\n  Empty: {\n    description: 'Տվյալներ չկան'\n  },\n  Form: {\n    optional: '(ընտրելի)'\n  },\n  Icon: {\n    icon: 'պատկեր'\n  },\n  Text: {\n    edit: 'Խմբագրել',\n    copy: 'Պատճենել',\n    copied: 'Պատճենվել է',\n    expand: 'Տեսնել ավելին'\n  },\n  PageHeader: {\n    back: 'Հետ'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/id_ID.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'id',\n  Pagination: {\n    items_per_page: '/ halaman',\n    jump_to: 'Menuju',\n    jump_to_confirm: 'konfirmasi',\n    page: 'Halaman',\n    prev_page: 'Halaman Sebelumnya',\n    next_page: 'Halaman Berikutnya',\n    prev_5: '5 Halaman Sebelumnya',\n    next_5: '5 Halaman Berikutnya',\n    prev_3: '3 Halaman Sebelumnya',\n    next_3: '3 Halaman Berikutnya',\n    page_size: 'ukuran halaman'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Pilih tanggal',\n      rangePlaceholder: ['Mulai tanggal', 'Tanggal akhir'],\n      locale: 'id_ID',\n      today: 'Hari ini',\n      now: 'Sekarang',\n      backToToday: 'Kembali ke hari ini',\n      ok: 'Baik',\n      clear: 'Bersih',\n      month: 'Bulan',\n      year: 'Tahun',\n      timeSelect: 'pilih waktu',\n      dateSelect: 'pilih tanggal',\n      weekSelect: 'Pilih satu minggu',\n      monthSelect: 'Pilih satu bulan',\n      yearSelect: 'Pilih satu tahun',\n      decadeSelect: 'Pilih satu dekade',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Bulan sebelumnya (PageUp)',\n      nextMonth: 'Bulan selanjutnya (PageDown)',\n      previousYear: 'Tahun lalu (Control + kiri)',\n      nextYear: 'Tahun selanjutnya (Kontrol + kanan)',\n      previousDecade: 'Dekade terakhir',\n      nextDecade: 'Dekade berikutnya',\n      previousCentury: 'Abad terakhir',\n      nextCentury: 'Abad berikutnya'\n    },\n    timePickerLocale: {\n      placeholder: 'Pilih waktu'\n    }\n  },\n  TimePicker: {\n    placeholder: 'Pilih waktu'\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Pilih tanggal',\n      rangePlaceholder: ['Mulai tanggal', 'Tanggal akhir'],\n      locale: 'id_ID',\n      today: 'Hari ini',\n      now: 'Sekarang',\n      backToToday: 'Kembali ke hari ini',\n      ok: 'Baik',\n      clear: 'Bersih',\n      month: 'Bulan',\n      year: 'Tahun',\n      timeSelect: 'pilih waktu',\n      dateSelect: 'pilih tanggal',\n      weekSelect: 'Pilih satu minggu',\n      monthSelect: 'Pilih satu bulan',\n      yearSelect: 'Pilih satu tahun',\n      decadeSelect: 'Pilih satu dekade',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Bulan sebelumnya (PageUp)',\n      nextMonth: 'Bulan selanjutnya (PageDown)',\n      previousYear: 'Tahun lalu (Control + kiri)',\n      nextYear: 'Tahun selanjutnya (Kontrol + kanan)',\n      previousDecade: 'Dekade terakhir',\n      nextDecade: 'Dekade berikutnya',\n      previousCentury: 'Abad terakhir',\n      nextCentury: 'Abad berikutnya'\n    },\n    timePickerLocale: {\n      placeholder: 'Pilih waktu'\n    }\n  },\n  Table: {\n    filterTitle: 'Saring',\n    filterConfirm: 'OK',\n    filterReset: 'Hapus',\n    selectAll: 'Pilih semua di halaman ini',\n    selectInvert: 'Balikkan pilihan di halaman ini',\n    sortTitle: 'Urutkan'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Batal',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Batal'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'Cari',\n    itemUnit: 'item',\n    itemsUnit: 'item'\n  },\n  Upload: {\n    uploading: 'Mengunggah...',\n    removeFile: 'Hapus file',\n    uploadError: 'Kesalahan pengunggahan',\n    previewFile: 'File pratinjau',\n    downloadFile: 'Unduh berkas'\n  },\n  Empty: {\n    description: 'Tidak ada data'\n  },\n  Form: {\n    optional: '(pilihan)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/is_IS.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'is',\n  Pagination: {\n    items_per_page: '/ síðu',\n    jump_to: 'Síða',\n    jump_to_confirm: 'staðfest',\n    page: '',\n    prev_page: 'Fyrri síða',\n    next_page: 'Næsta síða',\n    prev_5: 'Til baka 5 síður',\n    next_5: 'Áfram 5 síður',\n    prev_3: 'Til baka 3 síður',\n    next_3: 'Áfram 3 síður',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Veldu dag',\n      rangePlaceholder: ['Upphafsdagur', 'Lokadagur'],\n      locale: 'is_IS',\n      today: 'Í dag',\n      now: 'Núna',\n      backToToday: 'Til baka til dagsins í dag',\n      ok: 'Í lagi',\n      clear: 'Hreinsa',\n      month: 'Mánuður',\n      year: 'Ár',\n      timeSelect: 'Velja tíma',\n      dateSelect: 'Velja dag',\n      monthSelect: 'Velja mánuð',\n      yearSelect: 'Velja ár',\n      decadeSelect: 'Velja áratug',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Fyrri mánuður (PageUp)',\n      nextMonth: 'Næsti mánuður (PageDown)',\n      previousYear: 'Fyrra ár (Control + left)',\n      nextYear: 'Næsta ár (Control + right)',\n      previousDecade: 'Fyrri áratugur',\n      nextDecade: 'Næsti áratugur',\n      previousCentury: 'Fyrri öld',\n      nextCentury: 'Næsta öld'\n    },\n    timePickerLocale: {\n      placeholder: 'Velja tíma'\n    }\n  },\n  TimePicker: {\n    placeholder: 'Velja tíma'\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Veldu dag',\n      rangePlaceholder: ['Upphafsdagur', 'Lokadagur'],\n      locale: 'is_IS',\n      today: 'Í dag',\n      now: 'Núna',\n      backToToday: 'Til baka til dagsins í dag',\n      ok: 'Í lagi',\n      clear: 'Hreinsa',\n      month: 'Mánuður',\n      year: 'Ár',\n      timeSelect: 'Velja tíma',\n      dateSelect: 'Velja dag',\n      monthSelect: 'Velja mánuð',\n      yearSelect: 'Velja ár',\n      decadeSelect: 'Velja áratug',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Fyrri mánuður (PageUp)',\n      nextMonth: 'Næsti mánuður (PageDown)',\n      previousYear: 'Fyrra ár (Control + left)',\n      nextYear: 'Næsta ár (Control + right)',\n      previousDecade: 'Fyrri áratugur',\n      nextDecade: 'Næsti áratugur',\n      previousCentury: 'Fyrri öld',\n      nextCentury: 'Næsta öld'\n    },\n    timePickerLocale: {\n      placeholder: 'Velja tíma'\n    }\n  },\n  Table: {\n    filterTitle: 'Afmarkanir',\n    filterConfirm: 'Staðfesta',\n    filterReset: 'Núllstilla',\n    selectAll: 'Velja allt',\n    selectInvert: 'Viðsnúa vali'\n  },\n  Modal: {\n    okText: 'Áfram',\n    cancelText: 'Hætta við',\n    justOkText: 'Í lagi'\n  },\n  Popconfirm: {\n    okText: 'Áfram',\n    cancelText: 'Hætta við'\n  },\n  Transfer: {\n    searchPlaceholder: 'Leita hér',\n    itemUnit: 'færsla',\n    itemsUnit: 'færslur'\n  },\n  Upload: {\n    uploading: 'Hleð upp...',\n    removeFile: 'Fjarlægja skrá',\n    uploadError: 'Villa við að hlaða upp',\n    previewFile: 'Forskoða skrá',\n    downloadFile: 'Hlaða niður skrá'\n  },\n  Empty: {\n    description: 'Engin gögn'\n  },\n  Form: {\n    optional: '(valfrjálst)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/it_IT.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'it',\n  Pagination: {\n    items_per_page: '/ pagina',\n    jump_to: 'vai a',\n    jump_to_confirm: 'Conferma',\n    page: 'Pagina',\n    prev_page: 'Pagina precedente',\n    next_page: 'Pagina successiva',\n    prev_5: 'Precedente 5 pagine',\n    next_5: 'Prossime 5 pagine',\n    prev_3: 'Precedente 3 pagine',\n    next_3: 'Prossime 3 pagine',\n    page_size: 'dimensioni della pagina'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Selezionare la data',\n      yearPlaceholder: \"Selezionare l'anno\",\n      quarterPlaceholder: 'Selezionare il trimestre',\n      monthPlaceholder: 'Selezionare il mese',\n      weekPlaceholder: 'Selezionare la settimana',\n      rangePlaceholder: [\"Data d'inizio\", 'Data di fine'],\n      rangeYearPlaceholder: [\"Anno d'inizio\", 'Anno di fine'],\n      rangeMonthPlaceholder: [\"Mese d'inizio \", 'Mese di fine'],\n      rangeWeekPlaceholder: [\"Settimana d'inizio\", 'Settimana di fine'],\n      locale: 'it_IT',\n      today: 'Oggi',\n      now: 'Adesso',\n      backToToday: 'Torna ad oggi',\n      ok: 'Ok',\n      clear: 'Cancella',\n      month: 'Mese',\n      year: 'Anno',\n      timeSelect: \"Seleziona l'ora\",\n      dateSelect: 'Seleziona la data',\n      weekSelect: 'Seleziona la settimana',\n      monthSelect: 'Seleziona il mese',\n      yearSelect: \"Seleziona l'anno\",\n      decadeSelect: 'Seleziona il decennio',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Il mese scorso (PageUp)',\n      nextMonth: 'Il prossimo mese (PageDown)',\n      previousYear: \"L'anno scorso (Control + sinistra)\",\n      nextYear: \"L'anno prossimo (Control + destra)\",\n      previousDecade: 'Ultimo decennio',\n      nextDecade: 'Prossimo decennio',\n      previousCentury: 'Secolo precedente',\n      nextCentury: 'Prossimo secolo'\n    },\n    timePickerLocale: {\n      placeholder: \"Selezionare l'orario\",\n      rangePlaceholder: [\"Ora d'inizio\", 'Ora di fine']\n    }\n  },\n  TimePicker: {\n    placeholder: \"Selezionare l'orario\",\n    rangePlaceholder: [\"Ora d'inizio\", 'Ora di fine']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Selezionare la data',\n      yearPlaceholder: \"Selezionare l'anno\",\n      quarterPlaceholder: 'Selezionare il trimestre',\n      monthPlaceholder: 'Selezionare il mese',\n      weekPlaceholder: 'Selezionare la settimana',\n      rangePlaceholder: [\"Data d'inizio\", 'Data di fine'],\n      rangeYearPlaceholder: [\"Anno d'inizio\", 'Anno di fine'],\n      rangeMonthPlaceholder: [\"Mese d'inizio \", 'Mese di fine'],\n      rangeWeekPlaceholder: [\"Settimana d'inizio\", 'Settimana di fine'],\n      locale: 'it_IT',\n      today: 'Oggi',\n      now: 'Adesso',\n      backToToday: 'Torna ad oggi',\n      ok: 'Ok',\n      clear: 'Cancella',\n      month: 'Mese',\n      year: 'Anno',\n      timeSelect: \"Seleziona l'ora\",\n      weekSelect: 'Seleziona la settimana',\n      dateSelect: 'Seleziona la data',\n      monthSelect: 'Seleziona il mese',\n      yearSelect: \"Seleziona l'anno\",\n      decadeSelect: 'Seleziona il decennio',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Il mese scorso (PageUp)',\n      nextMonth: 'Il prossimo mese (PageDown)',\n      previousYear: \"L'anno scorso (Control + sinistra)\",\n      nextYear: \"L'anno prossimo (Control + destra)\",\n      previousDecade: 'Ultimo decennio',\n      nextDecade: 'Prossimo decennio',\n      previousCentury: 'Secolo precedente',\n      nextCentury: 'Prossimo secolo'\n    },\n    timePickerLocale: {\n      placeholder: \"Selezionare l'orario\",\n      rangePlaceholder: [\"Ora d'inizio\", 'Ora di fine']\n    }\n  },\n  global: {\n    placeholder: 'Selezionare'\n  },\n  Table: {\n    filterTitle: 'Menù Filtro',\n    filterConfirm: 'OK',\n    filterReset: 'Reset',\n    filterEmptyText: 'Nessun filtro',\n    emptyText: 'Nessun dato',\n    selectAll: 'Seleziona pagina corrente',\n    selectInvert: 'Inverti selezione nella pagina corrente',\n    selectionAll: 'Seleziona tutti i dati',\n    sortTitle: 'Ordina',\n    expand: 'Esapandi riga',\n    collapse: 'Chiudi riga',\n    triggerDesc: 'Clicca per ordinare in modo discendente',\n    triggerAsc: 'Clicca per ordinare in modo ascendente',\n    cancelSort: 'Clicca per eliminare i filtri',\n    filterCheckall: 'Seleziona tutto',\n    filterSearchPlaceholder: 'Cerca nei filtri',\n    selectNone: 'Pulisci tutti i dati'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Annulla',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Annulla'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'Cerca qui',\n    itemUnit: 'elemento',\n    itemsUnit: 'elementi',\n    remove: 'Rimuovi',\n    selectCurrent: 'Seleziona pagina corrente',\n    removeCurrent: 'Rimuovi pagina corrente',\n    selectAll: 'Selezione tutti i dati',\n    removeAll: 'Rimuovi tutti i dati',\n    selectInvert: 'Inverti selezione nella pagina corrente'\n  },\n  Upload: {\n    uploading: 'Caricamento...',\n    removeFile: 'Rimuovi il file',\n    uploadError: 'Errore di caricamento',\n    previewFile: 'Anteprima file',\n    downloadFile: 'Download file'\n  },\n  Form: {\n    optional: '(opzionale)'\n  },\n  Empty: {\n    description: 'Nessun dato'\n  },\n  Icon: {\n    icon: 'icona'\n  },\n  Text: {\n    edit: 'modifica',\n    copy: 'copia',\n    copied: 'copia effettuata',\n    expand: 'espandi'\n  },\n  PageHeader: {\n    back: 'Indietro'\n  },\n  Image: {\n    preview: 'Anteprima'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/ja_JP.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'ja',\n  Pagination: {\n    items_per_page: '件 / ページ',\n    jump_to: '移動',\n    jump_to_confirm: '確認する',\n    page: 'ページ',\n    prev_page: '前のページ',\n    next_page: '次のページ',\n    prev_5: '前 5ページ',\n    next_5: '次 5ページ',\n    prev_3: '前 3ページ',\n    next_3: '次 3ページ',\n    page_size: 'ページサイズ'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: '日付を選択',\n      yearPlaceholder: '年を選択',\n      monthPlaceholder: '月を選択',\n      weekPlaceholder: '週を選択',\n      rangePlaceholder: ['開始日付', '終了日付'],\n      rangeYearPlaceholder: ['開始年', '終了年'],\n      rangeMonthPlaceholder: ['開始月', '終了月'],\n      rangeWeekPlaceholder: ['開始週', '終了週'],\n      locale: 'ja_JP',\n      today: '今日',\n      now: '現在時刻',\n      backToToday: '今日に戻る',\n      ok: '決定',\n      timeSelect: '時間を選択',\n      dateSelect: '日時を選択',\n      weekSelect: '週を選択',\n      clear: 'クリア',\n      month: '月',\n      year: '年',\n      previousMonth: '前月 (ページアップキー)',\n      nextMonth: '翌月 (ページダウンキー)',\n      monthSelect: '月を選択',\n      yearSelect: '年を選択',\n      decadeSelect: '年代を選択',\n      yearFormat: 'YYYY年',\n      dayFormat: 'D日',\n      dateFormat: 'YYYY年M月D日',\n      dateTimeFormat: 'YYYY年M月D日 HH時mm分ss秒',\n      previousYear: '前年 (Controlを押しながら左キー)',\n      nextYear: '翌年 (Controlを押しながら右キー)',\n      previousDecade: '前の年代',\n      nextDecade: '次の年代',\n      previousCentury: '前の世紀',\n      nextCentury: '次の世紀'\n    },\n    timePickerLocale: {\n      placeholder: '時間を選択',\n      rangePlaceholder: ['開始時間', '終了時間']\n    }\n  },\n  TimePicker: {\n    placeholder: '時間を選択',\n    rangePlaceholder: ['開始時間', '終了時間']\n  },\n  Calendar: {\n    lang: {\n      placeholder: '日付を選択',\n      rangePlaceholder: ['開始日付', '終了日付'],\n      locale: 'ja_JP',\n      today: '今日',\n      now: '現在時刻',\n      backToToday: '今日に戻る',\n      ok: '決定',\n      timeSelect: '時間を選択',\n      dateSelect: '日時を選択',\n      weekSelect: '週を選択',\n      clear: 'クリア',\n      month: '月',\n      year: '年',\n      previousMonth: '前月 (ページアップキー)',\n      nextMonth: '翌月 (ページダウンキー)',\n      monthSelect: '月を選択',\n      yearSelect: '年を選択',\n      decadeSelect: '年代を選択',\n      yearFormat: 'YYYY年',\n      dayFormat: 'D日',\n      dateFormat: 'YYYY年M月D日',\n      dateTimeFormat: 'YYYY年M月D日 HH時mm分ss秒',\n      previousYear: '前年 (Controlを押しながら左キー)',\n      nextYear: '翌年 (Controlを押しながら右キー)',\n      previousDecade: '前の年代',\n      nextDecade: '次の年代',\n      previousCentury: '前の世紀',\n      nextCentury: '次の世紀'\n    },\n    timePickerLocale: {\n      placeholder: '時間を選択',\n      rangePlaceholder: ['開始時間', '終了時間']\n    }\n  },\n  Table: {\n    filterTitle: 'フィルター',\n    filterConfirm: 'OK',\n    filterReset: 'リセット',\n    filterEmptyText: 'フィルターなし',\n    selectAll: 'ページ単位で選択',\n    selectInvert: 'ページ単位で反転',\n    selectionAll: 'すべてを選択',\n    sortTitle: 'ソート',\n    expand: '展開する',\n    collapse: '折り畳む',\n    triggerDesc: 'クリックで降順にソート',\n    triggerAsc: 'クリックで昇順にソート',\n    cancelSort: 'ソートをキャンセル'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'キャンセル',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'キャンセル'\n  },\n  Transfer: {\n    searchPlaceholder: 'ここを検索',\n    itemUnit: 'アイテム',\n    itemsUnit: 'アイテム'\n  },\n  Upload: {\n    uploading: 'アップロード中...',\n    removeFile: 'ファイルを削除',\n    uploadError: 'アップロードエラー',\n    previewFile: 'ファイルをプレビュー',\n    downloadFile: 'ダウンロードファイル'\n  },\n  Empty: {\n    description: 'データがありません'\n  },\n  Form: {\n    optional: '(任意)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/ka_GE.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'ka',\n  Pagination: {\n    items_per_page: '/ გვერდი.',\n    jump_to: 'გადასვლა',\n    jump_to_confirm: 'დადასტურება',\n    page: '',\n    prev_page: 'წინა გვერდი',\n    next_page: 'შემდეგი გვერდი',\n    prev_5: 'წინა 5 გვერდი',\n    next_5: 'შემდეგი 5 გვერდი',\n    prev_3: 'წინა 3 გვერდი',\n    next_3: 'შემდეგი 3 გვერდი',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'აირჩიეთ თარიღი',\n      yearPlaceholder: 'აირჩიეთ წელი',\n      quarterPlaceholder: 'აირჩიეთ მეოთხედი',\n      monthPlaceholder: 'აირჩიეთ თვე',\n      weekPlaceholder: 'აირჩიეთ კვირა',\n      rangePlaceholder: ['საწყისი თარიღი', 'საბოლოო თარიღი'],\n      rangeYearPlaceholder: ['საწყისი წელი', 'საბოლოო წელი'],\n      rangeMonthPlaceholder: ['საწყისი თვე', 'საბოლოო თვე'],\n      rangeWeekPlaceholder: ['საწყისი კვირა', 'საბოლოო კვირა'],\n      locale: 'ka_GE',\n      today: 'დღეს',\n      now: 'ახლა',\n      backToToday: 'მიმდინარე თარიღი',\n      ok: 'Ok',\n      clear: 'გასუფთავება',\n      month: 'თვე',\n      year: 'წელი',\n      timeSelect: 'დროის არჩევა',\n      dateSelect: 'თარიღის არჩევა',\n      weekSelect: 'კვირის არჩევა',\n      monthSelect: 'თვის არჩევა',\n      yearSelect: 'წლის არჩევა',\n      decadeSelect: 'ათწლეულის არჩევა',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'წინა თვე (PageUp)',\n      nextMonth: 'მომდევნო თვე (PageDown)',\n      previousYear: 'წინა წელი (Control + left)',\n      nextYear: 'მომდევნო წელი (Control + right)',\n      previousDecade: 'წინა ათწლეული',\n      nextDecade: 'მომდევნო ათწლეული',\n      previousCentury: 'გასული საუკუნე',\n      nextCentury: 'მომდევნო საუკუნე'\n    },\n    timePickerLocale: {\n      placeholder: 'აირჩიეთ დრო',\n      rangePlaceholder: ['საწყისი თარიღი', 'საბოლოო თარიღი']\n    }\n  },\n  TimePicker: {\n    placeholder: 'აირჩიეთ დრო',\n    rangePlaceholder: ['საწყისი თარიღი', 'საბოლოო თარიღი']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'აირჩიეთ თარიღი',\n      yearPlaceholder: 'აირჩიეთ წელი',\n      quarterPlaceholder: 'აირჩიეთ მეოთხედი',\n      monthPlaceholder: 'აირჩიეთ თვე',\n      weekPlaceholder: 'აირჩიეთ კვირა',\n      rangePlaceholder: ['საწყისი თარიღი', 'საბოლოო თარიღი'],\n      rangeYearPlaceholder: ['საწყისი წელი', 'საბოლოო წელი'],\n      rangeMonthPlaceholder: ['საწყისი თვე', 'საბოლოო თვე'],\n      rangeWeekPlaceholder: ['საწყისი კვირა', 'საბოლოო კვირა'],\n      locale: 'ka_GE',\n      today: 'დღეს',\n      now: 'ახლა',\n      backToToday: 'მიმდინარე თარიღი',\n      ok: 'Ok',\n      clear: 'გასუფთავება',\n      month: 'თვე',\n      year: 'წელი',\n      timeSelect: 'დროის არჩევა',\n      dateSelect: 'თარიღის არჩევა',\n      weekSelect: 'კვირის არჩევა',\n      monthSelect: 'თვის არჩევა',\n      yearSelect: 'წლის არჩევა',\n      decadeSelect: 'ათწლეულის არჩევა',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'წინა თვე (PageUp)',\n      nextMonth: 'მომდევნო თვე (PageDown)',\n      previousYear: 'წინა წელი (Control + left)',\n      nextYear: 'მომდევნო წელი (Control + right)',\n      previousDecade: 'წინა ათწლეული',\n      nextDecade: 'მომდევნო ათწლეული',\n      previousCentury: 'გასული საუკუნე',\n      nextCentury: 'მომდევნო საუკუნე'\n    },\n    timePickerLocale: {\n      placeholder: 'აირჩიეთ დრო',\n      rangePlaceholder: ['საწყისი თარიღი', 'საბოლოო თარიღი']\n    }\n  },\n  global: {\n    placeholder: 'გთხოვთ აირჩიოთ'\n  },\n  Table: {\n    filterTitle: 'ფილტრის მენიუ',\n    filterConfirm: 'კარგი',\n    filterReset: 'გასუფთავება',\n    filterEmptyText: 'ფილტრები არაა',\n    emptyText: 'ინფორმაცია არაა',\n    selectAll: 'აირჩიეთ მიმდინარე გვერდი',\n    selectInvert: 'შეაბრუნეთ მიმდინარე გვერდი',\n    selectionAll: 'ყველას მონიშვნა',\n    sortTitle: 'დალაგება',\n    expand: 'სტრიქონის გაშლა',\n    collapse: 'სტრიქონის შეკუმშვა',\n    triggerDesc: 'დაღმავალი დალაგება',\n    triggerAsc: 'აღმავალი დალაგება',\n    cancelSort: 'დალაგების გაუქმება',\n    selectNone: 'მონაცემების გასუფთავება'\n  },\n  Modal: {\n    okText: 'კარგი',\n    cancelText: 'გაუქმება',\n    justOkText: 'ოკ'\n  },\n  Popconfirm: {\n    okText: 'კარგი',\n    cancelText: 'გაუქმება'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'მოძებნე აქ',\n    itemUnit: 'ერთეული',\n    itemsUnit: 'ერთეულები',\n    remove: 'ამოშლა',\n    selectCurrent: 'მიმდინარე გვერდის არჩევა',\n    removeCurrent: 'მიმდინარე გვერდის ამოშლა',\n    selectAll: 'ყველას მონიშვნა',\n    removeAll: 'ყველას წაშლა',\n    selectInvert: 'მიმდინარე გვერდის შებრუნება'\n  },\n  Upload: {\n    uploading: 'იტვირთება...',\n    removeFile: 'ფაილის ამოშლა',\n    uploadError: 'ატვირთვის შეცდომა',\n    previewFile: 'ფაილის გადახედვა',\n    downloadFile: 'ფაილის ჩამოტვირთვა'\n  },\n  Empty: {\n    description: 'ინფორმაცია არაა'\n  },\n  Form: {\n    optional: '(არასავალდებულო)'\n  },\n  Icon: {\n    icon: 'ხატულა'\n  },\n  Text: {\n    edit: 'რედაქტირება',\n    copy: 'ასლი',\n    copied: 'ასლი აღებულია',\n    expand: 'გაშლა'\n  },\n  PageHeader: {\n    back: 'უკან'\n  },\n  Image: {\n    preview: 'გადახედვა'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/kk_KZ.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'kk',\n  Pagination: {\n    items_per_page: '/ бет',\n    jump_to: 'Секіру',\n    jump_to_confirm: 'Растау',\n    page: '',\n    prev_page: 'Артқа',\n    next_page: 'Алға',\n    prev_5: 'Алдыңғы 5',\n    next_5: 'Келесі 5',\n    prev_3: 'Алдыңғы 3',\n    next_3: 'Келесі 3',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Күнді таңдаңыз',\n      yearPlaceholder: 'Жылды таңдаңыз',\n      quarterPlaceholder: 'Тоқсанды таңдаңыз',\n      monthPlaceholder: 'Айды таңдаңыз',\n      weekPlaceholder: 'Аптаны таңдаңыз',\n      rangePlaceholder: ['Бастау күні', 'Аяқталу күні'],\n      rangeYearPlaceholder: ['Бастау жылы', 'Аяқталу жылы'],\n      rangeMonthPlaceholder: ['Бастау айы', 'Аяқталу айы'],\n      rangeWeekPlaceholder: ['Бастау апта', 'Аяқталу апта'],\n      locale: 'kk_KZ',\n      today: 'Бүгін',\n      now: 'Қазір',\n      backToToday: 'Ағымдағы күн',\n      ok: 'Таңдау',\n      clear: 'Таза',\n      month: 'Ай',\n      year: 'Жыл',\n      timeSelect: 'Уақытты таңдау',\n      dateSelect: 'Күнді таңдау',\n      monthSelect: 'Айды таңдаңыз',\n      yearSelect: 'Жылды таңдаңыз',\n      decadeSelect: 'Онжылды таңдаңыз',\n      yearFormat: 'YYYY',\n      dateFormat: 'D-M-YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D-M-YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Алдыңғы ай (PageUp)',\n      nextMonth: 'Келесі ай (PageDown)',\n      previousYear: 'Алдыңғы жыл (Control + left)',\n      nextYear: 'Келесі жыл (Control + right)',\n      previousDecade: 'Алдыңғы онжылдық',\n      nextDecade: 'Келесі онжылдық',\n      previousCentury: 'Алдыңғы ғасыр',\n      nextCentury: 'Келесі ғасыр'\n    },\n    timePickerLocale: {\n      placeholder: 'Уақытты таңдаңыз',\n      rangePlaceholder: ['Бастау уақыты', 'Аяқталу уақыты']\n    }\n  },\n  TimePicker: {\n    placeholder: 'Уақытты таңдаңыз',\n    rangePlaceholder: ['Бастау уақыты', 'Аяқталу уақыты']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Күнді таңдаңыз',\n      yearPlaceholder: 'Жылды таңдаңыз',\n      quarterPlaceholder: 'Тоқсанды таңдаңыз',\n      monthPlaceholder: 'Айды таңдаңыз',\n      weekPlaceholder: 'Аптаны таңдаңыз',\n      rangePlaceholder: ['Бастау күні', 'Аяқталу күні'],\n      rangeYearPlaceholder: ['Бастау жылы', 'Аяқталу жылы'],\n      rangeMonthPlaceholder: ['Бастау айы', 'Аяқталу айы'],\n      rangeWeekPlaceholder: ['Бастау апта', 'Аяқталу апта'],\n      locale: 'kk_KZ',\n      today: 'Бүгін',\n      now: 'Қазір',\n      backToToday: 'Ағымдағы күн',\n      ok: 'Таңдау',\n      clear: 'Таза',\n      month: 'Ай',\n      year: 'Жыл',\n      timeSelect: 'Уақытты таңдау',\n      dateSelect: 'Күнді таңдау',\n      monthSelect: 'Айды таңдаңыз',\n      yearSelect: 'Жылды таңдаңыз',\n      decadeSelect: 'Онжылды таңдаңыз',\n      yearFormat: 'YYYY',\n      dateFormat: 'D-M-YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D-M-YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Алдыңғы ай (PageUp)',\n      nextMonth: 'Келесі ай (PageDown)',\n      previousYear: 'Алдыңғы жыл (Control + left)',\n      nextYear: 'Келесі жыл (Control + right)',\n      previousDecade: 'Алдыңғы онжылдық',\n      nextDecade: 'Келесі онжылдық',\n      previousCentury: 'Алдыңғы ғасыр',\n      nextCentury: 'Келесі ғасыр'\n    },\n    timePickerLocale: {\n      placeholder: 'Уақытты таңдаңыз',\n      rangePlaceholder: ['Бастау уақыты', 'Аяқталу уақыты']\n    }\n  },\n  global: {\n    placeholder: 'Таңдаңыз'\n  },\n  Table: {\n    filterTitle: 'Фильтр',\n    filterConfirm: 'OK',\n    filterReset: 'Тазарту',\n    filterEmptyText: 'Фильтр жоқ',\n    emptyText: 'Деректер жоқ',\n    selectAll: 'Барлығын таңдау',\n    selectInvert: 'Таңдауды төңкеру',\n    selectionAll: 'Барлық деректерді таңдаңыз',\n    sortTitle: 'Сұрыптау',\n    expand: 'Жолды жазу',\n    collapse: 'Жолды бүктеу',\n    triggerDesc: 'Төмендеуді сұрыптау үшін басыңыз',\n    triggerAsc: 'Өсу ретімен сұрыптау үшін басыңыз',\n    cancelSort: 'Сұрыптаудан бас тарту үшін басыңыз'\n  },\n  Modal: {\n    okText: 'Жарайды',\n    cancelText: 'Болдырмау',\n    justOkText: 'Жарайды'\n  },\n  Popconfirm: {\n    okText: 'Жарайды',\n    cancelText: 'Болдырмау'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'Іздеу',\n    itemUnit: 'элемент.',\n    itemsUnit: 'элемент.',\n    remove: 'Жою',\n    selectAll: 'Барлық деректерді таңдау',\n    selectCurrent: 'Ағымдағы бетті таңдау',\n    selectInvert: 'Кері тәртіпте көрсету',\n    removeAll: 'Барлық деректерді жою',\n    removeCurrent: 'Ағымдағы парақты өшіру'\n  },\n  Upload: {\n    uploading: 'Жүктеу...',\n    removeFile: 'Файлды жою',\n    uploadError: 'Жүктеу кезінде қате пайда болды',\n    previewFile: 'Файлды алдын ала қарау',\n    downloadFile: 'Файлды жүктеу'\n  },\n  Empty: {\n    description: 'Деректер жоқ'\n  },\n  Form: {\n    optional: '(міндетті емес)'\n  },\n  Icon: {\n    icon: 'белгішесі'\n  },\n  Text: {\n    edit: 'Өңдеу',\n    copy: 'Көшіру',\n    copied: 'Көшірілді',\n    expand: 'Жазу'\n  },\n  PageHeader: {\n    back: 'Артқа'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/km_KH.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'km',\n  Pagination: {\n    items_per_page: '/ ទំព័រ',\n    jump_to: 'លោត​ទៅ',\n    jump_to_confirm: 'បញ្ជាក់',\n    page: 'ទំព័រ',\n    prev_page: 'ទំព័រ​មុន',\n    next_page: 'ទំព័រ​​បន្ទាប់',\n    prev_5: '៥ ទំព័រថយក្រោយ',\n    next_5: '៥ ទំព័រទៅមុខ',\n    prev_3: '៣ ទំព័រថយក្រោយ',\n    next_3: '៣ ទំព័រទៅមុខ',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'រើសថ្ងៃ',\n      yearPlaceholder: 'រើសឆ្នាំ',\n      quarterPlaceholder: 'រើសត្រីមាស',\n      monthPlaceholder: 'រើសខែ',\n      weekPlaceholder: 'រើសសប្តាហ៍',\n      rangePlaceholder: ['ថ្ងៃចាប់ផ្ដើម', 'ថ្ងៃបញ្ចប់'],\n      rangeYearPlaceholder: ['ឆ្នាំចាប់ផ្ដើម', 'ឆ្នាំបញ្ចប់'],\n      rangeMonthPlaceholder: ['ខែចាប់ផ្ដើម', 'ខែបញ្ចប់'],\n      rangeWeekPlaceholder: ['សប្ដាហ៍ចាប់ផ្ដើម', 'សប្ដាហ៍បញ្ចប់'],\n      locale: 'km',\n      today: 'ថ្ងៃនេះ',\n      now: 'ឥឡូវ​នេះ',\n      backToToday: 'ត្រលប់ទៅថ្ងៃនេះ',\n      ok: 'កំណត់',\n      timeSelect: 'រយៈពេលជ្រើសរើស',\n      dateSelect: 'ជ្រើសរើសកាលបរិច្ឆេទ',\n      weekSelect: 'ជ្រើសរើសសប្តាហ៍',\n      clear: 'ច្បាស់',\n      month: 'ខែ',\n      year: 'ឆ្នាំ',\n      previousMonth: 'ខែមុន (ឡើងទំព័រ)',\n      nextMonth: 'ខែបន្ទាប់ (ប៊ូតុងចុះទំព័រ)',\n      monthSelect: 'ជ្រើសរើសខែ',\n      yearSelect: 'ជ្រើសរើសឆ្នាំ',\n      decadeSelect: 'ជ្រើសរើសអាយុ',\n      yearFormat: 'YYYY',\n      dayFormat: 'D',\n      dateFormat: 'YYYY-M-D',\n      dateTimeFormat: 'YYYY-M-D HH:mm:ss',\n      previousYear: 'ឆ្នាំមុន (Controlគ្រាប់ចុចបូកព្រួញខាងឆ្វេង)',\n      nextYear: 'ឆ្នាំក្រោយ (Control គ្រាប់ចុចបូកព្រួញស្ដាំ)',\n      previousDecade: 'ជំនាន់ចុងក្រោយ',\n      nextDecade: 'ជំនាន់​ក្រោយ',\n      previousCentury: 'សតវត្សចុងក្រោយ',\n      nextCentury: 'សតវត្សរ៍បន្ទាប់',\n      monthBeforeYear: true\n    },\n    timePickerLocale: {\n      placeholder: 'រើសម៉ោង',\n      rangePlaceholder: ['ម៉ោងចប់ផ្ដើម', 'ម៉ោងបញ្ចប់']\n    }\n  },\n  TimePicker: {\n    placeholder: 'រើសម៉ោង',\n    rangePlaceholder: ['ម៉ោងចប់ផ្ដើម', 'ម៉ោងបញ្ចប់']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'រើសថ្ងៃ',\n      yearPlaceholder: 'រើសឆ្នាំ',\n      quarterPlaceholder: 'រើសត្រីមាស',\n      monthPlaceholder: 'រើសខែ',\n      weekPlaceholder: 'រើសសប្តាហ៍',\n      rangePlaceholder: ['ថ្ងៃចាប់ផ្ដើម', 'ថ្ងៃបញ្ចប់'],\n      rangeYearPlaceholder: ['ឆ្នាំចាប់ផ្ដើម', 'ឆ្នាំបញ្ចប់'],\n      rangeMonthPlaceholder: ['ខែចាប់ផ្ដើម', 'ខែបញ្ចប់'],\n      rangeWeekPlaceholder: ['សប្ដាហ៍ចាប់ផ្ដើម', 'សប្ដាហ៍បញ្ចប់'],\n      locale: 'km',\n      today: 'ថ្ងៃនេះ',\n      now: 'ឥឡូវ​នេះ',\n      backToToday: 'ត្រលប់ទៅថ្ងៃនេះ',\n      ok: 'កំណត់',\n      timeSelect: 'រយៈពេលជ្រើសរើស',\n      dateSelect: 'ជ្រើសរើសកាលបរិច្ឆេទ',\n      weekSelect: 'ជ្រើសរើសសប្តាហ៍',\n      clear: 'ច្បាស់',\n      month: 'ខែ',\n      year: 'ឆ្នាំ',\n      previousMonth: 'ខែមុន (ឡើងទំព័រ)',\n      nextMonth: 'ខែបន្ទាប់ (ប៊ូតុងចុះទំព័រ)',\n      monthSelect: 'ជ្រើសរើសខែ',\n      yearSelect: 'ជ្រើសរើសឆ្នាំ',\n      decadeSelect: 'ជ្រើសរើសអាយុ',\n      yearFormat: 'YYYY',\n      dayFormat: 'D',\n      dateFormat: 'YYYY-M-D',\n      dateTimeFormat: 'YYYY-M-D HH:mm:ss',\n      previousYear: 'ឆ្នាំមុន (Controlគ្រាប់ចុចបូកព្រួញខាងឆ្វេង)',\n      nextYear: 'ឆ្នាំក្រោយ (Control គ្រាប់ចុចបូកព្រួញស្ដាំ)',\n      previousDecade: 'ជំនាន់ចុងក្រោយ',\n      nextDecade: 'ជំនាន់​ក្រោយ',\n      previousCentury: 'សតវត្សចុងក្រោយ',\n      nextCentury: 'សតវត្សរ៍បន្ទាប់',\n      monthBeforeYear: true\n    },\n    timePickerLocale: {\n      placeholder: 'រើសម៉ោង',\n      rangePlaceholder: ['ម៉ោងចប់ផ្ដើម', 'ម៉ោងបញ្ចប់']\n    }\n  },\n  global: {\n    placeholder: 'សូមជ្រើសរើស'\n  },\n  Table: {\n    filterTitle: 'បញ្ចីតម្រៀប',\n    filterConfirm: 'យល់ព្រម',\n    filterReset: 'ត្រឡប់ដើម',\n    filterEmptyText: 'គ្មានបញ្ចីតម្រៀប',\n    emptyText: 'គ្មានទិន្នន័យ',\n    selectAll: 'រើសក្នុងទំព័រនេះ',\n    selectInvert: 'បញ្ច្រាសក្នុងទំព័រនេះ',\n    selectNone: 'លុបចេញទាំងអស់',\n    selectionAll: 'រើសយកទាំងអស់',\n    sortTitle: 'តម្រៀប',\n    expand: 'ពន្លាត',\n    collapse: 'បិតបាំង',\n    triggerDesc: 'ចុចដើម្បីរៀបតាមលំដាប់ធំ',\n    triggerAsc: 'ចុចដើម្បីរៀបតាមលំដាប់តូច​',\n    cancelSort: 'ចុចដើម្បីបោះបង់'\n  },\n  Modal: {\n    okText: 'យល់ព្រម',\n    cancelText: 'បោះបង់',\n    justOkText: 'យល់ព្រម'\n  },\n  Popconfirm: {\n    okText: 'យល់ព្រម',\n    cancelText: 'បោះបង់'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'ស្វែងរកនៅទីនេះ',\n    itemUnit: 'item',\n    itemsUnit: 'items',\n    remove: 'លុប',\n    selectCurrent: 'រើសទំព័របច្ចុប្បន្ន',\n    removeCurrent: 'លុបទំព័របច្ចុប្បន្ន',\n    selectAll: 'រើសទិន្នន័យទាំងអស់',\n    removeAll: 'លុបទិន្នន័យទាំងអស់',\n    selectInvert: 'បញ្ច្រាសទំព័របច្ចុប្បន្ន'\n  },\n  Upload: {\n    uploading: 'កំពុងបញ្ចូលឡើង...',\n    removeFile: 'លុបឯកសារ',\n    uploadError: 'បញ្ចូលមិនជោកជ័យ',\n    previewFile: 'មើលឯកសារ',\n    downloadFile: 'ទាញយកឯកសារ'\n  },\n  Empty: {\n    description: 'គ្មានទិន្នន័យ'\n  },\n  Form: {\n    optional: '(ជំរុញ)'\n  },\n  Icon: {\n    icon: 'icon'\n  },\n  Text: {\n    edit: 'កែ',\n    copy: 'Copy',\n    copied: 'Copied',\n    expand: 'ពង្រីក'\n  },\n  PageHeader: {\n    back: 'Back'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/kmr_IQ.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'ku',\n  Pagination: {\n    items_per_page: '/ rûpel',\n    jump_to: 'Biçe',\n    jump_to_confirm: 'piştrast bike',\n    page: '',\n    prev_page: 'Rûpelê Pêş',\n    next_page: 'Rûpelê Paş',\n    prev_5: '5 Rûpelên Pêş',\n    next_5: '5 Rûpelên Paş',\n    prev_3: '3 Rûpelên Pêş',\n    next_3: '3 Rûpelên Paş',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Dîrok hilbijêre',\n      rangePlaceholder: ['Dîroka destpêkê', 'Dîroka dawîn'],\n      locale: 'ku',\n      today: 'Îro',\n      now: 'Niha',\n      backToToday: 'Vegere îro',\n      ok: 'Temam',\n      clear: 'Paqij bike',\n      month: 'Meh',\n      year: 'Sal',\n      timeSelect: 'Demê hilbijêre',\n      dateSelect: 'Dîrok hilbijêre',\n      monthSelect: 'Meh hilbijêre',\n      yearSelect: 'Sal hilbijêre',\n      decadeSelect: 'Dehsal hilbijêre',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Meha peş (PageUp))',\n      nextMonth: 'Meha paş (PageDown)',\n      previousYear: 'Sala peş (Control + şep)',\n      nextYear: 'Sala paş (Control + rast)',\n      previousDecade: 'Dehsalen peş',\n      nextDecade: 'Dehsalen paş',\n      previousCentury: 'Sedsalen peş',\n      nextCentury: 'Sedsalen paş'\n    },\n    timePickerLocale: {\n      placeholder: 'Demê hilbijêre'\n    }\n  },\n  TimePicker: {\n    placeholder: 'Demê hilbijêre'\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Dîrok hilbijêre',\n      rangePlaceholder: ['Dîroka destpêkê', 'Dîroka dawîn'],\n      locale: 'ku',\n      today: 'Îro',\n      now: 'Niha',\n      backToToday: 'Vegere îro',\n      ok: 'Temam',\n      clear: 'Paqij bike',\n      month: 'Meh',\n      year: 'Sal',\n      timeSelect: 'Demê hilbijêre',\n      dateSelect: 'Dîrok hilbijêre',\n      monthSelect: 'Meh hilbijêre',\n      yearSelect: 'Sal hilbijêre',\n      decadeSelect: 'Dehsal hilbijêre',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Meha peş (PageUp))',\n      nextMonth: 'Meha paş (PageDown)',\n      previousYear: 'Sala peş (Control + şep)',\n      nextYear: 'Sala paş (Control + rast)',\n      previousDecade: 'Dehsalen peş',\n      nextDecade: 'Dehsalen paş',\n      previousCentury: 'Sedsalen peş',\n      nextCentury: 'Sedsalen paş'\n    },\n    timePickerLocale: {\n      placeholder: 'Demê hilbijêre'\n    }\n  },\n  Table: {\n    filterTitle: 'Menuê peldanka',\n    filterConfirm: 'Temam',\n    filterReset: 'Jê bibe',\n    selectAll: 'Hemî hilbijêre',\n    selectInvert: 'Hilbijartinan veguhere'\n  },\n  Modal: {\n    okText: 'Temam',\n    cancelText: 'Betal ke',\n    justOkText: 'Temam'\n  },\n  Popconfirm: {\n    okText: 'Temam',\n    cancelText: 'Betal ke'\n  },\n  Transfer: {\n    searchPlaceholder: 'Lêgerîn',\n    itemUnit: 'tişt',\n    itemsUnit: 'tişt'\n  },\n  Upload: {\n    uploading: 'Bardike...',\n    removeFile: 'Pelê rabike',\n    uploadError: 'Xeta barkirine',\n    previewFile: 'Pelê pêşbibîne',\n    downloadFile: 'Pelê dakêşin'\n  },\n  Empty: {\n    description: 'Agahî tune'\n  },\n  Form: {\n    optional: '(êzîfî)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/kn_IN.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'kn',\n  Pagination: {\n    items_per_page: '/ ಪುಟ',\n    jump_to: 'ಜಿಗಿತವನ್ನು',\n    jump_to_confirm: 'ಖಚಿತಪಡಿಸಲು ಜಿಗಿತವನ್ನು',\n    page: '',\n    prev_page: 'ಹಿಂದಿನ ಪುಟ',\n    next_page: 'ಮುಂದಿನ ಪುಟ',\n    prev_5: 'ಹಿಂದಿನ 5 ಪುಟಗಳು',\n    next_5: 'ಮುಂದಿನ 5 ಪುಟಗಳು',\n    prev_3: 'ಹಿಂದಿನ 3 ಪುಟಗಳು',\n    next_3: 'ಮುಂದಿನ 3 ಪುಟಗಳು',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'ದಿನಾಂಕ ಆಯ್ಕೆಮಾಡಿ',\n      rangePlaceholder: ['ಪ್ರಾರಂಭ ದಿನಾಂಕ', 'ಅಂತಿಮ ದಿನಾಂಕ'],\n      locale: 'kn_IN',\n      today: 'ಇಂದು',\n      now: 'ಈಗ',\n      backToToday: 'ಇಂದು ಹಿಂದಿರುಗಿ',\n      ok: 'ಸರಿ',\n      clear: 'ಸ್ಪಷ್ಟ',\n      month: 'ತಿಂಗಳು',\n      year: 'ವರ್ಷ',\n      timeSelect: 'ಸಮಯ ಆಯ್ಕೆಮಾಡಿ',\n      dateSelect: 'ದಿನಾಂಕವನ್ನು ಆಯ್ಕೆ ಮಾಡಿ',\n      weekSelect: 'ಒಂದು ವಾರದ ಆರಿಸಿ',\n      monthSelect: 'ಒಂದು ತಿಂಗಳು ಆಯ್ಕೆಮಾಡಿ',\n      yearSelect: 'ಒಂದು ವರ್ಷ ಆರಿಸಿ',\n      decadeSelect: 'ಒಂದು ದಶಕದ ಆಯ್ಕೆಮಾಡಿ',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'ಹಿಂದಿನ ತಿಂಗಳು (ಪೇಜ್ಅಪ್)',\n      nextMonth: 'ಮುಂದಿನ ತಿಂಗಳು (ಪೇಜ್ಡೌನ್)',\n      previousYear: 'ಕಳೆದ ವರ್ಷ (Ctrl + ಎಡ)',\n      nextYear: 'ಮುಂದಿನ ವರ್ಷ (Ctrl + ಬಲ)',\n      previousDecade: 'ಕಳೆದ ದಶಕ',\n      nextDecade: 'ಮುಂದಿನ ದಶಕ',\n      previousCentury: 'ಕಳೆದ ಶತಮಾನ',\n      nextCentury: 'ಮುಂದಿನ ಶತಮಾನ'\n    },\n    timePickerLocale: {\n      placeholder: 'ಸಮಯ ಆಯ್ಕೆಮಾಡಿ'\n    }\n  },\n  TimePicker: {\n    placeholder: 'ಸಮಯ ಆಯ್ಕೆಮಾಡಿ'\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'ದಿನಾಂಕ ಆಯ್ಕೆಮಾಡಿ',\n      rangePlaceholder: ['ಪ್ರಾರಂಭ ದಿನಾಂಕ', 'ಅಂತಿಮ ದಿನಾಂಕ'],\n      locale: 'kn_IN',\n      today: 'ಇಂದು',\n      now: 'ಈಗ',\n      backToToday: 'ಇಂದು ಹಿಂದಿರುಗಿ',\n      ok: 'ಸರಿ',\n      clear: 'ಸ್ಪಷ್ಟ',\n      month: 'ತಿಂಗಳು',\n      year: 'ವರ್ಷ',\n      timeSelect: 'ಸಮಯ ಆಯ್ಕೆಮಾಡಿ',\n      dateSelect: 'ದಿನಾಂಕವನ್ನು ಆಯ್ಕೆ ಮಾಡಿ',\n      weekSelect: 'ಒಂದು ವಾರದ ಆರಿಸಿ',\n      monthSelect: 'ಒಂದು ತಿಂಗಳು ಆಯ್ಕೆಮಾಡಿ',\n      yearSelect: 'ಒಂದು ವರ್ಷ ಆರಿಸಿ',\n      decadeSelect: 'ಒಂದು ದಶಕದ ಆಯ್ಕೆಮಾಡಿ',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'ಹಿಂದಿನ ತಿಂಗಳು (ಪೇಜ್ಅಪ್)',\n      nextMonth: 'ಮುಂದಿನ ತಿಂಗಳು (ಪೇಜ್ಡೌನ್)',\n      previousYear: 'ಕಳೆದ ವರ್ಷ (Ctrl + ಎಡ)',\n      nextYear: 'ಮುಂದಿನ ವರ್ಷ (Ctrl + ಬಲ)',\n      previousDecade: 'ಕಳೆದ ದಶಕ',\n      nextDecade: 'ಮುಂದಿನ ದಶಕ',\n      previousCentury: 'ಕಳೆದ ಶತಮಾನ',\n      nextCentury: 'ಮುಂದಿನ ಶತಮಾನ'\n    },\n    timePickerLocale: {\n      placeholder: 'ಸಮಯ ಆಯ್ಕೆಮಾಡಿ'\n    }\n  },\n  global: {\n    placeholder: 'ದಯವಿಟ್ಟು ಆರಿಸಿ'\n  },\n  Table: {\n    filterTitle: 'ಪಟ್ಟಿ ಸೋಸಿ',\n    filterConfirm: 'ಸರಿ',\n    filterReset: 'ಮರುಹೊಂದಿಸಿ',\n    emptyText: 'ಮಾಹಿತಿ ಇಲ್ಲ',\n    selectAll: 'ಪ್ರಸ್ತುತ ಪುಟವನ್ನು ಆಯ್ಕೆಮಾಡಿ',\n    selectInvert: 'ಪ್ರಸ್ತುತ ಪುಟವನ್ನು ತಿರುಗಿಸಿ',\n    sortTitle: 'ವಿಂಗಡಿಸಿ'\n  },\n  Modal: {\n    okText: 'ಸರಿ',\n    cancelText: 'ರದ್ದು',\n    justOkText: 'ಸರಿ'\n  },\n  Popconfirm: {\n    okText: 'ಸರಿ',\n    cancelText: 'ರದ್ದು'\n  },\n  Transfer: {\n    titles: ['', ''],\n    notFoundContent: 'ದೊರೆತಿಲ್ಲ',\n    searchPlaceholder: 'ಇಲ್ಲಿ ಹುಡುಕಿ',\n    itemUnit: 'ವಿಷಯ',\n    itemsUnit: 'ವಿಷಯಗಳು'\n  },\n  Select: {\n    notFoundContent: 'ದೊರೆತಿಲ್ಲ'\n  },\n  Upload: {\n    uploading: 'ಏರಿಸಿ...',\n    removeFile: 'ಫೈಲ್ ತೆಗೆದುಹಾಕಿ',\n    uploadError: 'ಏರಿಸುವ ದೋಷ',\n    previewFile: 'ಫೈಲ್ ಮುನ್ನೋಟ',\n    downloadFile: 'ಫೈಲ್ ಡೌನ್‌ಲೋಡ್ ಮಾಡಿ'\n  },\n  Form: {\n    optional: '(ಅಗತ್ಯ)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/ko_KR.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'ko',\n  Pagination: {\n    items_per_page: '/ 쪽',\n    jump_to: '이동하기',\n    jump_to_confirm: '확인하다',\n    page: '페이지',\n    prev_page: '이전 페이지',\n    next_page: '다음 페이지',\n    prev_5: '이전 5 페이지',\n    next_5: '다음 5 페이지',\n    prev_3: '이전 3 페이지',\n    next_3: '다음 3 페이지',\n    page_size: '페이지 크기'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: '날짜 선택',\n      rangePlaceholder: ['시작일', '종료일'],\n      locale: 'ko_KR',\n      today: '오늘',\n      now: '현재 시각',\n      backToToday: '오늘로 돌아가기',\n      ok: '확인',\n      clear: '지우기',\n      month: '월',\n      year: '년',\n      timeSelect: '시간 선택',\n      dateSelect: '날짜 선택',\n      monthSelect: '달 선택',\n      yearSelect: '연 선택',\n      decadeSelect: '연대 선택',\n      yearFormat: 'YYYY년',\n      dateFormat: 'YYYY-MM-DD',\n      dayFormat: 'Do',\n      dateTimeFormat: 'YYYY-MM-DD HH:mm:ss',\n      monthBeforeYear: false,\n      previousMonth: '이전 달 (PageUp)',\n      nextMonth: '다음 달 (PageDown)',\n      previousYear: '이전 해 (Control + left)',\n      nextYear: '다음 해 (Control + right)',\n      previousDecade: '이전 연대',\n      nextDecade: '다음 연대',\n      previousCentury: '이전 세기',\n      nextCentury: '다음 세기'\n    },\n    timePickerLocale: {\n      placeholder: '시간 선택',\n      rangePlaceholder: ['시작 시간', '종료 시간']\n    }\n  },\n  TimePicker: {\n    placeholder: '시간 선택',\n    rangePlaceholder: ['시작 시간', '종료 시간']\n  },\n  Calendar: {\n    lang: {\n      placeholder: '날짜 선택',\n      rangePlaceholder: ['시작일', '종료일'],\n      locale: 'ko_KR',\n      today: '오늘',\n      now: '현재 시각',\n      backToToday: '오늘로 돌아가기',\n      ok: '확인',\n      clear: '지우기',\n      month: '월',\n      year: '년',\n      timeSelect: '시간 선택',\n      dateSelect: '날짜 선택',\n      monthSelect: '달 선택',\n      yearSelect: '연 선택',\n      decadeSelect: '연대 선택',\n      yearFormat: 'YYYY년',\n      dateFormat: 'YYYY-MM-DD',\n      dayFormat: 'Do',\n      dateTimeFormat: 'YYYY-MM-DD HH:mm:ss',\n      monthBeforeYear: false,\n      previousMonth: '이전 달 (PageUp)',\n      nextMonth: '다음 달 (PageDown)',\n      previousYear: '이전 해 (Control + left)',\n      nextYear: '다음 해 (Control + right)',\n      previousDecade: '이전 연대',\n      nextDecade: '다음 연대',\n      previousCentury: '이전 세기',\n      nextCentury: '다음 세기'\n    },\n    timePickerLocale: {\n      placeholder: '시간 선택',\n      rangePlaceholder: ['시작 시간', '종료 시간']\n    }\n  },\n  Table: {\n    filterTitle: '필터 메뉴',\n    filterConfirm: '확인',\n    filterReset: '초기화',\n    selectAll: '모두 선택',\n    selectInvert: '선택 반전',\n    filterEmptyText: '필터 없음',\n    emptyText: '데이터 없음'\n  },\n  Modal: {\n    okText: '확인',\n    cancelText: '취소',\n    justOkText: '확인'\n  },\n  Popconfirm: {\n    okText: '확인',\n    cancelText: '취소'\n  },\n  Transfer: {\n    searchPlaceholder: '여기에 검색하세요',\n    itemUnit: '개',\n    itemsUnit: '개'\n  },\n  Upload: {\n    uploading: '업로드 중...',\n    removeFile: '파일 삭제',\n    uploadError: '업로드 실패',\n    previewFile: '파일 미리보기',\n    downloadFile: '파일 다운로드'\n  },\n  Empty: {\n    description: '데이터 없음'\n  },\n  Form: {\n    optional: '(선택)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/ku_IQ.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'ku-iq',\n  Pagination: {\n    items_per_page: '/ rûpel',\n    jump_to: 'Biçe',\n    jump_to_confirm: 'piştrast bike',\n    page: '',\n    prev_page: 'Rûpelê Pêş',\n    next_page: 'Rûpelê Paş',\n    prev_5: '5 Rûpelên Pêş',\n    next_5: '5 Rûpelên Paş',\n    prev_3: '3 Rûpelên Pêş',\n    next_3: '3 Rûpelên Paş',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Dîrok hilbijêre',\n      rangePlaceholder: ['Dîroka destpêkê', 'Dîroka dawîn'],\n      locale: 'ku',\n      today: 'Îro',\n      now: 'Niha',\n      backToToday: 'Vegere îro',\n      ok: 'Temam',\n      clear: 'Paqij bike',\n      month: 'Meh',\n      year: 'Sal',\n      timeSelect: 'Demê hilbijêre',\n      dateSelect: 'Dîrok hilbijêre',\n      monthSelect: 'Meh hilbijêre',\n      yearSelect: 'Sal hilbijêre',\n      decadeSelect: 'Dehsal hilbijêre',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Meha peş (PageUp))',\n      nextMonth: 'Meha paş (PageDown)',\n      previousYear: 'Sala peş (Control + şep)',\n      nextYear: 'Sala paş (Control + rast)',\n      previousDecade: 'Dehsalen peş',\n      nextDecade: 'Dehsalen paş',\n      previousCentury: 'Sedsalen peş',\n      nextCentury: 'Sedsalen paş'\n    },\n    timePickerLocale: {\n      placeholder: 'Demê hilbijêre'\n    }\n  },\n  TimePicker: {\n    placeholder: 'Demê hilbijêre'\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Dîrok hilbijêre',\n      rangePlaceholder: ['Dîroka destpêkê', 'Dîroka dawîn'],\n      locale: 'ku',\n      today: 'Îro',\n      now: 'Niha',\n      backToToday: 'Vegere îro',\n      ok: 'Temam',\n      clear: 'Paqij bike',\n      month: 'Meh',\n      year: 'Sal',\n      timeSelect: 'Demê hilbijêre',\n      dateSelect: 'Dîrok hilbijêre',\n      monthSelect: 'Meh hilbijêre',\n      yearSelect: 'Sal hilbijêre',\n      decadeSelect: 'Dehsal hilbijêre',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Meha peş (PageUp))',\n      nextMonth: 'Meha paş (PageDown)',\n      previousYear: 'Sala peş (Control + şep)',\n      nextYear: 'Sala paş (Control + rast)',\n      previousDecade: 'Dehsalen peş',\n      nextDecade: 'Dehsalen paş',\n      previousCentury: 'Sedsalen peş',\n      nextCentury: 'Sedsalen paş'\n    },\n    timePickerLocale: {\n      placeholder: 'Demê hilbijêre'\n    }\n  },\n  Table: {\n    filterTitle: 'Menuê peldanka',\n    filterConfirm: 'Temam',\n    filterReset: 'Jê bibe',\n    selectAll: 'Hemî hilbijêre',\n    selectInvert: 'Hilbijartinan veguhere'\n  },\n  Modal: {\n    okText: 'Temam',\n    cancelText: 'Betal ke',\n    justOkText: 'Temam'\n  },\n  Popconfirm: {\n    okText: 'Temam',\n    cancelText: 'Betal ke'\n  },\n  Transfer: {\n    searchPlaceholder: 'Lêgerîn',\n    itemUnit: 'tişt',\n    itemsUnit: 'tişt'\n  },\n  Upload: {\n    uploading: 'Bardike...',\n    removeFile: 'Pelê rabike',\n    uploadError: 'Xeta barkirine',\n    previewFile: 'Pelê pêşbibîne',\n    downloadFile: 'Pelê dakêşin'\n  },\n  Empty: {\n    description: 'Agahî tune'\n  },\n  Form: {\n    optional: '(êzîfî)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/lt_LT.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'lt',\n  Pagination: {\n    items_per_page: '/ psl.',\n    jump_to: 'Pereiti',\n    jump_to_confirm: 'patvirtinti',\n    page: '',\n    prev_page: 'Atgal',\n    next_page: 'Pirmyn',\n    prev_5: 'Grįžti 5 pls.',\n    next_5: 'Peršokti 5 pls.',\n    prev_3: 'Grįžti 3 pls.',\n    next_3: 'Peršokti 3 pls.',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Pasirinkite datą',\n      yearPlaceholder: 'Pasirinkite metus',\n      quarterPlaceholder: 'Pasirinkite ketvirtį',\n      monthPlaceholder: 'Pasirinkite mėnesį',\n      weekPlaceholder: 'Pasirinkite savaitę',\n      rangePlaceholder: ['Pradžios data', 'Pabaigos data'],\n      rangeYearPlaceholder: ['Pradžios metai', 'Pabaigos metai'],\n      rangeMonthPlaceholder: ['Pradžios mėnesis', 'Pabaigos mėnesis'],\n      rangeWeekPlaceholder: ['Pradžios savaitė', 'Pabaigos savaitė'],\n      locale: 'lt_LT',\n      today: 'Šiandien',\n      now: 'Dabar',\n      backToToday: 'Rodyti šiandien',\n      ok: 'Gerai',\n      clear: 'Išvalyti',\n      month: 'Mėnesis',\n      year: 'Metai',\n      timeSelect: 'Pasirinkti laiką',\n      dateSelect: 'Pasirinkti datą',\n      monthSelect: 'Pasirinkti mėnesį',\n      yearSelect: 'Pasirinkti metus',\n      decadeSelect: 'Pasirinkti dešimtmetį',\n      yearFormat: 'YYYY',\n      dateFormat: 'YYYY-MM-DD',\n      dayFormat: 'DD',\n      dateTimeFormat: 'YYYY-MM-DD HH:MM:SS',\n      monthBeforeYear: true,\n      previousMonth: 'Buvęs mėnesis (PageUp)',\n      nextMonth: 'Sekantis mėnesis (PageDown)',\n      previousYear: 'Buvę metai (Control + left)',\n      nextYear: 'Sekantis metai (Control + right)',\n      previousDecade: 'Buvęs dešimtmetis',\n      nextDecade: 'Sekantis dešimtmetis',\n      previousCentury: 'Buvęs amžius',\n      nextCentury: 'Sekantis amžius'\n    },\n    timePickerLocale: {\n      placeholder: 'Pasirinkite laiką',\n      rangePlaceholder: ['Pradžios laikas', 'Pabaigos laikas']\n    }\n  },\n  TimePicker: {\n    placeholder: 'Pasirinkite laiką',\n    rangePlaceholder: ['Pradžios laikas', 'Pabaigos laikas']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Pasirinkite datą',\n      yearPlaceholder: 'Pasirinkite metus',\n      quarterPlaceholder: 'Pasirinkite ketvirtį',\n      monthPlaceholder: 'Pasirinkite mėnesį',\n      weekPlaceholder: 'Pasirinkite savaitę',\n      rangePlaceholder: ['Pradžios data', 'Pabaigos data'],\n      rangeYearPlaceholder: ['Pradžios metai', 'Pabaigos metai'],\n      rangeMonthPlaceholder: ['Pradžios mėnesis', 'Pabaigos mėnesis'],\n      rangeWeekPlaceholder: ['Pradžios savaitė', 'Pabaigos savaitė'],\n      locale: 'lt_LT',\n      today: 'Šiandien',\n      now: 'Dabar',\n      backToToday: 'Rodyti šiandien',\n      ok: 'Gerai',\n      clear: 'Išvalyti',\n      month: 'Mėnesis',\n      year: 'Metai',\n      timeSelect: 'Pasirinkti laiką',\n      dateSelect: 'Pasirinkti datą',\n      monthSelect: 'Pasirinkti mėnesį',\n      yearSelect: 'Pasirinkti metus',\n      decadeSelect: 'Pasirinkti dešimtmetį',\n      yearFormat: 'YYYY',\n      dateFormat: 'YYYY-MM-DD',\n      dayFormat: 'DD',\n      dateTimeFormat: 'YYYY-MM-DD HH:MM:SS',\n      monthBeforeYear: true,\n      previousMonth: 'Buvęs mėnesis (PageUp)',\n      nextMonth: 'Sekantis mėnesis (PageDown)',\n      previousYear: 'Buvę metai (Control + left)',\n      nextYear: 'Sekantis metai (Control + right)',\n      previousDecade: 'Buvęs dešimtmetis',\n      nextDecade: 'Sekantis dešimtmetis',\n      previousCentury: 'Buvęs amžius',\n      nextCentury: 'Sekantis amžius'\n    },\n    timePickerLocale: {\n      placeholder: 'Pasirinkite laiką',\n      rangePlaceholder: ['Pradžios laikas', 'Pabaigos laikas']\n    }\n  },\n  Table: {\n    filterTitle: 'Filtras',\n    filterConfirm: 'Gerai',\n    filterReset: 'Atstatyti',\n    filterEmptyText: 'Be filtrų',\n    emptyText: 'Nėra duomenų',\n    selectAll: 'Pasirinkti viską',\n    selectInvert: 'Apversti pasirinkimą',\n    selectionAll: 'Rinktis visus',\n    sortTitle: 'Rikiavimas',\n    expand: 'Išskleisti',\n    collapse: 'Suskleisti',\n    triggerDesc: 'Spustelėkite norėdami rūšiuoti mažėjančia tvarka',\n    triggerAsc: 'Spustelėkite norėdami rūšiuoti didėjančia tvarka',\n    cancelSort: 'Spustelėkite, kad atšauktumėte rūšiavimą'\n  },\n  Modal: {\n    okText: 'Taip',\n    cancelText: 'Atšaukti',\n    justOkText: 'Gerai'\n  },\n  Popconfirm: {\n    okText: 'Taip',\n    cancelText: 'Atšaukti'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'Paieška',\n    itemUnit: 'vnt.',\n    itemsUnit: 'vnt.',\n    remove: 'Pašalinti',\n    selectAll: 'Pasirinkti visus',\n    selectCurrent: 'Pasirinkite dabartinį puslapį',\n    selectInvert: 'Atkeist pasirinkimą',\n    removeAll: 'Ištrinti visus duomenis',\n    removeCurrent: 'Ištrinti dabartinį puslapį'\n  },\n  Upload: {\n    uploading: 'Gaunami duomenys...',\n    removeFile: 'Ištrinti failą',\n    uploadError: 'Įkeliant įvyko klaida',\n    previewFile: 'Failo peržiūra',\n    downloadFile: 'Įkelti failą'\n  },\n  Empty: {\n    description: 'Nėra duomenų'\n  },\n  Icon: {\n    icon: 'piktograma'\n  },\n  Text: {\n    edit: 'Redaguoti',\n    copy: 'Kopijuoti',\n    copied: 'Nukopijuota',\n    expand: 'Plačiau'\n  },\n  PageHeader: {\n    back: 'Atgal'\n  },\n  Form: {\n    optional: '(neprivaloma)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/lv_LV.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'lv',\n  Pagination: {\n    items_per_page: '/ lappuse',\n    jump_to: 'iet uz',\n    jump_to_confirm: 'apstiprināt',\n    page: '',\n    prev_page: 'Iepriekšējā lapa',\n    next_page: 'Nākamā lapa',\n    prev_5: 'Iepriekšējās 5 lapas',\n    next_5: 'Nākamās 5 lapas',\n    prev_3: 'Iepriekšējās 3 lapas',\n    next_3: 'Nākamās 3 lapas',\n    page_size: 'Lapas izmērs'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Izvēlieties datumu',\n      yearPlaceholder: 'Izvēlieties gadu',\n      quaterPlaceholder: 'Izvēlieties ceturksni',\n      monthPlaceholder: 'Izvēlieties mēnesi',\n      weekPlaceholder: 'Izvēlieties nedēļu',\n      rangePlaceholder: ['Sākuma datums', 'Beigu datums'],\n      rangeYearPlaceholder: ['Sākuma gads', 'Beigu gads'],\n      rangeMonthPlaceholder: ['Sākuma mēnesis', 'Beigu mēnesis'],\n      rangeWeekPlaceholder: ['Sākuma nedēļa', 'Beigu nedēļa'],\n      locale: 'lv_LV',\n      today: 'Šodien',\n      now: 'Tagad',\n      backToToday: 'Atpakaļ uz šodienu',\n      ok: 'Ok',\n      clear: 'Notīrīt',\n      month: 'Mēnesis',\n      year: 'Gads',\n      timeSelect: 'Izvēlieties laiku',\n      dateSelect: 'Izvēlieties datumu',\n      monthSelect: 'Izvēlieties mēnesi',\n      yearSelect: 'Izvēlieties gadu',\n      decadeSelect: 'Izvēlieties dekādi',\n      yearFormat: 'YYYY',\n      dateFormat: 'D.M.YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D.M.YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Iepriekšējais mēnesis (PageUp)',\n      nextMonth: 'Nākammēnes (PageDown)',\n      previousYear: 'Pagājušais gads (Control + left)',\n      nextYear: 'Nākamgad (Control + right)',\n      previousDecade: 'Iepriekšējā dekāde',\n      nextDecade: 'Nākamā dekāde',\n      previousCentury: 'Pagājušajā gadsimtā',\n      nextCentury: 'Nākamajā gadsimtā'\n    },\n    timePickerLocale: {\n      placeholder: 'Izvēlieties laiku',\n      rangePlaceholder: ['Sākuma laiks', 'Beigu laiks']\n    }\n  },\n  TimePicker: {\n    placeholder: 'Izvēlieties laiku',\n    rangePlaceholder: ['Sākuma laiks', 'Beigu laiks']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Izvēlieties datumu',\n      yearPlaceholder: 'Izvēlieties gadu',\n      quarterPlaceholder: 'Izvēlieties ceturksni',\n      monthPlaceholder: 'Izvēlieties mēnesi',\n      weekPlaceholder: 'Izvēlieties nedēļu',\n      rangePlaceholder: ['Sākuma datums', 'Beigu datums'],\n      rangeYearPlaceholder: ['Sākuma gads', 'Beigu gads'],\n      rangeMonthPlaceholder: ['Sākuma mēnesis', 'Beigu mēnesis'],\n      rangeWeekPlaceholder: ['Sākuma nedēļa', 'Beigu nedēļa'],\n      locale: 'lv_LV',\n      today: 'Šodien',\n      now: 'Tagad',\n      backToToday: 'Atpakaļ pie šodienas',\n      ok: 'Ok',\n      clear: 'Notīrīt',\n      month: 'Mēnesis',\n      year: 'Gads',\n      timeSelect: 'Izvēlieties laiku',\n      dateSelect: 'Izvēlieties datumu',\n      monthSelect: 'Izvēlieties mēnesi',\n      yearSelect: 'Izvēlieties gadu',\n      decadeSelect: 'Izvēlieties dekādi',\n      yearFormat: 'YYYY',\n      dateFormat: 'D.M.YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D.M.YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Iepriekšējais mēnesis (PageUp)',\n      nextMonth: 'Nākammēnes (PageDown)',\n      previousYear: 'Pagājušais gads (Control + left)',\n      nextYear: 'Nākamgad (Control + right)',\n      previousDecade: 'Iepriekšējā dekāde',\n      nextDecade: 'Nākamā dekāde',\n      previousCentury: 'Pagājušajā gadsimtā',\n      nextCentury: 'Nākamajā gadsimtā'\n    },\n    timePickerLocale: {\n      placeholder: 'Izvēlieties laiku',\n      rangePlaceholder: ['Sākuma laiks', 'Beigu laiks']\n    }\n  },\n  global: {\n    placeholder: 'Lūdzu izvēlieties'\n  },\n  Table: {\n    filterTitle: 'Filtrēšanas izvēlne',\n    filterConfirm: 'OK',\n    filterReset: 'Atiestatīt',\n    filterEmptyText: 'Nav filtru',\n    emptyText: 'Nav datu',\n    selectAll: 'Atlasīt pašreizējo lapu',\n    selectInvert: 'Pārvērst pašreizējo lapu',\n    selectionAll: 'Izvēlēties visu',\n    sortTitle: 'Kārtot',\n    expand: 'Izvērst',\n    collapse: 'Aizvērt',\n    triggerDesc: 'Nospiediet lai kārtotu dilstošā secībā',\n    triggerAsc: 'Nospiediet lai kārtotu augošā secībā',\n    cancelSort: 'Nospiediet lai atceltu kārtošanu',\n    filterCheckall: 'Izvēlēties visus ierakstus',\n    filterSearchPlaceholder: 'Meklēt filtros',\n    selectNone: 'Notīrīt visus datus'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Atcelt',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Atcelt'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'Meklēt šeit',\n    itemUnit: 'vienumu',\n    itemsUnit: 'vienumus',\n    remove: 'Noņemt',\n    selectCurrent: 'Izvēlēties pašreizējo lapu',\n    removeCurrent: 'Noņemt pašreizējo lapu',\n    selectAll: 'Izvēlēties visus datus',\n    removeAll: 'Noņemt visus datus',\n    selectInvert: 'Pārvērst pašreizējo lapu'\n  },\n  Upload: {\n    uploading: 'Augšupielāde...',\n    removeFile: 'Noņemt failu',\n    uploadError: 'Augšupielādes kļūda',\n    previewFile: 'Priekšskatiet failu',\n    downloadFile: 'Lejupielādēt failu'\n  },\n  Empty: {\n    description: 'Nav datu'\n  },\n  Icon: {\n    icon: 'ikona'\n  },\n  Text: {\n    edit: 'Labot',\n    copy: 'Kopēt',\n    copied: 'Nokopēts',\n    expand: 'Izvērst'\n  },\n  PageHeader: {\n    back: 'Atpakaļ'\n  },\n  Image: {\n    preview: 'Priekšskatījums'\n  },\n  CronExpression: {\n    cronError: 'Nekorekta cron izteiksme',\n    second: 'sekunde',\n    minute: 'minūte',\n    hour: 'stunda',\n    day: 'diena',\n    month: 'mēnesis',\n    week: 'nedēļa'\n  },\n  QRCode: {\n    expired: 'QR koda termiņš ir beidzies',\n    refresh: 'Atjaunot',\n    scanned: 'Skenēts'\n  },\n  Form: {\n    optional: '(nepieciešams)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/mk_MK.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'mk',\n  Pagination: {\n    items_per_page: '/ стр',\n    jump_to: 'Оди на',\n    jump_to_confirm: 'потврди',\n    page: '',\n    prev_page: 'Претходна страница',\n    next_page: 'Наредна страница',\n    prev_5: 'Претходни 5 страници',\n    next_5: 'Наредни 5 страници',\n    prev_3: 'Претходни 3 страници',\n    next_3: 'Наредни 3 страници',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Избери датум',\n      rangePlaceholder: ['Од датум', 'До датум'],\n      locale: 'mk_MK',\n      today: 'Денес',\n      now: 'Сега',\n      backToToday: 'Назад до денес',\n      ok: 'ОК',\n      clear: 'Избриши',\n      month: 'Месец',\n      year: 'Година',\n      timeSelect: 'Избери време',\n      dateSelect: 'Избери датум',\n      monthSelect: 'Избери месец',\n      yearSelect: 'Избери година',\n      decadeSelect: 'Избери деценија',\n      yearFormat: 'YYYY',\n      dateFormat: 'D.M.YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D.M.YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Претходен месец (PageUp)',\n      nextMonth: 'Нареден месец (PageDown)',\n      previousYear: 'Претходна година (Control + left)',\n      nextYear: 'Наредна година (Control + right)',\n      previousDecade: 'Претходна деценија',\n      nextDecade: 'Наредна деценија',\n      previousCentury: 'Претходен век',\n      nextCentury: 'Нареден век'\n    },\n    timePickerLocale: {\n      placeholder: 'Избери време'\n    }\n  },\n  TimePicker: {\n    placeholder: 'Избери време'\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Избери датум',\n      rangePlaceholder: ['Од датум', 'До датум'],\n      locale: 'mk_MK',\n      today: 'Денес',\n      now: 'Сега',\n      backToToday: 'Назад до денес',\n      ok: 'ОК',\n      clear: 'Избриши',\n      month: 'Месец',\n      year: 'Година',\n      timeSelect: 'Избери време',\n      dateSelect: 'Избери датум',\n      monthSelect: 'Избери месец',\n      yearSelect: 'Избери година',\n      decadeSelect: 'Избери деценија',\n      yearFormat: 'YYYY',\n      dateFormat: 'D.M.YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D.M.YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Претходен месец (PageUp)',\n      nextMonth: 'Нареден месец (PageDown)',\n      previousYear: 'Претходна година (Control + left)',\n      nextYear: 'Наредна година (Control + right)',\n      previousDecade: 'Претходна деценија',\n      nextDecade: 'Наредна деценија',\n      previousCentury: 'Претходен век',\n      nextCentury: 'Нареден век'\n    },\n    timePickerLocale: {\n      placeholder: 'Избери време'\n    }\n  },\n  global: {\n    placeholder: 'Ве молиме означете'\n  },\n  Table: {\n    filterTitle: 'Мени за филтрирање',\n    filterConfirm: 'ОК',\n    filterReset: 'Избриши',\n    selectAll: 'Одбери страница',\n    selectInvert: 'Инвертирај страница'\n  },\n  Modal: {\n    okText: 'ОК',\n    cancelText: 'Откажи',\n    justOkText: 'ОК'\n  },\n  Popconfirm: {\n    okText: 'ОК',\n    cancelText: 'Откажи'\n  },\n  Transfer: {\n    searchPlaceholder: 'Пребарај тука',\n    itemUnit: 'предмет',\n    itemsUnit: 'предмети'\n  },\n  Upload: {\n    uploading: 'Се прикачува...',\n    removeFile: 'Избриши фајл',\n    uploadError: 'Грешка при прикачување',\n    previewFile: 'Прикажи фајл',\n    downloadFile: 'Преземи фајл'\n  },\n  Empty: {\n    description: 'Нема податоци'\n  },\n  Icon: {\n    icon: 'Икона'\n  },\n  Text: {\n    edit: 'Уреди',\n    copy: 'Копирај',\n    copied: 'Копирано',\n    expand: 'Зголеми'\n  },\n  PageHeader: {\n    back: 'Назад'\n  },\n  Form: {\n    optional: '(незадолжително)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/ml_IN.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'ml',\n  Pagination: {\n    items_per_page: '/ പേജ്',\n    jump_to: 'അടുത്തത്',\n    jump_to_confirm: 'ഉറപ്പാക്കുക',\n    page: '',\n    prev_page: 'മുൻപുള്ള പേജ്',\n    next_page: 'അടുത്ത പേജ്',\n    prev_5: 'മുൻപുള്ള 5 പേജുകൾ',\n    next_5: 'അടുത്ത 5 പേജുകൾ',\n    prev_3: 'മുൻപുള്ള 3 പേജുകൾ',\n    next_3: 'അടുത്ത 3 പേജുകൾ',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'തിയതി തിരഞ്ഞെടുക്കുക',\n      yearPlaceholder: 'വർഷം തിരഞ്ഞെടുക്കുക',\n      quarterPlaceholder: 'ത്രൈമാസം തിരഞ്ഞെടുക്കുക',\n      monthPlaceholder: 'മാസം തിരഞ്ഞെടുക്കുക',\n      weekPlaceholder: 'വാരം തിരഞ്ഞെടുക്കുക',\n      rangePlaceholder: ['ആരംഭ ദിനം', 'അവസാന ദിനം'],\n      rangeYearPlaceholder: ['ആരംഭ വർഷം', 'അവസാന വർഷം'],\n      rangeMonthPlaceholder: ['ആരംഭ മാസം', 'അവസാന മാസം'],\n      rangeWeekPlaceholder: ['ആരംഭ വാരം', 'അവസാന വാരം'],\n      locale: 'ml_IN',\n      today: 'ഇന്ന്',\n      now: 'ഇപ്പോൾ',\n      backToToday: 'ഇന്നത്തെ ദിവസത്തിലേക്ക് തിരിച്ചു പോകുക',\n      ok: 'ശരിയാണ്',\n      clear: 'നീക്കം ചെയ്യുക',\n      month: 'മാസം',\n      year: 'വർഷം',\n      timeSelect: 'സമയം തിരഞ്ഞെടുക്കുക',\n      dateSelect: 'ദിവസം തിരഞ്ഞെടുക്കുക',\n      weekSelect: 'വാരം തിരഞ്ഞെടുക്കുക',\n      monthSelect: 'മാസം തിരഞ്ഞെടുക്കുക',\n      yearSelect: 'വർഷം തിരഞ്ഞെടുക്കുക',\n      decadeSelect: 'ദശാബ്ദം തിരഞ്ഞെടുക്കുക',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'കഴിഞ്ഞ മാസം (PageUp)',\n      nextMonth: 'അടുത്ത മാസം (PageDown)',\n      previousYear: 'കഴിഞ്ഞ വർഷം (Control + left)',\n      nextYear: 'അടുത്ത വർഷം (Control + right)',\n      previousDecade: 'കഴിഞ്ഞ ദശാബ്ദം',\n      nextDecade: 'അടുത്ത ദശാബ്ദം',\n      previousCentury: 'കഴിഞ്ഞ നൂറ്റാണ്ട്',\n      nextCentury: 'അടുത്ത നൂറ്റാണ്ട്'\n    },\n    timePickerLocale: {\n      placeholder: 'സമയം തിരഞ്ഞെടുക്കുക',\n      rangePlaceholder: ['ആരംഭ സമയം', 'അവസാന സമയം']\n    }\n  },\n  TimePicker: {\n    placeholder: 'സമയം തിരഞ്ഞെടുക്കുക',\n    rangePlaceholder: ['ആരംഭ സമയം', 'അവസാന സമയം']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'തിയതി തിരഞ്ഞെടുക്കുക',\n      yearPlaceholder: 'വർഷം തിരഞ്ഞെടുക്കുക',\n      quarterPlaceholder: 'ത്രൈമാസം തിരഞ്ഞെടുക്കുക',\n      monthPlaceholder: 'മാസം തിരഞ്ഞെടുക്കുക',\n      weekPlaceholder: 'വാരം തിരഞ്ഞെടുക്കുക',\n      rangePlaceholder: ['ആരംഭ ദിനം', 'അവസാന ദിനം'],\n      rangeYearPlaceholder: ['ആരംഭ വർഷം', 'അവസാന വർഷം'],\n      rangeMonthPlaceholder: ['ആരംഭ മാസം', 'അവസാന മാസം'],\n      rangeWeekPlaceholder: ['ആരംഭ വാരം', 'അവസാന വാരം'],\n      locale: 'ml_IN',\n      today: 'ഇന്ന്',\n      now: 'ഇപ്പോൾ',\n      backToToday: 'ഇന്നത്തെ ദിവസത്തിലേക്ക് തിരിച്ചു പോകുക',\n      ok: 'ശരിയാണ്',\n      clear: 'നീക്കം ചെയ്യുക',\n      month: 'മാസം',\n      year: 'വർഷം',\n      timeSelect: 'സമയം തിരഞ്ഞെടുക്കുക',\n      dateSelect: 'ദിവസം തിരഞ്ഞെടുക്കുക',\n      weekSelect: 'വാരം തിരഞ്ഞെടുക്കുക',\n      monthSelect: 'മാസം തിരഞ്ഞെടുക്കുക',\n      yearSelect: 'വർഷം തിരഞ്ഞെടുക്കുക',\n      decadeSelect: 'ദശാബ്ദം തിരഞ്ഞെടുക്കുക',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'കഴിഞ്ഞ മാസം (PageUp)',\n      nextMonth: 'അടുത്ത മാസം (PageDown)',\n      previousYear: 'കഴിഞ്ഞ വർഷം (Control + left)',\n      nextYear: 'അടുത്ത വർഷം (Control + right)',\n      previousDecade: 'കഴിഞ്ഞ ദശാബ്ദം',\n      nextDecade: 'അടുത്ത ദശാബ്ദം',\n      previousCentury: 'കഴിഞ്ഞ നൂറ്റാണ്ട്',\n      nextCentury: 'അടുത്ത നൂറ്റാണ്ട്'\n    },\n    timePickerLocale: {\n      placeholder: 'സമയം തിരഞ്ഞെടുക്കുക',\n      rangePlaceholder: ['ആരംഭ സമയം', 'അവസാന സമയം']\n    }\n  },\n  global: {\n    placeholder: 'ദയവായി തിരഞ്ഞെടുക്കുക'\n  },\n  Table: {\n    filterTitle: 'ഫിൽറ്റർ',\n    filterConfirm: 'ശരിയാണ്',\n    filterReset: 'പുനഃക്രമീകരിക്കുക',\n    filterEmptyText: 'ഫിൽറ്ററുകളൊന്നുമില്ല',\n    emptyText: 'ഡാറ്റയൊന്നുമില്ല',\n    selectAll: 'നിലവിലെ പേജ് തിരഞ്ഞെടുക്കുക',\n    selectInvert: 'നിലവിലെ പേജിൽ ഇല്ലാത്തത് തിരഞ്ഞെടുക്കുക',\n    selectNone: 'എല്ലാ ഡാറ്റയും നീക്കം ചെയ്യുക',\n    selectionAll: 'എല്ലാ ഡാറ്റയും തിരഞ്ഞെടുക്കുക',\n    sortTitle: 'ക്രമമാക്കുക',\n    expand: 'വരി വികസിപ്പിക്കുക',\n    collapse: 'വരി ചുരുക്കുക',\n    triggerDesc: 'അവരോഹണ ക്രമത്തിനായി ക്ലിക്ക് ചെയ്യുക',\n    triggerAsc: 'ആരോഹണ ക്രമത്തിനായി ക്ലിക്ക് ചെയ്യുക',\n    cancelSort: 'ക്രമീകരണം ഒഴിവാക്കുന്നതിനായി ക്ലിക്ക് ചെയ്യുക'\n  },\n  Modal: {\n    okText: 'ശരിയാണ്',\n    cancelText: 'റദ്ദാക്കുക',\n    justOkText: 'ശരിയാണ്'\n  },\n  Popconfirm: {\n    okText: 'ശരിയാണ്',\n    cancelText: 'റദ്ദാക്കുക'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'ഇവിടെ തിരയുക',\n    itemUnit: 'ഇനം',\n    itemsUnit: 'ഇനങ്ങൾ',\n    remove: 'നീക്കം ചെയ്യുക',\n    selectCurrent: 'നിലവിലെ പേജ് തിരഞ്ഞെടുക്കുക',\n    removeCurrent: 'നിലവിലെ പേജ് നീക്കം ചെയ്യുക',\n    selectAll: 'എല്ലാ ഡാറ്റയും തിരഞ്ഞെടുക്കുക',\n    removeAll: 'എല്ലാ ഡാറ്റയും നീക്കം ചെയ്യുക',\n    selectInvert: 'നിലവിലെ പേജിൽ ഇല്ലാത്തത് തിരഞ്ഞെടുക്കുക'\n  },\n  Upload: {\n    uploading: 'അപ്‌ലോഡ് ചെയ്തു കൊണ്ടിരിക്കുന്നു...',\n    removeFile: 'ഫയൽ നീക്കം ചെയ്യുക',\n    uploadError: 'അപ്‌ലോഡിൽ പിശക് സംഭവിച്ചിരിക്കുന്നു',\n    previewFile: 'ഫയൽ പ്രിവ്യൂ ചെയ്യുക',\n    downloadFile: 'ഫയൽ ഡൗൺലോഡ് ചെയ്യുക'\n  },\n  Empty: {\n    description: 'ഡാറ്റയൊന്നുമില്ല'\n  },\n  Icon: {\n    icon: 'ഐക്കൺ'\n  },\n  Text: {\n    edit: 'തിരുത്തുക',\n    copy: 'കോപ്പി ചെയ്യുക',\n    copied: 'കോപ്പി ചെയ്തു',\n    expand: 'വികസിപ്പിക്കുക'\n  },\n  PageHeader: {\n    back: 'തിരികെ'\n  },\n  Image: {\n    preview: 'പ്രിവ്യൂ'\n  },\n  Form: {\n    optional: '(ആവശ്യകമായ)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/mn_MN.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'mn-mn',\n  Pagination: {\n    items_per_page: '/ хуудас',\n    jump_to: 'Шилжих',\n    jump_to_confirm: 'сонгох',\n    page: '',\n    prev_page: 'Өмнөх хуудас',\n    next_page: 'Дараагийн хуудас',\n    prev_5: 'Дараагийн 5 хуудас',\n    next_5: 'Дараагийн 5 хуудас',\n    prev_3: 'Дараагийн 3 хуудас',\n    next_3: 'Дараагийн 3 хуудас',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Огноо сонгох',\n      rangePlaceholder: ['Эхлэх огноо', 'Дуусах огноо'],\n      locale: 'mn_MN',\n      today: 'Өнөөдөр',\n      now: 'Одоо',\n      backToToday: 'Өнөөдөрлүү буцах',\n      ok: 'Ok',\n      clear: 'Цэвэрлэх',\n      month: 'Сар',\n      year: 'Жил',\n      timeSelect: 'Цаг сонгох',\n      dateSelect: 'Огноо сонгох',\n      weekSelect: '7 хоног сонгох',\n      monthSelect: 'Сар сонгох',\n      yearSelect: 'Жил сонгох',\n      decadeSelect: 'Арван сонгох',\n      yearFormat: 'YYYY',\n      dateFormat: 'YYYY/MM/DD',\n      dayFormat: 'DD',\n      dateTimeFormat: 'YYYY/MM/DD HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Өмнөх сар (PageUp)',\n      nextMonth: 'Дараа сар (PageDown)',\n      previousYear: 'Өмнөх жил (Control + left)',\n      nextYear: 'Дараа жил (Control + right)',\n      previousDecade: 'Өмнөх арван',\n      nextDecade: 'Дараа арван',\n      previousCentury: 'Өмнөх зуун',\n      nextCentury: 'Дараа зуун'\n    },\n    timePickerLocale: {\n      placeholder: 'Цаг сонгох'\n    }\n  },\n  TimePicker: {\n    placeholder: 'Цаг сонгох'\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Огноо сонгох',\n      rangePlaceholder: ['Эхлэх огноо', 'Дуусах огноо'],\n      locale: 'mn_MN',\n      today: 'Өнөөдөр',\n      now: 'Одоо',\n      backToToday: 'Өнөөдөрлүү буцах',\n      ok: 'Ok',\n      clear: 'Цэвэрлэх',\n      month: 'Сар',\n      year: 'Жил',\n      timeSelect: 'Цаг сонгох',\n      dateSelect: 'Огноо сонгох',\n      weekSelect: '7 хоног сонгох',\n      monthSelect: 'Сар сонгох',\n      yearSelect: 'Жил сонгох',\n      decadeSelect: 'Арван сонгох',\n      yearFormat: 'YYYY',\n      dateFormat: 'YYYY/MM/DD',\n      dayFormat: 'DD',\n      dateTimeFormat: 'YYYY/MM/DD HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Өмнөх сар (PageUp)',\n      nextMonth: 'Дараа сар (PageDown)',\n      previousYear: 'Өмнөх жил (Control + left)',\n      nextYear: 'Дараа жил (Control + right)',\n      previousDecade: 'Өмнөх арван',\n      nextDecade: 'Дараа арван',\n      previousCentury: 'Өмнөх зуун',\n      nextCentury: 'Дараа зуун'\n    },\n    timePickerLocale: {\n      placeholder: 'Цаг сонгох'\n    }\n  },\n  Table: {\n    filterTitle: 'Хайх цэс',\n    filterConfirm: 'OK',\n    filterReset: 'Цэвэрлэх',\n    selectAll: 'Бүгдийг сонгох',\n    selectInvert: 'Бусдыг сонгох'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Цуцлах',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Цуцлах'\n  },\n  Transfer: {\n    searchPlaceholder: 'Хайх',\n    itemUnit: 'Зүйл',\n    itemsUnit: 'Зүйлүүд'\n  },\n  Upload: {\n    uploading: 'Хуулж байна...',\n    removeFile: 'Файл устгах',\n    uploadError: 'Хуулахад алдаа гарлаа',\n    previewFile: 'Файлыг түргэн үзэх',\n    downloadFile: 'Файлыг татах'\n  },\n  Empty: {\n    description: 'Мэдээлэл байхгүй байна'\n  },\n  Form: {\n    optional: '(заавалгүй)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/ms_MY.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'ms-my',\n  Pagination: {\n    items_per_page: '/ halaman',\n    jump_to: 'Lompat ke',\n    jump_to_confirm: 'Sahkan',\n    page: '',\n    prev_page: 'Halaman sebelumnya',\n    next_page: 'Halam seterusnya',\n    prev_5: '5 halaman sebelum',\n    next_5: '5 halaman seterusnya',\n    prev_3: '3 halaman sebelumnya',\n    next_3: '3 halaman seterusnya',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Pilih tarikh',\n      rangePlaceholder: ['Tarikh mula', 'Tarikh akhir'],\n      locale: 'ms_MY',\n      today: 'Hari ini',\n      now: 'Sekarang',\n      backToToday: 'Kembali ke hari ini',\n      ok: 'Ok',\n      timeSelect: 'Pilih masa',\n      dateSelect: 'Pilih tarikh',\n      weekSelect: 'Pilih minggu',\n      clear: 'Padam',\n      month: 'Bulan',\n      year: 'Tahun',\n      previousMonth: 'Bulan lepas',\n      nextMonth: 'Bulan depan',\n      monthSelect: 'Pilih bulan',\n      yearSelect: 'Pilih tahun',\n      decadeSelect: 'Pilih dekad',\n      yearFormat: 'YYYY',\n      dayFormat: 'D',\n      dateFormat: 'M/D/YYYY',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      previousYear: 'Tahun lepas (Ctrl+left)',\n      nextYear: 'Tahun depan (Ctrl+right)',\n      previousDecade: 'Dekad lepas',\n      nextDecade: 'Dekad depan',\n      previousCentury: 'Abad lepas',\n      nextCentury: 'Abad depan'\n    },\n    timePickerLocale: {\n      placeholder: 'Sila pilih masa'\n    }\n  },\n  TimePicker: {\n    placeholder: 'Sila pilih masa'\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Pilih tarikh',\n      rangePlaceholder: ['Tarikh mula', 'Tarikh akhir'],\n      locale: 'ms_MY',\n      today: 'Hari ini',\n      now: 'Sekarang',\n      backToToday: 'Kembali ke hari ini',\n      ok: 'Ok',\n      timeSelect: 'Pilih masa',\n      dateSelect: 'Pilih tarikh',\n      weekSelect: 'Pilih minggu',\n      clear: 'Padam',\n      month: 'Bulan',\n      year: 'Tahun',\n      previousMonth: 'Bulan lepas',\n      nextMonth: 'Bulan depan',\n      monthSelect: 'Pilih bulan',\n      yearSelect: 'Pilih tahun',\n      decadeSelect: 'Pilih dekad',\n      yearFormat: 'YYYY',\n      dayFormat: 'D',\n      dateFormat: 'M/D/YYYY',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      previousYear: 'Tahun lepas (Ctrl+left)',\n      nextYear: 'Tahun depan (Ctrl+right)',\n      previousDecade: 'Dekad lepas',\n      nextDecade: 'Dekad depan',\n      previousCentury: 'Abad lepas',\n      nextCentury: 'Abad depan'\n    },\n    timePickerLocale: {\n      placeholder: 'Sila pilih masa'\n    }\n  },\n  global: {\n    placeholder: 'Sila pilih'\n  },\n  PageHeader: {\n    back: 'Kembali'\n  },\n  Text: {\n    edit: 'Sunting',\n    copy: 'Salin',\n    copied: 'Berjaya menyalin',\n    expand: 'Kembang'\n  },\n  Empty: {\n    description: 'Tiada data'\n  },\n  Table: {\n    filterTitle: 'Cari dengan tajuk',\n    filterConfirm: 'OK',\n    filterReset: 'Menetapkan semula',\n    emptyText: 'Tiada data',\n    selectAll: 'Pilih semua',\n    selectInvert: 'Terbalikkan'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Batal',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Batal'\n  },\n  Transfer: {\n    notFoundContent: 'Tidak dijumpai',\n    searchPlaceholder: 'Carian di sini',\n    itemUnit: 'item',\n    itemsUnit: 'item'\n  },\n  Icon: {\n    icon: 'ikon'\n  },\n  Select: {\n    notFoundContent: 'Tidak Dijumpai'\n  },\n  Upload: {\n    uploading: 'Sedang memuat naik...',\n    removeFile: 'Buang fail',\n    uploadError: 'Masalah muat naik',\n    previewFile: 'Tengok fail',\n    downloadFile: 'Muat turun fail'\n  },\n  Form: {\n    optional: '(pilihan)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/nb_NO.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'nb',\n  Pagination: {\n    items_per_page: '/ side',\n    jump_to: 'Gå til side',\n    jump_to_confirm: 'bekreft',\n    page: 'Side',\n    prev_page: 'Forrige side',\n    next_page: 'Neste side',\n    prev_5: '5 forrige',\n    next_5: '5 neste',\n    prev_3: '3 forrige',\n    next_3: '3 neste',\n    page_size: 'sidestørrelse'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Velg dato',\n      yearPlaceholder: 'Velg år',\n      quarterPlaceholder: 'Velg kvartal',\n      monthPlaceholder: 'Velg måned',\n      weekPlaceholder: 'Velg uke',\n      rangePlaceholder: ['Startdato', 'Sluttdato'],\n      rangeYearPlaceholder: ['Startår', 'Sluttår'],\n      rangeQuarterPlaceholder: ['Startkvartal', 'Sluttkvartal'],\n      rangeMonthPlaceholder: ['Startmåned', 'Sluttmåned'],\n      rangeWeekPlaceholder: ['Start uke', 'Sluttuke'],\n      locale: 'nb_NO',\n      today: 'I dag',\n      now: 'Nå',\n      backToToday: 'Gå til i dag',\n      ok: 'Ok',\n      clear: 'Annuller',\n      month: 'Måned',\n      year: 'År',\n      timeSelect: 'Velg tidspunkt',\n      dateSelect: 'Velg dato',\n      weekSelect: 'Velg uke',\n      monthSelect: 'Velg måned',\n      yearSelect: 'Velg år',\n      decadeSelect: 'Velg tiår',\n      yearFormat: 'YYYY',\n      dateFormat: 'DD.MM.YYYY',\n      dayFormat: 'DD',\n      dateTimeFormat: 'DD.MM.YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Forrige måned (PageUp)',\n      nextMonth: 'Neste måned (PageDown)',\n      previousYear: 'Forrige år (Control + venstre)',\n      nextYear: 'Neste år (Control + høyre)',\n      previousDecade: 'Forrige tiår',\n      nextDecade: 'Neste tiår',\n      previousCentury: 'Forrige århundre',\n      nextCentury: 'Neste århundre'\n    },\n    timePickerLocale: {\n      placeholder: 'Velg tid',\n      rangePlaceholder: ['Starttid', 'Sluttid']\n    }\n  },\n  TimePicker: {\n    placeholder: 'Velg tid',\n    rangePlaceholder: ['Starttid', 'Sluttid']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Velg dato',\n      yearPlaceholder: 'Velg år',\n      quarterPlaceholder: 'Velg kvartal',\n      monthPlaceholder: 'Velg måned',\n      weekPlaceholder: 'Velg uke',\n      rangePlaceholder: ['Startdato', 'Sluttdato'],\n      rangeYearPlaceholder: ['Startår', 'Sluttår'],\n      rangeMonthPlaceholder: ['Startmåned', 'Sluttmåned'],\n      rangeWeekPlaceholder: ['Start uke', 'Sluttuke'],\n      locale: 'nb_NO',\n      today: 'I dag',\n      now: 'Nå',\n      backToToday: 'Gå til i dag',\n      ok: 'Ok',\n      clear: 'Annuller',\n      month: 'Måned',\n      year: 'År',\n      timeSelect: 'Velg tidspunkt',\n      dateSelect: 'Velg dato',\n      weekSelect: 'Velg uke',\n      monthSelect: 'Velg måned',\n      yearSelect: 'Velg år',\n      decadeSelect: 'Velg tiår',\n      yearFormat: 'YYYY',\n      dateFormat: 'DD.MM.YYYY',\n      dayFormat: 'DD',\n      dateTimeFormat: 'DD.MM.YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Forrige måned (PageUp)',\n      nextMonth: 'Neste måned (PageDown)',\n      previousYear: 'Forrige år (Control + venstre)',\n      nextYear: 'Neste år (Control + høyre)',\n      previousDecade: 'Forrige tiår',\n      nextDecade: 'Neste tiår',\n      previousCentury: 'Forrige århundre',\n      nextCentury: 'Neste århundre'\n    },\n    timePickerLocale: {\n      placeholder: 'Velg tid',\n      rangePlaceholder: ['Starttid', 'Sluttid']\n    }\n  },\n  global: {\n    placeholder: 'Vennligst velg'\n  },\n  Table: {\n    filterTitle: 'Filtermeny',\n    filterConfirm: 'OK',\n    filterReset: 'Nullstill',\n    filterEmptyText: 'Ingen filtre',\n    emptyText: 'Ingen data',\n    selectAll: 'Velg alle',\n    selectInvert: 'Inverter gjeldende side',\n    selectionAll: 'Velg all data',\n    sortTitle: 'Sorter',\n    expand: 'Utvid rad',\n    collapse: 'Skjul rad',\n    triggerDesc: 'Sorter data i synkende rekkefølge',\n    triggerAsc: 'Sorterer data i stigende rekkefølge',\n    cancelSort: 'Klikk for å avbryte sorteringen',\n    filterCheckall: 'Velg alle elementer',\n    filterSearchPlaceholder: 'Søk i filtre',\n    selectNone: 'Tøm alle data'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Avbryt',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Avbryt'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'Søk her',\n    itemUnit: 'element',\n    itemsUnit: 'elementer',\n    remove: 'Fjern',\n    selectCurrent: 'Velg gjeldende side',\n    removeCurrent: 'Fjern gjeldende side',\n    selectAll: 'Velg all data',\n    removeAll: 'Fjern all data',\n    selectInvert: 'Inverter gjeldende side'\n  },\n  Upload: {\n    uploading: 'Laster opp...',\n    removeFile: 'Fjern fil',\n    uploadError: 'Feil ved opplastning',\n    previewFile: 'Forhåndsvisning',\n    downloadFile: 'Last ned fil'\n  },\n  Empty: {\n    description: 'Ingen data'\n  },\n  Icon: {\n    icon: 'ikon'\n  },\n  Text: {\n    edit: 'Rediger',\n    copy: 'Kopier',\n    copied: 'Kopiert',\n    expand: 'Utvid'\n  },\n  PageHeader: {\n    back: 'Tilbake'\n  },\n  Image: {\n    preview: 'Forhåndsvis'\n  },\n  CronExpression: {\n    cronError: 'Ugyldig cron-uttrykk',\n    second: 'sekund',\n    minute: 'minutt',\n    hour: 'time',\n    day: 'dag',\n    month: 'måned',\n    week: 'uke'\n  },\n  QRCode: {\n    expired: 'QR-koden er utløpt',\n    refresh: 'Oppdater',\n    scanned: 'Skannet'\n  },\n  Form: {\n    optional: '(valgfritt)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/ne_NP.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'ne-np',\n  Pagination: {\n    items_per_page: '/ page',\n    jump_to: 'Go to',\n    jump_to_confirm: 'confirm',\n    page: 'Page',\n    prev_page: 'Previous Page',\n    next_page: 'Next Page',\n    prev_5: 'Previous 5 Pages',\n    next_5: 'Next 5 Pages',\n    prev_3: 'Previous 3 Pages',\n    next_3: 'Next 3 Pages',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Select date',\n      yearPlaceholder: 'Select year',\n      quarterPlaceholder: 'Select quarter',\n      monthPlaceholder: 'Select month',\n      weekPlaceholder: 'Select week',\n      rangePlaceholder: ['Start date', 'End date'],\n      rangeYearPlaceholder: ['Start year', 'End year'],\n      rangeMonthPlaceholder: ['Start month', 'End month'],\n      rangeWeekPlaceholder: ['Start week', 'End week'],\n      locale: 'en_US',\n      today: 'Today',\n      now: 'Now',\n      backToToday: 'Back to today',\n      ok: 'Ok',\n      clear: 'Clear',\n      month: 'Month',\n      year: 'Year',\n      timeSelect: 'select time',\n      dateSelect: 'select date',\n      weekSelect: 'Choose a week',\n      monthSelect: 'Choose a month',\n      yearSelect: 'Choose a year',\n      decadeSelect: 'Choose a decade',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Previous month (PageUp)',\n      nextMonth: 'Next month (PageDown)',\n      previousYear: 'Last year (Control + left)',\n      nextYear: 'Next year (Control + right)',\n      previousDecade: 'Last decade',\n      nextDecade: 'Next decade',\n      previousCentury: 'Last century',\n      nextCentury: 'Next century'\n    },\n    timePickerLocale: {\n      placeholder: 'Select time',\n      rangePlaceholder: ['Start time', 'End time']\n    }\n  },\n  TimePicker: {\n    placeholder: 'Select time',\n    rangePlaceholder: ['Start time', 'End time']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Select date',\n      yearPlaceholder: 'Select year',\n      quarterPlaceholder: 'Select quarter',\n      monthPlaceholder: 'Select month',\n      weekPlaceholder: 'Select week',\n      rangePlaceholder: ['Start date', 'End date'],\n      rangeYearPlaceholder: ['Start year', 'End year'],\n      rangeMonthPlaceholder: ['Start month', 'End month'],\n      rangeWeekPlaceholder: ['Start week', 'End week'],\n      locale: 'en_US',\n      today: 'Today',\n      now: 'Now',\n      backToToday: 'Back to today',\n      ok: 'Ok',\n      clear: 'Clear',\n      month: 'Month',\n      year: 'Year',\n      timeSelect: 'select time',\n      dateSelect: 'select date',\n      weekSelect: 'Choose a week',\n      monthSelect: 'Choose a month',\n      yearSelect: 'Choose a year',\n      decadeSelect: 'Choose a decade',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Previous month (PageUp)',\n      nextMonth: 'Next month (PageDown)',\n      previousYear: 'Last year (Control + left)',\n      nextYear: 'Next year (Control + right)',\n      previousDecade: 'Last decade',\n      nextDecade: 'Next decade',\n      previousCentury: 'Last century',\n      nextCentury: 'Next century'\n    },\n    timePickerLocale: {\n      placeholder: 'Select time',\n      rangePlaceholder: ['Start time', 'End time']\n    }\n  },\n  Table: {\n    filterTitle: 'फिल्टर मेनु',\n    filterConfirm: 'हो',\n    filterReset: 'रीसेट',\n    selectAll: 'सबै छान्नुुहोस्',\n    selectInvert: 'छनौट उल्टाउनुहोस'\n  },\n  Modal: {\n    okText: 'हो',\n    cancelText: 'होईन',\n    justOkText: 'हो'\n  },\n  Popconfirm: {\n    okText: 'हो',\n    cancelText: 'होईन'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'यहाँ खोज्नुहोस्',\n    itemUnit: 'वस्तु',\n    itemsUnit: 'वस्तुहरू'\n  },\n  Upload: {\n    uploading: 'अपलोड गर्दै...',\n    removeFile: 'फाइल हटाउनुहोस्',\n    uploadError: 'अप्लोडमा समस्या भयो',\n    previewFile: 'फाइल पूर्वावलोकन गर्नुहोस्',\n    downloadFile: 'डाउनलोड फाइल'\n  },\n  Empty: {\n    description: 'डाटा छैन'\n  },\n  Form: {\n    optional: '(वैकल्पिक)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/nl_BE.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'nl-be',\n  Pagination: {\n    items_per_page: '/ pagina',\n    jump_to: 'Ga naar',\n    jump_to_confirm: 'bevestigen',\n    page: '',\n    prev_page: 'Vorige pagina',\n    next_page: 'Volgende pagina',\n    prev_5: \"Vorige 5 pagina's\",\n    next_5: \"Volgende 5 pagina's\",\n    prev_3: \"Vorige 3 pagina's\",\n    next_3: \"Volgende 3 pagina's\",\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Selecteer datum',\n      rangePlaceholder: ['Begin datum', 'Eind datum'],\n      locale: 'nl_BE',\n      today: 'Vandaag',\n      now: 'Nu',\n      backToToday: 'Terug naar vandaag',\n      ok: 'Ok',\n      clear: 'Reset',\n      month: 'Maand',\n      year: 'Jaar',\n      timeSelect: 'Selecteer tijd',\n      dateSelect: 'Selecteer datum',\n      monthSelect: 'Kies een maand',\n      yearSelect: 'Kies een jaar',\n      decadeSelect: 'Kies een decennium',\n      yearFormat: 'YYYY',\n      dateFormat: 'D-M-YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D-M-YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Vorige maand (PageUp)',\n      nextMonth: 'Volgende maand (PageDown)',\n      previousYear: 'Vorig jaar (Control + left)',\n      nextYear: 'Volgend jaar (Control + right)',\n      previousDecade: 'Vorig decennium',\n      nextDecade: 'Volgend decennium',\n      previousCentury: 'Vorige eeuw',\n      nextCentury: 'Volgende eeuw',\n      monthPlaceholder: 'Selecteer maand',\n      quarterPlaceholder: 'Selecteer kwartaal',\n      rangeMonthPlaceholder: ['Begin maand', 'Eind maand'],\n      rangeWeekPlaceholder: ['Begin week', 'Eind week'],\n      rangeYearPlaceholder: ['Begin jaar', 'Eind jaar'],\n      weekPlaceholder: 'Selecteer week',\n      yearPlaceholder: 'Selecteer jaar'\n    },\n    timePickerLocale: {\n      placeholder: 'Selecteer tijd',\n      rangePlaceholder: ['Start tijd', 'Eind tijd']\n    }\n  },\n  TimePicker: {\n    placeholder: 'Selecteer tijd',\n    rangePlaceholder: ['Start tijd', 'Eind tijd']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Selecteer datum',\n      rangePlaceholder: ['Begin datum', 'Eind datum'],\n      locale: 'nl_BE',\n      today: 'Vandaag',\n      now: 'Nu',\n      backToToday: 'Terug naar vandaag',\n      ok: 'Ok',\n      clear: 'Reset',\n      month: 'Maand',\n      year: 'Jaar',\n      timeSelect: 'Selecteer tijd',\n      dateSelect: 'Selecteer datum',\n      monthSelect: 'Kies een maand',\n      yearSelect: 'Kies een jaar',\n      decadeSelect: 'Kies een decennium',\n      yearFormat: 'YYYY',\n      dateFormat: 'D-M-YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D-M-YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Vorige maand (PageUp)',\n      nextMonth: 'Volgende maand (PageDown)',\n      previousYear: 'Vorig jaar (Control + left)',\n      nextYear: 'Volgend jaar (Control + right)',\n      previousDecade: 'Vorig decennium',\n      nextDecade: 'Volgend decennium',\n      previousCentury: 'Vorige eeuw',\n      nextCentury: 'Volgende eeuw',\n      monthPlaceholder: 'Selecteer maand',\n      quarterPlaceholder: 'Selecteer kwartaal',\n      rangeMonthPlaceholder: ['Begin maand', 'Eind maand'],\n      rangeWeekPlaceholder: ['Begin week', 'Eind week'],\n      rangeYearPlaceholder: ['Begin jaar', 'Eind jaar'],\n      weekPlaceholder: 'Selecteer week',\n      yearPlaceholder: 'Selecteer jaar'\n    },\n    timePickerLocale: {\n      placeholder: 'Selecteer tijd',\n      rangePlaceholder: ['Start tijd', 'Eind tijd']\n    }\n  },\n  Table: {\n    filterTitle: 'Filteren',\n    filterConfirm: 'OK',\n    filterReset: 'Reset',\n    selectAll: 'Selecteer huidige pagina',\n    selectInvert: 'Keer volgorde om',\n    cancelSort: 'Klik om sortering te annuleren',\n    collapse: 'Rij inklappen',\n    emptyText: 'Geen data',\n    expand: 'Rij uitklappen',\n    filterEmptyText: 'Geen filters',\n    selectNone: 'Maak selectie leeg',\n    selectionAll: 'Selecteer alle data',\n    sortTitle: 'Sorteren',\n    triggerAsc: 'Klik om oplopend te sorteren',\n    triggerDesc: 'Klik om aflopend te sorteren'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Annuleer',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Annuleer'\n  },\n  Transfer: {\n    searchPlaceholder: 'Zoek hier',\n    itemUnit: 'item',\n    itemsUnit: 'items',\n    remove: 'Verwijder',\n    removeAll: 'Verwijder alles',\n    removeCurrent: 'Verwijder huidige pagina',\n    selectAll: 'Selecteer alles',\n    selectCurrent: 'Selecteer huidige pagina',\n    selectInvert: 'Huidige pagina omkeren',\n    titles: ['', '']\n  },\n  Upload: {\n    uploading: 'Uploaden...',\n    removeFile: 'Verwijder bestand',\n    uploadError: 'Fout tijdens uploaden',\n    previewFile: 'Preview file',\n    downloadFile: 'Bestand downloaden'\n  },\n  Empty: {\n    description: 'Geen gegevens'\n  },\n  global: {\n    placeholder: 'Maak een selectie'\n  },\n  Icon: {\n    icon: 'icoon'\n  },\n  Text: {\n    edit: 'Bewerken',\n    copy: 'kopiëren',\n    copied: 'Gekopieerd',\n    expand: 'Uitklappen'\n  },\n  PageHeader: {\n    back: 'Terug'\n  },\n  Image: {\n    preview: 'Voorbeeld'\n  },\n  Form: {\n    optional: '(optioneel)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/nl_NL.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'nl',\n  Pagination: {\n    items_per_page: '/ pagina',\n    jump_to: 'Ga naar',\n    jump_to_confirm: 'bevestigen',\n    page: 'Pagina',\n    prev_page: 'Vorige pagina',\n    next_page: 'Volgende pagina',\n    prev_5: \"Vorige 5 pagina's\",\n    next_5: \"Volgende 5 pagina's\",\n    prev_3: \"Vorige 3 pagina's\",\n    next_3: \"Volgende 3 pagina's\",\n    page_size: 'pagina grootte'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Selecteer datum',\n      rangePlaceholder: ['Begin datum', 'Eind datum'],\n      locale: 'nl_NL',\n      today: 'Vandaag',\n      now: 'Nu',\n      backToToday: 'Terug naar vandaag',\n      ok: 'Ok',\n      clear: 'Reset',\n      month: 'Maand',\n      year: 'Jaar',\n      timeSelect: 'Selecteer tijd',\n      dateSelect: 'Selecteer datum',\n      monthSelect: 'Kies een maand',\n      yearSelect: 'Kies een jaar',\n      decadeSelect: 'Kies een decennium',\n      yearFormat: 'YYYY',\n      dateFormat: 'D-M-YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D-M-YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Vorige maand (PageUp)',\n      nextMonth: 'Volgende maand (PageDown)',\n      previousYear: 'Vorig jaar (Control + left)',\n      nextYear: 'Volgend jaar (Control + right)',\n      previousDecade: 'Vorig decennium',\n      nextDecade: 'Volgend decennium',\n      previousCentury: 'Vorige eeuw',\n      nextCentury: 'Volgende eeuw',\n      monthPlaceholder: 'Selecteer maand',\n      quarterPlaceholder: 'Selecteer kwartaal',\n      rangeMonthPlaceholder: ['Begin maand', 'Eind maand'],\n      rangeWeekPlaceholder: ['Begin week', 'Eind week'],\n      rangeYearPlaceholder: ['Begin jaar', 'Eind jaar'],\n      weekPlaceholder: 'Selecteer week',\n      yearPlaceholder: 'Selecteer jaar'\n    },\n    timePickerLocale: {\n      placeholder: 'Selecteer tijd',\n      rangePlaceholder: ['Start tijd', 'Eind tijd']\n    }\n  },\n  TimePicker: {\n    placeholder: 'Selecteer tijd',\n    rangePlaceholder: ['Start tijd', 'Eind tijd']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Selecteer datum',\n      rangePlaceholder: ['Begin datum', 'Eind datum'],\n      locale: 'nl_NL',\n      today: 'Vandaag',\n      now: 'Nu',\n      backToToday: 'Terug naar vandaag',\n      ok: 'Ok',\n      clear: 'Reset',\n      month: 'Maand',\n      year: 'Jaar',\n      timeSelect: 'Selecteer tijd',\n      dateSelect: 'Selecteer datum',\n      monthSelect: 'Kies een maand',\n      yearSelect: 'Kies een jaar',\n      decadeSelect: 'Kies een decennium',\n      yearFormat: 'YYYY',\n      dateFormat: 'D-M-YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D-M-YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Vorige maand (PageUp)',\n      nextMonth: 'Volgende maand (PageDown)',\n      previousYear: 'Vorig jaar (Control + left)',\n      nextYear: 'Volgend jaar (Control + right)',\n      previousDecade: 'Vorig decennium',\n      nextDecade: 'Volgend decennium',\n      previousCentury: 'Vorige eeuw',\n      nextCentury: 'Volgende eeuw',\n      monthPlaceholder: 'Selecteer maand',\n      quarterPlaceholder: 'Selecteer kwartaal',\n      rangeMonthPlaceholder: ['Begin maand', 'Eind maand'],\n      rangeWeekPlaceholder: ['Begin week', 'Eind week'],\n      rangeYearPlaceholder: ['Begin jaar', 'Eind jaar'],\n      weekPlaceholder: 'Selecteer week',\n      yearPlaceholder: 'Selecteer jaar'\n    },\n    timePickerLocale: {\n      placeholder: 'Selecteer tijd',\n      rangePlaceholder: ['Start tijd', 'Eind tijd']\n    }\n  },\n  global: {\n    placeholder: 'Maak een selectie'\n  },\n  Table: {\n    filterTitle: 'Filteren',\n    filterConfirm: 'OK',\n    filterReset: 'Reset',\n    selectAll: 'Selecteer huidige pagina',\n    selectInvert: 'Keer volgorde om',\n    sortTitle: 'Sorteren',\n    expand: 'Rij uitklappen',\n    collapse: 'Rij inklappen',\n    cancelSort: 'Klik om sortering te annuleren',\n    emptyText: 'Geen data',\n    filterEmptyText: 'Geen filters',\n    selectNone: 'Maak selectie leeg',\n    selectionAll: 'Selecteer alle data',\n    triggerAsc: 'Klik om oplopend te sorteren',\n    triggerDesc: 'Klik om aflopend te sorteren'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Annuleer',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Annuleer'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'Zoek hier',\n    itemUnit: 'item',\n    itemsUnit: 'items',\n    remove: 'Verwijder',\n    removeAll: 'Verwijder alles',\n    removeCurrent: 'Verwijder huidige pagina',\n    selectAll: 'Selecteer alles',\n    selectCurrent: 'Selecteer huidige pagina',\n    selectInvert: 'Huidige pagina omkeren'\n  },\n  Upload: {\n    uploading: 'Uploaden...',\n    removeFile: 'Verwijder bestand',\n    uploadError: 'Fout tijdens uploaden',\n    previewFile: 'Preview file',\n    downloadFile: 'Bestand downloaden'\n  },\n  Empty: {\n    description: 'Geen gegevens'\n  },\n  Icon: {\n    icon: 'icoon'\n  },\n  Text: {\n    edit: 'Bewerken',\n    copy: 'kopiëren',\n    copied: 'Gekopieerd',\n    expand: 'Uitklappen'\n  },\n  PageHeader: {\n    back: 'Terug'\n  },\n  Image: {\n    preview: 'Voorbeeld'\n  },\n  Form: {\n    optional: '(optioneel)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/pl_PL.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'pl',\n  Pagination: {\n    items_per_page: 'na stronę',\n    jump_to: 'Idź do',\n    jump_to_confirm: 'potwierdź',\n    page: '',\n    prev_page: 'Poprzednia strona',\n    next_page: 'Następna strona',\n    prev_5: 'Poprzednie 5 stron',\n    next_5: 'Następne 5 stron',\n    prev_3: 'Poprzednie 3 strony',\n    next_3: 'Następne 3 strony',\n    page_size: 'rozmiar strony'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Wybierz datę',\n      yearPlaceholder: 'Wybierz rok',\n      monthPlaceholder: 'Wybierz miesiąc',\n      weekPlaceholder: 'Wybierz tydzień',\n      rangePlaceholder: ['Data początkowa', 'Data końcowa'],\n      rangeYearPlaceholder: ['Początkowy rok', 'Końcowy rok'],\n      rangeMonthPlaceholder: ['Początkowy miesiąc', 'Końcowy miesiąc'],\n      rangeWeekPlaceholder: ['Początkowy tydzień', 'Końcowy tydzień'],\n      locale: 'pl_PL',\n      today: 'Dzisiaj',\n      now: 'Teraz',\n      backToToday: 'Ustaw dzisiaj',\n      ok: 'Ok',\n      clear: 'Wyczyść',\n      month: 'Miesiąc',\n      year: 'Rok',\n      timeSelect: 'Ustaw czas',\n      dateSelect: 'Ustaw datę',\n      monthSelect: 'Wybierz miesiąc',\n      yearSelect: 'Wybierz rok',\n      decadeSelect: 'Wybierz dekadę',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Poprzedni miesiąc (PageUp)',\n      nextMonth: 'Następny miesiąc (PageDown)',\n      previousYear: 'Ostatni rok (Ctrl + left)',\n      nextYear: 'Następny rok (Ctrl + right)',\n      previousDecade: 'Ostatnia dekada',\n      nextDecade: 'Następna dekada',\n      previousCentury: 'Ostatni wiek',\n      nextCentury: 'Następny wiek'\n    },\n    timePickerLocale: {\n      placeholder: 'Wybierz godzinę'\n    }\n  },\n  TimePicker: {\n    placeholder: 'Wybierz godzinę'\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Wybierz datę',\n      rangePlaceholder: ['Data początkowa', 'Data końcowa'],\n      locale: 'pl_PL',\n      today: 'Dzisiaj',\n      now: 'Teraz',\n      backToToday: 'Ustaw dzisiaj',\n      ok: 'Ok',\n      clear: 'Wyczyść',\n      month: 'Miesiąc',\n      year: 'Rok',\n      timeSelect: 'Ustaw czas',\n      dateSelect: 'Ustaw datę',\n      monthSelect: 'Wybierz miesiąc',\n      yearSelect: 'Wybierz rok',\n      decadeSelect: 'Wybierz dekadę',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Poprzedni miesiąc (PageUp)',\n      nextMonth: 'Następny miesiąc (PageDown)',\n      previousYear: 'Ostatni rok (Ctrl + left)',\n      nextYear: 'Następny rok (Ctrl + right)',\n      previousDecade: 'Ostatnia dekada',\n      nextDecade: 'Następna dekada',\n      previousCentury: 'Ostatni wiek',\n      nextCentury: 'Następny wiek'\n    },\n    timePickerLocale: {\n      placeholder: 'Wybierz godzinę'\n    }\n  },\n  Table: {\n    filterTitle: 'Menu filtra',\n    filterConfirm: 'OK',\n    filterReset: 'Usuń filtry',\n    selectAll: 'Zaznacz bieżącą stronę',\n    selectInvert: 'Odwróć zaznaczenie',\n    triggerDesc: 'Sortuj malejąco',\n    triggerAsc: 'Sortuj rosnąco',\n    cancelSort: 'Usuń sortowanie',\n    filterEmptyText: 'Brak filtrów',\n    filterCheckall: 'Wybierz wszystkie elementy',\n    filterSearchPlaceholder: 'Szukaj w filtrach',\n    emptyText: 'Brak danych',\n    selectNone: 'Wyczyść',\n    selectionAll: 'Wybierz wszystkie',\n    sortTitle: 'Sortowanie',\n    expand: 'Rozwiń wiersz',\n    collapse: 'Zwiń wiersz'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Anuluj',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Anuluj'\n  },\n  Transfer: {\n    searchPlaceholder: 'Szukaj',\n    itemUnit: 'obiekt',\n    itemsUnit: 'obiekty',\n    titles: ['', ''],\n    remove: 'Usuń',\n    selectCurrent: 'Wybierz aktualną stronę',\n    removeCurrent: 'Usuń aktualną stronę',\n    selectAll: 'Wybierz wszystkie',\n    removeAll: 'Usuń wszystkie',\n    selectInvert: 'Odwróć wybór'\n  },\n  Upload: {\n    uploading: 'Wysyłanie...',\n    removeFile: 'Usuń plik',\n    uploadError: 'Błąd wysyłania',\n    previewFile: 'Podejrzyj plik',\n    downloadFile: 'Pobieranie pliku'\n  },\n  Empty: {\n    description: 'Brak danych'\n  },\n  global: {\n    placeholder: 'Wybierz'\n  },\n  Icon: {\n    icon: 'Ikona'\n  },\n  Text: {\n    edit: 'Edytuj',\n    copy: 'Kopiuj',\n    copied: 'Skopiowany',\n    expand: 'Rozwiń'\n  },\n  PageHeader: {\n    back: 'Wstecz'\n  },\n  Image: {\n    preview: 'Podgląd'\n  },\n  Form: {\n    optional: '(opcjonalne)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/pt_BR.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'pt-br',\n  Pagination: {\n    items_per_page: '/ página',\n    jump_to: 'Vá até',\n    jump_to_confirm: 'confirme',\n    page: 'Página',\n    prev_page: 'Página anterior',\n    next_page: 'Próxima página',\n    prev_5: '5 páginas anteriores',\n    next_5: '5 próximas páginas',\n    prev_3: '3 páginas anteriores',\n    next_3: '3 próximas páginas',\n    page_size: 'tamanho da página'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Selecionar data',\n      yearPlaceholder: 'Selecionar ano',\n      quarterPlaceholder: 'Selecionar trimestre',\n      monthPlaceholder: 'Selecionar mês',\n      weekPlaceholder: 'Selecionar semana',\n      rangePlaceholder: ['Data inicial', 'Data final'],\n      rangeYearPlaceholder: ['Ano inicial', 'Ano Final'],\n      rangeMonthPlaceholder: ['Mês inicial', 'Mês final'],\n      rangeWeekPlaceholder: ['Semana inicial', 'Semana final'],\n      locale: 'pt_BR',\n      today: 'Hoje',\n      now: 'Agora',\n      backToToday: 'Voltar para hoje',\n      ok: 'Ok',\n      clear: 'Limpar',\n      month: 'Mês',\n      year: 'Ano',\n      timeSelect: 'Selecionar hora',\n      dateSelect: 'Selecionar data',\n      weekSelect: 'Escolher semana',\n      monthSelect: 'Escolher mês',\n      yearSelect: 'Escolher ano',\n      decadeSelect: 'Escolher década',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: false,\n      previousMonth: 'Mês anterior (PageUp)',\n      nextMonth: 'Próximo mês (PageDown)',\n      previousYear: 'Ano anterior (Control + esquerda)',\n      nextYear: 'Próximo ano (Control + direita)',\n      previousDecade: 'Década anterior',\n      nextDecade: 'Próxima década',\n      previousCentury: 'Século anterior',\n      nextCentury: 'Próximo século',\n      shortWeekDays: ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'],\n      shortMonths: ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez']\n    },\n    timePickerLocale: {\n      placeholder: 'Hora',\n      rangePlaceholder: ['Hora inicial', 'Hora final']\n    }\n  },\n  TimePicker: {\n    placeholder: 'Hora',\n    rangePlaceholder: ['Hora inicial', 'Hora final']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Selecionar data',\n      yearPlaceholder: 'Selecionar ano',\n      quarterPlaceholder: 'Selecionar trimestre',\n      monthPlaceholder: 'Selecionar mês',\n      weekPlaceholder: 'Selecionar semana',\n      rangePlaceholder: ['Data inicial', 'Data final'],\n      rangeYearPlaceholder: ['Ano inicial', 'Ano Final'],\n      rangeMonthPlaceholder: ['Mês inicial', 'Mês final'],\n      rangeWeekPlaceholder: ['Semana inicial', 'Semana final'],\n      locale: 'pt_BR',\n      today: 'Hoje',\n      now: 'Agora',\n      backToToday: 'Voltar para hoje',\n      ok: 'Ok',\n      clear: 'Limpar',\n      month: 'Mês',\n      year: 'Ano',\n      timeSelect: 'Selecionar hora',\n      dateSelect: 'Selecionar data',\n      weekSelect: 'Escolher semana',\n      monthSelect: 'Escolher mês',\n      yearSelect: 'Escolher ano',\n      decadeSelect: 'Escolher década',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: false,\n      previousMonth: 'Mês anterior (PageUp)',\n      nextMonth: 'Próximo mês (PageDown)',\n      previousYear: 'Ano anterior (Control + esquerda)',\n      nextYear: 'Próximo ano (Control + direita)',\n      previousDecade: 'Década anterior',\n      nextDecade: 'Próxima década',\n      previousCentury: 'Século anterior',\n      nextCentury: 'Próximo século',\n      shortWeekDays: ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'],\n      shortMonths: ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez']\n    },\n    timePickerLocale: {\n      placeholder: 'Hora',\n      rangePlaceholder: ['Hora inicial', 'Hora final']\n    }\n  },\n  global: {\n    placeholder: 'Por favor escolha'\n  },\n  Table: {\n    filterTitle: 'Menu de Filtro',\n    filterConfirm: 'OK',\n    filterReset: 'Resetar',\n    filterEmptyText: 'Sem filtros',\n    emptyText: 'Sem conteúdo',\n    selectAll: 'Selecionar página atual',\n    selectInvert: 'Inverter seleção',\n    selectionAll: 'Selecionar todo o conteúdo',\n    sortTitle: 'Ordenar título',\n    expand: 'Expandir linha',\n    collapse: 'Colapsar linha',\n    triggerDesc: 'Clique organiza por descendente',\n    triggerAsc: 'Clique organiza por ascendente',\n    cancelSort: 'Clique para cancelar organização',\n    selectNone: 'Apagar todo o conteúdo'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Cancelar',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Cancelar'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'Procurar',\n    itemUnit: 'item',\n    itemsUnit: 'items',\n    remove: 'Remover',\n    selectCurrent: 'Selecionar página atual',\n    removeCurrent: 'Remover página atual',\n    selectAll: 'Selecionar todos',\n    removeAll: 'Remover todos',\n    selectInvert: 'Inverter seleção atual'\n  },\n  Upload: {\n    uploading: 'Enviando...',\n    removeFile: 'Remover arquivo',\n    uploadError: 'Erro no envio',\n    previewFile: 'Visualizar arquivo',\n    downloadFile: 'Baixar arquivo'\n  },\n  Empty: {\n    description: 'Não há dados'\n  },\n  Icon: {\n    icon: 'ícone'\n  },\n  Text: {\n    edit: 'editar',\n    copy: 'copiar',\n    copied: 'copiado',\n    expand: 'expandir'\n  },\n  PageHeader: {\n    back: 'Retornar'\n  },\n  Image: {\n    preview: 'Pré-visualização'\n  },\n  CronExpression: {\n    cronError: 'Erro verifique as informações',\n    second: 'Segundo',\n    minute: 'Minuto',\n    hour: 'Hora',\n    day: 'Dia',\n    month: 'Mês',\n    week: 'Semana'\n  },\n  Form: {\n    optional: '(opcional)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/pt_PT.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'pt',\n  Pagination: {\n    items_per_page: '/ página',\n    jump_to: 'Saltar',\n    jump_to_confirm: 'confirmar',\n    page: 'Página',\n    prev_page: 'Página Anterior',\n    next_page: 'Página Seguinte',\n    prev_5: 'Recuar 5 Páginas',\n    next_5: 'Avançar 5 Páginas',\n    prev_3: 'Recuar 3 Páginas',\n    next_3: 'Avançar 3 Páginas',\n    page_size: 'mărimea paginii'\n  },\n  DatePicker: {\n    lang: {\n      yearPlaceholder: 'Selecionar ano',\n      quarterPlaceholder: 'Selecionar trimestre',\n      monthPlaceholder: 'Selecionar mês',\n      weekPlaceholder: 'Selecionar semana',\n      rangePlaceholder: ['Data inicial', 'Data final'],\n      rangeYearPlaceholder: ['Ano inicial', 'Ano final'],\n      rangeMonthPlaceholder: ['Mês inicial', 'Mês final'],\n      rangeWeekPlaceholder: ['Semana inicial', 'Semana final'],\n      locale: 'pt_PT',\n      today: 'Hoje',\n      now: 'Agora',\n      backToToday: 'Hoje',\n      ok: 'OK',\n      clear: 'Limpar',\n      month: 'Mês',\n      year: 'Ano',\n      timeSelect: 'Hora',\n      dateSelect: 'Selecionar data',\n      monthSelect: 'Selecionar mês',\n      yearSelect: 'Selecionar ano',\n      decadeSelect: 'Selecionar década',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: false,\n      previousMonth: 'Mês anterior (PageUp)',\n      nextMonth: 'Mês seguinte (PageDown)',\n      previousYear: 'Ano anterior (Control + left)',\n      nextYear: 'Ano seguinte (Control + right)',\n      previousDecade: 'Última década',\n      nextDecade: 'Próxima década',\n      previousCentury: 'Último século',\n      nextCentury: 'Próximo século',\n      placeholder: 'Data',\n      monthFormat: 'MMMM'\n    },\n    timePickerLocale: {\n      placeholder: 'Hora'\n    }\n  },\n  TimePicker: {\n    placeholder: 'Hora'\n  },\n  Calendar: {\n    lang: {\n      locale: 'pt_PT',\n      today: 'Hoje',\n      now: 'Agora',\n      backToToday: 'Hoje',\n      ok: 'OK',\n      clear: 'Limpar',\n      month: 'Mês',\n      year: 'Ano',\n      timeSelect: 'Hora',\n      dateSelect: 'Selecionar data',\n      monthSelect: 'Selecionar mês',\n      yearSelect: 'Selecionar ano',\n      decadeSelect: 'Selecionar década',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: false,\n      previousMonth: 'Mês anterior (PageUp)',\n      nextMonth: 'Mês seguinte (PageDown)',\n      previousYear: 'Ano anterior (Control + left)',\n      nextYear: 'Ano seguinte (Control + right)',\n      previousDecade: 'Última década',\n      nextDecade: 'Próxima década',\n      previousCentury: 'Último século',\n      nextCentury: 'Próximo século',\n      placeholder: 'Data',\n      rangePlaceholder: ['Data inicial', 'Data final'],\n      monthFormat: 'MMMM'\n    },\n    timePickerLocale: {\n      placeholder: 'Hora'\n    }\n  },\n  Table: {\n    filterTitle: 'Filtro',\n    filterConfirm: 'Aplicar',\n    filterReset: 'Reiniciar',\n    selectAll: 'Selecionar página atual',\n    selectInvert: 'Inverter seleção',\n    sortTitle: 'Ordenação'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Cancelar',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Cancelar'\n  },\n  Transfer: {\n    searchPlaceholder: 'Procurar...',\n    itemUnit: 'item',\n    itemsUnit: 'itens'\n  },\n  Upload: {\n    uploading: 'A carregar...',\n    removeFile: 'Remover',\n    uploadError: 'Erro ao carregar',\n    previewFile: 'Pré-visualizar',\n    downloadFile: 'Baixar'\n  },\n  Empty: {\n    description: 'Sem resultados'\n  },\n  Form: {\n    optional: '(opcional)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/ro_RO.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'ro',\n  Pagination: {\n    items_per_page: '/ pagină',\n    jump_to: 'Mergi la',\n    jump_to_confirm: 'confirm',\n    page: '',\n    prev_page: 'Pagina Anterioară',\n    next_page: 'Pagina Următoare',\n    prev_5: '5 Pagini Anterioare',\n    next_5: '5 Pagini Următoare',\n    prev_3: '3 Pagini Anterioare',\n    next_3: '3 Pagini Următoare',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Selectează data',\n      rangePlaceholder: ['Data start', 'Data sfârșit'],\n      locale: 'ro_RO',\n      today: 'Azi',\n      now: 'Acum',\n      backToToday: 'Înapoi la azi',\n      ok: 'Ok',\n      clear: 'Șterge',\n      month: 'Lună',\n      year: 'An',\n      timeSelect: 'selectează timpul',\n      dateSelect: 'selectează data',\n      weekSelect: 'Alege o săptămână',\n      monthSelect: 'Alege o lună',\n      yearSelect: 'Alege un an',\n      decadeSelect: 'Alege un deceniu',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Luna anterioară (PageUp)',\n      nextMonth: 'Luna următoare (PageDown)',\n      previousYear: 'Anul anterior (Control + stânga)',\n      nextYear: 'Anul următor (Control + dreapta)',\n      previousDecade: 'Deceniul anterior',\n      nextDecade: 'Deceniul următor',\n      previousCentury: 'Secolul anterior',\n      nextCentury: 'Secolul următor'\n    },\n    timePickerLocale: {\n      placeholder: 'Selectează ora'\n    }\n  },\n  TimePicker: {\n    placeholder: 'Selectează ora'\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Selectează data',\n      rangePlaceholder: ['Data start', 'Data sfârșit'],\n      locale: 'ro_RO',\n      today: 'Azi',\n      now: 'Acum',\n      backToToday: 'Înapoi la azi',\n      ok: 'Ok',\n      clear: 'Șterge',\n      month: 'Lună',\n      year: 'An',\n      timeSelect: 'selectează timpul',\n      dateSelect: 'selectează data',\n      weekSelect: 'Alege o săptămână',\n      monthSelect: 'Alege o lună',\n      yearSelect: 'Alege un an',\n      decadeSelect: 'Alege un deceniu',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Luna anterioară (PageUp)',\n      nextMonth: 'Luna următoare (PageDown)',\n      previousYear: 'Anul anterior (Control + stânga)',\n      nextYear: 'Anul următor (Control + dreapta)',\n      previousDecade: 'Deceniul anterior',\n      nextDecade: 'Deceniul următor',\n      previousCentury: 'Secolul anterior',\n      nextCentury: 'Secolul următor'\n    },\n    timePickerLocale: {\n      placeholder: 'Selectează ora'\n    }\n  },\n  global: {\n    placeholder: 'Selectează'\n  },\n  Table: {\n    filterTitle: 'Filtrează',\n    filterConfirm: 'OK',\n    filterReset: 'Resetează',\n    selectAll: 'Selectează pagina curentă',\n    selectInvert: 'Inversează pagina curentă',\n    sortTitle: 'Ordonează',\n    expand: 'Extinde rândul',\n    collapse: 'Micșorează rândul',\n    filterEmptyText: 'Fără filtre',\n    emptyText: 'Nu există date',\n    selectNone: 'Șterge selecția',\n    selectionAll: 'Selectează toate datele',\n    triggerDesc: 'Apasă pentru ordonare descrescătoare',\n    triggerAsc: 'Apasă pentru ordonare crescătoare',\n    cancelSort: 'Apasă pentru a anula ordonarea'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Anulare',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Anulare'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'Căutare',\n    itemUnit: 'element',\n    itemsUnit: 'elemente',\n    remove: 'Șterge',\n    selectCurrent: 'Selectează pagina curentă',\n    removeCurrent: 'Șterge pagina curentă',\n    selectAll: 'Selectează toate datele',\n    removeAll: 'Șterge toate datele',\n    selectInvert: 'Inversează pagina curentă'\n  },\n  Upload: {\n    uploading: 'Se transferă...',\n    removeFile: 'Înlătură fișierul',\n    uploadError: 'Eroare la upload',\n    previewFile: 'Previzualizare fișier',\n    downloadFile: 'Descărcare fișier'\n  },\n  Empty: {\n    description: 'Fără date'\n  },\n  Icon: {\n    icon: 'icon'\n  },\n  Text: {\n    edit: 'editează',\n    copy: 'copiază',\n    copied: 'copiat',\n    expand: 'extinde'\n  },\n  PageHeader: {\n    back: 'înapoi'\n  },\n  Image: {\n    preview: 'Preview'\n  },\n  Form: {\n    optional: '(opțional)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/ru_RU.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'ru',\n  Pagination: {\n    items_per_page: '/ стр.',\n    jump_to: 'Перейти',\n    jump_to_confirm: 'подтвердить',\n    page: 'Страница',\n    prev_page: 'Назад',\n    next_page: 'Вперед',\n    prev_5: 'Предыдущие 5',\n    next_5: 'Следующие 5',\n    prev_3: 'Предыдущие 3',\n    next_3: 'Следующие 3',\n    page_size: 'размер страницы'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Выберите дату',\n      yearPlaceholder: 'Выберите год',\n      quarterPlaceholder: 'Выберите квартал',\n      monthPlaceholder: 'Выберите месяц',\n      weekPlaceholder: 'Выберите неделю',\n      rangePlaceholder: ['Начальная дата', 'Конечная дата'],\n      rangeYearPlaceholder: ['Начальный год', 'Год окончания'],\n      rangeMonthPlaceholder: ['Начальный месяц', 'Конечный месяц'],\n      rangeWeekPlaceholder: ['Начальная неделя', 'Конечная неделя'],\n      locale: 'ru_RU',\n      today: 'Сегодня',\n      now: 'Сейчас',\n      backToToday: 'Текущая дата',\n      ok: 'ОК',\n      clear: 'Очистить',\n      month: 'Месяц',\n      year: 'Год',\n      timeSelect: 'Выбрать время',\n      dateSelect: 'Выбрать дату',\n      monthSelect: 'Выбрать месяц',\n      yearSelect: 'Выбрать год',\n      decadeSelect: 'Выбрать десятилетие',\n      yearFormat: 'YYYY',\n      dateFormat: 'D-M-YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D-M-YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Предыдущий месяц (PageUp)',\n      nextMonth: 'Следующий месяц (PageDown)',\n      previousYear: 'Предыдущий год (Control + left)',\n      nextYear: 'Следующий год (Control + right)',\n      previousDecade: 'Предыдущее десятилетие',\n      nextDecade: 'Следущее десятилетие',\n      previousCentury: 'Предыдущий век',\n      nextCentury: 'Следующий век'\n    },\n    timePickerLocale: {\n      placeholder: 'Выберите время',\n      rangePlaceholder: ['Время начала', 'Время окончания']\n    }\n  },\n  TimePicker: {\n    placeholder: 'Выберите время',\n    rangePlaceholder: ['Время начала', 'Время окончания']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Выберите дату',\n      yearPlaceholder: 'Выберите год',\n      quarterPlaceholder: 'Выберите квартал',\n      monthPlaceholder: 'Выберите месяц',\n      weekPlaceholder: 'Выберите неделю',\n      rangePlaceholder: ['Начальная дата', 'Конечная дата'],\n      rangeYearPlaceholder: ['Начальный год', 'Год окончания'],\n      rangeMonthPlaceholder: ['Начальный месяц', 'Конечный месяц'],\n      rangeWeekPlaceholder: ['Начальная неделя', 'Конечная неделя'],\n      locale: 'ru_RU',\n      today: 'Сегодня',\n      now: 'Сейчас',\n      backToToday: 'Текущая дата',\n      ok: 'ОК',\n      clear: 'Очистить',\n      month: 'Месяц',\n      year: 'Год',\n      timeSelect: 'Выбрать время',\n      dateSelect: 'Выбрать дату',\n      monthSelect: 'Выбрать месяц',\n      yearSelect: 'Выбрать год',\n      decadeSelect: 'Выбрать десятилетие',\n      yearFormat: 'YYYY',\n      dateFormat: 'D-M-YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D-M-YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Предыдущий месяц (PageUp)',\n      nextMonth: 'Следующий месяц (PageDown)',\n      previousYear: 'Предыдущий год (Control + left)',\n      nextYear: 'Следующий год (Control + right)',\n      previousDecade: 'Предыдущее десятилетие',\n      nextDecade: 'Следущее десятилетие',\n      previousCentury: 'Предыдущий век',\n      nextCentury: 'Следующий век'\n    },\n    timePickerLocale: {\n      placeholder: 'Выберите время',\n      rangePlaceholder: ['Время начала', 'Время окончания']\n    }\n  },\n  global: {\n    placeholder: 'Пожалуйста выберите'\n  },\n  Table: {\n    filterTitle: 'Фильтр',\n    filterConfirm: 'OK',\n    filterReset: 'Сбросить',\n    filterEmptyText: 'Без фильтров',\n    emptyText: 'Нет данных',\n    selectAll: 'Выбрать всё',\n    selectInvert: 'Инвертировать выбор',\n    selectionAll: 'Выбрать все данные',\n    sortTitle: 'Сортировка',\n    expand: 'Развернуть строку',\n    collapse: 'Свернуть строку',\n    triggerDesc: 'Нажмите для сортировки по убыванию',\n    triggerAsc: 'Нажмите для сортировки по возрастанию',\n    cancelSort: 'Нажмите, чтобы отменить сортировку',\n    selectNone: 'Очистить все данные'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Отмена',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Отмена'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'Поиск',\n    itemUnit: 'элем.',\n    itemsUnit: 'элем.',\n    remove: 'Удалить',\n    selectAll: 'Выбрать все данные',\n    selectCurrent: 'Выбрать текущую страницу',\n    selectInvert: 'Показать в обратном порядке',\n    removeAll: 'Удалить все данные',\n    removeCurrent: 'Удалить текущую страницу'\n  },\n  Upload: {\n    uploading: 'Загрузка...',\n    removeFile: 'Удалить файл',\n    uploadError: 'При загрузке произошла ошибка',\n    previewFile: 'Предпросмотр файла',\n    downloadFile: 'Загрузить файл'\n  },\n  Empty: {\n    description: 'Нет данных'\n  },\n  Icon: {\n    icon: 'иконка'\n  },\n  Text: {\n    edit: 'Редактировать',\n    copy: 'Копировать',\n    copied: 'Скопировано',\n    expand: 'Раскрыть'\n  },\n  PageHeader: {\n    back: 'Назад'\n  },\n  Image: {\n    preview: 'Предпросмотр'\n  },\n  Form: {\n    optional: '(необязательно)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/sk_SK.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'sk',\n  Pagination: {\n    items_per_page: '/ strana',\n    jump_to: 'Choď na',\n    jump_to_confirm: 'potvrdiť',\n    page: 'strana',\n    prev_page: 'Predchádzajúca strana',\n    next_page: 'Nasledujúca strana',\n    prev_5: 'Predchádzajúcich 5 strán',\n    next_5: 'Nasledujúcich 5 strán',\n    prev_3: 'Predchádzajúce 3 strany',\n    next_3: 'Nasledujúce 3 strany',\n    page_size: 'Veľkosť strany'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Vybrať dátum',\n      yearPlaceholder: 'Vybrať rok',\n      quarterPlaceholder: 'Vybrať štvrťrok',\n      monthPlaceholder: 'Vybrať mesiac',\n      weekPlaceholder: 'Vybrať týždeň',\n      rangePlaceholder: ['Od', 'Do'],\n      rangeYearPlaceholder: ['Začiatočný rok', 'Koncový rok'],\n      rangeQuarterPlaceholder: ['Začiatočný štvrťrok', 'Koncový štvrťrok'],\n      rangeMonthPlaceholder: ['Začiatočný mesiac', 'Koncový mesiac'],\n      rangeWeekPlaceholder: ['Začiatočný týždeň', 'Koncový týždeň'],\n      locale: 'sk_SK',\n      today: 'Dnes',\n      now: 'Teraz',\n      backToToday: 'Späť na dnes',\n      ok: 'Ok',\n      clear: 'Vymazať',\n      month: 'Mesiac',\n      year: 'Rok',\n      timeSelect: 'Vybrať čas',\n      dateSelect: 'Vybrať dátum',\n      weekSelect: 'Vybrať týždeň',\n      monthSelect: 'Vybrať mesiac',\n      yearSelect: 'Vybrať rok',\n      decadeSelect: 'Vybrať dekádu',\n      yearFormat: 'YYYY',\n      dateFormat: 'D.M.YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D.M.YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Predchádzajúci mesiac (PageUp)',\n      nextMonth: 'Nasledujúci mesiac (PageDown)',\n      previousYear: 'Predchádzajúci rok (Control + left)',\n      nextYear: 'Nasledujúci rok (Control + right)',\n      previousDecade: 'Predchádzajúca dekáda',\n      nextDecade: 'Nasledujúca dekáda',\n      previousCentury: 'Predchádzajúce storočie',\n      nextCentury: 'Nasledujúce storočie'\n    },\n    timePickerLocale: {\n      placeholder: 'Vybrať čas',\n      rangePlaceholder: ['Začiatočný čas', 'Koncový čas']\n    }\n  },\n  TimePicker: {\n    placeholder: 'Vybrať čas',\n    rangePlaceholder: ['Začiatočný čas', 'Koncový čas']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Vybrať dátum',\n      yearPlaceholder: 'Vybrať rok',\n      quarterPlaceholder: 'Vybrať štvrťrok',\n      monthPlaceholder: 'Vybrať mesiac',\n      weekPlaceholder: 'Vybrať týždeň',\n      rangePlaceholder: ['Od', 'Do'],\n      rangeYearPlaceholder: ['Začiatočný rok', 'Koncový rok'],\n      rangeMonthPlaceholder: ['Začiatočný mesiac', 'Koncový mesiac'],\n      rangeWeekPlaceholder: ['Začiatočný týždeň', 'Koncový týždeň'],\n      locale: 'sk_SK',\n      today: 'Dnes',\n      now: 'Teraz',\n      backToToday: 'Späť na dnes',\n      ok: 'Ok',\n      clear: 'Vymazať',\n      month: 'Mesiac',\n      year: 'Rok',\n      timeSelect: 'Vybrať čas',\n      dateSelect: 'Vybrať dátum',\n      weekSelect: 'Vybrať týždeň',\n      monthSelect: 'Vybrať mesiac',\n      yearSelect: 'Vybrať rok',\n      decadeSelect: 'Vybrať dekádu',\n      yearFormat: 'YYYY',\n      dateFormat: 'D.M.YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D.M.YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Predchádzajúci mesiac (PageUp)',\n      nextMonth: 'Nasledujúci mesiac (PageDown)',\n      previousYear: 'Predchádzajúci rok (Control + left)',\n      nextYear: 'Nasledujúci rok (Control + right)',\n      previousDecade: 'Predchádzajúca dekáda',\n      nextDecade: 'Nasledujúca dekáda',\n      previousCentury: 'Predchádzajúce storočie',\n      nextCentury: 'Nasledujúce storočie'\n    },\n    timePickerLocale: {\n      placeholder: 'Vybrať čas',\n      rangePlaceholder: ['Začiatočný čas', 'Koncový čas']\n    }\n  },\n  global: {\n    placeholder: 'Prosím vyberte'\n  },\n  Table: {\n    filterTitle: 'Filter',\n    filterConfirm: 'OK',\n    filterReset: 'Obnoviť',\n    filterEmptyText: 'Žiadne filtre',\n    emptyText: 'Žiadne dáta',\n    selectAll: 'Vybrať všetko',\n    selectInvert: 'Vybrať opačné',\n    selectionAll: 'Vybrať všetky dáta',\n    sortTitle: 'Zoradiť',\n    expand: 'Rozbaliť riadok',\n    collapse: 'Zbaliť riadok',\n    triggerDesc: 'Kliknite pre zoradenie zostupne',\n    triggerAsc: 'Kliknite pre zoradenie vzostupne',\n    cancelSort: 'Kliknite pre zrušenie zoradenia',\n    filterCheckall: 'Vybrať všetky položky',\n    filterSearchPlaceholder: 'Hľadať vo filtroch',\n    selectNone: 'Zrušiť výber všetkých dát'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Zrušiť',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Zrušiť'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'Vyhľadávanie',\n    itemUnit: 'položka',\n    itemsUnit: 'položiek',\n    remove: 'Odstrániť',\n    selectCurrent: 'Vybrať aktuálnu stranu',\n    removeCurrent: 'Odstrániť aktuálnu stranu',\n    selectAll: 'Vybrať všetky dáta',\n    removeAll: 'Odstrániť všetky dáta',\n    selectInvert: 'Invertovať aktuálnu stranu'\n  },\n  Upload: {\n    uploading: 'Nahrávanie...',\n    removeFile: 'Odstrániť súbor',\n    uploadError: 'Chyba pri nahrávaní',\n    previewFile: 'Zobraziť súbor',\n    downloadFile: 'Stiahnuť súbor'\n  },\n  Empty: {\n    description: 'Žiadne dáta'\n  },\n  Icon: {\n    icon: 'ikona'\n  },\n  Text: {\n    edit: 'Upraviť',\n    copy: 'Kopírovať',\n    copied: 'Skopírované',\n    expand: 'Zväčšiť'\n  },\n  PageHeader: {\n    back: 'Späť'\n  },\n  Image: {\n    preview: 'Náhľad'\n  },\n  Form: {\n    optional: '(nepovinné)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/sl_SI.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'sl',\n  Pagination: {\n    items_per_page: '/ strani',\n    jump_to: 'Pojdi na',\n    jump_to_confirm: 'potrdi',\n    page: '',\n    prev_page: 'Prejšnja stran',\n    next_page: 'Naslednja stran',\n    prev_5: 'Prejšnjih 5 strani',\n    next_5: 'Naslednjih 5 strani',\n    prev_3: 'Prejšnje 3 strani',\n    next_3: 'Naslednje 3 strani',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      locale: 'sl',\n      placeholder: 'Izberite datum',\n      rangePlaceholder: ['Začetni datum', 'Končni datum'],\n      today: 'Danes',\n      now: 'Trenutno',\n      backToToday: 'Nazaj na trenutni datum',\n      ok: 'OK',\n      clear: 'Počisti',\n      month: 'Mesec',\n      year: 'Leto',\n      timeSelect: 'Izberi čas',\n      dateSelect: 'Izberi datum',\n      monthSelect: 'Izberite mesec',\n      yearSelect: 'Izberite leto',\n      decadeSelect: 'Izberite desetletje',\n      yearFormat: 'YYYY',\n      dateFormat: 'D.M.YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D.M.YYYY HH:mm:ss',\n      monthFormat: 'MMMM',\n      monthBeforeYear: true,\n      previousMonth: 'Prejšnji mesec (PageUp)',\n      nextMonth: 'Naslednji mesec (PageDown)',\n      previousYear: 'Lansko leto (Control + left)',\n      nextYear: 'Naslednje leto (Control + right)',\n      previousDecade: 'Prejšnje desetletje',\n      nextDecade: 'Naslednje desetletje',\n      previousCentury: 'Zadnje stoletje',\n      nextCentury: 'Naslednje stoletje'\n    },\n    timePickerLocale: {\n      placeholder: 'Izberite čas'\n    }\n  },\n  TimePicker: {\n    placeholder: 'Izberite čas'\n  },\n  Calendar: {\n    lang: {\n      locale: 'sl',\n      placeholder: 'Izberite datum',\n      rangePlaceholder: ['Začetni datum', 'Končni datum'],\n      today: 'Danes',\n      now: 'Trenutno',\n      backToToday: 'Nazaj na trenutni datum',\n      ok: 'OK',\n      clear: 'Počisti',\n      month: 'Mesec',\n      year: 'Leto',\n      timeSelect: 'Izberi čas',\n      dateSelect: 'Izberi datum',\n      monthSelect: 'Izberite mesec',\n      yearSelect: 'Izberite leto',\n      decadeSelect: 'Izberite desetletje',\n      yearFormat: 'YYYY',\n      dateFormat: 'D.M.YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D.M.YYYY HH:mm:ss',\n      monthFormat: 'MMMM',\n      monthBeforeYear: true,\n      previousMonth: 'Prejšnji mesec (PageUp)',\n      nextMonth: 'Naslednji mesec (PageDown)',\n      previousYear: 'Lansko leto (Control + left)',\n      nextYear: 'Naslednje leto (Control + right)',\n      previousDecade: 'Prejšnje desetletje',\n      nextDecade: 'Naslednje desetletje',\n      previousCentury: 'Zadnje stoletje',\n      nextCentury: 'Naslednje stoletje'\n    },\n    timePickerLocale: {\n      placeholder: 'Izberite čas'\n    }\n  },\n  Table: {\n    filterTitle: 'Filter',\n    filterConfirm: 'Filtriraj',\n    filterReset: 'Pobriši filter',\n    selectAll: 'Izberi vse na trenutni strani',\n    selectInvert: 'Obrni izbor na trenutni strani'\n  },\n  Modal: {\n    okText: 'V redu',\n    cancelText: 'Prekliči',\n    justOkText: 'V redu'\n  },\n  Popconfirm: {\n    okText: 'v redu',\n    cancelText: 'Prekliči'\n  },\n  Transfer: {\n    searchPlaceholder: 'Išči tukaj',\n    itemUnit: 'Objekt',\n    itemsUnit: 'Objektov'\n  },\n  Upload: {\n    uploading: 'Nalaganje...',\n    removeFile: 'Odstrani datoteko',\n    uploadError: 'Napaka pri nalaganju',\n    previewFile: 'Predogled datoteke',\n    downloadFile: 'Prenos datoteke'\n  },\n  Empty: {\n    description: 'Ni podatkov'\n  },\n  Form: {\n    optional: '(neobvezen)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/sr_RS.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'sr',\n  Pagination: {\n    items_per_page: '/ strani',\n    jump_to: 'Idi na',\n    page: '',\n    prev_page: 'Prethodna strana',\n    next_page: 'Sledeća strana',\n    prev_5: 'Prethodnih 5 Strana',\n    next_5: 'Sledećih 5 Strana',\n    prev_3: 'Prethodnih 3 Strane',\n    next_3: 'Sledećih 3 Strane',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Izaberi datum',\n      rangePlaceholder: ['Datum početka', 'Datum završetka'],\n      locale: 'sr_RS',\n      today: 'Danas',\n      now: 'Sada',\n      backToToday: 'Vrati se na danas',\n      ok: 'U redu',\n      clear: 'Obriši',\n      month: 'Mesec',\n      year: 'Godina',\n      timeSelect: 'Izaberi vreme',\n      dateSelect: 'Izaberi datum',\n      monthSelect: 'Izaberi mesec',\n      yearSelect: 'Izaberi godinu',\n      decadeSelect: 'Izaberi deceniju',\n      yearFormat: 'YYYY',\n      dateFormat: 'DD.MM.YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'DD.MM.YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Prethodni mesec (PageUp)',\n      nextMonth: 'Sledeći mesec (PageDown)',\n      previousYear: 'Prethodna godina (Control + left)',\n      nextYear: 'Sledeća godina (Control + right)',\n      previousDecade: 'Prethodna decenija',\n      nextDecade: 'Sledeća decenija',\n      previousCentury: 'Prethodni vek',\n      nextCentury: 'Sledeći vek',\n      yearPlaceholder: 'Izaberi godinu',\n      quarterPlaceholder: 'Izaberi tromesečje',\n      monthPlaceholder: 'Izaberi mesec',\n      weekPlaceholder: 'Izaberi sedmicu',\n      rangeYearPlaceholder: ['Godina početka', 'Godina završetka'],\n      rangeMonthPlaceholder: ['Mesec početka', 'Mesec završetka'],\n      rangeWeekPlaceholder: ['Sedmica početka', 'Sedmica završetka']\n    },\n    timePickerLocale: {\n      placeholder: 'Izaberi vreme',\n      rangePlaceholder: ['Vreme početka', 'Vreme završetka']\n    }\n  },\n  TimePicker: {\n    placeholder: 'Izaberi vreme',\n    rangePlaceholder: ['Vreme početka', 'Vreme završetka']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Izaberi datum',\n      rangePlaceholder: ['Datum početka', 'Datum završetka'],\n      locale: 'sr_RS',\n      today: 'Danas',\n      now: 'Sada',\n      backToToday: 'Vrati se na danas',\n      ok: 'U redu',\n      clear: 'Obriši',\n      month: 'Mesec',\n      year: 'Godina',\n      timeSelect: 'Izaberi vreme',\n      dateSelect: 'Izaberi datum',\n      monthSelect: 'Izaberi mesec',\n      yearSelect: 'Izaberi godinu',\n      decadeSelect: 'Izaberi deceniju',\n      yearFormat: 'YYYY',\n      dateFormat: 'DD.MM.YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'DD.MM.YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Prethodni mesec (PageUp)',\n      nextMonth: 'Sledeći mesec (PageDown)',\n      previousYear: 'Prethodna godina (Control + left)',\n      nextYear: 'Sledeća godina (Control + right)',\n      previousDecade: 'Prethodna decenija',\n      nextDecade: 'Sledeća decenija',\n      previousCentury: 'Prethodni vek',\n      nextCentury: 'Sledeći vek',\n      yearPlaceholder: 'Izaberi godinu',\n      quarterPlaceholder: 'Izaberi tromesečje',\n      monthPlaceholder: 'Izaberi mesec',\n      weekPlaceholder: 'Izaberi sedmicu',\n      rangeYearPlaceholder: ['Godina početka', 'Godina završetka'],\n      rangeMonthPlaceholder: ['Mesec početka', 'Mesec završetka'],\n      rangeWeekPlaceholder: ['Sedmica početka', 'Sedmica završetka']\n    },\n    timePickerLocale: {\n      placeholder: 'Izaberi vreme',\n      rangePlaceholder: ['Vreme početka', 'Vreme završetka']\n    }\n  },\n  Table: {\n    filterTitle: 'Meni filtera',\n    filterConfirm: 'U redu',\n    filterReset: 'Poništi',\n    selectAll: 'Izaberi trenutnu stranicu',\n    selectInvert: 'Obrni izbor trenutne stranice',\n    filterEmptyText: 'Nema filtera',\n    emptyText: 'Nema podataka',\n    selectNone: 'Obriši sve podatke',\n    selectionAll: 'Izaberi sve podatke',\n    sortTitle: 'Sortiraj',\n    expand: 'Proširi red',\n    collapse: 'Skupi red',\n    triggerDesc: 'Klikni da sortiraš po padajućem redosledu',\n    triggerAsc: 'Klikni da sortiraš po rastućem redosledu',\n    cancelSort: 'Klikni da otkažeš sortiranje'\n  },\n  Modal: {\n    okText: 'U redu',\n    cancelText: 'Otkaži',\n    justOkText: 'U redu'\n  },\n  Popconfirm: {\n    okText: 'U redu',\n    cancelText: 'Otkaži'\n  },\n  Transfer: {\n    searchPlaceholder: 'Pretraži ovde',\n    itemUnit: 'stavka',\n    itemsUnit: 'stavki',\n    titles: ['', ''],\n    remove: 'Ukloni',\n    selectCurrent: 'Izaberi trenutnu stranicu',\n    removeCurrent: 'Ukloni trenutnu stranicu',\n    selectAll: 'Izaberi sve podatke',\n    removeAll: 'Ukloni sve podatke',\n    selectInvert: 'Obrni izbor trenutne stranice'\n  },\n  Upload: {\n    uploading: 'Otpremanje...',\n    removeFile: 'Ukloni datoteku',\n    uploadError: 'Greška pri otpremanju',\n    previewFile: 'Pregledaj datoteku',\n    downloadFile: 'Preuzmi datoteku'\n  },\n  Empty: {\n    description: 'Nema podataka'\n  },\n  global: {\n    placeholder: 'Izaberi'\n  },\n  Icon: {\n    icon: 'ikona'\n  },\n  Text: {\n    edit: 'Uredi',\n    copy: 'Kopiraj',\n    copied: 'Kopirano',\n    expand: 'Proširi'\n  },\n  PageHeader: {\n    back: 'Nazad'\n  },\n  Image: {\n    preview: 'Pregled'\n  },\n  Form: {\n    optional: '(neobavezno)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/sv_SE.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'sv',\n  Pagination: {\n    items_per_page: '/ sida',\n    jump_to: 'Gå till',\n    jump_to_confirm: 'bekräfta',\n    page: 'Sida',\n    prev_page: 'Föreg sida',\n    next_page: 'Nästa sida',\n    prev_5: 'Föreg 5 sidor',\n    next_5: 'Nästa 5 sidor',\n    prev_3: 'Föreg 3 sidor',\n    next_3: 'Nästa 3 sidor',\n    page_size: 'sidstorlek'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Välj datum',\n      rangePlaceholder: ['Startdatum', 'Slutdatum'],\n      locale: 'sv_SE',\n      today: 'I dag',\n      now: 'Nu',\n      backToToday: 'Till idag',\n      ok: 'Ok',\n      clear: 'Avbryt',\n      month: 'Månad',\n      year: 'År',\n      timeSelect: 'Välj tidpunkt',\n      dateSelect: 'Välj datum',\n      monthSelect: 'Välj månad',\n      yearSelect: 'Välj år',\n      decadeSelect: 'Välj årtionde',\n      yearFormat: 'YYYY',\n      dateFormat: 'YYYY-MM-DD',\n      dayFormat: 'D',\n      dateTimeFormat: 'YYYY-MM-DD H:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Förra månaden (PageUp)',\n      nextMonth: 'Nästa månad (PageDown)',\n      previousYear: 'Föreg år (Control + left)',\n      nextYear: 'Nästa år (Control + right)',\n      previousDecade: 'Föreg årtionde',\n      nextDecade: 'Nästa årtionde',\n      previousCentury: 'Föreg århundrade',\n      nextCentury: 'Nästa århundrade',\n      yearPlaceholder: 'Välj år',\n      quarterPlaceholder: 'Välj kvartal',\n      monthPlaceholder: 'Välj månad',\n      weekPlaceholder: 'Välj vecka',\n      rangeYearPlaceholder: ['Startår', 'Slutår'],\n      rangeMonthPlaceholder: ['Startmånad', 'Slutmånad'],\n      rangeWeekPlaceholder: ['Startvecka', 'Slutvecka']\n    },\n    timePickerLocale: {\n      placeholder: 'Välj tid'\n    }\n  },\n  TimePicker: {\n    placeholder: 'Välj tid'\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Välj datum',\n      rangePlaceholder: ['Startdatum', 'Slutdatum'],\n      locale: 'sv_SE',\n      today: 'I dag',\n      now: 'Nu',\n      backToToday: 'Till idag',\n      ok: 'Ok',\n      clear: 'Avbryt',\n      month: 'Månad',\n      year: 'År',\n      timeSelect: 'Välj tidpunkt',\n      dateSelect: 'Välj datum',\n      monthSelect: 'Välj månad',\n      yearSelect: 'Välj år',\n      decadeSelect: 'Välj årtionde',\n      yearFormat: 'YYYY',\n      dateFormat: 'YYYY-MM-DD',\n      dayFormat: 'D',\n      dateTimeFormat: 'YYYY-MM-DD H:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Förra månaden (PageUp)',\n      nextMonth: 'Nästa månad (PageDown)',\n      previousYear: 'Föreg år (Control + left)',\n      nextYear: 'Nästa år (Control + right)',\n      previousDecade: 'Föreg årtionde',\n      nextDecade: 'Nästa årtionde',\n      previousCentury: 'Föreg århundrade',\n      nextCentury: 'Nästa århundrade',\n      yearPlaceholder: 'Välj år',\n      quarterPlaceholder: 'Välj kvartal',\n      monthPlaceholder: 'Välj månad',\n      weekPlaceholder: 'Välj vecka',\n      rangeYearPlaceholder: ['Startår', 'Slutår'],\n      rangeMonthPlaceholder: ['Startmånad', 'Slutmånad'],\n      rangeWeekPlaceholder: ['Startvecka', 'Slutvecka']\n    },\n    timePickerLocale: {\n      placeholder: 'Välj tid'\n    }\n  },\n  Table: {\n    filterTitle: 'Filtermeny',\n    filterConfirm: 'OK',\n    filterReset: 'Återställ',\n    filterEmptyText: 'Inga filter',\n    emptyText: 'Ingen data',\n    selectAll: 'Markera nuvarande sida',\n    selectInvert: 'Invertera nuvarande sida',\n    selectNone: 'Avmarkera all data',\n    selectionAll: 'Markera all data',\n    sortTitle: 'Sortera',\n    expand: 'Expandera rad',\n    collapse: 'Komprimera rad',\n    triggerDesc: 'Klicka för att sortera i fallande ordning',\n    triggerAsc: 'Klicka för att sortera i stigande ordning',\n    cancelSort: 'Klicka för att avbryta sortering'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Avbryt',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Avbryt'\n  },\n  Transfer: {\n    searchPlaceholder: 'Sök här',\n    itemUnit: 'objekt',\n    itemsUnit: 'objekt',\n    titles: ['', ''],\n    remove: 'Ta bort',\n    selectCurrent: 'Markera nuvarande sida',\n    removeCurrent: 'Ta bort nuvarande sida',\n    selectAll: 'Markera all data',\n    removeAll: 'Ta bort all data',\n    selectInvert: 'Invertera nuvarande sida'\n  },\n  Empty: {\n    description: 'Ingen data'\n  },\n  Text: {\n    edit: 'Redigera',\n    copy: 'Kopiera',\n    copied: 'Kopierad',\n    expand: 'Expandera'\n  },\n  Upload: {\n    uploading: 'Laddar upp...',\n    removeFile: 'Ta bort fil',\n    uploadError: 'Uppladdningsfel',\n    previewFile: 'Förhandsgranska fil',\n    downloadFile: 'Ladda ned fil'\n  },\n  global: {\n    placeholder: 'Vänligen välj'\n  },\n  Icon: {\n    icon: 'ikon'\n  },\n  PageHeader: {\n    back: 'Tillbaka'\n  },\n  Image: {\n    preview: 'Förhandsgranska'\n  },\n  Form: {\n    optional: '(valfritt)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/ta_IN.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'ta',\n  Pagination: {\n    items_per_page: '/ பக்கம்',\n    jump_to: 'அடுத்த',\n    jump_to_confirm: 'உறுதிப்படுத்தவும்',\n    page: '',\n    prev_page: 'முந்தைய பக்கம்',\n    next_page: 'அடுத்த பக்கம்',\n    prev_5: 'முந்தைய 5 பக்கங்கள்',\n    next_5: 'அடுத்த 5 பக்கங்கள்',\n    prev_3: 'முந்தைய 3 பக்கங்கள்',\n    next_3: 'அடுத்த 3 பக்கங்கள்',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'தேதியைத் தேர்ந்தெடுக்கவும்',\n      rangePlaceholder: ['தொடக்க தேதி', 'கடைசி தேதி'],\n      locale: 'ta_IN',\n      today: 'இன்று',\n      now: 'இப்போது',\n      backToToday: 'இன்றுக்கு திரும்பு',\n      ok: 'சரி',\n      clear: 'அழி',\n      month: 'மாதம்',\n      year: 'வருடம்',\n      timeSelect: 'நேரத்தைத் தேர்ந்தெடு',\n      dateSelect: 'தேதியைத் தேர்ந்தெடு',\n      weekSelect: 'வாரத்தைத் தேர்வுசெய்க',\n      monthSelect: 'மாதத்தைத் தேர்வுசெய்க',\n      yearSelect: 'வருடத்தைத் தேர்வுசெய்க',\n      decadeSelect: 'தசாப்தத்தைத் தேர்வுசெய்க',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'முந்தைய மாதம் (PageUp)',\n      nextMonth: 'அடுத்த மாதம் (PageDown)',\n      previousYear: 'முந்தைய வருடம் (Control + left)',\n      nextYear: 'அடுத்த வருடம் (Control + right)',\n      previousDecade: 'முந்தைய தசாப்தம்',\n      nextDecade: 'அடுத்த தசாப்தம்',\n      previousCentury: 'முந்தைய நூற்றாண்டு',\n      nextCentury: 'அடுத்த நூற்றாண்டு'\n    },\n    timePickerLocale: {\n      placeholder: 'நேரத்தைத் தேர்ந்தெடுக்கவும்'\n    }\n  },\n  TimePicker: {\n    placeholder: 'நேரத்தைத் தேர்ந்தெடுக்கவும்'\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'தேதியைத் தேர்ந்தெடுக்கவும்',\n      rangePlaceholder: ['தொடக்க தேதி', 'கடைசி தேதி'],\n      locale: 'ta_IN',\n      today: 'இன்று',\n      now: 'இப்போது',\n      backToToday: 'இன்றுக்கு திரும்பு',\n      ok: 'சரி',\n      clear: 'அழி',\n      month: 'மாதம்',\n      year: 'வருடம்',\n      timeSelect: 'நேரத்தைத் தேர்ந்தெடு',\n      dateSelect: 'தேதியைத் தேர்ந்தெடு',\n      weekSelect: 'வாரத்தைத் தேர்வுசெய்க',\n      monthSelect: 'மாதத்தைத் தேர்வுசெய்க',\n      yearSelect: 'வருடத்தைத் தேர்வுசெய்க',\n      decadeSelect: 'தசாப்தத்தைத் தேர்வுசெய்க',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'முந்தைய மாதம் (PageUp)',\n      nextMonth: 'அடுத்த மாதம் (PageDown)',\n      previousYear: 'முந்தைய வருடம் (Control + left)',\n      nextYear: 'அடுத்த வருடம் (Control + right)',\n      previousDecade: 'முந்தைய தசாப்தம்',\n      nextDecade: 'அடுத்த தசாப்தம்',\n      previousCentury: 'முந்தைய நூற்றாண்டு',\n      nextCentury: 'அடுத்த நூற்றாண்டு'\n    },\n    timePickerLocale: {\n      placeholder: 'நேரத்தைத் தேர்ந்தெடுக்கவும்'\n    }\n  },\n  global: {\n    placeholder: 'தேதியைத் தேர்ந்தெடுக்கவும்'\n  },\n  Table: {\n    filterTitle: 'பட்டியலை மூடு',\n    filterConfirm: 'சரி',\n    filterReset: 'மீட்டமை',\n    emptyText: 'தகவல் இல்லை',\n    selectAll: 'அனைத்தையும் தேர்வுசெய்',\n    selectInvert: 'தலைகீழாக மாற்று',\n    sortTitle: 'தலைப்பை வரிசைப்படுத்தவும்'\n  },\n  Modal: {\n    okText: 'சரி',\n    cancelText: 'ரத்து செய்யவும்',\n    justOkText: 'பரவாயில்லை, சரி'\n  },\n  Popconfirm: {\n    okText: 'சரி',\n    cancelText: 'ரத்து செய்யவும்'\n  },\n  Transfer: {\n    titles: ['', ''],\n    notFoundContent: 'உள்ளடக்கம் கிடைக்கவில்லை',\n    searchPlaceholder: 'இங்கு தேடவும்',\n    itemUnit: 'தகவல்',\n    itemsUnit: 'தகவல்கள்'\n  },\n  Upload: {\n    uploading: 'பதிவேற்றுகிறது...',\n    removeFile: 'கோப்பை அகற்று',\n    uploadError: 'பதிவேற்றுவதில் பிழை',\n    previewFile: 'கோப்பை முன்னோட்டமிடுங்கள்',\n    downloadFile: 'பதிவிறக்க கோப்பு'\n  },\n  Empty: {\n    description: 'தகவல் இல்லை'\n  },\n  Icon: {\n    icon: 'உருவம்'\n  },\n  Text: {\n    edit: 'திருத்து',\n    copy: 'நகல் எடு',\n    copied: 'நகல் எடுக்கப்பட்டது',\n    expand: 'விரிவாக்கவும்'\n  },\n  PageHeader: {\n    back: 'பின் செல்லவும்'\n  },\n  Form: {\n    optional: '(தேர்வுமுறை)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/th_TH.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'th',\n  Pagination: {\n    items_per_page: '/ หน้า',\n    jump_to: 'ไปยัง',\n    jump_to_confirm: 'ยืนยัน',\n    page: 'หน้า',\n    prev_page: 'หน้าก่อนหน้า',\n    next_page: 'หน้าถัดไป',\n    prev_5: 'ย้อนกลับ 5 หน้า',\n    next_5: 'ถัดไป 5 หน้า',\n    prev_3: 'ย้อนกลับ 3 หน้า',\n    next_3: 'ถัดไป 3 หน้า',\n    page_size: 'ขนาดหน้า'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'เลือกวันที่',\n      yearPlaceholder: 'เลือกปี',\n      quarterPlaceholder: 'เลือกไตรมาส',\n      monthPlaceholder: 'เลือกเดือน',\n      weekPlaceholder: 'เลือกสัปดาห์',\n      rangePlaceholder: ['วันเริ่มต้น', 'วันสิ้นสุด'],\n      rangeYearPlaceholder: ['ปีเริ่มต้น', 'ปีสิ้นสุด'],\n      rangeMonthPlaceholder: ['เดือนเริ่มต้น', 'เดือนสิ้นสุด'],\n      rangeWeekPlaceholder: ['สัปดาห์เริ่มต้น', 'สัปดาห์สิ้นสุด'],\n      locale: 'th_TH',\n      today: 'วันนี้',\n      now: 'ตอนนี้',\n      backToToday: 'กลับไปยังวันนี้',\n      ok: 'ตกลง',\n      clear: 'ลบล้าง',\n      month: 'เดือน',\n      year: 'ปี',\n      timeSelect: 'เลือกเวลา',\n      dateSelect: 'เลือกวัน',\n      monthSelect: 'เลือกเดือน',\n      yearSelect: 'เลือกปี',\n      decadeSelect: 'เลือกทศวรรษ',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'เดือนก่อนหน้า (PageUp)',\n      nextMonth: 'เดือนถัดไป (PageDown)',\n      previousYear: 'ปีก่อนหน้า (Control + left)',\n      nextYear: 'ปีถัดไป (Control + right)',\n      previousDecade: 'ทศวรรษก่อนหน้า',\n      nextDecade: 'ทศวรรษถัดไป',\n      previousCentury: 'ศตวรรษก่อนหน้า',\n      nextCentury: 'ศตวรรษถัดไป'\n    },\n    timePickerLocale: {\n      placeholder: 'เลือกเวลา'\n    }\n  },\n  TimePicker: {\n    placeholder: 'เลือกเวลา'\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'เลือกวันที่',\n      yearPlaceholder: 'เลือกปี',\n      quarterPlaceholder: 'เลือกไตรมาส',\n      monthPlaceholder: 'เลือกเดือน',\n      weekPlaceholder: 'เลือกสัปดาห์',\n      rangePlaceholder: ['วันเริ่มต้น', 'วันสิ้นสุด'],\n      rangeYearPlaceholder: ['ปีเริ่มต้น', 'ปีสิ้นสุด'],\n      rangeMonthPlaceholder: ['เดือนเริ่มต้น', 'เดือนสิ้นสุด'],\n      rangeWeekPlaceholder: ['สัปดาห์เริ่มต้น', 'สัปดาห์สิ้นสุด'],\n      locale: 'th_TH',\n      today: 'วันนี้',\n      now: 'ตอนนี้',\n      backToToday: 'กลับไปยังวันนี้',\n      ok: 'ตกลง',\n      clear: 'ลบล้าง',\n      month: 'เดือน',\n      year: 'ปี',\n      timeSelect: 'เลือกเวลา',\n      dateSelect: 'เลือกวัน',\n      monthSelect: 'เลือกเดือน',\n      yearSelect: 'เลือกปี',\n      decadeSelect: 'เลือกทศวรรษ',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'เดือนก่อนหน้า (PageUp)',\n      nextMonth: 'เดือนถัดไป (PageDown)',\n      previousYear: 'ปีก่อนหน้า (Control + left)',\n      nextYear: 'ปีถัดไป (Control + right)',\n      previousDecade: 'ทศวรรษก่อนหน้า',\n      nextDecade: 'ทศวรรษถัดไป',\n      previousCentury: 'ศตวรรษก่อนหน้า',\n      nextCentury: 'ศตวรรษถัดไป'\n    },\n    timePickerLocale: {\n      placeholder: 'เลือกเวลา'\n    }\n  },\n  global: {\n    placeholder: 'กรุณาเลือก'\n  },\n  Table: {\n    filterTitle: 'ตัวกรอง',\n    filterConfirm: 'ยืนยัน',\n    filterReset: 'รีเซ็ต',\n    filterEmptyText: 'ไม่มีตัวกรอง',\n    emptyText: 'ไม่มีข้อมูล',\n    selectAll: 'เลือกทั้งหมดในหน้านี้',\n    selectInvert: 'กลับสถานะการเลือกในหน้านี้',\n    selectionAll: 'เลือกข้อมูลทั้งหมด',\n    sortTitle: 'เรียง',\n    expand: 'แสดงแถวข้อมูล',\n    collapse: 'ย่อแถวข้อมูล',\n    triggerDesc: 'คลิกเรียงจากมากไปน้อย',\n    triggerAsc: 'คลิกเรียงจากน้อยไปมาก',\n    cancelSort: 'คลิกเพื่อยกเลิกการเรียง'\n  },\n  Modal: {\n    okText: 'ตกลง',\n    cancelText: 'ยกเลิก',\n    justOkText: 'ตกลง'\n  },\n  Popconfirm: {\n    okText: 'ตกลง',\n    cancelText: 'ยกเลิก'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'ค้นหา',\n    itemUnit: 'ชิ้น',\n    itemsUnit: 'ชิ้น',\n    remove: 'นำออก',\n    selectCurrent: 'เลือกทั้งหมดในหน้านี้',\n    removeCurrent: 'นำออกทั้งหมดในหน้านี้',\n    selectAll: 'เลือกข้อมูลทั้งหมด',\n    removeAll: 'นำข้อมูลออกทั้งหมด',\n    selectInvert: 'กลับสถานะการเลือกในหน้านี้'\n  },\n  Upload: {\n    uploading: 'กำลังอัปโหลด...',\n    removeFile: 'ลบไฟล์',\n    uploadError: 'เกิดข้อผิดพลาดในการอัปโหลด',\n    previewFile: 'ดูตัวอย่างไฟล์',\n    downloadFile: 'ดาวน์โหลดไฟล์'\n  },\n  Empty: {\n    description: 'ไม่มีข้อมูล'\n  },\n  Icon: {\n    icon: 'ไอคอน'\n  },\n  Text: {\n    edit: 'แก้ไข',\n    copy: 'คัดลอก',\n    copied: 'คัดลอกแล้ว',\n    expand: 'ขยาย'\n  },\n  PageHeader: {\n    back: 'ย้อนกลับ'\n  },\n  Form: {\n    optional: '(ไม่จำเป็น)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/tr_TR.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'tr',\n  Pagination: {\n    items_per_page: '/ sayfa',\n    jump_to: 'Git',\n    jump_to_confirm: 'onayla',\n    page: 'Sayfa',\n    prev_page: 'Önceki Sayfa',\n    next_page: 'Sonraki Sayfa',\n    prev_5: 'Önceki 5 Sayfa',\n    next_5: 'Sonraki 5 Sayfa',\n    prev_3: 'Önceki 3 Sayfa',\n    next_3: 'Sonraki 3 Sayfa',\n    page_size: 'sayfa boyutu'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Tarih seç',\n      yearPlaceholder: 'Yıl seç',\n      quarterPlaceholder: 'Çeyrek seç',\n      monthPlaceholder: 'Ay seç',\n      weekPlaceholder: 'Hafta seç',\n      rangePlaceholder: ['Başlangıç tarihi', 'Bitiş tarihi'],\n      rangeYearPlaceholder: ['Başlangıç yılı', 'Bitiş yılı'],\n      rangeMonthPlaceholder: ['Başlangıç ayı', 'Bitiş ayı'],\n      rangeWeekPlaceholder: ['Başlangıç haftası', 'Bitiş haftası'],\n      locale: 'tr_TR',\n      today: 'Bugün',\n      now: 'Şimdi',\n      backToToday: 'Bugüne Geri Dön',\n      ok: 'tamam',\n      clear: 'Temizle',\n      month: 'Ay',\n      year: 'Yıl',\n      timeSelect: 'Zaman Seç',\n      dateSelect: 'Tarih Seç',\n      monthSelect: 'Ay Seç',\n      yearSelect: 'Yıl Seç',\n      decadeSelect: 'On Yıl Seç',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Önceki Ay (PageUp)',\n      nextMonth: 'Sonraki Ay (PageDown)',\n      previousYear: 'Önceki Yıl (Control + Sol)',\n      nextYear: 'Sonraki Yıl (Control + Sağ)',\n      previousDecade: 'Önceki On Yıl',\n      nextDecade: 'Sonraki On Yıl',\n      previousCentury: 'Önceki Yüzyıl',\n      nextCentury: 'Sonraki Yüzyıl'\n    },\n    timePickerLocale: {\n      placeholder: 'Zaman seç',\n      rangePlaceholder: ['Başlangıç zamanı', 'Bitiş zamanı']\n    }\n  },\n  TimePicker: {\n    placeholder: 'Zaman seç',\n    rangePlaceholder: ['Başlangıç zamanı', 'Bitiş zamanı']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Tarih seç',\n      yearPlaceholder: 'Yıl seç',\n      quarterPlaceholder: 'Çeyrek seç',\n      monthPlaceholder: 'Ay seç',\n      weekPlaceholder: 'Hafta seç',\n      rangePlaceholder: ['Başlangıç tarihi', 'Bitiş tarihi'],\n      rangeYearPlaceholder: ['Başlangıç yılı', 'Bitiş yılı'],\n      rangeMonthPlaceholder: ['Başlangıç ayı', 'Bitiş ayı'],\n      rangeWeekPlaceholder: ['Başlangıç haftası', 'Bitiş haftası'],\n      locale: 'tr_TR',\n      today: 'Bugün',\n      now: 'Şimdi',\n      backToToday: 'Bugüne Geri Dön',\n      ok: 'tamam',\n      clear: 'Temizle',\n      month: 'Ay',\n      year: 'Yıl',\n      timeSelect: 'Zaman Seç',\n      dateSelect: 'Tarih Seç',\n      monthSelect: 'Ay Seç',\n      yearSelect: 'Yıl Seç',\n      decadeSelect: 'On Yıl Seç',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Önceki Ay (PageUp)',\n      nextMonth: 'Sonraki Ay (PageDown)',\n      previousYear: 'Önceki Yıl (Control + Sol)',\n      nextYear: 'Sonraki Yıl (Control + Sağ)',\n      previousDecade: 'Önceki On Yıl',\n      nextDecade: 'Sonraki On Yıl',\n      previousCentury: 'Önceki Yüzyıl',\n      nextCentury: 'Sonraki Yüzyıl'\n    },\n    timePickerLocale: {\n      placeholder: 'Zaman seç',\n      rangePlaceholder: ['Başlangıç zamanı', 'Bitiş zamanı']\n    }\n  },\n  global: {\n    placeholder: 'Lütfen seçiniz'\n  },\n  Table: {\n    filterTitle: 'Filtre menüsü',\n    filterConfirm: 'Tamam',\n    filterReset: 'Sıfırla',\n    filterEmptyText: 'Filtre yok',\n    selectAll: 'Tüm sayfayı seç',\n    selectInvert: 'Tersini seç',\n    selectionAll: 'Tümünü seç',\n    sortTitle: 'Sırala',\n    expand: 'Satırı genişlet',\n    collapse: 'Satırı daralt',\n    triggerDesc: 'Azalan düzende sırala',\n    triggerAsc: 'Artan düzende sırala',\n    cancelSort: 'Sıralamayı kaldır'\n  },\n  Modal: {\n    okText: 'Tamam',\n    cancelText: 'İptal',\n    justOkText: 'Tamam'\n  },\n  Popconfirm: {\n    okText: 'Tamam',\n    cancelText: 'İptal'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'Arama',\n    itemUnit: 'Öğe',\n    itemsUnit: 'Öğeler',\n    remove: 'Kaldır',\n    selectCurrent: 'Tüm sayfayı seç',\n    removeCurrent: 'Sayfayı kaldır',\n    selectAll: 'Tümünü seç',\n    removeAll: 'Tümünü kaldır',\n    selectInvert: 'Tersini seç'\n  },\n  Upload: {\n    uploading: 'Yükleniyor...',\n    removeFile: 'Dosyayı kaldır',\n    uploadError: 'Yükleme hatası',\n    previewFile: 'Dosyayı önizle',\n    downloadFile: 'Dosyayı indir'\n  },\n  Empty: {\n    description: 'Veri Yok'\n  },\n  Icon: {\n    icon: 'ikon'\n  },\n  Text: {\n    edit: 'Düzenle',\n    copy: 'Kopyala',\n    copied: 'Kopyalandı',\n    expand: 'Genişlet'\n  },\n  PageHeader: {\n    back: 'Geri'\n  },\n  Image: {\n    preview: 'Önizleme'\n  },\n  Form: {\n    optional: '(isteğe bağlı)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/uk_UA.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'uk',\n  Pagination: {\n    items_per_page: '/ сторінці',\n    jump_to: 'Перейти',\n    jump_to_confirm: 'підтвердити',\n    page: '',\n    prev_page: 'Попередня сторінка',\n    next_page: 'Наступна сторінка',\n    prev_5: 'Попередні 5 сторінок',\n    next_5: 'Наступні 5 сторінок',\n    prev_3: 'Попередні 3 сторінки',\n    next_3: 'Наступні 3 сторінки',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Оберіть дату',\n      yearPlaceholder: 'Оберіть рік',\n      quarterPlaceholder: 'Оберіть квартал',\n      monthPlaceholder: 'Оберіть місяць',\n      weekPlaceholder: 'Оберіть тиждень',\n      rangePlaceholder: ['Початкова дата', 'Кінцева дата'],\n      rangeYearPlaceholder: ['Початковий рік', 'Рік закінчення'],\n      rangeMonthPlaceholder: ['Початковий місяць', 'Кінцевий місяць'],\n      rangeWeekPlaceholder: ['Початковий тиждень', 'Кінцевий тиждень'],\n      locale: 'uk_UA',\n      today: 'Сьогодні',\n      now: 'Зараз',\n      backToToday: 'Поточна дата',\n      ok: 'Ok',\n      clear: 'Очистити',\n      month: 'Місяць',\n      year: 'Рік',\n      timeSelect: 'Обрати час',\n      dateSelect: 'Обрати дату',\n      monthSelect: 'Обрати місяць',\n      yearSelect: 'Обрати рік',\n      decadeSelect: 'Обрати десятиріччя',\n      yearFormat: 'YYYY',\n      dateFormat: 'D-M-YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D-M-YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Попередній місяць (PageUp)',\n      nextMonth: 'Наступний місяць (PageDown)',\n      previousYear: 'Попередній рік (Control + left)',\n      nextYear: 'Наступний рік (Control + right)',\n      previousDecade: 'Попереднє десятиріччя',\n      nextDecade: 'Наступне десятиріччя',\n      previousCentury: 'Попереднє століття',\n      nextCentury: 'Наступне століття'\n    },\n    timePickerLocale: {\n      placeholder: 'Оберіть час',\n      rangePlaceholder: ['Час початку', 'Час закінчення']\n    }\n  },\n  TimePicker: {\n    placeholder: 'Оберіть час',\n    rangePlaceholder: ['Час початку', 'Час закінчення']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Оберіть дату',\n      rangePlaceholder: ['Початкова дата', 'Кінцева дата'],\n      locale: 'uk_UA',\n      today: 'Сьогодні',\n      now: 'Зараз',\n      backToToday: 'Поточна дата',\n      ok: 'Ok',\n      clear: 'Очистити',\n      month: 'Місяць',\n      year: 'Рік',\n      timeSelect: 'Обрати час',\n      dateSelect: 'Обрати дату',\n      monthSelect: 'Обрати місяць',\n      yearSelect: 'Обрати рік',\n      decadeSelect: 'Обрати десятиріччя',\n      yearFormat: 'YYYY',\n      dateFormat: 'D-M-YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D-M-YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Попередній місяць (PageUp)',\n      nextMonth: 'Наступний місяць (PageDown)',\n      previousYear: 'Попередній рік (Control + left)',\n      nextYear: 'Наступний рік (Control + right)',\n      previousDecade: 'Попереднє десятиріччя',\n      nextDecade: 'Наступне десятиріччя',\n      previousCentury: 'Попереднє століття',\n      nextCentury: 'Наступне століття'\n    },\n    timePickerLocale: {\n      placeholder: 'Оберіть час'\n    }\n  },\n  Table: {\n    filterTitle: 'Фільтрувати',\n    filterConfirm: 'OK',\n    filterReset: 'Скинути',\n    selectAll: 'Обрати всі',\n    selectInvert: 'Інвертувати вибір'\n  },\n  Modal: {\n    okText: 'Гаразд',\n    cancelText: 'Скасувати',\n    justOkText: 'Гаразд'\n  },\n  Popconfirm: {\n    okText: 'Гаразд',\n    cancelText: 'Скасувати'\n  },\n  Transfer: {\n    searchPlaceholder: 'Введіть текст для пошуку',\n    itemUnit: 'елем.',\n    itemsUnit: 'елем.'\n  },\n  Upload: {\n    uploading: 'Завантаження ...',\n    removeFile: 'Видалити файл',\n    uploadError: 'Помилка завантаження',\n    previewFile: 'Попередній перегляд файлу',\n    downloadFile: 'Завантажити файл'\n  },\n  Empty: {\n    description: 'Даних немає'\n  },\n  Icon: {\n    icon: 'іконка'\n  },\n  Text: {\n    edit: 'Редагувати',\n    copy: 'Копіювати',\n    copied: 'Скопійовано',\n    expand: 'Розгорнути'\n  },\n  PageHeader: {\n    back: 'Назад'\n  },\n  Form: {\n    optional: '(необовʼязково)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/ur_PK.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'ur',\n  Pagination: {\n    items_per_page: '/ صفحہ',\n    jump_to: 'پاس جاؤ',\n    jump_to_confirm: 'تصدیق کریں',\n    page: '',\n    prev_page: 'پچھلا صفحہ',\n    next_page: 'اگلا صفحہ',\n    prev_5: 'پچھلے 5 صفحات',\n    next_5: 'اگلے 5 صفحات',\n    prev_3: 'پچھلے 3 صفحات',\n    next_3: 'اگلے 3 صفحات',\n    page_size: 'Page Size'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'تاریخ منتخب کریں',\n      yearPlaceholder: 'سال کو منتخب کریں',\n      quarterPlaceholder: 'کوارٹر منتخب کریں',\n      monthPlaceholder: 'ماہ منتخب کریں',\n      weekPlaceholder: 'ہفتہ منتخب کریں',\n      rangePlaceholder: ['شروع کرنے کی تاریخ', 'آخری تاریخ'],\n      rangeYearPlaceholder: ['آغاز سال', 'آخر سال'],\n      rangeMonthPlaceholder: ['مہینہ شروع', 'اختتامی مہینہ'],\n      rangeWeekPlaceholder: ['ہفتے شروع کریں', 'اختتام ہفتہ'],\n      locale: 'ur_PK',\n      today: 'آج',\n      now: 'ابھی',\n      backToToday: 'آج واپس',\n      ok: 'ٹھیک ہے',\n      clear: 'صاف',\n      month: 'مہینہ',\n      year: 'سال',\n      timeSelect: 'وقت منتخب کریں',\n      dateSelect: 'تاریخ منتخب کریں',\n      weekSelect: 'ایک ہفتہ کا انتخاب کریں',\n      monthSelect: 'ایک مہینہ کا انتخاب کریں',\n      yearSelect: 'ایک سال کا انتخاب کریں',\n      decadeSelect: 'ایک دہائی کا انتخاب کریں',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'پچھلے مہینے (PageUp)',\n      nextMonth: 'اگلے مہینے (PageDown)',\n      previousYear: 'گزشتہ سال (Control + left)',\n      nextYear: 'اگلے سال (Control + right)',\n      previousDecade: 'پچھلی دہائی',\n      nextDecade: 'اگلی دہائی',\n      previousCentury: 'پچھلی صدی',\n      nextCentury: 'اگلی صدی'\n    },\n    timePickerLocale: {\n      placeholder: 'وقت منتخب کریں',\n      rangePlaceholder: ['وقت منتخب کریں', 'آخر وقت']\n    }\n  },\n  TimePicker: {\n    placeholder: 'وقت منتخب کریں',\n    rangePlaceholder: ['وقت منتخب کریں', 'آخر وقت']\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'تاریخ منتخب کریں',\n      yearPlaceholder: 'سال کو منتخب کریں',\n      quarterPlaceholder: 'کوارٹر منتخب کریں',\n      monthPlaceholder: 'ماہ منتخب کریں',\n      weekPlaceholder: 'ہفتہ منتخب کریں',\n      rangePlaceholder: ['شروع کرنے کی تاریخ', 'آخری تاریخ'],\n      rangeYearPlaceholder: ['آغاز سال', 'آخر سال'],\n      rangeMonthPlaceholder: ['مہینہ شروع', 'اختتامی مہینہ'],\n      rangeWeekPlaceholder: ['ہفتے شروع کریں', 'اختتام ہفتہ'],\n      locale: 'ur_PK',\n      today: 'آج',\n      now: 'ابھی',\n      backToToday: 'آج واپس',\n      ok: 'ٹھیک ہے',\n      clear: 'صاف',\n      month: 'مہینہ',\n      year: 'سال',\n      timeSelect: 'وقت منتخب کریں',\n      dateSelect: 'تاریخ منتخب کریں',\n      weekSelect: 'ایک ہفتہ کا انتخاب کریں',\n      monthSelect: 'ایک مہینہ کا انتخاب کریں',\n      yearSelect: 'ایک سال کا انتخاب کریں',\n      decadeSelect: 'ایک دہائی کا انتخاب کریں',\n      yearFormat: 'YYYY',\n      dateFormat: 'M/D/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'M/D/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'پچھلے مہینے (PageUp)',\n      nextMonth: 'اگلے مہینے (PageDown)',\n      previousYear: 'گزشتہ سال (Control + left)',\n      nextYear: 'اگلے سال (Control + right)',\n      previousDecade: 'پچھلی دہائی',\n      nextDecade: 'اگلی دہائی',\n      previousCentury: 'پچھلی صدی',\n      nextCentury: 'اگلی صدی'\n    },\n    timePickerLocale: {\n      placeholder: 'وقت منتخب کریں',\n      rangePlaceholder: ['وقت منتخب کریں', 'آخر وقت']\n    }\n  },\n  global: {\n    placeholder: 'منتخب کریں'\n  },\n  Table: {\n    filterTitle: 'فلٹر مینو',\n    filterConfirm: 'ٹھیک ہے',\n    filterReset: 'ری سیٹ کریں',\n    filterEmptyText: 'فلٹرز نہیں',\n    emptyText: 'کوئی ڈیٹا نہیں',\n    selectAll: 'موجودہ صفحہ منتخب کریں',\n    selectInvert: 'موجودہ صفحے کو الٹ دیں',\n    selectNone: 'تمام ڈیٹا صاف کریں',\n    selectionAll: 'تمام ڈیٹا کو منتخب کریں',\n    sortTitle: 'ترتیب دیں',\n    expand: 'پھیلائیں',\n    collapse: 'سمیٹیں',\n    triggerDesc: 'نزولی کو ترتیب دینے کیلئے کلک کریں',\n    triggerAsc: 'چڑھنے کو ترتیب دینے کیلئے کلک کریں',\n    cancelSort: 'ترتیب کو منسوخ کرنے کیلئے دبائیں'\n  },\n  Modal: {\n    okText: 'ٹھیک ہے',\n    cancelText: 'منسوخ کریں',\n    justOkText: 'ٹھیک ہے'\n  },\n  Popconfirm: {\n    okText: 'ٹھیک ہے',\n    cancelText: 'منسوخ کریں'\n  },\n  Transfer: {\n    titles: ['', ''],\n    searchPlaceholder: 'یہاں تلاش کریں',\n    itemUnit: 'شے',\n    itemsUnit: 'اشیاء',\n    remove: 'ہٹائیں',\n    selectCurrent: 'موجودہ صفحہ منتخب کریں',\n    removeCurrent: 'موجودہ صفحہ ہٹائیں',\n    selectAll: 'تمام ڈیٹا کو منتخب کریں',\n    removeAll: 'تمام ڈیٹا کو ہٹا دیں',\n    selectInvert: 'موجودہ صفحے کو الٹ دیں'\n  },\n  Upload: {\n    uploading: 'اپ لوڈ ہو رہا ہے…',\n    removeFile: 'فائل کو ہٹا دیں',\n    uploadError: 'اپ لوڈ کی خرابی',\n    previewFile: 'پیش نظار فائل',\n    downloadFile: 'فائل ڈاؤن لوڈ کریں'\n  },\n  Empty: {\n    description: 'کوئی ڈیٹا نہیں'\n  },\n  Icon: {\n    icon: 'آئیکن'\n  },\n  Text: {\n    edit: 'ترمیم',\n    copy: 'کاپی',\n    copied: 'کاپی ہوگیا',\n    expand: 'پھیلائیں'\n  },\n  PageHeader: {\n    back: 'پیچھے'\n  },\n  Image: {\n    preview: 'پیش نظارہ'\n  },\n  Form: {\n    optional: '(اختیاری)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/vi_VN.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'vi',\n  Pagination: {\n    items_per_page: '/ trang',\n    jump_to: 'Đến',\n    jump_to_confirm: 'xác nhận',\n    page: 'Trang',\n    prev_page: 'Trang Trước',\n    next_page: 'Trang Kế',\n    prev_5: 'Về 5 Trang Trước',\n    next_5: 'Đến 5 Trang Kế',\n    prev_3: 'Về 3 Trang Trước',\n    next_3: 'Đến 3 Trang Kế',\n    page_size: 'kích thước trang'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: 'Chọn thời điểm',\n      yearPlaceholder: 'Chọn năm',\n      quarterPlaceholder: 'Chọn quý',\n      monthPlaceholder: 'Chọn tháng',\n      weekPlaceholder: 'Chọn tuần',\n      rangePlaceholder: ['Ngày bắt đầu', 'Ngày kết thúc'],\n      rangeYearPlaceholder: ['Năm bắt đầu', 'Năm kết thúc'],\n      rangeQuarterPlaceholder: ['Qúy bắt đầu', 'Quý kết thúc'],\n      rangeMonthPlaceholder: ['Tháng bắt đầu', 'Tháng kết thúc'],\n      rangeWeekPlaceholder: ['Tuần bắt đầu', 'Tuần kết thúc'],\n      locale: 'vi_VN',\n      today: 'Hôm nay',\n      now: 'Bây giờ',\n      backToToday: 'Trở về hôm nay',\n      ok: 'Ok',\n      clear: 'Xóa',\n      month: 'Tháng',\n      year: 'Năm',\n      timeSelect: 'Chọn thời gian',\n      dateSelect: 'Chọn ngày',\n      weekSelect: 'Chọn tuần',\n      monthSelect: 'Chọn tháng',\n      yearSelect: 'Chọn năm',\n      decadeSelect: 'Chọn thập kỷ',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Tháng trước (PageUp)',\n      nextMonth: 'Tháng sau (PageDown)',\n      previousYear: 'Năm trước (Control + left)',\n      nextYear: 'Năm sau (Control + right)',\n      previousDecade: 'Thập kỷ trước',\n      nextDecade: 'Thập kỷ sau',\n      previousCentury: 'Thế kỷ trước',\n      nextCentury: 'Thế kỷ sau'\n    },\n    timePickerLocale: {\n      placeholder: 'Chọn thời gian'\n    }\n  },\n  TimePicker: {\n    placeholder: 'Chọn thời gian'\n  },\n  Calendar: {\n    lang: {\n      placeholder: 'Chọn thời điểm',\n      yearPlaceholder: 'Chọn năm',\n      quarterPlaceholder: 'Chọn quý',\n      monthPlaceholder: 'Chọn tháng',\n      weekPlaceholder: 'Chọn tuần',\n      rangePlaceholder: ['Ngày bắt đầu', 'Ngày kết thúc'],\n      rangeYearPlaceholder: ['Năm bắt đầu', 'Năm kết thúc'],\n      rangeMonthPlaceholder: ['Tháng bắt đầu', 'Tháng kết thúc'],\n      rangeWeekPlaceholder: ['Tuần bắt đầu', 'Tuần kết thúc'],\n      locale: 'vi_VN',\n      today: 'Hôm nay',\n      now: 'Bây giờ',\n      backToToday: 'Trở về hôm nay',\n      ok: 'Ok',\n      clear: 'Xóa',\n      month: 'Tháng',\n      year: 'Năm',\n      timeSelect: 'Chọn thời gian',\n      dateSelect: 'Chọn ngày',\n      weekSelect: 'Chọn tuần',\n      monthSelect: 'Chọn tháng',\n      yearSelect: 'Chọn năm',\n      decadeSelect: 'Chọn thập kỷ',\n      yearFormat: 'YYYY',\n      dateFormat: 'D/M/YYYY',\n      dayFormat: 'D',\n      dateTimeFormat: 'D/M/YYYY HH:mm:ss',\n      monthBeforeYear: true,\n      previousMonth: 'Tháng trước (PageUp)',\n      nextMonth: 'Tháng sau (PageDown)',\n      previousYear: 'Năm trước (Control + left)',\n      nextYear: 'Năm sau (Control + right)',\n      previousDecade: 'Thập kỷ trước',\n      nextDecade: 'Thập kỷ sau',\n      previousCentury: 'Thế kỷ trước',\n      nextCentury: 'Thế kỷ sau'\n    },\n    timePickerLocale: {\n      placeholder: 'Chọn thời gian'\n    }\n  },\n  Table: {\n    filterTitle: 'Bộ ',\n    filterConfirm: 'OK',\n    filterReset: 'Tạo Lại',\n    selectAll: 'Chọn Tất Cả',\n    selectInvert: 'Chọn Ngược Lại'\n  },\n  Modal: {\n    okText: 'OK',\n    cancelText: 'Huỷ',\n    justOkText: 'OK'\n  },\n  Popconfirm: {\n    okText: 'OK',\n    cancelText: 'Huỷ'\n  },\n  Transfer: {\n    searchPlaceholder: 'Tìm ở đây',\n    itemUnit: 'mục',\n    itemsUnit: 'mục'\n  },\n  Upload: {\n    uploading: 'Đang tải lên...',\n    removeFile: 'Gỡ bỏ tập tin',\n    uploadError: 'Lỗi tải lên',\n    previewFile: 'Xem thử tập tin',\n    downloadFile: 'Tải tập tin'\n  },\n  Empty: {\n    description: 'Trống'\n  },\n  Form: {\n    optional: '(tùy chọn)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/zh_CN.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'zh-cn',\n  Pagination: {\n    items_per_page: '条/页',\n    jump_to: '跳至',\n    jump_to_confirm: '确定',\n    page: '页',\n    prev_page: '上一页',\n    next_page: '下一页',\n    prev_5: '向前 5 页',\n    next_5: '向后 5 页',\n    prev_3: '向前 3 页',\n    next_3: '向后 3 页',\n    page_size: '页码'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: '请选择日期',\n      yearPlaceholder: '请选择年份',\n      quarterPlaceholder: '请选择季度',\n      monthPlaceholder: '请选择月份',\n      weekPlaceholder: '请选择周',\n      rangePlaceholder: ['开始日期', '结束日期'],\n      rangeYearPlaceholder: ['开始年份', '结束年份'],\n      rangeQuarterPlaceholder: ['开始季度', '结束季度'],\n      rangeMonthPlaceholder: ['开始月份', '结束月份'],\n      rangeWeekPlaceholder: ['开始周', '结束周'],\n      locale: 'zh_CN',\n      today: '今天',\n      now: '此刻',\n      backToToday: '返回今天',\n      ok: '确定',\n      timeSelect: '选择时间',\n      dateSelect: '选择日期',\n      weekSelect: '选择周',\n      clear: '清除',\n      month: '月',\n      year: '年',\n      previousMonth: '上个月 (翻页上键)',\n      nextMonth: '下个月 (翻页下键)',\n      monthSelect: '选择月份',\n      yearSelect: '选择年份',\n      decadeSelect: '选择年代',\n      yearFormat: 'YYYY年',\n      dayFormat: 'D日',\n      dateFormat: 'YYYY年M月D日',\n      dateTimeFormat: 'YYYY年M月D日 HH时mm分ss秒',\n      previousYear: '上一年 (Control键加左方向键)',\n      nextYear: '下一年 (Control键加右方向键)',\n      previousDecade: '上一年代',\n      nextDecade: '下一年代',\n      previousCentury: '上一世纪',\n      nextCentury: '下一世纪'\n    },\n    timePickerLocale: {\n      placeholder: '请选择时间',\n      rangePlaceholder: ['开始时间', '结束时间']\n    }\n  },\n  TimePicker: {\n    placeholder: '请选择时间',\n    rangePlaceholder: ['开始时间', '结束时间']\n  },\n  Calendar: {\n    lang: {\n      placeholder: '请选择日期',\n      yearPlaceholder: '请选择年份',\n      quarterPlaceholder: '请选择季度',\n      monthPlaceholder: '请选择月份',\n      weekPlaceholder: '请选择周',\n      rangePlaceholder: ['开始日期', '结束日期'],\n      rangeYearPlaceholder: ['开始年份', '结束年份'],\n      rangeMonthPlaceholder: ['开始月份', '结束月份'],\n      rangeWeekPlaceholder: ['开始周', '结束周'],\n      locale: 'zh_CN',\n      today: '今天',\n      now: '此刻',\n      backToToday: '返回今天',\n      ok: '确定',\n      timeSelect: '选择时间',\n      dateSelect: '选择日期',\n      weekSelect: '选择周',\n      clear: '清除',\n      month: '月',\n      year: '年',\n      previousMonth: '上个月 (翻页上键)',\n      nextMonth: '下个月 (翻页下键)',\n      monthSelect: '选择月份',\n      yearSelect: '选择年份',\n      decadeSelect: '选择年代',\n      yearFormat: 'YYYY年',\n      dayFormat: 'D日',\n      dateFormat: 'YYYY年M月D日',\n      dateTimeFormat: 'YYYY年M月D日 HH时mm分ss秒',\n      previousYear: '上一年 (Control键加左方向键)',\n      nextYear: '下一年 (Control键加右方向键)',\n      previousDecade: '上一年代',\n      nextDecade: '下一年代',\n      previousCentury: '上一世纪',\n      nextCentury: '下一世纪'\n    },\n    timePickerLocale: {\n      placeholder: '请选择时间',\n      rangePlaceholder: ['开始时间', '结束时间']\n    }\n  },\n  global: {\n    placeholder: '请选择'\n  },\n  Table: {\n    filterTitle: '筛选',\n    filterConfirm: '确定',\n    filterReset: '重置',\n    filterEmptyText: '无筛选项',\n    selectAll: '全选当页',\n    selectInvert: '反选当页',\n    selectionAll: '全选所有',\n    sortTitle: '排序',\n    expand: '展开行',\n    collapse: '关闭行',\n    triggerDesc: '点击降序',\n    triggerAsc: '点击升序',\n    cancelSort: '取消排序',\n    filterCheckall: '全选',\n    filterSearchPlaceholder: '在筛选项中搜索',\n    selectNone: '清空所有'\n  },\n  Modal: {\n    okText: '确定',\n    cancelText: '取消',\n    justOkText: '知道了'\n  },\n  Popconfirm: {\n    cancelText: '取消',\n    okText: '确定'\n  },\n  Transfer: {\n    searchPlaceholder: '请输入搜索内容',\n    itemUnit: '项',\n    itemsUnit: '项',\n    remove: '删除',\n    selectCurrent: '全选当页',\n    removeCurrent: '删除当页',\n    selectAll: '全选所有',\n    removeAll: '删除全部',\n    selectInvert: '反选当页'\n  },\n  Upload: {\n    uploading: '文件上传中',\n    removeFile: '删除文件',\n    uploadError: '上传错误',\n    previewFile: '预览文件',\n    downloadFile: '下载文件'\n  },\n  Empty: {\n    description: '暂无数据'\n  },\n  Form: {\n    optional: '(可选)'\n  },\n  Icon: {\n    icon: '图标'\n  },\n  Text: {\n    edit: '编辑',\n    copy: '复制',\n    copied: '复制成功',\n    expand: '展开'\n  },\n  PageHeader: {\n    back: '返回'\n  },\n  Image: {\n    preview: '预览'\n  },\n  CronExpression: {\n    cronError: 'cron 表达式不合法',\n    second: '秒',\n    minute: '分钟',\n    hour: '小时',\n    day: '日',\n    month: '月',\n    week: '周'\n  },\n  QRCode: {\n    expired: '二维码过期',\n    refresh: '点击刷新',\n    scanned: '已扫描'\n  },\n  CheckList: {\n    checkList: '任务清单',\n    checkListFinish: '你已成功完成任务清单！',\n    checkListClose: '关闭',\n    checkListFooter: '不需要操作指引',\n    checkListCheck: '你要关闭操作清单吗',\n    ok: '确定',\n    cancel: '取消',\n    checkListCheckOther: '以后不再需要操作清单'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/zh_HK.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'zh-hk',\n  Pagination: {\n    items_per_page: '條/頁',\n    jump_to: '跳至',\n    jump_to_confirm: '確定',\n    page: '頁',\n    prev_page: '上一頁',\n    next_page: '下一頁',\n    prev_5: '向前 5 頁',\n    next_5: '向後 5 頁',\n    prev_3: '向前 3 頁',\n    next_3: '向後 3 頁',\n    page_size: '頁碼'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: '請選擇日期',\n      rangePlaceholder: ['開始日期', '結束日期'],\n      locale: 'zh_TW',\n      today: '今天',\n      now: '此刻',\n      backToToday: '返回今天',\n      ok: '確定',\n      timeSelect: '選擇時間',\n      dateSelect: '選擇日期',\n      weekSelect: '選擇周',\n      clear: '清除',\n      month: '月',\n      year: '年',\n      previousMonth: '上個月 (翻頁上鍵)',\n      nextMonth: '下個月 (翻頁下鍵)',\n      monthSelect: '選擇月份',\n      yearSelect: '選擇年份',\n      decadeSelect: '選擇年代',\n      yearFormat: 'YYYY年',\n      dayFormat: 'D日',\n      dateFormat: 'YYYY年M月D日',\n      dateTimeFormat: 'YYYY年M月D日 HH時mm分ss秒',\n      previousYear: '上一年 (Control鍵加左方向鍵)',\n      nextYear: '下一年 (Control鍵加右方向鍵)',\n      previousDecade: '上一年代',\n      nextDecade: '下一年代',\n      previousCentury: '上一世紀',\n      nextCentury: '下一世紀',\n      yearPlaceholder: '請選擇年份',\n      quarterPlaceholder: '請選擇季度',\n      monthPlaceholder: '請選擇月份',\n      weekPlaceholder: '請選擇周',\n      rangeYearPlaceholder: ['開始年份', '結束年份'],\n      rangeQuarterPlaceholder: ['開始季度', '結束季度'],\n      rangeMonthPlaceholder: ['開始月份', '結束月份'],\n      rangeWeekPlaceholder: ['開始周', '結束周']\n    },\n    timePickerLocale: {\n      placeholder: '請選擇時間'\n    }\n  },\n  TimePicker: {\n    placeholder: '請選擇時間'\n  },\n  Calendar: {\n    lang: {\n      placeholder: '請選擇日期',\n      rangePlaceholder: ['開始日期', '結束日期'],\n      locale: 'zh_TW',\n      today: '今天',\n      now: '此刻',\n      backToToday: '返回今天',\n      ok: '確定',\n      timeSelect: '選擇時間',\n      dateSelect: '選擇日期',\n      weekSelect: '選擇周',\n      clear: '清除',\n      month: '月',\n      year: '年',\n      previousMonth: '上個月 (翻頁上鍵)',\n      nextMonth: '下個月 (翻頁下鍵)',\n      monthSelect: '選擇月份',\n      yearSelect: '選擇年份',\n      decadeSelect: '選擇年代',\n      yearFormat: 'YYYY年',\n      dayFormat: 'D日',\n      dateFormat: 'YYYY年M月D日',\n      dateTimeFormat: 'YYYY年M月D日 HH時mm分ss秒',\n      previousYear: '上一年 (Control鍵加左方向鍵)',\n      nextYear: '下一年 (Control鍵加右方向鍵)',\n      previousDecade: '上一年代',\n      nextDecade: '下一年代',\n      previousCentury: '上一世紀',\n      nextCentury: '下一世紀',\n      yearPlaceholder: '請選擇年份',\n      quarterPlaceholder: '請選擇季度',\n      monthPlaceholder: '請選擇月份',\n      weekPlaceholder: '請選擇周',\n      rangeYearPlaceholder: ['開始年份', '結束年份'],\n      rangeMonthPlaceholder: ['開始月份', '結束月份'],\n      rangeWeekPlaceholder: ['開始周', '結束周']\n    },\n    timePickerLocale: {\n      placeholder: '請選擇時間'\n    }\n  },\n  global: {\n    placeholder: '請選擇'\n  },\n  Table: {\n    filterTitle: '篩選器',\n    filterConfirm: '確定',\n    filterReset: '重置',\n    filterEmptyText: '無篩選項',\n    selectAll: '全部選取',\n    selectInvert: '反向選取',\n    selectionAll: '全選所有',\n    sortTitle: '排序',\n    expand: '展開行',\n    collapse: '關閉行',\n    triggerDesc: '點擊降序',\n    triggerAsc: '點擊升序',\n    cancelSort: '取消排序',\n    selectNone: '清空所有'\n  },\n  Modal: {\n    okText: '確定',\n    cancelText: '取消',\n    justOkText: '知道了'\n  },\n  Popconfirm: {\n    okText: '確定',\n    cancelText: '取消'\n  },\n  Transfer: {\n    searchPlaceholder: '搜尋資料',\n    itemUnit: '項目',\n    itemsUnit: '項目',\n    remove: '刪除',\n    selectCurrent: '全選當頁',\n    removeCurrent: '刪除當頁',\n    selectAll: '全選所有',\n    removeAll: '刪除全部',\n    selectInvert: '反選當頁'\n  },\n  Upload: {\n    uploading: '正在上傳...',\n    removeFile: '刪除檔案',\n    uploadError: '上傳失敗',\n    previewFile: '檔案預覽',\n    downloadFile: '下载文件'\n  },\n  Empty: {\n    description: '無此資料'\n  },\n  Icon: {\n    icon: '圖標'\n  },\n  Text: {\n    edit: '編輯',\n    copy: '複製',\n    copied: '複製成功',\n    expand: '展開'\n  },\n  PageHeader: {\n    back: '返回'\n  },\n  Image: {\n    preview: '預覽'\n  },\n  Form: {\n    optional: '(可選)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/languages/zh_TW.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport default {\n  locale: 'zh-tw',\n  Pagination: {\n    items_per_page: '條/頁',\n    jump_to: '跳至',\n    jump_to_confirm: '確定',\n    page: '頁',\n    prev_page: '上一頁',\n    next_page: '下一頁',\n    prev_5: '向前 5 頁',\n    next_5: '向後 5 頁',\n    prev_3: '向前 3 頁',\n    next_3: '向後 3 頁',\n    page_size: '頁碼'\n  },\n  DatePicker: {\n    lang: {\n      placeholder: '請選擇日期',\n      rangePlaceholder: ['開始日期', '結束日期'],\n      locale: 'zh_TW',\n      today: '今天',\n      now: '此刻',\n      backToToday: '返回今天',\n      ok: '確定',\n      timeSelect: '選擇時間',\n      dateSelect: '選擇日期',\n      weekSelect: '選擇周',\n      clear: '清除',\n      month: '月',\n      year: '年',\n      previousMonth: '上個月 (翻頁上鍵)',\n      nextMonth: '下個月 (翻頁下鍵)',\n      monthSelect: '選擇月份',\n      yearSelect: '選擇年份',\n      decadeSelect: '選擇年代',\n      yearFormat: 'YYYY年',\n      dayFormat: 'D日',\n      dateFormat: 'YYYY年M月D日',\n      dateTimeFormat: 'YYYY年M月D日 HH時mm分ss秒',\n      previousYear: '上一年 (Control鍵加左方向鍵)',\n      nextYear: '下一年 (Control鍵加右方向鍵)',\n      previousDecade: '上一年代',\n      nextDecade: '下一年代',\n      previousCentury: '上一世紀',\n      nextCentury: '下一世紀',\n      yearPlaceholder: '請選擇年份',\n      quarterPlaceholder: '請選擇季度',\n      monthPlaceholder: '請選擇月份',\n      weekPlaceholder: '請選擇周',\n      rangeYearPlaceholder: ['開始年份', '結束年份'],\n      rangeMonthPlaceholder: ['開始月份', '結束月份'],\n      rangeWeekPlaceholder: ['開始周', '結束周'],\n      rangeQuarterPlaceholder: ['開始季度', '結束季度']\n    },\n    timePickerLocale: {\n      placeholder: '請選擇時間',\n      rangePlaceholder: ['開始時間', '結束時間']\n    }\n  },\n  TimePicker: {\n    placeholder: '請選擇時間',\n    rangePlaceholder: ['開始時間', '結束時間']\n  },\n  Calendar: {\n    lang: {\n      placeholder: '請選擇日期',\n      rangePlaceholder: ['開始日期', '結束日期'],\n      locale: 'zh_TW',\n      today: '今天',\n      now: '此刻',\n      backToToday: '返回今天',\n      ok: '確定',\n      timeSelect: '選擇時間',\n      dateSelect: '選擇日期',\n      weekSelect: '選擇周',\n      clear: '清除',\n      month: '月',\n      year: '年',\n      previousMonth: '上個月 (翻頁上鍵)',\n      nextMonth: '下個月 (翻頁下鍵)',\n      monthSelect: '選擇月份',\n      yearSelect: '選擇年份',\n      decadeSelect: '選擇年代',\n      yearFormat: 'YYYY年',\n      dayFormat: 'D日',\n      dateFormat: 'YYYY年M月D日',\n      dateTimeFormat: 'YYYY年M月D日 HH時mm分ss秒',\n      previousYear: '上一年 (Control鍵加左方向鍵)',\n      nextYear: '下一年 (Control鍵加右方向鍵)',\n      previousDecade: '上一年代',\n      nextDecade: '下一年代',\n      previousCentury: '上一世紀',\n      nextCentury: '下一世紀',\n      yearPlaceholder: '請選擇年份',\n      quarterPlaceholder: '請選擇季度',\n      monthPlaceholder: '請選擇月份',\n      weekPlaceholder: '請選擇周',\n      rangeYearPlaceholder: ['開始年份', '結束年份'],\n      rangeMonthPlaceholder: ['開始月份', '結束月份'],\n      rangeWeekPlaceholder: ['開始周', '結束周']\n    },\n    timePickerLocale: {\n      placeholder: '請選擇時間',\n      rangePlaceholder: ['開始時間', '結束時間']\n    }\n  },\n  global: {\n    placeholder: '請選擇'\n  },\n  Table: {\n    filterTitle: '篩選器',\n    filterConfirm: '確定',\n    filterReset: '重置',\n    filterEmptyText: '無篩選項',\n    selectAll: '全部選取',\n    selectInvert: '反向選取',\n    selectionAll: '全選所有',\n    sortTitle: '排序',\n    expand: '展開行',\n    collapse: '關閉行',\n    triggerDesc: '點擊降序',\n    triggerAsc: '點擊升序',\n    cancelSort: '取消排序',\n    filterCheckall: '全選',\n    filterSearchPlaceholder: '在篩選項中搜尋',\n    selectNone: '清空所有'\n  },\n  Modal: {\n    okText: '確定',\n    cancelText: '取消',\n    justOkText: '知道了'\n  },\n  Popconfirm: {\n    okText: '確定',\n    cancelText: '取消'\n  },\n  Transfer: {\n    searchPlaceholder: '搜尋資料',\n    itemUnit: '項目',\n    itemsUnit: '項目',\n    remove: '删除',\n    selectCurrent: '全選當頁',\n    removeCurrent: '删除當頁',\n    selectAll: '全選所有',\n    removeAll: '删除全部',\n    selectInvert: '反選當頁'\n  },\n  Upload: {\n    uploading: '正在上傳...',\n    removeFile: '刪除檔案',\n    uploadError: '上傳失敗',\n    previewFile: '檔案預覽',\n    downloadFile: '下載文件'\n  },\n  Empty: {\n    description: '無此資料'\n  },\n  Icon: {\n    icon: '圖標'\n  },\n  Text: {\n    edit: '編輯',\n    copy: '複製',\n    copied: '複製成功',\n    expand: '展開'\n  },\n  PageHeader: {\n    back: '返回'\n  },\n  Image: {\n    preview: '預覽'\n  },\n  CronExpression: {\n    cronError: 'cron 表達式不合法',\n    second: '秒',\n    minute: '分',\n    hour: '時',\n    day: '日',\n    month: '月',\n    week: '週'\n  },\n  QRCode: {\n    expired: '二維條碼已過期',\n    refresh: '點擊刷新',\n    scanned: '已掃描'\n  },\n  Form: {\n    optional: '(可選)'\n  }\n};\n"
  },
  {
    "path": "components/i18n/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/i18n/nz-i18n.interface.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Locale } from 'date-fns';\n\nexport interface NzPaginationI18nInterface {\n  items_per_page: string;\n  jump_to: string;\n  jump_to_confirm: string;\n  page: string;\n\n  // Pagination.jsx\n  prev_page: string;\n  next_page: string;\n  prev_5: string;\n  next_5: string;\n  prev_3: string;\n  next_3: string;\n}\n\nexport interface NzGlobalI18nInterface {\n  placeholder: string;\n}\n\nexport interface NzDatePickerI18nInterface {\n  lang: NzDatePickerLangI18nInterface;\n  timePickerLocale: NzTimePickerI18nInterface;\n}\n\nexport interface NzCalendarI18nInterface {\n  today: string;\n  now: string;\n  backToToday: string;\n  ok: string;\n  clear: string;\n  month: string;\n  year: string;\n  timeSelect: string;\n  dateSelect: string;\n  monthSelect: string;\n  yearSelect: string;\n  decadeSelect: string;\n  yearFormat: string;\n  monthFormat?: string;\n  dateFormat: string;\n  dayFormat: string;\n  dateTimeFormat: string;\n  monthBeforeYear?: boolean;\n  previousMonth: string;\n  nextMonth: string;\n  previousYear: string;\n  nextYear: string;\n  previousDecade: string;\n  nextDecade: string;\n  previousCentury: string;\n  nextCentury: string;\n}\n\nexport interface NzDatePickerLangI18nInterface extends NzCalendarI18nInterface {\n  placeholder?: string;\n  yearPlaceholder?: string;\n  quarterPlaceholder?: string;\n  monthPlaceholder?: string;\n  weekPlaceholder?: string;\n  rangePlaceholder?: string[];\n  rangeYearPlaceholder?: string[];\n  rangeQuarterPlaceholder?: string[];\n  rangeMonthPlaceholder?: string[];\n  rangeWeekPlaceholder?: string[];\n}\n\nexport interface NzTimePickerI18nInterface {\n  placeholder?: string;\n  rangePlaceholder?: string[];\n}\n\nexport type ValidateMessage = string | (() => string);\n\nexport type NzCascaderI18nInterface = NzGlobalI18nInterface;\n\nexport interface NzTableI18nInterface {\n  filterTitle?: string;\n  filterConfirm?: string;\n  filterReset?: string;\n  selectAll?: string;\n  selectInvert?: string;\n  selectionAll?: string;\n  sortTitle?: string;\n  expand?: string;\n  collapse?: string;\n  triggerDesc?: string;\n  triggerAsc?: string;\n  cancelSort?: string;\n}\n\nexport interface NzModalI18nInterface {\n  okText: string;\n  cancelText: string;\n  justOkText: string;\n}\n\nexport interface NzPopconfirmI18nInterface {\n  okText: string;\n  cancelText: string;\n}\n\nexport interface NzTransferI18nInterface {\n  titles?: string[];\n  searchPlaceholder?: string;\n  itemUnit?: string;\n  itemsUnit?: string;\n}\n\nexport interface NzUploadI18nInterface {\n  uploading?: string;\n  removeFile?: string;\n  uploadError?: string;\n  previewFile?: string;\n  downloadFile?: string;\n}\n\nexport interface NzEmptyI18nInterface {\n  description: string;\n}\n\nexport interface NzTextI18nInterface {\n  edit: string;\n  copy: string;\n  copied: string;\n  expand: string;\n}\n\nexport interface NzCronExpressionLabelI18n {\n  second?: string;\n  minute?: string;\n  hour?: string;\n  day?: string;\n  month?: string;\n  week?: string;\n}\n\nexport interface NzCronExpressionCronErrorI18n {\n  cronError?: string;\n}\n\nexport type NzCronExpressionI18nInterface = NzCronExpressionCronErrorI18n & NzCronExpressionLabelI18n;\n\nexport interface NzQRCodeI18nInterface {\n  expired: string;\n  refresh: string;\n  scanned: string;\n}\n\nexport interface NzCheckListI18nInterface {\n  checkList: string;\n  checkListFinish: string;\n  checkListClose: string;\n  checkListFooter: string;\n  checkListCheck: string;\n  ok: string;\n  cancel: string;\n  checkListCheckOther: string;\n}\n\nexport interface NzFormI18nInterface {\n  optional: string;\n}\n\nexport interface NzI18nInterface {\n  locale: string;\n  Pagination: NzPaginationI18nInterface;\n  DatePicker: NzDatePickerI18nInterface;\n  TimePicker: NzTimePickerI18nInterface;\n  Calendar: NzDatePickerI18nInterface;\n  global?: NzGlobalI18nInterface;\n  Table: NzTableI18nInterface;\n  Modal: NzModalI18nInterface;\n  Popconfirm: NzPopconfirmI18nInterface;\n  Transfer: NzTransferI18nInterface;\n  Upload: NzUploadI18nInterface;\n  Empty: NzEmptyI18nInterface;\n  Form: NzFormI18nInterface;\n  Text?: NzTextI18nInterface;\n  CronExpression?: NzCronExpressionI18nInterface;\n  QRCode?: NzQRCodeI18nInterface;\n  CheckList?: NzCheckListI18nInterface;\n}\n\nexport type DateLocale = Locale;\n"
  },
  {
    "path": "components/i18n/nz-i18n.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzI18nPipe } from './nz-i18n.pipe';\n\n@NgModule({\n  imports: [NzI18nPipe],\n  exports: [NzI18nPipe]\n})\nexport class NzI18nModule {}\n"
  },
  {
    "path": "components/i18n/nz-i18n.pipe.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { inject, Pipe, PipeTransform } from '@angular/core';\n\nimport { NzI18nService } from './nz-i18n.service';\n\n@Pipe({\n  name: 'nzI18n'\n})\nexport class NzI18nPipe implements PipeTransform {\n  private _locale = inject(NzI18nService);\n\n  transform(path: string, keyValue?: object): string {\n    return this._locale.translate(path, keyValue);\n  }\n}\n"
  },
  {
    "path": "components/i18n/nz-i18n.service.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, inject, OnDestroy } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { Subscription } from 'rxjs';\n\nimport { NZ_I18N, provideNzI18n } from 'ng-zorro-antd/i18n/nz-i18n.token';\n\nimport en_US from './languages/en_US';\nimport zh_CN from './languages/zh_CN';\nimport { NzI18nInterface } from './nz-i18n.interface';\nimport { NzI18nService } from './nz-i18n.service';\n\ndescribe('i18n service', () => {\n  let srv: NzI18nService;\n  let fixture: ComponentFixture<NzI18nTestComponent>;\n  let testComponent: NzI18nTestComponent;\n  const DEFAULT_LAN = zh_CN;\n\n  describe('#setLocale', () => {\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        providers: [provideNzI18n(DEFAULT_LAN)]\n      });\n\n      fixture = TestBed.createComponent(NzI18nTestComponent);\n      testComponent = fixture.debugElement.componentInstance;\n      srv = TestBed.inject(NzI18nService);\n    });\n\n    it('should be provide interface be right', () => {\n      fixture = TestBed.createComponent(NzI18nTestComponent);\n      expect(fixture.componentInstance.locale === DEFAULT_LAN).toBe(true);\n    });\n\n    it('should be auto default zh_CN', () => {\n      expect(testComponent.locale.locale).toBe(DEFAULT_LAN.locale);\n    });\n\n    it('should trigger changed when set different lang', () => {\n      const spy = spyOn(testComponent, 'updateLocale');\n      expect(spy).not.toHaveBeenCalled();\n      srv.setLocale(en_US);\n      expect(spy).toHaveBeenCalledTimes(1);\n    });\n\n    it('should not trigger change when set same lang', () => {\n      const spy = spyOn(testComponent, 'updateLocale');\n      expect(spy).not.toHaveBeenCalled();\n      srv.setLocale(zh_CN);\n      expect(spy).not.toHaveBeenCalled();\n    });\n\n    it('should warn when locale for a component is not provided', () => {\n      const spy = spyOn(console, 'warn');\n      srv.setLocale({ locale: 'not_existing_language' } as any); // eslint-disable-line  @typescript-eslint/no-explicit-any\n      expect(srv.getLocaleData('global.placeholder')).toBeTruthy();\n      expect(spy).toHaveBeenCalledWith(\n        '[NG-ZORRO]:',\n        `Missing translations for \"global.placeholder\" in language \"not_existing_language\".\nYou can use \"NzI18nService.setLocale\" as a temporary fix.\nWelcome to submit a pull request to help us optimize the translations!\nhttps://github.com/NG-ZORRO/ng-zorro-antd/blob/master/CONTRIBUTING.md`\n      );\n    });\n  });\n\n  describe('provideNzI18n', () => {\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        providers: [provideNzI18n(() => en_US)]\n      });\n\n      fixture = TestBed.createComponent(NzI18nTestComponent);\n      testComponent = fixture.debugElement.componentInstance;\n      srv = TestBed.inject(NzI18nService);\n    });\n\n    it('should factory work', () => {\n      expect(testComponent.locale.locale).toBe(en_US.locale);\n    });\n  });\n});\n\n@Component({\n  template: ''\n})\nexport class NzI18nTestComponent implements OnDestroy {\n  private localeSubscription: Subscription;\n  locale = inject(NZ_I18N);\n\n  constructor(private nzI18nService: NzI18nService) {\n    this.localeSubscription = this.nzI18nService.localeChange.subscribe(locale => {\n      this.updateLocale(locale);\n    });\n  }\n\n  ngOnDestroy(): void {\n    this.localeSubscription.unsubscribe();\n  }\n\n  updateLocale(locale: NzI18nInterface): void {\n    this.locale = locale;\n  }\n}\n"
  },
  {
    "path": "components/i18n/nz-i18n.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Injectable, inject } from '@angular/core';\nimport { BehaviorSubject, Observable } from 'rxjs';\n\nimport { warn } from 'ng-zorro-antd/core/logger';\nimport { IndexableObject, NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport en_US from './languages/en_US';\nimport zh_CN from './languages/zh_CN';\nimport { DateLocale, NzI18nInterface } from './nz-i18n.interface';\nimport { NZ_DATE_LOCALE, NZ_I18N } from './nz-i18n.token';\n\n@Injectable({\n  providedIn: 'root'\n})\nexport class NzI18nService {\n  private _locale!: NzI18nInterface;\n  private _change = new BehaviorSubject<NzI18nInterface>(this._locale);\n  private dateLocale!: DateLocale;\n\n  get localeChange(): Observable<NzI18nInterface> {\n    return this._change.asObservable();\n  }\n\n  constructor() {\n    this.setLocale(inject(NZ_I18N, { optional: true }) || zh_CN);\n    this.setDateLocale(inject(NZ_DATE_LOCALE, { optional: true }) as DateLocale); // TODO: fix the type\n  }\n\n  // [NOTE] Performance issue: this method may called by every change detections\n  // TODO: cache more deeply paths for performance\n  translate(path: string, data?: NzSafeAny): string {\n    // this._logger.debug(`[NzI18nService] Translating(${this._locale.locale}): ${path}`);\n    let content = this._getObjectPath(this._locale, path) as string;\n    if (typeof content === 'string') {\n      if (data) {\n        Object.keys(data).forEach(key => (content = content.replace(new RegExp(`%${key}%`, 'g'), data[key])));\n      }\n      return content;\n    }\n    return path;\n  }\n\n  /**\n   * Set/Change current locale globally throughout the WHOLE application\n   * NOTE: If called at runtime, rendered interface may not change along with the locale change,\n   * because this do not trigger another render schedule.\n   *\n   * @param locale The translating letters\n   */\n  setLocale(locale: NzI18nInterface): void {\n    if (this._locale && this._locale.locale === locale.locale) {\n      return;\n    }\n    this._locale = locale;\n    this._change.next(locale);\n  }\n\n  getLocale(): NzI18nInterface {\n    return this._locale;\n  }\n\n  getLocaleId(): string {\n    return this._locale ? this._locale.locale : '';\n  }\n\n  setDateLocale(dateLocale: DateLocale): void {\n    this.dateLocale = dateLocale;\n  }\n\n  getDateLocale(): DateLocale {\n    return this.dateLocale;\n  }\n\n  /**\n   * Get locale data\n   *\n   * @param path dot paths for finding exist value from locale data, eg. \"a.b.c\"\n   * @param defaultValue default value if the result is not \"truthy\"\n   */\n  getLocaleData(path: string, defaultValue?: NzSafeAny): NzSafeAny {\n    const result = path ? this._getObjectPath(this._locale, path) : this._locale;\n\n    if (!result && !defaultValue) {\n      warn(`Missing translations for \"${path}\" in language \"${this._locale.locale}\".\nYou can use \"NzI18nService.setLocale\" as a temporary fix.\nWelcome to submit a pull request to help us optimize the translations!\nhttps://github.com/NG-ZORRO/ng-zorro-antd/blob/master/CONTRIBUTING.md`);\n    }\n\n    return result || defaultValue || this._getObjectPath(en_US, path) || {};\n  }\n\n  private _getObjectPath(obj: IndexableObject, path: string): string | object | NzSafeAny {\n    let res = obj;\n    const paths = path.split('.');\n    const depth = paths.length;\n    let index = 0;\n    while (res && index < depth) {\n      res = res[paths[index++]];\n    }\n    return index === depth ? res : null;\n  }\n}\n"
  },
  {
    "path": "components/i18n/nz-i18n.token.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { InjectionToken, makeEnvironmentProviders, EnvironmentProviders } from '@angular/core';\n\nimport { DateLocale, NzI18nInterface } from './nz-i18n.interface';\n\nexport const NZ_I18N = new InjectionToken<NzI18nInterface>(\n  typeof ngDevMode !== 'undefined' && ngDevMode ? 'nz-i18n' : ''\n);\n\ntype FactoryLike<T> = T | (() => T);\n\n/**\n * Set the locale globally.\n */\nexport function provideNzI18n(config: NzI18nInterface): EnvironmentProviders;\nexport function provideNzI18n(factory: () => NzI18nInterface): EnvironmentProviders;\nexport function provideNzI18n(config: FactoryLike<NzI18nInterface>): EnvironmentProviders {\n  return makeEnvironmentProviders([\n    typeof config === 'function' ? { provide: NZ_I18N, useFactory: config } : { provide: NZ_I18N, useValue: config }\n  ]);\n}\n\n/** Locale for date operations, should import from date-fns, see example: https://github.com/date-fns/date-fns/blob/v1.30.1/src/locale/zh_cn/index.js */\nexport const NZ_DATE_LOCALE = new InjectionToken<DateLocale>(\n  typeof ngDevMode !== 'undefined' && ngDevMode ? 'nz-date-locale' : ''\n);\n"
  },
  {
    "path": "components/i18n/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './nz-i18n.module';\nexport * from './nz-i18n.service';\nexport * from './date-config';\nexport * from './nz-i18n.interface';\nexport * from './nz-i18n.token';\nexport * from './nz-i18n.pipe';\nexport * from './date-helper.service';\n\nexport { default as ar_EG } from './languages/ar_EG';\nexport { default as az_AZ } from './languages/az_AZ';\nexport { default as bg_BG } from './languages/bg_BG';\nexport { default as bn_BD } from './languages/bn_BD';\nexport { default as by_BY } from './languages/by_BY';\nexport { default as ca_ES } from './languages/ca_ES';\nexport { default as cs_CZ } from './languages/cs_CZ';\nexport { default as da_DK } from './languages/da_DK';\nexport { default as de_DE } from './languages/de_DE';\nexport { default as el_GR } from './languages/el_GR';\nexport { default as en_AU } from './languages/en_AU';\nexport { default as en_GB } from './languages/en_GB';\nexport { default as en_US } from './languages/en_US';\nexport { default as es_ES } from './languages/es_ES';\nexport { default as et_EE } from './languages/et_EE';\nexport { default as fa_IR } from './languages/fa_IR';\nexport { default as fi_FI } from './languages/fi_FI';\nexport { default as fr_BE } from './languages/fr_BE';\nexport { default as fr_CA } from './languages/fr_CA';\nexport { default as fr_FR } from './languages/fr_FR';\nexport { default as ga_IE } from './languages/ga_IE';\nexport { default as gl_ES } from './languages/gl_ES';\nexport { default as he_IL } from './languages/he_IL';\nexport { default as hi_IN } from './languages/hi_IN';\nexport { default as hr_HR } from './languages/hr_HR';\nexport { default as hu_HU } from './languages/hu_HU';\nexport { default as hy_AM } from './languages/hy_AM';\nexport { default as id_ID } from './languages/id_ID';\nexport { default as is_IS } from './languages/is_IS';\nexport { default as it_IT } from './languages/it_IT';\nexport { default as ja_JP } from './languages/ja_JP';\nexport { default as ka_GE } from './languages/ka_GE';\nexport { default as km_KH } from './languages/km_KH';\nexport { default as kk_KZ } from './languages/kk_KZ';\nexport { default as kmr_IQ } from './languages/kmr_IQ';\nexport { default as kn_IN } from './languages/kn_IN';\nexport { default as ko_KR } from './languages/ko_KR';\nexport { default as ku_IQ } from './languages/ku_IQ';\nexport { default as lt_LT } from './languages/lt_LT';\nexport { default as lv_LV } from './languages/lv_LV';\nexport { default as mk_MK } from './languages/mk_MK';\nexport { default as ml_IN } from './languages/ml_IN';\nexport { default as mn_MN } from './languages/mn_MN';\nexport { default as ms_MY } from './languages/ms_MY';\nexport { default as nb_NO } from './languages/nb_NO';\nexport { default as ne_NP } from './languages/ne_NP';\nexport { default as nl_BE } from './languages/nl_BE';\nexport { default as nl_NL } from './languages/nl_NL';\nexport { default as pl_PL } from './languages/pl_PL';\nexport { default as pt_BR } from './languages/pt_BR';\nexport { default as pt_PT } from './languages/pt_PT';\nexport { default as ro_RO } from './languages/ro_RO';\nexport { default as ru_RU } from './languages/ru_RU';\nexport { default as sk_SK } from './languages/sk_SK';\nexport { default as sl_SI } from './languages/sl_SI';\nexport { default as sr_RS } from './languages/sr_RS';\nexport { default as sv_SE } from './languages/sv_SE';\nexport { default as ta_IN } from './languages/ta_IN';\nexport { default as th_TH } from './languages/th_TH';\nexport { default as tr_TR } from './languages/tr_TR';\nexport { default as uk_UA } from './languages/uk_UA';\nexport { default as ur_PK } from './languages/ur_PK';\nexport { default as vi_VN } from './languages/vi_VN';\nexport { default as zh_CN } from './languages/zh_CN';\nexport { default as zh_HK } from './languages/zh_HK';\nexport { default as zh_TW } from './languages/zh_TW';\n"
  },
  {
    "path": "components/icon/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本使用\n  en-US: Basic usage\n---\n\n## zh-CN\n\n使用 `<nz-icon>` 来声明组件。使用 `nzType` 属性指定对应的图标。\n可以通过 `nzTheme` 属性来设置不同的主题风格的图标，也可以通过设置 `nzSpin` 属性来实现动画旋转效果。\n\n> `<nz-icon>` 自 v19 版本起受支持，而 `<span nz-icon>` 与 `<i nz-icon>` 仍受支持，但不再推荐。\n\n## en-US\n\nUse `<nz-icon>` to declare the component. Use the `nzType` property to specify the corresponding icon.\nYou can set different theme styles of icons by setting the `nzTheme` property, and you can achieve the animation rotation effect by setting the `nzSpin` property.\n\n> `<nz-icon>` is supported since v19, while `<span nz-icon>` and `<i nz-icon>` are still supported but not recommended.\n"
  },
  {
    "path": "components/icon/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-demo-icon-basic',\n  imports: [NzIconModule],\n  template: `\n    <div class=\"icons-list\">\n      <nz-icon nzType=\"home\" />\n      <nz-icon nzType=\"setting\" nzTheme=\"fill\" />\n      <nz-icon nzType=\"smile\" nzTheme=\"outline\" />\n      <nz-icon nzType=\"sync\" [nzSpin]=\"true\" />\n      <nz-icon nzType=\"smile\" nzTheme=\"outline\" [nzRotate]=\"180\" />\n      <!-- Loading with new API would spin automatically! -->\n      <nz-icon nzType=\"loading\" />\n    </div>\n  `,\n  styles: `\n    nz-icon {\n      margin-right: 6px;\n      font-size: 24px;\n    }\n  `\n})\nexport class NzDemoIconBasicComponent {}\n"
  },
  {
    "path": "components/icon/demo/custom.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 自定义图标\n  en-US: Custom icon\n---\n\n## zh-CN\n\n你可以直接将 `svg` 标签放在 `nz-icon` 中来渲染自定义内容，我们会为你处理大小和颜色等问题。\n\n## en-US\n\nYou can just put a `svg` element inside a `nz-icon` to render custom content. We would take care of size and color for you.\n"
  },
  {
    "path": "components/icon/demo/custom.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-demo-icon-custom',\n  imports: [NzIconModule],\n  template: `\n    <nz-icon style=\"color: hotpink\">\n      <svg>\n        <path\n          d=\"M923 283.6c-13.4-31.1-32.6-58.9-56.9-82.8-24.3-23.8-52.5-42.4-84-55.5-32.5-13.5-66.9-20.3-102.4-20.3-49.3 0-97.4 13.5-139.2 39-10 6.1-19.5 12.8-28.5 20.1-9-7.3-18.5-14-28.5-20.1-41.8-25.5-89.9-39-139.2-39-35.5 0-69.9 6.8-102.4 20.3-31.4 13-59.7 31.7-84 55.5-24.4 23.9-43.5 51.7-56.9 82.8-13.9 32.3-21 66.6-21 101.9 0 33.3 6.8 68 20.3 103.3 11.3 29.5 27.5 60.1 48.2 91 32.8 48.9 77.9 99.9 133.9 151.6 92.8 85.7 184.7 144.9 188.6 147.3l23.7 15.2c10.5 6.7 24 6.7 34.5 0l23.7-15.2c3.9-2.5 95.7-61.6 188.6-147.3 56-51.7 101.1-102.7 133.9-151.6 20.7-30.9 37-61.5 48.2-91 13.5-35.3 20.3-70 20.3-103.3 0.1-35.3-7-69.6-20.9-101.9z\"\n        />\n      </svg>\n    </nz-icon>\n    <nz-icon style=\"font-size: 32px\">\n      <svg>\n        <path\n          d=\"M99.096 315.634s-82.58-64.032-82.58-132.13c0-66.064 33.032-165.162 148.646-148.646 83.37 11.91 99.096 165.162 99.096 165.162l-165.162 115.614zM924.906 315.634s82.58-64.032 82.58-132.13c0-66.064-33.032-165.162-148.646-148.646-83.37 11.91-99.096 165.162-99.096 165.162l165.162 115.614z\"\n          fill=\"#6B676E\"\n          p-id=\"1143\"\n        />\n        <path\n          d=\"M1024 561.548c0 264.526-229.23 429.42-512.002 429.42S0 826.076 0 561.548 283.96 66.064 512.002 66.064 1024 297.022 1024 561.548z\"\n          fill=\"#FFEBD2\"\n          p-id=\"1144\"\n        />\n        <path\n          d=\"M330.324 842.126c0 82.096 81.34 148.646 181.678 148.646s181.678-66.55 181.678-148.646H330.324z\"\n          fill=\"#E9D7C3\"\n          p-id=\"1145\"\n        />\n        <path\n          d=\"M644.13 611.098C594.582 528.516 561.55 512 512.002 512c-49.548 0-82.58 16.516-132.13 99.096-42.488 70.814-78.73 211.264-49.548 247.742 66.064 82.58 165.162 33.032 181.678 33.032 16.516 0 115.614 49.548 181.678-33.032 29.18-36.476-7.064-176.93-49.55-247.74z\"\n          fill=\"#FFFFFF\"\n          p-id=\"1146\"\n        />\n        <path\n          d=\"M611.098 495.484c0-45.608 36.974-82.58 82.58-82.58 49.548 0 198.194 99.098 198.194 165.162s-79.934 144.904-148.646 99.096c-49.548-33.032-132.128-148.646-132.128-181.678zM412.904 495.484c0-45.608-36.974-82.58-82.58-82.58-49.548 0-198.194 99.098-198.194 165.162s79.934 144.904 148.646 99.096c49.548-33.032 132.128-148.646 132.128-181.678z\"\n          fill=\"#6B676E\"\n          p-id=\"1147\"\n        />\n        <path\n          d=\"M512.002 726.622c-30.06 0-115.614 5.668-115.614 33.032 0 49.638 105.484 85.24 115.614 82.58 10.128 2.66 115.614-32.944 115.614-82.58-0.002-27.366-85.556-33.032-115.614-33.032z\"\n          fill=\"#464655\"\n          p-id=\"1148\"\n        />\n        <path\n          d=\"M330.324 495.484m-33.032 0a33.032 33.032 0 1 0 66.064 0 33.032 33.032 0 1 0-66.064 0Z\"\n          fill=\"#464655\"\n          p-id=\"1149\"\n        />\n        <path\n          d=\"M693.678 495.484m-33.032 0a33.032 33.032 0 1 0 66.064 0 33.032 33.032 0 1 0-66.064 0Z\"\n          fill=\"#464655\"\n          p-id=\"1150\"\n        />\n      </svg>\n    </nz-icon>\n  `,\n  styles: `\n    nz-icon {\n      margin-right: 6px;\n      font-size: 24px;\n    }\n  `\n})\nexport class NzDemoIconCustomComponent {}\n"
  },
  {
    "path": "components/icon/demo/iconfont.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 使用 Iconfont.cn\n  en-US: Use iconfont.cn\n---\n\n## zh-CN\n\n对于使用 [iconfont.cn](http://iconfont.cn/) 的用户，通过设置 `fetchFromIconfont` 方法参数对象中的 `scriptUrl` 字段，即可轻松地使用已有项目中的图标。\n\n## en-US\n\nIf you are using [iconfont.cn](http://iconfont.cn/), you can use the icons in your project gracefully.\n"
  },
  {
    "path": "components/icon/demo/iconfont.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzIconModule, NzIconService } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-demo-icon-iconfont',\n  imports: [NzIconModule],\n  template: `\n    <nz-icon nzIconfont=\"icon-tuichu\" />\n    <nz-icon nzIconfont=\"icon-facebook\" />\n    <nz-icon nzIconfont=\"icon-twitter\" />\n  `,\n  styles: `\n    nz-icon {\n      margin-right: 6px;\n      font-size: 24px;\n    }\n  `\n})\nexport class NzDemoIconIconfontComponent {\n  constructor(private iconService: NzIconService) {\n    this.iconService.fetchFromIconfont({\n      scriptUrl: 'https://at.alicdn.com/t/font_8d5l8fzk5b87iudi.js'\n    });\n  }\n}\n"
  },
  {
    "path": "components/icon/demo/namespace.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 命名空间\n  en-US: Namespace\n---\n\n## zh-CN\n\n可以使用命名空间来添加自定义的 Icon，支持静态加载和动态加载。\n\n## en-US\n\nYou can use namespace to add your own icons. Static loading and dynamic loading are both supported.\n"
  },
  {
    "path": "components/icon/demo/namespace.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzIconModule, NzIconService } from 'ng-zorro-antd/icon';\n\nconst ngZorroIconLiteral =\n  '<svg viewBox=\"0 0 106 120\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\\n  <defs>\\n    <linearGradient x1=\"68.1279872%\" y1=\"-35.6905737%\" x2=\"30.4400914%\" y2=\"114.942679%\" id=\"linearGradient-1\">\\n      <stop stop-color=\"#FA8E7D\" offset=\"0%\"></stop>\\n      <stop stop-color=\"#F74A5C\" offset=\"51.2635191%\"></stop>\\n      <stop stop-color=\"#F51D2C\" offset=\"100%\"></stop>\\n    </linearGradient>\\n    <linearGradient x1=\"68.1279872%\" y1=\"-35.6905737%\" x2=\"74.5363914%\" y2=\"162.511755%\" id=\"linearGradient-2\">\\n      <stop stop-color=\"#FA8E7D\" offset=\"0%\"></stop>\\n      <stop stop-color=\"#F74A5C\" offset=\"51.2635191%\"></stop>\\n      <stop stop-color=\"#F51D2C\" offset=\"100%\"></stop>\\n    </linearGradient>\\n    <linearGradient x1=\"69.644116%\" y1=\"0%\" x2=\"69.644116%\" y2=\"100%\" id=\"linearGradient-3\">\\n      <stop stop-color=\"#29CDFF\" offset=\"0%\"></stop>\\n      <stop stop-color=\"#148EFF\" offset=\"37.8600687%\"></stop>\\n      <stop stop-color=\"#0A60FF\" offset=\"100%\"></stop>\\n    </linearGradient>\\n    <linearGradient x1=\"-19.8191553%\" y1=\"-36.7931464%\" x2=\"138.57919%\" y2=\"157.637507%\" id=\"linearGradient-4\">\\n      <stop stop-color=\"#29CDFF\" offset=\"0%\"></stop>\\n      <stop stop-color=\"#0F78FF\" offset=\"100%\"></stop>\\n    </linearGradient>\\n  </defs>\\n  <g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\\n    <g id=\"Angular\" transform=\"translate(-11.000000, -4.000000)\">\\n      <g id=\"Group-9\" transform=\"translate(11.000000, 4.000000)\">\\n        <path d=\"M65.63,72.2 L53.23,53.2 L46,63.69 L53.37,63.69 C56.4075661,63.69 58.87,66.1524339 58.87,69.19 C58.87,72.2275661 56.4075661,74.69 53.37,74.69 L35.49,74.69 C33.4448986,74.6890667 31.569189,73.5534846 30.620326,71.7418281 C29.671463,69.9301715 29.8061511,67.7416349 30.97,66.06 L48.84,40.26 C49.879226,38.7527636 51.6013948,37.8627393 53.4320154,37.8868264 C55.2626361,37.9109135 56.960791,38.8459421 57.96,40.38 L74.84,66.18 C75.9449505,67.8698206 76.0352122,70.0292067 75.0751376,71.8053446 C74.115063,73.5814826 72.2590116,74.6888076 70.24,74.69 C68.3799194,74.6978131 66.6433454,73.7598372 65.63,72.2 Z\" id=\"Path\" fill=\"url(#linearGradient-1)\"></path>\\n        <path d=\"M70.28,25 C69.0616939,25.0004053 67.8648105,24.6796268 66.81,24.07 L52.87,16.07 L39,24 C36.8331842,25.2504298 34.1638674,25.249892 31.9975556,23.9985892 C29.8312438,22.7472865 28.4970513,20.4353214 28.4975555,17.933589 C28.4980597,15.4318566 29.833184,13.1204295 32,11.87 L49.34,1.87 C51.5058075,0.619570435 54.1741925,0.619570435 56.34,1.87 L73.76,11.87 C76.574107,13.4207731 77.9710889,16.688234 77.147902,19.7941088 C76.324715,22.8999837 73.492775,25.0466031 70.28,25 Z\" id=\"Path\" fill=\"url(#linearGradient-2)\"></path>\\n        <path d=\"M52.86,119.92 C51.6310454,119.919338 50.4239235,119.595139 49.36,118.98 L3.93,92.75 C1.76486614,91.4999595 0.43077789,89.190081 0.43,86.69 L0.43,34.23 C0.43077789,31.729919 1.76486614,29.4200405 3.93,28.17 L15.16,21.69 C17.3290879,20.369153 20.0434251,20.3267208 22.2527396,21.5791219 C24.4620541,22.831523 25.8197544,25.182284 25.8004986,27.7218131 C25.7812428,30.2613423 24.3880518,32.5912449 22.16,33.81 L14.43,38.27 L14.43,82.65 L52.86,104.83 L89.7896161,83.5159515 C90.7180357,82.9801111 91.29,81.9896088 91.29,80.9176536 L91.29,40.0028421 C91.29,38.9306213 90.7177545,37.9399157 89.7889721,37.4041727 L83.61,33.84 C81.4431842,32.5895704 80.1080601,30.2781434 80.1075559,27.7764111 C80.1070518,25.2746788 81.4412443,22.9627138 83.6075559,21.7114111 C85.7738676,20.4601083 88.4431842,20.4595704 90.61,21.71 L101.79,28.17 C103.955134,29.4200405 105.289222,31.729919 105.29,34.23 L105.29,86.69 C105.289222,89.190081 103.955134,91.4999595 101.79,92.75 L56.36,119 C55.2952279,119.610805 54.087499,119.928265 52.86,119.92 Z\" id=\"Path\" fill=\"url(#linearGradient-3)\" fill-rule=\"nonzero\"></path>\\n        <path d=\"M78.06,106.45 C66.89,113 52.87,104.83 52.87,104.83 L15.9403839,83.5159515 C15.0119643,82.9801111 14.44,81.9896088 14.44,80.9176536 L14.44,40.0026171 C14.44,38.9305169 15.0121179,37.9399035 15.9407356,37.4041163 L22.17,33.81 C24.3980518,32.5912449 25.7912428,30.2613423 25.8104986,27.7218131 C25.8297544,25.182284 24.4720541,22.831523 22.2627396,21.5791219 C20.0534251,20.3267208 17.3390879,20.369153 15.17,21.69 L3.94,28.17 C1.77486614,29.4200405 0.44077789,31.729919 0.44,34.23 L0.44,86.69 C0.44077789,89.190081 1.77486614,91.4999595 3.94,92.75 L49.36,119 C51.5258075,120.25043 54.1941925,120.25043 56.36,119 L78.06,106.47 L78.06,106.45 Z\" id=\"Path\" fill=\"url(#linearGradient-4)\" fill-rule=\"nonzero\"></path>\\n      </g>\\n    </g>\\n  </g>\\n</svg>';\n\n@Component({\n  selector: 'nz-demo-icon-namespace',\n  imports: [NzIconModule],\n  template: `<nz-icon nzType=\"ng-zorro:antd\" />`,\n  styles: `\n    nz-icon {\n      margin-right: 6px;\n      font-size: 24px;\n    }\n  `\n})\nexport class NzDemoIconNamespaceComponent {\n  constructor(private iconService: NzIconService) {\n    this.iconService.addIconLiteral('ng-zorro:antd', ngZorroIconLiteral);\n  }\n}\n"
  },
  {
    "path": "components/icon/demo/twotone.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 多色图标\n  en-US: Two-tone icon and colorful icon\n---\n\n## zh-CN\n\n可以通过设置 `nzTheme` 属性为 `twotone` 来渲染双色图标，并且可以设置主题色。\n\n## en-US\n\nSpecify property `nzTheme` to `twotone` to render two-tone icons. You can also set the primary color.\n"
  },
  {
    "path": "components/icon/demo/twotone.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-demo-icon-twotone',\n  imports: [NzIconModule],\n  template: `\n    <nz-icon nzType=\"smile\" nzTheme=\"twotone\" />\n    <nz-icon nzType=\"heart\" nzTheme=\"twotone\" nzTwotoneColor=\"#eb2f96\" />\n    <nz-icon nzType=\"check-circle\" nzTheme=\"twotone\" nzTwotoneColor=\"#52c41a\" />\n  `,\n  styles: `\n    nz-icon {\n      margin-right: 6px;\n      font-size: 24px;\n    }\n  `\n})\nexport class NzDemoIconTwotoneComponent {}\n"
  },
  {
    "path": "components/icon/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: General\ntitle: Icon\nhasPageDemo: true\ncover: 'https://gw.alipayobjects.com/zos/alicdn/rrwbSt3FQ/Icon.svg'\ndescription: Semantic vector graphics.\n---\n\n## List of icons\n\nWe keep in syncing with [antd](https://ant.design/components/icon/).\n\n## API\n\n### nz-icon, [nz-icon]\n\n| Property           | Description                         | Type                           | Default     | Global Config |\n| ------------------ | ----------------------------------- | ------------------------------ | ----------- | ------------- |\n| `[nzType]`         | Type of the ant design icon         | `string`                       | -           | -             |\n| `[nzTheme]`        | Type of the ant design icon         | `'fill'\\|'outline'\\|'twotone'` | `'outline'` | ✅            |\n| `[nzSpin]`         | Rotate icon with animation          | `boolean`                      | `false`     | -             |\n| `[nzTwotoneColor]` | Primary color of the two-tone icon. | `string (hex color)`           | -           | ✅            |\n| `[nzIconfont]`     | Type of the icon from iconfont      | `string`                       | -           | -             |\n| `[nzRotate]`       | Rotate degrees                      | `number`                       | -           | -             |\n\n### NzIconService\n\n| Methods                | Description                                                                   | Parameters               |\n| ---------------------- | ----------------------------------------------------------------------------- | ------------------------ |\n| `addIcon()`            | To import icons statically                                                    | `IconDefinition`         |\n| `addIconLiteral()`     | To statically import custom icons                                             | `string`, `string (SVG)` |\n| `fetchFromIconfont()`  | To get icon assets from iconfont                                              | `NzIconfontOption`       |\n| `changeAssetsSource()` | Change the location of your icon assets, so that you can deploy them anywhere | `string`                 |\n\n### SVG icons\n\nNG-ZORRO supports svg icons, which bring benefits below:\n\n- Support multiple colors.\n- Much more display accuracy in lower-level devices.\n- Able to change built-in icons with more props but no styles override.\n\nYou can use `nz-icon` component and specify the `theme` property.\n\n```html\n<nz-icon nzType=\"star\" nzTheme=\"fill\" />\n```\n\n### Static loading and dynamic loading\n\nAs for icons provided by Ant Design, there are two ways to import them into your project.\n\n**Static loading**. You can load icons statically by registering icons in `app.config.ts` with `provideNzIcons` API.\n\n```typescript\nimport { IconDefinition } from '@ant-design/icons-angular';\nimport { provideNzIcons } from 'ng-zorro-antd/icon';\n\n// Import what you need. RECOMMENDED. ✔️\nimport { AccountBookFill, AlertFill, AlertOutline } from '@ant-design/icons-angular/icons';\n\nconst icons: IconDefinition[] = [AccountBookFill, AlertOutline, AlertFill];\n\n// Import all. NOT RECOMMENDED. ❌\n// import * as AllIcons from '@ant-design/icons-angular/icons';\n\n// const antDesignIcons = AllIcons as Record<string, IconDefinition>;\n// const icons: IconDefinition[] = Object.keys(antDesignIcons).map(key => antDesignIcons[key])\n\nexport const appConfig: ApplicationConfig = {\n  providers: [provideNzIcons(icons)]\n};\n```\n\nActually this calls `addIcon` of `NzIconService`. Imported icons would be bundled into your `.js` files.\nStatic loading may increase your bundle size, thus we recommend to use dynamic importing.\n\n> Icons used by `NG-ZORRO` itself are imported statically to increase loading speed. However, icons demonstrated on the\n> official website are loaded dynamically.\n\n**Dynamic loading**. This way would not increase your bundle size. When NG-ZORRO detects that the icon you want to\nrender hasn't been registered yet, it would fire an HTTP request to load it. All you have to do is to config your\n`angular.json` like this:\n\n```json\n{\n  \"assets\": [\n    {\n      \"glob\": \"**/*\",\n      \"input\": \"./node_modules/@ant-design/icons-angular/src/inline-svg/\",\n      \"output\": \"/assets/\"\n    }\n  ]\n}\n```\n\nYou can call `changeAssetsSource()` of `NzIconService` to change the location of your icon assets, so that you can\ndeploy the assets to CDN. The parameter you passed would be added in front of `assets/`.\n\nAssume that you deploy the static assets under `https://mycdn.somecdn.com/icons/assets`. You can call\n`changeAssetsSource('https://mycdn.somecdn.com/icons')` to tell NG-ZORRO that all your resources are located there.\n\n### Add Icons in Lazy-loaded Components\n\nSometimes, you want to import icons in lazy components to avoid increasing the size of the `main.js`.\nYou can import icons in `providers` of the component or router with `provideNzIconsPatch` API.\n\n```typescript\nimport { NzIconModule, provideNzIconsPatch } from 'ng-zorro-antd/icon';\n\n// in xxx.component.ts\n@Component({\n  imports: [NzIconModule],\n  providers: [provideNzIconsPatch([QuestionOutline])]\n})\nclass ChildComponent {}\n\n// or in xxx.routes.ts\nconst routes: Routes = [\n  {\n    path: '',\n    providers: [provideNzIconsPatch([QuestionOutline])]\n  }\n];\n```\n\nOnce the QuestionOutline icon get loaded, it would be usable across the application.\n\n### Set Default TwoTone Color\n\nWhen using two-tone icons, you should provide a global configuration like `{ nzIcon: { nzTwotoneColor: 'xxx' } }` via `NzConfigService` or call corresponding `set` method to change to default twotone color.\n\n### Custom Font Icon\n\nWe provided a `fetchFromIconfont` method, which is specified for iconfont, to help you use your own icons deployed at [iconfont.cn](http://iconfont.cn/) in a convenient way.\n\n```typescript\nthis._iconService.fetchFromIconfont({\n  scriptUrl: 'https://at.alicdn.com/t/font_8d5l8fzk5b87iudi.js'\n});\n```\n\nAnd then you can use it like this:\n\n```html\n<nz-icon nzIconfont=\"icon-tuichu\" />\n```\n\nIt creates a component that uses SVG sprites in essence.\n\nThe following options are available:\n\n| Property    | Description                               | Type     | Default |\n| ----------- | ----------------------------------------- | -------- | ------- |\n| `scriptUrl` | The URL generated by iconfont.cn project. | `string` | -       |\n\nThe property `scriptUrl` should be set to import the svg sprite symbols.\n\nSee [iconfont.cn document](https://www.iconfont.cn/help/detail?helptype=code) to learn about how to generate the `scriptUrl`.\n\n### Namespace\n\nWe introduced namespace so you could add your own icons in a convenient way.\nWhen you want to render an icon, you could assign `type` `namespace:name`. Dynamic importing and static importing are both supported.\n\nStatic importing. Invoke `addIconLiteral` of `NzIconService`.\n\nDynamic importing. Make sure that you have put your SVG resources in directory like `assets/${namespace}`.\nFor example, if you have a `panda` icon and in `zoo` namespace, you should put the file `panda.svg` in `assets/zoo`.\n\n## FAQ\n\n### All my icons are gone!\n\nHave you ever read the docs above?\n\n### There are two similar icons in a `<span></span>` tag. What happened?\n\nIn older versions of NG-ZORRO, there was a font file which would use `:before` to insert an icon according to a `<i>` tag's `class`.\nSo if you have two icons, try to remove `node_modules` and install again. If the problem is still there, search `@icon-url` and remove that line.\n\n### I want to import all icons statically. What should I do?\n\nAlthough it is not recommended, actually we demonstrate it at section <a href=\"/components/icon/en#static-loading-and-dynamic-loading\">Static loading and dynamic loading</a>:\n\n```typescript\nimport * as AllIcons from '@ant-design/icons-angular/icons';\n\nconst antDesignIcons = AllIcons as Record<string, IconDefinition>;\nconst icons: IconDefinition[] = Object.keys(antDesignIcons).map(key => antDesignIcons[key]);\n```\n\n### Does dynamic loading affect web pages' performance?\n\nWe used several methods to reduce requests, such as static cache, dynamic cache and reusable request.\nIt's basically not noticeable for visitors that icons are loaded asynchronously assuming web connections are fairly good.\n\n### How do I know an icon's corresponding module to import?\n\nCapital camel-case `type & theme`, i.e. `alibaba` => `AlibabaOutline`.\n"
  },
  {
    "path": "components/icon/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 图标\ntype: 通用\ntitle: Icon\nhasPageDemo: true\ncover: 'https://gw.alipayobjects.com/zos/alicdn/rrwbSt3FQ/Icon.svg'\ndescription: 语义化的矢量图形。\n---\n\n## 图标列表\n\n新版图标可能略有缺失，我们将与 [Ant Design](https://ant.design/components/icon-cn/) 同步保持图标的更新。\n\n## API\n\n### nz-icon, [nz-icon]\n\n| 参数               | 说明                                                         | 类型                           | 默认值      | 支持全局配置 |\n| ------------------ | ------------------------------------------------------------ | ------------------------------ | ----------- | ------------ |\n| `[nzType]`         | 图标类型，遵循图标的命名规范                                 | string                         | -           | -            |\n| `[nzTheme]`        | 图标主题风格。可选实心、描线、双色等主题风格，适用于官方图标 | `'fill'丨'outline'丨'twotone'` | `'outline'` | ✅           |\n| `[nzSpin]`         | 是否有旋转动画                                               | `boolean`                      | `false`     | -            |\n| `[nzTwotoneColor]` | 双色图标的主要颜色，默认为 Ant Design 蓝色                   | `string (十六进制颜色)`        | -           | ✅           |\n| `[nzIconfont]`     | 指定来自 IconFont 的图标类型                                 | string                         | -           | -            |\n| `[nzRotate]`       | 图标旋转角度                                                 | `number`                       | -           | -            |\n\n### NzIconService\n\n| 方法                   | 说明                                                                               | 参数                     |\n| ---------------------- | ---------------------------------------------------------------------------------- | ------------------------ |\n| `addIcon()`            | 用于静态引入图标，可传入多个值（或者用数组解构赋值）                               | `IconDefinition`         |\n| `addIconLiteral()`     | 用于静态引入用户自定义图标                                                         | `string`, `string (SVG)` |\n| `fetchFromIconfont()`  | 用于从 IconFont 获取图标资源文件                                                   | `NzIconfontOption`       |\n| `changeAssetsSource()` | 用于修改动态加载图标的资源前缀，使得你可以部署图标资源到你想要的任何位置，例如 CDN | `string`                 |\n\n### SVG 图标\n\nNG-ZORRO 采用 svg 图标，带来了以下优势：\n\n- 支持多色图标。\n- 在低端设备上 SVG 有更好的清晰度。\n- 对于内建图标的更换可以提供更多 API，而无需样式覆盖。\n\n你可以使用 `nz-icon` 组件，传入 `theme` 以明确图标的主题风格，例如：\n\n```html\n<nz-icon nzType=\"star\" nzTheme=\"fill\" />\n```\n\n### 静态加载与动态加载\n\n对于 Ant Design 提供的图标，我们提供了两种方式来加载图标资源文件。\n\n**静态加载**，可以在 `app.config.ts` 中使用 `provideNzIcons` 引入你需要的图标（推荐）或者是全部的图标，例如：\n\n```typescript\nimport { IconDefinition } from '@ant-design/icons-angular';\nimport { provideNzIcons } from 'ng-zorro-antd/icon';\n\n// 引入你需要的图标，比如你需要 fill 主题的 AccountBook Alert 和 outline 主题的 Alert，推荐 ✔️\nimport { AccountBookFill, AlertFill, AlertOutline } from '@ant-design/icons-angular/icons';\n\nconst icons: IconDefinition[] = [AccountBookFill, AlertOutline, AlertFill];\n\n// 引入全部的图标，不推荐 ❌\n// import * as AllIcons from '@ant-design/icons-angular/icons';\n\n// const antDesignIcons = AllIcons as Record<string, IconDefinition>;\n// const icons: IconDefinition[] = Object.keys(antDesignIcons).map(key => antDesignIcons[key])\n\nexport const appConfig: ApplicationConfig = {\n  providers: [provideNzIcons(icons)]\n};\n```\n\n本质上是调用了 `NzIconService` 的 `addIcon` 方法，引入后的文件会被打包到 `.js` 文件中。\n静态引入会增加包体积，所以我们建议尽可能地使用动态加载，如果要静态加载，也仅仅加载你需要用到的图标。\n\n> 为了加快渲染速度，NG-ZORRO 本身用到的图标是静态引入的。官网的图标是动态引入的。\n\n**动态加载**，这是为了减少包体积而提供的方式。当 NG-ZORRO 检测用户想要渲染的图标还没有静态引入时，会发起 HTTP 请求动态引入。\n你只需要配置 `angular.json` 文件：\n\n```json\n{\n  \"assets\": [\n    {\n      \"glob\": \"**/*\",\n      \"input\": \"./node_modules/@ant-design/icons-angular/src/inline-svg/\",\n      \"output\": \"/assets/\"\n    }\n  ]\n}\n```\n\n你可以通过 `NzIconService` 的 `changeAssetsSource()` 方法来修改图标资源的位置，这样你就可以部署这些资源到 CDN 上。你的参数会被直接添加到 `assets/` 的前面。\n\n例如，你在 `https://mycdn.somecdn.com/icons/assets` 目录下部署了静态资源文件，则可以通过调用 `changeAssetsSource('https://mycdn.somecdn.com/icons')`，来告诉 NG-ZORRO 从这个位置动态加载图标资源。\n\n### 在子模块中补充图标\n\n有时候，为了避免增大 `main.js` 的体积，你可能想要在懒加载的组件中或路由的 `providers` 中使用 `provideNzIconsPatch` 来补充图标\n\n```typescript\nimport { NzIconModule, provideNzIconsPatch } from 'ng-zorro-antd/icon';\n\n// 在 xxx.component.ts 中\n@Component({\n  imports: [NzIconModule],\n  providers: [provideNzIconsPatch([QuestionOutline])]\n})\nclass ChildComponent {}\n\n// 或 在 xxx.routes.ts 中\nconst routes: Routes = [\n  {\n    path: '',\n    providers: [provideNzIconsPatch([QuestionOutline])]\n  }\n];\n```\n\n这样，当 QuestionOutline 图标加载之后，整个应用都能够使用它。\n\n### 双色图标主色\n\n对于双色图标，可以通过提供全局配置 `{ nzIcon: { nzTwotoneColor: 'xxx' } }` 或 `NzConfigService` 的对应方法修改来全局设置图标主色。\n\n### 自定义 font 图标\n\n我们提供了 `fetchFromIconfont` 方法，方便开发者调用在 [iconfont.cn](http://iconfont.cn/) 上自行管理的图标。\n\n```typescript\nthis._iconService.fetchFromIconfont({\n  scriptUrl: 'https://at.alicdn.com/t/font_8d5l8fzk5b87iudi.js'\n});\n```\n\n```html\n<nz-icon nzIconfont=\"icon-tuichu\" />\n```\n\n其本质上是创建了一个使用 `<use>` 标签渲染图标的组件。\n\n`options` 的配置项如下：\n\n| 参数        | 说明                                                                                           | 类型   | 默认值 |\n| ----------- | ---------------------------------------------------------------------------------------------- | ------ | ------ |\n| `scriptUrl` | [iconfont.cn](http://iconfont.cn/) 项目在线生成的 `js` 地址，在 `namespace` 也设置的情况下有效 | string | -      |\n\n在 `scriptUrl` 都设置有效的情况下，组件在渲染前会自动引入 [iconfont.cn](http://iconfont.cn/) 项目中的图标符号集，无需手动引入。\n\n见 [iconfont.cn 使用帮助](http://iconfont.cn/help/detail?spm=a313x.7781069.1998910419.15&helptype=code) 查看如何生成 js 地址。\n\n### 命名空间\n\n用户可以使用该功能方便地添加自己的图标。在渲染自定义图标时，只需要将 `type` 指定为 `namespace:name` 的形式，`nz-icon` 组件就会在用户自行添加的图标中进行检索并渲染。同时支持静态和动态引入。\n\n静态引入，只需要调用 `NzIconService` 的 `addIconLiteral` 方法即可。\n\n动态引入，只需要保证 SVG 资源文件放到了相应的目录，即 `assets/${namespace}`。\n例如你在 `zoo` 命名空间下有一个 `panda` 图标，你需要将 `panda.svg` 放到 `assets/zoo` 目录下。\n\n## 常见问题\n\n### 图标都不见了！\n\n你是不是没有阅读以上的文档？\n\n### 我想静态引入全部的图标，该怎么做？\n\n尽管这是不推荐的行为，实际上我们已经在 <a href=\"/components/icon/zh#%E9%9D%99%E6%80%81%E5%8A%A0%E8%BD%BD%E4%B8%8E%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD\">静态加载与动态加载</a> 部分演示过了：\n\n```typescript\nimport * as AllIcons from '@ant-design/icons-angular/icons';\n\nconst antDesignIcons = AllIcons as Record<string, IconDefinition>;\nconst icons: IconDefinition[] = Object.keys(antDesignIcons).map(key => antDesignIcons[key]);\n```\n\n然后通过 `provideNzIcons` 或者 `NzIconService` 的 `addIcon` 方法引入。\n\n### 动态加载会不会影响网页的性能？\n\n我们用了多种手段来尽量减少动态请求，包括先静态后动态、缓存和相同图标的请求复用，用户很少能感知到图标是异步加载的。\n在网络环境尚可的情况下，即使是有三百多个图标同时展示的 NG-ZORRO 官网，也基本没有卡顿。\n对于加载速度要求更高的用户，我们也支持 CDN。\n\n### 我怎么知道一个图标的静态引入名？\n\n很简单，大写驼峰加主题即为图标的引入名。比如 `alibaba` 的引入名就是 `AlibabaOutline`，事实上，编辑器的自动补全能帮助到你。\n"
  },
  {
    "path": "components/icon/icon.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n  AfterContentChecked,\n  ChangeDetectorRef,\n  DestroyRef,\n  Directive,\n  Input,\n  NgZone,\n  OnChanges,\n  PLATFORM_ID,\n  PendingTasks,\n  Renderer2,\n  SimpleChanges,\n  booleanAttribute,\n  inject,\n  numberAttribute\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { animationFrameScheduler, asapScheduler, debounceTime, finalize } from 'rxjs';\n\nimport { IconDirective, ThemeType } from '@ant-design/icons-angular';\n\nimport { warn } from 'ng-zorro-antd/core/logger';\nimport { wrapIntoObservable } from 'ng-zorro-antd/core/util';\n\nimport { NzIconPatchService, NzIconService } from './icon.service';\n\n@Directive({\n  selector: 'nz-icon,[nz-icon]',\n  exportAs: 'nzIcon',\n  host: {\n    class: 'anticon',\n    '[class]': `'anticon-' + type`,\n    '[class.anticon-spin]': `nzSpin || type === 'loading'`,\n    role: 'img',\n    '[attr.aria-label]': 'type'\n  }\n})\nexport class NzIconDirective extends IconDirective implements OnChanges, AfterContentChecked {\n  private readonly ngZone = inject(NgZone);\n  private readonly changeDetectorRef = inject(ChangeDetectorRef);\n  public readonly renderer = inject(Renderer2);\n  private destroyRef = inject(DestroyRef);\n  private pendingTasks = inject(PendingTasks);\n  private isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n  @Input({ transform: booleanAttribute }) nzSpin: boolean = false;\n  @Input({ transform: numberAttribute }) nzRotate: number = 0;\n  @Input()\n  set nzType(value: string) {\n    this.type = value;\n  }\n\n  @Input()\n  set nzTheme(value: ThemeType) {\n    this.theme = value;\n  }\n\n  @Input()\n  set nzTwotoneColor(value: string) {\n    this.twoToneColor = value;\n  }\n\n  @Input()\n  set nzIconfont(value: string) {\n    this.iconfont = value;\n  }\n\n  hostClass?: string;\n\n  private readonly el: HTMLElement;\n  private iconfont?: string;\n\n  constructor(public readonly iconService: NzIconService) {\n    super(iconService);\n    inject(NzIconPatchService, { optional: true })?.doPatch();\n    this.el = this._elementRef.nativeElement;\n  }\n\n  override ngOnChanges(changes: SimpleChanges): void {\n    const { nzType, nzTwotoneColor, nzTheme, nzRotate, nzSpin } = changes;\n\n    if (nzType || nzTwotoneColor || nzTheme || nzSpin) {\n      // This is used to reduce the number of change detections\n      // while the icon is being loaded asynchronously.\n      this.ngZone.runOutsideAngular(() => this.changeIcon2());\n    } else if (nzRotate) {\n      this.handleRotate(this.el.firstChild as SVGElement);\n    } else {\n      this._setSVGElement(this.iconService.createIconfontIcon(`#${this.iconfont}`));\n    }\n  }\n\n  /**\n   * If custom content is provided, try to normalize SVG elements.\n   */\n  ngAfterContentChecked(): void {\n    if (!this.type) {\n      const children = this.el.children;\n      let length = children.length;\n      if (!this.type && children.length) {\n        while (length--) {\n          const child = children[length];\n          if (child.tagName.toLowerCase() === 'svg') {\n            this.iconService.normalizeSvgElement(child as SVGElement);\n          }\n        }\n      }\n    }\n  }\n\n  /**\n   * Replacement of `changeIcon` for more modifications.\n   */\n  private changeIcon2(): void {\n    // It is used to hydrate the icon component properly when\n    // zoneless change detection is used in conjunction with server-side rendering.\n    const removeTask = this.pendingTasks.add();\n\n    const svgOrRemove$ = wrapIntoObservable(this._changeIcon()).pipe(\n      // We need to individually debounce the icon rendering on each animation\n      // frame to prevent frame drops when many icons are being rendered on the\n      // page, such as in a `@for` loop.\n      debounceTime(0, this.isBrowser ? animationFrameScheduler : asapScheduler),\n      takeUntilDestroyed(this.destroyRef),\n      finalize(removeTask)\n    );\n\n    svgOrRemove$.subscribe({\n      next: svgOrRemove => {\n        // Get back into the Angular zone after completing all the tasks.\n        // Since we manually run change detection locally, we have to re-enter\n        // the zone because the change detection might also be run on other local\n        // components, leading them to handle template functions outside of the Angular zone.\n        this.ngZone.run(() => {\n          // The _changeIcon method would call Renderer to remove the element of the old icon,\n          // which would call `markElementAsRemoved` eventually,\n          // so we should call `detectChanges` to tell Angular remove the DOM node.\n          // #7186\n          this.changeDetectorRef.detectChanges();\n\n          if (svgOrRemove) {\n            this.setSVGData(svgOrRemove);\n            this.handleRotate(svgOrRemove);\n          }\n        });\n      },\n      error: warn\n    });\n  }\n\n  private handleRotate(svg: SVGElement): void {\n    if (this.nzRotate) {\n      this.renderer.setAttribute(svg, 'style', `transform: rotate(${this.nzRotate}deg)`);\n    } else {\n      this.renderer.removeAttribute(svg, 'style');\n    }\n  }\n\n  private setSVGData(svg: SVGElement): void {\n    this.renderer.setAttribute(svg, 'data-icon', this.type as string);\n    this.renderer.setAttribute(svg, 'aria-hidden', 'true');\n  }\n}\n"
  },
  {
    "path": "components/icon/icon.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ModuleWithProviders, NgModule } from '@angular/core';\n\nimport { IconDefinition } from '@ant-design/icons-angular';\n\nimport { NzIconDirective } from './icon.directive';\nimport { provideNzIcons, provideNzIconsPatch } from './provide-icons';\n\n@NgModule({\n  imports: [NzIconDirective],\n  exports: [NzIconDirective]\n})\nexport class NzIconModule {\n  static forRoot(icons: IconDefinition[]): ModuleWithProviders<NzIconModule> {\n    return {\n      ngModule: NzIconModule,\n      providers: [provideNzIcons(icons)]\n    };\n  }\n\n  static forChild(icons: IconDefinition[]): ModuleWithProviders<NzIconModule> {\n    return {\n      ngModule: NzIconModule,\n      providers: [provideNzIconsPatch(icons)]\n    };\n  }\n}\n"
  },
  {
    "path": "components/icon/icon.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Platform } from '@angular/cdk/platform';\nimport { inject, Injectable, InjectionToken } from '@angular/core';\nimport { Subject } from 'rxjs';\n\nimport { IconDefinition, IconService } from '@ant-design/icons-angular';\n\nimport { IconConfig, NzConfigService, onConfigChangeEventForComponent } from 'ng-zorro-antd/core/config';\nimport { warn } from 'ng-zorro-antd/core/logger';\n\nimport { NZ_ICONS_USED_BY_ZORRO } from './icons';\n\nexport interface NzIconfontOption {\n  scriptUrl: string;\n}\n\nexport const NZ_ICONS = new InjectionToken<IconDefinition[]>(\n  typeof ngDevMode !== 'undefined' && ngDevMode ? 'nz-icons' : ''\n);\nexport const NZ_ICON_DEFAULT_TWOTONE_COLOR = new InjectionToken(\n  typeof ngDevMode !== 'undefined' && ngDevMode ? 'nz-icon-default-twotone-color' : ''\n);\nexport const DEFAULT_TWOTONE_COLOR = '#1890ff';\n\n/**\n * It should be a global singleton, otherwise registered icons could not be found.\n */\n@Injectable({\n  providedIn: 'root'\n})\nexport class NzIconService extends IconService {\n  protected nzConfigService = inject(NzConfigService);\n  private platform = inject(Platform);\n\n  configUpdated$ = new Subject<void>();\n\n  protected override get _disableDynamicLoading(): boolean {\n    return !this.platform.isBrowser;\n  }\n\n  private iconfontCache = new Set<string>();\n\n  normalizeSvgElement(svg: SVGElement): void {\n    if (!svg.getAttribute('viewBox')) {\n      this._renderer.setAttribute(svg, 'viewBox', '0 0 1024 1024');\n    }\n    if (!svg.getAttribute('width') || !svg.getAttribute('height')) {\n      this._renderer.setAttribute(svg, 'width', '1em');\n      this._renderer.setAttribute(svg, 'height', '1em');\n    }\n    if (!svg.getAttribute('fill')) {\n      this._renderer.setAttribute(svg, 'fill', 'currentColor');\n    }\n  }\n\n  fetchFromIconfont(opt: NzIconfontOption): void {\n    const { scriptUrl } = opt;\n    if (this._document && !this.iconfontCache.has(scriptUrl)) {\n      const script = this._renderer.createElement('script');\n      this._renderer.setAttribute(script, 'src', scriptUrl);\n      this._renderer.setAttribute(script, 'data-namespace', scriptUrl.replace(/^(https?|http):/g, ''));\n      this._renderer.appendChild(this._document.body, script);\n      this.iconfontCache.add(scriptUrl);\n    }\n  }\n\n  createIconfontIcon(type: string): SVGElement {\n    return this._createSVGElementFromString(`<svg><use xlink:href=\"${type}\"></svg>`);\n  }\n\n  constructor() {\n    super([...NZ_ICONS_USED_BY_ZORRO, ...(inject(NZ_ICONS, { optional: true }) || [])]);\n\n    this.onConfigChange();\n    this.configDefaultTwotoneColor();\n    this.configDefaultTheme();\n  }\n\n  private onConfigChange(): void {\n    onConfigChangeEventForComponent('icon', () => {\n      this.configDefaultTwotoneColor();\n      this.configDefaultTheme();\n      this.configUpdated$.next();\n    });\n  }\n\n  private configDefaultTheme(): void {\n    const iconConfig = this.getConfig();\n    this.defaultTheme = iconConfig.nzTheme || 'outline';\n  }\n\n  private configDefaultTwotoneColor(): void {\n    const iconConfig = this.getConfig();\n    const defaultTwotoneColor = iconConfig.nzTwotoneColor || DEFAULT_TWOTONE_COLOR;\n\n    let primaryColor = DEFAULT_TWOTONE_COLOR;\n\n    if (defaultTwotoneColor) {\n      if (defaultTwotoneColor.startsWith('#')) {\n        primaryColor = defaultTwotoneColor;\n      } else {\n        warn('Twotone color must be a hex color!');\n      }\n    }\n\n    this.twoToneColor = { primaryColor };\n  }\n\n  private getConfig(): IconConfig {\n    return this.nzConfigService.getConfigForComponent('icon') || {};\n  }\n}\n\nexport const NZ_ICONS_PATCH = new InjectionToken<IconDefinition[]>('nz_icons_patch');\n\n@Injectable()\nexport class NzIconPatchService {\n  patched = false;\n  private extraIcons = inject(NZ_ICONS_PATCH, { self: true });\n\n  constructor(private rootIconService: NzIconService) {}\n\n  doPatch(): void {\n    if (this.patched) {\n      return;\n    }\n\n    this.extraIcons.forEach(iconDefinition => this.rootIconService.addIcon(iconDefinition));\n    this.patched = true;\n  }\n}\n"
  },
  {
    "path": "components/icon/icon.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, DebugElement, NgModule, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport {\n  HomeOutline,\n  LeftOutline,\n  LoadingOutline,\n  QuestionCircleFill,\n  QuestionCircleOutline,\n  QuestionOutline,\n  RightOutline\n} from '@ant-design/icons-angular/icons';\n\nimport { NzConfigService } from 'ng-zorro-antd/core/config';\n\nimport { NzIconDirective } from './icon.directive';\nimport { NzIconModule } from './icon.module';\nimport { NzIconService } from './icon.service';\nimport { provideNzIcons, provideNzIconsPatch } from './provide-icons';\n\ndescribe('nz-icon', () => {\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [\n        // todo: use zoneless\n        provideZoneChangeDetection(),\n        provideNzIcons([\n          LeftOutline,\n          RightOutline,\n          QuestionOutline,\n          QuestionCircleOutline,\n          LoadingOutline,\n          QuestionCircleFill\n        ])\n      ]\n    });\n  });\n\n  describe('basic', () => {\n    let testComponent: NzTestIconExtensionsComponent;\n    let fixture: ComponentFixture<NzTestIconExtensionsComponent>;\n    let icons: DebugElement[];\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestIconExtensionsComponent);\n      testComponent = fixture.componentInstance;\n      icons = fixture.debugElement.queryAll(By.directive(NzIconDirective));\n    });\n\n    it('should get icon class name back', () => {\n      fixture.detectChanges();\n      expect(icons[0].nativeElement.classList.contains('anticon')).toBe(true);\n      expect(icons[0].nativeElement.classList.contains('anticon-question')).toBe(true);\n      expect(icons[1].nativeElement.classList.contains('anticon-loading')).toBe(true);\n    });\n\n    it('should change class name when type changes', () => {\n      testComponent.type = 'question-circle';\n      fixture.detectChanges();\n      expect(icons[0].nativeElement.classList.contains('anticon')).toBe(true);\n      expect(icons[0].nativeElement.classList.contains('anticon-question-circle')).toBe(true);\n      expect(icons[0].nativeElement.classList.contains('anticon-question')).not.toBe(true);\n    });\n\n    it('should support spin and cancel', fakeAsync(() => {\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n      // Only test fails. Don't know why.\n      // expect(icons[0].nativeElement.firstChild.classList.contains('anticon-spin')).toBe(true);\n\n      testComponent.spin = false;\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n      expect(icons[0].nativeElement.firstChild.classList.contains('anticon-spin')).toBe(false);\n    }));\n\n    it('should make loading spin', fakeAsync(() => {\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n      // expect(icons[1].nativeElement.firstChild.classList.contains('anticon-spin')).toBe(true);\n    }));\n\n    it('should rotate work', fakeAsync(() => {\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n      expect(icons[0].nativeElement.firstChild.style.transform).toBeFalsy();\n\n      testComponent.rotate = 120;\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n      expect(icons[0].nativeElement.firstChild.style.transform).toBe('rotate(120deg)');\n\n      testComponent.rotate = 0;\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n      expect(icons[0].nativeElement.firstChild.style.transform).toBeFalsy();\n    }));\n  });\n\n  describe('custom', () => {\n    let fixture: ComponentFixture<NzTestIconCustomComponent>;\n    let icons: DebugElement[];\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestIconCustomComponent);\n      fixture.detectChanges();\n    });\n\n    it('should support custom svg element', () => {\n      icons = fixture.debugElement.queryAll(By.directive(NzIconDirective));\n      expect(icons[0].nativeElement.className).toContain('anticon');\n      expect(icons[0].nativeElement.innerHTML).toContain('svg');\n      expect(icons[0].nativeElement.innerHTML).toContain(\n        'viewBox=\"0 0 1024 1024\" width=\"1em\" height=\"1em\" fill=\"currentColor\"'\n      );\n    });\n  });\n\n  describe('iconfont', () => {\n    let fixture: ComponentFixture<NzTestIconIconfontComponent>;\n    let icons: DebugElement[];\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestIconIconfontComponent);\n      fixture.detectChanges();\n    });\n\n    it('should support iconfont', async () => {\n      await fixture.whenStable();\n      icons = fixture.debugElement.queryAll(By.directive(NzIconDirective));\n      expect(icons[0].nativeElement.className).toContain('anticon');\n      expect(icons[0].nativeElement.innerHTML).toContain('xlink:href=\"#icon-tuichu\"');\n      expect(icons[1].nativeElement.innerHTML).toContain('link:href=\"#icon-facebook\"');\n      expect(icons[2].nativeElement.innerHTML).toContain('xlink:href=\"#icon-twitter\"');\n    });\n  });\n\n  describe('config service', () => {\n    let fixture: ComponentFixture<NzTestIconExtensionsComponent>;\n    let nzConfigService: NzConfigService;\n    let icons: DebugElement[];\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestIconExtensionsComponent);\n      fixture.detectChanges();\n      icons = fixture.debugElement.queryAll(By.directive(NzIconDirective));\n      nzConfigService = TestBed.inject(NzConfigService);\n    });\n\n    it('should support config service', () => {\n      nzConfigService!.set('icon', { nzTwotoneColor: '#234567' });\n      expect(icons[0].componentInstance.iconService.twoToneColor.primaryColor).toBe('#234567');\n\n      // Should ignore invalid value.\n      nzConfigService!.set('icon', { nzTwotoneColor: '234567' });\n      expect(icons[0].componentInstance.iconService.twoToneColor.primaryColor).not.toBe('234567');\n      expect(icons[0].componentInstance.iconService.twoToneColor.primaryColor).toBe('#1890ff');\n    });\n  });\n});\n\ndescribe('nz-icon injection', () => {\n  describe('injection on multi places', () => {\n    let fixture: ComponentFixture<NzTestIconMultiInjectionComponent>;\n    let icons: DebugElement[];\n\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        providers: [provideNzIcons([HomeOutline])]\n      });\n    });\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestIconMultiInjectionComponent);\n      fixture.detectChanges();\n    });\n\n    it('should support forRoot and forChild', () => {\n      fixture.detectChanges();\n      icons = fixture.debugElement.queryAll(By.directive(NzIconDirective));\n      expect(icons[0].nativeElement.classList.contains('anticon-home')).toBe(true);\n      expect(icons[1].nativeElement.classList.contains('anticon-question')).toBe(true);\n    });\n  });\n\n  describe('[standalone] injection on multi places', () => {\n    let fixture: ComponentFixture<NzTestIconMultiInjectionStandaloneComponent>;\n\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        providers: [provideNzIcons([HomeOutline])]\n      });\n    });\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestIconMultiInjectionStandaloneComponent);\n      fixture.detectChanges();\n    });\n\n    it('should support forRoot and forChild', () => {\n      const icons = fixture.debugElement.queryAll(By.directive(NzIconDirective));\n      expect(icons[0].nativeElement.classList.contains('anticon-home')).toBe(true);\n      expect(icons[1].nativeElement.classList.contains('anticon-question')).toBe(true);\n    });\n  });\n});\n\n@Component({\n  imports: [NzIconModule],\n  template: `\n    <nz-icon [nzType]=\"type\" [nzTheme]=\"theme\" [nzSpin]=\"spin\" [nzRotate]=\"rotate\" />\n    <nz-icon nzType=\"loading\" [nzTheme]=\"theme\" />\n  `\n})\nexport class NzTestIconExtensionsComponent {\n  type = 'question';\n  theme: 'fill' | 'outline' | 'twotone' = 'outline';\n  spin = true;\n  rotate = 0;\n\n  constructor(public iconService: NzIconService) {}\n}\n\n@Component({\n  imports: [NzIconModule],\n  template: `\n    <nz-icon style=\"color: hotpink;\">\n      <svg>\n        <path\n          d=\"M923 283.6c-13.4-31.1-32.6-58.9-56.9-82.8-24.3-23.8-52.5-42.4-84-55.5-32.5-13.5-66.9-20.3-102.4-20.3-49.3 0-97.4 13.5-139.2 39-10 6.1-19.5 12.8-28.5 20.1-9-7.3-18.5-14-28.5-20.1-41.8-25.5-89.9-39-139.2-39-35.5 0-69.9 6.8-102.4 20.3-31.4 13-59.7 31.7-84 55.5-24.4 23.9-43.5 51.7-56.9 82.8-13.9 32.3-21 66.6-21 101.9 0 33.3 6.8 68 20.3 103.3 11.3 29.5 27.5 60.1 48.2 91 32.8 48.9 77.9 99.9 133.9 151.6 92.8 85.7 184.7 144.9 188.6 147.3l23.7 15.2c10.5 6.7 24 6.7 34.5 0l23.7-15.2c3.9-2.5 95.7-61.6 188.6-147.3 56-51.7 101.1-102.7 133.9-151.6 20.7-30.9 37-61.5 48.2-91 13.5-35.3 20.3-70 20.3-103.3 0.1-35.3-7-69.6-20.9-101.9z\"\n        />\n      </svg>\n    </nz-icon>\n  `\n})\nexport class NzTestIconCustomComponent {}\n\n@Component({\n  imports: [NzIconModule],\n  template: `\n    <nz-icon nzIconfont=\"icon-tuichu\" />\n    <nz-icon nzIconfont=\"icon-facebook\" />\n    <nz-icon nzIconfont=\"icon-twitter\" />\n  `\n})\nexport class NzTestIconIconfontComponent {\n  constructor(private iconService: NzIconService) {\n    this.iconService.fetchFromIconfont({\n      scriptUrl: 'https://at.alicdn.com/t/font_8d5l8fzk5b87iudi.js'\n    });\n  }\n}\n\n@NgModule({\n  imports: [NzIconModule.forChild([QuestionOutline])]\n})\nclass ChildModule {}\n\n@Component({\n  imports: [NzIconModule, ChildModule],\n  template: `\n    <nz-icon nzType=\"home\" />\n    <nz-icon nzType=\"question\" />\n  `\n})\nclass NzTestIconMultiInjectionComponent {}\n\n@Component({\n  imports: [NzIconModule],\n  providers: [provideNzIconsPatch([QuestionOutline])],\n  template: `\n    <nz-icon nzType=\"home\" />\n    <nz-icon nzType=\"question\" />\n  `\n})\nclass NzTestIconMultiInjectionStandaloneComponent {}\n"
  },
  {
    "path": "components/icon/icons.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { IconDefinition } from '@ant-design/icons-angular';\nimport {\n  BarsOutline,\n  CalendarOutline,\n  CaretDownFill,\n  CaretDownOutline,\n  CaretUpFill,\n  CaretUpOutline,\n  CheckCircleFill,\n  CheckCircleOutline,\n  CheckOutline,\n  ClockCircleOutline,\n  CloseCircleFill,\n  CloseCircleOutline,\n  CloseOutline,\n  CopyOutline,\n  DeleteOutline,\n  DoubleLeftOutline,\n  DoubleRightOutline,\n  DownOutline,\n  EditOutline,\n  EllipsisOutline,\n  ExclamationCircleFill,\n  ExclamationCircleOutline,\n  EyeInvisibleOutline,\n  EyeOutline,\n  FileFill,\n  FileOutline,\n  FilterFill,\n  InfoCircleFill,\n  InfoCircleOutline,\n  LeftOutline,\n  LoadingOutline,\n  PaperClipOutline,\n  QuestionCircleOutline,\n  RightOutline,\n  RotateLeftOutline,\n  RotateRightOutline,\n  SearchOutline,\n  StarFill,\n  SwapOutline,\n  SwapRightOutline,\n  UploadOutline,\n  UpOutline,\n  VerticalAlignTopOutline,\n  ZoomInOutline,\n  ZoomOutOutline\n} from '@ant-design/icons-angular/icons';\n\nexport const NZ_ICONS_USED_BY_ZORRO: IconDefinition[] = [\n  BarsOutline,\n  CalendarOutline,\n  CaretUpFill,\n  CaretUpOutline,\n  CaretDownFill,\n  CaretDownOutline,\n  CheckCircleFill,\n  CheckCircleOutline,\n  CheckOutline,\n  ClockCircleOutline,\n  CloseCircleOutline,\n  CloseCircleFill,\n  CloseOutline,\n  CopyOutline,\n  DeleteOutline,\n  DoubleLeftOutline,\n  DoubleRightOutline,\n  DownOutline,\n  EditOutline,\n  EllipsisOutline,\n  ExclamationCircleFill,\n  ExclamationCircleOutline,\n  EyeOutline,\n  EyeInvisibleOutline,\n  FileFill,\n  FileOutline,\n  FilterFill,\n  InfoCircleFill,\n  InfoCircleOutline,\n  LeftOutline,\n  LoadingOutline,\n  PaperClipOutline,\n  QuestionCircleOutline,\n  RightOutline,\n  RotateRightOutline,\n  RotateLeftOutline,\n  StarFill,\n  SearchOutline,\n  StarFill,\n  UploadOutline,\n  VerticalAlignTopOutline,\n  UpOutline,\n  SwapOutline,\n  SwapRightOutline,\n  ZoomInOutline,\n  ZoomOutOutline\n];\n"
  },
  {
    "path": "components/icon/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/icon/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/icon/page/en-US.txt",
    "content": "{\n  chooseTheme: 'Select the Icon Theme',\n  direction: 'Directional Icons',\n  suggestion: 'Suggested Icons',\n  edit: 'Editor Icons',\n  data: 'Data Icons',\n  other: 'Application Icons',\n  logo: 'Brand and Logos',\n  search: 'Search icon here. Click icon to copy code.',\n  picSearcherIntro: 'AI Search by image is online, you are welcome to use it! 🎉',\n  picSearcherMatching: 'Matching...',\n  picSearcherModelLoading: 'Model is loading...',\n  picSearcherResultTip: 'Matched the following icons for you:',\n  picSearcherServerError: 'Predict service is temporarily unavailable',\n  picSearcherThIcon: 'Icon',\n  picSearcherThScore: 'Probability',\n  picSearcherTitle: 'Search by image',\n  picSearcherUploadHint: 'We will find the best matching icon based on the image provided',\n  picSearcherUploadText: 'Click, drag, or paste file to this area to upload'\n}\n"
  },
  {
    "path": "components/icon/page/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n  Component,\n  DestroyRef,\n  DOCUMENT,\n  inject,\n  Input,\n  OnInit,\n  PLATFORM_ID,\n  TemplateRef,\n  ViewChild,\n  ViewContainerRef\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { of, Subscription } from 'rxjs';\n\nimport { manifest, ThemeType } from '@ant-design/icons-angular';\nimport { AccountBookFill } from '@ant-design/icons-angular/icons';\n\nimport { NzBadgeModule } from 'ng-zorro-antd/badge';\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { PREFIX } from 'ng-zorro-antd/core/logger';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { NzIconModule, NzIconService } from 'ng-zorro-antd/icon';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzMessageService } from 'ng-zorro-antd/message';\nimport { NzModalModule } from 'ng-zorro-antd/modal';\nimport { NzPopoverModule } from 'ng-zorro-antd/popover';\nimport { NzProgressModule } from 'ng-zorro-antd/progress';\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\nimport { NzResultModule } from 'ng-zorro-antd/result';\nimport { NzSpinModule } from 'ng-zorro-antd/spin';\nimport { NzTooltipModule } from 'ng-zorro-antd/tooltip';\nimport { NzUploadFile, NzUploadModule, NzUploadXHRArgs } from 'ng-zorro-antd/upload';\n\nexport interface Categories {\n  direction: string[];\n  suggestion: string[];\n  logo: string[];\n  data: string[];\n  edit: string[];\n  other?: string[];\n}\n\ndeclare global {\n  interface Window {\n    antdIconClassifier: AntdIconClassifier;\n  }\n}\n\ninterface AntdIconClassifier {\n  load: () => Promise<void>;\n  predict: (element: HTMLElement) => Result[];\n}\n\ninterface Result {\n  className: string;\n  score: number;\n}\n\ninterface Icon {\n  type: string;\n  score: number;\n}\n\nconst direction = [\n  'StepBackward',\n  'StepForward',\n  'FastBackward',\n  'FastForward',\n  'Shrink',\n  'ArrowsAlt',\n  'Down',\n  'Up',\n  'Left',\n  'Right',\n  'CaretUp',\n  'CaretDown',\n  'CaretLeft',\n  'CaretRight',\n  'UpCircle',\n  'DownCircle',\n  'LeftCircle',\n  'RightCircle',\n  'DoubleRight',\n  'DoubleLeft',\n  'VerticalLeft',\n  'VerticalRight',\n  'VerticalAlignTop',\n  'VerticalAlignMiddle',\n  'VerticalAlignBottom',\n  'Forward',\n  'Backward',\n  'Rollback',\n  'Enter',\n  'Retweet',\n  'Swap',\n  'SwapLeft',\n  'SwapRight',\n  'ArrowUp',\n  'ArrowDown',\n  'ArrowLeft',\n  'ArrowRight',\n  'PlayCircle',\n  'UpSquare',\n  'DownSquare',\n  'LeftSquare',\n  'RightSquare',\n  'Login',\n  'Logout',\n  'MenuFold',\n  'MenuUnfold',\n  'BorderBottom',\n  'BorderHorizontal',\n  'BorderInner',\n  'BorderOuter',\n  'BorderLeft',\n  'BorderRight',\n  'BorderTop',\n  'BorderVerticle',\n  'PicCenter',\n  'PicLeft',\n  'PicRight',\n  'RadiusBottomleft',\n  'RadiusBottomright',\n  'RadiusUpleft',\n  'RadiusUpright',\n  'Fullscreen',\n  'FullscreenExit'\n];\n\nconst suggestion = [\n  'Question',\n  'QuestionCircle',\n  'Plus',\n  'PlusCircle',\n  'Pause',\n  'PauseCircle',\n  'Minus',\n  'MinusCircle',\n  'PlusSquare',\n  'MinusSquare',\n  'Info',\n  'InfoCircle',\n  'Exclamation',\n  'ExclamationCircle',\n  'Close',\n  'CloseCircle',\n  'CloseSquare',\n  'Check',\n  'CheckCircle',\n  'CheckSquare',\n  'ClockCircle',\n  'Warning',\n  'IssuesClose',\n  'Stop'\n];\n\nconst edit = [\n  'Edit',\n  'Form',\n  'Copy',\n  'Scissor',\n  'Delete',\n  'Snippets',\n  'Diff',\n  'Highlight',\n  'AlignCenter',\n  'AlignLeft',\n  'AlignRight',\n  'BgColors',\n  'Bold',\n  'Italic',\n  'Underline',\n  'Strikethrough',\n  'Redo',\n  'Undo',\n  'ZoomIn',\n  'ZoomOut',\n  'FontColors',\n  'FontSize',\n  'LineHeight',\n  'Dash',\n  'SmallDash',\n  'SortAscending',\n  'SortDescending',\n  'Drag',\n  'OrderedList',\n  'UnorderedList',\n  'RadiusSetting',\n  'ColumnWidth',\n  'ColumnHeight'\n];\n\nconst data = [\n  'AreaChart',\n  'PieChart',\n  'BarChart',\n  'DotChart',\n  'LineChart',\n  'RadarChart',\n  'HeatMap',\n  'Fall',\n  'Rise',\n  'Stock',\n  'BoxPlot',\n  'Fund',\n  'Sliders'\n];\n\nconst logo = [\n  'Android',\n  'Apple',\n  'Windows',\n  'Linux',\n  'Ie',\n  'Chrome',\n  'Github',\n  'Aliwangwang',\n  'Dingding',\n  'Dingtalk',\n  'WeiboSquare',\n  'WeiboCircle',\n  'Weibo',\n  'Taobao',\n  'TaobaoCircle',\n  'Twitter',\n  'Wechat',\n  'Youtube',\n  'AlipayCircle',\n  'Skype',\n  'Qq',\n  'MediumWorkmark',\n  'Gitlab',\n  'Medium',\n  'Linkedin',\n  'GooglePlus',\n  'Dropbox',\n  'Facebook',\n  'Html5',\n  'Java',\n  'JavaScript',\n  'Python',\n  'Docker',\n  'Kubernetes',\n  'Ruby',\n  'DotNet',\n  'Codepen',\n  'CodeSandbox',\n  'CodeSandboxCircle',\n  'Amazon',\n  'Google',\n  'CodepenCircle',\n  'Alipay',\n  'AntDesign',\n  'AntCloud',\n  'Aliyun',\n  'Zhihu',\n  'Slack',\n  'SlackSquare',\n  'Behance',\n  'BehanceSquare',\n  'Dribbble',\n  'DribbbleSquare',\n  'Instagram',\n  'Yuque',\n  'Alibaba',\n  'Yahoo',\n  'Reddit',\n  'Discord',\n  'Sketch',\n  'Baidu',\n  'Bilibili',\n  'HarmonyOS',\n  'OpenAI',\n  'Pinterest',\n  'Spotify',\n  'TikTok',\n  'Twitch',\n  'WechatWork',\n  'WhatsApp',\n  'X'\n];\n\nconst categories: Categories = {\n  direction,\n  suggestion,\n  edit,\n  data,\n  logo\n};\n\nconst newIconNames: string[] = [\n  // direction\n  'border-outter',\n  'radius-upright',\n  // suggestion\n  // edit\n  'colum-width',\n  // data\n  // other\n  'eye-invisible',\n  'batch-folding',\n  // logo\n  'code-sandbox',\n  'code-sandbox-circle'\n];\n\ndeclare const locale: NzSafeAny;\n\n@Component({\n  selector: 'nz-page-demo-icon',\n  imports: [\n    FormsModule,\n    NzBadgeModule,\n    NzButtonModule,\n    NzIconModule,\n    NzInputModule,\n    NzModalModule,\n    NzPopoverModule,\n    NzRadioModule,\n    NzResultModule,\n    NzSpinModule,\n    NzTooltipModule,\n    NzProgressModule,\n    NzUploadModule\n  ],\n  template: `\n    <h3>{{ localeObj.chooseTheme }}</h3>\n    <div class=\"icon-selector\">\n      <nz-radio-group [ngModel]=\"currentTheme\" (ngModelChange)=\"setIconsShouldBeDisplayed($event)\">\n        <label nz-radio-button nzValue=\"outline\">\n          <nz-icon>\n            <svg>\n              <path\n                d=\"M864 64H160C107 64 64 107 64 160v704c0 53 43 96 96 96h704c53 0 96-43 96-96V160c0-53-43-96-96-96z m-12 800H172c-6.6 0-12-5.4-12-12V172c0-6.6 5.4-12 12-12h680c6.6 0 12 5.4 12 12v680c0 6.6-5.4 12-12 12z\"\n              />\n            </svg>\n          </nz-icon>\n          Outlined\n        </label>\n        <label nz-radio-button nzValue=\"fill\">\n          <nz-icon>\n            <svg>\n              <path\n                d=\"M864 64H160C107 64 64 107 64 160v704c0 53 43 96 96 96h704c53 0 96-43 96-96V160c0-53-43-96-96-96z\"\n              />\n            </svg>\n          </nz-icon>\n          Filled\n        </label>\n        <label nz-radio-button nzValue=\"twotone\">\n          <nz-icon>\n            <svg>\n              <path\n                d=\"M16 512c0 273.932 222.066 496 496 496s496-222.068 496-496S785.932 16 512 16 16 238.066 16 512z m496 368V144c203.41 0 368 164.622 368 368 0 203.41-164.622 368-368 368z\"\n              />\n            </svg>\n          </nz-icon>\n          Two Tone\n        </label>\n      </nz-radio-group>\n      <nz-input-search>\n        <input\n          nz-input\n          [placeholder]=\"localeObj.search\"\n          [(ngModel)]=\"searchingString\"\n          (ngModelChange)=\"onSearchChange()\"\n        />\n        <div nzInputSuffix class=\"icon-pic-searcher\">\n          <nz-icon\n            class=\"icon-pic-btn\"\n            nz-popover\n            [nzPopoverTrigger]=\"null\"\n            [(nzPopoverVisible)]=\"popoverVisible\"\n            [nzPopoverContent]=\"localeObj.picSearcherIntro\"\n            (click)=\"toggleModal()\"\n          >\n            <svg viewBox=\"64 64 896 896\">\n              <path\n                d=\"M864 248H728l-32.4-90.8a32.07 32.07 0 00-30.2-21.2H358.6c-13.5 0-25.6 8.5-30.1 21.2L296 248H160c-44.2 0-80 35.8-80 80v456c0 44.2 35.8 80 80 80h704c44.2 0 80-35.8 80-80V328c0-44.2-35.8-80-80-80zm8 536c0 4.4-3.6 8-8 8H160c-4.4 0-8-3.6-8-8V328c0-4.4 3.6-8 8-8h186.7l17.1-47.8 22.9-64.2h250.5l22.9 64.2 17.1 47.8H864c4.4 0 8 3.6 8 8v456zM512 384c-88.4 0-160 71.6-160 160s71.6 160 160 160 160-71.6 160-160-71.6-160-160-160zm0 256c-53 0-96-43-96-96s43-96 96-96 96 43 96 96-43 96-96 96z\"\n              />\n            </svg>\n          </nz-icon>\n        </div>\n      </nz-input-search>\n    </div>\n    @for (category of categoryNames; track category; let i = $index) {\n      <h3>{{ localeObj[category] }}</h3>\n      <ul class=\"anticons-list\">\n        @for (icon of displayedNames[i].icons; track trackByFn(icon)) {\n          <li (click)=\"onIconClick($event, icon)\">\n            <nz-icon [nzType]=\"kebabCase(icon)\" [nzTheme]=\"currentTheme\" />\n            <span class=\"anticon-class\">\n              @if (isNewIcon(icon)) {\n                <nz-badge nzDot>\n                  {{ icon }}\n                </nz-badge>\n              } @else {\n                {{ icon }}\n              }\n            </span>\n          </li>\n        }\n      </ul>\n    }\n    <nz-modal\n      [nzTitle]=\"localeObj.picSearcherTitle\"\n      [(nzVisible)]=\"modalVisible\"\n      (nzOnCancel)=\"toggleModal()\"\n      [nzFooter]=\"null\"\n    >\n      <ng-container *nzModalContent>\n        @if (modelLoaded) {\n          <nz-upload\n            nzType=\"drag\"\n            nzAccept=\"image/jpeg, image/png\"\n            nzListType=\"picture\"\n            [nzCustomRequest]=\"customRequestUploadFile\"\n            [nzFileList]=\"fileList\"\n            [nzShowUploadList]=\"{ showPreviewIcon: false, showRemoveIcon: false }\"\n          >\n            <p class=\"ant-upload-drag-icon\">\n              <nz-icon nzType=\"inbox\" nzTheme=\"outline\" />\n            </p>\n            <p class=\"ant-upload-text\">{{ localeObj.picSearcherUploadText }}</p>\n            <p class=\"ant-upload-hint\">{{ localeObj.picSearcherUploadHint }}</p>\n          </nz-upload>\n          <nz-spin [nzSpinning]=\"loading\" [nzTip]=\"localeObj.picSearcherMatching\">\n            <div class=\"icon-pic-search-result\">\n              @if (icons.length) {\n                <div class=\"result-tip\">\n                  {{ localeObj.picSearcherResultTip }}\n                </div>\n                <table>\n                  <thead>\n                    <tr>\n                      <th class=\"col-icon\">\n                        {{ localeObj.picSearcherThIcon }}\n                      </th>\n                      <th>{{ localeObj.picSearcherThScore }}</th>\n                    </tr>\n                  </thead>\n                  <tbody>\n                    @for (icon of icons; track icon) {\n                      <tr>\n                        <td class=\"col-icon\">\n                          <nz-icon\n                            nz-tooltip\n                            [nzTooltipTitle]=\"icon.type\"\n                            nzTooltipPlacement=\"right\"\n                            [nzType]=\"icon.type\"\n                            [nzTheme]=\"currentTheme\"\n                            (click)=\"onIconClick($event, icon.type)\"\n                          />\n                        </td>\n                        <td>\n                          <nz-progress nzStrokeLinecap=\"round\" [nzPercent]=\"icon.score\" />\n                        </td>\n                      </tr>\n                    }\n                  </tbody>\n                </table>\n              }\n              @if (error) {\n                <nz-result nzStatus=\"500\" nzTitle=\"503\" [nzSubTitle]=\"localeObj.picSearcherServerError\" />\n              }\n            </div>\n          </nz-spin>\n        } @else {\n          <nz-spin [nzTip]=\"localeObj.picSearcherModelLoading\">\n            <div style=\"height: 100px;\"></div>\n          </nz-spin>\n        }\n      </ng-container>\n    </nz-modal>\n  `,\n  styles: `\n    h3 {\n      margin: 1.6em 0 0.6em;\n      font-size: 18px;\n    }\n\n    ul.anticons-list li .anticon {\n      font-size: 24px;\n    }\n\n    .icon-selector {\n      display: flex;\n      justify-content: space-between;\n    }\n\n    nz-input-search {\n      margin-left: 10px;\n      flex: 1 1 0;\n    }\n  `\n})\nexport class NzPageDemoIconComponent implements OnInit {\n  private platformId = inject(PLATFORM_ID);\n  private message = inject(NzMessageService);\n  private viewContainerRef = inject(ViewContainerRef);\n\n  displayedNames: Array<{ name: string; icons: string[] }> = [];\n  categoryNames: string[] = [];\n  currentTheme: ThemeType = 'outline';\n  localeObj: Record<string, string> = locale;\n  searchingString = '';\n\n  error = false;\n  loading = false;\n  modelLoaded = false;\n  modalVisible = false;\n  popoverVisible = false;\n  fileList: NzUploadFile[] = [];\n  icons: Icon[] = [];\n\n  private document: Document = inject(DOCUMENT);\n\n  trackByFn = (item: string): string => `${item}-${this.currentTheme}`;\n\n  kebabCase = (str: string): string => kebabCase(str);\n\n  isNewIcon = (name: string): boolean => newIconNames.indexOf(name) > -1;\n\n  onIconClick(e: MouseEvent, icon: string): void {\n    const target = e.target as HTMLElement;\n    const copiedString = `<nz-icon nzType=\"${kebabCase(icon)}\" nzTheme=\"${this.currentTheme}\" />`;\n    target.classList.add('copied');\n    this._copy(copiedString).then(() => {\n      setTimeout(() => {\n        target.classList.remove('copied');\n      }, 1000);\n    });\n\n    const content = this.getCopiedStringTemplateRef(copiedString);\n    this.message.success(content);\n  }\n\n  private _copy(value: string): Promise<string> {\n    return new Promise<string>((resolve): void => {\n      let copyTextArea: HTMLTextAreaElement | null = null;\n      try {\n        copyTextArea = this.document.createElement('textarea') as HTMLTextAreaElement;\n        copyTextArea.style.height = '0px';\n        copyTextArea.style.opacity = '0';\n        copyTextArea.style.width = '0px';\n        this.document.body.appendChild(copyTextArea);\n        copyTextArea.value = value;\n        copyTextArea.select();\n        this.document.execCommand('copy');\n        resolve(value);\n      } finally {\n        if (copyTextArea && copyTextArea.parentNode) {\n          copyTextArea.parentNode.removeChild(copyTextArea);\n        }\n      }\n    });\n  }\n\n  prepareIcons(): void {\n    const theme = this.currentTheme;\n\n    const currentThemeIcons = (manifest[theme] as string[])\n      .filter((name: string) => !['interation', 'canlendar'].includes(name))\n      .map(name => upperCamelCase(name));\n\n    let notEmptyCategories = Object.keys(categories).map(category => ({\n      name: category,\n      icons: categories[category as keyof Categories]!.filter(\n        (name: string) =>\n          currentThemeIcons.indexOf(name) > -1 && name.toLowerCase().includes(this.searchingString.toLowerCase())\n      )\n    }));\n\n    const otherIcons = currentThemeIcons\n      .filter(icon => notEmptyCategories.filter(({ name }) => name !== 'all').every(item => !item.icons.includes(icon)))\n      .filter(name => name.toLowerCase().includes(this.searchingString.toLocaleLowerCase()));\n\n    notEmptyCategories.push({ name: 'other', icons: otherIcons });\n    notEmptyCategories = notEmptyCategories.filter(({ icons }) => Boolean(icons.length));\n\n    this.displayedNames = notEmptyCategories;\n    this.categoryNames = notEmptyCategories.map(({ name }) => name);\n  }\n\n  setIconsShouldBeDisplayed(theme: ThemeType): void {\n    this.currentTheme = theme;\n    this.prepareIcons();\n  }\n\n  onSearchChange(): void {\n    this.prepareIcons();\n  }\n\n  private getCopiedStringTemplateRef(copiedString: string): TemplateRef<void> {\n    this.viewContainerRef.clear();\n    const componentRef = this.viewContainerRef.createComponent(NzPageDemoIconCopiedCodeComponent);\n    componentRef.instance.copiedCode = copiedString;\n\n    return componentRef.instance.templateRef;\n  }\n\n  private loadModel(): void {\n    if (window.antdIconClassifier) {\n      this.onLoad();\n      return;\n    }\n\n    const script = this.document.createElement('script');\n    const source = 'https://cdn.jsdelivr.net/gh/lewis617/antd-icon-classifier@0.0/dist/main.js';\n    script.type = 'text/javascript';\n    script.src = source;\n    script.onload = async () => {\n      await window.antdIconClassifier?.load();\n      this.onLoad();\n    };\n    script.onerror = () => {\n      throw new Error(`${PREFIX} cannot load assets of antd icon classifier from source \"${source}\".`);\n    };\n\n    this.document.head.appendChild(script);\n  }\n\n  private onLoad(): void {\n    this.modelLoaded = true;\n    this.document.addEventListener('paste', this.onPaste as EventListener);\n  }\n\n  private onPaste = (event: ClipboardEvent): void => {\n    const items = event.clipboardData && event.clipboardData.items;\n    let file = null;\n    if (items && items.length) {\n      let i = 0;\n      while (i < items.length) {\n        if (items[i].type.indexOf('image') !== -1) {\n          file = items[i].getAsFile();\n          break;\n        }\n        i++;\n      }\n    }\n    if (file) this.uploadFile(file);\n  };\n\n  // We don't need to upload it, so just fake api here\n  customRequestUploadFile = (o: NzUploadXHRArgs): Subscription => {\n    return of(true).subscribe(() => {\n      this.uploadFile(o.file);\n    });\n  };\n\n  private uploadFile = (file: File | NzUploadFile): void => {\n    this.loading = true;\n    const reader: FileReader = new FileReader();\n    reader.onload = () => {\n      this.toImage(reader.result as string).then(this.predict);\n      this.fileList = [{ uid: '1', name: file.name, status: 'done', url: reader.result as string }];\n    };\n    reader.readAsDataURL(file as File);\n  };\n\n  private toImage(url: string): Promise<HTMLImageElement> {\n    return new Promise(resolve => {\n      const img = new Image();\n      img.setAttribute('crossOrigin', 'anonymous');\n      img.src = url;\n      img.onload = function onload() {\n        resolve(img);\n      };\n    });\n  }\n\n  private predict = (imgEl: HTMLImageElement): void => {\n    try {\n      const results = window.antdIconClassifier?.predict(imgEl);\n      this.icons = results.map((r: Result) => ({\n        score: Math.ceil(r.score * 100),\n        type: r.className.replace(/\\s/g, '-')\n      }));\n      this.loading = false;\n      this.error = false;\n    } catch {\n      this.loading = false;\n      this.error = true;\n    }\n  };\n\n  toggleModal(): void {\n    this.modalVisible = !this.modalVisible;\n    this.popoverVisible = false;\n    this.fileList = [];\n    this.icons = [];\n\n    if (!localStorage.getItem('disableIconTip')) {\n      localStorage.setItem('disableIconTip', 'true');\n    }\n  }\n\n  constructor() {\n    // This is to test that tree shake works!\n    inject(NzIconService).addIcon(AccountBookFill);\n\n    inject(DestroyRef).onDestroy(() => {\n      this.document.removeEventListener('paste', this.onPaste as EventListener);\n      this.viewContainerRef.clear();\n    });\n  }\n\n  ngOnInit(): void {\n    this.setIconsShouldBeDisplayed('outline');\n    // load model in browser\n    if (isPlatformBrowser(this.platformId)) {\n      this.loadModel();\n      this.popoverVisible = !localStorage.getItem('disableIconTip');\n    }\n  }\n}\n\n@Component({\n  selector: 'nz-page-demo-icon-copied-code',\n  template: `\n    <ng-template #templateRef>\n      <span>\n        <code class=\"copied-code\">{{ copiedCode }}</code> copied 🎉\n      </span>\n    </ng-template>\n  `\n})\nexport class NzPageDemoIconCopiedCodeComponent {\n  @Input() copiedCode!: string;\n  @ViewChild('templateRef', { static: true }) templateRef!: TemplateRef<void>;\n}\n\nfunction camelCase(value: string): string {\n  return value.replace(/-\\w/g, (_r, i) => value.charAt(i + 1).toUpperCase());\n}\n\nfunction upperCamelCase(value: string): string {\n  const camelCased = camelCase(value);\n  return camelCased.charAt(0).toUpperCase() + camelCased.slice(1);\n}\n\nfunction kebabCase(value: string): string {\n  return value\n    .replace(/([a-z])([A-Z])/g, '$1-$2')\n    .replace(/([A-Z])([A-Z])/g, '$1-$2')\n    .replace(/([0-9])([a-zA-Z]+)$/g, '-$1-$2')\n    .replace(/[\\s_]+/g, '-')\n    .toLowerCase();\n}\n"
  },
  {
    "path": "components/icon/page/zh-CN.txt",
    "content": "{\n  chooseTheme: '选择图标主题风格',\n  direction: '方向性图标',\n  suggestion: '提示建议性图标',\n  edit: '编辑类图标',\n  data: '数据类图标',\n  other: '网站通用图标',\n  logo: '品牌和标识',\n  search: '在此搜索图标，点击图标可复制代码',\n  picSearcherIntro: 'AI 截图搜索上线了，快来体验吧！🎉',\n  picSearcherMatching: '匹配中...',\n  picSearcherModelLoading: '神经网络模型加载中...',\n  picSearcherResultTip: '为您匹配到以下图标：',\n  picSearcherServerError: '识别服务暂不可用',\n  picSearcherThIcon: '图标',\n  picSearcherThScore: '匹配度',\n  picSearcherTitle: '上传图片搜索图标',\n  picSearcherUploadHint: '我们会通过上传的图片进行匹配，得到最相似的图标',\n  picSearcherUploadText: '点击/拖拽/粘贴上传图片'\n}\n"
  },
  {
    "path": "components/icon/provide-icons.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { EnvironmentProviders, makeEnvironmentProviders, Provider } from '@angular/core';\n\nimport { IconDefinition } from '@ant-design/icons-angular';\n\nimport { NZ_ICONS, NZ_ICONS_PATCH, NzIconPatchService } from './icon.service';\n\n/**\n * Provide icon definitions for NzIcon in root\n *\n * @param icons Icon definitions\n */\nexport const provideNzIcons = (icons: IconDefinition[]): EnvironmentProviders => {\n  return makeEnvironmentProviders([\n    {\n      provide: NZ_ICONS,\n      useValue: icons\n    }\n  ]);\n};\n\n/**\n * Provide icon definitions for NzIcon in feature module or standalone component\n *\n * @param icons Icon definitions\n */\nexport const provideNzIconsPatch = (icons: IconDefinition[]): Provider[] => {\n  return [\n    NzIconPatchService,\n    {\n      provide: NZ_ICONS_PATCH,\n      useValue: icons\n    }\n  ];\n};\n"
  },
  {
    "path": "components/icon/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './icon.module';\nexport * from './icon.directive';\nexport * from './icon.service';\nexport * from './icons';\nexport * from './provide-icons';\n"
  },
  {
    "path": "components/icon/style/entry.less",
    "content": "@import './index.less';\n"
  },
  {
    "path": "components/icon/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@icon-prefix-cls: ~'@{ant-prefix}-icon';\n"
  },
  {
    "path": "components/icon/testing/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/icon/testing/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/icon/testing/nz-icon-test.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { EnvironmentProviders } from '@angular/core';\n\nimport { IconDefinition } from '@ant-design/icons-angular';\nimport * as AllIcons from '@ant-design/icons-angular/icons';\n\nimport { provideNzIcons } from 'ng-zorro-antd/icon';\n\nconst antDesignIcons = AllIcons as Record<string, IconDefinition>;\n\nconst icons: IconDefinition[] = Object.keys(antDesignIcons).map(key => antDesignIcons[key]);\n\nexport const provideNzIconsTesting = (): EnvironmentProviders => provideNzIcons(icons);\n"
  },
  {
    "path": "components/icon/testing/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './nz-icon-test.module';\n"
  },
  {
    "path": "components/image/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本用法\n  en-US: Basic Usage\n---\n\n## zh-CN\n\n单击图像可以放大显示。\n\n## en-US\n\nClick the image to preview.\n"
  },
  {
    "path": "components/image/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzImageModule } from 'ng-zorro-antd/image';\n\n@Component({\n  selector: 'nz-demo-image-basic',\n  imports: [NzImageModule],\n  template: `\n    <img\n      nz-image\n      width=\"200px\"\n      height=\"200px\"\n      nzSrc=\"https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png\"\n      alt=\"\"\n    />\n  `\n})\nexport class NzDemoImageBasicComponent {}\n"
  },
  {
    "path": "components/image/demo/controlled-preview.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 受控的预览\n  en-US: Controlled Preview\n---\n\n## zh-CN\n\n可以使预览受控。\n\n## en-US\n\nYou can make preview controlled.\n"
  },
  {
    "path": "components/image/demo/controlled-preview.ts",
    "content": "import { Component, inject } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzImageModule, NzImageService } from 'ng-zorro-antd/image';\nimport { NzInputNumberModule } from 'ng-zorro-antd/input-number';\n\n@Component({\n  selector: 'nz-demo-image-controlled-preview',\n  imports: [FormsModule, NzButtonModule, NzImageModule, NzInputNumberModule],\n  template: `\n    <div>\n      <label>\n        <span>scale step:</span>\n        <nz-input-number [(ngModel)]=\"scaleStep\" [nzMin]=\"0.1\" [nzStep]=\"1\" />\n      </label>\n\n      <button nz-button nzType=\"primary\" (click)=\"onClick()\">Preview</button>\n    </div>\n  `,\n  styles: `\n    div {\n      display: flex;\n      flex-direction: column;\n      align-items: flex-start;\n      gap: 1rem;\n    }\n\n    label {\n      display: flex;\n      align-items: center;\n      gap: 0.5rem;\n    }\n  `\n})\nexport class NzDemoImageControlledPreviewComponent {\n  private nzImageService = inject(NzImageService);\n  scaleStep = 0.5;\n  readonly images = [\n    {\n      src: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',\n      alt: ''\n    }\n  ];\n\n  onClick(): void {\n    this.nzImageService.preview(this.images, { nzZoom: 1, nzRotate: 0, nzScaleStep: this.scaleStep });\n  }\n}\n"
  },
  {
    "path": "components/image/demo/fallback.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 容错处理\n  en-US: Fault tolerant\n---\n\n## zh-CN\n\n加载失败显示图像占位符。\n\n## en-US\n\nLoad failed to display image placeholder.\n"
  },
  {
    "path": "components/image/demo/fallback.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzImageModule } from 'ng-zorro-antd/image';\n\n@Component({\n  selector: 'nz-demo-image-fallback',\n  imports: [NzImageModule],\n  template: `<img nz-image width=\"200px\" height=\"200px\" nzSrc=\"error\" [nzFallback]=\"fallback\" alt=\"\" />`\n})\nexport class NzDemoImageFallbackComponent {\n  fallback =\n    'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMIAAADDCAYAAADQvc6UAAABRWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwSDCIMogwMCcmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsis7PPOq3QdDFcvjV3jOD1boQVTPQrgSkktTgbSf4A4LbmgqISBgTEFyFYuLykAsTuAbJEioKOA7DkgdjqEvQHEToKwj4DVhAQ5A9k3gGyB5IxEoBmML4BsnSQk8XQkNtReEOBxcfXxUQg1Mjc0dyHgXNJBSWpFCYh2zi+oLMpMzyhRcASGUqqCZ16yno6CkYGRAQMDKMwhqj/fAIcloxgHQqxAjIHBEugw5sUIsSQpBobtQPdLciLEVJYzMPBHMDBsayhILEqEO4DxG0txmrERhM29nYGBddr//5/DGRjYNRkY/l7////39v///y4Dmn+LgeHANwDrkl1AuO+pmgAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAwqADAAQAAAABAAAAwwAAAAD9b/HnAAAHlklEQVR4Ae3dP3PTWBSGcbGzM6GCKqlIBRV0dHRJFarQ0eUT8LH4BnRU0NHR0UEFVdIlFRV7TzRksomPY8uykTk/zewQfKw/9znv4yvJynLv4uLiV2dBoDiBf4qP3/ARuCRABEFAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghgg0Aj8i0JO4OzsrPv69Wv+hi2qPHr0qNvf39+iI97soRIh4f3z58/u7du3SXX7Xt7Z2enevHmzfQe+oSN2apSAPj09TSrb+XKI/f379+08+A0cNRE2ANkupk+ACNPvkSPcAAEibACyXUyfABGm3yNHuAECRNgAZLuYPgEirKlHu7u7XdyytGwHAd8jjNyng4OD7vnz51dbPT8/7z58+NB9+/bt6jU/TI+AGWHEnrx48eJ/EsSmHzx40L18+fLyzxF3ZVMjEyDCiEDjMYZZS5wiPXnyZFbJaxMhQIQRGzHvWR7XCyOCXsOmiDAi1HmPMMQjDpbpEiDCiL358eNHurW/5SnWdIBbXiDCiA38/Pnzrce2YyZ4//59F3ePLNMl4PbpiL2J0L979+7yDtHDhw8vtzzvdGnEXdvUigSIsCLAWavHp/+qM0BcXMd/q25n1vF57TYBp0a3mUzilePj4+7k5KSLb6gt6ydAhPUzXnoPR0dHl79WGTNCfBnn1uvSCJdegQhLI1vvCk+fPu2ePXt2tZOYEV6/fn31dz+shwAR1sP1cqvLntbEN9MxA9xcYjsxS1jWR4AIa2Ibzx0tc44fYX/16lV6NDFLXH+YL32jwiACRBiEbf5KcXoTIsQSpzXx4N28Ja4BQoK7rgXiydbHjx/P25TaQAJEGAguWy0+2Q8PD6/Ki4R8EVl+bzBOnZY95fq9rj9zAkTI2SxdidBHqG9+skdw43borCXO/ZcJdraPWdv22uIEiLA4q7nvvCug8WTqzQveOH26fodo7g6uFe/a17W3+nFBAkRYENRdb1vkkz1CH9cPsVy/jrhr27PqMYvENYNlHAIesRiBYwRy0V+8iXP8+/fvX11Mr7L7ECueb/r48eMqm7FuI2BGWDEG8cm+7G3NEOfmdcTQw4h9/55lhm7DekRYKQPZF2ArbXTAyu4kDYB2YxUzwg0gi/41ztHnfQG26HbGel/crVrm7tNY+/1btkOEAZ2M05r4FB7r9GbAIdxaZYrHdOsgJ/wCEQY0J74TmOKnbxxT9n3FgGGWWsVdowHtjt9Nnvf7yQM2aZU/TIAIAxrw6dOnAWtZZcoEnBpNuTuObWMEiLAx1HY0ZQJEmHJ3HNvGCBBhY6jtaMoEiJB0Z29vL6ls58vxPcO8/zfrdo5qvKO+d3Fx8Wu8zf1dW4p/cPzLly/dtv9Ts/EbcvGAHhHyfBIhZ6NSiIBTo0LNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiEC/wGgKKC4YMA4TAAAAABJRU5ErkJggg==';\n}\n"
  },
  {
    "path": "components/image/demo/placeholder.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 渐进加载\n  en-US: Progressive Loading\n---\n\n## zh-CN\n\n大图使用 placeholder 渐进加载。\n\n## en-US\n\nProgressive when large image loading.\n"
  },
  {
    "path": "components/image/demo/placeholder.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzImageModule } from 'ng-zorro-antd/image';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\n\n@Component({\n  selector: 'nz-demo-image-placeholder',\n  imports: [NzButtonModule, NzImageModule, NzSpaceModule],\n  template: `\n    <nz-space [nzSize]=\"12\">\n      <img *nzSpaceItem nz-image width=\"200px\" height=\"200px\" [nzSrc]=\"src\" [nzPlaceholder]=\"placeholder\" />\n      <button *nzSpaceItem nz-button nzType=\"primary\" (click)=\"onReload()\">Reload</button>\n    </nz-space>\n  `\n})\nexport class NzDemoImagePlaceholderComponent {\n  src = `https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png`;\n  placeholder =\n    'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png?x-oss-process=image/blur,r_50,s_50/quality,q_1/resize,m_mfit,h_200,w_200';\n\n  onReload(): void {\n    this.src = `https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png?${new Date()}`;\n  }\n}\n"
  },
  {
    "path": "components/image/demo/preview-group.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 多张图片预览\n  en-US: Multiple image preview\n---\n\n## zh-CN\n\n点击左右切换按钮可以预览多张图片。\n\n## en-US\n\nClick the left and right switch buttons to preview multiple images.\n"
  },
  {
    "path": "components/image/demo/preview-group.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzImageModule } from 'ng-zorro-antd/image';\n\n@Component({\n  selector: 'nz-demo-image-preview-group',\n  imports: [NzImageModule],\n  template: `\n    <nz-image-group>\n      <img nz-image width=\"200px\" nzSrc=\"https://img.alicdn.com/tfs/TB1g.mWZAL0gK0jSZFtXXXQCXXa-200-200.svg\" alt=\"\" />\n      <img nz-image width=\"200px\" nzSrc=\"https://img.alicdn.com/tfs/TB1Z0PywTtYBeNjy1XdXXXXyVXa-186-200.svg\" alt=\"\" />\n    </nz-image-group>\n  `\n})\nexport class NzDemoImagePreviewGroupComponent {}\n"
  },
  {
    "path": "components/image/demo/service.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 服务方式创建预览层\n  en-US: Image Preview Service\n---\n\n## zh-CN\n\n图片预览的 Service 用法，示例中包含使用 Service 创建单张或多张图片预览的用法\n\n## en-US\n\nThe usage of `NzImageService` for images preview, the example includes the usage of using `NzImageService` to create single or multiple images preview\n"
  },
  {
    "path": "components/image/demo/service.ts",
    "content": "import { Component, inject } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzImageModule, NzImageService } from 'ng-zorro-antd/image';\n\n@Component({\n  selector: 'nz-demo-image-service',\n  imports: [NzButtonModule, NzImageModule],\n  template: `<button nz-button nzType=\"primary\" (click)=\"onClick()\">Preview</button>`\n})\nexport class NzDemoImageServiceComponent {\n  private nzImageService = inject(NzImageService);\n  readonly images = [\n    {\n      src: 'https://img.alicdn.com/tfs/TB1g.mWZAL0gK0jSZFtXXXQCXXa-200-200.svg',\n      width: '200px',\n      height: '200px',\n      alt: 'ng-zorro'\n    },\n    {\n      src: 'https://img.alicdn.com/tfs/TB1Z0PywTtYBeNjy1XdXXXXyVXa-186-200.svg',\n      width: '200px',\n      height: '200px',\n      alt: 'angular'\n    }\n  ];\n\n  onClick(): void {\n    this.nzImageService.preview(this.images, { nzZoom: 1.5, nzRotate: 0 });\n  }\n}\n"
  },
  {
    "path": "components/image/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Display\ntitle: Image\ncover: 'https://gw.alipayobjects.com/zos/antfincdn/D1dXz9PZqa/image.svg'\ndescription: Preview-able image.\n---\n\n## When To Use\n\n- When you need to display pictures.\n- Display when loading a large image or fault-tolerant handling when loading fail.\n\n## API\n\n### [nz-image]\n\n| Property              | Description                                                                                                                                                                                        | Type        | Default | Global Config |\n| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------- | ------------- |\n| `nzSrc`               | Image path                                                                                                                                                                                         | `string`    | -       | -             |\n| `nzFallback`          | Load failure fault-tolerant src                                                                                                                                                                    | `string`    | -       | ✅            |\n| `nzPlaceholder`       | Load placeholder src                                                                                                                                                                               | `string`    | -       | ✅            |\n| `nzDisablePreview`    | Whether to disable the preview                                                                                                                                                                     | `boolean`   | `false` | ✅            |\n| `nzCloseOnNavigation` | Whether to close the image preview when the user goes backwards/forwards in history. Note that this usually doesn't include clicking on links (unless the user is using the HashLocationStrategy). | `boolean`   | `false` | ✅            |\n| `nzDirection`         | Text directionality                                                                                                                                                                                | `Direction` | `'ltr'` | ✅            |\n| `nzScaleStep`         | `1 + nzScaleStep` is the step to increase or decrease the scale                                                                                                                                    | `number`    | `0.5`   | ✅            |\n\nOther attributes [<img\\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#Attributes)\n\n### NzImageService\n\n| Property  | Description     | Type                    | Default |\n| --------- | --------------- | ----------------------- | ------- |\n| `images`  | Preview images  | `NzImage[]`             | -       |\n| `options` | Preview options | `NzImagePreviewOptions` | -       |\n\n## Related type definition\n\n### NzImage\n\n| Property | Description | Type     | Default |\n| -------- | ----------- | -------- | ------- |\n| `src`    | src         | `string` | -       |\n| `alt`    | alt         | `string` | -       |\n| `width`  | width       | `string` | -       |\n| `height` | height      | `string` | -       |\n\n### NzImagePreviewOptions\n\n| Property              | Description                                                                                                                                                                                        | Type      | Default |\n| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ------- |\n| `nzKeyboard`          | Whether support press `esc` to close, press `left` or `right` to switch image                                                                                                                      | `boolean` | `true`  |\n| `nzMaskClosable`      | Whether to close the image preview when the mask (area outside the image) is clicked                                                                                                               | `boolean` | `true`  |\n| `nzCloseOnNavigation` | Whether to close the image preview when the user goes backwards/forwards in history. Note that this usually doesn't include clicking on links (unless the user is using the HashLocationStrategy). | `boolean` | `true`  |\n| `nzZIndex`            | The z-index of the image preview                                                                                                                                                                   | `number`  | `1000`  |\n| `nzZoom`              | Zoom rate                                                                                                                                                                                          | `number`  | `1`     |\n| `nzRotate`            | Rotate rate                                                                                                                                                                                        | `number`  | `0`     |\n| `nzScaleStep`         | `1 + nzScaleStep` is the step to increase or decrease the scale                                                                                                                                    | `number`  | `0.5`   |\n| `nzFlipHorizontally`  | Flip image on horizontal vector                                                                                                                                                                    | `boolean` | `false` |\n| `nzFlipVertically`    | Flip image on vertical vector                                                                                                                                                                      | `boolean` | `false` |\n\n### NzImagePreviewRef\n\n| Name                            | Description         |\n| ------------------------------- | ------------------- |\n| `switchTo(index: number): void` | Switch to index     |\n| `prev(): void`                  | Previous image      |\n| `next(): void`                  | Next image          |\n| `close(): void`                 | Close image preview |\n\n### NzImageGroupComponent\n\n| Property      | Description                                                                                                                     | Type     | Default |\n| ------------- | ------------------------------------------------------------------------------------------------------------------------------- | -------- | ------- |\n| `nzScaleStep` | The value of `nzScaleStep` will be applied to all the images inside, unless an image has its own `nzScaleStep` value specified. | `number` | -       |\n"
  },
  {
    "path": "components/image/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 图片\ntype: 数据展示\ntitle: Image\ncover: 'https://gw.alipayobjects.com/zos/antfincdn/D1dXz9PZqa/image.svg'\ndescription: 可预览的图片。\n---\n\n## 何时使用\n\n- 需要展示图片时使用。\n- 加载大图时渐进加载或加载失败时容错处理。\n\n## API\n\n### [nz-image]\n\n| 参数                  | 说明                                                                                                     | 类型        | 默认值  | 支持全局配置 |\n| --------------------- | -------------------------------------------------------------------------------------------------------- | ----------- | ------- | ------------ |\n| `nzSrc`               | 图片地址                                                                                                 | `string`    | -       | -            |\n| `nzFallback`          | 加载失败容错地址                                                                                         | `string`    | -       | ✅           |\n| `nzPlaceholder`       | 加载占位地址                                                                                             | `string`    | -       | ✅           |\n| `nzDisablePreview`    | 是否禁止预览                                                                                             | `boolean`   | `false` | ✅           |\n| `nzCloseOnNavigation` | 当用户在历史中前进/后退时是否关闭预览。注意，这通常不包括点击链接（除非用户使用 HashLocationStrategy）。 | `boolean`   | `false` | ✅           |\n| `nzDirection`         | 文字方向                                                                                                 | `Direction` | `'ltr'` | ✅           |\n| `nzScaleStep`         | `1 + nzScaleStep` 为缩放放大的每步倍数                                                                   | `number`    | `0.5`   | ✅           |\n\n其他属性见 [<img\\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#Attributes)\n\n### NzImageService\n\n| 参数      | 说明     | 类型                    | 默认值 |\n| --------- | -------- | ----------------------- | ------ |\n| `images`  | 预览图片 | `NzImage[]`             | -      |\n| `options` | 预览参数 | `NzImagePreviewOptions` | -      |\n\n## 相关类型定义\n\n### NzImage\n\n| 参数     | 说明     | 类型     | 默认值 |\n| -------- | -------- | -------- | ------ |\n| `src`    | src      | `string` | -      |\n| `alt`    | alt      | `string` | -      |\n| `width`  | 图片宽度 | `string` | -      |\n| `height` | 图片高度 | `string` | -      |\n\n### NzImagePreviewOptions\n\n| 参数                  | 说明                                                                                                     | 类型      | 默认值  |\n| --------------------- | -------------------------------------------------------------------------------------------------------- | --------- | ------- |\n| `nzKeyboard`          | 是否支持键盘 esc 关闭、左右键切换图片                                                                    | `boolean` | `true`  |\n| `nzMaskClosable`      | 点击蒙层是否允许关闭                                                                                     | `boolean` | `true`  |\n| `nzCloseOnNavigation` | 当用户在历史中前进/后退时是否关闭预览。注意，这通常不包括点击链接（除非用户使用 HashLocationStrategy）。 | `boolean` | `true`  |\n| `nzZIndex`            | 设置预览层的 z-index                                                                                     | `number`  | `1000`  |\n| `nzZoom`              | 缩放比例                                                                                                 | `number`  | `1`     |\n| `nzRotate`            | 旋转角度                                                                                                 | `number`  | `0`     |\n| `nzScaleStep`         | `1 + nzScaleStep` 为缩放放大的每步倍数                                                                   | `number`  | `0.5`   |\n| `nzFlipHorizontally`  | 在水平向量上翻转图像                                                                                     | `boolean` | `false` |\n| `nzFlipVertically`    | 在垂直向量上翻转图像                                                                                     | `boolean` | `false` |\n\n### NzImagePreviewRef\n\n| 名称                            | 描述         |\n| ------------------------------- | ------------ |\n| `switchTo(index: number): void` | 设置预览索引 |\n| `prev(): void`                  | 上一张       |\n| `next(): void`                  | 下一张       |\n| `close(): void`                 | 关闭预览     |\n\n### NzImageGroupComponent\n\n| 名称          | 描述                                   | 类型     | 默认值 |\n| ------------- | -------------------------------------- | -------- | ------ |\n| `nzScaleStep` | `1 + nzScaleStep` 为缩放放大的每步倍数 | `number` | -      |\n"
  },
  {
    "path": "components/image/image-config.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzConfigKey } from 'ng-zorro-antd/core/config';\n\nexport const NZ_CONFIG_MODULE_NAME: NzConfigKey = 'image';\n"
  },
  {
    "path": "components/image/image-group.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, Input, ViewEncapsulation } from '@angular/core';\n\nimport { NzImageDirective } from './image.directive';\n\n@Component({\n  selector: 'nz-image-group',\n  exportAs: 'nzImageGroup',\n  template: '<ng-content />',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None\n})\nexport class NzImageGroupComponent {\n  @Input() nzScaleStep: number | null = null;\n\n  images: NzImageDirective[] = [];\n\n  addImage(image: NzImageDirective): void {\n    this.images.push(image);\n  }\n}\n"
  },
  {
    "path": "components/image/image-preview-options.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction } from '@angular/cdk/bidi';\n\nexport class NzImagePreviewOptions {\n  nzKeyboard?: boolean = true;\n  nzNoAnimation?: boolean = false;\n  nzMaskClosable?: boolean = true;\n  nzCloseOnNavigation?: boolean = true;\n  nzZIndex?: number;\n  nzZoom?: number;\n  nzRotate?: number;\n  nzFlipHorizontally?: boolean;\n  nzFlipVertically?: boolean;\n  nzScaleStep?: number;\n  nzDirection?: Direction;\n}\n\nexport interface NzImage {\n  src: string;\n  srcset?: string;\n  alt?: string;\n  width?: string | number;\n  height?: string | number;\n}\n"
  },
  {
    "path": "components/image/image-preview-ref.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ESCAPE, hasModifierKey, LEFT_ARROW, RIGHT_ARROW } from '@angular/cdk/keycodes';\nimport { OverlayRef } from '@angular/cdk/overlay';\nimport { Subject } from 'rxjs';\nimport { filter, take, takeUntil } from 'rxjs/operators';\n\nimport { generateClassName } from 'ng-zorro-antd/core/util';\n\nimport { NzImagePreviewOptions } from './image-preview-options';\nimport { NzImagePreviewComponent } from './image-preview.component';\n\nconst CLASS_NAME = 'ant-image-preview';\nconst FADE_CLASS_NAME_MAP = {\n  enter: generateClassName(CLASS_NAME, 'fade-motion-enter'),\n  leave: generateClassName(CLASS_NAME, 'fade-motion-leave')\n};\nconst FADE_OUT_KEYFRAME_NAME = 'antFadeOut';\n\nexport class NzImagePreviewRef {\n  private destroy$ = new Subject<void>();\n\n  constructor(\n    public previewInstance: NzImagePreviewComponent,\n    private config: NzImagePreviewOptions,\n    private overlayRef: OverlayRef\n  ) {\n    if (config.nzKeyboard) {\n      overlayRef\n        .keydownEvents()\n        .pipe(\n          filter(\n            event =>\n              (event.keyCode === ESCAPE || event.keyCode === LEFT_ARROW || event.keyCode === RIGHT_ARROW) &&\n              !hasModifierKey(event)\n          )\n        )\n        .subscribe(event => {\n          event.preventDefault();\n          if (event.keyCode === ESCAPE) {\n            previewInstance.onClose();\n          }\n          if (event.keyCode === LEFT_ARROW) {\n            this.prev();\n          }\n          if (event.keyCode === RIGHT_ARROW) {\n            this.next();\n          }\n        });\n    }\n\n    overlayRef.detachments().subscribe(() => this.overlayRef.dispose());\n\n    previewInstance.closeClick.pipe(take(1), takeUntil(this.destroy$)).subscribe(() => this.close());\n\n    this._startEnterAnimation();\n  }\n\n  private get element(): HTMLElement {\n    return this.previewInstance.elementRef.nativeElement as HTMLElement;\n  }\n\n  private get _animationsEnabled(): boolean {\n    return !(this.config.nzNoAnimation ?? false);\n  }\n\n  private _startEnterAnimation(): void {\n    if (this._animationsEnabled) {\n      this.element.classList.add(FADE_CLASS_NAME_MAP.enter);\n    }\n  }\n\n  private _startLeaveAnimation(): void {\n    if (this._animationsEnabled) {\n      this.element.classList.remove(FADE_CLASS_NAME_MAP.enter);\n      this.element.classList.add(FADE_CLASS_NAME_MAP.leave);\n    }\n  }\n\n  switchTo(index: number): void {\n    this.previewInstance.switchTo(index);\n  }\n\n  next(): void {\n    this.previewInstance.next();\n  }\n\n  prev(): void {\n    this.previewInstance.prev();\n  }\n\n  close(): void {\n    if (this._animationsEnabled) {\n      // if animation is enabled, close after animation end\n      const onAnimationEnd = (event: AnimationEvent): void => {\n        if (event.animationName === FADE_OUT_KEYFRAME_NAME) {\n          this.element.removeEventListener('animationend', onAnimationEnd);\n          this._doClose();\n        }\n      };\n\n      this.element.addEventListener('animationend', onAnimationEnd);\n      this._startLeaveAnimation();\n    } else {\n      this._doClose();\n    }\n  }\n\n  private _doClose(): void {\n    this.destroy$.next();\n    this.overlayRef.dispose();\n    this.previewInstance = null!;\n  }\n}\n"
  },
  {
    "path": "components/image/image-preview.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { CdkDrag, CdkDragEnd, CdkDragHandle } from '@angular/cdk/drag-drop';\nimport { ESCAPE } from '@angular/cdk/keycodes';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DestroyRef,\n  DOCUMENT,\n  ElementRef,\n  EventEmitter,\n  inject,\n  NgZone,\n  OnInit,\n  signal,\n  ViewChild,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';\nimport { merge } from 'rxjs';\nimport { filter, map } from 'rxjs/operators';\n\nimport { NzConfigService } from 'ng-zorro-antd/core/config';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { fromEventOutsideAngular, isNotNil } from 'ng-zorro-antd/core/util';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nimport { NZ_CONFIG_MODULE_NAME } from './image-config';\nimport { NzImage, NzImagePreviewOptions } from './image-preview-options';\nimport { NzImagePreviewRef } from './image-preview-ref';\nimport { NzImageScaleStep, NzImageUrl } from './image.directive';\nimport { getClientSize, getFitContentPosition, getOffset } from './utils';\n\nexport interface NzImageContainerOperation {\n  icon: string;\n  type: string;\n  rotate?: number;\n  onClick(): void;\n}\n\nconst initialPosition = {\n  x: 0,\n  y: 0\n};\n\nexport const NZ_DEFAULT_SCALE_STEP = 0.5;\nconst NZ_DEFAULT_ZOOM = 1;\nconst NZ_DEFAULT_ROTATE = 0;\n\n@Component({\n  selector: 'nz-image-preview',\n  exportAs: 'nzImagePreview',\n  template: `\n    <div class=\"ant-image-preview-mask\"></div>\n\n    <div class=\"ant-image-preview-operations-wrapper\">\n      @if (images.length > 1) {\n        <div\n          class=\"ant-image-preview-switch-left\"\n          [class.ant-image-preview-switch-left-disabled]=\"index <= 0\"\n          (click)=\"onSwitchLeft($event)\"\n        >\n          <nz-icon nzType=\"left\" nzTheme=\"outline\" />\n        </div>\n        <div\n          class=\"ant-image-preview-switch-right\"\n          [class.ant-image-preview-switch-right-disabled]=\"index >= images.length - 1\"\n          (click)=\"onSwitchRight($event)\"\n        >\n          <nz-icon nzType=\"right\" nzTheme=\"outline\" />\n        </div>\n      }\n\n      <ul class=\"ant-image-preview-operations\">\n        @if (images.length > 1) {\n          <li class=\"ant-image-preview-operations-progress\">{{ index + 1 }} / {{ images.length }}</li>\n        }\n\n        @for (option of operations; track option) {\n          <li\n            class=\"ant-image-preview-operations-operation\"\n            [class.ant-image-preview-operations-operation-disabled]=\"zoomOutDisabled && option.type === 'zoomOut'\"\n            (click)=\"option.onClick()\"\n          >\n            <nz-icon\n              class=\"ant-image-preview-operations-icon\"\n              [nzType]=\"option.icon\"\n              [nzRotate]=\"option.rotate ?? 0\"\n              nzTheme=\"outline\"\n            />\n          </li>\n        }\n      </ul>\n    </div>\n\n    <div\n      class=\"ant-image-preview-wrap\"\n      tabindex=\"-1\"\n      (click)=\"maskClosable && $event.target === $event.currentTarget && onClose()\"\n    >\n      <div class=\"ant-image-preview\" role=\"dialog\" aria-modal=\"true\">\n        <div tabindex=\"0\" aria-hidden=\"true\" class=\"ant-image-preview-focus-trap\"></div>\n        <div class=\"ant-image-preview-content\">\n          <div class=\"ant-image-preview-body\">\n            <div\n              class=\"ant-image-preview-img-wrapper\"\n              #imagePreviewWrapper\n              cdkDrag\n              [style.transform]=\"previewImageWrapperTransform()\"\n              [cdkDragFreeDragPosition]=\"position\"\n              (cdkDragEnded)=\"onDragEnd($event)\"\n            >\n              @for (image of images; track image) {\n                @if ($index === index) {\n                  <img\n                    cdkDragHandle\n                    class=\"ant-image-preview-img\"\n                    #imgRef\n                    [attr.src]=\"sanitizerResourceUrl(image.src)\"\n                    [attr.srcset]=\"image.srcset\"\n                    [attr.alt]=\"image.alt\"\n                    [style.width]=\"image.width\"\n                    [style.height]=\"image.height\"\n                    [style.transform]=\"previewImageTransform()\"\n                  />\n                }\n              }\n            </div>\n          </div>\n        </div>\n        <div tabindex=\"0\" aria-hidden=\"true\" class=\"ant-image-preview-focus-trap\"></div>\n      </div>\n    </div>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  host: {\n    class: 'ant-image-preview-root',\n    '[class.ant-image-preview-moving]': 'isDragging()',\n    '[style.zIndex]': 'config.nzZIndex'\n  },\n  imports: [NzIconModule, CdkDragHandle, CdkDrag]\n})\nexport class NzImagePreviewComponent implements OnInit {\n  private readonly document = inject(DOCUMENT);\n  private readonly ngZone = inject(NgZone);\n  private readonly cdr = inject(ChangeDetectorRef);\n  private readonly nzConfigService = inject(NzConfigService);\n  private readonly sanitizer = inject(DomSanitizer);\n  private readonly destroyRef = inject(DestroyRef);\n  public readonly elementRef = inject(ElementRef);\n  public readonly config = inject(NzImagePreviewOptions);\n  readonly _defaultNzZoom = NZ_DEFAULT_ZOOM;\n  readonly _defaultNzScaleStep = NZ_DEFAULT_SCALE_STEP;\n  readonly _defaultNzRotate = NZ_DEFAULT_ROTATE;\n\n  readonly isDragging = signal(false);\n  images: NzImage[] = [];\n  index = 0;\n  visible = true;\n  scaleStepMap: Map<NzImageUrl, NzImageScaleStep> = new Map<NzImageUrl, NzImageScaleStep>();\n\n  protected readonly previewImageTransform = signal('');\n  protected readonly previewImageWrapperTransform = signal('');\n  operations: NzImageContainerOperation[] = [\n    {\n      icon: 'close',\n      onClick: () => {\n        this.onClose();\n      },\n      type: 'close'\n    },\n    {\n      icon: 'zoom-in',\n      onClick: () => {\n        this.onZoomIn();\n      },\n      type: 'zoomIn'\n    },\n    {\n      icon: 'zoom-out',\n      onClick: () => {\n        this.onZoomOut();\n      },\n      type: 'zoomOut'\n    },\n    {\n      icon: 'rotate-right',\n      onClick: () => {\n        this.onRotateRight();\n      },\n      type: 'rotateRight'\n    },\n    {\n      icon: 'rotate-left',\n      onClick: () => {\n        this.onRotateLeft();\n      },\n      type: 'rotateLeft'\n    },\n    {\n      icon: 'swap',\n      onClick: () => {\n        this.onHorizontalFlip();\n      },\n      type: 'flipHorizontally'\n    },\n    {\n      icon: 'swap',\n      onClick: () => {\n        this.onVerticalFlip();\n      },\n      type: 'flipVertically',\n      rotate: 90\n    }\n  ];\n\n  zoomOutDisabled = false;\n  position = { ...initialPosition };\n  previewRef!: NzImagePreviewRef;\n  closeClick = new EventEmitter<void>();\n\n  @ViewChild('imgRef') imageRef!: ElementRef<HTMLImageElement>;\n  @ViewChild('imagePreviewWrapper', { static: true }) imagePreviewWrapper!: ElementRef<HTMLElement>;\n\n  private zoom = this.config.nzZoom ?? this._defaultNzZoom;\n  private rotate = this.config.nzRotate ?? this._defaultNzRotate;\n  private scaleStep = this.config.nzScaleStep ?? this._defaultNzScaleStep;\n  private flipHorizontally = this.config.nzFlipHorizontally ?? false;\n  private flipVertically = this.config.nzFlipVertically ?? false;\n\n  get maskClosable(): boolean {\n    const defaultConfig: NzSafeAny = this.nzConfigService.getConfigForComponent(NZ_CONFIG_MODULE_NAME) || {};\n    return this.config.nzMaskClosable ?? defaultConfig.nzMaskClosable ?? true;\n  }\n\n  constructor() {\n    this.updateZoomOutDisabled();\n    this.updatePreviewImageTransform();\n    this.updatePreviewImageWrapperTransform();\n  }\n\n  ngOnInit(): void {\n    merge(\n      fromEventOutsideAngular(this.imagePreviewWrapper.nativeElement, 'mousedown').pipe(map(() => true)),\n      fromEventOutsideAngular(this.imagePreviewWrapper.nativeElement, 'mouseup').pipe(map(() => false))\n    )\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(dragging => this.isDragging.set(dragging));\n\n    fromEventOutsideAngular<WheelEvent>(this.imagePreviewWrapper.nativeElement, 'wheel')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(event => {\n        this.ngZone.run(() => this.wheelZoomEventHandler(event));\n      });\n\n    fromEventOutsideAngular<KeyboardEvent>(this.document, 'keydown')\n      .pipe(\n        filter(event => event.keyCode === ESCAPE),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(() => {\n        this.ngZone.run(() => {\n          this.onClose();\n          this.markForCheck();\n        });\n      });\n  }\n\n  setImages(images: NzImage[], scaleStepMap?: Map<string, number>): void {\n    if (scaleStepMap) this.scaleStepMap = scaleStepMap;\n    this.images = images;\n    this.markForCheck();\n  }\n\n  switchTo(index: number): void {\n    this.index = index;\n    this.markForCheck();\n  }\n\n  next(): void {\n    if (this.index < this.images.length - 1) {\n      this.reset();\n      this.index++;\n      this.updatePreviewImageTransform();\n      this.updatePreviewImageWrapperTransform();\n      this.updateZoomOutDisabled();\n      this.markForCheck();\n    }\n  }\n\n  prev(): void {\n    if (this.index > 0) {\n      this.reset();\n      this.index--;\n      this.updatePreviewImageTransform();\n      this.updatePreviewImageWrapperTransform();\n      this.updateZoomOutDisabled();\n      this.markForCheck();\n    }\n  }\n\n  markForCheck(): void {\n    this.cdr.markForCheck();\n  }\n\n  onClose(): void {\n    this.visible = false;\n    this.closeClick.emit();\n  }\n\n  onZoomIn(): void {\n    const zoomStep =\n      this.scaleStepMap.get(this.images[this.index].src ?? this.images[this.index].srcset) ?? this.scaleStep;\n    this.zoom += zoomStep;\n    this.updatePreviewImageTransform();\n    this.updateZoomOutDisabled();\n  }\n\n  onZoomOut(): void {\n    if (this.zoom > 1) {\n      const zoomStep =\n        this.scaleStepMap.get(this.images[this.index].src ?? this.images[this.index].srcset) ?? this.scaleStep;\n      this.zoom -= zoomStep;\n      this.updatePreviewImageTransform();\n      this.updateZoomOutDisabled();\n\n      if (this.zoom <= 1) {\n        this.reCenterImage();\n      }\n    }\n  }\n\n  onRotateRight(): void {\n    this.rotate += 90;\n    this.updatePreviewImageTransform();\n  }\n\n  onRotateLeft(): void {\n    this.rotate -= 90;\n    this.updatePreviewImageTransform();\n  }\n\n  onSwitchLeft(event: MouseEvent): void {\n    event.preventDefault();\n    event.stopPropagation();\n    this.prev();\n  }\n\n  onSwitchRight(event: MouseEvent): void {\n    event.preventDefault();\n    event.stopPropagation();\n    this.next();\n  }\n\n  onHorizontalFlip(): void {\n    this.flipHorizontally = !this.flipHorizontally;\n    this.updatePreviewImageTransform();\n  }\n\n  onVerticalFlip(): void {\n    this.flipVertically = !this.flipVertically;\n    this.updatePreviewImageTransform();\n  }\n\n  wheelZoomEventHandler(event: WheelEvent): void {\n    event.preventDefault();\n    event.stopPropagation();\n\n    this.handlerImageTransformationWhileZoomingWithMouse(event, event.deltaY);\n    this.handleImageScaleWhileZoomingWithMouse(event.deltaY);\n\n    this.updatePreviewImageWrapperTransform();\n    this.updatePreviewImageTransform();\n\n    this.markForCheck();\n  }\n\n  onDragEnd(event: CdkDragEnd): void {\n    this.isDragging.set(false);\n    const width = this.imageRef.nativeElement.offsetWidth * this.zoom;\n    const height = this.imageRef.nativeElement.offsetHeight * this.zoom;\n    const { left, top } = getOffset(this.imageRef.nativeElement);\n    const { width: clientWidth, height: clientHeight } = getClientSize();\n    const isRotate = this.rotate % 180 !== 0;\n    const fitContentParams = {\n      width: isRotate ? height : width,\n      height: isRotate ? width : height,\n      left,\n      top,\n      clientWidth,\n      clientHeight\n    };\n    const fitContentPos = getFitContentPosition(fitContentParams);\n    if (isNotNil(fitContentPos.x) || isNotNil(fitContentPos.y)) {\n      this.position = { ...this.position, ...fitContentPos };\n    } else if (!isNotNil(fitContentPos.x) && !isNotNil(fitContentPos.y)) {\n      this.position = {\n        x: event.source.getFreeDragPosition().x,\n        y: event.source.getFreeDragPosition().y\n      };\n    }\n  }\n\n  sanitizerResourceUrl(url: string): SafeResourceUrl {\n    return this.sanitizer.bypassSecurityTrustResourceUrl(url);\n  }\n\n  private updatePreviewImageTransform(): void {\n    this.previewImageTransform.set(\n      `scale3d(${this.zoom * (this.flipHorizontally ? -1 : 1)}, ${\n        this.zoom * (this.flipVertically ? -1 : 1)\n      }, 1) rotate(${this.rotate}deg)`\n    );\n  }\n\n  private updatePreviewImageWrapperTransform(): void {\n    this.previewImageWrapperTransform.set(`translate3d(${this.position.x}px, ${this.position.y}px, 0)`);\n  }\n\n  private updateZoomOutDisabled(): void {\n    this.zoomOutDisabled = this.zoom <= 1;\n  }\n\n  private handlerImageTransformationWhileZoomingWithMouse(event: WheelEvent, deltaY: number): void {\n    let scaleValue: number;\n    const imageElement = this.imageRef.nativeElement;\n\n    const elementTransform = getComputedStyle(imageElement).transform;\n    const matrixValue = elementTransform.match(/matrix.*\\((.+)\\)/);\n\n    if (matrixValue) {\n      scaleValue = +matrixValue[1].split(', ')[0];\n    } else {\n      scaleValue = this.zoom;\n    }\n\n    const x = (event.clientX - imageElement.getBoundingClientRect().x) / scaleValue;\n    const y = (event.clientY - imageElement.getBoundingClientRect().y) / scaleValue;\n    const halfOfScaleStepValue = deltaY < 0 ? this.scaleStep / 2 : -this.scaleStep / 2;\n\n    this.position.x += -x * halfOfScaleStepValue * 2 + imageElement.offsetWidth * halfOfScaleStepValue;\n    this.position.y += -y * halfOfScaleStepValue * 2 + imageElement.offsetHeight * halfOfScaleStepValue;\n  }\n\n  private handleImageScaleWhileZoomingWithMouse(deltaY: number): void {\n    if (this.isZoomedInWithMouseWheel(deltaY)) {\n      this.onZoomIn();\n    } else {\n      this.onZoomOut();\n    }\n\n    if (this.zoom <= 1) {\n      this.reCenterImage();\n    }\n  }\n\n  private isZoomedInWithMouseWheel(delta: number): boolean {\n    return delta < 0;\n  }\n\n  private reset(): void {\n    this.zoom = this.config.nzZoom ?? this._defaultNzZoom;\n    this.scaleStep = this.config.nzScaleStep ?? this._defaultNzScaleStep;\n    this.rotate = this.config.nzRotate ?? this._defaultNzRotate;\n    this.flipHorizontally = false;\n    this.flipVertically = false;\n    this.reCenterImage();\n  }\n\n  private reCenterImage(): void {\n    this.position = { ...initialPosition };\n  }\n}\n"
  },
  {
    "path": "components/image/image.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport {\n  booleanAttribute,\n  ChangeDetectorRef,\n  DestroyRef,\n  Directive,\n  DOCUMENT,\n  ElementRef,\n  inject,\n  Input,\n  OnChanges,\n  OnInit,\n  SimpleChanges\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { fromEvent, Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\n\nimport { NzConfigKey, NzConfigService, WithConfig } from 'ng-zorro-antd/core/config';\n\nimport { NzImageGroupComponent } from './image-group.component';\nimport { NZ_DEFAULT_SCALE_STEP } from './image-preview.component';\nimport { NzImageService } from './image.service';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'image';\n\nexport type ImageStatusType = 'error' | 'loading' | 'normal';\nexport type NzImageUrl = string;\nexport type NzImageScaleStep = number;\n\n@Directive({\n  selector: 'img[nz-image]',\n  exportAs: 'nzImage',\n  host: {\n    '(click)': 'onPreview()'\n  }\n})\nexport class NzImageDirective implements OnInit, OnChanges {\n  private document: Document = inject(DOCUMENT);\n  public nzConfigService = inject(NzConfigService);\n  private elementRef = inject(ElementRef);\n  private nzImageService = inject(NzImageService);\n  protected cdr = inject(ChangeDetectorRef);\n  private directionality = inject(Directionality);\n  private destroyRef = inject(DestroyRef);\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  @Input() nzSrc = '';\n  @Input() nzSrcset = '';\n  @Input({ transform: booleanAttribute }) @WithConfig() nzDisablePreview: boolean = false;\n  @Input() @WithConfig() nzFallback: string | null = null;\n  @Input() @WithConfig() nzPlaceholder: string | null = null;\n  @Input() @WithConfig() nzScaleStep: number | null = null;\n\n  dir?: Direction;\n  backLoadImage!: HTMLImageElement;\n  status: ImageStatusType = 'normal';\n  private backLoadDestroy$ = new Subject<void>();\n\n  private parentGroup = inject(NzImageGroupComponent, { optional: true });\n\n  get previewable(): boolean {\n    return !this.nzDisablePreview && this.status !== 'error';\n  }\n  ngOnInit(): void {\n    this.backLoad();\n    if (this.parentGroup) {\n      this.parentGroup.addImage(this);\n    }\n    if (this.directionality) {\n      this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n        this.dir = direction;\n        this.cdr.detectChanges();\n      });\n      this.dir = this.directionality.value;\n    }\n  }\n\n  onPreview(): void {\n    if (!this.previewable) {\n      return;\n    }\n\n    if (this.parentGroup) {\n      // preview inside image group\n      const previewAbleImages = this.parentGroup.images.filter(e => e.previewable);\n      const previewImages = previewAbleImages.map(e => ({ src: e.nzSrc, srcset: e.nzSrcset }));\n      const previewIndex = previewAbleImages.findIndex(el => this === el);\n      const scaleStepMap = new Map<NzImageUrl, NzImageScaleStep>();\n      previewAbleImages.forEach(imageDirective => {\n        scaleStepMap.set(\n          imageDirective.nzSrc ?? imageDirective.nzSrcset,\n          imageDirective.nzScaleStep ?? this.parentGroup!.nzScaleStep ?? this.nzScaleStep ?? NZ_DEFAULT_SCALE_STEP\n        );\n      });\n      const previewRef = this.nzImageService.preview(\n        previewImages,\n        {\n          nzDirection: this.dir\n        },\n        scaleStepMap\n      );\n      previewRef.switchTo(previewIndex);\n    } else {\n      // preview not inside image group\n      const previewImages = [{ src: this.nzSrc, srcset: this.nzSrcset }];\n      this.nzImageService.preview(previewImages, {\n        nzDirection: this.dir,\n        nzScaleStep: this.nzScaleStep ?? NZ_DEFAULT_SCALE_STEP\n      });\n    }\n  }\n\n  getElement(): ElementRef<HTMLImageElement> {\n    return this.elementRef;\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzSrc } = changes;\n    if (nzSrc) {\n      this.getElement().nativeElement.src = nzSrc.currentValue;\n      this.backLoad();\n    }\n  }\n\n  /**\n   * use internal Image object handle fallback & placeholder\n   *\n   * @private\n   */\n  private backLoad(): void {\n    this.backLoadImage = this.document.createElement('img');\n    this.backLoadImage.src = this.nzSrc;\n    this.backLoadImage.srcset = this.nzSrcset;\n    this.status = 'loading';\n\n    // unsubscribe last backLoad\n    this.backLoadDestroy$.next();\n    this.backLoadDestroy$.complete();\n    this.backLoadDestroy$ = new Subject();\n    if (this.backLoadImage.complete) {\n      this.status = 'normal';\n      this.getElement().nativeElement.src = this.nzSrc;\n      this.getElement().nativeElement.srcset = this.nzSrcset;\n    } else {\n      if (this.nzPlaceholder) {\n        this.getElement().nativeElement.src = this.nzPlaceholder;\n        this.getElement().nativeElement.srcset = '';\n      } else {\n        this.getElement().nativeElement.src = this.nzSrc;\n        this.getElement().nativeElement.srcset = this.nzSrcset;\n      }\n\n      // The `nz-image` directive can be destroyed before the `load` or `error` event is dispatched,\n      // so there's no sense to keep capturing `this`.\n      fromEvent(this.backLoadImage, 'load')\n        .pipe(takeUntil(this.backLoadDestroy$), takeUntilDestroyed(this.destroyRef))\n        .subscribe(() => {\n          this.status = 'normal';\n          this.getElement().nativeElement.src = this.nzSrc;\n          this.getElement().nativeElement.srcset = this.nzSrcset;\n        });\n\n      fromEvent(this.backLoadImage, 'error')\n        .pipe(takeUntil(this.backLoadDestroy$), takeUntilDestroyed(this.destroyRef))\n        .subscribe(() => {\n          this.status = 'error';\n          if (this.nzFallback) {\n            this.getElement().nativeElement.src = this.nzFallback;\n            this.getElement().nativeElement.srcset = '';\n          }\n        });\n    }\n  }\n}\n"
  },
  {
    "path": "components/image/image.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzImageGroupComponent } from './image-group.component';\nimport { NzImagePreviewComponent } from './image-preview.component';\nimport { NzImageDirective } from './image.directive';\nimport { NzImageService } from './image.service';\n\n@NgModule({\n  imports: [NzImageDirective, NzImagePreviewComponent, NzImageGroupComponent],\n  exports: [NzImageDirective, NzImagePreviewComponent, NzImageGroupComponent],\n  providers: [NzImageService]\n})\nexport class NzImageModule {}\n"
  },
  {
    "path": "components/image/image.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport {\n  createBlockScrollStrategy,\n  createGlobalPositionStrategy,\n  createOverlayRef,\n  OverlayRef\n} from '@angular/cdk/overlay';\nimport { ComponentPortal } from '@angular/cdk/portal';\nimport { inject, Injectable, Injector } from '@angular/core';\n\nimport { ImageConfig, NzConfigService } from 'ng-zorro-antd/core/config';\n\nimport { NZ_CONFIG_MODULE_NAME } from './image-config';\nimport { NzImage, NzImagePreviewOptions } from './image-preview-options';\nimport { NzImagePreviewRef } from './image-preview-ref';\nimport { NzImagePreviewComponent } from './image-preview.component';\nimport { NzImageScaleStep, NzImageUrl } from './image.directive';\n\n// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging\nexport interface NzImageService {\n  preview(images: NzImage[], option?: NzImagePreviewOptions): NzImagePreviewRef;\n}\n\n@Injectable()\n// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging\nexport class NzImageService {\n  private injector = inject(Injector);\n  private nzConfigService = inject(NzConfigService);\n  private directionality = inject(Directionality);\n\n  preview(\n    images: NzImage[],\n    options?: NzImagePreviewOptions,\n    zoomMap?: Map<NzImageUrl, NzImageScaleStep>\n  ): NzImagePreviewRef {\n    return this.display(images, options, zoomMap);\n  }\n\n  private display(\n    images: NzImage[],\n    config?: NzImagePreviewOptions,\n    scaleStepMap?: Map<NzImageUrl, NzImageScaleStep>\n  ): NzImagePreviewRef {\n    const configMerged = { ...new NzImagePreviewOptions(), ...(config ?? {}) };\n    const overlayRef = this.createOverlay(configMerged);\n    const previewComponent = this.attachPreviewComponent(overlayRef, configMerged);\n    previewComponent.setImages(images, scaleStepMap);\n    const previewRef = new NzImagePreviewRef(previewComponent, configMerged, overlayRef);\n\n    previewComponent.previewRef = previewRef;\n    return previewRef;\n  }\n\n  private attachPreviewComponent(overlayRef: OverlayRef, config: NzImagePreviewOptions): NzImagePreviewComponent {\n    const injector = Injector.create({\n      parent: this.injector,\n      providers: [\n        { provide: OverlayRef, useValue: overlayRef },\n        { provide: NzImagePreviewOptions, useValue: config }\n      ]\n    });\n\n    const containerPortal = new ComponentPortal(NzImagePreviewComponent, null, injector);\n    const containerRef = overlayRef.attach(containerPortal);\n\n    return containerRef.instance;\n  }\n\n  private createOverlay(config: NzImagePreviewOptions): OverlayRef {\n    const globalConfig = (this.nzConfigService.getConfigForComponent(NZ_CONFIG_MODULE_NAME) as ImageConfig) || {};\n\n    return createOverlayRef(this.injector, {\n      scrollStrategy: createBlockScrollStrategy(this.injector),\n      positionStrategy: createGlobalPositionStrategy(this.injector),\n      disposeOnNavigation: config.nzCloseOnNavigation ?? globalConfig.nzCloseOnNavigation ?? true,\n      direction: config.nzDirection || globalConfig.nzDirection || this.directionality.value\n    });\n  }\n}\n"
  },
  {
    "path": "components/image/image.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ESCAPE, LEFT_ARROW, RIGHT_ARROW } from '@angular/cdk/keycodes';\nimport { Overlay, OverlayContainer } from '@angular/cdk/overlay';\nimport { Component, DebugElement, NgZone, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, inject, TestBed, tick } from '@angular/core/testing';\n\nimport { NzConfigService } from 'ng-zorro-antd/core/config';\nimport {\n  dispatchEvent,\n  dispatchFakeEvent,\n  dispatchKeyboardEvent,\n  dispatchMouseEvent,\n  MockNgZone,\n  updateNonSignalsInput\n} from 'ng-zorro-antd/core/testing';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\nimport {\n  getFitContentPosition,\n  NzImage,\n  NzImageDirective,\n  NzImageGroupComponent,\n  NzImageModule,\n  NzImagePreviewRef,\n  NzImageService\n} from 'ng-zorro-antd/image';\n\nconst SRC = 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png';\nconst QUICK_SRC =\n  'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTA2cHgiIGhlaWdodD0iMTIwcHgiIHZpZXdCb3g9IjAgMCAxMDYgMTIwIiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgogICAgPGRlZnM+CiAgICAgICAgPGxpbmVhckdyYWRpZW50IHgxPSI2OC4xMjc5ODcyJSIgeTE9Ii0zNS42OTA1NzM3JSIgeDI9IjMwLjQ0MDA5MTQlIiB5Mj0iMTE0Ljk0MjY3OSUiIGlkPSJsaW5lYXJHcmFkaWVudC0xIj4KICAgICAgICAgICAgPHN0b3Agc3RvcC1jb2xvcj0iI0ZBOEU3RCIgb2Zmc2V0PSIwJSI+PC9zdG9wPgogICAgICAgICAgICA8c3RvcCBzdG9wLWNvbG9yPSIjRjc0QTVDIiBvZmZzZXQ9IjUxLjI2MzUxOTElIj48L3N0b3A+CiAgICAgICAgICAgIDxzdG9wIHN0b3AtY29sb3I9IiNGNTFEMkMiIG9mZnNldD0iMTAwJSI+PC9zdG9wPgogICAgICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICAgICAgPGxpbmVhckdyYWRpZW50IHgxPSI2OC4xMjc5ODcyJSIgeTE9Ii0zNS42OTA1NzM3JSIgeDI9Ijc0LjUzNjM5MTQlIiB5Mj0iMTYyLjUxMTc1NSUiIGlkPSJsaW5lYXJHcmFkaWVudC0yIj4KICAgICAgICAgICAgPHN0b3Agc3RvcC1jb2xvcj0iI0ZBOEU3RCIgb2Zmc2V0PSIwJSI+PC9zdG9wPgogICAgICAgICAgICA8c3RvcCBzdG9wLWNvbG9yPSIjRjc0QTVDIiBvZmZzZXQ9IjUxLjI2MzUxOTElIj48L3N0b3A+CiAgICAgICAgICAgIDxzdG9wIHN0b3AtY29sb3I9IiNGNTFEMkMiIG9mZnNldD0iMTAwJSI+PC9zdG9wPgogICAgICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICAgICAgPGxpbmVhckdyYWRpZW50IHgxPSI2OS42NDQxMTYlIiB5MT0iMCUiIHgyPSI2OS42NDQxMTYlIiB5Mj0iMTAwJSIgaWQ9ImxpbmVhckdyYWRpZW50LTMiPgogICAgICAgICAgICA8c3RvcCBzdG9wLWNvbG9yPSIjMjlDREZGIiBvZmZzZXQ9IjAlIj48L3N0b3A+CiAgICAgICAgICAgIDxzdG9wIHN0b3AtY29sb3I9IiMxNDhFRkYiIG9mZnNldD0iMzcuODYwMDY4NyUiPjwvc3RvcD4KICAgICAgICAgICAgPHN0b3Agc3RvcC1jb2xvcj0iIzBBNjBGRiIgb2Zmc2V0PSIxMDAlIj48L3N0b3A+CiAgICAgICAgPC9saW5lYXJHcmFkaWVudD4KICAgICAgICA8bGluZWFyR3JhZGllbnQgeDE9Ii0xOS44MTkxNTUzJSIgeTE9Ii0zNi43OTMxNDY0JSIgeDI9IjEzOC41NzkxOSUiIHkyPSIxNTcuNjM3NTA3JSIgaWQ9ImxpbmVhckdyYWRpZW50LTQiPgogICAgICAgICAgICA8c3RvcCBzdG9wLWNvbG9yPSIjMjlDREZGIiBvZmZzZXQ9IjAlIj48L3N0b3A+CiAgICAgICAgICAgIDxzdG9wIHN0b3AtY29sb3I9IiMwRjc4RkYiIG9mZnNldD0iMTAwJSI+PC9zdG9wPgogICAgICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8L2RlZnM+CiAgICA8ZyBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgICAgICA8ZyBpZD0iQW5ndWxhciIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTExLjAwMDAwMCwgLTQuMDAwMDAwKSI+CiAgICAgICAgICAgIDxnIGlkPSJHcm91cC05IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMS4wMDAwMDAsIDQuMDAwMDAwKSI+CiAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNjUuNjMsNzIuMiBMNTMuMjMsNTMuMiBMNDYsNjMuNjkgTDUzLjM3LDYzLjY5IEM1Ni40MDc1NjYxLDYzLjY5IDU4Ljg3LDY2LjE1MjQzMzkgNTguODcsNjkuMTkgQzU4Ljg3LDcyLjIyNzU2NjEgNTYuNDA3NTY2MSw3NC42OSA1My4zNyw3NC42OSBMMzUuNDksNzQuNjkgQzMzLjQ0NDg5ODYsNzQuNjg5MDY2NyAzMS41NjkxODksNzMuNTUzNDg0NiAzMC42MjAzMjYsNzEuNzQxODI4MSBDMjkuNjcxNDYzLDY5LjkzMDE3MTUgMjkuODA2MTUxMSw2Ny43NDE2MzQ5IDMwLjk3LDY2LjA2IEw0OC44NCw0MC4yNiBDNDkuODc5MjI2LDM4Ljc1Mjc2MzYgNTEuNjAxMzk0OCwzNy44NjI3MzkzIDUzLjQzMjAxNTQsMzcuODg2ODI2NCBDNTUuMjYyNjM2MSwzNy45MTA5MTM1IDU2Ljk2MDc5MSwzOC44NDU5NDIxIDU3Ljk2LDQwLjM4IEw3NC44NCw2Ni4xOCBDNzUuOTQ0OTUwNSw2Ny44Njk4MjA2IDc2LjAzNTIxMjIsNzAuMDI5MjA2NyA3NS4wNzUxMzc2LDcxLjgwNTM0NDYgQzc0LjExNTA2Myw3My41ODE0ODI2IDcyLjI1OTAxMTYsNzQuNjg4ODA3NiA3MC4yNCw3NC42OSBDNjguMzc5OTE5NCw3NC42OTc4MTMxIDY2LjY0MzM0NTQsNzMuNzU5ODM3MiA2NS42Myw3Mi4yIFoiIGlkPSJQYXRoIiBmaWxsPSJ1cmwoI2xpbmVhckdyYWRpZW50LTEpIj48L3BhdGg+CiAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNzAuMjgsMjUgQzY5LjA2MTY5MzksMjUuMDAwNDA1MyA2Ny44NjQ4MTA1LDI0LjY3OTYyNjggNjYuODEsMjQuMDcgTDUyLjg3LDE2LjA3IEwzOSwyNCBDMzYuODMzMTg0MiwyNS4yNTA0Mjk4IDM0LjE2Mzg2NzQsMjUuMjQ5ODkyIDMxLjk5NzU1NTYsMjMuOTk4NTg5MiBDMjkuODMxMjQzOCwyMi43NDcyODY1IDI4LjQ5NzA1MTMsMjAuNDM1MzIxNCAyOC40OTc1NTU1LDE3LjkzMzU4OSBDMjguNDk4MDU5NywxNS40MzE4NTY2IDI5LjgzMzE4NCwxMy4xMjA0Mjk1IDMyLDExLjg3IEw0OS4zNCwxLjg3IEM1MS41MDU4MDc1LDAuNjE5NTcwNDM1IDU0LjE3NDE5MjUsMC42MTk1NzA0MzUgNTYuMzQsMS44NyBMNzMuNzYsMTEuODcgQzc2LjU3NDEwNywxMy40MjA3NzMxIDc3Ljk3MTA4ODksMTYuNjg4MjM0IDc3LjE0NzkwMiwxOS43OTQxMDg4IEM3Ni4zMjQ3MTUsMjIuODk5OTgzNyA3My40OTI3NzUsMjUuMDQ2NjAzMSA3MC4yOCwyNSBaIiBpZD0iUGF0aCIgZmlsbD0idXJsKCNsaW5lYXJHcmFkaWVudC0yKSI+PC9wYXRoPgogICAgICAgICAgICAgICAgPHBhdGggZD0iTTUyLjg2LDExOS45MiBDNTEuNjMxMDQ1NCwxMTkuOTE5MzM4IDUwLjQyMzkyMzUsMTE5LjU5NTEzOSA0OS4zNiwxMTguOTggTDMuOTMsOTIuNzUgQzEuNzY0ODY2MTQsOTEuNDk5OTU5NSAwLjQzMDc3Nzg5LDg5LjE5MDA4MSAwLjQzLDg2LjY5IEwwLjQzLDM0LjIzIEMwLjQzMDc3Nzg5LDMxLjcyOTkxOSAxLjc2NDg2NjE0LDI5LjQyMDA0MDUgMy45MywyOC4xNyBMMTUuMTYsMjEuNjkgQzE3LjMyOTA4NzksMjAuMzY5MTUzIDIwLjA0MzQyNTEsMjAuMzI2NzIwOCAyMi4yNTI3Mzk2LDIxLjU3OTEyMTkgQzI0LjQ2MjA1NDEsMjIuODMxNTIzIDI1LjgxOTc1NDQsMjUuMTgyMjg0IDI1LjgwMDQ5ODYsMjcuNzIxODEzMSBDMjUuNzgxMjQyOCwzMC4yNjEzNDIzIDI0LjM4ODA1MTgsMzIuNTkxMjQ0OSAyMi4xNiwzMy44MSBMMTQuNDMsMzguMjcgTDE0LjQzLDgyLjY1IEw1Mi44NiwxMDQuODMgTDg5Ljc4OTYxNjEsODMuNTE1OTUxNSBDOTAuNzE4MDM1Nyw4Mi45ODAxMTExIDkxLjI5LDgxLjk4OTYwODggOTEuMjksODAuOTE3NjUzNiBMOTEuMjksNDAuMDAyODQyMSBDOTEuMjksMzguOTMwNjIxMyA5MC43MTc3NTQ1LDM3LjkzOTkxNTcgODkuNzg4OTcyMSwzNy40MDQxNzI3IEw4My42MSwzMy44NCBDODEuNDQzMTg0MiwzMi41ODk1NzA0IDgwLjEwODA2MDEsMzAuMjc4MTQzNCA4MC4xMDc1NTU5LDI3Ljc3NjQxMTEgQzgwLjEwNzA1MTgsMjUuMjc0Njc4OCA4MS40NDEyNDQzLDIyLjk2MjcxMzggODMuNjA3NTU1OSwyMS43MTE0MTExIEM4NS43NzM4Njc2LDIwLjQ2MDEwODMgODguNDQzMTg0MiwyMC40NTk1NzA0IDkwLjYxLDIxLjcxIEwxMDEuNzksMjguMTcgQzEwMy45NTUxMzQsMjkuNDIwMDQwNSAxMDUuMjg5MjIyLDMxLjcyOTkxOSAxMDUuMjksMzQuMjMgTDEwNS4yOSw4Ni42OSBDMTA1LjI4OTIyMiw4OS4xOTAwODEgMTAzLjk1NTEzNCw5MS40OTk5NTk1IDEwMS43OSw5Mi43NSBMNTYuMzYsMTE5IEM1NS4yOTUyMjc5LDExOS42MTA4MDUgNTQuMDg3NDk5LDExOS45MjgyNjUgNTIuODYsMTE5LjkyIFoiIGlkPSJQYXRoIiBmaWxsPSJ1cmwoI2xpbmVhckdyYWRpZW50LTMpIiBmaWxsLXJ1bGU9Im5vbnplcm8iPjwvcGF0aD4KICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik03OC4wNiwxMDYuNDUgQzY2Ljg5LDExMyA1Mi44NywxMDQuODMgNTIuODcsMTA0LjgzIEwxNS45NDAzODM5LDgzLjUxNTk1MTUgQzE1LjAxMTk2NDMsODIuOTgwMTExMSAxNC40NCw4MS45ODk2MDg4IDE0LjQ0LDgwLjkxNzY1MzYgTDE0LjQ0LDQwLjAwMjYxNzEgQzE0LjQ0LDM4LjkzMDUxNjkgMTUuMDEyMTE3OSwzNy45Mzk5MDM1IDE1Ljk0MDczNTYsMzcuNDA0MTE2MyBMMjIuMTcsMzMuODEgQzI0LjM5ODA1MTgsMzIuNTkxMjQ0OSAyNS43OTEyNDI4LDMwLjI2MTM0MjMgMjUuODEwNDk4NiwyNy43MjE4MTMxIEMyNS44Mjk3NTQ0LDI1LjE4MjI4NCAyNC40NzIwNTQxLDIyLjgzMTUyMyAyMi4yNjI3Mzk2LDIxLjU3OTEyMTkgQzIwLjA1MzQyNTEsMjAuMzI2NzIwOCAxNy4zMzkwODc5LDIwLjM2OTE1MyAxNS4xNywyMS42OSBMMy45NCwyOC4xNyBDMS43NzQ4NjYxNCwyOS40MjAwNDA1IDAuNDQwNzc3ODksMzEuNzI5OTE5IDAuNDQsMzQuMjMgTDAuNDQsODYuNjkgQzAuNDQwNzc3ODksODkuMTkwMDgxIDEuNzc0ODY2MTQsOTEuNDk5OTU5NSAzLjk0LDkyLjc1IEw0OS4zNiwxMTkgQzUxLjUyNTgwNzUsMTIwLjI1MDQzIDU0LjE5NDE5MjUsMTIwLjI1MDQzIDU2LjM2LDExOSBMNzguMDYsMTA2LjQ3IEw3OC4wNiwxMDYuNDUgWiIgaWQ9IlBhdGgiIGZpbGw9InVybCgjbGluZWFyR3JhZGllbnQtNCkiIGZpbGwtcnVsZT0ibm9uemVybyI+PC9wYXRoPgogICAgICAgICAgICA8L2c+CiAgICAgICAgPC9nPgogICAgPC9nPgo8L3N2Zz4=';\nconst PLACEHOLDER =\n  'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMwAAADICAYAAACksw7kAAAgAElEQVR4AZzB2YFc26Fs1xmxEvTfM1mgT5lA4qByr5iqAk7HS76nZoz8X//n/+EntnHv5Xm/eb8/+PjxwY8fv/Hjt9/47ft3fvv+nd++f+f79+/89v07v33/jR/fv/Pjtx/8+PEbHz8++Pjxwfvjzfv95nm/eZ7LvZd7x93YZBMVhSkCClMUVBQGqHxRkC+C/CUhQAJJaEIT2tCG03Iazimn5XXKaXidclrOKa+GtpwTTkobmpBAAuEvKigqKhNUpqhMmaKiMPkkAvIlJIGEJKShLW1pS1t6yunhnHJeh3MO5/XidQ7ndXi9Xrxeh9frxet1eL1evF6Hb68Xr9fhdV68XofX6/A6h9frcE559XBOOaeclra04bQkoQ1JSCAEwk/hU/iTyi+CfBIVEBQVEBQVHCgqOFBAcKigoKCgqKCAoKiggKCooICooKDIQEFBUQHBgXwSFRQQFBQRFBQU+aT8pMgf5MtrGyrb2C7b2MY23HBDRUUFBQVFQAQB+Z38nfx38r8XfpFfAsin8LsQIIEQQkggCUlIQgJJCCEJPyVAIOGLCYRPQUBA/hD+IhAMCMgXgRBAIEAIIASqSIggnxJISEIS0tCUJCQhDU1JQ1qSkJQmJKEJCSQhgRAChPBLIED4NyEQ/kP4/y6A/EH+V+SL/FfyX8kfBAUEBAQF5E/yN4L8SX6n/CIo/0/k38l/ej3vNyrbuPfyPA/3ebj34d7LvZd7L/eO3bGNTaaoqKiIqAioCMgnQT7Jfyf/KYD8hxD+LgkJJKEJSUhDEpqQlDSkIQlpaUpakpCUJJAiwQQJJhA+BQLhSyCAEoQACgpCEZUIIgryi/whEEhCEpKShra0pS1t6SnnlHMO55S29JS2tKUJSUlDGpKQhASSEEISkvCfwl/C/074/0k+yR9EQP4iCggIKCggIH9QQP4ioICIoKDI7wQUEJC/ky/yk/wkn+S/EvmLID+9Pj4+UNnG7uV5Hp73m/fHm/f7zfN+uO+H+zw89+E+l3svu5fd4WTKJioqXxRQ5JMgoPwk/07lvwogJIAgkPC7kEATkpCENjThNLSlDU1pS1vakhYSaKGFBBJIIMEECRAInwLhpwAJiEQIIp8EAZUv8kmRX+RLIJAEEpKQhCS0pQ1pacs5pS3nHM4p5xzOOZxzOOfQczintKUtbWlLU5qQhCQkkIQEkpCE8Ckh4U/h/yX5LwQEBQQEBAEB5S8C8ouAgHyRTwoKigoKCIoKCggKCogICorITwLyk/IX+SQgyl8E+Z0in+R3giC/vH58/46Ik3sv93l4P2/eH2/eHx98fHzwfn/wfr953g/P83Cfh3sv917uvWzDjSlONlFRQBFBPokKAoqA/K+FvwmEQCB8SkhCAk1oQlua0Ia2tKUntCUtaUlDWpJCgikmmCCBBBNIIPyS8FP4Kfwl/Dv5HxL+kAQCSUhCEpLShjQ0JS1tOKe0h3NKTznncM7hnHLO4XUO53U453BOOaf0lLa0pQlJaUJSkpCEJIQvIeGX8DfhP8jv5BdBflL+pPyNgMgnBQUBRQUBBUUFBQFBBQQERQUFRAUFRQQFRQQFRQUEBQQF+Un5naCI/CQovyhfVP6n12/fv6Oi495x78PzPLw/3rzfH3z8+MHHjw/eHz94f3zwfr95vx+e98N9Hu693Hu5G9uYQ4fKlCkKIgoCIvJJPslf5A8BJCT8myR8SUISmpCGJrShKW1oSxvakpa2JIUEUkghwQQJSyAhBBKSEEICSQifEn4KP4VPgRC+JHwKCZ9CAiSETwkJJCEJSUhDU5LQhrS0oS1taUtPOS095fRwTuk5nHM4p7zO4ZxyzuF1DueUc8o55ZzSljY0oQ1pSEMTkpCEEJIQIHwKhP9JfhHkk6CAoICAoKggoKAgoKCIoKAgqKCAgMgAQVFBQVEBQVEBQVFBAVFBAUFB+aJ8EhQQBOUXAUUERPlF+aJ8kj+8vv/rn6io7I57H57n4Xm/eb/ffHx88PHjgx8/fvDx4wcfPz54f3zwfr95Pw/P83Cfy72Xey/3jjvZhoqKyhQVBQUBEeQX+VMAA+EvIRAIIYEkJCEJbUhCW5rQlja0JSltSUta0pAWG0xJggkQTCBhhBJIIGBCgCQk/C4QCJ8SEkhCEr4koQlJSEICSUhDW5LQhqakoQ1taUNb2tKWtrSlp5yWnnJazjn0lNNyzuGccs7htJxTzimnh9NyTjkNbWlDU9KQhCQkIUASCIT/JwICgvKTgoICAvKLgICIIJ8ERAQEBEUFBUUFBUUFBUQFRQUERQUEBUUE+UUBQVF+UUBUUFBEEFRQQJTfyU/C6/s//8mXbWzj3st9Hp7n4f1+8/Hxwfvjgx8/Pvj4+ODjxwcfHx+8Pz54Pt4874fneXiey33G7tjGJtuYMEVBvshPyhf5XSAC4afwJXxJ+BQSPoUkJKEJSUhDE9LShLakIS1pIYEEEkyREIoJIzSBhBFCSAoJCYQQAgESCEhI+CWBBAJJICEJTUhDE9qQhCa0pQ1taUNb2tKGc0pb2tCWtrTltPSUtrSlp5yWtpxT2nJaziltOS2npaecljY05TSkoQlNSEITEkgCgfCXACJ/UkBAEJBfFBUQEBQUHSgoKigoKCooKCgqKCooKCooKCogKCooIigoIigoIMonQQFBUT4JCooIigqKCop8Ur6o/N3r+7/+CcIcu2O7PM/leR7e7zfv95v3x5uPjw8+Pj54f7z5+Pjg/X7zfj887zfv98N9Hu59uPeyO7YxRYeKioqCivy7ACaEv4RPCeFTQggJJCEJSUhCGpLShDSkISlJSAIpJJgAwYQRQihhhBBCCCEECSUQCKEJIYRPCQGS0AAJJNhAQhJoSEJa0tCGtpyGtpyWnnJaziltOQ3nlLacU9pyTmlLW05LW9rSlja0pS2npQ1tacNpaUNT2pCENjQhCU1IIIQECIRfwh8kgAjySVBAUERQUFBAVFBUUFBUUFB0oKDgUEFBUUFBUUFBUUERQUFRAVFBAVFBQfmiAoICooACooKiooKigqIignwS5U+v7//8JwhzbGP38tzL81ye95v3++H9fvPx8cH7/eb98eb9fvN+Pzzvh+d5eJ6H517uc7l37F7uxiabqKgoiPxJ/k34XSCEhE8hgSSEQEISkpCEJCQhDUlIShKSQIIJIUiA8GWEACWMgCGEEJJQIQSBEJKgIQkBQkhCAiQkoQkmkGCLCTTQkoY09JS09JTTck45p5xzOKeclnPK65RzDm05p5yWc0pb2tKWNrSlDU1pQ1uakIYmNCENTUhCEhoIIYHwKRACSPg7+UWQT4IigoICgqKCIoKCggNFBQeKCgqKCgoKigqKCgqKCgqKCooIigqKCAqKCgiKCgiCCgiKigqKigqKig4VBBUR5JPIL6/v//wnIk62cTfuc3nuw/N+eL8fnvebj/eb9/vh/X7zvB/ez8N9Ls/zcO/l3nHvZXfcjU1UNlFRUZDfKRL+kPC7kEASAiSBhCQkIYEQkkBCEpKQBFLSQAIJEAQGhBAhgQgJKAQIkED4ZJCQQAghxJCECCGEEEIAE0KQIqEECCQkJQlLSYoJ9JAWTsk59JRzyjmH16u8zuGc8jqHc8o5h3PKOeW0nJa2tKUNbWlCGpqQhCYkIQkNJCEJ4VMgQPgUfgp/o/xB+SmICggKigiKCgoKCA4VFBUcKCo4UFRwoKig4FBBUUFB0YGigqJ8EhUUFRQRFBUUFBEUFRQVERQVJzpUVJyoqKiIIIj84fX9X/9ERWUb9457L/e5vJ+H53l4Pw/P++H9fni/H57n4bmX+1zuvdw77h3b2MYmKlOcyCdB5E8J4ZckfElCgCQkIYEkJCEJEJKQAAlJgEBCEiBAgCAgEAMBhQQQAkQIECB8GqQQYEDlpwABIiQhhBAKhKAhCRIkSIAAJYSkJMUEU0wwhRRaaEkPPYee0nM4r8M5h9fr8DrlnMPrlHPKaWlLW05LG5LQhiQkoYQESEggQPhdIPyN8ieFBJUvQVRAQFBQUEBwoKCooIig6EBBUcGhggNFBQVFBwqKExwqKCooKiAqKCoqKCooKiIoKiooKio6UFRUNtGh4mQOFRUVBRT5Igiv7//8Jwoqc+yOe8dzL8/z8DyX53l4P5fneXieh+e53Dvuvdw7trHJNjZRUVFQPon8IXxJ+BSSkEAISUggCUlIQhKSkISET4GEnxIg/JQAgYD8RQRDEBYoBMlCIgTSED4NEklDBwkQSCCDBFoIMEIJI9RgQAMJECCEEEIIIYRQggQTJJBiAgmkpCUtPaUt5xzOOZzX4bScU07LOaUJbWlDEpqQQAgJP4XfBZDfyU8KAQT5g4CgiICooKig6EARQVFB0YGigoKiA0UFB4oKDhUUFBUcKigqOJyogKigqKiooKioqOhQYaKioqKiQ0VlEx1O5thERWUTFRUQ5ZMIvP71r3+BoDLHJvde7h33Xp7n8tzL81ye5/Lcy72Xe8fuuBM3pqhsfBIF+SIQEn4XEkhCEpKQhCQkoQlJSEICSUgChIRPQf4QBORLkE8GAwjyB4EQhAEJiSRAQyYEEkhCkCQkkEACCaSQQQMpFGiCBg0mQNCAAQIG5FOI4RoC1DDhCiWMMMIIEiSQQEpaktCWtrSlLW05DUloQhISSEL4S5BfRH4nP8kXAQFBQQFBQUFBwaGCooIiA0UFRQVFBwqKDhQVHCooKG6gqOBQUUFxQwVFRUVFRUVFhxMVFR0qTlR0qKhsoqJjkzmcbDKHkyluTFE+ifJJBF6//es7IgpO5rgbu+O5497LveO5l3vHvZd7xyZ3w8kUBZUvyk/hUwIJIRBIQhKSkIQ2JKEpSWhDAkkIgYTwKeGLgIKAfJKfFAQEFARUCJBAhAABIgkQiEIgAQLpiCUZSUkhgQQitJCEAg0UaKHCGQicgoIDAwgMCCBkkEgKmWSSSSadnMmECVOmKAjI/xSSkIQEkhAg/HcBlE8CggKCgqKCIoKigqIDBUUFhwqKCg4VEBUmOlB0oKjgUEHRwURFBYcTHSoobqioqDhRmUNFxYmOKU50THGiomOKkyluTNnGJnNs4saUTVRUFEQQBF6/ff+OgIrCHJts4165G/eOu3Hv2MY2NpmioKL8KQk/JSQQAglJaENS0tCEtiShCWloQhJCIHwKfxBQUBmfFAEFkQlDFAQEDJAhhQABMkhIChkkJIGErKQjKcnIQhqakkCFVCq04SAFSrBSg4ODkMAEgogRIiBEuOOnhCRASEISyEhCEkhIAjdACEIEJBEGFEoAgUAgfJGflC8qICgqICooKigiKCooOlBUdKCo4FBBUUHRgaKiA8UNFBUdTHSooLihouKGihsqOpyobENFZRMdU5zo2ERlDidT3JiisomOTbYxZRubbGPKJiqbqIioyCfh9eO3HwiIKKhsMmUbd7LJ3dhkGxOcCCifQsIvCSGQkEBSkpCENrQlKW1oSxPS0IQkJCEJfyegoKIwJcoEEYUrTJgyQWCAfArIIEECCSQkQgIJENJCJAmpJCEJbUmkLTV00IYKs1Q4yoSjWBgwZMIYo8hQ8MCACQoTFKaITFEQmTJBQUFFDyIqIqcFAglJaOTvwhdRPgmKCooIigqKCogKDhUUFR0oKjhUnOBQQdGhguKGCg4VN3SgONHhRIeKG07mcENlGyqb6NhEZRtTnMzhZJM5VLahsskUN6ZsMscm29hkG1O2sckUlSkqyidReP34+OCLypcJKlMcTJmyyRQV5E9JIBACCUlIQhKS0JQ0tKUtbWlLG5qShiYkIQlJ+IN8UiaoTLkTNhQEplzlKhtcZcIQBQkmSJBPCRJIIAECCSQkkoS0JJKGpLSSlFba0sIxVJhQyxyHImOUI8jQMMs61nAqU87GVrbyrNyN1z3cO+4d9467F/eOe8fdi7vx7Rz2klle56BixYbT0gYCSQiQ8DtBPokKigiKCooKigoOERQVHUx0qOBQUWFDRQeKihsqbuhwosMNFR1O3FBxYw4n29iGyjY2cWPKNqY4mWOTTXRsMoeTKduY4mTKNqZsso1N5tjkbmyyDZUpKhNUvoi83u83PwkCAgoqAgpTFJBPgUASAiSBhCQkISlNSEtbmtCWtvSUtrSlLU1ISxMIhPAHEQWVbNxJJskwQURgwlXu5E6usMmACSMISJAgnxIgmEBCEiDQkZRkpKUJqTQhlTacSiu35RTugaPMcoXTcCq34VhOQiun4SS04bnjdcJzw2l5nfKc8jqX55bnOTyvw3Mv314v/vHt8NzLfb24r8O9h2/3cF9j5/A6Zaes47SchiYkkECA8EV+UlRQRFBUdKCooKjgUNGhwoaKDhU2VHQ40eFEhxsqbuhwYxMdbmyiYxtOtrENlW1sYxubbGPKJm5M2cYmU7axyRxOpmxjipMp25iyyTY2meNOtrHJlG1MUVFQkU/C697xB/kkyC8CCiEQIBDCl6SQkIQkpKUJaWlKW9rSlp7SlvZwTmlLG5LQlITfBRCVKSp3QoKMMTRIGHCVO7mT58qdXOVOJlxAYQQBCQISSIBAAgkkJIGMpqQjKe1ISjvacio90srp6MppacdpOQ1tOQ3NOA1NaOEktOE0nIaTcE44Da9TXqe8Tvn2Onx7Hf7xHL69Ls9z+PZ68Xy7/OPbi+ce7n3xbWNn7FVeO3iKZ2g5CW1IIECA8EVAVFBUUFRQRNxAUdGhgsOJDh1OdLih4oYOJzrc2MQNHdtwYxtuTNmGG5tsYxvb2GQb29jGlG1sso1Npmxjkzk22WSOTaa4MWWTKdtQuZNtbDLHJndjk02mTHEioqL89FL5d+GXkEASIAgkgQQSkpKEpLQlDU1pS1vaQ09pyzmHtpxT2tKWpqQhCX9SpqhscjfMkIDAREBhgzt5lOfKs/FcucqdXGHKhBEUBCTIpwQJJJCQBBKSkJQ2JKEtaWlCW9pybmlDW05LTzkJbTgtbWhCG05CC01oQgtNOA0ncBpOyznhdcq3U16vw7fX4f06fHs9vJ8X/3hdnufwPJd/fHtxv427w16H7bDX2A6vFY/YUEMTGgiQ8EmQT4KigkNFxQkOFR0qbqi4ocMNFTfcmMMNN6a44cY2tuHGNrbhxiZzbGMbTraxjW3cjU22sY072cYm29hkjk3uZI5NtjHFyTamTNlEZRubTNnGnWxjyp1sY5MpU1RUFEQQXk2AQPhdIHwKJEAgIQkkJCUpaUhKW9LSlra05fTQlp7DOeX00FPaQ1va0IYQCD+pqGyyjbvhDQJ3AkHChKtc5Zk8d7w3njueO57JnVxhyoQJEgbIl/BTAgQSSEhCEpKShqakow1NaUsbbktbTstt6C1NaENbmtCGBprQhBaa0EADTTgNbTgJrxPOKd9OeZ3Dt1d5v158+3Z4P5f3t4fnvnju5d7L7mX3xb692MYme4kWLbacBhsMNCF8kQAqIDqYqOhQcUNFhxMdbuhwYxM35nBjG25sw41tbMONbWxjG9vYxja2sYkbd2Mbm2xjG3djk23cjU22scndmLLJNjaZso1N5thkyiYqm8yxySZzbHIn25hyJ9uYojJFQeWLwOu8XvwpAQKBEEhIShJISUNS0tKUtLSlLW3pOZyWnsNp6TmcczgtPYe2tKUJJCQgn5RN5rh3sOG9VLgTMgYMmHAnzx3PHe873s/lueOZPHc8kwlXmTBBQEDDFxMgJEBCEkhJQjuy0ow0NKUdaWlCW9pyG9rShDY0IQ1NaEISmtBAAk1ooIEmtNCE03AaXqe8Tnmd8u11eL8e/vG8eN4Pz7cXzz8uz3O5d9w77sY2thebuOEOvoqn7P9mDF6UY0e25Ih67ASqePr/P3YIID1E8vTjtkbXTGvNsCasgRISCOW3QktbWqmllVpaqWJLlSpWqlRRUamiolJFRUVFRUXFLbrRoqKioqKiRWUrKlq2orK3aLGyLVpUtsWKFi0qtmixokWLLW1RsUWLFitatsWKFi22aLGlLW0p0PLjOM+TvyVASAIJSUiGTEiGzJAMM8PMkBlmFrOGNcPMYtaw1mLNYtaw1mKtxcwwMyQhCUkohYKKlu2GSJ+NLUwhUoLAbnksj3Ir95Z7y73leeRWHsu2aNktFiwUKOFb+RZISCAZSEhKEmrIlCakoREdZsSEmWESMsNMSMIkJGFmmEASkjCBJEwgCQMkMIEJzISVsCasCccajjWcx+I+Fvezuc/FvTfP3uxns7e4RUVFSyv1oJW68BiONXSCCROYQAJp+dYKLW1RaaWKlipWqqhUUVGpoqIbFbeoqKioqKi4RUVFRWUrbrGiRWUrWtyyFZVtUdGyFVu2okWLlW3RomKLFhVbtNhSixUttmixRUWLLVp2RUtbLLSlLS2Ub+V4vV78CF9CEkhIQjIkITNkhsmQGWaGWYuZYWYxa1izmDWsWcxarDWsWay1mDXMDMmQCeG3ttjilkdhh7KxBQcQAQsWtuVR7l2eLfeW+9ncj9x78+zyKNtiiwULFspv5VsgEAIJSUlCZpgEE9LShOnQhKTUkAlaJiEjSUjCJCQhCTMhgRCSMIEEkjBAAhOYwCRMYE1YE9YajjU8z+I5Fs/ePM/Bfjb72ewtKioqVWppD2ppxUN06Bpcw0pYAwkM3wottLSlFZVarFRRUamioqIbt6ioqLg3KioqKipuUdmKiltUtqKiokVlK1pUVLZFZStatmKLFpXdokWLFS3bYkWLLVpU2qLFFi22qGixRYvKbtHSFlsstKUtBVp+HK/3mx+BEEhIQhIyQzLMDJlhZpgZZhYzw6zFzDBrsWaYtVhrsWaYtVhrsWaYtUjCzPCXttiiskfYmwKxJAMZmmBht2zLs8uz5d6b+5H72dxb7r15ttxbtmVbbLFgS4E2/C2BhAAJMPymmJCESWCCliQkoQnTISlNiCEJCZiQhCQkIYEkBJiEBBIIkMAACUzCBNaESTjWsNewl+y92XuxD9l7sbdoUdHSlrbY0pZaVFR6LHQ4dlgTVsIEkvKjhUpbqqhUUVFRUVFRUXFvVFRU3BsVFZW9RUVFxS1bUVHZiopbVGzZihYVFS1b0bIVW7TYYosWW9qiZVds0aLFihYttmixRUWLLSrushVbtkXFFoW22FJKCy1fSoHj4+MNBMKXkIQkJCEzZIaZYWaYGWYWM8Osxcwws1hrmLVYs1hrmLVYa7FmmLWYGZJAwre2tGVv2QrZCIwlI00oYMHCttxb7i33lvuRa8u95X4295bnkUfZlm2xpQX5UiiF8CWkQAoJEOjwl/Bb+SIQIECAFANJSEICSSAhhASSkIQkJBBCA0lIIEAoBgJMQgI7sBJ02HvYS3SxFS0qWmyxpS1taUtb2tJKe1DFLecx7AlrwkqYQCihQGlLlVZUquwtKioqKu6NioqKW7YbFbeobMUtKipbUXGLylZUVFS2RUWLFS0qWlR2RYstFtpiSwtSWrBFiy22aFGwRYstWlRs0bK3qGxl76KyLSq22NKCLS2UQqH8dnz8+sVfkkBCEpJhJmSGmWFmmFnMDLMWM8Oaxaxh1mLNYq1h1mLNYq1h1mJmSEISIJSiRWVG8mxa2AozkFCChW15LPeWe8u9N/ezuZ/N/WzuZ3NveZ7Ns+WxbIsttrRQfiuBQsKP8C0QoOUv5VuBAAECBBqakEgSkpCEpCShhCQkJQmTQICEEqDQAIUA5YcpARpoQls60i7aootatLSlLW1pSwttaUtb2qJFZbvZezjXsBLWwARCgUILLVVaUXHLVlTcGxUVlb1FRTdu2YqKW7aiGxW3bEVFZVtU3KKiYstWtFSxRUWLlW3RYktbBNpSoEAbSilgi4IFCxYsWFCwYEFhW7Q8u2yLW7aiZSttsdCWAi2Ub6V8KRwfHx8QCIFAMiQhCTNDZpgZZoaZYdZizTBrMTOstZhZrDXMWqxZrDXMLGYNkyEJBFqwReXZQh4sRGEGCDbYsi2Pcm+5t9zP5ro31725ns39bO5n8zybe8vesi27xZYWypdCw48A5Uv4EqBQ/rsCAQKk0EACCSSQQAIpJEAI4VuBEKB8CyEpAcJ/KH8rRfmT0PJb+a20/F/Kj0JbqtTF3ou9hr3CSlgDAySFAhVaWlFRcW9UtuIWFd3sLSoqKnuLblT2FhWVrbhFZSsqWlRUVLSo2KKixUottqhosUVKCwVK+NYEKCUUKCBQQEBAgsAGbLHBll3YhadlW7ZFixYLFloo4VsDFMqfAsevP37xlyQkIQmZYTLMhMywZjFrmFnMGtYMsxZrFrOGmcVai7WGmcWsYTIkgYRSKmxlbyEPtowle4BQwJZteZT7kfvZ3M/mejb3s7mezf1s7mdzb3m27C2PosUWC+VLoUAIUJoQvrT8CP9W/qX8pUD4rUCAAAECDUlhQhkCJBBgCBOYQBISCBAgfAkECOVvhbZY2Ft+C7+F8I8UKNDSSj1wyz42+xieNRyBCUwglFBoaaVKFZW9RTd7i4rKVtyist24RUVlK25R2YqKyt6iokVFRcUWFS1WarFFpS1abGnFQlua8K0JSSADCQRIaKGBEkrplLaUAqWEIgIWpEiQICBhU0qQL4ESCH8L/zh+/foAQsKXkIQkzAyZMDPMDDPDmsWsYWaYtVizmDWsWcwa1lrMDDOLmZAMSSjQlq3MlmRjy4yQUKCALdvybHm23HtzP5vr3tz35no297O5H7m3PHvzbHmUbdHSlgItEL6EtiThRwsJP8q/pfxoKCXht0KBUEr4USCFBBJCoBBKAiEMMAkrYWaYhAQmEEL4kvIt5UshIUAIIVCoxciz+bJJgDuEL+VLgdKWWtybvRfPHs4Ja2AFJhAKLbS0UqWKbvYWlb03Kltxi8pWVNyishUVt2xFRWUrKlpUVLaipYotKm2xpZa22NKKlrYUKF8SSEgCM2RKEpJAAhkCFEhLCmlJSlISSUIypBsWpECBFocwFpgAACAASURBVCghtCUUCCEkgUAIhL8df/z6BeFLSEICyZCEmWFmmBlmhlnDmsWsYWZYazEzzFqsGWYtZoaZIRkSKKEtWmYLPFiYLSR8a2Fbni3P3txb7ntz35vrfrieh+t5uO6H+9nc++F5Ns8jz5ataLGlQPlTA5QklJICCf9vBQKFpoRA+VKakJYSQvmtQPhbIA1JGcIAE1gDa4a1hpUwEyYQQsI/Wn4rv4UEkgChBS1GnieETfgtQAstVNHF3pv9DM8KK7ACEwiFFiqtVFFRcW+24patuDcqW1FRcZftRkXLVtyishUVLSoqVrSoaLGllVpsaUtb2tKWtrSlfAkkAzPMDEkZvoVkyAwkfBugfCmkJQUULFGwkIEMJDSBDFHSMi2/hSRkhiQQCIHwJRy/fv2C8CMJSZgJyTAzzISZYWaYWcwa1gwzi1nDzLDWYmaYGWaGzBBCgQJa9t58211kCwEKtmxl782zN/ezue+H63647ofrfriuh+t+uJ+H+3m4n839bJ692cq22NLyo3wLoZAAhQbCf1EgUCAFAi0EWghQIAEK5R/hS4ACKQFCWYE14Ug4JqwZjhVmhkmYhATCX0oLpVAo/yEQAoQKOyVbEkgg/KmlDlvZa3hWOCasCStlgFBoodJKFRXduGXvjcreorIVFRWVvUVFZStaVFS2oqJFRYuKLSpt0dJKW9rSlpYvpS1taQuBZMhAgCZMIYRkyAyzFiSQUKAJUyhgy1i02LKUvTbP2uQZZm323mhpS1sgkDAzZIYkJAFCwo/jjz9+8SOQhCRMQiZMhplhZpgZZg0zw8wwM8xazAwzw8wwMyRDEgi0oGUr37Qkm28t2LK3PHtzP5v73lz3w3XffN43n/fNdd1c9811PVz3w31vnmfz7M3eshULbSl/CaSUEKCFhP+iQKBASglpIaEtSWhLgPJb+BL+lkICQxnCBCZwJBwznGs4juFYw5phzTATkhAClG9taUsLUlq+lJbfAgRo0bK3hBB+a0s7uMU1HCscE9bAAJMSChVaqtSNiop7s7dsN25R2YoWFZWtqLhlW1RUVLbFiooWFVu0tKKlLW1pC5S2UCiFlvKlhcBMGcoEyJDFj0zIDLOGzEACCSSUUKAFWyy0RWU/sp6HYx/s52FvUWmh/JYMM8OsRRKSkISEH8cff3zwIyFAEjJhMmTCZJgZZsLMMDPMDDPDrCEZZoaZITMkAUJbbNm7FEiEQAtW9t48e3M/m/t+uO6Hz+vmum4+r5vP6+bz8+bzuvm8bq775r4f7ufheTZ7y1a02FL+EkhJAwFaSPi38o/wW4FACwltSaCFAA2k/Ev4LYEQAkxgBY7AMXCucK7hXMNxLI61ONYwM0xCEgKU0hYtLdhiiy1taaGUv7Uo7EgefrSlHdzDXuGYsAZWYAVCCYUKLXVTRUU3btl7sxUVt2xFRYvKVlS0qGxFRYuKLSparGixpS1taUtb2kLLb+VbW8K3kgSBlcCUUH4kZMLMMGuYNSRDZiADCQ2U0EJbWtCy92bvg/1snr1xi0rLbwnJsGYxa8gMk0BCwpdw/PHrAxK+JSFAJiTDJGTCzDAZZkJmmBlmhswwCZkhGZJAgIItW2kl8qMtKnvLszf3/XDfN9d9c10Xn9fF/1wXn58Xn9fF53Xxed9c98N9P9zP5tmbZ2+2osVCW8q3kBQaGggFwr8VCP9SINBCAm0J3wIUApTfwr8ECGEoQ1nASlgTjhnOGc41vI7FeR6ca3GsxVrDJMyEv9iixRZbtGyLlW1piy20EGhBy0Z4Ci20dGRv2BPWwASGMnwTWlDaTRUV90Zl741btqKishUtKipatqKiRcUWFS1WtNiipZW2tNCWUmj5Rwm/hW9lJkzCTGn5kcBMmBnWMRzHYq1F1jCzYIYkkIGEFgq00Ja9Ze/NfjZ7y96btrRAQgjJMGux1mImJEMSEiDh+PXrgx8JAZKQhCRkwiQkw0zIDJOQGSYhMyQhCUkgoYW2YGlLgLao7L3Z++G+H6775rpuPq+bz8+b//m8+LwuPj8v/ue6+fy8ua6b67q575v7eXiezbM3W9GipUALhB8Fwp8KDYS/FAj/UiCFBlIoEL6EtiTQQgikUH6EkECAUIawAmvgCJwTzhXOI7yO4X0sXsfiPA+OtTjWYibMDAEKtMWWbbFlW/aWR9nK3qJiS1tCaYsCLbS0YsIa2AkTmJShhBIKSiu4UVHRjVvcm63sLSoqWqyoaFHZFitaVGzRomJLW7S0xZa2QGnLj/KlfAuQQIAEEqAQSoEEZsLMsNZwHovzODjPk+NY5FjMLGYtMgMzJKGEEii0sJX9bPbe7C1uaUsLBELILNZazFrMDJOQhCQQOD4+3oQvCd+SkEASkpCEJEyGTEhCEpKQhGQgEEKBtmwhSFusqOz98DwP9/1w3zfXdXPdF5/Xxef1yed18fl58XldXNfFdV1c9819P9zPw/1snr3ZW1S0WH6ULw1JoYHwpUD4rfwWKP+WAqGUFJqQQikJtBACKRRICCVAgCEMMIGVsBKOCceEc4bXWryPxftcvM+D8zw5z8WxFmuGmSGBAi1siy1bebY8ytryPJsnm23YW1RaoKUVE2hpg4EdmMCkDCWUtARBaaVK3ai4Nyp7b1T2FhVbVLSo2KKixRYVW7RYqcUWW9rSlhbaUgrlTyV8CQSYQAgTmIE2hJCEmWFmWMfiOA7O8+D1Onm9XxznwToWsw7mWMwsMkNmgKEBGgrsLXuLz2bvzVYqvwXCkBnWOpg1zCxmQhJCIHB8vF/8SAhfAiEkIYEkJCEJJCQhhARIgJBACwW0hNKWKu7Nfh6e5+G+H6775rouruvi8/Pi8/Pi8/Pi8/Pi87r4vG4+r5vP++a6H+7n4Xk2e2+2GxUttrT8lgClhAClpIHwpUD4USD8qfwW2pJACWkpkEALSYBCgYRQQggwwARWYAVW4Bg4J5xreK3htYb3sXifB+/Xwfs8OM+DYy3WWswMSfhWyrZsy1aeLfeW59ncCTPheTYBNkVLCy200oCFAZIyQFLSEiQtVKhUqZsqKrpxy3bjFpWtaGlFixYrWmypxYotWtpiS1tsaaEtpVAo5S8BAgRIgMAMlFBCEjJhZpg1HMfBeRyc58nrdfJ+v3i9X5yvk+M8WMfBOg5mLTKLzCIJzfCtDSr7kb037s221PIjIYTMYq3FWouZITMkIeFLON7vF/8pfEkIXxLCl4QEQiB8CeFL+BLKt4KFllbqZu/N3g/Pc3PfN/d9cV0Xn9fF53XxeV18Xhef18XndfF53VyfF9d1c18P131z3w/Ps3m27C1a2tLyjwIBCqRA+FYgfCm/hT8VCN/akoQWQmkgQBsSoIXwJYQCIcAEJjCBlXAkHBPOGY41vNbwOob3uXgfi49z8T4P3q+T13lwHAfHWswakvCthd2ylWfLvWU9m3uGTMgdwrdCCy27BUpbWr4UKaFACSUtqVCh0gqKSt2o1I1bthu3qGixosWWWmyxUosttrTFlra0YEtb2lK+tJS/lAABkpDAACWULwmZMGuYGdaxOI6D4zw4z5PX++T9fvH+ePPx8eJ8vTjOk+M8WMfJOhazDjKLZGgChALu4pa9N3uLSgsUSEhCslhrsdZi1pAMCSQhhOM8D/5T+A+BEP4W/reWb6W0ouLe7L3Z++G5H+774b5vruvmui6u6+L6vPj8vPj8vPj8vPm8bq7Pi8/75rpvrufmeTbP3jx7o6LFFltafkuAEsLfCoQvBcK/FQjf2pIEWgi/NfxIoUBCgFBCGGACA0zCCqwJxwrnGs41vNbwWsPrWLyPxfs8+DgP3q+T9+vk/To5joPjWKwZkkCCLduyLc+WY2+O9bBmSEL4VmippS2tbKEtbaEFCi1UoFBJhUorVVDqRqVuVHTjFhUVW1RsqcWWttjSQltsaUtbbGmhlBZoKdCWvwRoYMKP8C1kwswwa1hrWGtxnAfnefJ6vXi/Xrw/Xny833x8fPDx64OPjzev94vz9eI4T47zZB0HsxaZRbIggYQ2qLhlb9lbVFr+FJKQWay1WGsxMyQhCUkIcBxr+P9XKJR/lEILllbqxr3Z++F5bu7n5r4vruviui6u6+Lzuvi8Lj6vi+u6+Lwuruvi87q5rofrfrjvh/t5ePZmK1uxpZZSIPwoEGghKSWE/6ZA+NaWJNDSQBoKJOVbCAFCCSFAgAlMYCaswDHhnHDMcK7hXMPrWLzPxfs8eJ8HH6+Dj9fJx+vk/T55vU7O8+RYi7UWSSChLdvybLm3rL2ZGZKbHy2tVNGhioTwpaWWVtrSSitUaKGC0m5QquimSt2oqFRRUbFFpS0t2NKWttjSQltKaaEtLZTS8qWUP7UQvoTwLRBIhkyYGWYNx1ocx3CcB+f54vV68Xq/eH+8+fj44OPXLz5+/eLXr1/8+vXB6/3ifL04zxfHebLOg1kHsxbJQAYS2qDFvdlbVLS0BcK3ZMgMax2stZgZkjAJBAIcMwOUH+X/Ulr+VL6VEqDlS6HQSlvcG/dm74f9PDz3w3Pf3PfNfd9c18V1XVzXxXVdXNfF53VxXTfX9XA/D/d9c98Pz7PZj+wte4uWWkqhfCkkQIHwvxUIFAhfCoTypSUJtDQhBVJ+NBC+FAgBAkxgAhNYCUfgmOGc4VjD6xhex/A+Fu9z8T4OPs6Dj9fBx+vk43Xy8T75eL94vU7O8+Q4DtYMmeFbgb3l3rL2Zj3DJARooZW6cMnem50wAflSaEWllSoqrdBCN1VaqVI3VeqmikoVlVZUtLSlLRZKaUsLbWlLgbaULy0F2lK+lC+lQPhTIAkkTEJmWCvMWhzHYh2L41i8Xiev94v3+837/cH744OPj1/8+vXBr1+/+OOPP/j49cH7/eZ8vThfJ8d5so6TdRzMWiQDGUiAoMUtW3GLlpYfSUhCslhrsdZiJmSGJARIwhHK38JvLeW3UL6VQvlSaKF8KW3B0i11s/fDfh6e++a5b+775r5uruvium6u6+a6bj6vm+u6ua6b67657pvrvrmfh/t5ePbmcbMVW1op0EL5R/hLgUCBlBLCXwqEAmkhAQoEKBAoJBBKCAEmMIEJTMJKWAlrwjHDucK5htcxvNbifSze58H7OHi/Dt7nwcd58vE6+HidfLxefLxP3q8X53lyHAdrLZJAgi17y9qyns3MQ4C2qOhi78WxN3uGPbATQqGlllpsUVGp0gqVKnXTSpW6qVKlipUqKm1RaaEtpbTQlm9taaGUli+lQFvKl0Ip/xZCIGESMsPMMGtYa7GOg/NYnOfJ+Tp5vd+8Pt68P958fHzw8euDj19/8OuPP/j16xcfv37x/njzer04Xy+O18lxnMyxWOsgGchAhm9atLhFRQstEEhIwmSYtVhrMTMkIYEkBDhC+Vb+VL6UAG350QKFAi1QKLSFFrfoZu/Nfh6e5+F5Hu775r4uruvium6u6+Lzuriui+u6ua6b6765rpv7vrnvh/vZPHvzbNlbVGqx0JbyLfylQAqEPxUIPwqkQCiQFhJ+FJqSBlIg/AgECBAghElYCWvCMeGccK7hXMN5LF7H4n0u3sfB+1x8vA4+zpOP18H7dfJ+/R/G4AUxkiNJsuBTM/MI1Nz/rMsM/5guEqgiWd3snhEZfFyDj3vwcV1c98U1BlVFZCIJIRqzTxP7EBFIgE23Oac553Ai2BHsECERgHgz2NhNd9Pd9GnajbvBjftgN+7GfXA37sZu3I3duJu2cTe2sY0Nxthg88nYYIx5MwZsvpl/JD4JJKEQEUFmkJlUFVVFXYNxFdd9c9839/3Bx8cPPn784OPH//Djxw9+/PgffvzPD378+MH9cXPdF2Nc1HVRVUQVmYUUKAIkQHSbbtPduJtuY/NFgBRIQWYSGYSEQgghgRAF5k0G82Ywnww2b7bBxuaTsY1tbNNt3E3vQ+/N2Zu9FmtN1prMOZlzMudkzsmcizkXc07mWsy5WWuz1mHtw96HvQ/nHLqbbtM2tjGfDMiAwAYJY4SwQeJvDIgvNkh8MyDEmwEhjBACJAiJkMgQKZEhKkRFUBmMDK5M7gruSu4q7lHco7hHcV/FxzX4uAYf18V9XdzX4L4uruviGoOqIjKQAgQ25D4oAkkY6DbnNPsEeweVQYVIiRRIIEA2uHEbd+M23U13Yzd2Qzd2427cxja2cRvbuI0NtrHBBhuMsfnJmDfzxfyN+cWY30ggIQlJKIKIIDLJLHIUNQZjDK7r4rovrvuD++OD++OD++MHHx8/uH/84OPHDz4+/of7xwf3fXPdN2NcjGuQVWQVmYUikAIkQGDobrqNu7GNAfFNCEWQkUQEEUIS4pOEgMLNm81PBoNtwNgGg21sA8Y2btM23c05zdmbvTZ7LfZarLlYczHnYs7FnJM5F3NO5lzMtZhzsdZi7s3am703ex/OaU43p03b2OaL+V8YEF9skHgzIH4xWCCDhQTik0BAIEIiBClIQYaoEBXByODK4KrgquSq5K7iHsk9insU9xjcY3CNwTWKaxTXVVxjcF2DawzGNagqIgJFIKBtFIGXwNA25yR1ktpJRZARZIgQhERghAGDDW7sprvpbrobu8GN29jGbWxDG9vYxjbGYIP5ZIwxn8wX23wxmF+M+WS+mN8ZEH8nJBEKIoLIJKuoGtQYjOtiXBfX/cF1f3B/fHB//OD++MH98cF9/+C6P7juD+77g+u+ua6LcV2MMcgqqorIIiKQAiQkYYNt3MZubINBEm+SkERGEBFIQhLik4SAcjd/sjGfbGwDxgbbYGM3tnEb23Sb0805h703e23WWsw5mXPyPA9zTuaczGfyzMmcizkXc27m2sy1WWuz9mbtwz6H081p425sY4zNTwID4icDAhsk3owR4k82SPwnAgIRgggIQUpkiIqgQlQGFcHIYGRyZXJVcldxVXJVcY/kHsU9insU1yiuMbjGYNRgjEFVMUYxqqgqIhMkBLQNOrRN21Q3lUlGkCEyRAaEREoERoAwssHGNrTBjd3Yjd24G9zYxja2AWMbYzBgMG/mL+ab+Yv5d+YXY97MJ4PFFwkkkIQiUAaRSWSSVdQY1LgY1824bq77ZtwfXPcH1/3BdX9w3x9c9wfXfTOum+u6GdfFdQ1qDKqKzCKyiAgUQgokYQM2tsEGGxskPgkBkogIQkISEl+EQFDuw59szCcb29jGNrZxG7uxjdvYTbc557DPYa3DnIv5LOZ8mM/DnJPneXieyTMXcy7mXMy1WGux1mLtzd6bvQ/7HHY3p5vupm1sY/Mn800YEBgQvzMgfjIgvhkQYISQIAQhCEFIpESGSAUZolJUBCOCkcGo5K7kquSu5KrkHsU9kquKu4prFNcorlFcoxhVjFGMKqqKrCKryCoiAkkgEd0YyDZ5mowgQ2SIlAiJkAiBBAKEkQ0Y3ODGNrZxG3djG9tgYxvbYGObLwZjvpl/Zf5izC+2+cWA+WS+mE8GA+IXYQkkkJCCiCQyiSyyBjUGdV2M62ZcN9d1M+6b67657g/GfXNdN+O6GddNjZsxBjUGVYOqIivJSCICRSAJSWA+GQy2weaL+SI+CSQhhATik0B8K5/DmzEYbIONbWxjm3bjNrbpbtym3fRpzmnW3sx1mHMxn8nzmjzP5HkmzzN5nofnmTxz8szJnIs5F3Nt1tqsfVjncE5zTtPduI1tbP5k3gyI3xkQ3wyIvxMgQIAA8U2AEJIIiQyRITKCClERVIiRwchgZHJVcldyjeJjJPcoPkZyj8F9FfdV3KO4RnHVYIxijKKqyEqqksokM8lMFIHEJ2GJsAmJiCBChERISBACAcIII4wwYGSDDTa4cTe4sY3d2AYbu7ENNhhsA+a/M//OvJlPNr8Y88VgzJstEJifJCShCBSBMolMooqoQdUgx6Cui7puxnUzrpu6bsZ1U9dNXTc1LsZ1UdegxqCqqCoyk4wkIlAISQgBBvPJYIONbTBgY0CYb0Y2XwzGvNXZm2/GNraxjW3cxjbdjW26m25jN93NOc05h7UOz9o8c/F6Js8zeb0eXq+H55k8z+SZk/lM5lzMtZhrs/Zm78M+h7MP+zTdTbdpmzbY5s0IxJ9skAwIDIhPBgvETwbENwPiTYIQhCAEKcgQKZEhKsSIoDIYGYwMRgZXJXclVxX3KO5RfFzFPQYfV/ExBvcY3NfgHoPrKq4xGFWMKiqLzCIzyUwiAylAQoDdhIKIICQkIQkBAgQII0A2YLDBBhts7AYbbGxjN7axG2xsAwaMMW/mk8GY39j8YvPJYDBgfjEGzCebNxuMeTNvBvPFgAFLGIGEFCgCRRCZRBVZg6xBjkGOQY6LGhc5Lmpc1LiocZHjompQNagqqpLMJCOICCQhPgnEJxvb0MYY02BjDDa2wXwybQMG88m81V6TN5tPxja26TZ2023cTdt0N92Nuzlt+hz2Ocx1mGvzehavZ/J6Pbyeyet5eD0PzzN5nskzF3Mu5lysvVhrs/Zm78M+zTmH0023sQ2YN/NmsEB8MiD+OwPi7wQIEEKIkIgQGSJDVIiKoDIYGYwMRiZXBlclVyVXJXcV9yjuq7hH8XEN7jG4r8F9Da4xuMbgGoNRRY2iKqlKMpPIJDKJSCTxl0DRSEICAQIEiDeDjWzAyEYYYbCBhjZ2Yzd2Yxt3A8ZubIMNNthggw0YzJ/MTzbfjPnFYDBg85MxYMAY88lgQOKLbX4jMAIJFCgCIiASZaIslElUEVVEFVFFVBFVRA0yi6xBVpFVZCaZSUagEEKIN4PNN2MMbtyNu+lu3I1t3I1t7MY22JhPhppz8mYbDLaxTbtxm+6mbbqb7sZtuptzmtOHvQ9rHZ61eD2L1zP54zV5vSav18PrNXnNyZyTORdzLebazLXZ+7DPYZ/D6UO36Tbtpm1sMH9nsEB8sUEyIMCAeBMGxC8CBEgQghCEIAQpkQoqREUwMhiZjAxGBVcmVyVXJVcldyX3KO5R3KO4r8E9io+ruEdxjcE1ijGKMYoxilFFVZFZZCaRSUSgCCTxp25CQgIhBAgQRhjZiDcjGzDYYAONbezGNtjYxt3YBhvbgLEN5ifzZn4ymE82bwZsvhmMMWDezJsxNhiwzReDeTO2QGDABgPmTSCwBBIQEIEiIAIiIBKUEAmRKBJFokgUiTJRJIpEkSgSRYAC8RcbsHE37qa78Tl0H/oczjm4m+5Dd9PduI3d2AYbA/U8D282YGMb27RNd+Nuuk130910N92mu9nnsPdhrs2zNs+zeD2T12vyek2eZ/I8D88zeebiWYs5F3Mt9jqsvdn7sM/hnOZ0093YxjbmF/HvDIjfGJABIUCA+CSQhBBChESEyAgyRKWoCEYGo5Irg1HJlclVyV3JVcldyTWKeyT3GNyjuMfgvgb3GNzX4B7FNQbXGIwqqorKIjPJDCKDiEARRAQIMN8kJCEJCSQQ5ncGmy822GCDDTbY4MY2uLGN3WBjGzDYYAMGAzbYgDEGmzfzizFgjPlkPhkbDNhgPtm82WDAmD+ZvxEgzJv4IoEECCRQgAQSKEABEihAAgkkUIACFCABwggDNp+MbWzjbtyHPk2fTZ/DOZuzD3025xz6bM45dDfdjbuxzReber0e3myDwTZtYzfdxt10m+6mu+luupvTzTnN2oe1Ns9cvObij2fxek1ez+T1TF5z8szJMxdzLubarL1Ze7P2YZ/DOc3pprtpmzbfzE8GiW8GxO8MiH8iQIAACUIQEimREhVBRTAyGJVcmVwVXJVcldxV3CO5KrmruEdyV3GN4r4G9yiuUdxjcI3iGoNrFKOKUUVVkZVkJhFBRBASISEJSRgDBglJBEKA+CaMMMLIRhhsvhkw2GCDG7exG7fBjW2wsQ0YbMDIBoz5ZvMn82YMmE/mm8EYG8wnm18MGDBvBvNNfDFg/on4k4QR3wQIxCeBhBEogAACCFCAAgiMwGCgMdi4G3fTffBpztn02Zy92Xtx1mbvxdmbczZnH/psupu2wcY2YOqPP178Yhvb2Kbb2E236W66m27T3XQ3fZp9Dmsf1t48c/Oaiz+exR/P4vWavJ7J8yyeuZhzMddirc1eh7UP5xzOaU433aZtbIONzX9mQHwyWCC+iN+JbwIkCCAkQpAhMkSFqAxGJiODq5KrknskdyV3FfdI7lFcldxV3KO4RnGN4hrFPYprJFcVo5KqpCrJTDKCiCAiUASSQAIJiS+SwICM+CRAfBE/GbABg/lksMFgGzDY2AY32NjGNu7mixvzyY0AY7DBxhgwGMw3G7B5M8YGA+YXY8CAbcwn88WA+Yv4iwHzOwPmk/ligwHbtME2Nhhogw1GGGGELWywoQ2yEcbduJvuQ59Dn83Zm70We032Wuw12Wux9+Lszd6bszfdjd24jTEY6o/XCwwGbGMb29im27ibbtPddDfdTbfpbvY5rH1Ya/OszWsuXs/i9Sxez+J5Js9czLmYa7HWZu3N2pt9Dvsc9mn6NKebbmMb27yZN/EmGyS+GRD/RIAA8U0CCYSQREhEiJTICCqDEcHI4KrkquQeyT2Ku5KPUdyjuKu4RnJXcY3kquIaxRjFGEVVUVVkJZVJZBARKAJJvIl/YUD8RoAAAQKEEQbMF/PJYAMGDDa2sRtsbONu7MY2tgGDDRjbvIm/MV+MwcY2bwZsML8YDAZsMGDzJwPGYP4jAeLvDOaTsU130276NOc05zS7m32ac5pzmt3NPk2d5pwmokFgICyEwYZuug99Nmdvzt6cvdhrsuZkzcmaD3st9pqstTh7sfeh++A2trENmPp/fzxgYz7Z2GCbduM2beNuuptu0910N93NPs3eh7k2z9o8c/Gam9ezeJ7FMxdzLuZczLWYa7P2Zp3DPod9mtPNaeM2trHBgPmdAWFA/CLejBDfDIhfJBAgRAhCIgQpkRFUiIqgMhgVXJlcldxV3FV8jOLjKu5R3JVco7gquaq4RjEq124fWgAAIABJREFUGVWMKqqSzCQzUSShQCEkgcSbDbaxjdu0jADxZjBfBAgQ5hdhhAHzJwM2fzG2sY1tbONubAMGGzDYmF8MNmBsvphvNj8ZDAZsMGCbvxgDNn8y/5kB8802Ntim23Q33U2fZp/D2Ye9N3tt1tqstVhrUWuQuYhMFAGY7uAoCIH45MbddG96H85enL3Ya7HmZM2HNR/m87Dmw5qTvRZ7LfbedDfdjW1s81b/748XX2xsMMY2bmOb7qbb2E236W7czenmnGbtzVyHuTavtXnm4nk2r7l4ns0zF3Nt1tqsvVn7sPfh7MM5TXfTbtrGNrb5YkB8MiC+GBDfbJD4RXwSXwRIIEAICSQRgggREhmiIqgIRgYjk1HJVclVyT2SexT3KD5GcY/iGsVVxVXJqKSqGJVUJZlFZRCRRAhJgDBgmzbIjbpRN+iAQBISYMCNbbDB5k2AAPFNgDDizXwz2GA+Gdxgg41t7OaLDZg3YQwI82bzydjmzeaTscEGA7YxfzFg8xvzf2CDDTZfbOzG3XQ3fQ5nb87erL1YczLHYIziqSKziEwkAcLdnFFkBBEiBLKxG3fTZ9PncPZir8Veiz0f5vMwnxfzeZjPw5oPay32Wuy16G66jd1gMKb++OPFL7axjQ124zZt4zbtprtxm+7mdHNOs/ZmrsNcm2cdnrV4zc0zN8/azLWYazPXZu/D3od9Drub7qa76TZtY5sv5r8wIP6JAAkQCBBCghCEICRCIiPIEJmiMqhMRiZXJlcl10juUdxXcY/BfRX3KO4qxkiuKiqTqqSqyEyykswkI5ACJN5ssKG7UQd0w2mQQCIkxC/GbmwDBhswAgRIIPFJSCCBBALEm8HmzRjbgMHmzRhsBBgQxrwZMDZfbAPGgDHmdzaYv5h/JcD8b2ywjd24TXfT53D2Ye/NXos1i1mTqqIyiUgyhAQY3M05F3slEUGGEG8GN+5Dn0Pvzd6Lsxd7LuZ8WM+L+XrxPA/zeVjzYc3JXou9N+c0duM2xmCo1+vhzTZvtrGNbdrGbbqN3XQbd9Nuzmn2afY+zH2YazPX4VmbZ26etZlzM9dmrc3ah7U3+xzOac5pTjfdpm1sY8AY85MF4pMB8U/EvxMghAQChAiJkEiJDJEKKoLKYGQwMhgVXJXcVVxV3FV8XMU9Bvco7lGMSkYlVUVlkplkJlFJZKIMFAESRhjTNtjQDUeghiNAOIQAAcLYxjbYCBAgARJCSEICBEK8SYBAvBlssAGDjTGYT+bNNhI/GQzmzZhvBmz+ZBvzO/OLMOZ/ZcCAwTa2cTfdTZ/DOYe9N3sv1kwyk4ggI8gIIgJJCLCh25yzufZiVREhQiIE2ODGfehzOHtz9mLvxZ6L+TzM58V8XjyvF/N5WPNhzclai702pxt3YxvbvNXr9fDN2GAb29jGNm3jNt2NbbpNd9Pd7NOsfVj7MPfmWYdnbZ51mHMz12GtzdqHvQ97H/Y5nNOcbrpN27iNbWyD+Q8MCAzICAEGhAABAsRPAgGSkEBACCJESmSIiqBCVAQjgyuTkcmo5KrkGsVVxT2K+yquUYwqRiZVSWaSmSiSyCQyUQQKIQnEJ2GDbdymZdRNS0giECAQnww2YEAgkISAEEhCEpKQhCQkAUKABOLvzBfzyWA+mS82CDCfDOabwYDNFxvMXwyYv5j/RPwnxtjG3XQ3fZp9Drk2O4IVQSgICQESIL7Yxm66m3M2e9+sOahKMoIIId4MbtyHPoezN3svzlqstVjPi/k8PK8Xz+vFfF7MOVlzsuZk7805jW3cxhgwNZ+HN/PJxgbb2MY2beM27abb2E23Od3s3axzWPsw92Guw1yHuTZzHdY6rH1Y+7DPYZ/mnOZ00910N93GNjb/wIB4E28GxH8jQBICJJAgJEIiJEIiQ1SIDFERjAwqg8pgZHBlclVyVXKN4hrFNQbXKK4qqpLMJDOJCJSJIlAkkQmRKAJFIAmJT+IX29jGNrZARgbEF0lIIAkJJCEFEUISkggJSUgiJCQhCUlIIIx4M2DejBFv5u/MN/NmMF/MXwyY/0aA+ZMAA+KLAQO2cZvuprs557D3RgpCQhLim23sxja2cTfdTZ/D3oe9F2st1hhUJRFBhJBANnbjPvQ5nL05e7P3Ys3Jeh6e58V8vXheL57nYT0Pc07WWuy96dO0G7cxn2xqPhMwbzYYY4NtbGObbtNu3KZtupvTzT7N2s3ah7kPcx/WOqx1WPuw9mHtwz7N3odzmnOac5pu0zZt0za2sfl3BsQ/EiDxRYD4JCFAgBABhCAkQiIlQiIjyAgqggxREVQEI5PKYGQyKhmVjEpGFVcVo4qqJCvJSJSJIlAERKIIiEQRKAJFQARIIGHexL8yID5JvElCCCQkIQlJSEISIBBIgEDib8zfCTC/mH9mfjH/RID5xQgw/5X4nY1t2k20ON3oHCQhCYkvtrFNd9N96G66mz6Hcw57b/be7LW45mRcg6okIwgJiU/G3bib7sPZm7M3ey32msznYT4Pz+vF83oxn4c5H+ac7LlYe9OnaRvbYGOg1px8MzYYsI1tbGObtuk2tmmb7mYfc85hnWbtZu3D2oe5D2s3ex/WOexz2KfZ3ew+nG5ON92m29gG85P5Jt7Em8EC8SfxOwkQICFAgAQSSEKIEIRESGSIkEiJDFERVASVQWVQmVQmlUllMqoYlVQVNYqqJLPIDBSJIiACIlAkViAFRKAIUKAQSEgC8Um8GRDfbDBvwoDFJ2HAgAEDBsybMOLN/GIw/8CIvxHfBDJYAhvzzXwz/zvzkwQ2/4kB29imu9E5HIEQ4s3Yxm7spvvQ59DdnD6cs9nnsPdm78Vak2vejGtQlUSIkJCEMHbT3fQ59N7svdl7sddiPg/zeXheL+bz4nk9zDlZa7LmZu9Nd9NtbAPGhtprYn4yGLCNbWxoG9u0jdu0TXezu9mnWadZu1n7sHaz92GfZp/DOc05zTnNOU23OW3apm1sYxtjbPPFgIwQfzEgvhkQwoD4RYAAARIIIUCCEEgiJEIiJDJEhsgQGSJDZAQZoiKoDCqDyqQyqUyqkqqiKslMIpOIhAhQQAREgAIUEAEKJIGEQigEEpJAQhKIv1ggPgkQ5pMEEkaAeDNgwID5ZsCA+e8EiH8nPkkYg/mdAAswCDCfBDIymF8EmH9jPhkL3KYxqGHzk7GN27ibPs05h7MP52zO2Zx9OHuz12LvxZqL656MMahKIoIIIb7ZjbvpPpy92Xtz9matxXoe5vPwPA/P82I+kzUncy32XOy96TZtYxvbvNVeGzBvNl9sY8A2NrSNbdqmbbrN6eac5pzmnOac5vThdHPO4ZzmdHPanG66m+6mbdymbdpgG5tv5ov4BzZIiL8IECC+ib9IIIlASCIEIQhBSoRESoRESKSClMgIMkRGUJFUBplBZpKZZCaZRWaSmSgTIkABERCBFYAgAilAAglJKIKIQBlEJiEh8UUYEChQCCQUAgkkkLCEJZCw+A8MGDDidxJ/Et8skMECzDcBBiSw+YsA8xcB5k8CLMD8nfnJYEy7oUF82oCNbWzT3XQfztmcKs45nHM4+3D2Zu/N3pt1Lea8GNegKokQUiDxxW7cTZ/mnM3Zh70Xey3WXMzn4ZkP8/Uw58Oai7UWay32PnQ3NtjGGAzVe/Fm/mKDMTbYxoa2McYN7aaP6W76NN1Nd9Ntupu2aZvupruxTdu0jdu0jW3A2HwyvzEgA+KfiH8nvkkgQIAACUIQEiEREpIIQUiEREpEQIYIiYggQkSIiCAjyUwyk8wkM8lKMgtlogisgAiIAAWWQIEUIIGEJCQREUQGkUlISHyRTSMiG51EGaCECKRAESgECpBAAgkkQPwr8U0CDIhPQhhJgHmThWWwACNAgCVkYwlsJLD5JCRj800Cmz8JZGHezG9szCeDu2neDBjbuJvupvuQmZxzOOdwzuacwz6bfTZrb9ZajLUYs8hMIgKFEN9sYzfdzTmHszd7b/berDmZz2TOh/lM1pzMudhrsfbm7EN3Y4MxNl+qu/mNjfnJfDI2YIMBG9rgxm1sYxvb2I1tbGMbG2zTNjbYYIwBG2y+2PwfGRBvEggQIL5JIEASEkggQAgBEoQggEBIEBKSEEISIRESoSAUhIKIICLISDKSzCSzyEqUhSJAARE4EiRQgAQKkOD/cwYvCHIbWZIAzQOluf95mYjni0zUl5TU3WsWkkiWrFjrcBxLVsS71gozhxxb1pK1JIsVErJISBAEIYg/BfUpSCIuCa2GNKSeKtSlCCqJFqmgDamUIom2grqElIqnuNVTGWZhRhtttdWpNWNmmb3tddh7m9n23vZ5Os/T/52n83H66/Hw9teb4zhkLSshQbXV1syYve29nefpfJzOx8OvX7/8+vXLr1+/PH49PB4P5/lwPra9t5lqqy6tpzczfhcUUcrCqKeopIKkoqKi4ruiXkpVWy1aVFtVL61bfCniQ3woQrwkJARBEBGxEglJREQkJCwRBCsRJJHESiSxViSx1pK1rGNZx2Edh3W8WcfBOliLdbAWWZpIFgkJiYRkyYq1lrUOa8VTVFuDdVT2IetgLdYiiywSEhISQkP9VD8lQX0KQRNpNahLUEK8a1QJaVQlaDREtSTRElWXEJcivhSpDpNaiWm01YzpsmbMirW2mcPMtve29/a2t/Pc/vrr9Hb+5e3tzXEcsiJZEi9ttTUz9ozZ2z63c5/OX6dfj18evx4ej18evx7O83Sep/Pc9t7aamld6ultqb9Tt4aWhLq1rLCwQkJCEMTfKEVV0brVpf5ZER+CIAgSL3FLIkhYIQiChISIuIQgCCKCuIQkkiVZkshasg5Zh7UO6zis402Og7VYB2tpFglZJCSSeMpaViLHstay1hKltONpOrKWrCVryVqsxQpZJJpFogmCqGioW92CugUJEVIpTaQlQaUEFZQQodUQ0VaCUpFUS0JFWvUu/tCSlMaoqOxoYk01MStWxszYM/Yee49zj7e9nef2dp6OtzfHsSSRhMRTVaemNTP2Hntve2/neTofD4/Hw+PXw3mezvO0z23vbe/RVr2rl7cVn+JLXUKLUDGtNKiWCTtxhBUSVgjiu/pUWpcqivquCEW8q4h/Ere4JQRBQpAQBEEQBPFTREQST0kkSxLJstayjsNah3UccryxFutgLdZSYS1JSBAJSWQtWctay1oRl1YbRWbkOGQdshZryVqsxQprSUKCkBDv4rugQYkQtxDRVEoTWi9Bg5JIq0hCq0iirQSlIqnWLZFW/buq1CWqqGkkaExidaypzpgZx4y9t/NtezvfrOOwjiUJiSTq0hrVqZmaGXvG7O08t/M8nefpfGznue099h6zx0y19VTvytvbcomneBcvdStaWnZdomUaR2tPrMQKQUJCfKnSqqdq0aLU/5cgbkESQUSQECQEQRDv6g/xU4QEkSxZkbVkHdZxWMebHIccB+tgLc0iYS0SRBJCEkmstay1ZEVcWm20ZG1rHbKWrCVZrCVZZJFFQiIJCQmJl8SHKiKppyAhbhFNqXfxknpKaULrJZFSlUSLVEqFVEr9b1oSWpeqSKupNlraWmVaM2PPOPe21mGtkJD4ULTV1rQ6NTP2jL23vbd9bud52nubPfaMmZqWUpfWh7e/juUp4iV+KIq2ppEW0TKNY2IlVliJFRLiQ32oS6tudak/RBEtQtyChCC+BAlBQpB4CSKC+FBB1KfWH+pLIiJZkmWtZa3DOg7reOM4ZB0cS7PIImEFIREkJEtWrLUkQWlpZFXWwTplLdZiLRKySEjIIouEBPGS+K/Erb4kKPUupJQkqlIaItoS0mhKiah6SaRVPxVBi3hXGuLWugU1UzWKac3Umlp7ZG1JiEvUrWirqmVmtDVTs7c9Y+9t7232mBkzNaVT9ae3/zsO4oegLkEpRs2wOlhqTGOvOBYrsUISQRIJ8a6+lPpT/BSXIi5FvMRLkJC4xFOQEBGXRBC3+E1Rt1aLlnqpbxIRyZK1ZB3WOqzjkOON45C1dC2yWCGLRNySEFYia0ncWp0xa0kiWWSRRUIWCQkJCQlZkpCQCJIQfy8k8RQ0pSGlXoq6VVC3kFKfgroltAjqpf5e3VLqEpdSlxCKtCqiMrQjZVqZyopkEZcQL0VbdSnTaqutTs2MPWNmzIyZMVOdmlZd6qW+vP31tggRf6eqmNakMks7pnGsOFasxFqRRELiJd7VrRR1abVV/6Ru8buIBCFuQULcgiCIW9ziUtSlKPWpvinqEoREsiTLWss6Dus45O2Q403WwVqsRUJCQiJuCUkkkaC0o1hryVqSJYkkJAgJWQgJCQkJCQmJW9wiqiKpiKf4e/U3QutdULegBI2qf1KXutQPcQn1qanUJeqpUqSSSMmEVZmQ8aFudSlVLVVttbQ1U+2YqZnRqWm11VbrpfXD2//9dfg3RdUMew27iil71VqxVqywwkpExO+qStGqd3Up4t8EQXyJp4gI4ha3hCgqnoq6FaW0LqWlpbTV1u+SSGKtZa3DsQ7reLOONzne5Dg4FlmsRSKJH0JE4l11YpAsySIhQRASFS8JgkhCIokkJCR+CPEU4ha3BkVQT0VRtwrqqW51K+pdKVovLXVr6++0RD3VJZFST/UhLkVIhmAiifpSt6KturSKtlqq2upUW21Nq1NFi/pUX94uPsR3VbdpzapM1BisqbWWlVqJJJJ4SvxQtChVRYu61K2IPxXxuwgi3sVLQpAQBImXIJ7qS1HqVpdSFC1FiSCSSGKtZR3LcRzWccjbIcebHIssWYuExE9FJC7Vqa6hSxLiXTxV1K3iqUhCiCBukUQS4u/FD0VRtBRFvSv1rtSt3pWivhRVrZe61KeqeIp6F9KqDxG3qpci9ZL4ULeWKqWqaF2qpa2ntlqqWrTaqkupb+pST29vb4ffBfVUT9OaKRmDXdaqtWqtSCKJp8QP9VRF0dIWVb8r4t8EcYtLSAiCiIT4EsSX1K1udatLqU9FPRUVBEkksbKstRzHYR2HHIccB2tJFiskbqUu9ak1a3SiISFuVXVpKS1F3eopBEFC/KOEIOJW3xVF0XppXeqp9amlLqVo66mlaGmpp2q9VKmXeqqnuFV8iGpQl7iVeql6qltbT0VbdWkVrUu1LtV6qUurLqW+qZf68na8vfkQH+pDW2nJWFhlLdaqpGQkESRBfKhLab209aF1qfpdEd8FCXEJQlxCEASJH4LESxDELZ5KvSvqU0tL0VLUp4iEJFZiZVlrWceSY5FDVlhLUB9K61YdIgZNBClpaWm11VZbbbXU7+IpQkJc4kO8S3yJqqe6FS11KfWu1LtStPXUUrQu1dJW0dZTXVr19+pSl4pbE+pd/a7elaIurbq1VZdW3dp6ar1UvZT6ptR38fR2vL35EB/qVm1lSmLEKllkjaxIQkKC+KEURVtPbbVe6n8UgriEIL4EURFBEMQl9UPrVpS6Fa2XoqW+1K0uESSRxMqysiRLVmQt1vKlWrdWPZVWkI5MtaOtTs2MzpgZM6NTbWlp3eIWQjzFhwghiHdBEdqgWoqipZ5KvdSlVZdSl1LVUrQoRUvRulRdWk/1p7hV3Co+xHf1pZ6q9VKXVl1K3dp6ar1UvZT677wdb2/+VLdqy4zZsURKhqxFKlmSIfFUVBRFWy0tLfVUVeofFPG7+BJfgsRLQhAl8SGIW9zilrrVl/qmtLS01KW0PiQkJJEVay1Zi4QEpRRtvbSe2tJhqh1mdG/dW/c2e5u9dcbM1hlttbRFfQmJD4kvQYioS0qDailaWorWp9alnlqXaqlLKdpqqVKqWqqUqqfW36pblKBU3OolLvHSqi/1rlW3qqfWS/2mXoL6JqQ+1e0tb395ivpSL612NMuypWSVVbLIaKKCqCCKlraKqqKqrRb1pYjfFBG3uAVxCxISgngXhCCIdyHqKX4KgiCIoqJS1Lui1K2oLyG+xJe6tKLaoWWGDlNmmK17dEb3NnvMHrPHzNYZM9Wptl7qP0qI+BBUUN8VRVGXUk+l1KVVtC7VUqVUtVQpVa2X1ks9lfpTqEi9K0Lc6lLf1btSX1r/ol6CeolbvQvqJW5veXtzq3jXotoyC5vSRVMymmiiomFQDFqKoqWlrZaWot7Vvwtxi0sQEsRPIQiCIAiCqCBBCIK4xU9xqZcoLSUtKi2K0lK0FC0tQakyQ6tTbZlhhikzOqN7dLbZY2Z0ts7obDPVqXa01ZZWPdXvEpdIiEtIXIJSLw0tRdFWS1t1qZe6tOpSqlqXaqlLKVovLXVp1btW/YO6VEXiXalL/JN6qg/194J6iqiX0PoU38QPb3l7o95VPJWWVjOeWqSaZSxjqRgxjcFgyrSmNaWttlpa6lIvVbdQxL9LRMQtCIKEIG7xTQjiFsQtLiEhIQiCIIgKgqintLS0tNSlFC0trdallLY6ox1mdEY7OqMd7WhHp3S0o1PtaMuMtrSoqKeop4SEIHGJxC2RELcKKY0PVcqgKFqXar20XqqUqtZLW09t1aVVl1bd2vqufooP1bqEeFe3+FP9UJf6ENQtQV2i6inxpf7RW443X0pdSocpQukwq5qliSZGDAZTpkyZMmWmpkyZ1rS0qlrUuyIU8SmKEJL4LohLEF9CFBEkxJd4qiAIgiBISEi8JMSHemlRLy0thpaONjR0ZIKo6ozOaIcZndEOHZ3RPTqjMzrDjM7ojM5oS+ulXoKIiCSSSCJihSaChCR+KFLqXVQRbRVF66Wtp7aeWi+tS9WlVZdSl1K31g/1p/oST6Uhvqn/JEGpdyH1JRRpUD/EP3rL218odamXjnaRQbTVVc0yibGMGDFiypRdprXLnprWTM1US0tL61I/FfF34hYkJG4hCIIgLiEu8SkIEoIgQUhISAiCICFICIKoeNeiKC0tLS0dutRTaenQYUZndEY7OqMz2tEZOjqjUzra0tJqS4v6LiFYSFghieWSSEhc4lYVKUkJLUVRtBR1adWl1KVUKVVPrZfWpZ7qu/r/VsT/JqS+JCj1EjQu8VMpQf30lrc36lKUVruko6KlPTQ1YiyT2GKXKbuxywx7mKkpu+zWtKZVVf+miO/iFpd4FwlBfEm8xCUEUVFC4iUu8RIEQURCQhJBQpAQHyotSktHZ7SjHZmoWxJCW53RGe1oRzvM6AwzOqNTndGOdsxUZ7TVDh1taWlRUUFcQpBEEkkkJCEE9RRRCRq3ItoqipbWS0uVulTrpfWuWp/qNwmtD/E/iP9JPIWU+ik+pf5GiJf46S3Hm5dWlVZaM1sbLZ2aLJNlxG5M2WKXXXbZrd3arT01U9OaMq2Wttpq/c+CIL4JCYmXuMVPUU9BQhAkJJFEwkpEBCsECVFJRUVROnR0ho7O6Iz6UBJEVWe0ozM6Q0dbbU1HZ7RjWjM1M9rRqZkxUzPVGdNqq6222nopQbCCFU8rIV6CujUkSBFNCUpR1KXUpdSl1KX1VJf6VH8KGtR/L/5V/LsIqS+hLvUS/5O3HG+qlCgdnXpq6dRkGTGNLTbOxh7O4Zzawzl1Tp1Te2pP7WGmWqbVUv9ZfElI3EJCEkkEcYtLiFtURBAEiUsECREJCQnBCgkRCUFCEJeWDh2d0Rmzt6xTw/SQVrsk8VSXGe3oVDs6ox2d0T1mxuwxe5sZs8feY882M2bGzJgZndEZndGWVltRTwkrIZGQxFNCMSVISCoiqQiCIqinuhWtl9Yf6t9FSP134j+KS8RT/S6e4qX1Epd4iqf6Q/2ttxyHoC2tdqmt6DCpEVtscZY9nOWcOqfOqXPXObV37V3n1J6aGdOaVkv9D0LiU0LcgniKpwQhLiHeBfESBAkJQcJCkJCQsEJCEglBPBWl1anO6GydZfZC5KjMkrU08dJqqx2d0tEZbc2MfZ72edrnae9tn6e9t723vcfe297bzDYzZm8zW2d0Rju0noIkVkIiIYnEJaoSlCKNhCSSSpDQ+pRo60P91PpbiUtQL3WJL/Wn+EN8E7+LpxCf4kMpEvFd3eJT3eJS8dNbjjdFWu0w9VKamsRYduNs7MbZ2FNnOcs5nFPn1Dl1Tu0Ze2oP05rSVlutfxW3uAUJEUS8CwlJBHGLS0gIggTxEgQJQUJCREJCQkKQkJAQxFMxdJjRPZqtLl1kaSKJp6IztNrRqXZ0xp6xz22fD/tx2o/TfpzO82Gfp32e9rntvZ1723vbM/YeM2NmdIYOrYTlErJCWAmJW0yLaMbKstZYjSSSSEh8aiuokFIE9ZKgvgnqS7yknuJD/HfiU3yKp/gU4ruKELd6iSJ+qp/id285DkFbJmpQnWrGWHZji112OVvncE6du86px9S565xxzthTe2paM7RV/1n8i5CQREIQxFMICUH8KUjcQpB4SUhISCKJhIQkEqKSitLS0tEO3Uw0aElJSDy11SkdbXXGzGjH7LHP036czvPhfDycj4fz1+l8PJzn6TxP53na5+k8T/s8zd723ma2zmiLikpYiSIhK5J4KtLQOizTMWJ1Wa010SCMW1BPpURUEdRLgvoQcasvEb+rL/GfReKHCPEpPgQV7+JLvcRTEYL6pr57y3FQdFS8tJoxYsrGHnY5p87hnDqnzqlzxrnHOePctaf21G7N1LRaWupfxG8iSIgI4haRRIKQEPGSeAqCIL4kxCUECUFCRBAkrJCQIMRTRelohxmd0QzCqqokJJS2tNrRqenojD1j722f23me9uN0Pk7neTrP0+M8nY/T4zyd5+k8t723c2/nPu29zR7ToUNLWaErlCSyInGJp0GmqlY5MB1rlrVoRxdrGCyM70pDqkLrKeJLxVN8F/VT/CF+Ex/ikvgQl8RTfIkPQcV3IfVSPwWtW3z3ttahLSWGLjUqRkxjD7t1Tp1T565z6rHrsce565w6d50z9q49NVPTaqutqn8TP8UlQQhxCQkJ8RRBECQRJEi8BCEhnuopLiEhiSAx95dPAAAgAElEQVQhISGJhIQkkhASX1rt6IxmvHSRIiSUKlPtmKl2zIzZY+9tn6fzPD0ep/M8PR6nx+P0eJwe58Pj8fB4nB7n6XGezvO0z23v08zWPdrSinpKQliJrFgJiSKtJJpRUcuUYzGtdtExLmWGhfFdEVoST/FUt4ifooj/WojvQrxEiJeIp8QP8SHiQ91CS1xC60PjS316S+KpFnGpimlM2a3d2sOeOnedMx67zl3n1LnHuce5x951Tu2p3ZpS1KWoHxLfxIfESxDEJRERt4SEJJJICBKCuMQfgsRLEEQJQkJCgkREQkK8S0VRWlo6DA1BE8RLq1PT0amZsWfsve29nY+H89fD4/Hw+PXweDz8ejw8Hg+/HqfH4/R4PDweD4/Hw3mezvO0z23vbWZ0BhWXECSxElnLSgjFErsUU6ZjuhxHTZcaZmEYLDpeiiIo4kPd4im+xFMR38Xv6kuI30TiloinSNxCxIf4EnWLl5YEpTRBKRHUS3x6S0LIeCmKqpmaqT11zjh3nVPnrnOPc49zj3PX3mNP7amZMVOdaquldQvxz+KbuMVLkCCRhEQSCQlJJG6JpyCIvxHELQTxLgQJCUFCQkJ8VzraeIqnUJd6aqtTZnTGzJi9zR57n87H6fE4nY+Hx+Ph1+Ph8Xj49evh16+HX4+HX4/Tr8fp8Tg9HqfzPO29zd5mtnZoUQtJJKy1rBVrBVEUqZfBYNTRmoN6qiAqHeNSWlpa0mpCfYpvQjwV8RR/p14aP8QlPkQIcUkk8RIinhIv8RS3ivhSGrdqKy5F3BrUd28S6lJFMa09tafOqb3H3nXuce5x7nHuce5x7nHOOKf2jD1jt6bVUt+ElLrFU/wQn4IgSCIhCBKCICJuEUkEiVt8iW+K+lKU1EsQBEGQEAQp6lOLooooQkurU50xe8xss/f/owwOsCM3smRRmgeQ1ftfrZgA4voni6qSNK2Zd76ZvcfzbM/zuJ/HdT+u+3Ffj+u6Xfftum/Xfbvu233f7ufxPI9nP2Y/ureZ0RlaXxJWWCvWirWWtULiyyClOMuUaZ1HTWl9GrEwdKHSMUNRnxJtif8SfxdR/7ugxL+I+FPiSxKJT5H4FIlPkfgtfon4u1Kfqo2ktCTqU0t8ir87fSktSqc6NVN7xt7j2ePZ49nj2ePZ27O3Z4+9x95j77GnZqpTbVVpFQkaTcWX+L/En+JTxJdIIomIJBISkkhICBKCJOJT/Km+1U+lqq2i6r8E8S3+RVG/tcSnaEurrXbMjJkxe+w9nv14nsf9bPd9u+7Hdd/e9+193973433frvtx3bfrftz3434e+9m6t3brDK2oqIiVWGs5VqwVay0SXxZ2KQYnqqZ1HNSnkJSQqRgzS9aY0qI0qH8VfxfUl/j/K35KJD5FgkREgkR8S+KX+J+K0CLSItrSik8JSv3DqUVptdXWTM2MmbFn7Bl7jz1j723vsffYe+w99h57xsyY1pSWlvpSv0T8v9SXCCLiW3xLSAiSSEJIQiKJJCS+RcQvVUVbVVVV1Je2qqqqqv4hiG/xN0UR8aW+VLXVqZmxZ3tme/Z2P9v1PK779r4f7/v2cd3e9+193d7X7X3d3tflfd+u+3Y/t/t5zPNot8xgaEUlJKwVR2Kt5VjLWpFEE0WKMBiMOlon6lvUlxixxJguabXVVov4FG3Fp/iH+CW+lfofgvp3IT5FgkREgkQS8SkRfwoRv8SXIrQk2pLQCpqg1KeQ+ruzrc5oR2d0xsyYPWaP2dveY+9tP9veY++x99gz9ow9Y6Zmqq22qqgvEVWJ31r/q/gUJH4KCQlJRCSRRESwRMQKCUGQkPgWf1Nfqtpqa1ptVVVVVSlVRdVv8e/iH1ramta0Zsbe497b/Wz3vV3P47pv13W77sf7ur3v2/u+ve/b+35c1+N+HvfzeJ7H7C0d6YiKkiJWSFgrjhXHirWWrKgoguIsU6Z1HjWlJdgZLPFlyGJGS4eGNrSKJH6JX+q/hdRP9TdB/bcQnyIhCYn4lEgiiS+JT/El8Vt8CUWKSqMtQUOLoL7FtyJOHVqmOqMzOmNm7D32HrPH3mPP2HvsPfbUnrGnZmpa05pWVesfEpT6lvgvFeqn+JYQXyIIEoKEhCSSWCEiCYmE+JYQFFUtVW21VdWO6ZjWtKbV1qiWqqKqqL8U8Sl+q0+lrWlNx56xZzx7PHt79nbvx3Vv17O9n8f7vr3vx/t+XPfjuh/X/bifx/08nr3tGZ2hYxlLJX5KSGIlVmIl1oq1IiuIJtKqZXCgalrHQf1dJQiZCmaqq9pqSqPq30T8pdSfgmp8qz8F9U8hPkWCRBJJCBFJCBHip4hf4kuJb42qJLSq4k9B/U18OVPqS2m11amZmhkztWfMjL3HntpTM2N2zYxpdaqtFvVbfAoaDfGn+qm+FBGf4rf4S3xKJEQksRIrkURCEgkJKyQhkfib+lLV1rSmNVPTmtZ0zIyZMa3pmI5ptTWlrbaqisSf4kt9KlVtzdSe2jOePZ693c923Y/3/Xjft/d1e1+3931737f3fXvft+t+XM/j3o/n2Z5nm711xupoqr5UEsEKK7HCWrFWHCuyFqIhjaopR2nHcSxnaVF/GizfBkuMKS0tQhvU/y2kfqpPEVQJ6h/qW4T4FEISSUgkJEEkSMSXEOLvQougEpQiqP/bSVAVFS3TaqtlpmZqT83UzJipPTUzZmqmptWiVfVbUBLUX0IRnxpf6i/xKUQkIQQRCQlBwgpJJCQREREkRCSIfyjamtZ07Bl7xp4xHdPaM2Zqt6ZjOqZjWgstVUURf6ma1rT2jL2359nuZ7ufx3U/3vftfV3e1+Xjuny8Lx/vy8f78vG+fLwv7+tyXZfrftzPY/Y2ezODkSCIn1ZIYiXWipU4EmtFEkk0kVJjuhxlcJQ5mBbLXwbLlxhj0dFGW20lVPyr1l+CEtS/qm/xS3xJkEhCIglBIomfEt8i8Q/xl/o/FPFfTgldooiKiilTpswwZcoe9tRMTWumZmpabbWoT/UlQqol8VtLfGv8FJ9KfQoR4qcgISGJiCSSSGIlVliJlUhIIiLxKeJbVVtttdXWtKZjZsyMPWPPNjP2bDNjz9gzjqnpmNZq1aeWUL9US1szNTP2Hs/e7udx3bfrurzfl4/35ePj8vHx9vF+++Pj7Y+PDx8fbx/vt4/35X3drvv2PLeZzWzpiMpixaeISGKFhCRWYiVWlrVClgZlWZZxWAZ7sVrHsTAqavk2CBaGWaqKJtqK/0Wirb8E9aWIT0Uo4n+KnxIJEkkkIZH4FEmInyLEb/EvivinIqg/1S9nsiSDIAiioqWlZYaZaqutmZphWlVttVVVfxM0Ej+1PlXip5b4S0MQEQQJSUQkEayQxBIrkZBEEglJJLFCEglC/KVqMB0zY6Z2x56x99h77Bl7xt7bnjEzpmOmZsasSquoiE+JtoqWae3WM+PZ2/M8rvvxvm/v6/Lxvny83z7eb398vH18fPj4ePt4v328397vt/d9u+/b3lu7mbGMLFZDQ0kIIlZiJVYiK1YiiayoEJZxdNkZa8WxYrq0tBw+dbAULTKshdHS0tLQ+ldF/IuQ+hTiv8VPEYJERFYISRBJSIj/XetL/VNbXyp+SrUh9VPjl5OoaEKioj41KiqKoqKlKOpLtD4FQcSXSNAS34r4FF9aEqqIL6mfEoQkIoKEYCWSWCEhYSVWYoWVWIkVkkhIIkL8VLS01da09oyZsWfsGXvGs7e9t2fGucfeY+9xHGNa01qt+lP8KWqMGjUz9oxnj3tv9/O47sf7vr2vy8d1+eN9+Xi//fG+fLzfPt6X9/vyvi7XfXuex8zWjrSk6lOiXb6VkJCQkLASWawVSTShrCxrjdVYXdaqNbFWrEYtLTXa6ArCIMsYBEVQ/yY+JX6JvyR+i0/xKeJTQohIQiKJJASJJMSn+FLfqpS2vrTVllZbQX0q9aXqS1AV3+qXs6KWdkyjoo2iKCoqiooK4pckfgoJSSR+C+qX+tKS+Nb4LdS3JILEpyCSSEhIYiVWYiVWWImVWImEJJJYISEiiKKoac2M6dgzZsaebe9t7+3ZY+9t7+2Z7Zhtz1gzZsa0VquqRRg1Zcq0duuZce/t2tv1bNfzeN+P93X7uG7v6/Lxvny83z6uy8f77eN9eV+3677t2WZGjKVWaKINioiIiEgiIokklkgiCYkVFtJYa1kda5a1WK21lnZ0RRtdS30qzchidWmrjaKtbyHEX+JT/BTf4lMIkviS+BRJJCEkkUQSEklISPwUlKJoqWqrrbba6lRbM6M+FanWTxXUb/UpfjmbRUazSFQ0Sy211NIsErLIIouELLJIZC3JklRWLbS0tARVhCJ+aivxKb60RCURJEQkJCQkscRCEiuRkMRKrBULSaywQhIrkSB+a6utac3UTO099h57xt5j720/297bfrZ9bntva29rHWZqprIqqq22pjWtPfXMeGY8M+5nu57H+36879vHfXtfl4/r8nFd3tftfd3e1+26b9d9u5/H3hsj6sssuhYtIkhISAgSEoIkVkIiYURSa8UqK5EVayJZVkZXtEsXVb8l0mqrpa36FyGCik8hvgXxKQQJEUkISSSRRBLJkhVJSEj8lChaqlramlZb0+qMaY1hSKI+pdqgivpUn0Lrl/p2ykEiQUbWkIN1yDpkLcmSHJIla0mWrCVryYq1lpVlrWWtUQs1HRpptQgpDVrf4rciPkWQRBIJCSuxEiskkcQKSaywEmvFSiQssRYrsUJCQpAQ31ramtbM2DP2jGdvz96e/bj343wex3k6nm0d29pjHWPNmI600mK0TGt37I4949nbvbd7b9ezXc/jfT/e9+3jvn1ct4/r8nFd3u/Ldd+u63bdt2dvMyNqqSza0PoSJAQJCUISEUkkfkqQSEkiSCqJhSxWo41m6apvJSGRVFqdKtqq/xbfEp8qvkUFCUESCUkksRJZSxIrkbVkRbJkRRJE41MUU9qa1rSmY6ZmxiTM+DIdEloVVUVL/al+qn86sw6xZJFVWWMdh3Ucsg7rOK3jsY7DOg5rHdZxWOtwHMtxHNYa6xhHl/ZQXyplWhpttdS3oEXQkvhWXyISIpKICIIkVliJlVhhJdaKlViJFZJYYSVWYiVWWImIxJ+qrbb2jD1j7+3Z27O3+9nOZ7ufbT2PdZ7W3tbesrccwwwzJFja2lN7xrPHvce9x7W363lc+/G+H+/79r5v7+v2vi7v+/a+bu/7dt2367ndz2Pvra0oi9X4S/0W4ktE/BS/JQRFQor4FFESEQlZsVDUslRnyCLF6IppRVT9T/EpREUECUESKySsxFqRLGvFyrJWZC1rLWstWctaS9aSRBNF0TKt3ZqpPWPPmD32jL2H+KmtNAhKaRmf6rf6VP9wZp1i5CBDjpFj5NjWsa1jW8dpHds6Tse5HcfjOE/Hsx3HOM5xdrTVUiRjhrTaammjrZb6pYifgsaXhIiEICEhiYUkElZiJVbiSKzEsSJhiRWOFceKlQhWYi2SSEL81FYxrT2193ie7Xm263ms+5HjkONhHZqlWZplxDSOFsuUmXE/49qP93689+P9PN7P9vE83vvxfh4f9/Z+Hu/n8b4f7+dxPY/redzP9jzbzKCSWhOCxpcgSCKCiG9B/LegvgXxKSQkERURBCvVsBJNJURoJUERivgpSAiChBUSllgrVliJtZa1Yq3lWMs6lrWWtQ7rWNY6rLWsY8lakqUoBtPaU3tq77Fne/bYa8seyeahZaaSSuJLUbQ+laJV/+3McUpGxBrWMY5jHMc4zu04tuN8Oc/tfL0cz3a+Xs5nnK/t3GPPaKv1LcyOSUxrZrTV1oy/pNKov6svSSQkJJFEEglJrLASCSuxVqzEsWIlVkjiCMeKI7ESCSux1nKsZa1YCQmhaJnWnvHMuPe2nm0dj9wH69YstYxli7NxTB37lCzT2lPP3q778XHf/rhvf9yPP57bx/344358PI/38/h4Hu9nu57t3o97b/fenr3tGTMjai0an+JLkERCECR+ir8EQXyK/1OQkJCQkEYQrETDwoSFIj7FT0FCQrASCSussBJrcSTWimMtx7Eca1nH4TiWYx3WcVjH4TiWtQ7rOGQtWVExZVq7taeevT17PHtZz/asSLYvbU1rrTETf9dSn4r6rfUP5zpeZCzLGo6zjl3HWcc5jlede5zPeO3xesazx7PHnrGnplX1U5DY2TKRGUnMjLaotlpa6kv9Jb4EK5FEwgrBSiQkscJKrLDCWrESx4qElTgSx4pjxUoER+Jcy3EsK5EVKxHxpWpae+rZ49hjPVuOLevRdWiWLR485RyOPY5jk6XYU/ezXffj47r8cd3+uC5/XLc/7tvHc/u4Hx/P7f08rv249uPa2723Z49nxp7RVlQa6lPFp/gpQhDiUxD/roh/Fd+CIEgiYQWLTqwwWCvaalDfQpCwkLDCCiscK1Y4VhwrjrUcx3Icy3kcjuNwHIfjPBzH6TgO6zgcx2EdhxyHJAZTdtkznj2evd3Ptp4lWZJQ2uoss8ZOEOJTFG21pT6V+oeqL+fxeskM61DLiD3xGp6pZ+qZenY9M167nhl7as/YM9qiIoiIJPbekkhGMK0YUzqMvwQtUl8iEhKSiEgiWIkVkkhYiZVYYa1YiRVW4lhxrDjXshIJK3Ecy7GWlVgrspashaiY1m7tGffe8mzWQ5bJssWrPOUZjl3H+TiOk8SUPfXscT2Pj/flj4/LH++3P67LH9fl4335uC/v+3Hdj/f9uJ7H/Wz33p7Z9ow9g1pB/SkSggQhiL+p36qKloS26lP9qeJbfImEhKWEJqJWQvw0ikhpiPqSELHCCiuscCyOFceKY8V5xHEs53E4j8N5Hs7zcByn8zwd5+k4T8dxWOfpOA5Zh6xlym7t1t517+1+trUeaz2SJWiZ1kztGStLskX8VIrWp1J/U+q38zh/SMvaahmxG2d5DXvYw57aU3uYqZmaqbZ+S0gkCAmzYyciMmN8ao1aHZ2q+FYaQhBEJCQkJCQkkbASCSuxEkc4VqywEseKcy3HimMtCUfiPA7rWBJWYq0la7GiqJjWM5U9rK3PY7JscZZ717nrfMZxbsdxWMchWQZ7xrPHdW8f1+WP9+WPj7c/Pt7+eL/9cV0+rtv7urzv2/U87me7n8ezt73HzGiLIoQgSEgiIogg/qe2vhWlJfGlSutL67cgCOJLJJVGVBDEl/pWX4JgpVZYYSWOxbHiXHEecax4nct5HM7z8DoP53k6z9PrdTrPl+M8nefpOF/WeTqOwzoO1jJlTz1Tz4zz2Y77sdaStXD70jKtmbH2slYk8UvR0tZv9an+p/N4/cfqyBpymCxjmcY0dmOXXXbZZbdGDUbVnxJBfIkkdjab+BTfZljMLDK+FUF9SSKJhCAhCIJgIWElVjgSK3GsWIkjcaw4j+Vcy3FEEitxnodjHYSItWKtJWuRZTCN3cquZtS2PZ5yTB3POPY4nu04Hus4HMdBYsq0nj2uZ/u4Lh/v28f77Y+Pyx8fbx/vy8d1ed+363nc9+N+HnuPPWNmTEdb8SkVISQRESQkCOK3oupLWy0tUi31qdXSFqVVRWlRX6LSov4uqC8V36KCiGDhSB2Jc3EuzhWvc3kdh9d5OF+H13l6vU6v18vr9XK+Xs7zdL5ejvPlOE/H+bKOQ9ayyzP1zHiecT2PtQ5ZB1m+FDO1Z+x1ONaWLEkk8a2q6lP9qf6hfjrPH//RjuxhHboOzTJiLCOKEVOmFC0tbX2JkPi7hIhgiy/xpxlCV7TVBkV8iU8hiSQIQSIhIYmFFVZihWPFShwrjrWcazmPOI/DcSwrcazlOA/HWiS+JMtasbJkhSwjFFOzx7YdYk2tZ6xjW892HKd1HNY6rOOQxGBP7RnXvb3v2/u6fVyXj/fl47p8XJf3dbvux/U87v149rZnmxnT0VZbCRFCREJCQnyJIP6ulKovbVVpVBVTqpS2WrS0fipav6Q+FRXVVlr1pYIgiFpYiRWOcCbOFa8jXsfyOpcfr+XH6/B6nX68Xl6vl9ePl9fr5fzxw/l6Oc+X4/VynC/rOGQdduvZdc+4n3Hcj6xb1vKlpWWm9mzPc1jrsNZjJSR+Kkpbv9W/Os8fP3Qqx8g6WIdaammWESNGTKkoWor6Jf6uPsXfPH5p/WnMxJdgfKn4FgQJCUEQBAkJCSusFStxrDjWcqzlOJbzWF7n4TyWrOVYy3ke1jpI/JRIgpCwookpbWWPlFWyh2xZh3Vsaz1yLGstxzpIDGbqmfHs8b5v1/X4uC7v6/ZxXd7X7bpv13177sfzbHuPPWOm2mr9JbGwwhJJJCEk/ktRtLQUrU9VUbTVVlttUV/qU+svRVEpQeu3tL5EJQQLK7FwhGPFsThXvFa8jvhxLj/Ow4/z8ON1+PHj8OPH6cePl9frh9ePH84fP5yvl/P1w3G+rPOUtezh3uPe497jOG7JEtHSMq29x36259yOZznWkiwRSXxpUYr4N6Wc5+s/2sresg7WQRZZmqWiiYqKJoqK+ksSiW8tJYhf6qcWRRAsnVEs1F8SEoIgiYQgIUhYSFiJteJYcaw4jziP5TwP53l4HYd1LMc6HOfhOA4V9SUk/q6JCkNTOjIlS0XysJasJVnWWtZaJIrdmql7b/e9Xc/tfT2u+/a+bu/rcl23+3nc+7H3tmebGe1oi/qSECSRREJCEPFT4pcWpa2WttpqqygGbU1rWi1ttaVVX+pLSvxdUVFVVHwpJUgiaoUljnCEc8V5xGvF64gfR/znXH6ch/+cpx+v04/X6cd/Xl4/Xl4/fjh//HC+fjheL8f5krXs4Z66n3E921qHZJGoaJmp2dvzbOfzONZhrWWtWAmC+FLf6lP9qf7uPF4/tJVjZG/WQQ7N0ixNNEtFRQUh/hT1JX4q9S3x3+pbUWTMWtKaqb9LIiEhIYhPIQgWklhY4UisFcdajrWcx3Ieh9d5eJ2ndRyOYzmP0zoOFUVF0db4VIqWabXVUlHb+NSQkJBYa1lrIUa17Nbe2/1s17Pd9+O6b9f9uO7bdT/u57Gfbe9tZnSqLfVTQsQKCQlJRCQkxF+KqqqirWmlNa0vxZRpdaqttlraqk+tttSn0oqilKCttL5VsLBC1BILRzjCmTgXZ+I84rXidSyvY/nPufzndfjxOv3nx8uPHy8//vPD68cPrx8/nD/+43i9HOdLjtOUa4/7GeezreOQLBVTZmrv8ezt9Wz3fTqPx7GWlSWJBPFTW8Rf6n86z9cPVTNj7ZF1yDpYi3WwFlkkZJGQkCB+CkkkfiqCJL7Et/ilqupLGYok/i6ISCLxWxAkJARJrLAWR+I44jyW8zic5/I6T6/X6TgOx3E4zlPW4cuIYsq0DNNqa7emNa09NWWmpjWt+hISEWuFRMuoKXuPZ2/33u7ncT/bfT/u+3Hft+d5PHvbM2ZGW1pUfFsh+f8ogxcsR7LlSJCidh3B/S+XFe6mA0RW1od8PadbJCYxiYSEJH4kPupvLduKSklJ66PYsq2nta1tbaulrapf6p+CCVsmUR8VETVhEme4Jq6Ja+KauE5cE68TXzO+zvg64+s6vq7j6zr+6zr+63X5el2+Xi9fXy+v//pyfX25vr6c68uc4ynXU3/c69w3GW085dl6nvV9P1737TqX6zrOGTPHzEgiiYjfqj7iP7vO66Vlup5ZZpghQ4aEhAQhkURC/C2Iv8X/SWn9KFqs1lvs+lNFJAQRCYkfQVREUhOCSczESZwZ54zrHNd1vK7LuY5zLue6ZI6i4ikpdjVlV7fWesS99Tzrftaz9ex6ntVWUURkIiiKLbvrftbzPO7n8f087vvxfd/u+3bft+e57fPornb9FiSRxISEhEkkBEn8U9GySGmp2lYaStWDZ2vLtnarrbbaamlLUT+CSSxmaFFvEUxqwiSuiWvideJ14nXG1xlf1/g6x+s6Xuf4OsfXOV7n+LqOr+v4uo7/el2+XpfX6/J6vbxeL9fr5bxe5rpsY56VszLHime5n3Xfj+/vx+t1u74v13Wcc5w5ZsYkkoj4rd7qR+Pf6sd1XS9Fd2VWZmRGMswwkQyJZCSRhEQSQhIzkUQS/xQEQRKK+tEW9dFdEkJVRLyFhIT4Jd5SxEcQTGLCSZyJc+I64zrjOsd1Hdd1metyrsvMUfEg5V52l2cR7drUU+6t76fue93P4/t+PM/j2WqrSpmJj/qlZbueredZzz7uZz3P434e9/14nsfzPHbXttrSircQJCQxiYggCYm/xF+KlmJLipLWx4ptbdmtZ9myrS0tWh/1UfGW0JpQ8dFE1GASkzjDNXHNeJ14nfi6xtc1vs7xusbXOb6u43UdX9fxdR2vc3xdl6/r8nVdvq7L67q8rsvrdbleL9fXy5yXFfOsmZU8Fs9T9/P44368XrfX9+U6l+scZ44548zIjMlIIgnio4j/IH5c57p87K7smhkzIxmZMYnJSGISSWRiEpOISCKJJBK0giDxp/poi6rS+m3jT6v1I4hIiLcQfwuCIKmEIGEmzowz4zrHdR2v63Jel3Mu57rkXCpSnlaXfR5paHRZ6yn31vezvp/HH9+37/t234/7eexWW1qJt/itqq1t7a5na5/17OPZ9TyP51m7j91Hd2lRVJDEJCYkTEgiIt4SEkQTFUWxJdiipBRVT3laT9lWVUtV1UdbSn2U+hEfJaQkMThhJk7iTFwnrjNeJ64ZrzNeZ3yd43WO1zle53id4+u6fF2Xr+vydV2+rsvX6/L1enm9Xl6vL9fXl+v1Za6XFbOVs8xtxfPU972+Xo8/Xrfr+va6Ltd1OddxzjHnmBmZSEYSCRFVEv8Uf7vOOT5mxu7aXUkkMRMzkRmZmIlkzMTMmImZyMQkJpHEPwVB/FY/ivpLvLUqrB9B4i2EeAtCfBQVBFEJk5jETJwT54xzxrmO67qcc0nQHF4AACAASURBVDnXJeeyQtHarRHpQ2nWikfc5Xvrj3v99/3444/b9/ftfm7Ps9rSouIjxI+2ttXWbm3X7tqt3bW7dtdutVX1kXiLCROSmEQSSSRIBPG3oqIotv6S0tCyZcu2tmzZ0tKi1aL10XqrH60g3sJgwpmYxDVxJa4Zrxmvia8zXuf4OsfrHF/X8XWOr+vydV1e5/J1XV7X5XVdXtfL63p5vV5er5fX6+V6vVyvL+f1siJPyarxLN/3er0er9ftdd2u6+Vc3865XOdyznFmnBkzIxNJJJFE/BJv8Rb/dJ1zaFVNYhNJzMRMTMYkJjGJJGZiEpNIIpjEJBKCIIkkkvgRvxT1Lw9aP1a1FZVEQhLirSL+rT6ChISZOBMz45xxneM6x3Ud51zmuuQcMZRuTSp9ZOlUZzTxlLv1/aw/nscf9+O/v29/fH/7/r49z6O72oo/xT+UUtVWW7vV1nZp7Va7tOK3SGoSk5jEJGZiQhJJJCEhQRBFRUVFG1uSaFksnrJYbCnaaktpi1K/lHhLREUEEyZxTZzENXGd8XXG1xmvK76u4+uMr+vydR2vc7zO5TXHNcd1jjPHmePMMTMmYzImYxIxkpGMyZiuGWbGzDEzZsbMmBlnxsyYGTPjzDFzzBwzY2bMjJmRrPgl3uJ/uc4ZStFZs2N2PTsmYzIykRkzkRkzY2bMjCSSSGISScRb6yOIX+KX+Kf6rS2K1aIkBEEQH/VLUB9RQjBhEpM4EzNjzjjXcc5xrmOuI+cS0WVSY2UwJaMZK1Y8y731/aw/7scf9+O//7h9f3+7n0d3tUsR4pfE31r11mqLar1VW1oUJQQRk5iJCTMxiSSSSEJCgpCQICoqisWIlorF09qyZcu22qpfqn6UeKsf8UvEhIgJ18RJXBPXjNeMa8Y14zXjmnHNcWacjJPjZMyMyRhjMiLSSCNCUdpQ/xAxkkrGJCZjMiZjMmbGmXHmOOeYOc4Z54wzx5lxzpgZM2ERf4mP+O26zuWjqh3d2l3TtTPmjLnHzJhEMiYxiUl8BINJ/Gi1fgTxP5TWn+pv9RHsFish3uIt/q0I6rf4JSETM+Occc5xzjjXca4j55JzEBOSirCY0YyKFU95yr31/dT3vf64H/99376/b/fz2H10V/wSJMRbiKD+VupP9Ut9BPGWSJjEJGZiwiQykURCEklIEBUSEsWKESuIYss2Fk9rS7FFUVq01FvFv8VbI6kIJSGIikoJUtJISSMiQkYMhgwGgyAIBoMgNHQkkZCMSU3GzDgzzhznjDPHOcc5xznHOcc5xznHOeOc48xxnfE8h6wfRfyIv13nHB9VbXVqduyunTXPmIyZmMTMmIlJJPGRRBISP1ptUfERv5RW660+2vpRtFq/5NEdUVFB4j+o36I+EhImMRMzY2bMHGeOOcecwzmICZPSyJQZMppYsXhad+ve9f08/rgf3/fjj/tx37fdR3f9UhETEpJICOKXeAvxS5AgRARRSczETJzEzJiJSSQkkQSRhIQEQTRDYkUEUTxY9ZRtbKulpUXR0tJqifpICTYMmmiiiYqKGk2Z0lLUW0QkIzmSkRyZIzmSkQw5koPBkBFDDhkyZCQkZGrmmDlmjplx5jjnOOdyruOc47qO67pc1+W6jusc13Wc+7jOylK/1S/xEVyZ+EijqbaqkkgjiSSSSCIJIokkkgiCIH6p/6nqrf5ULW19tNVWW1SwHqkf8T/VjwZF/YgfSSSRjMyYM+aMOcecI2eYEZEQlSEzZEjUqFg8ZbeerXvX/Ty+78f3/bjv2+7qLuojmETCJGYiSAiSiF+SEOItDJKImHASk5gZk5hEEpNIQiIJCQmJJgiCIUG0sdjW09jWlkVLi5ZWW7a00iqiWiYoTbQIBkVDUZQIiSSSkRmTY2ZMjsyRHMkhR3Ikh4zkSEYMGQRBxJCKMSozTsaZ45zjnOM6x3WO61yu6/K6Lq/reF3H67rc1+1+jtd17K48UVVvLfEj4uOK+BEUIUNLOiIiEhIkkpgQ/5BIEG/VltZH/KloFW213uqjrbba+rjdKLvirZX4UdWGeiv1L0l8JJGJmZEZmWPOMXNkjs6IMSVdGWQkwwwJoWjZ1rNrt55dz65nH/ezuqtd6q0SmphghhKMt0QUISRMiEiYEJEwYRJn4kyciZmYRBJJJJEEIYNgNEEQREWxWLGtLVu2tLSlaFm0tNqKt1ZQRFBCfYT6SxJJRIyRjMmYHJkjuWQuyZEcyUiOZCQRg2AQGhpttARpJJHEyZgZZ8Y1x3WO6xzXdbyu43VdXtfldb28Xi+v69v9ujzP47keuyuJtqrUW0n8diV+FBFBBSU1qYQkJJIIIpKQCIL4CKVF/aWlpaqttlraaqu72mqrqiql3rp+qR9FKIqqttqiPpJIIokkZsZMZEZmZIaMiI9kSElIfDRUtFS1tLWtbrW1rbbaauu3oKrit8RbJCSRxIRJJEwimETCYIaTOBMzMRMzMYkkkkhCRjIICQmiCYkaRLHlaW3ZxqotSr211Fu1pKXe6kf9qKqoPxUJIomICBlJJCM5kpGMzEhGcsyM5EgGg0EQShsVP4qiQQWTmMSZcc64znGd47our+vyui6v6/J6Xb5el6/X5ft1eZ7LPo/neXRX8mirrSpF/OXyp3iLt/hIaKOpimQlPIJIIvEj3hIf8dZqS4v6UW+l1VJvrbba2q1tdastrbtV1fW24qM+qn7U/1lIIgkJGUlkQkKC+Gjqt6KipaWlrW211V1ttaVFUX8rIv4WRCQkkcSEJJKYMImESQQTzsRJnIkzcWZMxkzMxGQkkYSEhAwJGUQFQRSLYrFqS0tLi6IoWi1pUS3jI4p6i7f4WxBEjIhkJCMZyTE5JkdyJCOOZMSIQRAahKIoitISERExGWfGmeOc47our+vyui6v1+Xrdfl+Xb6/Lv/1/XJ/vezz2GftrnbNHdvaXW39TxfxPyVFJLTRqTYkJBISkpAgPoIkPuo/qZa22urWttrarra61ZZWW6uqupES9aMURVsU9b8EiSSSkCCSaNCgCIL4qF+qqlraaqutttpqS/1Dxd+ChCQSkkhiEpmYMIkJk0gYMWESZziJmTgZM3EmkkhGEkkkkUQSEjIkmhFDomJRtWXLlpYtSouiZUvLVltB1IppNVG0CBVEEJGERDKSkYzMmBmZkYyZMRnJiEEQMTQIDUJpaWmJXyKSmMTMuM54Xcfruryuy9fr8n2/3F+3+/vlfr3cX7f7/rLPapcuXd8znl27q62qv5TLn+JP8Rb/lERbKRERSSQR8ZGQxG/11vqXVktbbbXVrm7trm7tru1qV1tPa1v11qWh9aNFfLQUbVGCREQSEhISSfwSQhvUR1FvrRalpa222mqrLS31VlrxtyBISCIhiUlMYiaSmDCJScwwImHCJM7ECWdiJs6MSSQxiSSSISEhg5CQkYQEQXy0FG21bGlLq1ta3dKypWUrKoiS+AjaaFFvQSSRjMmYjMk4c5w5Zo7JMXNMjpljZmTG5EhGRDIiiL8URdEighGTOIkz45rxOsfrOr6uy/d1ua/L/Xq5Xy/P1+25b30euuzSmtx217Nru+q3Uq74h/iH+Ej8SGhHUkkkkUQSQvxbW1q/tbTV0lZb2+qu3dp97K7neeyubnWrXdR629KQ+ijaaqtK66PeitZvEb/V31pvpdRHfRRVVVptUW21RVVRP4L6txAxYRKTyDATSczEhElMYhITJiRxwpk4iTNxzpiJyUjIRCaSSEYykjBDhowmZEgULUVbRYuitNRb0epWiy2tqPER9af4UySRxGQkYzJmxswxc8wcZ44zxznHmeOcY+aYHJMxMyYjGUnISCINDUVLS0kqCJI4iZM4M64ZrzPuM76u474uz+tyf7089+35uvV56LJLayaeZ+2up6ut36ou/1Ek/oeQ0BqVkPiXJJKI/6BFKW21q7u6a3ftrmfX7mqru9rVrmcrrVWUjaY+inorLW21VfVRRVVRWlpa1I9WldaPFqWot6La0qLaUn8J6pcgiLeQRBIJk5gwE5OYMImZOImEwSTOxJk4EyecGWfGJJKYjMmYGZnIjMyQYUYzCIkmUv8QxP9StFoUrbbS+qh/iLeICCImkRkzY2bMHOeMc45zjjnHOceZ45xj5jhzzDnOHJMxMyYjRsRfipZWW7YkqKhRg5O4Jq6J14z7HF/neK7jeV2e+7JfL/vc7Eorragz49nH86ynq6i3UnX5D+KfIvGXoEM7kviIX+Jvbf1PRUtb27Vb29pdz65nH/usfR67q7u6SxeLaksqPkppa1tVbbXVVlstLVotbbWlVfXRli4tLS31VlotbWnVW/2pqKCIPwUhIggSkkgiiUlMYoaTmMRMDJI44UycM65wJs6MMyOJJGbGzMiMmZEZmcMMGU1UyCgWUeItiIj6iPil/qGoHy3xFn8JIpJIIhmTmIyZMROTMTMm42TMjJlj5jgzZsbJmBkzIxnJSCKJiB8tpVu2OitGkJISHHES14zXjHvGc8ZzHc912etlX48+j2ylFRWcM+5nPc9ju7YU9da6/P+KxJ8i3oJEWm19JCERJPGj9b+0tNq1Xd21u/Z5PM/jeR77PPZ5PLv2eeyu7sMurXa1QVUULVXb2tLSUqXVVlttVWlpUfXW0qK0KC0tioo/tSjqI/4hfgRBQhJJTGLChJmYiUmcxAyTOImESZyJa+KaccKZOGfMjElInDPmjJmRc2SOzJBDohkSFSvSylasJIKIiN9alJQW9aMlRVC/NIiEiEkkMYlJTGIyZsYkZmJmTMZMTGIyZkZmJCMZk5FEEhE/ilZbWt3VHabqrRUMJhxxJZ6J14znHM+57PXo69J9sUsrKpjE9T2+n8fzrKdrS0NbWpf/S4k/RVBvifFvSfxHrbbaaqu79lm7a5/H8zye5/Hcj+d5PPvY59F9dB+6dD0dWraoj6qWttraru3qVltttdVWtzqlVUUpbWlR6q1+i7d6q/hTifotKIIg8WPChIRMzMQkJnEmJnEmJjGJCZM4E2finLgSM3FmXGckQcyMM0fOMXPkHJkhh4wmKio+upWsJCKSSIhfWqJa2mqrrW5pfRTxlgiCiCQiRiRjMiZjZkxiZpwZM2NmTMbMmBmTMRmTkYwkkoj4Udpqy65utdVdPxKUVtTghBOuxGvGnrHX0efo60VXWlGDwSTOjNfzuJ/H01pVsS2ty/+V+CXEj4iozhASgif+VNRfWpRWW7uP3bX7eJ7H/dzu+3bfj+e5Pfdjn8fuY59Hd9mlta2qdFUVbbW01VZb29pWW9tqV1vt0lGrokVLSysqiKIoKj7qI/EjSKol6kcIEhKSmMQkJjETMzGJmZjETJzEhJM4E9cZ18SZODPOHOeMCIk5xzlHzjHnyByZQ4aMJipWaFW1TNjUiCLe6kdLWm1ptaWl9VEhaFHqR5BEEpPIxMyYxMyYGclIIhkzYzKSkRmZkYlMyJAgPtrSaqtb3dVnNRFviY/sylZaow6uxE7sjD3DdbErLa20ggkzcZ3xfT/u53F3LSqq2rr8P4o/xVt8jLETI8SfqkW9lVZb3dpdu4991vM8nudx37fnfjzP43lu+zz2eezz6PPoLl3t0tEugvoo2trWtnZrW9varm7tVru2la4a9VZvVfVLUVS8lcRfoqh4i38JgmASSSQkTJjEJE5iJk5iJk7iTEziDGfGmXGdcSbOxJkx54iQOOcy15G5zDkyR+YwQ0ZFkUZatVqyNYmGER/rraRVpaWVVuuXeqsfCfVLiV8SPyIECQlCQkL8EsQ/BJH4UbTVVlvdtXnYsJGHRRI/unSla8oJG67Ezug5XEsvUVFBwmASZ47r3L6fx9N6ULGqrYv6JRTxVgRFUMS/BZXEx6ATDMWhLaqqrbbatbt2H8/zeJ7H89zu+3bft/u+3fftuW/PfXue2z6P7kMf3cOudnQrjaqWbbW1W9vard21W9u1u3YrW1JVRUtbWlrql/qR+BEkfsQvQbwFJSGJhGDCJCaRxCQmMRNn4iRm4iTOjBNm4ppxnXGdcSbOjDnHzJFEMuYccy5zLnOOzJE5ZMioWG/F1kGXmbUbIxoiBqs+0kppS4vS+oj4pyB+iX+qX6qtqrbaamtbW4qiqKra1rTatTsytc+SkPCs5LGJ8Tbjo13ZlVbU4EITnTDDOdIKUj+ClCRm4pxxnse99WATbbV11S9RPxoNKYIi/rd4C60kfhkZplSdHm21Zatb7dpdu4/neTzP475v9/ft/v52f9/u+9tzf3vu2/Pc9nnsc+vz6Fl2bVeVrd+KbW1rd23XtnbXbm1rd6VrdjSroqUtLYpKK95aH0H8Er8k/i1EBEkkkcQkkpjETJyJM3FmnMRMnIkrMRNn4ppxnXGdcWacGXOOOUdEZsy5zLnMdclcMiNzyJBRpCiyqmZqdkxWE+MttSolrRYtLSWtjyAIgvj/2IIXxEqOINeSB/DIq/3vtsUMB4as0q9fjxlIIIElJCEJW0hCgADxtwKlLW1pQxKa0ISkNCEpSVECWlh+W36TYAVafgiQgARa1OAWWpCIoBLYMIMooqiFFhpI+SGBZCTjlgUikZa2HFp+lB8CFRUqUKECVfwi/i8JWiTxw4jYmMIMbaGlJ5we2iX7kF32XvZe7h8v9/2D931535f7/sF9X+57ufey95J9aJZkaQYaSilFDX9roS1JSUoS0pKEJKTFCVEAU6AFWtpCCy1QoAgQRQIEAiSQhAAJJKB8ExJYYIENlpDBAltYwhKWsMRYjIUtxmYkxuKMOTOcMWMzY+yDxyAjG89hzoNm8BykARtkQBRBCykFmiIFSxgoUEAF8aOohRZa1AKlgAABAixhCVtYwja2sMVYWMIWtpCFDBJI4kcppbSlLWlJSxqSooQkEIEEiB/lLxIgJH4xBQkSSKBFLQIMHAksqAAjBhVaaEoSekJboPxNLUIs4Ja2nKYg/lKoQPxFQEH8In6I/0NAAYEQElgCm5mBlra0oXnYJzy77OfD7uXey31f3vfD+/7BfV/u/YN7L/e+ZB+yS/aSXZqFhjSUoAjEX0pb2tKGJiQhCU1oQlqcgKGIFprShja0hRYoUMRvAiS+CQGSECC+iV8kkIQkLGEJS9jCAhvGYizGYizGYmyOzViMxZnhjDkzzJjxoBk8g2Rk43nwOXgOmkEasAGDRAq0QHAhDpaRFklIYKCAWtQCRS2iFBC/CbCEJSwxFmMzNmMxNmfM2MyYGTM2Y2MbW0gCCfFbW9rSljQ0JQlK2ARW/GihlH9IgJAAgQRIqIUWtUAxRQIElcEgQAUG2tITNkNySEpaEshAU8oPsS1qOW2gfBOIbwWEgAICCohvEi1IQMsv4h9CFJAKEpKwRW08ZjL0hOwhz2H34e6Hz/vyfj58/viDP96X9/3wvi/v+8V9P+y97L1kH7pLdyGBhlIESAWJHy2U0pa2tKUNaWhCEypDCgIKbaGFFihQaBG/CZCEJSywQAJLRAKKAEtYYAlL2DASlhiJkbDF2IzF2IzFsZkRx2ZszgznmDPDmcEeNIM9yEYefA6eB82gGaQBGSSKoEBCKlxwjLQIIcBAAVEEiKIWKGoRBYoEAiwxFmMxNsfmjDkznDOcGc4ZzgxnhjnDzDAzjAePsAUSvwhKaUtTkpAEJSiLxH+Uf0iAQIBAgCV+SaBFLRQEFDEqSCBTl1SMzdgcmyszNmNjG8dIRfwmoMBJAwUkVECClkpIAoSAStAiQRHiLwXE/0MgIQnJyGVqOkMT5gxnD8952OdyPx/ez8sf7xfv58Mfnw/383LfD/te9r7kPmQv2UOy0EUNaYBiFQskIfFLC21pS1toKYUWGn4U0wANNLSFBloEiCKBBRZIwha2sIQsHFGEBEbYYizGYmxsYYEtbDESthibGXFsxuaMOTYz5szwzHDOcMZ4DvLgGSSjOXgOOgfNQR4kg0Qx5VtKEe6SCElIQgILCggwUIoAUdRSwEABAZIYi7GZMWeGc4ZzhucMzxmeMzxneJ7heYbnDM8zPGc4x8wMYzMWlhAgfhQobWhDGxIhoEAptPxDQggJKlFELExRCi1QVKDFlBYKVGCEEQaMMMICIQSIH0KUAgVaSOFkwz8EQkgCCUlIQhLmm80PAQUk8Uv5l0B8q6iEBJaojW08w8xwzmGfy7mH53n4fB7e98Mfn5f38+H944v3/XDfl70fci/ZS3fpLmRRQygNmGKBLCQjCQmQgPKPllLaIgEtUGhpCw20iCKKAFMssMRY2MI2YxMLLFojgQWWGJuxGQtL2MISlrDFWIzF2IzNGXNszpgzw5nhnOGc4czgOciDZpAHe9B58Bw0AxqQQKaIFlApS2KkIIEFBgKIIhVRRFGLCqKI8kMSAixhibE4NmfMmeE5h+ccnnN4nsPnOXyew+c5fM7hcw7PGZ5zOGc4Y8bGFpaQQBRaaGlDE5Aov7UllB8CKhEJRSiLJIwohRRRfqhAiwpqUcEFAwIEqIUC5VtpoYW2pNBCgE1py8ku/xBIAglJSEYStkjBFX+TRFt+SOK3QvlNoPJNSMIStbHNzJAZzhye53Dv4XkePs/D+3n4448P9/1w/3jZ+7L3Ze9D9kOzNIsaLiWCLqhlVMbCY2wjG0kI8Q8J8bfyS/lW1CJAgAALbLDF2MyIsTg2Z0zGtIYWWiQQMBZjMSPGYixGYizGYixGYizG4ow4NmfMmeHMcM5wznDmcM7gOciD5iAbzcFz0ByYQTLFINFCCyRERgoSCCFAAgECBAhQQRQoAsS/LLDFWIzNmeGMeY55xjxn+Jzhc4bPOXzO4XMOn+fwOcNzDmeGc8zYWGYsbDAgQBRRaKGhFS1QaKGBIirRhCY0gRgcqGkLLbSIH4UWWtSiAi20KIUUWtrSlKY0JSlJ2ZTbsoWb0Jazu0ABgUASkpCMXCRBjRElYAEGCggJWkBA+b8EkpCEJGwxNhkzZzh7eM7heR6ez8Pn/fC+X7yfD/d92fdl7yV76S7NQoIoVllBR6jFlBGcYzzDeLCNbGxjG0tIwhZIGFEVCSRhgQ22sMVYnDEz5szwnOE+h91LM0CxRBMkEGCLYzE2Z8xYjMVYjMXYjMUZc2yOhzPmzHDGnDOcM5xzOOdw5uAZmINnkAfNQXPQHJBBpogfBRIQoBZJSEICAQJEEaAWKFCgCBBFlB8SSMISYzEWY3FmeGZ4zvA5w3OGzzl8nuHzDJ8zfM7wnOE5wxlzZrCEJSwYCQtEUQsttNBCQhEiFChQRCWaQAIJbWhNE8S3BspfCi000EKBFlLa0JSkdEMSkrIJm3A37IZbeCk3JQln9/I3SSAhCauoQjIYEL8YgwISqFCBQPyrBVp+E6hIwhKVqY1nmBlmhnMOz3P4PA/38/C+H+4fL3tf9r7sXrKX7kKDKFZ5BWvTHWgwxSrH5nkOcw5zhpnBM9jGY2xjG2SKCMUFO7hmXI7LGXNmeGb4PId7D3sPu0vzIIol7oqmSMWAJcZibMZiLMbi2Jwxz5jnDM+YM8MzwxlzZjhnOHM453DOcM7hnIPmwBw8gzxoDsxBHpCpBBXhW0EEVQghCQGiSCCKKKKIohZRBIjyQ3wTCLDAAkuMzRlzRpwxzwzPMZ8zPMc8MzwzfM7wnOE5wzPmzDAWlpHAEgYEiB+FFhoaUQkaGvGjQBG1aENb2tKUpmBoCy3iR/mlhZS2tNCEJGRLErJhN+yG3WVvuHe5d3k3vIW35SZswtldaEFCEj9kUwXV2AUKAiFCkY0QqqhA/E1A+VH+Vv4hIQlZjE3GnDPsOZxzeJ6H53n4fB7u++G+L3tfspfuhSyiSGUEY7FjsgMNajHljHjO4Xkeznk453BmmHOYOXgGz4BMgVEJMECAKUzLyfCcsDnchM8edh+SAEUCW5wd2iBAgAVjMRJjYcFYnDHH5jnDc4ZnhjPDc8yZ4cxwZjjncM5hzuGcwzkHzQEPmkEeNAd8wKaYAkU4JRRJIEB8K1Ao0ELLbwUKFChQoIjyW5GEAEtYYizG4ticMWfEsTljnhmeMc8xZ8wz5hlzxpwxtjBCgCQksECA+NZCCgqNEFAbEgpUohFNaEITSKChET/U0hYE4lsKLU1pS1OakCzZZXfZXXaX94Z7l3uX9y7vhjflq+XdkISz9/I3SSDhhNq4pS1t+SFAGPNNohJCgAABBQQUCqX8QyCBBJKQhG3sYc7wnMN9Ds/z8Hk+3M/L3g/ZS3ZpAg2iWHAkjs09h+yFLGoRZSw+Z3g+D8/nw3ke5nmYc5hz8Ay2QaZ8UwmiiCAOIkBa0rIt25IsSShFAlvMmN2FFgECLBgLS4zBEiMYmzPDc4bnmGeGZ4ZzhjPDmWFmOOdwzjBzmHM454AHPMiDZsAHbCpTRAspVEBLCxRoaUsbaKCBFhpooIUWWmih5bfyQ4AEElhgwUiMxUiMzRlzbM6IM+bYnDHH5ticMWNhG/ObAEkIEIUWVNrSFjU0/CIbWkioRFPaQEMbmoANlKaI31qgpS1taEpSdkM27C67y93lvcu9l/devt7L13v5c8OfKV8pb5bdcHaXv8lCiFqopS1u+SEJJMxvkpAEEkgggYQoP8q3QgsUKL9JSMIWtpkxM8Oc4TmH+xz283Dvh72X7KVZSKBBEmNzxpwz3PeQvZBAgwiWeM7weQ7P83A+H87zcJ6HOYeZQTbIlG8p0VKJyqBQiQKtKFCgDW0RMBYz5jnD7tIWAQYkGAtLWGDBSMyYY/Oc4TnDM8NzhjPDGTMznDnMGWYOM8PMYc4BD9igARt5iEwRRSQFCpS2tKUNTWhCE9KQhDa0oS1toIUWWqDQ8kOAKEYYsIQlbGGJsRiLsRiLsRmbGXNsZsyMGZuxsYQElF8kEP/RAoWUUnAgUKBA+WZDAwlNIIGGFtRCSwEVyreWJDQhKdmQvdx7ufdy38v7Xt738r6Xr/fy9V6+vi5fu/yZR8R01gAAIABJREFU8pXwbtiEs3v5IQkqJKEKu0CB8kP8rdAiG0lIQhKyUQsSf2sLFCh/EyAJyVjGNjPDOYc9h+d52Hv5fD5kL83ShCZAscSxOGPOGfY9ZJcm0IUGS5wxzzl8nofP5+H5fDifD+d5GA9YINEKEiqBihzkgA0IJLBA4ocA28wMZw73XjYLLQIESDASFlggYCzG5szwnOEZ85zhzHDOcDzMDGeGOYPnYA8zw5xDZSqDDDbICBMgLRRoKaUtbUhCEpIlCd2lCcnShCa0pQ1tKeW3IgoCyUhCEhZYwhJjYYuxGIsZMxYzYmxsMxYjMxK2sMTfxF/Eby2/hRYI3wSCAgUq0YQmtIWWNjThR1soiFIJAU1oQhKSsBvuLncv917ee3nv5X1fvt6XP9+XP9+XP78u/7PLnxv+THg37Iazu4hvEpKQhCRooaUtPySBxC8GAZaohC0IINEWSfxoC5T/XwJZ2MY2M8M5h+c57H3YvWQ/dJcm0GLBWJwxzzm872HvZe+FhmahQcAZc87hcw7Pc/h8PjyfD89zsI1kKtGCE+RBE5yiDeyCjWzkQTaysMXMcM5w38O9l81CQRQBEljCEhaIMhZjc2Z4znBmeM5wZnhmmDHjYc4wM9iDPHgGe6hEZYpAJhIUWiAFLT/akpYkbMJmyS7ZZbMkSxKS0IQmpKEUWtryi0D8JoEFkrDAAkuMhCUsYwlbWGIkxsISNsjCEpIQP0oLkvhXafktAQMREhSogApqaCGhCY0hofymlvKjtNCWNCRhN9xd7r3cu7zv5X1f3vfl6738+b58fb38+fXyP18vf97lfzb8mfB1l0042QXxTUhCEpIopYABSUgL4h+mREYSQUggCUlAoVB+lF9aWv4hhBCSsI3HzAxzDs9z2H3ILk1oiygW2ObMcM/heQ57L7tLszSBBlHG5pzhzPA8h+d5eD4PzznIRjI/CmwCG5TgFG/RLvZiG83iMbaxzZzheQ/vvdx7SQIFUQRIYAlLSCDKSJwZZswzh3PMM8M5hzNmPMwYe5gZZCMZ2dhDJFIoogghmqIEUSgkIQnZZXfZe9l72V12L9lld8kuyZIuaWhLE9oCBQoFBBL/EEUCAQIESCCBBAYkkEACCYQwIECAgAIS/1GogFIKGCUgUwcVqKClDW1oAw00tKIFAW35TdCSliRswmbZvdxd3nv5upev9/L1vny9L19fL3++L39+vfz59fI/9/I/N/yZ8HWXTTjJAgKBJCQhmX8VAZKQRIFQwEhFMkYgQAKJSvxWxG9toaXlXwJJ2GJsMsOZQ56HZ5dkaQItokhixtwz3Pdw78PuJbs0oQlk+WGLM+bMcM7wPA/nPJwzyEYSPwJ4gyY4wSlO8S6exWfwXeYePIPHnHO4z+Xey92lCS0IkECAJSwQIMFIzJgzw5nDOeaZ4ZzDsfEYexgb2UgGGVlIJoUtpBC+pZiwEQXS0pTdsLvsvexe9l7uvey97F6yS3bJhmxoQhPaUkpbyo8iBBQoUH4pfykIxI8ifhP/EiDxiwDxmxBQfpRv5VuhhQoUavFLRAVE1IIaWmhoQ7M0UEoRtPyogEJSNmF3uXe5u9x7ed+X9335ui9f7+XrvXy9l6+vy9f78uf78ud7+fMuf2742mU3nCT8JmQhCYn/RQhlkcQPAwEkYUEQEshCCFUg/h+lFCh/E0ISkpGNx8wZTg55HppAChQJbHNnuOewz8Pey+6SLE1oliZAscTYzJgzwzmH8xxmBksgASKUbHDCpmzKJuwunjC7zFnmLjPmjHmf5d7L7rK7JAWKAAGSsEAICQSMxMxwZjhnODOcGc4ZxsPYyMI2kkECBBIgtkUpm6KWqqggBVrakCzJsnvZvey93HvZ+7J72bvsXjZLsiQhCWlIQ1t+aRH/EiBAfBOIb+Jb+SF+lL8JEH9pEb+Jv6hQKCCgFMpfCi3UQABDCiq0tKFZGtFdKuhCW4IQRfwQpSRhN9y93F3ee3nv5b2X917e9/Ley9e9fN3L1718vZev9/L1Xv68y9eGr112w0nC31QhG6uUUqCCIBQhhb+ZbxIxOAIDEUggQQXiPwqFFmj5RYCEJGzjGSYh53CyNKEtPyRhm5nh7GHvJbvsLk1oQ3ZpAy2WsMVYzAxnhjmHGSMJJH6kJSneZVK2JQm7YXaZhLPh3Ms5wzmHZ5fdZXfZXZLyQ4AEAiwhCQECbHFmmBnOHM6YM8M5w3iwjSRkI4kWCpTftIVdSCHBBBRAlNKUJGSX3WXvZe9l97J72bvsXrJLdkmWZGlCW2hpCy2IXyQQAgECBKJAUYECLf9LCxRaaPmtiPJDiF8EAloQUH4UChKoRYAUhIBABRWtaEIlsiC+tQgQ/2ohCXeXu8u9l3sv77289/Ley7uX917ee3nv8nUvX3f52svXvbx3eTe8u+yGkyy/CUmoBZtfJAjfhCOqUEELCcjGCbFxAjb/KlQg/qNAKf8SIAnJ2GZmaELPQ1NKEWDB2JwZdi/ZZXdJQhPa0IRmoUUSlrCFLWaGcw62kfgmCrQlCZuQlG1Jwm6YLGfDJtw9nHt5nsvdsLtkwya0BYr4IQRYQgLxQ4zFzDBzOGc4M5wZZoaxkYQkJAEiLSm0pS041IZdukItkoDSljQkS3bJXnYvu5fcS3bJXpIlWZqQhDakoSltgfJDgAABEgghQPxXgQKlLbTQAqUtbaGFFlp+CJAK5R8SFBClBVSEgPJLgQYqSEEBiWqJCgyiNEYS4l9t2ZR7l3uXu8u7l/de7i7vLu9d3l3uhneXm3Cz3A034SbchN2wCScJvwlJ2CIBJEj4IYnEyIEIKHYgUAsCsXECEpWQhChFiL+Vll9K+UVCEpaoTG08wyT0OfwQIAvPsGfIPiRLdmlCW9rQhCbQgsACSVhiZpgZbIH4JkppS1K8Swtp2YQk7IbNsglnw97L3WUTsmETktCWH+I3SRiBQIAkxsYezgxzDmfMeJgZZowQiG+iLWlJShKSUC1BtKCAZH4UaEoTkpAs2SW77L3sXrJLsnSXJCRLE5pCC5R/CChIQhI/xP9VCi1toaEtbWlLW2gppS2/tCC+CQmE+FFAQAG1FBDlhwDxraUNrWgg4i+FFmpkI8R/tXAT3l3uLu9d7l3uLu8ud8NNuCm3YVtuwk3Zlm1JIS0ppOU05RcVMAnYpQkFKtGUOjSiEi20BkoCdqGl/Cag/If4rXwrtPwvElioxh1mCi1QKAiwzdokh2RpQhKa0BZakqUttEggQIAsxsZjJPFfaWnCJrSQliQkYROSsAm7y+5hd0lKEpKQlrb8ED+EBEJIQnyTGJvxMGeYOcyY8TAz2OZvbWnLbtiEbNhdgtgWxcjhHw1taJZmyS7ZJbskS7MkSxOa0ARaaCmF8q38EH+RECBAAgkk/lKg0NIWWtrShDY0hYY2NAaHVoCgQgIB4ptABQRFVEXlL0XlL4WEIgIYSIEWHGojGUn8rYhQNuXe5d3lZnkTbsKmbMsWtmULCwQRRBFFlG8SSCBz0vJDBRzAtKUtbWlLG1rTlra0pSk4CNMWNRTzv0iopQjxr/I38UMUSdiCmjK0ZVpAWMI2M0M2tKEJbWhLW9rShDbQIvGLKJKwjW0Q/2ppS1omoS0pJCEJaciGJGzC7pIsKSShKWn5L/FNQggJhJCEbWaGmcPMMB48ZjxI4kdb0pIE76K7rBcktsUb7CAJ8aO0pQlNaEKzNEuzkNAEEmgpRRQoUMQ3ARVSKeKHAAGSsIQAAaKoQEtb2tKEJrShCW1oQltoaA0tbUHlhxASv4nfWhDfym8CCoUSqCB8K2lQTWsaIwdkJIFE+SFCuSlvwt3wbrgpt7AtCwSIRCUqUQkssJGNXARoQMBpi4AKqIDSlra0pS2ltKUtTalKKRRKoaXlW/mb+K0SAgqIv4nfigRFCINABvNtQIAkIuExydCEtrSlCVBaaEMTaClF/Ci0SEIWlkF8Kz9aaEsbktBCKUlJQhuSsAlJyIYktCUtbWnLb+KHJH5IQghJSMIePMPMYWYYG9vYRhJtSUISdoPuBV2QaMEb5AWJf7Q0hYa2NIGWtrSFFgH/H2lwghxJtiQHUM0j6v7nHWQ8N2YCXb38hUMRqsZHxUdMQqKJJjKho7uEIJhEQhLxW2lp6WqrXd3Vru5qq13taKstLa2UDEESHy0JLUXrrX4U0Q2ptpJIK7s6IzvMkiAqmlh1tp6znl2ndVqrTmLFJprRGWa4RuaSa2Uvgznjcsi4tRo0ooS22qrSammrrXa10VQaTaXVBpV4i/oRby2JIv4moSR+zBh/SUhiZ+xeuqtdbWm1VW+ttrqL1Xqrb11BJpIRVH201VZb7Wppa7u6tV27de/arj3HttpqfWvrtySIJJIgkpgZM5eZy3XfZi4zYyaSEeyus2vPkechUdFydmVGEhEfbbWlqy1dlFZUVEJCwiRMtKFhxkeDRVcztIIgmMSEJBJ/KK222mqrrbbaaldbbelqR7uIbw3xVh/xo4iPqrdSby2JJqSSESUjrUxpSFQ0IXHKaT2tp3VaixVNmDDDjMwwl8zKVdk1yyWaJZGtu0ojqQolKUqp0tJq61tLq6k0mkpLovVW8TeJv0RSbVASSuLHjEkkbEgiu2arXW1p1VuLatG1XVpt/ShdH0kk8dEW1VZLu9r6aKut7Wqru3bXtrprd33UW/0lEW8ZSUQkkRnJmOtyzWWu23VdkkgiiZbdY85xnqOJLbOVcyQhvlVpabWrrXZpaVHBhIYmXCMqKBLmRCdsmOgOXVpBVBBM4pq4EhOCIIhSb6WlpaWl1ZYujXa1QyreShJUVVTVj6ofFVq/1coOWZlhlwyhoaVh8Wyd1mKxaKIZnYurcpVr5aq512xdW1djZ/Uss7J1K1IERfxDfasfbbUUKVIaDVHEfxO/RVLEb0WEVFr1Ec3ILFttVWl9tPWt1a7dpVX1rdWuj8RbUFTrrdpqx0frrdq1W1Xd1a3t6q62/hJ/SiQhkYyIzEjGzGWuy8zlui4zlyTEW3TXOYc8Kq7WuVbOIUGob23t1nZ1q11aVFRCwszoDFclDDbRje7qrO7SZatddmlRQVQwuBLXjCtjJiZMCCYEUVI/ivqHorTVRPyo+BZ/KA2hpf5d1UdaP6ooimJx1CmLTTTRDFNmZIZr5LrMtbKXuWruurAnJLIjrdu/KQ31Vh/1h9aP0hKK+Kg2kiL+qwSl8acQQUVUmZiEVjs6pUW13kqp0more2hVqbfVHVWJt6DairdWlVL1W3fNVW11a7um1V1aEn8JISIZSSRDYmZkLjOXuS4zl7kukyGhVO1ZxJbZSo4kIj5airbaald36dL6CJKYiWuGGe7LJHZXZ3RXd7Wru+zS6i5ddmlpRaVEBVe4Evc17hnXNWZiJiZMIokkkkhCQoKQkJCQISFBCFpaWi1ttVTVj4pv9S2o+qgqWhqKU05ZdbDYRId2GFwjZ+QauS5z1lxjdlylCRu2pnVXpfF3TRX1W2nVW+svRfw/S/yIxH9UJJFWS1tpfbT1o1pvpbTVroS22qLakJWWeAstqW+tH5UiKE20VXRWNtrqDC2J+AiJIBlJZEYykpEZM5e5LnNdZi4zl2R8tLW7krWt2ZWEBFG0tNWt7uqutrSqPoIkZsY1o/flYzZ2Vrfa1V1a3WVXW3bpsqutdGlppRWVMuFK3BP3jPsa93W5r8t1XeYac11mRmZkRmZkhhlmmItrJMOEBBHVoqWlZYv6qLfS+JtqfauPVVFRY1tHLE7ZsmiiQcKEGblGzsg15hqz49qxpUEiU23dWo1/SINS2lL/74r4myB+ixD/RUR9CzpStKrird6q3lptRe360ZVWWyyCoD4a0qCaiCLE34REWjU6tNXWR4QQIZFEEsnIjJlLMmbGXLe5LjOXzGVmyNDaXRItkyEh8dFWW+1qV7u21a7uaksJkpiJa0avizKJ3dFdWm1ptWWXVnel1S677NKllZZWuqIGk7gnrol7Lr/ucd+3677d1+26L9d1m+sy1yXXJdcl18VcXBczzJCQkND6tqWli9JqS6t+1I/6S9FSNLS1iW0drNhQUSVhRkqmMmNmzMTMmBnXNbY0SKXV1t16q79rqkWLaqt+1Fv9KX6Lb4m/hCBEEOItPhJ/KeItfhQlpfGtJd5KkdJqKykJooiP0GiKoNS/iH9IEWk1ER+DSupHJCERkUQSmTFzyYyZS2bMdbvmkuuSjGRIdEu8VbFo2a3dtVu7a8/as8459hy71a62ohJmYmZc1+CWxO5ol5aipUW1ZUuXll267LJLK11autIaTOIK14x74r4uv+7LfV+u+3bdt7lvc99y3ea65bq4brkuuYYZMkxI/KlI2aUhZUuXllb9aKkf9VYaim01bFmsqKooKqQEQyYykWEm5opr49rYKyQStmjc7dIQpGRUNdVWW5SW1ke91bcifsTfJMRfQuItEn8IIYL6p6CoHyWhRUipP5REE0TQ1j+V+kP9rxJBfVQE8ZEEkUQSEknMjMyYGZkxc5mMzEhGMiSIqra2tbt21znHOcc5xznHeR7nHOcce47d1V1tfUtkYmZc90XIjLlGt9r6Uam3UrR0aWllV7vssktXWrpsRY0aTOJKXBP3Ne7rct+X+77d9+26L9d9m/uW+5brkuvmuphhRieSIdGg3kpLRlrtkrKhpaVVNNX6VhRVLYtisVgsinqLbwkJEybMxAxXuIZroo2ICVuUe3cRCUkkJHRjE9lqqlP1WxUt8RY/Et8SQUQEQRBJfAsRf4p/k6DRVBpU/UhpUG/xW1A/ivpDqVJ/U0RQ/6qI+Agp4iMJiYgkJJKQkYREEklIEB9tKVV71jnHeY5zjvM8zvM4z+N5Hs/z8jyP53mc8zi7dtfuahGSmBnXdflIRmdtL1ofET8q3kqULV1auuyyS5eWXbrS0prWhAmTuBLXjOsa13W5r8t1X677Ntdl7luuS+5brou5uIYMEzIEiaAtLVN2paNZElrd1VZbRdFWUdVSLIpVK6qaqH9KGEzqCle4wxnORK8IrsSWLcq9ZwlJJJGQIJGNDemYlpbWj/pWlMQf4kcIEgmCIER8S8Rv8Zf6VhriRxE/6q0ktN4iqKDqrUVpVam3qr+rCupbvZUi/iaECImIJCSSSCLxFhF/V6VFtdHWOcd5jud5eV4vr9fL6/Xyen15Xi/P6+V5Xs7zeJ7HOY89R1vURxIzFxeZ6FaV1m9JBPEj3lpaaWnpsqu7dGWXli670ooaBBMmMRPXjGvGdV2u6zLXZe5Lrkuum+viumQurmGGhISE+FHS0pLVLgkJu761uqulqlgUxaqirRWrmvhLJAwGM8xyDfdwJs7EDrkYsaktbXzcZ48IIYmZio+ISGhWW221pf5Q/0m8xVv8iIiICIl4i7f4iH9XxFtpSGlQ3xLaSqLeElo/6t9VvbX+IfWXUn+ov4uQiBD/RX0rbemyNLTVsrv2HM/r8Twvr6+X19eX19eX19eX19eX1+vL83p5npfzPPY5dle7tBJmBpUwLlq/BUlkIiJIfEvR0kpLl13dZZeudNnSpStIK4iaRMJkXBMz47ouc10yl1yXXBfXxXXpjM6lE53RhERQf2jpasIGQbQ0bFcT2yoWbRXFoigWDfUjIZjEx6U23MMOZ9hhLzTSmLKJXeqj7j3rI4kk1I8QJGRWd3VXZ7TVVktVUcRv8VsSEhISEhFCvCX+m6B+BEVKU0GLhCKo/6je6kfrL0V8q7eqogj1X5RGQ1r1hy1TuyshSEuKo8u29qxzHs/r8Xq9vF5fXl9fXl//4/X15evry+vr5fV6eV4v5xxnj+1qqyGJzJgwMyQ+EiKSyIxJJJFEEERpKVF22dVduuzSZZdWurSilKiPIGESyciMzMh1cV06o9elc+mMzqUTm5BIIvEtpaluNGzY1BErFouWLW1tq62qloaioinit2BCg9ByYcs13MMOOxgyHHG2GlpvcZ9zfCSRRFv1EUQ2Zmtb25pWlXor9VZ/ij9E4lsQREQIEeIt4qPEH0JpSBHaCppIqd+KIAhB/QfV+pv6URoUpShS/66UCupPrSYS0koqKbskIlq2tWedXed5PK+X1+vl9fXy+vofX19fvv7nf7y+vjyvL8/r5Xke53nsWd3VEiFjpoiPTExGJpKYGZMxM2YiIiGIt9ZHWrq6yy67dNlll5YuLS1dWm3FWxGSSMKMZnQunbG5yGhGEytGrIhISbyVUqxYbDmtbW1rt3ZXu7qrrbaqihahgvgW4i0hxFu8VVMb7tSGHToYMgwutBQt9znHRxJJtPVbcBIza3e11Va3OtXSVktbLSkN8RHfEhKCROItEn8T/xBSmtJIqLeWxEeURkPQoPEj/l39qG9FvNVH662qlIj6qI82BK0fVfGRVkOEVLIIomjZXeesc47zPF6vl9fry+vr5fX15fX1P76+vry+vrxeL8/zOOdxzrG7tkUJSUQkkcTMmBkzY2bMNa4ZM2MykkhIIkiLStHVXXZ1ly5buuyyq11a3dVdbbVLaUu8hUQzNqNGsEiZrYSEhElFfES11VZ37amztVu7tad2V3ftrnZptVX1Ld5CfAviR1S8hfhxpTa14UrdoaHBkLJDS4vUfc6DSCKJqt9OyI7d1V27a3fNrHa0VaX1o/6uiPhLiLcQbyG+xb+qiqDeihC0FVRIaUikUR/xr+q3+laqNBLaotpS35pSqoik1LcW9VYf9VFJEPURHy3b2rPOOZ7neJ6X5/Xy+np5vb68vr58fX15vV6ery+v5/G8Xp7nOHtsl9ZHEkkkkRkz45ox1+W6Ltc1Zi7XNWbGzJhEEkESaX2kpaWru+zSZatddnWXXe3ac+yu7tpdu6utlqJogiDSsCSVIERNIkgiPkqrrd21Z+1Zu2vPsefYXd3VLl1taVGCkkQmiCQYQdSPIkZta9SoK3XUpK5UU0ltWfVRdZ9zEEkkUaV+JCbHXpfd1V1ttdWtppS22mppK0pLS4r4VxHiLeJfFUERSRUp9b9I/K9K/VbEt/pDfSv1Vm9VQSn1h1b9Fh+tbxVtteyu8xznHM/zeF6P1+vl9fry+vryer28Xi/P68vr9TjP43ke5zx2V3fVWyKJmciMay5zjeu+3Nftui7Xdbmuy1zjui4zYxJJTCJ+BFFadnVLly5burqre3TXnrXn2HOcc5w9ctbZ1ZZWS1Hx0aJI/aggISIh3lpUt7pr99hznD161u7qHt2lhy4t6iMhyEQ2MtGGEqHe4kdopZVd6UrXWNMadSmKRVHF/ZwjSEYmqhQhJ86Ma4/dy+7aXduarna01VZbbVW1NARFiviP4m/iD6EktEUE9SOhPkrjRwiK+BHUW6lvrT/Ub21RVepP9daqP9S3tpR6a7X1UaHVUrS0tVtn13mO8zye5/G8Xl6vl9fXl9fr5fV6eZ6X5/V4nsc5j3OOPWu7fktiZsyMuS7Xfbmvy3Xf7vty3bf7ulzX7bouc41rRjJmIolB4lvqrWzpskurXbbssbu6a89xzuM8R55HzvE8R8/RXbu1rW21bCnaqrdW1UcQBPFRWm111+6x59g9eo7u0R526dIVRUUlMSGNmYggRjVBSQhFS7e6q3t0l650pUsrKiqtqpT7PIeQrNnRKRdCMmbX2XXt2q52ddfOSFcbbbTVlpZWW22l1ZRGgiIUEUW8xVv8KEEjoS0J6lv9IShC0PhT0Pi7tv539dHWR+utPuqt1dLWR1tttfXRslstbW1rzzpnPc/jPI/nebxeL6/Xy/N6eb1entfL8zye53HO45y1e3SrKsiMTMyM67pc9+W6b/d9u+/bfd/uX7frul335bou13W5ZsyMJCaRRBDEH7ps6dLS6i5de9busc/jOUdeD9dLn8fk2Hl4Dlk9a1tHbWtbu7Wlrbba+ogfUfHWald3ddfusefoHvZoj+xipSsqakLChJloYxo6dJmRriSEira61V3dZQ972GVXuuzSFaWl3Oc8iCQ61da3xOTYGXsue63dtVvd1V2d0VZbbbVrG2lptdVWilRbEh/x1pL4d/EtpSFoET/qH4L6myB+BMH6v6o/tfXR1kdbH20V3Wrro7u21dZHl+3q1pbddc4653iex/N6PM/jeb28Xi/P8/J6PZ7Xy3kezzn2HLurXW1JSCQxc5nrMvflum/3fbt//fLr1+2+f7nv23Xf7uty3ZfrusxcZmIyMjGJIImPtLS0KC27tLprd+05zvPI88i8mMvmZb0QGus4G0+Os3W2nq3ddbZ21+5qS+sjfkRpaXVX9+geu6t72EOPdKUraqwJo2ZiwjXRiW6YMMNEEpkgii3b2l09q7t6ju7Swy4tu7S+te7nOZJIoq22PpI4E7OXa9fu6lZ3bWta3bUZSXVXE91qlkZbbbVLB5XWb02k1YSSFPGfBfUjqP+mPuqjKOo/aEn8qf7SolraUoq2utVWW9vqrraKbu3Wdu3WnnXOOud4vR7nebyel+f1eJ6X1+vleR7nPM45do/dtV1aRZBEZlzXuO7Lfd/u+5dfv273r1/uX7/8um/3r9t13a77cl+3uS7XjJkxMzIxiSCJj3hrUVpaWlpae45zjnkeeT06l83LJCJSWrpsOF1P47U8Zz3nOGeds845uqutj6iPKEWXru7aPbrLHnqkK12xRo11hQlXuIYmrolOmOiMTiSRhETRsmV39azd1V3d1V3dZZeWllLc5xxJJLGtq/WRxMzY69g9dtfu2la7tjWtdrXRRlvt2sZ0tdFWW1pUuxh/CkoSLUkRfxfRFKH1n8WP+BH1h/qPivjPihattpS2ttWtdrXsrnbt1sdu7a7d2l3nrHOO5zme5/E8j+d5PM/jeR7nOfY5zjl2j93VLq0iIYnMuK4x1+W6bvd9u3/d7l+/3L9++fXrl/u+3fftum/3fbuuy3VdZsbMmBlJzERE4i0StKLUW2lpae2uOUdeD/MB3rEdAAAL1ElEQVSyGUdcyGLLsqdO6ojX1mvr9azXczzneJ7jnOOco1sUFaTeSpdW9+iu9rBLj3RN11ijrtSVusI9bGIndrhmdGImZsYkMkEUxSm7dbZ61u7qrp7Vrbbaaqutj/ucQyKJ6dLLRyZmx3Uuu6tdbbWrrXa1o6222mpXG2211a42tjW7DO2g/i4oEtqIEn+q/67e6lv9fwrqb6otrZZtddfuamu32rVb3dWyXXtqd+2uc9ZzjvMc53mc53Gex57HnmP32K622tKqH0kkMTOuGXNdruty35frvt33L/evX379+uX+9ct93+77dt23+7pc92Xmcl0jGTNjJpKREJF4i6jf0vrW0tpdOYe5NOMSV8mSU87qrOZY8TSe8jrr66yv53i9Hs/zeD3HnmP3aEuJio/S0tVd7WFX90jXdI1j1GVdqSvcqTNxD9fEPbETO+OamImZkYRERcXibO3W2bVbu7W72uqWVr2V4j7n+EiiM3r5lhkz61xrt3Zrd3Vrt6bVVltttdWtprqromqzptTQ2q2ZRRDER1AR1YQS1L+Kqoqqf4rf6t8V8V8E9U+laKutbu2u3bW72tpdu6tbLbtrd+2us3We45zjPMd5Hucce46za3e11ZZWvSXiLd5iZsw15rpc1+W+b9d9u+/b/et237f7vt337b5v93277tt13a7rcl1jZmTGzEhiEhJJJER8RH3EW/1opSvn6IwVU2aZs/Ic5miOzeV4HDzLa+vrrP95jtfr8fV6vF4v5xx7jm1pRcVHaenqru5hlx7pSo/puqwrdafucA93uC/uiTNxz7iuuGbMjJmYGRIyihWndZazdba2tVvbamtL1UdxP+cIkmirCGbGXpfdtbt2V1vbaqutttpqq6222tVGu9qwVbVTs8vQjiL+g0RaEvV/U78V9aPe6g/xl6CKoD7iR/wogvqot1Zbu9Wu3bXn2FZ37a7dtVtt7a7dtafOrnOOc9Y5x9ljz7G72mqr/pBI8n8qgxNEt47kCICR1eD9j2tieZUG+EVqHY8c4ZdEEjPjnOPcjnO7Obeb2+3mdru53W5ut5vb7eZ2u7ndbs7t5na7OeeYc8yMmTEzMmMSSSQhESTxEV/ijypbchzjWuaqXMvtG+diXjpjEytey3PX41qP1+X+fHk8Xx6Ph8fj6fV6ua5L99JWEKWlpau72mUvurKXscY66mbdwm3q23Cb+DZxndiJ64zbxDnjzJgZM8OMJJqx2HKVq7XL1drWlpaqlvpy2+vykUTrh03srt3VXe1qa7va1ZZWW1pttdVWt5pqa7um0ZZdO2NauysZgvFLUG9Bibd4i39Uv6tf6q1+Kep39RHUnwVFUFRbbbVrd3Uvu2t37a7dtddq125ta6+1u65d17Wu1+W61l5rd7XVrj8JSQhpCJORM845zjlu5zjnOLebc7s5t5tzuzm3m3Nuzu3m3G7OOc65mTNmxsxIxkwkIZFEEknE75L4o2BTk5VWzk3OxRyZIaOJFVteW69dz2s9Xy/3x9P98XS/393vD4/Hw/P5dL1e9lrt+oj6SFd3aXUvunSla7qOdVK31LfwbbiGbyf2xE70jNsZPbE7do5zRmbMDBlNNbFlscu2tiza2lJU/HS7dgVJfCRcu86u3bWtbbXVVltUS1FUVVVVtdWWVrtab0NX622wGBbxS1AR1YSSVOsftd6KqlJ/ET/UW3yp34WgvgT1pVS11dbu2l27l73W7tpd13XpVlu7de3aXde1dtfuZXftXnbXdqlfkogwpCEIM2POMec455hznNtxznHOcTvHOcc5xznHOceZY84x5zhnZMZkZCKJJJJIQiIi8UuE+CG+JAQ5NznLHJmjOZpYseVqXbte13q9Xh7Pl8fz6X5/+P797vv97n6/ez6eXq+X67p0V9RHlJZWu+zSla6osY66pb6lruEa9sSe6Bk90R3d0R3do6faY6b2IBgqVmy5sGXLtopFG0J9ue21hEkQycqu3dVWW91qq62Wtqq0tBStttpqq6202mqLZUeVqS+L8VdBE2lJtL7UDy0tVZRSb/U39U+C+rOgfqqq0mqru7prd+21di/XtXbXXpfdamt37a5ra6917bqutbt2V1stVR8JTUQQUh9JzIyZcc445zjnOHOcc5zbMec455hzzBkzY86YOeaMmSMTk5GJJJKQiEiQiPglxEcIEWmlZCozMkNCooliW9fWtet1XZ6vy/P58ng83e933+933//nu+/3u8f94fV6ul6X7Yr6SL2Vlq620qVr1Ekd9W3qFa4TO/RET7gNO3To0EOrPVrmkJJBaWKNxVW2LFoWFUUbP912lyBBJGTXttrVVlttKW21KFVFVVtptUVVtZVWWz+k2tL6KarxNylNpCXxUVRRP5Si3uqHqqqi9S+FVERbPxSlpa222uqu3bW7umuvy+7aXW3t1u7aa+3W7uqu3dVWWxQhaCTehhQRJDFnzIyZY844Z8w5zhlnjjNjzjgzZo6ZY2bMGTMjM2ZGEkkkkUTiLZIQIn4JET8kgiATSUhISBQtLdvaXde1rtfl9Xx5Pp8ej4f74+H+/e779+++f7+73++ez6fruuwuKn7TimorLVZao07qFq7h29ATPdiRRjrSIyqt+FJRMSIilkYnVi22sdhSsSgq6i3xcduuNHZI1zam1VZLW1VtVVFtVX0pRWgraCutpqrSIrSaSuunplK/iY96C2k1ofVLfWn90KKoeivqHxXx3wT1S0urre7aXe3aXburXd3VXdvard21u3aru7bVVltVrV+SqIqP+AgyIxkzY2ZMxsw4M2bGzMiMmZEZM5GJmTEZkzETSWQiiSQikhAixFv8FG/xFom3iI+QIJQWpa3dtVvXta5rva7L6/XyfL48nk+Px9P9/vD9/vD9+3f3+8Pj+XC9LruLii9R6q20oqJOOKkr7NATNrIxrTEGEyYMkiCaaGIykoq3qW6tKC4s2lgUFU3UW6O4dUtIaWmrrbbaakupaml9qT+pitD6KFJaGm+lpFX1Q0LrS1Af8aWJtCS+1EdLUfXRUm+tqh9aP7RaqhTxJ0V8BPVHVVVttdVWW93VrXbt1nZtq1vt2l1ttWtb7WqrrdbfRDSkCEESSSSRRCaSkYlkZGJmTMbMyIzJSCKJTCQjiWRMQiLxFom3iLf4i0i8xZdI4qf6UtXSVnftrmsv13V5XZfX6+X1fHk+nx7Pp8fj4f54uj/uHo+n1+tld8VHfcRb6yMqajDhNnQwpDGNY5zULXWFK1yJVyJbSdmS2tSkqI+GhsViy2JRURQVEh+3toQ2qtpq64+qvhRFUX9ShPpNaSotLeKjRSqirXhLUF/iowiK+E2pon6o/6C+1H8T/yC+1G+qrbbaaqutttrVVndta7e6tbt2q7t2a7e21fqlKOo38SXxkUQSSSQjiSSSSCKJJJKYRBJJJEEIScRbIol4S3wk3uKP4i3eIvEW1F+1tLTV1m51a691Xeu6Lq/r8nq9vJ4vz+fT8/H0fDw8Hk+Px8Pr9bK71C9RH1EJwYST6kSGnDjiMq6ww7Wxu7axrba2ta0shml1EZRisdiyWFQsKiqI+nKrSkNK/dJW/aao/6qItyIoQn3UR5RGUxH11ooQb1XEW5HQkqi/a32pL6Uoivqjqoi3+qGI/0NpvVVbWlVUW0pbVW21VdVWW21pVSlaTfxn8ZHED4kkkkgiIiEiIYkECfEWEklESCQRxFsi3uItPhJ/EV/iPyv1Vi1tbWtbu+u61nVdXtfl9Xp5vV6er5fn6+X5fHo8n17Pl931U3xUkBBMmCCRw6txxJWxU9varba2tLRsadmSlqJEabVVVK24yqJYFA0tDUrFTWmqglLUl9Y/aX2pv6iPqiji36rfxb9Rv6v/t9AS/6B+qaJavyv1pf5vRX0pmvjXQrzFlyDeQrzFlwgiEuJ38Q8S/1l8xB/Fl/izammrqq222mqrW7trd+2u3XVdl+u6XNflui67i/opCBKSaBB2YjcatrTVVltF64ei6qOlKNpqaUlpKRaLqoqiqqKloUWi+F8C2tVUBBTxuQAAAABJRU5ErkJggg==';\nconst FALLBACK =\n  'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMIAAADDCAYAAADQvc6UAAABRWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwSDCIMogwMCcmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsis7PPOq3QdDFcvjV3jOD1boQVTPQrgSkktTgbSf4A4LbmgqISBgTEFyFYuLykAsTuAbJEioKOA7DkgdjqEvQHEToKwj4DVhAQ5A9k3gGyB5IxEoBmML4BsnSQk8XQkNtReEOBxcfXxUQg1Mjc0dyHgXNJBSWpFCYh2zi+oLMpMzyhRcASGUqqCZ16yno6CkYGRAQMDKMwhqj/fAIcloxgHQqxAjIHBEugw5sUIsSQpBobtQPdLciLEVJYzMPBHMDBsayhILEqEO4DxG0txmrERhM29nYGBddr//5/DGRjYNRkY/l7////39v///y4Dmn+LgeHANwDrkl1AuO+pmgAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAwqADAAQAAAABAAAAwwAAAAD9b/HnAAAHlklEQVR4Ae3dP3PTWBSGcbGzM6GCKqlIBRV0dHRJFarQ0eUT8LH4BnRU0NHR0UEFVdIlFRV7TzRksomPY8uykTk/zewQfKw/9znv4yvJynLv4uLiV2dBoDiBf4qP3/ARuCRABEFAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghgg0Aj8i0JO4OzsrPv69Wv+hi2qPHr0qNvf39+iI97soRIh4f3z58/u7du3SXX7Xt7Z2enevHmzfQe+oSN2apSAPj09TSrb+XKI/f379+08+A0cNRE2ANkupk+ACNPvkSPcAAEibACyXUyfABGm3yNHuAECRNgAZLuYPgEirKlHu7u7XdyytGwHAd8jjNyng4OD7vnz51dbPT8/7z58+NB9+/bt6jU/TI+AGWHEnrx48eJ/EsSmHzx40L18+fLyzxF3ZVMjEyDCiEDjMYZZS5wiPXnyZFbJaxMhQIQRGzHvWR7XCyOCXsOmiDAi1HmPMMQjDpbpEiDCiL358eNHurW/5SnWdIBbXiDCiA38/Pnzrce2YyZ4//59F3ePLNMl4PbpiL2J0L979+7yDtHDhw8vtzzvdGnEXdvUigSIsCLAWavHp/+qM0BcXMd/q25n1vF57TYBp0a3mUzilePj4+7k5KSLb6gt6ydAhPUzXnoPR0dHl79WGTNCfBnn1uvSCJdegQhLI1vvCk+fPu2ePXt2tZOYEV6/fn31dz+shwAR1sP1cqvLntbEN9MxA9xcYjsxS1jWR4AIa2Ibzx0tc44fYX/16lV6NDFLXH+YL32jwiACRBiEbf5KcXoTIsQSpzXx4N28Ja4BQoK7rgXiydbHjx/P25TaQAJEGAguWy0+2Q8PD6/Ki4R8EVl+bzBOnZY95fq9rj9zAkTI2SxdidBHqG9+skdw43borCXO/ZcJdraPWdv22uIEiLA4q7nvvCug8WTqzQveOH26fodo7g6uFe/a17W3+nFBAkRYENRdb1vkkz1CH9cPsVy/jrhr27PqMYvENYNlHAIesRiBYwRy0V+8iXP8+/fvX11Mr7L7ECueb/r48eMqm7FuI2BGWDEG8cm+7G3NEOfmdcTQw4h9/55lhm7DekRYKQPZF2ArbXTAyu4kDYB2YxUzwg0gi/41ztHnfQG26HbGel/crVrm7tNY+/1btkOEAZ2M05r4FB7r9GbAIdxaZYrHdOsgJ/wCEQY0J74TmOKnbxxT9n3FgGGWWsVdowHtjt9Nnvf7yQM2aZU/TIAIAxrw6dOnAWtZZcoEnBpNuTuObWMEiLAx1HY0ZQJEmHJ3HNvGCBBhY6jtaMoEiJB0Z29vL6ls58vxPcO8/zfrdo5qvKO+d3Fx8Wu8zf1dW4p/cPzLly/dtv9Ts/EbcvGAHhHyfBIhZ6NSiIBTo0LNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiEC/wGgKKC4YMA4TAAAAABJRU5ErkJggg==';\n\ndescribe('image', () => {\n  let fixture: ComponentFixture<TestImageBasicComponent>;\n  let context: TestImageBasicComponent;\n  let debugElement: DebugElement;\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [\n        { provide: Overlay, useClass: Overlay },\n        {\n          provide: NgZone,\n          useFactory: () => new MockNgZone()\n        }\n      ]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(TestImageBasicComponent);\n    fixture.detectChanges();\n    context = fixture.componentInstance;\n    debugElement = fixture.debugElement;\n  });\n\n  it('should only latest src work', async () => {\n    context.src = 'error.png';\n    context.placeholder = null;\n    await updateNonSignalsInput(fixture);\n\n    const image = debugElement.nativeElement.querySelector('img');\n    await fixture.whenStable();\n\n    const oldBackLoadImage = context.nzImage.backLoadImage;\n    context.src = SRC;\n    await updateNonSignalsInput(fixture, 1000);\n\n    context.nzImage.backLoadImage.dispatchEvent(new Event('load'));\n    await fixture.whenStable();\n    expect(image.src).toBe(SRC);\n\n    oldBackLoadImage.dispatchEvent(new ErrorEvent('error'));\n    await fixture.whenStable();\n    expect(image.src).toBe(SRC);\n    expect(context.nzImage.status).toBe('normal');\n  });\n\n  it('should keep placeholder when latest src is loading', async () => {\n    context.src = SRC;\n    context.placeholder = PLACEHOLDER;\n    await updateNonSignalsInput(fixture);\n\n    const image = debugElement.nativeElement.querySelector('img');\n    const oldBackLoadImage = context.nzImage.backLoadImage;\n    const SECOND_SRC = 'https://test.com/SECOND_SRC.png';\n    context.src = SECOND_SRC;\n    await updateNonSignalsInput(fixture, 1000);\n\n    oldBackLoadImage.dispatchEvent(new Event('load'));\n    await fixture.whenStable();\n    expect(image.src).toBe(PLACEHOLDER);\n\n    context.nzImage.backLoadImage.dispatchEvent(new Event('load'));\n    await fixture.whenStable();\n    expect(image.src).toBe(SECOND_SRC);\n  });\n});\n\ndescribe('image placeholder', () => {\n  let fixture: ComponentFixture<TestImagePlaceholderComponent>;\n  let context: TestImagePlaceholderComponent;\n  let debugElement: DebugElement;\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: Overlay, useClass: Overlay }]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(TestImagePlaceholderComponent);\n    fixture.detectChanges();\n    context = fixture.componentInstance;\n    debugElement = fixture.debugElement;\n  });\n\n  xit('should placeholder src work', () => {\n    const image = debugElement.nativeElement.querySelector('img');\n    const spy = spyOnProperty(image, 'src', 'set').and.callThrough();\n    context.src = SRC;\n    context.placeholder = PLACEHOLDER;\n    fixture.detectChanges();\n    expect(spy).toHaveBeenCalled();\n    expect(spy).toHaveBeenCalledWith(PLACEHOLDER);\n  });\n\n  it('should hide placeholder when image loaded', async () => {\n    context.src = QUICK_SRC;\n    context.placeholder = PLACEHOLDER;\n    const imageComponent = context.nzImage;\n    const imageElement = imageComponent.getElement().nativeElement;\n    await updateNonSignalsInput(fixture, 300);\n\n    imageComponent.backLoadImage.dispatchEvent(new Event('load'));\n    await fixture.whenStable();\n    expect(imageElement.getAttribute('src')).toBe(QUICK_SRC);\n  });\n});\n\ndescribe('image fallback', () => {\n  let fixture: ComponentFixture<TestImageFallbackComponent>;\n  let context: TestImageFallbackComponent;\n  let debugElement: DebugElement;\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: Overlay, useClass: Overlay }]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(TestImageFallbackComponent);\n    fixture.detectChanges();\n    context = fixture.componentInstance;\n    debugElement = fixture.debugElement;\n  });\n\n  it('should fallback src work', async () => {\n    context.src = 'error.png';\n    context.fallback = FALLBACK;\n    await updateNonSignalsInput(fixture);\n\n    context.image.backLoadImage.dispatchEvent(new ErrorEvent('error'));\n    await fixture.whenStable();\n    const image = debugElement.nativeElement.querySelector('img');\n    expect(image.src).toBe(FALLBACK);\n  });\n});\n\ndescribe('image preview', () => {\n  let fixture: ComponentFixture<TestImagePreviewGroupComponent>;\n  let context: TestImagePreviewGroupComponent;\n  let debugElement: DebugElement;\n  let overlayContainer: OverlayContainer;\n  let overlayContainerElement: HTMLElement;\n  let previewElement: HTMLElement | null;\n  let configService: NzConfigService;\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [\n        provideNzIconsTesting(),\n        { provide: Overlay, useClass: Overlay },\n        {\n          provide: NgZone,\n          useFactory: () => new MockNgZone()\n        }\n      ]\n    });\n  });\n\n  beforeEach(inject([OverlayContainer, NzConfigService], (oc: OverlayContainer, cs: NzConfigService) => {\n    overlayContainer = oc;\n    configService = cs;\n    overlayContainerElement = oc.getContainerElement();\n  }));\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(TestImagePreviewGroupComponent);\n    fixture.detectChanges();\n    context = fixture.componentInstance;\n    debugElement = fixture.debugElement;\n  });\n\n  afterEach(() => {\n    overlayContainer.ngOnDestroy();\n  });\n\n  function getPreviewWrapElement(): HTMLElement {\n    return overlayContainerElement.querySelector('.ant-image-preview-wrap')! as HTMLElement;\n  }\n\n  function getPreviewRootElement(): HTMLDivElement {\n    return overlayContainerElement.querySelector('.ant-image-preview-root')! as HTMLDivElement;\n  }\n\n  function getPreviewImageElement(): HTMLImageElement {\n    return previewElement!.querySelector('.ant-image-preview-img')! as HTMLImageElement;\n  }\n\n  function tickChanges(time: number = 300): void {\n    fixture.detectChanges();\n    tick(time);\n    fixture.detectChanges();\n  }\n\n  describe('nzDisablePreview', () => {\n    it('should nzDisablePreview work outside group', async () => {\n      context.firstSrc = QUICK_SRC;\n      context.disablePreview = true;\n      await updateNonSignalsInput(fixture);\n\n      context.triggerPreview();\n      await fixture.whenStable();\n      expect(getPreviewRootElement()).toBeFalsy();\n\n      context.disablePreview = false;\n      await updateNonSignalsInput(fixture);\n\n      context.triggerPreview();\n      await fixture.whenStable();\n      expect(getPreviewRootElement()).toBeTruthy();\n    });\n\n    it('should nzDisablePreview work inside group', async () => {\n      context.firstSrc = QUICK_SRC;\n      context.disablePreview = true;\n      await updateNonSignalsInput(fixture);\n\n      const image = debugElement.nativeElement.querySelector('img');\n      image.click();\n      await fixture.whenStable();\n      expect(getPreviewRootElement()).toBeFalsy();\n\n      context.disablePreview = false;\n      await updateNonSignalsInput(fixture);\n\n      image.click();\n      await fixture.whenStable();\n      expect(getPreviewRootElement()).toBeTruthy();\n    });\n  });\n\n  describe('tool actions', () => {\n    it('should rotate, zoom and close and flip work', async () => {\n      context.firstSrc = QUICK_SRC;\n      await updateNonSignalsInput(fixture);\n      const image = debugElement.nativeElement.querySelector('img');\n      image.click();\n      await fixture.whenStable();\n\n      previewElement = getPreviewRootElement();\n      const imageElement = getPreviewImageElement();\n      const [close, zoomIn, zoomOut, rotateRight, rotateLeft, flipHorizontally, flipVertically] =\n        overlayContainerElement.querySelectorAll('.ant-image-preview-operations-operation');\n      const getStyle = (): string | null => imageElement!.getAttribute('style');\n\n      dispatchFakeEvent(rotateLeft, 'click');\n      await fixture.whenStable();\n      expect(getStyle()).toContain('transform: scale3d(1, 1, 1) rotate(-90deg)');\n\n      dispatchFakeEvent(rotateRight, 'click');\n      await fixture.whenStable();\n      expect(getStyle()).toContain('transform: scale3d(1, 1, 1) rotate(0deg)');\n\n      dispatchFakeEvent(zoomIn, 'click');\n      await fixture.whenStable();\n      expect(getStyle()).toContain('transform: scale3d(1.5, 1.5, 1) rotate(0deg)');\n\n      dispatchFakeEvent(zoomOut, 'click');\n      await fixture.whenStable();\n      expect(getStyle()).toContain('transform: scale3d(1, 1, 1) rotate(0deg)');\n\n      dispatchFakeEvent(flipHorizontally, 'click');\n      await fixture.whenStable();\n      expect(getStyle()).toContain('transform: scale3d(-1, 1, 1) rotate(0deg)');\n\n      dispatchFakeEvent(flipVertically, 'click');\n      await fixture.whenStable();\n      expect(getStyle()).toContain('transform: scale3d(-1, -1, 1) rotate(0deg)');\n\n      dispatchFakeEvent(close, 'click');\n      // mock animationend event\n      dispatchEvent(getPreviewRootElement(), new AnimationEvent('animationend', { animationName: 'antFadeOut' }));\n      await fixture.whenStable();\n      expect(context.previewRef?.previewInstance).toBeFalsy();\n    });\n\n    it('should zoom in/out based on the zoom step value', async () => {\n      context.firstSrc = QUICK_SRC;\n      context.zoomStep = 2;\n      await updateNonSignalsInput(fixture);\n\n      const image = debugElement.nativeElement.querySelectorAll('img');\n      image[2].click();\n      await fixture.whenStable();\n\n      previewElement = getPreviewRootElement();\n      const imageElement = getPreviewImageElement();\n      const operations = overlayContainerElement.querySelectorAll('.ant-image-preview-operations-operation');\n      const zoomIn = operations[1];\n      const zoomOut = operations[2];\n\n      dispatchFakeEvent(zoomIn, 'click');\n      await fixture.whenStable();\n      expect(imageElement!.getAttribute('style')).toContain('transform: scale3d(3, 3, 1) rotate(0deg)');\n\n      dispatchFakeEvent(zoomOut, 'click');\n      await fixture.whenStable();\n      expect(imageElement!.getAttribute('style')).toContain('transform: scale3d(1, 1, 1) rotate(0deg)');\n    });\n\n    it('should have a default value of 0.5 for zoomStep', async () => {\n      context.firstSrc = QUICK_SRC;\n      context.zoomStep = null;\n      await updateNonSignalsInput(fixture);\n\n      context.triggerPreview();\n      await fixture.whenStable();\n\n      previewElement = getPreviewRootElement();\n      const imageElement = getPreviewImageElement();\n      const operations = overlayContainerElement.querySelectorAll('.ant-image-preview-operations-operation');\n      const zoomIn = operations[1];\n\n      dispatchFakeEvent(zoomIn, 'click');\n      await fixture.whenStable();\n      expect(imageElement!.getAttribute('style')).toContain('transform: scale3d(1.5, 1.5, 1) rotate(0deg)');\n    });\n\n    it('should the groupZoomStep variable be set for each image\"s zoomStep', async () => {\n      context.firstSrc = QUICK_SRC;\n      context.groupZoomStep = 5;\n      await updateNonSignalsInput(fixture);\n\n      context.triggerPreview();\n      await fixture.whenStable();\n\n      previewElement = getPreviewRootElement();\n      const imageElement = getPreviewImageElement();\n      const operations = overlayContainerElement.querySelectorAll('.ant-image-preview-operations-operation');\n      const zoomIn = operations[1];\n\n      dispatchFakeEvent(zoomIn, 'click');\n      await fixture.whenStable();\n      expect(imageElement!.getAttribute('style')).toContain('transform: scale3d(6, 6, 1) rotate(0deg)');\n    });\n\n    it('should the groupZoomStep variable be set for each image\"s zoomStep Except those that already have a zoomStep value', async () => {\n      context.firstSrc = QUICK_SRC;\n      context.groupZoomStep = 5;\n      context.zoomStep = 3;\n      await updateNonSignalsInput(fixture);\n\n      const image = debugElement.nativeElement.querySelectorAll('img');\n      image[2].click();\n      await fixture.whenStable();\n\n      previewElement = getPreviewRootElement();\n      const imageElement = getPreviewImageElement();\n      const operations = overlayContainerElement.querySelectorAll('.ant-image-preview-operations-operation');\n      const zoomIn = operations[1];\n\n      dispatchFakeEvent(zoomIn, 'click');\n      await fixture.whenStable();\n      expect(imageElement!.getAttribute('style')).toContain('transform: scale3d(4, 4, 1) rotate(0deg)');\n    });\n\n    it('should global config work', async () => {\n      configService.set('image', { nzScaleStep: 10 });\n      context.firstSrc = QUICK_SRC;\n      await updateNonSignalsInput(fixture);\n\n      const image = debugElement.nativeElement.querySelectorAll('img');\n      image[3].click();\n      await fixture.whenStable();\n\n      previewElement = getPreviewRootElement();\n      const imageElement = getPreviewImageElement();\n      const operations = overlayContainerElement.querySelectorAll('.ant-image-preview-operations-operation');\n      const zoomIn = operations[1];\n\n      dispatchFakeEvent(zoomIn, 'click');\n      await fixture.whenStable();\n      expect(imageElement!.getAttribute('style')).toContain('transform: scale3d(11, 11, 1) rotate(0deg)');\n    });\n\n    // depends on NgZone.runOutsideAngular, keep using `fakeAsync` here\n    it('should detect mouse zoom direction correctly', fakeAsync(() => {\n      context.images = [{ src: QUICK_SRC }];\n      context.createByService();\n      const previewInstance = context.previewRef!.previewInstance;\n      tickChanges();\n      dispatchMouseEvent(previewInstance.imagePreviewWrapper.nativeElement, 'mousedown');\n      expect(previewInstance.isDragging()).toEqual(true);\n      let isZoomingInside = previewInstance['isZoomedInWithMouseWheel'](10);\n      expect(isZoomingInside).toBeFalsy();\n      isZoomingInside = previewInstance['isZoomedInWithMouseWheel'](-10);\n      expect(isZoomingInside).toBeTruthy();\n    }));\n\n    it('should call correct methods when zooming in or out', async () => {\n      context.images = [{ src: QUICK_SRC }];\n      context.createByService();\n\n      const previewInstance = context.previewRef!.previewInstance;\n      dispatchMouseEvent(previewInstance.imagePreviewWrapper.nativeElement, 'mousedown');\n      await fixture.whenStable();\n      previewInstance['zoom'] = 5;\n      spyOn(previewInstance, 'onZoomOut');\n      spyOn<NzSafeAny>(previewInstance, 'reCenterImage');\n      previewInstance['handleImageScaleWhileZoomingWithMouse'](10);\n      expect(previewInstance.onZoomOut).toHaveBeenCalled();\n      expect(previewInstance['reCenterImage']).not.toHaveBeenCalled();\n\n      previewInstance['zoom'] = 0.5;\n      spyOn(previewInstance, 'onZoomIn');\n      spyOn<NzSafeAny>(previewInstance, 'reCenterImage');\n      previewInstance['handleImageScaleWhileZoomingWithMouse'](-10);\n      expect(previewInstance.onZoomOut).toHaveBeenCalled();\n      expect(previewInstance['reCenterImage']).toHaveBeenCalled();\n    });\n\n    it('should close image preview when escape is pressed', fakeAsync(() => {\n      context.images = [{ src: QUICK_SRC }];\n      context.createByService();\n      const previewInstance = context.previewRef!.previewInstance;\n      tickChanges();\n      spyOn(previewInstance, 'onClose');\n\n      dispatchKeyboardEvent(document, 'keydown', ESCAPE);\n      tick();\n\n      expect(previewInstance.onClose).toHaveBeenCalled();\n    }));\n\n    it('should container click work', async () => {\n      context.firstSrc = QUICK_SRC;\n      await updateNonSignalsInput(fixture);\n\n      const image = debugElement.nativeElement.querySelector('img');\n      image.click();\n      await fixture.whenStable();\n\n      getPreviewWrapElement()!.click();\n\n      // mock animationend event\n      dispatchEvent(getPreviewRootElement(), new AnimationEvent('animationend', { animationName: 'antFadeOut' }));\n      await fixture.whenStable();\n      expect(context.previewRef?.previewInstance).toBeFalsy();\n    });\n\n    it('should preview group work', async () => {\n      context.firstSrc = SRC;\n      context.secondSrc = QUICK_SRC;\n      await updateNonSignalsInput(fixture);\n\n      const images = debugElement.nativeElement.querySelectorAll('img');\n      images[0].click();\n      await fixture.whenStable();\n\n      previewElement = getPreviewRootElement();\n      const left = previewElement!.querySelector('.ant-image-preview-switch-left')!;\n      const right = previewElement!.querySelector('.ant-image-preview-switch-right')!;\n      expect(left).toBeTruthy();\n      expect(right).toBeTruthy();\n      expect(left.classList.contains('ant-image-preview-switch-left-disabled')).toBeTrue();\n\n      dispatchFakeEvent(right, 'click');\n      await fixture.whenStable();\n\n      let previewImage = getPreviewImageElement();\n      expect(previewImage.getAttribute('src')).toContain(QUICK_SRC);\n      expect(right.classList.contains('ant-image-preview-switch-right-disabled')).toBeTrue();\n\n      dispatchFakeEvent(left, 'click');\n      await fixture.whenStable();\n      previewImage = getPreviewImageElement();\n      expect(previewImage.getAttribute('src')).toContain(SRC);\n    });\n  });\n\n  describe('Service', () => {\n    it('should switchTo, next, prev work', async () => {\n      const images = [\n        {\n          src: 'https://img.alicdn.com/tfs/TB1g.mWZAL0gK0jSZFtXXXQCXXa-200-200.svg',\n          width: '200px',\n          height: '200px',\n          alt: 'ng-zorro'\n        },\n        {\n          src: 'https://img.alicdn.com/tfs/TB1Z0PywTtYBeNjy1XdXXXXyVXa-186-200.svg',\n          width: '200px',\n          height: '200px',\n          alt: 'angular'\n        }\n      ];\n      context.images = images;\n      context.createByService();\n      context.previewRef?.switchTo(1);\n      await fixture.whenStable();\n\n      previewElement = getPreviewRootElement();\n      let previewImageElement = getPreviewImageElement();\n      expect(previewImageElement.src).toContain(images[1].src);\n\n      context.previewRef?.next();\n      await fixture.whenStable();\n      previewImageElement = getPreviewImageElement();\n      expect(previewImageElement.src).toContain(images[1].src);\n\n      context.previewRef?.prev();\n      await fixture.whenStable();\n      previewImageElement = getPreviewImageElement();\n      expect(previewImageElement.src).toContain(images[0].src);\n\n      context.previewRef?.next();\n      await fixture.whenStable();\n      previewImageElement = getPreviewImageElement();\n      expect(previewImageElement.src).toContain(images[1].src);\n\n      dispatchKeyboardEvent(overlayContainerElement, 'keydown', RIGHT_ARROW);\n      await fixture.whenStable();\n      previewImageElement = getPreviewImageElement();\n      expect(previewImageElement.src).toContain(images[1].src);\n\n      dispatchKeyboardEvent(overlayContainerElement, 'keydown', LEFT_ARROW);\n      await fixture.whenStable();\n      previewImageElement = getPreviewImageElement();\n      expect(previewImageElement.src).toContain(images[0].src);\n\n      dispatchKeyboardEvent(overlayContainerElement, 'keydown', RIGHT_ARROW);\n      await fixture.whenStable();\n      previewImageElement = getPreviewImageElement();\n      expect(previewImageElement.src).toContain(images[1].src);\n    });\n  });\n\n  describe('Drag', () => {\n    // depends on NgZone.runOutsideAngular, keep using `fakeAsync` here\n    it('should drag released work', fakeAsync(() => {\n      context.images = [{ src: QUICK_SRC }];\n      context.createByService();\n      const previewInstance = context.previewRef!.previewInstance;\n      tickChanges();\n      previewInstance.imagePreviewWrapper.nativeElement.dispatchEvent(new MouseEvent('mousedown'));\n      expect(previewInstance.isDragging()).toEqual(true);\n      spyOn(previewInstance, 'onDragEnd').and.callFake(function () {\n        return true;\n      });\n      expect(previewInstance.position).toEqual({ x: 0, y: 0 });\n    }));\n\n    it('should onDragEnd be called after drag is ended', async () => {\n      context.images = [{ src: QUICK_SRC }];\n      context.createByService();\n      const previewInstance = context.previewRef!.previewInstance;\n      previewInstance.imagePreviewWrapper.nativeElement.dispatchEvent(new MouseEvent('mousedown'));\n      await fixture.whenStable();\n      spyOn(previewInstance, 'onDragEnd').and.callFake(function () {\n        return true;\n      });\n      const e: NzSafeAny = {};\n      previewInstance.onDragEnd(e);\n      expect(previewInstance['onDragEnd']).toHaveBeenCalled();\n    });\n\n    it('should zoom to center when zoom is <= 1', async () => {\n      context.images = [{ src: QUICK_SRC }];\n      context.createByService();\n      const previewInstance = context.previewRef!.previewInstance;\n      spyOn<NzSafeAny>(previewInstance, 'reCenterImage');\n      await fixture.whenStable();\n\n      context.zoomStep = 0.25;\n      await updateNonSignalsInput(fixture);\n\n      (previewInstance as NzSafeAny).zoom = 1.1;\n      previewInstance.onZoomOut();\n      await fixture.whenStable();\n      expect(previewInstance['reCenterImage']).toHaveBeenCalled();\n    });\n\n    it('should position calculate correct', () => {\n      let params = {\n        width: 200,\n        height: 200,\n        top: 0,\n        left: 0,\n        clientWidth: 1080,\n        clientHeight: 768\n      };\n      let pos = getFitContentPosition(params);\n      expect(pos.x).toBe(0);\n      expect(pos.y).toBe(0);\n\n      params = {\n        width: 2000,\n        height: 1000,\n        top: 0,\n        left: 0,\n        clientWidth: 1080,\n        clientHeight: 768\n      };\n      pos = getFitContentPosition(params);\n      expect(pos.x).toBeNull();\n      expect(pos.y).toBeNull();\n\n      params = {\n        width: 2000,\n        height: 1000,\n        top: 100,\n        left: 100,\n        clientWidth: 1080,\n        clientHeight: 768\n      };\n      pos = getFitContentPosition(params);\n      expect(pos.x).toBe(460);\n      expect(pos.y).toBe(116);\n\n      params = {\n        width: 2000,\n        height: 1000,\n        top: -200,\n        left: -200,\n        clientWidth: 1080,\n        clientHeight: 768\n      };\n      pos = getFitContentPosition(params);\n      expect(pos.x).toBeNull();\n      expect(pos.y).toBeNull();\n\n      params = {\n        width: 1000,\n        height: 500,\n        top: -200,\n        left: -200,\n        clientWidth: 1080,\n        clientHeight: 768\n      };\n      pos = getFitContentPosition(params);\n      expect(pos.x).toBe(0);\n      expect(pos.y).toBe(0);\n\n      params = {\n        width: 1200,\n        height: 600,\n        top: -200,\n        left: -200,\n        clientWidth: 1080,\n        clientHeight: 768\n      };\n\n      pos = getFitContentPosition(params);\n      expect(pos.x).toBe(-60);\n      expect(pos.y).toBe(-84);\n\n      params = {\n        width: 1000,\n        height: 900,\n        top: -200,\n        left: -200,\n        clientWidth: 1080,\n        clientHeight: 768\n      };\n\n      pos = getFitContentPosition(params);\n      expect(pos.x).toBe(-40);\n      expect(pos.y).toBe(-66);\n    });\n  });\n\n  describe('Zoom with mouse', () => {\n    it('should call proper methods', async () => {\n      context.images = [{ src: QUICK_SRC }];\n      context.createByService();\n      const previewInstance = context.previewRef!.previewInstance;\n      await fixture.whenStable();\n\n      const e = jasmine.createSpyObj('e', ['preventDefault', 'stopPropagation']);\n      spyOn<NzSafeAny>(previewInstance, 'handlerImageTransformationWhileZoomingWithMouse');\n      spyOn<NzSafeAny>(previewInstance, 'handleImageScaleWhileZoomingWithMouse');\n      spyOn<NzSafeAny>(previewInstance, 'updatePreviewImageWrapperTransform');\n      spyOn<NzSafeAny>(previewInstance, 'updatePreviewImageTransform');\n      spyOn<NzSafeAny>(previewInstance, 'markForCheck');\n      previewInstance.wheelZoomEventHandler(e);\n      expect(e.preventDefault).toHaveBeenCalled();\n      expect(e.stopPropagation).toHaveBeenCalled();\n      expect(previewInstance['handlerImageTransformationWhileZoomingWithMouse']).toHaveBeenCalled();\n      expect(previewInstance['handleImageScaleWhileZoomingWithMouse']).toHaveBeenCalled();\n      expect(previewInstance['updatePreviewImageWrapperTransform']).toHaveBeenCalled();\n      expect(previewInstance['updatePreviewImageTransform']).toHaveBeenCalled();\n      expect(previewInstance['markForCheck']).toHaveBeenCalled();\n    });\n  });\n});\n\n@Component({\n  selector: 'test-image-basic',\n  imports: [NzImageModule],\n  template: `<img alt=\"\" nz-image [nzSrc]=\"src\" [nzPlaceholder]=\"placeholder\" />`\n})\nexport class TestImageBasicComponent {\n  @ViewChild(NzImageDirective) nzImage!: NzImageDirective;\n  src = '';\n  placeholder: string | null = '';\n}\n\n@Component({\n  selector: 'test-image-placeholder',\n  imports: [NzImageModule],\n  template: `<img alt=\"\" nz-image [nzSrc]=\"src\" [nzPlaceholder]=\"placeholder\" [nzDisablePreview]=\"disablePreview\" />`\n})\nexport class TestImagePlaceholderComponent {\n  @ViewChild(NzImageDirective) nzImage!: NzImageDirective;\n  src = '';\n  placeholder = '';\n  disablePreview = true;\n}\n\n@Component({\n  selector: 'test-image-fallback',\n  imports: [NzImageModule],\n  template: `<img alt=\"\" nz-image [nzSrc]=\"src\" [nzFallback]=\"fallback\" />`\n})\nexport class TestImageFallbackComponent {\n  @ViewChild(NzImageDirective) image!: NzImageDirective;\n  src = '';\n  fallback = '';\n}\n\n@Component({\n  selector: 'test-image-preview-group',\n  imports: [NzImageModule],\n  template: `\n    <nz-image-group [nzScaleStep]=\"groupZoomStep\">\n      <img alt=\"\" nz-image [nzSrc]=\"firstSrc\" [nzDisablePreview]=\"disablePreview\" />\n      <img alt=\"\" nz-image [nzSrc]=\"secondSrc\" [nzDisablePreview]=\"disablePreview\" [nzScaleStep]=\"zoomStep\" />\n    </nz-image-group>\n    <img alt=\"\" nz-image [nzSrc]=\"firstSrc\" [nzDisablePreview]=\"disablePreview\" [nzScaleStep]=\"zoomStep\" />\n    <img alt=\"\" nz-image [nzSrc]=\"firstSrc\" [nzDisablePreview]=\"disablePreview\" />\n  `\n})\nexport class TestImagePreviewGroupComponent {\n  disablePreview = false;\n  firstSrc = '';\n  secondSrc = '';\n  previewRef: NzImagePreviewRef | null = null;\n  images: NzImage[] = [];\n  zoomStep: number | null = null;\n  groupZoomStep: number | null = null;\n\n  @ViewChild(NzImageGroupComponent) nzImageGroup!: NzImageGroupComponent;\n  @ViewChild(NzImageDirective) nzImage!: NzImageDirective;\n\n  constructor(private nzImageService: NzImageService) {}\n\n  createByService(): void {\n    this.previewRef = this.nzImageService.preview(this.images, { nzZoom: 1.5, nzRotate: 0 });\n  }\n\n  triggerPreview(): void {\n    this.nzImage.getElement().nativeElement.click();\n  }\n}\n"
  },
  {
    "path": "components/image/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/image/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/image/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './image.directive';\nexport * from './image.service';\nexport * from './image-config';\nexport * from './image-group.component';\nexport * from './image-preview.component';\nexport * from './image-preview-options';\nexport * from './image-preview-ref';\nexport * from './image.module';\nexport * from './utils';\n"
  },
  {
    "path": "components/image/style/animation.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/core/motion/fade';\n\n.fade-motion('image-preview-fade', linear);\n"
  },
  {
    "path": "components/image/style/entry.less",
    "content": "@import './index.less';\n@import './animation.less';\n@import './patch.less';"
  },
  {
    "path": "components/image/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@image-prefix-cls: ~'@{ant-prefix}-image';\n@image-preview-prefix-cls: ~'@{image-prefix-cls}-preview';\n\n.@{image-prefix-cls} {\n  position: relative;\n  display: inline-block;\n\n  &-img {\n    width: 100%;\n    height: auto;\n    vertical-align: middle;\n\n    &-placeholder {\n      background-color: @image-bg;\n      background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTQuNSAyLjVoLTEzQS41LjUgMCAwIDAgMSAzdjEwYS41LjUgMCAwIDAgLjUuNWgxM2EuNS41IDAgMCAwIC41LS41VjNhLjUuNSAwIDAgMC0uNS0uNXpNNS4yODEgNC43NWExIDEgMCAwIDEgMCAyIDEgMSAwIDAgMSAwLTJ6bTguMDMgNi44M2EuMTI3LjEyNyAwIDAgMS0uMDgxLjAzSDIuNzY5YS4xMjUuMTI1IDAgMCAxLS4wOTYtLjIwN2wyLjY2MS0zLjE1NmEuMTI2LjEyNiAwIDAgMSAuMTc3LS4wMTZsLjAxNi4wMTZMNy4wOCAxMC4wOWwyLjQ3LTIuOTNhLjEyNi4xMjYgMCAwIDEgLjE3Ny0uMDE2bC4wMTUuMDE2IDMuNTg4IDQuMjQ0YS4xMjcuMTI3IDAgMCAxLS4wMi4xNzV6IiBmaWxsPSIjOEM4QzhDIiBmaWxsLXJ1bGU9Im5vbnplcm8iLz48L3N2Zz4=');\n      background-repeat: no-repeat;\n      background-position: center center;\n      background-size: 30%;\n    }\n  }\n\n  &-mask {\n    position: absolute;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    color: @text-color-inverse;\n    background: fade(@black, 50%);\n    cursor: pointer;\n    opacity: 0;\n    transition: opacity @animation-duration-slow;\n\n    &-info {\n      padding: 0 @padding-xss;\n      overflow: hidden;\n      white-space: nowrap;\n      text-overflow: ellipsis;\n      .@{iconfont-css-prefix} {\n        margin-inline-end: @margin-xss;\n      }\n    }\n\n    &:hover {\n      opacity: 1;\n    }\n  }\n\n  &-placeholder {\n    .box();\n  }\n\n  &-preview {\n    .modal-mask();\n\n    height: 100%;\n    text-align: center;\n\n    &-body {\n      .box();\n      overflow: hidden;\n    }\n\n    &-img {\n      max-width: 100%;\n      max-height: 100%;\n      vertical-align: middle;\n      transform: scale3d(1, 1, 1);\n      cursor: grab;\n      transition: transform 0.3s @ease-out 0s;\n      user-select: none;\n      pointer-events: auto;\n\n      &-wrapper {\n        .box();\n        transition: transform 0.3s @ease-out 0s;\n\n        &::before {\n          display: inline-block;\n          width: 1px;\n          height: 50%;\n          margin-right: -1px;\n          content: '';\n        }\n      }\n    }\n\n    &-moving {\n      .@{image-prefix-cls}-preview-img {\n        cursor: grabbing;\n\n        &-wrapper {\n          transition-duration: 0s;\n        }\n      }\n    }\n\n    &-wrap {\n      z-index: @zindex-image;\n    }\n\n    &-operations-wrapper {\n      position: fixed;\n      top: 0;\n      right: 0;\n      z-index: @zindex-image + 1;\n      width: 100%;\n    }\n\n    &-operations {\n      .reset-component();\n      display: flex;\n      flex-direction: row-reverse;\n      align-items: center;\n      color: @image-preview-operation-color;\n      list-style: none;\n      background: fade(@modal-mask-bg, 10%);\n      pointer-events: auto;\n\n      &-operation {\n        margin-left: @control-padding-horizontal;\n        padding: @control-padding-horizontal;\n        cursor: pointer;\n        transition: all 0.3s;\n\n        &:hover {\n          background: fade(@modal-mask-bg, 20%);\n        }\n\n        &-disabled {\n          color: @image-preview-operation-disabled-color;\n          pointer-events: none;\n        }\n\n        &:last-of-type {\n          margin-left: 0;\n        }\n      }\n\n      &-progress {\n        position: absolute;\n        left: 50%;\n        transform: translateX(-50%);\n      }\n\n      &-icon {\n        font-size: @image-preview-operation-size;\n      }\n    }\n\n    &-switch-left,\n    &-switch-right {\n      position: fixed;\n      top: 50%;\n      right: 8px;\n      z-index: @zindex-image + 1;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      width: 44px;\n      height: 44px;\n      color: @image-preview-operation-color;\n      background: fade(@modal-mask-bg, 10%);\n      border-radius: 50%;\n      transform: translateY(-50%);\n      cursor: pointer;\n      transition: all 0.3s;\n      pointer-events: auto;\n\n      &:hover {\n        background: fade(@modal-mask-bg, 20%);\n      }\n\n      &-disabled,\n      &-disabled:hover {\n        color: @image-preview-operation-disabled-color;\n        background: fade(@modal-mask-bg, 10%);\n        cursor: not-allowed;\n        > .@{iconfont-css-prefix} {\n          cursor: not-allowed;\n        }\n      }\n\n      > .@{iconfont-css-prefix} {\n        font-size: 18px;\n      }\n    }\n\n    &-switch-left {\n      left: 8px;\n    }\n\n    &-switch-right {\n      right: 8px;\n    }\n\n    &-focus-trap {\n      width: 0;\n      height: 0;\n      overflow: hidden;\n      outline: none;\n    }\n  }\n}\n"
  },
  {
    "path": "components/image/style/patch.less",
    "content": "@image-prefix-cls: ~'@{ant-prefix}-image';\n\n.cdk-overlay-backdrop {\n  &.ant-image-preview-mask {\n    opacity: 1;\n  }\n}\n\n.cdk-global-overlay-wrapper[dir='rtl'] {\n  .@{image-prefix-cls} {\n    &-preview {\n      &-switch-left {\n        right: 10px;\n        left: unset;\n\n        rotate: 180deg;\n      }\n\n      &-switch-right {\n        right: unset;\n        left: 10px;\n\n        rotate: 180deg;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/image/utils.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\n/**\n * fit content details: https://github.com/NG-ZORRO/ng-zorro-antd/pull/6154#issuecomment-745025554\n *\n * calc position x,y point\n *\n * CASE (width <= clientWidth && height <= clientHeight):\n *\n * ------------- clientWidth -------------\n * |                                     |\n * |        ------ width ------          |\n * |        |                 |          |\n * |        |                 |          |\n * client   height            |          |\n * Height   |                 |          |\n * |        |                 |          |\n * |        -------------------          |\n * |                                     |\n * |                                     |\n * ---------------------------------------\n * fixedPosition = { x: 0, y: 0 }\n *\n *\n *\n * CASE (width > clientWidth || height > clientHeight):\n *\n * ------------- clientWidth -------------\n * |        |                            |\n * |        top                          |\n * |        |                            |\n * |--left--|--------------- width -----------------\n * |        |                                      |\n * client   |                                      |\n * Height   |                                      |\n * |        |                                      |\n * |        |                                      |\n * |        height                                 |\n * |        |                                      |\n * ---------|                                      |\n *          |                                      |\n *          |                                      |\n *          |                                      |\n *          ----------------------------------------\n *\n *\n * - left || top > 0\n *   left -> 0 || top -> 0\n *\n * - (left + width) < clientWidth || (top + height) < clientHeight\n * - left | top + width | height < clientWidth | clientHeight -> Back left | top + width | height === clientWidth | clientHeight\n *\n * DEFAULT:\n * - hold position\n *\n */\nexport function getFitContentPosition(params: {\n  width: number;\n  height: number;\n  left: number;\n  top: number;\n  clientWidth: number;\n  clientHeight: number;\n}): { x?: number; y?: number } {\n  let fixPos = {};\n\n  if (params.width <= params.clientWidth && params.height <= params.clientHeight) {\n    fixPos = {\n      x: 0,\n      y: 0\n    };\n  }\n\n  if (params.width > params.clientWidth || params.height > params.clientHeight) {\n    fixPos = {\n      x: fitPoint(params.left, params.width, params.clientWidth),\n      y: fitPoint(params.top, params.height, params.clientHeight)\n    };\n  }\n\n  return fixPos;\n}\n\nexport function getOffset(node: HTMLElement): { left: number; top: number } {\n  const box = node.getBoundingClientRect();\n  const docElem = document.documentElement;\n\n  // use docElem.scrollLeft to support IE\n  return {\n    left: box.left + (window.pageXOffset || docElem.scrollLeft) - (docElem.clientLeft || document.body.clientLeft || 0),\n    top: box.top + (window.pageYOffset || docElem.scrollTop) - (docElem.clientTop || document.body.clientTop || 0)\n  };\n}\n\nexport function getClientSize(): { width: number; height: number } {\n  const width = document.documentElement.clientWidth;\n  const height = window.innerHeight || document.documentElement.clientHeight;\n  return {\n    width,\n    height\n  };\n}\n\nfunction fitPoint(start: number, size: number, clientSize: number): number | null {\n  const startAddSize = start + size;\n  const offsetStart = (size - clientSize) / 2;\n  let distance: number | null = null;\n\n  if (size > clientSize) {\n    if (start > 0) {\n      distance = offsetStart;\n    }\n    if (start < 0 && startAddSize < clientSize) {\n      distance = -offsetStart;\n    }\n  } else {\n    if (start < 0 || startAddSize > clientSize) {\n      distance = start < 0 ? offsetStart : -offsetStart;\n    }\n  }\n\n  return distance;\n}\n"
  },
  {
    "path": "components/input/autosize.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Platform } from '@angular/cdk/platform';\nimport { AfterViewInit, DestroyRef, Directive, DoCheck, ElementRef, inject, Input, NgZone } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { NzResizeService } from 'ng-zorro-antd/core/services';\n\n/**\n * @deprecated Will be removed in v22.\n */\nexport interface AutoSizeType {\n  minRows?: number;\n  maxRows?: number;\n}\n\n/**\n * @deprecated Will be removed in v22. It is recommended to use {@link CdkTextareaAutosize} instead.\n */\n@Directive({\n  selector: 'textarea[nzAutosize]',\n  exportAs: 'nzAutosize',\n  host: {\n    // Textarea elements that have the directive applied should have a single row by default.\n    // Browsers normally show two rows by default and therefore this limits the minRows binding.\n    rows: '1',\n    '(input)': 'noopInputHandler()'\n  }\n})\nexport class NzAutosizeDirective implements AfterViewInit, DoCheck {\n  private ngZone = inject(NgZone);\n  private platform = inject(Platform);\n  private destroyRef = inject(DestroyRef);\n  private resizeService = inject(NzResizeService);\n  private el: HTMLTextAreaElement | HTMLInputElement = inject(ElementRef).nativeElement;\n\n  private autosize: boolean = false;\n  private cachedLineHeight!: number;\n  private previousValue!: string;\n  private previousMinRows: number | undefined;\n  private minRows: number | undefined;\n  private maxRows: number | undefined;\n  private maxHeight: number | null = null;\n  private minHeight: number | null = null;\n  private inputGap = 10;\n  private destroyed = false;\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      this.destroyed = true;\n    });\n  }\n\n  @Input()\n  set nzAutosize(value: string | boolean | AutoSizeType) {\n    const isAutoSizeType = (data: string | boolean | AutoSizeType): data is AutoSizeType =>\n      typeof data !== 'string' && typeof data !== 'boolean' && (!!data.maxRows || !!data.minRows);\n    if (typeof value === 'string' || value === true) {\n      this.autosize = true;\n    } else if (isAutoSizeType(value)) {\n      this.autosize = true;\n      this.minRows = value.minRows;\n      this.maxRows = value.maxRows;\n      this.maxHeight = this.setMaxHeight();\n      this.minHeight = this.setMinHeight();\n    }\n  }\n\n  resizeToFitContent(force: boolean = false): void {\n    this.cacheTextareaLineHeight();\n\n    // If we haven't determined the line-height yet, we know we're still hidden and there's no point\n    // in checking the height of the textarea.\n    if (!this.cachedLineHeight) {\n      return;\n    }\n\n    const textarea = this.el as HTMLTextAreaElement;\n    const value = textarea.value;\n\n    // Only resize if the value or minRows have changed since these calculations can be expensive.\n    if (!force && this.minRows === this.previousMinRows && value === this.previousValue) {\n      return;\n    }\n    const placeholderText = textarea.placeholder;\n\n    // Reset the textarea height to auto in order to shrink back to its default size.\n    // Also temporarily force overflow:hidden, so scroll bars do not interfere with calculations.\n    // Long placeholders that are wider than the textarea width may lead to a bigger scrollHeight\n    // value. To ensure that the scrollHeight is not bigger than the content, the placeholders\n    // need to be removed temporarily.\n    textarea.classList.add('nz-textarea-autosize-measuring');\n    textarea.placeholder = '';\n    let height =\n      Math.round((textarea.scrollHeight - this.inputGap) / this.cachedLineHeight) * this.cachedLineHeight +\n      this.inputGap;\n    if (this.maxHeight !== null && height > this.maxHeight) {\n      height = this.maxHeight!;\n    }\n    if (this.minHeight !== null && height < this.minHeight) {\n      height = this.minHeight!;\n    }\n    // Use the scrollHeight to know how large the textarea *would* be if fit its entire value.\n    textarea.style.height = `${height}px`;\n    textarea.classList.remove('nz-textarea-autosize-measuring');\n    textarea.placeholder = placeholderText;\n\n    // On Firefox resizing the textarea will prevent it from scrolling to the caret position.\n    // We need to re-set the selection in order for it to scroll to the proper position.\n    if (typeof requestAnimationFrame !== 'undefined') {\n      this.ngZone.runOutsideAngular(() =>\n        requestAnimationFrame(() => {\n          const { selectionStart, selectionEnd } = textarea;\n\n          // IE will throw an \"Unspecified error\" if we try to set the selection range after the\n          // element has been removed from the DOM. Assert that the directive hasn't been destroyed\n          // between the time we requested the animation frame and when it was executed.\n          // Also note that we have to assert that the textarea is focused before we set the\n          // selection range. Setting the selection range on a non-focused textarea will cause\n          // it to receive focus on IE and Edge.\n          if (!this.destroyed && document.activeElement === textarea) {\n            textarea.setSelectionRange(selectionStart, selectionEnd);\n          }\n        })\n      );\n    }\n\n    this.previousValue = value;\n    this.previousMinRows = this.minRows;\n  }\n\n  private cacheTextareaLineHeight(): void {\n    if (this.cachedLineHeight >= 0 || !this.el.parentNode) {\n      return;\n    }\n\n    // Use a clone element because we have to override some styles.\n    const textareaClone = this.el.cloneNode(false) as HTMLTextAreaElement;\n    textareaClone.rows = 1;\n\n    // Use `position: absolute` so that this doesn't cause a browser layout and use\n    // `visibility: hidden` so that nothing is rendered. Clear any other styles that\n    // would affect the height.\n    textareaClone.style.position = 'absolute';\n    textareaClone.style.visibility = 'hidden';\n    textareaClone.style.border = 'none';\n    textareaClone.style.padding = '0';\n    textareaClone.style.height = '';\n    textareaClone.style.minHeight = '';\n    textareaClone.style.maxHeight = '';\n\n    // In Firefox it happens that textarea elements are always bigger than the specified amount\n    // of rows. This is because Firefox tries to add extra space for the horizontal scrollbar.\n    // As a workaround that removes the extra space for the scrollbar, we can just set overflow\n    // to hidden. This ensures that there is no invalid calculation of the line height.\n    // See Firefox bug report: https://bugzilla.mozilla.org/show_bug.cgi?id=33654\n    textareaClone.style.overflow = 'hidden';\n\n    this.el.parentNode!.appendChild(textareaClone);\n    this.cachedLineHeight = textareaClone.clientHeight - this.inputGap;\n    this.el.parentNode!.removeChild(textareaClone);\n\n    // Min and max heights have to be re-calculated if the cached line height changes\n    this.maxHeight = this.setMaxHeight();\n    this.minHeight = this.setMinHeight();\n  }\n\n  setMinHeight(): number | null {\n    const minHeight =\n      this.minRows && this.cachedLineHeight ? this.minRows * this.cachedLineHeight + this.inputGap : null;\n\n    if (minHeight !== null) {\n      this.el.style.minHeight = `${minHeight}px`;\n    }\n    return minHeight;\n  }\n\n  setMaxHeight(): number | null {\n    const maxHeight =\n      this.maxRows && this.cachedLineHeight ? this.maxRows * this.cachedLineHeight + this.inputGap : null;\n    if (maxHeight !== null) {\n      this.el.style.maxHeight = `${maxHeight}px`;\n    }\n    return maxHeight;\n  }\n\n  noopInputHandler(): void {\n    // no-op handler that ensures we're running change detection on input events.\n  }\n\n  ngAfterViewInit(): void {\n    if (this.autosize && this.platform.isBrowser) {\n      this.resizeToFitContent();\n      this.resizeService\n        .connect()\n        .pipe(takeUntilDestroyed(this.destroyRef))\n        .subscribe(() => this.resizeToFitContent(true));\n    }\n  }\n\n  ngDoCheck(): void {\n    if (this.autosize && this.platform.isBrowser) {\n      this.resizeToFitContent();\n    }\n  }\n}\n"
  },
  {
    "path": "components/input/autosize.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, NgZone, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing';\nimport { FormsModule } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\n\nimport { dispatchFakeEvent, MockNgZone } from 'ng-zorro-antd/core/testing';\n\nimport { NzAutosizeDirective } from './autosize.directive';\nimport { NzInputModule } from './input.module';\n\ndescribe('autoresize', () => {\n  let zone: MockNgZone;\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [\n        // todo: use zoneless\n        provideZoneChangeDetection(),\n        {\n          provide: NgZone,\n          useFactory: () => {\n            zone = new MockNgZone();\n            return zone;\n          }\n        }\n      ]\n    });\n  });\n\n  describe('single input', () => {\n    describe('textarea autosize string', () => {\n      let fixture: ComponentFixture<NzTestInputWithTextAreaAutoSizeStringComponent>;\n      let testComponent: NzTestInputWithTextAreaAutoSizeStringComponent;\n      let textarea: HTMLTextAreaElement;\n      let autosize: NzAutosizeDirective;\n\n      beforeEach(() => {\n        fixture = TestBed.createComponent(NzTestInputWithTextAreaAutoSizeStringComponent);\n        testComponent = fixture.debugElement.componentInstance;\n        fixture.detectChanges();\n        textarea = fixture.debugElement.query(By.directive(NzAutosizeDirective)).nativeElement;\n        autosize = fixture.debugElement.query(By.directive(NzAutosizeDirective)).injector.get(NzAutosizeDirective);\n      });\n\n      it('should resize the textarea based on its ngModel', fakeAsync(() => {\n        let previousHeight = textarea.clientHeight;\n        testComponent.value = `\n    Once upon a midnight dreary, while I pondered, weak and weary,\n    Over many a quaint and curious volume of forgotten lore—\n        While I nodded, nearly napping, suddenly there came a tapping,\n    As of some one gently rapping, rapping at my chamber door.\n    “’Tis some visitor,” I muttered, “tapping at my chamber door—\n                Only this and nothing more.”`;\n        flush();\n        // Manually call resizeTextArea instead of faking an `input` event.\n        fixture.detectChanges();\n        flush();\n        autosize.resizeToFitContent();\n        zone.simulateZoneExit();\n        fixture.detectChanges();\n        expect(textarea.clientHeight)\n          .withContext('Expected textarea to have grown with added content.')\n          .toBeGreaterThan(previousHeight);\n        expect(textarea.clientHeight)\n          .withContext('Expected textarea height to match its scrollHeight')\n          .toBe(textarea.scrollHeight);\n\n        previousHeight = textarea.clientHeight;\n        testComponent.value += `\n        Ah, distinctly I remember it was in the bleak December;\n    And each separate dying ember wrought its ghost upon the floor.\n        Eagerly I wished the morrow;—vainly I had sought to borrow\n        From my books surcease of sorrow—sorrow for the lost Lenore—\n    For the rare and radiant maiden whom the angels name Lenore—\n                Nameless here for evermore.`;\n        fixture.detectChanges();\n        flush();\n        fixture.detectChanges();\n        autosize.resizeToFitContent(true);\n        zone.simulateZoneExit();\n        fixture.detectChanges();\n        expect(textarea.clientHeight)\n          .withContext('Expected textarea to have grown with added content.')\n          .toBeGreaterThan(previousHeight);\n        expect(textarea.clientHeight)\n          .withContext('Expected textarea height to match its scrollHeight')\n          .toBe(textarea.scrollHeight);\n      }));\n\n      it('should trigger a resize when the window is resized', fakeAsync(() => {\n        spyOn(autosize, 'resizeToFitContent');\n\n        dispatchFakeEvent(window, 'resize');\n        tick(16);\n\n        expect(autosize.resizeToFitContent).toHaveBeenCalled();\n      }));\n    });\n\n    describe('textarea autosize object', () => {\n      let fixture: ComponentFixture<NzTestInputWithTextAreaAutoSizeObjectComponent>;\n      let testComponent: NzTestInputWithTextAreaAutoSizeObjectComponent;\n      let textarea: HTMLTextAreaElement;\n      let autosize: NzAutosizeDirective;\n\n      beforeEach(() => {\n        fixture = TestBed.createComponent(NzTestInputWithTextAreaAutoSizeObjectComponent);\n        testComponent = fixture.debugElement.componentInstance;\n        fixture.detectChanges();\n        textarea = fixture.debugElement.query(By.directive(NzAutosizeDirective)).nativeElement;\n        autosize = fixture.debugElement.query(By.directive(NzAutosizeDirective)).injector.get(NzAutosizeDirective);\n      });\n\n      it('should set a min-height based on minRows', fakeAsync(() => {\n        autosize.resizeToFitContent(true);\n        fixture.detectChanges();\n        flush();\n        fixture.detectChanges();\n        const previousMinHeight = parseInt(textarea.style.minHeight as string, 10);\n        testComponent.minRows = 6;\n        fixture.detectChanges();\n        flush();\n        fixture.detectChanges();\n        autosize.resizeToFitContent(true);\n        expect(parseInt(textarea.style.minHeight as string, 10))\n          .withContext('Expected increased min-height with minRows increase.')\n          .toBeGreaterThan(previousMinHeight);\n      }));\n\n      it('should set a max-height based on maxRows', fakeAsync(() => {\n        autosize.resizeToFitContent(true);\n        fixture.detectChanges();\n        flush();\n        fixture.detectChanges();\n        const previousMaxHeight = parseInt(textarea.style.maxHeight as string, 10);\n        testComponent.maxRows = 6;\n        fixture.detectChanges();\n        flush();\n        fixture.detectChanges();\n        autosize.resizeToFitContent(true);\n        expect(parseInt(textarea.style.maxHeight as string, 10))\n          .withContext('Expected increased max-height with maxRows increase.')\n          .toBeGreaterThan(previousMaxHeight);\n      }));\n    });\n\n    describe('textarea autosize boolean', () => {\n      let fixture: ComponentFixture<NzTestInputWithTextAreaAutoSizeBooleanComponent>;\n      let testComponent: NzTestInputWithTextAreaAutoSizeBooleanComponent;\n      let textarea: HTMLTextAreaElement;\n      let autosize: NzAutosizeDirective;\n\n      beforeEach(() => {\n        fixture = TestBed.createComponent(NzTestInputWithTextAreaAutoSizeBooleanComponent);\n        testComponent = fixture.debugElement.componentInstance;\n        fixture.detectChanges();\n        textarea = fixture.debugElement.query(By.directive(NzAutosizeDirective)).nativeElement;\n        autosize = fixture.debugElement.query(By.directive(NzAutosizeDirective)).injector.get(NzAutosizeDirective);\n      });\n\n      it('should resize the textarea based on its ngModel', fakeAsync(() => {\n        let previousHeight = textarea.clientHeight;\n        testComponent.value = `\n    Once upon a midnight dreary, while I pondered, weak and weary,\n    Over many a quaint and curious volume of forgotten lore—\n        While I nodded, nearly napping, suddenly there came a tapping,\n    As of some one gently rapping, rapping at my chamber door.\n    “’Tis some visitor,” I muttered, “tapping at my chamber door—\n                Only this and nothing more.”`;\n        flush();\n        // Manually call resizeTextArea instead of faking an `input` event.\n        fixture.detectChanges();\n        flush();\n        autosize.resizeToFitContent();\n        zone.simulateZoneExit();\n        fixture.detectChanges();\n        expect(textarea.clientHeight)\n          .withContext('Expected textarea to have grown with added content.')\n          .toBeGreaterThan(previousHeight);\n        expect(textarea.clientHeight)\n          .withContext('Expected textarea height to match its scrollHeight')\n          .toBe(textarea.scrollHeight);\n\n        previousHeight = textarea.clientHeight;\n        testComponent.value += `\n        Ah, distinctly I remember it was in the bleak December;\n    And each separate dying ember wrought its ghost upon the floor.\n        Eagerly I wished the morrow;—vainly I had sought to borrow\n        From my books surcease of sorrow—sorrow for the lost Lenore—\n    For the rare and radiant maiden whom the angels name Lenore—\n                Nameless here for evermore.`;\n        fixture.detectChanges();\n        flush();\n        fixture.detectChanges();\n        autosize.resizeToFitContent(true);\n        zone.simulateZoneExit();\n        fixture.detectChanges();\n        expect(textarea.clientHeight)\n          .withContext('Expected textarea to have grown with added content.')\n          .toBeGreaterThan(previousHeight);\n        expect(textarea.clientHeight)\n          .withContext('Expected textarea height to match its scrollHeight')\n          .toBe(textarea.scrollHeight);\n      }));\n\n      it('should trigger a resize when the window is resized', fakeAsync(() => {\n        spyOn(autosize, 'resizeToFitContent');\n\n        dispatchFakeEvent(window, 'resize');\n        tick(16);\n\n        expect(autosize.resizeToFitContent).toHaveBeenCalled();\n      }));\n    });\n  });\n});\n\n@Component({\n  imports: [FormsModule, NzInputModule],\n  template: `<textarea nz-input nzAutosize [ngModel]=\"value\"></textarea>`\n})\nexport class NzTestInputWithTextAreaAutoSizeStringComponent {\n  value = '';\n}\n\n@Component({\n  imports: [FormsModule, NzInputModule],\n  template: `<textarea nz-input ngModel [nzAutosize]=\"{ minRows, maxRows }\"></textarea>`\n})\nexport class NzTestInputWithTextAreaAutoSizeObjectComponent {\n  minRows = 2;\n  maxRows = 2;\n}\n\n@Component({\n  imports: [FormsModule, NzInputModule],\n  template: `<textarea nz-input [nzAutosize]=\"true\" [ngModel]=\"value\"></textarea>`\n})\nexport class NzTestInputWithTextAreaAutoSizeBooleanComponent {\n  value = '';\n}\n"
  },
  {
    "path": "components/input/demo/addon.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 前置/后置标签\n  en-US: Pre / Post tab\n---\n\n## zh-CN\n\n用于配置一些固定组合。\n\n## en-US\n\nUsing pre & post tabs example.\n"
  },
  {
    "path": "components/input/demo/addon.ts",
    "content": "import { Component, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCascaderModule } from 'ng-zorro-antd/cascader';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\n@Component({\n  selector: 'nz-demo-input-addon',\n  imports: [NzInputModule, NzIconModule, NzSelectModule, NzCascaderModule, FormsModule],\n  template: `\n    <nz-input-wrapper nzAddonBefore=\"http://\" nzAddonAfter=\".com\">\n      <input nz-input [(ngModel)]=\"value\" />\n    </nz-input-wrapper>\n    <br />\n    <br />\n    <nz-input-wrapper>\n      <nz-select nzInputAddonBefore ngModel=\"Http://\">\n        <nz-option nzLabel=\"Http://\" nzValue=\"Http://\" />\n        <nz-option nzLabel=\"Https://\" nzValue=\"Https://\" />\n      </nz-select>\n      <input nz-input [(ngModel)]=\"value\" />\n      <nz-select nzInputAddonAfter ngModel=\".com\">\n        <nz-option nzLabel=\".com\" nzValue=\".com\" />\n        <nz-option nzLabel=\".jp\" nzValue=\".jp\" />\n        <nz-option nzLabel=\".cn\" nzValue=\".cn\" />\n        <nz-option nzLabel=\".org\" nzValue=\".org\" />\n      </nz-select>\n    </nz-input-wrapper>\n    <br />\n    <br />\n    <nz-input-wrapper>\n      <input nz-input [(ngModel)]=\"value\" />\n      <nz-icon nzInputAddonBefore nzType=\"setting\" />\n    </nz-input-wrapper>\n    <br />\n    <br />\n    <nz-input-wrapper nzAddonBefore=\"http://\" nzSuffix=\".com\">\n      <input nz-input [(ngModel)]=\"value\" />\n    </nz-input-wrapper>\n    <br />\n    <br />\n    <nz-input-wrapper>\n      <nz-cascader nzInputAddonBefore [nzOptions]=\"[]\" nzPlaceHolder=\"cascader\" [style.width.px]=\"150\" />\n      <input nz-input [(ngModel)]=\"value\" />\n    </nz-input-wrapper>\n  `\n})\nexport class NzDemoInputAddonComponent {\n  readonly value = signal('mysite');\n}\n"
  },
  {
    "path": "components/input/demo/advance-count.md",
    "content": "---\norder: 18\ntitle:\n  zh-CN: 定制计数能力\n  en-US: Custom count logic\n---\n\n## zh-CN\n\n在某些场景下，需要定制计数能力（例如 emoji 长度以 1 计算），可以通过 `nzShowCount` 属性来实现。在该模式下，通过 `nzCount` 属性来超出原生 `maxLength` 的限制。\n\n## en-US\n\nIt is necessary to customize the counting ability in some scenarios (such as emoji length is counted as 1), which can be achieved through the `nzShowCount` attribute. Use `nzCount` attribute exceeds the limit of the native `maxLength`.\n"
  },
  {
    "path": "components/input/demo/advance-count.ts",
    "content": "import { Component, inject } from '@angular/core';\nimport { FormBuilder, ReactiveFormsModule } from '@angular/forms';\n\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-input-advance-count',\n  imports: [ReactiveFormsModule, NzFormModule, NzInputModule],\n  template: `\n    <form nz-form [formGroup]=\"form\" nzLayout=\"vertical\">\n      <nz-form-item>\n        <nz-form-label><h4>ShowCount</h4></nz-form-label>\n        <nz-form-control>\n          <nz-input-wrapper nzAllowClear nzShowCount>\n            <input nz-input formControlName=\"test_0\" />\n          </nz-input-wrapper>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label><h4>Exceed Max</h4></nz-form-label>\n        <nz-form-control>\n          <nz-input-wrapper nzShowCount [nzCount]=\"{ max: 10 }\">\n            <input nz-input formControlName=\"test_1\" />\n          </nz-input-wrapper>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label><h4>Emoji count as length 1</h4></nz-form-label>\n        <nz-form-control>\n          <nz-input-wrapper nzShowCount [nzCount]=\"{ max: 6, strategy: countStrategyFn }\">\n            <input nz-input formControlName=\"test_2\" />\n          </nz-input-wrapper>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label><h4>Not exceed max</h4></nz-form-label>\n        <nz-form-control>\n          <nz-input-wrapper\n            nzShowCount\n            [nzCount]=\"{ max: 10, strategy: countStrategyFn, exceedFormatter: exceedFormatterFn }\"\n          >\n            <input nz-input formControlName=\"test_3\" />\n          </nz-input-wrapper>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label><h4>nz-input-password</h4></nz-form-label>\n        <nz-form-control>\n          <nz-input-password\n            [nzVisibilityToggle]=\"false\"\n            nzShowCount\n            [nzCount]=\"{ max: 20, strategy: countStrategyFn, exceedFormatter: exceedFormatterFn }\"\n          >\n            <input nz-input formControlName=\"test_4\" />\n          </nz-input-password>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item>\n        <nz-form-label><h4>nz-input-search</h4></nz-form-label>\n        <nz-form-control>\n          <nz-input-search nzShowCount [nzCount]=\"{ max: 20, strategy: countStrategyFn }\">\n            <input nz-input formControlName=\"test_5\" />\n          </nz-input-search>\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `\n})\nexport class NzDemoInputAdvanceCountComponent {\n  private fb = inject(FormBuilder);\n  form = this.fb.group({\n    test_0: ['Angular & NG-ZORRO'],\n    test_1: ['Angular & NG-ZORRO'],\n    test_2: ['🔥🔥🔥'],\n    test_3: ['AAA🔥🔥🔥'],\n    test_4: ['BBB'],\n    test_5: ['CCC']\n  });\n\n  countStrategyFn: (v: string) => number = v => runes(v).length;\n  exceedFormatterFn: (cur: string, config: { max: number }) => string = (v, { max }) => {\n    const result = runes(v).slice(0, max).join('');\n    return result;\n  };\n}\n\nfunction runes(str: string): string[] {\n  return [...str];\n}\n"
  },
  {
    "path": "components/input/demo/allow-clear.md",
    "content": "---\norder: 13\nversion: 20.4.0\ntitle:\n  zh-CN: 带移除图标\n  en-US: With clear icon\n---\n\n## zh-CN\n\n带移除图标的输入框，点击图标删除所有内容。\n\n## en-US\n\nInput with clear icon.\n"
  },
  {
    "path": "components/input/demo/allow-clear.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-input-allow-clear',\n  imports: [FormsModule, NzInputModule, NzIconModule],\n  template: `\n    <nz-input-wrapper nzAllowClear>\n      <input nz-input [(ngModel)]=\"inputValue\" placeholder=\"input with clear icon\" />\n    </nz-input-wrapper>\n    <br />\n    <br />\n    <nz-input-wrapper nzAllowClear>\n      <input nz-input [(ngModel)]=\"inputValue\" placeholder=\"input with custom clear icon\" />\n      <nz-icon nzInputClearIcon nzType=\"close\" />\n    </nz-input-wrapper>\n    <br />\n    <br />\n    <nz-input-wrapper nzAllowClear>\n      <textarea nz-input [(ngModel)]=\"textValue\" placeholder=\"textarea with clear icon\"></textarea>\n    </nz-input-wrapper>\n  `\n})\nexport class NzDemoInputAllowClearComponent {\n  inputValue: string | null = null;\n  textValue: string | null = null;\n}\n"
  },
  {
    "path": "components/input/demo/autosize-textarea.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 适应文本高度的文本域\n  en-US: Autosizing the height to fit the content\n---\n\n## zh-CN\n\n使用 `@angular/cdk` 提供的 [`CdkTextareaAutosize`](https://material.angular.dev/cdk/text-field/overview#automatically-resizing-a-lesstextareagreater) 指令实现文本域高度自适应。\n\n## en-US\n\nUse [`CdkTextareaAutosize`](https://material.angular.dev/cdk/text-field/overview#automatically-resizing-a-lesstextareagreater) directive provided by `@angular/cdk` to achieve textarea height adaptation.\n"
  },
  {
    "path": "components/input/demo/autosize-textarea.ts",
    "content": "import { CdkTextareaAutosize } from '@angular/cdk/text-field';\nimport { Component } from '@angular/core';\n\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-input-autosize-textarea',\n  imports: [NzInputModule, CdkTextareaAutosize],\n  template: `\n    <textarea nz-input placeholder=\"Autosize height based on content lines\" cdkTextareaAutosize></textarea>\n    <br />\n    <br />\n    <textarea\n      nz-input\n      placeholder=\"Autosize height with minimum and maximum number of lines\"\n      cdkTextareaAutosize\n      cdkAutosizeMinRows=\"2\"\n      cdkAutosizeMaxRows=\"6\"\n    ></textarea>\n    <br />\n    <br />\n    <textarea\n      nz-input\n      placeholder=\"Controlled autosize\"\n      cdkTextareaAutosize\n      cdkAutosizeMinRows=\"3\"\n      cdkAutosizeMaxRows=\"5\"\n    ></textarea>\n  `\n})\nexport class NzDemoInputAutosizeTextareaComponent {}\n"
  },
  {
    "path": "components/input/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本使用\n  en-US: Basic usage\n---\n\n## zh-CN\n\n基本使用。\n\n## en-US\n\nBasic usage example.\n"
  },
  {
    "path": "components/input/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-input-basic',\n  imports: [FormsModule, NzInputModule],\n  template: ` <input nz-input placeholder=\"Basic usage\" [(ngModel)]=\"value\" /> `\n})\nexport class NzDemoInputBasicComponent {\n  value?: string;\n}\n"
  },
  {
    "path": "components/input/demo/compact.md",
    "content": "---\norder: 4\nversion: 20.4.0\ntitle:\n  zh-CN: 紧凑模式\n  en-US: Compact Style\n---\n\n## zh-CN\n\n使用 `<nz-space-compact>` 创建紧凑模式，更多请查看[文档](/components/space/zh#nz-space-compact)。\n\n## en-US\n\nUse `<nz-space-compact>` create compact style, See the [documentation](/components/space/en#nz-space-compact) for more.\n"
  },
  {
    "path": "components/input/demo/compact.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzSelectModule, NzSelectOptionInterface } from 'ng-zorro-antd/select';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\n\n@Component({\n  selector: 'nz-demo-input-compact',\n  imports: [NzInputModule, NzIconModule, NzSelectModule, NzSpaceModule, NzButtonModule, FormsModule],\n  template: `\n    <nz-space-compact>\n      <input nz-input value=\"26888888\" />\n    </nz-space-compact>\n    <br />\n    <br />\n    <nz-space-compact>\n      <input nz-input value=\"0571\" [style.width.%]=\"20\" />\n      <input nz-input value=\"26888888\" [style.width.%]=\"80\" />\n    </nz-space-compact>\n    <br />\n    <br />\n    <nz-space-compact>\n      <nz-input-search>\n        <span nzInputAddonBefore>https://</span>\n        <input nz-input placeholder=\"input search text\" />\n      </nz-input-search>\n    </nz-space-compact>\n    <br />\n    <br />\n    <nz-space-compact [style.width.%]=\"100\">\n      <input nz-input placeholder=\"Combine input and button\" />\n      <button nz-button nzType=\"primary\">Submit</button>\n    </nz-space-compact>\n    <br />\n    <br />\n    <nz-space-compact>\n      <nz-select ngModel=\"zhejiang\" [nzOptions]=\"options\" />\n      <input nz-input placeholder=\"Xihu District, Hangzhou\" />\n    </nz-space-compact>\n    <br />\n    <br />\n    <nz-space-compact nzSize=\"large\">\n      <nz-input-wrapper>\n        <nz-icon nzInputAddonBefore nzType=\"search\" />\n        <input nz-input placeholder=\"large size\" />\n      </nz-input-wrapper>\n      <input nz-input placeholder=\"another input\" />\n    </nz-space-compact>\n  `\n})\nexport class NzDemoInputCompactComponent {\n  options: NzSelectOptionInterface[] = [\n    {\n      value: 'zhejiang',\n      label: 'Zhejiang'\n    },\n    {\n      value: 'jiangsu',\n      label: 'Jiangsu'\n    }\n  ];\n}\n"
  },
  {
    "path": "components/input/demo/focus.md",
    "content": "---\norder: 18\ntitle:\n  zh-CN: Focus 额外配置属性\n  en-US: Focus with additional option\n---\n\n## zh-CN\n\nFocus 提供额外配置属性\n\n## en-US\n\nFocus with additional option.\n`\n"
  },
  {
    "path": "components/input/demo/focus.ts",
    "content": "import { Component, ViewChild } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzInputDirective, NzInputModule } from 'ng-zorro-antd/input';\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\n\n@Component({\n  selector: 'nz-demo-input-focus',\n  imports: [FormsModule, NzInputModule, NzButtonModule, NzSwitchModule],\n  template: `\n    <button nz-button (click)=\"input.focus({ cursor: 'start' })\">Focus at first</button>\n    <button nz-button (click)=\"input.focus({ cursor: 'end' })\">Focus at last</button>\n    <button nz-button (click)=\"input.focus({ cursor: 'all' })\">Focus to select all</button>\n    <button nz-button (click)=\"input.focus({ preventScroll: true })\"> Focus prevent scroll </button>\n\n    <br />\n    <nz-switch [(ngModel)]=\"inputElem\" nzCheckedChildren=\"input\" nzUnCheckedChildren=\"textarea\" />\n    <br />\n    <br />\n\n    @if (inputElem) {\n      <input #input=\"nzInput\" nz-input [(ngModel)]=\"value\" />\n    } @else {\n      <textarea #input=\"nzInput\" nz-input rows=\"2\" [(ngModel)]=\"value\"> </textarea>\n    }\n  `\n})\nexport class NzDemoInputFocusComponent {\n  value = 'NG-ZORRO love you!';\n  inputElem = true;\n\n  @ViewChild(NzInputDirective) input!: NzInputDirective;\n}\n"
  },
  {
    "path": "components/input/demo/otp.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 一次性密码框\n  en-US: OTP\n---\n\n## zh-CN\n\n一次性密码输入框。\n\n## en-US\n\nOne time password input.\n"
  },
  {
    "path": "components/input/demo/otp.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzFlexDirective } from 'ng-zorro-antd/flex';\nimport { NzInputOtpComponent } from 'ng-zorro-antd/input';\nimport { NzTypographyComponent } from 'ng-zorro-antd/typography';\n\n@Component({\n  selector: 'nz-demo-input-otp',\n  template: `\n    <nz-flex nzVertical [nzGap]=\"16\">\n      <nz-flex nzVertical>\n        <h5 nz-typography>With Formatter (Uppercase)</h5>\n        <nz-input-otp [nzFormatter]=\"formatter\" />\n      </nz-flex>\n\n      <nz-flex nzVertical>\n        <h5 nz-typography>With Disabled</h5>\n        <nz-input-otp [disabled]=\"true\" />\n      </nz-flex>\n\n      <nz-flex nzVertical>\n        <h5 nz-typography>With Length (8)</h5>\n        <nz-input-otp [nzLength]=\"8\" />\n      </nz-flex>\n\n      <nz-flex nzVertical>\n        <h5 nz-typography>With custom display character</h5>\n        <nz-input-otp nzMask=\"🔒\" />\n      </nz-flex>\n    </nz-flex>\n  `,\n  imports: [NzFlexDirective, NzTypographyComponent, NzInputOtpComponent]\n})\nexport class NzDemoInputOtpComponent {\n  formatter: (value: string) => string = value => value.toUpperCase();\n}\n"
  },
  {
    "path": "components/input/demo/password-input.md",
    "content": "---\norder: 12\nversion: 20.4.0\ntitle:\n  zh-CN: 密码框\n  en-US: Password box\n---\n\n## zh-CN\n\n密码框。\n\n## en-US\n\nInput type of password.\n"
  },
  {
    "path": "components/input/demo/password-input.ts",
    "content": "import { Component, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzFlexModule } from 'ng-zorro-antd/flex';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-input-password-input',\n  imports: [FormsModule, NzInputModule, NzIconModule, NzFlexModule, NzButtonModule],\n  template: `\n    <nz-input-password>\n      <input nz-input placeholder=\"input password\" [(ngModel)]=\"password\" />\n    </nz-input-password>\n    <br />\n    <br />\n    <nz-input-password>\n      <input nz-input placeholder=\"input password\" [(ngModel)]=\"password\" />\n      <ng-template nzInputPasswordIcon let-visible>\n        @if (visible) {\n          <nz-icon nzType=\"eye\" nzTheme=\"twotone\" />\n        } @else {\n          <nz-icon nzType=\"eye-invisible\" nzTheme=\"outline\" />\n        }\n      </ng-template>\n    </nz-input-password>\n    <br />\n    <br />\n    <nz-flex nzGap=\"8px\">\n      <nz-input-password [(nzVisible)]=\"passwordVisible\" [style.flex]=\"1\">\n        <input nz-input placeholder=\"input password\" [(ngModel)]=\"password\" />\n      </nz-input-password>\n      <button nz-button (click)=\"passwordVisible.set(!passwordVisible())\">\n        {{ passwordVisible() ? 'Hide' : 'Show' }}\n      </button>\n    </nz-flex>\n    <br />\n    <nz-input-password>\n      <input nz-input placeholder=\"input password\" [(ngModel)]=\"password\" disabled />\n    </nz-input-password>\n  `\n})\nexport class NzDemoInputPasswordInputComponent {\n  readonly passwordVisible = signal(false);\n  readonly password = signal('');\n}\n"
  },
  {
    "path": "components/input/demo/presuffix.md",
    "content": "---\norder: 11\ntitle:\n  zh-CN: 前缀和后缀\n  en-US: prefix and suffix\n---\n\n## zh-CN\n\n在输入框上添加前缀或后缀图标。\n\n## en-US\n\nAdd prefix or suffix icons inside input.\n"
  },
  {
    "path": "components/input/demo/presuffix.ts",
    "content": "import { Component, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCascaderModule } from 'ng-zorro-antd/cascader';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\n@Component({\n  selector: 'nz-demo-input-presuffix',\n  imports: [NzInputModule, NzIconModule, NzSelectModule, NzCascaderModule, FormsModule],\n  template: `\n    <nz-input-wrapper>\n      <nz-icon nzInputPrefix nzType=\"user\" />\n      <input nz-input placeholder=\"Enter your username\" />\n      <nz-icon nzInputSuffix nzType=\"info-circle\" />\n    </nz-input-wrapper>\n    <br />\n    <br />\n    <nz-input-wrapper nzPrefix=\"¥\" nzSuffix=\"RMB\">\n      <input nz-input />\n    </nz-input-wrapper>\n    <br />\n    <br />\n    <nz-input-wrapper nzPrefix=\"¥\" nzSuffix=\"RMB\">\n      <input nz-input disabled />\n    </nz-input-wrapper>\n    <br />\n    <br />\n    <nz-input-wrapper>\n      <input nz-input placeholder=\"input password support suffix\" />\n      <nz-icon nzInputSuffix class=\"ant-input-password-icon\" nzType=\"eye-invisible\" />\n      <nz-icon nzInputSuffix nzType=\"lock\" />\n    </nz-input-wrapper>\n  `\n})\nexport class NzDemoInputPresuffixComponent {\n  readonly value = signal('mysite');\n}\n"
  },
  {
    "path": "components/input/demo/search-input-loading.md",
    "content": "---\norder: 6\nversion: 20.4.0\ntitle:\n  zh-CN: 搜索框 loading\n  en-US: Search box with loading\n---\n\n## zh-CN\n\n用于 `nzSearch` 的时候展示 `loading`。\n\n## en-US\n\nSearch loading when onSearch.\n"
  },
  {
    "path": "components/input/demo/search-input-loading.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-input-search-input-loading',\n  imports: [NzInputModule],\n  template: `\n    <nz-input-search nzLoading>\n      <input nz-input placeholder=\"input search loading default\" />\n    </nz-input-search>\n    <br />\n    <br />\n    <nz-input-search nzLoading nzEnterButton>\n      <input nz-input placeholder=\"input search loading with enterButton\" />\n    </nz-input-search>\n    <br />\n    <br />\n    <nz-input-search nzLoading nzEnterButton=\"Search\">\n      <input nz-input placeholder=\"input search text\" nzSize=\"large\" />\n    </nz-input-search>\n  `\n})\nexport class NzDemoInputSearchInputLoadingComponent {}\n"
  },
  {
    "path": "components/input/demo/search-input.md",
    "content": "---\norder: 5\nversion: 20.4.0\ntitle:\n  zh-CN: 搜索框\n  en-US: Search box\n---\n\n## zh-CN\n\n带有搜索按钮的输入框。\n\n## en-US\n\nExample of creating a search box by grouping a standard input with a search button.\n"
  },
  {
    "path": "components/input/demo/search-input.ts",
    "content": "import { Component, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputModule, NzInputSearchEvent } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-input-search-input',\n  imports: [FormsModule, NzInputModule, NzIconModule],\n  template: `\n    <nz-input-search (nzSearch)=\"onSearch($event)\">\n      <input nz-input [(ngModel)]=\"value\" placeholder=\"input search text\" />\n    </nz-input-search>\n    <br />\n    <br />\n    <nz-input-search nzAllowClear (nzSearch)=\"onSearch($event)\">\n      <input nz-input [(ngModel)]=\"value\" placeholder=\"input search text\" />\n    </nz-input-search>\n    <br />\n    <br />\n    <nz-input-search (nzSearch)=\"onSearch($event)\">\n      <span nzInputAddonBefore>https://</span>\n      <input nz-input [(ngModel)]=\"value\" placeholder=\"input search text\" />\n    </nz-input-search>\n    <br />\n    <br />\n    <nz-input-search nzEnterButton=\"Submit\" (nzSearch)=\"onSearch($event)\">\n      <input nz-input [(ngModel)]=\"value\" placeholder=\"input search text\" />\n    </nz-input-search>\n    <br />\n    <br />\n    <nz-input-search nzEnterButton=\"Submit\" (nzSearch)=\"onSearch($event)\">\n      <input nz-input [(ngModel)]=\"value\" placeholder=\"input search text\" nzSize=\"large\" />\n    </nz-input-search>\n    <br />\n    <br />\n    <nz-input-search (nzSearch)=\"onSearch($event)\">\n      <input nz-input [(ngModel)]=\"value\" placeholder=\"input search text\" nzSize=\"large\" />\n      <nz-icon nzInputSuffix nzType=\"audio\" [style.font-size.px]=\"16\" [style.color]=\"'#1677ff'\" />\n      <span nzInputSearchEnterButton>Custom</span>\n    </nz-input-search>\n  `\n})\nexport class NzDemoInputSearchInputComponent {\n  readonly value = signal('');\n\n  onSearch(event: NzInputSearchEvent): void {\n    console.log(event);\n  }\n}\n"
  },
  {
    "path": "components/input/demo/size.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 三种大小\n  en-US: Three sizes of Input\n---\n\n## zh-CN\n\n我们为 `nz-input` 输入框定义了三种尺寸（大、默认、小），高度分别为 `40px`、`32px` 和 `24px`。\n\n## en-US\n\nThere are three sizes of an Input box: `large` (40px)、`default` (32px) and `small` (24px).\n"
  },
  {
    "path": "components/input/demo/size.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-input-size',\n  imports: [NzInputModule, NzIconModule],\n  template: `\n    <nz-input-wrapper>\n      <nz-icon nzInputPrefix nzType=\"user\" />\n      <input nz-input placeholder=\"large size\" nzSize=\"large\" />\n    </nz-input-wrapper>\n    <br />\n    <br />\n    <nz-input-wrapper>\n      <nz-icon nzInputPrefix nzType=\"user\" />\n      <input nz-input placeholder=\"default size\" nzSize=\"default\" />\n    </nz-input-wrapper>\n    <br />\n    <br />\n    <nz-input-wrapper>\n      <nz-icon nzInputPrefix nzType=\"user\" />\n      <input nz-input placeholder=\"small size\" nzSize=\"small\" />\n    </nz-input-wrapper>\n  `\n})\nexport class NzDemoInputSizeComponent {}\n"
  },
  {
    "path": "components/input/demo/status.md",
    "content": "---\norder: 15\ntitle:\n  zh-CN: 自定义状态\n  en-US: Status\n---\n\n## zh-CN\n\n使用 `nzStatus` 为 Input 添加状态，可选 `error` 或者 `warning`。\n\n## en-US\n\nAdd status to Input with `nzStatus`, which could be `error` or `warning`.\n"
  },
  {
    "path": "components/input/demo/status.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\n\n@Component({\n  selector: 'nz-demo-input-status',\n  imports: [FormsModule, NzIconModule, NzInputModule, NzSpaceModule],\n  template: `\n    <nz-space nzDirection=\"vertical\" style=\"width: 100%\">\n      <input *nzSpaceItem nz-input placeholder=\"Error\" [(ngModel)]=\"value\" nzStatus=\"error\" />\n      <input *nzSpaceItem nz-input placeholder=\"Warning\" [(ngModel)]=\"value\" nzStatus=\"warning\" />\n      <nz-input-wrapper *nzSpaceItem>\n        <nz-icon nzInputPrefix nzType=\"clock-circle\" nzTheme=\"outline\" />\n        <input type=\"text\" nz-input placeholder=\"Error with prefix\" nzStatus=\"error\" />\n      </nz-input-wrapper>\n      <nz-input-wrapper *nzSpaceItem>\n        <nz-icon nzInputPrefix nzType=\"clock-circle\" nzTheme=\"outline\" />\n        <input type=\"text\" nz-input placeholder=\"Warning with prefix\" nzStatus=\"warning\" />\n      </nz-input-wrapper>\n    </nz-space>\n  `\n})\nexport class NzDemoInputStatusComponent {\n  value?: string;\n}\n"
  },
  {
    "path": "components/input/demo/textarea-with-character-count.md",
    "content": "---\norder: 14\ntitle:\n  zh-CN: 带数字提示的文本域\n  en-US: Textarea with character count\n---\n\n## zh-CN\n\n展示数字提示。\n\n## en-US\n\nShow character count.\n"
  },
  {
    "path": "components/input/demo/textarea-with-character-count.ts",
    "content": "import { Component, inject } from '@angular/core';\nimport { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';\n\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-input-textarea-with-character-count',\n  imports: [ReactiveFormsModule, NzFormModule, NzInputModule],\n  template: `\n    <form nz-form [formGroup]=\"form\" nzLayout=\"vertical\">\n      <nz-form-item>\n        <nz-form-control>\n          <nz-textarea-count [nzMaxCharacterCount]=\"100\">\n            <textarea rows=\"4\" formControlName=\"comment\" nz-input></textarea>\n          </nz-textarea-count>\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `\n})\nexport class NzDemoInputTextareaWithCharacterCountComponent {\n  private fb = inject(FormBuilder);\n  form = this.fb.group({ comment: this.fb.control('', [Validators.maxLength(100)]) });\n}\n"
  },
  {
    "path": "components/input/demo/textarea.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 文本域\n  en-US: TextArea\n---\n\n## zh-CN\n\n用于多行输入。\n\n## en-US\n\nFor multi-line input.\n"
  },
  {
    "path": "components/input/demo/textarea.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\n@Component({\n  selector: 'nz-demo-input-textarea',\n  imports: [FormsModule, NzInputModule],\n  template: `<textarea rows=\"4\" nz-input [(ngModel)]=\"inputValue\"></textarea>`\n})\nexport class NzDemoInputTextareaComponent {\n  inputValue?: string;\n}\n"
  },
  {
    "path": "components/input/demo/tooltip.md",
    "content": "---\norder: 10\ntitle:\n  zh-CN: 输入时格式化展示\n  en-US: Format Tooltip Input\n---\n\n## zh-CN\n\n结合 [Tooltip](/components/tooltip/zh) 组件，实现一个数值输入框，方便内容超长时的全量展现。\n\n## en-US\n\nYou can use the Input in conjunction with [Tooltip](/components/tooltip/en) component to create a Numeric Input, which can provide a good experience for extra-long content display.\n"
  },
  {
    "path": "components/input/demo/tooltip.ts",
    "content": "import { Component, ElementRef, ViewChild } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzTooltipModule } from 'ng-zorro-antd/tooltip';\n\n@Component({\n  selector: 'nz-demo-input-tooltip',\n  imports: [FormsModule, NzInputModule, NzTooltipModule],\n  template: `\n    <input\n      #inputElement\n      style=\"width: 120px\"\n      nz-input\n      nz-tooltip\n      nzTooltipTrigger=\"focus\"\n      nzTooltipPlacement=\"topLeft\"\n      nzTooltipOverlayClassName=\"numeric-input\"\n      [ngModel]=\"value\"\n      [nzTooltipTitle]=\"title\"\n      placeholder=\"Input a number\"\n      (ngModelChange)=\"onChange($event)\"\n      (blur)=\"onBlur()\"\n    />\n  `,\n  styles: `\n    .numeric-input .ant-tooltip-inner {\n      min-width: 32px;\n      min-height: 37px;\n    }\n\n    .numeric-input .numeric-input-title {\n      font-size: 14px;\n    }\n  `\n})\nexport class NzDemoInputTooltipComponent {\n  value = '';\n  title = 'Input a number';\n\n  @ViewChild('inputElement', { static: false }) inputElement?: ElementRef;\n\n  onChange(value: string): void {\n    this.updateValue(value);\n  }\n\n  // '.' at the end or only '-' in the input box.\n  onBlur(): void {\n    if (this.value.charAt(this.value.length - 1) === '.' || this.value === '-') {\n      this.updateValue(this.value.slice(0, -1));\n    }\n  }\n\n  updateValue(value: string): void {\n    const reg = /^-?(0|[1-9][0-9]*)(\\.[0-9]*)?$/;\n    if ((!isNaN(+value) && reg.test(value)) || value === '' || value === '-') {\n      this.value = value;\n    }\n    this.inputElement!.nativeElement.value = this.value;\n    this.updateTitle();\n  }\n\n  updateTitle(): void {\n    this.title = (this.value !== '-' ? this.formatNumber(this.value) : '-') || 'Input a number';\n  }\n\n  formatNumber(value: string): string {\n    const stringValue = `${value}`;\n    const list = stringValue.split('.');\n    const prefix = list[0].charAt(0) === '-' ? '-' : '';\n    let num = prefix ? list[0].slice(1) : list[0];\n    let result = '';\n    while (num.length > 3) {\n      result = `,${num.slice(-3)}${result}`;\n      num = num.slice(0, num.length - 3);\n    }\n    if (num) {\n      result = num + result;\n    }\n    return `${prefix}${result}${list[1] ? `.${list[1]}` : ''}`;\n  }\n}\n"
  },
  {
    "path": "components/input/demo/variant.md",
    "content": "---\norder: 2\nversion: 20.0.0\ntitle:\n  zh-CN: 形态变体\n  en-US: Variants\n---\n\n## zh-CN\n\nInput 形态变体，可选 `outlined`、`filled`、`borderless`、`underlined` 四种形态。\n\n## en-US\n\nVariants of Input, there are four variants: `outlined`, `filled`, `borderless` and `underlined`.\n"
  },
  {
    "path": "components/input/demo/variant.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\n\n@Component({\n  selector: 'nz-demo-input-variant',\n  imports: [NzInputModule, NzSpaceModule],\n  template: `\n    <nz-space nzDirection=\"vertical\" style=\"width: 100%\">\n      <input *nzSpaceItem nz-input placeholder=\"outlined\" nzVariant=\"outlined\" />\n      <input *nzSpaceItem nz-input placeholder=\"filled\" nzVariant=\"filled\" />\n      <input *nzSpaceItem nz-input placeholder=\"borderless\" nzVariant=\"borderless\" />\n      <input *nzSpaceItem nz-input placeholder=\"underlined\" nzVariant=\"underlined\" />\n    </nz-space>\n  `\n})\nexport class NzDemoInputVariantComponent {}\n"
  },
  {
    "path": "components/input/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Entry\ntitle: Input\ntag: updated\ncover: 'https://gw.alipayobjects.com/zos/alicdn/xS9YEJhfe/Input.svg'\ndescription: Through mouse or keyboard input content, it is the most basic form field wrapper.\n---\n\n## When To Use\n\n- A user input in a form field is needed.\n- A search input is required.\n\n## API\n\n### [nz-input]\n\nAll props of input supported by [w3c standards](https://www.w3schools.com/tags/tag_input.asp) and Angular can used in `[nz-input]`.\n\n| Property              | Description                                                                                                              | Type                                                     | Default      | Version |\n| --------------------- | ------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------- | ------------ | ------- |\n| `[nzSize]`            | The size of the input box. Note: in the context of a form, the `large` size is used.                                     | `'large' \\| 'small' \\| 'default'`                        | `'default'`  |\n| ~~`[nzAutosize]`~~    | ~~Only used for `textarea`, height autosize feature, can be set to `boolean` or an object `{ minRows: 2, maxRows: 6 }`~~ | ~~`boolean \\| { minRows: number, maxRows: number }`~~    | ~~`false`~~  |\n| `[nzVariant]`         | Variants of Input                                                                                                        | `'outlined' \\| 'borderless' \\| 'filled' \\| 'underlined'` | `'outlined'` | 20.0.0  |\n| `[nzStatus]`          | Set validation status                                                                                                    | `'error' \\| 'warning'`                                   | -            |\n| ~~`[nzStepperless]`~~ | ~~Whether hide stepper when input type is number~~                                                                       | ~~`boolean`~~                                            | ~~`true`~~   |\n\n#### Methods\n\nYou can get instance by `ViewChild`\n\n| Name           | Description  | Parameters                                                                   |\n| -------------- | ------------ | ---------------------------------------------------------------------------- |\n| focus(option?) | get focus    | `(option?: { preventScroll?: boolean, cursor?: 'start' \\| 'end' \\| 'all' })` |\n| blur()         | remove focus | -                                                                            |\n\n### nz-input-wrapper\n\nUse when you need to add extra functionality to `[nz-input]`.\n\n| Property          | Description                                                           | Type                     | Default |\n| ----------------- | --------------------------------------------------------------------- | ------------------------ | ------- |\n| `[nzAddonBefore]` | The label text displayed before (on the left side of) the input field | `string`                 | -       |\n| `[nzAddonAfter]`  | The label text displayed after (on the right side of) the input field | `string`                 | -       |\n| `[nzPrefix]`      | The prefix icon for the Input                                         | `string`                 | -       |\n| `[nzSuffix]`      | The suffix icon for the Input                                         | `string`                 | -       |\n| `[nzAllowClear]`  | If allow to remove input content with clear icon                      | `boolean`                | `false` |\n| `[nzShowCount]`   | Should the character count be displayed                               | `boolean`                | `false` |\n| `[nzCount]`       | Custom character counting config                                      | `NzCountConfig`          | -       |\n| `(nzClear)`       | Event emitted when the clear icon is clicked                          | `OutputEmitterRef<void>` | -       |\n\n#### NzCountConfig\n\n```ts\nexport interface NzCountConfig {\n  // Maximum character limit: exceeding will be highlighted in red but will not be truncated.\n  max?: number;\n  // Custom character counting strategy\n  strategy?: (value: string) => number;\n  // Trimming logic when the number of characters exceeds `max`\n  exceedFormatter?: (value: string, config: { max: number }) => string;\n}\n```\n\n### nz-input-password\n\nAll properties of `nz-input-wrapper` can be used.\n\n| Property               | Description                                               | Type                        | Default |\n| ---------------------- | --------------------------------------------------------- | --------------------------- | ------- |\n| `[nzVisibilityToggle]` | Whether to show the toggle button                         | `boolean`                   | `true`  |\n| `[nzVisible]`          | Whether the password is visible, supports two-way binding | `boolean`                   | `false` |\n| `(nzVisibleChange)`    | Event emitted when the visibility of the password changes | `OutputEmitterRef<boolean>` | -       |\n\n### nz-input-search\n\nAll properties of `nz-input-wrapper` can be used.\n\n| Property          | Description                                                                                                                              | Type                                                          | Default |\n| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | ------- |\n| `[nzEnterButton]` | false displays the default button color, true uses the primary color, or you can provide a custom button. Conflicts with `nzAddonAfter`. | `boolean \\| string`                                           | `false` |\n| `[nzLoading]`     | Search box with loading                                                                                                                  | `boolean`                                                     | `false` |\n| `(nzSearch)`      | The event triggered when you click on the search-icon, the clear-icon or press the Enter key                                             | `{ value: string, event: Event, source: 'clear' \\| 'input' }` |         |\n\n### nz-input-group\n\n> ⚠️ `nz-input-group` has been deprecated in `v20.0.0` and will be removed in `v22.0.0`. Please use the `nz-input-wrapper` component instead.\n\n| Property          | Description                                                                                          | Type                              | Default     |\n| ----------------- | ---------------------------------------------------------------------------------------------------- | --------------------------------- | ----------- |\n| `[nzAddOnAfter]`  | The label text displayed after (on the right side of) the input field, can work with `nzAddOnBefore` | `string \\| TemplateRef<void>`     | -           |\n| `[nzAddOnBefore]` | The label text displayed before (on the left side of) the input field, can work with `nzAddOnAfter`  | `string \\| TemplateRef<void>`     | -           |\n| `[nzPrefix]`      | The prefix icon for the Input, can work with `nzSuffix`                                              | `string \\| TemplateRef<void>`     | -           |\n| `[nzSuffix]`      | The suffix icon for the Input, can work with `nzPrefix`                                              | `string \\| TemplateRef<void>`     | -           |\n| `[nzSize]`        | The size of `nz-input-group` specifies the size of the included `nz-input` fields                    | `'large' \\| 'small' \\| 'default'` | `'default'` |\n| `[nzStatus]`      | Set validation status                                                                                | `'error' \\| 'warning'`            | -           |\n\n### nz-textarea-count\n\n| Property                    | Description                                      | Type                    | Default         |\n| --------------------------- | ------------------------------------------------ | ----------------------- | --------------- |\n| `[nzMaxCharacterCount]`     | `textarea` maximum character count displayed     | `number`                | -               |\n| `[nzComputeCharacterCount]` | customized `characterCount` computation function | `(v: string) => number` | `v => v.length` |\n\n### nz-input-otp\n\n| Property        | Description                                             | Type                              | Default     |\n| --------------- | ------------------------------------------------------- | --------------------------------- | ----------- |\n| `[disabled]`    | Whether the input is disabled                           | `boolean`                         | `false`     |\n| `[nzFormatter]` | Format display, blank fields will be filled with ` `    | `(value: string) => string`       | -           |\n| `[nzMask]`      | Custom display, the original value will not be modified | `boolean  \\| null`                | `null`      |\n| `[nzLength]`    | The number of input elements                            | `number`                          | `6`         |\n| `[nzStatus]`    | Set validation status                                   | `'error' \\| 'warning'`            | -           |\n| `[nzSize]`      | The size of the input box                               | `'large' \\| 'small' \\| 'default'` | `'default'` |\n\n## Q&A\n\n### How to use compact input group?\n\n`nz-input-group` is no longer support compact mode directly in v20, you can use [nz-space-compact](/components/space/en#components-space-demo-compact) instead.\n\n### NG0951 Error\n\nIf you attempt to dynamically render `nz-input` inside `nz-input-wrapper` using `ngTemplateOutlet` or similar methods, you may encounter the `NG0951` error.\nThis is because Angular's Content Projection and Child Query mechanisms are static and cannot recognize dynamically rendered components (Reference: [angular/angular#64504](https://github.com/angular/angular/issues/64504)).\n\nSince `nz-input-wrapper` relies on content child queries to locate `nz-input`, it is recommended to treat `nz-input-wrapper` and `nz-input` as a single unit and avoid rendering them separately.\n\n```html\n@if (need_affix_or_addon) {\n<nz-input-wrapper nzAddonBefore=\"...\">\n  <input nz-input />\n</nz-input-wrapper>\n} @else {\n<input nz-input />\n}\n```\n"
  },
  {
    "path": "components/input/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 输入框\ntype: 数据录入\ntitle: Input\ntag: updated\ncover: 'https://gw.alipayobjects.com/zos/alicdn/xS9YEJhfe/Input.svg'\ndescription: 通过鼠标或键盘输入内容，是最基础的表单域的包装。\n---\n\n## 何时使用\n\n- 需要用户输入表单域内容时。\n- 提供组合型输入框，带搜索的输入框，还可以进行大小选择。\n\n## API\n\n### [nz-input]\n\n`[nz-input]` 可以使用所有的 W3C 标准下的所有 [使用方式](https://www.w3schools.com/tags/tag_input.asp) 和 Angular 对 input 的全部额外功能支持。\n\n| 参数               | 说明                                                                                               | 类型                                                     | 默认值       | 版本   |\n| ------------------ | -------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | ------------ | ------ |\n| `[nzSize]`         | 控件大小。注：标准表单内的输入框大小限制为 `large`                                                 | `'large' \\| 'small' \\| 'default'`                        | `'default'`  |\n| ~~`[nzAutosize]`~~ | ~~只可以用于 `textarea`，自适应内容高度，可设置为 `boolean` 或对象：`{ minRows: 2, maxRows: 6 }`~~ | ~~`boolean \\| { minRows: number, maxRows: number }`~~    | ~~`false`~~  |\n| `[nzVariant]`      | 形态变体                                                                                           | `'outlined' \\| 'borderless' \\| 'filled' \\| 'underlined'` | `'outlined'` | 20.0.0 |\n| `[nzStatus]`       | 设置校验状态                                                                                       | `'error' \\| 'warning'`                                   | -            |\n\n#### 方法\n\n通过 `ViewChild` 等方法获得实例后调用\n\n| 名称           | 描述     | 参数                                                                         |\n| -------------- | -------- | ---------------------------------------------------------------------------- |\n| focus(option?) | 获取焦点 | `(option?: { preventScroll?: boolean, cursor?: 'start' \\| 'end' \\| 'all' })` |\n| blur()         | 移除焦点 | -                                                                            |\n\n### nz-input-wrapper\n\n当需要为 `[nz-input]` 添加额外功能时使用。\n\n| 参数              | 说明                         | 类型                     | 默认值  |\n| ----------------- | ---------------------------- | ------------------------ | ------- |\n| `[nzAddonBefore]` | 带标签的 input，设置前置标签 | `string`                 | -       |\n| `[nzAddonAfter]`  | 带标签的 input，设置后置标签 | `string`                 | -       |\n| `[nzPrefix]`      | 带有前缀图标的 input         | `string`                 | -       |\n| `[nzSuffix]`      | 带有后缀图标的 input         | `string`                 | -       |\n| `[nzAllowClear]`  | 可以点击清除图标删除内容     | `boolean`                | `false` |\n| `[nzShowCount]`   | 是否显示字符计数             | `boolean`                | `false` |\n| `[nzCount]`       | 自定义字符计数配置           | `NzCountConfig`          | -       |\n| `(nzClear)`       | 点击清除图标时触发           | `OutputEmitterRef<void>` | -       |\n\n#### NzCountConfig\n\n```ts\nexport interface NzCountConfig {\n  // 最大字符数，超出后标红但不会截断\n  max?: number;\n  // 自定义字符计数策略\n  strategy?: (value: string) => number;\n  // 当字符数超出 `max` 时的裁剪逻辑\n  exceedFormatter?: (value: string, config: { max: number }) => string;\n}\n```\n\n### nz-input-password\n\n可使用 `nz-input-wrapper` 的所有属性。\n\n| 参数                   | 说明                       | 类型                        | 默认值  |\n| ---------------------- | -------------------------- | --------------------------- | ------- |\n| `[nzVisibilityToggle]` | 是否显示切换按钮           | `boolean`                   | `true`  |\n| `[nzVisible]`          | 是否显示密码，支持双向绑定 | `boolean`                   | `false` |\n| `(nzVisibleChange)`    | 是否显示密码变更事件       | `OutputEmitterRef<boolean>` | -       |\n\n### nz-input-search\n\n可使用 `nz-input-wrapper` 的所有属性。\n\n| 参数              | 说明                                                             | 类型                                                          | 默认值  |\n| ----------------- | ---------------------------------------------------------------- | ------------------------------------------------------------- | ------- |\n| `[nzEnterButton]` | 是否有确认按钮，可设为按钮文字。该属性会与 `nzAddonAfter` 冲突。 | `boolean \\| string`                                           | `false` |\n| `[nzLoading]`     | 搜索 loading                                                     | `boolean`                                                     | `false` |\n| `(nzSearch)`      | 点击搜索图标、清除图标，或按下回车键时的事件                     | `{ value: string, event: Event, source: 'clear' \\| 'input' }` |         |\n\n### nz-input-group\n\n> ⚠️ `nz-input-group` 已在 `v20.0.0` 中废弃，将在 `v22.0.0` 中移除，请使用 `nz-input-wrapper` 组件。\n\n| 参数              | 说明                                                          | 类型                              | 默认值      |\n| ----------------- | ------------------------------------------------------------- | --------------------------------- | ----------- |\n| `[nzAddOnAfter]`  | 带标签的 input，设置后置标签，可以与 `nzAddOnBefore` 配合使用 | `string \\| TemplateRef<void>`     | -           |\n| `[nzAddOnBefore]` | 带标签的 input，设置前置标签，可以与 `nzAddOnAfter` 配合使用  | `string \\| TemplateRef<void>`     | -           |\n| `[nzPrefix]`      | 带有前缀图标的 input，可以与 `nzSuffix` 配合使用              | `string \\| TemplateRef<void>`     | -           |\n| `[nzSuffix]`      | 带有后缀图标的 input，可以与 `nzPrefix` 配合使用              | `string \\| TemplateRef<void>`     | -           |\n| `[nzSearch]`      | 是否用搜索框                                                  | `boolean`                         | `false`     |\n| `[nzSize]`        | `nz-input-group` 中所有的 `nz-input` 的大小                   | `'large' \\| 'small' \\| 'default'` | `'default'` |\n| `[nzStatus]`      | 设置校验状态                                                  | `'error' \\| 'warning'`            | -           |\n\n### nz-textarea-count\n\n| 参数                        | 说明                               | 类型                    | 默认值          |\n| --------------------------- | ---------------------------------- | ----------------------- | --------------- |\n| `[nzMaxCharacterCount]`     | `textarea` 数字提示显示的最大值    | `number`                | -               |\n| `[nzComputeCharacterCount]` | 自定义计算 `characterCount` 的函数 | `(v: string) => number` | `v => v.length` |\n\n### nz-input-otp\n\n| Property        | Description                                       | Type                              | Default     |\n| --------------- | ------------------------------------------------- | --------------------------------- | ----------- |\n| `[disabled]`    | 是否禁用                                          | boolean                           | `false`     |\n| `[nzFormatter]` | 格式化展示，留空字段会被 ` ` 填充                 | `(value: string) => string`       | -           |\n| `[nzMask]`      | 自定义展示，和 `formatter` 的区别是不会修改原始值 | `boolean  \\| null`                | `null`      |\n| `[nzLength]`    | 输入元素数量                                      | `number`                          | `6`         |\n| `[nzStatus]`    | 设置校验状态                                      | `'error' \\| 'warning'`            | -           |\n| `[nzSize]`      | 输入框大小                                        | `'large' \\| 'small' \\| 'default'` | `'default'` |\n\n## Q&A\n\n### 如何使用紧凑型输入框组合？\n\n从 v20 版本开始，`nz-input-group` 不再直接支持紧凑模式，你可以使用 [nz-space-compact](/components/space/zh#components-space-demo-compact) 替代。\n\n### NG0951 错误\n\n若通过 `ngTemplateOutlet` 等方式将 `nz-input` 动态渲染到 `nz-input-wrapper` 内部，可能会触发 `NG0951` 错误。\n这是由于 Angular 的内容投影（Content Projection）与子查询（Child Query）机制是静态的，无法识别动态渲染的组件（参考：[angular/angular#64504](https://github.com/angular/angular/issues/64504)）。\n\n鉴于 `nz-input-wrapper` 依赖于内容子查询来定位 `nz-input`，建议将 `nz-input-wrapper` 与 `nz-input` 视为一个整体，避免拆分渲染。\n\n```html\n@if (need_affix_or_addon) {\n<nz-input-wrapper nzAddonBefore=\"...\">\n  <input nz-input />\n</nz-input-wrapper>\n} @else {\n<input nz-input />\n}\n```\n"
  },
  {
    "path": "components/input/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/input/input-addon.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive } from '@angular/core';\n\n@Directive({\n  selector: '[nzInputAddonBefore]'\n})\nexport class NzInputAddonBeforeDirective {}\n\n@Directive({\n  selector: '[nzInputAddonAfter]'\n})\nexport class NzInputAddonAfterDirective {}\n"
  },
  {
    "path": "components/input/input-affix.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive } from '@angular/core';\n\n@Directive({\n  selector: '[nzInputPrefix]'\n})\nexport class NzInputPrefixDirective {}\n\n@Directive({\n  selector: '[nzInputSuffix]'\n})\nexport class NzInputSuffixDirective {}\n"
  },
  {
    "path": "components/input/input-group-slot.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, Input, TemplateRef, ViewEncapsulation } from '@angular/core';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n/**\n * @deprecated Will be removed in v22.0.0. This component will be removed along with input-group.\n */\n@Component({\n  selector: '[nz-input-group-slot]',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    @if (icon) {\n      <nz-icon [nzType]=\"icon\" />\n    }\n    <ng-container *nzStringTemplateOutlet=\"template\">{{ template }}</ng-container>\n    <ng-content />\n  `,\n  host: {\n    '[class.ant-input-group-addon]': `type === 'addon'`,\n    '[class.ant-input-prefix]': `type === 'prefix'`,\n    '[class.ant-input-suffix]': `type === 'suffix'`\n  },\n  imports: [NzIconModule, NzOutletModule]\n})\nexport class NzInputGroupSlotComponent {\n  @Input() icon?: string | null = null;\n  @Input() type: 'addon' | 'prefix' | 'suffix' | null = null;\n  @Input() template?: string | TemplateRef<void> | null = null;\n}\n"
  },
  {
    "path": "components/input/input-group.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { FocusMonitor } from '@angular/cdk/a11y';\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterContentInit,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ContentChildren,\n  DestroyRef,\n  Directive,\n  ElementRef,\n  Input,\n  OnChanges,\n  OnInit,\n  QueryList,\n  Renderer2,\n  SimpleChanges,\n  TemplateRef,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { merge } from 'rxjs';\nimport { distinctUntilChanged, map, mergeMap, startWith, switchMap } from 'rxjs/operators';\n\nimport { NzFormItemFeedbackIconComponent, NzFormNoStatusService, NzFormStatusService } from 'ng-zorro-antd/core/form';\nimport { NgClassInterface, NzSizeLDSType, NzStatus, NzValidateStatus } from 'ng-zorro-antd/core/types';\nimport { getStatusClassNames } from 'ng-zorro-antd/core/util';\nimport { NZ_SPACE_COMPACT_ITEM_TYPE, NzSpaceCompactItemDirective } from 'ng-zorro-antd/space';\n\nimport { NzInputGroupSlotComponent } from './input-group-slot.component';\nimport { NzInputDirective } from './input.directive';\n\n/**\n * @deprecated Will be removed in v22.0.0. This component will be removed along with input-group.\n */\n@Directive({\n  selector: `nz-input-group[nzSuffix], nz-input-group[nzPrefix]`\n})\nexport class NzInputGroupWhitSuffixOrPrefixDirective {\n  public readonly elementRef = inject(ElementRef);\n}\n\n/**\n * @deprecated Will be removed in v22. It is recommended to use `<nz-input-wrapper>` instead.\n */\n@Component({\n  selector: 'nz-input-group',\n  exportAs: 'nzInputGroup',\n  imports: [NzInputGroupSlotComponent, NgTemplateOutlet, NzFormItemFeedbackIconComponent],\n  encapsulation: ViewEncapsulation.None,\n  providers: [NzFormNoStatusService, { provide: NZ_SPACE_COMPACT_ITEM_TYPE, useValue: 'input' }],\n  template: `\n    @if (isAddOn) {\n      <span class=\"ant-input-wrapper ant-input-group\">\n        @if (nzAddOnBefore || nzAddOnBeforeIcon) {\n          <span nz-input-group-slot type=\"addon\" [icon]=\"nzAddOnBeforeIcon\" [template]=\"nzAddOnBefore\"></span>\n        }\n\n        @if (isAffix || hasFeedback) {\n          <span\n            class=\"ant-input-affix-wrapper\"\n            [class.ant-input-affix-wrapper-disabled]=\"disabled\"\n            [class.ant-input-affix-wrapper-sm]=\"isSmall\"\n            [class.ant-input-affix-wrapper-lg]=\"isLarge\"\n            [class.ant-input-affix-wrapper-focused]=\"focused\"\n            [class]=\"affixInGroupStatusCls\"\n          >\n            <ng-template [ngTemplateOutlet]=\"affixTemplate\" />\n          </span>\n        } @else {\n          <ng-template [ngTemplateOutlet]=\"contentTemplate\" />\n        }\n        @if (nzAddOnAfter || nzAddOnAfterIcon) {\n          <span nz-input-group-slot type=\"addon\" [icon]=\"nzAddOnAfterIcon\" [template]=\"nzAddOnAfter\"></span>\n        }\n      </span>\n    } @else {\n      @if (isAffix) {\n        <ng-template [ngTemplateOutlet]=\"affixTemplate\" />\n      } @else {\n        <ng-template [ngTemplateOutlet]=\"contentTemplate\" />\n      }\n    }\n\n    <!-- affix template -->\n    <ng-template #affixTemplate>\n      @if (nzPrefix || nzPrefixIcon) {\n        <span nz-input-group-slot type=\"prefix\" [icon]=\"nzPrefixIcon\" [template]=\"nzPrefix\"></span>\n      }\n      <ng-template [ngTemplateOutlet]=\"contentTemplate\" />\n      @if (nzSuffix || nzSuffixIcon || isFeedback) {\n        <span nz-input-group-slot type=\"suffix\" [icon]=\"nzSuffixIcon\" [template]=\"nzSuffix\">\n          @if (isFeedback) {\n            <nz-form-item-feedback-icon [status]=\"status\" />\n          }\n        </span>\n      }\n    </ng-template>\n\n    <!-- content template -->\n    <ng-template #contentTemplate>\n      <ng-content />\n      @if (!isAddOn && !isAffix && isFeedback) {\n        <span nz-input-group-slot type=\"suffix\">\n          <nz-form-item-feedback-icon [status]=\"status\" />\n        </span>\n      }\n    </ng-template>\n  `,\n  host: {\n    '[class.ant-input-search-enter-button]': `nzSearch`,\n    '[class.ant-input-search]': `nzSearch`,\n    '[class.ant-input-search-rtl]': `dir === 'rtl'`,\n    '[class.ant-input-search-sm]': `nzSearch && isSmall`,\n    '[class.ant-input-search-large]': `nzSearch && isLarge`,\n    '[class.ant-input-group-wrapper]': `isAddOn`,\n    '[class.ant-input-group-wrapper-rtl]': `dir === 'rtl'`,\n    '[class.ant-input-group-wrapper-lg]': `isAddOn && isLarge`,\n    '[class.ant-input-group-wrapper-sm]': `isAddOn && isSmall`,\n    '[class.ant-input-affix-wrapper]': `isAffix && !isAddOn`,\n    '[class.ant-input-affix-wrapper-rtl]': `dir === 'rtl'`,\n    '[class.ant-input-affix-wrapper-focused]': `isAffix && focused`,\n    '[class.ant-input-affix-wrapper-disabled]': `isAffix && disabled`,\n    '[class.ant-input-affix-wrapper-lg]': `isAffix && !isAddOn && isLarge`,\n    '[class.ant-input-affix-wrapper-sm]': `isAffix && !isAddOn && isSmall`,\n    '[class.ant-input-group]': `!isAffix && !isAddOn`,\n    '[class.ant-input-group-rtl]': `dir === 'rtl'`,\n    '[class.ant-input-group-lg]': `!isAffix && !isAddOn && isLarge`,\n    '[class.ant-input-group-sm]': `!isAffix && !isAddOn && isSmall`\n  },\n  hostDirectives: [NzSpaceCompactItemDirective],\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class NzInputGroupComponent implements AfterContentInit, OnChanges, OnInit {\n  private focusMonitor = inject(FocusMonitor);\n  private elementRef = inject(ElementRef);\n  private renderer = inject(Renderer2);\n  private cdr = inject(ChangeDetectorRef);\n  private directionality = inject(Directionality);\n  private destroyRef = inject(DestroyRef);\n  private nzFormStatusService = inject(NzFormStatusService, { optional: true });\n  private nzFormNoStatusService = inject(NzFormNoStatusService, { optional: true });\n\n  @ContentChildren(NzInputDirective) listOfNzInputDirective!: QueryList<NzInputDirective>;\n  @Input() nzAddOnBeforeIcon?: string | null = null;\n  @Input() nzAddOnAfterIcon?: string | null = null;\n  @Input() nzPrefixIcon?: string | null = null;\n  @Input() nzSuffixIcon?: string | null = null;\n  @Input() nzAddOnBefore?: string | TemplateRef<void>;\n  @Input() nzAddOnAfter?: string | TemplateRef<void>;\n  @Input() nzPrefix?: string | TemplateRef<void>;\n  @Input() nzStatus: NzStatus = '';\n  @Input() nzSuffix?: string | TemplateRef<void>;\n  @Input() nzSize: NzSizeLDSType = 'default';\n  @Input({ transform: booleanAttribute }) nzSearch = false;\n  isLarge = false;\n  isSmall = false;\n  isAffix = false;\n  isAddOn = false;\n  isFeedback = false;\n  focused = false;\n  disabled = false;\n  dir: Direction = 'ltr';\n  // status\n  prefixCls: string = 'ant-input';\n  affixStatusCls: NgClassInterface = {};\n  groupStatusCls: NgClassInterface = {};\n  affixInGroupStatusCls: NgClassInterface = {};\n  status: NzValidateStatus = '';\n  hasFeedback: boolean = false;\n\n  constructor() {\n    this.destroyRef.onDestroy(() => this.focusMonitor.stopMonitoring(this.elementRef));\n  }\n\n  updateChildrenInputSize(): void {\n    if (this.listOfNzInputDirective) {\n      this.listOfNzInputDirective.forEach(item => item['size'].set(this.nzSize));\n    }\n  }\n\n  ngOnInit(): void {\n    this.nzFormStatusService?.formStatusChanges\n      .pipe(\n        distinctUntilChanged((pre, cur) => pre.status === cur.status && pre.hasFeedback === cur.hasFeedback),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(({ status, hasFeedback }) => {\n        this.setStatusStyles(status, hasFeedback);\n      });\n\n    this.focusMonitor\n      .monitor(this.elementRef, true)\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(focusOrigin => {\n        this.focused = !!focusOrigin;\n        this.cdr.markForCheck();\n      });\n\n    this.dir = this.directionality.value;\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n      this.dir = direction;\n    });\n  }\n\n  ngAfterContentInit(): void {\n    this.updateChildrenInputSize();\n    const listOfInputChange$ = this.listOfNzInputDirective.changes.pipe(startWith(this.listOfNzInputDirective));\n    listOfInputChange$\n      .pipe(\n        switchMap(list => merge(...[listOfInputChange$, ...list.map((input: NzInputDirective) => input.disabled$)])),\n        mergeMap(() => listOfInputChange$),\n        map(list => list.some((input: NzInputDirective) => input.finalDisabled())),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(disabled => {\n        this.disabled = disabled;\n        this.cdr.markForCheck();\n      });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const {\n      nzSize,\n      nzSuffix,\n      nzPrefix,\n      nzPrefixIcon,\n      nzSuffixIcon,\n      nzAddOnAfter,\n      nzAddOnBefore,\n      nzAddOnAfterIcon,\n      nzAddOnBeforeIcon,\n      nzStatus\n    } = changes;\n    if (nzSize) {\n      this.updateChildrenInputSize();\n      this.isLarge = this.nzSize === 'large';\n      this.isSmall = this.nzSize === 'small';\n    }\n    if (nzSuffix || nzPrefix || nzPrefixIcon || nzSuffixIcon) {\n      this.isAffix = !!(this.nzSuffix || this.nzPrefix || this.nzPrefixIcon || this.nzSuffixIcon);\n    }\n    if (nzAddOnAfter || nzAddOnBefore || nzAddOnAfterIcon || nzAddOnBeforeIcon) {\n      this.isAddOn = !!(this.nzAddOnAfter || this.nzAddOnBefore || this.nzAddOnAfterIcon || this.nzAddOnBeforeIcon);\n      this.nzFormNoStatusService?.noFormStatus?.next(this.isAddOn);\n    }\n    if (nzStatus) {\n      this.setStatusStyles(this.nzStatus, this.hasFeedback);\n    }\n  }\n\n  private setStatusStyles(status: NzValidateStatus, hasFeedback: boolean): void {\n    // set inner status\n    this.status = status;\n    this.hasFeedback = hasFeedback;\n    this.isFeedback = !!status && hasFeedback;\n    const baseAffix = !!(this.nzSuffix || this.nzPrefix || this.nzPrefixIcon || this.nzSuffixIcon);\n    this.isAffix = baseAffix || (!this.isAddOn && hasFeedback);\n    this.affixInGroupStatusCls =\n      this.isAffix || this.isFeedback\n        ? (this.affixStatusCls = getStatusClassNames(`${this.prefixCls}-affix-wrapper`, status, hasFeedback))\n        : {};\n    this.cdr.markForCheck();\n    // render status if nzStatus is set\n    this.affixStatusCls = getStatusClassNames(\n      `${this.prefixCls}-affix-wrapper`,\n      this.isAddOn ? '' : status,\n      this.isAddOn ? false : hasFeedback\n    );\n    this.groupStatusCls = getStatusClassNames(\n      `${this.prefixCls}-group-wrapper`,\n      this.isAddOn ? status : '',\n      this.isAddOn ? hasFeedback : false\n    );\n    const statusCls = {\n      ...this.affixStatusCls,\n      ...this.groupStatusCls\n    };\n    Object.keys(statusCls).forEach(status => {\n      if (statusCls[status]) {\n        this.renderer.addClass(this.elementRef.nativeElement, status);\n      } else {\n        this.renderer.removeClass(this.elementRef.nativeElement, status);\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "components/input/input-group.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, DebugElement, provideZoneChangeDetection, TemplateRef, ViewChild } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\n\nimport { dispatchFakeEvent } from 'ng-zorro-antd/core/testing';\nimport { NzSizeLDSType, NzStatus } from 'ng-zorro-antd/core/types';\nimport { NzGridModule } from 'ng-zorro-antd/grid';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzFormControlStatusType, NzFormModule } from '../form';\nimport { NzInputGroupComponent } from './input-group.component';\nimport { NzInputModule } from './input.module';\n\ndescribe('input-group', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideZoneChangeDetection()]\n    });\n  });\n\n  describe('input group', () => {\n    describe('addon', () => {\n      let testComponent: NzTestInputGroupAddonComponent;\n      let fixture: ComponentFixture<NzTestInputGroupAddonComponent>;\n      let inputGroupElement: HTMLElement;\n\n      beforeEach(() => {\n        fixture = TestBed.createComponent(NzTestInputGroupAddonComponent);\n        testComponent = fixture.debugElement.componentInstance;\n        fixture.detectChanges();\n        inputGroupElement = fixture.debugElement.query(By.directive(NzInputGroupComponent)).nativeElement;\n      });\n\n      it('should not show addon without before and after content', () => {\n        expect(inputGroupElement.firstElementChild!.classList).not.toContain('ant-input-group');\n        expect(inputGroupElement.firstElementChild!.classList).toContain('ant-input');\n      });\n\n      it('should before content string work', () => {\n        testComponent.beforeContent = 'before';\n        fixture.detectChanges();\n        expect(inputGroupElement.firstElementChild!.classList).toContain('ant-input-group');\n        expect(inputGroupElement.firstElementChild!.children.length).toBe(2);\n        expect(inputGroupElement.firstElementChild!.lastElementChild!.classList).toContain('ant-input');\n        expect((inputGroupElement.firstElementChild!.firstElementChild as HTMLElement).innerText).toBe('before');\n      });\n\n      it('should before content template work', () => {\n        testComponent.beforeContent = testComponent.beforeTemplate;\n        fixture.detectChanges();\n        expect(inputGroupElement.firstElementChild!.classList).toContain('ant-input-group');\n        expect(inputGroupElement.firstElementChild!.children.length).toBe(2);\n        expect(inputGroupElement.firstElementChild!.lastElementChild!.classList).toContain('ant-input');\n        expect((inputGroupElement.firstElementChild!.firstElementChild as HTMLElement).innerText).toBe(\n          'beforeTemplate'\n        );\n      });\n\n      it('should after content string work', () => {\n        testComponent.afterContent = 'after';\n        fixture.detectChanges();\n        expect(inputGroupElement.firstElementChild!.classList).toContain('ant-input-group');\n        expect(inputGroupElement.firstElementChild!.children.length).toBe(2);\n        expect(inputGroupElement.firstElementChild!.firstElementChild!.classList).toContain('ant-input');\n        expect((inputGroupElement.firstElementChild!.lastElementChild as HTMLElement).innerText).toBe('after');\n      });\n\n      it('should after content template work', () => {\n        testComponent.afterContent = testComponent.afterTemplate;\n        fixture.detectChanges();\n        expect(inputGroupElement.firstElementChild!.classList).toContain('ant-input-group');\n        expect(inputGroupElement.firstElementChild!.children.length).toBe(2);\n        expect(inputGroupElement.firstElementChild!.firstElementChild!.classList).toContain('ant-input');\n        expect((inputGroupElement.firstElementChild!.lastElementChild as HTMLElement).innerText).toBe('afterTemplate');\n      });\n\n      it('should size work', () => {\n        testComponent.beforeContent = 'before';\n        fixture.detectChanges();\n        expect(inputGroupElement.classList).toContain('ant-input-group-wrapper');\n        testComponent.size = 'large';\n        fixture.detectChanges();\n        expect(inputGroupElement.classList).toContain('ant-input-group-wrapper-lg');\n        testComponent.size = 'small';\n        fixture.detectChanges();\n        expect(inputGroupElement.classList).toContain('ant-input-group-wrapper-sm');\n      });\n    });\n\n    describe('affix', () => {\n      let fixture: ComponentFixture<NzTestInputGroupAffixComponent>;\n      let testComponent: NzTestInputGroupAffixComponent;\n      let inputGroupElement: HTMLElement;\n\n      beforeEach(() => {\n        fixture = TestBed.createComponent(NzTestInputGroupAffixComponent);\n        testComponent = fixture.debugElement.componentInstance;\n        fixture.detectChanges();\n        inputGroupElement = fixture.debugElement.query(By.directive(NzInputGroupComponent)).nativeElement;\n      });\n\n      it('should not show addon without before and after content', () => {\n        expect(inputGroupElement.firstElementChild!.classList).toContain('ant-input');\n      });\n\n      it('should before content string work', () => {\n        testComponent.beforeContent = 'before';\n        fixture.detectChanges();\n        expect(inputGroupElement.firstElementChild!.classList).toContain('ant-input-prefix');\n        expect(inputGroupElement.children.length).toBe(2);\n        expect(inputGroupElement.lastElementChild!.classList).toContain('ant-input');\n        expect((inputGroupElement.firstElementChild as HTMLElement).innerText).toBe('before');\n      });\n\n      it('should before content template work', () => {\n        testComponent.beforeContent = testComponent.beforeTemplate;\n        fixture.detectChanges();\n        expect(inputGroupElement.firstElementChild!.classList).toContain('ant-input-prefix');\n        expect(inputGroupElement.children.length).toBe(2);\n        expect(inputGroupElement.lastElementChild!.classList).toContain('ant-input');\n        expect((inputGroupElement.firstElementChild as HTMLElement).innerText).toBe('beforeTemplate');\n      });\n\n      it('should after content string work', () => {\n        testComponent.afterContent = 'after';\n        fixture.detectChanges();\n        expect(inputGroupElement.lastElementChild!.classList).toContain('ant-input-suffix');\n        expect(inputGroupElement.children.length).toBe(2);\n        expect(inputGroupElement.firstElementChild!.classList).toContain('ant-input');\n        expect((inputGroupElement.lastElementChild as HTMLElement).innerText).toBe('after');\n      });\n\n      it('should after content template work', () => {\n        testComponent.afterContent = testComponent.afterTemplate;\n        fixture.detectChanges();\n        expect(inputGroupElement.lastElementChild!.classList).toContain('ant-input-suffix');\n        expect(inputGroupElement.children.length).toBe(2);\n        expect(inputGroupElement.firstElementChild!.classList).toContain('ant-input');\n        expect((inputGroupElement.lastElementChild as HTMLElement).innerText).toBe('afterTemplate');\n      });\n\n      it('should size work', () => {\n        testComponent.beforeContent = 'before';\n        fixture.detectChanges();\n        expect(inputGroupElement.classList).toContain('ant-input-affix-wrapper');\n        testComponent.size = 'large';\n        fixture.detectChanges();\n        expect(inputGroupElement.classList).toContain('ant-input-affix-wrapper-lg');\n        testComponent.size = 'small';\n        fixture.detectChanges();\n        expect(inputGroupElement.classList).toContain('ant-input-affix-wrapper-sm');\n      });\n\n      it('should disabled work', () => {\n        testComponent.beforeContent = 'before';\n        fixture.detectChanges();\n        expect(inputGroupElement.classList).not.toContain('ant-input-affix-wrapper-disabled');\n        testComponent.disabled = true;\n        fixture.detectChanges();\n        expect(inputGroupElement.classList).toContain('ant-input-affix-wrapper-disabled');\n      });\n\n      it('should focus work', () => {\n        testComponent.beforeContent = 'before';\n        fixture.detectChanges();\n        expect(inputGroupElement.classList).not.toContain('ant-input-affix-wrapper-focused');\n        dispatchFakeEvent(inputGroupElement.querySelector('input')!, 'focus');\n        fixture.detectChanges();\n        expect(inputGroupElement.classList).toContain('ant-input-affix-wrapper-focused');\n      });\n    });\n\n    describe('multiple', () => {\n      let fixture: ComponentFixture<NzTestInputGroupMultipleComponent>;\n      let testComponent: NzTestInputGroupMultipleComponent;\n      let inputGroupElement: HTMLElement;\n      beforeEach(() => {\n        fixture = TestBed.createComponent(NzTestInputGroupMultipleComponent);\n        testComponent = fixture.debugElement.componentInstance;\n        fixture.detectChanges();\n        inputGroupElement = fixture.debugElement.query(By.directive(NzInputGroupComponent)).nativeElement;\n      });\n\n      it('should search work', () => {\n        expect(inputGroupElement.classList).not.toContain('ant-input-search-enter-button');\n        expect(inputGroupElement.classList).not.toContain('ant-input-search');\n        testComponent.search = true;\n        fixture.detectChanges();\n        expect(inputGroupElement.classList).toContain('ant-input-search-enter-button');\n        expect(inputGroupElement.classList).toContain('ant-input-search');\n      });\n\n      it('should size work', () => {\n        expect(inputGroupElement.classList).toContain('ant-input-group');\n        testComponent.size = 'large';\n        fixture.detectChanges();\n        expect(inputGroupElement.classList).toContain('ant-input-group-lg');\n        testComponent.size = 'small';\n        fixture.detectChanges();\n        expect(inputGroupElement.classList).toContain('ant-input-group-sm');\n      });\n\n      it('should search size work', () => {\n        testComponent.search = true;\n        fixture.detectChanges();\n        expect(inputGroupElement.classList).toContain('ant-input-search');\n        testComponent.size = 'large';\n        fixture.detectChanges();\n        expect(inputGroupElement.classList).toContain('ant-input-search-large');\n        testComponent.size = 'small';\n        fixture.detectChanges();\n        expect(inputGroupElement.classList).toContain('ant-input-search-sm');\n      });\n    });\n\n    describe('mix', () => {\n      let fixture: ComponentFixture<NzTestInputGroupMixComponent>;\n      let inputGroupElement: HTMLElement;\n\n      beforeEach(() => {\n        fixture = TestBed.createComponent(NzTestInputGroupMixComponent);\n        fixture.detectChanges();\n        inputGroupElement = fixture.debugElement.query(By.directive(NzInputGroupComponent)).nativeElement;\n      });\n\n      it('should mix work', () => {\n        expect(inputGroupElement.querySelector('.ant-input-affix-wrapper')!.nextElementSibling!.classList).toContain(\n          'ant-input-group-addon'\n        );\n      });\n    });\n\n    describe('status', () => {\n      let fixture: ComponentFixture<NzTestInputGroupWithStatusComponent>;\n      let inputElement: DebugElement;\n\n      beforeEach(() => {\n        fixture = TestBed.createComponent(NzTestInputGroupWithStatusComponent);\n        fixture.detectChanges();\n        inputElement = fixture.debugElement.query(By.directive(NzInputGroupComponent));\n      });\n\n      it('should className correct with prefix', () => {\n        fixture.detectChanges();\n        expect(inputElement.nativeElement.classList).toContain('ant-input-affix-wrapper-status-error');\n\n        fixture.componentInstance.status = 'warning';\n        fixture.detectChanges();\n        expect(inputElement.nativeElement.className).toContain('ant-input-affix-wrapper-status-warning');\n\n        fixture.componentInstance.status = '';\n        fixture.detectChanges();\n        expect(inputElement.nativeElement.className).not.toContain('ant-input-affix-wrapper-status-warning');\n      });\n\n      it('should className correct with addon', () => {\n        fixture.componentInstance.isAddon = true;\n        fixture.detectChanges();\n        // re-query input element\n        inputElement = fixture.debugElement.query(By.directive(NzInputGroupComponent));\n        expect(inputElement.nativeElement.classList).toContain('ant-input-group-wrapper-status-error');\n\n        fixture.componentInstance.status = 'warning';\n        fixture.detectChanges();\n        expect(inputElement.nativeElement.className).toContain('ant-input-group-wrapper-status-warning');\n\n        fixture.componentInstance.status = '';\n        fixture.detectChanges();\n        expect(inputElement.nativeElement.className).not.toContain('ant-input-group-wrapper-status-warning');\n      });\n    });\n\n    describe('in form', () => {\n      let fixture: ComponentFixture<NzTestInputGroupInFormComponent>;\n      let inputElement: DebugElement;\n\n      beforeEach(() => {\n        fixture = TestBed.createComponent(NzTestInputGroupInFormComponent);\n        inputElement = fixture.debugElement.query(By.directive(NzInputGroupComponent));\n        fixture.detectChanges();\n      });\n\n      it('should className correct', () => {\n        fixture.detectChanges();\n        expect(inputElement.nativeElement.classList).toContain('ant-input-affix-wrapper-status-error');\n        expect(inputElement.nativeElement.querySelector('nz-form-item-feedback-icon')).toBeTruthy();\n\n        fixture.componentInstance.status = 'warning';\n        fixture.detectChanges();\n        expect(inputElement.nativeElement.classList).toContain('ant-input-affix-wrapper-status-warning');\n\n        fixture.componentInstance.status = 'success';\n        fixture.detectChanges();\n        expect(inputElement.nativeElement.classList).toContain('ant-input-affix-wrapper-status-success');\n\n        fixture.componentInstance.feedback = false;\n        fixture.detectChanges();\n        expect(inputElement.nativeElement.querySelector('nz-form-item-feedback-icon')).toBeNull();\n      });\n\n      it('should className correct with addon', () => {\n        fixture.componentInstance.addon = 'before';\n        fixture.detectChanges();\n        fixture.componentInstance.status = 'warning';\n        fixture.detectChanges();\n        expect(inputElement.nativeElement.classList).toContain('ant-input-group-wrapper-status-warning');\n        expect(inputElement.nativeElement.classList).not.toContain('ant-input-affix-wrapper-status-warning');\n      });\n    });\n  });\n});\n\n@Component({\n  imports: [NzInputModule],\n  template: `\n    <nz-input-group [nzAddOnBefore]=\"beforeContent\" [nzAddOnAfter]=\"afterContent\" [nzSize]=\"size\">\n      <input type=\"text\" nz-input />\n    </nz-input-group>\n    <ng-template #beforeTemplate>beforeTemplate</ng-template>\n    <ng-template #afterTemplate>afterTemplate</ng-template>\n  `\n})\nexport class NzTestInputGroupAddonComponent {\n  @ViewChild('beforeTemplate', { static: false }) beforeTemplate!: TemplateRef<void>;\n  @ViewChild('afterTemplate', { static: false }) afterTemplate!: TemplateRef<void>;\n  beforeContent?: string | TemplateRef<void>;\n  afterContent?: string | TemplateRef<void>;\n  size: NzSizeLDSType = 'default';\n}\n\n@Component({\n  imports: [NzInputModule],\n  template: `\n    <nz-input-group [nzPrefix]=\"beforeContent\" [nzSuffix]=\"afterContent\" [nzSize]=\"size\">\n      <input type=\"text\" nz-input [disabled]=\"disabled\" />\n    </nz-input-group>\n    <ng-template #beforeTemplate>beforeTemplate</ng-template>\n    <ng-template #afterTemplate>afterTemplate</ng-template>\n  `\n})\nexport class NzTestInputGroupAffixComponent {\n  @ViewChild('beforeTemplate', { static: false }) beforeTemplate!: TemplateRef<void>;\n  @ViewChild('afterTemplate', { static: false }) afterTemplate!: TemplateRef<void>;\n  beforeContent?: string | TemplateRef<void>;\n  afterContent?: string | TemplateRef<void>;\n  size: NzSizeLDSType = 'default';\n  disabled = false;\n}\n\n@Component({\n  imports: [NzInputModule],\n  template: `\n    <nz-input-group [nzSearch]=\"search\" [nzSize]=\"size\">\n      <input type=\"text\" nz-input />\n      <input type=\"text\" nz-input />\n    </nz-input-group>\n  `\n})\nexport class NzTestInputGroupMultipleComponent {\n  search = false;\n  size: NzSizeLDSType = 'default';\n}\n\n/** https://github.com/NG-ZORRO/ng-zorro-antd/issues/1795 **/\n@Component({\n  imports: [NzInputModule],\n  template: `\n    <nz-input-group nzPrefixIcon=\"user\" nzAddOnAfter=\"@example.com\">\n      <input type=\"text\" nz-input placeholder=\"邮箱地址\" />\n    </nz-input-group>\n  `\n})\nexport class NzTestInputGroupMixComponent {}\n\n@Component({\n  imports: [FormsModule, NzGridModule, NzInputModule],\n  template: `\n    <nz-input-group>\n      <div nz-col nzSpan=\"4\">\n        <input type=\"text\" nz-input ngModel=\"0571\" />\n      </div>\n      <div nz-col nzSpan=\"8\">\n        <input type=\"text\" nz-input ngModel=\"26888888\" />\n      </div>\n    </nz-input-group>\n  `\n})\nexport class NzTestInputGroupColComponent {}\n\n@Component({\n  imports: [NzInputModule, NzIconModule],\n  template: `\n    @if (!isAddon) {\n      <nz-input-group [nzPrefix]=\"prefixTemplateClock\" [nzStatus]=\"status\">\n        <input type=\"text\" nz-input />\n      </nz-input-group>\n      <ng-template #prefixTemplateClock>\n        <nz-icon nzType=\"clock-circle\" nzTheme=\"outline\" />\n      </ng-template>\n    } @else {\n      <nz-input-group nzAddOnAfterIcon=\"setting\" [nzStatus]=\"status\">\n        <input type=\"text\" nz-input />\n      </nz-input-group>\n    }\n  `\n})\nexport class NzTestInputGroupWithStatusComponent {\n  isAddon = false;\n  status: NzStatus = 'error';\n}\n\n@Component({\n  imports: [ReactiveFormsModule, NzFormModule, NzInputModule],\n  template: `\n    <form nz-form>\n      <nz-form-item>\n        <nz-form-control [nzHasFeedback]=\"feedback\" [nzValidateStatus]=\"status\">\n          <nz-input-group [nzAddOnBefore]=\"addon\">\n            <input type=\"text\" nz-input />\n          </nz-input-group>\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `\n})\nexport class NzTestInputGroupInFormComponent {\n  status: NzFormControlStatusType = 'error';\n  feedback = true;\n  addon: string = '';\n}\n"
  },
  {
    "path": "components/input/input-otp.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BACKSPACE, LEFT_ARROW, RIGHT_ARROW } from '@angular/cdk/keycodes';\nimport {\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  Component,\n  DestroyRef,\n  ElementRef,\n  forwardRef,\n  inject,\n  Input,\n  numberAttribute,\n  OnChanges,\n  QueryList,\n  SimpleChanges,\n  ViewChildren,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport {\n  ControlValueAccessor,\n  FormArray,\n  FormBuilder,\n  FormControl,\n  NG_VALUE_ACCESSOR,\n  ReactiveFormsModule,\n  Validators\n} from '@angular/forms';\nimport { tap } from 'rxjs/operators';\n\nimport { NzSafeAny, NzSizeLDSType, NzStatus, OnTouchedType } from 'ng-zorro-antd/core/types';\n\nimport { NzInputDirective } from './input.directive';\n\n@Component({\n  selector: 'nz-input-otp',\n  exportAs: 'nzInputOtp',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    @for (item of otpArray.controls; track $index) {\n      <input\n        nz-input\n        class=\"ant-otp-input\"\n        type=\"text\"\n        maxlength=\"1\"\n        size=\"1\"\n        [nzSize]=\"nzSize\"\n        [formControl]=\"item\"\n        [nzStatus]=\"nzStatus\"\n        (input)=\"onInput($index, $event)\"\n        (focus)=\"onFocus($event)\"\n        (keydown)=\"onKeyDown($index, $event)\"\n        (paste)=\"onPaste($index, $event)\"\n        #otpInput\n      />\n    }\n  `,\n  host: {\n    class: 'ant-otp'\n  },\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => NzInputOtpComponent),\n      multi: true\n    }\n  ],\n  imports: [NzInputDirective, ReactiveFormsModule]\n})\nexport class NzInputOtpComponent implements ControlValueAccessor, OnChanges {\n  private formBuilder = inject(FormBuilder);\n  private destroyRef = inject(DestroyRef);\n\n  @ViewChildren('otpInput') otpInputs!: QueryList<ElementRef>;\n\n  @Input({ transform: numberAttribute }) nzLength: number = 6;\n  @Input() nzSize: NzSizeLDSType = 'default';\n  @Input({ transform: booleanAttribute }) disabled = false;\n  @Input() nzStatus: NzStatus = '';\n  @Input() nzFormatter: (value: string) => string = value => value;\n  @Input() nzMask: string | null = null;\n\n  protected otpArray!: FormArray<FormControl<string>>;\n  private internalValue: string[] = [];\n  private onChangeCallback?: (_: NzSafeAny) => void;\n  onTouched: OnTouchedType = () => {};\n\n  constructor() {\n    this.createFormArray();\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    if (changes['nzLength']?.currentValue) {\n      this.createFormArray();\n    }\n\n    if (changes['disabled']) {\n      this.setDisabledState(this.disabled);\n    }\n  }\n\n  onInput(index: number, event: Event): void {\n    const inputElement = event.target as HTMLInputElement;\n    const nextInput = this.otpInputs.toArray()[index + 1];\n\n    if (inputElement.value && nextInput) {\n      nextInput.nativeElement.focus();\n    } else if (!nextInput) {\n      this.selectInputBox(index);\n    }\n  }\n\n  onFocus(event: FocusEvent): void {\n    const inputElement = event.target as HTMLInputElement;\n    inputElement.select();\n  }\n\n  onKeyDown(index: number, event: KeyboardEvent): void {\n    const previousInput = this.otpInputs.toArray()[index - 1];\n\n    if (event.keyCode === BACKSPACE) {\n      event.preventDefault();\n\n      this.internalValue[index] = '';\n      this.otpArray.at(index).setValue('', { emitEvent: false });\n\n      if (previousInput) {\n        this.selectInputBox(index - 1);\n      }\n\n      this.emitValue();\n    } else if (event.keyCode === LEFT_ARROW) {\n      event.preventDefault();\n      this.selectInputBox(index - 1);\n    } else if (event.keyCode === RIGHT_ARROW) {\n      event.preventDefault();\n      this.selectInputBox(index + 1);\n    }\n  }\n\n  writeValue(value: string): void {\n    if (!value) {\n      this.otpArray.reset();\n      return;\n    }\n\n    const controlValues = value.split('');\n    this.internalValue = controlValues;\n\n    controlValues.forEach((val, i) => {\n      const formattedValue = this.nzFormatter(val);\n      const value = this.nzMask ? this.nzMask : formattedValue;\n      this.otpArray.at(i).setValue(value, { emitEvent: false });\n    });\n  }\n\n  registerOnChange(fn: (value: string) => void): void {\n    this.onChangeCallback = fn;\n  }\n\n  registerOnTouched(fn: () => {}): void {\n    this.onTouched = fn;\n  }\n\n  setDisabledState(isDisabled: boolean): void {\n    if (isDisabled) {\n      this.otpArray.disable();\n    } else {\n      this.otpArray.enable();\n    }\n  }\n\n  onPaste(index: number, event: ClipboardEvent): void {\n    const pastedText = event.clipboardData?.getData('text') || '';\n    if (!pastedText) return;\n\n    let currentIndex = index;\n    for (const char of pastedText.split('')) {\n      if (currentIndex < this.nzLength) {\n        const formattedChar = this.nzFormatter(char);\n        this.internalValue[currentIndex] = char;\n        const maskedValue = this.nzMask ? this.nzMask : formattedChar;\n        this.otpArray.at(currentIndex).setValue(maskedValue, { emitEvent: false });\n        currentIndex++;\n      } else {\n        break;\n      }\n    }\n\n    event.preventDefault(); // this line is needed, otherwise the last index that is going to be selected will also be filled (in the next line).\n    this.selectInputBox(currentIndex);\n    this.emitValue();\n  }\n\n  private createFormArray(): void {\n    this.otpArray = this.formBuilder.array<FormControl<string>>([]);\n    this.internalValue = new Array(this.nzLength).fill('');\n\n    for (let i = 0; i < this.nzLength; i++) {\n      const control = this.formBuilder.nonNullable.control('', [Validators.required]);\n\n      control.valueChanges\n        .pipe(\n          tap(value => {\n            const unmaskedValue = this.nzFormatter(value);\n            this.internalValue[i] = unmaskedValue;\n\n            control.setValue(this.nzMask ?? unmaskedValue, { emitEvent: false });\n\n            this.emitValue();\n          }),\n          takeUntilDestroyed(this.destroyRef)\n        )\n        .subscribe();\n\n      this.otpArray.push(control);\n    }\n  }\n\n  private emitValue(): void {\n    const result = this.internalValue.join('');\n    if (this.onChangeCallback) {\n      this.onChangeCallback(result);\n    }\n  }\n\n  private selectInputBox(index: number): void {\n    const otpInputArray = this.otpInputs.toArray();\n    if (index <= 0) index = 0;\n    if (index >= otpInputArray.length) index = otpInputArray.length - 1;\n\n    otpInputArray[index].nativeElement.select();\n  }\n}\n"
  },
  {
    "path": "components/input/input-otp.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BACKSPACE } from '@angular/cdk/keycodes';\nimport { DebugElement } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { FormArray, FormControl } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { NzInputOtpComponent } from 'ng-zorro-antd/input/input-otp.component';\n\ndescribe('NzInputOtpComponent', () => {\n  let component: NzInputOtpComponent;\n  let fixture: ComponentFixture<NzInputOtpComponent>;\n  let inputElements: DebugElement[];\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzInputOtpComponent);\n    component = fixture.componentInstance;\n    component.nzLength = 6;\n    fixture.detectChanges();\n\n    inputElements = fixture.debugElement.queryAll(By.css('.ant-otp-input'));\n  });\n\n  it('should create', () => {\n    expect(component).toBeTruthy();\n  });\n\n  it('should initialize form controls based on nzLength', () => {\n    expect(component['otpArray'].controls).toBeTruthy();\n    expect(component['otpArray'].length).toBe(6);\n  });\n\n  it('should format the value on input using nzFormatter', () => {\n    component.nzFormatter = value => value.toUpperCase();\n    inputElements[0].nativeElement.value = 'a';\n    inputElements[0].triggerEventHandler('input', { target: inputElements[0].nativeElement });\n\n    fixture.detectChanges();\n    expect(component['otpArray'].at(0).value).toBe('A');\n  });\n\n  it('should apply nzMask if defined', () => {\n    component.nzMask = '*';\n    inputElements[0].nativeElement.value = '1';\n    inputElements[0].triggerEventHandler('input', { target: inputElements[0].nativeElement });\n\n    fixture.detectChanges();\n    expect(component['otpArray'].at(0).value).toBe('*');\n    expect(component['internalValue'][0]).toBe('1');\n  });\n\n  it('should focus on the next input after input is entered', () => {\n    spyOn(inputElements[1].nativeElement, 'focus');\n    inputElements[0].nativeElement.value = '2';\n    inputElements[0].triggerEventHandler('input', { target: inputElements[0].nativeElement });\n\n    fixture.detectChanges();\n    expect(inputElements[1].nativeElement.focus).toHaveBeenCalled();\n  });\n\n  it('should handle Backspace key to delete and select on previous input', () => {\n    inputElements[1].nativeElement.value = '3';\n    inputElements[1].triggerEventHandler('input', { target: inputElements[1].nativeElement });\n    fixture.detectChanges();\n\n    spyOn(inputElements[0].nativeElement, 'select');\n    const event = new KeyboardEvent('keydown', { keyCode: BACKSPACE });\n    inputElements[1].triggerEventHandler('keydown', event);\n\n    fixture.detectChanges();\n    expect(inputElements[0].nativeElement.select).toHaveBeenCalled();\n    expect(component['otpArray'].at(1).value).toBe('');\n  });\n\n  it('should handle paste event and correctly distribute characters', () => {\n    const event = new ClipboardEvent('paste', {\n      clipboardData: new DataTransfer()\n    });\n    event.clipboardData?.setData('text', '123456');\n    spyOn(event, 'preventDefault');\n\n    inputElements[0].triggerEventHandler('paste', event);\n    fixture.detectChanges();\n\n    expect(event.preventDefault).toHaveBeenCalled();\n    expect(component['otpArray'].at(0).value).toBe('1');\n    expect(component['otpArray'].at(1).value).toBe('2');\n    expect(component['otpArray'].at(2).value).toBe('3');\n    expect(component['otpArray'].at(3).value).toBe('4');\n    expect(component['otpArray'].at(4).value).toBe('5');\n    expect(component['otpArray'].at(5).value).toBe('6');\n  });\n\n  it('should update internal value correctly on paste event with nzMask', () => {\n    component.nzMask = '*';\n    const event = new ClipboardEvent('paste', {\n      clipboardData: new DataTransfer()\n    });\n    event.clipboardData?.setData('text', '789');\n    spyOn(event, 'preventDefault');\n\n    inputElements[0].triggerEventHandler('paste', event);\n    fixture.detectChanges();\n\n    expect(event.preventDefault).toHaveBeenCalled();\n    expect(component['otpArray'].at(0).value).toBe('*');\n    expect(component['internalValue'][0]).toBe('7');\n    expect(component['otpArray'].at(1).value).toBe('*');\n    expect(component['internalValue'][1]).toBe('8');\n    expect(component['otpArray'].at(2).value).toBe('*');\n    expect(component['internalValue'][2]).toBe('9');\n  });\n\n  it('should disable all inputs when setDisabledState is called with true', () => {\n    component.setDisabledState(true);\n    fixture.detectChanges();\n\n    inputElements.forEach(input => {\n      expect(input.nativeElement.disabled).toBe(true);\n    });\n  });\n\n  it('should recreate form array when nzLength changes', () => {\n    component.nzLength = 6;\n    component['createFormArray']();\n    const initialFormArray = component['otpArray'];\n\n    component.nzLength = 8;\n    component.ngOnChanges({\n      nzLength: {\n        currentValue: 8,\n        previousValue: 6,\n        firstChange: false,\n        isFirstChange: () => false\n      }\n    });\n\n    expect(component['otpArray']).not.toBe(initialFormArray);\n    expect(component['otpArray'].length).toBe(8);\n  });\n\n  it('should set disabled state correctly when disabled input changes', () => {\n    (component as NzSafeAny)['otpArray'] = new FormArray([]);\n    const spy = spyOn(component['otpArray'], 'disable').and.callThrough();\n    const enableSpy = spyOn(component['otpArray'], 'enable').and.callThrough();\n\n    component.disabled = true;\n    component.ngOnChanges({\n      disabled: {\n        currentValue: true,\n        previousValue: false,\n        firstChange: false,\n        isFirstChange: () => false\n      }\n    });\n\n    expect(spy).toHaveBeenCalled();\n    expect(enableSpy).not.toHaveBeenCalled();\n  });\n\n  it('should reset form array if the provided value is empty', () => {\n    const spy = spyOn(component['otpArray'], 'reset');\n\n    component.writeValue('');\n\n    expect(spy).toHaveBeenCalled();\n  });\n\n  it('should set formatted values correctly in the form array', () => {\n    component.nzFormatter = value => value.toUpperCase();\n    component['createFormArray']();\n\n    component.writeValue('abcd');\n\n    expect(component['otpArray'].at(0).value).toBe('A');\n    expect(component['otpArray'].at(1).value).toBe('B');\n    expect(component['otpArray'].at(2).value).toBe('C');\n    expect(component['otpArray'].at(3).value).toBe('D');\n  });\n\n  it('should register onChange callback', () => {\n    const callback = jasmine.createSpy('onChangeCallback');\n    component.registerOnChange(callback);\n\n    component['onChangeCallback']?.('test value');\n\n    expect(callback).toHaveBeenCalledWith('test value');\n  });\n\n  it('should register onTouched callback', () => {\n    const callback = jasmine.createSpy('onTouched');\n    component.registerOnTouched(callback);\n\n    component.onTouched();\n\n    expect(callback).toHaveBeenCalled();\n  });\n\n  it('should enable form array when setDisabledState is called with false', () => {\n    component['otpArray'] = new FormArray<FormControl<string>>([\n      new FormControl<string>('', { nonNullable: true }),\n      new FormControl<string>('', { nonNullable: true }),\n      new FormControl<string>('', { nonNullable: true }),\n      new FormControl<string>('', { nonNullable: true }),\n      new FormControl<string>('', { nonNullable: true }),\n      new FormControl<string>('', { nonNullable: true })\n    ]);\n\n    const spy = spyOn(component['otpArray'], 'enable').and.callThrough();\n    const disableSpy = spyOn(component['otpArray'], 'disable').and.callThrough();\n\n    component.setDisabledState(false);\n\n    expect(spy).toHaveBeenCalled();\n    expect(disableSpy).not.toHaveBeenCalled();\n  });\n\n  it('should call onChangeCallback with the joined internalValue', () => {\n    component['internalValue'] = ['1', '2', '3', '4', '5', '6'];\n    const callback = jasmine.createSpy('onChangeCallback');\n    component['onChangeCallback'] = callback;\n\n    component['emitValue']();\n\n    expect(callback).toHaveBeenCalledWith('123456');\n  });\n});\n"
  },
  {
    "path": "components/input/input-password.directive.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\n\nimport { NzInputModule } from './input.module';\n\ndescribe('input-password', () => {\n  let component: InputPasswordTestComponent;\n  let fixture: ComponentFixture<InputPasswordTestComponent>;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(InputPasswordTestComponent);\n    component = fixture.componentInstance;\n    fixture.autoDetectChanges();\n  });\n\n  it('should be apply classes', () => {\n    const passwordElement = fixture.nativeElement.querySelector('nz-input-password');\n    expect(passwordElement.classList).toContain('ant-input-password');\n  });\n\n  it('should be toggle visible by two-way binding', () => {\n    const inputElement = fixture.nativeElement.querySelector('input');\n    expect(inputElement.type).toEqual('password');\n    component.visible = true;\n    fixture.detectChanges();\n    expect(inputElement.type).toEqual('text');\n  });\n\n  it('should be toggle visible by click toggle button', () => {\n    const inputElement = fixture.nativeElement.querySelector('input');\n    const toggleElement = fixture.nativeElement.querySelector('.ant-input-password-icon');\n    expect(inputElement.type).toEqual('password');\n    expect(component.visible).toBe(false);\n    toggleElement.click();\n    fixture.detectChanges();\n    expect(inputElement.type).toEqual('text');\n    expect(component.visible).toBe(true);\n    toggleElement.click();\n    fixture.detectChanges();\n    expect(inputElement.type).toEqual('password');\n    expect(component.visible).toBe(false);\n  });\n\n  it('should be hide toggle', () => {\n    expect(fixture.nativeElement.querySelector('.ant-input-password-icon')).toBeTruthy();\n    component.visibilityToggle = false;\n    fixture.detectChanges();\n    expect(fixture.nativeElement.querySelector('.ant-input-password-icon')).toBeFalsy();\n  });\n\n  it('should be custom icon', () => {\n    component.customeIcon = true;\n    fixture.detectChanges();\n    expect(fixture.nativeElement.querySelector('.ant-input-password-icon').textContent.trim()).toEqual('show');\n    component.visible = true;\n    fixture.detectChanges();\n    expect(fixture.nativeElement.querySelector('.ant-input-password-icon').textContent.trim()).toEqual('hide');\n  });\n});\n\n@Component({\n  imports: [NzInputModule],\n  template: `\n    <nz-input-password [nzVisibilityToggle]=\"visibilityToggle\" [(nzVisible)]=\"visible\">\n      <input nz-input />\n      @if (customeIcon) {\n        <ng-template nzInputPasswordIcon let-visible>{{ visible ? 'hide' : 'show' }}</ng-template>\n      }\n    </nz-input-password>\n  `\n})\nclass InputPasswordTestComponent {\n  visibilityToggle = true;\n  visible = false;\n  customeIcon = false;\n}\n"
  },
  {
    "path": "components/input/input-password.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, input, model } from '@angular/core';\n\n@Directive({\n  selector: 'nz-input-password',\n  exportAs: 'nzInputPassword',\n  host: {\n    class: 'ant-input-password'\n  }\n})\nexport class NzInputPasswordDirective {\n  readonly nzVisibilityToggle = input(true);\n  readonly nzVisible = model(false);\n\n  toggleVisible(): void {\n    this.nzVisible.update(value => !value);\n  }\n}\n\n@Directive({\n  selector: '[nzInputPasswordIcon]'\n})\nexport class NzInputPasswordIconDirective {\n  /**\n   * @internal\n   */\n  static ngTemplateContextGuard(_: NzInputPasswordIconDirective, context: unknown): context is { $implicit: boolean } {\n    return true;\n  }\n}\n"
  },
  {
    "path": "components/input/input-search.directive.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { FormsModule } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\n\nimport { NzSizeLDSType } from 'ng-zorro-antd/core/types';\n\nimport { NzInputSearchDirective, NzInputSearchEvent } from './input-search.directive';\nimport { NzInputModule } from './input.module';\n\ndescribe('input-search', () => {\n  let component: InputSearchTestComponent;\n  let fixture: ComponentFixture<InputSearchTestComponent>;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(InputSearchTestComponent);\n    component = fixture.componentInstance;\n    fixture.autoDetectChanges();\n  });\n\n  it('should be apply classes', () => {\n    const searchElement: HTMLElement = fixture.debugElement.query(By.directive(NzInputSearchDirective)).nativeElement;\n    expect(searchElement.classList).toContain('ant-input-search');\n    expect(searchElement.classList).toContain('ant-input-group-wrapper');\n  });\n\n  it('should be apply size classes', () => {\n    const searchElement: HTMLElement = fixture.debugElement.query(By.directive(NzInputSearchDirective)).nativeElement;\n    component.size = 'small';\n    fixture.detectChanges();\n    expect(searchElement.classList).toContain('ant-input-search-small');\n    component.size = 'large';\n    fixture.detectChanges();\n    expect(searchElement.classList).toContain('ant-input-search-large');\n  });\n\n  it('should be apply button classes', async () => {\n    const searchElement: HTMLElement = fixture.debugElement.query(By.directive(NzInputSearchDirective)).nativeElement;\n    expect(searchElement.classList).not.toContain('ant-input-search-with-button');\n    component.enterButton = true;\n    fixture.detectChanges();\n    await fixture.whenStable();\n    expect(searchElement.classList).toContain('ant-input-search-with-button');\n    component.enterButton = 'submit';\n    fixture.detectChanges();\n    await fixture.whenStable();\n    expect(searchElement.classList).toContain('ant-input-search-with-button');\n    component.enterButton = '';\n    fixture.detectChanges();\n    await fixture.whenStable();\n    expect(searchElement.classList).toContain('ant-input-search-with-button');\n  });\n\n  it('should be input type = search', () => {\n    const inputElement: HTMLInputElement = fixture.nativeElement.querySelector('input');\n    expect(inputElement.type).toEqual('search');\n  });\n\n  it('should be render search button', async () => {\n    const searchButtonElement: HTMLButtonElement = fixture.nativeElement.querySelector('.ant-input-search-button');\n    expect(searchButtonElement).toBeTruthy();\n    expect(searchButtonElement.classList).toContain('ant-btn-default');\n    component.enterButton = true;\n    fixture.detectChanges();\n    await fixture.whenStable();\n    expect(searchButtonElement.classList).toContain('ant-btn-primary');\n    component.enterButton = '';\n    fixture.detectChanges();\n    await fixture.whenStable();\n    expect(searchButtonElement.classList).toContain('ant-btn-primary');\n  });\n\n  it('should be render search icon when enterButton is an empty string', async () => {\n    const searchButtonElement: HTMLButtonElement = fixture.nativeElement.querySelector('.ant-input-search-button');\n    component.enterButton = '';\n    fixture.detectChanges();\n    await fixture.whenStable();\n    const searchIconElement = searchButtonElement.querySelector('.anticon-search');\n    expect(searchIconElement).toBeTruthy();\n  });\n\n  it('should be apply size classes to search button', async () => {\n    const searchButtonElement: HTMLButtonElement = fixture.nativeElement.querySelector('.ant-input-search-button');\n    expect(searchButtonElement).toBeTruthy();\n    component.size = 'small';\n    fixture.detectChanges();\n    await fixture.whenStable();\n    expect(searchButtonElement.classList).toContain('ant-btn-sm');\n    component.size = 'large';\n    fixture.detectChanges();\n    await fixture.whenStable();\n    expect(searchButtonElement.classList).toContain('ant-btn-lg');\n  });\n\n  it('should be loading work', async () => {\n    const searchButtonElement: HTMLButtonElement = fixture.nativeElement.querySelector('.ant-input-search-button');\n    component.loading = true;\n    fixture.detectChanges();\n    await fixture.whenStable();\n    expect(searchButtonElement.classList).toContain('ant-btn-loading');\n  });\n\n  describe('should be disabled work', () => {\n    it('by input', async () => {\n      const searchButtonElement: HTMLButtonElement = fixture.nativeElement.querySelector('.ant-input-search-button');\n      component.enterButton = 'submit';\n      fixture.detectChanges();\n      await fixture.whenStable();\n      expect(searchButtonElement.textContent.trim()).toEqual('submit');\n    });\n\n    it('by ng-content', async () => {\n      const fixture = TestBed.createComponent(InputSearchCustomEnterButtonTestComponent);\n      fixture.autoDetectChanges();\n      const searchButtonElement: HTMLButtonElement = fixture.nativeElement.querySelector('.ant-input-search-button');\n      await fixture.whenStable();\n      expect(searchButtonElement.textContent.trim()).toEqual('custom');\n    });\n  });\n\n  it('should be emit search event when click search button', async () => {\n    spyOn(component, 'onSearch');\n    const searchButtonElement: HTMLButtonElement = fixture.nativeElement.querySelector('.ant-input-search-button');\n    component.value = 'test';\n    fixture.detectChanges();\n    await fixture.whenStable();\n    searchButtonElement.click();\n    expect(component.onSearch).toHaveBeenCalledTimes(1);\n    expect(component.onSearch).toHaveBeenCalledWith({ value: 'test', event: jasmine.any(Event), source: 'input' });\n  });\n\n  it('should be emit search event when keydown enter', async () => {\n    spyOn(component, 'onSearch');\n    const inputElement: HTMLInputElement = fixture.nativeElement.querySelector('input');\n    component.value = 'test';\n    fixture.detectChanges();\n    await fixture.whenStable();\n    inputElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }));\n    expect(component.onSearch).toHaveBeenCalledTimes(1);\n    expect(component.onSearch).toHaveBeenCalledWith({ value: 'test', event: jasmine.any(Event), source: 'input' });\n  });\n\n  it('should be emit search event when click clear button', async () => {\n    spyOn(component, 'onSearch');\n    const clearButtonElement: HTMLElement = fixture.nativeElement.querySelector('.ant-input-clear-icon');\n    component.value = 'test';\n    fixture.detectChanges();\n    await fixture.whenStable();\n    clearButtonElement.click();\n    expect(component.onSearch).toHaveBeenCalledTimes(1);\n    expect(component.onSearch).toHaveBeenCalledWith({ value: '', event: jasmine.any(Event), source: 'clear' });\n  });\n\n  it('should not emit search event when loading', async () => {\n    spyOn(component, 'onSearch');\n    const searchButtonElement: HTMLButtonElement = fixture.nativeElement.querySelector('.ant-input-search-button');\n    const inputElement: HTMLInputElement = fixture.nativeElement.querySelector('input');\n    const clearButtonElement: HTMLElement = fixture.nativeElement.querySelector('.ant-input-clear-icon');\n    component.value = 'test';\n    component.loading = true;\n    fixture.detectChanges();\n    await fixture.whenStable();\n    searchButtonElement.click();\n    clearButtonElement.click();\n    inputElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }));\n    expect(component.onSearch).not.toHaveBeenCalled();\n  });\n});\n\n@Component({\n  imports: [NzInputModule, FormsModule],\n  template: `\n    <nz-input-search nzAllowClear [nzLoading]=\"loading\" [nzEnterButton]=\"enterButton\" (nzSearch)=\"onSearch($event)\">\n      <input nz-input [(ngModel)]=\"value\" [nzSize]=\"size\" />\n    </nz-input-search>\n  `\n})\nclass InputSearchTestComponent {\n  loading = false;\n  enterButton: boolean | string = false;\n  value = '';\n  size: NzSizeLDSType = 'default';\n\n  onSearch(_event: NzInputSearchEvent): void {}\n}\n\n@Component({\n  imports: [NzInputModule],\n  template: `\n    <nz-input-search>\n      <input nz-input />\n      <span nzInputSearchEnterButton>custom</span>\n    </nz-input-search>\n  `\n})\nclass InputSearchCustomEnterButtonTestComponent {}\n"
  },
  {
    "path": "components/input/input-search.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  booleanAttribute,\n  computed,\n  contentChild,\n  Directive,\n  ElementRef,\n  forwardRef,\n  input,\n  output\n} from '@angular/core';\n\nimport { NzInputDirective } from './input.directive';\nimport { NZ_INPUT_SEARCH } from './tokens';\n\n@Directive({\n  selector: 'nz-input-search',\n  exportAs: 'nzInputSearch',\n  providers: [{ provide: NZ_INPUT_SEARCH, useExisting: forwardRef(() => NzInputSearchDirective) }],\n  host: {\n    class: 'ant-input-search',\n    '[class.ant-input-search-large]': `size() === 'large'`,\n    '[class.ant-input-search-small]': `size() === 'small'`,\n    '[class.ant-input-search-with-button]': 'nzEnterButton() !== false',\n    '(keydown.enter)': 'onEnter($any($event))'\n  }\n})\nexport class NzInputSearchDirective {\n  private readonly inputDir = contentChild.required(NzInputDirective);\n  private readonly inputRef = contentChild.required(NzInputDirective, { read: ElementRef });\n\n  readonly nzEnterButton = input<boolean | string>(false);\n  readonly nzLoading = input(false, { transform: booleanAttribute });\n\n  readonly nzSearch = output<NzInputSearchEvent>();\n\n  readonly size = computed(() => this.inputDir().nzSize());\n\n  search(event: Event, source: 'input' | 'clear' = 'input'): void {\n    if (!this.nzLoading()) {\n      this.nzSearch.emit({ value: this.inputRef().nativeElement.value, event, source });\n    }\n  }\n\n  onEnter(event: KeyboardEvent): void {\n    if (event.target === this.inputRef().nativeElement) {\n      this.search(event);\n    }\n  }\n}\n\n@Directive({\n  selector: '[nzInputSearchEnterButton]'\n})\nexport class NzInputSearchEnterButtonDirective {}\n\nexport interface NzInputSearchEvent {\n  value: string;\n  event: Event;\n  source: 'clear' | 'input';\n}\n"
  },
  {
    "path": "components/input/input-wrapper.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, ElementRef, provideZoneChangeDetection, viewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSizeLDSType, NzVariant } from 'ng-zorro-antd/core/types';\n\nimport { NzCountConfig } from './input-wrapper.component';\nimport { NzInputModule } from './input.module';\n\ndescribe('input-wrapper', () => {\n  let component: InputWithAffixesAndAddonsTestComponent;\n  let fixture: ComponentFixture<InputWithAffixesAndAddonsTestComponent>;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(InputWithAffixesAndAddonsTestComponent);\n    component = fixture.componentInstance;\n    fixture.autoDetectChanges();\n  });\n\n  it('should be apply affix classes', () => {\n    expect(component.withPropAffixes().nativeElement.classList).toContain('ant-input-affix-wrapper');\n    expect(component.withContentAffixes().nativeElement.classList).toContain('ant-input-affix-wrapper');\n  });\n\n  it('should be apply addon classes', () => {\n    expect(component.withPropAddons().nativeElement.classList).toContain('ant-input-group-wrapper');\n    expect(component.withContentAddons().nativeElement.classList).toContain('ant-input-group-wrapper');\n  });\n\n  it('should be apply mix classes', () => {\n    expect(component.withPropMix().nativeElement.classList).toContain('ant-input-group-wrapper');\n    expect(component.withPropMix().nativeElement.classList).toContain('ant-input-group-wrapper');\n    expect(component.withContentMix().nativeElement.classList).toContain('ant-input-group-wrapper');\n    expect(component.withContentMix().nativeElement.querySelector('.ant-input-affix-wrapper')).toBeTruthy();\n  });\n\n  it('should be not apply affix or addon classes when only input is present', () => {\n    expect(component.onlyInput().nativeElement.classList).not.toContain('ant-input-group-wrapper');\n    expect(component.onlyInput().nativeElement.classList).not.toContain('ant-input-affix-wrapper');\n  });\n\n  it('should be apply size class', () => {\n    component.size = 'large';\n    fixture.detectChanges();\n    expect(component.withPropAffixes().nativeElement.classList).toContain('ant-input-affix-wrapper-lg');\n    expect(component.withPropAddons().nativeElement.classList).toContain('ant-input-group-wrapper-lg');\n    component.size = 'small';\n    fixture.detectChanges();\n    expect(component.withPropAffixes().nativeElement.classList).toContain('ant-input-affix-wrapper-sm');\n    expect(component.withPropAddons().nativeElement.classList).toContain('ant-input-group-wrapper-sm');\n  });\n\n  it('should be apply disabled class', () => {\n    component.disabled = true;\n    fixture.detectChanges();\n    expect(component.withContentAffixes().nativeElement.classList).toContain('ant-input-affix-wrapper-disabled');\n  });\n\n  it('should be apply readonly class', () => {\n    component.readonly = true;\n    fixture.detectChanges();\n    expect(component.withContentAffixes().nativeElement.classList).toContain('ant-input-affix-wrapper-readonly');\n  });\n\n  describe('should be apply variant class', () => {\n    it('filled', () => {\n      fixture.detectChanges();\n      expect(component.withContentAffixes().nativeElement.classList).not.toContain('ant-input-affix-wrapper-filled');\n      expect(component.withContentAddons().nativeElement.classList).not.toContain('ant-input-group-wrapper-filled');\n      expect(component.withContentMix().nativeElement.classList).not.toContain('ant-input-group-wrapper-filled');\n      expect(component.withContentMix().nativeElement.querySelector('.ant-input-affix-wrapper-filled')).toBeFalsy();\n      component.variant = 'filled';\n      fixture.detectChanges();\n      expect(component.withContentAffixes().nativeElement.classList).toContain('ant-input-affix-wrapper-filled');\n      expect(component.withContentAddons().nativeElement.classList).toContain('ant-input-group-wrapper-filled');\n      expect(component.withContentMix().nativeElement.classList).toContain('ant-input-group-wrapper-filled');\n      expect(component.withContentMix().nativeElement.querySelector('.ant-input-affix-wrapper-filled')).toBeTruthy();\n    });\n\n    it('borderless', () => {\n      fixture.detectChanges();\n      expect(component.withContentAffixes().nativeElement.classList).not.toContain(\n        'ant-input-affix-wrapper-borderless'\n      );\n      expect(component.withContentAddons().nativeElement.classList).not.toContain('ant-input-group-wrapper-borderless');\n      expect(component.withContentMix().nativeElement.classList).not.toContain('ant-input-group-wrapper-borderless');\n      expect(component.withContentMix().nativeElement.querySelector('.ant-input-affix-wrapper-borderless')).toBeFalsy();\n      component.variant = 'borderless';\n      fixture.detectChanges();\n      expect(component.withContentAffixes().nativeElement.classList).toContain('ant-input-affix-wrapper-borderless');\n      expect(component.withContentAddons().nativeElement.classList).toContain('ant-input-group-wrapper-borderless');\n      expect(component.withContentMix().nativeElement.classList).toContain('ant-input-group-wrapper-borderless');\n      expect(\n        component.withContentMix().nativeElement.querySelector('.ant-input-affix-wrapper-borderless')\n      ).toBeTruthy();\n    });\n\n    it('underlined', () => {\n      fixture.detectChanges();\n      expect(component.withContentAffixes().nativeElement.classList).not.toContain(\n        'ant-input-affix-wrapper-underlined'\n      );\n      expect(component.withContentAddons().nativeElement.classList).not.toContain('ant-input-group-wrapper-underlined');\n      expect(component.withContentMix().nativeElement.classList).not.toContain('ant-input-group-wrapper-underlined');\n      expect(component.withContentMix().nativeElement.querySelector('.ant-input-affix-wrapper-underlined')).toBeFalsy();\n      component.variant = 'underlined';\n      fixture.detectChanges();\n      expect(component.withContentAffixes().nativeElement.classList).toContain('ant-input-affix-wrapper-underlined');\n      expect(component.withContentAddons().nativeElement.classList).toContain('ant-input-group-wrapper-underlined');\n      expect(component.withContentMix().nativeElement.classList).toContain('ant-input-group-wrapper-underlined');\n      expect(\n        component.withContentMix().nativeElement.querySelector('.ant-input-affix-wrapper-underlined')\n      ).toBeTruthy();\n    });\n  });\n\n  it('should be handle focus / blur', () => {\n    let inputElement = component.withContentAffixes().nativeElement.querySelector('input')!;\n    inputElement.focus();\n    expect(component.withContentAffixes().nativeElement.classList).toContain('ant-input-affix-wrapper-focused');\n    inputElement.blur();\n    expect(component.withContentAffixes().nativeElement.classList).not.toContain('ant-input-affix-wrapper-focused');\n\n    inputElement = component.withContentMix().nativeElement.querySelector('input')!;\n    inputElement.focus();\n    expect(component.withContentMix().nativeElement.querySelector('.ant-input-affix-wrapper-focused')).toBeTruthy();\n    inputElement.blur();\n    expect(component.withContentMix().nativeElement.querySelector('.ant-input-affix-wrapper-focused')).toBeFalsy();\n  });\n});\n\ndescribe('input-wrapper allow clear', () => {\n  let component: InputAllowClearTestComponent;\n  let fixture: ComponentFixture<InputAllowClearTestComponent>;\n  let clearIconElement: HTMLElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(InputAllowClearTestComponent);\n    component = fixture.componentInstance;\n    fixture.autoDetectChanges();\n    clearIconElement = fixture.nativeElement.querySelector('.ant-input-clear-icon');\n  });\n\n  it('should be show clear icon when input has value', async () => {\n    expect(clearIconElement.classList).toContain('ant-input-clear-icon-hidden');\n    component.value = 'test';\n    fixture.detectChanges();\n    await fixture.whenStable();\n    expect(clearIconElement.classList).not.toContain('ant-input-clear-icon-hidden');\n    component.value = '';\n    fixture.detectChanges();\n    await fixture.whenStable();\n    expect(clearIconElement.classList).toContain('ant-input-clear-icon-hidden');\n  });\n\n  it('should be clear input value when click clear icon', () => {\n    component.value = 'test';\n    fixture.detectChanges();\n    clearIconElement.click();\n    fixture.detectChanges();\n    expect(component.value).toBe('');\n    expect(clearIconElement.classList).toContain('ant-input-clear-icon-hidden');\n  });\n\n  it('should be not show clear icon when input is disabled or readonly', () => {\n    component.value = 'test';\n    component.disabled = true;\n    component.readonly = false;\n    fixture.detectChanges();\n    expect(clearIconElement.classList).toContain('ant-input-clear-icon-hidden');\n    component.disabled = false;\n    component.readonly = true;\n    fixture.detectChanges();\n    expect(clearIconElement.classList).toContain('ant-input-clear-icon-hidden');\n  });\n\n  it('should be not show clear icon when nzAllowClear is false', () => {\n    component.value = 'test';\n    component.allowClear = false;\n    fixture.detectChanges();\n    expect(fixture.nativeElement.querySelector('.ant-input-clear-icon')).toBeFalsy();\n  });\n\n  it('should be emit nzClear event when click clear icon', () => {\n    spyOn(component, 'onClear');\n    component.value = 'test';\n    fixture.detectChanges();\n    expect(component.onClear).not.toHaveBeenCalled();\n    clearIconElement.click();\n    fixture.detectChanges();\n    expect(component.onClear).toHaveBeenCalled();\n  });\n});\n\ndescribe('input-wrapper with count config', () => {\n  let fixture: ComponentFixture<InputWithCountTestComponent>;\n  let component: InputWithCountTestComponent;\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(InputWithCountTestComponent);\n    component = fixture.componentInstance;\n  });\n\n  describe('should be work with show count', () => {\n    it('should be show/hidden count suffix', () => {\n      component.showCount = false;\n      fixture.detectChanges();\n      expect(component.withShowCount().nativeElement.classList).not.toContain('ant-input-out-of-range');\n      expect(component.withShowCount().nativeElement.querySelector('.ant-input-show-count-suffix')).toBeFalsy();\n\n      component.showCount = true;\n      fixture.detectChanges();\n      expect(component.withShowCount().nativeElement.classList).not.toContain('ant-input-out-of-range');\n      expect(component.withShowCount().nativeElement.querySelector('.ant-input-show-count-suffix')).toBeTruthy();\n    });\n\n    it('should be correct counting', fakeAsync(() => {\n      component.value = '';\n      component.showCount = true;\n      fixture.detectChanges();\n      expect(component.withShowCount().nativeElement.classList).not.toContain('ant-input-out-of-range');\n      expect(component.withShowCount().nativeElement.querySelector('.ant-input-show-count-suffix').textContent).toEqual(\n        '0'\n      );\n\n      component.value = 'Hello';\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(component.withShowCount().nativeElement.classList).not.toContain('ant-input-out-of-range');\n      expect(component.withShowCount().nativeElement.querySelector('.ant-input-show-count-suffix').textContent).toEqual(\n        '5'\n      );\n    }));\n  });\n\n  describe('should be work with count / max', () => {\n    it('should be show/hidden count suffix', () => {\n      component.showCount = false;\n      fixture.detectChanges();\n      expect(component.withCountConfig().nativeElement.classList).not.toContain('ant-input-out-of-range');\n      expect(component.withCountConfig().nativeElement.querySelector('.ant-input-show-count-suffix')).toBeFalsy();\n\n      component.showCount = true;\n      fixture.detectChanges();\n      expect(component.withCountConfig().nativeElement.classList).not.toContain('ant-input-out-of-range');\n      expect(component.withCountConfig().nativeElement.querySelector('.ant-input-show-count-suffix')).toBeTruthy();\n    });\n\n    it('should be correct counting', fakeAsync(() => {\n      component.value = 'Hello';\n      component.showCount = true;\n      component.countConfig = { max: 10 };\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(component.withCountConfig().nativeElement.classList).not.toContain('ant-input-out-of-range');\n      expect(\n        component.withCountConfig().nativeElement.querySelector('.ant-input-show-count-suffix').textContent\n      ).toEqual('5/10');\n\n      component.value = 'Hello World';\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(component.withCountConfig().nativeElement.classList).toContain('ant-input-out-of-range');\n      expect(\n        component.withCountConfig().nativeElement.querySelector('.ant-input-show-count-suffix').textContent\n      ).toEqual('11/10');\n\n      component.value = 'Hello World';\n      component.countConfig = { max: 20 };\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(component.withCountConfig().nativeElement.classList).not.toContain('ant-input-out-of-range');\n      expect(\n        component.withCountConfig().nativeElement.querySelector('.ant-input-show-count-suffix').textContent\n      ).toEqual('11/20');\n    }));\n  });\n\n  describe('should be work with count / max / strategy / formatter', () => {\n    it('should be show/hidden count suffix', () => {\n      component.showCount = false;\n      fixture.detectChanges();\n      expect(component.withCountConfig().nativeElement.classList).not.toContain('ant-input-out-of-range');\n      expect(component.withCountConfig().nativeElement.querySelector('.ant-input-show-count-suffix')).toBeFalsy();\n\n      component.showCount = true;\n      fixture.detectChanges();\n      expect(component.withCountConfig().nativeElement.classList).not.toContain('ant-input-out-of-range');\n      expect(component.withCountConfig().nativeElement.querySelector('.ant-input-show-count-suffix')).toBeTruthy();\n    });\n\n    it('should be correct counting', fakeAsync(() => {\n      component.value = 'Hello';\n      component.showCount = true;\n      component.countConfig = { max: 10, strategy: countStrategyFn };\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(component.withCountConfig().nativeElement.classList).not.toContain('ant-input-out-of-range');\n      expect(\n        component.withCountConfig().nativeElement.querySelector('.ant-input-show-count-suffix').textContent\n      ).toEqual('5/10');\n\n      component.value = 'HelloWorld';\n      component.countConfig = { max: 10, strategy: countStrategyFn };\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(component.withCountConfig().nativeElement.classList).not.toContain('ant-input-out-of-range');\n      expect(\n        component.withCountConfig().nativeElement.querySelector('.ant-input-show-count-suffix').textContent\n      ).toEqual('10/10');\n    }));\n\n    it('should be work count strategy', fakeAsync(() => {\n      component.showCount = true;\n      component.countConfig = { max: 10, strategy: countStrategyFn };\n      component.value = 'Hello';\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(component.withCountConfig().nativeElement.classList).not.toContain('ant-input-out-of-range');\n      expect(\n        component.withCountConfig().nativeElement.querySelector('.ant-input-show-count-suffix').textContent\n      ).toEqual('5/10');\n\n      component.value = '🔥🔥🔥';\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(component.withCountConfig().nativeElement.classList).not.toContain('ant-input-out-of-range');\n      expect(\n        component.withCountConfig().nativeElement.querySelector('.ant-input-show-count-suffix').textContent\n      ).toEqual('3/10');\n\n      component.value = 'Hello🔥🔥🔥';\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(component.withCountConfig().nativeElement.classList).not.toContain('ant-input-out-of-range');\n      expect(\n        component.withCountConfig().nativeElement.querySelector('.ant-input-show-count-suffix').textContent\n      ).toEqual('8/10');\n    }));\n\n    it('should be work exceedFormatter', fakeAsync(() => {\n      component.showCount = true;\n      component.countConfig = { max: 10, strategy: countStrategyFn, exceedFormatter: exceedFormatterFn };\n      component.value = 'HelloWorld NG-ZORRO';\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(component.withCountConfig().nativeElement.classList).not.toContain('ant-input-out-of-range');\n      expect(\n        component.withCountConfig().nativeElement.querySelector('.ant-input-show-count-suffix').textContent\n      ).toEqual('10/10');\n      expect(component.withCountConfig().nativeElement.querySelector('.ant-input').value).toEqual('HelloWorld');\n\n      component.value = 'Hello🔥🔥🔥🔥🔥World';\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(component.withCountConfig().nativeElement.classList).not.toContain('ant-input-out-of-range');\n      expect(\n        component.withCountConfig().nativeElement.querySelector('.ant-input-show-count-suffix').textContent\n      ).toEqual('10/10');\n      expect(component.withCountConfig().nativeElement.querySelector('.ant-input').value).toEqual('Hello🔥🔥🔥🔥🔥');\n    }));\n  });\n});\n\n@Component({\n  imports: [NzInputModule, FormsModule],\n  template: `\n    <nz-input-wrapper [nzAllowClear]=\"allowClear\" (nzClear)=\"onClear()\">\n      <input nz-input [(ngModel)]=\"value\" [disabled]=\"disabled\" [readonly]=\"readonly\" />\n    </nz-input-wrapper>\n  `\n})\nclass InputAllowClearTestComponent {\n  allowClear = true;\n  disabled = false;\n  readonly = false;\n  value = '';\n\n  onClear(): void {}\n}\n\n@Component({\n  imports: [NzInputModule],\n  template: `\n    <nz-input-wrapper #withPropAffixes nzPrefix=\"Prefix\" nzSuffix=\"Suffix\">\n      <input nz-input [nzSize]=\"size\" [nzVariant]=\"variant\" [disabled]=\"disabled\" [readonly]=\"readonly\" />\n    </nz-input-wrapper>\n\n    <nz-input-wrapper #withContentAffixes>\n      <span nzInputPrefix>Prefix</span>\n      <input nz-input [nzSize]=\"size\" [nzVariant]=\"variant\" [disabled]=\"disabled\" [readonly]=\"readonly\" />\n      <span nzInputSuffix>Suffix</span>\n    </nz-input-wrapper>\n\n    <nz-input-wrapper #withPropAddons nzAddonBefore=\"Before\" nzAddonAfter=\"After\">\n      <input nz-input [nzSize]=\"size\" [nzVariant]=\"variant\" [disabled]=\"disabled\" [readonly]=\"readonly\" />\n    </nz-input-wrapper>\n\n    <nz-input-wrapper #withContentAddons>\n      <span nzInputAddonBefore>Before</span>\n      <input nz-input [nzSize]=\"size\" [nzVariant]=\"variant\" [disabled]=\"disabled\" [readonly]=\"readonly\" />\n      <span nzInputAddonAfter>After</span>\n    </nz-input-wrapper>\n\n    <nz-input-wrapper #withPropMix nzAddonBefore=\"Before\" nzAddonAfter=\"After\" nzPrefix=\"Prefix\" nzSuffix=\"Suffix\">\n      <input nz-input [nzSize]=\"size\" [nzVariant]=\"variant\" [disabled]=\"disabled\" [readonly]=\"readonly\" />\n    </nz-input-wrapper>\n\n    <nz-input-wrapper #withContentMix>\n      <span nzInputAddonBefore>Before</span>\n      <span nzInputPrefix>Prefix</span>\n      <input nz-input [nzSize]=\"size\" [nzVariant]=\"variant\" [disabled]=\"disabled\" [readonly]=\"readonly\" />\n      <span nzInputSuffix>Suffix</span>\n      <span nzInputAddonAfter>After</span>\n    </nz-input-wrapper>\n\n    <nz-input-wrapper #onlyInput>\n      <input nz-input [nzSize]=\"size\" [nzVariant]=\"variant\" [disabled]=\"disabled\" [readonly]=\"readonly\" />\n    </nz-input-wrapper>\n  `\n})\nclass InputWithAffixesAndAddonsTestComponent {\n  size: NzSizeLDSType = 'default';\n  disabled = false;\n  readonly = false;\n  variant: NzVariant = 'outlined';\n\n  readonly withPropAffixes = viewChild.required('withPropAffixes', { read: ElementRef });\n  readonly withContentAffixes = viewChild.required('withContentAffixes', { read: ElementRef });\n  readonly withPropAddons = viewChild.required('withPropAddons', { read: ElementRef });\n  readonly withContentAddons = viewChild.required('withContentAddons', { read: ElementRef });\n  readonly withPropMix = viewChild.required('withPropMix', { read: ElementRef });\n  readonly withContentMix = viewChild.required('withContentMix', { read: ElementRef });\n  readonly onlyInput = viewChild.required('onlyInput', { read: ElementRef });\n}\n\n@Component({\n  imports: [FormsModule, NzInputModule],\n  template: `\n    <nz-input-wrapper #withShowCount [nzShowCount]=\"showCount\">\n      <input nz-input [(ngModel)]=\"value\" />\n    </nz-input-wrapper>\n\n    <nz-input-wrapper #withCountConfig [nzShowCount]=\"showCount\" [nzCount]=\"countConfig\">\n      <input nz-input [(ngModel)]=\"value\" />\n    </nz-input-wrapper>\n  `\n})\nexport class InputWithCountTestComponent {\n  value = '';\n  showCount = false;\n\n  countConfig: NzCountConfig = {};\n\n  readonly withShowCount = viewChild.required('withShowCount', { read: ElementRef });\n  readonly withCountConfig = viewChild.required('withCountConfig', { read: ElementRef });\n}\n\nconst runes = (str: string): string[] => [...str];\nconst countStrategyFn = (v: string): number => runes(v).length;\nconst exceedFormatterFn = (v: string, { max }: { max: number }): string => runes(v).slice(0, max).join('');\n"
  },
  {
    "path": "components/input/input-wrapper.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { FocusMonitor } from '@angular/cdk/a11y';\nimport { Directionality } from '@angular/cdk/bidi';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  afterNextRender,\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  Component,\n  computed,\n  contentChild,\n  DestroyRef,\n  effect,\n  ElementRef,\n  forwardRef,\n  inject,\n  input,\n  output,\n  signal,\n  TemplateRef,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed, toObservable, toSignal } from '@angular/core/rxjs-interop';\nimport { EMPTY, startWith, switchMap } from 'rxjs';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzFormItemFeedbackIconComponent } from 'ng-zorro-antd/core/form';\nimport { getStatusClassNames, getVariantClassNames, isNotNil, isNumberFinite } from 'ng-zorro-antd/core/util';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NZ_SPACE_COMPACT_ITEM_TYPE, NZ_SPACE_COMPACT_SIZE, NzSpaceCompactItemDirective } from 'ng-zorro-antd/space';\n\nimport { NzInputAddonAfterDirective, NzInputAddonBeforeDirective } from './input-addon.directive';\nimport { NzInputPrefixDirective, NzInputSuffixDirective } from './input-affix.directive';\nimport { NzInputPasswordDirective, NzInputPasswordIconDirective } from './input-password.directive';\nimport { NzInputSearchDirective, NzInputSearchEnterButtonDirective } from './input-search.directive';\nimport { NzInputDirective } from './input.directive';\nimport { NZ_INPUT_WRAPPER } from './tokens';\n\nexport interface NzCountConfig {\n  max?: number;\n  strategy?: (value: string) => number;\n  exceedFormatter?: (value: string, config: { max: number }) => string;\n}\n\n@Component({\n  selector: 'nz-input-wrapper,nz-input-password,nz-input-search',\n  exportAs: 'nzInputWrapper',\n  imports: [NzIconModule, NzButtonModule, NzFormItemFeedbackIconComponent, NgTemplateOutlet],\n  template: `\n    @if (hasAddon()) {\n      <ng-template [ngTemplateOutlet]=\"inputWithAddonInner\" />\n    } @else if (hasAffix()) {\n      <ng-template [ngTemplateOutlet]=\"inputWithAffixInner\" />\n    } @else {\n      <ng-template [ngTemplateOutlet]=\"input\" />\n    }\n\n    <ng-template #inputWithAddonInner>\n      <span class=\"ant-input-wrapper ant-input-group\">\n        @if (hasAddonBefore()) {\n          <span class=\"ant-input-group-addon\">\n            <ng-content select=\"[nzInputAddonBefore]\">{{ nzAddonBefore() }}</ng-content>\n          </span>\n        }\n\n        @if (hasAffix()) {\n          <ng-template [ngTemplateOutlet]=\"inputWithAffix\" />\n        } @else {\n          <ng-template [ngTemplateOutlet]=\"input\" />\n        }\n\n        @if (hasAddonAfter()) {\n          <span class=\"ant-input-group-addon\">\n            @if (inputSearchDir) {\n              @let nzEnterButton = inputSearchDir.nzEnterButton();\n              @let hasEnterButton = inputSearchEnterButton() ?? nzEnterButton !== false;\n              <button\n                nz-button\n                [nzType]=\"hasEnterButton ? 'primary' : 'default'\"\n                [nzSize]=\"size()\"\n                [nzLoading]=\"inputSearchDir.nzLoading()\"\n                type=\"button\"\n                class=\"ant-input-search-button\"\n                (click)=\"inputSearchDir.search($event)\"\n              >\n                <ng-content select=\"[nzInputSearchEnterButton]\">\n                  @if (nzEnterButton && typeof nzEnterButton === 'string') {\n                    {{ nzEnterButton }}\n                  } @else {\n                    <nz-icon nzType=\"search\" nzTheme=\"outline\" />\n                  }\n                </ng-content>\n              </button>\n            }\n            <ng-content select=\"[nzInputAddonAfter]\">{{ nzAddonAfter() }}</ng-content>\n          </span>\n        }\n      </span>\n    </ng-template>\n\n    <ng-template #inputWithAffix>\n      <span [class]=\"affixWrapperClass()\">\n        <ng-template [ngTemplateOutlet]=\"inputWithAffixInner\" />\n      </span>\n    </ng-template>\n\n    <ng-template #inputWithAffixInner>\n      @if (hasPrefix()) {\n        <span class=\"ant-input-prefix\">\n          <ng-content select=\"[nzInputPrefix]\">{{ nzPrefix() }}</ng-content>\n        </span>\n      }\n      <ng-template [ngTemplateOutlet]=\"input\" />\n      @if (hasSuffix()) {\n        <span class=\"ant-input-suffix\">\n          @if (nzAllowClear()) {\n            <span\n              class=\"ant-input-clear-icon\"\n              [class.ant-input-clear-icon-has-suffix]=\"\n                nzSuffix() || suffix() || hasFeedback() || inputPasswordDir?.nzVisibilityToggle()\n              \"\n              [class.ant-input-clear-icon-hidden]=\"!inputDir().value() || disabled() || readOnly()\"\n              role=\"button\"\n              tabindex=\"-1\"\n              (click)=\"clear(); inputSearchDir?.search($event, 'clear')\"\n            >\n              <ng-content select=\"[nzInputClearIcon]\">\n                <nz-icon nzType=\"close-circle\" nzTheme=\"fill\" />\n              </ng-content>\n            </span>\n          }\n          @if (nzShowCount()) {\n            <span class=\"ant-input-show-count-suffix\">{{ dataCount() }}</span>\n          }\n          @if (inputPasswordDir && inputPasswordDir.nzVisibilityToggle()) {\n            <span\n              class=\"ant-input-password-icon\"\n              role=\"button\"\n              tabindex=\"-1\"\n              (click)=\"inputPasswordDir.toggleVisible()\"\n            >\n              @if (inputPasswordIconTmpl(); as tmpl) {\n                <ng-template\n                  [ngTemplateOutlet]=\"tmpl\"\n                  [ngTemplateOutletContext]=\"{ $implicit: inputPasswordDir.nzVisible() }\"\n                />\n              } @else {\n                <nz-icon [nzType]=\"inputPasswordDir.nzVisible() ? 'eye' : 'eye-invisible'\" nzTheme=\"outline\" />\n              }\n            </span>\n          }\n          <ng-content select=\"[nzInputSuffix]\">{{ nzSuffix() }}</ng-content>\n          @if (hasFeedback() && status()) {\n            <nz-form-item-feedback-icon [status]=\"status()\" />\n          }\n        </span>\n      }\n    </ng-template>\n\n    <ng-template #input>\n      <ng-content select=\"[nz-input]\" />\n    </ng-template>\n  `,\n  providers: [\n    { provide: NZ_SPACE_COMPACT_ITEM_TYPE, useValue: 'input' },\n    { provide: NZ_INPUT_WRAPPER, useExisting: forwardRef(() => NzInputWrapperComponent) }\n  ],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  hostDirectives: [NzSpaceCompactItemDirective],\n  host: {\n    '[class]': 'class()',\n    '[class.ant-input-disabled]': 'disabled()',\n    '[class.ant-input-out-of-range]': 'nzShowCount() && isOutOfRange()',\n    '[class.ant-input-affix-wrapper-textarea-with-clear-btn]': 'nzAllowClear() && isTextarea()'\n  }\n})\nexport class NzInputWrapperComponent {\n  private readonly focusMonitor = inject(FocusMonitor);\n\n  protected readonly inputPasswordDir = inject(NzInputPasswordDirective, { self: true, optional: true });\n  protected readonly inputSearchDir = inject(NzInputSearchDirective, { self: true, optional: true });\n\n  protected readonly inputRef = contentChild.required(NzInputDirective, { read: ElementRef });\n  protected readonly inputDir = contentChild.required(NzInputDirective);\n\n  protected readonly prefix = contentChild(NzInputPrefixDirective);\n  protected readonly suffix = contentChild(NzInputSuffixDirective);\n  protected readonly addonBefore = contentChild(NzInputAddonBeforeDirective);\n  protected readonly addonAfter = contentChild(NzInputAddonAfterDirective);\n  protected readonly inputPasswordIconTmpl = contentChild(NzInputPasswordIconDirective, { read: TemplateRef });\n  protected readonly inputSearchEnterButton = contentChild(NzInputSearchEnterButtonDirective);\n\n  readonly nzAllowClear = input(false, { transform: booleanAttribute });\n  readonly nzPrefix = input<string>();\n  readonly nzSuffix = input<string>();\n  readonly nzAddonBefore = input<string>();\n  readonly nzAddonAfter = input<string>();\n\n  readonly nzShowCount = input(false, { transform: booleanAttribute });\n  readonly nzCount = input<NzCountConfig>();\n\n  readonly nzClear = output<void>();\n\n  readonly size = computed(() => this.inputDir().nzSize());\n  readonly variant = computed(() => this.inputDir().nzVariant());\n  readonly disabled = computed(() => this.inputDir().finalDisabled());\n  readonly readOnly = computed(() => this.inputDir().readonly());\n  readonly status = computed(() => this.inputDir().status());\n  readonly hasFeedback = computed(() => this.inputDir().hasFeedback());\n\n  protected readonly hasPrefix = computed(() => !!this.nzPrefix() || !!this.prefix());\n  protected readonly hasSuffix = computed(\n    () =>\n      !!this.nzSuffix() ||\n      !!this.suffix() ||\n      this.nzAllowClear() ||\n      this.hasFeedback() ||\n      this.nzShowCount() ||\n      this.inputPasswordDir\n  );\n  protected readonly hasAffix = computed(() => this.hasPrefix() || this.hasSuffix());\n  protected readonly hasAddonBefore = computed(() => !!this.nzAddonBefore() || !!this.addonBefore());\n  protected readonly hasAddonAfter = computed(\n    () => !!this.nzAddonAfter() || !!this.addonAfter() || !!this.inputSearchDir\n  );\n  protected readonly hasAddon = computed(() => this.hasAddonBefore() || this.hasAddonAfter());\n\n  private readonly compactSize = inject(NZ_SPACE_COMPACT_SIZE, { optional: true });\n  protected readonly dir = inject(Directionality).valueSignal;\n  protected readonly focused = signal(false);\n  protected readonly isTextarea = computed(() => this.inputRef().nativeElement instanceof HTMLTextAreaElement);\n\n  protected readonly finalSize = computed(() => {\n    if (this.compactSize) {\n      return this.compactSize();\n    }\n    return this.size();\n  });\n\n  protected readonly class = computed(() => {\n    if (this.hasAddon()) {\n      return this.groupWrapperClass();\n    }\n    if (this.hasAffix()) {\n      return this.affixWrapperClass();\n    }\n    return null;\n  });\n  protected readonly affixWrapperClass = computed(() => {\n    return {\n      'ant-input-affix-wrapper': true,\n      'ant-input-affix-wrapper-lg': this.finalSize() === 'large',\n      'ant-input-affix-wrapper-sm': this.finalSize() === 'small',\n      'ant-input-affix-wrapper-disabled': this.disabled(),\n      'ant-input-affix-wrapper-readonly': this.readOnly(),\n      'ant-input-affix-wrapper-focused': this.focused(),\n      'ant-input-affix-wrapper-rtl': this.dir() === 'rtl',\n      ...getStatusClassNames('ant-input-affix-wrapper', this.status(), this.hasFeedback()),\n      ...getVariantClassNames('ant-input-affix-wrapper', this.variant())\n    };\n  });\n  protected readonly groupWrapperClass = computed(() => {\n    return {\n      'ant-input-group-wrapper': true,\n      'ant-input-group-wrapper-sm': this.finalSize() === 'small',\n      'ant-input-group-wrapper-lg': this.finalSize() === 'large',\n      'ant-input-group-wrapper-rtl': this.dir() === 'rtl',\n      ...getStatusClassNames('ant-input-group-wrapper', this.status(), this.hasFeedback()),\n      ...getVariantClassNames('ant-input-group-wrapper', this.variant())\n    };\n  });\n\n  protected readonly inputValue = toSignal(\n    toObservable(this.inputDir).pipe(\n      switchMap(inputDir => {\n        const ngControl = inputDir.ngControl;\n        if (!ngControl) return EMPTY;\n        return (ngControl.valueChanges ?? EMPTY).pipe(startWith(ngControl.value as string));\n      })\n    )\n  );\n  protected readonly formattedValue = computed(() => {\n    const countConfig = this.nzCount();\n    const inputValue = this.inputValue();\n    const countMax = countConfig?.max ?? 0;\n    const value = isNotNil(inputValue) ? String(inputValue) : '';\n    let formattedValue = value;\n\n    if (countConfig?.exceedFormatter) {\n      formattedValue = countConfig.exceedFormatter(value, { max: countMax });\n    }\n    return formattedValue;\n  });\n  protected readonly computedCount = computed(() => {\n    const countConfig = this.nzCount();\n    const formattedValue = this.formattedValue();\n    let computedCount = formattedValue.length;\n\n    if (countConfig?.strategy) {\n      computedCount = countConfig.strategy(formattedValue);\n    }\n    return computedCount;\n  });\n  protected readonly dataCount = computed(() => {\n    const countConfig = this.nzCount();\n    const computedCount = this.computedCount();\n    const countMax = countConfig?.max;\n    return `${computedCount}${countMax ? `/${countMax}` : ``}`;\n  });\n  protected readonly isOutOfRange = computed(() => {\n    const countConfig = this.nzCount();\n    const countMax = countConfig?.max;\n    if (isNumberFinite(countMax)) {\n      return this.computedCount() > countMax!;\n    }\n    return false;\n  });\n\n  constructor() {\n    const destroyRef = inject(DestroyRef);\n\n    afterNextRender(() => {\n      const element = this.inputRef();\n      this.focusMonitor\n        .monitor(element)\n        .pipe(takeUntilDestroyed(destroyRef))\n        .subscribe(origin => {\n          this.focused.set(!!origin);\n        });\n\n      destroyRef.onDestroy(() => {\n        this.focusMonitor.stopMonitoring(element);\n      });\n    });\n\n    effect(() => {\n      const inputValue = this.inputValue();\n      const formattedValue = this.formattedValue();\n      if (formattedValue !== inputValue) {\n        this.inputDir().ngControl?.control?.setValue(formattedValue);\n      }\n    });\n  }\n\n  clear(): void {\n    this.inputDir().ngControl?.control?.setValue('');\n    this.nzClear.emit();\n  }\n}\n"
  },
  {
    "path": "components/input/input.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { FocusMonitor } from '@angular/cdk/a11y';\nimport { Directionality } from '@angular/cdk/bidi';\nimport {\n  booleanAttribute,\n  ComponentRef,\n  computed,\n  DestroyRef,\n  Directive,\n  effect,\n  ElementRef,\n  inject,\n  input,\n  linkedSignal,\n  OnInit,\n  signal,\n  ViewContainerRef\n} from '@angular/core';\nimport { takeUntilDestroyed, toObservable, toSignal } from '@angular/core/rxjs-interop';\nimport { NgControl } from '@angular/forms';\nimport { EMPTY } from 'rxjs';\nimport { map, startWith } from 'rxjs/operators';\n\nimport {\n  NZ_FORM_SIZE,\n  NZ_FORM_VARIANT,\n  NzFormItemFeedbackIconComponent,\n  NzFormNoStatusService,\n  NzFormStatusService\n} from 'ng-zorro-antd/core/form';\nimport { NzSizeLDSType, NzStatus, NzVariant } from 'ng-zorro-antd/core/types';\nimport { getStatusClassNames, InputFocusOptions, triggerFocus } from 'ng-zorro-antd/core/util';\nimport { NZ_SPACE_COMPACT_ITEM_TYPE, NZ_SPACE_COMPACT_SIZE, NzSpaceCompactItemDirective } from 'ng-zorro-antd/space';\n\nimport { NzInputPasswordDirective } from './input-password.directive';\nimport { NZ_INPUT_SEARCH, NZ_INPUT_WRAPPER } from './tokens';\n\nconst PREFIX_CLS = 'ant-input';\n\n@Directive({\n  selector: 'input[nz-input],textarea[nz-input]',\n  exportAs: 'nzInput',\n  host: {\n    class: 'ant-input',\n    '[attr.type]': 'type()',\n    '[class]': 'classes()',\n    '[class.ant-input-disabled]': 'finalDisabled()',\n    '[class.ant-input-borderless]': `finalVariant() === 'borderless'`,\n    '[class.ant-input-filled]': `finalVariant() === 'filled'`,\n    '[class.ant-input-underlined]': `finalVariant() === 'underlined'`,\n    '[class.ant-input-lg]': `finalSize() === 'large'`,\n    '[class.ant-input-sm]': `finalSize() === 'small'`,\n    '[attr.disabled]': 'finalDisabled() || null',\n    '[attr.readonly]': 'readonly() || null',\n    '[class.ant-input-rtl]': `dir() === 'rtl'`,\n    '[class.ant-input-stepperless]': `nzStepperless()`,\n    '[class.ant-input-focused]': 'focused()'\n  },\n  hostDirectives: [NzSpaceCompactItemDirective],\n  providers: [{ provide: NZ_SPACE_COMPACT_ITEM_TYPE, useValue: 'input' }]\n})\nexport class NzInputDirective implements OnInit {\n  private elementRef = inject<ElementRef<HTMLInputElement | HTMLTextAreaElement>>(ElementRef);\n  private compactSize = inject(NZ_SPACE_COMPACT_SIZE, { optional: true });\n  private destroyRef = inject(DestroyRef);\n  private nzFormStatusService = inject(NzFormStatusService, { optional: true });\n  private nzFormNoStatusService = inject(NzFormNoStatusService, { optional: true });\n  private inputWrapper = inject(NZ_INPUT_WRAPPER, { host: true, optional: true });\n  private focusMonitor = inject(FocusMonitor);\n  private hostView = inject(ViewContainerRef);\n  private readonly inputPasswordDir = inject(NzInputPasswordDirective, { host: true, optional: true });\n  private readonly inputSearchDir = inject(NZ_INPUT_SEARCH, { host: true, optional: true });\n\n  readonly ngControl = inject(NgControl, { self: true, optional: true });\n  readonly value = signal<string>(this.elementRef.nativeElement.value);\n\n  readonly nzVariant = input<NzVariant>();\n  readonly nzSize = input<NzSizeLDSType>('default');\n  /**\n   * @deprecated Will be removed in v22.\n   */\n  readonly nzStepperless = input(true, { transform: booleanAttribute });\n  readonly nzStatus = input<NzStatus>('');\n  readonly disabled = input(false, { transform: booleanAttribute });\n  readonly readonly = input(false, { transform: booleanAttribute });\n\n  readonly controlDisabled = signal(false);\n  readonly finalDisabled = this.ngControl ? this.controlDisabled : this.disabled;\n  readonly dir = inject(Directionality).valueSignal;\n  // TODO: When the input group is removed, we can remove this.\n  readonly size = linkedSignal(this.nzSize);\n\n  private readonly formSize = inject(NZ_FORM_SIZE, { optional: true });\n  private readonly formVariant = inject(NZ_FORM_VARIANT, { optional: true });\n\n  readonly status = this.nzFormStatusService\n    ? toSignal(this.nzFormStatusService.formStatusChanges.pipe(map(value => value.status)), { initialValue: '' })\n    : this.nzStatus;\n  readonly hasFeedback = toSignal(\n    this.nzFormStatusService?.formStatusChanges.pipe(map(value => value.hasFeedback)) ?? EMPTY,\n    { initialValue: false }\n  );\n  readonly classes = computed(() => getStatusClassNames(PREFIX_CLS, this.status(), this.hasFeedback()));\n  readonly type = computed(() => {\n    if (this.inputPasswordDir) {\n      return this.inputPasswordDir.nzVisible() ? 'text' : 'password';\n    }\n    if (this.inputSearchDir) {\n      return 'search';\n    }\n    return this.elementRef.nativeElement.getAttribute('type') || 'text';\n  });\n\n  protected readonly focused = signal<boolean>(false);\n  protected readonly finalSize = computed(() => {\n    if (this.formSize?.()) {\n      return this.formSize();\n    }\n    if (this.compactSize) {\n      return this.compactSize();\n    }\n    return this.size();\n  });\n\n  protected readonly finalVariant = computed(() => this.nzVariant() || this.formVariant?.() || 'outlined');\n\n  feedbackRef: ComponentRef<NzFormItemFeedbackIconComponent> | null = null;\n  // TODO: When the input group is removed, we can remove this.\n  disabled$ = toObservable(this.finalDisabled);\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      this.focusMonitor.stopMonitoring(this.elementRef);\n    });\n\n    this.focusMonitor\n      .monitor(this.elementRef, false)\n      .pipe(takeUntilDestroyed())\n      .subscribe(origin => this.focused.set(!!origin));\n\n    effect(() => {\n      this.renderFeedbackIcon();\n    });\n  }\n\n  ngOnInit(): void {\n    // statusChanges is only accessible in onInit\n    this.ngControl?.statusChanges?.pipe(startWith(null), takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      this.controlDisabled.set(!!this.ngControl!.disabled);\n    });\n\n    this.ngControl?.valueChanges?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(value => {\n      this.value.set(value);\n    });\n  }\n\n  private renderFeedbackIcon(): void {\n    if (!this.status() || !this.hasFeedback() || this.inputWrapper || !!this.nzFormNoStatusService) {\n      // remove feedback\n      this.hostView.clear();\n      this.feedbackRef = null;\n      return;\n    }\n\n    this.feedbackRef = this.feedbackRef || this.hostView.createComponent(NzFormItemFeedbackIconComponent);\n    this.feedbackRef.location.nativeElement.classList.add('ant-input-suffix');\n    this.feedbackRef.instance.status = this.status();\n    this.feedbackRef.instance.updateIcon();\n  }\n\n  focus(options?: InputFocusOptions): void {\n    triggerFocus(this.elementRef.nativeElement, options);\n  }\n\n  blur(): void {\n    this.elementRef.nativeElement.blur();\n  }\n}\n"
  },
  {
    "path": "components/input/input.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzAutosizeDirective } from './autosize.directive';\nimport { NzInputAddonAfterDirective, NzInputAddonBeforeDirective } from './input-addon.directive';\nimport { NzInputPrefixDirective, NzInputSuffixDirective } from './input-affix.directive';\nimport { NzInputGroupSlotComponent } from './input-group-slot.component';\nimport { NzInputGroupComponent, NzInputGroupWhitSuffixOrPrefixDirective } from './input-group.component';\nimport { NzInputOtpComponent } from './input-otp.component';\nimport { NzInputPasswordDirective, NzInputPasswordIconDirective } from './input-password.directive';\nimport { NzInputSearchDirective, NzInputSearchEnterButtonDirective } from './input-search.directive';\nimport { NzInputWrapperComponent } from './input-wrapper.component';\nimport { NzInputDirective } from './input.directive';\nimport { NzTextareaCountComponent } from './textarea-count.component';\n\n@NgModule({\n  imports: [\n    NzTextareaCountComponent,\n    NzInputDirective,\n    NzInputWrapperComponent,\n    NzInputPasswordDirective,\n    NzInputPasswordIconDirective,\n    NzInputSearchDirective,\n    NzInputSearchEnterButtonDirective,\n    NzInputAddonBeforeDirective,\n    NzInputAddonAfterDirective,\n    NzInputPrefixDirective,\n    NzInputSuffixDirective,\n    NzInputGroupComponent,\n    NzAutosizeDirective,\n    NzInputGroupSlotComponent,\n    NzInputGroupWhitSuffixOrPrefixDirective,\n    NzInputOtpComponent\n  ],\n  exports: [\n    NzTextareaCountComponent,\n    NzInputDirective,\n    NzInputWrapperComponent,\n    NzInputPasswordDirective,\n    NzInputPasswordIconDirective,\n    NzInputSearchDirective,\n    NzInputSearchEnterButtonDirective,\n    NzInputAddonBeforeDirective,\n    NzInputAddonAfterDirective,\n    NzInputPrefixDirective,\n    NzInputSuffixDirective,\n    NzInputGroupComponent,\n    NzAutosizeDirective,\n    NzInputGroupWhitSuffixOrPrefixDirective,\n    NzInputOtpComponent\n  ]\n})\nexport class NzInputModule {}\n"
  },
  {
    "path": "components/input/input.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Direction } from '@angular/cdk/bidi';\nimport {\n  Component,\n  DebugElement,\n  provideZoneChangeDetection,\n  signal,\n  viewChild,\n  type WritableSignal\n} from '@angular/core';\nimport { ComponentFixture, TestBed, fakeAsync, flush } from '@angular/core/testing';\nimport { FormControl, ReactiveFormsModule } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\n\nimport { NZ_FORM_SIZE, NZ_FORM_VARIANT } from 'ng-zorro-antd/core/form';\nimport { NzSizeLDSType, NzStatus, NzVariant } from 'ng-zorro-antd/core/types';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\nimport { NzInputWrapperComponent } from 'ng-zorro-antd/input/input-wrapper.component';\nimport { NZ_SPACE_COMPACT_SIZE } from 'ng-zorro-antd/space';\n\nimport { NzFormControlStatusType, NzFormModule } from '../form';\nimport { NzInputDirective } from './input.directive';\nimport { NzInputModule } from './input.module';\n\ndescribe('input', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideZoneChangeDetection()]\n    });\n  });\n\n  describe('single input', () => {\n    describe('input with input element', () => {\n      let fixture: ComponentFixture<NzTestInputWithInputComponent>;\n      let testComponent: NzTestInputWithInputComponent;\n      let inputElement: DebugElement;\n\n      beforeEach(() => {\n        fixture = TestBed.createComponent(NzTestInputWithInputComponent);\n        testComponent = fixture.debugElement.componentInstance;\n        fixture.detectChanges();\n        inputElement = fixture.debugElement.query(By.directive(NzInputDirective));\n      });\n\n      it('should className correct', () => {\n        fixture.detectChanges();\n        expect(inputElement.nativeElement.classList).toContain('ant-input');\n      });\n\n      it('should disabled work', () => {\n        fixture.detectChanges();\n        expect(inputElement.nativeElement.classList).not.toContain('ant-input-disabled');\n        testComponent.disabled = true;\n        fixture.detectChanges();\n        expect(inputElement.nativeElement.classList).toContain('ant-input-disabled');\n      });\n\n      it('should nzSize work', () => {\n        testComponent.size = 'small';\n        fixture.detectChanges();\n        expect(inputElement.nativeElement.classList).toContain('ant-input');\n        expect(inputElement.nativeElement.classList).toContain('ant-input-sm');\n        testComponent.size = 'large';\n        fixture.detectChanges();\n        expect(inputElement.nativeElement.classList).toContain('ant-input');\n        expect(inputElement.nativeElement.classList).toContain('ant-input-lg');\n      });\n\n      it('should nzStepperLess work', () => {\n        fixture.detectChanges();\n        expect(inputElement.nativeElement.classList).toContain('ant-input-stepperless');\n        testComponent.stepperless = false;\n        fixture.detectChanges();\n        expect(inputElement.nativeElement.classList).not.toContain('ant-input-stepperless');\n      });\n\n      it('should be focus / blur work', async () => {\n        const input = inputElement.nativeElement;\n        testComponent.inputDirective().focus();\n        expect(document.activeElement).toBe(input);\n        testComponent.inputDirective().blur();\n        expect(document.activeElement).not.toBe(input);\n\n        testComponent.value = 'NG-ZORRO';\n        fixture.detectChanges();\n        await fixture.whenStable();\n\n        testComponent.inputDirective().focus({ cursor: 'start' });\n        expect(input.selectionStart).toBe(0);\n        expect(input.selectionEnd).toBe(0);\n        testComponent.inputDirective().focus({ cursor: 'end' });\n        expect(input.selectionStart).toBe(testComponent.value.length);\n        expect(input.selectionEnd).toBe(testComponent.value.length);\n        testComponent.inputDirective().focus({ cursor: 'all' });\n        expect(input.selectionStart).toBe(0);\n        expect(input.selectionEnd).toBe(testComponent.value.length);\n      });\n\n      describe('should nzVariant work', () => {\n        it('filled', () => {\n          fixture.detectChanges();\n          expect(inputElement.nativeElement.classList).not.toContain('ant-input-filled');\n          testComponent.variant = 'filled';\n          fixture.detectChanges();\n          expect(inputElement.nativeElement.classList).toContain('ant-input-filled');\n        });\n\n        it('borderless', () => {\n          fixture.detectChanges();\n          expect(inputElement.nativeElement.classList).not.toContain('ant-input-borderless');\n          testComponent.variant = 'borderless';\n          fixture.detectChanges();\n          expect(inputElement.nativeElement.classList).toContain('ant-input-borderless');\n        });\n\n        it('underlined', () => {\n          fixture.detectChanges();\n          expect(inputElement.nativeElement.classList).not.toContain('ant-input-borderless');\n          testComponent.variant = 'underlined';\n          fixture.detectChanges();\n          expect(inputElement.nativeElement.classList).toContain('ant-input-underlined');\n        });\n      });\n    });\n\n    describe('input with textarea element', () => {\n      let fixture: ComponentFixture<NzTestInputWithInputComponent>;\n      let inputElement: DebugElement;\n\n      beforeEach(() => {\n        fixture = TestBed.createComponent(NzTestInputWithInputComponent);\n        fixture.detectChanges();\n        inputElement = fixture.debugElement.query(By.directive(NzInputDirective));\n      });\n\n      it('should className correct', () => {\n        fixture.detectChanges();\n        expect(inputElement.nativeElement.classList).toContain('ant-input');\n      });\n    });\n  });\n\n  describe('input form', () => {\n    describe('input with form', () => {\n      let fixture: ComponentFixture<NzTestInputFormComponent>;\n      let testComponent: NzTestInputFormComponent;\n      let inputElement: DebugElement;\n\n      beforeEach(() => {\n        fixture = TestBed.createComponent(NzTestInputFormComponent);\n        testComponent = fixture.debugElement.componentInstance;\n        fixture.detectChanges();\n        inputElement = fixture.debugElement.query(By.directive(NzInputDirective));\n      });\n\n      it('should set disabled work', fakeAsync(() => {\n        flush();\n        expect(inputElement.nativeElement.classList).not.toContain('ant-input-disabled');\n        expect(inputElement.nativeElement.getAttribute('disabled')).toBeNull();\n        testComponent.disable();\n        flush();\n        fixture.detectChanges();\n        expect(inputElement.nativeElement.classList).toContain('ant-input-disabled');\n        expect(inputElement.nativeElement.getAttribute('disabled')).toBe('true');\n      }));\n    });\n  });\n\n  describe('input RTL', () => {\n    let fixture: ComponentFixture<NzTestInputWithDirComponent>;\n    let inputElement: DebugElement;\n    let inputGroupElement: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestInputWithDirComponent);\n      fixture.detectChanges();\n      inputElement = fixture.debugElement.query(By.directive(NzInputDirective));\n      inputGroupElement = fixture.debugElement.query(By.directive(NzInputWrapperComponent));\n    });\n\n    it('should className correct on dir change', () => {\n      expect(inputElement.nativeElement.classList).not.toContain('ant-input-rtl');\n      expect(inputGroupElement.nativeElement.classList).not.toContain('ant-input-group-wrapper-rtl');\n\n      fixture.componentInstance.dir = 'rtl';\n      fixture.detectChanges();\n      expect(inputElement.nativeElement.classList).toContain('ant-input-rtl');\n      expect(inputGroupElement.nativeElement.classList).toContain('ant-input-group-wrapper-rtl');\n    });\n  });\n\n  describe('input with status', () => {\n    let fixture: ComponentFixture<NzTestInputWithStatusComponent>;\n    let inputElement: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestInputWithStatusComponent);\n      fixture.detectChanges();\n      inputElement = fixture.debugElement.query(By.directive(NzInputDirective));\n    });\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n      expect(inputElement.nativeElement.classList).toContain('ant-input-status-error');\n\n      fixture.componentInstance.status = 'warning';\n      fixture.detectChanges();\n      expect(inputElement.nativeElement.className).toContain('ant-input-status-warning');\n\n      fixture.componentInstance.status = '';\n      fixture.detectChanges();\n      expect(inputElement.nativeElement.className).not.toContain('ant-input-status-warning');\n    });\n  });\n\n  describe('input in form', () => {\n    let fixture: ComponentFixture<NzTestInputInFormComponent>;\n    let inputElement: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestInputInFormComponent);\n      fixture.detectChanges();\n      inputElement = fixture.debugElement.query(By.directive(NzInputDirective));\n    });\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n      expect(inputElement.nativeElement.classList).toContain('ant-input-status-error');\n      expect(inputElement.nativeElement.nextSibling.classList).toContain('ant-form-item-feedback-icon-error');\n\n      fixture.componentInstance.status = 'success';\n      fixture.detectChanges();\n      expect(inputElement.nativeElement.classList).toContain('ant-input-status-success');\n      expect(inputElement.nativeElement.nextSibling.classList).toContain('ant-form-item-feedback-icon-success');\n\n      fixture.componentInstance.status = 'warning';\n      fixture.detectChanges();\n      expect(inputElement.nativeElement.classList).toContain('ant-input-status-warning');\n      expect(inputElement.nativeElement.nextSibling.classList).toContain('ant-form-item-feedback-icon-warning');\n\n      fixture.componentInstance.status = 'validating';\n      fixture.detectChanges();\n      expect(inputElement.nativeElement.classList).toContain('ant-input-status-validating');\n      expect(inputElement.nativeElement.nextSibling.classList).toContain('ant-form-item-feedback-icon-validating');\n\n      fixture.componentInstance.feedback = false;\n      fixture.detectChanges();\n      expect(inputElement.nativeElement.classList).toContain('ant-input-status-validating');\n      expect(inputElement.nativeElement.nextSibling?.classList).not.toContain('ant-form-item-feedback-icon');\n    });\n  });\n\n  describe('input with type', () => {\n    let fixture: ComponentFixture<NzTestInputWithTypeComponent>;\n    let inputElement: DebugElement;\n    let component: NzTestInputWithTypeComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestInputWithTypeComponent);\n      fixture.detectChanges();\n      inputElement = fixture.debugElement.query(By.directive(NzInputDirective));\n      component = fixture.componentInstance;\n      fixture.detectChanges();\n    });\n\n    it('should type correct', () => {\n      expect(inputElement.nativeElement.type).toEqual('text');\n\n      component.type = 'password';\n      fixture.detectChanges();\n      expect(inputElement.nativeElement.type).toEqual('password');\n\n      component.type = 'number';\n      fixture.detectChanges();\n      expect(inputElement.nativeElement.type).toEqual('number');\n\n      component.type = '';\n      fixture.detectChanges();\n      expect(inputElement.nativeElement.type).toEqual('text');\n    });\n  });\n\n  describe('finalSize', () => {\n    let fixture: ComponentFixture<TestInputFinalSizeComponent>;\n    let inputElement: HTMLButtonElement;\n    let component: TestInputFinalSizeComponent;\n    let formSizeSignal: WritableSignal<NzSizeLDSType | undefined>;\n    let compactSizeSignal: WritableSignal<NzSizeLDSType>;\n\n    beforeEach(() => {\n      compactSizeSignal = signal<NzSizeLDSType>('large');\n      formSizeSignal = signal<NzSizeLDSType | undefined>('default');\n    });\n\n    afterEach(() => {\n      TestBed.resetTestingModule();\n    });\n\n    it('should set correctly the size from the formSize signal', () => {\n      TestBed.configureTestingModule({\n        providers: [\n          { provide: NZ_FORM_SIZE, useValue: formSizeSignal },\n          { provide: NZ_SPACE_COMPACT_SIZE, useValue: compactSizeSignal }\n        ]\n      });\n      fixture = TestBed.createComponent(TestInputFinalSizeComponent);\n      component = fixture.componentInstance;\n      inputElement = fixture.debugElement.query(By.directive(NzInputDirective)).nativeElement;\n      fixture.detectChanges();\n      formSizeSignal.set('large');\n      fixture.detectChanges();\n      expect(inputElement.classList).toContain('ant-input-lg');\n    });\n    it('should set correctly the size from the compactSize signal', () => {\n      TestBed.configureTestingModule({\n        providers: [{ provide: NZ_SPACE_COMPACT_SIZE, useValue: compactSizeSignal }]\n      });\n      fixture = TestBed.createComponent(TestInputFinalSizeComponent);\n      component = fixture.componentInstance;\n      inputElement = fixture.debugElement.query(By.directive(NzInputDirective)).nativeElement;\n      fixture.detectChanges();\n      compactSizeSignal.set('large');\n      fixture.detectChanges();\n      expect(inputElement.classList).toContain('ant-input-lg');\n    });\n    it('should set correctly the size from the nzSize input', () => {\n      TestBed.configureTestingModule({});\n      fixture = TestBed.createComponent(TestInputFinalSizeComponent);\n      component = fixture.componentInstance;\n      inputElement = fixture.debugElement.query(By.directive(NzInputDirective)).nativeElement;\n      fixture.detectChanges();\n      component.size = 'large';\n      fixture.detectChanges();\n      expect(inputElement.classList).toContain('ant-input-lg');\n    });\n  });\n\n  describe('finalVariant', () => {\n    let fixture: ComponentFixture<TestInputFinalVariantComponent>;\n    let inputElement: HTMLElement;\n    let component: TestInputFinalVariantComponent;\n    let formVariantSignal: WritableSignal<NzVariant>;\n\n    beforeEach(() => {\n      formVariantSignal = signal<NzVariant>('outlined');\n    });\n\n    afterEach(() => {\n      TestBed.resetTestingModule();\n    });\n\n    it('should set correctly the variant from the formVariant signal', () => {\n      TestBed.configureTestingModule({\n        providers: [{ provide: NZ_FORM_VARIANT, useValue: formVariantSignal }]\n      });\n      fixture = TestBed.createComponent(TestInputFinalVariantComponent);\n      component = fixture.componentInstance;\n      inputElement = fixture.debugElement.query(By.directive(NzInputDirective)).nativeElement;\n      fixture.detectChanges();\n      formVariantSignal.set('filled');\n      fixture.detectChanges();\n      expect(inputElement.classList).toContain('ant-input-filled');\n    });\n\n    it('should prioritize any explicit nzVariant over formVariant', () => {\n      TestBed.configureTestingModule({\n        providers: [{ provide: NZ_FORM_VARIANT, useValue: formVariantSignal }]\n      });\n      fixture = TestBed.createComponent(TestInputFinalVariantComponent);\n      component = fixture.componentInstance;\n      inputElement = fixture.debugElement.query(By.directive(NzInputDirective)).nativeElement;\n      fixture.detectChanges();\n      formVariantSignal.set('filled');\n      component.variant.set('borderless');\n      fixture.detectChanges();\n      expect(inputElement.classList).toContain('ant-input-borderless');\n      expect(inputElement.classList).not.toContain('ant-input-filled');\n    });\n\n    it('should prioritize nzVariant over formVariant when nzVariant is explicitly set', () => {\n      TestBed.configureTestingModule({\n        providers: [{ provide: NZ_FORM_VARIANT, useValue: formVariantSignal }]\n      });\n      fixture = TestBed.createComponent(TestInputFinalVariantComponent);\n      component = fixture.componentInstance;\n      inputElement = fixture.debugElement.query(By.directive(NzInputDirective)).nativeElement;\n      fixture.detectChanges();\n      formVariantSignal.set('filled');\n      component.variant.set('outlined');\n      fixture.detectChanges();\n      expect(inputElement.classList).not.toContain('ant-input-filled');\n      expect(inputElement.classList).not.toContain('ant-input-borderless');\n      expect(inputElement.classList).not.toContain('ant-input-underlined');\n    });\n\n    it('should use nzVariant when no formVariant is provided', () => {\n      TestBed.configureTestingModule({});\n      fixture = TestBed.createComponent(TestInputFinalVariantComponent);\n      component = fixture.componentInstance;\n      inputElement = fixture.debugElement.query(By.directive(NzInputDirective)).nativeElement;\n      fixture.detectChanges();\n      component.variant.set('underlined');\n      fixture.detectChanges();\n      expect(inputElement.classList).toContain('ant-input-underlined');\n    });\n\n    it('should fallback to outlined when neither nzVariant nor formVariant is set', () => {\n      TestBed.configureTestingModule({});\n      fixture = TestBed.createComponent(TestInputFinalVariantComponent);\n      component = fixture.componentInstance;\n      inputElement = fixture.debugElement.query(By.directive(NzInputDirective)).nativeElement;\n      fixture.detectChanges();\n      expect(inputElement.classList).not.toContain('ant-input-filled');\n      expect(inputElement.classList).not.toContain('ant-input-borderless');\n      expect(inputElement.classList).not.toContain('ant-input-underlined');\n    });\n  });\n});\n\n@Component({\n  imports: [BidiModule, NzInputModule, NzIconModule],\n  template: `\n    <div [dir]=\"dir\">\n      <input nz-input />\n      <nz-input-wrapper>\n        <input type=\"text\" nz-input />\n        <nz-icon nzInputAddonAfter nzType=\"setting\" />\n      </nz-input-wrapper>\n    </div>\n  `\n})\nexport class NzTestInputWithDirComponent {\n  dir: Direction = 'ltr';\n}\n\n@Component({\n  imports: [NzInputModule],\n  template: `\n    <input\n      nz-input\n      [nzSize]=\"size\"\n      [disabled]=\"disabled\"\n      [nzVariant]=\"variant\"\n      [nzStepperless]=\"stepperless\"\n      [value]=\"value\"\n    />\n  `\n})\nexport class NzTestInputWithInputComponent {\n  size: NzSizeLDSType = 'default';\n  disabled = false;\n  stepperless = true;\n  variant: NzVariant = 'outlined';\n  value = 'NzTestInput';\n  inputDirective = viewChild.required(NzInputDirective);\n}\n\n@Component({\n  imports: [NzInputModule],\n  template: `<textarea nz-input></textarea>`\n})\nexport class NzTestInputWithTextAreaComponent {}\n\n@Component({\n  imports: [ReactiveFormsModule, NzInputModule],\n  template: `\n    <form>\n      <input nz-input [formControl]=\"formControl\" />\n    </form>\n  `\n})\nexport class NzTestInputFormComponent {\n  formControl = new FormControl('abc');\n\n  disable(): void {\n    this.formControl.disable();\n  }\n}\n\n// status\n@Component({\n  imports: [NzInputModule],\n  template: `<input nz-input [nzStatus]=\"status\" />`\n})\nexport class NzTestInputWithStatusComponent {\n  status: NzStatus = 'error';\n}\n\n@Component({\n  imports: [NzFormModule, NzInputModule],\n  template: `\n    <form nz-form>\n      <nz-form-item>\n        <nz-form-control [nzHasFeedback]=\"feedback\" [nzValidateStatus]=\"status\">\n          <input nz-input />\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `\n})\nexport class NzTestInputInFormComponent {\n  status: NzFormControlStatusType = 'error';\n  feedback = true;\n}\n\n@Component({\n  imports: [NzInputModule],\n  template: `<input nz-input [type]=\"type\" />`\n})\nexport class NzTestInputWithTypeComponent {\n  type: string | null = null;\n}\n\n@Component({\n  imports: [NzInputModule],\n  template: `<input nz-input [nzSize]=\"size\" />`\n})\nexport class TestInputFinalSizeComponent {\n  size: NzSizeLDSType = 'default';\n}\n\n@Component({\n  imports: [NzInputModule],\n  template: `<input nz-input [nzVariant]=\"variant()\" />`\n})\nexport class TestInputFinalVariantComponent {\n  readonly variant = signal<NzVariant | undefined>(undefined);\n}\n"
  },
  {
    "path": "components/input/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/input/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './autosize.directive';\nexport * from './input-addon.directive';\nexport * from './input-affix.directive';\nexport * from './input-group-slot.component';\nexport * from './input-group.component';\nexport * from './input-otp.component';\nexport * from './input-password.directive';\nexport * from './input-search.directive';\nexport * from './input-wrapper.component';\nexport * from './input.directive';\nexport * from './input.module';\nexport * from './textarea-count.component';\nexport * from './tokens';\n"
  },
  {
    "path": "components/input/style/IE11.less",
    "content": "// Fix Input component height issue in IE11\n@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {\n  .@{ant-prefix}-input {\n    height: @input-height-base;\n\n    &-lg {\n      height: @input-height-lg;\n    }\n\n    &-sm {\n      height: @input-height-sm;\n    }\n\n    &-affix-wrapper {\n      > input.@{ant-prefix}-input {\n        height: auto;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/input/style/affix.less",
    "content": "@import './mixin';\n@import (reference) '../../style/themes/index';\n@input-prefix-cls: ~'@{ant-prefix}-input';\n\n@input-affix-margin: 4px;\n\n.@{ant-prefix}-input {\n  &-affix-wrapper {\n    .input();\n    display: inline-flex;\n\n    &:not(&-disabled):hover {\n      .hover();\n      z-index: 1;\n      .@{ant-prefix}-input-search-with-button & {\n        z-index: 0;\n      }\n    }\n\n    &-focused,\n    &:focus {\n      z-index: 1;\n    }\n\n    &-disabled {\n      .@{ant-prefix}-input[disabled] {\n        background: rgba(255, 255, 255, 0);\n      }\n    }\n\n    > .@{ant-prefix}-input {\n      font-size: inherit;\n      border: none;\n      outline: none;\n\n      &:focus {\n        box-shadow: none !important;\n      }\n\n      &:not(textarea) {\n        padding: 0;\n      }\n    }\n\n    &::before {\n      display: inline-block;\n      width: 0;\n      visibility: hidden;\n      content: '\\a0';\n    }\n  }\n\n  &-prefix,\n  &-suffix {\n    display: flex;\n    flex: none;\n    align-items: center;\n\n    > *:not(:last-child) {\n      margin-right: 8px;\n    }\n  }\n\n  &-show-count-suffix {\n    color: @text-color-secondary;\n  }\n\n  &-show-count-has-suffix {\n    margin-right: 2px;\n  }\n\n  &-prefix {\n    margin-right: @input-affix-margin;\n  }\n\n  &-suffix {\n    margin-left: @input-affix-margin;\n  }\n}\n"
  },
  {
    "path": "components/input/style/allow-clear.less",
    "content": "@import (reference) '../../style/themes/index';\n@input-prefix-cls: ~'@{ant-prefix}-input';\n\n// ========================= Input =========================\n.@{iconfont-css-prefix}.@{input-prefix-cls}-clear-icon,\n.@{input-prefix-cls}-clear-icon {\n  margin: 0;\n  color: @disabled-color;\n  font-size: @font-size-sm;\n  vertical-align: -1px;\n  // https://github.com/ant-design/ant-design/pull/18151\n  // https://codesandbox.io/s/wizardly-sun-u10br\n  cursor: pointer;\n  transition: color 0.3s;\n\n  &:hover {\n    color: @text-color-secondary;\n  }\n\n  &:active {\n    color: @text-color;\n  }\n\n  &-hidden {\n    visibility: hidden;\n  }\n\n  &-has-suffix {\n    margin: 0 @input-affix-margin;\n  }\n}\n\n// ======================= TextArea ========================\n.@{input-prefix-cls}-affix-wrapper.@{input-prefix-cls}-affix-wrapper-textarea-with-clear-btn {\n  padding: 0;\n\n  .@{input-prefix-cls}-clear-icon {\n    position: absolute;\n    top: 8px;\n    right: 8px;\n    z-index: 1;\n  }\n}\n"
  },
  {
    "path": "components/input/style/entry.less",
    "content": "@import './index.less';\n@import './patch.less';\n"
  },
  {
    "path": "components/input/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import './mixin';\n@import './affix';\n@import './allow-clear';\n@import './status';\n@input-prefix-cls: ~'@{ant-prefix}-input';\n\n// Input styles\n.@{input-prefix-cls} {\n  .reset-component();\n  .input();\n\n  //== Style for input-group: input with label, with button or dropdown...\n  &-group {\n    .reset-component();\n    .input-group(~'@{input-prefix-cls}');\n\n    &-wrapper {\n      display: inline-block;\n      width: 100%;\n      text-align: start;\n      vertical-align: top; // https://github.com/ant-design/ant-design/issues/6403\n\n      .input-group-wrapper-compact(~'@{input-prefix-cls}');\n    }\n  }\n\n  &-password-icon {\n    color: @text-color-secondary;\n    cursor: pointer;\n    transition: all 0.3s;\n\n    &:hover {\n      color: @input-icon-hover-color;\n    }\n\n    .@{input-prefix-cls}-disabled & {\n      cursor: not-allowed;\n\n      &:hover {\n        color: @text-color-secondary;\n      }\n    }\n  }\n\n  &[type='color'] {\n    height: @input-height-base;\n\n    &.@{input-prefix-cls}-lg {\n      height: @input-height-lg;\n    }\n\n    &.@{input-prefix-cls}-sm {\n      height: @input-height-sm;\n      padding-top: 3px;\n      padding-bottom: 3px;\n    }\n  }\n\n  &-textarea-show-count {\n    // https://github.com/ant-design/ant-design/issues/33049\n    > .@{input-prefix-cls} {\n      height: 100%;\n    }\n\n    &::after {\n      float: right;\n      color: @text-color-secondary;\n      white-space: nowrap;\n      content: attr(data-count);\n      pointer-events: none;\n    }\n\n    &.@{input-prefix-cls}-textarea-in-form-item {\n      &::after {\n        margin-bottom: -22px;\n      }\n    }\n  }\n\n  &-textarea-suffix {\n    position: absolute;\n    top: 0;\n    right: @input-padding-horizontal-base;\n    bottom: 0;\n    z-index: 1;\n    display: inline-flex;\n    align-items: center;\n    margin: auto;\n  }\n\n  &-out-of-range {\n    .@{input-prefix-cls},\n    .@{input-prefix-cls}-show-count-suffix {\n      color: @error-color;\n    }\n  }\n\n  // ===================== Compact Item Styles =====================\n  .compact-item(@input-prefix-cls);\n  .compact-item(~'@{input-prefix-cls}-affix-wrapper');\n  .compact-item(~'@{input-prefix-cls}-group-wrapper', ~'@{input-prefix-cls}-group-addon');\n}\n\n@import './search-input';\n@import './rtl';\n@import './IE11';\n"
  },
  {
    "path": "components/input/style/input-otp.less",
    "content": ".@{ant-prefix}-otp {\n  display: inline-flex;\n  flex-wrap: nowrap;\n  align-items: center;\n  column-gap: 8px;\n\n  &-input {\n    text-align: center;\n    padding-inline: 4px;\n  }\n}\n"
  },
  {
    "path": "components/input/style/mixin.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@input-affix-with-clear-btn-width: 38px;\n\n// size mixins for input\n.input-lg() {\n  padding: @input-padding-vertical-lg @input-padding-horizontal-lg;\n  font-size: @font-size-lg;\n}\n\n.input-sm() {\n  padding: @input-padding-vertical-sm @input-padding-horizontal-sm;\n}\n\n// input status\n// == when focus or active\n.active(@borderColor: @primary-color; @hoverBorderColor: @primary-color-hover; @outlineColor: @primary-color-outline) {\n  & when (@theme = dark) {\n    border-color: @borderColor;\n  }\n  & when (not (@theme = dark) and not (@theme = variable)) {\n    border-color: @hoverBorderColor;\n  }\n  & when not (@theme = variable) {\n    box-shadow: @input-outline-offset @outline-blur-size @outline-width\n      fade(@borderColor, @outline-fade);\n  }\n  & when (@theme = variable) {\n    border-color: @hoverBorderColor;\n    box-shadow: @input-outline-offset @outline-blur-size @outline-width @outlineColor;\n  }\n  border-right-width: @border-width-base;\n  outline: 0;\n}\n\n// == when hover\n.hover(@color: @input-hover-border-color) {\n  border-color: @color;\n  border-right-width: @border-width-base;\n}\n\n.disabled() {\n  color: @input-disabled-color;\n  background-color: @input-disabled-bg;\n  border-color: @input-border-color;\n  box-shadow: none;\n  cursor: not-allowed;\n  opacity: 1;\n\n  &:hover {\n    .hover(@input-border-color);\n  }\n}\n\n// Basic style for input\n.input() {\n  position: relative;\n  display: inline-block;\n  width: 100%;\n  min-width: 0;\n  padding: @input-padding-vertical-base @input-padding-horizontal-base;\n  color: @input-color;\n  font-size: @font-size-base;\n  line-height: @line-height-base;\n  background-color: @input-bg;\n  background-image: none;\n  border: @border-width-base @border-style-base @input-border-color;\n  border-radius: @control-border-radius;\n  transition: all 0.3s;\n  .placeholder(); // Reset placeholder\n\n  &:hover {\n    .hover();\n  }\n\n  &:focus,\n  &-focused {\n    .active();\n  }\n\n  &-disabled {\n    .disabled();\n  }\n\n  &[disabled] {\n    .disabled();\n  }\n\n  &&-borderless,\n  &&-borderless:hover,\n  &&-borderless:focus,\n  &&-borderless&-focused,\n  &&-borderless&-disabled,\n  &&-borderless&[disabled] {\n    background-color: transparent;\n    border: none;\n    box-shadow: none;\n  }\n\n  &&-filled {\n    background-color: @input-variant-filled-bg;\n    border-color: transparent;\n    box-shadow: none;\n  }\n\n  &&-filled:hover {\n    background-color: @input-variant-filled-hover-bg;\n  }\n\n  &&-filled:focus,\n  &&-filled&-focused {\n    .active();\n    background-color: transparent;\n    box-shadow: none;\n  }\n\n  &&-filled&-disabled,\n  &&-filled&[disabled] {\n    .disabled();\n  }\n\n  &&-underlined,\n  &&-underlined:hover,\n  &&-underlined:focus,\n  &&-underlined&-focused,\n  &&-underlined&-disabled,\n  &&-underlined&[disabled] {\n    background-color: transparent;\n    border-width: 0 0 @border-width-base;\n    border-radius: 0;\n    box-shadow: none;\n  }\n\n  &&-underlined:hover:not(&-focused):not(:focus) {\n    border-color: @input-border-color;\n  }\n\n  // Reset height for `textarea`s\n  textarea& {\n    max-width: 100%; // prevent textearea resize from coming out of its container\n    height: auto;\n    min-height: @input-height-base;\n    line-height: @line-height-base;\n    vertical-align: bottom;\n    transition: all 0.3s, height 0s;\n  }\n\n  // Size\n  &-lg {\n    .input-lg();\n  }\n\n  &-sm {\n    .input-sm();\n  }\n}\n\n// label input\n.input-group(@inputClass) {\n  position: relative;\n  display: table;\n  width: 100%;\n  border-collapse: separate;\n  border-spacing: 0;\n\n  // Undo padding and float of grid classes\n  &[class*='col-'] {\n    float: none;\n    padding-right: 0;\n    padding-left: 0;\n  }\n\n  > [class*='col-'] {\n    padding-right: 8px;\n\n    &:last-child {\n      padding-right: 0;\n    }\n  }\n\n  &-addon,\n  &-wrap,\n  > .@{inputClass} {\n    display: table-cell;\n\n    &:not(:first-child):not(:last-child) {\n      border-radius: 0;\n    }\n  }\n\n  &-addon,\n  &-wrap {\n    width: 1px; // To make addon/wrap as small as possible\n    white-space: nowrap;\n    vertical-align: middle;\n  }\n\n  &-wrap > * {\n    display: block !important;\n  }\n\n  .@{inputClass} {\n    float: left;\n    width: 100%;\n    margin-bottom: 0;\n    text-align: inherit;\n\n    &:focus {\n      z-index: 1; // Fix https://gw.alipayobjects.com/zos/rmsportal/DHNpoqfMXSfrSnlZvhsJ.png\n      border-right-width: 1px;\n    }\n\n    &:hover {\n      z-index: 1;\n      border-right-width: 1px;\n      .@{ant-prefix}-input-search-with-button & {\n        z-index: 0;\n      }\n    }\n  }\n\n  &-addon {\n    position: relative;\n    padding: 0 @input-padding-horizontal-base;\n    color: @input-color;\n    font-weight: normal;\n    font-size: @font-size-base;\n    text-align: center;\n    background-color: @input-addon-bg;\n    border: @border-width-base @border-style-base @input-border-color;\n    border-radius: @control-border-radius;\n    transition: all 0.3s;\n\n    // Reset Select's style in addon\n    .@{ant-prefix}-select {\n      margin: -(@input-padding-vertical-base + 1px) (-@input-padding-horizontal-base);\n\n      &.@{ant-prefix}-select-single:not(.@{ant-prefix}-select-customize-input)\n        .@{ant-prefix}-select-selector {\n        background-color: inherit;\n        border: @border-width-base @border-style-base transparent;\n        box-shadow: none;\n      }\n\n      &-open,\n      &-focused {\n        .@{ant-prefix}-select-selector {\n          color: @primary-color;\n        }\n      }\n    }\n\n    // https://github.com/ant-design/ant-design/issues/31333\n    .@{ant-prefix}-cascader-picker {\n      margin: -9px (-@control-padding-horizontal);\n      background-color: transparent;\n      .@{ant-prefix}-cascader-input {\n        text-align: left;\n        border: 0;\n        box-shadow: none;\n      }\n    }\n  }\n\n  // Reset rounded corners\n  > .@{inputClass}:first-child,\n  &-addon:first-child {\n    border-top-right-radius: 0;\n    border-bottom-right-radius: 0;\n\n    // Reset Select's style in addon\n    .@{ant-prefix}-select .@{ant-prefix}-select-selector {\n      border-top-right-radius: 0;\n      border-bottom-right-radius: 0;\n    }\n  }\n\n  > .@{inputClass}-affix-wrapper {\n    &:not(:first-child) .@{inputClass} {\n      border-top-left-radius: 0;\n      border-bottom-left-radius: 0;\n    }\n\n    &:not(:last-child) .@{inputClass} {\n      border-top-right-radius: 0;\n      border-bottom-right-radius: 0;\n    }\n  }\n\n  &-addon:first-child {\n    border-right: 0;\n  }\n\n  &-addon:last-child {\n    border-left: 0;\n  }\n\n  > .@{inputClass}:last-child,\n  &-addon:last-child {\n    border-top-left-radius: 0;\n    border-bottom-left-radius: 0;\n\n    // Reset Select's style in addon\n    .@{ant-prefix}-select .@{ant-prefix}-select-selector {\n      border-top-left-radius: 0;\n      border-bottom-left-radius: 0;\n    }\n  }\n\n  // Sizing options\n  &-lg .@{inputClass},\n  &-lg > &-addon {\n    .input-lg();\n  }\n\n  &-sm .@{inputClass},\n  &-sm > &-addon {\n    .input-sm();\n  }\n\n  // Fix https://github.com/ant-design/ant-design/issues/5754\n  &-lg .@{ant-prefix}-select-single .@{ant-prefix}-select-selector {\n    height: @input-height-lg;\n  }\n\n  &-sm .@{ant-prefix}-select-single .@{ant-prefix}-select-selector {\n    height: @input-height-sm;\n  }\n\n  .@{inputClass}-affix-wrapper {\n    &:not(:last-child) {\n      border-top-right-radius: 0;\n      border-bottom-right-radius: 0;\n      .@{ant-prefix}-input-search & {\n        border-top-left-radius: @control-border-radius;\n        border-bottom-left-radius: @control-border-radius;\n      }\n    }\n\n    &:not(:first-child),\n    .@{ant-prefix}-input-search &:not(:first-child) {\n      border-top-left-radius: 0;\n      border-bottom-left-radius: 0;\n    }\n  }\n\n  &&-compact {\n    display: block;\n    .clearfix();\n\n    &-addon,\n    &-wrap,\n    > .@{inputClass} {\n      &:not(:first-child):not(:last-child) {\n        border-right-width: @border-width-base;\n\n        &:hover {\n          z-index: 1;\n        }\n\n        &:focus {\n          z-index: 1;\n        }\n      }\n    }\n\n    & > * {\n      display: inline-block;\n      float: none;\n      vertical-align: top; // https://github.com/ant-design/ant-design-pro/issues/139\n      border-radius: 0;\n    }\n\n    & > .@{inputClass}-affix-wrapper,\n    & > .@{inputClass}-number-affix-wrapper,\n    & > .@{ant-prefix}-picker-range {\n      display: inline-flex;\n    }\n\n    & > *:not(:last-child) {\n      margin-right: -@border-width-base;\n      border-right-width: @border-width-base;\n    }\n\n    // Undo float for .ant-input-group .ant-input\n    .@{inputClass} {\n      float: none;\n    }\n\n    // reset border for Select, DatePicker, AutoComplete, Cascader, Mention, TimePicker, Input\n    & > .@{ant-prefix}-select > .@{ant-prefix}-select-selector,\n    & > .@{ant-prefix}-select-auto-complete .@{ant-prefix}-input,\n    & > .@{ant-prefix}-cascader-picker .@{ant-prefix}-input,\n    & > .@{ant-prefix}-input-group-wrapper .@{ant-prefix}-input {\n      border-right-width: @border-width-base;\n      border-radius: 0;\n\n      &:hover {\n        z-index: 1;\n      }\n\n      &:focus {\n        z-index: 1;\n      }\n    }\n\n    & > .@{ant-prefix}-select-focused {\n      z-index: 1;\n    }\n\n    // update z-index for arrow icon\n    & > .@{ant-prefix}-select > .@{ant-prefix}-select-arrow {\n      z-index: 1; // https://github.com/ant-design/ant-design/issues/20371\n    }\n\n    & > *:first-child,\n    & > .@{ant-prefix}-select:first-child > .@{ant-prefix}-select-selector,\n    & > .@{ant-prefix}-select-auto-complete:first-child .@{ant-prefix}-input,\n    & > .@{ant-prefix}-cascader-picker:first-child .@{ant-prefix}-input {\n      border-top-left-radius: @control-border-radius;\n      border-bottom-left-radius: @control-border-radius;\n    }\n\n    & > *:last-child,\n    & > .@{ant-prefix}-select:last-child > .@{ant-prefix}-select-selector,\n    & > .@{ant-prefix}-cascader-picker:last-child .@{ant-prefix}-input,\n    & > .@{ant-prefix}-cascader-picker-focused:last-child .@{ant-prefix}-input {\n      border-right-width: @border-width-base;\n      border-top-right-radius: @control-border-radius;\n      border-bottom-right-radius: @control-border-radius;\n    }\n\n    // https://github.com/ant-design/ant-design/issues/12493\n    & > .@{ant-prefix}-select-auto-complete .@{ant-prefix}-input {\n      vertical-align: top;\n    }\n\n    .@{ant-prefix}-input-group-wrapper + .@{ant-prefix}-input-group-wrapper {\n      margin-left: -1px;\n      .@{ant-prefix}-input-affix-wrapper {\n        border-radius: 0;\n      }\n    }\n\n    .@{ant-prefix}-input-group-wrapper:not(:last-child) {\n      &.@{ant-prefix}-input-search > .@{ant-prefix}-input-group {\n        & > .@{ant-prefix}-input-group-addon > .@{ant-prefix}-input-search-button {\n          border-radius: 0;\n        }\n\n        & > .@{ant-prefix}-input {\n          border-radius: @control-border-radius 0 0 @control-border-radius;\n        }\n      }\n    }\n  }\n}\n\n.input-group-wrapper-compact(@inputClass) {\n  // Fix the issue of using icons in Space Compact mode\n  // https://github.com/ant-design/ant-design/issues/42122\n  &:not(.@{inputClass}-compact-first-item):not(.@{inputClass}-compact-last-item).@{inputClass}-compact-item {\n    .@{inputClass},\n    .@{inputClass}-group-addon {\n      border-radius: 0,\n    }\n  }\n\n  &:not(.@{inputClass}-compact-last-item).@{inputClass}-compact-first-item {\n    .@{inputClass},\n    .@{inputClass}-group-addon {\n      border-start-end-radius: 0;\n      border-end-end-radius: 0;\n    }\n  }\n\n  &:not(.@{inputClass}-compact-first-item).@{inputClass}-compact-last-item {\n    .@{inputClass},\n    .@{inputClass}-group-addon {\n      border-start-start-radius: 0;\n      border-end-start-radius: 0;\n    }\n  }\n\n  // Fix the issue of input use show-count param in space compact mode\n  // https://github.com/ant-design/ant-design/issues/46872\n  &:not(.@{inputClass}-compact-last-item).@{inputClass}-compact-item {\n    .@{inputClass}-affix-wrapper {\n      border-start-end-radius: 0;\n      border-end-end-radius: 0;\n    }\n  }\n\n  // Fix the issue of input use `addonAfter` param in space compact mode\n  // https://github.com/ant-design/ant-design/issues/52483\n  &:not(.@{inputClass}-compact-first-item).@{inputClass}-compact-item {\n    .@{inputClass}-affix-wrapper {\n      border-start-start-radius: 0;\n      border-end-start-radius: 0;\n    }\n  }\n}\n\n.status-color(\n  @prefix-cls: @input-prefix-cls;\n  @text-color: @input-color;\n  @border-color: @input-border-color;\n  @background-color: @input-bg;\n  @hoverBorderColor: @primary-color-hover;\n  @outlineColor: @primary-color-outline;\n) {\n  &:not(.@{prefix-cls}-disabled):not(.@{prefix-cls}-borderless).@{prefix-cls} {\n    &,\n    &:hover {\n      background: @background-color;\n      border-color: @border-color;\n    }\n\n    &:focus,\n    &-focused {\n      .active(@text-color, @hoverBorderColor, @outlineColor);\n    }\n  }\n}\n\n.status-color-common(\n  @prefix-cls: @input-prefix-cls;\n  @text-color: @input-color;\n  @border-color: @input-border-color;\n  @background-color: @input-bg;\n  @hoverBorderColor: @primary-color-hover;\n  @outlineColor: @primary-color-outline;\n) {\n  .@{prefix-cls}-prefix {\n    color: @text-color;\n  }\n}\n\n.group-status-color(\n  @prefix-cls: @input-prefix-cls;\n  @text-color: @input-color;\n  @border-color: @input-border-color;\n) {\n  .@{prefix-cls}-group-addon {\n    color: @text-color;\n    border-color: @border-color;\n  }\n}\n"
  },
  {
    "path": "components/input/style/patch.less",
    "content": "@import './input-otp';\n\ntextarea.nz-textarea-autosize-measuring {\n  height: auto !important;\n  // Having 2px top and bottom padding seems to fix a bug where Chrome gets an incorrect\n  // measurement. We just have to account for it later and subtract it off the final result.\n  padding: 2px 0 !important;\n  overflow: hidden !important;\n}\n\n.@{search-prefix} {\n  &-enter-button {\n    & + .@{ant-prefix}-input-group-addon,\n    input + .@{ant-prefix}-input-group-addon {\n      .@{search-rtl-cls}& {\n        .@{search-prefix}-button.@{ant-prefix}-btn-icon-only {\n          .square(@btn-height-base);\n          &.@{ant-prefix}-btn-sm {\n            .square(@btn-height-sm);\n          }\n          &.@{ant-prefix}-btn-lg {\n            .square(@btn-height-lg);\n          }\n        }\n      }\n    }\n  }\n}\n\n.ant-input-affix-wrapper-textarea-with-clear-btn .ant-input-suffix {\n  margin-left: 0;\n}\n\nnz-form-item-feedback-icon.@{ant-prefix}-input {\n  &-suffix {\n    position: absolute;\n    top: 0;\n    right: 0;\n    z-index: 1;\n    display: flex;\n    flex: none;\n    align-items: center;\n    height: 100%;\n    margin-right: @padding-sm;\n    margin-left: @input-affix-margin;\n    pointer-events: none;\n  }\n}\n\n.@{ant-prefix}-input {\n  &-status-error,\n  &-status-warning,\n  &-status-validating,\n  &-status-success {\n    &.@{ant-prefix}-input-has-feedback {\n      padding-right: @padding-lg + @padding-xss;\n    }\n  }\n}\n\n.@{ant-prefix}-input-textarea-show-count {\n  position: relative;\n  display: block;\n}\n\n.input() {\n  &-stepperless[type='number'] {\n    /* stylelint-disable-next-line property-no-vendor-prefix */\n    -moz-appearance: textfield;\n\n    &::-webkit-inner-spin-button,\n    ::-webkit-outer-spin-button {\n      margin: 0;\n      /* stylelint-disable-next-line property-no-vendor-prefix */\n      -webkit-appearance: none;\n    }\n  }\n}\n\n.@{ant-prefix}-otp-input {\n  width: auto;\n}\n"
  },
  {
    "path": "components/input/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n//== Style for input-group: input with label, with button or dropdown...\n.@{ant-prefix}-input-group {\n  &-wrapper {\n    &-rtl {\n      direction: rtl;\n    }\n  }\n\n  &-rtl {\n    direction: rtl;\n  }\n}\n\n// affix\n@input-affix-margin: 4px;\n\n.@{ant-prefix}-input {\n  &-affix-wrapper&-affix-wrapper-rtl {\n    > input.@{ant-prefix}-input {\n      border: none;\n      outline: none;\n    }\n  }\n\n  &-affix-wrapper-rtl {\n    .@{ant-prefix}-input-prefix {\n      margin: 0 0 0 @input-affix-margin;\n    }\n\n    .@{ant-prefix}-input-suffix {\n      margin: 0 @input-affix-margin 0 0;\n    }\n  }\n\n  &-textarea {\n    &-rtl {\n      direction: rtl;\n    }\n\n    &-rtl&-show-count::after {\n      text-align: left;\n    }\n  }\n}\n\n// allow-clear\n.@{ant-prefix}-input-clear-icon {\n  &-has-suffix {\n    .@{ant-prefix}-input-affix-wrapper-rtl & {\n      margin-right: 0;\n      margin-left: @input-affix-margin;\n    }\n  }\n\n  .@{ant-prefix}-input-affix-wrapper-rtl & {\n    right: auto;\n    left: 8px;\n  }\n}\n\n// mixin\n@input-rtl-cls: ~'@{ant-prefix}-input-rtl';\n\n.active() {\n  .@{input-rtl-cls} & {\n    border-right-width: 0;\n    border-left-width: @border-width-base !important;\n  }\n}\n\n.hover() {\n  .@{input-rtl-cls} & {\n    border-right-width: 0;\n    border-left-width: @border-width-base !important;\n  }\n}\n\n.input() {\n  &-rtl {\n    direction: rtl;\n  }\n}\n\n// label input\n.input-group(@inputClass) {\n  > .@{inputClass}-rtl:first-child,\n  &-rtl &-addon:first-child {\n    border-radius: 0 @border-radius-base @border-radius-base 0;\n  }\n\n  &-addon:first-child {\n    .@{inputClass}-group-rtl & {\n      border-right: @border-width-base @border-style-base @input-border-color;\n      border-left: 0;\n    }\n  }\n\n  &-addon:last-child {\n    .@{inputClass}-group-rtl & {\n      border-right: 0;\n      border-left: @border-width-base @border-style-base @input-border-color;\n      border-radius: @border-radius-base 0 0 @border-radius-base;\n    }\n  }\n\n  > .@{inputClass}:last-child,\n  &-addon:last-child {\n    .@{inputClass}-group-rtl& {\n      border-radius: @border-radius-base 0 0 @border-radius-base;\n    }\n  }\n\n  .@{inputClass}-affix-wrapper {\n    &:not(:first-child) {\n      .@{inputClass}-group-rtl& {\n        border-radius: @border-radius-base 0 0 @border-radius-base;\n      }\n    }\n\n    &:not(:last-child) {\n      .@{inputClass}-group-rtl& {\n        border-radius: 0 @border-radius-base @border-radius-base 0;\n      }\n    }\n  }\n\n  &&-compact {\n    & > *:not(:last-child) {\n      .@{inputClass}-group-rtl& {\n        margin-right: 0;\n        margin-left: -@border-width-base;\n        border-left-width: @border-width-base;\n      }\n    }\n\n    & > *:first-child,\n    & > .@{ant-prefix}-select:first-child > .@{ant-prefix}-select-selector,\n    & > .@{ant-prefix}-select-auto-complete:first-child .@{ant-prefix}-input,\n    & > .@{ant-prefix}-cascader-picker:first-child .@{ant-prefix}-input {\n      .@{inputClass}-group-rtl& {\n        border-radius: 0 @border-radius-base @border-radius-base 0;\n      }\n    }\n\n    & > *:last-child,\n    & > .@{ant-prefix}-select:last-child > .@{ant-prefix}-select-selector,\n    & > .@{ant-prefix}-select-auto-complete:last-child .@{ant-prefix}-input,\n    & > .@{ant-prefix}-cascader-picker:last-child .@{ant-prefix}-input,\n    & > .@{ant-prefix}-cascader-picker-focused:last-child .@{ant-prefix}-input {\n      .@{inputClass}-group-rtl& {\n        border-left-width: @border-width-base;\n        border-radius: @border-radius-base 0 0 @border-radius-base;\n      }\n    }\n\n    .@{ant-prefix}-input-group-wrapper-rtl + .@{ant-prefix}-input-group-wrapper-rtl {\n      margin-right: -1px;\n      margin-left: 0;\n    }\n\n    .@{ant-prefix}-input-group-wrapper-rtl:not(:last-child) {\n      &.@{ant-prefix}-input-search > .@{ant-prefix}-input-group {\n        & > .@{ant-prefix}-input {\n          border-radius: 0 @border-radius-base @border-radius-base 0;\n        }\n      }\n    }\n  }\n}\n\n// search-input\n@search-prefix: ~'@{ant-prefix}-input-search';\n@search-rtl-cls: ~'@{search-prefix}-rtl';\n\n.@{search-prefix}-rtl {\n  direction: rtl;\n\n  .@{ant-prefix}-input {\n    &:hover,\n    &:focus {\n      + .@{ant-prefix}-input-group-addon .@{search-prefix}-button:not(.@{ant-prefix}-btn-primary) {\n        border-left-color: @border-color-base;\n\n        &:hover {\n          border-left-color: @input-hover-border-color;\n        }\n      }\n    }\n  }\n\n  > .@{ant-prefix}-input-group {\n    > .@{ant-prefix}-input-affix-wrapper {\n      &:hover,\n      &-focused {\n        border-right-color: @input-hover-border-color;\n      }\n    }\n\n    > .@{ant-prefix}-input-group-addon:last-child {\n      right: -1px;\n      left: auto;\n      .@{search-prefix}-button {\n        border-radius: @border-radius-base 0 0 @border-radius-base;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/input/style/search-input.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import '../../button/style/mixin';\n@import './mixin';\n\n@search-prefix: ~'@{ant-prefix}-input-search';\n\n.@{search-prefix} {\n  .@{ant-prefix}-input {\n    &:hover,\n    &:focus {\n      border-color: @input-hover-border-color;\n\n      + .@{ant-prefix}-input-group-addon .@{search-prefix}-button:not(.@{ant-prefix}-btn-primary) {\n        border-left-color: @input-hover-border-color;\n      }\n    }\n  }\n\n  .@{ant-prefix}-input-affix-wrapper {\n    border-radius: 0;\n  }\n\n  // fix slight height diff in Firefox:\n  // https://ant.design/components/auto-complete-cn/#components-auto-complete-demo-certain-category\n  .@{ant-prefix}-input-lg {\n    line-height: @line-height-base - 0.0002;\n  }\n\n  > .@{ant-prefix}-input-group {\n    > .@{ant-prefix}-input-group-addon:last-child {\n      left: -1px;\n      padding: 0;\n      border: 0;\n\n      .@{search-prefix}-button {\n        padding-top: 0;\n        padding-bottom: 0;\n        border-radius: 0 @border-radius-base @border-radius-base 0;\n      }\n\n      .@{search-prefix}-button:not(.@{ant-prefix}-btn-primary) {\n        color: @text-color-secondary;\n\n        &.@{ant-prefix}-btn-loading::before {\n          top: 0;\n          right: 0;\n          bottom: 0;\n          left: 0;\n        }\n      }\n    }\n  }\n\n  &-button {\n    height: @input-height-base;\n\n    &:hover,\n    &:focus {\n      z-index: 1;\n    }\n  }\n\n  &-large &-button {\n    height: @input-height-lg;\n  }\n\n  &-small &-button {\n    height: @input-height-sm;\n  }\n\n  // ===================== Compact Item Customized Styles =====================\n  &.@{input-prefix-cls}-compact-item {\n    &:not(.@{input-prefix-cls}-compact-item-rtl) {\n      &:not(.@{input-prefix-cls}-compact-last-item) {\n        .@{input-prefix-cls}-group-addon {\n          .@{input-prefix-cls}-search-button {\n            margin-right: -@border-width-base;\n            border-radius: 0;\n          }\n        }\n      }\n    }\n\n    &:not(.@{input-prefix-cls}-compact-first-item) {\n      .@{input-prefix-cls},\n      .@{input-prefix-cls}-affix-wrapper {\n        border-radius: 0;\n      }\n    }\n\n    > .@{input-prefix-cls}-group-addon .@{input-prefix-cls}-search-button,\n    > .@{input-prefix-cls},\n    .@{input-prefix-cls}-affix-wrapper {\n      &:hover,\n      &:focus,\n      &:active {\n        z-index: 2;\n      }\n    }\n\n    > .@{input-prefix-cls}-affix-wrapper-focused {\n      z-index: 2;\n    }\n  }\n  // ===================== For RTL Compact Item Customized Styles =====================\n  &.@{input-prefix-cls}-compact-item-rtl {\n    &:not(.@{input-prefix-cls}-compact-last-item) {\n      .@{input-prefix-cls}-group-addon:last-child {\n        .@{input-prefix-cls}-search-button {\n          margin-left: -@border-width-base;\n          border-radius: 0;\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/input/style/status.less",
    "content": "@import './mixin';\n\n@input-prefix-cls: ~'@{ant-prefix}-input';\n\n@input-wrapper-cls: @input-prefix-cls, ~'@{input-prefix-cls}-affix-wrapper';\n\neach(@input-wrapper-cls, {\n  .@{value} {\n    &-status-error {\n      .status-color(@value, @error-color, @error-color, @input-bg, @error-color-hover, @error-color-outline);\n      .status-color-common(@input-prefix-cls, @error-color, @error-color, @input-bg, @error-color-hover, @error-color-outline);\n    }\n\n    &-status-warning {\n      .status-color(@value, @warning-color, @warning-color, @input-bg, @warning-color-hover, @warning-color-outline);\n      .status-color-common(@input-prefix-cls, @warning-color, @warning-color, @input-bg, @warning-color-hover, @warning-color-outline);\n    }\n  }\n});\n\n.@{input-prefix-cls}-textarea {\n  &-status-error,\n  &-status-warning,\n  &-status-success,\n  &-status-validating {\n    &.@{input-prefix-cls}-textarea-has-feedback {\n      .@{input-prefix-cls} {\n        padding-right: 24px;\n      }\n    }\n  }\n}\n\n.@{input-prefix-cls}-group-wrapper {\n  &-status-error {\n    .group-status-color(@input-prefix-cls, @error-color, @error-color);\n  }\n\n  &-status-warning {\n    .group-status-color(@input-prefix-cls, @warning-color, @warning-color);\n  }\n}\n"
  },
  {
    "path": "components/input/textarea-count.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  AfterContentInit,\n  ChangeDetectionStrategy,\n  Component,\n  ContentChild,\n  DestroyRef,\n  ElementRef,\n  inject,\n  Input,\n  isDevMode,\n  numberAttribute,\n  Renderer2\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { EMPTY } from 'rxjs';\nimport { map, startWith } from 'rxjs/operators';\n\nimport { isNotNil } from 'ng-zorro-antd/core/util';\n\nimport { NzInputDirective } from './input.directive';\n\n@Component({\n  selector: 'nz-textarea-count',\n  template: `<ng-content select=\"textarea[nz-input]\" />`,\n  host: {\n    class: 'ant-input-textarea-show-count'\n  },\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class NzTextareaCountComponent implements AfterContentInit {\n  private renderer = inject(Renderer2);\n  private destroyRef = inject(DestroyRef);\n  private elementRef: ElementRef<HTMLElement> = inject(ElementRef);\n\n  @ContentChild(NzInputDirective, { static: true }) nzInputDirective!: NzInputDirective;\n  @Input({ transform: numberAttribute }) nzMaxCharacterCount: number = 0;\n  @Input() nzComputeCharacterCount: (v: string) => number = v => v.length;\n  @Input() nzFormatter: (cur: number, max: number) => string = (c, m) => `${c}${m > 0 ? `/${m}` : ``}`;\n\n  ngAfterContentInit(): void {\n    if (!this.nzInputDirective && isDevMode()) {\n      throw new Error('[nz-textarea-count]: Could not find matching textarea[nz-input] child.');\n    }\n\n    if (this.nzInputDirective.ngControl) {\n      const valueChanges = this.nzInputDirective.ngControl.valueChanges || EMPTY;\n      valueChanges\n        .pipe(\n          takeUntilDestroyed(this.destroyRef),\n          map(() => this.nzInputDirective.ngControl!.value),\n          startWith(this.nzInputDirective.ngControl.value as string)\n        )\n        .subscribe(value => {\n          this.setDataCount(value);\n        });\n    }\n  }\n\n  setDataCount(value: string): void {\n    const inputValue = isNotNil(value) ? String(value) : '';\n    const currentCount = this.nzComputeCharacterCount(inputValue);\n    const dataCount = this.nzFormatter(currentCount, this.nzMaxCharacterCount);\n    this.renderer.setAttribute(this.elementRef.nativeElement, 'data-count', dataCount);\n  }\n}\n"
  },
  {
    "path": "components/input/textarea-count.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, fakeAsync, flush, TestBed } from '@angular/core/testing';\nimport { FormsModule } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\n\nimport { NzInputModule } from 'ng-zorro-antd/input/input.module';\nimport { NzTextareaCountComponent } from 'ng-zorro-antd/input/textarea-count.component';\n\ndescribe('textarea-count', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  describe('without-max-length', () => {\n    let fixture: ComponentFixture<NzTestInputTextareaCountWithoutMaxComponent>;\n    let testComponent: NzTestInputTextareaCountWithoutMaxComponent;\n    let textareaCountElement: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestInputTextareaCountWithoutMaxComponent);\n      testComponent = fixture.debugElement.componentInstance;\n      fixture.detectChanges();\n      textareaCountElement = fixture.debugElement.query(By.directive(NzTextareaCountComponent)).nativeElement;\n    });\n\n    it('should count work', () => {\n      expect(textareaCountElement.getAttribute('data-count')).toBe('0');\n    });\n\n    it('should count update work', fakeAsync(() => {\n      testComponent.inputValue = 'test';\n      fixture.detectChanges();\n      flush();\n\n      expect(textareaCountElement.getAttribute('data-count')).toBe('4');\n    }));\n  });\n\n  describe('with-max-length', () => {\n    let fixture: ComponentFixture<NzTestInputTextareaCountWithMaxComponent>;\n    let testComponent: NzTestInputTextareaCountWithMaxComponent;\n    let textareaCountElement: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestInputTextareaCountWithMaxComponent);\n      testComponent = fixture.debugElement.componentInstance;\n      fixture.detectChanges();\n      textareaCountElement = fixture.debugElement.query(By.directive(NzTextareaCountComponent)).nativeElement;\n    });\n\n    it('should count with max length work', () => {\n      expect(textareaCountElement.getAttribute('data-count')).toBe('0/100');\n    });\n\n    it('should count update with max length work', fakeAsync(() => {\n      testComponent.inputValue = 'test';\n      fixture.detectChanges();\n      flush();\n\n      expect(textareaCountElement.getAttribute('data-count')).toBe('4/100');\n    }));\n  });\n});\n\n@Component({\n  imports: [FormsModule, NzInputModule],\n  template: `\n    <nz-textarea-count>\n      <textarea rows=\"4\" nz-input [(ngModel)]=\"inputValue\"></textarea>\n    </nz-textarea-count>\n  `\n})\nexport class NzTestInputTextareaCountWithoutMaxComponent {\n  inputValue = '';\n}\n\n@Component({\n  imports: [FormsModule, NzInputModule],\n  template: `\n    <nz-textarea-count [nzMaxCharacterCount]=\"100\">\n      <textarea rows=\"4\" nz-input [(ngModel)]=\"inputValue\"></textarea>\n    </nz-textarea-count>\n  `\n})\nexport class NzTestInputTextareaCountWithMaxComponent {\n  inputValue = '';\n}\n"
  },
  {
    "path": "components/input/tokens.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { InjectionToken } from '@angular/core';\n\nimport { NzInputSearchDirective } from './input-search.directive';\nimport type { NzInputWrapperComponent } from './input-wrapper.component';\n\nexport const NZ_INPUT_WRAPPER = new InjectionToken<NzInputWrapperComponent>(\n  typeof ngDevMode !== 'undefined' && ngDevMode ? 'nz-input-wrapper' : ''\n);\n\nexport const NZ_INPUT_SEARCH = new InjectionToken<NzInputSearchDirective>(\n  typeof ngDevMode !== 'undefined' && ngDevMode ? 'nz-input-search' : ''\n);\n"
  },
  {
    "path": "components/input-number/demo/addon.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 前置/后置标签\n  en-US: Pre / Post tab\n---\n\n## zh-CN\n\n用于配置一些固定组合。\n\n## en-US\n\nUsing pre & post tabs example.\n"
  },
  {
    "path": "components/input-number/demo/addon.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCascaderModule } from 'ng-zorro-antd/cascader';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputNumberModule } from 'ng-zorro-antd/input-number';\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\n@Component({\n  selector: 'nz-demo-input-number-addon',\n  imports: [FormsModule, NzSelectModule, NzCascaderModule, NzInputNumberModule, NzIconModule],\n  template: `\n    <nz-input-number nzAddonBefore=\"+\" nzAddonAfter=\"$\" [(ngModel)]=\"value\" />\n\n    <nz-input-number [(ngModel)]=\"value\">\n      <span nzInputAddonBefore>+</span>\n      <span nzInputAddonAfter>$</span>\n    </nz-input-number>\n\n    <nz-input-number [(ngModel)]=\"value\">\n      <nz-select nzInputAddonBefore ngModel=\"add\" [style.width.px]=\"60\">\n        <nz-option nzLabel=\"+\" nzValue=\"add\" />\n        <nz-option nzLabel=\"-\" nzValue=\"minus\" />\n      </nz-select>\n      <nz-select nzInputAddonAfter ngModel=\"USD\" [style.width.px]=\"60\">\n        <nz-option nzValue=\"USD\" nzLabel=\"$\" />\n        <nz-option nzValue=\"EUR\" nzLabel=\"€\" />\n        <nz-option nzValue=\"GBP\" nzLabel=\"£\" />\n        <nz-option nzValue=\"CNY\" nzLabel=\"¥\" />\n      </nz-select>\n    </nz-input-number>\n\n    <nz-input-number [(ngModel)]=\"value\">\n      <nz-icon nzInputAddonAfter nzType=\"setting\" />\n    </nz-input-number>\n\n    <nz-input-number [(ngModel)]=\"value\">\n      <nz-cascader nzInputAddonBefore [nzOptions]=\"[]\" nzPlaceHolder=\"cascader\" [style.width.px]=\"150\" />\n    </nz-input-number>\n  `,\n  styles: `\n    nz-input-number {\n      display: block;\n      margin-bottom: 8px;\n    }\n  `\n})\nexport class NzDemoInputNumberAddonComponent {\n  value = 100;\n}\n"
  },
  {
    "path": "components/input-number/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n数字输入框。\n\n## en-US\n\nNumeric-only input box.\n"
  },
  {
    "path": "components/input-number/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzInputNumberModule } from 'ng-zorro-antd/input-number';\n\n@Component({\n  selector: 'nz-demo-input-number-basic',\n  imports: [FormsModule, NzInputNumberModule],\n  template: `<nz-input-number [(ngModel)]=\"value\" nzMin=\"1\" nzMax=\"10\" />`\n})\nexport class NzDemoInputNumberBasicComponent {\n  value = 3;\n}\n"
  },
  {
    "path": "components/input-number/demo/change-on-wheel.md",
    "content": "---\norder: 12\ntitle:\n  zh-CN: 鼠标滚轮控制\n  en-US: Mouse wheel behavior\n---\n\n## zh-CN\n\n使用 `nzChangeOnWheel` 启用鼠标滚轮控制。\n\n## en-US\n\nUse the `nzChangeOnWheel` property to control with the mouse wheel.\n`\n"
  },
  {
    "path": "components/input-number/demo/change-on-wheel.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzInputNumberModule, NzInputNumberStepEvent } from 'ng-zorro-antd/input-number';\n\n@Component({\n  selector: 'nz-demo-input-number-change-on-wheel',\n  imports: [FormsModule, NzInputNumberModule, NzButtonModule],\n  template: `\n    <nz-input-number\n      nzChangeOnWheel\n      [(ngModel)]=\"value\"\n      (ngModelChange)=\"onChange($event)\"\n      (nzOnStep)=\"onStep($event)\"\n    />\n  `\n})\nexport class NzDemoInputNumberChangeOnWheelComponent {\n  value = 3;\n\n  onChange(value: number): void {\n    console.log(value);\n  }\n\n  onStep(event: NzInputNumberStepEvent): void {\n    console.log(event);\n  }\n}\n"
  },
  {
    "path": "components/input-number/demo/digit.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 小数\n  en-US: Decimals\n---\n\n## zh-CN\n\n和原生的数字输入框一样，value 的精度由 `nzStep` 的小数位数决定。\n\n## en-US\n\nA numeric-only input box whose values can be increased or decreased using a decimal step. The number of decimals (also known as precision) is determined by the `nzStep` prop.\n"
  },
  {
    "path": "components/input-number/demo/digit.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzInputNumberModule } from 'ng-zorro-antd/input-number';\n\n@Component({\n  selector: 'nz-demo-input-number-digit',\n  imports: [FormsModule, NzInputNumberModule],\n  template: `<nz-input-number [(ngModel)]=\"value\" nzMin=\"0\" nzMax=\"10\" nzStep=\"0.1\" nzPlaceHolder=\"Digital\" />`\n})\nexport class NzDemoInputNumberDigitComponent {\n  value = 0.1;\n}\n"
  },
  {
    "path": "components/input-number/demo/disabled.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 不可用\n  en-US: Disabled\n---\n\n## zh-CN\n\n点击按钮切换可用状态。\n\n## en-US\n\nClick the button to toggle between available and disabled states.\n"
  },
  {
    "path": "components/input-number/demo/disabled.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzInputNumberModule } from 'ng-zorro-antd/input-number';\n\n@Component({\n  selector: 'nz-demo-input-number-disabled',\n  imports: [FormsModule, NzButtonModule, NzInputNumberModule],\n  template: `\n    <nz-input-number [(ngModel)]=\"value\" nzMin=\"1\" nzMax=\"10\" [nzDisabled]=\"isDisabled\" />\n    <br />\n    <br />\n    <button nz-button nzType=\"primary\" (click)=\"isDisabled = !isDisabled\">Toggle Disabled</button>\n  `\n})\nexport class NzDemoInputNumberDisabledComponent {\n  value = 3;\n  isDisabled = false;\n}\n"
  },
  {
    "path": "components/input-number/demo/focus.md",
    "content": "---\norder: 13\ntitle:\n  zh-CN: Focus 额外配置属性\n  en-US: Focus with additional option\n---\n\n## zh-CN\n\nFocus 提供额外配置属性\n\n## en-US\n\nFocus with additional option.\n`\n"
  },
  {
    "path": "components/input-number/demo/focus.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzInputNumberModule } from 'ng-zorro-antd/input-number';\n\n@Component({\n  selector: 'nz-demo-input-number-focus',\n  imports: [FormsModule, NzInputNumberModule, NzButtonModule],\n  template: `\n    <button nz-button (click)=\"inputNumber.focus({ cursor: 'start' })\">Focus at first</button>\n    <button nz-button (click)=\"inputNumber.focus({ cursor: 'end' })\">Focus at last</button>\n    <button nz-button (click)=\"inputNumber.focus({ cursor: 'all' })\">Focus to select all</button>\n    <button nz-button (click)=\"inputNumber.focus({ preventScroll: true })\"> Focus prevent scroll </button>\n\n    <br />\n    <br />\n\n    <nz-input-number #inputNumber [(ngModel)]=\"value\" [style.width.%]=\"100\" />\n  `\n})\nexport class NzDemoInputNumberFocusComponent {\n  value = 9999;\n}\n"
  },
  {
    "path": "components/input-number/demo/formatter.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 格式化展示\n  en-US: Formatter\n---\n\n## zh-CN\n\n通过 `nzFormatter` 格式化数字，以展示具有具体含义的数据，往往需要配合 `nzParser` 一起使用。\n\n## en-US\n\nDisplay value within it's situation with `nzFormatter`, and we usually use `nzParser` at the same time.\n"
  },
  {
    "path": "components/input-number/demo/formatter.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzInputNumberModule } from 'ng-zorro-antd/input-number';\n\n@Component({\n  selector: 'nz-demo-input-number-formatter',\n  imports: [FormsModule, NzInputNumberModule],\n  template: `\n    <nz-input-number [(ngModel)]=\"dollarValue\" [nzFormatter]=\"formatterDollar\" [nzParser]=\"parserDollar\" />\n    <nz-input-number\n      [(ngModel)]=\"percentValue\"\n      nzMin=\"1\"\n      nzMax=\"100\"\n      [nzFormatter]=\"formatterPercent\"\n      [nzParser]=\"parserPercent\"\n    />\n  `,\n  styles: `\n    nz-input-number {\n      margin-right: 8px;\n    }\n  `\n})\nexport class NzDemoInputNumberFormatterComponent {\n  dollarValue = 1000;\n  percentValue = 100;\n  formatterDollar = (value: number): string => `$ ${value}`.replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n  parserDollar = (value: string): number => +value?.replace(/\\$\\s?|(,*)/g, '');\n  formatterPercent = (value: number): string => `${value}%`;\n  parserPercent = (value: string): number => +value?.replace('%', '');\n}\n"
  },
  {
    "path": "components/input-number/demo/handler-icon.md",
    "content": "---\norder: 11\ntitle:\n  zh-CN: 自定义图标\n  en-US: Custom handler icon\n---\n\n## zh-CN\n\n自定义箭头图标。\n\n## en-US\n\nCustom arrow icon.\n"
  },
  {
    "path": "components/input-number/demo/handler-icon.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputNumberModule } from 'ng-zorro-antd/input-number';\n\n@Component({\n  selector: 'nz-demo-input-number-handler-icon',\n  imports: [FormsModule, NzInputNumberModule, NzIconModule],\n  template: `\n    <nz-input-number [(ngModel)]=\"value\">\n      <nz-icon nzInputNumberUpIcon nzType=\"arrow-up\" />\n      <nz-icon nzInputNumberDownIcon nzType=\"arrow-down\" />\n    </nz-input-number>\n  `\n})\nexport class NzDemoInputNumberHandlerIconComponent {\n  value = 3;\n}\n"
  },
  {
    "path": "components/input-number/demo/keyboard.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 键盘行为\n  en-US: Keyboard behavior\n---\n\n## zh-CN\n\n使用 `nzKeyboard` 属性可以控制键盘行为。\n\n## en-US\n\nUse the `nzKeyboard` property to control keyboard behavior.\n`\n"
  },
  {
    "path": "components/input-number/demo/keyboard.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCheckboxModule } from 'ng-zorro-antd/checkbox';\nimport { NzInputNumberModule } from 'ng-zorro-antd/input-number';\n\n@Component({\n  selector: 'nz-demo-input-number-keyboard',\n  imports: [FormsModule, NzInputNumberModule, NzCheckboxModule],\n  template: `\n    <nz-input-number [(ngModel)]=\"value\" [nzKeyboard]=\"keyboard\" nzMin=\"1\" nzMax=\"10\" />\n    <label nz-checkbox [(ngModel)]=\"keyboard\">Toggle Keyboard</label>\n  `,\n  styles: `\n    nz-input-number {\n      margin-right: 8px;\n    }\n  `\n})\nexport class NzDemoInputNumberKeyboardComponent {\n  keyboard = true;\n  value = 3;\n}\n"
  },
  {
    "path": "components/input-number/demo/out-of-range.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 超出边界\n  en-US: Out of range\n---\n\n## zh-CN\n\n当通过受控将 `value` 超出边界时，提供警告样式。\n\n## en-US\n\nWhen the `value` is out of range in controlled mode, a warning style is provided.\n"
  },
  {
    "path": "components/input-number/demo/out-of-range.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzInputNumberModule } from 'ng-zorro-antd/input-number';\n\n@Component({\n  selector: 'nz-demo-input-number-out-of-range',\n  imports: [FormsModule, NzInputNumberModule],\n  template: `<nz-input-number [(ngModel)]=\"value\" nzMin=\"1\" nzMax=\"10\" />`\n})\nexport class NzDemoInputNumberOutOfRangeComponent {\n  value = 99;\n}\n"
  },
  {
    "path": "components/input-number/demo/prefix.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 前缀\n  en-US: Prefix\n---\n\n## zh-CN\n\n在数字输入框上添加前缀图标。\n\n## en-US\n\nAdd a prefix inside input.\n"
  },
  {
    "path": "components/input-number/demo/prefix.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputNumberModule } from 'ng-zorro-antd/input-number';\n\n@Component({\n  selector: 'nz-demo-input-number-prefix',\n  imports: [FormsModule, NzInputNumberModule, NzIconModule],\n  template: `\n    <nz-input-number nzPrefix=\"￥\" [style.width.%]=\"100\" />\n\n    <nz-input-number [style.width.%]=\"100\">\n      <span nzInputPrefix>￥</span>\n    </nz-input-number>\n\n    <nz-input-number [style.width.%]=\"100\">\n      <nz-icon nzInputAddonBefore nzType=\"user\" />\n      <span nzInputPrefix>￥</span>\n    </nz-input-number>\n\n    <nz-input-number nzPrefix=\"￥\" nzDisabled [style.width.%]=\"100\" />\n  `,\n  styles: `\n    nz-input-number {\n      margin-bottom: 8px;\n    }\n  `\n})\nexport class NzDemoInputNumberPrefixComponent {}\n"
  },
  {
    "path": "components/input-number/demo/size.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 三种大小\n  en-US: Sizes\n---\n\n## zh-CN\n\n三种大小的数字输入框，当 `nzSize` 分别为 `large` 和 `small` 时，输入框高度为 `40px` 和 `24px` ，默认高度为 `32px`。\n\n## en-US\n\nThere are three sizes available to a numeric input box. By default, the `nzSize` is `32px`. The two additional sizes are `large` and `small` which means `40px` and `24px`, respectively.\n"
  },
  {
    "path": "components/input-number/demo/size.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzInputNumberModule } from 'ng-zorro-antd/input-number';\n\n@Component({\n  selector: 'nz-demo-input-number-size',\n  imports: [FormsModule, NzInputNumberModule],\n  template: `\n    <nz-input-number [(ngModel)]=\"value\" nzSize=\"large\" nzMin=\"1\" nzMax=\"10\" />\n    <nz-input-number [(ngModel)]=\"value\" nzMin=\"1\" nzMax=\"10\" />\n    <nz-input-number [(ngModel)]=\"value\" nzSize=\"small\" nzMin=\"1\" nzMax=\"10\" />\n  `,\n  styles: `\n    nz-input-number {\n      margin-right: 8px;\n    }\n  `\n})\nexport class NzDemoInputNumberSizeComponent {\n  value = 3;\n}\n"
  },
  {
    "path": "components/input-number/demo/status.md",
    "content": "---\norder: 10\ntitle:\n  zh-CN: 自定义状态\n  en-US: Status\n---\n\n## zh-CN\n\n使用 `nzStatus` 为 InputNumber 添加状态，可选 `error` 或者 `warning`。\n\n## en-US\n\nAdd status to InputNumber with `nzStatus`, which could be `error` or `warning`.\n"
  },
  {
    "path": "components/input-number/demo/status.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputNumberModule } from 'ng-zorro-antd/input-number';\n\n@Component({\n  selector: 'nz-demo-input-number-status',\n  imports: [FormsModule, NzInputNumberModule, NzIconModule],\n  template: `\n    <nz-input-number nzStatus=\"error\" [style.width.%]=\"100\" />\n    <nz-input-number nzStatus=\"warning\" [style.width.%]=\"100\" />\n    <nz-input-number nzStatus=\"error\" [style.width.%]=\"100\">\n      <nz-icon nzInputPrefix nzType=\"clock-circle\" />\n    </nz-input-number>\n    <nz-input-number nzStatus=\"warning\" [style.width.%]=\"100\">\n      <nz-icon nzInputPrefix nzType=\"clock-circle\" />\n    </nz-input-number>\n  `,\n  styles: `\n    nz-input-number {\n      margin-bottom: 8px;\n    }\n  `\n})\nexport class NzDemoInputNumberStatusComponent {}\n"
  },
  {
    "path": "components/input-number/demo/variant.md",
    "content": "---\norder: 7\nversion: 20.0.0\ntitle:\n  zh-CN: 形态变体\n  en-US: Variants\n---\n\n## zh-CN\n\nInputNumber 形态变体，可选 `outlined`、`filled`、`borderless`、`underlined` 四种形态。\n\n## en-US\n\nVariants of InputNumber, there are four variants: `outlined`, `filled`, `borderless` and `underlined`.\n"
  },
  {
    "path": "components/input-number/demo/variant.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzInputNumberModule } from 'ng-zorro-antd/input-number';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\n\n@Component({\n  selector: 'nz-demo-input-number-variant',\n  imports: [FormsModule, NzInputNumberModule, NzSpaceModule],\n  template: ` <nz-space nzDirection=\"vertical\" style=\"width: 100%\">\n    <nz-input-number *nzSpaceItem [ngModel]=\"3\" />\n    <nz-input-number *nzSpaceItem nzVariant=\"filled\" [ngModel]=\"3\" />\n    <nz-input-number *nzSpaceItem nzVariant=\"borderless\" [ngModel]=\"3\" />\n    <nz-input-number *nzSpaceItem nzVariant=\"underlined\" [ngModel]=\"3\" />\n  </nz-space>`\n})\nexport class NzDemoInputNumberVariantComponent {}\n"
  },
  {
    "path": "components/input-number/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Entry\ntitle: InputNumber\ncover: 'https://gw.alipayobjects.com/zos/alicdn/XOS8qZ0kU/InputNumber.svg'\ntag: 19.0.0\ndescription: Enter a number within certain range with the mouse or keyboard.\n---\n\n## When To Use\n\nWhen a numeric value needs to be provided.\n\n## API\n\n### nz-input-number\n\n| Property            | Description                                                                     | Type                                                     | Default                                                                                                                             | Version |\n| ------------------- | ------------------------------------------------------------------------------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ------- |\n| `[ngModel]`         | current value, two way binding                                                  | `number`                                                 | -                                                                                                                                   |\n| `[nzId]`            | ID of the input box                                                             | `string`                                                 | -                                                                                                                                   |\n| `[nzPlaceHolder]`   | placeholder                                                                     | `string`                                                 | -                                                                                                                                   |\n| `[nzAutoFocus]`     | auto focus                                                                      | `boolean`                                                | `false`                                                                                                                             |\n| `[nzVariant]`       | Variants of InputNumber                                                         | `'outlined' \\| 'borderless' \\| 'filled' \\| 'underlined'` | `'outlined'`                                                                                                                        | 20.0.0  |\n| `[nzControls]`      | whether to show up and down buttons                                             | `boolean`                                                | `true`                                                                                                                              |\n| `[nzDisabled]`      | whether to disable                                                              | `boolean`                                                | `false`                                                                                                                             |\n| `[nzFormatter]`     | specify the format of the displayed value                                       | `(value: number) => string`                              | -                                                                                                                                   |\n| `[nzKeyboard]`      | Whether to enable keyboard shortcuts                                            | `boolean`                                                | `true`                                                                                                                              |\n| `[nzChangeOnWheel]` | Whether to enable mouse wheel control                                           | `boolean`                                                | `true`                                                                                                                              | 21.0.0  |\n| `[nzMax]`           | maximum value                                                                   | `number`                                                 | [Number.MAX_SAFE_INTEGER](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER) |\n| `[nzMin]`           | minimum value                                                                   | `number`                                                 | [Number.MIN_SAFE_INTEGER](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Number/MIN_SAFE_INTEGER) |\n| `[nzParser]`        | specify how to convert back to a number from `formatter`, used with `formatter` | `(value: string) => number`                              | -                                                                                                                                   |\n| `[nzPrecision]`     | numerical precision, the `formatter` configuration takes precedence             | `number`                                                 | -                                                                                                                                   |\n| `[nzReadOnly]`      | whether to read only                                                            | `boolean`                                                | `false`                                                                                                                             |\n| `[nzStatus]`        | status, optional `error` `warning`                                              | `'error' \\| 'warning'`                                   | -                                                                                                                                   |\n| `[nzSize]`          | input box size, optional `large` `default` `small`                              | `'large' \\| 'small' \\| 'default'`                        | `'default'`                                                                                                                         |\n| `[nzStep]`          | step of each change, can be a decimal                                           | `number`                                                 | `1`                                                                                                                                 |\n| `[nzAddonBefore]`   | The label text displayed before (on the left side of) the input-number          | `string`                                                 | -                                                                                                                                   |\n| `[nzAddonAfter]`    | The label text displayed after (on the right side of) the input-number          | `string`                                                 | -                                                                                                                                   |\n| `[nzPrefix]`        | The prefix icon for the input-number                                            | `string`                                                 | -                                                                                                                                   |\n| `[nzSuffix]`        | The suffix icon for the input-number                                            | `string`                                                 | -                                                                                                                                   |\n| `(nzOnStep)`        | callback when clicking the up and down arrows                                   | `EventEmitter<NzInputNumberStepEvent>`                   | -                                                                                                                                   |\n| `(nzFocus)`         | callback when focus                                                             | `OutputRef<void>`                                        | -                                                                                                                                   |\n| `(nzBlur)`          | callback when blur                                                              | `OutputRef<void>`                                        | -                                                                                                                                   |\n| `(ngModelChange)`   | callback function when the value changes                                        | `EventEmitter<number>`                                   | -                                                                                                                                   |\n\n#### NzInputNumberStepEvent\n\n```ts\nexport type NzInputNumberStepEmitter = 'wheel' | 'handler' | 'keyboard';\nexport interface NzInputNumberStepEvent {\n  value: number;\n  offset: number;\n  type: 'up' | 'down';\n  emitter: NzInputNumberStepEmitter;\n}\n```\n\n#### Methods\n\nYou can get instance by `ViewChild`\n\n| Name           | Description  | Parameters                                                                   |\n| -------------- | ------------ | ---------------------------------------------------------------------------- |\n| focus(option?) | get focus    | `(option?: { preventScroll?: boolean, cursor?: 'start' \\| 'end' \\| 'all' })` |\n| blur()         | remove focus | -                                                                            |\n\n## FAQ\n\n### Why can the `value` exceed the `min` and `max` range in controlled mode?\n\nIn controlled mode, developers may store related data by themselves. If the component constrains the data back to the range, it will cause the displayed data to be inconsistent with the actual stored data. This leads to potential data problems in some scenarios such as form fields.\n"
  },
  {
    "path": "components/input-number/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 数字输入框\ntype: 数据录入\ntitle: InputNumber\ncover: 'https://gw.alipayobjects.com/zos/alicdn/XOS8qZ0kU/InputNumber.svg'\ntag: 19.0.0\ndescription: 通过鼠标或键盘，输入范围内的数值。\n---\n\n## 何时使用\n\n当需要获取标准数值时。\n\n## API\n\n### nz-input-number\n\n| 参数                | 说明                                                           | 类型                                                     | 默认值                                                                                                                              | 版本   |\n| ------------------- | -------------------------------------------------------------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ------ |\n| `[ngModel]`         | 当前值，可双向绑定                                             | `number`                                                 | -                                                                                                                                   |\n| `[nzId]`            | 输入框的 ID                                                    | `string`                                                 | -                                                                                                                                   |\n| `[nzPlaceHolder]`   | 占位符                                                         | `string`                                                 | -                                                                                                                                   |\n| `[nzAutoFocus]`     | 自动获取焦点                                                   | `boolean`                                                | `false`                                                                                                                             |\n| `[nzVariant]`       | 形态变体                                                       | `'outlined' \\| 'borderless' \\| 'filled' \\| 'underlined'` | `'outlined'`                                                                                                                        | 20.0.0 |\n| `[nzControls]`      | 是否显示增减按钮                                               | `boolean`                                                | `true`                                                                                                                              |\n| `[nzDisabled]`      | 是否禁用                                                       | `boolean`                                                | `false`                                                                                                                             |\n| `[nzFormatter]`     | 指定输入框展示值的格式                                         | `(value: number) => string`                              | -                                                                                                                                   |\n| `[nzKeyboard]`      | 是否启用键盘快捷行为                                           | `boolean`                                                | `true`                                                                                                                              |\n| `[nzChangeOnWheel]` | 是否启用鼠标滚轮控制                                           | `boolean`                                                | `true`                                                                                                                              | 21.0.0 |\n| `[nzMax]`           | 最大值                                                         | `number`                                                 | [Number.MAX_SAFE_INTEGER](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER) |\n| `[nzMin]`           | 最小值                                                         | `number`                                                 | [Number.MIN_SAFE_INTEGER](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Number/MIN_SAFE_INTEGER) |\n| `[nzParser]`        | 指定从 `formatter` 里转换回数字的方式，和 `formatter` 搭配使用 | `(value: string) => number`                              | -                                                                                                                                   |\n| `[nzPrecision]`     | 数值精度，配置 `formatter` 时会以 `formatter` 为准             | `number`                                                 | -                                                                                                                                   |\n| `[nzReadOnly]`      | 是否只读                                                       | `boolean`                                                | `false`                                                                                                                             |\n| `[nzStatus]`        | 状态，可选 `error` `warning`                                   | `'error' \\| 'warning'`                                   | -                                                                                                                                   |\n| `[nzSize]`          | 输入框大小，可选 `large` `default` `small`                     | `'large' \\| 'small' \\| 'default'`                        | `'default'`                                                                                                                         |\n| `[nzStep]`          | 每次改变步数，可以是小数                                       | `number`                                                 | `1`                                                                                                                                 |\n| `[nzAddonBefore]`   | 带标签的 input-number，设置前置标签                            | `string`                                                 | -                                                                                                                                   |\n| `[nzAddonAfter]`    | 带标签的 input-number，设置后置标签                            | `string`                                                 | -                                                                                                                                   |\n| `[nzPrefix]`        | 带有前缀图标的 input-number                                    | `string`                                                 | -                                                                                                                                   |\n| `[nzSuffix]`        | 带有后缀图标的 input-number                                    | `string`                                                 | -                                                                                                                                   |\n| `(nzOnStep)`        | 点击上下箭头的回调                                             | `EventEmitter<NzInputNumberStepEvent>`                   | -                                                                                                                                   |\n| `(nzFocus)`         | focus 时回调                                                   | `OutputRef<void>`                                        | -                                                                                                                                   |\n| `(nzBlur)`          | blur 时回调                                                    | `OutputRef<void>`                                        | -                                                                                                                                   |\n| `(ngModelChange)`   | 值变化时的回调函数                                             | `EventEmitter<number>`                                   | -                                                                                                                                   |\n\n#### NzInputNumberStepEvent\n\n```ts\nexport type NzInputNumberStepEmitter = 'wheel' | 'handler' | 'keyboard';\nexport interface NzInputNumberStepEvent {\n  value: number;\n  offset: number;\n  type: 'up' | 'down';\n  emitter: NzInputNumberStepEmitter;\n}\n```\n\n#### 方法\n\n通过 `ViewChild` 等方法获得实例后调用\n\n| 名称           | 描述     | 参数                                                                         |\n| -------------- | -------- | ---------------------------------------------------------------------------- |\n| focus(option?) | 获取焦点 | `(option?: { preventScroll?: boolean, cursor?: 'start' \\| 'end' \\| 'all' })` |\n| blur()         | 移除焦点 | -                                                                            |\n\n## FAQ\n\n### 为何受控模式下，`value` 可以超出 `min` 和 `max` 范围？\n\n在受控模式下，开发者可能自行存储相关数据。如果组件将数据约束回范围内，会导致展示数据与实际存储数据不一致的情况。这使得一些如表单场景存在潜在的数据问题。\n"
  },
  {
    "path": "components/input-number/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/input-number/input-number.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { DOWN_ARROW, ENTER, UP_ARROW } from '@angular/cdk/keycodes';\nimport {\n  ApplicationRef,\n  Component,\n  ElementRef,\n  provideZoneChangeDetection,\n  signal,\n  viewChild,\n  type WritableSignal\n} from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { FormsModule } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\n\nimport { NZ_FORM_SIZE, NZ_FORM_VARIANT } from 'ng-zorro-antd/core/form';\nimport { dispatchEvent, dispatchKeyboardEvent } from 'ng-zorro-antd/core/testing';\nimport { NzSizeLDSType, NzStatus, NzVariant } from 'ng-zorro-antd/core/types';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\nimport { NZ_SPACE_COMPACT_SIZE } from 'ng-zorro-antd/space';\n\nimport { NzInputNumberComponent, NzInputNumberStepEvent } from './input-number.component';\nimport { NzInputNumberModule } from './input-number.module';\n\ndescribe('input-number', () => {\n  let component: InputNumberTestComponent;\n  let fixture: ComponentFixture<InputNumberTestComponent>;\n  let hostElement: HTMLElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideZoneChangeDetection()]\n    });\n    fixture = TestBed.createComponent(InputNumberTestComponent);\n    component = fixture.componentInstance;\n    hostElement = fixture.nativeElement.querySelector('nz-input-number');\n    fixture.autoDetectChanges();\n  });\n\n  it('should set id', () => {\n    component.id = 'test-id';\n    fixture.detectChanges();\n    expect(hostElement.querySelector('input')!.id).toBe('test-id');\n  });\n\n  it('should be apply size class', () => {\n    component.size = 'large';\n    fixture.detectChanges();\n    expect(hostElement.classList).toContain('ant-input-number-lg');\n    component.size = 'small';\n    fixture.detectChanges();\n    expect(hostElement.classList).toContain('ant-input-number-sm');\n  });\n\n  it('should be set placeholder', () => {\n    component.placeholder = 'Enter a number';\n    fixture.detectChanges();\n    expect(hostElement.querySelector('input')!.placeholder).toBe('Enter a number');\n  });\n\n  it('should be set status', () => {\n    component.status = 'error';\n    fixture.detectChanges();\n    expect(hostElement.classList).toContain('ant-input-number-status-error');\n    component.status = 'warning';\n    fixture.detectChanges();\n    expect(hostElement.classList).toContain('ant-input-number-status-warning');\n  });\n\n  it('should be set step', () => {\n    component.step = 5;\n    fixture.detectChanges();\n    expect(hostElement.querySelector('input')!.step).toBe('5');\n    upStepByKeyboard();\n    expect(component.value).toBe(5);\n    upStepByKeyboard();\n    expect(component.value).toBe(10);\n    downStepByKeyboard();\n    expect(component.value).toBe(5);\n  });\n\n  it('should be update value through the handler', () => {\n    component.min = 1;\n    component.max = 2;\n    fixture.detectChanges();\n    upStepByHandler();\n    expect(component.value).toBe(1);\n    upStepByHandler();\n    expect(component.value).toBe(2);\n    upStepByHandler();\n    expect(component.value).toBe(2);\n    downStepByHandler();\n    expect(component.value).toBe(1);\n    downStepByHandler();\n    expect(component.value).toBe(1);\n  });\n\n  it('should be update value through the handler with floating numbers', () => {\n    component.step = 0.1;\n    fixture.detectChanges();\n    upStepByHandler();\n    expect(component.value).toBe(0.1);\n    upStepByHandler();\n    expect(component.value).toBe(0.2);\n    upStepByHandler();\n    expect(component.value).toBe(0.3);\n    downStepByHandler();\n    expect(component.value).toBe(0.2);\n    downStepByHandler();\n    expect(component.value).toBe(0.1);\n    downStepByHandler();\n    expect(component.value).toBe(0);\n  });\n\n  describe('should be update value through the handler with hold shift key', () => {\n    it('normal', () => {\n      upStepByHandler({ shiftKey: true });\n      expect(component.value).toBe(10);\n      upStepByHandler({ shiftKey: true });\n      expect(component.value).toBe(20);\n\n      downStepByHandler({ shiftKey: true });\n      expect(component.value).toBe(10);\n      downStepByHandler({ shiftKey: true });\n      expect(component.value).toBe(0);\n    });\n\n    it('with min & max', () => {\n      component.min = -5;\n      component.max = 5;\n      fixture.detectChanges();\n\n      for (let index = 0; index < 10; index++) {\n        upStepByHandler({ shiftKey: true });\n      }\n      expect(component.value).toBe(component.max);\n\n      for (let index = 0; index < 10; index++) {\n        downStepByHandler({ shiftKey: true });\n      }\n      expect(component.value).toBe(component.min);\n    });\n  });\n\n  describe('should be update value through user typing', () => {\n    it('normal', () => {\n      input('123');\n      expect(component.value).toBe(123);\n      enter();\n      expect(component.value).toBe(123);\n      blur();\n      expect(component.value).toBe(123);\n\n      input('NonNumber');\n      expect(component.value).toBe(123);\n      enter();\n      expect(component.value).toBe(123);\n      blur();\n      expect(component.value).toBe(123);\n\n      input('321NonNumber');\n      expect(component.value).toBe(123);\n      enter();\n      expect(component.value).toBe(123);\n      blur();\n      expect(component.value).toBe(123);\n\n      input('');\n      expect(component.value).toBe(null);\n      enter();\n      expect(component.value).toBe(null);\n      blur();\n      expect(component.value).toBe(null);\n    });\n\n    it('with range', () => {\n      component.min = 1;\n      component.max = 10;\n\n      // Running change detection (first time)\n      TestBed.inject(ApplicationRef).tick();\n\n      input('1');\n      expect(component.value).toBe(1);\n\n      input('99');\n      expect(component.value).toBe(1);\n      blur();\n      expect(component.value).toBe(10);\n\n      input('-99');\n      expect(component.value).toBe(10);\n      blur();\n      expect(component.value).toBe(1);\n\n      input('10');\n      expect(component.value).toBe(10);\n      blur();\n      expect(component.value).toBe(10);\n\n      input('');\n      expect(component.value).toBe(null);\n      blur();\n      expect(component.value).toBe(null);\n    });\n\n    it('with formatter', () => {\n      component.formatter = (value: number): string => `${value}%`;\n      component.parser = (value: string): number => parseFloat(value?.replace('%', ''));\n\n      // Running change detection (first time)\n      TestBed.inject(ApplicationRef).tick();\n\n      const inputElement = getInputElement();\n\n      input('123');\n      fixture.detectChanges();\n      expect(component.value).toBe(123);\n      expect(inputElement.value).toBe('123%');\n      blur();\n      fixture.detectChanges();\n      expect(component.value).toBe(123);\n      expect(inputElement.value).toBe('123%');\n\n      input('NonNumber');\n      fixture.detectChanges();\n      expect(component.value).toBe(123);\n      expect(inputElement.value).toBe('NonNumber');\n      blur();\n      fixture.detectChanges();\n      expect(component.value).toBe(123);\n      expect(inputElement.value).toBe('123%');\n\n      input('');\n      fixture.detectChanges();\n      expect(component.value).toBe(null);\n      expect(inputElement.value).toBe('');\n      blur();\n      fixture.detectChanges();\n      expect(component.value).toBe(null);\n      expect(inputElement.value).toBe('');\n    });\n  });\n\n  it('should be apply out-of-range class', async () => {\n    component.min = 1;\n    component.max = 2;\n    component.value = 3;\n    fixture.detectChanges();\n    await fixture.whenStable();\n    expect(hostElement.classList).toContain('ant-input-number-out-of-range');\n\n    component.value = 0;\n    fixture.detectChanges();\n    await fixture.whenStable();\n    expect(hostElement.classList).toContain('ant-input-number-out-of-range');\n  });\n\n  describe('should be set min and max with precision', () => {\n    beforeEach(() => {\n      component.precision = 0;\n      component.value = null;\n    });\n\n    it('max > 0', () => {\n      component.min = Number.MIN_SAFE_INTEGER;\n      component.max = 1.5;\n\n      // Running change detection (first time)\n      TestBed.inject(ApplicationRef).tick();\n\n      input('1.1');\n      expect(component.value).toBe(1.1);\n      blur();\n      expect(component.value).toBe(1);\n      input('1.5');\n      expect(component.value).toBe(1.5);\n      blur();\n      expect(component.value).toBe(1);\n    });\n\n    it('max < 0', () => {\n      component.min = Number.MIN_SAFE_INTEGER;\n      component.max = -1.5;\n\n      // Running change detection (first time)\n      TestBed.inject(ApplicationRef).tick();\n\n      input('-1.1');\n      expect(component.value).toBe(null);\n      blur();\n      expect(component.value).toBe(-2);\n      input('-1.5');\n      expect(component.value).toBe(-1.5);\n      blur();\n      expect(component.value).toBe(-2);\n    });\n\n    it('min > 0', () => {\n      component.min = 1.5;\n      component.max = Number.MAX_SAFE_INTEGER;\n\n      // Running change detection (first time)\n      TestBed.inject(ApplicationRef).tick();\n\n      input('1.1');\n      expect(component.value).toBe(null);\n      blur();\n      expect(component.value).toBe(2);\n      input('1.5');\n      expect(component.value).toBe(1.5);\n      blur();\n      expect(component.value).toBe(2);\n    });\n\n    it('min < 0', () => {\n      component.min = -1.5;\n      component.max = Number.MAX_SAFE_INTEGER;\n\n      // Running change detection (first time)\n      TestBed.inject(ApplicationRef).tick();\n\n      input('-1.1');\n      expect(component.value).toBe(-1.1);\n      blur();\n      expect(component.value).toBe(-1);\n      input('-1.5');\n      expect(component.value).toBe(-1.5);\n      blur();\n      expect(component.value).toBe(-1);\n    });\n  });\n\n  it('should set value with precision', () => {\n    component.precision = 1;\n\n    // Running change detection (first time)\n    TestBed.inject(ApplicationRef).tick();\n\n    input('1.23');\n    expect(component.value).toBe(1.23);\n    blur();\n    expect(component.value).toBe(1.2);\n\n    input('1.25');\n    expect(component.value).toBe(1.25);\n    blur();\n    expect(component.value).toBe(1.3);\n  });\n\n  it('should be set disabled', () => {\n    component.disabled = true;\n    fixture.detectChanges();\n    expect(hostElement.querySelector('input')!.disabled).toBeTruthy();\n    expect(hostElement.classList).toContain('ant-input-number-disabled');\n  });\n\n  it('should be set disabled by ng control', async () => {\n    component.controlDisabled = true;\n    fixture.detectChanges();\n    await fixture.whenStable();\n    expect(hostElement.querySelector('input')!.disabled).toBeTruthy();\n    expect(hostElement.classList).toContain('ant-input-number-disabled');\n  });\n\n  it('should be set readonly', () => {\n    component.readonly = true;\n    fixture.detectChanges();\n    expect(hostElement.querySelector('input')!.readOnly).toBeTruthy();\n    expect(hostElement.classList).toContain('ant-input-number-readonly');\n  });\n\n  it('should be focus / blur work', async () => {\n    await fixture.whenStable();\n    const input = hostElement.querySelector('input')!;\n    component.inputNumber().focus();\n    expect(document.activeElement).toBe(input);\n    component.inputNumber().blur();\n    expect(document.activeElement).not.toBe(input);\n\n    component.value = 555;\n    fixture.detectChanges();\n    await fixture.whenStable();\n\n    component.inputNumber().focus({ cursor: 'start' });\n    expect(input.selectionStart).toBe(0);\n    expect(input.selectionEnd).toBe(0);\n    component.inputNumber().focus({ cursor: 'end' });\n    expect(input.selectionStart).toBe(String(component.value).length);\n    expect(input.selectionEnd).toBe(String(component.value).length);\n    component.inputNumber().focus({ cursor: 'all' });\n    expect(input.selectionStart).toBe(0);\n    expect(input.selectionEnd).toBe(String(component.value).length);\n  });\n\n  describe('should nzVariant work', () => {\n    it('filled', () => {\n      fixture.detectChanges();\n      expect(hostElement.classList).not.toContain('ant-input-number-filled');\n      component.variant = 'filled';\n      fixture.detectChanges();\n      expect(hostElement.classList).toContain('ant-input-number-filled');\n    });\n\n    it('borderless', () => {\n      fixture.detectChanges();\n      expect(hostElement.classList).not.toContain('ant-input-number-borderless');\n      component.variant = 'borderless';\n      fixture.detectChanges();\n      expect(hostElement.classList).toContain('ant-input-number-borderless');\n    });\n\n    it('underlined', () => {\n      fixture.detectChanges();\n      expect(hostElement.classList).not.toContain('ant-input-number-underlined');\n      component.variant = 'underlined';\n      fixture.detectChanges();\n      expect(hostElement.classList).toContain('ant-input-number-underlined');\n    });\n  });\n\n  it('should be set keyboard', () => {\n    upStepByKeyboard();\n    expect(component.value).toBe(1);\n    downStepByKeyboard();\n    expect(component.value).toBe(0);\n\n    component.keyboard = false;\n    fixture.detectChanges();\n    upStepByKeyboard();\n    expect(component.value).toBe(0);\n  });\n\n  it('should be set mouse wheel', () => {\n    const input = hostElement.querySelector('input')!;\n    dispatchEvent(input, new WheelEvent('wheel', { deltaY: -100 }));\n    expect(component.value).toBe(1);\n    dispatchEvent(input, new WheelEvent('wheel', { deltaY: 100 }));\n    expect(component.value).toBe(0);\n\n    component.disabled = true;\n    fixture.detectChanges();\n    dispatchEvent(input, new WheelEvent('wheel', { deltaY: 100 }));\n    expect(component.value).toBe(0);\n  });\n\n  it('should be work onStep', () => {\n    const onStep = spyOn(component, 'onStep');\n    const input = hostElement.querySelector('input')!;\n\n    upStepByKeyboard();\n    expect(onStep).toHaveBeenCalledWith({ value: 1, offset: component.step, type: 'up', emitter: 'keyboard' });\n\n    downStepByKeyboard();\n    expect(onStep).toHaveBeenCalledWith({ value: 0, offset: component.step, type: 'down', emitter: 'keyboard' });\n\n    dispatchEvent(input, new WheelEvent('wheel', { deltaY: -100 }));\n    expect(onStep).toHaveBeenCalledWith({ value: 1, offset: component.step, type: 'up', emitter: 'wheel' });\n\n    dispatchEvent(input, new WheelEvent('wheel', { deltaY: 100 }));\n    expect(onStep).toHaveBeenCalledWith({ value: 0, offset: component.step, type: 'down', emitter: 'wheel' });\n\n    upStepByHandler();\n    expect(onStep).toHaveBeenCalledWith({ value: 1, offset: component.step, type: 'up', emitter: 'handler' });\n\n    downStepByHandler();\n    expect(onStep).toHaveBeenCalledWith({ value: 0, offset: component.step, type: 'down', emitter: 'handler' });\n  });\n\n  it('should be hide controls', () => {\n    component.controls = false;\n    fixture.detectChanges();\n    expect(hostElement.querySelector('.ant-input-number-handler-wrap')).toBeNull();\n  });\n\n  it('should not format input value if incomplete', () => {\n    fixture.detectChanges();\n\n    input('1.0');\n    expect(component.displayValue).toBe('1.0');\n\n    input('1.00'); // 2 consecutive zeros\n    expect(component.displayValue).toBe('1.00');\n\n    input('1.10'); // zero is not preceded by a `.`\n    expect(component.displayValue).toBe('1.10');\n  });\n\n  it('should be accepted numbers with commas', () => {\n    input('1,234');\n    expect(component.value).toBe(1234);\n    blur();\n    expect(component.value).toBe(1234);\n\n    input('1,,2');\n    expect(component.value).toBe(12);\n    blur();\n    expect(component.value).toBe(12);\n\n    input(',1,2,3,');\n    expect(component.value).toBe(123);\n    blur();\n    expect(component.value).toBe(123);\n\n    // Illegal value will fall back to the last legal value\n    input(',');\n    expect(component.value).toBe(123);\n    blur();\n    expect(component.value).toBe(123);\n    // Illegal value will fall back to the last legal value\n    input(',,,');\n    expect(component.value).toBe(123);\n    blur();\n    expect(component.value).toBe(123);\n\n    input('1,234,567');\n    expect(component.value).toBe(1234567);\n    blur();\n    expect(component.value).toBe(1234567);\n\n    input('1,234,567.01');\n    expect(component.value).toBe(1234567.01);\n    blur();\n    expect(component.value).toBe(1234567.01);\n  });\n\n  function upStepByHandler(eventInit?: MouseEventInit): void {\n    const handler = hostElement.querySelector('.ant-input-number-handler-up')!;\n    handler.dispatchEvent(new MouseEvent('mousedown', eventInit));\n    handler.dispatchEvent(new MouseEvent('mouseup'));\n  }\n  function downStepByHandler(eventInit?: MouseEventInit): void {\n    const handler = hostElement.querySelector('.ant-input-number-handler-down')!;\n    handler.dispatchEvent(new MouseEvent('mousedown', eventInit));\n    handler.dispatchEvent(new MouseEvent('mouseup'));\n  }\n\n  function upStepByKeyboard(): void {\n    dispatchKeyboardEvent(hostElement, 'keydown', UP_ARROW);\n  }\n  function downStepByKeyboard(): void {\n    dispatchKeyboardEvent(hostElement, 'keydown', DOWN_ARROW);\n  }\n  function enter(): void {\n    dispatchKeyboardEvent(hostElement, 'keydown', ENTER);\n  }\n\n  function getInputElement(): HTMLInputElement {\n    return fixture.nativeElement.querySelector('input')!;\n  }\n  function input(text: string): void {\n    const element = getInputElement();\n    element.value = text;\n    element.dispatchEvent(new Event('input'));\n  }\n  function blur(): void {\n    getInputElement().dispatchEvent(new Event('blur'));\n  }\n});\n\ndescribe('input-number with affixes or addons', () => {\n  let component: InputNumberWithAffixesAndAddonsTestComponent;\n  let fixture: ComponentFixture<InputNumberWithAffixesAndAddonsTestComponent>;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideZoneChangeDetection()]\n    });\n    fixture = TestBed.createComponent(InputNumberWithAffixesAndAddonsTestComponent);\n    component = fixture.componentInstance;\n    fixture.autoDetectChanges();\n  });\n\n  it('should be apply affix classes', () => {\n    expect(component.withPropAffixes().nativeElement.classList).toContain('ant-input-number-affix-wrapper');\n    expect(component.withContentAffixes().nativeElement.classList).toContain('ant-input-number-affix-wrapper');\n  });\n\n  it('should be apply addon classes', () => {\n    expect(component.withPropAddons().nativeElement.classList).toContain('ant-input-number-group-wrapper');\n    expect(component.withContentAddons().nativeElement.classList).toContain('ant-input-number-group-wrapper');\n  });\n\n  it('should be apply mix classes', () => {\n    expect(component.withPropMix().nativeElement.classList).toContain('ant-input-number-group-wrapper');\n    expect(component.withContentMix().nativeElement.classList).toContain('ant-input-number-group-wrapper');\n    expect(component.withPropMix().nativeElement.querySelector('.ant-input-number-affix-wrapper')).toBeTruthy();\n    expect(component.withContentMix().nativeElement.querySelector('.ant-input-number-affix-wrapper')).toBeTruthy();\n  });\n\n  it('should be apply disabled class', () => {\n    component.disabled = true;\n    fixture.detectChanges();\n    expect(component.withContentAffixes().nativeElement.classList).toContain('ant-input-number-affix-wrapper-disabled');\n  });\n\n  it('should be apply readonly class', () => {\n    component.readonly = true;\n    fixture.detectChanges();\n    expect(component.withContentAffixes().nativeElement.classList).toContain('ant-input-number-affix-wrapper-readonly');\n  });\n\n  it('should be apply borderless class', () => {\n    component.variant = 'borderless';\n    fixture.detectChanges();\n    expect(component.withContentAffixes().nativeElement.classList).toContain(\n      'ant-input-number-affix-wrapper-borderless'\n    );\n  });\n\n  describe('should be apply nzVariant class', () => {\n    it('filled', () => {\n      fixture.detectChanges();\n      expect(component.withContentAffixes().nativeElement.classList).not.toContain(\n        'ant-input-number-affix-wrapper-filled'\n      );\n      component.variant = 'filled';\n      fixture.detectChanges();\n      expect(component.withContentAffixes().nativeElement.classList).toContain('ant-input-number-affix-wrapper-filled');\n    });\n\n    it('borderless', () => {\n      fixture.detectChanges();\n      expect(component.withContentAffixes().nativeElement.classList).not.toContain(\n        'ant-input-number-affix-wrapper-borderless'\n      );\n      component.variant = 'borderless';\n      fixture.detectChanges();\n      expect(component.withContentAffixes().nativeElement.classList).toContain(\n        'ant-input-number-affix-wrapper-borderless'\n      );\n    });\n\n    it('underlined', () => {\n      fixture.detectChanges();\n      expect(component.withContentAffixes().nativeElement.classList).not.toContain(\n        'ant-input-number-affix-wrapper-borderless'\n      );\n      component.variant = 'underlined';\n      fixture.detectChanges();\n      expect(component.withContentAffixes().nativeElement.classList).toContain(\n        'ant-input-number-affix-wrapper-underlined'\n      );\n    });\n  });\n});\n\ndescribe('finalSize', () => {\n  let fixture: ComponentFixture<TestInputNumberFinalSizeComponent>;\n  let inputNumberElement: HTMLElement;\n  let compactSizeSignal: WritableSignal<NzSizeLDSType>;\n  let formSizeSignal: WritableSignal<NzSizeLDSType>;\n\n  beforeEach(() => {\n    compactSizeSignal = signal<NzSizeLDSType>('large');\n    formSizeSignal = signal<NzSizeLDSType>('default');\n  });\n\n  afterEach(() => {\n    TestBed.resetTestingModule();\n  });\n\n  it('should set correctly the size from the formSize signal', () => {\n    TestBed.configureTestingModule({\n      providers: [\n        { provide: NZ_FORM_SIZE, useValue: formSizeSignal },\n        { provide: NZ_SPACE_COMPACT_SIZE, useValue: compactSizeSignal }\n      ]\n    });\n    fixture = TestBed.createComponent(TestInputNumberFinalSizeComponent);\n    inputNumberElement = fixture.debugElement.query(By.directive(NzInputNumberComponent)).nativeElement;\n    fixture.detectChanges();\n    formSizeSignal.set('large');\n    fixture.detectChanges();\n    expect(inputNumberElement.classList).toContain('ant-input-number-lg');\n  });\n  it('should set correctly the size from the compactSize signal', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_SPACE_COMPACT_SIZE, useValue: compactSizeSignal }]\n    });\n    fixture = TestBed.createComponent(TestInputNumberFinalSizeComponent);\n    inputNumberElement = fixture.debugElement.query(By.directive(NzInputNumberComponent)).nativeElement;\n    fixture.detectChanges();\n    expect(inputNumberElement.classList).toContain('ant-input-number-lg');\n  });\n  it('should set correctly the size from the size input ', () => {\n    TestBed.configureTestingModule({});\n    fixture = TestBed.createComponent(TestInputNumberFinalSizeComponent);\n    inputNumberElement = fixture.debugElement.query(By.directive(NzInputNumberComponent)).nativeElement;\n    fixture.componentInstance.size = 'large';\n    fixture.detectChanges();\n    expect(inputNumberElement.classList).toContain('ant-input-number-lg');\n  });\n});\n\ndescribe('finalVariant', () => {\n  let fixture: ComponentFixture<TestInputNumberFinalVariantComponent>;\n  let inputNumberElement: HTMLElement;\n  let formVariantSignal: WritableSignal<NzVariant>;\n\n  beforeEach(() => {\n    formVariantSignal = signal<NzVariant>('outlined');\n  });\n\n  afterEach(() => {\n    TestBed.resetTestingModule();\n  });\n\n  it('should use the formVariant when nzVariant is not set', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_FORM_VARIANT, useValue: formVariantSignal }]\n    });\n    fixture = TestBed.createComponent(TestInputNumberFinalVariantComponent);\n    inputNumberElement = fixture.debugElement.query(By.directive(NzInputNumberComponent)).nativeElement;\n    fixture.detectChanges();\n    formVariantSignal.set('filled');\n    fixture.detectChanges();\n    expect(inputNumberElement.classList).toContain('ant-input-number-filled');\n  });\n\n  it('should use nzVariant over formVariant when nzVariant is explicitly set', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_FORM_VARIANT, useValue: formVariantSignal }]\n    });\n    fixture = TestBed.createComponent(TestInputNumberFinalVariantComponent);\n    inputNumberElement = fixture.debugElement.query(By.directive(NzInputNumberComponent)).nativeElement;\n    fixture.componentInstance.variant.set('borderless');\n    fixture.detectChanges();\n    formVariantSignal.set('filled');\n    fixture.detectChanges();\n    expect(inputNumberElement.classList).toContain('ant-input-number-borderless');\n    expect(inputNumberElement.classList).not.toContain('ant-input-number-filled');\n  });\n\n  it('should use nzVariant when no formVariant is provided', () => {\n    TestBed.configureTestingModule({});\n    fixture = TestBed.createComponent(TestInputNumberFinalVariantComponent);\n    inputNumberElement = fixture.debugElement.query(By.directive(NzInputNumberComponent)).nativeElement;\n    fixture.componentInstance.variant.set('filled');\n    fixture.detectChanges();\n    expect(inputNumberElement.classList).toContain('ant-input-number-filled');\n  });\n});\n\n@Component({\n  imports: [NzInputNumberModule, FormsModule],\n  template: `\n    <nz-input-number\n      [nzId]=\"id\"\n      [nzSize]=\"size\"\n      [nzPlaceHolder]=\"placeholder\"\n      [nzStatus]=\"status\"\n      [nzStep]=\"step\"\n      [nzMin]=\"min\"\n      [nzMax]=\"max\"\n      [nzPrecision]=\"precision\"\n      [nzDisabled]=\"disabled\"\n      [nzReadOnly]=\"readonly\"\n      [nzVariant]=\"variant\"\n      [nzKeyboard]=\"keyboard\"\n      [nzControls]=\"controls\"\n      [nzParser]=\"parser\"\n      [nzFormatter]=\"formatter\"\n      [(ngModel)]=\"value\"\n      [disabled]=\"controlDisabled\"\n      [nzChangeOnWheel]=\"changeOnWheel\"\n      (nzOnStep)=\"onStep($event)\"\n    />\n  `\n})\nclass InputNumberTestComponent {\n  id: string | null = null;\n  size: NzSizeLDSType = 'default';\n  placeholder: string | null = null;\n  status: NzStatus = '';\n  step = 1;\n  min = Number.MIN_SAFE_INTEGER;\n  max = Number.MAX_SAFE_INTEGER;\n  precision: null | number = null;\n  disabled = false;\n  readonly = false;\n  variant: NzVariant = 'outlined';\n  keyboard = true;\n  controls = true;\n  changeOnWheel = true;\n  parser: ((value: string) => number) | undefined = undefined;\n  formatter: ((value: number) => string) | undefined = undefined;\n\n  value: number | null = null;\n  controlDisabled = false;\n  inputNumber = viewChild.required(NzInputNumberComponent);\n\n  get displayValue(): string {\n    return this.inputNumber()['displayValue']();\n  }\n\n  onStep(_event: NzInputNumberStepEvent): void {}\n}\n\n@Component({\n  imports: [NzInputNumberModule],\n  template: `\n    <nz-input-number\n      #withPropAffixes\n      nzPrefix=\"Prefix\"\n      nzSuffix=\"Suffix\"\n      [nzDisabled]=\"disabled\"\n      [nzReadOnly]=\"readonly\"\n      [nzVariant]=\"variant\"\n    />\n\n    <nz-input-number #withContentAffixes [nzDisabled]=\"disabled\" [nzReadOnly]=\"readonly\" [nzVariant]=\"variant\">\n      <span nzInputPrefix>Prefix</span>\n      <span nzInputSuffix>Suffix</span>\n    </nz-input-number>\n\n    <nz-input-number\n      #withPropAddons\n      nzAddonBefore=\"Before\"\n      nzAddonAfter=\"After\"\n      [nzDisabled]=\"disabled\"\n      [nzReadOnly]=\"readonly\"\n      [nzVariant]=\"variant\"\n    />\n\n    <nz-input-number #withContentAddons [nzDisabled]=\"disabled\" [nzReadOnly]=\"readonly\" [nzVariant]=\"variant\">\n      <span nzInputAddonBefore>Before</span>\n      <span nzInputAddonAfter>After</span>\n    </nz-input-number>\n\n    <nz-input-number\n      #withPropMix\n      nzPrefix=\"Prefix\"\n      nzSuffix=\"Suffix\"\n      nzAddonBefore=\"Before\"\n      nzAddonAfter=\"After\"\n      [nzDisabled]=\"disabled\"\n      [nzReadOnly]=\"readonly\"\n      [nzVariant]=\"variant\"\n    />\n\n    <nz-input-number #withContentMix [nzDisabled]=\"disabled\" [nzReadOnly]=\"readonly\" [nzVariant]=\"variant\">\n      <span nzInputPrefix>Prefix</span>\n      <span nzInputSuffix>Suffix</span>\n      <span nzInputAddonBefore>Before</span>\n      <span nzInputAddonAfter>After</span>\n    </nz-input-number>\n  `\n})\nclass InputNumberWithAffixesAndAddonsTestComponent {\n  disabled = false;\n  readonly = false;\n  variant: NzVariant = 'outlined';\n\n  readonly withPropAffixes = viewChild.required('withPropAffixes', { read: ElementRef });\n  readonly withContentAffixes = viewChild.required('withContentAffixes', { read: ElementRef });\n  readonly withPropAddons = viewChild.required('withPropAddons', { read: ElementRef });\n  readonly withContentAddons = viewChild.required('withContentAddons', { read: ElementRef });\n  readonly withPropMix = viewChild.required('withPropMix', { read: ElementRef });\n  readonly withContentMix = viewChild.required('withContentMix', { read: ElementRef });\n}\n\n@Component({\n  imports: [NzInputNumberModule],\n  template: `<nz-input-number [nzSize]=\"size\" />`\n})\nclass TestInputNumberFinalSizeComponent {\n  size: NzSizeLDSType = 'default';\n}\n\n@Component({\n  imports: [NzInputNumberModule],\n  template: `<nz-input-number [nzVariant]=\"variant()\" />`\n})\nclass TestInputNumberFinalVariantComponent {\n  readonly variant = signal<NzVariant | undefined>(undefined);\n}\n"
  },
  {
    "path": "components/input-number/input-number.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { FocusMonitor } from '@angular/cdk/a11y';\nimport { Directionality } from '@angular/cdk/bidi';\nimport { DOWN_ARROW, ENTER, UP_ARROW } from '@angular/cdk/keycodes';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  afterNextRender,\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  Component,\n  computed,\n  contentChild,\n  DestroyRef,\n  ElementRef,\n  forwardRef,\n  inject,\n  Injector,\n  input,\n  linkedSignal,\n  numberAttribute,\n  OnInit,\n  output,\n  signal,\n  untracked,\n  viewChild,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\n\nimport {\n  NZ_FORM_SIZE,\n  NZ_FORM_VARIANT,\n  NzFormItemFeedbackIconComponent,\n  NzFormStatusService\n} from 'ng-zorro-antd/core/form';\nimport {\n  NzSizeLDSType,\n  NzStatus,\n  NzValidateStatus,\n  NzVariant,\n  OnChangeType,\n  OnTouchedType\n} from 'ng-zorro-antd/core/types';\nimport {\n  getStatusClassNames,\n  getVariantClassNames,\n  InputFocusOptions,\n  isNil,\n  isNotNil,\n  triggerFocus\n} from 'ng-zorro-antd/core/util';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport {\n  NzInputAddonAfterDirective,\n  NzInputAddonBeforeDirective,\n  NzInputPrefixDirective,\n  NzInputSuffixDirective\n} from 'ng-zorro-antd/input';\nimport { NZ_SPACE_COMPACT_ITEM_TYPE, NZ_SPACE_COMPACT_SIZE, NzSpaceCompactItemDirective } from 'ng-zorro-antd/space';\n\nexport type NzInputNumberStepEmitter = 'wheel' | 'handler' | 'keyboard';\nexport interface NzInputNumberStepEvent {\n  value: number;\n  offset: number;\n  type: 'up' | 'down';\n  emitter: NzInputNumberStepEmitter;\n}\n\n@Component({\n  selector: 'nz-input-number',\n  exportAs: 'nzInputNumber',\n  imports: [NzIconModule, NzFormItemFeedbackIconComponent, NgTemplateOutlet],\n  template: `\n    @if (hasAddon()) {\n      <ng-template [ngTemplateOutlet]=\"inputNumberWithAddonInner\" />\n    } @else if (hasAffix()) {\n      <ng-template [ngTemplateOutlet]=\"inputNumberWithAffixInner\" />\n    } @else {\n      <ng-template [ngTemplateOutlet]=\"inputNumberInner\" />\n    }\n\n    <ng-template #inputNumberWithAddonInner>\n      <div class=\"ant-input-number-wrapper ant-input-number-group\">\n        @if (hasAddonBefore()) {\n          <div class=\"ant-input-number-group-addon\">\n            <ng-content select=\"[nzInputAddonBefore]\">{{ nzAddonBefore() }}</ng-content>\n          </div>\n        }\n\n        @if (hasAffix()) {\n          <ng-template [ngTemplateOutlet]=\"inputNumberWithAffix\" />\n        } @else {\n          <ng-template [ngTemplateOutlet]=\"inputNumber\" />\n        }\n\n        @if (hasAddonAfter()) {\n          <div class=\"ant-input-number-group-addon\">\n            <ng-content select=\"[nzInputAddonAfter]\">{{ nzAddonAfter() }}</ng-content>\n          </div>\n        }\n      </div>\n    </ng-template>\n\n    <ng-template #inputNumberWithAffix>\n      <div [class]=\"affixWrapperClass()\">\n        <ng-template [ngTemplateOutlet]=\"inputNumberWithAffixInner\" />\n      </div>\n    </ng-template>\n\n    <ng-template #inputNumberWithAffixInner>\n      @if (hasPrefix()) {\n        <span class=\"ant-input-number-prefix\">\n          <ng-content select=\"[nzInputPrefix]\">{{ nzPrefix() }}</ng-content>\n        </span>\n      }\n      <ng-template [ngTemplateOutlet]=\"inputNumber\" />\n      @if (hasSuffix()) {\n        <span class=\"ant-input-number-suffix\">\n          <ng-content select=\"[nzInputSuffix]\">{{ nzSuffix() }}</ng-content>\n          @if (hasFeedback() && finalStatus()) {\n            <nz-form-item-feedback-icon [status]=\"finalStatus()\" />\n          }\n        </span>\n      }\n    </ng-template>\n\n    <ng-template #inputNumber>\n      <div #inputNumberHost [class]=\"inputNumberClass()\">\n        <ng-template [ngTemplateOutlet]=\"inputNumberInner\" />\n      </div>\n    </ng-template>\n\n    <ng-template #inputNumberInner>\n      @if (nzControls()) {\n        <div #handlers class=\"ant-input-number-handler-wrap\" (mouseup)=\"stopAutoStep()\" (mouseleave)=\"stopAutoStep()\">\n          <span\n            role=\"button\"\n            unselectable=\"on\"\n            class=\"ant-input-number-handler ant-input-number-handler-up\"\n            [class.ant-input-number-handler-up-disabled]=\"upDisabled()\"\n            [attr.aria-disabled]=\"upDisabled()\"\n            (mousedown)=\"onStepMouseDown($event, true)\"\n          >\n            <ng-content select=\"[nzInputNumberUpIcon]\">\n              <nz-icon nzType=\"up\" class=\"ant-input-number-handler-up-inner\" />\n            </ng-content>\n          </span>\n          <span\n            role=\"button\"\n            unselectable=\"on\"\n            class=\"ant-input-number-handler ant-input-number-handler-down\"\n            [class.ant-input-number-handler-down-disabled]=\"downDisabled()\"\n            [attr.aria-disabled]=\"downDisabled()\"\n            (mousedown)=\"onStepMouseDown($event, false)\"\n          >\n            <ng-content select=\"[nzInputNumberDownIcon]\">\n              <nz-icon nzType=\"down\" class=\"ant-input-number-handler-down-inner\" />\n            </ng-content>\n          </span>\n        </div>\n      }\n\n      <div class=\"ant-input-number-input-wrap\">\n        <input\n          #input\n          autocomplete=\"off\"\n          role=\"spinbutton\"\n          class=\"ant-input-number-input\"\n          [attr.aria-valuemin]=\"nzMin()\"\n          [attr.aria-valuemax]=\"nzMax()\"\n          [attr.id]=\"nzId()\"\n          [attr.step]=\"nzStep()\"\n          [attr.value]=\"displayValue()\"\n          [value]=\"displayValue()\"\n          [placeholder]=\"nzPlaceHolder() ?? ''\"\n          [disabled]=\"finalDisabled()\"\n          [readOnly]=\"nzReadOnly()\"\n          (input)=\"onInput(input.value)\"\n          (wheel)=\"onWheel($event)\"\n        />\n      </div>\n    </ng-template>\n  `,\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => NzInputNumberComponent),\n      multi: true\n    },\n    { provide: NZ_SPACE_COMPACT_ITEM_TYPE, useValue: 'input-number' }\n  ],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  host: {\n    '[class]': 'class()',\n    '(keydown)': 'onKeyDown($event)'\n  },\n  hostDirectives: [NzSpaceCompactItemDirective]\n})\nexport class NzInputNumberComponent implements OnInit, ControlValueAccessor {\n  readonly nzId = input<string | null>(null);\n  readonly nzSize = input<NzSizeLDSType>('default');\n  readonly nzPlaceHolder = input<string | null>(null);\n  readonly nzStatus = input<NzStatus>('');\n  readonly nzVariant = input<NzVariant>();\n  readonly nzStep = input(1, { transform: numberAttribute });\n  readonly nzMin = input(Number.MIN_SAFE_INTEGER, { transform: numberAttribute });\n  readonly nzMax = input(Number.MAX_SAFE_INTEGER, { transform: numberAttribute });\n  readonly nzPrecision = input<number | null>(null);\n  readonly nzParser = input<((value: string) => number) | null>();\n  readonly nzFormatter = input<((value: number) => string) | null>();\n  readonly nzDisabled = input(false, { transform: booleanAttribute });\n  readonly nzReadOnly = input(false, { transform: booleanAttribute });\n  readonly nzAutoFocus = input(false, { transform: booleanAttribute });\n  readonly nzKeyboard = input(true, { transform: booleanAttribute });\n  readonly nzControls = input(true, { transform: booleanAttribute });\n  readonly nzChangeOnWheel = input(true, { transform: booleanAttribute });\n  readonly nzPrefix = input<string>();\n  readonly nzSuffix = input<string>();\n  readonly nzAddonBefore = input<string>();\n  readonly nzAddonAfter = input<string>();\n\n  readonly nzBlur = output<void>();\n  readonly nzFocus = output<void>();\n\n  readonly nzOnStep = output<NzInputNumberStepEvent>();\n\n  private onChange: OnChangeType = () => {};\n  private onTouched: OnTouchedType = () => {};\n  private isDisabledFirstChange = true;\n  private compactSize = inject(NZ_SPACE_COMPACT_SIZE, { optional: true });\n  private inputRef = viewChild.required<ElementRef<HTMLInputElement>>('input');\n  private hostRef = viewChild<ElementRef<HTMLDivElement>>('inputNumberHost');\n  private elementRef = inject(ElementRef);\n  private injector = inject(Injector);\n  private focusMonitor = inject(FocusMonitor);\n  private directionality = inject(Directionality);\n  private nzFormStatusService = inject(NzFormStatusService, { optional: true });\n  private autoStepTimer: ReturnType<typeof setTimeout> | null = null;\n  private defaultFormatter = (value: number): string => {\n    const precision = this.nzPrecision();\n    if (isNotNil(precision)) {\n      return value.toFixed(precision);\n    }\n    return value.toString();\n  };\n\n  protected readonly value = signal<number | null>(null);\n  protected readonly displayValue = signal('');\n\n  private readonly formSize = inject(NZ_FORM_SIZE, { optional: true });\n  private readonly formVariant = inject(NZ_FORM_VARIANT, { optional: true });\n\n  protected readonly dir = inject(Directionality).valueSignal;\n  protected readonly focused = signal(false);\n  protected readonly hasFeedback = signal(false);\n  protected readonly finalStatus = linkedSignal<NzValidateStatus>(() => this.nzStatus());\n  protected readonly finalDisabled = linkedSignal(() => this.nzDisabled());\n\n  protected readonly prefix = contentChild(NzInputPrefixDirective);\n  protected readonly suffix = contentChild(NzInputSuffixDirective);\n  protected readonly addonBefore = contentChild(NzInputAddonBeforeDirective);\n  protected readonly addonAfter = contentChild(NzInputAddonAfterDirective);\n\n  protected readonly hasPrefix = computed(() => !!this.nzPrefix() || !!this.prefix());\n  protected readonly hasSuffix = computed(() => !!this.nzSuffix() || !!this.suffix() || this.hasFeedback());\n  protected readonly hasAffix = computed(() => this.hasPrefix() || this.hasSuffix());\n  protected readonly hasAddonBefore = computed(() => !!this.nzAddonBefore() || !!this.addonBefore());\n  protected readonly hasAddonAfter = computed(() => !!this.nzAddonAfter() || !!this.addonAfter());\n  protected readonly hasAddon = computed(() => this.hasAddonBefore() || this.hasAddonAfter());\n\n  protected readonly class = computed(() => {\n    if (this.hasAddon()) {\n      return this.groupWrapperClass();\n    }\n    if (this.hasAffix()) {\n      return this.affixWrapperClass();\n    }\n    return this.inputNumberClass();\n  });\n  protected readonly inputNumberClass = computed(() => {\n    return {\n      'ant-input-number': true,\n      'ant-input-number-lg': this.finalSize() === 'large',\n      'ant-input-number-sm': this.finalSize() === 'small',\n      'ant-input-number-disabled': this.finalDisabled(),\n      'ant-input-number-readonly': this.nzReadOnly(),\n      'ant-input-number-focused': this.focused(),\n      'ant-input-number-rtl': this.dir() === 'rtl',\n      'ant-input-number-in-form-item': !!this.nzFormStatusService,\n      'ant-input-number-out-of-range': this.value() !== null && !isInRange(this.value()!, this.nzMin(), this.nzMax()),\n      ...getVariantClassNames('ant-input-number', this.finalVariant()),\n      ...getStatusClassNames('ant-input-number', this.finalStatus(), this.hasFeedback())\n    };\n  });\n  protected readonly affixWrapperClass = computed(() => {\n    return {\n      'ant-input-number-affix-wrapper': true,\n      'ant-input-number-affix-wrapper-disabled': this.finalDisabled(),\n      'ant-input-number-affix-wrapper-readonly': this.nzReadOnly(),\n      'ant-input-number-affix-wrapper-focused': this.focused(),\n      'ant-input-number-affix-wrapper-rtl': this.dir() === 'rtl',\n      ...getStatusClassNames('ant-input-number-affix-wrapper', this.finalStatus(), this.hasFeedback()),\n      ...getVariantClassNames('ant-input-number-affix-wrapper', this.finalVariant())\n    };\n  });\n  protected readonly groupWrapperClass = computed(() => {\n    return {\n      'ant-input-number-group-wrapper': true,\n      'ant-input-number-group-wrapper-rtl': this.dir() === 'rtl',\n      ...getStatusClassNames('ant-input-number-group-wrapper', this.finalStatus(), this.hasFeedback()),\n      ...getVariantClassNames('ant-input-number-group-wrapper', this.finalVariant())\n    };\n  });\n\n  protected readonly finalSize = computed(() => {\n    if (this.formSize?.()) {\n      return this.formSize();\n    }\n    if (this.compactSize) {\n      return this.compactSize();\n    }\n    return this.nzSize();\n  });\n\n  protected readonly finalVariant = computed(() => this.nzVariant() || this.formVariant?.() || 'outlined');\n\n  protected readonly upDisabled = computed(() => {\n    return !isNil(this.value()) && this.value()! >= this.nzMax();\n  });\n  protected readonly downDisabled = computed(() => {\n    return !isNil(this.value()) && this.value()! <= this.nzMin();\n  });\n\n  constructor() {\n    const destroyRef = inject(DestroyRef);\n\n    afterNextRender(() => {\n      const hostRef = this.hostRef();\n      const element = hostRef ? hostRef : this.elementRef;\n\n      this.focusMonitor\n        .monitor(element, true)\n        .pipe(takeUntilDestroyed(destroyRef))\n        .subscribe(origin => {\n          this.focused.set(!!origin);\n\n          if (origin) {\n            this.nzFocus.emit();\n          } else {\n            this.fixValue();\n            this.onTouched();\n            this.nzBlur.emit();\n          }\n        });\n\n      destroyRef.onDestroy(() => {\n        this.focusMonitor.stopMonitoring(element);\n      });\n    });\n\n    this.nzFormStatusService?.formStatusChanges.pipe(takeUntilDestroyed()).subscribe(({ status, hasFeedback }) => {\n      this.finalStatus.set(status);\n      this.hasFeedback.set(hasFeedback);\n    });\n  }\n\n  ngOnInit(): void {\n    if (this.nzAutoFocus()) {\n      afterNextRender(() => this.focus(), { injector: this.injector });\n    }\n  }\n\n  writeValue(value: number | null | undefined): void {\n    if (isNil(value)) value = null;\n    untracked(() => {\n      this.value.set(value);\n      this.setValue(value);\n    });\n  }\n\n  registerOnChange(fn: OnChangeType): void {\n    this.onChange = fn;\n  }\n\n  registerOnTouched(fn: OnTouchedType): void {\n    this.onTouched = fn;\n  }\n\n  setDisabledState(disabled: boolean): void {\n    untracked(() => {\n      this.finalDisabled.set((this.isDisabledFirstChange && this.nzDisabled()) || disabled);\n    });\n    this.isDisabledFirstChange = false;\n  }\n\n  focus(options?: InputFocusOptions): void {\n    triggerFocus(this.inputRef().nativeElement, options);\n  }\n\n  blur(): void {\n    this.inputRef().nativeElement.blur();\n  }\n\n  private step(event: MouseEvent | KeyboardEvent, up: boolean, emitter: NzInputNumberStepEmitter): void {\n    // Ignore step since out of range\n    if ((up && this.upDisabled()) || (!up && this.downDisabled())) {\n      return;\n    }\n\n    // When hold the shift key, the step is 10 times\n    let step = event.shiftKey ? this.nzStep() * 10 : this.nzStep();\n    if (!up) {\n      step = -step;\n    }\n\n    const places = getDecimalPlaces(step);\n    const multiple = 10 ** places;\n    const nextValue = getRangeValue(\n      // Convert floating point numbers to integers to avoid floating point math errors\n      (Math.round((this.value() || 0) * multiple) + Math.round(step * multiple)) / multiple,\n      this.nzMin(),\n      this.nzMax(),\n      this.nzPrecision()\n    );\n    this.setValue(nextValue);\n\n    this.nzOnStep.emit({\n      type: up ? 'up' : 'down',\n      value: this.value()!,\n      offset: this.nzStep(),\n      emitter: emitter\n    });\n\n    this.focus();\n  }\n\n  private setValue(value: number | null): void {\n    const formatter = this.nzFormatter() ?? this.defaultFormatter;\n    const precision = this.nzPrecision();\n\n    if (isNotNil(precision)) {\n      value &&= +value.toFixed(precision);\n    }\n\n    const formattedValue = isNil(value) ? '' : formatter(value);\n    this.displayValue.set(formattedValue);\n    this.updateValue(value);\n  }\n\n  private setValueByTyping(value: string): void {\n    this.displayValue.set(value);\n\n    if (value === '') {\n      this.updateValue(null);\n      return;\n    }\n\n    const parser = this.nzParser() ?? defaultParser;\n    const parsedValue = parser(value);\n\n    if (isNotCompleteNumber(value) || Number.isNaN(parsedValue)) {\n      return;\n    }\n\n    // Formatting is called during input only if the user provided a formatter.\n    // Otherwise, formatting is only called when the input blurs.\n    const formatter = this.nzFormatter();\n    if (formatter) {\n      const formattedValue = formatter(parsedValue);\n      this.displayValue.set(formattedValue);\n    }\n\n    if (!isInRange(parsedValue, this.nzMin(), this.nzMax())) {\n      return;\n    }\n\n    this.updateValue(parsedValue);\n  }\n\n  private updateValue(value: number | null): void {\n    if (this.value() !== value) {\n      this.value.set(value);\n      this.onChange(value);\n    }\n  }\n\n  private fixValue(): void {\n    const displayValue = this.displayValue();\n\n    if (displayValue === '') {\n      return;\n    }\n\n    const parser = this.nzParser() ?? defaultParser;\n    let fixedValue: number | null = parser(displayValue);\n\n    // If parsing fails, revert to the previous value\n    if (Number.isNaN(fixedValue)) {\n      fixedValue = this.value();\n    } else {\n      const precision = this.nzPrecision();\n      // fix precision\n      if (isNotNil(precision) && getDecimalPlaces(fixedValue) !== precision) {\n        fixedValue = +fixedValue.toFixed(precision);\n      }\n\n      // fix range\n      if (!isInRange(fixedValue, this.nzMin(), this.nzMax())) {\n        fixedValue = getRangeValue(fixedValue, this.nzMin(), this.nzMax(), precision);\n      }\n    }\n\n    this.setValue(fixedValue);\n  }\n\n  protected stopAutoStep(): void {\n    if (this.autoStepTimer !== null) {\n      clearTimeout(this.autoStepTimer);\n      this.autoStepTimer = null;\n    }\n  }\n\n  protected onStepMouseDown(event: MouseEvent | KeyboardEvent, up: boolean): void {\n    event.preventDefault();\n    this.stopAutoStep();\n\n    this.step(event, up, 'handler');\n\n    // Loop step for interval\n    const loopStep: () => void = () => {\n      this.step(event, up, 'handler');\n      this.autoStepTimer = setTimeout(loopStep, STEP_INTERVAL);\n    };\n\n    // First time press will wait some time to trigger loop step update\n    this.autoStepTimer = setTimeout(loopStep, STEP_DELAY);\n  }\n\n  protected onKeyDown(event: KeyboardEvent): void {\n    switch (event.keyCode) {\n      case UP_ARROW:\n        event.preventDefault();\n        this.nzKeyboard() && this.step(event, true, 'keyboard');\n        break;\n      case DOWN_ARROW:\n        event.preventDefault();\n        this.nzKeyboard() && this.step(event, false, 'keyboard');\n        break;\n      case ENTER:\n        this.fixValue();\n        break;\n    }\n  }\n\n  protected onInput(value: string): void {\n    this.setValueByTyping(value);\n  }\n\n  protected onWheel(event: WheelEvent): void {\n    if (this.nzDisabled() || !this.nzChangeOnWheel()) {\n      return;\n    }\n\n    event.preventDefault();\n    this.step(event, event.deltaY < 0, 'wheel');\n  }\n}\n\n/**\n * When click and hold on a button - the speed of auto changing the value.\n */\nconst STEP_INTERVAL = 200;\n\n/**\n * When click and hold on a button - the delay before auto changing the value.\n */\nconst STEP_DELAY = 600;\n\nfunction defaultParser(value: string): number {\n  const parsedValue = value.trim().replace(/,/g, '').replace(/。/g, '.');\n  // `+'' === 0`, so we need to check if parsedValue is empty\n  if (parsedValue.length) {\n    return +parsedValue;\n  }\n  return NaN;\n}\n\nfunction isInRange(value: number, min: number, max: number): boolean {\n  return value >= min && value <= max;\n}\n\n/**\n * if max > 0, round down with precision. Example: input= 3.5, max= 3.5, precision=0; output= 3\n * if max < 0, round up   with precision. Example: input=-3.5, max=-3.5, precision=0; output=-4\n * if min > 0, round up   with precision. Example: input= 3.5, min= 3.5, precision=0; output= 4\n * if min < 0, round down with precision. Example: input=-3.5, min=-3.5, precision=0; output=-3\n */\nfunction getRangeValue(value: number, min: number, max: number, precision: number | null = null): number {\n  if (precision === null) {\n    if (value < min) {\n      return min;\n    }\n\n    if (value > max) {\n      return max;\n    }\n\n    return value;\n  }\n\n  const fixedValue = +value.toFixed(precision);\n  const multiple = Math.pow(10, precision);\n\n  if (fixedValue < min) {\n    return Math.ceil(min * multiple) / multiple;\n  }\n\n  if (fixedValue > max) {\n    return Math.floor(max * multiple) / multiple;\n  }\n\n  return fixedValue;\n}\n\nfunction getDecimalPlaces(num: number): number {\n  return num.toString().split('.')[1]?.length || 0;\n}\n\nfunction isNotCompleteNumber(value: string | number): boolean {\n  return /[.。](\\d*0)?$/.test(value.toString());\n}\n"
  },
  {
    "path": "components/input-number/input-number.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport {\n  NzInputAddonAfterDirective,\n  NzInputAddonBeforeDirective,\n  NzInputPrefixDirective,\n  NzInputSuffixDirective\n} from 'ng-zorro-antd/input';\n\nimport { NzInputNumberComponent } from './input-number.component';\n\n@NgModule({\n  imports: [\n    NzInputNumberComponent,\n    NzInputAddonBeforeDirective,\n    NzInputAddonAfterDirective,\n    NzInputPrefixDirective,\n    NzInputSuffixDirective\n  ],\n  exports: [\n    NzInputNumberComponent,\n    NzInputAddonBeforeDirective,\n    NzInputAddonAfterDirective,\n    NzInputPrefixDirective,\n    NzInputSuffixDirective\n  ]\n})\nexport class NzInputNumberModule {}\n"
  },
  {
    "path": "components/input-number/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/input-number/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './input-number.component';\nexport * from './input-number.module';\n"
  },
  {
    "path": "components/input-number/style/affix.less",
    "content": "@import '../../input/style/mixin';\n@import (reference) '../../style/themes/index';\n@input-prefix-cls: ~'@{ant-prefix}-input';\n\n@input-affix-margin: 4px;\n\n.@{ant-prefix}-input-number {\n  &-affix-wrapper {\n    .input();\n    // or number handler will cover form status\n    position: relative;\n    display: inline-flex;\n    width: 90px;\n    padding: 0;\n    padding-inline-start: @input-padding-horizontal-base;\n\n    &:not(&-disabled):hover {\n      .hover();\n      z-index: 1;\n    }\n\n    &-focused,\n    &:focus {\n      z-index: 1;\n    }\n\n    &-disabled {\n      .@{ant-prefix}-input-number[disabled] {\n        background: transparent;\n      }\n    }\n\n    > div.@{ant-prefix}-input-number {\n      width: 100%;\n      border: none;\n      outline: none;\n\n      &.@{ant-prefix}-input-number-focused {\n        box-shadow: none !important;\n      }\n    }\n\n    input.@{ant-prefix}-input-number-input {\n      padding: 0;\n    }\n\n    &::before {\n      display: inline-block;\n      width: 0;\n      visibility: hidden;\n      content: '\\a0';\n    }\n\n    .@{ant-prefix}-input-number-handler-wrap {\n      z-index: 2;\n    }\n  }\n\n  &-prefix,\n  &-suffix {\n    display: flex;\n    flex: none;\n    align-items: center;\n    pointer-events: none;\n  }\n\n  &-prefix {\n    margin-inline-end: @input-affix-margin;\n  }\n\n  &-suffix {\n    position: absolute;\n    top: 0;\n    right: 0;\n    z-index: 1;\n    height: 100%;\n    margin-right: @input-padding-horizontal-base;\n    margin-left: @input-affix-margin;\n  }\n}\n\n.@{ant-prefix}-input-number-group-wrapper .@{ant-prefix}-input-number-affix-wrapper {\n  width: 100%;\n}\n"
  },
  {
    "path": "components/input-number/style/entry.less",
    "content": "@import './index.less';\n"
  },
  {
    "path": "components/input-number/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import '../../input/style/mixin';\n@import './affix';\n@import './status';\n\n@input-number-prefix-cls: ~'@{ant-prefix}-input-number';\n@form-item-prefix-cls: ~'@{ant-prefix}-form-item';\n\n.@{input-number-prefix-cls} {\n  .reset-component();\n  .input();\n\n  //== Style for input-group: input with label, with button or dropdown...\n  &-group {\n    .reset-component();\n    .input-group(~'@{input-number-prefix-cls}');\n\n    &-wrapper {\n      display: inline-block;\n      text-align: start;\n      vertical-align: top; // https://github.com/ant-design/ant-design/issues/6403\n\n      .input-group-wrapper-compact(~'@{input-number-prefix-cls}');\n    }\n  }\n\n  display: inline-block;\n  width: 90px;\n  margin: 0;\n  padding: 0;\n  border: @border-width-base @border-style-base @input-border-color;\n  border-radius: @control-border-radius;\n\n  &-handler {\n    position: relative;\n    display: block;\n    width: 100%;\n    height: 50%;\n    overflow: hidden;\n    color: @text-color-secondary;\n    font-weight: bold;\n    line-height: 0;\n    text-align: center;\n    border-left: @border-width-base @border-style-base @input-number-handler-border-color;\n    transition: all 0.1s linear;\n\n    &:active {\n      background: @input-number-handler-active-bg;\n    }\n\n    &:hover &-up-inner,\n    &:hover &-down-inner {\n      color: @input-number-handler-hover-bg;\n    }\n  }\n\n  &-handler-up-inner,\n  &-handler-down-inner {\n    .iconfont-mixin();\n\n    position: absolute;\n    right: 4px;\n    width: 12px;\n    height: 12px;\n    color: @text-color-secondary;\n    line-height: 12px;\n    transition: all 0.1s linear;\n    user-select: none;\n  }\n\n  &:hover {\n    & + .@{form-item-prefix-cls}-children-icon {\n      opacity: 0;\n      transition: opacity 0.24s linear 0.24s;\n    }\n  }\n\n  &-focused {\n    .active();\n  }\n\n  &-disabled {\n    .disabled();\n    .@{input-number-prefix-cls}-input {\n      cursor: not-allowed;\n    }\n    .@{input-number-prefix-cls}-handler-wrap {\n      display: none;\n    }\n  }\n\n  &-readonly {\n    .@{input-number-prefix-cls}-handler-wrap {\n      display: none;\n    }\n  }\n\n  &-input {\n    width: 100%;\n    height: @input-height-base - 2px;\n    padding: 0 @control-padding-horizontal - 1px;\n    text-align: left;\n    background-color: transparent;\n    border: 0;\n    border-radius: @control-border-radius;\n    outline: 0;\n    transition: all 0.3s linear;\n    appearance: textfield !important;\n    .placeholder();\n\n    &[type='number']::-webkit-inner-spin-button,\n    &[type='number']::-webkit-outer-spin-button {\n      margin: 0;\n      /* stylelint-disable-next-line property-no-vendor-prefix */\n      -webkit-appearance: none;\n      appearance: none;\n    }\n  }\n\n  &-lg {\n    padding: 0;\n    font-size: @font-size-lg;\n\n    input {\n      height: @input-height-lg - 2px;\n    }\n  }\n\n  &-sm {\n    padding: 0;\n\n    input {\n      height: @input-height-sm - 2px;\n      padding: 0 @control-padding-horizontal-sm - 1px;\n    }\n  }\n\n  &-handler-wrap {\n    position: absolute;\n    top: 0;\n    right: 0;\n    width: 22px;\n    height: 100%;\n    background: transparent;\n    border-radius: 0 @control-border-radius @control-border-radius 0;\n    opacity: 0;\n    transition: opacity 0.24s linear 0.1s;\n\n    // Fix input number inside Menu makes icon too large\n    // We arise the selector priority by nest selector here\n    // https://github.com/ant-design/ant-design/issues/14367\n    .@{input-number-prefix-cls}-handler {\n      .@{input-number-prefix-cls}-handler-up-inner,\n      .@{input-number-prefix-cls}-handler-down-inner {\n        display: flex;\n        align-items: center;\n        justify-content: center;\n        min-width: auto;\n        margin-right: 0;\n        font-size: 7px;\n      }\n    }\n\n    .@{input-number-prefix-cls}-borderless & {\n      border-left-width: 0;\n    }\n  }\n\n  &-handler-wrap:hover &-handler {\n    height: 40%;\n  }\n\n  &:hover &-handler-wrap,\n  &-focused &-handler-wrap {\n    opacity: 1;\n  }\n\n  &-handler-up {\n    border-top-right-radius: @control-border-radius;\n    cursor: pointer;\n\n    &-inner {\n      top: 50%;\n      margin-top: -5px;\n      text-align: center;\n    }\n\n    &:hover {\n      height: 60% !important;\n    }\n  }\n\n  &-handler-down {\n    top: 0;\n    border-top: @border-width-base @border-style-base @input-number-handler-border-color;\n    border-bottom-right-radius: @control-border-radius;\n    cursor: pointer;\n\n    &-inner {\n      top: 50%;\n      text-align: center;\n      transform: translateY(-50%);\n    }\n\n    &:hover {\n      height: 60% !important;\n    }\n    .@{input-number-prefix-cls}-borderless & {\n      border-top-width: 0;\n    }\n  }\n\n  &:hover:not(.@{input-number-prefix-cls}-borderless) &-handler-down,\n  &-focused:not(.@{input-number-prefix-cls}-borderless) &-handler-down {\n    border-top: @border-width-base @border-style-base @input-number-handler-border-color;\n  }\n\n  &-handler-up-disabled,\n  &-handler-down-disabled {\n    cursor: not-allowed;\n  }\n\n  &-handler-up-disabled:hover &-handler-up-inner,\n  &-handler-down-disabled:hover &-handler-down-inner {\n    color: @disabled-color;\n  }\n\n  // ===================== Out Of Range =====================\n  &-out-of-range {\n    input {\n      color: @error-color;\n    }\n  }\n\n  // ===================== Compact Item Styles =====================\n  /* stylelint-disable less/no-duplicate-variables */\n  .compact-item(@input-number-prefix-cls, null, ~'@{input-number-prefix-cls}-focused');\n  .compact-item(~'@{input-number-prefix-cls}-affix-wrapper', null, ~'@{input-number-prefix-cls}-focused');\n  .compact-item(~'@{input-number-prefix-cls}-group-wrapper', ~'@{input-number-prefix-cls}-group-addon', ~'@{input-number-prefix-cls}-focused');\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/input-number/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import '../../input/style/mixin';\n\n@input-number-prefix-cls: ~'@{ant-prefix}-input-number';\n\n.@{input-number-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &-handler {\n    .@{input-number-prefix-cls}-rtl & {\n      border-right: @border-width-base @border-style-base @input-number-handler-border-color;\n      border-left: 0;\n    }\n\n    &-wrap {\n      .@{input-number-prefix-cls}-rtl & {\n        right: auto;\n        left: 0;\n      }\n\n      .@{input-number-prefix-cls}-rtl.@{input-number-prefix-cls}-borderless &,\n      .@{input-number-prefix-cls}-rtl.@{input-number-prefix-cls}-filled &,\n      .@{input-number-prefix-cls}-rtl.@{input-number-prefix-cls}-underlined & {\n        border-right-width: 0;\n      }\n    }\n\n    &-up {\n      .@{input-number-prefix-cls}-rtl & {\n        border-top-right-radius: 0;\n      }\n    }\n\n    &-down {\n      .@{input-number-prefix-cls}-rtl & {\n        border-bottom-right-radius: 0;\n      }\n    }\n  }\n\n  &-input {\n    .@{input-number-prefix-cls}-rtl & {\n      direction: ltr;\n      text-align: right;\n    }\n  }\n}\n\n// https://github.com/ant-design/ant-design/issues/35870\n.input-group(@input-number-prefix-cls) {\n  > .@{input-number-prefix-cls}-rtl:first-child {\n    border-radius: 0 @border-radius-base @border-radius-base 0;\n  }\n  > .@{input-number-prefix-cls}-rtl:last-child {\n    border-radius: @border-radius-base 0 0 @border-radius-base;\n  }\n\n  &-addon {\n    .@{input-number-prefix-cls}-group-rtl &:first-child {\n      border-right: @border-width-base @border-style-base @input-border-color;\n      border-left: 0;\n      border-radius: 0 @border-radius-base @border-radius-base 0;\n    }\n    .@{input-number-prefix-cls}-group-rtl &:last-child {\n      border-right: 0;\n      border-left: @border-width-base @border-style-base @input-border-color;\n      border-radius: @border-radius-base 0 0 @border-radius-base;\n    }\n  }\n}\n"
  },
  {
    "path": "components/input-number/style/status.less",
    "content": "@import '../../input/style/mixin';\n\n@input-number-prefix-cls: ~'@{ant-prefix}-input-number';\n\n@input-number-wrapper-cls: @input-number-prefix-cls, ~'@{input-number-prefix-cls}-affix-wrapper';\n\neach(@input-number-wrapper-cls, {\n  .@{value} {\n    &-status-error {\n      .status-color(@value, @error-color, @error-color, @input-bg, @error-color-hover, @error-color-outline);\n      .status-color-common(@input-number-prefix-cls, @error-color, @error-color, @input-bg, @error-color-hover, @error-color-outline)\n    }\n\n    &-status-warning {\n      .status-color(@value, @warning-color, @warning-color, @input-bg, @warning-color-hover, @warning-color-outline);\n      .status-color-common(@input-number-prefix-cls, @warning-color, @warning-color, @input-bg, @warning-color-hover, @warning-color-outline)\n    }\n  }\n});\n\n.@{input-number-prefix-cls}-group-wrapper {\n  &-status-error {\n    .group-status-color(@input-number-prefix-cls, @error-color, @error-color);\n  }\n\n  &-status-warning {\n    .group-status-color(@input-number-prefix-cls, @warning-color, @warning-color);\n  }\n}\n"
  },
  {
    "path": "components/karma.conf.js",
    "content": "// Karma configuration file, see link for more information\n// https://karma-runner.github.io/1.0/config/configuration-file.html\n\nconst tags = process.env && process.env['NG_TEST_TAGS'];\nconst processENV = require('process');\nprocessENV.env.CHROME_BIN = require('puppeteer').executablePath();\n\nmodule.exports = function (config) {\n  config.set({\n    basePath: '',\n    frameworks: ['jasmine', 'viewport'],\n    plugins: [\n      require('karma-jasmine'),\n      require('karma-chrome-launcher'),\n      require('karma-spec-reporter'),\n      require('karma-jasmine-html-reporter'),\n      require('karma-coverage'),\n      require('karma-junit-reporter'),\n      require('karma-viewport')\n    ],\n    client: {\n      jasmine: {\n        random: false\n      },\n      clearContext: true, // leave Jasmine Spec Runner output visible in browser\n      ...(tags && { args: [tags] })\n    },\n    coverageReporter: {\n      subdir: '.',\n      dir: require('path').join(__dirname, '../coverage-report'),\n      reporters: [{ type: 'html' }, { type: 'text-summary' }, { type: 'lcovonly' }, { type: 'cobertura' }]\n    },\n    reporters: ['progress', 'kjhtml', 'spec', 'junit'],\n    junitReporter: {\n      outputDir: 'junit'\n    },\n    specReporter: {\n      maxLogLines: 5,\n      suppressErrorSummary: true,\n      suppressFailed: false,\n      suppressPassed: false,\n      suppressSkipped: true,\n      showSpecTiming: false\n    },\n    port: 9876,\n    colors: true,\n    logLevel: config.LOG_INFO,\n    autoWatch: true,\n    browsers: ['Chrome'],\n    customLaunchers: {\n      ChromeHeadlessCI: {\n        base: 'ChromeHeadless',\n        flags: ['--disable-gpu', '--no-sandbox']\n      }\n    },\n    singleRun: false,\n    browserDisconnectTimeout: 1000 * 60 * 10, // (Default: 2000)\n    browserNoActivityTimeout: 1000 * 60 // (Default: 10000)\n  });\n};\n"
  },
  {
    "path": "components/layout/content.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';\n\n@Component({\n  selector: 'nz-content',\n  exportAs: 'nzContent',\n  template: `<ng-content />`,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  host: {\n    class: 'ant-layout-content'\n  }\n})\nexport class NzContentComponent {}\n"
  },
  {
    "path": "components/layout/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本结构\n  en-US: Basic Structure\n---\n\n## zh-CN\n\n典型的页面布局。\n\n## en-US\n\nClassic page layouts.\n"
  },
  {
    "path": "components/layout/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzLayoutModule } from 'ng-zorro-antd/layout';\n\n@Component({\n  selector: 'nz-demo-layout-basic',\n  imports: [NzLayoutModule],\n  template: `\n    <nz-layout>\n      <nz-header>Header</nz-header>\n      <nz-content>Content</nz-content>\n      <nz-footer>Footer</nz-footer>\n    </nz-layout>\n\n    <nz-layout>\n      <nz-header>Header</nz-header>\n      <nz-layout>\n        <nz-sider>Sider</nz-sider>\n        <nz-content>Content</nz-content>\n      </nz-layout>\n      <nz-footer>Footer</nz-footer>\n    </nz-layout>\n\n    <nz-layout>\n      <nz-header>Header</nz-header>\n      <nz-layout>\n        <nz-content>Content</nz-content>\n        <nz-sider>Sider</nz-sider>\n      </nz-layout>\n      <nz-footer>Footer</nz-footer>\n    </nz-layout>\n\n    <nz-layout>\n      <nz-sider>Sider</nz-sider>\n      <nz-layout>\n        <nz-header>Header</nz-header>\n        <nz-content>Content</nz-content>\n        <nz-footer>Footer</nz-footer>\n      </nz-layout>\n    </nz-layout>\n  `,\n  styles: `\n    :host {\n      display: flex;\n      flex-wrap: wrap;\n      gap: 16px;\n      text-align: center;\n    }\n\n    nz-header,\n    nz-footer {\n      text-align: center;\n      background: #4096ff;\n      color: #fff;\n    }\n\n    nz-header {\n      height: 64px;\n      padding-inline: 48px;\n      line-height: 64px;\n    }\n\n    nz-sider {\n      text-align: center;\n      background: #1677ff;\n      color: #fff;\n      line-height: 120px;\n    }\n\n    nz-content {\n      text-align: center;\n      background: #0958d9;\n      color: #fff;\n      min-height: 120px;\n      line-height: 120px;\n    }\n\n    :host > nz-layout {\n      width: calc(50% - 8px);\n      max-width: calc(50% - 8px);\n      border-radius: 8px;\n      overflow: hidden;\n    }\n  `\n})\nexport class NzDemoLayoutBasicComponent {}\n"
  },
  {
    "path": "components/layout/demo/custom-trigger.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 自定义触发器\n  en-US: Custom trigger\n---\n\n## zh-CN\n\n要使用自定义触发器，可以设置 `[nzTrigger]=\"null\"` 来隐藏默认设定。\n\n## en-US\n\nIf you want to use a customized trigger, you can hide the default one by setting `[nzTrigger]=\"null\"`.\n"
  },
  {
    "path": "components/layout/demo/custom-trigger.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzLayoutModule } from 'ng-zorro-antd/layout';\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\n\n@Component({\n  selector: 'nz-demo-layout-custom-trigger',\n  imports: [NzBreadCrumbModule, NzIconModule, NzMenuModule, NzLayoutModule],\n  template: `\n    <nz-layout>\n      <nz-sider nzCollapsible [(nzCollapsed)]=\"isCollapsed\" [nzTrigger]=\"null\">\n        <div class=\"logo\"></div>\n        <ul nz-menu nzTheme=\"dark\" nzMode=\"inline\">\n          <li nz-submenu nzTitle=\"User\" nzIcon=\"user\">\n            <ul>\n              <li nz-menu-item>Tom</li>\n              <li nz-menu-item>Bill</li>\n              <li nz-menu-item>Alex</li>\n            </ul>\n          </li>\n          <li nz-submenu nzTitle=\"Team\" nzIcon=\"team\">\n            <ul>\n              <li nz-menu-item>Team 1</li>\n              <li nz-menu-item>Team 2</li>\n            </ul>\n          </li>\n          <li nz-menu-item>\n            <nz-icon nzType=\"file\" />\n            <span>File</span>\n          </li>\n        </ul>\n      </nz-sider>\n      <nz-layout>\n        <nz-header>\n          <nz-icon\n            class=\"trigger\"\n            [nzType]=\"isCollapsed ? 'menu-unfold' : 'menu-fold'\"\n            (click)=\"isCollapsed = !isCollapsed\"\n          />\n        </nz-header>\n        <nz-content>\n          <nz-breadcrumb>\n            <nz-breadcrumb-item>User</nz-breadcrumb-item>\n            <nz-breadcrumb-item>Bill</nz-breadcrumb-item>\n          </nz-breadcrumb>\n          <div class=\"inner-content\">Bill is a cat.</div>\n        </nz-content>\n        <nz-footer>Ant Design ©{{ date.getFullYear() }} Implement By Angular</nz-footer>\n      </nz-layout>\n    </nz-layout>\n  `,\n  styles: `\n    .trigger {\n      font-size: 18px;\n      line-height: 64px;\n      padding: 0 24px;\n      cursor: pointer;\n      transition: color 0.3s;\n    }\n\n    .trigger:hover {\n      color: #1890ff;\n    }\n\n    .logo {\n      height: 32px;\n      background: rgba(255, 255, 255, 0.2);\n      margin: 16px;\n    }\n\n    nz-header {\n      background: #fff;\n      padding: 0;\n    }\n\n    nz-content {\n      margin: 0 16px;\n    }\n\n    nz-breadcrumb {\n      margin: 16px 0;\n    }\n\n    .inner-content {\n      padding: 24px;\n      background: #fff;\n      min-height: 360px;\n    }\n\n    nz-footer {\n      text-align: center;\n    }\n  `\n})\nexport class NzDemoLayoutCustomTriggerComponent {\n  isCollapsed = false;\n  protected readonly date = new Date();\n}\n"
  },
  {
    "path": "components/layout/demo/fixed-sider.md",
    "content": "---\norder: 7\niframe:\n  height: 360\ntitle:\n  zh-CN: 固定侧边栏\n  en-US: Fixed Sider\n---\n\n## zh-CN\n\n当内容较长时，使用固定侧边栏可以提供更好的体验。\n\n## en-US\n\nWhen dealing with long content, a fixed sider can provide a better user experience.\n"
  },
  {
    "path": "components/layout/demo/fixed-sider.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzLayoutModule } from 'ng-zorro-antd/layout';\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\n\n@Component({\n  selector: 'nz-demo-layout-fixed-sider',\n  imports: [NzIconModule, NzMenuModule, NzLayoutModule],\n  template: `\n    <nz-layout class=\"layout\">\n      <nz-sider>\n        <div class=\"logo\"></div>\n        <ul nz-menu nzTheme=\"dark\" nzMode=\"inline\">\n          <li nz-menu-item>\n            <nz-icon nzType=\"file\" />\n            <span>nav 1</span>\n          </li>\n          <li nz-menu-item>\n            <nz-icon nzType=\"video-camera\" />\n            <span>nav 2</span>\n          </li>\n          <li nz-menu-item>\n            <nz-icon nzType=\"upload\" />\n            <span>nav 3</span>\n          </li>\n          <li nz-menu-item>\n            <nz-icon nzType=\"bar-chart\" />\n            <span>nav 4</span>\n          </li>\n          <li nz-menu-item>\n            <nz-icon nzType=\"cloud-o\" />\n            <span>nav 5</span>\n          </li>\n          <li nz-menu-item>\n            <nz-icon nzType=\"appstore-o\" />\n            <span>nav 6</span>\n          </li>\n          <li nz-menu-item>\n            <nz-icon nzType=\"team\" />\n            <span>nav 7</span>\n          </li>\n          <li nz-menu-item>\n            <nz-icon nzType=\"shop\" />\n            <span>nav 8</span>\n          </li>\n        </ul>\n      </nz-sider>\n      <nz-layout class=\"right-layout\">\n        <nz-header />\n        <nz-content>\n          <div class=\"inner-content\">\n            ...\n            <br />\n            Really\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            long\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            ...\n            <br />\n            content\n          </div>\n        </nz-content>\n        <nz-footer>Ant Design ©{{ date.getFullYear() }} Implement By Angular</nz-footer>\n      </nz-layout>\n    </nz-layout>\n  `,\n  styles: `\n    .logo {\n      height: 32px;\n      background: rgba(255, 255, 255, 0.2);\n      margin: 16px;\n    }\n\n    .layout {\n      min-height: 100vh;\n    }\n\n    nz-sider {\n      overflow: auto;\n      height: 100%;\n      position: fixed;\n      left: 0;\n    }\n\n    .right-layout {\n      margin-left: 200px;\n    }\n\n    nz-header {\n      background: #fff;\n      padding: 0;\n    }\n\n    nz-content {\n      margin: 24px 16px 0;\n      overflow: initial;\n    }\n\n    .inner-content {\n      padding: 24px;\n      background: #fff;\n      text-align: center;\n    }\n\n    nz-footer {\n      text-align: center;\n    }\n  `\n})\nexport class NzDemoLayoutFixedSiderComponent {\n  protected readonly date = new Date();\n}\n"
  },
  {
    "path": "components/layout/demo/fixed.md",
    "content": "---\norder: 6\niframe:\n  height: 360\ntitle:\n  zh-CN: 固定头部\n  en-US: Fixed Header\n---\n\n## zh-CN\n\n一般用于固定顶部导航，方便页面切换。\n\n## en-US\n\nFixed Header is generally used to fix the top navigation to facilitate page switching.\n"
  },
  {
    "path": "components/layout/demo/fixed.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';\nimport { NzLayoutModule } from 'ng-zorro-antd/layout';\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\n\n@Component({\n  selector: 'nz-demo-layout-fixed',\n  imports: [NzBreadCrumbModule, NzMenuModule, NzLayoutModule],\n  template: `\n    <nz-layout class=\"layout\">\n      <nz-header>\n        <div class=\"logo\"></div>\n        <ul nz-menu nzTheme=\"dark\" nzMode=\"horizontal\">\n          <li nz-menu-item>nav 1</li>\n          <li nz-menu-item>nav 2</li>\n          <li nz-menu-item>nav 3</li>\n        </ul>\n      </nz-header>\n      <nz-content>\n        <nz-breadcrumb>\n          <nz-breadcrumb-item>Home</nz-breadcrumb-item>\n          <nz-breadcrumb-item>List</nz-breadcrumb-item>\n          <nz-breadcrumb-item>App</nz-breadcrumb-item>\n        </nz-breadcrumb>\n        <div class=\"inner-content\">Content</div>\n      </nz-content>\n      <nz-footer>Ant Design ©{{ date.getFullYear() }} Implement By Angular</nz-footer>\n    </nz-layout>\n  `,\n  styles: `\n    .layout {\n      min-height: 100vh;\n    }\n\n    .logo {\n      width: 120px;\n      height: 31px;\n      background: rgba(255, 255, 255, 0.2);\n      margin: 16px 24px 16px 0;\n      float: left;\n    }\n\n    nz-header {\n      position: fixed;\n      width: 100%;\n    }\n\n    [nz-menu] {\n      line-height: 64px;\n    }\n\n    nz-content {\n      padding: 0 50px;\n      margin-top: 64px;\n    }\n\n    nz-breadcrumb {\n      margin: 16px 0;\n    }\n\n    .inner-content {\n      background: #fff;\n      padding: 24px;\n      min-height: 380px;\n    }\n\n    nz-footer {\n      text-align: center;\n    }\n  `\n})\nexport class NzDemoLayoutFixedComponent {\n  protected readonly date = new Date();\n}\n"
  },
  {
    "path": "components/layout/demo/responsive.md",
    "content": "---\norder: 5\niframe:\n  height: 360\ntitle:\n  zh-CN: 响应式布局\n  en-US: Responsive\n---\n\n## zh-CN\n\nnz-sider 支持响应式布局。\n\n> 说明：配置 `nzBreakpoint` 属性即生效，视窗宽度小于 `nzBreakpoint` 时 `nz-sider` 缩小为 `nzCollapsedWidth` 宽度，若将 `nzCollapsedWidth` 设置为零，会出现特殊 trigger。\n\n## en-US\n\nLayout.Sider supports responsive layout.\n\n> Note: You can get a responsive layout by setting `nzBreakpoint`, the `nz-sider` will collapse to the width of `nzCollapsedWidth` when window width is below the `nzBreakpoint`. And a special trigger will appear if the `nzCollapsedWidth` is set to `0`.\n"
  },
  {
    "path": "components/layout/demo/responsive.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzLayoutModule } from 'ng-zorro-antd/layout';\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\n\n@Component({\n  selector: 'nz-demo-layout-responsive',\n  imports: [NzIconModule, NzMenuModule, NzLayoutModule],\n  template: `\n    <nz-layout>\n      <nz-sider nzCollapsible nzBreakpoint=\"lg\" [nzCollapsedWidth]=\"0\">\n        <div class=\"logo\"></div>\n        <ul nz-menu nzTheme=\"dark\" nzMode=\"inline\">\n          <li nz-menu-item>\n            <nz-icon nzType=\"user\" />\n            <span>nav 1</span>\n          </li>\n          <li nz-menu-item>\n            <nz-icon nzType=\"video-camera\" />\n            <span>nav 2</span>\n          </li>\n          <li nz-menu-item>\n            <nz-icon nzType=\"upload\" />\n            <span>nav 3</span>\n          </li>\n          <li nz-menu-item>\n            <nz-icon nzType=\"user\" />\n            <span>nav 4</span>\n          </li>\n        </ul>\n      </nz-sider>\n      <nz-layout>\n        <nz-header />\n        <nz-content>\n          <div class=\"inner-content\">Content</div>\n        </nz-content>\n        <nz-footer>Ant Design ©{{ date.getFullYear() }} Implement By Angular</nz-footer>\n      </nz-layout>\n    </nz-layout>\n  `,\n  styles: `\n    .logo {\n      height: 32px;\n      background: rgba(255, 255, 255, 0.2);\n      margin: 16px;\n    }\n\n    nz-header {\n      background: #fff;\n      padding: 0;\n    }\n\n    nz-content {\n      margin: 24px 16px 0;\n    }\n\n    .inner-content {\n      padding: 24px;\n      background: #fff;\n      min-height: 360px;\n    }\n\n    nz-footer {\n      text-align: center;\n    }\n  `\n})\nexport class NzDemoLayoutResponsiveComponent {\n  protected readonly date = new Date();\n}\n"
  },
  {
    "path": "components/layout/demo/side.md",
    "content": "---\norder: 4\niframe:\n  height: 360\ntitle:\n  zh-CN: 侧边布局\n  en-US: Sider\n---\n\n## zh-CN\n\n侧边两列式布局。页面横向空间有限时，侧边导航可收起。\n\n侧边导航在页面布局上采用的是左右的结构，一般主导航放置于页面的左侧固定位置，辅助菜单放置于工作区顶部。内容根据浏览器终端进行自适应，能提高横向空间的使用率，但是整个页面排版不稳定。侧边导航的模式层级扩展性强，一、二、三级导航项目可以更为顺畅且具关联性的被展示，同时侧边导航可以固定，使得用户在操作和浏览中可以快速的定位和切换当前位置，有很高的操作效率。但这类导航横向页面内容的空间会被牺牲一部份。\n\n## en-US\n\nTwo-columns layout. The sider menu can be collapsed when horizontal space is limited.\n\nGenerally, the mainnav is placed on the left side of the page, and the secondary menu is placed on the top of the working area. Contents will adapt the layout to the viewing area to improve the horizontal space usage, while the layout of the whole page is not stable.\n\nThe level of the aisde navigation is scalable. The first, second, and third level navigations could be present more fluently and relevantly, and aside navigation can be fixed, allowing the user to quickly switch and spot the current position, improving the user experience. However, this navigation occupies some horizontal space of the contents\n"
  },
  {
    "path": "components/layout/demo/side.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzLayoutModule } from 'ng-zorro-antd/layout';\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\n\n@Component({\n  selector: 'nz-demo-layout-side',\n  imports: [NzBreadCrumbModule, NzIconModule, NzMenuModule, NzLayoutModule],\n  template: `\n    <nz-layout>\n      <nz-sider nzCollapsible nzWidth=\"200px\">\n        <div class=\"logo\"></div>\n        <ul nz-menu nzTheme=\"dark\" nzMode=\"inline\">\n          <li nz-menu-item>\n            <nz-icon nzType=\"pie-chart\" />\n            <span>Option 1</span>\n          </li>\n          <li nz-menu-item>\n            <nz-icon nzType=\"desktop\" />\n            <span>Option 2</span>\n          </li>\n          <li nz-submenu nzTitle=\"User\" nzIcon=\"user\">\n            <ul>\n              <li nz-menu-item>Tom</li>\n              <li nz-menu-item>Bill</li>\n              <li nz-menu-item>Alex</li>\n            </ul>\n          </li>\n          <li nz-submenu nzTitle=\"Team\" nzIcon=\"team\">\n            <ul>\n              <li nz-menu-item>Team 1</li>\n              <li nz-menu-item>Team 2</li>\n            </ul>\n          </li>\n          <li nz-menu-item>\n            <nz-icon nzType=\"file\" />\n            <span>File</span>\n          </li>\n        </ul>\n      </nz-sider>\n      <nz-layout>\n        <nz-header />\n        <nz-content>\n          <nz-breadcrumb>\n            <nz-breadcrumb-item>User</nz-breadcrumb-item>\n            <nz-breadcrumb-item>Bill</nz-breadcrumb-item>\n          </nz-breadcrumb>\n          <div class=\"inner-content\">Bill is a cat.</div>\n        </nz-content>\n        <nz-footer>Ant Design ©{{ date.getFullYear() }} Implement By Angular</nz-footer>\n      </nz-layout>\n    </nz-layout>\n  `,\n  styles: `\n    .logo {\n      height: 32px;\n      margin: 16px;\n      background: rgba(255, 255, 255, 0.3);\n    }\n\n    nz-header {\n      background: #fff;\n      padding: 0;\n    }\n\n    nz-content {\n      margin: 0 16px;\n    }\n\n    nz-breadcrumb {\n      margin: 16px 0;\n    }\n\n    .inner-content {\n      padding: 24px;\n      background: #fff;\n      min-height: 360px;\n      border-radius: 8px;\n    }\n\n    nz-footer {\n      text-align: center;\n    }\n\n    :host > nz-layout {\n      min-height: 100vh;\n    }\n  `\n})\nexport class NzDemoLayoutSideComponent {\n  protected readonly date = new Date();\n}\n"
  },
  {
    "path": "components/layout/demo/top-side-2.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 顶部-侧边布局-通栏\n  en-US: Header Sider 2\n---\n\n## zh-CN\n\n同样拥有顶部导航及侧边栏，区别是两边未留边距，多用于应用型的网站。\n\n## en-US\n\nBoth the top navigation and the sidebar, commonly used in application site.\n"
  },
  {
    "path": "components/layout/demo/top-side-2.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzLayoutModule } from 'ng-zorro-antd/layout';\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\n\n@Component({\n  selector: 'nz-demo-layout-top-side-2',\n  imports: [NzBreadCrumbModule, NzIconModule, NzMenuModule, NzLayoutModule],\n  template: `\n    <nz-layout>\n      <nz-header>\n        <div class=\"logo\"></div>\n        <ul nz-menu nzTheme=\"dark\" nzMode=\"horizontal\" class=\"header-menu\">\n          <li nz-menu-item nzSelected>nav 1</li>\n          <li nz-menu-item>nav 2</li>\n          <li nz-menu-item>nav 3</li>\n        </ul>\n      </nz-header>\n      <nz-layout>\n        <nz-sider nzWidth=\"200px\" nzTheme=\"light\">\n          <ul nz-menu nzMode=\"inline\" class=\"sider-menu\">\n            <li nz-submenu nzOpen nzIcon=\"user\" nzTitle=\"subnav 1\">\n              <ul>\n                <li nz-menu-item nzSelected>option1</li>\n                <li nz-menu-item>option2</li>\n                <li nz-menu-item>option3</li>\n                <li nz-menu-item>option4</li>\n              </ul>\n            </li>\n            <li nz-submenu nzTitle=\"subnav 2\" nzIcon=\"laptop\">\n              <ul>\n                <li nz-menu-item>option5</li>\n                <li nz-menu-item>option6</li>\n                <li nz-menu-item>option7</li>\n                <li nz-menu-item>option8</li>\n              </ul>\n            </li>\n            <li nz-submenu nzTitle=\"subnav 3\" nzIcon=\"notification\">\n              <ul>\n                <li nz-menu-item>option9</li>\n                <li nz-menu-item>option10</li>\n                <li nz-menu-item>option11</li>\n                <li nz-menu-item>option12</li>\n              </ul>\n            </li>\n          </ul>\n        </nz-sider>\n        <nz-layout class=\"inner-layout\">\n          <nz-breadcrumb>\n            <nz-breadcrumb-item>Home</nz-breadcrumb-item>\n            <nz-breadcrumb-item>List</nz-breadcrumb-item>\n            <nz-breadcrumb-item>App</nz-breadcrumb-item>\n          </nz-breadcrumb>\n          <nz-content>Content</nz-content>\n        </nz-layout>\n      </nz-layout>\n    </nz-layout>\n  `,\n  styles: `\n    .logo {\n      width: 120px;\n      height: 31px;\n      background: rgba(255, 255, 255, 0.2);\n      margin: 16px 30px 16px 0;\n      float: left;\n    }\n\n    .header-menu {\n      line-height: 64px;\n    }\n\n    .sider-menu {\n      height: 100%;\n      border-right: 0;\n    }\n\n    .inner-layout {\n      padding: 0 24px 24px;\n    }\n\n    nz-breadcrumb {\n      margin: 16px 0;\n    }\n\n    nz-content {\n      background: #fff;\n      padding: 24px;\n      min-height: 280px;\n    }\n  `\n})\nexport class NzDemoLayoutTopSide2Component {}\n"
  },
  {
    "path": "components/layout/demo/top-side.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 顶部-侧边布局\n  en-US: Header-Sider\n---\n\n## zh-CN\n\n拥有顶部导航及侧边栏的页面，多用于展示类网站。\n\n## en-US\n\nBoth the top navigation and the sidebar, commonly used in documentation site.\n"
  },
  {
    "path": "components/layout/demo/top-side.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzLayoutModule } from 'ng-zorro-antd/layout';\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\n\n@Component({\n  selector: 'nz-demo-layout-top-side',\n  imports: [NzBreadCrumbModule, NzIconModule, NzMenuModule, NzLayoutModule],\n  template: `\n    <nz-layout>\n      <nz-header>\n        <div class=\"logo\"></div>\n        <ul nz-menu nzTheme=\"dark\" nzMode=\"horizontal\" class=\"header-menu\">\n          <li nz-menu-item>nav 1</li>\n          <li nz-menu-item nzSelected>nav 2</li>\n          <li nz-menu-item>nav 3</li>\n        </ul>\n      </nz-header>\n      <nz-content class=\"outer-content\">\n        <nz-breadcrumb>\n          <nz-breadcrumb-item>Home</nz-breadcrumb-item>\n          <nz-breadcrumb-item>List</nz-breadcrumb-item>\n          <nz-breadcrumb-item>App</nz-breadcrumb-item>\n        </nz-breadcrumb>\n        <nz-layout class=\"inner-layout\">\n          <nz-sider nzWidth=\"200px\" nzTheme=\"light\">\n            <ul nz-menu nzMode=\"inline\" class=\"sider-menu\">\n              <li nz-submenu nzOpen nzTitle=\"subnav 1\" nzIcon=\"user\">\n                <ul>\n                  <li nz-menu-item nzSelected>option1</li>\n                  <li nz-menu-item>option2</li>\n                  <li nz-menu-item>option3</li>\n                  <li nz-menu-item>option4</li>\n                </ul>\n              </li>\n              <li nz-submenu nzTitle=\"subnav 2\" nzIcon=\"laptop\">\n                <ul>\n                  <li nz-menu-item>option5</li>\n                  <li nz-menu-item>option6</li>\n                  <li nz-menu-item>option7</li>\n                  <li nz-menu-item>option8</li>\n                </ul>\n              </li>\n              <li nz-submenu nzTitle=\"subnav 3\" nzIcon=\"notification\">\n                <ul>\n                  <li nz-menu-item>option9</li>\n                  <li nz-menu-item>option10</li>\n                  <li nz-menu-item>option11</li>\n                  <li nz-menu-item>option12</li>\n                </ul>\n              </li>\n            </ul>\n          </nz-sider>\n          <nz-content class=\"inner-content\">Content</nz-content>\n        </nz-layout>\n        <nz-footer>Ant Design ©{{ date.getFullYear() }} Implement By Angular</nz-footer>\n      </nz-content>\n    </nz-layout>\n  `,\n  styles: `\n    .logo {\n      width: 120px;\n      height: 31px;\n      background: rgba(255, 255, 255, 0.2);\n      margin: 16px 28px 16px 0;\n      float: left;\n    }\n\n    .header-menu {\n      line-height: 64px;\n    }\n\n    .outer-content {\n      padding: 0 50px;\n    }\n\n    nz-breadcrumb {\n      margin: 16px 0;\n    }\n\n    .inner-layout {\n      padding: 24px 0;\n      background: #fff;\n    }\n\n    .sider-menu {\n      height: 100%;\n    }\n\n    .inner-content {\n      padding: 0 24px;\n      min-height: 280px;\n    }\n\n    nz-footer {\n      text-align: center;\n    }\n  `\n})\nexport class NzDemoLayoutTopSideComponent {\n  protected readonly date = new Date();\n}\n"
  },
  {
    "path": "components/layout/demo/top.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 上中下布局\n  en-US: Header-Content-Footer\n---\n\n## zh-CN\n\n最基本的『上-中-下』布局。\n\n一般主导航放置于页面的顶端，从左自右依次为：logo、一级导航项、辅助菜单（用户、设置、通知等）。通常将内容放在固定尺寸（例如：1200px）内，整个页面排版稳定，不受用户终端显示器影响；上下级的结构符合用户上下浏览的习惯，也是较为经典的网站导航模式。页面上下切分的方式提高了主工作区域的信息展示效率，但在纵向空间上会有一些牺牲。此外，由于导航栏水平空间的限制，不适合那些一级导航项很多的信息结构。\n\n## en-US\n\nThe most basic \"header-content-footer\" layout.\n\nGenerally, the mainnav is placed at the top of the page, and includes the logo, the first level navigation, and the secondary menu (users, settings, notifications) from left to right in it.\nWe always put contents in a fixed size navigation (eg: `1200px`), the layout of the whole page is stable, it's not affected by viewing area.\n\nTop-bottom structure is conform with the top-bottom viewing habit, it's a classical navigation pattern of websites. This pattern demonstrates efficiency in the main workarea, while using some vertical space. And because the horizontal space of the navigation is limited, this pattern is not suitable for cases when the first level navigation contains many elements or links\n"
  },
  {
    "path": "components/layout/demo/top.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzLayoutModule } from 'ng-zorro-antd/layout';\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\n\n@Component({\n  selector: 'nz-demo-layout-top',\n  imports: [NzBreadCrumbModule, NzIconModule, NzMenuModule, NzLayoutModule],\n  template: `\n    <nz-layout>\n      <nz-header>\n        <div class=\"logo\"></div>\n        <ul nz-menu nzTheme=\"dark\" nzMode=\"horizontal\">\n          <li nz-menu-item>nav 1</li>\n          <li nz-menu-item>nav 2</li>\n          <li nz-menu-item>nav 3</li>\n        </ul>\n      </nz-header>\n      <nz-content>\n        <nz-breadcrumb>\n          <nz-breadcrumb-item>Home</nz-breadcrumb-item>\n          <nz-breadcrumb-item>List</nz-breadcrumb-item>\n          <nz-breadcrumb-item>App</nz-breadcrumb-item>\n        </nz-breadcrumb>\n        <div class=\"inner-content\">Content</div>\n      </nz-content>\n      <nz-footer>Ant Design ©{{ date.getFullYear() }} Implement By Angular</nz-footer>\n    </nz-layout>\n  `,\n  styles: `\n    .logo {\n      width: 120px;\n      height: 31px;\n      background: rgba(255, 255, 255, 0.2);\n      margin: 16px 24px 16px 0;\n      float: left;\n    }\n\n    [nz-menu] {\n      line-height: 64px;\n    }\n\n    nz-breadcrumb {\n      margin: 16px 0;\n    }\n\n    nz-content {\n      padding: 0 50px;\n    }\n\n    nz-footer {\n      text-align: center;\n    }\n\n    .inner-content {\n      background: #fff;\n      padding: 24px;\n      min-height: 280px;\n    }\n  `\n})\nexport class NzDemoLayoutTopComponent {\n  protected readonly date = new Date();\n}\n"
  },
  {
    "path": "components/layout/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Layout\ncols: 1\ntitle: Layout\ncover: 'https://gw.alipayobjects.com/zos/alicdn/hzEndUVEx/Layout.svg'\ndescription: Handling the overall layout of a page.\n---\n\n## Specification\n\n### Size\n\nThe first level navigation is inclined left near a logo, and the secondary menu is inclined right.\n\n- Top Navigation (almost systems): the height of the first level navigation `64px`, the second level navigation `48px`.\n- Top Navigation(contents page): the height of the first level navigation `80px`, the second level navigation `56px`.\n- Calculation formula of a top navigation: `48+8n`.\n- Calculation formula of an aside navigation: `200+8n`.\n\n### Interaction rules\n\n- The first level navigation and the last level navigation should be distinguishable by visualization;\n- The current item should have the highest priority of visualization;\n- When the current navigation item is collapsed, the style of the current navigation item will be applied to its parent level;\n- The left side navigation bar has support for both the accordion and expanding styles, you can choose the one that fits your case best.\n\n## Visualization rules\n\nStyle of a navigation should conform to its level.\n\n- **Emphasis by colorblock**\n\n  When background color is a deep color, you can use this pattern for the parent level navigation item of current page.\n\n- **The highlight match stick**\n\n  When background color is a light color, you can use this pattern for the current page navigation item, we recommend using it for the last item of the navigation path.\n\n- **Highlighted font**\n\n  From the visualization aspect, highlighted font is stronger than colorblock, this pattern is often used for the parent level of the current item.\n\n- **Enlarge the size of the font**\n\n  `12px`、`14px` is a standard font size of navigations，`14px` is used for the first and the second level of the navigation. You can choose an appropriate font size in terms of the level of your navigation.\n\n## Component Overview\n\n- `nz-layout`: The layout wrapper, in which `nz-header` `nz-sider` `nz-content` `nz-footer` or `nz-layout` itself can be nested, and can be placed in any parent container.\n- `nz-header`: The top layout with default style, in which any element can be nested, and must be placed in `nz-layout`.\n- `nz-sider`: The sidebar with default style and basic functions, in which any element can be nested, and must be placed in `nz-layout`.\n- `nz-content`: The content layout with default style, in which any element can be nested, and must be placed in `nz-layout`.\n- `nz-footer`: The bottom layout with default style, in which any element can be nested, and must be placed in `nz-layout`.\n\n> Based on `flex layout`, please pay attention to the [compatibility](http://caniuse.com/#search=flex).\n\n## API\n\n```html\n<nz-layout>\n  <nz-header>header</nz-header>\n  <nz-layout>\n    <nz-sider>left sidebar</nz-sider>\n    <nz-content>main content</nz-content>\n    <nz-sider>right sidebar</nz-sider>\n  </nz-layout>\n  <nz-footer>footer</nz-footer>\n</nz-layout>\n```\n\n### nz-sider\n\nThe sidebar.\n\n| Property              | Description                                                                       | Type                                            | Default  |\n| --------------------- | --------------------------------------------------------------------------------- | ----------------------------------------------- | -------- |\n| `[nzBreakpoint]`      | breakpoints of the responsive layout                                              | `'xs' \\| 'sm' \\| 'md' \\| 'lg' \\| 'xl' \\| 'xxl'` | -        |\n| `[nzCollapsedWidth]`  | width of the collapsed sidebar, by setting to `0` a special `trigger` will appear | `number`                                        | `64`     |\n| `[nzCollapsible]`     | whether can be collapsed                                                          | `boolean`                                       | `false`  |\n| `[nzCollapsed]`       | the collapsed status can be double binding                                        | `boolean`                                       | `false`  |\n| `[nzReverseArrow]`    | reverse direction of arrow, for a sider that expands from the right               | `boolean`                                       | `false`  |\n| `[nzTrigger]`         | specify the customized `trigger`, set to `null` to hide the `trigger`             | `string \\| TemplateRef<void>`                   | -        |\n| `[nzZeroTrigger]`     | specify the customized trigger when `nzCollapsedWidth` setting to `0`             | `TemplateRef<void>`                             | -        |\n| `[nzWidth]`           | width of the sidebar                                                              | `number \\| string`                              | `200`    |\n| `[nzTheme]`           | color theme of the sidebar                                                        | `'light' \\| 'dark'`                             | `'dark'` |\n| `(nzCollapsedChange)` | the callback function                                                             | `EventEmitter<boolean>`                         | -        |\n\n#### breakpoint width\n\n```js\n{\n  xs: '575px',\n  sm: '576px',\n  md: '768px',\n  lg: '992px',\n  xl: '1200px',\n  xxl: '1600px'\n}\n```\n"
  },
  {
    "path": "components/layout/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 布局\ntype: 布局\ncols: 1\ntitle: Layout\ncover: 'https://gw.alipayobjects.com/zos/alicdn/hzEndUVEx/Layout.svg'\ndescription: 协助进行页面级整体布局。\n---\n\n## 设计规则\n\n### 尺寸\n\n一级导航项偏左靠近 logo 放置，辅助菜单偏右放置。\n\n- 顶部导航（大部分系统）：一级导航高度 `64px`，二级导航 `48px`。\n- 顶部导航（展示类页面）：一级导航高度 `80px`，二级导航 `56px`。\n- 顶部导航高度的范围计算公式为：`48+8n`。\n- 侧边导航宽度的范围计算公式：`200+8n`。\n\n### 交互\n\n- 一级导航和末级的导航需要在可视化的层面被强调出来；\n- 当前项应该在呈现上优先级最高；\n- 当导航收起的时候，当前项的样式自动赋予给它的上一个层级；\n- 左侧导航栏的收放交互同时支持手风琴和全展开的样式，根据业务的要求进行适当的选择。\n\n### 视觉\n\n导航样式上需要根据信息层级合理的选择样式：\n\n- **大色块强调**\n\n  建议用于底色为深色系时，当前页面父级的导航项。\n\n- **高亮火柴棍**\n\n  当导航栏底色为浅色系时使用，可用于当前页面对应导航项，建议尽量在导航路径的最终项使用。\n\n- **字体高亮变色**\n\n  从可视化层面，字体高亮的视觉强化力度低于大色块，通常在当前项的上一级使用。\n\n- **字体放大**\n\n  `12px`、`14px` 是导航的标准字号，14 号字体用在一、二级导航中。字号可以考虑导航项的等级做相应选择。\n\n## 组件概述\n\n- `nz-layout`：布局容器，其下可嵌套 `nz-header` `nz-sider` `nz-content` `nz-footer` 或 `nz-layout` 本身，可以放在任何父容器中。\n- `nz-header`：顶部布局，自带默认样式，其下可嵌套任何元素，只能放在 `nz-layout` 中。\n- `nz-sider`：侧边栏，自带默认样式及基本功能，其下可嵌套任何元素，只能放在 `nz-layout` 中。\n- `nz-content`：内容部分，自带默认样式，其下可嵌套任何元素，只能放在 `nz-layout` 中。\n- `nz-footer`：底部布局，自带默认样式，其下可嵌套任何元素，只能放在 `nz-layout` 中。\n\n> 注意：采用 flex 布局实现，请注意[浏览器兼容性](http://caniuse.com/#search=flex)问题。\n\n## API\n\n```html\n<nz-layout>\n  <nz-header>header</nz-header>\n  <nz-layout>\n    <nz-sider>left sidebar</nz-sider>\n    <nz-content>main content</nz-content>\n    <nz-sider>right sidebar</nz-sider>\n  </nz-layout>\n  <nz-footer>footer</nz-footer>\n</nz-layout>\n```\n\n### nz-sider\n\n侧边栏。\n\n| 参数                  | 说明                                                | 类型                                            | 默认值   |\n| --------------------- | --------------------------------------------------- | ----------------------------------------------- | -------- |\n| `[nzBreakpoint]`      | 触发响应式布局的断点                                | `'xs' \\| 'sm' \\| 'md' \\| 'lg' \\| 'xl' \\| 'xxl'` | -        |\n| `[nzCollapsedWidth]`  | 收缩宽度，设置为 0 会出现特殊 `trigger`             | `number`                                        | `64`     |\n| `[nzCollapsible]`     | 是否可收起                                          | `boolean`                                       | `false`  |\n| `[nzCollapsed]`       | 当前收起状态，可双向绑定                            | `boolean`                                       | `false`  |\n| `[nzReverseArrow]`    | 翻转折叠提示箭头的方向，当 `Sider` 在右边时可以使用 | `boolean`                                       | `false`  |\n| `[nzTrigger]`         | 自定义 `trigger`，设置为 `null` 时隐藏 `trigger`    | `TemplateRef<void>`                             | -        |\n| `[nzZeroTrigger]`     | 自定义 `nzCollapsedWidth` 为 0 时的 特殊`trigger`   | `TemplateRef<void>`                             | -        |\n| `[nzWidth]`           | 宽度                                                | `number \\| string`                              | `200`    |\n| `[nzTheme]`           | 主题颜色                                            | `'light' \\| 'dark'`                             | `'dark'` |\n| `(nzCollapsedChange)` | 展开-收起时的回调函数                               | `EventEmitter<boolean>`                         | -        |\n\n#### breakpoint width\n\n```js\n{\n  xs: '480px',\n  sm: '768px',\n  md: '992px',\n  lg: '1200px',\n  xl: '1600px',\n  xxl: '1600px'\n}\n```\n"
  },
  {
    "path": "components/layout/footer.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';\n\n@Component({\n  selector: 'nz-footer',\n  exportAs: 'nzFooter',\n  template: `<ng-content />`,\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    class: 'ant-layout-footer'\n  }\n})\nexport class NzFooterComponent {}\n"
  },
  {
    "path": "components/layout/header.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';\n\n@Component({\n  selector: 'nz-header',\n  exportAs: 'nzHeader',\n  template: `<ng-content />`,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  host: {\n    class: 'ant-layout-header'\n  }\n})\nexport class NzHeaderComponent {}\n"
  },
  {
    "path": "components/layout/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/layout/layout.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  ContentChildren,\n  DestroyRef,\n  inject,\n  OnInit,\n  QueryList,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { NzSiderComponent } from './sider.component';\n\n@Component({\n  selector: 'nz-layout',\n  exportAs: 'nzLayout',\n  template: `<ng-content />`,\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    class: 'ant-layout',\n    '[class.ant-layout-rtl]': `dir === 'rtl'`,\n    '[class.ant-layout-has-sider]': 'listOfNzSiderComponent.length > 0'\n  }\n})\nexport class NzLayoutComponent implements OnInit {\n  private destroyRef = inject(DestroyRef);\n  private directionality = inject(Directionality);\n  @ContentChildren(NzSiderComponent) listOfNzSiderComponent!: QueryList<NzSiderComponent>;\n\n  dir: Direction = 'ltr';\n\n  ngOnInit(): void {\n    this.dir = this.directionality.value;\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n      this.dir = direction;\n    });\n  }\n}\n"
  },
  {
    "path": "components/layout/layout.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzContentComponent } from './content.component';\nimport { NzFooterComponent } from './footer.component';\nimport { NzHeaderComponent } from './header.component';\nimport { NzLayoutComponent } from './layout.component';\nimport { NzSiderTriggerComponent } from './sider-trigger.component';\nimport { NzSiderComponent } from './sider.component';\n\n@NgModule({\n  imports: [\n    NzLayoutComponent,\n    NzHeaderComponent,\n    NzContentComponent,\n    NzFooterComponent,\n    NzSiderComponent,\n    NzSiderTriggerComponent\n  ],\n  exports: [NzLayoutComponent, NzHeaderComponent, NzContentComponent, NzFooterComponent, NzSiderComponent]\n})\nexport class NzLayoutModule {}\n"
  },
  {
    "path": "components/layout/layout.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport { Component, DebugElement, provideZoneChangeDetection, TemplateRef, ViewChild } from '@angular/core';\nimport { ComponentFixture, discardPeriodicTasks, fakeAsync, TestBed, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzContentComponent } from './content.component';\nimport { NzFooterComponent } from './footer.component';\nimport { NzHeaderComponent } from './header.component';\nimport { NzLayoutComponent } from './layout.component';\nimport { NzLayoutModule } from './layout.module';\nimport { NzSiderComponent } from './sider.component';\n\ndeclare const viewport: NzSafeAny;\n\ndescribe('nz-layout', () => {\n  describe('basic', () => {\n    let fixture: ComponentFixture<NzLayoutBasicComponent>;\n    let headers: DebugElement[];\n    let contents: DebugElement[];\n    let footers: DebugElement[];\n    let siders: DebugElement[];\n    let layouts: DebugElement[];\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzLayoutBasicComponent);\n      headers = fixture.debugElement.queryAll(By.directive(NzHeaderComponent));\n      contents = fixture.debugElement.queryAll(By.directive(NzContentComponent));\n      footers = fixture.debugElement.queryAll(By.directive(NzFooterComponent));\n      siders = fixture.debugElement.queryAll(By.directive(NzSiderComponent));\n      layouts = fixture.debugElement.queryAll(By.directive(NzLayoutComponent));\n    });\n\n    it('should have correct class', () => {\n      fixture.detectChanges();\n      expect(headers.every(header => header.nativeElement.classList.contains('ant-layout-header'))).toBe(true);\n      expect(layouts.every(layout => layout.nativeElement.classList.contains('ant-layout'))).toBe(true);\n      expect(contents.every(content => content.nativeElement.classList.contains('ant-layout-content'))).toBe(true);\n      expect(footers.every(footer => footer.nativeElement.classList.contains('ant-layout-footer'))).toBe(true);\n      expect(siders.every(sider => sider.nativeElement.classList.contains('ant-layout-sider'))).toBe(true);\n      expect(\n        siders.every(\n          sider =>\n            sider.nativeElement.style.cssText === 'flex: 0 0 200px; max-width: 200px; min-width: 200px; width: 200px;'\n        )\n      ).toBe(true);\n      expect(layouts[2].nativeElement.classList.contains('ant-layout-has-sider')).toBe(true);\n      expect(layouts[4].nativeElement.classList.contains('ant-layout-has-sider')).toBe(true);\n      expect(layouts[5].nativeElement.classList.contains('ant-layout-has-sider')).toBe(true);\n    });\n  });\n\n  describe('side', () => {\n    let fixture: ComponentFixture<NzLayoutSideComponent>;\n    let testComponent: NzLayoutSideComponent;\n    let sider: DebugElement;\n    let trigger: DebugElement;\n\n    beforeEach(() => {\n      // todo: use zoneless\n      TestBed.configureTestingModule({\n        providers: [provideZoneChangeDetection()]\n      });\n      fixture = TestBed.createComponent(NzLayoutSideComponent);\n      testComponent = fixture.componentInstance;\n      sider = fixture.debugElement.query(By.directive(NzSiderComponent));\n    });\n\n    it('should nzCollapsed work', () => {\n      testComponent.isCollapsed = false;\n      fixture.detectChanges();\n      trigger = fixture.debugElement.query(By.css('.ant-layout-sider-trigger'));\n      expect(\n        sider.nativeElement.style.cssText === 'flex: 0 0 200px; max-width: 200px; min-width: 200px; width: 200px;'\n      ).toBe(true);\n      expect(trigger.nativeElement.style.cssText === 'width: 200px;').toBe(true);\n      trigger.nativeElement.click();\n      fixture.detectChanges();\n      expect(testComponent.isCollapsed).toBe(true);\n      expect(\n        sider.nativeElement.style.cssText === 'flex: 0 0 80px; max-width: 80px; min-width: 80px; width: 80px;'\n      ).toBe(true);\n      expect(trigger.nativeElement.style.cssText === 'width: 80px;').toBe(true);\n      trigger.nativeElement.click();\n      fixture.detectChanges();\n      expect(testComponent.isCollapsed).toBe(false);\n      expect(\n        sider.nativeElement.style.cssText === 'flex: 0 0 200px; max-width: 200px; min-width: 200px; width: 200px;'\n      ).toBe(true);\n      expect(trigger.nativeElement.style.cssText === 'width: 200px;').toBe(true);\n      testComponent.isCollapsed = true;\n      fixture.detectChanges();\n      expect(\n        sider.nativeElement.style.cssText === 'flex: 0 0 80px; max-width: 80px; min-width: 80px; width: 80px;'\n      ).toBe(true);\n      expect(trigger.nativeElement.style.cssText === 'width: 80px;').toBe(true);\n      testComponent.isCollapsed = false;\n      fixture.detectChanges();\n      expect(\n        sider.nativeElement.style.cssText === 'flex: 0 0 200px; max-width: 200px; min-width: 200px; width: 200px;'\n      ).toBe(true);\n      expect(trigger.nativeElement.style.cssText === 'width: 200px;').toBe(true);\n    });\n\n    it('should nzWidth work', () => {\n      testComponent.isCollapsed = false;\n      testComponent.width = 300;\n      fixture.detectChanges();\n      trigger = fixture.debugElement.query(By.css('.ant-layout-sider-trigger'));\n      expect(\n        sider.nativeElement.style.cssText === 'flex: 0 0 300px; max-width: 300px; min-width: 300px; width: 300px;'\n      ).toBe(true);\n      expect(trigger.nativeElement.style.cssText === 'width: 300px;').toBe(true);\n      trigger.nativeElement.click();\n      fixture.detectChanges();\n      expect(testComponent.isCollapsed).toBe(true);\n      expect(\n        sider.nativeElement.style.cssText === 'flex: 0 0 80px; max-width: 80px; min-width: 80px; width: 80px;'\n      ).toBe(true);\n      expect(trigger.nativeElement.style.cssText === 'width: 80px;').toBe(true);\n      trigger.nativeElement.click();\n      fixture.detectChanges();\n      expect(testComponent.isCollapsed).toBe(false);\n      expect(\n        sider.nativeElement.style.cssText === 'flex: 0 0 300px; max-width: 300px; min-width: 300px; width: 300px;'\n      ).toBe(true);\n      expect(trigger.nativeElement.style.cssText === 'width: 300px;').toBe(true);\n      testComponent.isCollapsed = true;\n      fixture.detectChanges();\n      expect(\n        sider.nativeElement.style.cssText === 'flex: 0 0 80px; max-width: 80px; min-width: 80px; width: 80px;'\n      ).toBe(true);\n      expect(trigger.nativeElement.style.cssText === 'width: 80px;').toBe(true);\n      testComponent.isCollapsed = false;\n      fixture.detectChanges();\n      expect(\n        sider.nativeElement.style.cssText === 'flex: 0 0 300px; max-width: 300px; min-width: 300px; width: 300px;'\n      ).toBe(true);\n      expect(trigger.nativeElement.style.cssText === 'width: 300px;').toBe(true);\n    });\n\n    it('should nzReverseArrow work', () => {\n      testComponent.isCollapsed = false;\n      fixture.detectChanges();\n      trigger = fixture.debugElement.query(By.css('.ant-layout-sider-trigger'));\n      expect(trigger.nativeElement.firstElementChild!.classList.contains('anticon-left')).toBe(true);\n      testComponent.isCollapsed = true;\n      fixture.detectChanges();\n      expect(trigger.nativeElement.firstElementChild!.classList.contains('anticon-right')).toBe(true);\n      testComponent.isReverseArrow = true;\n      testComponent.isCollapsed = false;\n      fixture.detectChanges();\n      expect(trigger.nativeElement.firstElementChild!.classList.contains('anticon-right')).toBe(true);\n      testComponent.isCollapsed = true;\n      fixture.detectChanges();\n      expect(trigger.nativeElement.firstElementChild!.classList.contains('anticon-left')).toBe(true);\n    });\n  });\n\n  describe('custom-trigger', () => {\n    let fixture: ComponentFixture<NzLayoutCustomTriggerComponent>;\n    let testComponent: NzLayoutCustomTriggerComponent;\n\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        providers: [provideNzIconsTesting()]\n      });\n      fixture = TestBed.createComponent(NzLayoutCustomTriggerComponent);\n      testComponent = fixture.componentInstance;\n    });\n\n    it('should not display trigger', () => {\n      fixture.detectChanges();\n      const trigger = fixture.debugElement.query(By.css('.ant-layout-sider-trigger'));\n      expect(trigger).toBeNull();\n    });\n\n    it('should display trigger', () => {\n      testComponent.changeTrigger();\n      fixture.detectChanges();\n      const trigger = fixture.debugElement.query(By.css('.ant-layout-sider-trigger'));\n      expect(trigger.nativeElement.firstElementChild!.classList.contains('anticon-up')).toBe(true);\n      expect(trigger).not.toBeNull();\n    });\n  });\n\n  describe('responsive', () => {\n    let fixture: ComponentFixture<NzLayoutResponsiveComponent>;\n    let sider: DebugElement;\n\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        providers: [provideNzIconsTesting()]\n      });\n      fixture = TestBed.createComponent(NzLayoutResponsiveComponent);\n      sider = fixture.debugElement.query(By.directive(NzSiderComponent));\n    });\n\n    it('should responsive work', fakeAsync(() => {\n      viewport.set(500);\n      window.dispatchEvent(new Event('resize'));\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n      discardPeriodicTasks();\n      fixture.detectChanges();\n      expect(sider.nativeElement.style.cssText).toBe('flex: 0 0 0px; max-width: 0px; min-width: 0px; width: 0px;');\n      expect(\n        sider.nativeElement\n          .querySelector('.ant-layout-sider-zero-width-trigger')\n          .firstElementChild.getAttribute('nzType')\n      ).toBe('menu-fold');\n      viewport.reset();\n    }));\n  });\n\n  describe('RTL', () => {\n    let fixture: ComponentFixture<NzTestLayoutRtlComponent>;\n    let layouts: DebugElement[];\n\n    beforeEach(() => {\n      // todo: use zoneless\n      TestBed.configureTestingModule({\n        providers: [provideZoneChangeDetection()]\n      });\n      fixture = TestBed.createComponent(NzTestLayoutRtlComponent);\n      layouts = fixture.debugElement.queryAll(By.directive(NzLayoutComponent));\n    });\n\n    it('should className correct on dir change', fakeAsync(() => {\n      fixture.detectChanges();\n      expect(layouts.every(layout => layout.nativeElement.classList.contains('ant-layout-rtl'))).toBe(true);\n\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n\n      expect(layouts.every(layout => layout.nativeElement.classList.contains('ant-layout-rtl'))).toBe(false);\n    }));\n  });\n});\n\n@Component({\n  imports: [NzIconModule, NzLayoutModule],\n  template: `\n    <nz-layout>\n      <nz-sider nzCollapsible [(nzCollapsed)]=\"isCollapsed\" [nzTrigger]=\"triggerTemplate\" />\n      <nz-layout>\n        <nz-header>\n          <span\n            class=\"trigger\"\n            nz-icon\n            [nzType]=\"isCollapsed ? 'menu-unfold' : 'menu-fold'\"\n            (click)=\"isCollapsed = !isCollapsed\"\n          ></span>\n        </nz-header>\n        <nz-content>\n          <div>Bill is a cat.</div>\n        </nz-content>\n        <nz-footer>Ant Design ©2019 Implement By Angular</nz-footer>\n      </nz-layout>\n    </nz-layout>\n    <ng-template #trigger>\n      <nz-icon nzType=\"up\" />\n    </ng-template>\n  `\n})\nexport class NzLayoutCustomTriggerComponent {\n  isCollapsed = false;\n  triggerTemplate: TemplateRef<void> | null = null;\n  @ViewChild('trigger', { static: true }) customTrigger!: TemplateRef<void>;\n\n  /** custom trigger can be TemplateRef **/\n  changeTrigger(): void {\n    this.triggerTemplate = this.customTrigger;\n  }\n}\n\n@Component({\n  imports: [NzLayoutModule],\n  template: `\n    <nz-layout>\n      <nz-sider nzCollapsible [(nzCollapsed)]=\"isCollapsed\" [nzWidth]=\"width\" [nzReverseArrow]=\"isReverseArrow\" />\n      <nz-layout>\n        <nz-header />\n        <nz-content>\n          <div>Bill is a cat.</div>\n        </nz-content>\n        <nz-footer>Ant Design ©2019 Implement By Angular</nz-footer>\n      </nz-layout>\n    </nz-layout>\n  `\n})\nexport class NzLayoutSideComponent {\n  isCollapsed = false;\n  isReverseArrow = false;\n  width: string | number = '200px';\n}\n\n@Component({\n  imports: [NzIconModule, NzLayoutModule],\n  template: `\n    <nz-layout>\n      <nz-sider\n        nzCollapsible\n        [(nzCollapsed)]=\"isCollapsed\"\n        nzBreakpoint=\"lg\"\n        [nzCollapsedWidth]=\"0\"\n        [nzZeroTrigger]=\"zeroTrigger\"\n      />\n      <nz-layout>\n        <nz-header />\n        <nz-content>\n          <div>Content</div>\n        </nz-content>\n        <nz-footer>Ant Design ©2019 Implement By Angular</nz-footer>\n      </nz-layout>\n    </nz-layout>\n    <ng-template #zeroTrigger>\n      <nz-icon nzType=\"menu-fold\" nzTheme=\"outline\" />\n    </ng-template>\n  `\n})\nexport class NzLayoutResponsiveComponent {\n  isCollapsed = false;\n}\n\n@Component({\n  imports: [NzLayoutModule],\n  selector: 'nz-test-layout-basic',\n  template: `\n    <nz-layout>\n      <nz-header>Header</nz-header>\n      <nz-content>Content</nz-content>\n      <nz-footer>Footer</nz-footer>\n    </nz-layout>\n\n    <nz-layout>\n      <nz-header>Header</nz-header>\n      <nz-layout>\n        <nz-sider>Sider</nz-sider>\n        <nz-content>Content</nz-content>\n      </nz-layout>\n      <nz-footer>Footer</nz-footer>\n    </nz-layout>\n\n    <nz-layout>\n      <nz-header>Header</nz-header>\n      <nz-layout>\n        <nz-content>Content</nz-content>\n        <nz-sider>Sider</nz-sider>\n      </nz-layout>\n      <nz-footer>Footer</nz-footer>\n    </nz-layout>\n\n    <nz-layout>\n      <nz-sider>Sider</nz-sider>\n      <nz-layout>\n        <nz-header>Header</nz-header>\n        <nz-content>Content</nz-content>\n        <nz-footer>Footer</nz-footer>\n      </nz-layout>\n    </nz-layout>\n  `\n})\nexport class NzLayoutBasicComponent {}\n\n@Component({\n  imports: [BidiModule, NzLayoutBasicComponent],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-test-layout-basic />\n    </div>\n  `\n})\nexport class NzTestLayoutRtlComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n}\n"
  },
  {
    "path": "components/layout/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/layout/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './content.component';\nexport * from './footer.component';\nexport * from './header.component';\nexport * from './layout.component';\nexport * from './sider.component';\nexport { NzSiderTriggerComponent as ɵNzSiderTriggerComponent } from './sider-trigger.component';\nexport * from './layout.module';\n"
  },
  {
    "path": "components/layout/sider-trigger.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  Input,\n  OnChanges,\n  OnInit,\n  TemplateRef,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { NzBreakpointKey } from 'ng-zorro-antd/core/services';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: '[nz-sider-trigger]',\n  exportAs: 'nzSiderTrigger',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    @if (isZeroTrigger) {\n      <ng-template [ngTemplateOutlet]=\"nzZeroTrigger || defaultZeroTrigger\" />\n    }\n\n    @if (isNormalTrigger) {\n      <ng-template [ngTemplateOutlet]=\"nzTrigger || defaultTrigger\" />\n    }\n    <ng-template #defaultTrigger>\n      @if (nzReverseArrow) {\n        <nz-icon [nzType]=\"nzCollapsed ? 'left' : 'right'\" />\n      } @else {\n        <nz-icon [nzType]=\"nzCollapsed ? 'right' : 'left'\" />\n      }\n    </ng-template>\n    <ng-template #defaultZeroTrigger>\n      <nz-icon nzType=\"bars\" />\n    </ng-template>\n  `,\n  host: {\n    '[class.ant-layout-sider-trigger]': 'isNormalTrigger',\n    '[style.width]': 'isNormalTrigger ? siderWidth : null',\n    '[class.ant-layout-sider-zero-width-trigger]': 'isZeroTrigger',\n    '[class.ant-layout-sider-zero-width-trigger-right]': 'isZeroTrigger && nzReverseArrow',\n    '[class.ant-layout-sider-zero-width-trigger-left]': 'isZeroTrigger && !nzReverseArrow'\n  },\n  imports: [NgTemplateOutlet, NzIconModule]\n})\nexport class NzSiderTriggerComponent implements OnChanges, OnInit {\n  @Input() nzCollapsed = false;\n  @Input() nzReverseArrow = false;\n  @Input() nzZeroTrigger: TemplateRef<void> | null = null;\n  @Input() nzTrigger: TemplateRef<void> | undefined | null = undefined;\n  @Input() matchBreakPoint = false;\n  @Input() nzCollapsedWidth: number | null = null;\n  @Input() siderWidth: string | null = null;\n  @Input() nzBreakpoint: NzBreakpointKey | null = null;\n  isZeroTrigger = false;\n  isNormalTrigger = false;\n  updateTriggerType(): void {\n    this.isZeroTrigger =\n      this.nzCollapsedWidth === 0 && ((this.nzBreakpoint && this.matchBreakPoint) || !this.nzBreakpoint);\n    this.isNormalTrigger = this.nzCollapsedWidth !== 0;\n  }\n  ngOnInit(): void {\n    this.updateTriggerType();\n  }\n  ngOnChanges(): void {\n    this.updateTriggerType();\n  }\n}\n"
  },
  {
    "path": "components/layout/sider.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Platform } from '@angular/cdk/platform';\nimport {\n  AfterContentInit,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ContentChild,\n  DestroyRef,\n  EventEmitter,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  SimpleChanges,\n  TemplateRef,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { NzBreakpointKey, NzBreakpointService, siderResponsiveMap } from 'ng-zorro-antd/core/services';\nimport { inNextTick, toCssPixel } from 'ng-zorro-antd/core/util';\nimport { NzMenuDirective } from 'ng-zorro-antd/menu';\n\nimport { NzSiderTriggerComponent } from './sider-trigger.component';\n\n@Component({\n  selector: 'nz-sider',\n  exportAs: 'nzSider',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    <div class=\"ant-layout-sider-children\">\n      <ng-content />\n    </div>\n    @if (nzCollapsible && nzTrigger !== null) {\n      <div\n        nz-sider-trigger\n        [matchBreakPoint]=\"matchBreakPoint\"\n        [nzCollapsedWidth]=\"nzCollapsedWidth\"\n        [nzCollapsed]=\"nzCollapsed\"\n        [nzBreakpoint]=\"nzBreakpoint\"\n        [nzReverseArrow]=\"nzReverseArrow\"\n        [nzTrigger]=\"nzTrigger\"\n        [nzZeroTrigger]=\"nzZeroTrigger\"\n        [siderWidth]=\"widthSetting\"\n        (click)=\"setCollapsed(!nzCollapsed)\"\n      ></div>\n    }\n  `,\n  host: {\n    class: 'ant-layout-sider',\n    '[class.ant-layout-sider-zero-width]': `nzCollapsed && nzCollapsedWidth === 0`,\n    '[class.ant-layout-sider-light]': `nzTheme === 'light'`,\n    '[class.ant-layout-sider-dark]': `nzTheme === 'dark'`,\n    '[class.ant-layout-sider-collapsed]': `nzCollapsed`,\n    '[class.ant-layout-sider-has-trigger]': `nzCollapsible && nzTrigger !== null`,\n    '[style.flex]': 'flexSetting',\n    '[style.maxWidth]': 'widthSetting',\n    '[style.minWidth]': 'widthSetting',\n    '[style.width]': 'widthSetting'\n  },\n  imports: [NzSiderTriggerComponent]\n})\nexport class NzSiderComponent implements OnInit, OnChanges, AfterContentInit {\n  private destroyRef = inject(DestroyRef);\n  private platform = inject(Platform);\n  private cdr = inject(ChangeDetectorRef);\n  private breakpointService = inject(NzBreakpointService);\n\n  @ContentChild(NzMenuDirective) nzMenuDirective: NzMenuDirective | null = null;\n  @Output() readonly nzCollapsedChange = new EventEmitter();\n  @Input() nzWidth: string | number = 200;\n  @Input() nzTheme: 'light' | 'dark' = 'dark';\n  @Input() nzCollapsedWidth = 80;\n  @Input() nzBreakpoint: NzBreakpointKey | null = null;\n  @Input() nzZeroTrigger: TemplateRef<void> | null = null;\n  @Input() nzTrigger: TemplateRef<void> | undefined | null = undefined;\n  @Input({ transform: booleanAttribute }) nzReverseArrow = false;\n  @Input({ transform: booleanAttribute }) nzCollapsible = false;\n  @Input({ transform: booleanAttribute }) nzCollapsed = false;\n  matchBreakPoint = false;\n  flexSetting: string | null = null;\n  widthSetting: string | null = null;\n\n  updateStyleMap(): void {\n    this.widthSetting = this.nzCollapsed ? `${this.nzCollapsedWidth}px` : toCssPixel(this.nzWidth);\n    this.flexSetting = `0 0 ${this.widthSetting}`;\n    this.cdr.markForCheck();\n  }\n\n  updateMenuInlineCollapsed(): void {\n    if (this.nzMenuDirective && this.nzMenuDirective.nzMode === 'inline' && this.nzCollapsedWidth !== 0) {\n      this.nzMenuDirective.setInlineCollapsed(this.nzCollapsed);\n    }\n  }\n\n  setCollapsed(collapsed: boolean): void {\n    if (collapsed !== this.nzCollapsed) {\n      this.nzCollapsed = collapsed;\n      this.nzCollapsedChange.emit(collapsed);\n      this.updateMenuInlineCollapsed();\n      this.updateStyleMap();\n      this.cdr.markForCheck();\n    }\n  }\n\n  ngOnInit(): void {\n    this.updateStyleMap();\n\n    if (this.platform.isBrowser) {\n      this.breakpointService\n        .subscribe(siderResponsiveMap, true)\n        .pipe(takeUntilDestroyed(this.destroyRef))\n        .subscribe(map => {\n          const breakpoint = this.nzBreakpoint;\n          if (breakpoint) {\n            inNextTick().subscribe(() => {\n              this.matchBreakPoint = !map[breakpoint];\n              this.setCollapsed(this.matchBreakPoint);\n              this.cdr.markForCheck();\n            });\n          }\n        });\n    }\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzCollapsed, nzCollapsedWidth, nzWidth } = changes;\n    if (nzCollapsed || nzCollapsedWidth || nzWidth) {\n      this.updateStyleMap();\n    }\n    if (nzCollapsed) {\n      this.updateMenuInlineCollapsed();\n    }\n  }\n\n  ngAfterContentInit(): void {\n    this.updateMenuInlineCollapsed();\n  }\n}\n"
  },
  {
    "path": "components/layout/style/entry.less",
    "content": "@import './index.less';\n@import './patch.less';\n"
  },
  {
    "path": "components/layout/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@layout-prefix-cls: ~'@{ant-prefix}-layout';\n@layout-menu-prefix-cls: ~'@{ant-prefix}-menu';\n\n.@{layout-prefix-cls} {\n  display: flex;\n  flex: auto;\n  flex-direction: column;\n\n  /* fix firefox can't set height smaller than content on flex item */\n  min-height: 0;\n  background: @layout-body-background;\n\n  &,\n  * {\n    box-sizing: border-box;\n  }\n\n  &&-has-sider {\n    flex-direction: row;\n\n    > .@{layout-prefix-cls},\n    > .@{layout-prefix-cls}-content {\n      width: 0; // https://segmentfault.com/a/1190000019498300\n    }\n  }\n\n  &-header,\n  &-footer {\n    flex: 0 0 auto;\n  }\n\n  &-header {\n    height: @layout-header-height;\n    padding: @layout-header-padding;\n    color: @layout-header-color;\n    line-height: @layout-header-height;\n    background: @layout-header-background;\n  }\n\n  &-footer {\n    padding: @layout-footer-padding;\n    color: @text-color;\n    font-size: @font-size-base;\n    background: @layout-footer-background;\n  }\n\n  &-content {\n    flex: auto;\n\n    /* fix firefox can't set height smaller than content on flex item */\n    min-height: 0;\n  }\n\n  &-sider {\n    position: relative;\n\n    /* fix firefox can't set width smaller than content on flex item */\n    min-width: 0;\n    background: @layout-sider-background;\n    transition: all 0.2s;\n\n    &-children {\n      height: 100%;\n      margin-top: -0.1px;\n      // Hack for fixing margin collaspe bug\n      // https://github.com/ant-design/ant-design/issues/7967\n      // solution from https://stackoverflow.com/a/33132624/3040605\n      padding-top: 0.1px;\n\n      .@{layout-menu-prefix-cls}.@{layout-menu-prefix-cls}-inline-collapsed {\n        width: auto;\n      }\n    }\n\n    &-has-trigger {\n      padding-bottom: @layout-trigger-height;\n    }\n\n    &-right {\n      order: 1;\n    }\n\n    &-trigger {\n      position: fixed;\n      bottom: 0;\n      z-index: 1;\n      height: @layout-trigger-height;\n      color: @layout-trigger-color;\n      line-height: @layout-trigger-height;\n      text-align: center;\n      background: @layout-trigger-background;\n      cursor: pointer;\n      transition: all 0.2s;\n    }\n\n    &-zero-width {\n      > * {\n        overflow: hidden;\n      }\n\n      &-trigger {\n        position: absolute;\n        top: @layout-header-height;\n        right: -@layout-zero-trigger-width;\n        z-index: 1;\n        width: @layout-zero-trigger-width;\n        height: @layout-zero-trigger-height;\n        color: @layout-trigger-color;\n        font-size: (@layout-zero-trigger-width / 2);\n        line-height: @layout-zero-trigger-height;\n        text-align: center;\n        background: @layout-sider-background;\n        border-radius: 0 @border-radius-base @border-radius-base 0;\n        cursor: pointer;\n        transition: background 0.3s ease;\n\n        &::after {\n          position: absolute;\n          top: 0;\n          right: 0;\n          bottom: 0;\n          left: 0;\n          background: transparent;\n          transition: all 0.3s;\n          content: '';\n        }\n\n        &:hover::after {\n          background: rgba(255, 255, 255, 0.1);\n        }\n\n        &-right {\n          left: -@layout-zero-trigger-width;\n          border-radius: @border-radius-base 0 0 @border-radius-base;\n        }\n      }\n    }\n  }\n}\n\n@import './light';\n@import './rtl';\n"
  },
  {
    "path": "components/layout/style/light.less",
    "content": ".@{layout-prefix-cls}-sider-light {\n  background: @layout-sider-background-light;\n  .@{layout-prefix-cls}-sider-trigger {\n    color: @layout-trigger-color-light;\n    background: @layout-trigger-background-light;\n  }\n  .@{layout-prefix-cls}-sider-zero-width-trigger {\n    color: @layout-trigger-color-light;\n    background: @layout-trigger-background-light;\n  }\n}\n"
  },
  {
    "path": "components/layout/style/patch.less",
    "content": "nz-content {\n  display: block;\n}\n\nnz-footer {\n  display: block;\n}\n\nnz-header {\n  display: block;\n}\n"
  },
  {
    "path": "components/layout/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@layout-prefix-cls: ~'@{ant-prefix}-layout';\n\n.@{layout-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n}\n"
  },
  {
    "path": "components/list/demo/basic.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 基础列表\n  en-US: Basic list\n---\n\n## zh-CN\n\n基础列表。\n\n## en-US\n\nBasic list.\n"
  },
  {
    "path": "components/list/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzListModule } from 'ng-zorro-antd/list';\n\n@Component({\n  selector: 'nz-demo-list-basic',\n  imports: [NzButtonModule, NzListModule],\n  template: `\n    <div style=\"margin-bottom: 8px;\">\n      <button nz-button (click)=\"change()\">Switch Data</button>\n    </div>\n    <nz-list nzItemLayout=\"horizontal\" [nzLoading]=\"loading\">\n      @for (item of data; track item) {\n        <nz-list-item>\n          <nz-list-item-meta\n            nzAvatar=\"https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png\"\n            nzDescription=\"Ant Design, a design language for background applications, is refined by Ant UED Team\"\n          >\n            <nz-list-item-meta-title>\n              <a href=\"https://ng.ant.design\">{{ item.title }}</a>\n            </nz-list-item-meta-title>\n          </nz-list-item-meta>\n        </nz-list-item>\n      } @empty {\n        <nz-list-empty />\n      }\n    </nz-list>\n  `\n})\nexport class NzDemoListBasicComponent {\n  loading = false;\n  data = [\n    {\n      title: 'Ant Design Title 1'\n    },\n    {\n      title: 'Ant Design Title 2'\n    },\n    {\n      title: 'Ant Design Title 3'\n    },\n    {\n      title: 'Ant Design Title 4'\n    }\n  ];\n\n  change(): void {\n    this.loading = true;\n    if (this.data.length > 0) {\n      setTimeout(() => {\n        this.data = [];\n        this.loading = false;\n      }, 1000);\n    } else {\n      setTimeout(() => {\n        this.data = [\n          {\n            title: 'Ant Design Title 1'\n          },\n          {\n            title: 'Ant Design Title 2'\n          },\n          {\n            title: 'Ant Design Title 3'\n          },\n          {\n            title: 'Ant Design Title 4'\n          }\n        ];\n        this.loading = false;\n      }, 1000);\n    }\n  }\n}\n"
  },
  {
    "path": "components/list/demo/grid.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 栅格列表\n  en-US: Grid\n---\n\n## zh-CN\n\n可以通过设置 `nz-list` 的 `nzGrid` 属性来实现栅格列表。\n\n## en-US\n\nCreating a grid list by setting the `nzGrid` property of `nz-list`.\n"
  },
  {
    "path": "components/list/demo/grid.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCardModule } from 'ng-zorro-antd/card';\nimport { NzGridModule } from 'ng-zorro-antd/grid';\nimport { NzListModule } from 'ng-zorro-antd/list';\n\n@Component({\n  selector: 'nz-demo-list-grid',\n  imports: [NzCardModule, NzGridModule, NzListModule],\n  template: `\n    <nz-list nzGrid>\n      <div nz-row [nzGutter]=\"16\">\n        @for (item of data; track item) {\n          <div nz-col [nzSpan]=\"6\">\n            <nz-list-item>\n              <nz-card [nzTitle]=\"item.title\">Card content</nz-card>\n            </nz-list-item>\n          </div>\n        }\n      </div>\n    </nz-list>\n  `\n})\nexport class NzDemoListGridComponent {\n  data = [\n    {\n      title: 'Title 1'\n    },\n    {\n      title: 'Title 2'\n    },\n    {\n      title: 'Title 3'\n    },\n    {\n      title: 'Title 4'\n    }\n  ];\n}\n"
  },
  {
    "path": "components/list/demo/infinite-load.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 滚动加载无限长列表\n  en-US: Infinite & virtualized\n---\n\n## zh-CN\n\n结合 [cdk-virtual-scroll](https://material.angular.io/cdk/scrolling/overview) 实现滚动加载无限长列表，带有虚拟化 virtualization 功能，能够提高数据量大时候长列表的性能。\n\n`Virtualized` 是在大数据列表中应用的一种技术，主要是为了减少不可见区域不必要的渲染从而提高性能，特别是数据量在成千上万条效果尤为明显。\n\n## en-US\n\nAn example of infinite list & virtualized loading using [cdk-virtual-scroll](https://material.angular.io/cdk/scrolling/overview).\n\n`Virtualized` rendering is a technique to mount big sets of data. It reduces the amount of rendered DOM nodes by tracking and hiding whatever isn't currently visible.\n"
  },
  {
    "path": "components/list/demo/infinite-load.ts",
    "content": "import { CollectionViewer, DataSource } from '@angular/cdk/collections';\nimport { CdkFixedSizeVirtualScroll, CdkVirtualForOf, CdkVirtualScrollViewport } from '@angular/cdk/scrolling';\nimport { HttpClient } from '@angular/common/http';\nimport { ChangeDetectionStrategy, Component, DestroyRef, inject, OnInit } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { BehaviorSubject, Observable, of, Subject } from 'rxjs';\nimport { catchError, takeUntil } from 'rxjs/operators';\n\nimport { NzListModule } from 'ng-zorro-antd/list';\nimport { NzMessageService } from 'ng-zorro-antd/message';\nimport { NzSkeletonModule } from 'ng-zorro-antd/skeleton';\n\ninterface ItemData {\n  gender: string;\n  name: Name;\n  email: string;\n}\n\ninterface Name {\n  title: string;\n  first: string;\n  last: string;\n}\n\n@Component({\n  selector: 'nz-demo-list-infinite-load',\n  imports: [CdkVirtualScrollViewport, CdkFixedSizeVirtualScroll, CdkVirtualForOf, NzListModule, NzSkeletonModule],\n  template: `\n    <div>\n      <cdk-virtual-scroll-viewport itemSize=\"73\" class=\"demo-infinite-container\">\n        <nz-list>\n          <nz-list-item *cdkVirtualFor=\"let item of ds\">\n            @if (item) {\n              <nz-list-item-meta\n                nzAvatar=\"https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png\"\n                [nzDescription]=\"item.email\"\n              >\n                <nz-list-item-meta-title>\n                  <a href=\"https://ng.ant.design\">{{ item.name.last }}</a>\n                </nz-list-item-meta-title>\n              </nz-list-item-meta>\n            } @else {\n              <nz-skeleton [nzAvatar]=\"true\" [nzParagraph]=\"{ rows: 1 }\" />\n            }\n          </nz-list-item>\n        </nz-list>\n      </cdk-virtual-scroll-viewport>\n    </div>\n  `,\n  styles: `\n    .demo-infinite-container {\n      height: 300px;\n      border: 1px solid #e8e8e8;\n      border-radius: 4px;\n    }\n\n    nz-list {\n      padding: 24px;\n    }\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class NzDemoListInfiniteLoadComponent implements OnInit {\n  private http = inject(HttpClient);\n  private nzMessage = inject(NzMessageService);\n  private destroyRef = inject(DestroyRef);\n\n  ds = new MyDataSource(this.http);\n\n  ngOnInit(): void {\n    this.ds\n      .completed()\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(() => {\n        this.nzMessage.warning('Infinite List loaded all');\n      });\n  }\n}\n\nclass MyDataSource extends DataSource<ItemData> {\n  private pageSize = 10;\n  private cachedData: ItemData[] = [];\n  private fetchedPages = new Set<number>();\n  private dataStream = new BehaviorSubject<ItemData[]>(this.cachedData);\n  private complete$ = new Subject<void>();\n  private disconnect$ = new Subject<void>();\n\n  constructor(private http: HttpClient) {\n    super();\n  }\n\n  completed(): Observable<void> {\n    return this.complete$.asObservable();\n  }\n\n  connect(collectionViewer: CollectionViewer): Observable<ItemData[]> {\n    this.setup(collectionViewer);\n    return this.dataStream;\n  }\n\n  disconnect(): void {\n    this.disconnect$.next();\n    this.disconnect$.complete();\n  }\n\n  private setup(collectionViewer: CollectionViewer): void {\n    this.fetchPage(0);\n    collectionViewer.viewChange.pipe(takeUntil(this.complete$), takeUntil(this.disconnect$)).subscribe(range => {\n      if (this.cachedData.length >= 50) {\n        this.complete$.next();\n        this.complete$.complete();\n      } else {\n        const endPage = this.getPageForIndex(range.end);\n        this.fetchPage(endPage + 1);\n      }\n    });\n  }\n\n  private getPageForIndex(index: number): number {\n    return Math.floor(index / this.pageSize);\n  }\n\n  private fetchPage(page: number): void {\n    if (this.fetchedPages.has(page)) {\n      return;\n    }\n    this.fetchedPages.add(page);\n\n    this.http\n      .get<{ results: ItemData[] }>(\n        `https://randomuser.me/api/?results=${this.pageSize}&inc=name,gender,email,nat&noinfo`\n      )\n      .pipe(catchError(() => of({ results: [] })))\n      .subscribe(res => {\n        this.cachedData.splice(page * this.pageSize, this.pageSize, ...res.results);\n        this.dataStream.next(this.cachedData);\n      });\n  }\n}\n"
  },
  {
    "path": "components/list/demo/loadmore.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 加载更多\n  en-US: Load more\n---\n\n## zh-CN\n\n可通过 `loadMore` 属性实现加载更多功能。\n\n## en-US\n\nLoad more list with `loadMore` property.\n"
  },
  {
    "path": "components/list/demo/loadmore.ts",
    "content": "/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { HttpClient } from '@angular/common/http';\nimport { Component, OnInit } from '@angular/core';\nimport { of } from 'rxjs';\nimport { catchError } from 'rxjs/operators';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzListModule } from 'ng-zorro-antd/list';\nimport { NzMessageService } from 'ng-zorro-antd/message';\nimport { NzSkeletonModule } from 'ng-zorro-antd/skeleton';\n\nconst count = 5;\nconst fakeDataUrl = 'https://randomuser.me/api/?results=5&inc=name,gender,email,nat&noinfo';\n\n@Component({\n  selector: 'nz-demo-list-loadmore',\n  imports: [NzButtonModule, NzListModule, NzSkeletonModule],\n  template: `\n    <nz-list class=\"demo-loadmore-list\" [nzLoading]=\"initLoading\">\n      @for (item of list; track item) {\n        <nz-list-item>\n          @if (item.loading) {\n            <nz-skeleton [nzAvatar]=\"true\" [nzActive]=\"true\" [nzTitle]=\"false\" [nzLoading]=\"true\" />\n          } @else {\n            <ng-container>\n              <nz-list-item-meta\n                nzAvatar=\"https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png\"\n                nzDescription=\"Ant Design, a design language for background applications, is refined by Ant UED Team\"\n              >\n                <nz-list-item-meta-title>\n                  <a href=\"https://ng.ant.design\">{{ item.name.last }}</a>\n                </nz-list-item-meta-title>\n              </nz-list-item-meta>\n              content\n              <ul nz-list-item-actions>\n                <nz-list-item-action><a (click)=\"edit(item)\">edit</a></nz-list-item-action>\n                <nz-list-item-action><a (click)=\"edit(item)\">more</a></nz-list-item-action>\n              </ul>\n            </ng-container>\n          }\n        </nz-list-item>\n      }\n      <div class=\"loadmore\" nz-list-load-more>\n        @if (!loadingMore) {\n          <button nz-button (click)=\"onLoadMore()\">loading more</button>\n        }\n      </div>\n    </nz-list>\n  `,\n  styles: `\n    .demo-loadmore-list {\n      min-height: 350px;\n    }\n    .loadmore {\n      text-align: center;\n      margin-top: 12px;\n      height: 32px;\n      line-height: 32px;\n    }\n  `\n})\nexport class NzDemoListLoadmoreComponent implements OnInit {\n  initLoading = true; // bug\n  loadingMore = false;\n  data: any[] = [];\n  list: Array<{ loading: boolean; name: any }> = [];\n\n  constructor(\n    private http: HttpClient,\n    private msg: NzMessageService\n  ) {}\n\n  ngOnInit(): void {\n    this.getData((res: any) => {\n      this.data = res.results;\n      this.list = res.results;\n      this.initLoading = false;\n    });\n  }\n\n  getData(callback: (res: any) => void): void {\n    this.http\n      .get(fakeDataUrl)\n      .pipe(catchError(() => of({ results: [] })))\n      .subscribe((res: any) => callback(res));\n  }\n\n  onLoadMore(): void {\n    this.loadingMore = true;\n    this.list = this.data.concat([...Array(count)].fill({}).map(() => ({ loading: true, name: {} })));\n    this.http\n      .get(fakeDataUrl)\n      .pipe(catchError(() => of({ results: [] })))\n      .subscribe((res: any) => {\n        this.data = this.data.concat(res.results);\n        this.list = [...this.data];\n        this.loadingMore = false;\n      });\n  }\n\n  edit(item: any): void {\n    this.msg.success(item.email);\n  }\n}\n"
  },
  {
    "path": "components/list/demo/responsive.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 响应式的栅格列表\n  en-US: Responsive grid list\n---\n\n## zh-CN\n\n响应式的栅格列表。\n\n## en-US\n\nResponsive grid list.\n"
  },
  {
    "path": "components/list/demo/responsive.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCardModule } from 'ng-zorro-antd/card';\nimport { NzGridModule } from 'ng-zorro-antd/grid';\nimport { NzListModule } from 'ng-zorro-antd/list';\n\n@Component({\n  selector: 'nz-demo-list-responsive',\n  imports: [NzCardModule, NzGridModule, NzListModule],\n  template: `\n    <nz-list nzGrid>\n      <div nz-row [nzGutter]=\"16\">\n        @for (item of data; track item) {\n          <div nz-col [nzXXl]=\"8\" [nzXl]=\"4\" [nzLg]=\"6\" [nzMd]=\"6\" [nzSm]=\"12\" [nzXs]=\"24\">\n            <nz-list-item>\n              <nz-card [nzTitle]=\"item.title\">Card content</nz-card>\n            </nz-list-item>\n          </div>\n        }\n      </div>\n    </nz-list>\n  `\n})\nexport class NzDemoListResponsiveComponent {\n  data = [\n    {\n      title: 'Title 1'\n    },\n    {\n      title: 'Title 2'\n    },\n    {\n      title: 'Title 3'\n    },\n    {\n      title: 'Title 4'\n    },\n    {\n      title: 'Title 5'\n    },\n    {\n      title: 'Title 6'\n    }\n  ];\n}\n"
  },
  {
    "path": "components/list/demo/simple.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 简单列表\n  en-US: Simple list\n---\n\n## zh-CN\n\n列表拥有大、中、小三种尺寸。\n\n通过设置 `size` 为 `large` `small` 分别把按钮设为大、小尺寸。若不设置 `size`，则尺寸为中。\n\n可通过设置 `nzHeader` 和 `nzFooter`，来自定义列表头部和尾部。\n\n## en-US\n\nAnt Design supports a default list size as well as a large and small size.\n\nIf a large or small list is desired, set the size property to either large or small respectively. Omit the size property for a list with the default size.\n\nCustomizing the nzHeader and nzFooter of list by setting `nzHeader` and `nzFooter` property.\n"
  },
  {
    "path": "components/list/demo/simple.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzListModule } from 'ng-zorro-antd/list';\nimport { NzMessageService } from 'ng-zorro-antd/message';\nimport { NzTypographyModule } from 'ng-zorro-antd/typography';\n\n@Component({\n  selector: 'nz-demo-list-simple',\n  imports: [NzListModule, NzTypographyModule],\n  template: `\n    <h3>Default Size</h3>\n    <nz-list nzBordered nzHeader=\"Header\" nzFooter=\"Footer\">\n      @for (item of data; track item) {\n        <nz-list-item>\n          <span nz-typography><mark>[ITEM]</mark></span>\n          {{ item }}\n        </nz-list-item>\n      }\n    </nz-list>\n\n    <h3>Small Size</h3>\n    <nz-list nzBordered nzSize=\"small\">\n      <nz-list-header>Header</nz-list-header>\n      @for (item of data; track item) {\n        <nz-list-item>{{ item }}</nz-list-item>\n      }\n\n      <nz-list-footer>Footer</nz-list-footer>\n    </nz-list>\n\n    <h3>Large Size</h3>\n    <ul nz-list [nzDataSource]=\"data\" nzBordered nzSize=\"large\">\n      <nz-list-header>Header</nz-list-header>\n      @for (item of data; track item) {\n        <li nz-list-item nzNoFlex>\n          <ul nz-list-item-actions>\n            <nz-list-item-action>\n              <a (click)=\"msg.info('edit')\">edit</a>\n            </nz-list-item-action>\n          </ul>\n          {{ item }}\n        </li>\n      }\n      <nz-list-footer>Footer</nz-list-footer>\n    </ul>\n  `,\n  styles: `\n    h3 {\n      margin: 16px 0;\n    }\n    h3:first-child {\n      margin-top: 0;\n    }\n    h3:last-child {\n      margin-bottom: 0;\n    }\n  `\n})\nexport class NzDemoListSimpleComponent {\n  data = [\n    'Racing car sprays burning fuel into crowd.',\n    'Japanese princess to wed commoner.',\n    'Australian walks 100km after outback crash.',\n    'Man charged over missing wedding girl.',\n    'Los Angeles battles huge wildfires.'\n  ];\n\n  constructor(public msg: NzMessageService) {}\n}\n"
  },
  {
    "path": "components/list/demo/vertical.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 竖排列表样式\n  en-US: Vertical\n---\n\n## zh-CN\n\n通过设置 `nzItemLayout` 属性为 `vertical` 可实现竖排列表样式。\n\n## en-US\n\nSetting `nzItemLayout` property with `vertical` to create a vertical list.\n"
  },
  {
    "path": "components/list/demo/vertical.ts",
    "content": "import { Component, OnInit } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzListModule } from 'ng-zorro-antd/list';\n\ninterface ItemData {\n  href: string;\n  title: string;\n  avatar: string;\n  description: string;\n  content: string;\n}\n\n@Component({\n  selector: 'nz-demo-list-vertical',\n  imports: [NzIconModule, NzListModule],\n  template: `\n    <nz-list nzItemLayout=\"vertical\">\n      @for (item of data; track item) {\n        <nz-list-item>\n          <nz-list-item-meta>\n            <nz-list-item-meta-avatar [nzSrc]=\"item.avatar\" />\n            <nz-list-item-meta-title>\n              <a href=\"{{ item.href }}\">{{ item.title }}</a>\n            </nz-list-item-meta-title>\n            <nz-list-item-meta-description>\n              {{ item.description }}\n            </nz-list-item-meta-description>\n          </nz-list-item-meta>\n          {{ item.content }}\n          <ul nz-list-item-actions>\n            <nz-list-item-action>\n              <nz-icon nzType=\"star-o\" style=\"margin-right: 8px;\" />\n              156\n            </nz-list-item-action>\n            <nz-list-item-action>\n              <nz-icon nzType=\"star-o\" style=\"margin-right: 8px;\" />\n              156\n            </nz-list-item-action>\n            <nz-list-item-action>\n              <nz-icon nzType=\"star-o\" style=\"margin-right: 8px;\" />\n              2\n            </nz-list-item-action>\n          </ul>\n          <nz-list-item-extra>\n            <img width=\"272\" alt=\"logo\" src=\"https://gw.alipayobjects.com/zos/rmsportal/mqaQswcyDLcXyDKnZfES.png\" />\n          </nz-list-item-extra>\n        </nz-list-item>\n      }\n    </nz-list>\n  `\n})\nexport class NzDemoListVerticalComponent implements OnInit {\n  data: ItemData[] = [];\n\n  ngOnInit(): void {\n    this.loadData(1);\n  }\n\n  loadData(pi: number): void {\n    this.data = new Array(5).fill({}).map((_, index) => ({\n      href: 'https://ant.design',\n      title: `ant design part ${index} (page: ${pi})`,\n      avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',\n      description: 'Ant Design, a design language for background applications, is refined by Ant UED Team.',\n      content:\n        'We supply a series of design principles, practical patterns and high quality design resources ' +\n        '(Sketch and Axure), to help people create their product prototypes beautifully and efficiently.'\n    }));\n  }\n}\n"
  },
  {
    "path": "components/list/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Display\ntitle: List\ncols: 1\ncover: 'https://gw.alipayobjects.com/zos/alicdn/5FrZKStG_/List.svg'\ndescription: Basic list display, which can carry text, lists, pictures, paragraphs.\n---\n\n## When To Use\n\nA list can be used to display content related to a single subject. The content can consist of multiple elements of varying type and size.\n\n## API\n\n### nz-list\n\n| Property         | Description                                                                                                           | Type                              | Default        |\n| ---------------- | --------------------------------------------------------------------------------------------------------------------- | --------------------------------- | -------------- |\n| `[nzBordered]`   | Toggles rendering of the border around the list                                                                       | `boolean`                         | `false`        |\n| `[nzFooter]`     | List footer renderer                                                                                                  | `string \\| TemplateRef<void>`     | -              |\n| `[nzHeader]`     | List header renderer                                                                                                  | `string \\| TemplateRef<void>`     | -              |\n| `[nzItemLayout]` | The layout of list, default is `horizontal`, If a vertical list is desired, set the itemLayout property to `vertical` | `'vertical' \\| 'horizontal'`      | `'horizontal'` |\n| `[nzLoading]`    | Shows a loading indicator while the contents of the list are being fetched                                            | `boolean`                         | `false`        |\n| `[nzSize]`       | Size of list                                                                                                          | `'large' \\| 'small' \\| 'default'` | `'default'`    |\n| `[nzSplit]`      | Toggles rendering of the split under the list item                                                                    | `boolean`                         | `true`         |\n\n### nz-list-empty\n\nEmpty content component for the list.\n\n| Property       | Description   | Type                          | Default |\n| -------------- | ------------- | ----------------------------- | ------- |\n| `[nzNoResult]` | Empty content | `string \\| TemplateRef<void>` | -       |\n\n### nz-list[nzGrid]\n\nUse grid layout for the list.\n\n### nz-list-header\n\nHeader component for the list.\n\n### nz-list-footer\n\nFooter component for the list.\n\n### nz-list-pagination\n\nPagination component for the list.\n\n### nz-list-load-more\n\nLoad more component for the list.\n\n---\n\n### nz-list-item\n\n| Property     | Description                              | Type      | Default |\n| ------------ | ---------------------------------------- | --------- | ------- |\n| `[nzNoFlex]` | Whether it's not `flex` layout rendering | `boolean` | `false` |\n\n#### ul[nz-list-item-actions]\n\nActions container component for the list items.\n\n#### nz-list-item-action\n\nAction component for the list items.\n\n#### nz-list-item-extra\n\nExtra content for the list items.\n\n---\n\n### nz-list-item-meta\n\n| Property          | Description                  | Type                          | Default |\n| ----------------- | ---------------------------- | ----------------------------- | ------- |\n| `[nzAvatar]`      | The avatar of list item      | `string \\| TemplateRef<void>` | -       |\n| `[nzDescription]` | The description of list item | `string \\| TemplateRef<void>` | -       |\n| `[nzTitle]`       | The title of list item       | `string \\| TemplateRef<void>` | -       |\n\n#### nz-list-item-meta-title\n\nTitle component for the list items meta part.\n\n#### nz-list-item-meta-description\n\nDescription component for the list items meta part.\n\n#### nz-list-item-meta-avatar\n\nAvatar component for the list items meta part.\n\n| Property  | Description                                  | Type     | Default | Global Config |\n| --------- | -------------------------------------------- | -------- | ------- | ------------- |\n| `[nzSrc]` | The address of the image for an image avatar | `string` | -       |\n"
  },
  {
    "path": "components/list/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 列表\ntype: 数据展示\ntitle: List\ncols: 1\ncover: 'https://gw.alipayobjects.com/zos/alicdn/5FrZKStG_/List.svg'\ndescription: 最基础的列表展示，可承载文字、列表、图片、段落。\n---\n\n## 何时使用\n\n最基础的列表展示，可承载文字、列表、图片、段落，常用于后台数据展示页面。\n\n## API\n\n### nz-list\n\n| 参数             | 说明                                                                 | 类型                              | 默认值         |\n| ---------------- | -------------------------------------------------------------------- | --------------------------------- | -------------- |\n| `[nzBordered]`   | 是否展示边框                                                         | `boolean`                         | `false`        |\n| `[nzFooter]`     | 列表底部                                                             | `string \\| TemplateRef<void>`     | -              |\n| `[nzHeader]`     | 列表头部                                                             | `string \\| TemplateRef<void>`     | -              |\n| `[nzItemLayout]` | 设置 `nz-list-item` 布局, 设置成 `vertical` 则竖直样式显示, 默认横排 | `'vertical' \\| 'horizontal'`      | `'horizontal'` |\n| `[nzLoading]`    | 当卡片内容还在加载中时，可以用 `loading` 展示一个占位                | `boolean`                         | `false`        |\n| `[nzSize]`       | list 的尺寸                                                          | `'large' \\| 'small' \\| 'default'` | `'default'`    |\n| `[nzSplit]`      | 是否展示分割线                                                       | `boolean`                         | `true`         |\n\n### nz-list-empty\n\n列表空内容组件\n\n| 参数           | 说明           | 类型                          | 默认值 |\n| -------------- | -------------- | ----------------------------- | ------ |\n| `[nzNoResult]` | 空内容显示内容 | `string \\| TemplateRef<void>` | -      |\n\n### nz-list[nzGrid]\n\n使用栅格布局\n\n### nz-list-header\n\n列表头部位置组件\n\n### nz-list-footer\n\n列表脚部位置组件\n\n### nz-list-pagination\n\n列表分页位置组件\n\n### nz-list-load-more\n\n列表加载更多位置组件\n\n---\n\n### nz-list-item\n\n| 参数         | 说明                   | 类型      | 默认值  |\n| ------------ | ---------------------- | --------- | ------- |\n| `[nzNoFlex]` | 是否非 `flex` 布局渲染 | `boolean` | `false` |\n\n### ul[nz-list-item-actions]\n\n列表项操作项容器组件\n\n### nz-list-item-action\n\n列表项操作项组件\n\n### nz-list-item-extra\n\n---\n\n列表项扩展内容位置组件\n\n### nz-list-item-meta\n\n| 参数              | 说明               | 类型                          | 默认值 |\n| ----------------- | ------------------ | ----------------------------- | ------ |\n| `[nzAvatar]`      | 列表元素的图标     | `string \\| TemplateRef<void>` | -      |\n| `[nzDescription]` | 列表元素的描述内容 | `string \\| TemplateRef<void>` | -      |\n| `[nzTitle]`       | 列表元素的标题     | `string \\| TemplateRef<void>` | -      |\n\n### nz-list-item-meta-title\n\n列表项元信息标题部分组件\n\n### nz-list-item-meta-description\n\n列表项元信息描述部分组件\n\n### nz-list-item-meta-avatar\n\n列表项元信息头像部分组件\n\n| 参数      | 说明                 | 类型     | 默认值 |\n| --------- | -------------------- | -------- | ------ |\n| `[nzSrc]` | 图片类头像的资源地址 | `string` | -      |\n"
  },
  {
    "path": "components/list/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/list/interface.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport type ColumnCount = 1 | 2 | 3 | 4 | 6 | 8 | 12 | 24;\n\nexport interface NzListGrid {\n  gutter?: number;\n  span?: number;\n  column?: ColumnCount;\n  xs?: ColumnCount;\n  sm?: ColumnCount;\n  md?: ColumnCount;\n  lg?: ColumnCount;\n  xl?: ColumnCount;\n  xxl?: ColumnCount;\n}\n"
  },
  {
    "path": "components/list/list-cell.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, Directive, Input, TemplateRef } from '@angular/core';\n\nimport { NzEmptyModule } from 'ng-zorro-antd/empty';\n\n@Component({\n  selector: 'nz-list-empty',\n  exportAs: 'nzListHeader',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `<nz-embed-empty nzComponentName=\"list\" [specificContent]=\"nzNoResult\" />`,\n  host: {\n    class: 'ant-list-empty-text'\n  },\n  imports: [NzEmptyModule]\n})\nexport class NzListEmptyComponent {\n  @Input() nzNoResult?: string | TemplateRef<void>;\n}\n\n@Component({\n  selector: 'nz-list-header',\n  exportAs: 'nzListHeader',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `<ng-content />`,\n  host: {\n    class: 'ant-list-header'\n  }\n})\nexport class NzListHeaderComponent {}\n\n@Component({\n  selector: 'nz-list-footer',\n  exportAs: 'nzListFooter',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `<ng-content />`,\n  host: {\n    class: 'ant-list-footer'\n  }\n})\nexport class NzListFooterComponent {}\n\n@Component({\n  selector: 'nz-list-pagination',\n  exportAs: 'nzListPagination',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `<ng-content />`,\n  host: {\n    class: 'ant-list-pagination'\n  }\n})\nexport class NzListPaginationComponent {}\n\n@Directive({\n  selector: 'nz-list-load-more',\n  exportAs: 'nzListLoadMoreDirective'\n})\nexport class NzListLoadMoreDirective {}\n\n@Directive({\n  selector: 'nz-list[nzGrid]',\n  host: {\n    class: 'ant-list-grid'\n  }\n})\nexport class NzListGridDirective {}\n"
  },
  {
    "path": "components/list/list-item-cell.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterContentInit,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ContentChildren,\n  inject,\n  Input,\n  OnChanges,\n  QueryList,\n  TemplateRef,\n  ViewChild\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Observable, Subject, defer, merge, of } from 'rxjs';\nimport { mergeMap, startWith } from 'rxjs/operators';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\n@Component({\n  selector: 'nz-list-item-extra, [nz-list-item-extra]',\n  exportAs: 'nzListItemExtra',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `<ng-content />`,\n  host: {\n    class: 'ant-list-item-extra'\n  }\n})\nexport class NzListItemExtraComponent {}\n\n@Component({\n  selector: 'nz-list-item-action',\n  exportAs: 'nzListItemAction',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `<ng-template><ng-content /></ng-template>`\n})\nexport class NzListItemActionComponent {\n  @ViewChild(TemplateRef, { static: true }) templateRef?: TemplateRef<void>;\n}\n\n@Component({\n  selector: 'ul[nz-list-item-actions]',\n  exportAs: 'nzListItemActions',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    @for (i of actions; track i) {\n      <li>\n        <ng-template [ngTemplateOutlet]=\"i\" />\n        @if (!$last) {\n          <em class=\"ant-list-item-action-split\"></em>\n        }\n      </li>\n    }\n  `,\n  host: {\n    class: 'ant-list-item-action'\n  },\n  imports: [NgTemplateOutlet]\n})\nexport class NzListItemActionsComponent implements OnChanges, AfterContentInit {\n  private cdr = inject(ChangeDetectorRef);\n\n  @Input() nzActions: Array<TemplateRef<void>> = [];\n  @ContentChildren(NzListItemActionComponent) nzListItemActions!: QueryList<NzListItemActionComponent>;\n\n  actions: Array<TemplateRef<void>> = [];\n  private inputActionChanges$ = new Subject<null>();\n  private contentChildrenChanges$: Observable<NzSafeAny> = defer(() => {\n    if (this.nzListItemActions) {\n      return of(null);\n    }\n    return this.initialized.pipe(\n      mergeMap(() => this.nzListItemActions.changes.pipe(startWith(this.nzListItemActions)))\n    );\n  });\n\n  private initialized = new Subject<void>();\n\n  constructor() {\n    merge(this.contentChildrenChanges$, this.inputActionChanges$)\n      .pipe(takeUntilDestroyed())\n      .subscribe(() => {\n        if (this.nzActions.length) {\n          this.actions = this.nzActions;\n        } else {\n          this.actions = this.nzListItemActions.map(action => action.templateRef!);\n        }\n        this.cdr.detectChanges();\n      });\n  }\n\n  ngOnChanges(): void {\n    this.inputActionChanges$.next(null);\n  }\n\n  ngAfterContentInit(): void {\n    this.initialized.next();\n    this.initialized.complete();\n  }\n}\n"
  },
  {
    "path": "components/list/list-item-meta-cell.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, Input } from '@angular/core';\n\nimport { NzAvatarModule } from 'ng-zorro-antd/avatar';\n\n@Component({\n  selector: 'nz-list-item-meta-title',\n  exportAs: 'nzListItemMetaTitle',\n  template: `\n    <h4 class=\"ant-list-item-meta-title\">\n      <ng-content />\n    </h4>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class NzListItemMetaTitleComponent {}\n\n@Component({\n  selector: 'nz-list-item-meta-description',\n  exportAs: 'nzListItemMetaDescription',\n  template: `\n    <div class=\"ant-list-item-meta-description\">\n      <ng-content />\n    </div>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class NzListItemMetaDescriptionComponent {}\n\n@Component({\n  selector: 'nz-list-item-meta-avatar',\n  exportAs: 'nzListItemMetaAvatar',\n  template: `\n    <div class=\"ant-list-item-meta-avatar\">\n      @if (nzSrc) {\n        <nz-avatar [nzSrc]=\"nzSrc\" />\n      } @else {\n        <ng-content />\n      }\n    </div>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  imports: [NzAvatarModule]\n})\nexport class NzListItemMetaAvatarComponent {\n  @Input() nzSrc?: string;\n}\n"
  },
  {
    "path": "components/list/list-item-meta.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  ContentChild,\n  ElementRef,\n  inject,\n  Input,\n  TemplateRef,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\n\nimport {\n  NzListItemMetaAvatarComponent,\n  NzListItemMetaDescriptionComponent,\n  NzListItemMetaDescriptionComponent as DescriptionComponent,\n  NzListItemMetaTitleComponent,\n  NzListItemMetaTitleComponent as TitleComponent\n} from './list-item-meta-cell';\n\n@Component({\n  selector: 'nz-list-item-meta, [nz-list-item-meta]',\n  exportAs: 'nzListItemMeta',\n  template: `\n    <!--Old API Start-->\n    @if (avatarStr) {\n      <nz-list-item-meta-avatar [nzSrc]=\"avatarStr\" />\n    }\n\n    @if (avatarTpl) {\n      <nz-list-item-meta-avatar>\n        <ng-container [ngTemplateOutlet]=\"avatarTpl\" />\n      </nz-list-item-meta-avatar>\n    }\n\n    <!--Old API End-->\n\n    <ng-content select=\"nz-list-item-meta-avatar\" />\n\n    @if (nzTitle || nzDescription || descriptionComponent || titleComponent) {\n      <div class=\"ant-list-item-meta-content\">\n        <!--Old API Start-->\n\n        @if (nzTitle && !titleComponent) {\n          <nz-list-item-meta-title>\n            <ng-container *nzStringTemplateOutlet=\"nzTitle\">{{ nzTitle }}</ng-container>\n          </nz-list-item-meta-title>\n        }\n\n        @if (nzDescription && !descriptionComponent) {\n          <nz-list-item-meta-description>\n            <ng-container *nzStringTemplateOutlet=\"nzDescription\">{{ nzDescription }}</ng-container>\n          </nz-list-item-meta-description>\n        }\n        <!--Old API End-->\n\n        <ng-content select=\"nz-list-item-meta-title\" />\n        <ng-content select=\"nz-list-item-meta-description\" />\n      </div>\n    }\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  host: {\n    class: 'ant-list-item-meta'\n  },\n  imports: [\n    NzListItemMetaAvatarComponent,\n    NgTemplateOutlet,\n    NzListItemMetaTitleComponent,\n    NzOutletModule,\n    NzListItemMetaDescriptionComponent\n  ]\n})\nexport class NzListItemMetaComponent {\n  public readonly elementRef = inject(ElementRef);\n\n  avatarStr = '';\n  avatarTpl?: TemplateRef<void>;\n\n  @Input()\n  set nzAvatar(value: string | TemplateRef<void>) {\n    if (value instanceof TemplateRef) {\n      this.avatarStr = '';\n      this.avatarTpl = value;\n    } else {\n      this.avatarStr = value;\n    }\n  }\n\n  @Input() nzTitle?: string | TemplateRef<void>;\n\n  @Input() nzDescription?: string | TemplateRef<void>;\n\n  @ContentChild(DescriptionComponent) descriptionComponent?: DescriptionComponent;\n  @ContentChild(TitleComponent) titleComponent?: TitleComponent;\n}\n"
  },
  {
    "path": "components/list/list-item.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterViewInit,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ContentChild,\n  DestroyRef,\n  HostBinding,\n  Input,\n  TemplateRef,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzDirectionVHType } from 'ng-zorro-antd/core/types';\n\nimport { NzListItemActionsComponent, NzListItemExtraComponent } from './list-item-cell';\nimport { NzListComponent } from './list.component';\n\n@Component({\n  selector: 'nz-list-item, [nz-list-item]',\n  exportAs: 'nzListItem',\n  template: `\n    <ng-template #actionsTpl>\n      @if (nzActions && nzActions.length > 0) {\n        <ul nz-list-item-actions [nzActions]=\"nzActions\"></ul>\n      }\n      <ng-content select=\"nz-list-item-actions, [nz-list-item-actions]\" />\n    </ng-template>\n    <ng-template #contentTpl>\n      <ng-content select=\"nz-list-item-meta, [nz-list-item-meta]\" />\n      <ng-content />\n      @if (nzContent) {\n        <ng-container *nzStringTemplateOutlet=\"nzContent\">{{ nzContent }}</ng-container>\n      }\n    </ng-template>\n    <ng-template #extraTpl>\n      <ng-content select=\"nz-list-item-extra, [nz-list-item-extra]\" />\n    </ng-template>\n\n    @if (isVerticalAndExtra) {\n      <div class=\"ant-list-item-main\">\n        <ng-template [ngTemplateOutlet]=\"contentTpl\" />\n        <ng-template [ngTemplateOutlet]=\"actionsTpl\" />\n      </div>\n      @if (nzExtra) {\n        <nz-list-item-extra>\n          <ng-template [ngTemplateOutlet]=\"nzExtra\" />\n        </nz-list-item-extra>\n      }\n      <ng-template [ngTemplateOutlet]=\"extraTpl\" />\n    } @else {\n      <ng-template [ngTemplateOutlet]=\"contentTpl\" />\n      <ng-template [ngTemplateOutlet]=\"nzExtra\" />\n      <ng-template [ngTemplateOutlet]=\"extraTpl\" />\n      <ng-template [ngTemplateOutlet]=\"actionsTpl\" />\n    }\n  `,\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    class: 'ant-list-item'\n  },\n  imports: [NzListItemActionsComponent, NzOutletModule, NgTemplateOutlet, NzListItemExtraComponent]\n})\nexport class NzListItemComponent implements AfterViewInit {\n  private cdr = inject(ChangeDetectorRef);\n  private destroyRef = inject(DestroyRef);\n  private parentComp = inject(NzListComponent);\n\n  @Input() nzActions: Array<TemplateRef<void>> = [];\n  @Input() nzContent?: string | TemplateRef<void>;\n  @Input() nzExtra: TemplateRef<void> | null = null;\n  @Input({ transform: booleanAttribute }) @HostBinding('class.ant-list-item-no-flex') nzNoFlex: boolean = false;\n\n  @ContentChild(NzListItemExtraComponent) listItemExtraDirective?: NzListItemExtraComponent;\n\n  private itemLayout?: NzDirectionVHType;\n\n  get isVerticalAndExtra(): boolean {\n    return this.itemLayout === 'vertical' && (!!this.listItemExtraDirective || !!this.nzExtra);\n  }\n\n  ngAfterViewInit(): void {\n    this.parentComp.itemLayoutNotify$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(val => {\n      this.itemLayout = val;\n      this.cdr.detectChanges();\n    });\n  }\n}\n"
  },
  {
    "path": "components/list/list.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterContentInit,\n  ChangeDetectionStrategy,\n  Component,\n  ContentChild,\n  DestroyRef,\n  Input,\n  OnChanges,\n  OnInit,\n  SimpleChanges,\n  TemplateRef,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { BehaviorSubject, Observable } from 'rxjs';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzDirectionVHType, NzSafeAny, NzSizeLDSType } from 'ng-zorro-antd/core/types';\nimport { NzGridModule } from 'ng-zorro-antd/grid';\nimport { NzSpinModule } from 'ng-zorro-antd/spin';\n\nimport { NzListGrid } from './interface';\nimport {\n  NzListEmptyComponent,\n  NzListFooterComponent,\n  NzListHeaderComponent,\n  NzListLoadMoreDirective,\n  NzListPaginationComponent\n} from './list-cell';\n\n@Component({\n  selector: 'nz-list, [nz-list]',\n  exportAs: 'nzList',\n  template: `\n    @if (nzHeader) {\n      <nz-list-header>\n        <ng-container *nzStringTemplateOutlet=\"nzHeader\">{{ nzHeader }}</ng-container>\n      </nz-list-header>\n    }\n\n    <ng-content select=\"nz-list-header\" />\n\n    <nz-spin [nzSpinning]=\"nzLoading\">\n      <ng-container>\n        @if (nzLoading && nzDataSource && nzDataSource.length === 0) {\n          <div [style.min-height.px]=\"53\"></div>\n        }\n        @if (nzGrid && nzDataSource) {\n          <div nz-row [nzGutter]=\"nzGrid.gutter || null\">\n            @for (item of nzDataSource; track item) {\n              <div\n                nz-col\n                [nzSpan]=\"nzGrid.span || null\"\n                [nzXs]=\"nzGrid.xs || null\"\n                [nzSm]=\"nzGrid.sm || null\"\n                [nzMd]=\"nzGrid.md || null\"\n                [nzLg]=\"nzGrid.lg || null\"\n                [nzXl]=\"nzGrid.xl || null\"\n                [nzXXl]=\"nzGrid.xxl || null\"\n              >\n                <ng-template\n                  [ngTemplateOutlet]=\"nzRenderItem\"\n                  [ngTemplateOutletContext]=\"{ $implicit: item, index: $index }\"\n                />\n              </div>\n            }\n          </div>\n        } @else {\n          <div class=\"ant-list-items\">\n            @for (item of nzDataSource; track item) {\n              <ng-container>\n                <ng-template\n                  [ngTemplateOutlet]=\"nzRenderItem\"\n                  [ngTemplateOutletContext]=\"{ $implicit: item, index: $index }\"\n                />\n              </ng-container>\n            }\n            <ng-content />\n          </div>\n        }\n\n        @if (!nzLoading && nzDataSource && nzDataSource.length === 0) {\n          <nz-list-empty [nzNoResult]=\"nzNoResult\" />\n        }\n      </ng-container>\n    </nz-spin>\n\n    @if (nzFooter) {\n      <nz-list-footer>\n        <ng-container *nzStringTemplateOutlet=\"nzFooter\">{{ nzFooter }}</ng-container>\n      </nz-list-footer>\n    }\n\n    <ng-content select=\"nz-list-footer, [nz-list-footer]\" />\n\n    <ng-template [ngTemplateOutlet]=\"nzLoadMore\" />\n    <ng-content select=\"nz-list-load-more, [nz-list-load-more]\" />\n\n    @if (nzPagination) {\n      <nz-list-pagination>\n        <ng-template [ngTemplateOutlet]=\"nzPagination\" />\n      </nz-list-pagination>\n    }\n\n    <ng-content select=\"nz-list-pagination, [nz-list-pagination]\" />\n  `,\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    class: 'ant-list',\n    '[class.ant-list-rtl]': `dir === 'rtl'`,\n    '[class.ant-list-vertical]': 'nzItemLayout === \"vertical\"',\n    '[class.ant-list-lg]': 'nzSize === \"large\"',\n    '[class.ant-list-sm]': 'nzSize === \"small\"',\n    '[class.ant-list-split]': 'nzSplit',\n    '[class.ant-list-bordered]': 'nzBordered',\n    '[class.ant-list-loading]': 'nzLoading',\n    '[class.ant-list-something-after-last-item]': 'hasSomethingAfterLastItem'\n  },\n  imports: [\n    NgTemplateOutlet,\n    NzListHeaderComponent,\n    NzOutletModule,\n    NzSpinModule,\n    NzGridModule,\n    NzListEmptyComponent,\n    NzListFooterComponent,\n    NzListPaginationComponent\n  ]\n})\nexport class NzListComponent implements AfterContentInit, OnChanges, OnInit {\n  private directionality = inject(Directionality);\n  private destroyRef = inject(DestroyRef);\n\n  @Input() nzDataSource?: NzSafeAny[];\n  @Input({ transform: booleanAttribute }) nzBordered = false;\n  @Input() nzGrid?: NzListGrid | '' | null | undefined = '';\n  @Input() nzHeader?: string | TemplateRef<void>;\n  @Input() nzFooter?: string | TemplateRef<void>;\n  @Input() nzItemLayout: NzDirectionVHType = 'horizontal';\n  @Input() nzRenderItem: TemplateRef<{ $implicit: NzSafeAny; index: number }> | null = null;\n  @Input({ transform: booleanAttribute }) nzLoading = false;\n  @Input() nzLoadMore: TemplateRef<void> | null = null;\n  @Input() nzPagination?: TemplateRef<void>;\n  @Input() nzSize: NzSizeLDSType = 'default';\n  @Input({ transform: booleanAttribute }) nzSplit = true;\n  @Input() nzNoResult?: string | TemplateRef<void>;\n\n  @ContentChild(NzListFooterComponent) nzListFooterComponent!: NzListFooterComponent;\n  @ContentChild(NzListPaginationComponent) nzListPaginationComponent!: NzListPaginationComponent;\n  @ContentChild(NzListLoadMoreDirective) nzListLoadMoreDirective!: NzListLoadMoreDirective;\n\n  hasSomethingAfterLastItem = false;\n  dir: Direction = 'ltr';\n  private itemLayoutNotifySource = new BehaviorSubject<NzDirectionVHType>(this.nzItemLayout);\n\n  get itemLayoutNotify$(): Observable<NzDirectionVHType> {\n    return this.itemLayoutNotifySource.asObservable();\n  }\n\n  constructor() {\n    this.destroyRef.onDestroy(() => this.itemLayoutNotifySource.unsubscribe());\n  }\n\n  ngOnInit(): void {\n    this.dir = this.directionality.value;\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((direction: Direction) => {\n      this.dir = direction;\n    });\n  }\n\n  getSomethingAfterLastItem(): boolean {\n    return !!(\n      this.nzLoadMore ||\n      this.nzPagination ||\n      this.nzFooter ||\n      this.nzListFooterComponent ||\n      this.nzListPaginationComponent ||\n      this.nzListLoadMoreDirective\n    );\n  }\n  ngOnChanges(changes: SimpleChanges): void {\n    if (changes.nzItemLayout) {\n      this.itemLayoutNotifySource.next(this.nzItemLayout);\n    }\n  }\n\n  ngAfterContentInit(): void {\n    this.hasSomethingAfterLastItem = this.getSomethingAfterLastItem();\n  }\n}\n"
  },
  {
    "path": "components/list/list.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport {\n  NzListEmptyComponent,\n  NzListFooterComponent,\n  NzListGridDirective,\n  NzListHeaderComponent,\n  NzListLoadMoreDirective,\n  NzListPaginationComponent\n} from './list-cell';\nimport { NzListItemActionComponent, NzListItemActionsComponent, NzListItemExtraComponent } from './list-item-cell';\nimport {\n  NzListItemMetaAvatarComponent,\n  NzListItemMetaDescriptionComponent,\n  NzListItemMetaTitleComponent\n} from './list-item-meta-cell';\nimport { NzListItemMetaComponent } from './list-item-meta.component';\nimport { NzListItemComponent } from './list-item.component';\nimport { NzListComponent } from './list.component';\n\nconst DIRECTIVES = [\n  NzListComponent,\n  NzListHeaderComponent,\n  NzListFooterComponent,\n  NzListPaginationComponent,\n  NzListEmptyComponent,\n  NzListItemComponent,\n  NzListItemMetaComponent,\n  NzListItemMetaTitleComponent,\n  NzListItemMetaDescriptionComponent,\n  NzListItemMetaAvatarComponent,\n  NzListItemActionsComponent,\n  NzListItemActionComponent,\n  NzListItemExtraComponent,\n  NzListLoadMoreDirective,\n  NzListGridDirective\n];\n\n@NgModule({\n  imports: [DIRECTIVES],\n  exports: [DIRECTIVES]\n})\nexport class NzListModule {}\n"
  },
  {
    "path": "components/list/list.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport { AsyncPipe } from '@angular/common';\nimport { Component, DebugElement, provideZoneChangeDetection, TemplateRef, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { Observable, timer } from 'rxjs';\nimport { map } from 'rxjs/operators';\n\nimport { NzDirectionVHType, NzSizeLDSType } from 'ng-zorro-antd/core/types';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzListComponent } from './list.component';\nimport { NzListModule } from './list.module';\n\ndescribe('list', () => {\n  let fixture: ComponentFixture<TestListComponent>;\n  let context: TestListComponent;\n  let dl: DebugElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideZoneChangeDetection()]\n    });\n    fixture = TestBed.createComponent(TestListComponent);\n    context = fixture.componentInstance;\n    dl = fixture.debugElement;\n    fixture.detectChanges();\n  });\n\n  describe('[fields]', () => {\n    describe('#nzItemLayout', () => {\n      for (const item of [\n        { type: 'default', ret: false },\n        { type: 'vertical', ret: true }\n      ]) {\n        it(`[${item.type}]`, () => {\n          context.nzItemLayout = item.type as NzDirectionVHType;\n          fixture.detectChanges();\n          expect(dl.query(By.css(`.ant-list-${item.type}`)) != null).toBe(item.ret);\n        });\n      }\n    });\n\n    describe('#nzBordered', () => {\n      for (const value of [true, false]) {\n        it(`[${value}]`, () => {\n          context.nzBordered = value;\n          fixture.detectChanges();\n          expect(dl.query(By.css('.ant-list-bordered')) != null).toBe(value);\n        });\n      }\n    });\n\n    describe('#nzHeader', () => {\n      it('with string', () => {\n        expect(dl.query(By.css('.ant-list-header')) != null).toBe(true);\n      });\n      it('with custom template', () => {\n        const fixtureTemp = TestBed.createComponent(TestListWithTemplateComponent);\n        fixtureTemp.detectChanges();\n        expect(fixtureTemp.debugElement.query(By.css('.list-header')) != null).toBe(true);\n      });\n    });\n\n    describe('#nzFooter', () => {\n      let fixtureTemp: ComponentFixture<TestListWithTemplateComponent>;\n      beforeEach(() => {\n        fixtureTemp = TestBed.createComponent(TestListWithTemplateComponent);\n        fixtureTemp.detectChanges();\n      });\n      it('with string', () => {\n        expect(dl.query(By.css('.ant-list-footer')) != null).toBe(true);\n      });\n      it('with custom template', () => {\n        const footerEl = fixtureTemp.debugElement.query(By.css('.ant-list-footer'));\n        expect((footerEl.nativeElement as HTMLDivElement).innerText).toBe(\n          fixtureTemp.componentInstance.footer as string\n        );\n      });\n      it('change string to template', () => {\n        const footerEl = fixtureTemp.debugElement.query(By.css('.ant-list-footer'));\n        expect((footerEl.nativeElement as HTMLDivElement).innerText).toBe(\n          fixtureTemp.componentInstance.footer as string\n        );\n        (fixtureTemp.debugElement.query(By.css('#change')).nativeElement as HTMLButtonElement).click();\n        fixtureTemp.detectChanges();\n        expect(fixtureTemp.debugElement.query(By.css('.list-footer')) != null).toBe(true);\n      });\n    });\n\n    describe('#nzSize', () => {\n      for (const item of [\n        { type: 'default', cls: '.ant-list' },\n        { type: 'small', cls: '.ant-list-sm' },\n        { type: 'large', cls: '.ant-list-lg' }\n      ]) {\n        it(`[${item.type}]`, () => {\n          context.nzSize = item.type as NzSizeLDSType;\n          fixture.detectChanges();\n          expect(dl.query(By.css(item.cls)) != null).toBe(true);\n        });\n      }\n    });\n\n    describe('#nzSplit', () => {\n      for (const value of [true, false]) {\n        it(`[${value}]`, () => {\n          context.nzSplit = value;\n          fixture.detectChanges();\n          expect(dl.query(By.css('.ant-list-split')) != null).toBe(value);\n        });\n      }\n    });\n\n    describe('#nzLoading', () => {\n      for (const value of [true, false]) {\n        it(`[${value}]`, () => {\n          context.nzLoading = value;\n          fixture.detectChanges();\n          expect(dl.query(By.css('.ant-list-loading')) != null).toBe(value);\n        });\n      }\n\n      it('should be minimum area block when data is empty', () => {\n        context.nzLoading = true;\n        context.data = [];\n        fixture.detectChanges();\n        expect(dl.query(By.css('.ant-spin-nested-loading'))).not.toBeNull();\n      });\n    });\n\n    describe('#nzDataSource', () => {\n      it('should working', () => {\n        expect(dl.queryAll(By.css('nz-list-item')).length).toBe(context.data!.length);\n      });\n\n      it('should be render empty text when data source is empty', () => {\n        expect(dl.queryAll(By.css('.ant-list-empty-text')).length).toBe(0);\n        context.data = [];\n        fixture.detectChanges();\n        expect(dl.queryAll(By.css('.ant-list-empty-text')).length).toBe(1);\n      });\n\n      it('should be ignore empty text when unspecified data source', () => {\n        context.data = undefined;\n        fixture.detectChanges();\n        expect(dl.queryAll(By.css('.ant-list-empty-text')).length).toBe(0);\n      });\n    });\n\n    it('#nzGrid', () => {\n      const colCls = `.ant-col-${context.nzGrid.span}`;\n      expect(dl.queryAll(By.css(colCls)).length).toBe(context.data!.length);\n    });\n\n    it('#loadMore', () => {\n      expect(dl.query(By.css('.loadmore')) != null).toBe(true);\n    });\n\n    it('#pagination', () => {\n      expect(dl.query(By.css('.pagination')) != null).toBe(true);\n    });\n\n    it('should be use split main and extra when item layout is vertical', () => {\n      context.nzItemLayout = 'vertical';\n      fixture.detectChanges();\n      expect(dl.query(By.css('.ant-list-item-main')) != null).toBe(true);\n      expect(dl.query(By.css('.ant-list-item-extra')) != null).toBe(true);\n    });\n\n    it('should display the asynchronous action', fakeAsync(() => {\n      tick(2000);\n      fixture.detectChanges();\n      expect(dl.query(By.css('.ant-list-item-action')) != null).toBe(true);\n    }));\n  });\n\n  describe('item', () => {\n    let fixtureTemp: ComponentFixture<TestListItemComponent>;\n\n    beforeEach(() => {\n      fixtureTemp = TestBed.createComponent(TestListItemComponent);\n      fixtureTemp.detectChanges();\n    });\n\n    it('with string', () => {\n      expect(\n        (\n          fixtureTemp.debugElement.query(By.css('#item-string .ant-list-item')).nativeElement as HTMLElement\n        ).textContent!.includes('content')\n      ).toBe(true);\n      expect(fixtureTemp.debugElement.query(By.css('#item-string .ant-list-item-action')) != null).toBe(true);\n      expect(fixtureTemp.debugElement.query(By.css('#item-string .extra-logo')) != null).toBe(true);\n    });\n\n    it('with custom template of [nzContent]', () => {\n      expect(fixtureTemp.debugElement.query(By.css('#item-template .item-content')) != null).toBe(true);\n    });\n\n    it('#nzNoFlex', () => {\n      expect(fixtureTemp.debugElement.query(By.css('#item-string .ant-list-item-no-flex')) != null).toBe(false);\n      fixtureTemp.componentInstance.noFlex = true;\n      fixtureTemp.detectChanges();\n      expect(fixtureTemp.debugElement.query(By.css('#item-string .ant-list-item-no-flex')) != null).toBe(true);\n    });\n  });\n\n  describe('item-meta', () => {\n    let fixtureTemp: ComponentFixture<TestListItemComponent>;\n\n    beforeEach(() => {\n      fixtureTemp = TestBed.createComponent(TestListItemComponent);\n      fixtureTemp.detectChanges();\n    });\n\n    it('with string', () => {\n      expect(fixtureTemp.debugElement.query(By.css('#item-string .ant-list-item-meta-title')) != null).toBe(true);\n      expect(fixtureTemp.debugElement.query(By.css('#item-string .ant-list-item-meta-description')) != null).toBe(true);\n      expect(fixtureTemp.debugElement.query(By.css('#item-string .ant-list-item-meta-avatar')) != null).toBe(true);\n    });\n\n    it('with custom template', () => {\n      expect(fixtureTemp.debugElement.query(By.css('#item-template .item-title')) != null).toBe(true);\n      expect(fixtureTemp.debugElement.query(By.css('#item-template .item-desc')) != null).toBe(true);\n      expect(fixtureTemp.debugElement.query(By.css('#item-template .item-avatar')) != null).toBe(true);\n    });\n  });\n});\n\ndescribe('list RTL', () => {\n  let fixture: ComponentFixture<NzTestListRtlComponent>;\n  let componentElement: HTMLElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideZoneChangeDetection()]\n    });\n    fixture = TestBed.createComponent(NzTestListRtlComponent);\n    componentElement = fixture.debugElement.query(By.directive(NzListComponent)).nativeElement;\n    fixture.detectChanges();\n  });\n\n  it('should className correct on dir change', () => {\n    expect(componentElement.classList).toContain('ant-list-rtl');\n    fixture.componentInstance.direction = 'ltr';\n    fixture.detectChanges();\n    expect(componentElement.classList).not.toContain('ant-list-rtl');\n  });\n});\n\n@Component({\n  imports: [NzListModule, AsyncPipe],\n  selector: 'nz-test-list',\n  template: `\n    <nz-list\n      #comp\n      [nzDataSource]=\"data\"\n      [nzItemLayout]=\"nzItemLayout\"\n      [nzBordered]=\"nzBordered\"\n      [nzFooter]=\"nzFooter\"\n      [nzHeader]=\"nzHeader\"\n      [nzLoading]=\"nzLoading\"\n      [nzSize]=\"nzSize\"\n      [nzSplit]=\"nzSplit\"\n      [nzGrid]=\"nzGrid\"\n      [nzRenderItem]=\"item\"\n      [nzLoadMore]=\"loadMore\"\n      [nzPagination]=\"pagination\"\n    >\n      <ng-template #item let-item>\n        <nz-list-item [nzExtra]=\"extra\">\n          <nz-list-item-meta\n            nzTitle=\"title\"\n            nzAvatar=\"https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png\"\n            nzDescription=\"Ant Design, a design language for background applications, is refined by Ant UED Team\"\n          />\n          <ul nz-list-item-actions>\n            @for (action of actions$ | async; track action) {\n              <nz-list-item-action>{{ action }}</nz-list-item-action>\n            }\n          </ul>\n        </nz-list-item>\n      </ng-template>\n      <ng-template #loadMore>\n        <div class=\"loadmore\">load more</div>\n      </ng-template>\n      <ng-template #pagination>\n        <div class=\"pagination\">pagination</div>\n      </ng-template>\n      <ng-template #extra>\n        <span class=\"extra-content\">extra content</span>\n      </ng-template>\n    </nz-list>\n  `\n})\nclass TestListComponent {\n  @ViewChild('comp', { static: false }) comp!: NzListComponent;\n  nzItemLayout: NzDirectionVHType = 'horizontal';\n  nzBordered = false;\n  nzFooter = 'footer';\n  nzHeader = 'header';\n  nzLoading = false;\n  nzSize: NzSizeLDSType = 'default';\n  nzSplit = true;\n  data?: string[] = [\n    'Racing car sprays burning fuel into crowd.',\n    'Japanese princess to wed commoner.',\n    'Racing car sprays burning fuel into crowd.',\n    'Japanese princess to wed commoner.'\n  ];\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  nzGrid: any = { gutter: 16, span: 12 };\n  actions$: Observable<string[]> = timer(500).pipe(map(() => ['Edit', 'Delete']));\n}\n\n@Component({\n  imports: [NzListModule],\n  template: `\n    <button (click)=\"footer = nzFooter\" id=\"change\">change</button>\n    <nz-list [nzFooter]=\"footer\" [nzHeader]=\"nzHeader\">\n      <ng-template #nzFooter><p class=\"list-footer\">footer</p></ng-template>\n      <ng-template #nzHeader><p class=\"list-header\">header</p></ng-template>\n    </nz-list>\n  `\n})\nclass TestListWithTemplateComponent {\n  @ViewChild('nzFooter', { static: false }) nzFooter!: TemplateRef<void>;\n\n  footer: string | TemplateRef<void> = 'footer with string';\n}\n\n@Component({\n  imports: [NzIconModule, NzListModule],\n  template: `\n    <nz-list id=\"item-string\">\n      <nz-list-item nzContent=\"content\" [nzActions]=\"[action]\" [nzExtra]=\"extra\" [nzNoFlex]=\"noFlex\">\n        <ng-template #action>\n          <nz-icon nzType=\"star-o\" style=\"margin-right: 8px;\" />\n          156\n        </ng-template>\n        <ng-template #extra>\n          <img\n            width=\"272\"\n            class=\"extra-logo\"\n            alt=\"logo\"\n            src=\"https://gw.alipayobjects.com/zos/rmsportal/mqaQswcyDLcXyDKnZfES.png\"\n          />\n        </ng-template>\n        <nz-list-item-meta\n          nzTitle=\"title\"\n          nzAvatar=\"https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png\"\n          nzDescription=\"Ant Design, a design language for background applications, is refined by Ant UED Team\"\n        />\n      </nz-list-item>\n    </nz-list>\n    <nz-list id=\"item-template\">\n      <nz-list-item [nzContent]=\"nzContent\">\n        <ng-template #nzContent><p class=\"item-content\">nzContent</p></ng-template>\n        <nz-list-item-meta [nzTitle]=\"nzTitle\" [nzAvatar]=\"nzAvatar\" [nzDescription]=\"nzDescription\">\n          <ng-template #nzTitle><p class=\"item-title\">nzTitle</p></ng-template>\n          <ng-template #nzAvatar><p class=\"item-avatar\">nzAvatar</p></ng-template>\n          <ng-template #nzDescription><p class=\"item-desc\">nzDescription</p></ng-template>\n        </nz-list-item-meta>\n      </nz-list-item>\n    </nz-list>\n  `\n})\nclass TestListItemComponent {\n  noFlex = false;\n}\n\n@Component({\n  imports: [BidiModule, TestListComponent],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-test-list />\n    </div>\n  `\n})\nexport class NzTestListRtlComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n}\n"
  },
  {
    "path": "components/list/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/list/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './interface';\nexport { NzListItemMetaComponent } from './list-item-meta.component';\nexport { NzListItemComponent } from './list-item.component';\nexport { NzListComponent } from './list.component';\nexport { NzListModule } from './list.module';\nexport * from './list-cell';\nexport * from './list-item-cell';\nexport * from './list-item-meta-cell';\n"
  },
  {
    "path": "components/list/style/bordered.less",
    "content": "@import '../../style/themes/index';\n\n.@{list-prefix-cls}-bordered {\n  border: 1px solid @border-color-base;\n  border-radius: @border-radius-base;\n  .@{list-prefix-cls}-header {\n    padding-right: @padding-lg;\n    padding-left: @padding-lg;\n  }\n\n  .@{list-prefix-cls}-footer {\n    padding-right: @padding-lg;\n    padding-left: @padding-lg;\n  }\n\n  .@{list-prefix-cls}-item {\n    padding-right: @padding-lg;\n    padding-left: @padding-lg;\n  }\n\n  .@{list-prefix-cls}-pagination {\n    margin: @margin-md @margin-lg;\n  }\n\n  &.@{list-prefix-cls}-sm {\n    .@{list-prefix-cls}-item {\n      padding: @list-item-padding-sm;\n    }\n    .@{list-prefix-cls}-header,\n    .@{list-prefix-cls}-footer {\n      padding: @list-item-padding-sm;\n    }\n  }\n\n  &.@{list-prefix-cls}-lg {\n    .@{list-prefix-cls}-item {\n      padding: @list-item-padding-lg;\n    }\n    .@{list-prefix-cls}-header,\n    .@{list-prefix-cls}-footer {\n      padding: @list-item-padding-lg;\n    }\n  }\n}\n"
  },
  {
    "path": "components/list/style/customize.less",
    "content": "@import '../../style/themes/index';\n\n@list-prefix-cls: ~'@{ant-prefix}-list';\n@card-prefix-cls: ~'@{ant-prefix}-card';\n\n.@{list-prefix-cls} {\n  // =================== Dard Hook Components ===================\n  .@{card-prefix-cls} {\n    & when (@theme = dark) {\n      background: @list-customize-card-bg;\n    }\n  }\n}\n"
  },
  {
    "path": "components/list/style/entry.less",
    "content": "@import './index.less';\n@import '../../empty/style/entry.less';\n@import '../../spin/style/entry.less';\n@import '../../pagination/style/entry.less';\n@import '../../grid/style/entry.less';\n@import \"./patch\";\n"
  },
  {
    "path": "components/list/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import './customize.less';\n\n@list-prefix-cls: ~'@{ant-prefix}-list';\n\n.@{list-prefix-cls} {\n  .reset-component();\n\n  position: relative;\n\n  * {\n    outline: none;\n  }\n\n  &-pagination {\n    margin-top: @margin-lg;\n    text-align: right;\n\n    // https://github.com/ant-design/ant-design/issues/20037\n    .@{ant-prefix}-pagination-options {\n      text-align: left;\n    }\n  }\n\n  &-more {\n    margin-top: @margin-sm;\n    text-align: center;\n\n    button {\n      padding-right: 32px;\n      padding-left: 32px;\n    }\n  }\n\n  &-spin {\n    min-height: 40px;\n    text-align: center;\n  }\n\n  &-empty-text {\n    padding: @list-empty-text-padding;\n    color: @disabled-color;\n    font-size: @font-size-base;\n    text-align: center;\n  }\n\n  &-items {\n    margin: 0;\n    padding: 0;\n    list-style: none;\n  }\n\n  &-item {\n    display: flex;\n    align-items: center;\n    justify-content: space-between;\n    padding: @list-item-padding;\n    color: @text-color;\n\n    &-meta {\n      display: flex;\n      flex: 1;\n      align-items: flex-start;\n      max-width: 100%;\n\n      &-avatar {\n        margin-right: @list-item-meta-avatar-margin-right;\n      }\n\n      &-content {\n        flex: 1 0;\n        width: 0;\n        color: @text-color;\n      }\n\n      &-title {\n        margin-bottom: 4px;\n        color: @text-color;\n        font-size: @font-size-base;\n        line-height: @line-height-base;\n\n        > a {\n          color: @text-color;\n          transition: all 0.3s;\n\n          &:hover {\n            color: @primary-color;\n          }\n        }\n      }\n\n      &-description {\n        color: @text-color-secondary;\n        font-size: @list-item-meta-description-font-size;\n        line-height: @line-height-base;\n      }\n    }\n\n    &-action {\n      flex: 0 0 auto;\n      margin-left: 48px;\n      padding: 0;\n      font-size: 0;\n      list-style: none;\n\n      & > li {\n        position: relative;\n        display: inline-block;\n        padding: 0 @padding-xs;\n        color: @text-color-secondary;\n        font-size: @font-size-base;\n        line-height: @line-height-base;\n        text-align: center;\n\n        &:first-child {\n          padding-left: 0;\n        }\n      }\n\n      &-split {\n        position: absolute;\n        top: 50%;\n        right: 0;\n        width: 1px;\n        height: 14px;\n        margin-top: -7px;\n        background-color: @border-color-split;\n      }\n    }\n  }\n\n  &-header {\n    background: @list-header-background;\n  }\n\n  &-footer {\n    background: @list-footer-background;\n  }\n\n  &-header,\n  &-footer {\n    padding-top: @padding-sm;\n    padding-bottom: @padding-sm;\n  }\n\n  &-empty {\n    padding: @padding-md 0;\n    color: @text-color-secondary;\n    font-size: 12px;\n    text-align: center;\n  }\n\n  &-split &-item {\n    border-bottom: 1px solid @border-color-split;\n\n    &:last-child {\n      border-bottom: none;\n    }\n  }\n\n  &-split &-header {\n    border-bottom: 1px solid @border-color-split;\n  }\n\n  &-split&-empty &-footer {\n    border-top: 1px solid @border-color-split;\n  }\n\n  &-loading &-spin-nested-loading {\n    min-height: 32px;\n  }\n\n  &-split&-something-after-last-item .@{ant-prefix}-spin-container > &-items > &-item:last-child {\n    border-bottom: 1px solid @border-color-split;\n  }\n\n  &-lg &-item {\n    padding: @list-item-padding-lg;\n  }\n\n  &-sm &-item {\n    padding: @list-item-padding-sm;\n  }\n\n  &-vertical &-item {\n    align-items: initial;\n\n    &-main {\n      display: block;\n      flex: 1;\n    }\n\n    &-extra {\n      margin-left: 40px;\n    }\n\n    &-meta {\n      margin-bottom: @list-item-meta-margin-bottom;\n\n      &-title {\n        margin-bottom: @list-item-meta-title-margin-bottom;\n        color: @heading-color;\n        font-size: @font-size-lg;\n        line-height: 24px;\n      }\n    }\n\n    &-action {\n      margin-top: @padding-md;\n      margin-left: auto;\n\n      > li {\n        padding: 0 @padding-md;\n\n        &:first-child {\n          padding-left: 0;\n        }\n      }\n    }\n  }\n\n  &-grid .@{ant-prefix}-col > &-item {\n    display: block;\n    max-width: 100%;\n    margin-bottom: @margin-md;\n    padding-top: 0;\n    padding-bottom: 0;\n    border-bottom: none;\n  }\n\n  // ============================ without flex ============================\n  &-item-no-flex {\n    display: block;\n  }\n\n  // Horizontal\n  &:not(.@{list-prefix-cls}-vertical) {\n    .@{list-prefix-cls}-item-no-flex {\n      .@{list-prefix-cls}-item-action {\n        float: right;\n      }\n    }\n  }\n}\n\n@import './bordered';\n@import './responsive';\n@import './rtl';\n"
  },
  {
    "path": "components/list/style/patch.less",
    "content": "nz-list,\nnz-list nz-spin,\nnz-list-header,\nnz-list-footer,\nnz-list-pagination,\nnz-list-empty,\nnz-list-item-extra {\n  display: block;\n}\n"
  },
  {
    "path": "components/list/style/responsive.less",
    "content": "@media screen and (max-width: @screen-md) {\n  .@{list-prefix-cls} {\n    &-item {\n      &-action {\n        margin-left: 24px;\n      }\n    }\n  }\n\n  .@{list-prefix-cls}-vertical {\n    .@{list-prefix-cls}-item {\n      &-extra {\n        margin-left: 24px;\n      }\n    }\n  }\n}\n\n@media screen and (max-width: @screen-sm) {\n  .@{list-prefix-cls} {\n    &-item {\n      flex-wrap: wrap;\n\n      &-action {\n        margin-left: 12px;\n      }\n    }\n  }\n\n  .@{list-prefix-cls}-vertical {\n    .@{list-prefix-cls}-item {\n      flex-wrap: wrap-reverse;\n\n      &-main {\n        min-width: 220px;\n      }\n\n      &-extra {\n        margin: auto auto 16px;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/list/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import './customize.less';\n\n@list-prefix-cls: ~'@{ant-prefix}-list';\n\n.@{list-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n    text-align: right;\n\n    // fix for virtual scroll style attribute > (direction:ltr)\n    .ReactVirtualized__List .@{list-prefix-cls}-item {\n      direction: rtl;\n    }\n  }\n\n  &-pagination {\n    .@{list-prefix-cls}-rtl & {\n      text-align: left;\n    }\n  }\n\n  &-item {\n    &-meta {\n      &-avatar {\n        .@{list-prefix-cls}-rtl & {\n          margin-right: 0;\n          margin-left: @list-item-meta-avatar-margin-right;\n        }\n      }\n    }\n\n    &-action {\n      .@{list-prefix-cls}-rtl & {\n        margin-right: 48px;\n        margin-left: 0;\n      }\n\n      & > li:first-child {\n        .@{list-prefix-cls}.@{list-prefix-cls}-rtl & {\n          padding-right: 0;\n          padding-left: @padding-md;\n        }\n      }\n\n      &-split {\n        .@{list-prefix-cls}-rtl & {\n          right: auto;\n          left: 0;\n        }\n      }\n    }\n  }\n\n  &-vertical &-item {\n    &-extra {\n      .@{list-prefix-cls}-rtl& {\n        margin-right: 40px;\n        margin-left: 0;\n      }\n    }\n\n    &-action {\n      .@{list-prefix-cls}-rtl& {\n        margin-right: auto;\n      }\n\n      > li {\n        &:first-child {\n          .@{list-prefix-cls}-rtl & {\n            padding-right: 0;\n            padding-left: @padding-md;\n          }\n        }\n      }\n    }\n  }\n\n  // Horizontal\n  &:not(.@{list-prefix-cls}-vertical) {\n    .@{list-prefix-cls}-item-no-flex {\n      .@{list-prefix-cls}-item-action {\n        .@{list-prefix-cls}-rtl & {\n          float: left;\n        }\n      }\n    }\n  }\n}\n\n// responsive\n@media screen and (max-width: @screen-md) {\n  .@{list-prefix-cls} {\n    &-item {\n      &-action {\n        .@{list-prefix-cls}-rtl & {\n          margin-right: 24px;\n          margin-left: 0;\n        }\n      }\n    }\n  }\n\n  .@{list-prefix-cls}-vertical {\n    .@{list-prefix-cls}-item {\n      &-extra {\n        .@{list-prefix-cls}-rtl & {\n          margin-right: 24px;\n          margin-left: 0;\n        }\n      }\n    }\n  }\n}\n\n@media screen and (max-width: @screen-sm) {\n  .@{list-prefix-cls} {\n    &-item {\n      &-action {\n        .@{list-prefix-cls}-rtl & {\n          margin-right: 22px;\n          margin-left: 0;\n        }\n      }\n    }\n  }\n\n  .@{list-prefix-cls}-vertical {\n    .@{list-prefix-cls}-item {\n      &-extra {\n        // to override margins on rtl view\n        .@{list-prefix-cls}-rtl& {\n          margin: auto auto 16px;\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/mention/config.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport const NZ_MENTION_CONFIG = {\n  split: ' '\n};\n"
  },
  {
    "path": "components/mention/demo/async.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 异步加载\n  en-US: Asynchronous loading\n---\n\n## zh-CN\n\n匹配内容列表为异步返回时。\n\n## en-US\n\nasync\n"
  },
  {
    "path": "components/mention/demo/async.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { MentionOnSearchTypes, NzMentionModule } from 'ng-zorro-antd/mention';\n\n@Component({\n  selector: 'nz-demo-mention-async',\n  imports: [FormsModule, NzInputModule, NzMentionModule],\n  template: `\n    <nz-mention [nzSuggestions]=\"suggestions\" [nzLoading]=\"loading\" (nzOnSearchChange)=\"onSearchChange($event)\">\n      <textarea rows=\"1\" nzMentionTrigger nz-input [(ngModel)]=\"inputValue\"></textarea>\n    </nz-mention>\n  `\n})\nexport class NzDemoMentionAsyncComponent {\n  inputValue?: string;\n  loading = false;\n  suggestions: string[] = [];\n\n  onSearchChange({ value }: MentionOnSearchTypes): void {\n    console.log(`search: ${value}`);\n    this.loading = true;\n    this.fetchSuggestions(value, suggestions => {\n      console.log(suggestions);\n      this.suggestions = suggestions;\n      this.loading = false;\n    });\n  }\n\n  fetchSuggestions(value: string, callback: (suggestions: string[]) => void): void {\n    const users = ['afc163', 'benjycui', 'yiminghe', 'jljsj33', 'dqaria', 'RaoHai'];\n    setTimeout(() => callback(users.filter(item => item.indexOf(value) !== -1)), 500);\n  }\n}\n"
  },
  {
    "path": "components/mention/demo/auto-size.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 自动大小\n  en-US: autoSize\n---\n\n## zh-CN\n\n自适应内容高度。\n\n## en-US\n\nHeight autoSize.\n"
  },
  {
    "path": "components/mention/demo/auto-size.ts",
    "content": "import { CdkTextareaAutosize } from '@angular/cdk/text-field';\nimport { Component, model } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzMentionModule } from 'ng-zorro-antd/mention';\n\n@Component({\n  selector: 'nz-demo-mention-auto-size',\n  imports: [FormsModule, NzMentionModule, NzInputModule, CdkTextareaAutosize],\n  template: `\n    <nz-mention [nzSuggestions]=\"suggestions\" (nzOnSelect)=\"onSelect($event)\">\n      <textarea\n        nz-input\n        placeholder=\"input here\"\n        nzMentionTrigger\n        [(ngModel)]=\"inputValue\"\n        cdkTextareaAutosize\n      ></textarea>\n    </nz-mention>\n  `\n})\nexport class NzDemoMentionAutoSizeComponent {\n  readonly inputValue = model('@afc163');\n  suggestions = ['afc163', 'benjycui', 'yiminghe', 'RaoHai', '中文', 'にほんご'];\n\n  onSelect(suggestion: string): void {\n    console.log(`onSelect ${suggestion}`);\n  }\n}\n"
  },
  {
    "path": "components/mention/demo/avatar.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 头像\n  en-US: Icon Image\n---\n\n## zh-CN\n\n自定义建议（含头像）\n\n注意，`nzSuggestions` 不为 `string[]` 时，需要提供 `nzValueWith`。\n\n## en-US\n\nCustomize suggestions.\n"
  },
  {
    "path": "components/mention/demo/avatar.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzAvatarModule } from 'ng-zorro-antd/avatar';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzMentionModule } from 'ng-zorro-antd/mention';\n\n@Component({\n  selector: 'nz-demo-mention-avatar',\n  imports: [FormsModule, NzAvatarModule, NzInputModule, NzMentionModule],\n  template: `\n    <nz-mention [nzSuggestions]=\"webFrameworks\" [nzValueWith]=\"valueWith\" (nzOnSelect)=\"onSelect($event)\">\n      <textarea rows=\"1\" nz-input nzMentionTrigger [(ngModel)]=\"inputValue\"></textarea>\n      <ng-container *nzMentionSuggestion=\"let framework\">\n        <nz-avatar nzSize=\"small\" [nzText]=\"framework.name\" [nzSrc]=\"framework.icon\" />\n        <span>{{ framework.name }} - {{ framework.type }}</span>\n      </ng-container>\n    </nz-mention>\n  `,\n  styles: `\n    .ant-avatar.ant-avatar-sm {\n      width: 14px;\n      height: 14px;\n      margin-right: 8px;\n      position: relative;\n    }\n  `\n})\nexport class NzDemoMentionAvatarComponent {\n  inputValue?: string;\n  webFrameworks = [\n    { name: 'React', type: 'JavaScript', icon: 'https://zos.alipayobjects.com/rmsportal/LFIeMPzdLcLnEUe.svg' },\n    { name: 'Angular', type: 'JavaScript', icon: 'https://zos.alipayobjects.com/rmsportal/PJTbxSvzYWjDZnJ.png' },\n    { name: 'Dva', type: 'JavaScript', icon: 'https://zos.alipayobjects.com/rmsportal/EYPwSeEJKxDtVxI.png' },\n    { name: 'Flask', type: 'Python', icon: 'https://zos.alipayobjects.com/rmsportal/xaypBUijfnpAlXE.png' }\n  ];\n\n  valueWith = (data: { name: string; type: string; icon: string }): string => data.name;\n\n  onSelect(value: string): void {\n    console.log(value);\n  }\n}\n"
  },
  {
    "path": "components/mention/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本使用\n  en-US: Basic\n---\n\n## zh-CN\n\n基本使用\n\n## en-US\n\nBasic usage.\n"
  },
  {
    "path": "components/mention/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzMentionModule } from 'ng-zorro-antd/mention';\n\n@Component({\n  selector: 'nz-demo-mention-basic',\n  imports: [FormsModule, NzInputModule, NzMentionModule],\n  template: `\n    <nz-mention [nzSuggestions]=\"suggestions\" (nzOnSelect)=\"onSelect($event)\">\n      <textarea\n        rows=\"1\"\n        placeholder=\"input here\"\n        nzMentionTrigger\n        nz-input\n        [(ngModel)]=\"inputValue\"\n        (ngModelChange)=\"onChange($event)\"\n      ></textarea>\n    </nz-mention>\n  `\n})\nexport class NzDemoMentionBasicComponent {\n  inputValue: string = '@afc163';\n  suggestions = ['afc163', 'benjycui', 'yiminghe', 'RaoHai', '中文', 'にほんご'];\n\n  onChange(value: string): void {\n    console.log(value);\n  }\n\n  onSelect(suggestion: string): void {\n    console.log(`onSelect ${suggestion}`);\n  }\n}\n"
  },
  {
    "path": "components/mention/demo/clear.md",
    "content": "---\norder: 11\nversion: 20.3.0\ntitle:\n  zh-CN: 带移除图标\n  en-US: With clear icon\n---\n\n## zh-CN\n\n自定义清除按钮。\n\n## en-US\n\nCustomize clear button.\n"
  },
  {
    "path": "components/mention/demo/clear.ts",
    "content": "import { Component, model } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzMentionModule } from 'ng-zorro-antd/mention';\n\n@Component({\n  selector: 'nz-demo-mention-clear',\n  imports: [FormsModule, NzInputModule, NzMentionModule],\n  template: `\n    <nz-mention [nzSuggestions]=\"suggestions\" (nzOnSelect)=\"onSelect($event)\" nzAllowClear (nzOnClear)=\"onClear()\">\n      <textarea rows=\"1\" placeholder=\"input here\" nzMentionTrigger nz-input [(ngModel)]=\"inputValue\"></textarea>\n    </nz-mention>\n    <br />\n    <br />\n    <nz-mention [nzSuggestions]=\"suggestions\" (nzOnSelect)=\"onSelect($event)\" nzAllowClear (nzOnClear)=\"onClear()\">\n      <textarea rows=\"3\" placeholder=\"input here\" nzMentionTrigger nz-input [(ngModel)]=\"inputValue\"></textarea>\n    </nz-mention>\n  `\n})\nexport class NzDemoMentionClearComponent {\n  inputValue = model('@afc163');\n  suggestions = ['afc163', 'benjycui', 'yiminghe', 'RaoHai', '中文', 'にほんご'];\n\n  onSelect(e: string): void {\n    console.log(e);\n  }\n\n  onClear(): void {\n    console.log('onClear');\n  }\n}\n"
  },
  {
    "path": "components/mention/demo/custom-tag.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 自定义建议\n  en-US: Customize Suggestion\n---\n\n## zh-CN\n\n自定义建议\n\n注意，`nzSuggestions` 不为 `string[]` 时，需要提供 `nzValueWith`。\n\n## en-US\n\nCustomize suggestions.\n"
  },
  {
    "path": "components/mention/demo/custom-tag.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzMentionModule } from 'ng-zorro-antd/mention';\n\n@Component({\n  selector: 'nz-demo-mention-custom-tag',\n  imports: [FormsModule, NzInputModule, NzMentionModule],\n  template: `\n    <nz-mention [nzSuggestions]=\"webFrameworks\" [nzValueWith]=\"valueWith\" (nzOnSelect)=\"onSelect($event)\">\n      <textarea rows=\"1\" placeholder=\"@someone\" nz-input nzMentionTrigger [(ngModel)]=\"inputValue\"></textarea>\n      <ng-container *nzMentionSuggestion=\"let framework\">\n        <span>{{ framework.name }} - {{ framework.type }}</span>\n      </ng-container>\n    </nz-mention>\n  `\n})\nexport class NzDemoMentionCustomTagComponent {\n  inputValue?: string;\n  webFrameworks = [\n    { name: 'React', type: 'JavaScript' },\n    { name: 'Angular', type: 'JavaScript' },\n    { name: 'Laravel', type: 'PHP' },\n    { name: 'Flask', type: 'Python' },\n    { name: 'Django', type: 'Python' }\n  ];\n\n  valueWith = (data: { name: string; type: string }): string => data.name;\n\n  onSelect(value: string): void {\n    console.log(value);\n  }\n}\n"
  },
  {
    "path": "components/mention/demo/form.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 配合 Form 使用\n  en-US: With Form\n---\n\n## zh-CN\n\n受控模式，例如配合 Form 使用。\n\n## en-US\n\nControlled mode, for example, to work with `Form`.\n"
  },
  {
    "path": "components/mention/demo/form.ts",
    "content": "import { Component, inject, ViewChild } from '@angular/core';\nimport {\n  AbstractControl,\n  FormBuilder,\n  FormControl,\n  ReactiveFormsModule,\n  ValidationErrors,\n  ValidatorFn,\n  Validators\n} from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzMentionComponent, NzMentionModule } from 'ng-zorro-antd/mention';\n\n@Component({\n  selector: 'nz-demo-mention-form',\n  imports: [ReactiveFormsModule, NzButtonModule, NzFormModule, NzInputModule, NzMentionModule],\n  template: `\n    <form nz-form [formGroup]=\"validateForm\" (ngSubmit)=\"submitForm()\">\n      <nz-form-item>\n        <nz-form-label [nzSm]=\"6\" nzFor=\"mention\">Top coders</nz-form-label>\n        <nz-form-control [nzSm]=\"16\" nzErrorTip=\"More than one must be selected!\">\n          <nz-mention #mentions [nzSuggestions]=\"suggestions\">\n            <textarea\n              rows=\"1\"\n              id=\"mention\"\n              placeholder=\"input here\"\n              formControlName=\"mention\"\n              nzMentionTrigger\n              nz-input\n            ></textarea>\n          </nz-mention>\n        </nz-form-control>\n      </nz-form-item>\n      <nz-form-item nz-row style=\"margin-bottom:8px;\">\n        <nz-form-control [nzSpan]=\"14\" [nzOffset]=\"6\">\n          <div class=\"cta-wrapper\">\n            <button type=\"button\" nz-button nzType=\"primary\" (click)=\"submitForm()\">Submit</button>\n            <button type=\"button\" nz-button (click)=\"resetForm()\">Reset</button>\n          </div>\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `,\n  styles: `\n    .cta-wrapper {\n      display: flex;\n      gap: 1rem;\n    }\n  `\n})\nexport class NzDemoMentionFormComponent {\n  readonly suggestions = ['afc163', 'benjycui', 'yiminghe', 'RaoHai', '中文', 'にほんご', 'ParsaArvaneh'];\n  @ViewChild('mentions', { static: true }) mentionChild!: NzMentionComponent;\n\n  mentionValidator: ValidatorFn = (control: AbstractControl): ValidationErrors => {\n    if (!control.value) {\n      return { required: true };\n    } else if (this.mentionChild?.getMentions().length < 2) {\n      return { confirm: true, error: true };\n    }\n    return {};\n  };\n\n  private fb = inject(FormBuilder);\n  validateForm = this.fb.group({\n    mention: ['@afc163 ', [Validators.required, this.mentionValidator]]\n  });\n\n  get mention(): FormControl<string | null> {\n    return this.validateForm.controls.mention;\n  }\n\n  submitForm(): void {\n    this.mention.markAsDirty();\n    this.mention.updateValueAndValidity();\n    if (this.mention.valid) {\n      console.log('Submit!!!', this.mention.value);\n      console.log(this.mentionChild.getMentions());\n    } else {\n      console.log('Errors in form!!!');\n    }\n  }\n\n  resetForm(): void {\n    this.validateForm.reset({\n      mention: '@afc163 '\n    });\n  }\n}\n"
  },
  {
    "path": "components/mention/demo/placement.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 向上展开\n  en-US: Placement\n---\n\n## zh-CN\n\n向上展开建议。\n\n## en-US\n\nChange the suggestions placement.\n"
  },
  {
    "path": "components/mention/demo/placement.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzMentionModule } from 'ng-zorro-antd/mention';\n\n@Component({\n  selector: 'nz-demo-mention-placement',\n  imports: [FormsModule, NzInputModule, NzMentionModule],\n  template: `\n    <nz-mention nzPlacement=\"top\" [nzSuggestions]=\"suggestions\" (nzOnSelect)=\"onSelect($event)\">\n      <textarea\n        rows=\"1\"\n        nzMentionTrigger\n        nz-input\n        [(ngModel)]=\"inputValue\"\n        (ngModelChange)=\"onChange($event)\"\n      ></textarea>\n    </nz-mention>\n  `\n})\nexport class NzDemoMentionPlacementComponent {\n  inputValue?: string;\n  suggestions = ['afc163', 'benjycui', 'yiminghe', 'RaoHai', '中文', 'にほんご'];\n\n  onChange(value: string): void {\n    console.log(value);\n  }\n\n  onSelect(suggestion: string): void {\n    console.log(`onSelect ${suggestion}`);\n  }\n}\n"
  },
  {
    "path": "components/mention/demo/prefix.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 自定义触发字符\n  en-US: Customize Trigger Token\n---\n\n## zh-CN\n\n通过 `nzPrefix` 属性自定义触发字符。默认为 `@`, 可以定义为数组。\n\n## en-US\n\nCustomize Trigger Token by `nzPrefix` props. Default to `@`, `Array<string>` also supported.\n"
  },
  {
    "path": "components/mention/demo/prefix.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { MentionOnSearchTypes, NzMentionModule } from 'ng-zorro-antd/mention';\n\n@Component({\n  selector: 'nz-demo-mention-prefix',\n  imports: [FormsModule, NzInputModule, NzMentionModule],\n  template: `\n    <nz-mention [nzSuggestions]=\"suggestions\" (nzOnSearchChange)=\"onSearchChange($event)\" [nzPrefix]=\"['#', '@']\">\n      <textarea\n        rows=\"1\"\n        placeholder=\"input @ to mention people, # to mention tag\"\n        nzMentionTrigger\n        nz-input\n        [(ngModel)]=\"inputValue\"\n      ></textarea>\n    </nz-mention>\n  `\n})\nexport class NzDemoMentionPrefixComponent {\n  inputValue?: string;\n  suggestions: string[] = [];\n  users = ['afc163', 'benjycui', 'yiminghe', 'RaoHai', '中文', 'にほんご'];\n  tags = ['1.0', '2.0', '3.0'];\n\n  onSearchChange({ value, prefix }: MentionOnSearchTypes): void {\n    console.log('nzOnSearchChange', value, prefix);\n    this.suggestions = prefix === '@' ? this.users : this.tags;\n  }\n}\n"
  },
  {
    "path": "components/mention/demo/preview.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 预览\n  en-US: Preview\n---\n\n## zh-CN\n\n渲染提及\n\n## en-US\n\nRendering the mentions.\n"
  },
  {
    "path": "components/mention/demo/preview.ts",
    "content": "import { CdkTextareaAutosize } from '@angular/cdk/text-field';\nimport { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\n\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzMentionModule } from 'ng-zorro-antd/mention';\nimport { NzTabsModule } from 'ng-zorro-antd/tabs';\n\n@Component({\n  selector: 'nz-demo-mention-preview',\n  imports: [FormsModule, NzInputModule, NzMentionModule, NzTabsModule, CdkTextareaAutosize],\n  template: `\n    <nz-tabs>\n      <nz-tab nzTitle=\"Write\">\n        <nz-mention [nzSuggestions]=\"suggestions\">\n          <textarea\n            nz-input\n            cdkTextareaAutosize\n            cdkAutosizeMinRows=\"4\"\n            cdkAutosizeMaxRows=\"4\"\n            [(ngModel)]=\"inputValue\"\n            (ngModelChange)=\"renderPreView()\"\n            nzMentionTrigger\n          ></textarea>\n        </nz-mention>\n      </nz-tab>\n      <nz-tab nzTitle=\"Preview\">\n        <pre [innerHTML]=\"preview\"></pre>\n      </nz-tab>\n    </nz-tabs>\n  `\n})\nexport class NzDemoMentionPreviewComponent {\n  inputValue: string = 'Switch tab view preview @NG-ZORRO ';\n  preview?: SafeHtml;\n  suggestions = ['NG-ZORRO', 'angular', 'Reactive-Extensions'];\n\n  constructor(private sanitizer: DomSanitizer) {\n    this.renderPreView();\n  }\n\n  getRegExp(prefix: string | string[]): RegExp {\n    const prefixArray = Array.isArray(prefix) ? prefix : [prefix];\n    let prefixToken = prefixArray.join('').replace(/(\\$|\\^)/g, '\\\\$1');\n\n    if (prefixArray.length > 1) {\n      prefixToken = `[${prefixToken}]`;\n    }\n\n    return new RegExp(`(\\\\s|^)(${prefixToken})[^\\\\s]*`, 'g');\n  }\n\n  renderPreView(): void {\n    if (this.inputValue) {\n      const regex = this.getRegExp('@');\n      const previewValue = this.inputValue.replace(\n        regex,\n        match => `<a target=\"_blank\" href=\"https://github.com/${match.trim().substring(1)}\">${match}</a>`\n      );\n      this.preview = this.sanitizer.bypassSecurityTrustHtml(previewValue);\n    }\n  }\n}\n"
  },
  {
    "path": "components/mention/demo/readonly.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 无效或只读\n  en-US: disabled or readOnly\n---\n\n## zh-CN\n\n通过 `disabled` 属性设置是否生效。通过 `readOnly` 属性设置是否只读。\n\n## en-US\n\nConfigurate `disabled` and `readOnly`.\n"
  },
  {
    "path": "components/mention/demo/readonly.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzMentionModule } from 'ng-zorro-antd/mention';\n\n@Component({\n  selector: 'nz-demo-mention-readonly',\n  imports: [FormsModule, NzInputModule, NzMentionModule],\n  template: `\n    <nz-mention [nzSuggestions]=\"suggestions\" style=\"margin-bottom: 8px\">\n      <textarea\n        rows=\"1\"\n        placeholder=\"this is disabled Mention\"\n        nzMentionTrigger\n        nz-input\n        disabled\n        [(ngModel)]=\"inputValue\"\n      ></textarea>\n    </nz-mention>\n    <nz-mention [nzSuggestions]=\"suggestions\">\n      <textarea\n        rows=\"1\"\n        placeholder=\"this is readOnly Mention\"\n        nzMentionTrigger\n        nz-input\n        readOnly\n        [(ngModel)]=\"inputValue\"\n      ></textarea>\n    </nz-mention>\n  `\n})\nexport class NzDemoMentionReadonlyComponent {\n  inputValue?: string;\n  suggestions = ['afc163', 'benjycui', 'yiminghe', 'RaoHai', '中文', 'にほんご'];\n}\n"
  },
  {
    "path": "components/mention/demo/status.md",
    "content": "---\norder: 10\ntitle:\n  zh-CN: 自定义状态\n  en-US: Status\n---\n\n## zh-CN\n\n使用 `nzStatus` 为 Mentions 添加状态。可选 `error` 或者 `warning`。\n\n## en-US\n\nAdd status to Mentions with `nzStatus`, which could be `error` or `warning`。\n"
  },
  {
    "path": "components/mention/demo/status.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzMentionModule } from 'ng-zorro-antd/mention';\n\n@Component({\n  selector: 'nz-demo-mention-status',\n  imports: [FormsModule, NzInputModule, NzMentionModule],\n  template: `\n    <nz-mention [nzSuggestions]=\"suggestions\" nzStatus=\"error\" style=\"margin-bottom: 8px;\">\n      <textarea rows=\"1\" nz-input placeholder=\"input here\" [(ngModel)]=\"inputValue\" nzMentionTrigger></textarea>\n    </nz-mention>\n    <nz-mention [nzSuggestions]=\"suggestions\" nzStatus=\"warning\">\n      <textarea rows=\"1\" nz-input placeholder=\"input here\" [(ngModel)]=\"inputValue\" nzMentionTrigger></textarea>\n    </nz-mention>\n  `\n})\nexport class NzDemoMentionStatusComponent {\n  inputValue: string = '@afc163';\n  suggestions = ['afc163', 'benjycui', 'yiminghe', 'RaoHai', '中文', 'にほんご'];\n}\n"
  },
  {
    "path": "components/mention/demo/variant.md",
    "content": "---\norder: 12\nversion: 20.3.0\ntitle:\n  zh-CN: 形态变体\n  en-US: Variants\n---\n\n## zh-CN\n\nMentions 形态变体，可选 `outlined` `filled` `borderless` `underlined` 四种形态。\n\n## en-US\n\nVariants of Mentions, there are four variants: `outlined` `filled` `borderless` and `underlined`.\n"
  },
  {
    "path": "components/mention/demo/variant.ts",
    "content": "import { Component, model } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzVariant } from 'ng-zorro-antd/core/types';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzMentionModule } from 'ng-zorro-antd/mention';\nimport { NzSegmentedModule } from 'ng-zorro-antd/segmented';\n\n@Component({\n  selector: 'nz-demo-mention-variant',\n  imports: [FormsModule, NzInputModule, NzMentionModule, NzSegmentedModule],\n  template: `\n    <nz-segmented [nzOptions]=\"variants\" [(ngModel)]=\"variant\" />\n    <nz-mention [nzSuggestions]=\"suggestions\" (nzOnSelect)=\"onSelect($event)\" [nzVariant]=\"variant()\">\n      <textarea rows=\"1\" placeholder=\"input here\" nzMentionTrigger nz-input [(ngModel)]=\"inputValue\"></textarea>\n    </nz-mention>\n  `,\n  styles: `\n    nz-segmented {\n      margin-bottom: 1rem;\n    }\n  `\n})\nexport class NzDemoMentionVariantComponent {\n  inputValue = model('@afc163');\n  suggestions = ['afc163', 'benjycui', 'yiminghe', 'RaoHai', '中文', 'にほんご'];\n  variant = model<NzVariant>('outlined');\n  variants = [\n    { label: 'Outlined', value: 'outlined' },\n    { label: 'Filled', value: 'filled' },\n    { label: 'Borderless', value: 'borderless' },\n    { label: 'Underlined', value: 'underlined' }\n  ];\n\n  onSelect(value: string): void {\n    console.log(value);\n  }\n}\n"
  },
  {
    "path": "components/mention/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Entry\ntitle: Mention\ncover: 'https://gw.alipayobjects.com/zos/alicdn/jPE-itMFM/Mentions.svg'\ndescription: Used to mention someone or something in an input.\n---\n\n## When To Use\n\nWhen need to mention someone or something.\n\n## API\n\n```html\n<nz-mention [nzSuggestions]=\"suggestions\">\n  <textarea nz-input [(ngModel)]=\"value\" nzMentionTrigger> </textarea>\n</nz-mention>\n```\n\n### nz-mention\n\n| Property                | Description                                                                               | Type                                                     | Default                          | Version |\n| ----------------------- | ----------------------------------------------------------------------------------------- | -------------------------------------------------------- | -------------------------------- | ------- |\n| `[nzMentionTrigger]`    | Trigger element **(required)**                                                            | `HTMLTextAreaElement \\| HTMLInputElement`                | -                                |\n| `[nzMentionSuggestion]` | Customize the suggestion template                                                         | `TemplateRef<any>`                                       | -                                |\n| `[nzLoading]`           | Loading mode                                                                              | `boolean`                                                | `false`                          |\n| `[nzNotFoundContent]`   | Suggestion when suggestions empty                                                         | `string`                                                 | `'无匹配结果，轻敲空格完成输入'` |\n| `[nzPlacement]`         | The position of the suggestion relative to the target, which can be one of top and bottom | `'button' \\| 'top'`                                      | `'bottom'`                       |\n| `[nzPrefix]`            | Character which will trigger Mention to show mention list                                 | `string \\| string[]`                                     | `'@'`                            |\n| `[nzSuggestions]`       | Suggestion content                                                                        | `any[]`                                                  | `[]`                             |\n| `[nzStatus]`            | Set validation status                                                                     | `'error' \\| 'warning'`                                   | -                                |\n| `[nzAllowClear]`        | If allow to remove mentions content with clear icon                                       | `boolean`                                                | `false`                          | 20.3.0  |\n| `[nzClearIcon]`         | The custom clear icon                                                                     | `TemplateRef<void>`                                      | -                                | 20.3.0  |\n| `[nzVariant]`           | Variants of Input                                                                         | `'outlined' \\| 'filled' \\| 'borderless' \\| 'underlined'` | `'outlined'`                     | 20.3.0  |\n| `[nzValueWith]`         | Function that maps an suggestion's value                                                  | `(any) => string \\| (value: string) => string`           |\n| `(nzOnSelect)`          | Callback function called when select from suggestions                                     | `EventEmitter<any>`                                      | -                                |\n| `(nzOnSearchChange)`    | Callback function called when search content changes                                      | `EventEmitter<MentionOnSearchTypes>`                     | -                                |\n| `(nzOnClear)`           | Callback function called when click on clear button                                       | `EventEmitter<void>`                                     | -                                |\n\n#### Methods\n\n| Name        | Description                                             |\n| ----------- | ------------------------------------------------------- |\n| getMentions | Get the mentions array in the `input[nzMentionTrigger]` |\n\n### nzMentionTrigger\n\nTrigger element\n\n```html\n<nz-mention>\n  <textarea nzMentionTrigger></textarea>\n</nz-mention>\n```\n\n```html\n<nz-mention>\n  <input nzMentionTrigger />\n</nz-mention>\n```\n\n### nzMentionSuggestion\n\nCustomize the suggestion template\n\n```html\n<nz-mention [nzSuggestions]=\"items\" [nzValueWith]=\"valueWith\">\n  <input nz-input nzMentionTrigger />\n  <ng-container *nzMentionSuggestion=\"let item\">\n    <span>{{ item.label }} - {{ item.value }}</span>\n  </ng-container>\n</nz-mention>\n```\n\n### MentionOnSearchTypes\n\n| Property | Description    | Type     | Default |\n| -------- | -------------- | -------- | ------- |\n| value    | Search keyword | `string` | -       |\n| prefix   | prefix         | `string` | -       |\n\n## FAQ\n\n### Q: The overlay layer element does not follow the scroll position when scrolling\n\nBy default, the overlay layer element uses body as the scroll container. If using another scroll container, add the [CdkScrollable](https://material.angular.dev/cdk/scrolling/api#CdkScrollable) directive to the custom scroll container element.\nNote: You need to import the `CdkScrollable` directive or `ScrollingModule` module from `@angular/cdk/scrolling`.\n"
  },
  {
    "path": "components/mention/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 提及\ntype: 数据录入\ntitle: Mention\ncover: 'https://gw.alipayobjects.com/zos/alicdn/jPE-itMFM/Mentions.svg'\ndescription: 用于在输入中提及某人或某事。\n---\n\n## 何时使用\n\n用于在输入中提及某人或某事，常用于发布、聊天或评论功能。\n\n## API\n\n```html\n<nz-mention [nzSuggestions]=\"suggestions\">\n  <textarea nz-input [(ngModel)]=\"value\" nzMentionTrigger> </textarea>\n</nz-mention>\n```\n\n### nz-mention\n\n| 参数                    | 说明                              | 类型                                                     | 默认值                           | 版本   |\n| ----------------------- | --------------------------------- | -------------------------------------------------------- | -------------------------------- | ------ |\n| `[nzMentionTrigger]`    | 用于指定提及的触发元素 **(必须)** | `HTMLTextAreaElement \\| HTMLInputElement`                | -                                |\n| `[nzMentionSuggestion]` | 自定义建议渲染模板                | `TemplateRef<any>`                                       | -                                |\n| `[nzLoading]`           | 加载中                            | `boolean`                                                | `false`                          |\n| `[nzNotFoundContent]`   | 未找到时的内容                    | `string`                                                 | `'无匹配结果，轻敲空格完成输入'` |\n| `[nzPlacement]`         | 建议框位置                        | `'bottom' \\| 'top'`                                      | `'bottom'`                       |\n| `[nzPrefix]`            | 触发弹出下拉框的字符              | `string \\| string[]`                                     | `'@'`                            |\n| `[nzSuggestions]`       | 建议内容                          | `any[]`                                                  | `[]`                             |\n| `[nzStatus]`            | 设置校验状态                      | `'error' \\| 'warning'`                                   | -                                |\n| `[nzAllowClear]`        | 支持清除                          | `boolean`                                                | `false`                          | 20.3.0 |\n| `[nzClearIcon]`         | 自定义的多选框清空图标            | `TemplateRef<void>`                                      | -                                | 20.3.0 |\n| `[nzVariant]`           | 形态变体                          | `'outlined' \\| 'filled' \\| 'borderless' \\| 'underlined'` | `'outlined'`                     | 20.3.0 |\n| `[nzValueWith]`         | 建议选项的取值方法                | `(any) => string \\| (value: string) => string`           | -                                |\n| `(nzOnSelect)`          | 下拉框选择建议时回调              | `EventEmitter<any>`                                      | -                                |\n| `(nzOnSearchChange)`    | 输入框中 @ 变化时回调             | `EventEmitter<MentionOnSearchTypes>`                     | -                                |\n| `(nzOnClear)`           | 清空已选项时触发的回调函数        | `EventEmitter<void>`                                     | -                                |\n\n#### 方法\n\n| 方法名      | 说明                                        |\n| ----------- | ------------------------------------------- |\n| getMentions | 获取 `input[nzMentionTrigger]` 中的提及数组 |\n\n### nzMentionTrigger\n\n用于指定提及的触发元素\n\n```html\n<nz-mention>\n  <textarea nzMentionTrigger></textarea>\n</nz-mention>\n```\n\n```html\n<nz-mention>\n  <input nzMentionTrigger />\n</nz-mention>\n```\n\n### nzMentionSuggestion\n\n自定义建议渲染模板\n\n```html\n<nz-mention [nzSuggestions]=\"items\" [nzValueWith]=\"valueWith\">\n  <input nz-input nzMentionTrigger />\n  <ng-container *nzMentionSuggestion=\"let item\">\n    <span>{{ item.label }} - {{ item.value }}</span>\n  </ng-container>\n</nz-mention>\n```\n\n### MentionOnSearchTypes\n\n| 参数   | 说明       | 类型     | 默认值 |\n| ------ | ---------- | -------- | ------ |\n| value  | 搜索关键词 | `string` | -      |\n| prefix | 触发前缀   | `string` | -      |\n\n## FAQ\n\n### Q：滚动时浮层元素没有跟随滚动位置\n\n默认情况下，浮层元素使用 `body` 作为滚动容器，如果使用了其他滚动容器，在自定义滚动容器元素上添加 [CdkScrollable](https://material.angular.dev/cdk/scrolling/api#CdkScrollable) 指令。\n注意：您需要从 `@angular/cdk/scrolling` 导入 `CdkScrollable` 指令或 `ScrollingModule` 模块。\n"
  },
  {
    "path": "components/mention/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/mention/mention-suggestions.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive } from '@angular/core';\n\n@Directive({\n  selector: '[nzMentionSuggestion]',\n  exportAs: 'nzMentionSuggestion'\n})\nexport class NzMentionSuggestionDirective {}\n"
  },
  {
    "path": "components/mention/mention-trigger.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  afterNextRender,\n  ChangeDetectorRef,\n  DestroyRef,\n  Directive,\n  ElementRef,\n  EventEmitter,\n  forwardRef,\n  inject,\n  NgZone,\n  Output,\n  signal\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\n\nimport { OnChangeType, OnTouchedType } from 'ng-zorro-antd/core/types';\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\n\nimport { NZ_MENTION_CONFIG } from './config';\nimport { Mention } from './mention.component';\n\n@Directive({\n  selector: 'input[nzMentionTrigger], textarea[nzMentionTrigger]',\n  exportAs: 'nzMentionTrigger',\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => NzMentionTriggerDirective),\n      multi: true\n    }\n  ],\n  host: {\n    autocomplete: 'off'\n  }\n})\nexport class NzMentionTriggerDirective implements ControlValueAccessor {\n  public readonly elementRef: ElementRef<HTMLInputElement | HTMLTextAreaElement> = inject(\n    ElementRef<HTMLInputElement | HTMLTextAreaElement>\n  );\n  private readonly ngZone = inject(NgZone);\n  private readonly cdr = inject(ChangeDetectorRef);\n  private readonly destroyRef = inject(DestroyRef);\n\n  // eslint-disable-next-line @angular-eslint/no-output-on-prefix\n  @Output() readonly onFocusin = new EventEmitter<FocusEvent>();\n  // eslint-disable-next-line @angular-eslint/no-output-on-prefix\n  @Output() readonly onBlur = new EventEmitter<FocusEvent>();\n  // eslint-disable-next-line @angular-eslint/no-output-on-prefix\n  @Output() readonly onInput = new EventEmitter<KeyboardEvent>();\n  // eslint-disable-next-line @angular-eslint/no-output-on-prefix\n  @Output() readonly onKeydown = new EventEmitter<KeyboardEvent>();\n  // eslint-disable-next-line @angular-eslint/no-output-on-prefix\n  @Output() readonly onClick = new EventEmitter<MouseEvent>();\n\n  readonly value = signal<string>('');\n\n  readonly disabled = signal(false);\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      this.completeEvents();\n    });\n\n    afterNextRender(() => {\n      this.setupEventListener('blur', this.onBlur);\n      this.setupEventListener('focusin', this.onFocusin);\n      this.setupEventListener('input', this.onInput);\n      this.setupEventListener('click', this.onClick);\n      this.setupEventListener('keydown', this.onKeydown);\n    });\n  }\n\n  completeEvents(): void {\n    this.onFocusin.complete();\n    this.onBlur.complete();\n    this.onInput.complete();\n    this.onKeydown.complete();\n    this.onClick.complete();\n  }\n\n  focus(caretPos: number | null = null): void {\n    this.elementRef.nativeElement.focus();\n    this.elementRef.nativeElement.setSelectionRange(caretPos, caretPos);\n  }\n\n  insertMention(mention: Mention): void {\n    const value: string = this.elementRef.nativeElement.value;\n    const insertValue = `${mention.mention}${NZ_MENTION_CONFIG.split}`;\n    const newValue = [\n      value.slice(0, mention.startPos + 1),\n      insertValue,\n      value.slice(mention.endPos, value.length)\n    ].join('');\n    this.elementRef.nativeElement.value = newValue;\n    this.focus(mention.startPos + insertValue.length + 1);\n    this.onChange(newValue);\n    this.value.set(newValue);\n  }\n\n  clear(): void {\n    this.value.set('');\n    this.elementRef.nativeElement.value = '';\n    this.onChange('');\n  }\n\n  writeValue(value: string): void {\n    const parsedValue = typeof value === 'string' ? value : '';\n    this.value.set(parsedValue);\n    this.elementRef.nativeElement.value = parsedValue;\n  }\n\n  onChange: OnChangeType = () => {};\n  onTouched: OnTouchedType = () => {};\n  registerOnChange(fn: (value: string) => void): void {\n    this.onChange = fn;\n  }\n\n  registerOnTouched(fn: () => void): void {\n    this.onTouched = fn;\n  }\n\n  setDisabledState(isDisabled: boolean): void {\n    this.disabled.set(isDisabled);\n  }\n\n  private setupEventListener<TEvent extends Event>(eventName: string, eventEmitter: EventEmitter<TEvent>): void {\n    fromEventOutsideAngular<TEvent>(this.elementRef.nativeElement, eventName)\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(event => {\n        if (eventEmitter.observers.length) {\n          this.ngZone.run(() => {\n            eventEmitter.emit(event);\n            this.cdr.markForCheck();\n          });\n        }\n      });\n  }\n}\n"
  },
  {
    "path": "components/mention/mention.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport { DOWN_ARROW, ENTER, ESCAPE, LEFT_ARROW, RIGHT_ARROW, TAB, UP_ARROW } from '@angular/cdk/keycodes';\nimport {\n  ConnectionPositionPair,\n  createFlexibleConnectedPositionStrategy,\n  createOverlayRef,\n  createRepositionScrollStrategy,\n  FlexibleConnectedPositionStrategy,\n  OverlayRef,\n  PositionStrategy\n} from '@angular/cdk/overlay';\nimport { TemplatePortal } from '@angular/cdk/portal';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterViewInit,\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  computed,\n  contentChild,\n  ContentChild,\n  DestroyRef,\n  DOCUMENT,\n  effect,\n  ElementRef,\n  EventEmitter,\n  inject,\n  Injector,\n  Input,\n  NgZone,\n  OnChanges,\n  OnInit,\n  Output,\n  QueryList,\n  Renderer2,\n  signal,\n  SimpleChanges,\n  TemplateRef,\n  ViewChild,\n  ViewChildren,\n  ViewContainerRef\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { merge, of as observableOf, Subscription } from 'rxjs';\nimport { distinctUntilChanged, map, startWith, switchMap, withLatestFrom } from 'rxjs/operators';\n\nimport {\n  NZ_FORM_VARIANT,\n  NzFormItemFeedbackIconComponent,\n  NzFormNoStatusService,\n  NzFormStatusService\n} from 'ng-zorro-antd/core/form';\nimport { NzStringTemplateOutletDirective } from 'ng-zorro-antd/core/outlet';\nimport { DEFAULT_MENTION_BOTTOM_POSITIONS, DEFAULT_MENTION_TOP_POSITIONS } from 'ng-zorro-antd/core/overlay';\nimport { NgClassInterface, NzSafeAny, NzStatus, NzValidateStatus, NzVariant } from 'ng-zorro-antd/core/types';\nimport {\n  fromEventOutsideAngular,\n  getCaretCoordinates,\n  getMentions,\n  getStatusClassNames\n} from 'ng-zorro-antd/core/util';\nimport { NzEmptyModule } from 'ng-zorro-antd/empty';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nimport { NZ_MENTION_CONFIG } from './config';\nimport { NzMentionSuggestionDirective } from './mention-suggestions';\nimport { NzMentionTriggerDirective } from './mention-trigger';\n\nexport interface MentionOnSearchTypes {\n  value: string;\n  prefix: string;\n}\n\nexport interface Mention {\n  startPos: number;\n  endPos: number;\n  mention: string;\n}\n\nexport type MentionPlacement = 'top' | 'bottom';\n\n@Component({\n  selector: 'nz-mention',\n  exportAs: 'nzMention',\n  template: `\n    <ng-content />\n    <ng-template #suggestions>\n      <div class=\"ant-mentions-dropdown\">\n        <ul class=\"ant-mentions-dropdown-menu\" role=\"menu\" tabindex=\"0\">\n          @for (suggestion of filteredSuggestions; track suggestion) {\n            <li\n              #items\n              class=\"ant-mentions-dropdown-menu-item\"\n              role=\"menuitem\"\n              tabindex=\"-1\"\n              [class.ant-mentions-dropdown-menu-item-active]=\"$index === activeIndex\"\n              [class.ant-mentions-dropdown-menu-item-selected]=\"$index === activeIndex\"\n              (click)=\"selectSuggestion(suggestion)\"\n            >\n              @if (suggestionTemplate) {\n                <ng-container *ngTemplateOutlet=\"suggestionTemplate; context: { $implicit: suggestion }\" />\n              } @else {\n                {{ nzValueWith(suggestion) }}\n              }\n            </li>\n          } @empty {\n            <li class=\"ant-mentions-dropdown-menu-item ant-mentions-dropdown-menu-item-disabled\">\n              @if (nzLoading) {\n                <span><nz-icon nzType=\"loading\" /></span>\n              } @else {\n                <span>\n                  <nz-embed-empty nzComponentName=\"select\" [specificContent]=\"nzNotFoundContent!\" />\n                </span>\n              }\n            </li>\n          }\n        </ul>\n      </div>\n    </ng-template>\n    @if (hasFeedback && !!status) {\n      <nz-form-item-feedback-icon class=\"ant-mentions-suffix\" [status]=\"status\" />\n    }\n    @if (nzAllowClear && hasValue()) {\n      <span class=\"ant-mentions-suffix\">\n        <button type=\"button\" tabindex=\"-1\" class=\"ant-mentions-clear-icon\" (click)=\"clear()\">\n          <ng-template [nzStringTemplateOutlet]=\"nzClearIcon\">\n            <nz-icon nzType=\"close-circle\" nzTheme=\"fill\" />\n          </ng-template>\n        </button>\n      </span>\n    }\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    class: 'ant-mentions',\n    '[class.ant-mentions-rtl]': `dir === 'rtl'`,\n    '[class.ant-mentions-borderless]': `finalVariant() === 'borderless'`,\n    '[class.ant-mentions-filled]': `finalVariant() === 'filled'`,\n    '[class.ant-mentions-underlined]': `finalVariant() === 'underlined'`,\n    '[class.ant-mentions-focused]': `focused()`,\n    '[class.ant-mentions-disabled]': `disabled()`\n  },\n  imports: [\n    NgTemplateOutlet,\n    NzIconModule,\n    NzEmptyModule,\n    NzFormItemFeedbackIconComponent,\n    NzStringTemplateOutletDirective\n  ]\n})\nexport class NzMentionComponent implements OnInit, AfterViewInit, OnChanges {\n  private ngZone = inject(NgZone);\n  private directionality = inject(Directionality);\n  private cdr = inject(ChangeDetectorRef);\n  private injector = inject(Injector);\n  private viewContainerRef = inject(ViewContainerRef);\n  private elementRef = inject(ElementRef);\n  private renderer = inject(Renderer2);\n  private destroyRef = inject(DestroyRef);\n  @Input() nzValueWith: (value: NzSafeAny) => string = value => value;\n  @Input() nzPrefix: string | string[] = '@';\n  @Input({ transform: booleanAttribute }) nzLoading = false;\n  @Input() nzNotFoundContent: string = '无匹配结果，轻敲空格完成输入';\n  @Input() nzPlacement: MentionPlacement = 'bottom';\n  @Input() nzSuggestions: NzSafeAny[] = [];\n  @Input() nzStatus: NzStatus = '';\n  @Input() nzVariant: NzVariant | undefined = undefined;\n  @Input({ transform: booleanAttribute }) nzAllowClear = false;\n  @Input() nzClearIcon: TemplateRef<NzSafeAny> | null = null;\n  @Output() readonly nzOnSelect = new EventEmitter<NzSafeAny>();\n  @Output() readonly nzOnSearchChange = new EventEmitter<MentionOnSearchTypes>();\n  @Output() readonly nzOnClear = new EventEmitter<void>();\n\n  @ViewChild(TemplateRef, { static: false }) suggestionsTemp?: TemplateRef<void>;\n  @ViewChildren('items', { read: ElementRef })\n  items!: QueryList<ElementRef>;\n\n  @ContentChild(NzMentionSuggestionDirective, { static: false, read: TemplateRef })\n  set suggestionChild(value: TemplateRef<{ $implicit: NzSafeAny }>) {\n    if (value) {\n      this.suggestionTemplate = value;\n    }\n  }\n\n  readonly trigger = contentChild.required(NzMentionTriggerDirective);\n\n  isOpen = false;\n  filteredSuggestions: string[] = [];\n  suggestionTemplate: TemplateRef<{ $implicit: NzSafeAny }> | null = null;\n  activeIndex = -1;\n  dir: Direction = 'ltr';\n  // status\n  prefixCls: string = 'ant-mentions';\n  statusCls: NgClassInterface = {};\n  status: NzValidateStatus = '';\n  hasFeedback: boolean = false;\n  readonly focused = signal(false);\n\n  readonly disabled = computed(() => {\n    return this.trigger().disabled();\n  });\n  readonly hasValue = computed(() => {\n    return !!this.trigger()?.value().trim();\n  });\n\n  private previousValue: string | null = null;\n  private cursorMention: string | null = null;\n  private cursorMentionStart?: number;\n  private cursorMentionEnd?: number;\n  private overlayRef: OverlayRef | null = null;\n  private portal?: TemplatePortal<void>;\n  private positionStrategy!: FlexibleConnectedPositionStrategy;\n  private overlayOutsideClickSubscription!: Subscription;\n  private document: Document = inject(DOCUMENT);\n\n  private get triggerNativeElement(): HTMLTextAreaElement | HTMLInputElement {\n    return this.trigger().elementRef.nativeElement;\n  }\n\n  private get focusItemElement(): HTMLElement | null {\n    const itemArr = this.items?.toArray();\n    if (itemArr && itemArr[this.activeIndex]) {\n      return itemArr[this.activeIndex].nativeElement;\n    }\n    return null;\n  }\n\n  private nzFormStatusService = inject(NzFormStatusService, { optional: true });\n  private nzFormNoStatusService = inject(NzFormNoStatusService, { optional: true });\n\n  private readonly formVariant = inject(NZ_FORM_VARIANT, { optional: true });\n\n  protected readonly variant = signal<NzVariant | undefined>(this.nzVariant);\n\n  protected readonly finalVariant = computed(() => this.variant() || this.formVariant?.() || 'outlined');\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      this.closeDropdown();\n    });\n\n    effect(() => {\n      const trigger = this.trigger();\n      if (trigger) {\n        this.bindTriggerEvents();\n        this.closeDropdown();\n        this.overlayRef = null;\n      }\n    });\n  }\n\n  ngOnInit(): void {\n    this.nzFormStatusService?.formStatusChanges\n      .pipe(\n        distinctUntilChanged((pre, cur) => {\n          return pre.status === cur.status && pre.hasFeedback === cur.hasFeedback;\n        }),\n        withLatestFrom(this.nzFormNoStatusService ? this.nzFormNoStatusService.noFormStatus : observableOf(false)),\n        map(([{ status, hasFeedback }, noStatus]) => ({ status: noStatus ? '' : status, hasFeedback })),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(({ status, hasFeedback }) => {\n        this.setStatusStyles(status, hasFeedback);\n      });\n    this.dir = this.directionality.value;\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n      this.dir = direction;\n    });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzSuggestions, nzStatus, nzVariant } = changes;\n    if (nzSuggestions) {\n      if (this.isOpen) {\n        this.previousValue = null;\n        this.activeIndex = -1;\n        this.resetDropdown(false);\n      }\n    }\n    if (nzStatus) {\n      this.setStatusStyles(this.nzStatus, this.hasFeedback);\n    }\n    if (nzVariant) {\n      this.variant.set(nzVariant.currentValue);\n    }\n  }\n\n  ngAfterViewInit(): void {\n    this.items.changes\n      .pipe(\n        startWith(this.items),\n        switchMap(() => {\n          const items = this.items.toArray();\n          return merge(...items.map(item => fromEventOutsideAngular<MouseEvent>(item.nativeElement, 'mousedown')));\n        })\n      )\n      .subscribe(event => {\n        event.preventDefault();\n      });\n  }\n\n  closeDropdown(): void {\n    if (this.overlayRef && this.overlayRef.hasAttached()) {\n      this.overlayRef.detach();\n      this.overlayOutsideClickSubscription.unsubscribe();\n      this.isOpen = false;\n      this.cdr.markForCheck();\n    }\n  }\n\n  openDropdown(): void {\n    this.attachOverlay();\n    this.isOpen = true;\n    this.cdr.markForCheck();\n  }\n\n  getMentions(): string[] {\n    return this.trigger() ? getMentions(this.trigger().value(), this.nzPrefix) : [];\n  }\n\n  selectSuggestion(suggestion: string | {}): void {\n    const value = this.nzValueWith(suggestion);\n    this.trigger().insertMention({\n      mention: value,\n      startPos: this.cursorMentionStart!,\n      endPos: this.cursorMentionEnd!\n    });\n    this.nzOnSelect.emit(suggestion);\n    this.closeDropdown();\n    this.activeIndex = -1;\n  }\n\n  clear(): void {\n    this.closeDropdown();\n    this.trigger().clear();\n    this.nzOnClear.emit();\n  }\n\n  private handleInput(event: KeyboardEvent): void {\n    const target = event.target as HTMLInputElement | HTMLTextAreaElement;\n    this.trigger().onChange(target.value);\n    this.trigger().value.set(target.value);\n    this.resetDropdown();\n  }\n\n  private handleKeydown(event: KeyboardEvent): void {\n    const keyCode = event.keyCode;\n    if (this.isOpen && keyCode === ENTER && this.activeIndex !== -1 && this.filteredSuggestions.length) {\n      this.selectSuggestion(this.filteredSuggestions[this.activeIndex]);\n      event.preventDefault();\n    } else if (keyCode === LEFT_ARROW || keyCode === RIGHT_ARROW) {\n      this.resetDropdown();\n      event.stopPropagation();\n    } else {\n      if (this.isOpen && (keyCode === TAB || keyCode === ESCAPE)) {\n        this.closeDropdown();\n        return;\n      }\n\n      if (this.isOpen && keyCode === UP_ARROW) {\n        this.setPreviousItemActive();\n        event.preventDefault();\n        event.stopPropagation();\n      }\n\n      if (this.isOpen && keyCode === DOWN_ARROW) {\n        this.setNextItemActive();\n        event.preventDefault();\n        event.stopPropagation();\n      }\n    }\n  }\n\n  private handleClick(): void {\n    this.resetDropdown(false);\n  }\n\n  private bindTriggerEvents(): void {\n    this.trigger().onFocusin.subscribe(() => this.focused.set(true));\n    this.trigger().onBlur.subscribe(() => this.focused.set(false));\n    this.trigger().onInput.subscribe((e: KeyboardEvent) => this.handleInput(e));\n    this.trigger().onKeydown.subscribe((e: KeyboardEvent) => this.handleKeydown(e));\n    this.trigger().onClick.subscribe(() => this.handleClick());\n  }\n\n  private suggestionsFilter(value: string, emit: boolean): void {\n    const suggestions = value.substring(1);\n    /**\n     * Should always emit (nzOnSearchChange) when value empty\n     *\n     * @[something]... @[empty]... @[empty]\n     *     ^             ^           ^\n     * preValue        preValue  (should emit)\n     */\n    if (this.previousValue === value && value !== this.cursorMention![0]) {\n      return;\n    }\n    this.previousValue = value;\n    if (emit) {\n      this.nzOnSearchChange.emit({\n        value: this.cursorMention!.substring(1),\n        prefix: this.cursorMention![0]\n      });\n    }\n    const searchValue = suggestions.toLowerCase();\n    this.filteredSuggestions = this.nzSuggestions.filter(suggestion =>\n      this.nzValueWith(suggestion).toLowerCase().includes(searchValue)\n    );\n  }\n\n  private resetDropdown(emit: boolean = true): void {\n    this.resetCursorMention();\n    if (typeof this.cursorMention !== 'string' || !this.canOpen()) {\n      this.closeDropdown();\n      return;\n    }\n    this.suggestionsFilter(this.cursorMention, emit);\n    const activeIndex = this.filteredSuggestions.indexOf(this.cursorMention.substring(1));\n    this.activeIndex = activeIndex >= 0 ? activeIndex : 0;\n    this.openDropdown();\n  }\n\n  private setNextItemActive(): void {\n    this.activeIndex = this.activeIndex + 1 <= this.filteredSuggestions.length - 1 ? this.activeIndex + 1 : 0;\n    this.cdr.markForCheck();\n    this.scrollToFocusItem();\n  }\n\n  private setPreviousItemActive(): void {\n    this.activeIndex = this.activeIndex - 1 < 0 ? this.filteredSuggestions.length - 1 : this.activeIndex - 1;\n    this.cdr.markForCheck();\n    this.scrollToFocusItem();\n  }\n\n  private scrollToFocusItem(): void {\n    if (this.focusItemElement) {\n      this.focusItemElement.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'nearest' });\n    }\n  }\n\n  private canOpen(): boolean {\n    const element: HTMLInputElement | HTMLTextAreaElement = this.triggerNativeElement;\n    return !element.readOnly && !element.disabled;\n  }\n\n  private resetCursorMention(): void {\n    const value = this.triggerNativeElement.value.replace(/[\\r\\n]/g, NZ_MENTION_CONFIG.split) || '';\n    const selectionStart = this.triggerNativeElement.selectionStart!;\n    const prefix = typeof this.nzPrefix === 'string' ? [this.nzPrefix] : this.nzPrefix;\n    let i = prefix.length;\n    while (i >= 0) {\n      const startPos = value.lastIndexOf(prefix[i], selectionStart);\n      const endPos =\n        value.indexOf(NZ_MENTION_CONFIG.split, selectionStart) > -1\n          ? value.indexOf(NZ_MENTION_CONFIG.split, selectionStart)\n          : value.length;\n      const mention = value.substring(startPos, endPos);\n      if (\n        (startPos > 0 && value[startPos - 1] !== NZ_MENTION_CONFIG.split) ||\n        startPos < 0 ||\n        mention.includes(prefix[i], 1) ||\n        mention.includes(NZ_MENTION_CONFIG.split)\n      ) {\n        this.cursorMention = null;\n        this.cursorMentionStart = -1;\n        this.cursorMentionEnd = -1;\n      } else {\n        this.cursorMention = mention;\n        this.cursorMentionStart = startPos;\n        this.cursorMentionEnd = endPos;\n        return;\n      }\n      i--;\n    }\n  }\n\n  private updatePositions(): void {\n    const coordinates = getCaretCoordinates(this.triggerNativeElement, this.cursorMentionStart!);\n    const top =\n      coordinates.top -\n      this.triggerNativeElement.getBoundingClientRect().height -\n      this.triggerNativeElement.scrollTop +\n      (this.nzPlacement === 'bottom' ? coordinates.height - 6 : -6);\n    const left = coordinates.left - this.triggerNativeElement.scrollLeft;\n    this.positionStrategy.withDefaultOffsetX(left).withDefaultOffsetY(top);\n    if (this.nzPlacement === 'bottom') {\n      this.positionStrategy.withPositions([...DEFAULT_MENTION_BOTTOM_POSITIONS]);\n    }\n    if (this.nzPlacement === 'top') {\n      this.positionStrategy.withPositions([...DEFAULT_MENTION_TOP_POSITIONS]);\n    }\n    this.positionStrategy.apply();\n  }\n\n  private subscribeOverlayOutsideClick(): Subscription {\n    const canCloseDropdown = (event: MouseEvent | TouchEvent): boolean => {\n      const clickTarget = event.target as HTMLElement;\n      return (\n        this.isOpen &&\n        clickTarget !== this.triggerNativeElement &&\n        !this.overlayRef?.overlayElement.contains(clickTarget)\n      );\n    };\n\n    const subscription = new Subscription();\n\n    subscription.add(\n      this.overlayRef!.outsidePointerEvents().subscribe(event => canCloseDropdown(event) && this.closeDropdown())\n    );\n\n    subscription.add(\n      fromEventOutsideAngular<TouchEvent>(this.document, 'touchend').subscribe(\n        event => canCloseDropdown(event) && this.ngZone.run(() => this.closeDropdown())\n      )\n    );\n\n    return subscription;\n  }\n\n  private attachOverlay(): void {\n    if (!this.overlayRef) {\n      this.portal = new TemplatePortal(this.suggestionsTemp!, this.viewContainerRef);\n      this.overlayRef = createOverlayRef(this.injector, {\n        positionStrategy: this.getOverlayPosition(),\n        scrollStrategy: createRepositionScrollStrategy(this.injector),\n        disposeOnNavigation: true\n      });\n    }\n    if (this.overlayRef && !this.overlayRef.hasAttached()) {\n      this.overlayRef.attach(this.portal);\n      this.overlayOutsideClickSubscription = this.subscribeOverlayOutsideClick();\n    }\n    this.updatePositions();\n  }\n\n  private getOverlayPosition(): PositionStrategy {\n    return (this.positionStrategy = createFlexibleConnectedPositionStrategy(this.injector, this.trigger().elementRef)\n      .withPositions([\n        new ConnectionPositionPair({ originX: 'start', originY: 'bottom' }, { overlayX: 'start', overlayY: 'top' }),\n        new ConnectionPositionPair({ originX: 'start', originY: 'top' }, { overlayX: 'start', overlayY: 'bottom' })\n      ])\n      .withFlexibleDimensions(false)\n      .withPush(false));\n  }\n\n  private setStatusStyles(status: NzValidateStatus, hasFeedback: boolean): void {\n    // set inner status\n    this.status = status;\n    this.hasFeedback = hasFeedback;\n    this.cdr.markForCheck();\n    // render status if nzStatus is set\n    this.statusCls = getStatusClassNames(this.prefixCls, status, hasFeedback);\n    Object.keys(this.statusCls).forEach(status => {\n      if (this.statusCls[status]) {\n        this.renderer.addClass(this.elementRef.nativeElement, status);\n      } else {\n        this.renderer.removeClass(this.elementRef.nativeElement, status);\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "components/mention/mention.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzMentionSuggestionDirective } from './mention-suggestions';\nimport { NzMentionTriggerDirective } from './mention-trigger';\nimport { NzMentionComponent } from './mention.component';\n\nconst COMPONENTS = [NzMentionComponent, NzMentionTriggerDirective, NzMentionSuggestionDirective];\n\n@NgModule({\n  imports: [...COMPONENTS],\n  exports: [...COMPONENTS]\n})\nexport class NzMentionModule {}\n"
  },
  {
    "path": "components/mention/mention.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Direction } from '@angular/cdk/bidi';\nimport { DOWN_ARROW, ENTER, ESCAPE, RIGHT_ARROW, TAB, UP_ARROW } from '@angular/cdk/keycodes';\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport { ScrollDispatcher } from '@angular/cdk/scrolling';\nimport {\n  ApplicationRef,\n  Component,\n  DebugElement,\n  NgZone,\n  provideZoneChangeDetection,\n  signal,\n  ViewChild,\n  type WritableSignal\n} from '@angular/core';\nimport { ComponentFixture, fakeAsync, flush, inject, TestBed, tick } from '@angular/core/testing';\nimport { FormsModule } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\nimport { Subject } from 'rxjs';\n\nimport { NZ_FORM_VARIANT } from 'ng-zorro-antd/core/form';\nimport {\n  createKeyboardEvent,\n  dispatchFakeEvent,\n  dispatchKeyboardEvent,\n  MockNgZone,\n  provideMockDirectionality,\n  typeInElement\n} from 'ng-zorro-antd/core/testing';\nimport { NzStatus, type NzVariant } from 'ng-zorro-antd/core/types';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzFormControlStatusType, NzFormModule } from '../form';\nimport { NzInputModule } from '../input';\nimport { NzMentionTriggerDirective } from './mention-trigger';\nimport { NzMentionComponent } from './mention.component';\nimport { NzMentionModule } from './mention.module';\n\ndescribe('mention', () => {\n  let overlayContainer: OverlayContainer;\n  let overlayContainerElement: HTMLElement;\n  const scrolledSubject = new Subject();\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [\n        // todo: use zoneless\n        provideZoneChangeDetection(),\n        provideNoopAnimations(),\n        provideNzIconsTesting(),\n        provideMockDirectionality(),\n        { provide: ScrollDispatcher, useFactory: () => ({ scrolled: () => scrolledSubject }) },\n        {\n          provide: NgZone,\n          useFactory: () => new MockNgZone()\n        }\n      ]\n    });\n  });\n\n  beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n    overlayContainer = oc;\n    overlayContainerElement = oc.getContainerElement();\n  }));\n\n  afterEach(inject([OverlayContainer], (currentOverlayContainer: OverlayContainer) => {\n    currentOverlayContainer.ngOnDestroy();\n    overlayContainer.ngOnDestroy();\n  }));\n\n  describe('RTL', () => {\n    let fixture: ComponentFixture<NzTestDirMentionComponent>;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestDirMentionComponent);\n      fixture.detectChanges();\n    });\n\n    it('should classname correct', () => {\n      expect(fixture.debugElement.nativeElement.querySelector('nz-mention').classList).not.toContain(\n        'ant-mentions-rtl'\n      );\n      fixture.componentInstance.direction = 'rtl';\n      fixture.detectChanges();\n      expect(fixture.debugElement.nativeElement.querySelector('nz-mention').classList).toContain('ant-mentions-rtl');\n    });\n  });\n\n  describe('toggling', () => {\n    let fixture: ComponentFixture<NzTestSimpleMentionComponent>;\n    let textarea: HTMLTextAreaElement;\n\n    beforeEach(fakeAsync(() => {\n      fixture = TestBed.createComponent(NzTestSimpleMentionComponent);\n      fixture.detectChanges();\n      textarea = fixture.debugElement.query(By.css('textarea')).nativeElement;\n      textarea.value = '@angular';\n      tick();\n    }));\n\n    it('should open the dropdown when the input is click', () => {\n      dispatchFakeEvent(textarea, 'click');\n      fixture.detectChanges();\n      expect(fixture.componentInstance.mention.isOpen).toBe(true);\n    });\n\n    it('should not open the dropdown when the input is click but empty content', () => {\n      textarea.value = '';\n      fixture.detectChanges();\n      dispatchFakeEvent(textarea, 'click');\n      fixture.detectChanges();\n      expect(fixture.componentInstance.mention.isOpen).toBe(false);\n    });\n\n    it('should not open the dropdown on click if the input is readonly', fakeAsync(() => {\n      const mention = fixture.componentInstance.mention;\n      textarea.readOnly = true;\n      fixture.detectChanges();\n\n      expect(mention.isOpen).toBe(false);\n      dispatchFakeEvent(textarea, 'click');\n      flush();\n\n      fixture.detectChanges();\n      expect(mention.isOpen).toBe(false);\n    }));\n\n    it('should not open the dropdown on click if the input is disabled', fakeAsync(() => {\n      const mention = fixture.componentInstance.mention;\n      textarea.disabled = true;\n      fixture.detectChanges();\n\n      expect(mention.isOpen).toBe(false);\n      dispatchFakeEvent(textarea, 'click');\n      flush();\n\n      fixture.detectChanges();\n      expect(mention.isOpen).toBe(false);\n    }));\n\n    it('should close the dropdown when the user clicks away', fakeAsync(() => {\n      const mention = fixture.componentInstance.mention;\n      dispatchFakeEvent(textarea, 'click');\n      fixture.detectChanges();\n      flush();\n      expect(mention.isOpen).toBe(true);\n      dispatchFakeEvent(document.body, 'click');\n      expect(mention.isOpen).toBe(false);\n    }));\n\n    it('should close the dropdown when the user taps away on a touch device', fakeAsync(() => {\n      const mention = fixture.componentInstance.mention;\n      dispatchFakeEvent(textarea, 'click');\n      fixture.detectChanges();\n      flush();\n      dispatchFakeEvent(document, 'touchend');\n      expect(mention.isOpen).toBe(false);\n    }));\n\n    it('should close the dropdown when an option is clicked', fakeAsync(() => {\n      const mention = fixture.componentInstance.mention;\n      textarea.value = '@a';\n      fixture.detectChanges();\n      dispatchFakeEvent(textarea, 'click');\n      fixture.detectChanges();\n      flush();\n\n      const option = overlayContainerElement.querySelector('.ant-mentions-dropdown-menu-item') as HTMLElement;\n      option.click();\n      fixture.detectChanges();\n\n      tick(500);\n      expect(mention.isOpen).toBe(false);\n      expect(overlayContainerElement.textContent).toEqual('');\n      expect(textarea.value).toEqual('@angular ');\n    }));\n\n    it('should prevent default on the mousedown event when an option is clicked and should not run change detection', fakeAsync(() => {\n      textarea.value = '@a';\n      fixture.detectChanges();\n      dispatchFakeEvent(textarea, 'click');\n      fixture.detectChanges();\n      flush();\n\n      const appRef = TestBed.inject(ApplicationRef);\n      const option = overlayContainerElement.querySelector('.ant-mentions-dropdown-menu-item') as HTMLElement;\n      const event = new MouseEvent('mousedown');\n\n      spyOn(appRef, 'tick');\n      spyOn(event, 'preventDefault').and.callThrough();\n\n      option.dispatchEvent(event);\n\n      expect(event.preventDefault).toHaveBeenCalled();\n      expect(appRef.tick).not.toHaveBeenCalled();\n    }));\n\n    it('should support switch trigger', fakeAsync(() => {\n      fixture.componentInstance.inputTrigger = true;\n      fixture.detectChanges();\n      tick(); // Wait for afterNextRender\n      const textareaWithSingleLine = fixture.debugElement.query(By.css('textarea')).nativeElement;\n      const mention = fixture.componentInstance.mention;\n      expect(textareaWithSingleLine).toBeTruthy();\n\n      textareaWithSingleLine.value = '@a';\n      fixture.detectChanges();\n      dispatchFakeEvent(textareaWithSingleLine, 'click');\n      fixture.detectChanges();\n      flush();\n\n      expect(mention.isOpen).toBe(true);\n\n      const option = overlayContainerElement.querySelector('.ant-mentions-dropdown-menu-item') as HTMLElement;\n      expect(option).toBeTruthy(); // Ensure option exists before clicking\n      option.click();\n      fixture.detectChanges();\n\n      tick(500);\n      expect(mention.isOpen).toBe(false);\n      expect(overlayContainerElement.textContent).toEqual('');\n    }));\n  });\n\n  describe('keyboard events', () => {\n    let fixture: ComponentFixture<NzTestSimpleMentionComponent>;\n    let textarea: HTMLTextAreaElement;\n    let DOWN_ARROW_EVENT: KeyboardEvent;\n    let UP_ARROW_EVENT: KeyboardEvent;\n    let ENTER_EVENT: KeyboardEvent;\n    // let LEFT_EVENT: KeyboardEvent;\n    let RIGHT_EVENT: KeyboardEvent;\n\n    beforeEach(fakeAsync(() => {\n      fixture = TestBed.createComponent(NzTestSimpleMentionComponent);\n      fixture.detectChanges();\n      textarea = fixture.debugElement.query(By.css('textarea')).nativeElement;\n\n      DOWN_ARROW_EVENT = createKeyboardEvent('keydown', DOWN_ARROW);\n      UP_ARROW_EVENT = createKeyboardEvent('keydown', UP_ARROW);\n      ENTER_EVENT = createKeyboardEvent('keydown', ENTER);\n      // LEFT_EVENT = createKeyboardEvent('keydown', LEFT_ARROW);\n      RIGHT_EVENT = createKeyboardEvent('keydown', RIGHT_ARROW);\n\n      fixture.detectChanges();\n      flush();\n    }));\n\n    it('should set the active item to the second option when DOWN key is pressed', () => {\n      textarea.value = '@a';\n      fixture.detectChanges();\n      dispatchFakeEvent(textarea, 'click');\n      fixture.detectChanges();\n\n      const mention = fixture.componentInstance.mention;\n      const optionEls = overlayContainerElement.querySelectorAll(\n        '.ant-mentions-dropdown-menu-item'\n      ) as NodeListOf<HTMLElement>;\n\n      expect(mention.isOpen).toBe(true);\n      fixture.componentInstance.trigger.onKeydown.emit(DOWN_ARROW_EVENT);\n      fixture.detectChanges();\n\n      expect(optionEls[0].classList).not.toContain('ant-mentions-dropdown-menu-item-active');\n      expect(optionEls[1].classList).toContain('ant-mentions-dropdown-menu-item-active');\n    });\n\n    it('should set the active item to the first option when DOWN key is pressed in last item', () => {\n      textarea.value = '@';\n      fixture.detectChanges();\n      dispatchFakeEvent(textarea, 'click');\n      fixture.detectChanges();\n      const mention = fixture.componentInstance.mention;\n      const optionEls = overlayContainerElement.querySelectorAll(\n        '.ant-mentions-dropdown-menu-item'\n      ) as NodeListOf<HTMLElement>;\n\n      expect(mention.isOpen).toBe(true);\n\n      [1, 2, 3, 4, 5].forEach(() => fixture.componentInstance.trigger.onKeydown.emit(DOWN_ARROW_EVENT));\n      fixture.detectChanges();\n\n      expect(optionEls[1].classList).not.toContain('ant-mentions-dropdown-menu-item-active');\n      expect(optionEls[4].classList).not.toContain('ant-mentions-dropdown-menu-item-active');\n      expect(optionEls[0].classList).toContain('ant-mentions-dropdown-menu-item-active');\n    });\n\n    it('should set the active item to the last option when UP key is pressed', () => {\n      textarea.value = '@';\n      fixture.detectChanges();\n      dispatchFakeEvent(textarea, 'click');\n      fixture.detectChanges();\n      const mention = fixture.componentInstance.mention;\n      const optionEls = overlayContainerElement.querySelectorAll(\n        '.ant-mentions-dropdown-menu-item'\n      ) as NodeListOf<HTMLElement>;\n\n      expect(mention.isOpen).toBe(true);\n\n      fixture.componentInstance.trigger.onKeydown.emit(UP_ARROW_EVENT);\n      fixture.detectChanges();\n\n      expect(optionEls[0].classList).not.toContain('ant-mentions-dropdown-menu-item-active');\n      expect(optionEls[4].classList).toContain('ant-mentions-dropdown-menu-item-active');\n    });\n\n    it('should set the active item to the previous option when UP key is pressed', () => {\n      textarea.value = '@';\n      fixture.detectChanges();\n      dispatchFakeEvent(textarea, 'click');\n      fixture.detectChanges();\n      const mention = fixture.componentInstance.mention;\n      const optionEls = overlayContainerElement.querySelectorAll(\n        '.ant-mentions-dropdown-menu-item'\n      ) as NodeListOf<HTMLElement>;\n\n      expect(mention.isOpen).toBe(true);\n\n      [1, 2, 3].forEach(() => fixture.componentInstance.trigger.onKeydown.emit(UP_ARROW_EVENT));\n      fixture.detectChanges();\n\n      expect(optionEls[0].classList).not.toContain('ant-mentions-dropdown-menu-item-active');\n      expect(optionEls[2].classList).toContain('ant-mentions-dropdown-menu-item-active');\n    });\n\n    it('should set the active item properly after filtering', () => {\n      const componentInstance = fixture.componentInstance;\n\n      typeInElement('@a', textarea);\n      fixture.detectChanges();\n\n      componentInstance.trigger.onKeydown.emit(DOWN_ARROW_EVENT);\n      fixture.detectChanges();\n\n      const optionEls = overlayContainerElement.querySelectorAll(\n        '.ant-mentions-dropdown-menu-item'\n      ) as NodeListOf<HTMLElement>;\n\n      expect(optionEls[0].classList).not.toContain('ant-mentions-dropdown-menu-item-active');\n      expect(optionEls[1].classList).toContain('ant-mentions-dropdown-menu-item-active');\n      expect(optionEls[1].innerText).toEqual('ant-design');\n    });\n\n    it('should set the active after filtering item when RIGHT/LEFT key is pressed', () => {\n      textarea.value = '@a @t';\n      fixture.detectChanges();\n      dispatchFakeEvent(textarea, 'click');\n      fixture.detectChanges();\n      const componentInstance = fixture.componentInstance;\n      [1, 2, 3, 4].forEach(() => componentInstance.trigger.onKeydown.emit(RIGHT_EVENT));\n      fixture.detectChanges();\n\n      const optionEls = overlayContainerElement.querySelectorAll(\n        '.ant-mentions-dropdown-menu-item'\n      ) as NodeListOf<HTMLElement>;\n\n      expect(optionEls[0].classList).toContain('ant-mentions-dropdown-menu-item-active');\n      expect(optionEls[1].classList).not.toContain('ant-mentions-dropdown-menu-item-active');\n      expect(optionEls[0].innerText).toEqual('ant-design');\n      expect(optionEls[1].innerText).toEqual('mention');\n    });\n\n    it('should fill the text field when an option is selected with ENTER', fakeAsync(() => {\n      textarea.value = '@';\n      fixture.detectChanges();\n      dispatchFakeEvent(textarea, 'click');\n      const componentInstance = fixture.componentInstance;\n      componentInstance.trigger.onKeydown.emit(DOWN_ARROW_EVENT);\n      flush();\n      fixture.detectChanges();\n\n      componentInstance.trigger.onKeydown.emit(ENTER_EVENT);\n      fixture.detectChanges();\n\n      expect(componentInstance.inputValue).toContain('@ant-design ');\n\n      expect(textarea.value).toContain('@ant-design ');\n    }));\n\n    it('should prevent the default enter key action', fakeAsync(() => {\n      textarea.value = '@';\n      fixture.detectChanges();\n      dispatchFakeEvent(textarea, 'click');\n      fixture.componentInstance.trigger.onKeydown.emit(DOWN_ARROW_EVENT);\n      flush();\n\n      fixture.componentInstance.trigger.onKeydown.emit(ENTER_EVENT);\n      // TODO: ivy fix\n      expect(ENTER_EVENT.defaultPrevented).toBe(true);\n      // expect(false).toBe(true);\n    }));\n\n    it('should not prevent the default enter action for a closed dropdown', () => {\n      textarea.value = 'ABC';\n      fixture.detectChanges();\n      dispatchFakeEvent(textarea, 'click');\n      fixture.detectChanges();\n      fixture.componentInstance.trigger.onKeydown.emit(ENTER_EVENT);\n      // TODO: ivy fix\n      expect(ENTER_EVENT.defaultPrevented).toBe(false);\n      // expect(true).toBe(false);\n    });\n\n    it('should close the dropdown when tabbing', fakeAsync(() => {\n      textarea.value = '@';\n      dispatchFakeEvent(textarea, 'click');\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-mentions-dropdown')).toBeTruthy();\n      dispatchKeyboardEvent(textarea, 'keydown', TAB);\n      fixture.detectChanges();\n      tick(500);\n      expect(overlayContainerElement.querySelector('.ant-mentions-dropdown')).toBeFalsy();\n    }));\n\n    it('should close the dropdown when pressing escape', fakeAsync(() => {\n      textarea.value = '@';\n      dispatchFakeEvent(textarea, 'click');\n      fixture.detectChanges();\n\n      expect(overlayContainerElement.querySelector('.ant-mentions-dropdown')).toBeTruthy();\n\n      dispatchKeyboardEvent(textarea, 'keydown', ESCAPE);\n      fixture.detectChanges();\n\n      tick(500);\n      expect(overlayContainerElement.querySelector('.ant-mentions-dropdown')).toBeFalsy();\n    }));\n  });\n\n  describe('property', () => {\n    let fixture: ComponentFixture<NzTestPropertyMentionComponent>;\n    let textarea: HTMLTextAreaElement;\n    let spyNzOnSearch: jasmine.Spy;\n\n    beforeEach(fakeAsync(() => {\n      fixture = TestBed.createComponent(NzTestPropertyMentionComponent);\n      fixture.detectChanges();\n      tick();\n      textarea = fixture.debugElement.query(By.css('textarea')).nativeElement;\n      spyNzOnSearch = spyOn(fixture.componentInstance, 'onSearchChange');\n    }));\n\n    afterEach(() => {\n      spyNzOnSearch.calls.reset();\n    });\n\n    it('should open the dropdown when the async load suggestions', fakeAsync(() => {\n      fixture.detectChanges();\n      dispatchFakeEvent(textarea, 'click');\n      typeInElement('@', textarea);\n      fixture.detectChanges();\n      fixture.componentInstance.fetchSuggestions();\n      fixture.detectChanges();\n\n      tick();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-mentions-dropdown .anticon-loading')).toBeTruthy();\n      fixture.detectChanges();\n      flush(500);\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-mentions-dropdown .anticon-loading')).toBeFalsy();\n    }));\n\n    it('should open the dropdown when the type in @ prefix', () => {\n      fixture.componentInstance.setArrayPrefix();\n      dispatchFakeEvent(textarea, 'click');\n      fixture.detectChanges();\n      typeInElement('@', textarea);\n      fixture.detectChanges();\n\n      const mention = fixture.componentInstance.mention;\n\n      expect(mention.isOpen).toBe(true);\n    });\n\n    it('should emit nzOnSearchChange when type in @ prefix', () => {\n      dispatchFakeEvent(textarea, 'click');\n      fixture.detectChanges();\n      typeInElement('@test', textarea);\n      fixture.detectChanges();\n\n      expect(spyNzOnSearch).toHaveBeenCalledTimes(1);\n\n      typeInElement('@test  @', textarea);\n      fixture.detectChanges();\n\n      expect(spyNzOnSearch).toHaveBeenCalledTimes(2);\n\n      typeInElement('@test  @ @', textarea);\n      fixture.detectChanges();\n\n      expect(spyNzOnSearch).toHaveBeenCalledTimes(3);\n    });\n\n    it('should open the dropdown when the type in # prefix', () => {\n      fixture.componentInstance.setArrayPrefix();\n      dispatchFakeEvent(textarea, 'click');\n      fixture.detectChanges();\n      typeInElement('#', textarea);\n      fixture.detectChanges();\n\n      const mention = fixture.componentInstance.mention;\n\n      expect(mention.isOpen).toBe(true);\n    });\n\n    it('should has the custom template in the dropdown', () => {\n      dispatchFakeEvent(textarea, 'click');\n      fixture.detectChanges();\n      typeInElement('@', textarea);\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-mentions-dropdown .custom')).toBeTruthy();\n    });\n\n    it('should correct parsing the trigger content', () => {\n      fixture.componentInstance.setArrayPrefix();\n      typeInElement(\n        'ABC @Angular 123 @ant-design @你好 foo ant@gmail.com @@ng 123 .@.@ /@hello \\\\@hello #ng',\n        textarea\n      );\n      fixture.detectChanges();\n      expect(fixture.componentInstance.mention.getMentions().join(',')).toBe('@Angular,@ant-design,@你好,@@ng,#ng');\n    });\n  });\n\n  describe('status', () => {\n    let fixture: ComponentFixture<NzTestStatusMentionComponent>;\n    let mention: DebugElement;\n\n    beforeEach(fakeAsync(() => {\n      fixture = TestBed.createComponent(NzTestStatusMentionComponent);\n      mention = fixture.debugElement.query(By.directive(NzMentionComponent));\n      fixture.detectChanges();\n      tick();\n    }));\n\n    it('should className with status correct', () => {\n      fixture.detectChanges();\n      expect(mention.nativeElement.classList).toContain('ant-mentions-status-error');\n\n      fixture.componentInstance.status = 'warning';\n      fixture.detectChanges();\n      expect(mention.nativeElement.classList).toContain('ant-mentions-status-warning');\n\n      fixture.componentInstance.status = '';\n      fixture.detectChanges();\n      expect(mention.nativeElement.classList).not.toContain('ant-mentions-status-warning');\n    });\n  });\n\n  describe('in form', () => {\n    let fixture: ComponentFixture<NzTestMentionInFormComponent>;\n    let mention: DebugElement;\n\n    beforeEach(fakeAsync(() => {\n      fixture = TestBed.createComponent(NzTestMentionInFormComponent);\n      mention = fixture.debugElement.query(By.directive(NzMentionComponent));\n      fixture.detectChanges();\n      tick();\n    }));\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n      expect(mention.nativeElement.classList).toContain('ant-mentions-status-error');\n      expect(mention.nativeElement.querySelector('nz-form-item-feedback-icon')).toBeTruthy();\n\n      fixture.componentInstance.status = 'warning';\n      fixture.detectChanges();\n      expect(mention.nativeElement.classList).toContain('ant-mentions-status-warning');\n\n      fixture.componentInstance.status = 'success';\n      fixture.detectChanges();\n      expect(mention.nativeElement.classList).toContain('ant-mentions-status-success');\n\n      fixture.componentInstance.feedback = false;\n      fixture.detectChanges();\n      expect(mention.nativeElement.querySelector('nz-form-item-feedback-icon')).toBeNull();\n    });\n  });\n\n  describe('variant', () => {\n    let fixture: ComponentFixture<NzTestVariantMentionComponent>;\n    let mention: DebugElement;\n\n    beforeEach(fakeAsync(() => {\n      fixture = TestBed.createComponent(NzTestVariantMentionComponent);\n      mention = fixture.debugElement.query(By.directive(NzMentionComponent));\n      fixture.detectChanges();\n      tick();\n    }));\n\n    it('should have default outlined variant', () => {\n      expect(mention.nativeElement.classList).not.toContain('ant-mentions-borderless');\n      expect(mention.nativeElement.classList).not.toContain('ant-mentions-filled');\n      expect(mention.nativeElement.classList).not.toContain('ant-mentions-underlined');\n    });\n\n    it('should apply borderless variant correctly', () => {\n      fixture.componentInstance.variant = 'borderless';\n      fixture.detectChanges();\n      expect(mention.nativeElement.classList).toContain('ant-mentions-borderless');\n      expect(mention.nativeElement.classList).not.toContain('ant-mentions-filled');\n      expect(mention.nativeElement.classList).not.toContain('ant-mentions-underlined');\n    });\n\n    it('should apply filled variant correctly', () => {\n      fixture.componentInstance.variant = 'filled';\n      fixture.detectChanges();\n      expect(mention.nativeElement.classList).toContain('ant-mentions-filled');\n      expect(mention.nativeElement.classList).not.toContain('ant-mentions-borderless');\n      expect(mention.nativeElement.classList).not.toContain('ant-mentions-underlined');\n    });\n\n    it('should apply underlined variant correctly', () => {\n      fixture.componentInstance.variant = 'underlined';\n      fixture.detectChanges();\n      expect(mention.nativeElement.classList).toContain('ant-mentions-underlined');\n      expect(mention.nativeElement.classList).not.toContain('ant-mentions-borderless');\n      expect(mention.nativeElement.classList).not.toContain('ant-mentions-filled');\n    });\n\n    it('should switch between variants correctly', () => {\n      fixture.componentInstance.variant = 'filled';\n      fixture.detectChanges();\n      expect(mention.nativeElement.classList).toContain('ant-mentions-filled');\n\n      fixture.componentInstance.variant = 'borderless';\n      fixture.detectChanges();\n      expect(mention.nativeElement.classList).toContain('ant-mentions-borderless');\n      expect(mention.nativeElement.classList).not.toContain('ant-mentions-filled');\n\n      fixture.componentInstance.variant = 'outlined';\n      fixture.detectChanges();\n      expect(mention.nativeElement.classList).not.toContain('ant-mentions-borderless');\n      expect(mention.nativeElement.classList).not.toContain('ant-mentions-filled');\n      expect(mention.nativeElement.classList).not.toContain('ant-mentions-underlined');\n    });\n\n    it('should maintain functionality across different variants', fakeAsync(() => {\n      const variants: Array<'outlined' | 'filled' | 'borderless' | 'underlined'> = [\n        'outlined',\n        'filled',\n        'borderless',\n        'underlined'\n      ];\n\n      variants.forEach(variant => {\n        fixture.componentInstance.variant = variant;\n        fixture.detectChanges();\n\n        const textarea = fixture.debugElement.query(By.css('textarea')).nativeElement;\n        textarea.value = '@angular';\n        fixture.detectChanges();\n\n        dispatchFakeEvent(textarea, 'click');\n        fixture.detectChanges();\n        flush();\n\n        expect(fixture.componentInstance.mention.isOpen).toBe(true);\n\n        const option = overlayContainerElement.querySelector('.ant-mentions-dropdown-menu-item') as HTMLElement;\n        if (option) {\n          option.click();\n          fixture.detectChanges();\n          tick(500);\n\n          expect(fixture.componentInstance.mention.isOpen).toBe(false);\n        }\n      });\n    }));\n  });\n\n  describe('clear button', () => {\n    let fixture: ComponentFixture<NzTestClearMentionComponent>;\n    let textarea: HTMLTextAreaElement;\n\n    beforeEach(fakeAsync(() => {\n      fixture = TestBed.createComponent(NzTestClearMentionComponent);\n      fixture.detectChanges();\n      textarea = fixture.debugElement.query(By.css('textarea')).nativeElement;\n      tick();\n    }));\n\n    it('should not show clear button when nzAllowClear is false', fakeAsync(() => {\n      fixture.componentInstance.allowClear = false;\n      fixture.detectChanges();\n      typeInElement('test value', textarea);\n      fixture.detectChanges();\n      tick();\n      expect(fixture.debugElement.query(By.css('.ant-mentions-clear-icon'))).toBeNull();\n    }));\n\n    it('should show clear button when nzAllowClear is true and has value', fakeAsync(() => {\n      fixture.componentInstance.allowClear = true;\n      fixture.detectChanges();\n      typeInElement('test value', textarea);\n      fixture.detectChanges();\n      tick();\n      expect(fixture.debugElement.query(By.css('.ant-mentions-clear-icon'))).toBeTruthy();\n    }));\n\n    it('should not show clear button when nzAllowClear is true but has no value', fakeAsync(() => {\n      fixture.componentInstance.allowClear = true;\n      fixture.detectChanges();\n      typeInElement('', textarea);\n      fixture.detectChanges();\n      tick();\n      expect(fixture.debugElement.query(By.css('.ant-mentions-clear-icon'))).toBeNull();\n    }));\n\n    it('should clear input value when clear button is clicked', fakeAsync(() => {\n      fixture.componentInstance.allowClear = true;\n      fixture.detectChanges();\n      typeInElement('test value', textarea);\n      fixture.detectChanges();\n      tick();\n\n      const clearButton = fixture.debugElement.query(By.css('.ant-mentions-clear-icon')).nativeElement;\n      clearButton.click();\n      fixture.detectChanges();\n      tick();\n\n      expect(textarea.value).toBe('');\n      expect(fixture.componentInstance.inputValue).toBe('');\n    }));\n\n    it('should emit nzOnClear when clear button is clicked', fakeAsync(() => {\n      const spy = spyOn(fixture.componentInstance, 'onClear');\n      fixture.componentInstance.allowClear = true;\n      fixture.detectChanges();\n      typeInElement('test value', textarea);\n      fixture.detectChanges();\n      tick();\n\n      const clearButton = fixture.debugElement.query(By.css('.ant-mentions-clear-icon')).nativeElement;\n      clearButton.click();\n      fixture.detectChanges();\n\n      expect(spy).toHaveBeenCalled();\n    }));\n\n    it('should use custom clear icon when provided', fakeAsync(() => {\n      fixture.componentInstance.allowClear = true;\n      fixture.componentInstance.useCustomClearIcon = true;\n      fixture.detectChanges();\n      typeInElement('test value', textarea);\n      fixture.detectChanges();\n      tick();\n\n      const clearIcon = fixture.debugElement.query(By.css('.custom-clear-icon'));\n      expect(clearIcon).toBeTruthy();\n    }));\n  });\n});\n\ndescribe('finalVariant', () => {\n  let fixture: ComponentFixture<NzTestFinalVariantMentionComponent>;\n  let mentionHtmlElement: HTMLElement;\n  let formVariantSignal: WritableSignal<NzVariant>;\n\n  beforeEach(() => {\n    formVariantSignal = signal<NzVariant>('outlined');\n  });\n  afterEach(() => {\n    TestBed.resetTestingModule();\n  });\n  it('should use formVariant when nzVariant is not set (undefined by default)', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_FORM_VARIANT, useValue: formVariantSignal }]\n    });\n    fixture = TestBed.createComponent(NzTestFinalVariantMentionComponent);\n    mentionHtmlElement = fixture.debugElement.query(By.directive(NzMentionComponent)).nativeElement;\n    fixture.detectChanges();\n    formVariantSignal.set('filled');\n    fixture.detectChanges();\n    expect(mentionHtmlElement.classList).toContain('ant-mentions-filled');\n  });\n\n  it('should use nzVariant over formVariant when nzVariant is explicitly set', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_FORM_VARIANT, useValue: formVariantSignal }]\n    });\n    fixture = TestBed.createComponent(NzTestFinalVariantMentionComponent);\n    mentionHtmlElement = fixture.debugElement.query(By.directive(NzMentionComponent)).nativeElement;\n    fixture.componentInstance.variant.set('borderless');\n    fixture.detectChanges();\n    formVariantSignal.set('filled');\n    fixture.detectChanges();\n    expect(mentionHtmlElement.classList).toContain('ant-mentions-borderless');\n    expect(mentionHtmlElement.classList).not.toContain('ant-mentions-filled');\n  });\n\n  it('should use nzVariant outlined over formVariant when explicitly set', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_FORM_VARIANT, useValue: formVariantSignal }]\n    });\n    fixture = TestBed.createComponent(NzTestFinalVariantMentionComponent);\n    mentionHtmlElement = fixture.debugElement.query(By.directive(NzMentionComponent)).nativeElement;\n    fixture.componentInstance.variant.set('outlined');\n    fixture.detectChanges();\n    formVariantSignal.set('filled');\n    fixture.detectChanges();\n    expect(mentionHtmlElement.classList).not.toContain('ant-mentions-filled');\n  });\n\n  it('should use nzVariant when no formVariant is provided', () => {\n    fixture = TestBed.createComponent(NzTestFinalVariantMentionComponent);\n    mentionHtmlElement = fixture.debugElement.query(By.directive(NzMentionComponent)).nativeElement;\n    fixture.componentInstance.variant.set('filled');\n    fixture.detectChanges();\n    expect(mentionHtmlElement.classList).toContain('ant-mentions-filled');\n  });\n\n  it('should default to outlined when neither nzVariant nor formVariant is set', () => {\n    fixture = TestBed.createComponent(NzTestFinalVariantMentionComponent);\n    mentionHtmlElement = fixture.debugElement.query(By.directive(NzMentionComponent)).nativeElement;\n    fixture.detectChanges();\n    expect(mentionHtmlElement.classList).not.toContain('ant-mentions-filled');\n    expect(mentionHtmlElement.classList).not.toContain('ant-mentions-borderless');\n    expect(mentionHtmlElement.classList).not.toContain('ant-mentions-underlined');\n  });\n});\n\n@Component({\n  imports: [FormsModule, NzInputModule, NzMentionModule],\n  template: `\n    <nz-mention [nzSuggestions]=\"suggestions\">\n      @if (!inputTrigger) {\n        <textarea nz-input [(ngModel)]=\"inputValue\" nzMentionTrigger></textarea>\n      } @else {\n        <textarea rows=\"1\" nz-input [(ngModel)]=\"inputValue\" nzMentionTrigger></textarea>\n      }\n    </nz-mention>\n  `\n})\nclass NzTestSimpleMentionComponent {\n  inputValue: string = '@angular';\n  inputTrigger = false;\n  suggestions = ['angular', 'ant-design', 'mention', '中文', 'にほんご'];\n  @ViewChild(NzMentionComponent, { static: false }) mention!: NzMentionComponent;\n  @ViewChild(NzMentionTriggerDirective, { static: false }) trigger!: NzMentionTriggerDirective;\n}\n\n@Component({\n  imports: [FormsModule, NzInputModule, NzMentionModule],\n  template: `\n    <nz-mention\n      [nzSuggestions]=\"webFrameworks\"\n      [nzValueWith]=\"valueWith\"\n      [nzPrefix]=\"prefix\"\n      nzPlacement=\"top\"\n      [nzLoading]=\"loading\"\n      (nzOnSearchChange)=\"onSearchChange()\"\n    >\n      <textarea nz-input [(ngModel)]=\"inputValue\" nzMentionTrigger></textarea>\n      <ng-container *nzMentionSuggestion=\"let framework\">\n        <span class=\"custom\">{{ framework.name }} - {{ framework.type }}</span>\n      </ng-container>\n    </nz-mention>\n  `\n})\nclass NzTestPropertyMentionComponent {\n  inputValue: string = '@angular';\n  webFrameworks = [\n    { name: 'React', type: 'JavaScript' },\n    { name: 'Angular', type: 'JavaScript' },\n    { name: 'Laravel', type: 'PHP' },\n    { name: 'Flask', type: 'Python' },\n    { name: 'Django', type: 'Python' }\n  ];\n  loading = false;\n  prefix: string | string[] = '@';\n  valueWith = (data: { name: string; type: string }): string => data.name;\n  @ViewChild(NzMentionComponent, { static: false }) mention!: NzMentionComponent;\n  @ViewChild(NzMentionTriggerDirective, { static: false }) trigger!: NzMentionTriggerDirective;\n\n  setArrayPrefix(): void {\n    this.prefix = ['@', '#'];\n  }\n\n  onSearchChange(): void {}\n\n  fetchSuggestions(): void {\n    this.webFrameworks = [];\n    this.loading = true;\n    setTimeout(() => {\n      this.loading = false;\n      this.webFrameworks = [\n        { name: 'React', type: 'JavaScript' },\n        { name: 'Angular', type: 'JavaScript' },\n        { name: 'Laravel', type: 'PHP' },\n        { name: 'Flask', type: 'Python' },\n        { name: 'Django', type: 'Python' }\n      ];\n    }, 500);\n  }\n}\n\n@Component({\n  imports: [BidiModule, NzInputModule, NzMentionModule],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-mention [nzSuggestions]=\"[]\">\n        <textarea rows=\"1\" nz-input nzMentionTrigger></textarea>\n      </nz-mention>\n    </div>\n  `\n})\nclass NzTestDirMentionComponent {\n  direction: Direction = 'ltr';\n}\n\n@Component({\n  imports: [NzInputModule, NzMentionModule],\n  template: `\n    <nz-mention [nzSuggestions]=\"[]\" [nzStatus]=\"status\">\n      <textarea rows=\"1\" nz-input nzMentionTrigger></textarea>\n    </nz-mention>\n  `\n})\nclass NzTestStatusMentionComponent {\n  status: NzStatus = 'error';\n}\n\n@Component({\n  imports: [NzFormModule, NzMentionModule],\n  template: `\n    <form nz-form>\n      <nz-form-item>\n        <nz-form-control [nzHasFeedback]=\"feedback\" [nzValidateStatus]=\"status\">\n          <nz-mention [nzSuggestions]=\"[]\">\n            <textarea rows=\"1\" nzMentionTrigger></textarea>\n          </nz-mention>\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `\n})\nclass NzTestMentionInFormComponent {\n  status: NzFormControlStatusType = 'error';\n  feedback = true;\n}\n\n@Component({\n  imports: [FormsModule, NzInputModule, NzMentionModule],\n  template: `\n    <nz-mention [nzSuggestions]=\"suggestions\" [nzVariant]=\"variant\">\n      <textarea nz-input [(ngModel)]=\"inputValue\" nzMentionTrigger></textarea>\n    </nz-mention>\n  `\n})\nclass NzTestVariantMentionComponent {\n  inputValue: string = '@angular';\n  variant: 'outlined' | 'filled' | 'borderless' | 'underlined' = 'outlined';\n  suggestions = ['angular', 'ant-design', 'mention'];\n  @ViewChild(NzMentionComponent, { static: false }) mention!: NzMentionComponent;\n}\n\n@Component({\n  imports: [FormsModule, NzInputModule, NzMentionModule],\n  template: `\n    <nz-mention\n      [nzSuggestions]=\"suggestions\"\n      [nzAllowClear]=\"allowClear\"\n      [nzClearIcon]=\"useCustomClearIcon ? clearIconTemplate : null\"\n      (nzOnClear)=\"onClear()\"\n    >\n      <textarea nz-input [(ngModel)]=\"inputValue\" nzMentionTrigger></textarea>\n      <ng-template #clearIconTemplate>\n        <span class=\"custom-clear-icon\">×</span>\n      </ng-template>\n    </nz-mention>\n  `\n})\nclass NzTestClearMentionComponent {\n  inputValue = '';\n  suggestions = ['angular', 'ant-design', 'mention'];\n  allowClear = false;\n  useCustomClearIcon = false;\n\n  @ViewChild(NzMentionComponent, { static: false }) mention!: NzMentionComponent;\n\n  onClear(): void {}\n}\n\n@Component({\n  imports: [NzMentionModule],\n  template: `\n    <nz-mention [nzSuggestions]=\"suggestions\" [nzVariant]=\"variant()\">\n      <textarea nz-input nzMentionTrigger></textarea>\n    </nz-mention>\n  `\n})\nclass NzTestFinalVariantMentionComponent {\n  readonly variant = signal<NzVariant | undefined>(undefined);\n  suggestions = ['angular', 'ant-design', 'mention'];\n}\n"
  },
  {
    "path": "components/mention/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/mention/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './mention.module';\nexport * from './mention.component';\nexport * from './mention-trigger';\nexport * from './mention-suggestions';\n"
  },
  {
    "path": "components/mention/style/entry.less",
    "content": "@import './index.less';\n@import \"./patch\";\n"
  },
  {
    "path": "components/mention/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import '../../input/style/mixin';\n@import './status';\n\n@mention-prefix-cls: ~'@{ant-prefix}-mentions';\n\n.@{mention-prefix-cls} {\n  .reset-component();\n  .input();\n\n  position: relative;\n  display: inline-block;\n  height: auto;\n  padding: 0;\n  overflow: hidden;\n  line-height: @line-height-base;\n  white-space: pre-wrap;\n  vertical-align: bottom;\n\n  // =================== Status ===================\n  &-disabled {\n    > .@{ant-prefix}-input {\n      .disabled();\n    }\n  }\n\n  &-focused {\n    .active();\n  }\n\n  // ================= Input Area =================\n  > .@{ant-prefix}-input,\n  &-measure {\n    min-height: @input-height-base - 2px;\n    margin: 0;\n    padding: @input-padding-vertical-base @input-padding-horizontal-base;\n    overflow: inherit;\n    overflow-x: hidden;\n    overflow-y: auto;\n    /* stylelint-disable declaration-block-no-redundant-longhand-properties */\n    font-weight: inherit;\n    font-size: inherit;\n    font-family: inherit;\n    font-style: inherit;\n    font-variant: inherit;\n    font-size-adjust: inherit;\n    font-stretch: inherit;\n    line-height: inherit;\n    /* stylelint-enable declaration-block-no-redundant-longhand-properties */\n    direction: inherit;\n    letter-spacing: inherit;\n    white-space: inherit;\n    text-align: inherit;\n    vertical-align: top;\n    word-wrap: break-word;\n    word-break: inherit;\n    tab-size: inherit;\n  }\n\n  > .@{ant-prefix}-input {\n    width: 100%;\n    background-color: inherit;\n    border: none;\n    outline: none;\n    resize: none;\n\n    & when (@theme = dark) {\n      background-color: transparent;\n    }\n\n    .placeholder();\n  }\n\n  &-measure {\n    position: absolute;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    z-index: -1;\n    color: transparent;\n    pointer-events: none;\n\n    > span {\n      display: inline-block;\n      min-height: 1em;\n    }\n  }\n\n  // ================== Dropdown ==================\n  &-dropdown {\n    // Ref select dropdown style\n    .reset-component();\n\n    position: absolute;\n    top: -9999px;\n    left: -9999px;\n    z-index: @zindex-dropdown;\n    box-sizing: border-box;\n    font-size: @font-size-base;\n    font-variant: initial;\n    background-color: @mentions-dropdown-bg;\n    border-radius: @border-radius-base;\n    outline: none;\n    box-shadow: @box-shadow-base;\n\n    &-hidden {\n      display: none;\n    }\n\n    &-menu {\n      max-height: 250px;\n      margin-bottom: 0;\n      padding-left: 0; // Override default ul/ol\n      overflow: auto;\n      list-style: none;\n      outline: none;\n\n      &-item {\n        position: relative;\n        display: block;\n        min-width: 100px;\n        padding: 5px @control-padding-horizontal;\n        overflow: hidden;\n        color: @text-color;\n        font-weight: normal;\n        line-height: @line-height-base;\n        white-space: nowrap;\n        text-overflow: ellipsis;\n        cursor: pointer;\n        transition: background 0.3s ease;\n\n        &:hover {\n          background-color: @item-hover-bg;\n        }\n\n        &:first-child {\n          border-radius: @border-radius-base @border-radius-base 0 0;\n        }\n\n        &:last-child {\n          border-radius: 0 0 @border-radius-base @border-radius-base;\n        }\n\n        &-disabled {\n          color: @disabled-color;\n          cursor: not-allowed;\n\n          &:hover {\n            color: @disabled-color;\n            background-color: @mentions-dropdown-menu-item-hover-bg;\n            cursor: not-allowed;\n          }\n        }\n\n        &-selected {\n          color: @text-color;\n          font-weight: @select-item-selected-font-weight;\n          background-color: @background-color-light;\n        }\n\n        &-active {\n          background-color: @item-hover-bg;\n        }\n      }\n    }\n  }\n\n  &-suffix {\n    position: absolute;\n    top: 0;\n    right: @input-padding-horizontal-base;\n    bottom: 0;\n    z-index: 1;\n    display: inline-flex;\n    align-items: center;\n    margin: auto;\n  }\n\n  &-clear-icon {\n    padding: 0;\n    color: @disabled-color;\n    font-size: @font-size-sm;\n    line-height: 0;\n    vertical-align: -1px;\n    background-color: transparent;\n    border: none;\n    outline: none;\n    cursor: pointer;\n    transition: color 0.3s;\n\n    &:hover {\n      color: @text-color-secondary;\n    }\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/mention/style/patch.less",
    "content": ".@{mention-prefix-cls} {\n  &-dropdown {\n    position: relative;\n    top: 100%;\n    left: 12px;\n    width: 100%;\n    margin-top: 8px;\n    margin-bottom: 4px;\n  }\n\n  &:focus-within {\n    .active();\n  }\n\n  &&-status-error {\n    &:not(.@{mention-prefix-cls}-disabled):not(.@{mention-prefix-cls}-borderless).@{mention-prefix-cls} {\n      &:focus-within {\n        .active(@error-color, @error-color-hover, @error-color-outline);\n      }\n    }\n  }\n\n  &&-status-warning {\n    &:not(.@{mention-prefix-cls}-disabled):not(.@{mention-prefix-cls}-borderless).@{mention-prefix-cls} {\n      &:focus-within {\n        .active(@warning-color, @warning-color-hover, @warning-color-outline);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/mention/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@mention-prefix-cls: ~'@{ant-prefix}-mentions';\n\n.@{mention-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n}\n"
  },
  {
    "path": "components/mention/style/status.less",
    "content": "@import '../../input/style/mixin';\n\n@mention-prefix-cls: ~'@{ant-prefix}-mentions';\n@input-prefix-cls: ~'@{ant-prefix}-input';\n\n.@{mention-prefix-cls} {\n  &-status-error {\n    .status-color(@mention-prefix-cls, @error-color, @error-color, @input-bg, @error-color-hover, @error-color-outline);\n    .status-color-common(@input-prefix-cls, @error-color, @error-color, @input-bg, @error-color-hover, @error-color-outline);\n  }\n\n  &-status-warning {\n    .status-color(@mention-prefix-cls, @warning-color, @warning-color, @input-bg, @warning-color-hover, @warning-color-outline);\n    .status-color-common(@input-prefix-cls, @warning-color, @warning-color, @input-bg, @warning-color-hover, @warning-color-outline);\n  }\n}\n"
  },
  {
    "path": "components/menu/demo/horizontal-position.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 弹出位置\n  en-US: Placement\n---\n\n## zh-CN\n\n支持 6 个弹出位置。\n\n## en-US\n\nSupport 6 placements.\n"
  },
  {
    "path": "components/menu/demo/horizontal-position.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\n\n@Component({\n  selector: 'nz-demo-menu-horizontal-position',\n  imports: [NzMenuModule],\n  template: `\n    <ul nz-menu nzMode=\"horizontal\">\n      <li nz-submenu nzPlacement=\"bottomLeft\" nzTitle=\"bottomLeft\">\n        <ul>\n          <li nz-menu-group nzTitle=\"Item 1\">\n            <ul>\n              <li nz-menu-item>Option 1</li>\n              <li nz-menu-item>Option 2</li>\n            </ul>\n          </li>\n          <li nz-menu-group nzTitle=\"Item 2\">\n            <ul>\n              <li nz-menu-item>Option 3</li>\n              <li nz-menu-item>Option 4</li>\n              <li nz-submenu nzTitle=\"Sub Menu\">\n                <ul>\n                  <li nz-menu-item nzDisabled>Option 5</li>\n                  <li nz-menu-item>Option 6</li>\n                </ul>\n              </li>\n              <li nz-submenu nzDisabled nzTitle=\"Disabled Sub Menu\">\n                <ul>\n                  <li nz-menu-item>Option 5</li>\n                  <li nz-menu-item>Option 6</li>\n                </ul>\n              </li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li nz-submenu nzPlacement=\"bottomCenter\" nzTitle=\"bottomCenter\">\n        <ul>\n          <li nz-menu-group nzTitle=\"Item 1\">\n            <ul>\n              <li nz-menu-item>Option 1</li>\n              <li nz-menu-item>Option 2</li>\n            </ul>\n          </li>\n          <li nz-menu-group nzTitle=\"Item 2\">\n            <ul>\n              <li nz-menu-item>Option 3</li>\n              <li nz-menu-item>Option 4</li>\n              <li nz-submenu nzTitle=\"Sub Menu\">\n                <ul>\n                  <li nz-menu-item nzDisabled>Option 5</li>\n                  <li nz-menu-item>Option 6</li>\n                </ul>\n              </li>\n              <li nz-submenu nzDisabled nzTitle=\"Disabled Sub Menu\">\n                <ul>\n                  <li nz-menu-item>Option 5</li>\n                  <li nz-menu-item>Option 6</li>\n                </ul>\n              </li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li nz-submenu nzPlacement=\"bottomRight\" nzTitle=\"bottomRight\">\n        <ul>\n          <li nz-menu-group nzTitle=\"Item 1\">\n            <ul>\n              <li nz-menu-item>Option 1</li>\n              <li nz-menu-item>Option 2</li>\n            </ul>\n          </li>\n          <li nz-menu-group nzTitle=\"Item 2\">\n            <ul>\n              <li nz-menu-item>Option 3</li>\n              <li nz-menu-item>Option 4</li>\n              <li nz-submenu nzTitle=\"Sub Menu\">\n                <ul>\n                  <li nz-menu-item nzDisabled>Option 5</li>\n                  <li nz-menu-item>Option 6</li>\n                </ul>\n              </li>\n              <li nz-submenu nzDisabled nzTitle=\"Disabled Sub Menu\">\n                <ul>\n                  <li nz-menu-item>Option 5</li>\n                  <li nz-menu-item>Option 6</li>\n                </ul>\n              </li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li nz-submenu nzPlacement=\"topLeft\" nzTitle=\"topLeft\">\n        <ul>\n          <li nz-menu-group nzTitle=\"Item 1\">\n            <ul>\n              <li nz-menu-item>Option 1</li>\n              <li nz-menu-item>Option 2</li>\n            </ul>\n          </li>\n          <li nz-menu-group nzTitle=\"Item 2\">\n            <ul>\n              <li nz-menu-item>Option 3</li>\n              <li nz-menu-item>Option 4</li>\n              <li nz-submenu nzTitle=\"Sub Menu\">\n                <ul>\n                  <li nz-menu-item nzDisabled>Option 5</li>\n                  <li nz-menu-item>Option 6</li>\n                </ul>\n              </li>\n              <li nz-submenu nzDisabled nzTitle=\"Disabled Sub Menu\">\n                <ul>\n                  <li nz-menu-item>Option 5</li>\n                  <li nz-menu-item>Option 6</li>\n                </ul>\n              </li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li nz-submenu nzPlacement=\"topCenter\" nzTitle=\"topCenter\">\n        <ul>\n          <li nz-menu-group nzTitle=\"Item 1\">\n            <ul>\n              <li nz-menu-item>Option 1</li>\n              <li nz-menu-item>Option 2</li>\n            </ul>\n          </li>\n          <li nz-menu-group nzTitle=\"Item 2\">\n            <ul>\n              <li nz-menu-item>Option 3</li>\n              <li nz-menu-item>Option 4</li>\n              <li nz-submenu nzTitle=\"Sub Menu\">\n                <ul>\n                  <li nz-menu-item nzDisabled>Option 5</li>\n                  <li nz-menu-item>Option 6</li>\n                </ul>\n              </li>\n              <li nz-submenu nzDisabled nzTitle=\"Disabled Sub Menu\">\n                <ul>\n                  <li nz-menu-item>Option 5</li>\n                  <li nz-menu-item>Option 6</li>\n                </ul>\n              </li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li nz-submenu nzPlacement=\"topRight\" nzTitle=\"topRight\">\n        <ul>\n          <li nz-menu-group nzTitle=\"Item 1\">\n            <ul>\n              <li nz-menu-item>Option 1</li>\n              <li nz-menu-item>Option 2</li>\n            </ul>\n          </li>\n          <li nz-menu-group nzTitle=\"Item 2\">\n            <ul>\n              <li nz-menu-item>Option 3</li>\n              <li nz-menu-item>Option 4</li>\n              <li nz-submenu nzTitle=\"Sub Menu\">\n                <ul>\n                  <li nz-menu-item nzDisabled>Option 5</li>\n                  <li nz-menu-item>Option 6</li>\n                </ul>\n              </li>\n              <li nz-submenu nzDisabled nzTitle=\"Disabled Sub Menu\">\n                <ul>\n                  <li nz-menu-item>Option 5</li>\n                  <li nz-menu-item>Option 6</li>\n                </ul>\n              </li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n    </ul>\n  `\n})\nexport class NzDemoMenuHorizontalPositionComponent {}\n"
  },
  {
    "path": "components/menu/demo/horizontal.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 顶部导航\n  en-US: Top Navigation\n---\n\n## zh-CN\n\n水平的顶部导航菜单。\n\n## en-US\n\nHorizontal top navigation menu.\n"
  },
  {
    "path": "components/menu/demo/horizontal.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\n\n@Component({\n  selector: 'nz-demo-menu-horizontal',\n  imports: [NzIconModule, NzMenuModule],\n  template: `\n    <ul nz-menu nzMode=\"horizontal\">\n      <li nz-menu-item nzSelected>\n        <nz-icon nzType=\"mail\" />\n        Navigation One\n      </li>\n      <li nz-menu-item nzDisabled>\n        <nz-icon nzType=\"appstore\" />\n        Navigation Two\n      </li>\n      <li nz-submenu nzTitle=\"Navigation Three - Submenu\" nzIcon=\"setting\">\n        <ul>\n          <li nz-menu-group nzTitle=\"Item 1\">\n            <ul>\n              <li nz-menu-item>Option 1</li>\n              <li nz-menu-item>Option 2</li>\n            </ul>\n          </li>\n          <li nz-menu-group nzTitle=\"Item 2\">\n            <ul>\n              <li nz-menu-item>Option 3</li>\n              <li nz-menu-item>Option 4</li>\n              <li nz-submenu nzTitle=\"Sub Menu\">\n                <ul>\n                  <li nz-menu-item nzDisabled>Option 5</li>\n                  <li nz-menu-item>Option 6</li>\n                </ul>\n              </li>\n              <li nz-submenu nzTitle=\"Click me\" nzTriggerSubMenuAction=\"click\">\n                <ul>\n                  <li nz-menu-item nzDisabled>Option 5</li>\n                  <li nz-menu-item>Option 6</li>\n                </ul>\n              </li>\n              <li nz-submenu nzDisabled nzTitle=\"Disabled Sub Menu\">\n                <ul>\n                  <li nz-menu-item>Option 5</li>\n                  <li nz-menu-item>Option 6</li>\n                </ul>\n              </li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li nz-menu-item>\n        <a href=\"https://ng.ant.design\" target=\"_blank\" rel=\"noopener noreferrer\">Navigation Four - Link</a>\n      </li>\n    </ul>\n  `\n})\nexport class NzDemoMenuHorizontalComponent {}\n"
  },
  {
    "path": "components/menu/demo/inline-collapsed.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 缩起内嵌菜单\n  en-US: Collapsed inline menu\n---\n\n## zh-CN\n\n内嵌菜单可以被缩起/展开。\n\n你可以在 [Layout](/components/layout/zh/#components-layout-demo-side) 里查看侧边布局结合的完整示例。\n\n## en-US\n\nInline menu could be collapsed.\n\nHere is [a complete demo](/components/layout/en/#components-layout-demo-side) with sider layout.\n"
  },
  {
    "path": "components/menu/demo/inline-collapsed.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\nimport { NzTooltipModule } from 'ng-zorro-antd/tooltip';\n\n@Component({\n  selector: 'nz-demo-menu-inline-collapsed',\n  imports: [NzButtonModule, NzIconModule, NzMenuModule, NzTooltipModule],\n  template: `\n    <div class=\"wrapper\">\n      <button nz-button nzType=\"primary\" (click)=\"toggleCollapsed()\">\n        <nz-icon [nzType]=\"isCollapsed ? 'menu-unfold' : 'menu-fold'\" />\n      </button>\n      <ul nz-menu nzMode=\"inline\" nzTheme=\"dark\" [nzInlineCollapsed]=\"isCollapsed\">\n        <li\n          nz-menu-item\n          nz-tooltip\n          nzTooltipPlacement=\"right\"\n          [nzTooltipTitle]=\"isCollapsed ? 'Navigation One' : ''\"\n          nzSelected\n        >\n          <nz-icon nzType=\"mail\" />\n          <span>Navigation One</span>\n        </li>\n        <li nz-submenu nzTitle=\"Navigation Two\" nzIcon=\"appstore\">\n          <ul>\n            <li nz-menu-item>Option 5</li>\n            <li nz-menu-item>Option 6</li>\n            <li nz-menu-item>Option 7</li>\n            <li nz-menu-item>Option 8</li>\n          </ul>\n        </li>\n        <li nz-submenu nzTitle=\"Navigation Three\" nzIcon=\"setting\">\n          <ul>\n            <li nz-menu-item>Option 9</li>\n            <li nz-menu-item>Option 10</li>\n            <li nz-submenu nzTitle=\"Submenu\">\n              <ul>\n                <li nz-menu-item>Option 11</li>\n                <li nz-menu-item>Option 12</li>\n              </ul>\n            </li>\n          </ul>\n        </li>\n      </ul>\n    </div>\n  `,\n  styles: `\n    .wrapper {\n      width: 256px;\n    }\n\n    button {\n      margin-bottom: 12px;\n    }\n  `\n})\nexport class NzDemoMenuInlineCollapsedComponent {\n  isCollapsed = false;\n\n  toggleCollapsed(): void {\n    this.isCollapsed = !this.isCollapsed;\n  }\n}\n"
  },
  {
    "path": "components/menu/demo/inline.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 内嵌菜单\n  en-US: Inline menu\n---\n\n## zh-CN\n\n垂直菜单，子菜单内嵌在菜单区域。\n\n## en-US\n\nVertical menu with inline submenus.\n"
  },
  {
    "path": "components/menu/demo/inline.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\n\n@Component({\n  selector: 'nz-demo-menu-inline',\n  imports: [NzMenuModule],\n  template: `\n    <ul nz-menu nzMode=\"inline\">\n      <li nz-submenu nzTitle=\"Navigation One\" nzIcon=\"mail\" nzOpen>\n        <ul>\n          <li nz-menu-group nzTitle=\"Item 1\">\n            <ul>\n              <li nz-menu-item nzSelected>Option 1</li>\n              <li nz-menu-item>Option 2</li>\n            </ul>\n          </li>\n          <li nz-menu-group nzTitle=\"Item 2\">\n            <ul>\n              <li nz-menu-item>Option 3</li>\n              <li nz-menu-item>Option 4</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li nz-submenu nzTitle=\"Navigation Two\" nzIcon=\"appstore\">\n        <ul>\n          <li nz-menu-item>Option 5</li>\n          <li nz-menu-item>Option 6</li>\n          <li nz-submenu nzTitle=\"Submenu\">\n            <ul>\n              <li nz-menu-item>Option 7</li>\n              <li nz-menu-item>Option 8</li>\n              <li nz-submenu nzTitle=\"Submenu\">\n                <ul>\n                  <li nz-menu-item>Option 9</li>\n                  <li nz-menu-item>Option 10</li>\n                </ul>\n              </li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li nz-submenu nzTitle=\"Navigation Three\" nzIcon=\"setting\">\n        <ul>\n          <li nz-menu-item>Option 11</li>\n          <li nz-menu-item>Option 12</li>\n          <li nz-menu-item>Option 13</li>\n        </ul>\n      </li>\n    </ul>\n  `,\n  styles: `\n    [nz-menu] {\n      width: 240px;\n    }\n  `\n})\nexport class NzDemoMenuInlineComponent {}\n"
  },
  {
    "path": "components/menu/demo/recursive.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 递归生成菜单\n  en-US: Recursive\n---\n\n## zh-CN\n\n递归生成菜单，需要手动指定 `nzPaddingLeft`，仅在 `nzMode` 为 `inline` 的模式，且 `nzInlineCollapsed` 为 `false` 的情况下有效。\n\n> 追踪 Issue：[https://github.com/angular/angular/issues/14842](https://github.com/angular/angular/issues/14842)\n\n## en-US\n\nRecursive generation menu, you need to set `nzPaddingLeft` [manually](https://github.com/angular/angular/issues/14842), only works when `nzMode` is `inline` mode and `nzInlineCollapsed` is `false`;\n\n> Track Issue：[https://github.com/angular/angular/issues/14842](https://github.com/angular/angular/issues/14842)\n"
  },
  {
    "path": "components/menu/demo/recursive.ts",
    "content": "import { NgTemplateOutlet } from '@angular/common';\nimport { Component } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\n\n@Component({\n  selector: 'nz-demo-menu-recursive',\n  imports: [NgTemplateOutlet, NzIconModule, NzMenuModule],\n  template: `\n    <ul nz-menu nzMode=\"inline\" style=\"width: 240px;\">\n      <ng-container *ngTemplateOutlet=\"menuTpl; context: { $implicit: menus }\" />\n      <ng-template #menuTpl let-menus>\n        @for (menu of menus; track menu) {\n          @if (!menu.children) {\n            <li\n              nz-menu-item\n              [nzPaddingLeft]=\"menu.level * 24\"\n              [nzDisabled]=\"menu.disabled\"\n              [nzSelected]=\"menu.selected\"\n            >\n              @if (menu.icon) {\n                <nz-icon [nzType]=\"menu.icon\" />\n              }\n              <span>{{ menu.title }}</span>\n            </li>\n          } @else {\n            <li\n              nz-submenu\n              [nzPaddingLeft]=\"menu.level * 24\"\n              [nzOpen]=\"menu.open\"\n              [nzTitle]=\"menu.title\"\n              [nzIcon]=\"menu.icon\"\n              [nzDisabled]=\"menu.disabled\"\n            >\n              <ul>\n                <ng-container *ngTemplateOutlet=\"menuTpl; context: { $implicit: menu.children }\" />\n              </ul>\n            </li>\n          }\n        }\n      </ng-template>\n    </ul>\n  `\n})\nexport class NzDemoMenuRecursiveComponent {\n  mode = false;\n  dark = false;\n  menus = [\n    {\n      level: 1,\n      title: 'Mail Group',\n      icon: 'mail',\n      open: true,\n      selected: false,\n      disabled: false,\n      children: [\n        {\n          level: 2,\n          title: 'Group 1',\n          icon: 'bars',\n          open: false,\n          selected: false,\n          disabled: false,\n          children: [\n            {\n              level: 3,\n              title: 'Option 1',\n              selected: false,\n              disabled: false\n            },\n            {\n              level: 3,\n              title: 'Option 2',\n              selected: false,\n              disabled: true\n            }\n          ]\n        },\n        {\n          level: 2,\n          title: 'Group 2',\n          icon: 'bars',\n          selected: true,\n          disabled: false\n        },\n        {\n          level: 2,\n          title: 'Group 3',\n          icon: 'bars',\n          selected: false,\n          disabled: false\n        }\n      ]\n    },\n    {\n      level: 1,\n      title: 'Team Group',\n      icon: 'team',\n      open: false,\n      selected: false,\n      disabled: false,\n      children: [\n        {\n          level: 2,\n          title: 'User 1',\n          icon: 'user',\n          selected: false,\n          disabled: false\n        },\n        {\n          level: 2,\n          title: 'User 2',\n          icon: 'user',\n          selected: false,\n          disabled: false\n        }\n      ]\n    }\n  ];\n}\n"
  },
  {
    "path": "components/menu/demo/router.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 配合路由使用\n  en-US: Router\n---\n\n## zh-CN\n\n自动根据路由激活菜单项，需要结合 [RouterLink](https://angular.cn/api/router/RouterLink) 一起使用。\n\n## en-US\n\nAutomatically activate menu items based on routing, should work with [RouterLink](https://angular.dev/api/router/RouterLink).\n"
  },
  {
    "path": "components/menu/demo/router.ts",
    "content": "import { Component } from '@angular/core';\nimport { RouterLink } from '@angular/router';\n\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\n\n@Component({\n  selector: 'nz-demo-menu-router',\n  imports: [RouterLink, NzMenuModule],\n  template: `\n    <ul nz-menu nzMode=\"horizontal\">\n      <li nz-menu-item nzMatchRouter>\n        <a [routerLink]=\"['/', 'components', 'menu', 'en']\">English Menu Document</a>\n      </li>\n      <li nz-menu-item nzMatchRouter>\n        <a [routerLink]=\"['/', 'components', 'menu', 'zh']\">Chinese Menu Document</a>\n      </li>\n    </ul>\n  `\n})\nexport class NzDemoMenuRouterComponent {}\n"
  },
  {
    "path": "components/menu/demo/sider-current.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 只展开当前父级菜单\n  en-US: Open current submenu only\n---\n\n## zh-CN\n\n点击菜单，收起其他展开的所有菜单，保持菜单聚焦简洁。\n\n## en-US\n\nClick the menu and you will see that all the other menus gets collapsed to keep the entire menu compact.\n"
  },
  {
    "path": "components/menu/demo/sider-current.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\n\n@Component({\n  selector: 'nz-demo-menu-sider-current',\n  imports: [NzMenuModule],\n  template: `\n    <ul nz-menu nzMode=\"inline\" style=\"width: 240px;\">\n      <li\n        nz-submenu\n        [(nzOpen)]=\"openMap.sub1\"\n        (nzOpenChange)=\"openHandler('sub1')\"\n        nzTitle=\"Navigation One\"\n        nzIcon=\"mail\"\n      >\n        <ul>\n          <li nz-menu-group nzTitle=\"Item 1\">\n            <ul>\n              <li nz-menu-item>Option 1</li>\n              <li nz-menu-item>Option 2</li>\n            </ul>\n          </li>\n          <li nz-menu-group nzTitle=\"Item 2\">\n            <ul>\n              <li nz-menu-item>Option 3</li>\n              <li nz-menu-item>Option 4</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li\n        nz-submenu\n        [(nzOpen)]=\"openMap.sub2\"\n        (nzOpenChange)=\"openHandler('sub2')\"\n        nzTitle=\"Navigation Two\"\n        nzIcon=\"appstore\"\n      >\n        <ul>\n          <li nz-menu-item>Option 5</li>\n          <li nz-menu-item>Option 6</li>\n          <li nz-submenu nzTitle=\"Submenu\">\n            <ul>\n              <li nz-menu-item>Option 7</li>\n              <li nz-menu-item>Option 8</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li\n        nz-submenu\n        [(nzOpen)]=\"openMap.sub3\"\n        (nzOpenChange)=\"openHandler('sub3')\"\n        nzTitle=\"Navigation Three\"\n        nzIcon=\"setting\"\n      >\n        <ul>\n          <li nz-menu-item>Option 9</li>\n          <li nz-menu-item>Option 10</li>\n          <li nz-menu-item>Option 11</li>\n        </ul>\n      </li>\n    </ul>\n  `\n})\nexport class NzDemoMenuSiderCurrentComponent {\n  openMap: { [name: string]: boolean } = {\n    sub1: true,\n    sub2: false,\n    sub3: false\n  };\n\n  openHandler(value: string): void {\n    for (const key in this.openMap) {\n      if (key !== value) {\n        this.openMap[key] = false;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/menu/demo/switch-mode.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 切换菜单类型\n  en-US: Switch the menu type\n---\n\n## zh-CN\n\n展示动态切换模式。\n\n## en-US\n\nShow the dynamic switching mode (between 'inline' and 'vertical').\n"
  },
  {
    "path": "components/menu/demo/switch-mode.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\n\n@Component({\n  selector: 'nz-demo-menu-switch-mode',\n  imports: [FormsModule, NzDividerModule, NzMenuModule, NzSwitchModule],\n  template: `\n    <nz-switch [(ngModel)]=\"mode\" />\n    Change Mode\n    <nz-divider nzType=\"vertical\" />\n    <nz-switch [(ngModel)]=\"dark\" />\n    Change Theme\n    <br />\n    <br />\n    <ul nz-menu [nzMode]=\"mode ? 'vertical' : 'inline'\" [nzTheme]=\"dark ? 'dark' : 'light'\">\n      <li nz-submenu nzTitle=\"Navigation One\" nzIcon=\"mail\">\n        <ul>\n          <li nz-menu-group nzTitle=\"Item 1\">\n            <ul>\n              <li nz-menu-item>Option 1</li>\n              <li nz-menu-item>Option 2</li>\n            </ul>\n          </li>\n          <li nz-menu-group nzTitle=\"Item 2\">\n            <ul>\n              <li nz-menu-item>Option 3</li>\n              <li nz-menu-item>Option 4</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li nz-submenu nzTitle=\"Navigation Two\" nzIcon=\"appstore\">\n        <ul>\n          <li nz-menu-item>Option 5</li>\n          <li nz-menu-item>Option 6</li>\n          <li nz-submenu nzTitle=\"Submenu\">\n            <ul>\n              <li nz-menu-item>Option 7</li>\n              <li nz-menu-item>Option 8</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li nz-submenu nzTitle=\"Navigation Three\" nzIcon=\"setting\">\n        <ul>\n          <li nz-menu-item>Option 9</li>\n          <li nz-menu-item>Option 10</li>\n          <li nz-menu-item>Option 11</li>\n        </ul>\n      </li>\n    </ul>\n  `,\n  styles: `\n    [nz-menu] {\n      width: 240px;\n    }\n  `\n})\nexport class NzDemoMenuSwitchModeComponent {\n  mode = false;\n  dark = false;\n}\n"
  },
  {
    "path": "components/menu/demo/theme.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 主题\n  en-US: Menu Themes\n---\n\n## zh-CN\n\n内建了两套主题 `light|dark`，默认 `light`。\n\n## en-US\n\nThere are two built-in themes: 'light' and 'dark'. The default value is 'light'.\n"
  },
  {
    "path": "components/menu/demo/theme.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\n\n@Component({\n  selector: 'nz-demo-menu-theme',\n  imports: [FormsModule, NzMenuModule, NzSwitchModule],\n  template: `\n    <nz-switch [(ngModel)]=\"theme\">\n      <span checked>Dark</span>\n      <span unchecked>Light</span>\n    </nz-switch>\n    <br />\n    <br />\n    <ul nz-menu nzMode=\"inline\" style=\"width: 240px;\" [nzTheme]=\"theme ? 'dark' : 'light'\">\n      <li nz-submenu nzOpen nzTitle=\"Navigation One\" nzIcon=\"mail\">\n        <ul>\n          <li nz-menu-group nzTitle=\"Item 1\">\n            <ul>\n              <li nz-menu-item nzSelected>Option 1</li>\n              <li nz-menu-item>Option 2</li>\n            </ul>\n          </li>\n          <li nz-menu-group nzTitle=\"Item 2\">\n            <ul>\n              <li nz-menu-item>Option 3</li>\n              <li nz-menu-item>Option 4</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li nz-submenu nzTitle=\"Navigation Two\" nzIcon=\"appstore\">\n        <ul>\n          <li nz-menu-item>Option 5</li>\n          <li nz-menu-item>Option 6</li>\n          <li nz-submenu nzTitle=\"Submenu\">\n            <ul>\n              <li nz-menu-item>Option 7</li>\n              <li nz-menu-item>Option 8</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li nz-submenu nzTitle=\"Navigation Three\" nzIcon=\"setting\">\n        <ul>\n          <li nz-menu-item>Option 9</li>\n          <li nz-menu-item>Option 10</li>\n          <li nz-menu-item>Option 11</li>\n        </ul>\n      </li>\n    </ul>\n  `\n})\nexport class NzDemoMenuThemeComponent {\n  theme = true;\n}\n"
  },
  {
    "path": "components/menu/demo/vertical.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 垂直菜单\n  en-US: Vertical menu\n---\n\n## zh-CN\n\n子菜单是弹出的形式。\n\n## en-US\n\nSubmenus open as pop-ups.\n"
  },
  {
    "path": "components/menu/demo/vertical.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\n\n@Component({\n  selector: 'nz-demo-menu-vertical',\n  imports: [NzMenuModule],\n  template: `\n    <ul nz-menu nzMode=\"vertical\">\n      <li nz-submenu nzTitle=\"Navigation One\" nzIcon=\"mail\">\n        <ul>\n          <li nz-menu-group nzTitle=\"Item 1\">\n            <ul>\n              <li nz-menu-item>Option 1</li>\n              <li nz-menu-item>Option 2</li>\n            </ul>\n          </li>\n          <li nz-menu-group nzTitle=\"Item 2\">\n            <ul>\n              <li nz-menu-item>Option 3</li>\n              <li nz-menu-item>Option 4</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li nz-submenu (nzOpenChange)=\"change($event)\" nzTitle=\"Navigation Two\" nzIcon=\"appstore\">\n        <ul>\n          <li nz-menu-item>Option 5</li>\n          <li nz-menu-item>Option 6</li>\n          <li nz-submenu nzTitle=\"Submenu\">\n            <ul>\n              <li nz-menu-item>Option 7</li>\n              <li nz-menu-item>Option 8</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li nz-submenu nzTitle=\"Navigation Three\" nzIcon=\"setting\">\n        <ul>\n          <li nz-menu-item>Option 9</li>\n          <li nz-menu-item>Option 10</li>\n          <li nz-menu-item>Option 11</li>\n        </ul>\n      </li>\n    </ul>\n  `,\n  styles: `\n    [nz-menu] {\n      width: 240px;\n    }\n  `\n})\nexport class NzDemoMenuVerticalComponent {\n  change(value: boolean): void {\n    console.log(value);\n  }\n}\n"
  },
  {
    "path": "components/menu/doc/index.en-US.md",
    "content": "---\ncategory: Components\ncols: 1\ntype: Navigation\ntitle: Menu\ncover: 'https://gw.alipayobjects.com/zos/alicdn/3XZcjGpvK/Menu.svg'\ndescription: A versatile menu for navigation.\n---\n\n## When To Use\n\nNavigation menu is important for a website, it helps users jump from one site section to another quickly.\nMostly, it includes top navigation and side navigation. Top navigation provides all the category and functions of the website.\nSide navigation provides the multi-level structure of the website.\n\nMore layouts with navigation: [layout](/components/layout/en).\n\n## API\n\n```html\n<ul nz-menu>\n  <li nz-menu-item>Menu 1</li>\n  <li nz-menu-item>Menu 2</li>\n  <li nz-submenu nzTitle=\"SubMenu Title\">\n    <ul>\n      <li nz-menu-item>SubMenu Item 1</li>\n      <li nz-menu-item>SubMenu Item 2</li>\n      <li nz-menu-item>SubMenu Item 3</li>\n    </ul>\n  </li>\n</ul>\n```\n\n### [nz-menu]\n\n| Param                 | Description                                                                   | Type                                     | Default value |\n| --------------------- | ----------------------------------------------------------------------------- | ---------------------------------------- | ------------- |\n| `[nzInlineCollapsed]` | specifies the collapsed status when menu is `inline` mode                     | `boolean`                                | -             |\n| `[nzInlineIndent]`    | indent px of `inline` menu item on each level                                 | `number`                                 | `24`          |\n| `[nzMode]`            | type of the menu; `vertical`、 `horizontal`, and `inline` modes are supported | `'vertical' \\| 'horizontal' \\| 'inline'` | `'vertical'`  |\n| `[nzSelectable]`      | allow selecting menu items                                                    | `boolean`                                | `true`        |\n| `[nzTheme]`           | color theme of the menu                                                       | `'light' \\| 'dark'`                      | `'light'`     |\n| `(nzClick)`           | the Output when click `nz-menu-item` inside nz-menu                           | `EventEmitter<NzMenuItemComponent>`      |               |\n\n### [nz-menu-item]\n\n| Param                  | Description                                                                                                                                                  | Type      | Default value |\n| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------- | ------------- |\n| `[nzDisabled]`         | whether menu item is disabled or not                                                                                                                         | `boolean` | `false`       |\n| `[nzSelected]`         | whether menu item is selected or not                                                                                                                         | `boolean` | `false`       |\n| `[nzMatchRouter]`      | whether auto set `nzSelected` according to [routerLink](https://www.angular.io/api/router/RouterLink)                                                        | `boolean` | `false`       |\n| `[nzMatchRouterExact]` | only match when the url matches the link exactly, same as [routerLinkActiveOptions](https://angular.dev/api/router/RouterLinkActive#routerLinkActiveOptions) | `boolean` | `false`       |\n| `[nzDanger]`           | display the danger style                                                                                                                                     | `boolean` | `false`       |\n\n### [nz-submenu]\n\nYou can set the title of `[nz-submenu]` in the following ways.\n\n```html\n<li nz-submenu nzTitle=\"SubTitle\" nzIcon=\"appstore\"></li>\n\n<li nz-submenu>\n  <span title>\n    <nz-icon nzType=\"appstore\" />\n    <span>SubTitle</span>\n  </span>\n</li>\n\n<li nz-submenu [nzTitle]=\"titleTpl\"></li>\n<ng-template #titleTpl>\n  <nz-icon nzType=\"appstore\" />\n  <span>SubTitle</span>\n</ng-template>\n```\n\n| Param                      | Description                                     | Type                                                                                        | Default value  |\n| -------------------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------- | -------------- |\n| `[nzPlacement]`            | placement of pop menu                           | `'bottomLeft' \\| 'bottomCenter' \\| 'bottomRight' \\| 'topLeft' \\| 'topCenter' \\| 'topRight'` | `'bottomLeft'` |\n| `[nzOpen]`                 | whether sub menu is open or not, double binding | `boolean`                                                                                   | `false`        |\n| `[nzDisabled]`             | whether sub menu is disabled or not             | `boolean`                                                                                   | `false`        |\n| `[nzTitle]`                | set submenu title                               | `string \\| TemplateRef<void>`                                                               | -              |\n| `[nzIcon]`                 | `icon` type in title                            | `string`                                                                                    | -              |\n| `[nzMenuClassName]`        | Custom the submenu container's class name       | `string`                                                                                    | -              |\n| `[nzTriggerSubMenuAction]` | Which action can trigger submenu open/close     | `'hover' \\| 'click'`                                                                        | `'hover'`      |\n| `(nzOpenChange)`           | nzOpen callback                                 | `EventEmitter<boolean>`                                                                     | -              |\n\n### [nz-menu-group]\n\nYou can set the title of `[nz-menu-group]` in the following ways.\n\n```html\n<li nz-menu-group nzTitle=\"SubTitle\" nzIcon=\"appstore\"></li>\n\n<li nz-menu-group>\n  < title>\n    <nz-icon nzType=\"appstore\" />\n    <span>SubTitle</span>\n  </span>\n</li>\n\n<li nz-menu-group [nzTitle]=\"titleTpl\"></li>\n<ng-template #titleTpl>\n  <nz-icon nzType=\"appstore\" />\n  <span>SubTitle</span>\n</ng-template>\n```\n\n| Param       | Description          | Type                          | Default value |\n| ----------- | -------------------- | ----------------------------- | ------------- |\n| `[nzTitle]` | set menu group title | `string \\| TemplateRef<void>` | -             |\n\n### [nz-menu-divider]\n\nDivider line in between menu items, only used in vertical popup Menu or Dropdown Menu.\n"
  },
  {
    "path": "components/menu/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ncols: 1\ntype: 导航\ntitle: Menu\nsubtitle: 导航菜单\ncover: 'https://gw.alipayobjects.com/zos/alicdn/3XZcjGpvK/Menu.svg'\ndescription: 为页面和功能提供导航的菜单列表。\n---\n\n## 何时使用\n\n导航菜单是一个网站的灵魂，用户依赖导航在各个页面中进行跳转。一般分为顶部导航和侧边导航，顶部导航提供全局性的类目和功能，侧边导航提供多级结构来收纳和排列网站架构。\n\n更多布局和导航的使用可以参考：[通用布局](/components/layout/zh)。\n\n## API\n\n```html\n<ul nz-menu>\n  <li nz-menu-item>Menu 1</li>\n  <li nz-menu-item>Menu 2</li>\n  <li nz-submenu nzTitle=\"SubMenu Title\">\n    <ul>\n      <li nz-menu-item>SubMenu Item 1</li>\n      <li nz-menu-item>SubMenu Item 2</li>\n      <li nz-menu-item>SubMenu Item 3</li>\n    </ul>\n  </li>\n</ul>\n```\n\n### [nz-menu]\n\n| 参数                  | 说明                                         | 类型                                     | 默认值       |\n| --------------------- | -------------------------------------------- | ---------------------------------------- | ------------ |\n| `[nzInlineCollapsed]` | `inline` 时菜单是否收起状态                  | `boolean`                                | -            |\n| `[nzInlineIndent]`    | `inline` 模式的菜单缩进宽度                  | `number`                                 | `24`         |\n| `[nzMode]`            | 菜单类型，现在支持垂直、水平、和内嵌模式三种 | `'vertical' \\| 'horizontal' \\| 'inline'` | `'vertical'` |\n| `[nzSelectable]`      | 是否允许选中                                 | `boolean`                                | `true`       |\n| `[nzTheme]`           | 主题颜色                                     | `'light' \\| 'dark'`                      | `'light'`    |\n| `(nzClick)`           | 点击 `nz-menu-item` 输出属性                 | `EventEmitter<NzMenuItemComponent>`      |              |\n\n### [nz-menu-item]\n\n| 参数                   | 说明                                                                                                                         | 类型      | 默认值  |\n| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------- | --------- | ------- |\n| `[nzDisabled]`         | 是否禁用                                                                                                                     | `boolean` | `false` |\n| `[nzSelected]`         | 是否被选中                                                                                                                   | `boolean` | `false` |\n| `[nzMatchRouter]`      | 是否根据 [routerLink](https://www.angular.cn/api/router/RouterLink) 自动设定 `nzSelected`                                    | `boolean` | `false` |\n| `[nzMatchRouterExact]` | 是否路由完整精确匹配, 详见 [routerLinkActiveOptions](https://angular.cn/api/router/RouterLinkActive#routerLinkActiveOptions) | `boolean` | `false` |\n| `[nzDanger]`           | 展示错误状态样式                                                                                                             | `boolean` | `false` |\n\n### [nz-submenu]\n\n你可以使用以下三种方式来定义 `nz-submenu` 的标题\n\n```html\n<li nz-submenu nzTitle=\"SubTitle\" nzIcon=\"appstore\"></li>\n\n<li nz-submenu>\n  <span title>\n    <nz-icon nzType=\"appstore\" />\n    <span>SubTitle</span>\n  </span>\n</li>\n\n<li nz-submenu [nzTitle]=\"titleTpl\"></li>\n<ng-template #titleTpl>\n  <nz-icon nzType=\"appstore\" />\n  <span>SubTitle</span>\n</ng-template>\n```\n\n| 参数                       | 说明                        | 类型                                                                                        | 默认值         |\n| -------------------------- | --------------------------- | ------------------------------------------------------------------------------------------- | -------------- |\n| `[nzPlacement]`            | 菜单弹出位置                | `'bottomLeft' \\| 'bottomCenter' \\| 'bottomRight' \\| 'topLeft' \\| 'topCenter' \\| 'topRight'` | `'bottomLeft'` |\n| `[nzOpen]`                 | 是否展开，可双向绑定        | `boolean`                                                                                   | `false`        |\n| `[nzDisabled]`             | 是否禁用                    | `boolean`                                                                                   | `false`        |\n| `[nzTitle]`                | 标题内容                    | `string \\| TemplateRef<void>`                                                               | -              |\n| `[nzIcon]`                 | 标题中 `icon` 类型          | `string`                                                                                    | -              |\n| `[nzMenuClassName]`        | 自定义子菜单容器类名        | `string`                                                                                    | -              |\n| `[nzTriggerSubMenuAction]` | SubMenu 展开/关闭的触发行为 | `'hover' \\| 'click'`                                                                        | `'hover'`      |\n| `(nzOpenChange)`           | 展开回调                    | `EventEmitter<boolean>`                                                                     | -              |\n\n### [nz-menu-group]\n\n你可以使用以下三种方式来定义 `nz-menu-group` 的标题\n\n```html\n<li nz-menu-group nzTitle=\"SubTitle\" nzIcon=\"appstore\"></li>\n\n<li nz-menu-group>\n  < title>\n  <nz-icon nzType=\"appstore\" />\n  <span>SubTitle</span>\n  </span>\n</li>\n\n<li nz-menu-group [nzTitle]=\"titleTpl\"></li>\n<ng-template #titleTpl>\n  <nz-icon nzType=\"appstore\" />\n  <span>SubTitle</span>\n</ng-template>\n```\n\n| 参数        | 说明     | 类型                          | 默认值 |\n| ----------- | -------- | ----------------------------- | ------ |\n| `[nzTitle]` | 标题内容 | `string \\| TemplateRef<void>` | -      |\n\n### [nz-menu-divider]\n\n菜单项分割线，只用在弹出菜单内。\n"
  },
  {
    "path": "components/menu/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/menu/menu-divider.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive } from '@angular/core';\n\n@Directive({\n  selector: '[nz-menu-divider]',\n  exportAs: 'nzMenuDivider',\n  host: {\n    class: 'ant-dropdown-menu-item-divider'\n  }\n})\nexport class NzMenuDividerDirective {}\n"
  },
  {
    "path": "components/menu/menu-group.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  AfterViewInit,\n  ChangeDetectionStrategy,\n  Component,\n  ElementRef,\n  inject,\n  Input,\n  Renderer2,\n  TemplateRef,\n  ViewChild,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\n\nimport { NzIsMenuInsideDropdownToken } from './menu.token';\n\nfunction MenuGroupFactory(): boolean {\n  const isMenuInsideDropdownToken = inject(NzIsMenuInsideDropdownToken, { optional: true, skipSelf: true });\n  return isMenuInsideDropdownToken ?? false;\n}\n\n@Component({\n  selector: '[nz-menu-group]',\n  exportAs: 'nzMenuGroup',\n  providers: [\n    /** check if menu inside dropdown-menu component **/\n    {\n      provide: NzIsMenuInsideDropdownToken,\n      useFactory: MenuGroupFactory\n    }\n  ],\n  template: `\n    <div\n      [class.ant-menu-item-group-title]=\"!isMenuInsideDropdown\"\n      [class.ant-dropdown-menu-item-group-title]=\"isMenuInsideDropdown\"\n      #titleElement\n    >\n      <ng-container *nzStringTemplateOutlet=\"nzTitle\">{{ nzTitle }}</ng-container>\n      @if (!nzTitle) {\n        <ng-content select=\"[title]\" />\n      }\n    </div>\n    <ng-content />\n  `,\n  imports: [NzOutletModule],\n  host: {\n    '[class.ant-menu-item-group]': '!isMenuInsideDropdown',\n    '[class.ant-dropdown-menu-item-group]': 'isMenuInsideDropdown'\n  },\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None\n})\nexport class NzMenuGroupComponent implements AfterViewInit {\n  private readonly renderer = inject(Renderer2);\n  protected readonly isMenuInsideDropdown = inject(NzIsMenuInsideDropdownToken);\n\n  @Input() nzTitle?: string | TemplateRef<void>;\n  @ViewChild('titleElement') titleElement?: ElementRef;\n\n  ngAfterViewInit(): void {\n    const ulElement = this.titleElement!.nativeElement.nextElementSibling;\n    if (ulElement) {\n      /** add classname to ul **/\n      const className = this.isMenuInsideDropdown ? 'ant-dropdown-menu-item-group-list' : 'ant-menu-item-group-list';\n      this.renderer.addClass(ulElement, className);\n    }\n  }\n}\n"
  },
  {
    "path": "components/menu/menu-item.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  AfterContentInit,\n  ChangeDetectionStrategy,\n  Component,\n  ContentChildren,\n  Input,\n  OnChanges,\n  OnInit,\n  QueryList,\n  SimpleChanges,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject,\n  DestroyRef,\n  ChangeDetectorRef\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { NavigationEnd, Router, RouterLink } from '@angular/router';\nimport { Subject, combineLatest } from 'rxjs';\nimport { filter } from 'rxjs/operators';\n\nimport { numberAttributeWithZeroFallback } from 'ng-zorro-antd/core/util';\n\nimport { MenuService } from './menu.service';\nimport { NzIsMenuInsideDropdownToken } from './menu.token';\nimport { NzSubmenuService } from './submenu.service';\n\n@Component({\n  selector: '[nz-menu-item]',\n  exportAs: 'nzMenuItem',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <span class=\"ant-menu-title-content\">\n      <ng-content />\n    </span>\n  `,\n  host: {\n    '[class.ant-dropdown-menu-item]': `isMenuInsideDropdown`,\n    '[class.ant-dropdown-menu-item-selected]': `isMenuInsideDropdown && nzSelected`,\n    '[class.ant-dropdown-menu-item-danger]': `isMenuInsideDropdown && nzDanger`,\n    '[class.ant-dropdown-menu-item-disabled]': `isMenuInsideDropdown && nzDisabled`,\n    '[class.ant-menu-item]': `!isMenuInsideDropdown`,\n    '[class.ant-menu-item-selected]': `!isMenuInsideDropdown && nzSelected`,\n    '[class.ant-menu-item-danger]': `!isMenuInsideDropdown && nzDanger`,\n    '[class.ant-menu-item-disabled]': `!isMenuInsideDropdown && nzDisabled`,\n    '[style.padding-inline-start.px]': 'nzPaddingLeft || inlinePaddingLeft',\n    '(click)': 'clickMenuItem($event)'\n  }\n})\nexport class NzMenuItemComponent implements OnInit, OnChanges, AfterContentInit {\n  private readonly nzMenuService = inject(MenuService);\n  private readonly destroyRef = inject(DestroyRef);\n  private readonly cdr = inject(ChangeDetectorRef);\n  private readonly nzSubmenuService = inject(NzSubmenuService, { optional: true });\n  private readonly routerLink = inject(RouterLink, { optional: true });\n  private readonly router = inject(Router, { optional: true });\n  protected readonly isMenuInsideDropdown = inject(NzIsMenuInsideDropdownToken);\n\n  level = this.nzSubmenuService ? this.nzSubmenuService.level + 1 : 1;\n  selected$ = new Subject<boolean>();\n  inlinePaddingLeft: number | null = null;\n  @Input({ transform: numberAttributeWithZeroFallback }) nzPaddingLeft?: number;\n  @Input({ transform: booleanAttribute }) nzDisabled = false;\n  @Input({ transform: booleanAttribute }) nzSelected = false;\n  @Input({ transform: booleanAttribute }) nzDanger = false;\n  @Input({ transform: booleanAttribute }) nzMatchRouterExact = false;\n  @Input({ transform: booleanAttribute }) nzMatchRouter = false;\n  @ContentChildren(RouterLink, { descendants: true }) listOfRouterLink!: QueryList<RouterLink>;\n\n  /** clear all item selected status except this */\n  clickMenuItem(e: MouseEvent): void {\n    if (this.nzDisabled) {\n      e.preventDefault();\n      e.stopPropagation();\n      return;\n    }\n    this.nzMenuService.onDescendantMenuItemClick(this);\n    if (this.nzSubmenuService) {\n      /** menu item inside the submenu **/\n      this.nzSubmenuService.onChildMenuItemClick(this);\n    } else {\n      /** menu item inside the root menu **/\n      this.nzMenuService.onChildMenuItemClick(this);\n    }\n  }\n\n  setSelectedState(value: boolean): void {\n    this.nzSelected = value;\n    this.selected$.next(value);\n  }\n\n  private updateRouterActive(): void {\n    if (!this.listOfRouterLink || !this.router || !this.router.navigated || !this.nzMatchRouter) {\n      return;\n    }\n    Promise.resolve().then(() => {\n      const hasActiveLinks = this.hasActiveLinks();\n      if (this.nzSelected !== hasActiveLinks) {\n        this.nzSelected = hasActiveLinks;\n        this.setSelectedState(this.nzSelected);\n        this.cdr.markForCheck();\n      }\n    });\n  }\n\n  private hasActiveLinks(): boolean {\n    const isActiveCheckFn = this.isLinkActive(this.router!);\n    return (this.routerLink && isActiveCheckFn(this.routerLink)) || this.listOfRouterLink.some(isActiveCheckFn);\n  }\n\n  private isLinkActive(router: Router): (link: RouterLink) => boolean {\n    return (link: RouterLink) =>\n      router.isActive(link.urlTree || '', {\n        paths: this.nzMatchRouterExact ? 'exact' : 'subset',\n        queryParams: this.nzMatchRouterExact ? 'exact' : 'subset',\n        fragment: 'ignored',\n        matrixParams: 'ignored'\n      });\n  }\n\n  constructor() {\n    this.router?.events\n      .pipe(\n        takeUntilDestroyed(),\n        filter(e => e instanceof NavigationEnd)\n      )\n      .subscribe(() => this.updateRouterActive());\n  }\n\n  ngOnInit(): void {\n    /** store origin padding in padding */\n    combineLatest([this.nzMenuService.mode$, this.nzMenuService.inlineIndent$])\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(([mode, inlineIndent]) => {\n        this.inlinePaddingLeft = mode === 'inline' ? this.level * inlineIndent : null;\n      });\n  }\n\n  ngAfterContentInit(): void {\n    this.listOfRouterLink.changes.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => this.updateRouterActive());\n    this.updateRouterActive();\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzSelected } = changes;\n    if (nzSelected) {\n      this.setSelectedState(this.nzSelected);\n    }\n  }\n}\n"
  },
  {
    "path": "components/menu/menu.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport {\n  AfterContentInit,\n  ChangeDetectorRef,\n  ContentChildren,\n  Directive,\n  EventEmitter,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  QueryList,\n  SimpleChanges,\n  booleanAttribute,\n  inject,\n  DestroyRef\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { BehaviorSubject, combineLatest } from 'rxjs';\n\nimport { NzMenuItemComponent } from './menu-item.component';\nimport { MenuService } from './menu.service';\nimport { NzIsMenuInsideDropdownToken, NzMenuServiceLocalToken } from './menu.token';\nimport { NzMenuModeType, NzMenuThemeType } from './menu.types';\nimport { NzSubMenuComponent } from './submenu.component';\n\nfunction MenuServiceFactory(): MenuService {\n  const serviceInsideDropdown = inject(MenuService, { skipSelf: true, optional: true });\n  const serviceOutsideDropdown = inject(NzMenuServiceLocalToken);\n  return serviceInsideDropdown ?? serviceOutsideDropdown;\n}\n\nfunction MenuDropdownTokenFactory(): boolean {\n  const isMenuInsideDropdownToken = inject(NzIsMenuInsideDropdownToken, { skipSelf: true, optional: true });\n  return isMenuInsideDropdownToken ?? false;\n}\n\n@Directive({\n  selector: '[nz-menu]',\n  exportAs: 'nzMenu',\n  providers: [\n    {\n      provide: NzMenuServiceLocalToken,\n      useClass: MenuService\n    },\n    /** use the top level service **/\n    {\n      provide: MenuService,\n      useFactory: MenuServiceFactory\n    },\n    /** check if menu inside dropdown-menu component **/\n    {\n      provide: NzIsMenuInsideDropdownToken,\n      useFactory: MenuDropdownTokenFactory\n    }\n  ],\n  host: {\n    '[class.ant-dropdown-menu]': `isMenuInsideDropdown`,\n    '[class.ant-dropdown-menu-root]': `isMenuInsideDropdown`,\n    '[class.ant-dropdown-menu-light]': `isMenuInsideDropdown && nzTheme === 'light'`,\n    '[class.ant-dropdown-menu-dark]': `isMenuInsideDropdown && nzTheme === 'dark'`,\n    '[class.ant-dropdown-menu-vertical]': `isMenuInsideDropdown && actualMode === 'vertical'`,\n    '[class.ant-dropdown-menu-horizontal]': `isMenuInsideDropdown && actualMode === 'horizontal'`,\n    '[class.ant-dropdown-menu-inline]': `isMenuInsideDropdown && actualMode === 'inline'`,\n    '[class.ant-dropdown-menu-inline-collapsed]': `isMenuInsideDropdown && nzInlineCollapsed`,\n    '[class.ant-menu]': `!isMenuInsideDropdown`,\n    '[class.ant-menu-root]': `!isMenuInsideDropdown`,\n    '[class.ant-menu-light]': `!isMenuInsideDropdown && nzTheme === 'light'`,\n    '[class.ant-menu-dark]': `!isMenuInsideDropdown && nzTheme === 'dark'`,\n    '[class.ant-menu-vertical]': `!isMenuInsideDropdown && actualMode === 'vertical'`,\n    '[class.ant-menu-horizontal]': `!isMenuInsideDropdown && actualMode === 'horizontal'`,\n    '[class.ant-menu-inline]': `!isMenuInsideDropdown && actualMode === 'inline'`,\n    '[class.ant-menu-inline-collapsed]': `!isMenuInsideDropdown && nzInlineCollapsed`,\n    '[class.ant-menu-rtl]': `dir() === 'rtl'`\n  }\n})\nexport class NzMenuDirective implements AfterContentInit, OnInit, OnChanges {\n  private readonly nzMenuService = inject(MenuService);\n  private readonly destroyRef = inject(DestroyRef);\n  private readonly cdr = inject(ChangeDetectorRef);\n  protected readonly dir = inject(Directionality).valueSignal;\n  protected readonly isMenuInsideDropdown = inject(NzIsMenuInsideDropdownToken);\n\n  @ContentChildren(NzMenuItemComponent, { descendants: true })\n  listOfNzMenuItemDirective!: QueryList<NzMenuItemComponent>;\n  @ContentChildren(NzSubMenuComponent, { descendants: true }) listOfNzSubMenuComponent!: QueryList<NzSubMenuComponent>;\n  @Input() nzInlineIndent = 24;\n  @Input() nzTheme: NzMenuThemeType = 'light';\n  @Input() nzMode: NzMenuModeType = 'vertical';\n  @Input({ transform: booleanAttribute }) nzInlineCollapsed = false;\n  @Input({ transform: booleanAttribute }) nzSelectable = !this.isMenuInsideDropdown;\n  @Output() readonly nzClick = new EventEmitter<NzMenuItemComponent>();\n\n  actualMode: NzMenuModeType = 'vertical';\n  private inlineCollapsed$ = new BehaviorSubject<boolean>(this.nzInlineCollapsed);\n  private mode$ = new BehaviorSubject<NzMenuModeType>(this.nzMode);\n  private listOfOpenedNzSubMenuComponent: NzSubMenuComponent[] = [];\n\n  setInlineCollapsed(inlineCollapsed: boolean): void {\n    this.nzInlineCollapsed = inlineCollapsed;\n    this.inlineCollapsed$.next(inlineCollapsed);\n  }\n\n  updateInlineCollapse(): void {\n    if (this.listOfNzMenuItemDirective) {\n      if (this.nzInlineCollapsed) {\n        this.listOfOpenedNzSubMenuComponent = this.listOfNzSubMenuComponent.filter(submenu => submenu.nzOpen);\n        this.listOfNzSubMenuComponent.forEach(submenu => submenu.setOpenStateWithoutDebounce(false));\n      } else {\n        this.listOfOpenedNzSubMenuComponent.forEach(submenu => submenu.setOpenStateWithoutDebounce(true));\n        this.listOfOpenedNzSubMenuComponent = [];\n      }\n    }\n  }\n\n  ngOnInit(): void {\n    combineLatest([this.inlineCollapsed$, this.mode$])\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(([inlineCollapsed, mode]) => {\n        this.actualMode = inlineCollapsed ? 'vertical' : mode;\n        this.nzMenuService.setMode(this.actualMode);\n        this.cdr.markForCheck();\n      });\n    this.nzMenuService.descendantMenuItemClick$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(menu => {\n      this.nzClick.emit(menu);\n      if (this.nzSelectable && !menu.nzMatchRouter) {\n        this.listOfNzMenuItemDirective.forEach(item => item.setSelectedState(item === menu));\n      }\n    });\n  }\n\n  ngAfterContentInit(): void {\n    this.inlineCollapsed$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      this.updateInlineCollapse();\n      this.cdr.markForCheck();\n    });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzInlineCollapsed, nzInlineIndent, nzTheme, nzMode } = changes;\n    if (nzInlineCollapsed) {\n      this.inlineCollapsed$.next(this.nzInlineCollapsed);\n    }\n    if (nzInlineIndent) {\n      this.nzMenuService.setInlineIndent(this.nzInlineIndent);\n    }\n    if (nzTheme) {\n      this.nzMenuService.setTheme(this.nzTheme);\n    }\n    if (nzMode) {\n      this.mode$.next(this.nzMode);\n      if (!nzMode.isFirstChange() && this.listOfNzSubMenuComponent) {\n        this.listOfNzSubMenuComponent.forEach(submenu => submenu.setOpenStateWithoutDebounce(false));\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/menu/menu.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzMenuDividerDirective } from './menu-divider.directive';\nimport { NzMenuGroupComponent } from './menu-group.component';\nimport { NzMenuItemComponent } from './menu-item.component';\nimport { NzMenuDirective } from './menu.directive';\nimport { NzSubmenuInlineChildComponent } from './submenu-inline-child.component';\nimport { NzSubmenuNoneInlineChildComponent } from './submenu-non-inline-child.component';\nimport { NzSubMenuTitleComponent } from './submenu-title.component';\nimport { NzSubMenuComponent } from './submenu.component';\n\n@NgModule({\n  imports: [\n    NzMenuDirective,\n    NzMenuItemComponent,\n    NzSubMenuComponent,\n    NzMenuDividerDirective,\n    NzMenuGroupComponent,\n    NzSubMenuTitleComponent,\n    NzSubmenuInlineChildComponent,\n    NzSubmenuNoneInlineChildComponent\n  ],\n  exports: [NzMenuDirective, NzMenuItemComponent, NzSubMenuComponent, NzMenuDividerDirective, NzMenuGroupComponent]\n})\nexport class NzMenuModule {}\n"
  },
  {
    "path": "components/menu/menu.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Injectable } from '@angular/core';\nimport { BehaviorSubject, Subject } from 'rxjs';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzMenuModeType, NzMenuThemeType } from './menu.types';\n\n@Injectable()\nexport class MenuService {\n  /** all descendant menu click **/\n  descendantMenuItemClick$ = new Subject<NzSafeAny>();\n  /** child menu item click **/\n  childMenuItemClick$ = new Subject<NzSafeAny>();\n  theme$ = new BehaviorSubject<NzMenuThemeType>('light');\n  mode$ = new BehaviorSubject<NzMenuModeType>('vertical');\n  inlineIndent$ = new BehaviorSubject<number>(24);\n  isChildSubMenuOpen$ = new BehaviorSubject<boolean>(false);\n\n  onDescendantMenuItemClick(menu: NzSafeAny): void {\n    this.descendantMenuItemClick$.next(menu);\n  }\n\n  onChildMenuItemClick(menu: NzSafeAny): void {\n    this.childMenuItemClick$.next(menu);\n  }\n\n  setMode(mode: NzMenuModeType): void {\n    this.mode$.next(mode);\n  }\n\n  setTheme(theme: NzMenuThemeType): void {\n    this.theme$.next(theme);\n  }\n\n  setInlineIndent(indent: number): void {\n    this.inlineIndent$.next(indent);\n  }\n}\n"
  },
  {
    "path": "components/menu/menu.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { ConnectedOverlayPositionChange, OverlayContainer } from '@angular/cdk/overlay';\nimport {\n  Component,\n  DebugElement,\n  ElementRef,\n  provideZoneChangeDetection,\n  QueryList,\n  ViewChild,\n  ViewChildren\n} from '@angular/core';\nimport { ComponentFixture, fakeAsync, inject, TestBed, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { provideNzNoAnimation } from 'ng-zorro-antd/core/animation';\nimport { dispatchFakeEvent, provideMockDirectionality } from 'ng-zorro-antd/core/testing';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\nimport { NzSubmenuTrigger } from 'ng-zorro-antd/menu/menu.types';\n\nimport { NzMenuItemComponent } from './menu-item.component';\nimport { NzMenuDirective } from './menu.directive';\nimport { NzMenuModule } from './menu.module';\nimport { NzSubMenuComponent } from './submenu.component';\n\ndescribe('menu', () => {\n  let overlayContainer: OverlayContainer;\n  let overlayContainerElement: HTMLElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [\n        provideNzIconsTesting(),\n        provideNzNoAnimation(),\n        provideZoneChangeDetection(),\n        provideMockDirectionality()\n      ]\n    });\n  });\n\n  beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n    overlayContainer = oc;\n    overlayContainerElement = oc.getContainerElement();\n  }));\n\n  afterEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n    oc.ngOnDestroy();\n    overlayContainer.ngOnDestroy();\n  }));\n\n  describe('basic', () => {\n    describe('horizontal', () => {\n      let fixture: ComponentFixture<NzTestBasicMenuHorizontalComponent>;\n      let items: DebugElement[];\n      let submenu: DebugElement;\n      let menu: DebugElement;\n      beforeEach(() => {\n        fixture = TestBed.createComponent(NzTestBasicMenuHorizontalComponent);\n        items = fixture.debugElement.queryAll(By.directive(NzMenuItemComponent));\n        submenu = fixture.debugElement.query(By.directive(NzSubMenuComponent));\n        menu = fixture.debugElement.query(By.directive(NzMenuDirective));\n      });\n\n      it('should className correct', () => {\n        fixture.detectChanges();\n        expect(items.every(item => item.nativeElement.classList.contains('ant-menu-item'))).toBe(true);\n        expect(items[1].nativeElement.classList.contains('ant-menu-item-disabled')).toBe(true);\n        expect(submenu.nativeElement.classList.contains('ant-menu-submenu-horizontal')).toBe(true);\n        expect(submenu.nativeElement.classList.contains('ant-menu-submenu')).toBe(true);\n        expect(menu.nativeElement.className).toBe('ant-menu ant-menu-root ant-menu-light ant-menu-horizontal');\n      });\n\n      it('should menu item select', () => {\n        fixture.detectChanges();\n        items[0].nativeElement.click();\n        fixture.detectChanges();\n        expect(items[0].nativeElement.classList.contains('ant-menu-item-selected')).toBe(true);\n      });\n\n      it('should menu disabled work', () => {\n        fixture.detectChanges();\n        items[1].nativeElement.click();\n        fixture.detectChanges();\n        expect(items[0].nativeElement.classList.contains('ant-menu-item-selected')).toBe(false);\n      });\n\n      it('should menu danger work', () => {\n        fixture.detectChanges();\n        expect(items[3].nativeElement.classList.contains('ant-menu-item-danger')).toBe(true);\n      });\n    });\n\n    describe('inline', () => {\n      let fixture: ComponentFixture<NzTestBasicMenuInlineComponent>;\n      let items: DebugElement[];\n      let submenus: DebugElement[];\n      let menu: DebugElement;\n      beforeEach(() => {\n        fixture = TestBed.createComponent(NzTestBasicMenuInlineComponent);\n        items = fixture.debugElement.queryAll(By.directive(NzMenuItemComponent));\n        menu = fixture.debugElement.query(By.directive(NzMenuDirective));\n        submenus = fixture.debugElement.queryAll(By.directive(NzSubMenuComponent));\n      });\n\n      it('should className correct', () => {\n        fixture.detectChanges();\n        expect(submenus.every(subitem => subitem.nativeElement.classList.contains('ant-menu-submenu'))).toBe(true);\n        expect(submenus.every(subitem => subitem.nativeElement.classList.contains('ant-menu-submenu-inline'))).toBe(\n          true\n        );\n        expect(menu.nativeElement.className).toBe('ant-menu ant-menu-root ant-menu-light ant-menu-inline');\n      });\n\n      it('should padding left work', () => {\n        fixture.detectChanges();\n        const firstLevelItems = items;\n        const secondLevelItems = firstLevelItems.splice(6, 2);\n        expect(firstLevelItems.every(item => item.nativeElement.style.paddingLeft === '48px')).toBe(true);\n        expect(secondLevelItems.every(item => item.nativeElement.style.paddingLeft === '72px')).toBe(true);\n      });\n\n      it('should click expand', fakeAsync(() => {\n        fixture.detectChanges();\n        const ul = submenus[0].nativeElement.querySelector('.ant-menu');\n        const title = submenus[0].nativeElement.querySelector('.ant-menu-submenu-title');\n        expect(ul.style.height).toBe('0px');\n        title.click();\n        fixture.detectChanges();\n        tick(500);\n        expect(ul.style.height).not.toBe('0px');\n        expect(submenus[0].nativeElement.classList.contains('ant-menu-submenu-open')).toBe(true);\n        title.click();\n        fixture.detectChanges();\n        tick(500);\n        expect(ul.style.height).toBe('0px');\n        expect(submenus[0].nativeElement.classList.contains('ant-menu-submenu-open')).toBe(false);\n      }));\n    });\n\n    describe('inline-collapsed', () => {\n      let fixture: ComponentFixture<NzTestMenuInlineCollapsedComponent>;\n      let testComponent: NzTestMenuInlineCollapsedComponent;\n      let submenus: DebugElement[];\n      let menu: DebugElement;\n      beforeEach(() => {\n        fixture = TestBed.createComponent(NzTestMenuInlineCollapsedComponent);\n        testComponent = fixture.debugElement.componentInstance;\n        submenus = fixture.debugElement.queryAll(By.directive(NzSubMenuComponent));\n        menu = fixture.debugElement.query(By.directive(NzMenuDirective));\n      });\n\n      it('should className correct', () => {\n        fixture.detectChanges();\n        expect(menu.nativeElement.className).toBe('ant-menu ant-menu-root ant-menu-dark ant-menu-inline');\n        testComponent.isCollapsed = true;\n        fixture.detectChanges();\n        expect(menu.nativeElement.className).toBe(\n          'ant-menu ant-menu-root ant-menu-dark ant-menu-vertical ant-menu-inline-collapsed'\n        );\n        testComponent.isCollapsed = false;\n        fixture.detectChanges();\n        expect(menu.nativeElement.className).toBe('ant-menu ant-menu-root ant-menu-dark ant-menu-inline');\n      });\n\n      it('should keep open after change mode', () => {\n        fixture.detectChanges();\n        let ul = submenus[0].nativeElement.querySelector('.ant-menu');\n        const title = submenus[0].nativeElement.querySelector('.ant-menu-submenu-title');\n        expect(ul.style.height).toBe('0px');\n        testComponent.isCollapsed = true;\n        fixture.detectChanges();\n        testComponent.isCollapsed = false;\n        fixture.detectChanges();\n        ul = submenus[0].nativeElement.querySelector('.ant-menu');\n        expect(ul.style.height).toBe('0px');\n        title.click();\n        fixture.detectChanges();\n        expect(ul.style.height).not.toBe('0px');\n        testComponent.isCollapsed = true;\n        fixture.detectChanges();\n        testComponent.isCollapsed = false;\n        fixture.detectChanges();\n        expect(ul.style.height).not.toBe('0px');\n      });\n    });\n\n    describe('slider-current', () => {\n      let fixture: ComponentFixture<NzTestMenuSiderCurrentComponent>;\n      let submenus: DebugElement[];\n      beforeEach(() => {\n        fixture = TestBed.createComponent(NzTestMenuSiderCurrentComponent);\n        submenus = fixture.debugElement.queryAll(By.directive(NzSubMenuComponent));\n      });\n\n      it('should collapsed self work', fakeAsync(() => {\n        fixture.detectChanges();\n        const ul = submenus[0].nativeElement.querySelector('.ant-menu');\n        const title = submenus[0].nativeElement.querySelector('.ant-menu-submenu-title');\n        expect(ul.style.height).not.toBe('0px');\n        title.click();\n        fixture.detectChanges();\n        tick(500);\n        expect(ul.style.height).toBe('0px');\n        expect(submenus[0].nativeElement.classList.contains('ant-menu-submenu-open')).toBe(false);\n        title.click();\n        fixture.detectChanges();\n        tick(500);\n        expect(ul.style.height).not.toBe('0px');\n        expect(submenus[0].nativeElement.classList.contains('ant-menu-submenu-open')).toBe(true);\n      }));\n\n      it('should collapsed other work', fakeAsync(() => {\n        fixture.detectChanges();\n        const firstUl = submenus[0].nativeElement.querySelector('.ant-menu');\n        const secondUl = submenus[1].nativeElement.querySelector('.ant-menu');\n        const secondTitle = submenus[1].nativeElement.querySelector('.ant-menu-submenu-title');\n        expect(firstUl.style.height).not.toBe('0px');\n        expect(submenus[0].nativeElement.classList.contains('ant-menu-submenu-open')).toBe(true);\n        secondTitle.click();\n        fixture.detectChanges();\n        tick(500);\n        expect(firstUl.style.height).toBe('0px');\n        expect(submenus[0].nativeElement.classList.contains('ant-menu-submenu-open')).toBe(false);\n        expect(secondUl.style.height).not.toBe('0px');\n        expect(submenus[1].nativeElement.classList.contains('ant-menu-submenu-open')).toBe(true);\n      }));\n    });\n\n    describe('theme', () => {\n      let fixture: ComponentFixture<NzTestMenuThemeComponent>;\n      let testComponent: NzTestMenuThemeComponent;\n      let menu: DebugElement;\n      beforeEach(() => {\n        fixture = TestBed.createComponent(NzTestMenuThemeComponent);\n        testComponent = fixture.debugElement.componentInstance;\n        menu = fixture.debugElement.query(By.directive(NzMenuDirective));\n      });\n\n      it('should className correct', () => {\n        fixture.detectChanges();\n        expect(menu.nativeElement.className).toBe('ant-menu ant-menu-root ant-menu-dark ant-menu-inline');\n        testComponent.theme = false;\n        fixture.detectChanges();\n        expect(menu.nativeElement.className).toBe('ant-menu ant-menu-root ant-menu-inline ant-menu-light');\n      });\n    });\n\n    describe('switch-mode', () => {\n      let fixture: ComponentFixture<NzTestMenuSwitchModeComponent>;\n      let testComponent: NzTestMenuSwitchModeComponent;\n      let submenus: DebugElement[];\n      let menu: DebugElement;\n      beforeEach(() => {\n        fixture = TestBed.createComponent(NzTestMenuSwitchModeComponent);\n        testComponent = fixture.debugElement.componentInstance;\n        submenus = fixture.debugElement.queryAll(By.directive(NzSubMenuComponent));\n        menu = fixture.debugElement.query(By.directive(NzMenuDirective));\n      });\n\n      it('should className correct', () => {\n        fixture.detectChanges();\n        expect(menu.nativeElement.className).toBe('ant-menu ant-menu-root ant-menu-light ant-menu-inline');\n        expect(submenus.every(submenu => submenu.nativeElement.classList.contains('ant-menu-submenu-inline'))).toBe(\n          true\n        );\n        testComponent.mode = true;\n        fixture.detectChanges();\n        expect(menu.nativeElement.className).toBe('ant-menu ant-menu-root ant-menu-light ant-menu-vertical');\n        expect(submenus.every(submenu => submenu.nativeElement.classList.contains('ant-menu-submenu-inline'))).toBe(\n          false\n        );\n        expect(submenus.every(submenu => submenu.nativeElement.classList.contains('ant-menu-submenu-vertical'))).toBe(\n          true\n        );\n      });\n    });\n  });\n\n  describe('submenu', () => {\n    describe('horizontal submenu', () => {\n      let fixture: ComponentFixture<NzTestMenuHorizontalComponent>;\n      let testComponent: NzTestMenuHorizontalComponent;\n      let submenu: DebugElement;\n\n      beforeEach(() => {\n        fixture = TestBed.createComponent(NzTestMenuHorizontalComponent);\n        testComponent = fixture.debugElement.componentInstance;\n        submenu = fixture.debugElement.query(By.directive(NzSubMenuComponent));\n      });\n\n      it('should overlay work', fakeAsync(() => {\n        fixture.detectChanges();\n        expect(overlayContainerElement.textContent).toBe('');\n        testComponent.open = true;\n        fixture.detectChanges();\n        expect(overlayContainerElement.textContent).not.toBe('');\n      }));\n\n      it('should submenu mouseenter work', () => {\n        fixture.detectChanges();\n        const mouseenterCallback = jasmine.createSpy('mouseenter callback');\n        const subs = testComponent.subs.toArray();\n        const title = submenu.nativeElement.querySelector('.ant-menu-submenu-title');\n\n        (subs[0].nzSubmenuService as NzSafeAny).isMouseEnterTitleOrOverlay$.subscribe(mouseenterCallback);\n        dispatchFakeEvent(title, 'mouseenter');\n        fixture.detectChanges();\n        expect(mouseenterCallback).toHaveBeenCalledWith(true);\n        expect(mouseenterCallback).toHaveBeenCalledTimes(1);\n      });\n\n      it('should have \"hover\" as default trigger', () => {\n        fixture.detectChanges();\n        const mouseenterCallback = jasmine.createSpy('mouseenter callback');\n        const subs = testComponent.subs.toArray();\n        const title = submenu.nativeElement.querySelector('.ant-menu-submenu-title');\n\n        (subs[0].nzSubmenuService as NzSafeAny).isMouseEnterTitleOrOverlay$.subscribe(mouseenterCallback);\n        dispatchFakeEvent(title, 'mouseenter');\n        fixture.detectChanges();\n        expect(mouseenterCallback).toHaveBeenCalledWith(true);\n        expect(mouseenterCallback).toHaveBeenCalledTimes(1);\n      });\n\n      it('should have not open with mouse hover if trigger is set to \"click\"', () => {\n        testComponent.nzTriggerSubMenuAction = 'click';\n        fixture.detectChanges();\n        const mouseenterCallback = jasmine.createSpy('mouseenter callback');\n        const subs = testComponent.subs.toArray();\n        const title = submenu.nativeElement.querySelector('.ant-menu-submenu-title');\n\n        (subs[0].nzSubmenuService as NzSafeAny).isMouseEnterTitleOrOverlay$.subscribe(mouseenterCallback);\n        dispatchFakeEvent(title, 'mouseenter');\n        fixture.detectChanges();\n        expect(mouseenterCallback).toHaveBeenCalledTimes(0);\n      });\n\n      it('should open with mouse click if trigger is set to \"click\"', () => {\n        testComponent.nzTriggerSubMenuAction = 'click';\n        fixture.detectChanges();\n        const mouseenterCallback = jasmine.createSpy('mouseenter callback');\n        const subs = testComponent.subs.toArray();\n        const title = submenu.nativeElement.querySelector('.ant-menu-submenu-title');\n        (subs[0].nzSubmenuService as NzSafeAny).isMouseEnterTitleOrOverlay$.subscribe(mouseenterCallback);\n        title.click();\n        fixture.detectChanges();\n        expect(mouseenterCallback).toHaveBeenCalledTimes(1);\n      });\n\n      it('should submenu mouseleave work', () => {\n        fixture.detectChanges();\n        const mouseleaveCallback = jasmine.createSpy('mouseleave callback');\n        const subs = testComponent.subs.toArray();\n        const title = submenu.nativeElement.querySelector('.ant-menu-submenu-title');\n\n        (subs[0].nzSubmenuService as NzSafeAny).isMouseEnterTitleOrOverlay$.subscribe(mouseleaveCallback);\n        dispatchFakeEvent(title, 'mouseleave');\n        fixture.detectChanges();\n        expect(mouseleaveCallback).toHaveBeenCalledWith(false);\n        expect(mouseleaveCallback).toHaveBeenCalledTimes(1);\n      });\n\n      it('should nested submenu work', () => {\n        testComponent.open = true;\n        fixture.detectChanges();\n        const nestedCallback = jasmine.createSpy('nested callback');\n        const subs = testComponent.subs.toArray();\n\n        (subs[0].nzSubmenuService as NzSafeAny).isChildSubMenuOpen$.subscribe(nestedCallback);\n        subs[1].nzOpen = true;\n        subs[1].nzSubmenuService.isCurrentSubMenuOpen$.next(false);\n        fixture.detectChanges();\n        expect(nestedCallback).toHaveBeenCalledWith(false);\n        expect(nestedCallback).toHaveBeenCalledTimes(1);\n      });\n\n      it('should nested submenu disabled work', () => {\n        testComponent.open = true;\n        testComponent.disabled = true;\n        fixture.detectChanges();\n        const nestedCallback = jasmine.createSpy('nested callback');\n        const subs = testComponent.subs.toArray();\n\n        (subs[0].nzSubmenuService as NzSafeAny).isChildSubMenuOpen$.subscribe(nestedCallback);\n        subs[1].nzOpen = true;\n        subs[1].nzSubmenuService.isCurrentSubMenuOpen$.next(false);\n        fixture.detectChanges();\n        expect(nestedCallback).toHaveBeenCalledTimes(1);\n      });\n\n      it('should click menu and other submenu menu not active', fakeAsync(() => {\n        testComponent.open = true;\n        fixture.detectChanges();\n        const subs = testComponent.subs.toArray();\n        dispatchFakeEvent(testComponent.menuitem1.nativeElement, 'mouseenter');\n        fixture.detectChanges();\n        testComponent.menuitem1.nativeElement.click();\n        fixture.detectChanges();\n        tick(500);\n        expect(subs[1].isActive).toBe(false);\n      }));\n\n      it('should click submenu menu item close', () => {\n        testComponent.open = true;\n        fixture.detectChanges();\n        const nestedCallback = jasmine.createSpy('nested callback');\n        const subs = testComponent.subs.toArray();\n        subs[1].nzOpen = true;\n        fixture.detectChanges();\n\n        (subs[1].nzSubmenuService as NzSafeAny).isChildSubMenuOpen$.subscribe(nestedCallback);\n        testComponent.menuitem.nativeElement.click();\n        fixture.detectChanges();\n        expect(nestedCallback).toHaveBeenCalledWith(false);\n        expect(nestedCallback).toHaveBeenCalledTimes(1);\n      });\n\n      it('should click submenu disabled menu item not close', () => {\n        testComponent.open = true;\n        fixture.detectChanges();\n        const nestedCallback = jasmine.createSpy('nested callback');\n        const subs = testComponent.subs.toArray();\n\n        (subs[1].nzSubmenuService as NzSafeAny).isMouseEnterTitleOrOverlay$.subscribe(nestedCallback);\n        subs[1].nzOpen = true;\n        testComponent.disabledItem.nativeElement.click();\n        fixture.detectChanges();\n        expect(nestedCallback).toHaveBeenCalledTimes(0);\n      });\n\n      it('should width change correct', () => {\n        fixture.detectChanges();\n        testComponent.open = true;\n        fixture.detectChanges();\n        const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement;\n        expect(overlayPane.style.width).toBe('200px');\n        testComponent.open = false;\n        fixture.detectChanges();\n        testComponent.width = 300;\n        fixture.detectChanges();\n        testComponent.open = true;\n        fixture.detectChanges();\n        expect(overlayPane.style.width).toBe('300px');\n      });\n\n      it('should position change correct', () => {\n        const fakeLeftTopEvent = {\n          connectionPair: {\n            originX: 'start',\n            originY: 'top',\n            overlayX: 'end',\n            overlayY: 'top'\n          }\n        } as ConnectedOverlayPositionChange;\n        const fakeRightTopEvent = {\n          connectionPair: {\n            originX: 'end',\n            originY: 'top',\n            overlayX: 'start',\n            overlayY: 'top'\n          }\n        } as ConnectedOverlayPositionChange;\n        fixture.detectChanges();\n        testComponent.open = true;\n        const subs = testComponent.subs.toArray();\n        subs[1].nzOpen = true;\n        fixture.detectChanges();\n        subs[1].onPositionChange(fakeLeftTopEvent);\n        fixture.detectChanges();\n        expect(subs[1].position).toBe('left');\n        subs[1].onPositionChange(fakeRightTopEvent);\n        fixture.detectChanges();\n        expect(subs[1].position).toBe('right');\n      });\n\n      it('should `nzMenuClassName` work', fakeAsync(() => {\n        fixture.detectChanges();\n        testComponent.open = true;\n        fixture.detectChanges();\n        expect((overlayContainerElement.querySelector('.submenu') as HTMLUListElement).classList).toContain(\n          'ant-menu-sub'\n        );\n      }));\n\n      it('should nested submenu `nzMenuClassName` work', () => {\n        testComponent.open = true;\n        fixture.detectChanges();\n        const subs = testComponent.subs.toArray();\n        subs[0].nzOpen = true;\n        subs[1].nzOpen = true;\n\n        (subs[1] as NzSafeAny).cdr.markForCheck();\n        fixture.detectChanges();\n        expect((overlayContainerElement.querySelector('.nested-submenu') as HTMLUListElement).classList).toContain(\n          'ant-menu-sub'\n        );\n      });\n    });\n\n    describe('inline submenu', () => {\n      let fixture: ComponentFixture<NzTestMenuInlineComponent>;\n      let testComponent: NzTestMenuInlineComponent;\n      let submenu: DebugElement;\n\n      beforeEach(() => {\n        fixture = TestBed.createComponent(NzTestMenuInlineComponent);\n        testComponent = fixture.debugElement.componentInstance;\n        submenu = fixture.debugElement.query(By.directive(NzSubMenuComponent));\n      });\n\n      it('should click expand', fakeAsync(() => {\n        fixture.detectChanges();\n        const ul = submenu.nativeElement.querySelector('.ant-menu');\n        const title = submenu.nativeElement.querySelector('.ant-menu-submenu-title');\n        expect(ul.style.height).toBe('0px');\n        title.click();\n        fixture.detectChanges();\n        tick(500);\n        expect(ul.style.height).not.toBe('0px');\n        expect(submenu.nativeElement.classList.contains('ant-menu-submenu-open')).toBe(true);\n      }));\n\n      it('should `nzMenuClassName` work', fakeAsync(() => {\n        fixture.detectChanges();\n        expect(submenu.nativeElement.querySelector('.ant-menu-sub').className).toContain('submenu');\n      }));\n\n      it('should `nzMenuClassName` multi class names work', fakeAsync(() => {\n        fixture.detectChanges();\n        testComponent.submenuClassName = 'submenu submenu-1';\n        fixture.detectChanges();\n        expect(submenu.nativeElement.querySelector('.ant-menu-sub').className).toContain('submenu');\n        expect(submenu.nativeElement.querySelector('.ant-menu-sub').className).toContain('submenu-1');\n      }));\n\n      it('should disabled work', fakeAsync(() => {\n        testComponent.disabled = true;\n        fixture.detectChanges();\n        const ul = submenu.nativeElement.querySelector('.ant-menu');\n        const title = submenu.nativeElement.querySelector('.ant-menu-submenu-title');\n        expect(ul.style.height).toBe('0px');\n        title.click();\n        fixture.detectChanges();\n        tick(500);\n        expect(ul.style.height).toBe('0px');\n        expect(submenu.nativeElement.classList.contains('ant-menu-submenu-open')).toBe(false);\n      }));\n    });\n\n    describe('submenu default selected', () => {\n      it('should default selected active submenu', () => {\n        const fixture = TestBed.createComponent(NzTestSubMenuSelectedComponent);\n        fixture.detectChanges();\n        expect(fixture.debugElement.nativeElement.querySelector('.ant-menu-submenu').classList).toContain(\n          'ant-menu-submenu-selected'\n        );\n      });\n    });\n  });\n\n  describe('RTL', () => {\n    let fixture: ComponentFixture<NzTestMenuHorizontalComponent>;\n    let testComponent: NzTestMenuHorizontalComponent;\n    let submenu: DebugElement;\n    let menu: DebugElement;\n    let directionality: Directionality;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestMenuHorizontalComponent);\n      testComponent = fixture.componentInstance;\n      submenu = fixture.debugElement.query(By.directive(NzSubMenuComponent));\n      menu = fixture.debugElement.query(By.directive(NzMenuDirective));\n      directionality = TestBed.inject(Directionality);\n\n      testComponent.open = true;\n      directionality.valueSignal.set('rtl');\n      fixture.detectChanges();\n    });\n\n    it('should className correct on dir change', () => {\n      expect(submenu.nativeElement.classList.contains('ant-menu-submenu-rtl')).toBe(true);\n      expect(menu.nativeElement.classList.contains('ant-menu-rtl')).toBe(true);\n\n      directionality.valueSignal.set('ltr');\n      fixture.detectChanges();\n\n      expect(submenu.nativeElement.classList.contains('ant-menu-submenu-rtl')).toBe(false);\n      expect(menu.nativeElement.classList.contains('ant-menu-rtl')).toBe(false);\n    });\n\n    it('should nested submenu work', () => {\n      const subs = testComponent.subs.toArray();\n      subs[0].nzOpen = true;\n      fixture.detectChanges();\n\n      expect((overlayContainerElement.querySelector('.ant-menu-submenu') as HTMLUListElement).classList).toContain(\n        'ant-menu-submenu-rtl'\n      );\n    });\n  });\n});\n\n@Component({\n  selector: 'nz-test-menu-horizontal',\n  imports: [NzIconModule, NzMenuModule],\n  template: `\n    <ul nz-menu nzMode=\"horizontal\">\n      <li\n        nz-submenu\n        [nzTriggerSubMenuAction]=\"nzTriggerSubMenuAction\"\n        nzMenuClassName=\"submenu\"\n        [nzOpen]=\"open\"\n        [style.width.px]=\"width\"\n      >\n        <span title>\n          <nz-icon nzType=\"setting\" />\n          Navigation Three - Submenu\n        </span>\n        <ul>\n          <li nz-menu-group>\n            <span title>Item 1</span>\n            <ul>\n              <li nz-menu-item>Option 1</li>\n              <li nz-menu-item>Option 2</li>\n            </ul>\n          </li>\n          <li nz-menu-group>\n            <span title>Item 2</span>\n            <ul>\n              <li nz-menu-item #menuitem1>Option 3</li>\n              <li nz-menu-item>Option 4</li>\n              <li nz-submenu nzMenuClassName=\"nested-submenu\" [nzDisabled]=\"disabled\">\n                <span title>Sub Menu</span>\n                <ul>\n                  <li nz-menu-item #menuitem>Option 5</li>\n                  <li nz-menu-item #disabledItem nzDisabled>Option 6</li>\n                </ul>\n              </li>\n              <li nz-submenu nzDisabled>\n                <span title>Disabled Sub Menu</span>\n                <ul>\n                  <li nz-menu-item>Option 5</li>\n                  <li nz-menu-item>Option 6</li>\n                </ul>\n              </li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n    </ul>\n  `\n})\nexport class NzTestMenuHorizontalComponent {\n  width = 200;\n  open = false;\n  disabled = false;\n  nzTriggerSubMenuAction: NzSubmenuTrigger = 'hover';\n  @ViewChildren(NzSubMenuComponent) subs!: QueryList<NzSubMenuComponent>;\n  @ViewChild('menuitem', { static: false, read: ElementRef }) menuitem!: ElementRef;\n  @ViewChild('menuitem1', { static: false, read: ElementRef }) menuitem1!: ElementRef;\n  @ViewChild('disabledItem', { static: false, read: ElementRef }) disabledItem!: ElementRef;\n}\n\n@Component({\n  imports: [NzIconModule, NzMenuModule],\n  template: `\n    <ul nz-menu nzMode=\"inline\" [nzInlineCollapsed]=\"collapse\">\n      <li nz-submenu [nzMenuClassName]=\"submenuClassName\" [nzDisabled]=\"disabled\">\n        <span title>\n          <nz-icon nzType=\"mail\" />\n          Navigation One\n        </span>\n        <ul>\n          <li nz-menu-item style=\"padding-left:0\">Option 1</li>\n          <li nz-menu-item>Option 2</li>\n        </ul>\n      </li>\n    </ul>\n  `\n})\nexport class NzTestMenuInlineComponent {\n  disabled = false;\n  collapse = false;\n  submenuClassName = 'submenu';\n  @ViewChild(NzSubMenuComponent, { static: true }) submenu!: NzSubMenuComponent;\n}\n\n@Component({\n  imports: [NzIconModule, NzMenuModule],\n  template: `\n    <ul nz-menu nzMode=\"horizontal\">\n      <li nz-menu-item>\n        <nz-icon nzType=\"mail\" />\n        Navigation One\n      </li>\n      <li nz-menu-item nzDisabled>\n        <nz-icon nzType=\"appstore\" />\n        Navigation Two\n      </li>\n      <li nz-submenu nzTitle=\"Navigation Three - Submenu\" nzIcon=\"setting\">\n        <ul>\n          <li nz-menu-group nzTitle=\"Item 1\">\n            <ul>\n              <li nz-menu-item>Option 1</li>\n              <li nz-menu-item>Option 2</li>\n            </ul>\n          </li>\n          <li nz-menu-group nzTitle=\"Item 2\">\n            <ul>\n              <li nz-menu-item>Option 3</li>\n              <li nz-menu-item>Option 4</li>\n              <li nz-submenu nzTitle=\"Sub Menu\">\n                <ul>\n                  <li nz-menu-item nzDisabled>Option 5</li>\n                  <li nz-menu-item>Option 6</li>\n                </ul>\n              </li>\n              <li nz-submenu nzDisabled nzTitle=\"Disabled Sub Menu\">\n                <ul>\n                  <li nz-menu-item>Option 5</li>\n                  <li nz-menu-item>Option 6</li>\n                </ul>\n              </li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li nz-menu-item>\n        <a href=\"https://ng.ant.design\" target=\"_blank\" rel=\"noopener noreferrer\">Navigation Four - Link</a>\n      </li>\n      <li nz-menu-item nzDanger>Navigation Five</li>\n    </ul>\n  `\n})\nexport class NzTestBasicMenuHorizontalComponent {}\n\n@Component({\n  imports: [NzMenuModule],\n  template: `\n    <ul nz-menu nzMode=\"inline\">\n      <li nz-submenu nzTitle=\"Navigation One\" nzIcon=\"mail\">\n        <ul>\n          <li nz-menu-group nzTitle=\"Item 1\">\n            <ul>\n              <li nz-menu-item>Option 1</li>\n              <li nz-menu-item>Option 2</li>\n            </ul>\n          </li>\n          <li nz-menu-group nzTitle=\"Item 2\">\n            <ul>\n              <li nz-menu-item>Option 3</li>\n              <li nz-menu-item>Option 4</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li nz-submenu nzTitle=\"Navigation Two\" nzIcon=\"appstore\">\n        <ul>\n          <li nz-menu-item>Option 5</li>\n          <li nz-menu-item>Option 6</li>\n          <li nz-submenu nzTitle=\"Submenu\">\n            <ul>\n              <li nz-menu-item>Option 7</li>\n              <li nz-menu-item>Option 8</li>\n              <li nz-submenu nzTitle=\"Submenu\">\n                <ul>\n                  <li nz-menu-item>Option 9</li>\n                  <li nz-menu-item>Option 10</li>\n                </ul>\n              </li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li nz-submenu nzTitle=\"Navigation Three\" nzIcon=\"setting\">\n        <ul>\n          <li nz-menu-item>Option 11</li>\n          <li nz-menu-item>Option 12</li>\n          <li nz-menu-item>Option 13</li>\n        </ul>\n      </li>\n    </ul>\n  `\n})\nexport class NzTestBasicMenuInlineComponent {}\n\n// https://github.com/NG-ZORRO/ng-zorro-antd/issues/3345\n@Component({\n  imports: [NzIconModule, NzMenuModule],\n  template: `\n    <ul nz-menu nzMode=\"inline\" nzTheme=\"dark\" nzInlineCollapsed>\n      <li nz-menu-item>\n        <nz-icon nzType=\"mail\" />\n        <span>Navigation One</span>\n      </li>\n      <li nz-submenu nzTitle=\"Navigation Two\" nzIcon=\"appstore\">\n        <ul>\n          <li nz-menu-item nzSelected>Option 5</li>\n          <li nz-menu-item>Option 6</li>\n        </ul>\n      </li>\n    </ul>\n  `\n})\nexport class NzTestSubMenuSelectedComponent {}\n\n@Component({\n  imports: [NzButtonModule, NzIconModule, NzMenuModule],\n  template: `\n    <div class=\"wrapper\">\n      <button nz-button nzType=\"primary\" (click)=\"toggleCollapsed()\">\n        <nz-icon [nzType]=\"isCollapsed ? 'menu-unfold' : 'menu-fold'\" />\n      </button>\n      <ul nz-menu nzMode=\"inline\" nzTheme=\"dark\" [nzInlineCollapsed]=\"isCollapsed\">\n        <li nz-menu-item nzSelected>\n          <nz-icon nzType=\"mail\" />\n          <span>Navigation One</span>\n        </li>\n        <li nz-submenu nzTitle=\"Navigation Two\" nzIcon=\"appstore\">\n          <ul>\n            <li nz-menu-item>Option 5</li>\n            <li nz-menu-item>Option 6</li>\n            <li nz-submenu nzTitle=\"Submenu\">\n              <ul>\n                <li nz-menu-item>Option 7</li>\n                <li nz-menu-item>Option 8</li>\n              </ul>\n            </li>\n          </ul>\n        </li>\n        <li nz-submenu nzTitle=\"Navigation Three\" nzIcon=\"setting\">\n          <ul>\n            <li nz-menu-item>Option 9</li>\n            <li nz-menu-item>Option 10</li>\n            <li nz-menu-item>Option 11</li>\n          </ul>\n        </li>\n      </ul>\n    </div>\n  `\n})\nexport class NzTestMenuInlineCollapsedComponent {\n  isCollapsed = false;\n\n  toggleCollapsed(): void {\n    this.isCollapsed = !this.isCollapsed;\n  }\n}\n\n@Component({\n  imports: [NzMenuModule],\n  template: `\n    <ul nz-menu nzMode=\"inline\" style=\"width: 240px;\">\n      <li\n        nz-submenu\n        [(nzOpen)]=\"openMap.sub1\"\n        (nzOpenChange)=\"openHandler('sub1')\"\n        nzTitle=\"Navigation One\"\n        nzIcon=\"mail\"\n      >\n        <ul>\n          <li nz-menu-group nzTitle=\"Item 1\">\n            <ul>\n              <li nz-menu-item>Option 1</li>\n              <li nz-menu-item>Option 2</li>\n            </ul>\n          </li>\n          <li nz-menu-group nzTitle=\"Item 2\">\n            <ul>\n              <li nz-menu-item>Option 3</li>\n              <li nz-menu-item>Option 4</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li\n        nz-submenu\n        [(nzOpen)]=\"openMap.sub2\"\n        (nzOpenChange)=\"openHandler('sub2')\"\n        nzTitle=\"Navigation Two\"\n        nzIcon=\"appstore\"\n      >\n        <ul>\n          <li nz-menu-item>Option 5</li>\n          <li nz-menu-item>Option 6</li>\n          <li nz-submenu nzTitle=\"Submenu\">\n            <ul>\n              <li nz-menu-item>Option 7</li>\n              <li nz-menu-item>Option 8</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li\n        nz-submenu\n        [(nzOpen)]=\"openMap.sub3\"\n        (nzOpenChange)=\"openHandler('sub3')\"\n        nzTitle=\"Navigation Three\"\n        nzIcon=\"setting\"\n      >\n        <ul>\n          <li nz-menu-item>Option 9</li>\n          <li nz-menu-item>Option 10</li>\n          <li nz-menu-item>Option 11</li>\n        </ul>\n      </li>\n    </ul>\n  `\n})\nexport class NzTestMenuSiderCurrentComponent {\n  openMap: Record<string, boolean> = {\n    sub1: true,\n    sub2: false,\n    sub3: false\n  };\n\n  openHandler(value: string): void {\n    for (const key in this.openMap) {\n      if (key !== value) {\n        this.openMap[key] = false;\n      }\n    }\n  }\n}\n\n@Component({\n  imports: [NzMenuModule],\n  template: `\n    <ul nz-menu [nzMode]=\"mode ? 'vertical' : 'inline'\" [nzTheme]=\"dark ? 'dark' : 'light'\">\n      <li nz-submenu nzTitle=\"Navigation One\" nzIcon=\"mail\">\n        <ul>\n          <li nz-menu-group nzTitle=\"Item 1\">\n            <ul>\n              <li nz-menu-item>Option 1</li>\n              <li nz-menu-item>Option 2</li>\n            </ul>\n          </li>\n          <li nz-menu-group nzTitle=\"Item 2\">\n            <ul>\n              <li nz-menu-item>Option 3</li>\n              <li nz-menu-item>Option 4</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li nz-submenu nzTitle=\"Navigation Two\" nzIcon=\"appstore\">\n        <ul>\n          <li nz-menu-item>Option 5</li>\n          <li nz-menu-item>Option 6</li>\n          <li nz-submenu nzTitle=\"Submenu\">\n            <ul>\n              <li nz-menu-item>Option 7</li>\n              <li nz-menu-item>Option 8</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li nz-submenu nzTitle=\"Navigation Three\" nzIcon=\"setting\">\n        <ul>\n          <li nz-menu-item>Option 9</li>\n          <li nz-menu-item>Option 10</li>\n          <li nz-menu-item>Option 11</li>\n        </ul>\n      </li>\n    </ul>\n  `\n})\nexport class NzTestMenuSwitchModeComponent {\n  mode = false;\n  dark = false;\n}\n\n@Component({\n  imports: [NzMenuModule],\n  template: `\n    <ul nz-menu nzMode=\"inline\" style=\"width: 240px;\" [nzTheme]=\"theme ? 'dark' : 'light'\">\n      <li nz-submenu nzOpen nzTitle=\"Navigation One\" nzIcon=\"mail\">\n        <ul>\n          <li nz-menu-group nzTitle=\"Item 1\">\n            <ul>\n              <li nz-menu-item nzSelected>Option 1</li>\n              <li nz-menu-item>Option 2</li>\n            </ul>\n          </li>\n          <li nz-menu-group nzTitle=\"Item 2\">\n            <ul>\n              <li nz-menu-item>Option 3</li>\n              <li nz-menu-item>Option 4</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li nz-submenu nzTitle=\"Navigation Two\" nzIcon=\"appstore\">\n        <ul>\n          <li nz-menu-item>Option 5</li>\n          <li nz-menu-item>Option 6</li>\n          <li nz-submenu nzTitle=\"Submenu\">\n            <ul>\n              <li nz-menu-item>Option 7</li>\n              <li nz-menu-item>Option 8</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li nz-submenu nzTitle=\"Navigation Three\" nzIcon=\"setting\">\n        <ul>\n          <li nz-menu-item>Option 9</li>\n          <li nz-menu-item>Option 10</li>\n          <li nz-menu-item>Option 11</li>\n        </ul>\n      </li>\n    </ul>\n  `\n})\nexport class NzTestMenuThemeComponent {\n  theme = true;\n}\n"
  },
  {
    "path": "components/menu/menu.token.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { InjectionToken } from '@angular/core';\n\nimport { MenuService } from './menu.service';\n\n/**\n * A flag to mark if the menu is inside a dropdown.\n * @note Internally used only, please do not use it.\n */\nexport const NzIsMenuInsideDropdownToken = new InjectionToken<boolean>(\n  typeof ngDevMode !== 'undefined' && ngDevMode ? 'nz-is-in-dropdown-menu' : ''\n);\n\n/**\n * A token to hold the local {@link MenuService} instance. This is used for nested menu.\n * @note Internally used only, please do not use it.\n */\nexport const NzMenuServiceLocalToken = new InjectionToken<MenuService>(\n  typeof ngDevMode !== 'undefined' && ngDevMode ? 'nz-menu-service-local' : ''\n);\n"
  },
  {
    "path": "components/menu/menu.types.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport type NzMenuModeType = 'vertical' | 'horizontal' | 'inline';\nexport type NzMenuThemeType = 'light' | 'dark';\nexport type NzSubmenuTrigger = 'hover' | 'click';\n"
  },
  {
    "path": "components/menu/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/menu/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './menu.directive';\nexport * from './menu-group.component';\nexport * from './menu-divider.directive';\nexport * from './menu-item.component';\nexport * from './submenu.component';\nexport * from './submenu-title.component';\nexport * from './submenu-inline-child.component';\nexport * from './submenu-non-inline-child.component';\nexport * from './menu.module';\nexport * from './submenu.service';\nexport * from './menu.types';\nexport * from './menu.service';\nexport * from './menu.token';\n"
  },
  {
    "path": "components/menu/style/dark.less",
    "content": ".accessibility-focus-dark() {\n  box-shadow: 0 0 0 2px @primary-7;\n}\n\n.@{menu-prefix-cls} {\n  &&-root:focus-visible {\n    .accessibility-focus-dark();\n  }\n\n  &-dark &-item,\n  &-dark &-submenu-title {\n    &:focus-visible {\n      .accessibility-focus-dark();\n    }\n  }\n\n  // dark theme\n  &&-dark,\n  &-dark &-sub,\n  &&-dark &-sub {\n    color: @menu-dark-color;\n    background: @menu-dark-bg;\n    .@{menu-prefix-cls}-submenu-title .@{menu-prefix-cls}-submenu-arrow {\n      opacity: 0.45;\n      transition: all 0.3s;\n\n      &::after,\n      &::before {\n        background: @menu-dark-arrow-color;\n      }\n    }\n  }\n\n  &-dark&-submenu-popup {\n    background: transparent;\n  }\n\n  &-dark &-inline&-sub {\n    background: @menu-dark-inline-submenu-bg;\n  }\n\n  &-dark&-horizontal {\n    border-bottom: 0;\n  }\n\n  &-dark&-horizontal > &-item,\n  &-dark&-horizontal > &-submenu {\n    top: 0;\n    margin-top: 0;\n    padding: @menu-item-padding;\n    border-color: @menu-dark-bg;\n    border-bottom: 0;\n  }\n\n  &-dark&-horizontal > &-item:hover {\n    background-color: @menu-dark-item-active-bg;\n  }\n\n  &-dark&-horizontal > &-item > a::before {\n    bottom: 0;\n  }\n\n  &-dark &-item,\n  &-dark &-item-group-title,\n  &-dark &-item > a,\n  &-dark &-item > span > a {\n    color: @menu-dark-color;\n  }\n\n  &-dark&-inline,\n  &-dark&-vertical,\n  &-dark&-vertical-left,\n  &-dark&-vertical-right {\n    border-right: 0;\n  }\n\n  &-dark&-inline &-item,\n  &-dark&-vertical &-item,\n  &-dark&-vertical-left &-item,\n  &-dark&-vertical-right &-item {\n    left: 0;\n    margin-left: 0;\n    border-right: 0;\n\n    &::after {\n      border-right: 0;\n    }\n  }\n\n  &-dark&-inline &-item,\n  &-dark&-inline &-submenu-title {\n    width: 100%;\n  }\n\n  &-dark &-item:hover,\n  &-dark &-item-active,\n  &-dark &-submenu-active,\n  &-dark &-submenu-open,\n  &-dark &-submenu-selected,\n  &-dark &-submenu-title:hover {\n    color: @menu-dark-highlight-color;\n    background-color: transparent;\n\n    > a,\n    > span > a {\n      color: @menu-dark-highlight-color;\n    }\n    > .@{menu-prefix-cls}-submenu-title {\n      > .@{menu-prefix-cls}-submenu-arrow {\n        opacity: 1;\n\n        &::after,\n        &::before {\n          background: @menu-dark-highlight-color;\n        }\n      }\n    }\n  }\n\n  &-dark &-item:hover {\n    background-color: @menu-dark-item-hover-bg;\n  }\n\n  &-dark&-dark:not(&-horizontal) &-item-selected {\n    background-color: @menu-dark-item-active-bg;\n  }\n\n  &-dark &-item-selected {\n    color: @menu-dark-highlight-color;\n    border-right: 0;\n\n    &::after {\n      border-right: 0;\n    }\n\n    > a,\n    > span > a,\n    > a:hover,\n    > span > a:hover {\n      color: @menu-dark-highlight-color;\n    }\n\n    .@{menu-prefix-cls}-item-icon,\n    .@{iconfont-css-prefix} {\n      color: @menu-dark-selected-item-icon-color;\n\n      + span {\n        color: @menu-dark-selected-item-text-color;\n      }\n    }\n  }\n\n  &&-dark &-item-selected,\n  &-submenu-popup&-dark &-item-selected {\n    background-color: @menu-dark-item-active-bg;\n  }\n\n  // Disabled state sets text to dark gray and nukes hover/tab effects\n  &-dark &-item-disabled,\n  &-dark &-submenu-disabled {\n    &,\n    > a,\n    > span > a {\n      color: @disabled-color-dark !important;\n      opacity: 0.8;\n    }\n    > .@{menu-prefix-cls}-submenu-title {\n      color: @disabled-color-dark !important;\n      > .@{menu-prefix-cls}-submenu-arrow {\n        &::before,\n        &::after {\n          background: @disabled-color-dark !important;\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/menu/style/entry.less",
    "content": "@import './index.less';\n// style dependencies\n// deps-lint-skip: layout\n@import '../../tooltip/style/entry.less';\n@import './patch.less';\n"
  },
  {
    "path": "components/menu/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import './status';\n\n@menu-prefix-cls: ~'@{ant-prefix}-menu';\n@menu-animation-duration-normal: 0.15s;\n\n.accessibility-focus() {\n  box-shadow: 0 0 0 2px @primary-2;\n}\n\n// TODO: Should remove icon style compatible in v5\n\n// default theme\n.@{menu-prefix-cls} {\n  .reset-component();\n\n  margin-bottom: 0;\n  padding-left: 0; // Override default ul/ol\n  color: @menu-item-color;\n  font-size: @menu-item-font-size;\n  line-height: 0; // Fix display inline-block gap\n  text-align: left;\n  list-style: none;\n  background: @menu-bg;\n  outline: none;\n  box-shadow: @box-shadow-base;\n  transition: background @animation-duration-slow,\n    width @animation-duration-slow cubic-bezier(0.2, 0, 0, 1) 0s;\n  .clearfix();\n\n  &&-root:focus-visible {\n    .accessibility-focus();\n  }\n\n  ul,\n  ol {\n    margin: 0;\n    padding: 0;\n    list-style: none;\n  }\n\n  // Overflow ellipsis\n  &-overflow {\n    display: flex;\n\n    &-item {\n      flex: none;\n    }\n  }\n\n  &-hidden,\n  &-submenu-hidden {\n    display: none;\n  }\n\n  &-item-group-title {\n    height: @menu-item-group-height;\n    padding: 8px 16px;\n    color: @menu-item-group-title-color;\n    font-size: @menu-item-group-title-font-size;\n    line-height: @menu-item-group-height;\n    transition: all @animation-duration-slow;\n  }\n\n  &-horizontal &-submenu {\n    transition: border-color @animation-duration-slow @ease-in-out,\n      background @animation-duration-slow @ease-in-out;\n  }\n\n  &-submenu,\n  &-submenu-inline {\n    transition: border-color @animation-duration-slow @ease-in-out,\n      background @animation-duration-slow @ease-in-out,\n      padding @menu-animation-duration-normal @ease-in-out;\n  }\n\n  &-submenu-selected {\n    color: @menu-highlight-color;\n  }\n\n  &-item:active,\n  &-submenu-title:active {\n    background: @menu-item-active-bg;\n  }\n\n  &-submenu &-sub {\n    cursor: initial;\n    transition: background @animation-duration-slow @ease-in-out,\n      padding @animation-duration-slow @ease-in-out;\n  }\n\n  &-title-content {\n    transition: color @animation-duration-slow;\n  }\n\n  &-item a {\n    color: @menu-item-color;\n\n    &:hover {\n      color: @menu-highlight-color;\n    }\n\n    &::before {\n      position: absolute;\n      top: 0;\n      right: 0;\n      bottom: 0;\n      left: 0;\n      background-color: transparent;\n      content: '';\n    }\n  }\n\n  // https://github.com/ant-design/ant-design/issues/19809\n  &-item > .@{ant-prefix}-badge a {\n    color: @menu-item-color;\n\n    &:hover {\n      color: @menu-highlight-color;\n    }\n  }\n\n  &-item-divider {\n    overflow: hidden;\n    line-height: 0;\n    border-color: @border-color-split;\n    border-style: solid;\n    border-width: 1px 0 0;\n  }\n\n  &-item-divider-dashed {\n    border-style: dashed;\n  }\n\n  &-horizontal &-item,\n  &-horizontal &-submenu {\n    margin-top: -1px;\n  }\n\n  &-horizontal > &-item:hover,\n  &-horizontal > &-item-active,\n  &-horizontal > &-submenu &-submenu-title:hover {\n    background-color: transparent;\n  }\n\n  &-item-selected {\n    color: @menu-highlight-color;\n\n    a,\n    a:hover {\n      color: @menu-highlight-color;\n    }\n  }\n\n  &:not(&-horizontal) &-item-selected {\n    background-color: @menu-item-active-bg;\n  }\n\n  &-inline,\n  &-vertical,\n  &-vertical-left {\n    border-right: @border-width-base @border-style-base @border-color-split;\n  }\n\n  &-vertical-right {\n    border-left: @border-width-base @border-style-base @border-color-split;\n  }\n\n  &-vertical&-sub,\n  &-vertical-left&-sub,\n  &-vertical-right&-sub {\n    min-width: 160px;\n    max-height: calc(100vh - 100px);\n    padding: 0;\n    overflow: hidden;\n    border-right: 0;\n\n    // https://github.com/ant-design/ant-design/issues/22244\n    // https://github.com/ant-design/ant-design/issues/26812\n    &:not([class*='-active']) {\n      overflow-x: hidden;\n      overflow-y: auto;\n    }\n\n    .@{menu-prefix-cls}-item {\n      left: 0;\n      margin-left: 0;\n      border-right: 0;\n\n      &::after {\n        border-right: 0;\n      }\n    }\n    > .@{menu-prefix-cls}-item,\n    > .@{menu-prefix-cls}-submenu {\n      transform-origin: 0 0;\n    }\n  }\n\n  &-horizontal&-sub {\n    min-width: 114px; // in case of submenu width is too big: https://codesandbox.io/s/qvpwm6mk66\n  }\n\n  &-horizontal &-item,\n  &-horizontal &-submenu-title {\n    transition: border-color @animation-duration-slow, background @animation-duration-slow;\n  }\n\n  &-item,\n  &-submenu-title {\n    position: relative;\n    display: block;\n    margin: 0;\n    padding: @menu-item-padding;\n    white-space: nowrap;\n    cursor: pointer;\n    transition: border-color @animation-duration-slow, background @animation-duration-slow,\n      padding @animation-duration-slow @ease-in-out;\n\n    .@{menu-prefix-cls}-item-icon,\n    .@{iconfont-css-prefix} {\n      min-width: 14px;\n      font-size: @menu-icon-size;\n      transition: font-size @menu-animation-duration-normal @ease-out,\n        margin @animation-duration-slow @ease-in-out, color @animation-duration-slow;\n\n      + span {\n        margin-left: @menu-icon-margin-right;\n        opacity: 1;\n        transition: opacity @animation-duration-slow @ease-in-out, margin @animation-duration-slow,\n          color @animation-duration-slow;\n      }\n    }\n\n    .@{menu-prefix-cls}-item-icon.svg {\n      vertical-align: -0.125em;\n    }\n\n    &.@{menu-prefix-cls}-item-only-child {\n      > .@{iconfont-css-prefix},\n      > .@{menu-prefix-cls}-item-icon {\n        margin-right: 0;\n      }\n    }\n\n    &:not(.@{menu-prefix-cls}-item-disabled):focus-visible {\n      .accessibility-focus();\n    }\n  }\n\n  & > &-item-divider {\n    margin: 1px 0;\n    padding: 0;\n  }\n\n  &-submenu {\n    &-popup {\n      position: absolute;\n      z-index: @zindex-dropdown;\n      background: transparent;\n      border-radius: @border-radius-base;\n      box-shadow: none;\n      transform-origin: 0 0;\n\n      // https://github.com/ant-design/ant-design/issues/13955\n      &::before {\n        position: absolute;\n        top: -7px;\n        right: 0;\n        bottom: 0;\n        left: 0;\n        z-index: -1;\n        width: 100%;\n        height: 100%;\n        opacity: 0.0001;\n        content: ' ';\n      }\n    }\n\n    // https://github.com/ant-design/ant-design/issues/13955\n    &-placement-rightTop::before {\n      top: 0;\n      left: -7px;\n    }\n\n    > .@{menu-prefix-cls} {\n      background-color: @menu-bg;\n      border-radius: @border-radius-base;\n\n      &-submenu-title::after {\n        transition: transform @animation-duration-slow @ease-in-out;\n      }\n    }\n\n    &-popup > .@{menu-prefix-cls} {\n      background-color: @menu-popup-bg;\n    }\n\n    &-expand-icon,\n    &-arrow {\n      position: absolute;\n      top: 50%;\n      right: 16px;\n      width: 10px;\n      color: @menu-item-color;\n      transform: translateY(-50%);\n      transition: transform @animation-duration-slow @ease-in-out;\n    }\n\n    &-arrow {\n      // →\n      &::before,\n      &::after {\n        position: absolute;\n        width: 6px;\n        height: 1.5px;\n        background-color: currentcolor;\n        border-radius: 2px;\n        transition: background @animation-duration-slow @ease-in-out,\n          transform @animation-duration-slow @ease-in-out, top @animation-duration-slow @ease-in-out,\n          color @animation-duration-slow @ease-in-out;\n        content: '';\n      }\n\n      &::before {\n        transform: rotate(45deg) translateY(-2.5px);\n      }\n\n      &::after {\n        transform: rotate(-45deg) translateY(2.5px);\n      }\n    }\n\n    &:hover > &-title > &-expand-icon,\n    &:hover > &-title > &-arrow {\n      color: @menu-highlight-color;\n    }\n\n    .@{menu-prefix-cls}-inline-collapsed &-arrow,\n    &-inline &-arrow {\n      // ↓\n      &::before {\n        transform: rotate(-45deg) translateX(2.5px);\n      }\n\n      &::after {\n        transform: rotate(45deg) translateX(-2.5px);\n      }\n    }\n\n    &-horizontal &-arrow {\n      display: none;\n    }\n\n    &-open&-inline > &-title > &-arrow {\n      // ↑\n      transform: translateY(-2px);\n\n      &::after {\n        transform: rotate(-45deg) translateX(-2.5px);\n      }\n\n      &::before {\n        transform: rotate(45deg) translateX(2.5px);\n      }\n    }\n  }\n\n  &-vertical &-submenu-selected,\n  &-vertical-left &-submenu-selected,\n  &-vertical-right &-submenu-selected {\n    color: @menu-highlight-color;\n  }\n\n  &-horizontal {\n    line-height: @menu-horizontal-line-height;\n    border: 0;\n    border-bottom: @border-width-base @border-style-base @border-color-split;\n    box-shadow: none;\n\n    &:not(.@{menu-prefix-cls}-dark) {\n      > .@{menu-prefix-cls}-item,\n      > .@{menu-prefix-cls}-submenu {\n        margin-top: -1px;\n        margin-bottom: 0;\n        padding: @menu-item-padding;\n\n        &:hover,\n        &-active,\n        &-open,\n        &-selected {\n          color: @menu-highlight-color;\n\n          &::after {\n            border-bottom: 2px solid @menu-highlight-color;\n          }\n        }\n      }\n    }\n\n    > .@{menu-prefix-cls}-item,\n    > .@{menu-prefix-cls}-submenu {\n      position: relative;\n      top: 1px;\n      display: inline-block;\n      vertical-align: bottom;\n\n      &::after {\n        position: absolute;\n        right: @menu-item-padding-horizontal;\n        bottom: 0;\n        left: @menu-item-padding-horizontal;\n        border-bottom: 2px solid transparent;\n        transition: border-color @animation-duration-slow @ease-in-out;\n        content: '';\n      }\n    }\n\n    > .@{menu-prefix-cls}-submenu > .@{menu-prefix-cls}-submenu-title {\n      padding: 0;\n    }\n\n    > .@{menu-prefix-cls}-item {\n      a {\n        color: @menu-item-color;\n\n        &:hover {\n          color: @menu-highlight-color;\n        }\n\n        &::before {\n          bottom: -2px;\n        }\n      }\n\n      &-selected a {\n        color: @menu-highlight-color;\n      }\n    }\n\n    &::after {\n      display: block;\n      clear: both;\n      height: 0;\n      content: '\\20';\n    }\n  }\n\n  &-vertical,\n  &-vertical-left,\n  &-vertical-right,\n  &-inline {\n    .@{menu-prefix-cls}-item {\n      position: relative;\n\n      &::after {\n        position: absolute;\n        top: 0;\n        right: 0;\n        bottom: 0;\n        border-right: @menu-item-active-border-width solid @menu-highlight-color;\n        transform: scaleY(0.0001);\n        opacity: 0;\n        transition: transform @menu-animation-duration-normal @ease-out,\n          opacity @menu-animation-duration-normal @ease-out;\n        content: '';\n      }\n    }\n\n    .@{menu-prefix-cls}-item,\n    .@{menu-prefix-cls}-submenu-title {\n      height: @menu-item-height;\n      margin-top: @menu-item-vertical-margin;\n      margin-bottom: @menu-item-vertical-margin;\n      padding: 0 16px;\n      overflow: hidden;\n      line-height: @menu-item-height;\n      text-overflow: ellipsis;\n    }\n\n    // disable margin collapsed\n    .@{menu-prefix-cls}-submenu {\n      padding-bottom: 0.02px;\n    }\n\n    .@{menu-prefix-cls}-item:not(:last-child) {\n      margin-bottom: @menu-item-boundary-margin;\n    }\n\n    > .@{menu-prefix-cls}-item,\n    > .@{menu-prefix-cls}-submenu > .@{menu-prefix-cls}-submenu-title {\n      height: @menu-inline-toplevel-item-height;\n      line-height: @menu-inline-toplevel-item-height;\n    }\n  }\n\n  &-vertical {\n    .@{menu-prefix-cls}-item-group-list .@{menu-prefix-cls}-submenu-title,\n    .@{menu-prefix-cls}-submenu-title {\n      padding-right: 34px;\n    }\n  }\n\n  &-inline {\n    width: 100%;\n    .@{menu-prefix-cls}-selected,\n    .@{menu-prefix-cls}-item-selected {\n      &::after {\n        transform: scaleY(1);\n        opacity: 1;\n        transition: transform @menu-animation-duration-normal @ease-in-out,\n          opacity @menu-animation-duration-normal @ease-in-out;\n      }\n    }\n\n    .@{menu-prefix-cls}-item,\n    .@{menu-prefix-cls}-submenu-title {\n      width: ~'calc(100% + 1px)';\n    }\n\n    .@{menu-prefix-cls}-item-group-list .@{menu-prefix-cls}-submenu-title,\n    .@{menu-prefix-cls}-submenu-title {\n      padding-right: 34px;\n    }\n\n    // Motion enhance for first level\n    &.@{menu-prefix-cls}-root {\n      .@{menu-prefix-cls}-item,\n      .@{menu-prefix-cls}-submenu-title {\n        display: flex;\n        align-items: center;\n        transition: border-color @animation-duration-slow, background @animation-duration-slow,\n          padding 0.1s @ease-out;\n\n        > .@{menu-prefix-cls}-title-content {\n          flex: auto;\n          min-width: 0;\n          overflow: hidden;\n          text-overflow: ellipsis;\n        }\n\n        > * {\n          flex: none;\n        }\n      }\n    }\n  }\n\n  &&-inline-collapsed {\n    width: @menu-collapsed-width;\n\n    > .@{menu-prefix-cls}-item,\n    > .@{menu-prefix-cls}-item-group\n      > .@{menu-prefix-cls}-item-group-list\n      > .@{menu-prefix-cls}-item,\n    > .@{menu-prefix-cls}-item-group\n      > .@{menu-prefix-cls}-item-group-list\n      > .@{menu-prefix-cls}-submenu\n      > .@{menu-prefix-cls}-submenu-title,\n    > .@{menu-prefix-cls}-submenu > .@{menu-prefix-cls}-submenu-title {\n      left: 0;\n      padding: 0 ~'calc(50% - @{menu-icon-size-lg} / 2)';\n      text-overflow: clip;\n\n      .@{menu-prefix-cls}-submenu-arrow {\n        opacity: 0;\n      }\n\n      .@{menu-prefix-cls}-item-icon,\n      .@{iconfont-css-prefix} {\n        margin: 0;\n        font-size: @menu-icon-size-lg;\n        line-height: @menu-item-height;\n\n        + span {\n          display: inline-block;\n          opacity: 0;\n        }\n      }\n    }\n\n    .@{menu-prefix-cls}-item-icon,\n    .@{iconfont-css-prefix} {\n      display: inline-block;\n    }\n\n    &-tooltip {\n      pointer-events: none;\n\n      .@{menu-prefix-cls}-item-icon,\n      .@{iconfont-css-prefix} {\n        display: none;\n      }\n\n      a {\n        color: @text-color-dark;\n      }\n    }\n\n    .@{menu-prefix-cls}-item-group-title {\n      padding-right: 4px;\n      padding-left: 4px;\n      overflow: hidden;\n      white-space: nowrap;\n      text-overflow: ellipsis;\n    }\n  }\n\n  &-item-group-list {\n    margin: 0;\n    padding: 0;\n    .@{menu-prefix-cls}-item,\n    .@{menu-prefix-cls}-submenu-title {\n      padding: 0 16px 0 28px;\n    }\n  }\n\n  &-root&-vertical,\n  &-root&-vertical-left,\n  &-root&-vertical-right,\n  &-root&-inline {\n    box-shadow: none;\n  }\n\n  &-root&-inline-collapsed {\n    .@{menu-prefix-cls}-item,\n    .@{menu-prefix-cls}-submenu .@{menu-prefix-cls}-submenu-title {\n      > .@{menu-prefix-cls}-inline-collapsed-noicon {\n        font-size: @menu-icon-size-lg;\n        text-align: center;\n      }\n    }\n  }\n\n  &-sub&-inline {\n    padding: 0;\n    background: @menu-inline-submenu-bg;\n    border: 0;\n    border-radius: 0;\n    box-shadow: none;\n    & > .@{menu-prefix-cls}-item,\n    & > .@{menu-prefix-cls}-submenu > .@{menu-prefix-cls}-submenu-title {\n      height: @menu-item-height;\n      line-height: @menu-item-height;\n      list-style-position: inside;\n      list-style-type: disc;\n    }\n\n    & .@{menu-prefix-cls}-item-group-title {\n      padding-left: 32px;\n    }\n  }\n\n  // Disabled state sets text to gray and nukes hover/tab effects\n  &-item-disabled,\n  &-submenu-disabled {\n    color: @disabled-color !important;\n    background: none;\n    cursor: not-allowed;\n\n    &::after {\n      border-color: transparent !important;\n    }\n\n    a {\n      color: @disabled-color !important;\n      pointer-events: none;\n    }\n\n    > .@{menu-prefix-cls}-submenu-title {\n      color: @disabled-color !important;\n      cursor: not-allowed;\n      > .@{menu-prefix-cls}-submenu-arrow {\n        &::before,\n        &::after {\n          background: @disabled-color !important;\n        }\n      }\n    }\n  }\n}\n\n// Integration with header element so menu items have the same height\n.@{ant-prefix}-layout-header {\n  .@{menu-prefix-cls} {\n    line-height: inherit;\n  }\n}\n\n// https://github.com/ant-design/ant-design/issues/32950\n.@{ant-prefix}-menu-inline-collapsed-tooltip {\n  a,\n  a:hover {\n    color: @white;\n  }\n}\n\n@import './light';\n@import './dark';\n@import './rtl';\n"
  },
  {
    "path": "components/menu/style/light.less",
    "content": ".@{menu-prefix-cls} {\n  // light theme\n  &-light {\n    .@{menu-prefix-cls}-item:hover,\n    .@{menu-prefix-cls}-item-active,\n    .@{menu-prefix-cls}:not(.@{menu-prefix-cls}-inline) .@{menu-prefix-cls}-submenu-open,\n    .@{menu-prefix-cls}-submenu-active,\n    .@{menu-prefix-cls}-submenu-title:hover {\n      color: @menu-highlight-color;\n    }\n  }\n}\n"
  },
  {
    "path": "components/menu/style/patch.less",
    "content": ".ant-menu-submenu.ant-menu-submenu-placement-bottom {\n  position: relative;\n  top: 6px;\n}\n\n.ant-menu-submenu.ant-menu-submenu-placement-right {\n  position: relative;\n  left: 4px;\n\n  &.ant-menu-submenu-rtl {\n    right: 4px;\n    left: auto;\n  }\n}\n\n.ant-menu-submenu.ant-menu-submenu-placement-left {\n  position: relative;\n  right: 4px;\n\n  &.ant-menu-submenu-rtl {\n    right: auto;\n    left: 4px;\n  }\n}\n"
  },
  {
    "path": "components/menu/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@menu-prefix-cls: ~'@{ant-prefix}-menu';\n\n.@{menu-prefix-cls} {\n  &&-rtl {\n    direction: rtl;\n    text-align: right;\n  }\n\n  &-item-group-title {\n    .@{menu-prefix-cls}-rtl & {\n      text-align: right;\n    }\n  }\n\n  &-inline,\n  &-vertical {\n    .@{menu-prefix-cls}-rtl& {\n      border-right: none;\n      border-left: @border-width-base @border-style-base @border-color-split;\n    }\n  }\n\n  &-dark&-inline,\n  &-dark&-vertical {\n    .@{menu-prefix-cls}-rtl& {\n      border-left: none;\n    }\n  }\n\n  &-vertical&-sub,\n  &-vertical-left&-sub,\n  &-vertical-right&-sub {\n    > .@{menu-prefix-cls}-item,\n    > .@{menu-prefix-cls}-submenu {\n      .@{menu-prefix-cls}-rtl& {\n        transform-origin: top right;\n      }\n    }\n  }\n\n  &-item,\n  &-submenu-title {\n    .@{menu-prefix-cls}-item-icon,\n    .@{iconfont-css-prefix} {\n      .@{menu-prefix-cls}-rtl & {\n        margin-right: auto;\n        margin-left: @menu-icon-margin-right;\n      }\n    }\n\n    &.@{menu-prefix-cls}-item-only-child {\n      > .@{menu-prefix-cls}-item-icon,\n      > .@{iconfont-css-prefix} {\n        .@{menu-prefix-cls}-rtl & {\n          margin-left: 0;\n        }\n      }\n    }\n  }\n\n  &-submenu {\n    &-rtl.@{menu-prefix-cls}-submenu-popup {\n      transform-origin: 100% 0;\n    }\n\n    &-vertical,\n    &-vertical-left,\n    &-vertical-right,\n    &-inline {\n      > .@{menu-prefix-cls}-submenu-title .@{menu-prefix-cls}-submenu-arrow {\n        .@{menu-prefix-cls}-rtl & {\n          right: auto;\n          left: 16px;\n        }\n      }\n    }\n\n    &-vertical,\n    &-vertical-left,\n    &-vertical-right {\n      > .@{menu-prefix-cls}-submenu-title .@{menu-prefix-cls}-submenu-arrow {\n        &::before {\n          .@{menu-prefix-cls}-rtl & {\n            transform: rotate(-45deg) translateY(-2px);\n          }\n        }\n\n        &::after {\n          .@{menu-prefix-cls}-rtl & {\n            transform: rotate(45deg) translateY(2px);\n          }\n        }\n      }\n    }\n  }\n\n  &-vertical,\n  &-vertical-left,\n  &-vertical-right,\n  &-inline {\n    .@{menu-prefix-cls}-item {\n      &::after {\n        .@{menu-prefix-cls}-rtl& {\n          right: auto;\n          left: 0;\n        }\n      }\n    }\n\n    .@{menu-prefix-cls}-item,\n    .@{menu-prefix-cls}-submenu-title {\n      .@{menu-prefix-cls}-rtl& {\n        text-align: right;\n      }\n    }\n  }\n\n  &-inline {\n    .@{menu-prefix-cls}-submenu-title {\n      .@{menu-prefix-cls}-rtl& {\n        padding-right: 0;\n        padding-left: 34px;\n      }\n    }\n  }\n\n  &-vertical {\n    .@{menu-prefix-cls}-submenu-title {\n      .@{menu-prefix-cls}-rtl& {\n        padding-right: 16px;\n        padding-left: 34px;\n      }\n    }\n  }\n\n  &-inline-collapsed&-vertical {\n    .@{menu-prefix-cls}-submenu-title {\n      .@{menu-prefix-cls}-rtl& {\n        padding: 0 ~'calc(50% - @{menu-icon-size-lg} / 2)';\n      }\n    }\n  }\n\n  &-item-group-list {\n    .@{menu-prefix-cls}-item,\n    .@{menu-prefix-cls}-submenu-title {\n      .@{menu-prefix-cls}-rtl & {\n        padding: 0 28px 0 16px;\n      }\n    }\n  }\n\n  &-sub&-inline {\n    border: 0;\n    & .@{menu-prefix-cls}-item-group-title {\n      .@{menu-prefix-cls}-rtl& {\n        padding-right: 32px;\n        padding-left: 0;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/menu/style/status.less",
    "content": "@import (reference) '../../style/themes/index';\n@menu-prefix-cls: ~'@{ant-prefix}-menu';\n\n.@{menu-prefix-cls} {\n  // Danger\n  &-item-danger&-item {\n    color: @menu-highlight-danger-color;\n\n    &:hover,\n    &-active {\n      color: @menu-highlight-danger-color;\n    }\n\n    &:active {\n      background: @menu-item-active-danger-bg;\n    }\n\n    &-selected {\n      color: @menu-highlight-danger-color;\n\n      > a,\n      > a:hover {\n        color: @menu-highlight-danger-color;\n      }\n    }\n\n    .@{menu-prefix-cls}:not(.@{menu-prefix-cls}-horizontal) &-selected {\n      background-color: @menu-item-active-danger-bg;\n    }\n\n    .@{menu-prefix-cls}-inline &::after {\n      border-right-color: @menu-highlight-danger-color;\n    }\n  }\n\n  // ==================== Dark ====================\n  &-dark &-item-danger&-item {\n    &,\n    &:hover,\n    & > a {\n      color: @menu-dark-danger-color;\n    }\n  }\n\n  &-dark&-dark:not(&-horizontal) &-item-danger&-item-selected {\n    color: @menu-dark-highlight-color;\n    background-color: @menu-dark-item-active-danger-bg;\n  }\n}\n"
  },
  {
    "path": "components/menu/submenu-inline-child.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { ChangeDetectionStrategy, Component, computed, inject, input, ViewEncapsulation } from '@angular/core';\n\nimport { NzAnimationCollapseDirective } from 'ng-zorro-antd/core/animation';\nimport { generateClassName, getClassListFromValue } from 'ng-zorro-antd/core/util';\n\nconst MENU_PREFIX = 'ant-menu';\n\n@Component({\n  selector: '[nz-submenu-inline-child]',\n  exportAs: 'nzSubmenuInlineChild',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `<ng-content />`,\n  hostDirectives: [\n    {\n      directive: NzAnimationCollapseDirective,\n      inputs: ['open', 'leavedClassName']\n    }\n  ],\n  host: {\n    '[class]': 'mergedClass()'\n  }\n})\nexport class NzSubmenuInlineChildComponent {\n  protected readonly dir = inject(Directionality).valueSignal;\n\n  readonly menuClass = input<string>('');\n  readonly open = input(false);\n  readonly leavedClassName = input(generateClassName(MENU_PREFIX, 'submenu-hidden'));\n\n  protected readonly mergedClass = computed(() => {\n    const customCls = getClassListFromValue(this.menuClass()) || [];\n    const cls = [\n      MENU_PREFIX,\n      generateClassName(MENU_PREFIX, 'inline'),\n      generateClassName(MENU_PREFIX, 'sub'),\n      ...customCls\n    ];\n    if (this.dir() === 'rtl') {\n      cls.push(generateClassName(MENU_PREFIX, 'rtl'));\n    }\n    return cls;\n  });\n}\n"
  },
  {
    "path": "components/menu/submenu-non-inline-child.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { ChangeDetectionStrategy, Component, computed, inject, input, output, ViewEncapsulation } from '@angular/core';\n\nimport { SLIDE_ANIMATION_CLASS, withAnimationCheck } from 'ng-zorro-antd/core/animation';\nimport { generateClassName, getClassListFromValue } from 'ng-zorro-antd/core/util';\n\nimport { NzIsMenuInsideDropdownToken } from './menu.token';\nimport { NzMenuThemeType, NzSubmenuTrigger } from './menu.types';\n\nconst ANT_PREFIX = 'ant';\nconst MENU_PREFIX = `${ANT_PREFIX}-menu`;\nconst SUBMENU_PREFIX = `${MENU_PREFIX}-submenu`;\nconst DROPDOWN_PREFIX = `${ANT_PREFIX}-dropdown`;\nconst ANIMATION_PREFIX = `${ANT_PREFIX}-zoom-big`;\n\nconst ANIMATION_CLASS = {\n  vertical: {\n    enter: `${ANIMATION_PREFIX}-enter ${ANIMATION_PREFIX}-enter-active`,\n    leave: `${ANIMATION_PREFIX}-leave ${ANIMATION_PREFIX}-leave-active`\n  },\n  horizontal: SLIDE_ANIMATION_CLASS\n};\n\n@Component({\n  selector: '[nz-submenu-none-inline-child]',\n  exportAs: 'nzSubmenuNoneInlineChild',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    <div [class]=\"mergedMenuClass()\">\n      <ng-content />\n    </div>\n  `,\n  host: {\n    '[class]': 'submenuClass()',\n    '(mouseenter)': 'setMouseState(true)',\n    '(mouseleave)': 'setMouseState(false)',\n    '[animate.enter]': `animationEnter()`,\n    '[animate.leave]': `animationLeave()`\n  }\n})\nexport class NzSubmenuNoneInlineChildComponent {\n  protected readonly isMenuInsideDropdown = inject(NzIsMenuInsideDropdownToken);\n  protected readonly dir = inject(Directionality).valueSignal;\n\n  readonly menuClass = input<string>('');\n  readonly theme = input<NzMenuThemeType>('light');\n  readonly mode = input<'vertical' | 'horizontal'>('vertical');\n  readonly position = input<'right' | 'left'>('right');\n  readonly open = input<boolean>(false);\n  readonly nzDisabled = input<boolean>(false);\n  readonly nzTriggerSubMenuAction = input<NzSubmenuTrigger>('hover');\n  readonly subMenuMouseState = output<boolean>();\n\n  protected readonly animationEnter = withAnimationCheck(() => ANIMATION_CLASS[this.mode()].enter);\n  protected readonly animationLeave = withAnimationCheck(() => ANIMATION_CLASS[this.mode()].leave);\n\n  protected readonly submenuClass = computed(() => {\n    const cls = [\n      SUBMENU_PREFIX,\n      generateClassName(SUBMENU_PREFIX, 'popup'),\n      generateClassName(MENU_PREFIX, this.theme() === 'dark' ? 'dark' : 'light')\n    ];\n\n    const mode = this.mode();\n    const position = this.position() === 'left' ? 'left' : 'right';\n    if (mode === 'horizontal') {\n      cls.push(generateClassName(SUBMENU_PREFIX, 'placement-bottom'));\n    } else if (mode === 'vertical') {\n      cls.push(generateClassName(SUBMENU_PREFIX, `placement-${position}`));\n    }\n\n    if (this.dir() === 'rtl') {\n      cls.push(generateClassName(SUBMENU_PREFIX, 'rtl'));\n    }\n    return cls;\n  });\n\n  protected readonly mergedMenuClass = computed(() => {\n    const cls = getClassListFromValue(this.menuClass()) || [];\n    if (this.isMenuInsideDropdown) {\n      cls.push(\n        generateClassName(DROPDOWN_PREFIX, 'menu'),\n        generateClassName(DROPDOWN_PREFIX, 'menu-sub'),\n        generateClassName(DROPDOWN_PREFIX, 'menu-vertical')\n      );\n    } else {\n      cls.push(MENU_PREFIX, generateClassName(MENU_PREFIX, 'sub'), generateClassName(MENU_PREFIX, 'vertical'));\n    }\n\n    if (this.dir() === 'rtl') {\n      cls.push(generateClassName(MENU_PREFIX, 'rtl'));\n    }\n    return cls;\n  });\n\n  protected setMouseState(state: boolean): void {\n    if (!this.nzDisabled() && this.nzTriggerSubMenuAction() === 'hover') {\n      this.subMenuMouseState.emit(state);\n    }\n  }\n}\n"
  },
  {
    "path": "components/menu/submenu-title.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  EventEmitter,\n  inject,\n  Input,\n  Output,\n  TemplateRef,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nimport { NzIsMenuInsideDropdownToken } from './menu.token';\nimport { NzMenuModeType, NzSubmenuTrigger } from './menu.types';\n\n@Component({\n  selector: '[nz-submenu-title]',\n  exportAs: 'nzSubmenuTitle',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    @if (nzIcon) {\n      <nz-icon [nzType]=\"nzIcon\" />\n    }\n    <ng-container *nzStringTemplateOutlet=\"nzTitle\">\n      <span class=\"ant-menu-title-content\">{{ nzTitle }}</span>\n    </ng-container>\n    <ng-content />\n    @if (isMenuInsideDropdown) {\n      <span class=\"ant-dropdown-menu-submenu-expand-icon\">\n        <nz-icon [nzType]=\"dir() === 'rtl' ? 'left' : 'right'\" class=\"ant-dropdown-menu-submenu-arrow-icon\" />\n      </span>\n    } @else {\n      <span class=\"ant-menu-submenu-arrow\"></span>\n    }\n  `,\n  host: {\n    '[class.ant-dropdown-menu-submenu-title]': 'isMenuInsideDropdown',\n    '[class.ant-menu-submenu-title]': '!isMenuInsideDropdown',\n    '[style.padding-inline-start.px]': 'paddingLeft',\n    '(click)': 'clickTitle()',\n    '(mouseenter)': 'setMouseState(true)',\n    '(mouseleave)': 'setMouseState(false)'\n  },\n  imports: [NzIconModule, NzOutletModule]\n})\nexport class NzSubMenuTitleComponent {\n  protected readonly isMenuInsideDropdown = inject(NzIsMenuInsideDropdownToken);\n  protected readonly dir = inject(Directionality).valueSignal;\n\n  @Input() nzIcon: string | null = null;\n  @Input() nzTitle: string | TemplateRef<void> | null = null;\n  @Input() nzDisabled = false;\n  @Input() paddingLeft: number | null = null;\n  @Input() mode: NzMenuModeType = 'vertical';\n  @Input() nzTriggerSubMenuAction: NzSubmenuTrigger = 'hover';\n  @Output() readonly toggleSubMenu = new EventEmitter();\n  @Output() readonly subMenuMouseState = new EventEmitter<boolean>();\n\n  protected setMouseState(state: boolean): void {\n    if (!this.nzDisabled && this.nzTriggerSubMenuAction === 'hover') {\n      this.subMenuMouseState.next(state);\n    }\n  }\n\n  protected clickTitle(): void {\n    if ((this.mode === 'inline' || this.nzTriggerSubMenuAction === 'click') && !this.nzDisabled) {\n      this.subMenuMouseState.next(true);\n      this.toggleSubMenu.emit();\n    }\n  }\n}\n"
  },
  {
    "path": "components/menu/submenu.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { CdkOverlayOrigin, ConnectedOverlayPositionChange, OverlayModule } from '@angular/cdk/overlay';\nimport { Platform } from '@angular/cdk/platform';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterContentInit,\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ContentChildren,\n  DestroyRef,\n  ElementRef,\n  EventEmitter,\n  forwardRef,\n  inject,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  QueryList,\n  SimpleChanges,\n  TemplateRef,\n  ViewChild,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { combineLatest, merge } from 'rxjs';\nimport { map, startWith, switchMap } from 'rxjs/operators';\n\nimport { NzNoAnimationDirective } from 'ng-zorro-antd/core/animation';\nimport { getPlacementName, POSITION_MAP, POSITION_TYPE_HORIZONTAL } from 'ng-zorro-antd/core/overlay';\n\nimport { NzMenuItemComponent } from './menu-item.component';\nimport { MenuService } from './menu.service';\nimport { NzIsMenuInsideDropdownToken } from './menu.token';\nimport { NzMenuModeType, NzMenuThemeType, NzSubmenuTrigger } from './menu.types';\nimport { NzSubmenuInlineChildComponent } from './submenu-inline-child.component';\nimport { NzSubmenuNoneInlineChildComponent } from './submenu-non-inline-child.component';\nimport { NzSubMenuTitleComponent } from './submenu-title.component';\nimport { NzSubmenuService } from './submenu.service';\n\nconst listOfVerticalPositions = [\n  POSITION_MAP.rightTop,\n  POSITION_MAP.right,\n  POSITION_MAP.rightBottom,\n  POSITION_MAP.leftTop,\n  POSITION_MAP.left,\n  POSITION_MAP.leftBottom\n];\nconst listOfHorizontalPositions = [\n  POSITION_MAP.bottomLeft,\n  POSITION_MAP.bottomRight,\n  POSITION_MAP.topRight,\n  POSITION_MAP.topLeft\n];\n\n@Component({\n  selector: '[nz-submenu]',\n  exportAs: 'nzSubmenu',\n  providers: [NzSubmenuService],\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    <div\n      nz-submenu-title\n      cdkOverlayOrigin\n      #origin=\"cdkOverlayOrigin\"\n      [nzIcon]=\"nzIcon\"\n      [nzTitle]=\"nzTitle\"\n      [mode]=\"mode\"\n      [nzDisabled]=\"nzDisabled\"\n      [paddingLeft]=\"nzPaddingLeft || inlinePaddingLeft\"\n      [nzTriggerSubMenuAction]=\"nzTriggerSubMenuAction\"\n      (subMenuMouseState)=\"setMouseEnterState($event)\"\n      (toggleSubMenu)=\"toggleSubMenu()\"\n    >\n      @if (!nzTitle) {\n        <ng-content select=\"[title]\" />\n      }\n    </div>\n    @if (mode === 'inline') {\n      <div\n        nz-submenu-inline-child\n        [open]=\"nzOpen\"\n        [menuClass]=\"nzMenuClassName\"\n        leavedClassName=\"ant-menu-submenu-hidden\"\n      >\n        <ng-template [ngTemplateOutlet]=\"subMenuTemplate\" />\n      </div>\n    } @else {\n      <ng-template\n        cdkConnectedOverlay\n        (positionChange)=\"onPositionChange($event)\"\n        [cdkConnectedOverlayPositions]=\"overlayPositions\"\n        [cdkConnectedOverlayOrigin]=\"origin\"\n        [cdkConnectedOverlayWidth]=\"triggerWidth!\"\n        [cdkConnectedOverlayOpen]=\"nzOpen\"\n        cdkConnectedOverlayTransformOriginOn=\".ant-menu-submenu\"\n        (overlayOutsideClick)=\"setMouseEnterState(false)\"\n      >\n        <div\n          nz-submenu-none-inline-child\n          [theme]=\"theme\"\n          [mode]=\"mode\"\n          [open]=\"nzOpen\"\n          [position]=\"position\"\n          [menuClass]=\"nzMenuClassName\"\n          [nzDisabled]=\"nzDisabled\"\n          [nzTriggerSubMenuAction]=\"nzTriggerSubMenuAction\"\n          [nzNoAnimation]=\"noAnimation?.nzNoAnimation?.()\"\n          (subMenuMouseState)=\"setMouseEnterState($event)\"\n        >\n          <ng-template [ngTemplateOutlet]=\"subMenuTemplate\" />\n        </div>\n      </ng-template>\n    }\n\n    <ng-template #subMenuTemplate>\n      <ng-content />\n    </ng-template>\n  `,\n  host: {\n    '[class.ant-dropdown-menu-submenu]': `isMenuInsideDropdown`,\n    '[class.ant-dropdown-menu-submenu-disabled]': `isMenuInsideDropdown && nzDisabled`,\n    '[class.ant-dropdown-menu-submenu-open]': `isMenuInsideDropdown && nzOpen`,\n    '[class.ant-dropdown-menu-submenu-selected]': `isMenuInsideDropdown && isSelected`,\n    '[class.ant-dropdown-menu-submenu-vertical]': `isMenuInsideDropdown && mode === 'vertical'`,\n    '[class.ant-dropdown-menu-submenu-horizontal]': `isMenuInsideDropdown && mode === 'horizontal'`,\n    '[class.ant-dropdown-menu-submenu-inline]': `isMenuInsideDropdown && mode === 'inline'`,\n    '[class.ant-dropdown-menu-submenu-active]': `isMenuInsideDropdown && isActive`,\n    '[class.ant-menu-submenu]': `!isMenuInsideDropdown`,\n    '[class.ant-menu-submenu-disabled]': `!isMenuInsideDropdown && nzDisabled`,\n    '[class.ant-menu-submenu-open]': `!isMenuInsideDropdown && nzOpen`,\n    '[class.ant-menu-submenu-selected]': `!isMenuInsideDropdown && isSelected`,\n    '[class.ant-menu-submenu-vertical]': `!isMenuInsideDropdown && mode === 'vertical'`,\n    '[class.ant-menu-submenu-horizontal]': `!isMenuInsideDropdown && mode === 'horizontal'`,\n    '[class.ant-menu-submenu-inline]': `!isMenuInsideDropdown && mode === 'inline'`,\n    '[class.ant-menu-submenu-active]': `!isMenuInsideDropdown && isActive`,\n    '[class.ant-menu-submenu-rtl]': `dir() === 'rtl'`\n  },\n  imports: [\n    NgTemplateOutlet,\n    NzSubMenuTitleComponent,\n    NzSubmenuInlineChildComponent,\n    NzNoAnimationDirective,\n    NzSubmenuNoneInlineChildComponent,\n    OverlayModule\n  ]\n})\nexport class NzSubMenuComponent implements OnInit, AfterContentInit, OnChanges {\n  public readonly nzSubmenuService = inject(NzSubmenuService);\n  protected readonly isMenuInsideDropdown = inject(NzIsMenuInsideDropdownToken);\n  protected readonly noAnimation = inject(NzNoAnimationDirective, { optional: true, host: true });\n  protected readonly dir = inject(Directionality).valueSignal;\n  private readonly destroyRef = inject(DestroyRef);\n  private readonly nzMenuService = inject(MenuService);\n  private readonly cdr = inject(ChangeDetectorRef);\n  private readonly platform = inject(Platform);\n\n  @Input() nzMenuClassName: string = '';\n  @Input() nzPaddingLeft: number | null = null;\n  @Input() nzTitle: string | TemplateRef<void> | null = null;\n  @Input() nzIcon: string | null = null;\n  @Input() nzTriggerSubMenuAction: NzSubmenuTrigger = 'hover';\n  @Input({ transform: booleanAttribute }) nzOpen = false;\n  @Input({ transform: booleanAttribute }) nzDisabled = false;\n  @Input() nzPlacement: POSITION_TYPE_HORIZONTAL = 'bottomLeft';\n  @Output() readonly nzOpenChange = new EventEmitter<boolean>();\n  @ViewChild(CdkOverlayOrigin, { static: true, read: ElementRef }) cdkOverlayOrigin: ElementRef | null = null;\n  // fix errors about circular dependency\n  // Can't construct a query for the property ... since the query selector wasn't defined\n  @ContentChildren(forwardRef(() => NzSubMenuComponent), { descendants: true })\n  listOfNzSubMenuComponent: QueryList<NzSubMenuComponent> | null = null;\n  @ContentChildren(NzMenuItemComponent, { descendants: true })\n  listOfNzMenuItemDirective: QueryList<NzMenuItemComponent> | null = null;\n\n  private level = this.nzSubmenuService.level;\n  position: 'left' | 'right' = 'right';\n  triggerWidth: number | null = null;\n  theme: NzMenuThemeType = 'light';\n  mode: NzMenuModeType = 'vertical';\n  inlinePaddingLeft: number | null = null;\n  overlayPositions = listOfVerticalPositions;\n  isSelected = false;\n  isActive = false;\n\n  /** set the submenu host open status directly **/\n  setOpenStateWithoutDebounce(open: boolean): void {\n    this.nzSubmenuService.setOpenStateWithoutDebounce(open);\n  }\n\n  toggleSubMenu(): void {\n    this.setOpenStateWithoutDebounce(!this.nzOpen);\n  }\n\n  setMouseEnterState(value: boolean): void {\n    this.isActive = value;\n    if (this.mode !== 'inline') {\n      this.nzSubmenuService.setMouseEnterTitleOrOverlayState(value);\n    }\n  }\n\n  setTriggerWidth(): void {\n    if (\n      this.mode === 'horizontal' &&\n      this.platform.isBrowser &&\n      this.cdkOverlayOrigin &&\n      this.nzPlacement === 'bottomLeft'\n    ) {\n      /** TODO: fast dom */\n      this.triggerWidth = this.cdkOverlayOrigin!.nativeElement.getBoundingClientRect().width;\n    }\n  }\n\n  onPositionChange(position: ConnectedOverlayPositionChange): void {\n    const placement = getPlacementName(position);\n    if (placement === 'rightTop' || placement === 'rightBottom' || placement === 'right') {\n      this.position = 'right';\n    } else if (placement === 'leftTop' || placement === 'leftBottom' || placement === 'left') {\n      this.position = 'left';\n    }\n  }\n\n  ngOnInit(): void {\n    /** submenu theme update **/\n    this.nzMenuService.theme$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(theme => {\n      this.theme = theme;\n      this.cdr.markForCheck();\n    });\n\n    /** submenu mode update **/\n    this.nzSubmenuService.mode$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(mode => {\n      this.mode = mode;\n      if (mode === 'horizontal') {\n        this.overlayPositions = [POSITION_MAP[this.nzPlacement], ...listOfHorizontalPositions];\n      } else if (mode === 'vertical') {\n        this.overlayPositions = listOfVerticalPositions;\n      }\n      this.cdr.markForCheck();\n    });\n\n    /** inlineIndent update **/\n    combineLatest([this.nzSubmenuService.mode$, this.nzMenuService.inlineIndent$])\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(([mode, inlineIndent]) => {\n        this.inlinePaddingLeft = mode === 'inline' ? this.level * inlineIndent : null;\n        this.cdr.markForCheck();\n      });\n\n    /** current submenu open status **/\n    this.nzSubmenuService.isCurrentSubMenuOpen$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(open => {\n      this.isActive = open;\n      if (open !== this.nzOpen) {\n        this.setTriggerWidth();\n        this.nzOpen = open;\n        this.nzOpenChange.emit(this.nzOpen);\n        this.cdr.markForCheck();\n      }\n    });\n  }\n\n  ngAfterContentInit(): void {\n    this.setTriggerWidth();\n    const listOfNzMenuItemDirective = this.listOfNzMenuItemDirective;\n    const changes = listOfNzMenuItemDirective!.changes;\n    const mergedObservable = merge(changes, ...listOfNzMenuItemDirective!.map(menu => menu.selected$));\n    changes\n      .pipe(\n        startWith(listOfNzMenuItemDirective),\n        switchMap(() => mergedObservable),\n        startWith(true),\n        map(() => listOfNzMenuItemDirective!.some(e => e.nzSelected)),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(selected => {\n        this.isSelected = selected;\n        this.cdr.markForCheck();\n      });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzOpen } = changes;\n    if (nzOpen) {\n      this.nzSubmenuService.setOpenStateWithoutDebounce(this.nzOpen);\n      this.setTriggerWidth();\n    }\n  }\n}\n"
  },
  {
    "path": "components/menu/submenu.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Injectable, inject } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { BehaviorSubject, Observable, Subject, combineLatest, merge } from 'rxjs';\nimport { auditTime, distinctUntilChanged, filter, map, mergeMap } from 'rxjs/operators';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { MenuService } from './menu.service';\nimport { NzIsMenuInsideDropdownToken } from './menu.token';\nimport { NzMenuModeType } from './menu.types';\n\n@Injectable()\nexport class NzSubmenuService {\n  public readonly nzMenuService = inject(MenuService);\n  private readonly isMenuInsideDropdown = inject(NzIsMenuInsideDropdownToken);\n  private readonly nzHostSubmenuService = inject(NzSubmenuService, { optional: true, skipSelf: true });\n\n  mode$: Observable<NzMenuModeType> = this.nzMenuService.mode$.pipe(\n    map(mode => {\n      if (mode === 'inline') {\n        return 'inline';\n        /** if inside another submenu, set the mode to vertical **/\n      } else if (mode === 'vertical' || this.nzHostSubmenuService) {\n        return 'vertical';\n      } else {\n        return 'horizontal';\n      }\n    })\n  );\n  level = 1;\n  isCurrentSubMenuOpen$ = new BehaviorSubject<boolean>(false);\n  private isChildSubMenuOpen$ = new BehaviorSubject<boolean>(false);\n  /** submenu title & overlay mouse enter status **/\n  private isMouseEnterTitleOrOverlay$ = new Subject<boolean>();\n  private childMenuItemClick$ = new Subject<NzSafeAny>();\n  /**\n   * menu item inside submenu clicked\n   */\n  onChildMenuItemClick(menu: NzSafeAny): void {\n    this.childMenuItemClick$.next(menu);\n  }\n  setOpenStateWithoutDebounce(value: boolean): void {\n    this.isCurrentSubMenuOpen$.next(value);\n  }\n  setMouseEnterTitleOrOverlayState(value: boolean): void {\n    this.isMouseEnterTitleOrOverlay$.next(value);\n  }\n\n  constructor() {\n    if (this.nzHostSubmenuService) {\n      this.level = this.nzHostSubmenuService.level + 1;\n    }\n\n    /** close if menu item clicked **/\n    const isClosedByMenuItemClick = this.childMenuItemClick$.pipe(\n      mergeMap(() => this.mode$),\n      filter(mode => mode !== 'inline' || this.isMenuInsideDropdown),\n      map(() => false)\n    );\n    const isCurrentSubmenuOpen$ = merge(this.isMouseEnterTitleOrOverlay$, isClosedByMenuItemClick);\n    /** combine the child submenu status with current submenu status to calculate host submenu open **/\n    const isSubMenuOpenWithDebounce$ = combineLatest([this.isChildSubMenuOpen$, isCurrentSubmenuOpen$]).pipe(\n      map(([isChildSubMenuOpen, isCurrentSubmenuOpen]) => isChildSubMenuOpen || isCurrentSubmenuOpen),\n      auditTime(150)\n    );\n    isSubMenuOpenWithDebounce$.pipe(distinctUntilChanged(), takeUntilDestroyed()).subscribe(data => {\n      this.setOpenStateWithoutDebounce(data);\n      if (this.nzHostSubmenuService) {\n        /** set parent submenu's child submenu open status **/\n        this.nzHostSubmenuService.isChildSubMenuOpen$.next(data);\n      } else {\n        this.nzMenuService.isChildSubMenuOpen$.next(data);\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "components/message/base.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ComponentType,\n  createGlobalPositionStrategy,\n  createNoopScrollStrategy,\n  createOverlayRef\n} from '@angular/cdk/overlay';\nimport { ComponentPortal } from '@angular/cdk/portal';\nimport {\n  ChangeDetectorRef,\n  DestroyRef,\n  Directive,\n  ElementRef,\n  EventEmitter,\n  inject,\n  Injector,\n  OnInit,\n  Signal\n} from '@angular/core';\nimport { Subject } from 'rxjs';\n\nimport { MessageConfig, NzConfigService } from 'ng-zorro-antd/core/config';\nimport { NzSingletonService } from 'ng-zorro-antd/core/services';\n\nimport { NzMessageData, NzMessageDataOptions } from './typings';\n\nlet globalCounter = 0;\n\nexport abstract class NzMNService<T extends NzMNContainerComponent> {\n  protected abstract componentPrefix: string;\n  protected container?: T;\n  protected nzSingletonService = inject(NzSingletonService);\n  protected injector = inject(Injector);\n\n  remove(id?: string): void {\n    if (this.container) {\n      if (id) {\n        this.container.remove(id);\n      } else {\n        this.container.removeAll();\n      }\n    }\n  }\n\n  protected getInstanceId(): string {\n    return `${this.componentPrefix}-${globalCounter++}`;\n  }\n\n  protected withContainer(ctor: ComponentType<T>): T {\n    let containerInstance = this.nzSingletonService.getSingletonWithKey(this.componentPrefix);\n    if (containerInstance) {\n      return containerInstance as T;\n    }\n\n    const overlayRef = createOverlayRef(this.injector, {\n      hasBackdrop: false,\n      scrollStrategy: createNoopScrollStrategy(),\n      positionStrategy: createGlobalPositionStrategy(this.injector)\n    });\n    const componentPortal = new ComponentPortal(ctor, null, this.injector);\n    const componentRef = overlayRef.attach(componentPortal);\n    const overlayWrapper = overlayRef.hostElement;\n    overlayWrapper.style.zIndex = '1010';\n\n    if (!containerInstance) {\n      this.container = containerInstance = componentRef.instance;\n      this.nzSingletonService.registerSingletonWithKey(this.componentPrefix, containerInstance);\n      this.container.afterAllInstancesRemoved.subscribe(() => {\n        this.container = undefined;\n        this.nzSingletonService.unregisterSingletonWithKey(this.componentPrefix);\n        overlayRef.dispose();\n      });\n    }\n\n    return containerInstance as T;\n  }\n}\n\n@Directive()\nexport abstract class NzMNContainerComponent<\n  C extends MessageConfig = MessageConfig,\n  D extends NzMessageData = NzMessageData\n> {\n  config?: Required<C>;\n  instances: Array<Required<D>> = [];\n\n  private readonly _afterAllInstancesRemoved = new Subject<void>();\n\n  readonly afterAllInstancesRemoved = this._afterAllInstancesRemoved.asObservable();\n\n  protected cdr = inject(ChangeDetectorRef);\n  protected nzConfigService = inject(NzConfigService);\n\n  constructor() {\n    this.subscribeConfigChange();\n  }\n\n  create(data: D): Required<D> {\n    const instance = this.onCreate(data);\n\n    if (this.instances.length >= this.config!.nzMaxStack!) {\n      this.instances = this.instances.slice(1);\n    }\n\n    this.instances = [...this.instances, instance];\n\n    this.readyInstances();\n\n    return instance;\n  }\n\n  remove(id: string, userAction: boolean = false): void {\n    this.instances\n      .map((instance, index) => ({ index, instance }))\n      .filter(({ instance }) => instance.messageId === id)\n      .forEach(({ index, instance }) => {\n        this.instances.splice(index, 1);\n        this.instances = [...this.instances];\n        this.onRemove(instance, userAction);\n        this.readyInstances();\n      });\n\n    if (!this.instances.length) {\n      this.onAllInstancesRemoved();\n    }\n  }\n\n  removeAll(): void {\n    this.instances.forEach(i => this.onRemove(i, false));\n    this.instances = [];\n\n    this.readyInstances();\n    this.onAllInstancesRemoved();\n  }\n\n  protected onCreate(instance: D): Required<D> {\n    instance.options = this.mergeOptions(instance.options);\n    instance.onClose = new Subject<boolean>();\n    return instance as Required<D>;\n  }\n\n  protected onRemove(instance: Required<D>, userAction: boolean): void {\n    instance.onClose!.next(userAction);\n    instance.onClose!.complete();\n  }\n\n  private onAllInstancesRemoved(): void {\n    this._afterAllInstancesRemoved.next();\n    this._afterAllInstancesRemoved.complete();\n  }\n\n  protected readyInstances(): void {\n    this.cdr.detectChanges();\n  }\n\n  protected abstract subscribeConfigChange(): void;\n\n  protected mergeOptions(options?: D['options']): D['options'] {\n    const { nzDuration, nzAnimate, nzPauseOnHover } = this.config!;\n    return { nzDuration, nzAnimate, nzPauseOnHover, ...options };\n  }\n}\n\n@Directive()\nexport abstract class NzMNComponent implements OnInit {\n  abstract instance: Required<NzMessageData>;\n  abstract index?: number;\n  abstract destroyed: EventEmitter<{ id: string; userAction: boolean }>;\n\n  protected destroyRef = inject(DestroyRef);\n  protected elementRef = inject(ElementRef);\n\n  /**\n   * To get the element which triggers the animation.\n   */\n  protected abstract animationElement: Signal<ElementRef<HTMLElement>>;\n\n  /**\n   * When the animation is enabled, it is used to judge whether the leave animation is done or not.\n   * @note Keyframe of notification may have different keyframe names with individual placements, so use array here.\n   */\n  protected abstract _animationKeyframeMap: Record<'enter' | 'leave', string | string[]>;\n\n  /**\n   * The animation class map for enter and leave.\n   */\n  protected abstract _animationClassMap: Record<'enter' | 'leave', string>;\n\n  protected options!: Required<NzMessageDataOptions>;\n  protected autoClose?: boolean;\n  protected userAction: boolean = false;\n  protected eraseTimer?: ReturnType<typeof setTimeout>;\n  protected eraseTimingStart?: number;\n  protected eraseTTL!: number;\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      if (this.autoClose) {\n        this.clearEraseTimeout();\n      }\n    });\n  }\n\n  ngOnInit(): void {\n    this.options = this.instance.options as Required<NzMessageDataOptions>;\n\n    if (this.options.nzAnimate) {\n      // todo: remove this line in v22.0.0\n      this.instance.state = 'enter';\n      this._startEnterAnimation();\n    }\n\n    this.autoClose = this.options.nzDuration > 0;\n\n    if (this.autoClose) {\n      this.initErase();\n      this.startEraseTimeout();\n    }\n  }\n\n  onEnter(): void {\n    if (this.autoClose && this.options.nzPauseOnHover) {\n      this.clearEraseTimeout();\n      this.updateTTL();\n    }\n  }\n\n  onLeave(): void {\n    if (this.autoClose && this.options.nzPauseOnHover) {\n      this.startEraseTimeout();\n    }\n  }\n\n  protected destroy(userAction: boolean = false): void {\n    this.userAction = userAction;\n    if (this.options.nzAnimate) {\n      // todo: remove this line in v22.0.0\n      this.instance.state = 'leave';\n      this._startLeaveAnimation(() => this.destroyed.next({ id: this.instance.messageId, userAction }));\n    } else {\n      this.destroyed.next({ id: this.instance.messageId, userAction });\n    }\n  }\n\n  private initErase(): void {\n    this.eraseTTL = this.options.nzDuration;\n    this.eraseTimingStart = Date.now();\n  }\n\n  private updateTTL(): void {\n    if (this.autoClose) {\n      this.eraseTTL -= Date.now() - this.eraseTimingStart!;\n    }\n  }\n\n  private startEraseTimeout(): void {\n    if (this.eraseTTL > 0) {\n      this.clearEraseTimeout();\n      this.eraseTimer = setTimeout(() => this.destroy(), this.eraseTTL);\n      this.eraseTimingStart = Date.now();\n    } else {\n      this.destroy();\n    }\n  }\n\n  private clearEraseTimeout(): void {\n    if (this.eraseTimer !== null) {\n      clearTimeout(this.eraseTimer);\n      this.eraseTimer = undefined;\n    }\n  }\n\n  private _startEnterAnimation(): void {\n    const element = this.animationElement().nativeElement;\n    element.classList.add(this._animationClassMap.enter);\n\n    const onAnimationEnd = (event: AnimationEvent): void => {\n      if (this.matchAnimationKeyframe(event, this._animationKeyframeMap.enter)) {\n        element.removeEventListener('animationend', onAnimationEnd);\n        // should remove animation enter class once animation is done\n        element.classList.remove(this._animationClassMap.enter);\n      }\n    };\n\n    element.addEventListener('animationend', onAnimationEnd);\n  }\n\n  private _startLeaveAnimation(callback: () => void): void {\n    const element = this.animationElement().nativeElement;\n    element.classList.remove(this._animationClassMap.enter);\n    element.classList.add(this._animationClassMap.leave);\n\n    const onAnimationEnd = (event: AnimationEvent): void => {\n      if (this.matchAnimationKeyframe(event, this._animationKeyframeMap.leave)) {\n        element.removeEventListener('animationend', onAnimationEnd);\n        callback();\n      }\n    };\n\n    element.addEventListener('animationend', onAnimationEnd);\n  }\n\n  private matchAnimationKeyframe(event: AnimationEvent, animationName: string | string[]): boolean {\n    return typeof animationName === 'string'\n      ? event.animationName === animationName\n      : animationName.includes(event.animationName);\n  }\n}\n"
  },
  {
    "path": "components/message/demo/close.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 结束事件\n  en-US: Customize duration\n---\n\n## zh-CN\n\n可通过订阅 `onClose` 事件在 message 关闭时做出某些操作。以上用例将依次打开三个 message。\n\n## en-US\n\nYou can subscribe to `onClose` event to make some operations. This case would open three messages in sequence.\n"
  },
  {
    "path": "components/message/demo/close.ts",
    "content": "import { Component } from '@angular/core';\nimport { concatMap } from 'rxjs/operators';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzMessageService } from 'ng-zorro-antd/message';\n\n@Component({\n  selector: 'nz-demo-message-close',\n  imports: [NzButtonModule],\n  template: `<button nz-button nzType=\"default\" (click)=\"startShowMessages()\">Display a sequence of messages</button>`\n})\nexport class NzDemoMessageCloseComponent {\n  constructor(private message: NzMessageService) {}\n\n  startShowMessages(): void {\n    this.message\n      .loading('Action in progress', { nzDuration: 2500 })\n      .onClose!.pipe(\n        concatMap(() => this.message.success('Loading finished', { nzDuration: 2500 }).onClose!),\n        concatMap(() => this.message.info('Loading finished is finished', { nzDuration: 2500 }).onClose!)\n      )\n      .subscribe(() => {\n        console.log('All completed!');\n      });\n  }\n}\n"
  },
  {
    "path": "components/message/demo/custom-style.md",
    "content": "---\norder: 7\nversion: 20.4.0\ntitle:\n  zh-CN: 自定义样式\n  en-US: Customized style\n---\n\n## zh-CN\n\n使用 `nzStyle` 和 `nzClass` 来定义样式。\n\n## en-US\n\nThe `nzStyle` and `nzClass` are available to customize Message.\n"
  },
  {
    "path": "components/message/demo/custom-style.ts",
    "content": "import { Component, inject } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzMessageService } from 'ng-zorro-antd/message';\n\n@Component({\n  selector: 'nz-demo-message-custom-style',\n  imports: [NzButtonModule],\n  template: `<button nz-button nzType=\"primary\" (click)=\"createNotification()\">Open the notification box</button>`\n})\nexport class NzDemoMessageCustomStyleComponent {\n  readonly #messageService = inject(NzMessageService);\n\n  createNotification(): void {\n    this.#messageService.success('This is the content of the notification', {\n      nzStyle: {\n        'margin-top': '20vh'\n      },\n      nzClass: 'custom-class'\n    });\n  }\n}\n"
  },
  {
    "path": "components/message/demo/duration.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 修改延时\n  en-US: Customize duration\n---\n\n## zh-CN\n\n自定义时长 `10s`，默认时长为 `3s`。\n\n## en-US\n\nCustomize message display duration from default `3s` to `10s`.\n"
  },
  {
    "path": "components/message/demo/duration.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzMessageService } from 'ng-zorro-antd/message';\n\n@Component({\n  selector: 'nz-demo-message-duration',\n  imports: [NzButtonModule],\n  template: `<button nz-button nzType=\"default\" (click)=\"createBasicMessage()\">Customized display duration</button>`\n})\nexport class NzDemoMessageDurationComponent {\n  createBasicMessage(): void {\n    this.message.success('This is a prompt message for success, and it will disappear in 10 seconds', {\n      nzDuration: 10000\n    });\n  }\n\n  constructor(private message: NzMessageService) {}\n}\n"
  },
  {
    "path": "components/message/demo/info.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 普通提示\n  en-US: Normal prompt\n---\n\n## zh-CN\n\n信息提醒反馈。\n\n## en-US\n\nNormal messages as feedbacks.\n"
  },
  {
    "path": "components/message/demo/info.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzMessageService } from 'ng-zorro-antd/message';\n\n@Component({\n  selector: 'nz-demo-message-info',\n  imports: [NzButtonModule],\n  template: `<button nz-button nzType=\"primary\" (click)=\"createBasicMessage()\">Display normal message</button>`\n})\nexport class NzDemoMessageInfoComponent {\n  constructor(private message: NzMessageService) {}\n\n  createBasicMessage(): void {\n    this.message.info('This is a normal message');\n  }\n}\n"
  },
  {
    "path": "components/message/demo/loading.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 加载中\n  en-US: Message of loading\n---\n\n## zh-CN\n\n进行全局 loading，异步自行移除。\n\n## en-US\n\nDisplay a global loading indicator, which is dismissed by itself asynchronously.\n"
  },
  {
    "path": "components/message/demo/loading.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzMessageService } from 'ng-zorro-antd/message';\n\n@Component({\n  selector: 'nz-demo-message-loading',\n  imports: [NzButtonModule],\n  template: `<button nz-button nzType=\"default\" (click)=\"createBasicMessage()\">Display a loading indicator</button>`\n})\nexport class NzDemoMessageLoadingComponent {\n  constructor(private message: NzMessageService) {}\n\n  createBasicMessage(): void {\n    const id = this.message.loading('Action in progress..', { nzDuration: 0 }).messageId;\n    setTimeout(() => {\n      this.message.remove(id);\n    }, 2500);\n  }\n}\n"
  },
  {
    "path": "components/message/demo/other.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 其他提示类型\n  en-US: Other types of message\n---\n\n## zh-CN\n\n包括成功、失败、警告。\n\n## en-US\n\nMessages of success, error and warning types.\n"
  },
  {
    "path": "components/message/demo/other.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzMessageService } from 'ng-zorro-antd/message';\n\n@Component({\n  selector: 'nz-demo-message-other',\n  imports: [NzButtonModule],\n  template: `\n    <button nz-button (click)=\"createMessage('success')\">Success</button>\n    <button nz-button (click)=\"createMessage('error')\">Error</button>\n    <button nz-button (click)=\"createMessage('warning')\">Warning</button>\n  `,\n  styles: `\n    [nz-button] {\n      margin-right: 8px;\n    }\n  `\n})\nexport class NzDemoMessageOtherComponent {\n  createMessage(type: string): void {\n    this.message.create(type, `This is a message of ${type}`);\n  }\n\n  constructor(private message: NzMessageService) {}\n}\n"
  },
  {
    "path": "components/message/demo/template.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 自定义模板\n  en-US: Custom Template\n---\n\n## zh-CN\n\n您可以为消息内容创建自定义模板。\n通过 `nzData` 选项，您可以传递一些可选的数据给此自定义模板。\n\n## en-US\n\nYou can have a custom template for the message content.\nYou would have the possibility to pass some optional data to this custom template thanks to the `nzData` option\n"
  },
  {
    "path": "components/message/demo/template.ts",
    "content": "import { Component, TemplateRef, ViewChild } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzMessageComponent, NzMessageService } from 'ng-zorro-antd/message';\n\n@Component({\n  selector: 'nz-demo-message-template',\n  imports: [NzButtonModule],\n  template: `\n    <button nz-button nzType=\"default\" (click)=\"showMessage()\">Display a custom template</button>\n    <ng-template #customTemplate let-data=\"data\">My Favorite Framework is {{ data }}</ng-template>\n  `\n})\nexport class NzDemoMessageTemplateComponent {\n  @ViewChild('customTemplate', { static: true }) customTemplate!: TemplateRef<{\n    $implicit: NzMessageComponent;\n    data: string;\n  }>;\n\n  constructor(private message: NzMessageService) {}\n\n  showMessage(): void {\n    this.message.success(this.customTemplate, { nzData: 'Angular' });\n  }\n}\n"
  },
  {
    "path": "components/message/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Feedback\ntitle: Message\ncover: 'https://gw.alipayobjects.com/zos/alicdn/hAkKTIW0K/Message.svg'\ndescription: Display global messages as feedback in response to user operations.\n---\n\n## When To Use\n\n- To provide feedback such as success, warning, error etc.\n- A message is displayed at top and center and will be dismissed automatically, as a non-interrupting light-weighted\n  prompt.\n\n## API\n\n### NzMessageService\n\nThis components provides some service methods, with usage and arguments as following:\n\n- `NzMessageService.success(content, [options])`\n- `NzMessageService.error(content, [options])`\n- `NzMessageService.info(content, [options])`\n- `NzMessageService.warning(content, [options])`\n- `NzMessageService.loading(content, [options])`\n\n| Argument | Description                                                                     | Type                          | Default |\n| -------- | ------------------------------------------------------------------------------- | ----------------------------- | ------- |\n| content  | The content of message                                                          | `string \\| TemplateRef<void>` | -       |\n| options  | Support setting the parameters for the current message box, see the table below | `object`                      | -       |\n\nThe parameters that are set by the `options` support are as follows:\n\n| Argument       | Description                                                            | Type                         | Version |\n| -------------- | ---------------------------------------------------------------------- | ---------------------------- | ------- |\n| nzDuration     | Duration (milliseconds), does not disappear when set to 0              | `number`                     |         |\n| nzPauseOnHover | Do not remove automatically when mouse is over while setting to `true` | `boolean`                    |         |\n| nzAnimate      | Whether to turn on animation                                           | `boolean`                    |         |\n| nzData         | Data to pass to custom template                                        | `NzSafeAny`                  |         |\n| nzStyle        | Customized inline style                                                | `NgStyleInterface \\| string` | 20.4.0  |\n| nzClass        | Customized CSS class                                                   | `NgClassInterface \\| string` | 20.4.0  |\n\nMethods for destruction are also provided:\n\n- `message.remove(id)` : Remove the message with the specified id. When the id is empty, remove all messages (the\n  message id is returned by the above method)\n\n### Global Configuration\n\nYou can use `NzConfigService` to configure this component globally. Please check\nthe [Global Configuration](/docs/global-config/en) chapter for more information.\n\n| Argument       | Description                                                            | Type               | Default |\n| -------------- | ---------------------------------------------------------------------- | ------------------ | ------- |\n| nzDuration     | Duration (milliseconds), does not disappear when set to 0              | `number`           | `3000`  |\n| nzMaxStack     | The maximum number of messages that can be displayed at the same time  | `number`           | `7`     |\n| nzPauseOnHover | Do not remove automatically when mouse is over while setting to `true` | `boolean`          | `true`  |\n| nzAnimate      | Whether to turn on animation                                           | `boolean`          | `true`  |\n| nzTop          | Distance from top                                                      | `number \\| string` | `24`    |\n| nzDirection    | Direction of the text in the messages                                  | `'ltr' \\| 'rtl'`   | -       |\n\n### NzMessageRef\n\nIt's the object that returned when you call `NzMessageService.success` and others.\n\n```ts\nexport interface NzMessageRef {\n  messageId: string;\n  onClose: Subject<false>; // It would emit an event when the message is closed\n}\n```\n"
  },
  {
    "path": "components/message/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 全局提示\ntype: 反馈\ntitle: Message\ncover: 'https://gw.alipayobjects.com/zos/alicdn/hAkKTIW0K/Message.svg'\ndescription: 全局展示操作反馈信息。\n---\n\n## 何时使用\n\n- 可提供成功、警告和错误等反馈信息。\n- 顶部居中显示并自动消失，是一种不打断用户操作的轻量级提示方式。\n\n## API\n\n### NzMessageService\n\n组件提供了一些服务方法，使用方式和参数如下：\n\n- `NzMessageService.success(content, [options])`\n- `NzMessageService.error(content, [options])`\n- `NzMessageService.info(content, [options])`\n- `NzMessageService.warning(content, [options])`\n- `NzMessageService.loading(content, [options])`\n\n| 参数    | 说明                                     | 类型                          | 默认值 |\n| ------- | ---------------------------------------- | ----------------------------- | ------ |\n| content | 提示内容                                 | `string \\| TemplateRef<void>` | -      |\n| options | 支持设置针对当前提示框的参数，见下方表格 | `object`                      | -      |\n\n`options` 支持设置的参数如下：\n\n| 参数           | 说明                              | 类型                         | 版本   |\n| -------------- | --------------------------------- | ---------------------------- | ------ |\n| nzDuration     | 持续时间(毫秒)，当设置为0时不消失 | `number`                     |        |\n| nzPauseOnHover | 鼠标移上时禁止自动移除            | `boolean`                    |        |\n| nzAnimate      | 开关动画效果                      | `boolean`                    |        |\n| nzData         | 传递给自定义模板的数据            | `NzSafeAny`                  |        |\n| nzStyle        | 自定义内联样式                    | `NgStyleInterface \\| string` | 20.4.0 |\n| nzClass        | 自定义 CSS class                  | `NgClassInterface \\| string` | 20.4.0 |\n\n还提供了全局销毁方法：\n\n- `NzMessageService.remove(id)`: 移除特定id的消息，当id为空时，移除所有消息（该消息id通过上述方法返回值中得到）\n\n### 全局配置\n\n可以通过 `NzConfigService` 进行全局配置，详情请见文档中 [全局配置项](/docs/global-config/zh) 章节。\n\n| 参数           | 说明                                | 类型               | 默认值 |\n| -------------- | ----------------------------------- | ------------------ | ------ |\n| nzDuration     | 持续时间(毫秒)，当设置为 0 时不消失 | `number`           | `3000` |\n| nzMaxStack     | 同一时间可展示的最大提示数量        | `number`           | `7`    |\n| nzPauseOnHover | 鼠标移上时禁止自动移除              | `boolean`          | `true` |\n| nzAnimate      | 开关动画效果                        | `boolean`          | `true` |\n| nzTop          | 消息距离顶部的位置                  | `number \\| string` | `24`   |\n| nzDirection    | 消息文字方向                        | `'ltr' \\| 'rtl'`   | -      |\n\n### NzMessageRef\n\n当你调用 `NzMessageService.success` 或其他方法时会返回该对象。\n\n```ts\nexport interface NzMessageRef {\n  messageId: string;\n  onClose: Subject<false>; // 当 message 关闭时它会派发一个事件\n}\n```\n"
  },
  {
    "path": "components/message/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/message/message-container.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction } from '@angular/cdk/bidi';\nimport { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';\n\nimport { MessageConfig, onConfigChangeEventForComponent } from 'ng-zorro-antd/core/config';\nimport { toCssPixel } from 'ng-zorro-antd/core/util';\n\nimport { NzMNContainerComponent } from './base';\nimport { NzMessageComponent } from './message.component';\n\nconst NZ_CONFIG_COMPONENT_NAME = 'message';\n\nconst NZ_MESSAGE_DEFAULT_CONFIG: Required<MessageConfig> = {\n  nzAnimate: true,\n  nzDuration: 3000,\n  nzMaxStack: 7,\n  nzPauseOnHover: true,\n  nzTop: 24,\n  nzDirection: 'ltr'\n};\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-message-container',\n  exportAs: 'nzMessageContainer',\n  template: `\n    <div class=\"ant-message\" [class.ant-message-rtl]=\"dir === 'rtl'\" [style.top]=\"top\">\n      @for (instance of instances; track instance) {\n        <nz-message [instance]=\"instance\" (destroyed)=\"remove($event.id, $event.userAction)\" />\n      }\n    </div>\n  `,\n  imports: [NzMessageComponent]\n})\nexport class NzMessageContainerComponent extends NzMNContainerComponent {\n  dir: Direction = this.nzConfigService.getConfigForComponent(NZ_CONFIG_COMPONENT_NAME)?.nzDirection || 'ltr';\n  top?: string | null;\n\n  constructor() {\n    super();\n    this.updateConfig();\n  }\n\n  protected subscribeConfigChange(): void {\n    onConfigChangeEventForComponent(NZ_CONFIG_COMPONENT_NAME, () => {\n      this.updateConfig();\n      this.dir = this.nzConfigService.getConfigForComponent(NZ_CONFIG_COMPONENT_NAME)?.nzDirection || this.dir;\n    });\n  }\n\n  protected updateConfig(): void {\n    this.config = {\n      ...NZ_MESSAGE_DEFAULT_CONFIG,\n      ...this.config,\n      ...this.nzConfigService.getConfigForComponent(NZ_CONFIG_COMPONENT_NAME)\n    };\n\n    this.top = toCssPixel(this.config.nzTop);\n    this.cdr.markForCheck();\n  }\n}\n"
  },
  {
    "path": "components/message/message.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  ElementRef,\n  EventEmitter,\n  Input,\n  OnInit,\n  Output,\n  viewChild,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nimport { NzMNComponent } from './base';\nimport { NzMessageData } from './typings';\n\n@Component({\n  selector: 'nz-message',\n  exportAs: 'nzMessage',\n  imports: [NzIconModule, NzOutletModule],\n  template: `\n    <div\n      #animationElement\n      class=\"ant-message-notice\"\n      [class]=\"instance.options?.nzClass\"\n      [style]=\"instance.options?.nzStyle\"\n      (mouseenter)=\"onEnter()\"\n      (mouseleave)=\"onLeave()\"\n    >\n      <div class=\"ant-message-notice-content\">\n        <div class=\"ant-message-custom-content\" [class]=\"'ant-message-' + instance.type\">\n          @switch (instance.type) {\n            @case ('success') {\n              <nz-icon nzType=\"check-circle\" />\n            }\n            @case ('info') {\n              <nz-icon nzType=\"info-circle\" />\n            }\n            @case ('warning') {\n              <nz-icon nzType=\"exclamation-circle\" />\n            }\n            @case ('error') {\n              <nz-icon nzType=\"close-circle\" />\n            }\n            @case ('loading') {\n              <nz-icon nzType=\"loading\" />\n            }\n          }\n          <ng-container\n            *nzStringTemplateOutlet=\"instance.content; context: { $implicit: this, data: instance.options?.nzData }\"\n          >\n            <span [innerHTML]=\"instance.content\"></span>\n          </ng-container>\n        </div>\n      </div>\n    </div>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None\n})\nexport class NzMessageComponent extends NzMNComponent implements OnInit {\n  @Input() override instance!: Required<NzMessageData>;\n  @Output() override readonly destroyed = new EventEmitter<{ id: string; userAction: boolean }>();\n  index?: number;\n\n  readonly animationElement = viewChild.required('animationElement', { read: ElementRef });\n  protected readonly _animationKeyframeMap = {\n    enter: 'MessageMoveIn',\n    leave: 'MessageMoveOut'\n  };\n  protected readonly _animationClassMap = {\n    enter: 'ant-message-move-up-enter',\n    leave: 'ant-message-move-up-leave'\n  };\n}\n"
  },
  {
    "path": "components/message/message.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Injectable } from '@angular/core';\n\nimport { NzMNService } from './base';\nimport { NzMessageContainerComponent } from './message-container.component';\nimport { NzMessageContentType, NzMessageData, NzMessageDataOptions, NzMessageRef, NzMessageType } from './typings';\n\n@Injectable({\n  providedIn: 'root'\n})\nexport class NzMessageService extends NzMNService<NzMessageContainerComponent> {\n  protected componentPrefix = 'message-';\n\n  success(content: NzMessageContentType, options?: NzMessageDataOptions): NzMessageRef {\n    return this.createInstance({ type: 'success', content }, options);\n  }\n\n  error(content: NzMessageContentType, options?: NzMessageDataOptions): NzMessageRef {\n    return this.createInstance({ type: 'error', content }, options);\n  }\n\n  info(content: NzMessageContentType, options?: NzMessageDataOptions): NzMessageRef {\n    return this.createInstance({ type: 'info', content }, options);\n  }\n\n  warning(content: NzMessageContentType, options?: NzMessageDataOptions): NzMessageRef {\n    return this.createInstance({ type: 'warning', content }, options);\n  }\n\n  loading(content: NzMessageContentType, options?: NzMessageDataOptions): NzMessageRef {\n    return this.createInstance({ type: 'loading', content }, options);\n  }\n\n  create(type: NzMessageType | string, content: NzMessageContentType, options?: NzMessageDataOptions): NzMessageRef {\n    return this.createInstance({ type, content }, options);\n  }\n\n  private createInstance(message: NzMessageData, options?: NzMessageDataOptions): NzMessageRef {\n    this.container = this.withContainer(NzMessageContainerComponent);\n\n    return this.container.create({\n      ...message,\n      ...{\n        createdAt: new Date(),\n        messageId: this.getInstanceId(),\n        options\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "components/message/message.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport { Component, TemplateRef, ViewChild } from '@angular/core';\nimport { ComponentFixture, inject, TestBed } from '@angular/core/testing';\n\nimport { NzConfigService, provideNzConfig } from 'ng-zorro-antd/core/config';\nimport { dispatchEvent, dispatchMouseEvent, sleep } from 'ng-zorro-antd/core/testing';\n\nimport { NzMessageComponent } from './message.component';\nimport { NzMessageService } from './message.service';\n\ndescribe('message', () => {\n  let messageService: NzMessageService;\n  let overlayContainer: OverlayContainer;\n  let overlayContainerElement: HTMLElement;\n  let fixture: ComponentFixture<NzTestMessageComponent>;\n  let testComponent: NzTestMessageComponent;\n  let configService: NzConfigService;\n\n  function getMessageElement(): HTMLElement {\n    return overlayContainerElement.querySelector('.ant-message-notice') as HTMLElement;\n  }\n\n  // mock animationend event\n  async function animationEnd(): Promise<void> {\n    dispatchEvent(getMessageElement(), new AnimationEvent('animationend', { animationName: 'MessageMoveOut' }));\n    await fixture.whenStable();\n  }\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [provideNzConfig({ message: { nzMaxStack: 2, nzTop: 24 } }), NzMessageService]\n    });\n\n    fixture = TestBed.createComponent(NzTestMessageComponent);\n    testComponent = fixture.componentInstance;\n  });\n\n  beforeEach(inject(\n    [NzMessageService, OverlayContainer, NzConfigService],\n    (m: NzMessageService, oc: OverlayContainer, c: NzConfigService) => {\n      messageService = m;\n      overlayContainer = oc;\n      configService = c;\n    }\n  ));\n\n  afterEach(() => {\n    messageService.remove();\n  });\n\n  it('should open a message box with success', () => {\n    messageService.success('SUCCESS');\n    overlayContainerElement = overlayContainer.getContainerElement();\n\n    const overlayWrapper = overlayContainerElement.querySelector('.cdk-global-overlay-wrapper') as HTMLElement;\n    expect(overlayWrapper.style.zIndex).toBe('1010');\n    expect(overlayContainerElement.textContent).toContain('SUCCESS');\n    expect(overlayContainerElement.querySelector('.anticon-check-circle')).not.toBeNull();\n  });\n\n  it('should open a message box with error', () => {\n    messageService.error('ERROR');\n    overlayContainerElement = overlayContainer.getContainerElement();\n    expect(overlayContainerElement.textContent).toContain('ERROR');\n    expect(overlayContainerElement.querySelector('.anticon-close-circle')).not.toBeNull();\n  });\n\n  it('should open a message box with warning', () => {\n    messageService.warning('WARNING');\n    overlayContainerElement = overlayContainer.getContainerElement();\n\n    expect(overlayContainerElement.textContent).toContain('WARNING');\n    expect(overlayContainerElement.querySelector('.anticon-exclamation-circle')).not.toBeNull();\n  });\n\n  it('should open a message box with info', () => {\n    messageService.info('INFO');\n    overlayContainerElement = overlayContainer.getContainerElement();\n\n    expect(overlayContainerElement.textContent).toContain('INFO');\n    expect(overlayContainerElement.querySelector('.anticon-info-circle')).not.toBeNull();\n  });\n\n  it('should open a message box with loading', () => {\n    messageService.loading('LOADING');\n    overlayContainerElement = overlayContainer.getContainerElement();\n\n    expect(overlayContainerElement.textContent).toContain('LOADING');\n    expect(overlayContainerElement.querySelector('.anticon-loading')).not.toBeNull();\n  });\n\n  it('should support template', async () => {\n    messageService.info(testComponent.template, { nzData: 'from template' });\n    await fixture.whenStable();\n    overlayContainerElement = overlayContainer.getContainerElement();\n    expect(overlayContainerElement.textContent).toContain('Content in template from template');\n  });\n\n  it('should auto closed by 1s', async () => {\n    messageService.create('', 'EXISTS', { nzDuration: 1000 });\n    overlayContainerElement = overlayContainer.getContainerElement();\n\n    expect(overlayContainerElement.textContent).toContain('EXISTS');\n\n    await sleep(1000);\n    await animationEnd();\n    expect(overlayContainerElement.textContent).not.toContain('EXISTS');\n  });\n\n  it('should not destroy when hovered', async () => {\n    messageService.create('', 'EXISTS', { nzDuration: 2250 });\n    overlayContainerElement = overlayContainer.getContainerElement();\n\n    const messageElement = getMessageElement();\n    dispatchMouseEvent(messageElement, 'mouseenter');\n    await sleep(2250);\n    await fixture.whenStable();\n    expect(overlayContainerElement.textContent).toContain('EXISTS');\n\n    dispatchMouseEvent(messageElement, 'mouseleave');\n    await sleep(2250);\n    await animationEnd();\n    expect(overlayContainerElement.textContent).not.toContain('EXISTS');\n  });\n\n  it('should not destroyed automatically but manually', async () => {\n    const filledMessage = messageService.success('SUCCESS', { nzDuration: 0 });\n    overlayContainerElement = overlayContainer.getContainerElement();\n\n    await sleep(4500);\n    await fixture.whenStable();\n    expect(overlayContainerElement.textContent).toContain('SUCCESS');\n\n    messageService.remove(filledMessage.messageId);\n    await fixture.whenStable();\n    expect(overlayContainerElement.textContent).not.toContain('SUCCESS');\n  });\n\n  it('should keep the balance of messages length and then remove all', async () => {\n    for (const id of [1, 2, 3]) {\n      const content = `SUCCESS-${id}`;\n      messageService.success(content);\n      await fixture.whenStable();\n\n      overlayContainerElement = overlayContainer.getContainerElement();\n      expect(overlayContainerElement.textContent).toContain(content);\n      if (id === 3) {\n        expect(overlayContainerElement.textContent).not.toContain('SUCCESS-1');\n        expect(messageService['container']?.instances.length).toBe(2);\n      }\n    }\n\n    messageService.remove();\n    await fixture.whenStable();\n    expect(overlayContainerElement.textContent).not.toContain('SUCCESS-3');\n    expect(messageService['container']).toBeUndefined();\n  });\n\n  it('should destroy without animation', async () => {\n    messageService.error('EXISTS', { nzDuration: 1000, nzAnimate: false });\n    await sleep(1000);\n    await fixture.whenStable();\n    expect(overlayContainerElement.textContent).not.toContain('EXISTS');\n  });\n\n  it('should emit event when message close', async () => {\n    const closeSpy = jasmine.createSpy('message closed');\n    const msg = messageService.create('loading', 'CLOSE');\n    const messageId = msg.messageId;\n    msg.onClose.subscribe(closeSpy);\n    messageService.remove(messageId);\n\n    await fixture.whenStable();\n    expect(closeSpy).toHaveBeenCalledTimes(1);\n  });\n\n  it('should container top to configured', async () => {\n    messageService.create('top', 'CHANGE');\n    await fixture.whenStable();\n\n    overlayContainerElement = overlayContainer.getContainerElement();\n    const messageContainerElement = overlayContainerElement.querySelector('.ant-message') as HTMLElement;\n    expect(messageContainerElement.style.top).toBe('24px');\n  });\n\n  describe('custom styling', () => {\n    it('should apply custom class', () => {\n      messageService.success('SUCCESS', { nzClass: 'custom-message-class' });\n      overlayContainerElement = overlayContainer.getContainerElement();\n\n      const messageElement = getMessageElement();\n      expect(messageElement).not.toBeNull();\n      expect(messageElement.classList.contains('custom-message-class')).toBe(true);\n      expect(messageElement.classList.contains('ant-message-notice')).toBe(true);\n    });\n\n    it('should apply space-separated custom class', () => {\n      messageService.info('INFO', { nzClass: 'class1 class2 class3' });\n      overlayContainerElement = overlayContainer.getContainerElement();\n\n      const messageElement = getMessageElement();\n      expect(messageElement.classList.contains('ant-message-notice')).toBe(true);\n      expect(messageElement.classList.contains('class1')).toBe(true);\n      expect(messageElement.classList.contains('class2')).toBe(true);\n      expect(messageElement.classList.contains('class3')).toBe(true);\n    });\n\n    it('should apply custom styles', () => {\n      messageService.error('ERROR', {\n        nzStyle: {\n          'background-color': 'rgb(255, 0, 0)',\n          color: 'white',\n          border: '2px solid black'\n        }\n      });\n      overlayContainerElement = overlayContainer.getContainerElement();\n\n      const messageElement = getMessageElement();\n      expect(messageElement.style.backgroundColor).toBe('rgb(255, 0, 0)');\n      expect(messageElement.style.color).toBe('white');\n      expect(messageElement.style.border).toBe('2px solid black');\n    });\n\n    it('should work without custom class or style', () => {\n      messageService.warning('WARNING');\n      overlayContainerElement = overlayContainer.getContainerElement();\n\n      const messageElement = getMessageElement();\n      expect(messageElement).not.toBeNull();\n      expect(messageElement.classList.contains('ant-message-notice')).toBe(true);\n    });\n\n    it('should combine custom class and style', () => {\n      messageService.loading('LOADING', {\n        nzClass: 'custom-loading-class',\n        nzStyle: { 'font-weight': 'bold', opacity: '0.8' }\n      });\n      overlayContainerElement = overlayContainer.getContainerElement();\n\n      const messageElement = getMessageElement();\n      expect(messageElement.classList.contains('custom-loading-class')).toBe(true);\n      expect(messageElement.classList.contains('ant-message-notice')).toBe(true);\n      expect(messageElement.style.fontWeight).toBe('bold');\n      expect(messageElement.style.opacity).toBe('0.8');\n    });\n\n    it('should handle empty class gracefully', () => {\n      messageService.success('SUCCESS', { nzClass: '' });\n      overlayContainerElement = overlayContainer.getContainerElement();\n\n      const messageElement = getMessageElement();\n      expect(messageElement).not.toBeNull();\n      expect(messageElement.classList.contains('ant-message-notice')).toBe(true);\n    });\n\n    it('should handle empty style object gracefully', () => {\n      messageService.info('INFO', { nzStyle: {} });\n      overlayContainerElement = overlayContainer.getContainerElement();\n\n      const messageElement = getMessageElement();\n      expect(messageElement).not.toBeNull();\n    });\n  });\n\n  describe('RTL', () => {\n    it('should apply classname', () => {\n      configService.set('message', { nzDirection: 'rtl' });\n      messageService.info('INFO');\n\n      overlayContainerElement = overlayContainer.getContainerElement();\n      expect(overlayContainerElement.textContent).toContain('INFO');\n      expect(overlayContainerElement.querySelector('.ant-message-rtl')).not.toBeNull();\n    });\n  });\n});\n\n@Component({\n  selector: 'nz-test-message',\n  template: `<ng-template #contentTemplate let-data=\"data\">Content in template {{ data }}</ng-template>`\n})\nclass NzTestMessageComponent {\n  @ViewChild('contentTemplate', { static: true }) template!: TemplateRef<{\n    $implicit: NzMessageComponent;\n    data: string;\n  }>;\n}\n"
  },
  {
    "path": "components/message/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/message/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './base';\nexport * from './message-container.component';\nexport * from './message.component';\nexport * from './message.service';\nexport * from './typings';\n"
  },
  {
    "path": "components/message/style/animation.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import '../../style/core/motion/util';\n\n@message-prefix-cls: ~'@{ant-prefix}-message';\n\n.@{message-prefix-cls} {\n  @name: ~'@{message-prefix-cls}-move-up';\n\n  .@{name} {\n    animation-fill-mode: forwards;\n  }\n\n  .make-motion-enter(@name, MessageMoveIn, @ease-in-out-circ, @animation-duration-slow);\n  .make-motion-leave(@name, MessageMoveOut, @ease-in-out-circ, @animation-duration-slow);\n\n  @keyframes MessageMoveIn {\n    0% {\n      padding: 0;\n      transform: translateY(-100%);\n      opacity: 0;\n    }\n\n    100% {\n      padding: @padding-xs;\n      transform: translateY(0);\n      opacity: 1;\n    }\n  }\n\n  @keyframes MessageMoveOut {\n    0% {\n      max-height: 150px;\n      padding: @padding-xs;\n      opacity: 1;\n    }\n\n    100% {\n      max-height: 0;\n      padding: 0;\n      opacity: 0;\n    }\n  }\n}\n"
  },
  {
    "path": "components/message/style/entry.less",
    "content": "@import './index.less';\n"
  },
  {
    "path": "components/message/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@message-prefix-cls: ~'@{ant-prefix}-message';\n\n.@{message-prefix-cls} {\n  .reset-component();\n\n  position: fixed;\n  top: 8px;\n  left: 0;\n  z-index: @zindex-message;\n  width: 100%;\n  pointer-events: none;\n\n  &-notice {\n    padding: 8px;\n    text-align: center;\n  }\n\n  &-notice-content {\n    display: inline-block;\n    padding: @message-notice-content-padding;\n    background: @message-notice-content-bg;\n    border-radius: @border-radius-base;\n    box-shadow: @shadow-2;\n    pointer-events: all;\n  }\n\n  &-success .@{iconfont-css-prefix} {\n    color: @success-color;\n  }\n\n  &-error .@{iconfont-css-prefix} {\n    color: @error-color;\n  }\n\n  &-warning .@{iconfont-css-prefix} {\n    color: @warning-color;\n  }\n\n  &-info .@{iconfont-css-prefix},\n  &-loading .@{iconfont-css-prefix} {\n    color: @info-color;\n  }\n\n  .@{iconfont-css-prefix} {\n    position: relative;\n    top: 1px;\n    margin-right: 8px;\n    font-size: @font-size-lg;\n  }\n}\n\n@import './rtl';\n@import './animation';\n"
  },
  {
    "path": "components/message/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@message-prefix-cls: ~'@{ant-prefix}-message';\n\n.@{message-prefix-cls}-rtl {\n  direction: rtl;\n\n  span {\n    direction: rtl;\n  }\n\n  .@{iconfont-css-prefix} {\n    margin-right: 0;\n    margin-left: 8px;\n  }\n}\n"
  },
  {
    "path": "components/message/typings.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { TemplateRef } from '@angular/core';\nimport { Subject } from 'rxjs';\n\nimport { NzSafeAny, type NgClassInterface, type NgStyleInterface } from 'ng-zorro-antd/core/types';\n\nimport { NzMNComponent } from './base';\n\nexport type NzMessageType = 'success' | 'info' | 'warning' | 'error' | 'loading';\n\nexport type NzMessageContentType = string | TemplateRef<void | { $implicit: NzMNComponent; data: NzSafeAny }>;\n\nexport interface NzMessageDataOptions {\n  nzDuration?: number;\n  nzAnimate?: boolean;\n  nzPauseOnHover?: boolean;\n  nzData?: NzSafeAny;\n  nzStyle?: NgStyleInterface | string;\n  nzClass?: NgClassInterface | string;\n}\n\nexport interface NzMessageData {\n  type?: NzMessageType | string;\n  content?: NzMessageContentType;\n  messageId?: string;\n  createdAt?: Date;\n  options?: NzMessageDataOptions;\n  /**\n   * @deprecated Will be removed in v22.0.0\n   */\n  state?: 'enter' | 'leave';\n  onClose?: Subject<boolean>;\n}\n\nexport type NzMessageRef = Pick<Required<NzMessageData>, 'onClose' | 'messageId'>;\n"
  },
  {
    "path": "components/modal/demo/async.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 异步关闭\n  en-US: Asynchronously close\n---\n\n## zh-CN\n\n点击确定后异步关闭对话框，例如提交表单。\n\n## en-US\n\nAsynchronously close a modal dialog when a user clicked OK button, for example,\nyou can use this pattern when you submit a form.\n"
  },
  {
    "path": "components/modal/demo/async.ts",
    "content": "import { Component, model, signal } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzModalModule } from 'ng-zorro-antd/modal';\n\n@Component({\n  selector: 'nz-demo-modal-async',\n  imports: [NzButtonModule, NzModalModule],\n  template: `\n    <button nz-button nzType=\"primary\" (click)=\"showModal()\">\n      <span>Show Modal</span>\n    </button>\n    <nz-modal\n      [(nzVisible)]=\"visible\"\n      nzTitle=\"Modal Title\"\n      (nzOnCancel)=\"handleCancel()\"\n      (nzOnOk)=\"handleOk()\"\n      [nzOkLoading]=\"loading()\"\n    >\n      <p *nzModalContent>Modal Content</p>\n    </nz-modal>\n  `\n})\nexport class NzDemoModalAsyncComponent {\n  visible = model(false);\n  loading = signal(false);\n\n  showModal(): void {\n    this.visible.set(true);\n  }\n\n  handleOk(): void {\n    this.loading.set(true);\n    setTimeout(() => {\n      this.visible.set(false);\n      this.loading.set(false);\n    }, 3000);\n  }\n\n  handleCancel(): void {\n    this.visible.set(false);\n  }\n}\n"
  },
  {
    "path": "components/modal/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n第一个对话框。\n\n## en-US\n\nBasic modal.\n"
  },
  {
    "path": "components/modal/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzModalModule } from 'ng-zorro-antd/modal';\n\n@Component({\n  selector: 'nz-demo-modal-basic',\n  imports: [NzButtonModule, NzModalModule],\n  template: `\n    <button nz-button nzType=\"primary\" (click)=\"showModal()\"><span>Show Modal</span></button>\n    <nz-modal [(nzVisible)]=\"isVisible\" nzTitle=\"The first Modal\" (nzOnCancel)=\"handleCancel()\" (nzOnOk)=\"handleOk()\">\n      <ng-container *nzModalContent>\n        <p>Content one</p>\n        <p>Content two</p>\n        <p>Content three</p>\n      </ng-container>\n    </nz-modal>\n  `\n})\nexport class NzDemoModalBasicComponent {\n  isVisible = false;\n\n  showModal(): void {\n    this.isVisible = true;\n  }\n\n  handleOk(): void {\n    console.log('Button ok clicked!');\n    this.isVisible = false;\n  }\n\n  handleCancel(): void {\n    console.log('Button cancel clicked!');\n    this.isVisible = false;\n  }\n}\n"
  },
  {
    "path": "components/modal/demo/confirm-promise.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 确认对话框\n  en-US: Confirmation modal dialog\n---\n\n## zh-CN\n\n使用 `NzModalService.confirm()` 可以快捷地弹出确认框。NzOnCancel/NzOnOk 返回 promise 可以延迟关闭\n\n## en-US\n\nTo use `NzModalService.confirm()` to popup confirmation modal dialog. Let NzOnCancel/NzOnOk function return a promise object to\ndelay closing the dialog.\n"
  },
  {
    "path": "components/modal/demo/confirm-promise.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzModalModule, NzModalRef, NzModalService } from 'ng-zorro-antd/modal';\n\n@Component({\n  selector: 'nz-demo-modal-confirm-promise',\n  imports: [NzButtonModule, NzModalModule],\n  template: `<button nz-button nzType=\"primary\" (click)=\"showConfirm()\">Confirm</button>`\n})\nexport class NzDemoModalConfirmPromiseComponent {\n  confirmModal?: NzModalRef; // For testing by now\n\n  constructor(private modal: NzModalService) {}\n\n  showConfirm(): void {\n    this.confirmModal = this.modal.confirm({\n      nzTitle: 'Do you Want to delete these items?',\n      nzContent: 'When clicked the OK button, this dialog will be closed after 1 second',\n      nzOnOk: () =>\n        new Promise((resolve, reject) => {\n          setTimeout(Math.random() > 0.5 ? resolve : reject, 1000);\n        }).catch(() => console.log('Oops errors!'))\n    });\n  }\n}\n"
  },
  {
    "path": "components/modal/demo/confirm.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 确认对话框\n  en-US: Confirmation modal dialog\n---\n\n## zh-CN\n\n使用 `NzModalService.confirm()` 可以快捷地弹出确认框。\n\n## en-US\n\nTo use `NzModalService.confirm()` to popup a confirmation modal dialog.\n"
  },
  {
    "path": "components/modal/demo/confirm.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzModalModule, NzModalService } from 'ng-zorro-antd/modal';\n\n@Component({\n  selector: 'nz-demo-modal-confirm',\n  imports: [NzButtonModule, NzModalModule],\n  template: `\n    <button nz-button nzType=\"primary\" (click)=\"showConfirm()\">Confirm</button>\n    <button nz-button nzType=\"dashed\" (click)=\"showDeleteConfirm()\">Delete</button>\n  `,\n  styles: `\n    button {\n      margin-right: 8px;\n    }\n  `\n})\nexport class NzDemoModalConfirmComponent {\n  constructor(private modal: NzModalService) {}\n\n  showConfirm(): void {\n    this.modal.confirm({\n      nzTitle: '<i>Do you Want to delete these items?</i>',\n      nzContent: '<b>Some descriptions</b>',\n      nzOnOk: () => console.log('OK')\n    });\n  }\n\n  showDeleteConfirm(): void {\n    this.modal.confirm({\n      nzTitle: 'Are you sure delete this task?',\n      nzContent: '<b style=\"color: red;\">Some descriptions</b>',\n      nzOkText: 'Yes',\n      nzOkType: 'primary',\n      nzOkDanger: true,\n      nzOnOk: () => console.log('OK'),\n      nzCancelText: 'No',\n      nzOnCancel: () => console.log('Cancel')\n    });\n  }\n}\n"
  },
  {
    "path": "components/modal/demo/draggable.md",
    "content": "---\norder: 11\ntitle:\n  zh-CN: 可拖拽\n  en-US: Draggable\n---\n\n## zh-CN\n\n可拖拽的对话框。\n\n## en-US\n\nDraggable modal.\n"
  },
  {
    "path": "components/modal/demo/draggable.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzModalModule } from 'ng-zorro-antd/modal';\n\n@Component({\n  selector: 'nz-demo-modal-draggable',\n  imports: [NzButtonModule, NzModalModule],\n  template: `\n    <button nz-button nzType=\"default\" (click)=\"showModal()\">\n      <span>Open Draggable Modal</span>\n    </button>\n\n    <nz-modal\n      nzDraggable\n      nzCentered\n      [(nzVisible)]=\"isVisible\"\n      nzTitle=\"Draggable Modal\"\n      (nzOnCancel)=\"handleCancel()\"\n      (nzOnOk)=\"handleOk()\"\n    >\n      <ng-container *nzModalContent>\n        <p>Just don't learn physics at school and your life will be full of magic and miracles.</p>\n        <p>Day before yesterday I saw a rabbit, and yesterday a deer, and today, you.</p>\n      </ng-container>\n    </nz-modal>\n  `\n})\nexport class NzDemoModalDraggableComponent {\n  isVisible = false;\n\n  showModal(): void {\n    this.isVisible = true;\n  }\n\n  handleOk(): void {\n    console.log('Button ok clicked!');\n    this.isVisible = false;\n  }\n\n  handleCancel(): void {\n    console.log('Button cancel clicked!');\n    this.isVisible = false;\n  }\n}\n"
  },
  {
    "path": "components/modal/demo/footer.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 自定义组成部分\n  en-US: Customized Parts\n---\n\n## zh-CN\n\n更复杂的例子，自定义了页脚的按钮，点击提交后进入 loading 状态，完成后关闭。\n\n不需要默认确定取消按钮时，你可以把 `nzFooter` 设为 `null`。\n\n## en-US\n\nA more complex example which define a customized footer button bar,\nthe dialog will change to loading state after clicking submit button, when the loading is over,\nthe modal dialog will be closed.\n\nYou could set `nzFooter` to `null` if you don't need default footer buttons.\n"
  },
  {
    "path": "components/modal/demo/footer.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzModalModule } from 'ng-zorro-antd/modal';\n\n@Component({\n  selector: 'nz-demo-modal-footer',\n  imports: [NzButtonModule, NzModalModule],\n  template: `\n    <button nz-button nzType=\"primary\" (click)=\"showModal()\">\n      <span>Show Modal</span>\n    </button>\n    <nz-modal\n      [(nzVisible)]=\"isVisible\"\n      [nzTitle]=\"modalTitle\"\n      [nzContent]=\"modalContent\"\n      [nzFooter]=\"modalFooter\"\n      (nzOnCancel)=\"handleCancel()\"\n    >\n      <ng-template #modalTitle>Custom Modal Title</ng-template>\n\n      <ng-template #modalContent>\n        <p>Modal Content</p>\n        <p>Modal Content</p>\n        <p>Modal Content</p>\n        <p>Modal Content</p>\n        <p>Modal Content</p>\n      </ng-template>\n\n      <ng-template #modalFooter>\n        <span>Modal Footer:</span>\n        <button nz-button nzType=\"default\" (click)=\"handleCancel()\">Custom Callback</button>\n        <button nz-button nzType=\"primary\" (click)=\"handleOk()\" [nzLoading]=\"isConfirmLoading\">Custom Submit</button>\n      </ng-template>\n    </nz-modal>\n  `\n})\nexport class NzDemoModalFooterComponent {\n  isVisible = false;\n  isConfirmLoading = false;\n\n  showModal(): void {\n    this.isVisible = true;\n  }\n\n  handleOk(): void {\n    this.isConfirmLoading = true;\n    setTimeout(() => {\n      this.isVisible = false;\n      this.isConfirmLoading = false;\n    }, 1000);\n  }\n\n  handleCancel(): void {\n    this.isVisible = false;\n  }\n}\n"
  },
  {
    "path": "components/modal/demo/footer2.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 自定义页脚\n  en-US: Customized Footer\n---\n\n## zh-CN\n\n使用 `nzModalFooter` 指令自定义了页脚的按钮。\n\n## en-US\n\nuse `nzModalFooter` directive to customized footer button bar.\n"
  },
  {
    "path": "components/modal/demo/footer2.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzModalModule, NzModalRef, NzModalService } from 'ng-zorro-antd/modal';\n\n@Component({\n  selector: 'nz-demo-modal-footer2',\n  imports: [NzButtonModule, NzModalModule],\n  template: `\n    <button nz-button nzType=\"primary\" (click)=\"showModal1()\">\n      <span>In Template</span>\n    </button>\n    <br />\n    <br />\n    <button nz-button nzType=\"primary\" (click)=\"showModal2()\">\n      <span>In Component</span>\n    </button>\n    <nz-modal [(nzVisible)]=\"isVisible\" nzTitle=\"Custom Modal Title\" (nzOnCancel)=\"handleCancel()\">\n      <div *nzModalContent>\n        <p>Modal Content</p>\n        <p>Modal Content</p>\n        <p>Modal Content</p>\n        <p>Modal Content</p>\n        <p>Modal Content</p>\n      </div>\n      <div *nzModalFooter>\n        <span>Modal Footer:</span>\n        <button nz-button nzType=\"default\" (click)=\"handleCancel()\">Custom Callback</button>\n        <button nz-button nzType=\"primary\" (click)=\"handleOk()\" [nzLoading]=\"isConfirmLoading\">Custom Submit</button>\n      </div>\n    </nz-modal>\n  `,\n  styles: []\n})\nexport class NzDemoModalFooter2Component {\n  isVisible = false;\n  isConfirmLoading = false;\n\n  constructor(private modalService: NzModalService) {}\n\n  showModal1(): void {\n    this.isVisible = true;\n  }\n\n  showModal2(): void {\n    this.modalService.create({\n      nzTitle: 'Modal Title',\n      nzContent: NzModalCustomFooterComponent\n    });\n  }\n\n  handleOk(): void {\n    this.isConfirmLoading = true;\n    setTimeout(() => {\n      this.isVisible = false;\n      this.isConfirmLoading = false;\n    }, 3000);\n  }\n\n  handleCancel(): void {\n    this.isVisible = false;\n  }\n}\n\n@Component({\n  selector: 'nz-modal-custom-footer-component',\n  imports: [NzButtonModule, NzModalModule],\n  template: `\n    <div>\n      <p>Modal Content</p>\n      <p>Modal Content</p>\n      <p>Modal Content</p>\n      <p>Modal Content</p>\n      <p>Modal Content</p>\n    </div>\n    <div *nzModalFooter>\n      <button nz-button nzType=\"default\" (click)=\"destroyModal()\">Custom Callback</button>\n      <button nz-button nzType=\"primary\" (click)=\"destroyModal()\">Custom Submit</button>\n    </div>\n  `\n})\nexport class NzModalCustomFooterComponent {\n  constructor(private modal: NzModalRef) {}\n\n  destroyModal(): void {\n    this.modal.destroy();\n  }\n}\n"
  },
  {
    "path": "components/modal/demo/info.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 信息提示\n  en-US: Information modal dialog\n---\n\n## zh-CN\n\n各种类型的信息提示，只提供一个按钮用于关闭。\n\n## en-US\n\nIn the various types of information modal dialog, only one button to close dialog is provided.\n"
  },
  {
    "path": "components/modal/demo/info.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzModalModule, NzModalService } from 'ng-zorro-antd/modal';\n\n@Component({\n  selector: 'nz-demo-modal-info',\n  imports: [NzButtonModule, NzModalModule],\n  template: `\n    <button nz-button (click)=\"info()\">Info</button>\n    <button nz-button (click)=\"success()\">Success</button>\n    <button nz-button (click)=\"error()\">Error</button>\n    <button nz-button (click)=\"warning()\">Warning</button>\n  `,\n  styles: `\n    button {\n      margin-right: 8px;\n    }\n  `\n})\nexport class NzDemoModalInfoComponent {\n  constructor(private modal: NzModalService) {}\n\n  info(): void {\n    this.modal.info({\n      nzTitle: 'This is a notification message',\n      nzContent: '<p>some messages...some messages...</p><p>some messages...some messages...</p>',\n      nzOnOk: () => console.log('Info OK')\n    });\n  }\n\n  success(): void {\n    this.modal.success({\n      nzTitle: 'This is a success message',\n      nzContent: 'some messages...some messages...'\n    });\n  }\n\n  error(): void {\n    this.modal.error({\n      nzTitle: 'This is an error message',\n      nzContent: 'some messages...some messages...'\n    });\n  }\n\n  warning(): void {\n    this.modal.warning({\n      nzTitle: 'This is an warning message',\n      nzContent: 'some messages...some messages...'\n    });\n  }\n}\n"
  },
  {
    "path": "components/modal/demo/locale.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 国际化\n  en-US: Internationalization\n---\n\n## zh-CN\n\n设置 `nzOkText` 与 `nzCancelText` 以自定义按钮文字。\n\n## en-US\n\nTo customize the text of the buttons, you need to set `nzOkText` and `nzCancelText` props.\n"
  },
  {
    "path": "components/modal/demo/locale.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzModalModule, NzModalService } from 'ng-zorro-antd/modal';\n\n@Component({\n  selector: 'nz-demo-modal-locale',\n  imports: [NzButtonModule, NzModalModule],\n  template: `\n    <div>\n      <button nz-button nzType=\"primary\" (click)=\"showModal()\">Modal</button>\n      <nz-modal\n        [(nzVisible)]=\"isVisible\"\n        nzTitle=\"Modal\"\n        nzOkText=\"Ok\"\n        nzCancelText=\"Cancel\"\n        (nzOnOk)=\"handleOk()\"\n        (nzOnCancel)=\"handleCancel()\"\n      >\n        <ng-container *nzModalContent>\n          <p>Bla bla ...</p>\n          <p>Bla bla ...</p>\n          <p>Bla bla ...</p>\n        </ng-container>\n      </nz-modal>\n    </div>\n    <br />\n    <button nz-button nzType=\"primary\" (click)=\"showConfirm()\">Confirm</button>\n  `\n})\nexport class NzDemoModalLocaleComponent {\n  isVisible = false;\n\n  constructor(private modalService: NzModalService) {}\n\n  showModal(): void {\n    this.isVisible = true;\n  }\n\n  handleOk(): void {\n    this.isVisible = false;\n  }\n\n  handleCancel(): void {\n    this.isVisible = false;\n  }\n\n  showConfirm(): void {\n    this.modalService.confirm({\n      nzTitle: 'Confirm',\n      nzContent: 'Bla bla ...',\n      nzOkText: 'OK',\n      nzCancelText: 'Cancel'\n    });\n  }\n}\n"
  },
  {
    "path": "components/modal/demo/manual.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 手动移除\n  en-US: Manual to destroy\n---\n\n## zh-CN\n\n手动关闭modal。\n\n## en-US\n\nManually destroying a modal.\n"
  },
  {
    "path": "components/modal/demo/manual.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzModalModule, NzModalService } from 'ng-zorro-antd/modal';\n\n@Component({\n  selector: 'nz-demo-modal-manual',\n  imports: [NzButtonModule, NzModalModule],\n  template: `<button nz-button (click)=\"success()\">Success</button>`\n})\nexport class NzDemoModalManualComponent {\n  constructor(private modalService: NzModalService) {}\n\n  success(): void {\n    const modal = this.modalService.success({\n      nzTitle: 'This is a notification message',\n      nzContent: 'This modal will be destroyed after 1 second'\n    });\n\n    setTimeout(() => modal.destroy(), 1000);\n  }\n}\n"
  },
  {
    "path": "components/modal/demo/position.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 自定义位置\n  en-US: To customize the position of modal\n---\n\n## zh-CN\n\n使用 `nzCentered` 或类似 `style.top` 的样式来设置对话框位置。\n\n> **注意** 由于Angular的样式隔离，若在Component中没有加入`encapsulation: ViewEncapsulation.None`，则您可能需要在自定义样式内采用`::ng-deep`来覆盖NgZorro的样式\n\n## en-US\n\nYou can use `nzCentered`,`style.top` or other styles to set position of modal dialog.\n\n> **NOTE** Due to Angular's style isolation, you may need to override the NgZorro style with `:: ng-deep` within a custom style if `encapsulation: ViewEncapsulation.None` is not included in the Component\n"
  },
  {
    "path": "components/modal/demo/position.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzModalModule } from 'ng-zorro-antd/modal';\n\n@Component({\n  selector: 'nz-demo-modal-position',\n  imports: [NzButtonModule, NzModalModule],\n  template: `\n    <button nz-button nzType=\"primary\" (click)=\"showModalTop()\">Display a modal dialog at 20px to Top</button>\n    <nz-modal\n      [nzStyle]=\"{ top: '20px' }\"\n      [(nzVisible)]=\"isVisibleTop\"\n      nzTitle=\"20px to Top\"\n      (nzOnCancel)=\"handleCancelTop()\"\n      (nzOnOk)=\"handleOkTop()\"\n    >\n      <ng-container *nzModalContent>\n        <p>some contents...</p>\n        <p>some contents...</p>\n        <p>some contents...</p>\n      </ng-container>\n    </nz-modal>\n\n    <br />\n    <br />\n\n    <button nz-button nzType=\"primary\" (click)=\"showModalMiddle()\">Vertically centered modal dialog</button>\n    <nz-modal\n      [(nzVisible)]=\"isVisibleMiddle\"\n      nzTitle=\"Vertically centered modal dialog\"\n      nzCentered\n      (nzOnCancel)=\"handleCancelMiddle()\"\n      (nzOnOk)=\"handleOkMiddle()\"\n    >\n      <ng-container *nzModalContent>\n        <p>some contents...</p>\n        <p>some contents...</p>\n        <p>some contents...</p>\n      </ng-container>\n    </nz-modal>\n  `\n})\nexport class NzDemoModalPositionComponent {\n  isVisibleTop = false;\n  isVisibleMiddle = false;\n\n  showModalTop(): void {\n    this.isVisibleTop = true;\n  }\n\n  showModalMiddle(): void {\n    this.isVisibleMiddle = true;\n  }\n\n  handleOkTop(): void {\n    console.log('点击了确定');\n    this.isVisibleTop = false;\n  }\n\n  handleCancelTop(): void {\n    this.isVisibleTop = false;\n  }\n\n  handleOkMiddle(): void {\n    console.log('click ok');\n    this.isVisibleMiddle = false;\n  }\n\n  handleCancelMiddle(): void {\n    this.isVisibleMiddle = false;\n  }\n}\n"
  },
  {
    "path": "components/modal/demo/service.md",
    "content": "---\norder: 10\ntitle:\n  zh-CN: 服务方式创建\n  en-US: Modal's service\n---\n\n## zh-CN\n\nModal的service用法，示例中演示了用户自定义模板、自定义component、以及注入模态框实例的方法。\n\n使用模版作为内容或页脚时的上下文为 ` { $implicit: nzData, modalRef: NzModalRef }`\n\n## en-US\n\nUsage of Modal's service, examples demonstrate user-defined templates, custom components, and methods for injecting modal instances.\n\nThe template context is ` { $implicit: nzData, modalRef: NzModalRef }` when the content or footer is templates.\n"
  },
  {
    "path": "components/modal/demo/service.ts",
    "content": "import { Component, inject, Input, TemplateRef, ViewContainerRef } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzModalRef, NzModalService, NZ_MODAL_DATA, NzModalModule } from 'ng-zorro-antd/modal';\n\ninterface IModalData {\n  favoriteLibrary: string;\n  favoriteFramework: string;\n}\n\n@Component({\n  selector: 'nz-demo-modal-service',\n  imports: [NzButtonModule, NzModalModule],\n  template: `\n    <button nz-button nzType=\"primary\" (click)=\"createModal()\">\n      <span>String</span>\n    </button>\n\n    <button nz-button nzType=\"primary\" (click)=\"createTplModal(tplTitle, tplContent, tplFooter)\">\n      <span>Template</span>\n    </button>\n    <ng-template #tplTitle>\n      <span>Title Template</span>\n    </ng-template>\n    <ng-template #tplContent let-params>\n      <p>some contents...</p>\n      <p>some contents...</p>\n      <p>{{ params?.value }}</p>\n    </ng-template>\n    <ng-template #tplFooter let-ref=\"modalRef\">\n      <button nz-button (click)=\"ref.destroy()\">Destroy</button>\n      <button nz-button nzType=\"primary\" (click)=\"destroyTplModal(ref)\" [nzLoading]=\"tplModalButtonLoading\">\n        Close after submit\n      </button>\n    </ng-template>\n\n    <br />\n    <br />\n\n    <button nz-button nzType=\"primary\" (click)=\"createComponentModal()\">\n      <span>Use Component</span>\n    </button>\n\n    <button nz-button nzType=\"primary\" (click)=\"createCustomButtonModal()\">Custom Button</button>\n\n    <br />\n    <br />\n\n    <button nz-button nzType=\"primary\" (click)=\"openAndCloseAll()\">Open more modals then close all after 2s</button>\n  `,\n  styles: `\n    button {\n      margin-right: 8px;\n    }\n  `\n})\nexport class NzDemoModalServiceComponent {\n  tplModalButtonLoading = false;\n  disabled = false;\n\n  constructor(\n    private modal: NzModalService,\n    private viewContainerRef: ViewContainerRef\n  ) {}\n\n  createModal(): void {\n    this.modal.create({\n      nzTitle: 'Modal Title',\n      nzContent: 'string, will close after 1 sec',\n      nzClosable: false,\n      nzOnOk: () => new Promise(resolve => setTimeout(resolve, 1000))\n    });\n  }\n\n  createTplModal(tplTitle: TemplateRef<{}>, tplContent: TemplateRef<{}>, tplFooter: TemplateRef<{}>): void {\n    this.modal.create({\n      nzTitle: tplTitle,\n      nzContent: tplContent,\n      nzFooter: tplFooter,\n      nzMaskClosable: false,\n      nzClosable: false,\n      nzOnOk: () => console.log('Click ok')\n    });\n  }\n\n  destroyTplModal(modelRef: NzModalRef): void {\n    this.tplModalButtonLoading = true;\n    setTimeout(() => {\n      this.tplModalButtonLoading = false;\n      modelRef.destroy();\n    }, 1000);\n  }\n\n  createComponentModal(): void {\n    const modal = this.modal.create<NzModalCustomComponent, IModalData>({\n      nzTitle: 'Modal Title',\n      nzContent: NzModalCustomComponent,\n      nzViewContainerRef: this.viewContainerRef,\n      nzData: {\n        favoriteLibrary: 'angular',\n        favoriteFramework: 'angular'\n      },\n      nzOnOk: () => new Promise(resolve => setTimeout(resolve, 1000)),\n      nzFooter: [\n        {\n          label: 'change component title from outside',\n          onClick: componentInstance => {\n            componentInstance!.title = 'title in inner component is changed';\n          }\n        }\n      ]\n    });\n    const instance = modal.getContentComponent();\n    modal.afterOpen.subscribe(() => console.log('[afterOpen] emitted!'));\n    // Return a result when closed\n    modal.afterClose.subscribe(result => console.log('[afterClose] The result is:', result));\n\n    // delay until modal instance created\n    setTimeout(() => {\n      instance.subtitle = 'sub title is changed';\n    }, 2000);\n  }\n\n  createCustomButtonModal(): void {\n    const modal: NzModalRef = this.modal.create({\n      nzTitle: 'custom button demo',\n      nzContent: 'pass array of button config to nzFooter to create multiple buttons',\n      nzFooter: [\n        {\n          label: 'Close',\n          shape: 'round',\n          onClick: () => modal.destroy()\n        },\n        {\n          label: 'Confirm',\n          type: 'primary',\n          onClick: () => this.modal.confirm({ nzTitle: 'Confirm Modal Title', nzContent: 'Confirm Modal Content' })\n        },\n        {\n          label: 'Change Button Status',\n          type: 'primary',\n          danger: true,\n          loading: false,\n          onClick(): void {\n            this.loading = true;\n            setTimeout(() => (this.loading = false), 1000);\n            setTimeout(() => {\n              this.loading = false;\n              this.disabled = true;\n              this.label = 'can not be clicked！';\n            }, 2000);\n          }\n        },\n        {\n          label: 'async load',\n          type: 'dashed',\n          onClick: () => new Promise(resolve => setTimeout(resolve, 2000))\n        }\n      ]\n    });\n  }\n\n  openAndCloseAll(): void {\n    let pos = 0;\n\n    ['create', 'info', 'success', 'error'].forEach(method =>\n      // @ts-ignore\n      this.modal[method]({\n        nzMask: false,\n        nzTitle: `Test ${method} title`,\n        nzContent: `Test content: <b>${method}</b>`,\n        nzStyle: { position: 'absolute', top: `${pos * 70}px`, left: `${pos++ * 300}px` }\n      })\n    );\n\n    this.modal.afterAllClose.subscribe(() => console.log('afterAllClose emitted!'));\n\n    setTimeout(() => this.modal.closeAll(), 2000);\n  }\n}\n\n@Component({\n  selector: 'nz-modal-custom-component',\n  imports: [NzButtonModule],\n  template: `\n    <h2>{{ title }}</h2>\n    <h4>{{ subtitle }}</h4>\n    <p>\n      My favorite framework is {{ nzModalData.favoriteFramework }} and my favorite library is\n      {{ nzModalData.favoriteLibrary }}\n    </p>\n    <br />\n    <button nz-button (click)=\"destroyModal()\">destroy modal in the component</button>\n  `\n})\nexport class NzModalCustomComponent {\n  @Input() title?: string;\n  @Input() subtitle?: string;\n\n  readonly modalRef = inject(NzModalRef);\n  readonly nzModalData = inject<IModalData>(NZ_MODAL_DATA);\n\n  destroyModal(): void {\n    this.modalRef.destroy({ data: 'this the result data' });\n  }\n}\n"
  },
  {
    "path": "components/modal/doc/index.en-US.md",
    "content": "---\ntype: Feedback\ncategory: Components\ntitle: Modal\ncover: 'https://gw.alipayobjects.com/zos/alicdn/3StSdUlSH/Modal.svg'\ndescription: Display a modal dialog box, providing a title, content area, and action buttons.\n---\n\n## When To Use\n\nWhen requiring users to interact with the application without jumping to a new page to interrupt the user's workflow,\nyou can use `Modal` to create a new overlay layer over the current page for user-getting feedback or information\npurposes. Additionally, if you need to show a simple confirmation dialog, you can use `NzModalService.confirm()` and so\non.\n\nIt is recommended to use the `Component` way to pop up the Modal so that the component logic of the popup layer can be\ncompletely isolated from the outer component and reused at any time. In the popup layer component, you can obtain\nModal's component instance by injecting `NzModalRef` to control the behavior of the modal box.\n\n## API\n\n### NzModalService\n\nThe dialog is currently divided into 2 modes, `normal mode` and `confirm box mode` (for instance, the `Confirm` dialog,\nwhich is called by `confirm/info/success/error/warning`). The degree of API support for the two modes is slightly\ndifferent.\n\n| Property              | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                | Type                                                                                             | Default               | Global Config |\n| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------ | --------------------- | ------------- |\n| `nzAfterOpen`         | Specify a EventEmitter that will be emitted when modal opened                                                                                                                                                                                                                                                                                                                                                                                                                              | `EventEmitter`                                                                                   | -                     |\n| `nzAfterClose`        | Specify a EventEmitter that will be emitted when modal is closed completely (Can listen for parameters passed in the close/destroy method)                                                                                                                                                                                                                                                                                                                                                 | `EventEmitter`                                                                                   | -                     |\n| `nzBodyStyle`         | Body style for modal body element. Such as height, padding etc.                                                                                                                                                                                                                                                                                                                                                                                                                            | `object`                                                                                         | -                     |\n| `nzCancelText`        | Text of the Cancel button. <i>Set to null to show no cancel button (this value is invalid if the nzFooter parameter is used in normal mode)</i>                                                                                                                                                                                                                                                                                                                                            | `string`                                                                                         | `'Cancel'`            |\n| `nzCentered`          | Centered Modal                                                                                                                                                                                                                                                                                                                                                                                                                                                                             | `boolean`                                                                                        | `false`               |\n| `nzClosable`          | Whether a close (x) button is visible on top right of the modal dialog or not. <i>Invalid value in confirm box mode (default will be hidden)</i>                                                                                                                                                                                                                                                                                                                                           | `boolean`                                                                                        | `true`                |\n| `nzOkLoading`         | Whether to apply loading visual effect for OK button or not                                                                                                                                                                                                                                                                                                                                                                                                                                | `boolean`                                                                                        | `false`               |\n| `nzCancelLoading`     | Whether to apply loading visual effect for Cancel button or not                                                                                                                                                                                                                                                                                                                                                                                                                            | `boolean`                                                                                        | `false`               |\n| `nzOkDisabled`        | Whether to disable Ok button or not                                                                                                                                                                                                                                                                                                                                                                                                                                                        | `boolean`                                                                                        | `false`               |\n| `nzCancelDisabled`    | Whether to disable Cancel button or not                                                                                                                                                                                                                                                                                                                                                                                                                                                    | `boolean`                                                                                        | `false`               |\n| `nzDraggable`         | Whether modal is draggable or not                                                                                                                                                                                                                                                                                                                                                                                                                                                          | `boolean`                                                                                        | `false`               |\n| `nzFooter`            | Footer content, set as footer=null when you don't need default buttons. <br><i>1. Only valid in normal mode.<br>2. You can customize the buttons to the maximum extent by passing a `ModalButtonOptions` configuration (see the case or the instructions below).</i>                                                                                                                                                                                                                       | `string \\| TemplateRef<{}> \\| ModalButtonOptions[] \\| null`                                      | OK and Cancel buttons |\n| `nzKeyboard`          | Whether support press esc to close                                                                                                                                                                                                                                                                                                                                                                                                                                                         | `boolean`                                                                                        | `true`                |\n| `nzMask`              | Whether show mask or not.                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | `boolean`                                                                                        | `true`                | ✅            |\n| `nzMaskClosable`      | Whether to close the modal dialog when the mask (area outside the modal) is clicked                                                                                                                                                                                                                                                                                                                                                                                                        | `boolean`                                                                                        | `true`                | ✅            |\n| `nzCloseOnNavigation` | Whether to close the modal when the user goes backwards/forwards in history. Note that this usually doesn't include clicking on links (unless the user is using the HashLocationStrategy).                                                                                                                                                                                                                                                                                                 | `boolean`                                                                                        | `true`                | ✅            |\n| `nzDirection`         | Direction of the text in the modal                                                                                                                                                                                                                                                                                                                                                                                                                                                         | `'ltr' \\| 'rtl'`                                                                                 | -                     | ✅            |\n| `nzMaskStyle`         | Style for modal's mask element.                                                                                                                                                                                                                                                                                                                                                                                                                                                            | `object`                                                                                         | -                     |\n| `nzOkText`            | Text of the OK button. <i>Set to null to show no ok button (this value is invalid if the nzFooter parameter is used in normal mode)</i>                                                                                                                                                                                                                                                                                                                                                    | `string`                                                                                         | `'OK'`                |\n| `nzOkType`            | Button type of the OK button. <i>Consistent with the `nzType` of the `nz-button`.</i>                                                                                                                                                                                                                                                                                                                                                                                                      | `'primary' \\|'dashed' \\|'link' \\|'text'`                                                         | `primary`             |\n| `nzOkDanger`          | Danger status of the OK button. <i>Consistent with the `nzDanger` of the `nz-button`.</i>                                                                                                                                                                                                                                                                                                                                                                                                  | `boolean`                                                                                        | `false`               |\n| `nzStyle`             | Style of overlay layer, typically used at least for adjusting the position.                                                                                                                                                                                                                                                                                                                                                                                                                | `object`                                                                                         | -                     |\n| `nzCloseIcon`         | Custom close icon                                                                                                                                                                                                                                                                                                                                                                                                                                                                          | `string \\| TemplateRef<void>`                                                                    | -                     |\n| `nzTitle`             | The modal dialog's title. <i>Leave blank to show no title. The usage of TemplateRef can refer to the case</i>                                                                                                                                                                                                                                                                                                                                                                              | `string \\| TemplateRef<{}>`                                                                      | -                     |\n| `nzVisible`           | Whether the modal dialog is visible or not. <i>When using the `<nz-modal>` tag, be sure to use two-way binding, for example: `[(nzVisible)]=\"visible\"`.</i>                                                                                                                                                                                                                                                                                                                                | `boolean`                                                                                        | `false`               |\n| `nzWidth`             | Width of the modal dialog. <i>When using numbers, the default unit is `px`</i>                                                                                                                                                                                                                                                                                                                                                                                                             | `string \\| number`                                                                               | `520`                 |\n| `nzClassName`         | The class name of the modal dialog                                                                                                                                                                                                                                                                                                                                                                                                                                                         | `string`                                                                                         | -                     |\n| `nzWrapClassName`     | The class name of the container of the modal dialog                                                                                                                                                                                                                                                                                                                                                                                                                                        | `string`                                                                                         | -                     |\n| `nzZIndex`            | The z-index of the Modal                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | `number`                                                                                         | `1000`                |\n| `nzOnCancel`          | Specify a function that will be called when a user clicks mask, close button on top right or Cancel button (If nzContent is Component, the Component instance will be put in as an argument). <i>Note: When created with `NzModalService.create`, this parameter should be passed into the type of function (callback function). This function returns a promise, which is automatically closed when the execution is complete or the promise ends (return `false` to prevent closing)</i> | `EventEmitter`                                                                                   | -                     |\n| `nzOnOk`              | Specify a EventEmitter that will be emitted when a user clicks the OK button (If nzContent is Component, the Component instance will be put in as an argument). <i>Note: When created with `NzModalService.create`, this parameter should be passed into the type of function (callback function). This function returns a promise, which is automatically closed when the execution is complete or the promise ends (return `false` to prevent closing)</i>                               | `EventEmitter`                                                                                   | -                     |\n| `nzContent`           | Content                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | `string \\| TemplateRef<{}> \\| Component \\| ng-content`                                           | -                     |\n| `nzData`              | Will be a template variable when `nzContent` is `TemplateRef`                                                                                                                                                                                                                                                                                                                                                                                                                              | `object`, will be the value of the injection token NZ_MODAL_DATA when `nzContent` is a component | -                     |\n| `nzIconType`          | Icon type of the Icon component. <i>Only valid in confirm box mode</i>                                                                                                                                                                                                                                                                                                                                                                                                                     | `string`                                                                                         | `'question-circle'`   |\n| `nzAutofocus`         | autofocus and the position，disabled when is `null`                                                                                                                                                                                                                                                                                                                                                                                                                                        | `'ok' \\| 'cancel' \\| 'auto' \\| null`                                                             | `'auto'`              |\n\n#### NZ_MODAL_DATA\n\n> NZ_MODAL_DATA injection token is used to retrieve `nzData` in the custom component.\n> The dialog created by the service method `NzModalService.create()` inject a `NZ_MODAL_DATA` token (if `nzContent` is\n> used as Component) to retrieve the parameters that have used to the '`nzContent` component'\n\n#### Using service to create Normal Mode modal\n\n> You can call `NzModalService.create(options)` to dynamically create **normal mode** modals, where `options` is an\n> object that supports the support given in the API above **normal mode** parameters\n\n### Confirm box mode - NzModalService.method()\n\nThere are five ways to display the information based on the content's nature:\n\n- `NzModalService.info`\n- `NzModalService.success`\n- `NzModalService.error`\n- `NzModalService.warning`\n- `NzModalService.confirm`\n\nThe above items are all functions, expecting a settings object as a parameter.\nConsistent with the above API, some property types or initial values are different as follows:\n\n| Property         | Description                                                                                                                                                                                                                                                                                                                                                 | Type               | Default |\n| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ------- |\n| `nzOnOk`         | Specify a EventEmitter that will be emitted when a user clicks the OK button (If nzContent is Component, the Component instance will be put in as an argument.). <i>This function returns a promise, which is automatically closed when the execution is complete or the promise ends (return `false` to prevent closing)</i>                               | `function`         | -       |\n| `nzOnCancel`     | Specify a function that will be called when a user clicks mask, close button on top right or Cancel button (If nzContent is Component, the Component instance will be put in as an argument.). <i>This function returns a promise, which is automatically closed when the execution is complete or the promise ends (return `false` to prevent closing)</i> | `function`         | -       |\n| `nzWidth`        | Width of the modal dialog                                                                                                                                                                                                                                                                                                                                   | `string \\| number` | `416`   |\n| `nzMaskClosable` | Whether to close the modal dialog when the mask (area outside the modal) is clicked                                                                                                                                                                                                                                                                         | `boolean`          | `false` |\n\nAll the `NzModalService.method`s will return a reference, and then we can close the popup by the reference.\n\n```ts\nconstructor(modal: NzModalService) {\n  const ref: NzModalRef = modal.info();\n  ref.close(); // Or ref.destroy(); This dialog will be destroyed directly\n}\n```\n\n### Related type definition\n\n#### Other Methods/Attributes for NzModalService\n\n| Methods/Attributes | Description                                        | Type               |\n| ------------------ | -------------------------------------------------- | ------------------ |\n| `openModals`       | All currently open Modal list                      | `NzModalRef[]`     |\n| `afterAllClose`    | Callback called after all Modals closed completely | `Observable<void>` |\n| `closeAll()`       | Close all modals                                   | `function`         |\n\n#### NzModalRef\n\n> `NzModalRef` object is used to control dialogs and communicate with their content\n\nThe dialog created by the service method `NzModalService.xxx()` will return a `NzModalRef` object that is used to\nmanipulate the dialog (this object can also be obtained by dependency injection `NzModalRef` if `nzContent` is used as\nComponent), This object has the following methods:\n\n| Method                                     | Description                                                                                                                                                                                     |\n| ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `afterOpen`                                | Same as nzAfterOpen but of type Observable&lt;void&gt;                                                                                                                                          |\n| `afterClose`                               | Same as nzAfterClose, but of type Observable&lt;result:any&gt;                                                                                                                                  |\n| `close()`                                  | Close (hide) the dialog. <i>Note: When used for a dialog created as a service, this method will destroy the dialog directly (as with the destroy method)</i>                                    |\n| `destroy()`                                | Destroy the dialog. <i>Note: Used only for dialogs created by the service (non-service created dialogs, this method only hides the dialog)</i>                                                  |\n| `getContentComponent()`                    | Gets the Component instance in the contents of the dialog for `nzContent`. <i> Note: When the dialog is not initialized (`ngOnInit` is not executed), this function will return `undefined`</i> |\n| `getContentComponentRef()`                 | Gets the Component ref in the contents of the dialog for `nzContent`. <i> Note: When the dialog is not initialized (`ngOnInit` is not executed), this function will return `null`</i>           |\n| `triggerOk()`                              | Manually trigger nzOnOk                                                                                                                                                                         |\n| `triggerCancel()`                          | Manually trigger nzOnCancel                                                                                                                                                                     |\n| `updateConfig(config: ModalOptions): void` | Update the config                                                                                                                                                                               |\n\n### ModalButtonOptions (used to customize the bottom button)\n\nAn array of `ModalButtonOptions` type can be passed to `nzFooter` for custom bottom buttons.\n\nThe button configuration items are as follows (along with the button component):\n\n```ts\nnzFooter: [{\n  label: string; // Button text\n  type? : string; // Types\n  danger? : boolean; // Whether danger\n  shape? : string; // Shape\n  ghost? : boolean; // Whether ghost\n  size? : string; // Size\n  autoLoading? : boolean; // The default is true. If true, this button will automatically be set to the loading state when onClick returns a promise.\n\n  // Tip: The `this` of below methods points to the configuration object itself. When nzContent is a component class, the contentComponentInstance parameter passed in by the method below is an instance of the component class\n  // Whether to show this button\n  show? : boolean | ((this: ModalButtonOptions, contentComponentInstance?: object) => boolean);\n  // Whether to display loading\n  loading? : boolean | ((this: ModalButtonOptions, contentComponentInstance?: object) => boolean);\n  // Is it disabled\n  disabled? : boolean | ((this: ModalButtonOptions, contentComponentInstance?: object) => boolean);\n  // Callback of clicking\n  onClick? (this: ModalButtonOptions, contentComponentInstance?: object): void | Promise<void> | any;\n}]\n```\n\nThe above configuration items can also be changed in real-time to trigger the button behavior change.\n\n### [nzModalTitle]\n\nCustomize the title.\n\n```html\n<div *nzModalTitle> Custom Modal Title</div>\n\n<!-- or -->\n\n<ng-template [nzModalTitle]> Custom Modal Title</ng-template>\n```\n\n### [nzModalContent]\n\nCustomize the content.\n\n```html\n<div *nzModalContent> Custom Modal Content</div>\n\n<!-- or -->\n\n<ng-template [nzModalContent]> Custom Modal Content</ng-template>\n```\n\n### [nzModalFooter]\n\nCustomize the footer.\n\n```html\n<div *nzModalFooter>\n  <button nz-button nzType=\"default\" (click)=\"handleCancel()\">Custom Callback</button>\n  <button nz-button nzType=\"primary\" (click)=\"handleOk()\" [nzLoading]=\"isConfirmLoading\">Custom Submit</button>\n</div>\n\n<!-- or -->\n\n<ng-template [nzModalFooter]>\n  <button nz-button nzType=\"default\" (click)=\"handleCancel()\">Custom Callback</button>\n  <button nz-button nzType=\"primary\" (click)=\"handleOk()\" [nzLoading]=\"isConfirmLoading\">Custom Submit</button>\n</ng-template>\n```\n"
  },
  {
    "path": "components/modal/doc/index.zh-CN.md",
    "content": "---\ntype: 反馈\ncategory: Components\nsubtitle: 对话框\ntitle: Modal\ncover: 'https://gw.alipayobjects.com/zos/alicdn/3StSdUlSH/Modal.svg'\ndescription: 展示一个对话框，提供标题、内容区、操作区。\n---\n\n## 何时使用\n\n需要用户处理事务，又不希望跳转页面以致打断工作流程时，可以使用 `Modal` 在当前页面正中打开一个浮层，承载相应的操作。\n\n另外当需要一个简洁的确认框询问用户时，可以使用精心封装好的 `NzModalService.confirm()` 等方法。\n\n推荐使用加载 Component 的方式弹出 Modal，这样弹出层的 Component 逻辑可以与外层 Component 完全隔离，并且做到可以随时复用，\n\n在弹出层 Component 中可以通过依赖注入`NzModalRef`方式直接获取模态框的组件实例，用于控制在弹出层组件中控制模态框行为。\n\n## API\n\n### NzModalService\n\n对话框当前分为 2 种模式，`普通模式` 和 `确认框模式`（即`Confirm`对话框，通过调用`confirm/info/success/error/warning`弹出），两种模式对 API 的支持程度稍有不同。\n\n| 参数                  | 说明                                                                                                                                                                                                                                                                                | 类型                                                        | 默认值              | 全局配置 |\n| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- | ------------------- | -------- |\n| `nzAfterOpen`         | Modal 打开后的回调                                                                                                                                                                                                                                                                  | `EventEmitter`                                              | -                   |\n| `nzAfterClose`        | Modal 完全关闭后的回调，可监听 close/destroy 方法传入的参数                                                                                                                                                                                                                         | `EventEmitter`                                              | -                   |\n| `nzBodyStyle`         | Modal body 样式                                                                                                                                                                                                                                                                     | `object`                                                    | -                   |\n| `nzCancelText`        | 取消按钮文字。<i>设为 null 表示不显示取消按钮（若在普通模式下使用了 nzFooter 参数，则该值无效）</i>                                                                                                                                                                                 | `string`                                                    | `'取消'`            |\n| `nzCentered`          | 垂直居中展示 Modal                                                                                                                                                                                                                                                                  | `boolean`                                                   | `false`             |\n| `nzClosable`          | 是否显示右上角的关闭按钮。<i>确认框模式下该值无效（默认会被隐藏）</i>                                                                                                                                                                                                               | `boolean`                                                   | `true`              |\n| `nzOkLoading`         | 确定按钮 loading                                                                                                                                                                                                                                                                    | `boolean`                                                   | `false`             |\n| `nzCancelLoading`     | 取消按钮 loading                                                                                                                                                                                                                                                                    | `boolean`                                                   | `false`             |\n| `nzOkDisabled`        | 是否禁用确定按钮                                                                                                                                                                                                                                                                    | `boolean`                                                   | `false`             |\n| `nzCancelDisabled`    | 是否禁用取消按钮                                                                                                                                                                                                                                                                    | `boolean`                                                   | `false`             |\n| `nzDraggable`         | 模态框是否可拖动                                                                                                                                                                                                                                                                    | `boolean`                                                   | `false`             |\n| `nzFooter`            | 底部内容。<br><i>1. 仅在普通模式下有效。<br>2. 可通过传入 ModalButtonOptions 来最大程度自定义按钮（详见案例或下方说明）。<br>3. 当不需要底部时，可以设为 null</i>                                                                                                                   | `string \\| TemplateRef<{}> \\| ModalButtonOptions[] \\| null` | 默认的确定取消按钮  |\n| `nzKeyboard`          | 是否支持键盘 esc 关闭                                                                                                                                                                                                                                                               | `boolean`                                                   | `true`              |\n| `nzMask`              | 是否展示遮罩                                                                                                                                                                                                                                                                        | `boolean`                                                   | `true`              | ✅       |\n| `nzMaskClosable`      | 点击蒙层是否允许关闭                                                                                                                                                                                                                                                                | `boolean`                                                   | `true`              | ✅       |\n| `nzCloseOnNavigation` | 当用户在历史中前进/后退时是否关闭模态框。注意，这通常不包括点击链接（除非用户使用 HashLocationStrategy）。                                                                                                                                                                          | `boolean`                                                   | `true`              | ✅       |\n| `nzDirection`         | 文字方向                                                                                                                                                                                                                                                                            | `'ltr' \\| 'rtl'`                                            | -                   | ✅       |\n| `nzMaskStyle`         | 遮罩样式                                                                                                                                                                                                                                                                            | `object`                                                    | -                   |\n| `nzOkText`            | 确认按钮文字。<i>设为 null 表示不显示确认按钮（若在普通模式下使用了 nzFooter 参数，则该值无效）</i>                                                                                                                                                                                 | `string`                                                    | `'确定'`            |\n| `nzOkType`            | 确认按钮类型。<i>与 `nz-button` 的 `nzType` 类型值一致</i>                                                                                                                                                                                                                          | `string`                                                    | `primary`           |\n| `nzOkDanger`          | 确认按钮是否为危险按钮。<i>与 `nz-button` 的 `nzDanger` 值保持一致</i>                                                                                                                                                                                                              | `boolean`                                                   | `false`             |\n| `nzStyle`             | 可用于设置浮层的样式，调整浮层位置等                                                                                                                                                                                                                                                | `object`                                                    | -                   |\n| `nzTitle`             | 标题。<i>留空表示不展示标题。TemplateRef 的使用方法可参考案例</i>                                                                                                                                                                                                                   | `string \\| TemplateRef<{}>`                                 | -                   |\n| `nzCloseIcon`         | 自定义关闭图标                                                                                                                                                                                                                                                                      | `string \\| TemplateRef<void>`                               | -                   |\n| `nzVisible`           | 对话框是否可见。<i>当以 `<nz-modal>` 标签使用时，请务必使用双向绑定，例如：`[(nzVisible)]=\"visible\"`</i>                                                                                                                                                                            | `boolean`                                                   | `false`             |\n| `nzWidth`             | 宽度。<i>使用数字时，默认单位为 px</i>                                                                                                                                                                                                                                              | `string \\| number`                                          | `520`               |\n| `nzClassName`         | 对话框的类名                                                                                                                                                                                                                                                                        | `string`                                                    | -                   |\n| `nzWrapClassName`     | 对话框外层容器的类名                                                                                                                                                                                                                                                                | `string`                                                    | -                   |\n| `nzZIndex`            | 设置 Modal 的 `z-index`                                                                                                                                                                                                                                                             | `number`                                                    | `1000`              |\n| `nzOnCancel`          | 点击遮罩层或右上角叉或取消按钮的回调（若 nzContent 为 Component，则将会以该 Component 实例作为参数）。<i>注：当以`NzModalService.create`创建时，此参数应传入 function（回调函数）。该函数可返回 promise，待执行完毕或 promise 结束时，将自动关闭对话框（返回 false 可阻止关闭）</i> | `EventEmitter`                                              | -                   |\n| `nzOnOk`              | 点击确定回调（若 nzContent 为 Component，则将会以该 Component 实例作为参数）。<i>注：当以`NzModalService.create`创建时，此参数应传入 function（回调函数）。该函数可返回 promise，待执行完毕或 promise 结束时，将自动关闭对话框（返回 false 可阻止关闭）</i>                         | `EventEmitter`                                              | -                   |\n| `nzContent`           | 内容                                                                                                                                                                                                                                                                                | `string \\| TemplateRef<{}> \\| Component \\| ng-content`      | -                   |\n| `nzIconType`          | 图标 Icon 类型。<i>仅 确认框模式 下有效</i>                                                                                                                                                                                                                                         | `string`                                                    | `'question-circle'` |\n| `nzAutofocus`         | 自动聚焦及聚焦位置，为 `null` 时禁用                                                                                                                                                                                                                                                | `'ok' \\| 'cancel' \\| 'auto' \\| null`                        | `'auto'`            |\n\n#### 采用服务方式创建普通模式对话框\n\n> 您可调用 `NzModalService.create(options)` 来动态创建**普通模式**对话框，这里的 `options` 是一个对象，支持上方 API 中给出的支持 **普通模式** 的参数\n\n### 确认框模式 - NzModalService.method()\n\n包括：\n\n- `NzModalService.info`\n- `NzModalService.success`\n- `NzModalService.error`\n- `NzModalService.warning`\n- `NzModalService.confirm`\n\n以上均为一个函数，参数为 object，与上方 API 一致。部分属性类型或初始值有所不同，已列在下方：\n\n| 参数             | 说明                                                                                                                                                                                                      | 类型               | 默认值  |\n| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ------- |\n| `nzOnOk`         | 点击确定按钮时将执行的回调函数（若 nzContent 为 Component，则将会以该 Component 实例作为参数）。<i>该函数可返回 promise，待执行完毕或 promise 结束时，将自动关闭对话框（返回 false 可阻止关闭）</i>       | `function`         | -       |\n| `nzOnCancel`     | 点击遮罩层或右上角叉或取消按钮的回调（若 nzContent 为 Component，则将会以该 Component 实例作为参数）。<i>该函数可返回 promise，待执行完毕或 promise 结束时，将自动关闭对话框（返回 false 可阻止关闭）</i> | `function`         | -       |\n| `nzWidth`        | 宽度                                                                                                                                                                                                      | `string \\| number` | `416`   |\n| `nzMaskClosable` | 点击蒙层是否允许关闭                                                                                                                                                                                      | `boolean`          | `false` |\n\n以上函数调用后，会返回一个引用，可以通过该引用关闭弹窗。\n\n```ts\nconstructor(modal: NzModalService) {\n  const ref: NzModalRef = modal.info();\n  ref.close(); // 或 ref.destroy(); 将直接销毁对话框\n}\n```\n\n### 相关类型定义\n\n#### NzModalService 的其他方法/属性\n\n| 方法/属性       | 说明                          | 类型               |\n| --------------- | ----------------------------- | ------------------ |\n| `openModals`    | 当前打开的所有 Modal 引用列表 | `NzModalRef[]`     |\n| `afterAllClose` | 所有 Modal 完全关闭后的回调   | `Observable<void>` |\n| `closeAll()`    | 关闭所有模态框                | `function`         |\n\n#### NzModalRef\n\n> NzModalRef 对象用于控制对话框以及进行内容间的通信\n\n通过服务方式 `NzModalService.xxx()` 创建的对话框，都会返回一个 `NzModalRef` 对象，用于操控该对话框（若使用 nzContent 为 Component 时，也可通过依赖注入 `NzModalRef` 方式获得此对象），该对象具有以下方法：\n\n| 方法/属性                                  | 说明                                                                                                                                    |\n| ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |\n| `afterOpen`                                | 同 nzAfterOpen，但类型为 Observable&lt;void&gt;                                                                                         |\n| `afterClose`                               | 同 nzAfterClose，但类型为 Observable&lt;result:any&gt;                                                                                  |\n| `close(result: any)`                       | 关闭(隐藏)对话框。<i>注：当用于以服务方式创建的对话框，此方法将直接 销毁 对话框（同 destroy 方法）</i>                                  |\n| `destroy(result: any)`                     | 销毁对话框。<i>注：仅用于服务方式创建的对话框（非服务方式创建的对话框，此方法只会隐藏对话框）</i>                                       |\n| `getContentComponent()`                    | 获取对话框内容中`nzContent`的 Component 实例 instance。<i>注：当对话框还未初始化完毕（`ngOnInit`未执行）时，此函数将返回`undefined`</i> |\n| `getContentComponentRef()`                 | 获取对话框内容中`nzContent`的 Component 引用 ComponentRef。<i>注：当对话框还未初始化完毕（`ngOnInit`未执行）时，此函数将返回`null`</i>  |\n| `triggerOk()`                              | 手动触发 nzOnOk                                                                                                                         |\n| `triggerCancel()`                          | 手动触发 nzOnCancel                                                                                                                     |\n| `updateConfig(config: ModalOptions): void` | 更新配置                                                                                                                                |\n\n### ModalButtonOptions（用于自定义底部按钮）\n\n可将此类型数组传入 `nzFooter`，用于自定义底部按钮。\n\n按钮配置项如下（与 button 组件保持一致）：\n\n```ts\nnzFooter: [{\n  label: string; // 按钮文本\n  type?: string; // 类型\n  danger?: boolean; // 是否danger\n  shape?: string; // 形状\n  ghost?: boolean; // 是否ghost\n  size?: string; // 大小\n  autoLoading?: boolean; // 默认为true，若为true时，当onClick返回promise时此按钮将自动置为loading状态\n\n  // 提示：下方方法的this指向该配置对象自身。当nzContent为组件类时，下方方法传入的contentComponentInstance参数为该组件类的实例\n  // 是否显示该按钮\n  show?: boolean | ((this: ModalButtonOptions, contentComponentInstance?: object) => boolean);\n  // 是否显示为loading\n  loading?: boolean | ((this: ModalButtonOptions, contentComponentInstance?: object) => boolean);\n  // 是否禁用\n  disabled?: boolean | ((this: ModalButtonOptions, contentComponentInstance?: object) => boolean);\n  // 按钮点击回调\n  onClick?(this: ModalButtonOptions, contentComponentInstance?: object): void | Promise<void> | any;\n}]\n```\n\n以上配置项也可在运行态实时改变，来触发按钮行为改变。\n\n### [nzModalTitle]\n\n自定义标题。\n\n```html\n<div *nzModalTitle> Custom Modal Title </div>\n\n<!-- or -->\n\n<ng-template [nzModalTitle]> Custom Modal Title </ng-template>\n```\n\n### [nzModalContent]\n\n自定义内容。\n\n```html\n<div *nzModalContent> Custom Modal Content </div>\n\n<!-- or -->\n\n<ng-template [nzModalContent]> Custom Modal Content </ng-template>\n```\n\n### [nzModalFooter]\n\n自定义页脚。\n\n```html\n<div *nzModalFooter>\n  <button nz-button nzType=\"default\" (click)=\"handleCancel()\">Custom Callback</button>\n  <button nz-button nzType=\"primary\" (click)=\"handleOk()\" [nzLoading]=\"isConfirmLoading\">Custom Submit</button>\n</div>\n\n<!-- or -->\n\n<ng-template [nzModalFooter]>\n  <button nz-button nzType=\"default\" (click)=\"handleCancel()\">Custom Callback</button>\n  <button nz-button nzType=\"primary\" (click)=\"handleOk()\" [nzLoading]=\"isConfirmLoading\">Custom Submit</button>\n</ng-template>\n```\n"
  },
  {
    "path": "components/modal/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/modal/modal-close.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, inject } from '@angular/core';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nimport { ModalOptions } from './modal-types';\n\n@Component({\n  selector: 'button[nz-modal-close]',\n  exportAs: 'nzModalCloseBuiltin',\n  template: `\n    <span class=\"ant-modal-close-x\">\n      <ng-container *nzStringTemplateOutlet=\"config.nzCloseIcon; let closeIcon\">\n        <nz-icon [nzType]=\"closeIcon\" class=\"ant-modal-close-icon\" />\n      </ng-container>\n    </span>\n  `,\n  host: {\n    class: 'ant-modal-close',\n    'aria-label': 'Close'\n  },\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  imports: [NzIconModule, NzOutletModule]\n})\nexport class NzModalCloseComponent {\n  public readonly config = inject(ModalOptions);\n}\n"
  },
  {
    "path": "components/modal/modal-config.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { InjectionToken } from '@angular/core';\n\nimport { NzConfigKey } from 'ng-zorro-antd/core/config';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nexport const ZOOM_CLASS_NAME_MAP = {\n  enter: 'ant-zoom-enter',\n  enterActive: 'ant-zoom-enter-active',\n  leave: 'ant-zoom-leave',\n  leaveActive: 'ant-zoom-leave-active'\n};\n\nexport const FADE_CLASS_NAME_MAP = {\n  enter: 'ant-fade-enter',\n  enterActive: 'ant-fade-enter-active',\n  leave: 'ant-fade-leave',\n  leaveActive: 'ant-fade-leave-active'\n};\n\nexport const MODAL_MASK_CLASS_NAME = 'ant-modal-mask';\nexport const NZ_CONFIG_MODULE_NAME: NzConfigKey = 'modal';\nexport const NZ_MODAL_DATA = new InjectionToken<NzSafeAny>(\n  typeof ngDevMode !== 'undefined' && ngDevMode ? 'nz-modal-data' : ''\n);\n"
  },
  {
    "path": "components/modal/modal-confirm-container.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { CdkScrollable } from '@angular/cdk/overlay';\nimport { CdkPortalOutlet, PortalModule } from '@angular/cdk/portal';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  ElementRef,\n  EventEmitter,\n  OnInit,\n  Output,\n  ViewChild,\n  inject\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzI18nService, NzModalI18nInterface } from 'ng-zorro-antd/i18n';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzPipesModule } from 'ng-zorro-antd/pipes';\n\nimport { NzModalCloseComponent } from './modal-close.component';\nimport { BaseModalContainerComponent } from './modal-container.directive';\n\n@Component({\n  selector: 'nz-modal-confirm-container',\n  exportAs: 'nzModalConfirmContainer',\n  template: `\n    <div\n      #modalElement\n      role=\"document\"\n      class=\"ant-modal\"\n      [class]=\"config.nzClassName!\"\n      [style]=\"config.nzStyle!\"\n      [style.width]=\"config?.nzWidth! | nzToCssUnit\"\n    >\n      <div class=\"ant-modal-content\">\n        @if (config.nzClosable) {\n          <button nz-modal-close (click)=\"onCloseClick()\"></button>\n        }\n\n        <div class=\"ant-modal-body\" [style]=\"config.nzBodyStyle!\">\n          <div class=\"ant-modal-confirm-body-wrapper\">\n            <div class=\"ant-modal-confirm-body\">\n              <nz-icon [nzType]=\"config.nzIconType!\" />\n              <span class=\"ant-modal-confirm-title\">\n                <ng-container *nzStringTemplateOutlet=\"config.nzTitle\">\n                  <span [innerHTML]=\"config.nzTitle\"></span>\n                </ng-container>\n              </span>\n              <div class=\"ant-modal-confirm-content\">\n                <ng-template cdkPortalOutlet />\n                @if (isStringContent) {\n                  <div [innerHTML]=\"config.nzContent\"></div>\n                }\n              </div>\n            </div>\n            <div class=\"ant-modal-confirm-btns\">\n              @if (config.nzCancelText !== null) {\n                <button\n                  [attr.cdkFocusInitial]=\"config.nzAutofocus === 'cancel' || null\"\n                  nz-button\n                  (click)=\"onCancel()\"\n                  [nzLoading]=\"config.nzCancelLoading\"\n                  [disabled]=\"config.nzCancelDisabled\"\n                >\n                  {{ config.nzCancelText || locale.cancelText }}\n                </button>\n              }\n              @if (config.nzOkText !== null) {\n                <button\n                  [attr.cdkFocusInitial]=\"config.nzAutofocus === 'ok' || null\"\n                  nz-button\n                  [nzType]=\"config.nzOkType!\"\n                  (click)=\"onOk()\"\n                  [nzLoading]=\"config.nzOkLoading\"\n                  [disabled]=\"config.nzOkDisabled\"\n                  [nzDanger]=\"config.nzOkDanger\"\n                >\n                  {{ config.nzOkText || locale.okText }}\n                </button>\n              }\n            </div>\n          </div>\n        </div>\n      </div>\n    </div>\n  `,\n  hostDirectives: [CdkScrollable],\n  // Using OnPush for modal caused footer can not to detect changes. we can fix it when 8.x.\n  changeDetection: ChangeDetectionStrategy.Default,\n  host: {\n    tabindex: '-1',\n    role: 'dialog',\n    '[class]': 'config.nzWrapClassName ? \"ant-modal-wrap \" + config.nzWrapClassName : \"ant-modal-wrap\"',\n    '[class.ant-modal-wrap-rtl]': `dir === 'rtl'`,\n    '[class.ant-modal-centered]': 'config.nzCentered',\n    '[style.zIndex]': 'config.nzZIndex',\n    '(click)': 'onContainerClick($event)'\n  },\n  imports: [NzPipesModule, NzIconModule, NzModalCloseComponent, NzOutletModule, PortalModule, NzButtonModule]\n})\nexport class NzModalConfirmContainerComponent extends BaseModalContainerComponent implements OnInit {\n  private i18n = inject(NzI18nService);\n\n  @ViewChild(CdkPortalOutlet, { static: true }) set _portalOutlet(portalOutlet: CdkPortalOutlet) {\n    this.portalOutlet = portalOutlet;\n  }\n  @ViewChild('modalElement', { static: true }) set _modalElementRef(elementRef: ElementRef<HTMLDivElement>) {\n    this.modalElementRef = elementRef;\n  }\n  @Output() override readonly cancelTriggered = new EventEmitter<void>();\n  @Output() override readonly okTriggered = new EventEmitter<void>();\n  locale!: NzModalI18nInterface;\n\n  constructor() {\n    super();\n\n    this.i18n.localeChange.pipe(takeUntilDestroyed()).subscribe(() => {\n      this.locale = this.i18n.getLocaleData('Modal');\n    });\n  }\n\n  ngOnInit(): void {\n    this.setupMouseListeners(this.modalElementRef);\n  }\n\n  onCancel(): void {\n    this.cancelTriggered.emit();\n  }\n\n  onOk(): void {\n    this.okTriggered.emit();\n  }\n}\n"
  },
  {
    "path": "components/modal/modal-container.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { CdkDrag, CdkDragHandle } from '@angular/cdk/drag-drop';\nimport { CdkScrollable } from '@angular/cdk/overlay';\nimport { CdkPortalOutlet, PortalModule } from '@angular/cdk/portal';\nimport { ChangeDetectionStrategy, Component, ElementRef, OnInit, ViewChild } from '@angular/core';\n\nimport { NzPipesModule } from 'ng-zorro-antd/pipes';\n\nimport { NzModalCloseComponent } from './modal-close.component';\nimport { BaseModalContainerComponent } from './modal-container.directive';\nimport { NzModalFooterComponent } from './modal-footer.component';\nimport { NzModalTitleComponent } from './modal-title.component';\n\n@Component({\n  selector: 'nz-modal-container',\n  exportAs: 'nzModalContainer',\n  hostDirectives: [CdkScrollable],\n  template: `\n    <div\n      #modalElement\n      cdkDrag\n      cdkDragBoundary=\".cdk-overlay-container\"\n      [cdkDragDisabled]=\"!config.nzDraggable\"\n      role=\"document\"\n      class=\"ant-modal\"\n      [class]=\"config.nzClassName!\"\n      [style]=\"config.nzStyle!\"\n      [style.width]=\"config?.nzWidth! | nzToCssUnit\"\n    >\n      <div class=\"ant-modal-content\">\n        @if (config.nzClosable) {\n          <button nz-modal-close (click)=\"onCloseClick()\"></button>\n        }\n        @if (config.nzTitle) {\n          <div nz-modal-title cdkDragHandle [style.cursor]=\"config.nzDraggable ? 'move' : 'auto'\"></div>\n        }\n\n        <div class=\"ant-modal-body\" [style]=\"config.nzBodyStyle!\">\n          <ng-template cdkPortalOutlet />\n          @if (isStringContent) {\n            <div [innerHTML]=\"config.nzContent\"></div>\n          }\n        </div>\n        @if (config.nzFooter !== null) {\n          <div\n            nz-modal-footer\n            [modalRef]=\"modalRef\"\n            (cancelTriggered)=\"onCloseClick()\"\n            (okTriggered)=\"onOkClick()\"\n          ></div>\n        }\n      </div>\n    </div>\n  `,\n  // Using OnPush for modal caused footer can not to detect changes. we can fix it when 8.x.\n  changeDetection: ChangeDetectionStrategy.Default,\n  host: {\n    tabindex: '-1',\n    role: 'dialog',\n    '[class]': 'config.nzWrapClassName ? \"ant-modal-wrap \" + config.nzWrapClassName : \"ant-modal-wrap\"',\n    '[class.ant-modal-wrap-rtl]': `dir === 'rtl'`,\n    '[class.ant-modal-centered]': 'config.nzCentered',\n    '[style.zIndex]': 'config.nzZIndex',\n    '(click)': 'onContainerClick($event)'\n  },\n  imports: [\n    NzModalCloseComponent,\n    NzModalTitleComponent,\n    PortalModule,\n    NzModalFooterComponent,\n    NzPipesModule,\n    CdkDrag,\n    CdkDragHandle\n  ]\n})\nexport class NzModalContainerComponent extends BaseModalContainerComponent implements OnInit {\n  @ViewChild(CdkPortalOutlet, { static: true }) set _portalOutlet(portalOutlet: CdkPortalOutlet) {\n    this.portalOutlet = portalOutlet;\n  }\n  @ViewChild('modalElement', { static: true }) set _modalElementRef(elementRef: ElementRef<HTMLDivElement>) {\n    this.modalElementRef = elementRef;\n  }\n\n  ngOnInit(): void {\n    this.setupMouseListeners(this.modalElementRef);\n  }\n}\n"
  },
  {
    "path": "components/modal/modal-container.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { FocusTrap, FocusTrapFactory } from '@angular/cdk/a11y';\nimport { Direction } from '@angular/cdk/bidi';\nimport { OverlayRef } from '@angular/cdk/overlay';\nimport { BasePortalOutlet, CdkPortalOutlet, ComponentPortal, TemplatePortal } from '@angular/cdk/portal';\nimport {\n  ANIMATION_MODULE_TYPE,\n  ChangeDetectorRef,\n  ComponentRef,\n  DestroyRef,\n  Directive,\n  DOCUMENT,\n  ElementRef,\n  EmbeddedViewRef,\n  EventEmitter,\n  inject,\n  NgZone,\n  Renderer2\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { NzConfigService, onConfigChangeEventForComponent } from 'ng-zorro-antd/core/config';\nimport { requestAnimationFrame } from 'ng-zorro-antd/core/polyfill';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { fromEventOutsideAngular, getElementOffset, isNotNil } from 'ng-zorro-antd/core/util';\n\nimport { FADE_CLASS_NAME_MAP, MODAL_MASK_CLASS_NAME, NZ_CONFIG_MODULE_NAME, ZOOM_CLASS_NAME_MAP } from './modal-config';\nimport { NzModalRef } from './modal-ref';\nimport { ModalOptions } from './modal-types';\nimport { getValueWithConfig } from './utils';\n\nexport function throwNzModalContentAlreadyAttachedError(): never {\n  throw Error('Attempting to attach modal content after content is already attached');\n}\n\ntype AnimationState = 'enter-start' | 'enter-active' | 'leave-start' | 'leave-active' | 'void';\n\n@Directive()\nexport class BaseModalContainerComponent extends BasePortalOutlet {\n  readonly document: Document = inject(DOCUMENT);\n  readonly cdr: ChangeDetectorRef = inject(ChangeDetectorRef);\n  readonly config: ModalOptions = inject(ModalOptions);\n  protected ngZone: NgZone = inject(NgZone);\n  protected host: ElementRef<HTMLElement> = inject(ElementRef);\n  protected focusTrapFactory: FocusTrapFactory = inject(FocusTrapFactory);\n  protected render: Renderer2 = inject(Renderer2);\n  protected overlayRef: OverlayRef = inject(OverlayRef);\n  protected nzConfigService: NzConfigService = inject(NzConfigService);\n  protected animationType = inject(ANIMATION_MODULE_TYPE, { optional: true });\n  protected destroyRef = inject(DestroyRef);\n\n  portalOutlet!: CdkPortalOutlet;\n  modalElementRef!: ElementRef<HTMLDivElement>;\n\n  animationStateChanged = new EventEmitter<AnimationState>();\n  containerClick = new EventEmitter<void>();\n  cancelTriggered = new EventEmitter<void>();\n  okTriggered = new EventEmitter<void>();\n\n  modalRef!: NzModalRef;\n  isStringContent: boolean = false;\n  dir: Direction = 'ltr';\n  private elementFocusedBeforeModalWasOpened: HTMLElement | null = null;\n  private focusTrap!: FocusTrap;\n  private mouseDown = false;\n  private oldMaskStyle: Record<string, string> | null = null;\n\n  get showMask(): boolean {\n    const defaultConfig: NzSafeAny = this.nzConfigService.getConfigForComponent(NZ_CONFIG_MODULE_NAME) || {};\n\n    return !!getValueWithConfig<boolean>(this.config.nzMask, defaultConfig.nzMask, true);\n  }\n\n  get maskClosable(): boolean {\n    const defaultConfig: NzSafeAny = this.nzConfigService.getConfigForComponent(NZ_CONFIG_MODULE_NAME) || {};\n\n    return !!getValueWithConfig<boolean>(this.config.nzMaskClosable, defaultConfig.nzMaskClosable, true);\n  }\n\n  constructor() {\n    super();\n    this.dir = this.overlayRef.getDirection();\n    this.isStringContent = typeof this.config.nzContent === 'string';\n\n    onConfigChangeEventForComponent(NZ_CONFIG_MODULE_NAME, () => this.updateMaskClassname());\n\n    this.destroyRef.onDestroy(() => {\n      this.setMaskExitAnimationClass(true);\n    });\n  }\n\n  onContainerClick(e: MouseEvent): void {\n    if (e.target === e.currentTarget && !this.mouseDown && this.showMask && this.maskClosable) {\n      this.containerClick.emit();\n    }\n  }\n\n  onCloseClick(): void {\n    this.cancelTriggered.emit();\n  }\n\n  onOkClick(): void {\n    this.okTriggered.emit();\n  }\n\n  attachComponentPortal<T>(portal: ComponentPortal<T>): ComponentRef<T> {\n    if (this.portalOutlet.hasAttached()) {\n      throwNzModalContentAlreadyAttachedError();\n    }\n    this.savePreviouslyFocusedElement();\n    this.setZIndexForBackdrop();\n    const result = this.portalOutlet.attachComponentPortal(portal);\n    // Trigger animation after content is attached and focus is saved\n    this._startEnterAnimation();\n    return result;\n  }\n\n  attachTemplatePortal<C>(portal: TemplatePortal<C>): EmbeddedViewRef<C> {\n    if (this.portalOutlet.hasAttached()) {\n      throwNzModalContentAlreadyAttachedError();\n    }\n    this.savePreviouslyFocusedElement();\n    this.setZIndexForBackdrop();\n    const result = this.portalOutlet.attachTemplatePortal(portal);\n    // Trigger animation after content is attached and focus is saved\n    this._startEnterAnimation();\n    return result;\n  }\n\n  attachStringContent(): void {\n    this.savePreviouslyFocusedElement();\n    this.setZIndexForBackdrop();\n    // Trigger animation after focus is saved\n    this._startEnterAnimation();\n  }\n\n  getNativeElement(): HTMLElement {\n    return this.host.nativeElement;\n  }\n\n  private animationDisabled(): boolean {\n    return this.config.nzNoAnimation || this.animationType === 'NoopAnimations';\n  }\n\n  private setModalTransformOrigin(): void {\n    const modalElement = this.modalElementRef.nativeElement;\n    if (this.elementFocusedBeforeModalWasOpened as HTMLElement) {\n      const previouslyDOMRect = this.elementFocusedBeforeModalWasOpened!.getBoundingClientRect();\n      const lastPosition = getElementOffset(this.elementFocusedBeforeModalWasOpened!);\n      const x = lastPosition.left + previouslyDOMRect.width / 2;\n      const y = lastPosition.top + previouslyDOMRect.height / 2;\n      const transformOrigin = `${x - modalElement.offsetLeft}px ${y - modalElement.offsetTop}px 0px`;\n      this.render.setStyle(modalElement, 'transform-origin', transformOrigin);\n    }\n  }\n\n  private savePreviouslyFocusedElement(): void {\n    if (!this.focusTrap) {\n      this.focusTrap = this.focusTrapFactory.create(this.host.nativeElement);\n    }\n\n    if (this.document) {\n      this.elementFocusedBeforeModalWasOpened = this.document.activeElement as HTMLElement;\n      if (this.host.nativeElement.focus) {\n        this.ngZone.runOutsideAngular(() => requestAnimationFrame(() => this.host.nativeElement.focus()));\n      }\n    }\n  }\n\n  private trapFocus(): void {\n    const element = this.host.nativeElement;\n\n    if (this.config.nzAutofocus) {\n      this.focusTrap.focusInitialElementWhenReady();\n    } else {\n      const activeElement = this.document.activeElement;\n      if (activeElement !== element && !element.contains(activeElement)) {\n        element.focus();\n      }\n    }\n  }\n\n  private restoreFocus(): void {\n    this.elementFocusedBeforeModalWasOpened?.focus();\n    this.focusTrap?.destroy();\n  }\n\n  private setEnterInitialClass(): void {\n    if (this.animationDisabled()) {\n      return;\n    }\n    const modalElement = this.modalElementRef.nativeElement;\n    const backdropElement = this.overlayRef.backdropElement;\n    // Add enter class immediately to hide the modal (scale(0), opacity: 0)\n    // This prevents the flicker when the modal is first rendered\n    modalElement.classList.add(ZOOM_CLASS_NAME_MAP.enter);\n    if (backdropElement) {\n      backdropElement.classList.add(FADE_CLASS_NAME_MAP.enter);\n    }\n  }\n\n  private setEnterActiveClass(): void {\n    if (this.animationDisabled()) {\n      return;\n    }\n    // Make sure to set the `TransformOrigin` style before set the enter-active class names\n    this.setModalTransformOrigin();\n    const modalElement = this.modalElementRef.nativeElement;\n    const backdropElement = this.overlayRef.backdropElement;\n    // Add enter-active class to trigger the animation\n    modalElement.classList.add(ZOOM_CLASS_NAME_MAP.enterActive);\n    if (backdropElement) {\n      backdropElement.classList.add(FADE_CLASS_NAME_MAP.enterActive);\n    }\n  }\n\n  private setExitAnimationClass(): void {\n    const modalElement = this.modalElementRef.nativeElement;\n\n    modalElement.classList.add(ZOOM_CLASS_NAME_MAP.leave);\n    modalElement.classList.add(ZOOM_CLASS_NAME_MAP.leaveActive);\n\n    this.setMaskExitAnimationClass();\n  }\n\n  private setMaskExitAnimationClass(force: boolean = false): void {\n    const backdropElement = this.overlayRef.backdropElement;\n    if (backdropElement) {\n      if (this.animationDisabled() || force) {\n        // https://github.com/angular/components/issues/18645\n        backdropElement.classList.remove(MODAL_MASK_CLASS_NAME);\n        return;\n      }\n      backdropElement.classList.add(FADE_CLASS_NAME_MAP.leave);\n      backdropElement.classList.add(FADE_CLASS_NAME_MAP.leaveActive);\n    }\n  }\n\n  private cleanAnimationClass(): void {\n    if (this.animationDisabled()) {\n      return;\n    }\n    const backdropElement = this.overlayRef.backdropElement;\n    const modalElement = this.modalElementRef.nativeElement;\n    if (backdropElement) {\n      backdropElement.classList.remove(FADE_CLASS_NAME_MAP.enter);\n      backdropElement.classList.remove(FADE_CLASS_NAME_MAP.enterActive);\n    }\n    modalElement.classList.remove(ZOOM_CLASS_NAME_MAP.enter);\n    modalElement.classList.remove(ZOOM_CLASS_NAME_MAP.enterActive);\n    modalElement.classList.remove(ZOOM_CLASS_NAME_MAP.leave);\n    modalElement.classList.remove(ZOOM_CLASS_NAME_MAP.leaveActive);\n  }\n\n  private setZIndexForBackdrop(): void {\n    const backdropElement = this.overlayRef.backdropElement;\n    if (backdropElement) {\n      if (isNotNil(this.config.nzZIndex)) {\n        this.render.setStyle(backdropElement, 'z-index', this.config.nzZIndex);\n      }\n    }\n  }\n\n  bindBackdropStyle(): void {\n    const backdropElement = this.overlayRef.backdropElement;\n    if (backdropElement) {\n      if (this.oldMaskStyle) {\n        const styles = this.oldMaskStyle as Record<string, string>;\n        Object.keys(styles).forEach(key => {\n          this.render.removeStyle(backdropElement, key);\n        });\n        this.oldMaskStyle = null;\n      }\n\n      this.setZIndexForBackdrop();\n\n      if (typeof this.config.nzMaskStyle === 'object' && Object.keys(this.config.nzMaskStyle).length) {\n        const styles: Record<string, string> = { ...this.config.nzMaskStyle };\n        Object.keys(styles).forEach(key => {\n          this.render.setStyle(backdropElement, key, styles[key]);\n        });\n        this.oldMaskStyle = styles;\n      }\n    }\n  }\n\n  updateMaskClassname(): void {\n    const backdropElement = this.overlayRef.backdropElement;\n    if (backdropElement) {\n      if (this.showMask) {\n        backdropElement.classList.add(MODAL_MASK_CLASS_NAME);\n      } else {\n        backdropElement.classList.remove(MODAL_MASK_CLASS_NAME);\n      }\n    }\n  }\n\n  _startEnterAnimation(): void {\n    this.bindBackdropStyle();\n    this.animationStateChanged.emit('enter-start');\n\n    if (this.animationDisabled()) {\n      this.trapFocus();\n      this.animationStateChanged.emit('enter-active');\n    } else {\n      // Immediately add enter class to hide the modal (prevents flicker)\n      // The enter class sets scale(0) and opacity(0) so the modal is invisible\n      this.setEnterInitialClass();\n\n      // In the next frame, add enter-active class to trigger the animation\n      requestAnimationFrame(() => this.setEnterActiveClass());\n\n      const element = this.modalElementRef.nativeElement;\n      const onAnimationEnd = (): void => {\n        element.removeEventListener('animationend', onAnimationEnd);\n        this.trapFocus();\n        this.cleanAnimationClass();\n        this.animationStateChanged.emit('enter-active');\n      };\n\n      element.addEventListener('animationend', onAnimationEnd);\n    }\n  }\n\n  _startLeaveAnimation(callback?: () => void): void {\n    this.animationStateChanged.emit('leave-start');\n\n    if (this.animationDisabled()) {\n      this.restoreFocus();\n      callback?.();\n      this.animationStateChanged.emit('leave-active');\n    } else {\n      this.setExitAnimationClass();\n      const element = this.modalElementRef.nativeElement;\n      const onAnimationEnd = (): void => {\n        element.removeEventListener('animationend', onAnimationEnd);\n        this.restoreFocus();\n        this.cleanAnimationClass();\n        callback?.();\n        this.animationStateChanged.emit('leave-active');\n      };\n\n      element.addEventListener('animationend', onAnimationEnd);\n    }\n  }\n\n  protected setupMouseListeners(modalContainer: ElementRef<HTMLElement>): void {\n    fromEventOutsideAngular(this.host.nativeElement, 'mouseup')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(() => {\n        if (this.mouseDown) {\n          setTimeout(() => {\n            this.mouseDown = false;\n          });\n        }\n      });\n\n    fromEventOutsideAngular(modalContainer.nativeElement, 'mousedown')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(() => {\n        this.mouseDown = true;\n      });\n  }\n}\n"
  },
  {
    "path": "components/modal/modal-content.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, inject, TemplateRef } from '@angular/core';\n\n@Directive({\n  selector: '[nzModalContent]',\n  exportAs: 'nzModalContent'\n})\nexport class NzModalContentDirective {\n  public readonly templateRef: TemplateRef<{}> = inject(TemplateRef);\n}\n"
  },
  {
    "path": "components/modal/modal-footer.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, EventEmitter, inject, Input, Output } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { isPromise } from 'ng-zorro-antd/core/util';\nimport { NzI18nService, NzModalI18nInterface } from 'ng-zorro-antd/i18n';\n\nimport { NzModalRef } from './modal-ref';\nimport { ModalButtonOptions, ModalOptions } from './modal-types';\n\n@Component({\n  selector: 'div[nz-modal-footer]',\n  exportAs: 'nzModalFooterBuiltin',\n  template: `\n    @if (config.nzFooter) {\n      <ng-container\n        *nzStringTemplateOutlet=\"config.nzFooter; context: { $implicit: config.nzData, modalRef: modalRef }\"\n      >\n        @if (buttonsFooter) {\n          @for (button of buttons; track button) {\n            <button\n              nz-button\n              (click)=\"onButtonClick(button)\"\n              [hidden]=\"!getButtonCallableProp(button, 'show')\"\n              [nzLoading]=\"getButtonCallableProp(button, 'loading')\"\n              [disabled]=\"getButtonCallableProp(button, 'disabled')\"\n              [nzType]=\"button.type!\"\n              [nzDanger]=\"button.danger\"\n              [nzShape]=\"button.shape!\"\n              [nzSize]=\"button.size!\"\n              [nzGhost]=\"button.ghost!\"\n            >\n              {{ button.label }}\n            </button>\n          }\n        } @else {\n          <div [innerHTML]=\"config.nzFooter\"></div>\n        }\n      </ng-container>\n    } @else {\n      @if (config.nzCancelText !== null) {\n        <button\n          [attr.cdkFocusInitial]=\"config.nzAutofocus === 'cancel' || null\"\n          nz-button\n          (click)=\"onCancel()\"\n          [nzLoading]=\"config.nzCancelLoading\"\n          [disabled]=\"config.nzCancelDisabled\"\n        >\n          {{ config.nzCancelText || locale.cancelText }}\n        </button>\n      }\n      @if (config.nzOkText !== null) {\n        <button\n          [attr.cdkFocusInitial]=\"config.nzAutofocus === 'ok' || null\"\n          nz-button\n          [nzType]=\"config.nzOkType!\"\n          [nzDanger]=\"config.nzOkDanger\"\n          (click)=\"onOk()\"\n          [nzLoading]=\"config.nzOkLoading\"\n          [disabled]=\"config.nzOkDisabled\"\n        >\n          {{ config.nzOkText || locale.okText }}\n        </button>\n      }\n    }\n  `,\n  host: {\n    class: 'ant-modal-footer'\n  },\n  changeDetection: ChangeDetectionStrategy.Default,\n  imports: [NzOutletModule, NzButtonModule]\n})\nexport class NzModalFooterComponent {\n  private i18n = inject(NzI18nService);\n  public readonly config = inject(ModalOptions);\n\n  buttonsFooter = false;\n  buttons: ModalButtonOptions[] = [];\n  locale!: NzModalI18nInterface;\n  @Output() readonly cancelTriggered = new EventEmitter<void>();\n  @Output() readonly okTriggered = new EventEmitter<void>();\n  @Input() modalRef!: NzModalRef;\n\n  constructor() {\n    if (Array.isArray(this.config.nzFooter)) {\n      this.buttonsFooter = true;\n      this.buttons = (this.config.nzFooter as ModalButtonOptions[]).map(mergeDefaultOption);\n    }\n    this.i18n.localeChange.pipe(takeUntilDestroyed()).subscribe(() => {\n      this.locale = this.i18n.getLocaleData('Modal');\n    });\n  }\n\n  onCancel(): void {\n    this.cancelTriggered.emit();\n  }\n\n  onOk(): void {\n    this.okTriggered.emit();\n  }\n\n  /**\n   * Returns the value of the specified key.\n   * If it is a function, run and return the return value of the function.\n   */\n  getButtonCallableProp(options: ModalButtonOptions, prop: keyof ModalButtonOptions): boolean {\n    const value = options[prop];\n    const componentInstance = this.modalRef.getContentComponent();\n    return typeof value === 'function' ? value.apply(options, componentInstance && [componentInstance]) : value;\n  }\n\n  /**\n   * Run function based on the type and set its `loading` prop if needed.\n   */\n  onButtonClick(options: ModalButtonOptions): void {\n    const loading = this.getButtonCallableProp(options, 'loading');\n    if (!loading) {\n      const result = this.getButtonCallableProp(options, 'onClick');\n      if (options.autoLoading && isPromise(result)) {\n        options.loading = true;\n        result\n          .then(() => (options.loading = false))\n          .catch(e => {\n            options.loading = false;\n            throw e;\n          });\n      }\n    }\n  }\n}\n\nfunction mergeDefaultOption(options: ModalButtonOptions): ModalButtonOptions {\n  return {\n    type: null,\n    size: 'default',\n    autoLoading: true,\n    show: true,\n    loading: false,\n    disabled: false,\n    ...options\n  };\n}\n"
  },
  {
    "path": "components/modal/modal-footer.directive.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport { Component, provideZoneChangeDetection, TemplateRef, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, flush, inject, TestBed } from '@angular/core/testing';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzModalFooterDirective } from './modal-footer.directive';\nimport { NzModalRef } from './modal-ref';\nimport { NzModalComponent } from './modal.component';\nimport { NzModalModule } from './modal.module';\nimport { NzModalService } from './modal.service';\n\ndescribe('modal footer directive', () => {\n  let overlayContainer: OverlayContainer;\n  let fixture: ComponentFixture<TestDirectiveFooterComponent>;\n  let testComponent: TestDirectiveFooterComponent;\n  let modalService: NzModalService;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [NzModalService, provideNoopAnimations(), provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(TestDirectiveFooterComponent);\n    testComponent = fixture.componentInstance;\n    fixture.detectChanges();\n  });\n\n  beforeEach(inject([OverlayContainer, NzModalService], (oc: OverlayContainer, m: NzModalService) => {\n    overlayContainer = oc;\n    modalService = m;\n  }));\n\n  afterEach(() => {\n    overlayContainer.ngOnDestroy();\n  });\n\n  it('should work with template', () => {\n    testComponent.showModal();\n    fixture.detectChanges();\n    expect(testComponent.isVisible).toBe(true);\n    const modalRef = testComponent.nzModalComponent.getModalRef();\n    expect(modalRef!.getConfig().nzFooter).toEqual(testComponent.nzModalFooterDirective);\n\n    testComponent.handleCancel();\n    fixture.detectChanges();\n  });\n\n  it('should work with template when init opened', fakeAsync(() => {\n    const initOpenedComponentFixture = TestBed.createComponent(TestDirectiveFooterWithInitOpenedComponent);\n    const initOpenedComponent = initOpenedComponentFixture.componentInstance;\n    initOpenedComponentFixture.detectChanges();\n    expect(initOpenedComponent.isVisible).toBe(true);\n    flush();\n    initOpenedComponentFixture.detectChanges();\n    const modalRef = initOpenedComponent.nzModalComponent.getModalRef();\n\n    expect(modalRef!.getConfig().nzFooter).toEqual(initOpenedComponent.nzModalFooterDirective);\n\n    initOpenedComponentFixture.detectChanges();\n  }));\n\n  it('should work with service', () => {\n    const modalRef = modalService.create({ nzContent: TestDirectiveFooterInServiceComponent, nzFooter: null });\n    fixture.detectChanges();\n\n    expect(modalRef.componentInstance!.nzModalRef).toBe(modalRef);\n    expect(modalRef.componentInstance!.nzModalFooterDirective).toEqual(\n      modalRef.getConfig().nzFooter as TemplateRef<{}>\n    );\n  });\n});\n\n@Component({\n  imports: [NzModalModule, NzButtonModule],\n  template: `\n    <nz-modal [(nzVisible)]=\"isVisible\" nzTitle=\"Custom Modal Title\" (nzOnCancel)=\"handleCancel()\">\n      <div>\n        <p>Modal Content</p>\n      </div>\n      <div *nzModalFooter>\n        <button id=\"btn-template\" nz-button nzType=\"default\" (click)=\"handleCancel()\">Custom Callback</button>\n      </div>\n    </nz-modal>\n  `\n})\nclass TestDirectiveFooterComponent {\n  isVisible = false;\n  @ViewChild(NzModalComponent) nzModalComponent!: NzModalComponent;\n  @ViewChild(NzModalFooterDirective, { static: true, read: TemplateRef })\n  nzModalFooterDirective!: TemplateRef<NzSafeAny>;\n\n  handleCancel(): void {\n    this.isVisible = false;\n  }\n\n  showModal(): void {\n    this.isVisible = true;\n  }\n}\n\n@Component({\n  imports: [NzModalModule, NzButtonModule],\n  template: `\n    <nz-modal [(nzVisible)]=\"isVisible\" nzTitle=\"Custom Modal Title\">\n      <div>\n        <p>Modal Content</p>\n      </div>\n      <div *nzModalFooter>\n        <button id=\"btn-template\" nz-button nzType=\"default\">Custom Callback</button>\n      </div>\n    </nz-modal>\n  `\n})\nclass TestDirectiveFooterWithInitOpenedComponent {\n  isVisible = true;\n  @ViewChild(NzModalComponent) nzModalComponent!: NzModalComponent;\n  @ViewChild(NzModalFooterDirective, { static: true, read: TemplateRef })\n  nzModalFooterDirective!: TemplateRef<NzSafeAny>;\n}\n\n@Component({\n  imports: [NzModalModule, NzButtonModule],\n  template: `\n    <div *nzModalFooter>\n      <button id=\"btn-template\" nz-button nzType=\"default\" (click)=\"handleCancel()\">Custom Callback</button>\n    </div>\n  `\n})\nclass TestDirectiveFooterInServiceComponent {\n  @ViewChild(NzModalFooterDirective, { static: true, read: TemplateRef })\n  nzModalFooterDirective!: TemplateRef<NzSafeAny>;\n\n  constructor(public nzModalRef: NzModalRef) {}\n\n  handleCancel(): void {\n    this.nzModalRef.close();\n  }\n}\n"
  },
  {
    "path": "components/modal/modal-footer.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, TemplateRef, inject } from '@angular/core';\n\nimport { NzModalRef } from './modal-ref';\n\n@Directive({\n  selector: '[nzModalFooter]',\n  exportAs: 'nzModalFooter'\n})\nexport class NzModalFooterDirective {\n  public readonly templateRef: TemplateRef<{}> = inject(TemplateRef);\n  private nzModalRef = inject(NzModalRef, { optional: true });\n\n  constructor() {\n    this.nzModalRef?.updateConfig({\n      nzFooter: this.templateRef\n    });\n  }\n}\n"
  },
  {
    "path": "components/modal/modal-legacy-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Observable } from 'rxjs';\n\nexport abstract class NzModalLegacyAPI<T, R> {\n  abstract afterOpen: Observable<void>;\n  abstract afterClose: Observable<R | undefined>;\n\n  abstract close(result?: R): void;\n  abstract destroy(result?: R): void;\n\n  /**\n   * Trigger the nzOnOk/nzOnCancel by manual\n   */\n  abstract triggerOk(): void;\n  abstract triggerCancel(): void;\n  /**\n   * Return the component instance of nzContent when specify nzContent as a Component\n   */\n  abstract getContentComponent(): T | void;\n\n  /**\n   * Get the dom element of this Modal\n   */\n  abstract getElement(): HTMLElement | void;\n}\n"
  },
  {
    "path": "components/modal/modal-ref.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ESCAPE, hasModifierKey } from '@angular/cdk/keycodes';\nimport { OverlayRef } from '@angular/cdk/overlay';\nimport { ComponentRef, EventEmitter } from '@angular/core';\nimport { Subject } from 'rxjs';\nimport { filter, take, takeUntil } from 'rxjs/operators';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { isPromise } from 'ng-zorro-antd/core/util';\n\nimport { BaseModalContainerComponent } from './modal-container.directive';\nimport { NzModalLegacyAPI } from './modal-legacy-api';\nimport { ModalOptions } from './modal-types';\n\nexport const NzModalState = {\n  OPEN: 0,\n  CLOSING: 1,\n  CLOSED: 2\n} as const;\n\nexport type NzModalState = (typeof NzModalState)[keyof typeof NzModalState];\n\nexport const NzTriggerAction = {\n  CANCEL: 'cancel',\n  OK: 'ok'\n} as const;\n\nexport type NzTriggerAction = (typeof NzTriggerAction)[keyof typeof NzTriggerAction];\n\nexport class NzModalRef<T = NzSafeAny, R = NzSafeAny> implements NzModalLegacyAPI<T, R> {\n  componentInstance: T | null = null;\n  componentRef: ComponentRef<T> | null = null;\n  result?: R;\n  state: NzModalState = NzModalState.OPEN;\n  afterClose = new Subject<R | undefined>();\n  afterOpen = new Subject<void>();\n\n  private destroy$ = new Subject<void>();\n\n  constructor(\n    private overlayRef: OverlayRef,\n    private config: ModalOptions,\n    public containerInstance: BaseModalContainerComponent\n  ) {\n    containerInstance.animationStateChanged\n      .pipe(\n        filter(event => event === 'enter-active'),\n        take(1)\n      )\n      .subscribe(() => {\n        this.afterOpen.next();\n        this.afterOpen.complete();\n        if (config.nzAfterOpen instanceof EventEmitter) {\n          config.nzAfterOpen.emit();\n        }\n      });\n\n    containerInstance.animationStateChanged\n      .pipe(\n        filter(event => event === 'leave-active'),\n        take(1)\n      )\n      .subscribe(() => this._finishDialogClose());\n\n    containerInstance.containerClick.pipe(takeUntil(this.destroy$)).subscribe(() => {\n      const cancelable = !this.config.nzCancelLoading && !this.config.nzOkLoading;\n      if (cancelable) {\n        this.trigger(NzTriggerAction.CANCEL);\n      }\n    });\n\n    overlayRef\n      .keydownEvents()\n      .pipe(\n        filter(() => (this.config.nzKeyboard as boolean) && !this.config.nzCancelLoading && !this.config.nzOkLoading),\n        filter(event => event.keyCode === ESCAPE && !hasModifierKey(event))\n      )\n      .subscribe(event => {\n        event.preventDefault();\n        this.trigger(NzTriggerAction.CANCEL);\n      });\n\n    containerInstance.cancelTriggered\n      .pipe(takeUntil(this.destroy$))\n      .subscribe(() => this.trigger(NzTriggerAction.CANCEL));\n\n    containerInstance.okTriggered.pipe(takeUntil(this.destroy$)).subscribe(() => this.trigger(NzTriggerAction.OK));\n\n    overlayRef.detachments().subscribe(() => {\n      this.afterClose.next(this.result);\n      this.afterClose.complete();\n      if (config.nzAfterClose instanceof EventEmitter) {\n        config.nzAfterClose.emit(this.result);\n      }\n      this.componentInstance = null;\n      this.componentRef = null;\n      this.overlayRef.dispose();\n    });\n  }\n\n  getContentComponent(): T {\n    return this.componentInstance as T;\n  }\n\n  getContentComponentRef(): Readonly<ComponentRef<T> | null> {\n    return this.componentRef as Readonly<ComponentRef<T> | null>;\n  }\n\n  getElement(): HTMLElement {\n    return this.containerInstance.getNativeElement();\n  }\n\n  destroy(result?: R): void {\n    this.close(result);\n  }\n\n  triggerOk(): Promise<void> {\n    return this.trigger(NzTriggerAction.OK);\n  }\n\n  triggerCancel(): Promise<void> {\n    return this.trigger(NzTriggerAction.CANCEL);\n  }\n\n  close(result?: R): void {\n    if (this.state !== NzModalState.OPEN) {\n      return;\n    }\n    this.result = result;\n    this.state = NzModalState.CLOSING;\n    this.containerInstance._startLeaveAnimation(() => {\n      this.overlayRef.detachBackdrop();\n      this._finishDialogClose();\n    });\n  }\n\n  updateConfig(config: ModalOptions): void {\n    Object.assign(this.config, config);\n    this.containerInstance.bindBackdropStyle();\n    this.containerInstance.cdr.markForCheck();\n  }\n\n  getState(): NzModalState {\n    return this.state;\n  }\n\n  getConfig(): ModalOptions {\n    return this.config;\n  }\n\n  getBackdropElement(): HTMLElement | null {\n    return this.overlayRef.backdropElement;\n  }\n\n  private async trigger(action: NzTriggerAction): Promise<void> {\n    if (this.state === NzModalState.CLOSING) {\n      return;\n    }\n    const actionMap = {\n      [NzTriggerAction.OK]: { trigger: this.config.nzOnOk, loadingKey: 'nzOkLoading' },\n      [NzTriggerAction.CANCEL]: { trigger: this.config.nzOnCancel, loadingKey: 'nzCancelLoading' }\n    } as const;\n    const { trigger, loadingKey } = actionMap[action];\n    if (this.config[loadingKey]) {\n      return;\n    }\n    if (trigger instanceof EventEmitter) {\n      trigger.emit(this.getContentComponent());\n    } else if (typeof trigger === 'function') {\n      const result = trigger(this.getContentComponent());\n      if (isPromise(result)) {\n        this.config[loadingKey] = true;\n        this.updateConfig(this.config);\n        let doClose: boolean | void | {} = false;\n        try {\n          doClose = (await result) as typeof result;\n        } finally {\n          this.config[loadingKey] = false;\n          this.updateConfig(this.config);\n          this.closeWhitResult(doClose);\n        }\n      } else {\n        this.closeWhitResult(result);\n      }\n    }\n  }\n\n  private closeWhitResult(result: NzSafeAny): void {\n    if (result !== false) {\n      this.close(result);\n    }\n  }\n\n  _finishDialogClose(): void {\n    this.state = NzModalState.CLOSED;\n    this.overlayRef.dispose();\n    this.destroy$.next();\n  }\n}\n"
  },
  {
    "path": "components/modal/modal-title.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, inject } from '@angular/core';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\n\nimport { ModalOptions } from './modal-types';\n\n@Component({\n  selector: 'div[nz-modal-title]',\n  exportAs: 'nzModalTitleBuiltin',\n  template: `\n    <div class=\"ant-modal-title\">\n      <ng-container *nzStringTemplateOutlet=\"config.nzTitle\">\n        <div [innerHTML]=\"config.nzTitle\"></div>\n      </ng-container>\n    </div>\n  `,\n  host: {\n    class: 'ant-modal-header'\n  },\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  imports: [NzOutletModule]\n})\nexport class NzModalTitleComponent {\n  public config = inject(ModalOptions);\n}\n"
  },
  {
    "path": "components/modal/modal-title.directive.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport { Component, provideZoneChangeDetection, TemplateRef, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, flush, inject, TestBed } from '@angular/core/testing';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzModalRef } from './modal-ref';\nimport { NzModalTitleDirective } from './modal-title.directive';\nimport { NzModalComponent } from './modal.component';\nimport { NzModalModule } from './modal.module';\nimport { NzModalService } from './modal.service';\n\ndescribe('modal title directive', () => {\n  let overlayContainer: OverlayContainer;\n  let fixture: ComponentFixture<TestDirectiveTitleComponent>;\n  let testComponent: TestDirectiveTitleComponent;\n  let modalService: NzModalService;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [NzModalService, provideNoopAnimations(), provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(TestDirectiveTitleComponent);\n    testComponent = fixture.componentInstance;\n    fixture.detectChanges();\n  });\n\n  beforeEach(inject([OverlayContainer, NzModalService], (oc: OverlayContainer, m: NzModalService) => {\n    overlayContainer = oc;\n    modalService = m;\n  }));\n\n  afterEach(() => {\n    overlayContainer.ngOnDestroy();\n  });\n\n  it('should work with template', () => {\n    testComponent.showModal();\n    fixture.detectChanges();\n    expect(testComponent.isVisible).toBe(true);\n    const modalRef = testComponent.nzModalComponent.getModalRef();\n    expect(modalRef!.getConfig().nzTitle).toEqual(testComponent.nzModalTitleDirective);\n\n    testComponent.handleCancel();\n    fixture.detectChanges();\n  });\n\n  it('should work with template when init opened', fakeAsync(() => {\n    const initOpenedComponentFixture = TestBed.createComponent(TestDirectiveTitleWithInitOpenedComponent);\n    const initOpenedComponent = initOpenedComponentFixture.componentInstance;\n    initOpenedComponentFixture.detectChanges();\n    expect(initOpenedComponent.isVisible).toBe(true);\n    flush();\n    initOpenedComponentFixture.detectChanges();\n    const modalRef = initOpenedComponent.nzModalComponent.getModalRef();\n\n    expect(modalRef!.getConfig().nzTitle).toEqual(initOpenedComponent.nzModalTitleDirective);\n\n    initOpenedComponentFixture.detectChanges();\n  }));\n\n  it('should work with service', () => {\n    const modalRef = modalService.create({ nzContent: TestDirectiveTitleInServiceComponent, nzTitle: '' });\n    fixture.detectChanges();\n\n    expect(modalRef.componentInstance!.nzModalRef).toBe(modalRef);\n    expect(modalRef.componentInstance!.NzModalTitleDirective).toEqual(modalRef.getConfig().nzTitle as TemplateRef<{}>);\n  });\n});\n\n@Component({\n  imports: [NzModalModule],\n  template: `\n    <nz-modal [(nzVisible)]=\"isVisible\" (nzOnCancel)=\"handleCancel()\">\n      <div>\n        <p>Modal Content</p>\n      </div>\n      <div *nzModalTitle>Custom Modal Title</div>\n    </nz-modal>\n  `\n})\nclass TestDirectiveTitleComponent {\n  isVisible = false;\n  @ViewChild(NzModalComponent) nzModalComponent!: NzModalComponent;\n  @ViewChild(NzModalTitleDirective, { static: true, read: TemplateRef }) nzModalTitleDirective!: TemplateRef<NzSafeAny>;\n\n  handleCancel(): void {\n    this.isVisible = false;\n  }\n\n  showModal(): void {\n    this.isVisible = true;\n  }\n}\n\n@Component({\n  imports: [NzModalModule],\n  template: `\n    <nz-modal [(nzVisible)]=\"isVisible\">\n      <div>\n        <p>Modal Content</p>\n      </div>\n      <div *nzModalTitle>Custom Modal Title</div>\n    </nz-modal>\n  `\n})\nclass TestDirectiveTitleWithInitOpenedComponent {\n  isVisible = true;\n  @ViewChild(NzModalComponent) nzModalComponent!: NzModalComponent;\n  @ViewChild(NzModalTitleDirective, { static: true, read: TemplateRef }) nzModalTitleDirective!: TemplateRef<NzSafeAny>;\n}\n\n@Component({\n  imports: [NzModalModule],\n  template: `<div *nzModalTitle>Custom Modal Title</div>`\n})\nclass TestDirectiveTitleInServiceComponent {\n  @ViewChild(NzModalTitleDirective, { static: true, read: TemplateRef }) NzModalTitleDirective!: TemplateRef<NzSafeAny>;\n\n  constructor(public nzModalRef: NzModalRef) {}\n\n  handleCancel(): void {\n    this.nzModalRef.close();\n  }\n}\n"
  },
  {
    "path": "components/modal/modal-title.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, TemplateRef, inject } from '@angular/core';\n\nimport { NzModalRef } from './modal-ref';\n\n@Directive({\n  selector: '[nzModalTitle]',\n  exportAs: 'nzModalTitle'\n})\nexport class NzModalTitleDirective {\n  public readonly templateRef: TemplateRef<{}> = inject(TemplateRef);\n  private nzModalRef = inject(NzModalRef, { optional: true });\n\n  constructor() {\n    this.nzModalRef?.updateConfig({\n      nzTitle: this.templateRef\n    });\n  }\n}\n"
  },
  {
    "path": "components/modal/modal-types.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction } from '@angular/cdk/bidi';\nimport { EventEmitter, TemplateRef, Type, ViewContainerRef } from '@angular/core';\n\nimport { NzButtonShape, NzButtonSize, NzButtonType } from 'ng-zorro-antd/button';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nexport type OnClickCallback<T> = (instance: T) => (false | void | {}) | Promise<false | void | {}>;\n\nexport type ModalTypes = 'default' | 'confirm'; // Different modal styles we have supported\n\nexport type ConfirmType = 'confirm' | 'info' | 'success' | 'error' | 'warning'; // Subtypes of Confirm Modal\n\nexport interface StyleObjectLike {\n  [key: string]: string;\n}\n\nconst noopFun = () => void 0;\n\nexport class ModalOptions<T = NzSafeAny, D = NzSafeAny, R = NzSafeAny> {\n  nzCentered?: boolean = false;\n  nzClosable?: boolean = true;\n  nzOkLoading?: boolean = false;\n  nzOkDisabled?: boolean = false;\n  nzCancelDisabled?: boolean = false;\n  nzCancelLoading?: boolean = false;\n  nzDraggable?: boolean = false;\n  nzNoAnimation?: boolean = false;\n  nzAutofocus?: 'ok' | 'cancel' | 'auto' | null = 'auto';\n  nzMask?: boolean;\n  nzMaskClosable?: boolean;\n  nzKeyboard?: boolean = true;\n  nzZIndex?: number = 1000;\n  nzWidth?: number | string = 520;\n  nzCloseIcon?: string | TemplateRef<void> = 'close';\n  nzOkType?: NzButtonType = 'primary';\n  nzOkDanger?: boolean = false;\n  nzModalType?: ModalTypes = 'default';\n  nzOnCancel?: EventEmitter<T> | OnClickCallback<T> = noopFun;\n  nzOnOk?: EventEmitter<T> | OnClickCallback<T> = noopFun;\n  nzData?: D;\n  nzMaskStyle?: StyleObjectLike;\n  nzBodyStyle?: StyleObjectLike;\n  nzWrapClassName?: string;\n  nzClassName?: string;\n  nzStyle?: object;\n  nzTitle?: string | TemplateRef<{}>;\n  nzFooter?: string | TemplateRef<{}> | Array<ModalButtonOptions<T>> | null; // Default Modal ONLY\n  nzCancelText?: string | null;\n  nzOkText?: string | null;\n  nzContent?: string | TemplateRef<NzSafeAny> | Type<T>;\n  nzCloseOnNavigation?: boolean;\n  nzViewContainerRef?: ViewContainerRef;\n  // Template use only\n  nzAfterOpen?: EventEmitter<void>;\n  nzAfterClose?: EventEmitter<R>;\n\n  // Confirm\n  nzIconType?: string = 'question-circle';\n  nzDirection?: Direction;\n}\n\nexport interface ModalButtonOptions<T = NzSafeAny> {\n  label: string;\n  type?: NzButtonType;\n  danger?: boolean;\n  shape?: NzButtonShape;\n  ghost?: boolean;\n  size?: NzButtonSize;\n  autoLoading?: boolean; // Default: true, indicate whether show loading automatically while onClick returned a Promise\n\n  // [NOTE] \"componentInstance\" will refer to the component's instance when using Component\n  show?: boolean | ((this: ModalButtonOptions<T>, contentComponentInstance?: T) => boolean);\n  loading?: boolean | ((this: ModalButtonOptions<T>, contentComponentInstance?: T) => boolean); // This prop CAN'T use with autoLoading=true\n  disabled?: boolean | ((this: ModalButtonOptions<T>, contentComponentInstance?: T) => boolean);\n  onClick?(this: ModalButtonOptions<T>, contentComponentInstance?: T): NzSafeAny | Promise<NzSafeAny>;\n  [key: string]: NzSafeAny;\n}\n"
  },
  {
    "path": "components/modal/modal.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ContentChild,\n  DestroyRef,\n  EventEmitter,\n  Input,\n  OnChanges,\n  Output,\n  SimpleChanges,\n  TemplateRef,\n  Type,\n  ViewContainerRef,\n  booleanAttribute,\n  inject,\n  numberAttribute\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Observable } from 'rxjs';\n\nimport { NzButtonType } from 'ng-zorro-antd/button';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzModalContentDirective } from './modal-content.directive';\nimport { NzModalFooterDirective } from './modal-footer.directive';\nimport { NzModalLegacyAPI } from './modal-legacy-api';\nimport { NzModalRef } from './modal-ref';\nimport { NzModalTitleDirective } from './modal-title.directive';\nimport { ModalButtonOptions, ModalOptions, ModalTypes, OnClickCallback, StyleObjectLike } from './modal-types';\nimport { NzModalService } from './modal.service';\nimport { getConfigFromComponent } from './utils';\n\n@Component({\n  selector: 'nz-modal',\n  exportAs: 'nzModal',\n  template: ``,\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class NzModalComponent<T extends ModalOptions = NzSafeAny, R = NzSafeAny>\n  implements OnChanges, NzModalLegacyAPI<T, R>\n{\n  private cdr = inject(ChangeDetectorRef);\n  private modal = inject(NzModalService);\n  private viewContainerRef = inject(ViewContainerRef);\n  private destroyRef = inject(DestroyRef);\n\n  @Input({ transform: booleanAttribute }) nzMask?: boolean;\n  @Input({ transform: booleanAttribute }) nzMaskClosable?: boolean;\n  @Input({ transform: booleanAttribute }) nzCloseOnNavigation?: boolean;\n  @Input({ transform: booleanAttribute }) nzVisible: boolean = false;\n  @Input({ transform: booleanAttribute }) nzClosable: boolean = true;\n  @Input({ transform: booleanAttribute }) nzOkLoading: boolean = false;\n  @Input({ transform: booleanAttribute }) nzOkDisabled: boolean = false;\n  @Input({ transform: booleanAttribute }) nzCancelDisabled: boolean = false;\n  @Input({ transform: booleanAttribute }) nzCancelLoading: boolean = false;\n  @Input({ transform: booleanAttribute }) nzKeyboard: boolean = true;\n  @Input({ transform: booleanAttribute }) nzNoAnimation = false;\n  @Input({ transform: booleanAttribute }) nzCentered = false;\n  @Input({ transform: booleanAttribute }) nzDraggable = false;\n  @Input() nzContent?: string | TemplateRef<{}> | Type<T>;\n  @Input() nzFooter?: string | TemplateRef<{}> | Array<ModalButtonOptions<T>> | null;\n  @Input({ transform: numberAttribute }) nzZIndex: number = 1000;\n  @Input() nzWidth: number | string = 520;\n  @Input() nzWrapClassName?: string;\n  @Input() nzClassName?: string;\n  @Input() nzStyle?: object;\n  @Input() nzTitle?: string | TemplateRef<{}>;\n  @Input() nzCloseIcon: string | TemplateRef<void> = 'close';\n  @Input() nzMaskStyle?: StyleObjectLike;\n  @Input() nzBodyStyle?: StyleObjectLike;\n  @Input() nzOkText?: string | null;\n  @Input() nzCancelText?: string | null;\n  @Input() nzOkType: NzButtonType = 'primary';\n  @Input({ transform: booleanAttribute }) nzOkDanger: boolean = false;\n  @Input() nzIconType: string = 'question-circle'; // Confirm Modal ONLY\n  @Input() nzModalType: ModalTypes = 'default';\n  @Input() nzAutofocus: 'ok' | 'cancel' | 'auto' | null = 'auto';\n\n  /**\n   * @note The input usage will be removed in v22.\n   */\n  @Input()\n  @Output()\n  readonly nzOnOk: EventEmitter<T> | OnClickCallback<T> | NzSafeAny = new EventEmitter<T>();\n\n  /**\n   * @note The input usage will be removed in v22.\n   */\n  @Input()\n  @Output()\n  readonly nzOnCancel: EventEmitter<T> | OnClickCallback<T> | NzSafeAny = new EventEmitter<T>();\n\n  @Output() readonly nzAfterOpen = new EventEmitter<void>();\n  @Output() readonly nzAfterClose = new EventEmitter<R>();\n  @Output() readonly nzVisibleChange = new EventEmitter<boolean>();\n\n  @ContentChild(NzModalTitleDirective, { static: true, read: TemplateRef })\n  set modalTitle(value: TemplateRef<NzSafeAny>) {\n    if (value) {\n      this.setTitleWithTemplate(value);\n    }\n  }\n\n  @ContentChild(NzModalContentDirective, { static: true, read: TemplateRef })\n  contentFromContentChild!: TemplateRef<NzSafeAny>;\n\n  @ContentChild(NzModalFooterDirective, { static: true, read: TemplateRef })\n  set modalFooter(value: TemplateRef<NzSafeAny>) {\n    if (value) {\n      this.setFooterWithTemplate(value);\n    }\n  }\n\n  private modalRef: NzModalRef | null = null;\n\n  get afterOpen(): Observable<void> {\n    // Observable alias for nzAfterOpen\n    return this.nzAfterOpen.asObservable();\n  }\n\n  get afterClose(): Observable<R> {\n    // Observable alias for nzAfterClose\n    return this.nzAfterClose.asObservable();\n  }\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      this.modalRef?._finishDialogClose();\n    });\n  }\n\n  open(): void {\n    if (!this.nzVisible) {\n      this.nzVisible = true;\n      this.nzVisibleChange.emit(true);\n    }\n\n    if (!this.modalRef) {\n      const config = this.getConfig();\n      this.modalRef = this.modal.create(config);\n\n      // When the modal is implicitly closed (e.g. closeAll) the nzVisible needs to be set to the correct value and emit.\n      this.modalRef.afterClose\n        .asObservable()\n        .pipe(takeUntilDestroyed(this.destroyRef))\n        .subscribe(() => {\n          this.close();\n        });\n    }\n  }\n\n  close(result?: R): void {\n    if (this.nzVisible) {\n      this.nzVisible = false;\n      this.nzVisibleChange.emit(false);\n    }\n\n    if (this.modalRef) {\n      this.modalRef.close(result);\n      this.modalRef = null;\n    }\n  }\n\n  destroy(result?: R): void {\n    this.close(result);\n  }\n\n  triggerOk(): void {\n    this.modalRef?.triggerOk();\n  }\n\n  triggerCancel(): void {\n    this.modalRef?.triggerCancel();\n  }\n\n  getContentComponent(): T | void {\n    return this.modalRef?.getContentComponent();\n  }\n\n  getElement(): HTMLElement | void {\n    return this.modalRef?.getElement();\n  }\n\n  getModalRef(): NzModalRef | null {\n    return this.modalRef;\n  }\n\n  private setTitleWithTemplate(templateRef: TemplateRef<{}>): void {\n    this.nzTitle = templateRef;\n    if (this.modalRef) {\n      // If modalRef already created, set the title in next tick\n      Promise.resolve().then(() => {\n        this.modalRef!.updateConfig({\n          nzTitle: this.nzTitle\n        });\n      });\n    }\n  }\n\n  private setFooterWithTemplate(templateRef: TemplateRef<{}>): void {\n    this.nzFooter = templateRef;\n    if (this.modalRef) {\n      // If modalRef already created, set the footer in next tick\n      Promise.resolve().then(() => {\n        this.modalRef!.updateConfig({\n          nzFooter: this.nzFooter\n        });\n      });\n    }\n\n    this.cdr.markForCheck();\n  }\n\n  private getConfig(): ModalOptions {\n    const componentConfig = getConfigFromComponent(this);\n    componentConfig.nzViewContainerRef = this.viewContainerRef;\n    componentConfig.nzContent = this.nzContent || this.contentFromContentChild;\n    return componentConfig;\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzVisible, ...otherChanges } = changes;\n\n    if (Object.keys(otherChanges).length && this.modalRef) {\n      this.modalRef.updateConfig(getConfigFromComponent(this));\n    }\n\n    if (nzVisible) {\n      if (this.nzVisible) {\n        this.open();\n      } else {\n        this.close();\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/modal/modal.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzModalCloseComponent } from './modal-close.component';\nimport { NzModalConfirmContainerComponent } from './modal-confirm-container.component';\nimport { NzModalContainerComponent } from './modal-container.component';\nimport { NzModalContentDirective } from './modal-content.directive';\nimport { NzModalFooterComponent } from './modal-footer.component';\nimport { NzModalFooterDirective } from './modal-footer.directive';\nimport { NzModalTitleComponent } from './modal-title.component';\nimport { NzModalTitleDirective } from './modal-title.directive';\nimport { NzModalComponent } from './modal.component';\nimport { NzModalService } from './modal.service';\n\n@NgModule({\n  imports: [\n    NzModalComponent,\n    NzModalFooterDirective,\n    NzModalContentDirective,\n    NzModalCloseComponent,\n    NzModalFooterComponent,\n    NzModalTitleComponent,\n    NzModalTitleDirective,\n    NzModalContainerComponent,\n    NzModalConfirmContainerComponent\n  ],\n  exports: [NzModalComponent, NzModalFooterDirective, NzModalContentDirective, NzModalTitleDirective],\n  providers: [NzModalService]\n})\nexport class NzModalModule {}\n"
  },
  {
    "path": "components/modal/modal.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport {\n  ComponentType,\n  OverlayRef,\n  createBlockScrollStrategy,\n  createGlobalPositionStrategy,\n  createOverlayRef\n} from '@angular/cdk/overlay';\nimport { ComponentPortal, TemplatePortal } from '@angular/cdk/portal';\nimport { Injectable, Injector, OnDestroy, TemplateRef, inject } from '@angular/core';\nimport { Observable, Subject, defer } from 'rxjs';\nimport { startWith } from 'rxjs/operators';\n\nimport { NzConfigService } from 'ng-zorro-antd/core/config';\nimport { warn } from 'ng-zorro-antd/core/logger';\nimport { overlayZIndexSetter } from 'ng-zorro-antd/core/overlay';\nimport { IndexableObject, NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { isNotNil } from 'ng-zorro-antd/core/util';\n\nimport { MODAL_MASK_CLASS_NAME, NZ_CONFIG_MODULE_NAME, NZ_MODAL_DATA } from './modal-config';\nimport { NzModalConfirmContainerComponent } from './modal-confirm-container.component';\nimport { NzModalContainerComponent } from './modal-container.component';\nimport { BaseModalContainerComponent } from './modal-container.directive';\nimport { NzModalRef } from './modal-ref';\nimport { ConfirmType, ModalOptions } from './modal-types';\nimport { applyConfigDefaults, getValueWithConfig } from './utils';\n\ntype ContentType<T> = ComponentType<T> | TemplateRef<T> | string;\n\n@Injectable()\nexport class NzModalService implements OnDestroy {\n  private injector = inject(Injector);\n  private nzConfigService = inject(NzConfigService);\n  private directionality = inject(Directionality);\n  private parentModal = inject(NzModalService, { skipSelf: true, optional: true });\n\n  private openModalsAtThisLevel: NzModalRef[] = [];\n  private readonly afterAllClosedAtThisLevel = new Subject<void>();\n\n  get openModals(): NzModalRef[] {\n    return this.parentModal ? this.parentModal.openModals : this.openModalsAtThisLevel;\n  }\n\n  get _afterAllClosed(): Subject<void> {\n    const parent = this.parentModal;\n    return parent ? parent._afterAllClosed : this.afterAllClosedAtThisLevel;\n  }\n\n  readonly afterAllClose: Observable<void> = defer(() =>\n    this.openModals.length ? this._afterAllClosed : this._afterAllClosed.pipe(startWith(undefined))\n  ) as Observable<void>;\n\n  create<T, D = NzSafeAny, R = NzSafeAny>(config: ModalOptions<T, D, R>): NzModalRef<T, R> {\n    return this.open<T, D, R>(config.nzContent as ComponentType<T>, config);\n  }\n\n  closeAll(): void {\n    this.closeModals(this.openModals);\n  }\n\n  confirm<T>(options: ModalOptions<T> = {}, confirmType: ConfirmType = 'confirm'): NzModalRef<T> {\n    if ('nzFooter' in options) {\n      warn(`The Confirm-Modal doesn't support \"nzFooter\", this property will be ignored.`);\n    }\n    if (!('nzWidth' in options)) {\n      options.nzWidth = 416;\n    }\n    if (!('nzMaskClosable' in options)) {\n      options.nzMaskClosable = false;\n    }\n\n    options.nzModalType = 'confirm';\n    options.nzClassName = `ant-modal-confirm ant-modal-confirm-${confirmType} ${options.nzClassName || ''}`;\n    return this.create(options);\n  }\n\n  info<T>(options: ModalOptions<T> = {}): NzModalRef<T> {\n    return this.confirmFactory(options, 'info');\n  }\n\n  success<T>(options: ModalOptions<T> = {}): NzModalRef<T> {\n    return this.confirmFactory(options, 'success');\n  }\n\n  error<T>(options: ModalOptions<T> = {}): NzModalRef<T> {\n    return this.confirmFactory(options, 'error');\n  }\n\n  warning<T>(options: ModalOptions<T> = {}): NzModalRef<T> {\n    return this.confirmFactory(options, 'warning');\n  }\n\n  private open<T, D, R>(componentOrTemplateRef: ContentType<T>, config?: ModalOptions<T, D, R>): NzModalRef<T, R> {\n    const configMerged = applyConfigDefaults(config || {}, new ModalOptions());\n    const overlayRef = this.createOverlay(configMerged);\n    const modalContainer = this.attachModalContainer(overlayRef, configMerged);\n    const modalRef = this.attachModalContent<T, D, R>(componentOrTemplateRef, modalContainer, overlayRef, configMerged);\n    modalContainer.modalRef = modalRef;\n\n    overlayZIndexSetter(overlayRef, config?.nzZIndex);\n\n    this.openModals.push(modalRef);\n    modalRef.afterClose.subscribe(() => this.removeOpenModal(modalRef));\n\n    return modalRef;\n  }\n\n  private removeOpenModal(modalRef: NzModalRef): void {\n    const index = this.openModals.indexOf(modalRef);\n    if (index > -1) {\n      this.openModals.splice(index, 1);\n\n      if (!this.openModals.length) {\n        this._afterAllClosed.next();\n      }\n    }\n  }\n\n  private closeModals(dialogs: NzModalRef[]): void {\n    let i = dialogs.length;\n    while (i--) {\n      dialogs[i].close();\n      if (!this.openModals.length) {\n        this._afterAllClosed.next();\n      }\n    }\n  }\n\n  private createOverlay(config: ModalOptions): OverlayRef {\n    const globalConfig: NzSafeAny = this.nzConfigService.getConfigForComponent(NZ_CONFIG_MODULE_NAME) || {};\n\n    return createOverlayRef(this.injector, {\n      hasBackdrop: true,\n      scrollStrategy: createBlockScrollStrategy(this.injector),\n      backdropClass: getValueWithConfig(config.nzMask, globalConfig.nzMask, true) ? MODAL_MASK_CLASS_NAME : '',\n      positionStrategy: createGlobalPositionStrategy(this.injector),\n      disposeOnNavigation: getValueWithConfig(config.nzCloseOnNavigation, globalConfig.nzCloseOnNavigation, true),\n      direction: getValueWithConfig(config.nzDirection, globalConfig.nzDirection, this.directionality.value)\n    });\n  }\n\n  private attachModalContainer(overlayRef: OverlayRef, config: ModalOptions): BaseModalContainerComponent {\n    const userInjector = config && config.nzViewContainerRef && config.nzViewContainerRef.injector;\n    const injector = Injector.create({\n      parent: userInjector || this.injector,\n      providers: [\n        { provide: OverlayRef, useValue: overlayRef },\n        { provide: ModalOptions, useValue: config }\n      ]\n    });\n\n    const ContainerComponent =\n      config.nzModalType === 'confirm'\n        ? // If the mode is `confirm`, use `NzModalConfirmContainerComponent`\n          NzModalConfirmContainerComponent\n        : // If the mode is not `confirm`, use `NzModalContainerComponent`\n          NzModalContainerComponent;\n\n    const containerPortal = new ComponentPortal<BaseModalContainerComponent>(\n      ContainerComponent,\n      config.nzViewContainerRef,\n      injector\n    );\n    const containerRef = overlayRef.attach<BaseModalContainerComponent>(containerPortal);\n\n    return containerRef.instance;\n  }\n\n  private attachModalContent<T, D, R>(\n    componentOrTemplateRef: ContentType<T>,\n    modalContainer: BaseModalContainerComponent,\n    overlayRef: OverlayRef,\n    config: ModalOptions<T>\n  ): NzModalRef<T, R> {\n    const modalRef = new NzModalRef<T, R>(overlayRef, config, modalContainer);\n\n    if (componentOrTemplateRef instanceof TemplateRef) {\n      modalContainer.attachTemplatePortal(\n        new TemplatePortal<T>(componentOrTemplateRef, null!, {\n          $implicit: config.nzData,\n          modalRef\n        } as NzSafeAny)\n      );\n    } else if (isNotNil(componentOrTemplateRef) && typeof componentOrTemplateRef !== 'string') {\n      const injector = this.createInjector<T, D, R>(modalRef, config);\n      const contentRef = modalContainer.attachComponentPortal<T>(\n        new ComponentPortal(componentOrTemplateRef, config.nzViewContainerRef, injector)\n      );\n      modalRef.componentRef = contentRef;\n      modalRef.componentInstance = contentRef.instance;\n    } else {\n      modalContainer.attachStringContent();\n    }\n    return modalRef;\n  }\n\n  private createInjector<T, D, R>(modalRef: NzModalRef<T, R>, config: ModalOptions<T, D, R>): Injector {\n    const userInjector = config && config.nzViewContainerRef && config.nzViewContainerRef.injector;\n\n    return Injector.create({\n      parent: userInjector || this.injector,\n      providers: [\n        { provide: NzModalRef, useValue: modalRef },\n        { provide: NZ_MODAL_DATA, useValue: config.nzData }\n      ]\n    });\n  }\n\n  private confirmFactory<T>(options: ModalOptions<T> = {}, confirmType: ConfirmType): NzModalRef<T> {\n    const iconMap: IndexableObject = {\n      info: 'info-circle',\n      success: 'check-circle',\n      error: 'close-circle',\n      warning: 'exclamation-circle'\n    };\n    if (!('nzIconType' in options)) {\n      options.nzIconType = iconMap[confirmType];\n    }\n    if (!('nzCancelText' in options)) {\n      // Remove the Cancel button if the user not specify a Cancel button\n      options.nzCancelText = null;\n    }\n    return this.confirm(options, confirmType);\n  }\n\n  ngOnDestroy(): void {\n    this.closeModals(this.openModalsAtThisLevel);\n    this.afterAllClosedAtThisLevel.complete();\n  }\n}\n"
  },
  {
    "path": "components/modal/modal.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ESCAPE } from '@angular/cdk/keycodes';\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport { ComponentPortal, TemplatePortal } from '@angular/cdk/portal';\nimport { Location } from '@angular/common';\nimport { SpyLocation } from '@angular/common/testing';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  Directive,\n  Injector,\n  Input,\n  TemplateRef,\n  ViewChild,\n  ViewContainerRef,\n  inject,\n  model,\n  signal\n} from '@angular/core';\nimport { ComponentFixture, TestBed, inject as testingInject } from '@angular/core/testing';\n\nimport { provideNzNoAnimation } from 'ng-zorro-antd/core/animation';\nimport { NzConfigService } from 'ng-zorro-antd/core/config';\nimport {\n  createKeyboardEvent,\n  dispatchEvent,\n  dispatchKeyboardEvent,\n  dispatchMouseEvent,\n  sleep,\n  updateNonSignalsInput\n} from 'ng-zorro-antd/core/testing';\n\nimport { NZ_MODAL_DATA } from './modal-config';\nimport { NzModalRef, NzModalState } from './modal-ref';\nimport { NzModalComponent } from './modal.component';\nimport { NzModalModule } from './modal.module';\nimport { NzModalService } from './modal.service';\n\ndescribe('modal with animation', () => {\n  let modalService: NzModalService;\n  let overlayContainer: OverlayContainer;\n  let overlayContainerElement: HTMLElement;\n  let fixture: ComponentFixture<TestWithServiceComponent>;\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [NzModalService]\n    });\n    modalService = TestBed.inject(NzModalService);\n  });\n\n  beforeEach(\n    testingInject([OverlayContainer], (oc: OverlayContainer) => {\n      overlayContainer = oc;\n      overlayContainerElement = oc.getContainerElement();\n    })\n  );\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(TestWithServiceComponent);\n  });\n\n  afterEach(() => {\n    overlayContainer.ngOnDestroy();\n  });\n\n  // mock animationend events\n  function animationDone(element: Element, action: 'enter' | 'leave'): void {\n    dispatchEvent(\n      element,\n      new AnimationEvent('animationend', { animationName: action === 'enter' ? 'antZoomIn' : 'antZoomOut' })\n    );\n  }\n\n  it('should apply enter class immediately to prevent flicker', () => {\n    modalService.create({\n      nzContent: TestWithModalContentComponent\n    });\n\n    const modalContentElement = overlayContainerElement.querySelector('.ant-modal');\n    const backdropElement = overlayContainerElement.querySelector('.cdk-overlay-backdrop');\n    // Enter class should be applied synchronously (before requestAnimationFrame)\n    // This ensures the modal starts hidden (scale(0), opacity: 0) to prevent flicker\n    expect(modalContentElement!.classList).toContain('ant-zoom-enter');\n    expect(modalContentElement!.classList).not.toContain('ant-zoom-enter-active');\n    if (backdropElement) {\n      expect(backdropElement.classList).toContain('ant-fade-enter');\n      expect(backdropElement.classList).not.toContain('ant-fade-enter-active');\n    }\n  });\n\n  it('should apply animations class', async () => {\n    const modalRef = modalService.create({\n      nzContent: TestWithModalContentComponent\n    });\n\n    await sleep(16); // wait for the next frame\n    const modalContentElement = overlayContainerElement.querySelector('.ant-modal');\n    expect(modalContentElement!.classList).toContain('ant-zoom-enter');\n    expect(modalContentElement!.classList).toContain('ant-zoom-enter-active');\n\n    animationDone(modalContentElement!, 'enter');\n    await fixture.whenStable();\n    modalRef.close();\n\n    expect(modalContentElement!.classList).toContain('ant-zoom-leave');\n    expect(modalContentElement!.classList).toContain('ant-zoom-leave-active');\n  });\n\n  it('should emit when modal opening animation is complete', async () => {\n    const modalRef = modalService.create({\n      nzContent: TestWithModalContentComponent\n    });\n\n    const spy = jasmine.createSpy('afterOpen spy');\n    modalRef.afterOpen.subscribe(spy);\n    expect(spy).not.toHaveBeenCalled();\n\n    const modalContentElement = overlayContainerElement.querySelector('.ant-modal');\n    animationDone(modalContentElement!, 'enter');\n\n    await fixture.whenStable();\n    expect(spy).toHaveBeenCalled();\n  });\n\n  it('should return the current state of the modal', async () => {\n    const modalRef = modalService.create({ nzContent: TestWithModalContentComponent });\n    const modalContentElement = overlayContainerElement.querySelector('.ant-modal');\n\n    expect(modalRef.getState()).toBe(NzModalState.OPEN);\n    animationDone(modalContentElement!, 'enter');\n    await fixture.whenStable();\n\n    modalRef.close();\n    expect(modalRef.getState()).toBe(NzModalState.CLOSING);\n\n    animationDone(modalContentElement!, 'leave');\n    await fixture.whenStable();\n    expect(modalRef.getState()).toBe(NzModalState.CLOSED);\n  });\n\n  describe('NzModalRef', () => {\n    it('should omit any action when closing', async () => {\n      const onOk = jasmine.createSpy('onOk', () => {});\n      const onCancel = jasmine.createSpy('onCancel', () => {});\n      const modalRef = modalService.create({\n        nzContent: TestWithModalContentComponent,\n        nzOnOk: onOk,\n        nzOnCancel: onCancel\n      });\n      const modalContentElement = overlayContainerElement.querySelector('.ant-modal');\n\n      animationDone(modalContentElement!, 'enter');\n      await fixture.whenStable();\n\n      expect(overlayContainerElement.querySelector('nz-modal-container')).not.toBeNull();\n      await modalRef.triggerOk();\n      expect(onOk).toHaveBeenCalledTimes(1);\n      expect(modalRef.getState()).toBe(NzModalState.CLOSING);\n\n      modalRef.triggerOk();\n      modalRef.triggerOk();\n      modalRef.triggerCancel();\n      modalRef.triggerCancel();\n      expect(onOk).toHaveBeenCalledTimes(1);\n      expect(onCancel).toHaveBeenCalledTimes(0);\n\n      animationDone(modalContentElement!, 'leave');\n      await fixture.whenStable();\n      expect(overlayContainerElement.querySelector('nz-modal-container')).toBeNull();\n    });\n  });\n});\n\ndescribe('modal', () => {\n  let modalService: NzModalService;\n  let overlayContainer: OverlayContainer;\n  let overlayContainerElement: HTMLElement;\n  let configService: NzConfigService;\n  let fixture: ComponentFixture<TestWithServiceComponent>;\n  let mockLocation: SpyLocation;\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [NzModalService, provideNzNoAnimation(), { provide: Location, useClass: SpyLocation }]\n    });\n  });\n\n  beforeEach(\n    testingInject(\n      [NzModalService, Location, OverlayContainer, NzConfigService],\n      (m: NzModalService, l: Location, oc: OverlayContainer, cs: NzConfigService) => {\n        modalService = m;\n        configService = cs;\n        mockLocation = l as SpyLocation;\n        overlayContainer = oc;\n        overlayContainerElement = oc.getContainerElement();\n      }\n    )\n  );\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(TestWithServiceComponent);\n  });\n\n  afterEach(() => {\n    overlayContainer.ngOnDestroy();\n  });\n\n  it('should open modal with component', async () => {\n    const modalRef = modalService.create({\n      nzContent: TestWithModalContentComponent,\n      nzData: 'Modal'\n    });\n    await fixture.whenStable();\n\n    const modalContentElement = overlayContainerElement.querySelector('.modal-content');\n    expect(modalContentElement).toBeTruthy();\n    expect(modalContentElement!.textContent).toBe('Hello Modal');\n    expect(modalRef.getContentComponent() instanceof TestWithModalContentComponent).toBe(true);\n    expect(modalRef.getContentComponent().modalRef).toBe(modalRef);\n    expect(modalRef.getContentComponentRef()).not.toBeNull();\n  });\n\n  it('should give correct z-index value to overlay', async () => {\n    const Z_INDEX = 9999;\n    modalService.create({\n      nzContent: TestWithModalContentComponent,\n      nzData: 'Modal',\n      nzZIndex: Z_INDEX\n    });\n    await fixture.whenStable();\n\n    const overlay = document.querySelector('.cdk-global-overlay-wrapper') as HTMLElement;\n    expect(overlay.style.zIndex).toEqual(Z_INDEX.toString());\n  });\n\n  it('should open a modal with data', async () => {\n    const modalRef = modalService.create({\n      nzContent: TestWithModalContentComponent,\n      nzData: 'NG-ZORRO'\n    });\n    await fixture.whenStable();\n\n    const modalContentElement = overlayContainerElement.querySelector('.modal-data');\n    expect(modalContentElement).toBeTruthy();\n    expect(modalContentElement!.textContent?.toString().includes('NG-ZORRO')).toBeTruthy();\n    expect(modalRef.getContentComponent() instanceof TestWithModalContentComponent).toBe(true);\n    expect(modalRef.getContentComponent().modalRef).toBe(modalRef);\n    expect(modalRef.getContentComponentRef()).not.toBeNull();\n  });\n\n  it('should open modal with template', async () => {\n    fixture.componentInstance.value = 'Modal';\n    await updateNonSignalsInput(fixture);\n    const modalRef = modalService.create({\n      nzContent: fixture.componentInstance.templateRef\n    });\n    await fixture.whenStable();\n\n    const modalContentElement = overlayContainerElement.querySelector('.modal-template-content');\n    expect(modalContentElement).toBeTruthy();\n    expect(modalContentElement!.textContent).toBe('Hello Modal');\n    expect(fixture.componentInstance.modalRef).toBe(modalRef);\n    expect(modalRef.getContentComponentRef()).toBeNull();\n    expect(modalRef.getContentComponent()).toBeNull();\n  });\n\n  it('should open modal with template and pass data', async () => {\n    fixture.componentInstance.value = 'Modal';\n    await updateNonSignalsInput(fixture);\n    const modalRef = modalService.create({\n      nzContent: fixture.componentInstance.templateRef,\n      nzData: 'NG-ZORRO'\n    });\n    await fixture.whenStable();\n\n    const modalContentElement = overlayContainerElement.querySelector('.modal-template-data');\n    expect(modalContentElement).toBeTruthy();\n    expect(modalContentElement!.textContent?.includes('NG-ZORRO')).toBeTruthy();\n    expect(fixture.componentInstance.modalRef).toBe(modalRef);\n    modalRef.close();\n  });\n\n  it('should be thrown when attaching repeatedly', async () => {\n    const modalRefComponent = modalService.create({\n      nzContent: TestWithModalContentComponent\n    });\n    await fixture.whenStable();\n\n    expect(() => {\n      modalRefComponent.containerInstance.attachComponentPortal(new ComponentPortal(TestWithModalContentComponent));\n    }).toThrowError('Attempting to attach modal content after content is already attached');\n\n    const modalRefTemplate = modalService.create({\n      nzContent: fixture.componentInstance.templateRef\n    });\n\n    expect(() => {\n      modalRefTemplate.containerInstance.attachTemplatePortal(\n        new TemplatePortal(fixture.componentInstance.templateRef, null!)\n      );\n    }).toThrowError('Attempting to attach modal content after content is already attached');\n  });\n\n  it('should open modal with HTML string', async () => {\n    const modalRef = modalService.create({\n      nzContent: `<span class=\"modal-html-content\">Hello Modal</span>`\n    });\n    await fixture.whenStable();\n\n    const modalContentElement = overlayContainerElement.querySelector('.modal-html-content');\n    expect(modalContentElement).toBeTruthy();\n    expect(modalContentElement!.textContent).toBe('Hello Modal');\n    modalRef.close();\n  });\n\n  describe('close', () => {\n    let modalRef: NzModalRef;\n\n    beforeEach(async () => {\n      modalRef = modalService.create({\n        nzContent: TestWithModalContentComponent\n      });\n      await fixture.whenStable();\n    });\n\n    describe('afterClose', () => {\n      let spy: jasmine.Spy;\n\n      beforeEach(() => {\n        spy = jasmine.createSpy('afterClose callback');\n      });\n\n      it('should close and get the result', async () => {\n        modalRef.afterClose.subscribe(spy);\n\n        modalRef.close('Hello Modal');\n        await fixture.whenStable();\n\n        expect(spy).toHaveBeenCalledWith('Hello Modal');\n        expect(overlayContainerElement.querySelector('nz-modal-container')).toBeNull();\n      });\n\n      it('should destroy and get the result', async () => {\n        modalRef.afterClose.subscribe(spy);\n\n        modalRef.destroy('Hello Modal');\n        await fixture.whenStable();\n\n        expect(spy).toHaveBeenCalledWith('Hello Modal');\n        expect(overlayContainerElement.querySelector('nz-modal-container')).toBeNull();\n      });\n    });\n\n    describe('animation', () => {\n      xit('should emit when modal closing animation is complete', async () => {\n        // todo: test with animation\n      });\n\n      xit('should dispose the modal if view container is destroyed while animating', async () => {\n        // todo: test with animation\n      });\n    });\n\n    describe('with keyboard', () => {\n      it('should close a modal via the escape key', async () => {\n        const event = dispatchKeyboardEvent(document.body, 'keydown', ESCAPE);\n        await fixture.whenStable();\n\n        expect(overlayContainerElement.querySelector('nz-modal-container')).toBeNull();\n        expect(event.defaultPrevented).toBe(true);\n      });\n\n      it('should not close a modal via the escape key with a modifier', async () => {\n        const event = createKeyboardEvent('keydown', ESCAPE);\n        Object.defineProperty(event, 'altKey', { get: () => true });\n        dispatchEvent(document.body, event);\n        await fixture.whenStable();\n\n        expect(overlayContainerElement.querySelector('nz-modal-container')).toBeTruthy();\n        expect(event.defaultPrevented).toBe(false);\n      });\n\n      it('should not close a modal when the nzKeyboard is false', async () => {\n        modalRef.updateConfig({\n          nzKeyboard: false\n        });\n        await fixture.whenStable();\n\n        dispatchKeyboardEvent(document.body, 'keydown', ESCAPE);\n        await fixture.whenStable();\n        expect(overlayContainerElement.querySelector('nz-modal-container')).toBeTruthy();\n      });\n    });\n\n    it('should not close a modal when the nzOkLoading is true', async () => {\n      modalRef.updateConfig({\n        nzOkLoading: true\n      });\n      await fixture.whenStable();\n\n      dispatchKeyboardEvent(document.body, 'keydown', ESCAPE);\n      await fixture.whenStable();\n      expect(overlayContainerElement.querySelector('nz-modal-container')).toBeTruthy();\n\n      modalRef.updateConfig({\n        nzOkLoading: false\n      });\n      await fixture.whenStable();\n\n      dispatchKeyboardEvent(document.body, 'keydown', ESCAPE);\n      await fixture.whenStable();\n      expect(overlayContainerElement.querySelector('nz-modal-container')).toBeNull();\n    });\n\n    it('should not close a modal when the nzCancelLoading is true', async () => {\n      modalRef.updateConfig({\n        nzCancelLoading: true\n      });\n      await fixture.whenStable();\n\n      dispatchKeyboardEvent(document.body, 'keydown', ESCAPE);\n      await fixture.whenStable();\n      expect(overlayContainerElement.querySelector('nz-modal-container')).toBeTruthy();\n\n      modalRef.updateConfig({\n        nzCancelLoading: false\n      });\n      await fixture.whenStable();\n\n      dispatchKeyboardEvent(document.body, 'keydown', ESCAPE);\n      await fixture.whenStable();\n      expect(overlayContainerElement.querySelector('nz-modal-container')).toBeNull();\n    });\n\n    it('should close when clicking on the modal wrap', async () => {\n      const modalWrapElement = overlayContainerElement.querySelector('nz-modal-container') as HTMLElement;\n      modalWrapElement.click();\n      await fixture.whenStable();\n      expect(overlayContainerElement.querySelector('nz-modal-container')).toBeFalsy();\n    });\n\n    it(\"should close when clicking on the modal's close button\", async () => {\n      const closeBtn = overlayContainerElement.querySelector('button[nz-modal-close]') as HTMLButtonElement;\n      closeBtn.click();\n      await fixture.whenStable();\n      expect(overlayContainerElement.querySelector('nz-modal-container')).toBeFalsy();\n    });\n\n    it('should not close when mouseup on the modal wrap and mousedown on the modal body', async () => {\n      const modalWrap = overlayContainerElement.querySelector('nz-modal-container') as HTMLElement;\n      const modalBody = overlayContainerElement.querySelector('.ant-modal-body') as HTMLElement;\n\n      dispatchMouseEvent(modalBody, 'mousedown');\n      await fixture.whenStable();\n\n      dispatchMouseEvent(modalWrap, 'mouseup');\n      await fixture.whenStable();\n      expect(overlayContainerElement.querySelector('nz-modal-container')).toBeTruthy();\n    });\n\n    it('should not close when clicking on the modal wrap and the nzMaskClosable or nzMask is false', async () => {\n      modalRef.updateConfig({\n        nzMaskClosable: false\n      });\n      await fixture.whenStable();\n\n      const modalWrap = overlayContainerElement.querySelector('nz-modal-container') as HTMLElement;\n      dispatchMouseEvent(modalWrap, 'mousedown');\n      dispatchMouseEvent(modalWrap, 'mouseup');\n      await fixture.whenStable();\n      expect(overlayContainerElement.querySelector('nz-modal-container')).toBeTruthy();\n\n      modalRef.updateConfig({\n        nzMaskClosable: true,\n        nzMask: false\n      });\n      await fixture.whenStable();\n\n      dispatchMouseEvent(modalWrap, 'mousedown');\n      dispatchMouseEvent(modalWrap, 'mouseup');\n      await fixture.whenStable();\n      expect(overlayContainerElement.querySelector('nz-modal-container')).toBeTruthy();\n    });\n  });\n\n  it('should global config work', async () => {\n    configService.set('modal', { nzMask: false });\n\n    const modalRef = modalService.create({\n      nzContent: TestWithModalContentComponent\n    });\n    await fixture.whenStable();\n\n    expect(modalRef.getBackdropElement()?.classList).not.toContain('ant-modal-mask');\n\n    configService.set('modal', { nzMask: true });\n    await fixture.whenStable();\n\n    // should add class when global config changed\n    expect(modalRef.getBackdropElement()?.classList).toContain('ant-modal-mask');\n\n    configService.set('modal', { nzMask: false });\n    await fixture.whenStable();\n\n    // should remove class when global config changed\n    expect(modalRef.getBackdropElement()?.classList).not.toContain('ant-modal-mask');\n\n    configService.set('modal', { nzMask: true }); // reset\n  });\n\n  it('nzMask work', async () => {\n    configService.set('modal', { nzMask: false });\n\n    const modalRef = modalService.create({\n      nzContent: TestWithModalContentComponent\n    });\n    await fixture.whenStable();\n\n    // should not have default cdk dark backdrop\n    expect(modalRef.getBackdropElement()?.classList).not.toContain('cdk-overlay-dark-backdrop');\n\n    configService.set('modal', { nzMask: true });\n    await fixture.whenStable();\n\n    // should add class when global config changed\n    expect(modalRef.getBackdropElement()?.classList).toContain('ant-modal-mask');\n  });\n\n  it('should notify the observers if all open modals have finished closing', async () => {\n    const ref1 = modalService.create({\n      nzContent: TestWithModalContentComponent\n    });\n    const ref2 = modalService.create({\n      nzContent: TestWithModalContentComponent\n    });\n    const spy = jasmine.createSpy('afterAllClose spy');\n\n    modalService.afterAllClose.subscribe(spy);\n\n    ref1.close();\n    await fixture.whenStable();\n    expect(spy).not.toHaveBeenCalled();\n\n    ref2.close();\n    await fixture.whenStable();\n    expect(spy).toHaveBeenCalled();\n  });\n\n  it('should emit the afterAllClose stream on subscribe if there are no open modals', () => {\n    const spy = jasmine.createSpy('afterAllClose spy');\n    modalService.afterAllClose.subscribe(spy);\n    expect(spy).toHaveBeenCalled();\n  });\n\n  it('should set and update the width of the modal', async () => {\n    const modalRef = modalService.create({\n      nzContent: TestWithModalContentComponent,\n      nzWidth: 500\n    });\n    await fixture.whenStable();\n\n    const modal = overlayContainerElement.querySelector('.ant-modal') as HTMLElement;\n    expect(modal.style.width).toBe('500px');\n\n    modalRef.updateConfig({\n      nzWidth: 300\n    });\n    await fixture.whenStable();\n\n    expect(modal.style.width).toBe('300px');\n\n    modalRef.updateConfig({\n      nzWidth: '100%'\n    });\n    await fixture.whenStable();\n\n    expect(modal.style.width).toBe('100%');\n  });\n\n  it('should set and update the z-index of the modal', async () => {\n    const modalRef = modalService.create({\n      nzContent: TestWithModalContentComponent,\n      nzZIndex: 1001\n    });\n    await fixture.whenStable();\n\n    const modal = overlayContainerElement.querySelector('nz-modal-container') as HTMLElement;\n    const mask = overlayContainerElement.querySelector('.ant-modal-mask') as HTMLElement;\n\n    expect(modal.style.zIndex).toBe('1001');\n    expect(mask.style.zIndex).toBe('1001');\n\n    modalRef.updateConfig({\n      nzZIndex: 1100\n    });\n    await fixture.whenStable();\n\n    expect(modal.style.zIndex).toBe('1100');\n    expect(mask.style.zIndex).toBe('1100');\n  });\n\n  it('should set the nzWrapClassName of the modal', async () => {\n    modalService.create({\n      nzContent: TestWithModalContentComponent,\n      nzWrapClassName: 'test-wrap-class'\n    });\n    await fixture.whenStable();\n\n    const modal = overlayContainerElement.querySelector('nz-modal-container') as HTMLElement;\n    expect(modal.classList).toContain('test-wrap-class');\n  });\n\n  it('should set the nzCentered of the modal', async () => {\n    modalService.create({\n      nzCentered: true,\n      nzContent: TestWithModalContentComponent\n    });\n    await fixture.whenStable();\n\n    const modal = overlayContainerElement.querySelector('nz-modal-container') as HTMLElement;\n    expect(modal.classList).toContain('ant-modal-centered');\n  });\n\n  it('should set the nzClassName of the modal', async () => {\n    modalService.create({\n      nzContent: TestWithModalContentComponent,\n      nzClassName: 'test-class-name'\n    });\n    await fixture.whenStable();\n\n    const modal = overlayContainerElement.querySelector('.ant-modal') as HTMLElement;\n    expect(modal.classList).toContain('test-class-name');\n  });\n\n  it('should set the nzStyle of the modal', async () => {\n    modalService.create({\n      nzContent: TestWithModalContentComponent,\n      nzStyle: {\n        color: 'rgb(0, 0, 0)'\n      }\n    });\n    await fixture.whenStable();\n\n    const modal = overlayContainerElement.querySelector('.ant-modal') as HTMLElement;\n    expect(modal.style.color).toContain('rgb(0, 0, 0)');\n  });\n\n  it('should set the nzBodyStyle of the modal', async () => {\n    modalService.create({\n      nzContent: TestWithModalContentComponent,\n      nzBodyStyle: {\n        color: 'rgb(0, 0, 0)'\n      }\n    });\n    await fixture.whenStable();\n\n    const modal = overlayContainerElement.querySelector('.ant-modal-body') as HTMLElement;\n    expect(modal.style.color).toContain('rgb(0, 0, 0)');\n  });\n\n  it('should set the nzMaskStyle of the modal', async () => {\n    const modalRef = modalService.create({\n      nzContent: TestWithModalContentComponent,\n      nzMaskStyle: {\n        color: 'rgb(0, 0, 0)'\n      }\n    });\n    await fixture.whenStable();\n\n    expect(modalRef.getBackdropElement()!.style.color).toBe('rgb(0, 0, 0)');\n\n    modalRef.updateConfig({\n      nzMaskStyle: {\n        color: 'rgb(255, 0, 0)'\n      }\n    });\n    await fixture.whenStable();\n\n    expect(modalRef.getBackdropElement()!.style.color).toBe('rgb(255, 0, 0)');\n  });\n\n  it('should close all of the modals', async () => {\n    modalService.create({ nzContent: TestWithModalContentComponent });\n    modalService.create({ nzContent: TestWithModalContentComponent });\n    modalService.create({ nzContent: TestWithModalContentComponent });\n    await fixture.whenStable();\n\n    expect(overlayContainerElement.querySelectorAll('nz-modal-container').length).toBe(3);\n\n    modalService.closeAll();\n    await fixture.whenStable();\n\n    expect(overlayContainerElement.querySelector('nz-modal-container')).toBeNull();\n  });\n\n  it('should close all open modals when the user goes forwards/backwards in history', async () => {\n    modalService.create({ nzContent: TestWithModalContentComponent });\n    modalService.create({ nzContent: TestWithModalContentComponent });\n    await fixture.whenStable();\n\n    expect(overlayContainerElement.querySelectorAll('nz-modal-container').length).toBe(2);\n\n    mockLocation.simulateHashChange('');\n    await fixture.whenStable();\n\n    expect(overlayContainerElement.querySelector('nz-modal-container')).toBeNull();\n  });\n\n  it('should close all open modals when the location hash changes', async () => {\n    modalService.create({ nzContent: TestWithModalContentComponent });\n    modalService.create({ nzContent: TestWithModalContentComponent });\n    await fixture.whenStable();\n\n    expect(overlayContainerElement.querySelectorAll('nz-modal-container').length).toBe(2);\n\n    mockLocation.simulateHashChange('');\n    await fixture.whenStable();\n\n    expect(overlayContainerElement.querySelector('nz-modal-container')).toBeNull();\n  });\n\n  it('should close all of the modals when the injectable is destroyed', async () => {\n    modalService.create({ nzContent: TestWithModalContentComponent });\n    modalService.create({ nzContent: TestWithModalContentComponent });\n    await fixture.whenStable();\n\n    expect(overlayContainerElement.querySelectorAll('nz-modal-container').length).toBe(2);\n\n    modalService.ngOnDestroy();\n    await fixture.whenStable();\n\n    expect(overlayContainerElement.querySelector('nz-modal-container')).toBeNull();\n  });\n\n  it('should complete close streams when the injectable is destroyed', async () => {\n    const afterAllCloseSpy = jasmine.createSpy('after all closed spy');\n    modalService.afterAllClose.subscribe({\n      complete: afterAllCloseSpy\n    });\n\n    modalService.ngOnDestroy();\n    await fixture.whenStable();\n\n    expect(afterAllCloseSpy).toHaveBeenCalled();\n  });\n\n  it('should allow the consumer to disable modals a modal on navigation', async () => {\n    modalService.create({ nzContent: TestWithModalContentComponent });\n    modalService.create({ nzContent: TestWithModalContentComponent, nzCloseOnNavigation: false });\n\n    expect(overlayContainerElement.querySelectorAll('nz-modal-container').length).toBe(2);\n\n    mockLocation.simulateUrlPop('');\n    await fixture.whenStable();\n\n    expect(overlayContainerElement.querySelector('nz-modal-container')).not.toBeNull();\n  });\n\n  it('should have the componentInstance available in the afterClose callback', async () => {\n    const modalRef = modalService.create({ nzContent: TestWithModalContentComponent });\n    const spy = jasmine.createSpy('afterClose spy');\n    modalRef.afterClose.subscribe(() => {\n      spy();\n      expect(modalRef.componentInstance).toBeTruthy();\n    });\n\n    await fixture.whenStable();\n    modalRef.close();\n\n    await sleep(500);\n    await fixture.whenStable();\n\n    expect(spy).toHaveBeenCalled();\n  });\n\n  it('should use injector from viewContainerRef', async () => {\n    const viewContainerFixture = TestBed.createComponent(TestWithChildViewContainerComponent);\n    await viewContainerFixture.whenStable();\n    const viewContainerRef = viewContainerFixture.componentInstance.childViewContainer;\n\n    const modalRef = modalService.create({\n      nzContent: TestWithModalContentComponent,\n      nzViewContainerRef: viewContainerRef\n    });\n    await viewContainerFixture.whenStable();\n\n    const modalInjector = modalRef.componentInstance!.modalInjector;\n\n    expect(modalRef.componentInstance!.modalRef).toBe(modalRef);\n    expect(modalInjector.get<TestWithViewContainerDirective>(TestWithViewContainerDirective)).toBeTruthy();\n  });\n\n  it('should close from a ViewContainerRef with OnPush change detection', async () => {\n    const onPushFixture = TestBed.createComponent(TestWithOnPushViewContainerComponent);\n    await onPushFixture.whenStable();\n\n    const modalRef = modalService.create({\n      nzContent: TestWithModalContentComponent,\n      nzViewContainerRef: onPushFixture.componentInstance.viewContainerRef\n    });\n    await onPushFixture.whenStable();\n\n    expect(overlayContainerElement.querySelector('nz-modal-container')).not.toBeNull();\n\n    modalRef.close();\n    await onPushFixture.whenStable();\n\n    expect(overlayContainerElement.querySelector('nz-modal-container')).toBeNull();\n  });\n\n  describe('NzModalRef', () => {\n    it('should getElement work', async () => {\n      const modalRef = modalService.create({ nzContent: TestWithModalContentComponent });\n      await fixture.whenStable();\n\n      const container = overlayContainerElement.querySelector('nz-modal-container') as HTMLElement;\n      expect(modalRef.getElement()).toBe(container);\n    });\n\n    it('should triggerOk work', async () => {\n      const modalRef = modalService.create({ nzContent: TestWithModalContentComponent });\n      await fixture.whenStable();\n\n      expect(overlayContainerElement.querySelector('nz-modal-container')).not.toBeNull();\n\n      modalRef.triggerOk();\n      await fixture.whenStable();\n      expect(overlayContainerElement.querySelector('nz-modal-container')).toBeNull();\n    });\n\n    it('should triggerCancel work', async () => {\n      const modalRef = modalService.create({ nzContent: TestWithModalContentComponent });\n      await fixture.whenStable();\n\n      expect(overlayContainerElement.querySelector('nz-modal-container')).not.toBeNull();\n\n      modalRef.triggerCancel();\n      await fixture.whenStable();\n      expect(overlayContainerElement.querySelector('nz-modal-container')).toBeNull();\n    });\n\n    it('should not close the modal when loading', async () => {\n      const modalRef = modalService.create({ nzContent: TestWithModalContentComponent });\n      await fixture.whenStable();\n\n      expect(overlayContainerElement.querySelector('nz-modal-container')).not.toBeNull();\n\n      modalRef.updateConfig({\n        nzOkLoading: true\n      });\n      await fixture.whenStable();\n      modalRef.triggerOk();\n      await fixture.whenStable();\n      expect(overlayContainerElement.querySelector('nz-modal-container')).not.toBeNull();\n\n      modalRef.updateConfig({\n        nzOkLoading: false\n      });\n      await fixture.whenStable();\n      modalRef.triggerOk();\n      await fixture.whenStable();\n      expect(overlayContainerElement.querySelector('nz-modal-container')).toBeNull();\n    });\n\n    it('should set loading state when the callback is promise', async () => {\n      const modalRef = modalService.create({\n        nzContent: TestWithModalContentComponent,\n        nzOnOk: () =>\n          new Promise(resolve => {\n            setTimeout(() => {\n              resolve();\n            }, 200);\n          })\n      });\n      await fixture.whenStable();\n\n      modalRef.triggerOk();\n      await fixture.whenStable();\n      expect(modalRef.getConfig().nzOkLoading).toBe(true);\n      expect(overlayContainerElement.querySelector('nz-modal-container')).not.toBeNull();\n\n      await sleep(200);\n      await fixture.whenStable();\n      expect(modalRef.getConfig().nzOkLoading).toBe(false);\n      expect(overlayContainerElement.querySelector('nz-modal-container')).toBeNull();\n    });\n\n    it('should not close when the callback is return false', async () => {\n      const modalRef = modalService.create({\n        nzContent: TestWithModalContentComponent,\n        nzOnOk: () => false\n      });\n      await fixture.whenStable();\n\n      modalRef.triggerOk();\n      await fixture.whenStable();\n\n      expect(overlayContainerElement.querySelector('nz-modal-container')).not.toBeNull();\n      modalRef.close();\n      await fixture.whenStable();\n      expect(overlayContainerElement.querySelector('nz-modal-container')).toBeNull();\n    });\n\n    it('should not close when the callback is return Promise<false>', async () => {\n      const modalRef = modalService.create({\n        nzContent: TestWithModalContentComponent,\n        nzOnOk: () =>\n          new Promise(resolve => {\n            setTimeout(() => {\n              resolve(false);\n            }, 200);\n          })\n      });\n      await fixture.whenStable();\n\n      modalRef.triggerOk();\n      await fixture.whenStable();\n      expect(modalRef.getConfig().nzOkLoading).toBe(true);\n      expect(overlayContainerElement.querySelector('nz-modal-container')).not.toBeNull();\n\n      await sleep(200);\n      await fixture.whenStable();\n      expect(modalRef.getConfig().nzOkLoading).toBe(false);\n      expect(overlayContainerElement.querySelector('nz-modal-container')).not.toBeNull();\n\n      modalRef.close();\n      await fixture.whenStable();\n      expect(overlayContainerElement.querySelector('nz-modal-container')).toBeNull();\n    });\n\n    it('should not close when the callback is return Promise.reject', async () => {\n      const modalRef = modalService.create({\n        nzContent: TestWithModalContentComponent,\n        nzOnOk: () =>\n          new Promise((_, reject) => {\n            setTimeout(() => {\n              reject('Promise.reject');\n            }, 200);\n          })\n      });\n      await fixture.whenStable();\n\n      expectAsync(modalRef.triggerOk()).toBeRejectedWith('Promise.reject');\n      await fixture.whenStable();\n\n      expect(modalRef.getConfig().nzOkLoading).toBe(true);\n      expect(overlayContainerElement.querySelector('nz-modal-container')).not.toBeNull();\n\n      await sleep(200);\n      await fixture.whenStable();\n\n      expect(modalRef.getConfig().nzOkLoading).toBe(false);\n      expect(overlayContainerElement.querySelector('nz-modal-container')).not.toBeNull();\n\n      modalRef.close();\n      await fixture.whenStable();\n      expect(overlayContainerElement.querySelector('nz-modal-container')).toBeNull();\n    });\n  });\n\n  describe('focus management', () => {\n    // When testing focus, all the elements must be in the DOM.\n    beforeEach(() => document.body.appendChild(overlayContainerElement));\n    afterEach(() => document.body.removeChild(overlayContainerElement));\n\n    it('should focus the first tabbable element of the modal on open', async () => {\n      modalService.create({\n        nzContent: TestWithModalContentComponent,\n        nzClosable: false,\n        nzFooter: null\n      });\n      await fixture.whenStable();\n\n      // expect the first tabbable element (input) in the modal to be focused.\n      expect(document.activeElement!.tagName).toBe('INPUT');\n    });\n\n    it('should focus the first tabbable element when content is string type', async () => {\n      const modalRef = modalService.confirm({\n        nzContent: 'confirm content'\n      });\n      await fixture.whenStable();\n\n      expect(modalRef.containerInstance.getNativeElement().contains(document.activeElement)).toBe(true);\n    });\n\n    it('should allow disabling focus of the first tabbable element', async () => {\n      modalService.create({\n        nzContent: TestWithModalContentComponent,\n        nzClosable: false,\n        nzFooter: null,\n        nzAutofocus: null\n      });\n      await fixture.whenStable();\n\n      expect(document.activeElement!.tagName).not.toBe('INPUT');\n    });\n\n    it('should re-focus trigger element when modal closes', async () => {\n      // Create an element that has focus before the modal is opened.\n      const button = document.createElement('button');\n      button.id = 'modal-trigger';\n      document.body.appendChild(button);\n      button.focus();\n\n      const modalRef = modalService.create({\n        nzContent: TestWithModalContentComponent\n      });\n      await fixture.whenStable();\n\n      // expect the focus to change when modal is opened\n      expect(document.activeElement!.id).not.toBe('modal-trigger');\n\n      // expect the focus not to have changed before the animation finishes\n      modalRef.close();\n      await fixture.whenStable();\n\n      // expect the trigger is refocused after the modal is closed.\n      expect(document.activeElement!.id).toBe('modal-trigger');\n\n      document.body.removeChild(button);\n    });\n\n    it('should move focus to the container if there are no focusable elements in the modal', async () => {\n      modalService.create({\n        nzContent: TestModalWithoutFocusableElementsComponent,\n        nzClosable: false,\n        nzFooter: null\n      });\n      await sleep(16);\n      await fixture.whenStable();\n\n      // expect the modal container to be focused\n      expect(document.activeElement!.tagName).toBe('NZ-MODAL-CONTAINER');\n    });\n  });\n\n  describe('footer', () => {\n    let modalRef: NzModalRef;\n\n    function getCancelButton(): HTMLButtonElement {\n      return overlayContainerElement.querySelector('div[nz-modal-footer] button:nth-child(1)') as HTMLButtonElement;\n    }\n\n    function getOkButton(): HTMLButtonElement {\n      return overlayContainerElement.querySelector('div[nz-modal-footer] button:nth-child(2)') as HTMLButtonElement;\n    }\n\n    beforeEach(async () => {\n      modalRef = modalService.create({\n        nzContent: TestWithModalContentComponent\n      });\n      await fixture.whenStable();\n    });\n\n    it('should the ok button work', async () => {\n      const spy = jasmine.createSpy('afterClose spy');\n      modalRef.afterClose.subscribe(spy);\n\n      const okButton = getOkButton();\n      expect(okButton).toBeTruthy();\n\n      okButton.click();\n      expect(spy).toHaveBeenCalled();\n    });\n\n    it('should the cancel button work', async () => {\n      const spy = jasmine.createSpy('afterClose spy');\n      modalRef.afterClose.subscribe(spy);\n\n      const cancelButton = getCancelButton();\n      expect(cancelButton).toBeTruthy();\n\n      cancelButton.click();\n      expect(spy).toHaveBeenCalled();\n    });\n\n    it('should loading work', async () => {\n      modalRef.updateConfig({\n        nzOkLoading: true,\n        nzCancelLoading: true\n      });\n      await fixture.whenStable();\n\n      const okButton = getOkButton();\n      const cancelButton = getCancelButton();\n      expect(okButton.classList).toContain('ant-btn-loading');\n      expect(cancelButton.classList).toContain('ant-btn-loading');\n    });\n\n    it('should loading work', async () => {\n      modalRef.updateConfig({\n        nzOkDisabled: true,\n        nzCancelDisabled: true\n      });\n      await fixture.whenStable();\n\n      const okButton = getOkButton();\n      const cancelButton = getCancelButton();\n      expect(okButton.disabled).toBe(true);\n      expect(cancelButton.disabled).toBe(true);\n    });\n  });\n\n  it('should set footer with buttons', async () => {\n    // note: the buttons in `nzFooter` only works in the constructor of the builtin modal footer\n    let errorThrown = false;\n    modalService.create({\n      nzContent: TestWithModalContentComponent,\n      nzFooter: [\n        {\n          label: 'Test Button0',\n          onClick: () =>\n            new Promise(resolve => {\n              setTimeout(() => {\n                resolve(null);\n              }, 200);\n            })\n        },\n        {\n          label: 'Test Button1',\n          loading: () => true\n        },\n        {\n          label: 'Test Button2',\n          autoLoading: false,\n          onClick: () =>\n            new Promise(resolve => {\n              setTimeout(() => {\n                resolve(null);\n              }, 200);\n            })\n        },\n        {\n          label: 'Test Button3',\n          onClick: () =>\n            new Promise(() => {\n              errorThrown = true;\n              throw new Error('Rethrow error');\n            })\n        }\n      ]\n    });\n    await fixture.whenStable();\n\n    const buttons = overlayContainerElement.querySelectorAll(\n      'div[nz-modal-footer] button'\n    ) as NodeListOf<HTMLButtonElement>;\n    expect(buttons[0].textContent!.trim()).toBe('Test Button0');\n    expect(buttons[0].classList).not.toContain('ant-btn-loading');\n\n    expect(buttons[1].textContent!.trim()).toBe('Test Button1');\n    expect(buttons[1].classList).toContain('ant-btn-loading');\n\n    expect(buttons[2].textContent!.trim()).toBe('Test Button2');\n    expect(buttons[2].classList).not.toContain('ant-btn-loading');\n\n    expect(buttons[3].textContent!.trim()).toBe('Test Button3');\n    expect(buttons[3].classList).not.toContain('ant-btn-loading');\n\n    // should click to set loading to true, and automatically set loading to false after 200ms\n    buttons[0].click();\n    await fixture.whenStable();\n    expect(buttons[0].classList).toContain('ant-btn-loading');\n    // skip: loading has been set to false, but the class is not removed\n    // await sleep(200);\n    // await fixture.whenStable();\n    // expect(buttons[0].classList).not.toContain('ant-btn-loading');\n\n    // loading is always true\n    expect(buttons[1].classList).toContain('ant-btn-loading');\n\n    // won't set loading to true if autoLoading is false\n    buttons[2].click();\n    await fixture.whenStable();\n    expect(buttons[2].classList).not.toContain('ant-btn-loading');\n\n    // should throw error\n    try {\n      buttons[3].click();\n      await fixture.whenStable();\n    } catch (e) {\n      expect(e).toMatch(/Rethrow error/);\n    }\n    expect(errorThrown).toBeTrue();\n  });\n\n  describe('confirm', () => {\n    it('should set default option', async () => {\n      const modalRef = modalService.confirm({\n        nzContent: 'Test Content',\n        nzTitle: 'Test Title',\n        nzFooter: [{ label: 'Test Footer' }]\n      });\n      await fixture.whenStable();\n\n      expect((overlayContainerElement.querySelector('.ant-modal') as HTMLDivElement).style.width).toBe('416px');\n      expect(modalRef.getConfig().nzMaskClosable).toBe(false);\n      expect(modalRef.getConfig().nzDraggable).toBe(false);\n      expect(modalRef.getConfig().nzCentered).toBe(false);\n      expect(overlayContainerElement.querySelector('nz-modal-confirm-container')).not.toBeNull();\n      expect(overlayContainerElement.querySelector('.ant-modal-confirm-title')!.textContent).toBe('Test Title');\n      expect(overlayContainerElement.querySelector('.ant-modal-confirm-content')!.textContent).toBe('Test Content');\n      expect(overlayContainerElement.querySelectorAll('.ant-modal-confirm-btns button').length).toBe(2);\n    });\n\n    it('should the ok button work', async () => {\n      modalService.confirm();\n      await fixture.whenStable();\n\n      expect(overlayContainerElement.querySelector('nz-modal-confirm-container')).not.toBeNull();\n      const okButton = overlayContainerElement.querySelector(\n        '.ant-modal-confirm-btns button:nth-child(2)'\n      ) as HTMLButtonElement;\n      okButton.click();\n      await fixture.whenStable();\n      expect(overlayContainerElement.querySelector('nz-modal-confirm-container')).toBeNull();\n    });\n\n    it('should the cancel button work', async () => {\n      modalService.confirm();\n      await fixture.whenStable();\n\n      expect(overlayContainerElement.querySelector('nz-modal-confirm-container')).not.toBeNull();\n      const cancelButton = overlayContainerElement.querySelector(\n        '.ant-modal-confirm-btns button:nth-child(1)'\n      ) as HTMLButtonElement;\n      cancelButton.click();\n      await fixture.whenStable();\n      expect(overlayContainerElement.querySelector('nz-modal-confirm-container')).toBeNull();\n    });\n\n    it('should info type work', async () => {\n      const modalRef = modalService.info();\n      await fixture.whenStable();\n      expect(modalRef.getConfig().nzIconType).toBe('info-circle');\n    });\n\n    it('should success type work', async () => {\n      const modalRef = modalService.success();\n      await fixture.whenStable();\n      expect(modalRef.getConfig().nzIconType).toBe('check-circle');\n    });\n\n    it('should error type work', async () => {\n      const modalRef = modalService.error();\n      await fixture.whenStable();\n      expect(modalRef.getConfig().nzIconType).toBe('close-circle');\n    });\n\n    it('should warning type work', async () => {\n      const modalRef = modalService.warning();\n      await fixture.whenStable();\n      expect(modalRef.getConfig().nzIconType).toBe('exclamation-circle');\n    });\n\n    it('should set nzIconType', async () => {\n      const modalRef = modalService.warning({\n        nzIconType: 'info-circle'\n      });\n      await fixture.whenStable();\n      expect(modalRef.getConfig().nzIconType).toBe('info-circle');\n    });\n\n    it('should set nzCancelText', async () => {\n      const modalRef = modalService.warning({\n        nzCancelText: 'cancel'\n      });\n      await fixture.whenStable();\n      expect(modalRef.getConfig().nzCancelText).toBe('cancel');\n    });\n\n    it('should set nzCentered', async () => {\n      const modalRef = modalService.confirm({\n        nzCentered: true\n      });\n      await fixture.whenStable();\n\n      expect(modalRef.getConfig().nzCentered).toBe(true);\n\n      const modal = overlayContainerElement.querySelector('nz-modal-confirm-container') as HTMLElement;\n      expect(modal.classList).toContain('ant-modal-centered');\n    });\n\n    it('should open confirm with component', async () => {\n      const modalRef = modalService.confirm({\n        nzContent: TestWithModalContentComponent,\n        nzData: 'Confirm'\n      });\n      await fixture.whenStable();\n\n      const modalContentElement = overlayContainerElement.querySelector('.modal-content');\n      expect(modalContentElement).toBeTruthy();\n      expect(modalContentElement!.textContent).toBe('Hello Confirm');\n      expect(modalRef.getContentComponent() instanceof TestWithModalContentComponent).toBe(true);\n      expect(modalRef.getContentComponent().modalRef).toBe(modalRef);\n    });\n  });\n\n  describe('nz-modal component', () => {\n    let componentFixture: ComponentFixture<TestModalComponent>;\n    let componentInstance: TestModalComponent;\n\n    beforeEach(async () => {\n      componentFixture = TestBed.createComponent(TestModalComponent);\n      componentInstance = componentFixture.componentInstance;\n    });\n\n    it('should nzVisible work', async () => {\n      const openSpy = jasmine.createSpy('open spy');\n      const closeSpy = jasmine.createSpy('close spy');\n\n      componentInstance.nzModalComponent.afterClose.subscribe(closeSpy);\n      componentInstance.nzModalComponent.afterOpen.subscribe(openSpy);\n\n      expect(openSpy).not.toHaveBeenCalled();\n      expect(closeSpy).not.toHaveBeenCalled();\n\n      componentInstance.visible.set(true);\n      await fixture.whenStable();\n\n      expect(openSpy).toHaveBeenCalled();\n      expect(overlayContainerElement.querySelector('nz-modal-container')).not.toBeNull();\n\n      componentInstance.visible.set(false);\n      await fixture.whenStable();\n\n      expect(closeSpy).toHaveBeenCalled();\n      expect(overlayContainerElement.querySelector('nz-modal-container')).toBeNull();\n    });\n\n    it('should set nzVisible to false when implicitly closed', async () => {\n      const closeSpy = jasmine.createSpy('close spy');\n      componentInstance.nzModalComponent.afterClose.subscribe(closeSpy);\n      expect(closeSpy).not.toHaveBeenCalled();\n\n      componentInstance.visible.set(true);\n      await fixture.whenStable();\n      expect(overlayContainerElement.querySelector('nz-modal-container')).not.toBeNull();\n\n      modalService.closeAll();\n      await fixture.whenStable();\n\n      expect(closeSpy).toHaveBeenCalled();\n      expect(componentInstance.visible()).toBe(false);\n      expect(overlayContainerElement.querySelector('nz-modal-container')).toBeNull();\n    });\n\n    it('should nzOnCancel work', async () => {\n      componentInstance.visible.set(true);\n      await fixture.whenStable();\n\n      expect(componentInstance.cancelSpy).not.toHaveBeenCalled();\n\n      const button = overlayContainerElement.querySelector(\n        'nz-modal-container div[nz-modal-footer] button:nth-child(1)'\n      ) as HTMLButtonElement;\n      button.click();\n      await fixture.whenStable();\n\n      expect(componentInstance.cancelSpy).toHaveBeenCalled();\n      expect(overlayContainerElement.querySelector('nz-modal-container')).toBeNull();\n    });\n\n    it('should nzOnOk work', async () => {\n      componentInstance.visible.set(true);\n      await fixture.whenStable();\n\n      expect(componentInstance.okSpy).not.toHaveBeenCalled();\n\n      const button = overlayContainerElement.querySelector(\n        'nz-modal-container div[nz-modal-footer] button:nth-child(2)'\n      ) as HTMLButtonElement;\n      button.click();\n      await fixture.whenStable();\n\n      expect(componentInstance.okSpy).toHaveBeenCalled();\n      expect(overlayContainerElement.querySelector('nz-modal-container')).toBeNull();\n    });\n\n    it('should nzContent work', async () => {\n      const modalInstance = componentInstance.nzModalComponent;\n\n      modalInstance.open();\n      await fixture.whenStable();\n\n      expect(modalInstance.getModalRef()!.getConfig().nzContent).not.toBe(componentInstance.templateRef);\n\n      componentInstance.content.set(componentInstance.templateRef);\n      await fixture.whenStable();\n\n      expect(modalInstance.getModalRef()!.getConfig().nzContent).toBe(componentInstance.templateRef);\n    });\n\n    it('should global config work', async () => {\n      configService.set('modal', {\n        nzMaskClosable: false\n      });\n      const modalInstance = componentInstance.nzModalComponent;\n      modalInstance.open();\n      await fixture.whenStable();\n\n      let modalWrapElement = overlayContainerElement.querySelector('nz-modal-container') as HTMLElement;\n      let modalElement = overlayContainerElement.querySelector('nz-modal-container .ant-modal') as HTMLElement;\n\n      dispatchMouseEvent(modalWrapElement, 'mousedown');\n      dispatchMouseEvent(modalElement, 'mouseup');\n      modalWrapElement.click();\n      await fixture.whenStable();\n\n      expect(componentInstance.cancelSpy).not.toHaveBeenCalled();\n\n      configService.set('modal', {\n        nzMaskClosable: true\n      });\n      await fixture.whenStable();\n\n      modalWrapElement = overlayContainerElement.querySelector('nz-modal-container') as HTMLElement;\n      modalElement = overlayContainerElement.querySelector('nz-modal-container .ant-modal') as HTMLElement;\n\n      dispatchMouseEvent(modalWrapElement, 'mousedown');\n      dispatchMouseEvent(modalElement, 'mouseup');\n      modalWrapElement.click();\n      await fixture.whenStable();\n      expect(componentInstance.cancelSpy).toHaveBeenCalled();\n    });\n\n    it('should instance API work', async () => {\n      const modalInstance = componentInstance.nzModalComponent;\n\n      expect(overlayContainerElement.querySelector('nz-modal-container')).toBeNull();\n\n      modalInstance.open();\n      await fixture.whenStable();\n\n      expect(overlayContainerElement.querySelector('nz-modal-container')).not.toBeNull();\n\n      modalInstance.open();\n      await fixture.whenStable();\n\n      expect(overlayContainerElement.querySelector('nz-modal-container')).not.toBeNull();\n\n      modalInstance.close();\n      await fixture.whenStable();\n\n      expect(overlayContainerElement.querySelector('nz-modal-container')).toBeNull();\n\n      expect(() => {\n        modalInstance.close();\n      }).not.toThrowError();\n\n      modalInstance.open();\n      await fixture.whenStable();\n\n      expect(overlayContainerElement.querySelector('nz-modal-container')).not.toBeNull();\n\n      expect(modalInstance.getContentComponent()).toBeFalsy();\n      expect(modalInstance.getElement()).toBeTruthy();\n\n      modalInstance.destroy();\n      await fixture.whenStable();\n\n      expect(overlayContainerElement.querySelector('nz-modal-container')).toBeNull();\n\n      expect(modalInstance.getContentComponent()).toBeFalsy();\n      expect(modalInstance.getElement()).toBeFalsy();\n\n      expect(() => {\n        modalInstance.triggerOk();\n        modalInstance.triggerCancel();\n      }).not.toThrowError();\n    });\n\n    it('should close when the host view is destroyed', async () => {\n      componentInstance.visible.set(true);\n      await fixture.whenStable();\n\n      expect(overlayContainerElement.querySelector('nz-modal-container')).not.toBeNull();\n\n      componentFixture.destroy();\n      await fixture.whenStable();\n\n      expect(overlayContainerElement.querySelector('nz-modal-container')).toBeNull();\n    });\n\n    it('should be draggable when nzDraggable is set to true', async () => {\n      componentInstance.visible.set(true);\n      componentInstance.draggable.set(true);\n      await fixture.whenStable();\n      expect(overlayContainerElement.querySelector('.cdk-drag')).not.toBeNull();\n\n      componentInstance.draggable.set(false);\n      await fixture.whenStable();\n      expect(overlayContainerElement.querySelector('.cdk-drag-disabled')).not.toBeNull();\n    });\n\n    it('should have \"move\" cursor on the top of modal when modal is draggable', async () => {\n      componentInstance.visible.set(true);\n      componentInstance.draggable.set(true);\n      await fixture.whenStable();\n      const modalHeader = overlayContainerElement.querySelector('.ant-modal-header');\n      expect(getComputedStyle(modalHeader!).cursor).toEqual('move');\n\n      componentInstance.visible.set(true);\n      componentInstance.draggable.set(false);\n      await fixture.whenStable();\n      expect(getComputedStyle(modalHeader!).cursor).toEqual('auto');\n    });\n  });\n});\n\n@Directive({\n  selector: 'nz-test-with-view-container'\n})\nclass TestWithViewContainerDirective {\n  constructor(public viewContainerRef: ViewContainerRef) {}\n}\n\n@Component({\n  selector: 'test-with-child-view-container',\n  imports: [TestWithViewContainerDirective],\n  template: `<nz-test-with-view-container />`\n})\nclass TestWithChildViewContainerComponent {\n  @ViewChild(TestWithViewContainerDirective) childWithViewContainer!: TestWithViewContainerDirective;\n\n  get childViewContainer(): ViewContainerRef {\n    return this.childWithViewContainer.viewContainerRef;\n  }\n}\n\n@Component({\n  selector: 'test-with-on-push-view-container',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: 'hello'\n})\nclass TestWithOnPushViewContainerComponent {\n  constructor(public viewContainerRef: ViewContainerRef) {}\n}\n\n@Component({\n  selector: 'test-with-service',\n  template: `\n    <ng-template let-modalRef=\"modalRef\" let-data>\n      <span class=\"modal-template-content\">Hello {{ value }}</span>\n      <span class=\"modal-template-data\">My favorite UI framework is {{ data }}</span>\n      {{ setModalRef(modalRef) }}\n    </ng-template>\n  `\n})\nclass TestWithServiceComponent {\n  value?: string;\n  modalRef?: NzModalRef;\n  @ViewChild(TemplateRef) templateRef!: TemplateRef<{}>;\n\n  constructor(\n    public nzModalService: NzModalService,\n    public viewContainerRef: ViewContainerRef\n  ) {}\n\n  setModalRef(modalRef: NzModalRef): string {\n    this.modalRef = modalRef;\n    return '';\n  }\n}\n\n@Component({\n  selector: 'test-with-modal-content',\n  imports: [NzModalModule],\n  template: `\n    <div class=\"modal-content\">Hello {{ value }}</div>\n    <div class=\"modal-data\">My favorite UI Library is {{ nzModalData }}</div>\n    <input />\n    <button (click)=\"destroyModal()\">destroy</button>\n  `\n})\nclass TestWithModalContentComponent {\n  @Input() value: string = inject(NZ_MODAL_DATA);\n  nzModalData: string = inject(NZ_MODAL_DATA);\n  modalRef = inject(NzModalRef);\n  modalInjector = inject(Injector);\n\n  destroyModal(): void {\n    this.modalRef.destroy();\n  }\n}\n\n@Component({\n  selector: 'test-modal',\n  imports: [NzModalModule],\n  template: `\n    <nz-modal\n      [(nzVisible)]=\"visible\"\n      [nzContent]=\"content()\"\n      [nzDraggable]=\"draggable()\"\n      nzTitle=\"Test Title\"\n      (nzOnCancel)=\"handleCancel()\"\n      (nzOnOk)=\"handleOk()\"\n    >\n      Test Content\n    </nz-modal>\n    <ng-template><span class=\"template-test\">Test Template Content</span></ng-template>\n  `\n})\nclass TestModalComponent {\n  readonly visible = model(false);\n  readonly draggable = signal(false);\n  cancelSpy = jasmine.createSpy('cancel spy');\n  okSpy = jasmine.createSpy('ok spy');\n  @ViewChild(NzModalComponent, { static: true }) nzModalComponent!: NzModalComponent;\n  @ViewChild(TemplateRef, { static: true }) templateRef!: TemplateRef<{}>;\n\n  readonly content = signal(this.templateRef);\n\n  handleCancel(): void {\n    this.visible.set(false);\n    this.cancelSpy();\n  }\n\n  handleOk(): void {\n    this.visible.set(false);\n    this.okSpy();\n  }\n}\n\n@Component({\n  selector: 'test-modal-without-focusable-elements',\n  template: '<p>Modal</p>'\n})\nclass TestModalWithoutFocusableElementsComponent {}\n"
  },
  {
    "path": "components/modal/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/modal/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './modal-types';\nexport * from './modal.service';\nexport * from './modal-ref';\nexport * from './modal-config';\nexport * from './modal.component';\nexport * from './modal-title.directive';\nexport * from './modal-footer.directive';\nexport * from './modal-content.directive';\nexport * from './modal.module';\nexport * from './modal-confirm-container.component';\nexport * from './modal-container.component';\nexport * from './modal-container.directive';\nexport * from './modal-close.component';\nexport * from './modal-title.component';\nexport * from './modal-legacy-api';\nexport * from './modal-types';\nexport * from './modal-footer.component';\nexport * from './utils';\n"
  },
  {
    "path": "components/modal/style/confirm.less",
    "content": "@import '../../style/mixins/index';\n\n@confirm-prefix-cls: ~'@{ant-prefix}-modal-confirm';\n\n.@{confirm-prefix-cls} {\n  .@{ant-prefix}-modal-header {\n    display: none;\n  }\n\n  .@{ant-prefix}-modal-body {\n    padding: @modal-confirm-body-padding;\n  }\n\n  &-body-wrapper {\n    .clearfix();\n  }\n\n  &-body {\n    .@{confirm-prefix-cls}-title {\n      display: block;\n      // create BFC to avoid\n      // https://user-images.githubusercontent.com/507615/37702510-ba844e06-2d2d-11e8-9b67-8e19be57f445.png\n      overflow: hidden;\n      color: @heading-color;\n      font-weight: 500;\n      font-size: @modal-confirm-title-font-size;\n      line-height: 1.4;\n    }\n\n    .@{confirm-prefix-cls}-content {\n      margin-top: 8px;\n      color: @text-color;\n      font-size: @font-size-base;\n    }\n\n    > .@{iconfont-css-prefix} {\n      float: left;\n      margin-right: 16px;\n      font-size: 22px;\n\n      // `content` after `icon` should set marginLeft\n      + .@{confirm-prefix-cls}-title + .@{confirm-prefix-cls}-content {\n        margin-left: 38px;\n      }\n    }\n  }\n\n  .@{confirm-prefix-cls}-btns {\n    margin-top: 24px;\n    text-align: right;\n\n    .@{ant-prefix}-btn + .@{ant-prefix}-btn {\n      margin-bottom: 0;\n      margin-left: 8px;\n    }\n  }\n\n  &-error &-body > .@{iconfont-css-prefix} {\n    color: @error-color;\n  }\n\n  &-warning &-body > .@{iconfont-css-prefix},\n  &-confirm &-body > .@{iconfont-css-prefix} {\n    color: @warning-color;\n  }\n\n  &-info &-body > .@{iconfont-css-prefix} {\n    color: @info-color;\n  }\n\n  &-success &-body > .@{iconfont-css-prefix} {\n    color: @success-color;\n  }\n\n  // https://github.com/ant-design/ant-design/issues/37329\n  .@{ant-prefix}-zoom-leave .@{confirm-prefix-cls}-btns {\n    pointer-events: none;\n  }\n}\n"
  },
  {
    "path": "components/modal/style/customize.less",
    "content": "@import './index.less';\n\n.popover-customize-bg(@dialog-prefix-cls, @popover-background);\n"
  },
  {
    "path": "components/modal/style/entry.less",
    "content": "@import './index.less';\n// style dependencies\n@import '../../button/style/entry.less';\n"
  },
  {
    "path": "components/modal/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import '../../style/core/motion/zoom';\n@import './modal';\n@import './confirm';\n@import './rtl';\n\n.popover-customize-bg(@dialog-prefix-cls, @popover-background);\n\n// Animations\n.zoom-motion('zoom', antZoom);\n"
  },
  {
    "path": "components/modal/style/modal.less",
    "content": "@dialog-prefix-cls: ~'@{ant-prefix}-modal';\n\n.@{dialog-prefix-cls} {\n  .reset-component();\n  .modal-mask();\n\n  position: relative;\n  top: 100px;\n  width: auto;\n  max-width: calc(100vw - 32px);\n  margin: 0 auto;\n  padding-bottom: 24px;\n\n  &-wrap {\n    z-index: @zindex-modal;\n  }\n\n  &-title {\n    margin: 0;\n    color: @modal-heading-color;\n    font-weight: 500;\n    font-size: @modal-header-title-font-size;\n    line-height: @modal-header-title-line-height;\n    word-wrap: break-word;\n  }\n\n  &-content {\n    position: relative;\n    background-color: @modal-content-bg;\n    background-clip: padding-box;\n    border: 0;\n    border-radius: @modal-border-radius;\n    box-shadow: @shadow-2;\n    pointer-events: auto;\n  }\n\n  &-close {\n    position: absolute;\n    top: 0;\n    right: 0;\n    z-index: @zindex-popup-close;\n    padding: 0;\n    color: @modal-close-color;\n    font-weight: 700;\n    line-height: 1;\n    text-decoration: none;\n    background: transparent;\n    border: 0;\n    outline: 0;\n    cursor: pointer;\n    transition: color 0.3s;\n\n    &-x {\n      display: block;\n      width: @modal-header-close-size;\n      height: @modal-header-close-size;\n      font-size: @font-size-lg;\n      font-style: normal;\n      line-height: @modal-header-close-size;\n      text-align: center;\n      text-transform: none;\n      text-rendering: auto;\n    }\n\n    &:focus,\n    &:hover {\n      color: @icon-color-hover;\n      text-decoration: none;\n    }\n  }\n\n  &-header {\n    padding: @modal-header-padding;\n    color: @text-color;\n    background: @modal-header-bg;\n    border-bottom: @modal-header-border-width @modal-header-border-style\n      @modal-header-border-color-split;\n    border-radius: @modal-border-radius @modal-border-radius 0 0;\n  }\n\n  &-body {\n    padding: @modal-body-padding;\n    font-size: @font-size-base;\n    line-height: @line-height-base;\n    word-wrap: break-word;\n  }\n\n  &-footer {\n    padding: @modal-footer-padding-vertical @modal-footer-padding-horizontal;\n    text-align: right;\n    background: @modal-footer-bg;\n    border-top: @modal-footer-border-width @modal-footer-border-style\n      @modal-footer-border-color-split;\n    border-radius: 0 0 @modal-border-radius @modal-border-radius;\n\n    .@{ant-prefix}-btn + .@{ant-prefix}-btn:not(.@{ant-prefix}-dropdown-trigger) {\n      margin-bottom: 0;\n      margin-left: 8px;\n    }\n  }\n\n  &-open {\n    overflow: hidden;\n  }\n}\n\n.@{dialog-prefix-cls}-centered {\n  text-align: center;\n\n  &::before {\n    display: inline-block;\n    width: 0;\n    height: 100%;\n    vertical-align: middle;\n    content: '';\n  }\n  .@{dialog-prefix-cls} {\n    top: 0;\n    display: inline-block;\n    padding-bottom: 0;\n    text-align: left;\n    vertical-align: middle;\n  }\n}\n\n@media (max-width: @screen-sm-max) {\n  .@{dialog-prefix-cls} {\n    max-width: calc(100vw - 16px);\n    margin: 8px auto;\n  }\n  .@{dialog-prefix-cls}-centered {\n    .@{dialog-prefix-cls} {\n      flex: 1;\n    }\n  }\n}\n"
  },
  {
    "path": "components/modal/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@dialog-prefix-cls: ~'@{ant-prefix}-modal';\n@confirm-prefix-cls: ~'@{ant-prefix}-modal-confirm';\n@dialog-wrap-rtl-cls: ~'@{dialog-prefix-cls}-wrap-rtl';\n\n.@{dialog-prefix-cls} {\n  &-wrap {\n    &-rtl {\n      direction: rtl;\n    }\n  }\n\n  &-close {\n    .@{dialog-wrap-rtl-cls} & {\n      right: initial;\n      left: 0;\n    }\n  }\n\n  &-footer {\n    .@{dialog-wrap-rtl-cls} & {\n      text-align: left;\n    }\n    .@{ant-prefix}-btn + .@{ant-prefix}-btn {\n      .@{dialog-wrap-rtl-cls} & {\n        margin-right: 8px;\n        margin-left: 0;\n      }\n    }\n  }\n\n  &-confirm {\n    &-body {\n      .@{dialog-wrap-rtl-cls} & {\n        direction: rtl;\n      }\n      > .@{iconfont-css-prefix} {\n        .@{dialog-wrap-rtl-cls} & {\n          float: right;\n          margin-right: 0;\n          margin-left: 16px;\n        }\n        + .@{confirm-prefix-cls}-title + .@{confirm-prefix-cls}-content {\n          .@{dialog-wrap-rtl-cls} & {\n            margin-right: 38px;\n            margin-left: 0;\n          }\n        }\n      }\n    }\n\n    &-btns {\n      .@{dialog-wrap-rtl-cls} & {\n        text-align: left;\n      }\n      .@{ant-prefix}-btn + .@{ant-prefix}-btn {\n        .@{dialog-wrap-rtl-cls} & {\n          margin-right: 8px;\n          margin-left: 0;\n        }\n      }\n    }\n  }\n}\n\n.@{dialog-prefix-cls}-centered {\n  .@{dialog-prefix-cls} {\n    .@{dialog-wrap-rtl-cls}& {\n      text-align: right;\n    }\n  }\n}\n"
  },
  {
    "path": "components/modal/utils.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ModalOptions } from './modal-types';\n\nexport function applyConfigDefaults(config: ModalOptions, defaultOptions: ModalOptions): ModalOptions {\n  return { ...defaultOptions, ...config };\n}\n\nexport function getValueWithConfig<T>(\n  userValue: T | undefined,\n  configValue: T | undefined,\n  defaultValue: T\n): T | undefined {\n  return typeof userValue === 'undefined'\n    ? typeof configValue === 'undefined'\n      ? defaultValue\n      : configValue\n    : userValue;\n}\n\nexport function getConfigFromComponent<T extends ModalOptions>(component: T): ModalOptions {\n  const {\n    nzCentered,\n    nzMask,\n    nzMaskClosable,\n    nzClosable,\n    nzOkLoading,\n    nzOkDisabled,\n    nzCancelDisabled,\n    nzCancelLoading,\n    nzKeyboard,\n    nzNoAnimation,\n    nzDraggable,\n    nzContent,\n    nzFooter,\n    nzZIndex,\n    nzWidth,\n    nzWrapClassName,\n    nzClassName,\n    nzStyle,\n    nzTitle,\n    nzCloseIcon,\n    nzMaskStyle,\n    nzBodyStyle,\n    nzOkText,\n    nzCancelText,\n    nzOkType,\n    nzOkDanger,\n    nzIconType,\n    nzModalType,\n    nzOnOk,\n    nzOnCancel,\n    nzAfterOpen,\n    nzAfterClose,\n    nzCloseOnNavigation,\n    nzAutofocus\n  } = component;\n  return {\n    nzCentered,\n    nzMask,\n    nzMaskClosable,\n    nzDraggable,\n    nzClosable,\n    nzOkLoading,\n    nzOkDisabled,\n    nzCancelDisabled,\n    nzCancelLoading,\n    nzKeyboard,\n    nzNoAnimation,\n    nzContent,\n    nzFooter,\n    nzZIndex,\n    nzWidth,\n    nzWrapClassName,\n    nzClassName,\n    nzStyle,\n    nzTitle,\n    nzCloseIcon,\n    nzMaskStyle,\n    nzBodyStyle,\n    nzOkText,\n    nzCancelText,\n    nzOkType,\n    nzOkDanger,\n    nzIconType,\n    nzModalType,\n    nzOnOk,\n    nzOnCancel,\n    nzAfterOpen,\n    nzAfterClose,\n    nzCloseOnNavigation,\n    nzAutofocus\n  };\n}\n"
  },
  {
    "path": "components/ng-package.json",
    "content": "{\n  \"$schema\": \"../node_modules/ng-packagr/ng-package.schema.json\",\n  \"dest\": \"../publish\",\n  \"deleteDestPath\": true,\n  \"lib\": {\n    \"entryFile\": \"./public_api.ts\"\n  },\n  \"allowedNonPeerDependencies\": [\n    \"tslib\",\n    \"angular\",\n    \"date-fns\",\n    \"@ant-design/icons-angular\",\n    \"@ctrl/tinycolor\",\n    \"monaco-editor\",\n    \"cron-parser\",\n    \"dagre-compound\",\n    \"d3\"\n  ]\n}\n"
  },
  {
    "path": "components/ng-zorro-antd.aliyun.less",
    "content": "@import \"./style/aliyun.less\";\n@import \"./style/entry.less\";\n@import \"./components.less\";\n"
  },
  {
    "path": "components/ng-zorro-antd.compact.less",
    "content": "@import \"./style/compact.less\";\n@import \"./style/entry.less\";\n@import \"./components.less\";\n"
  },
  {
    "path": "components/ng-zorro-antd.dark.less",
    "content": "@import \"./style/dark.less\";\n@import \"./style/entry.less\";\n@import \"./components.less\";\n"
  },
  {
    "path": "components/ng-zorro-antd.less",
    "content": "@import './style/default.less';\n@import './style/patch.less';\n@import './components.less';\n"
  },
  {
    "path": "components/ng-zorro-antd.variable.less",
    "content": "@import './style/variable.less';\n@import './style/patch.less';\n@import './components.less';\n"
  },
  {
    "path": "components/notification/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n最简单的用法，4.5 秒后自动关闭。\n\n## en-US\n\nThe simplest usage that close the notification box after 4.5s.\n"
  },
  {
    "path": "components/notification/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzNotificationService } from 'ng-zorro-antd/notification';\n\n@Component({\n  selector: 'nz-demo-notification-basic',\n  imports: [NzButtonModule],\n  template: `<button nz-button nzType=\"primary\" (click)=\"createNotification()\">Open the notification box</button>`\n})\nexport class NzDemoNotificationBasicComponent {\n  constructor(private notification: NzNotificationService) {}\n\n  createNotification(): void {\n    this.notification\n      .blank(\n        'Notification Title',\n        'This is the content of the notification. This is the content of the notification. This is the content of the notification.'\n      )\n      .onClick.subscribe(() => {\n        console.log('notification clicked!');\n      });\n  }\n}\n"
  },
  {
    "path": "components/notification/demo/custom-icon.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 自定义图标\n  en-US: Customized Icon\n---\n\n## zh-CN\n\n图标可以被自定义。\n\n## en-US\n\nThe icon can be customized to any `TemplateRef<void>`.\n"
  },
  {
    "path": "components/notification/demo/custom-icon.ts",
    "content": "import { Component, TemplateRef } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { type NzNotificationComponent, NzNotificationService } from 'ng-zorro-antd/notification';\n\n@Component({\n  selector: 'nz-demo-notification-custom-icon',\n  imports: [NzIconModule, NzButtonModule],\n  template: `\n    <ng-template #template>\n      <div class=\"ant-notification-notice-content\">\n        <div class=\"ant-notification-notice-with-icon\">\n          <span class=\"ant-notification-notice-icon\">\n            <nz-icon nzType=\"smile\" style=\"color: rgb(16, 142, 233);\" />\n          </span>\n          <div class=\"ant-notification-notice-message\">Notification Title</div>\n          <div class=\"ant-notification-notice-description\">\n            This is the content of the notification. This is the content of the notification. This is the content of the\n            notification.\n          </div>\n        </div>\n      </div>\n    </ng-template>\n    <button nz-button nzType=\"primary\" (click)=\"createNotification(template)\">Open the notification box</button>\n  `\n})\nexport class NzDemoNotificationCustomIconComponent {\n  constructor(private notification: NzNotificationService) {}\n\n  createNotification(template: TemplateRef<{ $implicit: NzNotificationComponent; data: undefined }>): void {\n    this.notification.template(template);\n  }\n}\n"
  },
  {
    "path": "components/notification/demo/custom-style.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 自定义样式\n  en-US: Customized style\n---\n\n## zh-CN\n\n使用 nzStyle 和 nzClass 来定义样式。\n\n## en-US\n\nThe nzStyle and nzClass are available to customize Notification.\n"
  },
  {
    "path": "components/notification/demo/custom-style.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzNotificationService } from 'ng-zorro-antd/notification';\n\n@Component({\n  selector: 'nz-demo-notification-custom-style',\n  imports: [NzButtonModule],\n  template: `<button nz-button nzType=\"primary\" (click)=\"createNotification()\">Open the notification box</button>`\n})\nexport class NzDemoNotificationCustomStyleComponent {\n  constructor(private notification: NzNotificationService) {}\n\n  createNotification(): void {\n    this.notification.blank(\n      'Notification Title',\n      'This is the content of the notification. This is the content of the notification. This is the content of the notification.',\n      {\n        nzStyle: {\n          width: '600px',\n          marginLeft: '-265px'\n        },\n        nzClass: 'test-class'\n      }\n    );\n  }\n}\n"
  },
  {
    "path": "components/notification/demo/duration.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 自动关闭的延时\n  en-US: Duration after which the notification box is closed\n---\n\n## zh-CN\n\n自定义通知框自动关闭的延时，默认`4.5s`，取消自动关闭只要将该值设为 `0` 即可。\n\n## en-US\n\n`nzDuration` can be used to specify how long the notification stays open. After the duration time elapses,\nthe notification closes automatically. If not specified, default value is 4.5 seconds. If you set the value to 0,\nthe notification box will never close automatically.\n"
  },
  {
    "path": "components/notification/demo/duration.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzNotificationService } from 'ng-zorro-antd/notification';\n\n@Component({\n  selector: 'nz-demo-notification-duration',\n  imports: [NzButtonModule],\n  template: `<button nz-button nzType=\"primary\" (click)=\"createNotification()\">Open the notification box</button>`\n})\nexport class NzDemoNotificationDurationComponent {\n  constructor(private notification: NzNotificationService) {}\n\n  createNotification(): void {\n    this.notification.blank(\n      'Notification Title',\n      'I will never close automatically. This is a purposely very very long description that has many many characters and words.',\n      { nzDuration: 0 }\n    );\n  }\n}\n"
  },
  {
    "path": "components/notification/demo/placement.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 位置\n  en-US: Placement\n---\n\n## zh-CN\n\n通知从右上角、右下角、左下角、左上角、上方、下方弹出。\n\n## en-US\n\nA notification box can pop up from `topRight` or `bottomRight` or `bottomLeft` or `topLeft` or `top` or `bottom`.\n"
  },
  {
    "path": "components/notification/demo/placement.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzNotificationPlacement, NzNotificationService } from 'ng-zorro-antd/notification';\n\n@Component({\n  selector: 'nz-demo-notification-placement',\n  imports: [NzButtonModule, NzDividerModule, NzIconModule],\n  template: `\n    <button nz-button (click)=\"createNotification('top')\" nzType=\"primary\">\n      <nz-icon nzType=\"border-top\" nzTheme=\"outline\" />\n      top\n    </button>\n    <button nz-button (click)=\"createNotification('bottom')\" nzType=\"primary\">\n      <nz-icon nzType=\"border-bottom\" nzTheme=\"outline\" />\n      bottom\n    </button>\n    <nz-divider />\n    <button nz-button (click)=\"createNotification('topLeft')\" nzType=\"primary\">\n      <nz-icon nzType=\"radius-upleft\" />\n      topLeft\n    </button>\n    <button nz-button (click)=\"createNotification('topRight')\" nzType=\"primary\">\n      <nz-icon nzType=\"radius-upright\" />\n      topRight\n    </button>\n    <nz-divider />\n    <button nz-button (click)=\"createNotification('bottomLeft')\" nzType=\"primary\">\n      <nz-icon nzType=\"radius-bottomleft\" />\n      bottomLeft\n    </button>\n    <button nz-button (click)=\"createNotification('bottomRight')\" nzType=\"primary\">\n      <nz-icon nzType=\"radius-bottomright\" />\n      bottomRight\n    </button>\n  `,\n  styles: `\n    button {\n      margin-right: 1em;\n    }\n  `\n})\nexport class NzDemoNotificationPlacementComponent {\n  placement = 'topRight';\n\n  constructor(private notification: NzNotificationService) {}\n\n  createNotification(position: NzNotificationPlacement): void {\n    this.notification.blank(\n      'Notification Title',\n      'This is the content of the notification. This is the content of the notification. This is the content of the notification.',\n      { nzPlacement: position }\n    );\n  }\n}\n"
  },
  {
    "path": "components/notification/demo/template.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 使用模板\n  en-US: Use a template\n---\n\n## zh-CN\n\n通过模板来实现更加复杂的效果和交互。\n\n## en-US\n\nUse template to implement more complex interactions.\n"
  },
  {
    "path": "components/notification/demo/template.ts",
    "content": "import { Component, TemplateRef, ViewChild } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { type NzNotificationComponent, NzNotificationService } from 'ng-zorro-antd/notification';\nimport { NzTagModule } from 'ng-zorro-antd/tag';\n\n@Component({\n  selector: 'nz-demo-notification-template',\n  imports: [NzButtonModule, NzTagModule],\n  template: `\n    <button nz-button nzType=\"primary\" (click)=\"createNotification()\">Open the notification box</button>\n    <ng-template let-fruit=\"data\">\n      It's a\n      <nz-tag [nzColor]=\"fruit.color\">{{ fruit.name }}</nz-tag>\n      <button nz-button nzSize=\"small\">Cut It!</button>\n    </ng-template>\n  `,\n  styles: `\n    button {\n      margin-top: 8px;\n    }\n  `\n})\nexport class NzDemoNotificationTemplateComponent {\n  @ViewChild(TemplateRef, { static: false }) template?: TemplateRef<{\n    $implicit: NzNotificationComponent;\n    data: Array<{ name: string; color: string }>;\n  }>;\n\n  constructor(private notificationService: NzNotificationService) {}\n\n  createNotification(): void {\n    const fruits = [\n      { name: 'Apple', color: 'red' },\n      { name: 'Orange', color: 'orange' },\n      { name: 'Watermelon', color: 'green' }\n    ];\n\n    fruits.forEach(fruit => {\n      this.notificationService.template(this.template!, { nzData: fruit });\n    });\n  }\n}\n"
  },
  {
    "path": "components/notification/demo/update.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 更新消息内容\n  en-US: Update Notification Content\n---\n\n## zh-CN\n\n可以通过唯一的 `nzKey` 来更新内容。\n\n## en-US\n\nUpdate content with unique `nzKey`.\n"
  },
  {
    "path": "components/notification/demo/update.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzNotificationService } from 'ng-zorro-antd/notification';\n\n@Component({\n  selector: 'nz-demo-notification-update',\n  imports: [NzButtonModule],\n  template: `<button nz-button nzType=\"primary\" (click)=\"createNotification()\"> Open the notification box </button>`\n})\nexport class NzDemoNotificationUpdateComponent {\n  constructor(private notification: NzNotificationService) {}\n\n  createNotification(): void {\n    this.notification.blank('Notification Title', 'Description.', {\n      nzKey: 'key'\n    });\n\n    setTimeout(() => {\n      this.notification.blank('New Title', 'New description', {\n        nzKey: 'key'\n      });\n    }, 1000);\n  }\n}\n"
  },
  {
    "path": "components/notification/demo/with-btn.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 自定义按钮\n  en-US: Custom close button\n---\n\n## zh-CN\n\n自定义关闭按钮的样式和文字。\n\n## en-US\n\nTo customize the style or font of the close button.\n"
  },
  {
    "path": "components/notification/demo/with-btn.ts",
    "content": "import { Component, TemplateRef, ViewChild } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzNotificationComponent, NzNotificationService } from 'ng-zorro-antd/notification';\n\n@Component({\n  selector: 'nz-demo-notification-with-btn',\n  imports: [NzButtonModule],\n  template: `\n    <ng-template #notificationBtnTpl let-notification>\n      <button nz-button nzType=\"primary\" nzSize=\"small\" (click)=\"notification.close()\">Confirm</button>\n    </ng-template>\n\n    <button nz-button nzType=\"primary\" (click)=\"createNotification()\">Open the notification box</button>\n  `\n})\nexport class NzDemoNotificationWithBtnComponent {\n  @ViewChild('notificationBtnTpl', { static: true }) btnTemplate!: TemplateRef<{ $implicit: NzNotificationComponent }>;\n  constructor(private notification: NzNotificationService) {}\n\n  createNotification(): void {\n    this.notification.blank(\n      'Notification Title',\n      'A function will be be called after the notification is closed (automatically after the \"duration\" time of manually).',\n      {\n        nzButton: this.btnTemplate\n      }\n    );\n  }\n}\n"
  },
  {
    "path": "components/notification/demo/with-icon.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 带有图标的通知提醒框\n  en-US: Notification with icon\n---\n\n## zh-CN\n\n通知提醒框左侧有图标。\n\n## en-US\n\nA notification box with a icon at the left side.\n"
  },
  {
    "path": "components/notification/demo/with-icon.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzNotificationService } from 'ng-zorro-antd/notification';\n\n@Component({\n  selector: 'nz-demo-notification-with-icon',\n  imports: [NzButtonModule],\n  template: `\n    <button nz-button (click)=\"createNotification('success')\">Success</button>\n    <button nz-button (click)=\"createNotification('info')\">Info</button>\n    <button nz-button (click)=\"createNotification('warning')\">Warning</button>\n    <button nz-button (click)=\"createNotification('error')\">Error</button>\n  `,\n  styles: `\n    button {\n      margin-right: 1em;\n    }\n  `\n})\nexport class NzDemoNotificationWithIconComponent {\n  constructor(private notification: NzNotificationService) {}\n\n  createNotification(type: string): void {\n    this.notification.create(\n      type,\n      'Notification Title',\n      'This is the content of the notification. This is the content of the notification. This is the content of the notification.'\n    );\n  }\n}\n"
  },
  {
    "path": "components/notification/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Feedback\ntitle: Notification\ncover: 'https://gw.alipayobjects.com/zos/alicdn/Jxm5nw61w/Notification.svg'\ndescription: Prompt notification message globally.\n---\n\n## When To Use\n\nTo display a notification message at any of the four corners of the viewport. Typically it can be\nused in the following cases:\n\n- A notification with complex content.\n- A notification providing a feedback based on the user interaction. Or it may show some details\n  about upcoming steps the user may have to follow.\n- A notification that is pushed by the application.\n\n## API\n\n### NzNotificationService\n\nThe component provides a number of service methods using the following methods and parameters:\n\n- `NzNotificationService.blank(title, content, [options])` // Notification without icon\n- `NzNotificationService.success(title, content, [options])`\n- `NzNotificationService.error(title, content, [options])`\n- `NzNotificationService.info(title, content, [options])`\n- `NzNotificationService.warning(title, content, [options])`\n\n| Argument  | Description                                                                          | Type                          | Default |\n| --------- | ------------------------------------------------------------------------------------ | ----------------------------- | ------- |\n| `title`   | Title                                                                                | `string \\| TemplateRef<void>` | -       |\n| `content` | Notification content                                                                 | `NzNotificationContentType`   | -       |\n| `options` | Support setting the parameters for the current notification box, see the table below | `object`                      | -       |\n\nThe parameters that are set by the `options` support are as follows:\n\n| Argument         | Description                                                            | Type                                                            |\n| ---------------- | ---------------------------------------------------------------------- | --------------------------------------------------------------- |\n| `nzKey`          | The unique identifier of the Notification                              | `string`                                                        |\n| `nzDuration`     | Duration (milliseconds), does not disappear when set to 0              | `number`                                                        |\n| `nzPauseOnHover` | Do not remove automatically when mouse is over while setting to `true` | `boolean`                                                       |\n| `nzAnimate`      | Whether to turn on animation                                           | `boolean`                                                       |\n| `nzStyle`        | Custom inline style                                                    | `object`                                                        |\n| `nzClass`        | Custom CSS class                                                       | `object`                                                        |\n| `nzData`         | Anything that would be used as template context                        | `any`                                                           |\n| `nzCloseIcon`    | Custom close icon                                                      | `TemplateRef<void> \\| string`                                   |\n| `nzButton`       | Custom button                                                          | `TemplateRef<{ $implicit: NzNotificationComponent }> \\| string` |\n\nMethods for destruction are also provided:\n\n- `NzNotificationService.remove(id)` // Remove the notification with the specified id. When the id is empty, remove all notifications (the notification id is returned by the above method)\n\n### Global Configuration\n\nYou can use `NzConfigService` to configure this component globally. Please check the [Global Configuration](/docs/global-config/en) chapter for more information.\n\n| Parameter        | Description                                                                             | Type                                                                            | Default      |\n| ---------------- | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ------------ |\n| `nzDuration`     | Duration (milliseconds), does not disappear when set to 0                               | `number`                                                                        | `4500`       |\n| `nzMaxStack`     | The maximum number of notifications that can be displayed at the same time              | `number`                                                                        | `8`          |\n| `nzPauseOnHover` | Do not remove automatically when mouse is over while setting to `true`                  | `boolean`                                                                       | `true`       |\n| `nzAnimate`      | Whether to turn on animation                                                            | `boolean`                                                                       | `true`       |\n| `nzTop`          | The top of the notification when it pops up from the top.                               | `string`                                                                        | `'24px'`     |\n| `nzBottom`       | The bottom of the notification when it pops up from the bottom.                         | `string`                                                                        | `'24px'`     |\n| `nzPlacement`    | Popup position, optional `topLeft` `topRight` `bottomLeft` `bottomRight` `top` `bottom` | `'topLeft' \\| 'topRight' \\| 'bottomLeft' \\| 'bottomRight' \\| 'top' \\| 'bottom'` | `'topRight'` |\n| `nzDirection`    | Direction of the text in the notification                                               | `'ltr' \\| 'rtl'`                                                                | -            |\n\n### NzNotificationRef\n\nIt's the object that returned when you call `NzNotificationService.success` and others.\n\n```ts\nexport interface NzNotificationRef {\n  messageId: string;\n  onClose: Subject<boolean>; // It would emit an event when the notification is closed, and emit a `true` if it's closed by user\n  onClick: Subject<MouseEvent>;\n}\n```\n"
  },
  {
    "path": "components/notification/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ntype: 反馈\ntitle: Notification\nsubtitle: 通知提醒框\ncover: 'https://gw.alipayobjects.com/zos/alicdn/Jxm5nw61w/Notification.svg'\ndescription: 全局展示通知提醒信息。\n---\n\n## 何时使用\n\n在系统四个角显示通知提醒信息。经常用于以下情况：\n\n- 较为复杂的通知内容。\n- 带有交互的通知，给出用户下一步的行动点。\n- 系统主动推送。\n\n## API\n\n### NzNotificationService\n\n组件提供了一些服务方法，使用方式和参数如下：\n\n- `NzNotificationService.blank(title, content, [options])` // 不带图标的提示\n- `NzNotificationService.success(title, content, [options])`\n- `NzNotificationService.error(title, content, [options])`\n- `NzNotificationService.info(title, content, [options])`\n- `NzNotificationService.warning(title, content, [options])`\n\n| 参数      | 说明                                     | 类型                          | 默认值 |\n| --------- | ---------------------------------------- | ----------------------------- | ------ |\n| `title`   | 标题                                     | `string \\| TemplateRef<void>` | -      |\n| `content` | 提示内容                                 | `NzNotificationContentType`   | -      |\n| `options` | 支持设置针对当前提示框的参数，见下方表格 | `object`                      | -      |\n\n`options` 支持设置的参数如下：\n\n| 参数             | 说明                                | 类型                                                            |\n| ---------------- | ----------------------------------- | --------------------------------------------------------------- |\n| `nzKey`          | 通知提示的唯一标识符                | `string`                                                        |\n| `nzDuration`     | 持续时间(毫秒)，当设置为 0 时不消失 | `number`                                                        |\n| `nzPauseOnHover` | 鼠标移上时禁止自动移除              | `boolean`                                                       |\n| `nzAnimate`      | 开关动画效果                        | `boolean`                                                       |\n| `nzStyle`        | 自定义内联样式                      | `object`                                                        |\n| `nzClass`        | 自定义 CSS class                    | `object`                                                        |\n| `nzData`         | 任何想要在模板中作为上下文的数据    | `any`                                                           |\n| `nzCloseIcon`    | 自定义关闭图标                      | `TemplateRef<void> \\| string`                                   |\n| `nzButton`       | 自定义按钮                          | `TemplateRef<{ $implicit: NzNotificationComponent }> \\| string` |\n\n还提供了全局销毁方法：\n\n- `NzNotificationService.remove(id)` // 移除特定id的消息，当id为空时，移除所有消息（该消息id通过上述方法返回值中得到）\n\n### 全局配置\n\n可以通过 `NzConfigService` 进行全局配置，详情请见文档中 [全局配置项](/docs/global-config/zh) 章节。\n\n| 参数             | 说明                                                                          | 类型                                                                            | 默认值       |\n| ---------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ------------ |\n| `nzDuration`     | 持续时间(毫秒)，当设置为0时不消失                                             | `number`                                                                        | `4500`       |\n| `nzMaxStack`     | 同一时间可展示的最大提示数量                                                  | `number`                                                                        | `8`          |\n| `nzPauseOnHover` | 鼠标移上时禁止自动移除                                                        | `boolean`                                                                       | `true`       |\n| `nzAnimate`      | 开关动画效果                                                                  | `boolean`                                                                       | `true`       |\n| `nzTop`          | 消息从顶部弹出时，距离顶部的位置。                                            | `string`                                                                        | `'24px'`     |\n| `nzBottom`       | 消息从底部弹出时，距离底部的位置。                                            | `string`                                                                        | `'24px'`     |\n| `nzPlacement`    | 弹出位置，可选 `topLeft` `topRight` `bottomLeft` `bottomRight` `top` `bottom` | `'topLeft' \\| 'topRight' \\| 'bottomLeft' \\| 'bottomRight' \\| 'top' \\| 'bottom'` | `'topRight'` |\n| `nzDirection`    | 通知的文字方向                                                                | `'ltr' \\| 'rtl'`                                                                | -            |\n\n### NzNotificationRef\n\n当你调用 `NzNotificationService.success` 或其他方法时会返回该对象。\n\n```ts\nexport interface NzNotificationDataRef {\n  messageId: string;\n  onClose: Subject<boolean>; // 当 notification 关闭时它会派发一个事件，如果为用户手动关闭会派发 `true`\n  onClick: Subject<MouseEvent>;\n}\n```\n"
  },
  {
    "path": "components/notification/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/notification/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/notification/notification-container.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction } from '@angular/cdk/bidi';\nimport { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';\nimport { Subject } from 'rxjs';\n\nimport { NotificationConfig, onConfigChangeEventForComponent } from 'ng-zorro-antd/core/config';\nimport { toCssPixel } from 'ng-zorro-antd/core/util';\nimport { NzMNContainerComponent } from 'ng-zorro-antd/message';\n\nimport { NzNotificationComponent } from './notification.component';\nimport { NzNotificationData, NzNotificationDataOptions, NzNotificationPlacement } from './typings';\n\nconst NZ_CONFIG_MODULE_NAME = 'notification';\n\nconst NZ_NOTIFICATION_DEFAULT_CONFIG: Required<NotificationConfig> = {\n  nzTop: '24px',\n  nzBottom: '24px',\n  nzPlacement: 'topRight',\n  nzDuration: 4500,\n  nzMaxStack: 8,\n  nzPauseOnHover: true,\n  nzAnimate: true,\n  nzDirection: 'ltr'\n};\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-notification-container',\n  exportAs: 'nzNotificationContainer',\n  template: `\n    <div\n      class=\"ant-notification ant-notification-topLeft\"\n      [class.ant-notification-rtl]=\"dir === 'rtl'\"\n      [style.top]=\"top\"\n      [style.left]=\"'0px'\"\n    >\n      @for (instance of topLeftInstances; track instance) {\n        <nz-notification [instance]=\"instance\" placement=\"topLeft\" (destroyed)=\"remove($event.id, $event.userAction)\" />\n      }\n    </div>\n    <div\n      class=\"ant-notification ant-notification-topRight\"\n      [class.ant-notification-rtl]=\"dir === 'rtl'\"\n      [style.top]=\"top\"\n      [style.right]=\"'0px'\"\n    >\n      @for (instance of topRightInstances; track instance) {\n        <nz-notification\n          [instance]=\"instance\"\n          placement=\"topRight\"\n          (destroyed)=\"remove($event.id, $event.userAction)\"\n        />\n      }\n    </div>\n    <div\n      class=\"ant-notification ant-notification-bottomLeft\"\n      [class.ant-notification-rtl]=\"dir === 'rtl'\"\n      [style.bottom]=\"bottom\"\n      [style.left]=\"'0px'\"\n    >\n      @for (instance of bottomLeftInstances; track instance) {\n        <nz-notification\n          [instance]=\"instance\"\n          placement=\"bottomLeft\"\n          (destroyed)=\"remove($event.id, $event.userAction)\"\n        />\n      }\n    </div>\n    <div\n      class=\"ant-notification ant-notification-bottomRight\"\n      [class.ant-notification-rtl]=\"dir === 'rtl'\"\n      [style.bottom]=\"bottom\"\n      [style.right]=\"'0px'\"\n    >\n      @for (instance of bottomRightInstances; track instance) {\n        <nz-notification\n          [instance]=\"instance\"\n          placement=\"bottomRight\"\n          (destroyed)=\"remove($event.id, $event.userAction)\"\n        />\n      }\n    </div>\n    <div\n      class=\"ant-notification ant-notification-top\"\n      [class.ant-notification-rtl]=\"dir === 'rtl'\"\n      [style.top]=\"top\"\n      [style.left]=\"'50%'\"\n      [style.transform]=\"'translateX(-50%)'\"\n    >\n      @for (instance of topInstances; track instance) {\n        <nz-notification [instance]=\"instance\" placement=\"top\" (destroyed)=\"remove($event.id, $event.userAction)\" />\n      }\n    </div>\n    <div\n      class=\"ant-notification ant-notification-bottom\"\n      [class.ant-notification-rtl]=\"dir === 'rtl'\"\n      [style.bottom]=\"bottom\"\n      [style.left]=\"'50%'\"\n      [style.transform]=\"'translateX(-50%)'\"\n    >\n      @for (instance of bottomInstances; track instance) {\n        <nz-notification [instance]=\"instance\" placement=\"bottom\" (destroyed)=\"remove($event.id, $event.userAction)\" />\n      }\n    </div>\n  `,\n  imports: [NzNotificationComponent]\n})\nexport class NzNotificationContainerComponent extends NzMNContainerComponent<NotificationConfig, NzNotificationData> {\n  dir: Direction = this.nzConfigService.getConfigForComponent(NZ_CONFIG_MODULE_NAME)?.nzDirection || 'ltr';\n  bottom?: string | null;\n  top?: string | null;\n  topLeftInstances: Array<Required<NzNotificationData>> = [];\n  topRightInstances: Array<Required<NzNotificationData>> = [];\n  bottomLeftInstances: Array<Required<NzNotificationData>> = [];\n  bottomRightInstances: Array<Required<NzNotificationData>> = [];\n  topInstances: Array<Required<NzNotificationData>> = [];\n  bottomInstances: Array<Required<NzNotificationData>> = [];\n\n  constructor() {\n    super();\n    this.updateConfig();\n  }\n\n  override create(notification: NzNotificationData): Required<NzNotificationData> {\n    const instance = this.onCreate(notification);\n    const key = instance.options.nzKey;\n    const notificationWithSameKey = this.instances.find(\n      msg => msg.options.nzKey === (notification.options as Required<NzNotificationDataOptions>).nzKey\n    );\n    if (key && notificationWithSameKey) {\n      this.replaceNotification(notificationWithSameKey, instance);\n    } else {\n      if (this.instances.length >= this.config!.nzMaxStack) {\n        this.instances = this.instances.slice(1);\n      }\n      this.instances = [...this.instances, instance];\n    }\n\n    this.readyInstances();\n\n    return instance;\n  }\n\n  protected override onCreate(instance: NzNotificationData): Required<NzNotificationData> {\n    instance.options = this.mergeOptions(instance.options);\n    instance.onClose = new Subject<boolean>();\n    instance.onClick = new Subject<MouseEvent>();\n    return instance as Required<NzNotificationData>;\n  }\n\n  protected subscribeConfigChange(): void {\n    onConfigChangeEventForComponent(NZ_CONFIG_MODULE_NAME, () => {\n      this.updateConfig();\n      this.dir = this.nzConfigService.getConfigForComponent(NZ_CONFIG_MODULE_NAME)?.nzDirection || this.dir;\n    });\n  }\n\n  protected updateConfig(): void {\n    this.config = {\n      ...NZ_NOTIFICATION_DEFAULT_CONFIG,\n      ...this.config,\n      ...this.nzConfigService.getConfigForComponent(NZ_CONFIG_MODULE_NAME)\n    };\n\n    this.top = toCssPixel(this.config.nzTop!);\n    this.bottom = toCssPixel(this.config.nzBottom!);\n\n    this.cdr.markForCheck();\n  }\n\n  private replaceNotification(old: NzNotificationData, _new: NzNotificationData): void {\n    old.title = _new.title;\n    old.content = _new.content;\n    old.template = _new.template;\n    old.type = _new.type;\n    old.options = _new.options;\n  }\n\n  protected override readyInstances(): void {\n    const instancesMap: Record<NzNotificationPlacement, Array<Required<NzNotificationData>>> = {\n      topLeft: [],\n      topRight: [],\n      bottomLeft: [],\n      bottomRight: [],\n      top: [],\n      bottom: []\n    };\n    this.instances.forEach(m => {\n      const placement = m.options.nzPlacement;\n      switch (placement) {\n        case 'topLeft':\n          instancesMap.topLeft.unshift(m);\n          break;\n        case 'topRight':\n          instancesMap.topRight.unshift(m);\n          break;\n        case 'bottomLeft':\n          instancesMap.bottomLeft.unshift(m);\n          break;\n        case 'bottomRight':\n          instancesMap.bottomRight.unshift(m);\n          break;\n        case 'top':\n          instancesMap.top.unshift(m);\n          break;\n        case 'bottom':\n          instancesMap.bottom.unshift(m);\n          break;\n        default:\n          instancesMap.topRight.unshift(m);\n      }\n    });\n    this.topLeftInstances = instancesMap.topLeft;\n    this.topRightInstances = instancesMap.topRight;\n    this.bottomLeftInstances = instancesMap.bottomLeft;\n    this.bottomRightInstances = instancesMap.bottomRight;\n    this.topInstances = instancesMap.top;\n    this.bottomInstances = instancesMap.bottom;\n\n    this.cdr.detectChanges();\n  }\n\n  protected override mergeOptions(options?: NzNotificationDataOptions): NzNotificationDataOptions {\n    const { nzDuration, nzAnimate, nzPauseOnHover, nzPlacement } = this.config!;\n    return { nzDuration, nzAnimate, nzPauseOnHover, nzPlacement, ...options };\n  }\n}\n"
  },
  {
    "path": "components/notification/notification.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  ElementRef,\n  EventEmitter,\n  Input,\n  Output,\n  viewChild,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzMNComponent } from 'ng-zorro-antd/message';\n\nimport { NzNotificationData } from './typings';\n\n@Component({\n  selector: 'nz-notification',\n  exportAs: 'nzNotification',\n  imports: [NzIconModule, NzOutletModule, NgTemplateOutlet],\n  template: `\n    <div\n      #animationElement\n      class=\"ant-notification-notice ant-notification-notice-closable\"\n      [style]=\"instance.options?.nzStyle || null\"\n      [class]=\"instance.options?.nzClass || ''\"\n      (click)=\"onClick($event)\"\n      (mouseenter)=\"onEnter()\"\n      (mouseleave)=\"onLeave()\"\n    >\n      @if (instance.template) {\n        <ng-template\n          [ngTemplateOutlet]=\"instance.template!\"\n          [ngTemplateOutletContext]=\"{ $implicit: this, data: instance.options?.nzData }\"\n        />\n      } @else {\n        <div class=\"ant-notification-notice-content\">\n          <div class=\"ant-notification-notice-content\">\n            <div [class.ant-notification-notice-with-icon]=\"instance.type !== 'blank'\">\n              @switch (instance.type) {\n                @case ('success') {\n                  <nz-icon\n                    nzType=\"check-circle\"\n                    class=\"ant-notification-notice-icon ant-notification-notice-icon-success\"\n                  />\n                }\n                @case ('info') {\n                  <nz-icon\n                    nzType=\"info-circle\"\n                    class=\"ant-notification-notice-icon ant-notification-notice-icon-info\"\n                  />\n                }\n                @case ('warning') {\n                  <nz-icon\n                    nzType=\"exclamation-circle\"\n                    class=\"ant-notification-notice-icon ant-notification-notice-icon-warning\"\n                  />\n                }\n                @case ('error') {\n                  <nz-icon\n                    nzType=\"close-circle\"\n                    class=\"ant-notification-notice-icon ant-notification-notice-icon-error\"\n                  />\n                }\n              }\n              <div class=\"ant-notification-notice-message\">\n                <ng-container *nzStringTemplateOutlet=\"instance.title\">\n                  <div [innerHTML]=\"instance.title\"></div>\n                </ng-container>\n              </div>\n              <div class=\"ant-notification-notice-description\">\n                <ng-container\n                  *nzStringTemplateOutlet=\"\n                    instance.content;\n                    context: { $implicit: this, data: instance.options?.nzData }\n                  \"\n                >\n                  <div [innerHTML]=\"instance.content\"></div>\n                </ng-container>\n              </div>\n              @if (instance.options?.nzButton; as btn) {\n                <span class=\"ant-notification-notice-btn\">\n                  <ng-template [ngTemplateOutlet]=\"btn\" [ngTemplateOutletContext]=\"{ $implicit: this }\" />\n                </span>\n              }\n            </div>\n          </div>\n        </div>\n      }\n      <a tabindex=\"0\" class=\"ant-notification-notice-close\" (click)=\"close()\">\n        <span class=\"ant-notification-notice-close-x\">\n          @if (instance.options?.nzCloseIcon) {\n            <ng-container *nzStringTemplateOutlet=\"instance.options?.nzCloseIcon; let closeIcon\">\n              <nz-icon [nzType]=\"closeIcon\" />\n            </ng-container>\n          } @else {\n            <nz-icon nzType=\"close\" class=\"ant-notification-close-icon\" />\n          }\n        </span>\n      </a>\n    </div>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None\n})\nexport class NzNotificationComponent extends NzMNComponent {\n  @Input() instance!: Required<NzNotificationData>;\n  @Input() index!: number;\n  @Input() placement?: string;\n  @Output() readonly destroyed = new EventEmitter<{ id: string; userAction: boolean }>();\n\n  readonly animationElement = viewChild.required('animationElement', { read: ElementRef });\n  protected readonly _animationKeyframeMap = {\n    enter: [\n      'antNotificationFadeIn',\n      'antNotificationTopFadeIn',\n      'antNotificationBottomFadeIn',\n      'antNotificationLeftFadeIn'\n    ],\n    leave: 'antNotificationFadeOut'\n  };\n  protected readonly _animationClassMap = {\n    enter: 'ant-notification-fade-enter',\n    leave: 'ant-notification-fade-leave'\n  };\n\n  constructor() {\n    super();\n    this.destroyRef.onDestroy(() => {\n      this.instance.onClick.complete();\n    });\n  }\n\n  onClick(event: MouseEvent): void {\n    this.instance.onClick.next(event);\n  }\n\n  close(): void {\n    this.destroy(true);\n  }\n}\n"
  },
  {
    "path": "components/notification/notification.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Injectable, TemplateRef } from '@angular/core';\n\nimport type { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { NzMNService } from 'ng-zorro-antd/message';\n\nimport { NzNotificationContainerComponent } from './notification-container.component';\nimport type { NzNotificationComponent } from './notification.component';\nimport { NzNotificationContentType, NzNotificationData, NzNotificationDataOptions, NzNotificationRef } from './typings';\n\nlet notificationId = 0;\n\n@Injectable({\n  providedIn: 'root'\n})\nexport class NzNotificationService extends NzMNService<NzNotificationContainerComponent> {\n  protected componentPrefix = 'notification-';\n\n  success(\n    title: string | TemplateRef<void>,\n    content: NzNotificationContentType,\n    options?: NzNotificationDataOptions\n  ): NzNotificationRef {\n    return this.create('success', title, content, options);\n  }\n\n  error(\n    title: string | TemplateRef<void>,\n    content: NzNotificationContentType,\n    options?: NzNotificationDataOptions\n  ): NzNotificationRef {\n    return this.create('error', title, content, options);\n  }\n\n  info(\n    title: string | TemplateRef<void>,\n    content: NzNotificationContentType,\n    options?: NzNotificationDataOptions\n  ): NzNotificationRef {\n    return this.create('info', title, content, options);\n  }\n\n  warning(\n    title: string | TemplateRef<void>,\n    content: NzNotificationContentType,\n    options?: NzNotificationDataOptions\n  ): NzNotificationRef {\n    return this.create('warning', title, content, options);\n  }\n\n  blank(\n    title: string | TemplateRef<void>,\n    content: NzNotificationContentType,\n    options?: NzNotificationDataOptions\n  ): NzNotificationRef {\n    return this.create('blank', title, content, options);\n  }\n\n  create(\n    type: 'success' | 'info' | 'warning' | 'error' | 'blank' | string,\n    title: string | TemplateRef<void>,\n    content: NzNotificationContentType,\n    options?: NzNotificationDataOptions\n  ): NzNotificationRef {\n    return this.createInstance({ type, title, content }, options);\n  }\n\n  template(\n    template: TemplateRef<{\n      $implicit: NzNotificationComponent;\n      data: NzSafeAny;\n    }>,\n    options?: NzNotificationDataOptions\n  ): NzNotificationRef {\n    return this.createInstance({ template }, options);\n  }\n\n  protected generateMessageId(): string {\n    return `${this.componentPrefix}-${notificationId++}`;\n  }\n\n  private createInstance(message: NzNotificationData, options?: NzNotificationDataOptions): NzNotificationRef {\n    this.container = this.withContainer(NzNotificationContainerComponent);\n\n    return this.container.create({\n      ...message,\n      ...{\n        createdAt: new Date(),\n        messageId: options?.nzKey || this.generateMessageId(),\n        options\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "components/notification/notification.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport { Component, TemplateRef, ViewChild } from '@angular/core';\nimport { ComponentFixture, inject, TestBed } from '@angular/core/testing';\n\nimport { NzConfigService, provideNzConfig } from 'ng-zorro-antd/core/config';\nimport { dispatchEvent, dispatchMouseEvent, sleep } from 'ng-zorro-antd/core/testing';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzNotificationComponent } from './notification.component';\nimport { NzNotificationService } from './notification.service';\n\n@Component({\n  selector: 'nz-test-notification',\n  template: `<ng-template let-data=\"data\">test template content {{ data }}</ng-template>`\n})\nclass NzTestNotificationComponent {\n  @ViewChild(TemplateRef, { static: true }) demoTemplateRef!: TemplateRef<{\n    $implicit: NzNotificationComponent;\n    data: string;\n  }>;\n}\n\ndescribe('notification', () => {\n  let notificationService: NzNotificationService;\n  let overlayContainer: OverlayContainer;\n  let overlayContainerElement: HTMLElement;\n  let fixture: ComponentFixture<NzTestNotificationComponent>;\n  let configService: NzConfigService;\n\n  function getMessageElement(): HTMLElement {\n    return overlayContainerElement.querySelector('.ant-notification-notice') as HTMLElement;\n  }\n\n  // mock animationend event\n  async function animationEnd(): Promise<void> {\n    dispatchEvent(getMessageElement(), new AnimationEvent('animationend', { animationName: 'antNotificationFadeOut' }));\n    await fixture.whenStable();\n  }\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [provideNzConfig({ notification: { nzMaxStack: 2 } }), provideNzIconsTesting(), NzNotificationService]\n    });\n\n    fixture = TestBed.createComponent(NzTestNotificationComponent);\n  });\n\n  beforeEach(inject(\n    [NzNotificationService, OverlayContainer, NzConfigService],\n    (n: NzNotificationService, oc: OverlayContainer, c: NzConfigService) => {\n      notificationService = n;\n      overlayContainer = oc;\n      configService = c;\n    }\n  ));\n\n  afterEach(() => {\n    notificationService.remove();\n  });\n\n  it('should open a message box with success', () => {\n    notificationService.success('test-title', 'SUCCESS');\n\n    overlayContainerElement = overlayContainer.getContainerElement();\n    expect(overlayContainerElement.textContent).toContain('SUCCESS');\n    expect(overlayContainerElement.querySelector('.ant-notification-notice-icon-success')).not.toBeNull();\n  });\n\n  it('should open a message box success with custom template and data', () => {\n    const template = fixture.componentInstance.demoTemplateRef;\n    notificationService.success('test-title', template, { nzData: 'SUCCESS' });\n\n    overlayContainerElement = overlayContainer.getContainerElement();\n    expect(overlayContainerElement.textContent).toContain('SUCCESS');\n    expect(overlayContainerElement.querySelector('.ant-notification-notice-icon-success')).not.toBeNull();\n  });\n\n  it('should open a message box with error', () => {\n    notificationService.error('test-title', 'ERROR');\n\n    overlayContainerElement = overlayContainer.getContainerElement();\n    expect(overlayContainerElement.textContent).toContain('ERROR');\n    expect(overlayContainerElement.querySelector('.ant-notification-notice-icon-error')).not.toBeNull();\n  });\n\n  it('should open a message box error with custom template and data', () => {\n    const template = fixture.componentInstance.demoTemplateRef;\n    notificationService.error('test-title', template, { nzData: 'ERROR' });\n\n    overlayContainerElement = overlayContainer.getContainerElement();\n    expect(overlayContainerElement.textContent).toContain('ERROR');\n    expect(overlayContainerElement.querySelector('.ant-notification-notice-icon-error')).not.toBeNull();\n  });\n\n  it('should open a message box with warning', () => {\n    notificationService.warning('test-title', 'WARNING');\n\n    overlayContainerElement = overlayContainer.getContainerElement();\n    expect(overlayContainerElement.textContent).toContain('WARNING');\n    expect(overlayContainerElement.querySelector('.ant-notification-notice-icon-warning')).not.toBeNull();\n  });\n\n  it('should open a message box warning with custom template and data', () => {\n    const template = fixture.componentInstance.demoTemplateRef;\n    notificationService.warning('test-title', template, { nzData: 'WARNING' });\n\n    overlayContainerElement = overlayContainer.getContainerElement();\n    expect(overlayContainerElement.textContent).toContain('WARNING');\n    expect(overlayContainerElement.querySelector('.ant-notification-notice-icon-warning')).not.toBeNull();\n  });\n\n  it('should open a message box with info', () => {\n    notificationService.info('test-title', 'INFO');\n\n    overlayContainerElement = overlayContainer.getContainerElement();\n    expect(overlayContainerElement.textContent).toContain('INFO');\n    expect(overlayContainerElement.querySelector('.ant-notification-notice-icon-info')).not.toBeNull();\n  });\n\n  it('should open a message box info with custom template and data', () => {\n    const template = fixture.componentInstance.demoTemplateRef;\n    notificationService.info('test-title', template, { nzData: 'INFO' });\n\n    overlayContainerElement = overlayContainer.getContainerElement();\n    expect(overlayContainerElement.textContent).toContain('INFO');\n    expect(overlayContainerElement.querySelector('.ant-notification-notice-icon-info')).not.toBeNull();\n  });\n\n  it('should open a message box with blank', () => {\n    notificationService.blank('test-title', 'BLANK');\n\n    overlayContainerElement = overlayContainer.getContainerElement();\n    expect(overlayContainerElement.textContent).toContain('BLANK');\n    expect(overlayContainerElement.querySelector('.ant-notification-notice-icon')).toBeNull();\n  });\n\n  it('should open a message box blank with custom template and data', () => {\n    const template = fixture.componentInstance.demoTemplateRef;\n    notificationService.blank('test-title', template, { nzData: 'BLANK' });\n\n    overlayContainerElement = overlayContainer.getContainerElement();\n    expect(overlayContainerElement.textContent).toContain('BLANK');\n    expect(overlayContainerElement.querySelector('.ant-notification-notice-icon')).toBeNull();\n  });\n\n  it('should auto closed by 1s', async () => {\n    notificationService.create('', '', 'EXISTS', { nzDuration: 1000 });\n    await fixture.whenStable();\n\n    overlayContainerElement = overlayContainer.getContainerElement();\n    expect(overlayContainerElement.textContent).toContain('EXISTS');\n\n    await sleep(1000);\n    await animationEnd();\n    expect(overlayContainerElement.textContent).not.toContain('EXISTS');\n  });\n\n  it('should not destroy when hovered', async () => {\n    notificationService.create('', '', 'EXISTS', { nzDuration: 2500 });\n    await fixture.whenStable();\n\n    overlayContainerElement = overlayContainer.getContainerElement();\n    const messageElement = getMessageElement();\n    dispatchMouseEvent(messageElement, 'mouseenter');\n    await sleep(2500);\n    await fixture.whenStable();\n    expect(overlayContainerElement.textContent).toContain('EXISTS');\n\n    dispatchMouseEvent(messageElement, 'mouseleave');\n    await sleep(2500);\n    await animationEnd();\n    expect(overlayContainerElement.textContent).not.toContain('EXISTS');\n  }, 6000);\n\n  it('should not destroyed automatically but manually', async () => {\n    const filledMessage = notificationService.success('title', 'SUCCESS', { nzDuration: 0 });\n    fixture.detectChanges();\n\n    await sleep(5000);\n    await fixture.whenStable();\n    overlayContainerElement = overlayContainer.getContainerElement();\n    expect(overlayContainerElement.textContent).toContain('SUCCESS');\n\n    notificationService.remove(filledMessage.messageId);\n    await fixture.whenStable();\n    expect(overlayContainerElement.textContent).not.toContain('SUCCESS');\n  }, 6000);\n\n  it('should keep the balance of messages length and then remove all', async () => {\n    for (const id of [1, 2, 3]) {\n      const content = `SUCCESS-${id}`;\n      notificationService.success('', content);\n      await fixture.whenStable();\n\n      overlayContainerElement = overlayContainer.getContainerElement();\n      expect(overlayContainerElement.textContent).toContain(content);\n      if (id === 3) {\n        expect(overlayContainerElement.textContent).not.toContain('SUCCESS-1');\n        expect((notificationService as any).container.instances.length).toBe(2); // eslint-disable-line @typescript-eslint/no-explicit-any\n      }\n    }\n\n    notificationService.remove();\n    await fixture.whenStable();\n    expect(overlayContainerElement.textContent).not.toContain('SUCCESS-3');\n    expect((notificationService as any).container).toBeUndefined(); // eslint-disable-line @typescript-eslint/no-explicit-any\n  });\n\n  it('should destroy without animation', async () => {\n    notificationService.error('', 'EXISTS', { nzDuration: 1000, nzAnimate: false });\n    await sleep(1000);\n    await fixture.whenStable();\n    overlayContainerElement = overlayContainer.getContainerElement();\n    expect(overlayContainerElement.textContent).not.toContain('EXISTS');\n  });\n\n  it('should show with placement of topLeft', () => {\n    configService.set('notification', { nzPlacement: 'topLeft' });\n    notificationService.create('', '', 'EXISTS');\n    fixture.detectChanges();\n    overlayContainerElement = overlayContainer.getContainerElement();\n    expect(overlayContainerElement.textContent).toContain('EXISTS');\n    expect(overlayContainerElement.querySelector('.ant-notification-topLeft')).not.toBeNull();\n  });\n\n  it('should show with placement of top', () => {\n    configService.set('notification', { nzPlacement: 'top' });\n    notificationService.create('', '', 'EXISTS');\n    fixture.detectChanges();\n    overlayContainerElement = overlayContainer.getContainerElement();\n    expect(overlayContainerElement.textContent).toContain('EXISTS');\n    expect(overlayContainerElement.querySelector('.ant-notification-top')).not.toBeNull();\n  });\n\n  it('should show with placement of bottom', () => {\n    configService.set('notification', { nzPlacement: 'bottom' });\n    notificationService.create('', '', 'EXISTS');\n    fixture.detectChanges();\n    overlayContainerElement = overlayContainer.getContainerElement();\n    expect(overlayContainerElement.textContent).toContain('EXISTS');\n    expect(overlayContainerElement.querySelector('.ant-notification-bottom')).not.toBeNull();\n  });\n\n  it('should open a message box with template ref', () => {\n    notificationService.template(fixture.componentInstance.demoTemplateRef, { nzData: 'data' });\n    fixture.detectChanges();\n    overlayContainerElement = overlayContainer.getContainerElement();\n    expect(overlayContainerElement.textContent).toContain('test template content data');\n  });\n\n  it('should update an existing notification with use template ref when change nzData', async () => {\n    notificationService.template(fixture.componentInstance.demoTemplateRef, { nzData: 'oldData', nzKey: 'exists' });\n    overlayContainerElement = overlayContainer.getContainerElement();\n    expect(overlayContainerElement.textContent).toContain('oldData');\n    notificationService.template(fixture.componentInstance.demoTemplateRef, { nzData: 'newData', nzKey: 'exists' });\n    await fixture.whenStable();\n    expect(overlayContainerElement.textContent).toContain('newData');\n  });\n\n  it('should update an existing notification when keys are matched', async () => {\n    let messageId: string | null;\n    messageId = notificationService.create('', '', 'EXISTS', { nzKey: 'exists' }).messageId;\n    overlayContainerElement = overlayContainer.getContainerElement();\n    expect(overlayContainerElement.textContent).toContain('EXISTS');\n    expect(messageId).toEqual('exists');\n\n    messageId = notificationService.create('success', 'Title', 'SHOULD NOT CHANGE', { nzKey: 'exists' }).messageId;\n    await fixture.whenStable();\n    expect(messageId).toEqual('exists');\n    expect(overlayContainerElement.textContent).not.toContain('EXISTS');\n    expect(overlayContainerElement.textContent).toContain('Title');\n    expect(overlayContainerElement.textContent).toContain('SHOULD NOT CHANGE');\n    expect(overlayContainerElement.querySelector('.ant-notification-notice-icon-success')).not.toBeNull();\n  });\n\n  it('should receive `true` when it is closed by user', async () => {\n    let onCloseFlag = false;\n\n    const ref = notificationService.create('', '', 'close');\n    ref.onClose.subscribe(user => {\n      if (user) {\n        onCloseFlag = true;\n      }\n    });\n\n    overlayContainerElement = overlayContainer.getContainerElement();\n    const closeEl = overlayContainerElement.querySelector('.ant-notification-notice-close')!;\n    dispatchMouseEvent(closeEl, 'click');\n\n    await animationEnd();\n    expect(onCloseFlag).toBeTruthy();\n  });\n\n  it('should support configurable nzTop ', () => {\n    configService.set('notification', { nzTop: 48 });\n    notificationService.create('', '', 'TEST TOP');\n    overlayContainerElement = overlayContainer.getContainerElement();\n    const notificationContainers = overlayContainerElement.querySelectorAll(\n      '.ant-notification'\n    ) as NodeListOf<HTMLDivElement>;\n    expect(notificationContainers[0].style.top).toBe('48px');\n    expect(notificationContainers[0].style.bottom).toBeFalsy();\n  });\n\n  it('should support configurable nzBottom', () => {\n    configService.set('notification', { nzPlacement: 'bottomLeft', nzBottom: '48px' });\n    notificationService.create('', '', 'TEST BOTTOM');\n    overlayContainerElement = overlayContainer.getContainerElement();\n    const notificationContainers = overlayContainerElement.querySelectorAll(\n      '.ant-notification'\n    ) as NodeListOf<HTMLDivElement>;\n    expect(notificationContainers[2].style.top).toBeFalsy();\n    expect(notificationContainers[2].style.bottom).toBe('48px');\n  });\n\n  it('should support close icon', () => {\n    notificationService.create('', '', 'ICON', { nzCloseIcon: 'home' });\n    overlayContainerElement = overlayContainer.getContainerElement();\n    expect(overlayContainerElement.querySelector('.anticon-home')).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "components/notification/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './notification.component';\nexport * from './typings';\nexport * from './notification.service';\nexport * from './notification-container.component';\n"
  },
  {
    "path": "components/notification/style/customize.less",
    "content": "@import './index.less';\n\n.popover-customize-bg(@notification-prefix-cls, @popover-background);\n"
  },
  {
    "path": "components/notification/style/entry.less",
    "content": "@import './index.less';\n"
  },
  {
    "path": "components/notification/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n.popover-customize-bg(@notification-prefix-cls, @popover-background);\n\n@notification-prefix-cls: ~'@{ant-prefix}-notification';\n@notification-width: 384px;\n@notification-padding: @notification-padding-vertical @notification-padding-horizontal;\n@notification-margin-bottom: 16px;\n@notification-margin-edge: 24px;\n\n.@{notification-prefix-cls} {\n  .reset-component();\n\n  position: fixed;\n  z-index: @zindex-notification;\n  margin-right: @notification-margin-edge;\n\n  &-close-icon {\n    font-size: @font-size-base;\n    cursor: pointer;\n  }\n\n  &-hook-holder {\n    position: relative;\n  }\n\n  &-notice {\n    position: relative;\n    width: @notification-width;\n    max-width: ~'calc(100vw - @{notification-margin-edge} * 2)';\n    margin-bottom: @notification-margin-bottom;\n    margin-left: auto;\n    padding: @notification-padding;\n    overflow: hidden;\n    line-height: @line-height-base;\n    word-wrap: break-word;\n    background: @notification-bg;\n    border-radius: @border-radius-base;\n    box-shadow: @shadow-2;\n\n    .@{notification-prefix-cls}-top &,\n    .@{notification-prefix-cls}-bottom & {\n      margin-right: auto;\n      margin-left: auto;\n    }\n\n    .@{notification-prefix-cls}-topLeft &,\n    .@{notification-prefix-cls}-bottomLeft & {\n      margin-right: auto;\n      margin-left: 0;\n    }\n\n    &-message {\n      margin-bottom: 8px;\n      color: @heading-color;\n      font-size: @font-size-lg;\n      line-height: 24px;\n\n      // https://github.com/ant-design/ant-design/issues/5846#issuecomment-296244140\n      &-single-line-auto-margin {\n        display: block;\n        width: ~'calc(@{notification-width} - @{notification-padding-horizontal} * 2 - 24px - 48px - 100%)';\n        max-width: 4px;\n        background-color: transparent;\n        pointer-events: none;\n\n        &::before {\n          display: block;\n          content: '';\n        }\n      }\n    }\n\n    &-description {\n      font-size: @font-size-base;\n    }\n\n    &-closable &-message {\n      padding-right: 24px;\n    }\n\n    &-with-icon &-message {\n      margin-bottom: 4px;\n      margin-left: 48px;\n      font-size: @font-size-lg;\n    }\n\n    &-with-icon &-description {\n      margin-left: 48px;\n      font-size: @font-size-base;\n    }\n\n    // Icon & color style in different selector level\n    // https://github.com/ant-design/ant-design/issues/16503\n    // https://github.com/ant-design/ant-design/issues/15512\n    &-icon {\n      position: absolute;\n      margin-left: 4px;\n      font-size: 24px;\n      line-height: 24px;\n    }\n\n    .@{iconfont-css-prefix}&-icon {\n      &-success {\n        color: @success-color;\n      }\n\n      &-info {\n        color: @info-color;\n      }\n\n      &-warning {\n        color: @warning-color;\n      }\n\n      &-error {\n        color: @error-color;\n      }\n    }\n\n    &-close {\n      position: absolute;\n      top: 16px;\n      right: 22px;\n      color: @text-color-secondary;\n      outline: none;\n\n      &:hover {\n        & when (@theme = dark) {\n          color: fade(@white, 85%);\n        }\n        & when not (@theme = dark) {\n          color: shade(@text-color-secondary, 40%);\n        }\n      }\n    }\n\n    &-btn {\n      float: right;\n      margin-top: 16px;\n    }\n  }\n}\n\n@import './rtl';\n@import './placement';\n"
  },
  {
    "path": "components/notification/style/placement.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/core/motion/util';\n\n@animation-max-height: 150px;\n\n.@{notification-prefix-cls} {\n  @notification-animation-cls: ~'@{notification-prefix-cls}-fade';\n\n  .make-motion-enter(@notification-animation-cls, antNotificationFadeIn, @ease-in-out);\n  .make-motion-leave(@notification-animation-cls, antNotificationFadeOut, @ease-in-out);\n\n  .notification-fade-effect {\n    animation-duration: 0.24s;\n    animation-timing-function: @ease-in-out;\n    animation-fill-mode: both;\n  }\n\n  &-top,\n  &-bottom {\n    margin-inline: 0;\n  }\n\n  &-top {\n    .@{notification-prefix-cls}-fade-enter {\n      animation-name: antNotificationTopFadeIn;\n    }\n  }\n\n  &-bottom {\n    .@{notification-prefix-cls}-fade-enter{\n      animation-name: antNotificationBottomFadeIn;\n    }\n  }\n\n  &-topLeft,\n  &-bottomLeft {\n    margin-right: 0;\n    margin-left: @notification-margin-edge;\n\n    .@{notification-prefix-cls}-fade-enter {\n      animation-name: antNotificationLeftFadeIn;\n    }\n  }\n}\n\n@keyframes antNotificationFadeIn {\n  0% {\n    transform: translate3d(100%, 0, 0);\n    opacity: 0;\n  }\n\n  100% {\n    transform: translate3d(0, 0, 0);\n    opacity: 1;\n  }\n}\n\n@keyframes antNotificationTopFadeIn {\n  0% {\n    top: -@animation-max-height;\n    opacity: 0;\n  }\n\n  100% {\n    top: 0;\n    opacity: 1;\n  }\n}\n\n@keyframes antNotificationBottomFadeIn {\n  0% {\n    bottom: -@animation-max-height;\n    opacity: 0;\n  }\n\n  100% {\n    bottom: 0;\n    opacity: 1;\n  }\n}\n\n@keyframes antNotificationLeftFadeIn {\n  0% {\n    transform: translate3d(-100%, 0, 0);\n    opacity: 0;\n  }\n\n  100% {\n    transform: translate3d(0, 0, 0);\n    opacity: 1;\n  }\n}\n\n@keyframes antNotificationFadeOut {\n  0% {\n    max-height: @animation-max-height;\n    margin-bottom: @notification-margin-bottom;\n  }\n\n  100% {\n    max-height: 0;\n    margin-bottom: 0;\n    padding-top: 0;\n    padding-bottom: 0;\n    opacity: 0;\n  }\n}\n"
  },
  {
    "path": "components/notification/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@notification-prefix-cls: ~'@{ant-prefix}-notification';\n\n.@{notification-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &-notice {\n    &-closable &-message {\n      .@{notification-prefix-cls}-rtl & {\n        padding-right: 0;\n        padding-left: 24px;\n      }\n    }\n\n    &-with-icon &-message {\n      .@{notification-prefix-cls}-rtl & {\n        margin-right: 48px;\n        margin-left: 0;\n      }\n    }\n\n    &-with-icon &-description {\n      .@{notification-prefix-cls}-rtl & {\n        margin-right: 48px;\n        margin-left: 0;\n      }\n    }\n\n    &-icon {\n      .@{notification-prefix-cls}-rtl & {\n        margin-right: 4px;\n        margin-left: 0;\n      }\n    }\n\n    &-close {\n      .@{notification-prefix-cls}-rtl & {\n        right: auto;\n        left: 22px;\n      }\n    }\n\n    &-btn {\n      .@{notification-prefix-cls}-rtl & {\n        float: left;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/notification/typings.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { TemplateRef } from '@angular/core';\nimport { Subject } from 'rxjs';\n\nimport { NgClassInterface, NgStyleInterface, NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport type { NzNotificationComponent } from './notification.component';\n\nexport type NzNotificationPlacement = 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight' | 'top' | 'bottom';\n\nexport type NzNotificationContentType =\n  | string\n  | TemplateRef<void | {\n      $implicit: NzNotificationComponent;\n      data: NzSafeAny;\n    }>;\n\nexport interface NzNotificationDataOptions<T = {}> {\n  nzKey?: string;\n  nzStyle?: NgStyleInterface;\n  nzClass?: NgClassInterface | string;\n  nzCloseIcon?: TemplateRef<void> | string;\n  nzButton?: TemplateRef<{ $implicit: NzNotificationComponent }>;\n  nzPlacement?: NzNotificationPlacement;\n  nzData?: T;\n  nzDuration?: number;\n  nzAnimate?: boolean;\n  nzPauseOnHover?: boolean;\n}\n\nexport interface NzNotificationData {\n  title?: string | TemplateRef<void>;\n  content?: NzNotificationContentType;\n  createdAt?: Date;\n  messageId?: string;\n  options?: NzNotificationDataOptions;\n  state?: 'enter' | 'leave';\n  template?: TemplateRef<{}>;\n  type?: 'success' | 'info' | 'warning' | 'error' | 'blank' | string;\n\n  // observables exposed to users\n  onClose?: Subject<boolean>;\n  onClick?: Subject<MouseEvent>;\n}\n\nexport type NzNotificationRef = Pick<Required<NzNotificationData>, 'onClose' | 'onClick' | 'messageId'>;\n"
  },
  {
    "path": "components/package.json",
    "content": "{\n  \"name\": \"ng-zorro-antd\",\n  \"version\": \"21.2.0\",\n  \"license\": \"MIT\",\n  \"description\": \"An enterprise-class UI components based on Ant Design and Angular\",\n  \"schematics\": \"./schematics/collection.json\",\n  \"ng-update\": {\n    \"migrations\": \"./schematics/migration.json\",\n    \"packageGroup\": [\n      \"ng-zorro-antd\"\n    ]\n  },\n  \"keywords\": [\n    \"ant\",\n    \"design\",\n    \"angular\",\n    \"ui\",\n    \"framework\",\n    \"frontend\"\n  ],\n  \"homepage\": \"https://ng.ant.design\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/NG-ZORRO/ng-zorro-antd\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/NG-ZORRO/ng-zorro-antd/issues\"\n  },\n  \"dependencies\": {\n    \"@angular/cdk\": \"^21.0.0\",\n    \"@ant-design/icons-angular\": \"^21.0.0\",\n    \"@ctrl/tinycolor\": \"^3.6.0\",\n    \"date-fns\": \"^2.16.1\"\n  },\n  \"peerDependencies\": {\n    \"@angular/common\": \"^21.0.0\",\n    \"@angular/forms\": \"^21.0.0\",\n    \"@angular/core\": \"^21.0.0\",\n    \"@angular/platform-browser\": \"^21.0.0\",\n    \"@angular/router\": \"^21.0.0\"\n  },\n  \"exports\": {\n    \"./ng-zorro-antd.aliyun.min.css\": {\n      \"style\": \"./ng-zorro-antd.aliyun.min.css\"\n    },\n    \"./ng-zorro-antd.compact.min.css\": {\n      \"style\": \"./ng-zorro-antd.compact.min.css\"\n    },\n    \"./ng-zorro-antd.dark.min.css\": {\n      \"style\": \"./ng-zorro-antd.dark.min.css\"\n    },\n    \"./ng-zorro-antd.min.css\": {\n      \"style\": \"./ng-zorro-antd.min.css\"\n    },\n    \"./ng-zorro-antd.variable.min.css\": {\n      \"style\": \"./ng-zorro-antd.variable.min.css\"\n    },\n    \"./ng-zorro-antd.aliyun.css\": {\n      \"style\": \"./ng-zorro-antd.aliyun.css\"\n    },\n    \"./ng-zorro-antd.compact.css\": {\n      \"style\": \"./ng-zorro-antd.compact.css\"\n    },\n    \"./ng-zorro-antd.dark.css\": {\n      \"style\": \"./ng-zorro-antd.dark.css\"\n    },\n    \"./ng-zorro-antd.css\": {\n      \"style\": \"./ng-zorro-antd.min.css\"\n    },\n    \"./ng-zorro-antd.variable.css\": {\n      \"style\": \"./ng-zorro-antd.variable.css\"\n    },\n    \"./*.less\": {\n      \"less\": \"./*.less\"\n    },\n    \"./affix/style/*\": {\n      \"less\": \"./affix/style/*.less\",\n      \"style\": \"./affix/style/index.min.css\"\n    },\n    \"./alert/style/*\": {\n      \"less\": \"./alert/style/*.less\",\n      \"style\": \"./alert/style/index.min.css\"\n    },\n    \"./anchor/style/*\": {\n      \"less\": \"./anchor/style/*.less\",\n      \"style\": \"./anchor/style/index.min.css\"\n    },\n    \"./auto-complete/style/*\": {\n      \"less\": \"./auto-complete/style/*.less\",\n      \"style\": \"./auto-complete/style/index.min.css\"\n    },\n    \"./avatar/style/*\": {\n      \"less\": \"./avatar/style/*.less\",\n      \"style\": \"./avatar/style/index.min.css\"\n    },\n    \"./badge/style/*\": {\n      \"less\": \"./badge/style/*.less\",\n      \"style\": \"./badge/style/index.min.css\"\n    },\n    \"./breadcrumb/style/*\": {\n      \"less\": \"./breadcrumb/style/*.less\",\n      \"style\": \"./breadcrumb/style/index.min.css\"\n    },\n    \"./button/style/*\": {\n      \"less\": \"./button/style/*.less\",\n      \"style\": \"./button/style/index.min.css\"\n    },\n    \"./calendar/style/*\": {\n      \"less\": \"./calendar/style/*.less\",\n      \"style\": \"./calendar/style/index.min.css\"\n    },\n    \"./card/style/*\": {\n      \"less\": \"./card/style/*.less\",\n      \"style\": \"./card/style/index.min.css\"\n    },\n    \"./carousel/style/*\": {\n      \"less\": \"./carousel/style/*.less\",\n      \"style\": \"./carousel/style/index.min.css\"\n    },\n    \"./cascader/style/*\": {\n      \"less\": \"./cascader/style/*.less\",\n      \"style\": \"./cascader/style/index.min.css\"\n    },\n    \"./code-editor/style/*\": {\n      \"less\": \"./code-editor/style/*.less\",\n      \"style\": \"./code-editor/style/index.min.css\"\n    },\n    \"./checkbox/style/*\": {\n      \"less\": \"./checkbox/style/*.less\",\n      \"style\": \"./checkbox/style/index.min.css\"\n    },\n    \"./collapse/style/*\": {\n      \"less\": \"./collapse/style/*.less\",\n      \"style\": \"./collapse/style/index.min.css\"\n    },\n    \"./comment/style/*\": {\n      \"less\": \"./comment/style/*.less\",\n      \"style\": \"./comment/style/index.min.css\"\n    },\n    \"./cron-expression/style/*\": {\n      \"less\": \"./cron-expression/style/*.less\",\n      \"style\": \"./cron-expression/style/index.min.css\"\n    },\n    \"./date-picker/style/*\": {\n      \"less\": \"./date-picker/style/*.less\",\n      \"style\": \"./date-picker/style/index.min.css\"\n    },\n    \"./descriptions/style/*\": {\n      \"less\": \"./descriptions/style/*.less\",\n      \"style\": \"./descriptions/style/index.min.css\"\n    },\n    \"./divider/style/*\": {\n      \"less\": \"./divider/style/*.less\",\n      \"style\": \"./divider/style/index.min.css\"\n    },\n    \"./drawer/style/*\": {\n      \"less\": \"./drawer/style/*.less\",\n      \"style\": \"./drawer/style/index.min.css\"\n    },\n    \"./dropdown/style/*\": {\n      \"less\": \"./dropdown/style/*.less\",\n      \"style\": \"./dropdown/style/index.min.css\"\n    },\n    \"./empty/style/*\": {\n      \"less\": \"./empty/style/*.less\",\n      \"style\": \"./empty/style/index.min.css\"\n    },\n    \"./form/style/*\": {\n      \"less\": \"./form/style/*.less\",\n      \"style\": \"./form/style/index.min.css\"\n    },\n    \"./graph/style/*\": {\n      \"less\": \"./graph/style/*.less\",\n      \"style\": \"./graph/style/index.min.css\"\n    },\n    \"./grid/style/*\": {\n      \"less\": \"./grid/style/*.less\",\n      \"style\": \"./grid/style/index.min.css\"\n    },\n    \"./icon/style/*\": {\n      \"less\": \"./icon/style/*.less\",\n      \"style\": \"./icon/style/index.min.css\"\n    },\n    \"./image/style/*\": {\n      \"less\": \"./image/style/*.less\",\n      \"style\": \"./image/style/index.min.css\"\n    },\n    \"./input/style/*\": {\n      \"less\": \"./input/style/*.less\",\n      \"style\": \"./input/style/index.min.css\"\n    },\n    \"./input-number/style/*\": {\n      \"less\": \"./input-number/style/*.less\",\n      \"style\": \"./input-number/style/index.min.css\"\n    },\n    \"./layout/style/*\": {\n      \"less\": \"./layout/style/*.less\",\n      \"style\": \"./layout/style/index.min.css\"\n    },\n    \"./list/style/*\": {\n      \"less\": \"./list/style/*.less\",\n      \"style\": \"./list/style/index.min.css\"\n    },\n    \"./mention/style/*\": {\n      \"less\": \"./mention/style/*.less\",\n      \"style\": \"./mention/style/index.min.css\"\n    },\n    \"./menu/style/*\": {\n      \"less\": \"./menu/style/*.less\",\n      \"style\": \"./menu/style/index.min.css\"\n    },\n    \"./message/style/*\": {\n      \"less\": \"./message/style/*.less\",\n      \"style\": \"./message/style/index.min.css\"\n    },\n    \"./modal/style/*\": {\n      \"less\": \"./modal/style/*.less\",\n      \"style\": \"./modal/style/index.min.css\"\n    },\n    \"./notification/style/*\": {\n      \"less\": \"./notification/style/*.less\",\n      \"style\": \"./notification/style/index.min.css\"\n    },\n    \"./page-header/style/*\": {\n      \"less\": \"./page-header/style/*.less\",\n      \"style\": \"./page-header/style/index.min.css\"\n    },\n    \"./pagination/style/*\": {\n      \"less\": \"./pagination/style/*.less\",\n      \"style\": \"./pagination/style/index.min.css\"\n    },\n    \"./popconfirm/style/*\": {\n      \"less\": \"./popconfirm/style/*.less\",\n      \"style\": \"./popconfirm/style/index.min.css\"\n    },\n    \"./popover/style/*\": {\n      \"less\": \"./popover/style/*.less\",\n      \"style\": \"./popover/style/index.min.css\"\n    },\n    \"./progress/style/*\": {\n      \"less\": \"./progress/style/*.less\",\n      \"style\": \"./progress/style/index.min.css\"\n    },\n    \"./qr-code/style/*\": {\n      \"less\": \"./qr-code/style/*.less\",\n      \"style\": \"./qr-code/style/index.min.css\"\n    },\n    \"./radio/style/*\": {\n      \"less\": \"./radio/style/*.less\",\n      \"style\": \"./radio/style/index.min.css\"\n    },\n    \"./rate/style/*\": {\n      \"less\": \"./rate/style/*.less\",\n      \"style\": \"./rate/style/index.min.css\"\n    },\n    \"./resizable/style/*\": {\n      \"less\": \"./resizable/style/*.less\",\n      \"style\": \"./resizable/style/index.min.css\"\n    },\n    \"./result/style/*\": {\n      \"less\": \"./result/style/*.less\",\n      \"style\": \"./result/style/index.min.css\"\n    },\n    \"./skeleton/style/*\": {\n      \"less\": \"./skeleton/style/*.less\",\n      \"style\": \"./skeleton/style/index.min.css\"\n    },\n    \"./slider/style/*\": {\n      \"less\": \"./slider/style/*.less\",\n      \"style\": \"./slider/style/index.min.css\"\n    },\n    \"./segmented/style/*\": {\n      \"less\": \"./segmented/style/*.less\",\n      \"style\": \"./segmented/style/index.min.css\"\n    },\n    \"./select/style/*\": {\n      \"less\": \"./select/style/*.less\",\n      \"style\": \"./select/style/index.min.css\"\n    },\n    \"./space/style/*\": {\n      \"less\": \"./space/style/*.less\",\n      \"style\": \"./space/style/index.min.css\"\n    },\n    \"./spin/style/*\": {\n      \"less\": \"./spin/style/*.less\",\n      \"style\": \"./spin/style/index.min.css\"\n    },\n    \"./statistic/style/*\": {\n      \"less\": \"./statistic/style/*.less\",\n      \"style\": \"./statistic/style/index.min.css\"\n    },\n    \"./steps/style/*\": {\n      \"less\": \"./steps/style/*.less\",\n      \"style\": \"./steps/style/index.min.css\"\n    },\n    \"./switch/style/*\": {\n      \"less\": \"./switch/style/*.less\",\n      \"style\": \"./switch/style/index.min.css\"\n    },\n    \"./table/style/*\": {\n      \"less\": \"./table/style/*.less\",\n      \"style\": \"./table/style/index.min.css\"\n    },\n    \"./tabs/style/*\": {\n      \"less\": \"./tabs/style/*.less\",\n      \"style\": \"./tabs/style/index.min.css\"\n    },\n    \"./tag/style/*\": {\n      \"less\": \"./tag/style/*.less\",\n      \"style\": \"./tag/style/index.min.css\"\n    },\n    \"./time-picker/style/*\": {\n      \"less\": \"./time-picker/style/*.less\",\n      \"style\": \"./time-picker/style/index.min.css\"\n    },\n    \"./timeline/style/*\": {\n      \"less\": \"./timeline/style/*.less\",\n      \"style\": \"./timeline/style/index.min.css\"\n    },\n    \"./tooltip/style/*\": {\n      \"less\": \"./tooltip/style/*.less\",\n      \"style\": \"./tooltip/style/index.min.css\"\n    },\n    \"./transfer/style/*\": {\n      \"less\": \"./transfer/style/*.less\",\n      \"style\": \"./transfer/style/index.min.css\"\n    },\n    \"./tree/style/*\": {\n      \"less\": \"./tree/style/*.less\",\n      \"style\": \"./tree/style/index.min.css\"\n    },\n    \"./tree-select/style/*\": {\n      \"less\": \"./tree-select/style/*.less\",\n      \"style\": \"./tree-select/style/index.min.css\"\n    },\n    \"./tree-view/style/*\": {\n      \"less\": \"./tree-view/style/*.less\",\n      \"style\": \"./tree-view/style/index.min.css\"\n    },\n    \"./typography/style/*\": {\n      \"less\": \"./typography/style/*.less\",\n      \"style\": \"./typography/style/index.min.css\"\n    },\n    \"./upload/style/*\": {\n      \"less\": \"./upload/style/*.less\",\n      \"style\": \"./upload/style/index.min.css\"\n    }\n  }\n}\n"
  },
  {
    "path": "components/page-header/demo/actions.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 多种形态的 PageHeader\n  en-US: Various forms of PageHeader\n---\n\n## zh-CN\n\n使用操作区，并自定义子节点，适合使用在需要展示一些复杂的信息，帮助用户快速了解这个页面的信息和操作。\n\n## en-US\n\nUse the operating area and customize the sub-nodes, suitable for use in the need to display some complex information to help users quickly understand the information and operations of this page.\n"
  },
  {
    "path": "components/page-header/demo/actions.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzDescriptionsModule } from 'ng-zorro-antd/descriptions';\nimport { NzGridModule } from 'ng-zorro-antd/grid';\nimport { NzPageHeaderModule } from 'ng-zorro-antd/page-header';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\nimport { NzStatisticModule } from 'ng-zorro-antd/statistic';\nimport { NzTagModule } from 'ng-zorro-antd/tag';\n\n@Component({\n  selector: 'nz-demo-page-header-actions',\n  imports: [\n    NzButtonModule,\n    NzDescriptionsModule,\n    NzGridModule,\n    NzPageHeaderModule,\n    NzSpaceModule,\n    NzStatisticModule,\n    NzTagModule\n  ],\n  template: `\n    <nz-page-header nzBackIcon>\n      <nz-page-header-title>Title</nz-page-header-title>\n      <nz-page-header-subtitle>This is a subtitle</nz-page-header-subtitle>\n      <nz-page-header-extra>\n        <nz-space>\n          <button *nzSpaceItem nz-button>Operation</button>\n          <button *nzSpaceItem nz-button>Operation</button>\n          <button *nzSpaceItem nz-button nzType=\"primary\">Primary</button>\n        </nz-space>\n      </nz-page-header-extra>\n      <nz-page-header-content>\n        <nz-descriptions nzSize=\"small\" [nzColumn]=\"3\">\n          <nz-descriptions-item nzTitle=\"Created\" [nzSpan]=\"1\">Lili Qu</nz-descriptions-item>\n          <nz-descriptions-item nzTitle=\"Association\" [nzSpan]=\"1\"><a>421421</a></nz-descriptions-item>\n          <nz-descriptions-item nzTitle=\"Creation Time\" [nzSpan]=\"1\">2017-01-10</nz-descriptions-item>\n          <nz-descriptions-item nzTitle=\"Effective Time\" [nzSpan]=\"1\">2017-10-10</nz-descriptions-item>\n          <nz-descriptions-item nzTitle=\"Remarks\" [nzSpan]=\"2\">\n            Gonghu Road, Xihu District, Hangzhou, Zhejiang, China\n          </nz-descriptions-item>\n        </nz-descriptions>\n      </nz-page-header-content>\n    </nz-page-header>\n    <br />\n    <nz-page-header nzBackIcon>\n      <nz-page-header-title>Title</nz-page-header-title>\n      <nz-page-header-subtitle>This is a subtitle</nz-page-header-subtitle>\n      <nz-page-header-tags>\n        <nz-tag nzColor=\"blue\">Running</nz-tag>\n      </nz-page-header-tags>\n      <nz-page-header-extra>\n        <nz-space>\n          <button *nzSpaceItem nz-button>Operation</button>\n          <button *nzSpaceItem nz-button>Operation</button>\n          <button *nzSpaceItem nz-button nzType=\"primary\">Primary</button>\n        </nz-space>\n      </nz-page-header-extra>\n      <nz-page-header-content>\n        <nz-row>\n          <nz-statistic nzTitle=\"Status\" nzValue=\"Pending\" />\n          <nz-statistic nzTitle=\"Price\" [nzValue]=\"568.08\" nzPrefix=\"$\" style=\"margin: 0 32px\" />\n          <nz-statistic nzTitle=\"Balance\" [nzValue]=\"3345.08\" nzPrefix=\"$\" />\n        </nz-row>\n      </nz-page-header-content>\n    </nz-page-header>\n  `\n})\nexport class NzDemoPageHeaderActionsComponent {}\n"
  },
  {
    "path": "components/page-header/demo/basic.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 标准样式\n  en-US: Basic Page Header\n---\n\n## zh-CN\n\n标准页头，适合使用在需要简单描述的场景。\n\n## en-US\n\nStandard header, suitable for use in scenarios that require a brief description.\n"
  },
  {
    "path": "components/page-header/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzPageHeaderModule } from 'ng-zorro-antd/page-header';\n\n@Component({\n  selector: 'nz-demo-page-header-basic',\n  imports: [NzPageHeaderModule],\n  template: ` <nz-page-header (nzBack)=\"onBack()\" nzBackIcon nzTitle=\"Title\" nzSubtitle=\"This is a subtitle\" /> `\n})\nexport class NzDemoPageHeaderBasicComponent {\n  onBack(): void {\n    console.log('onBack');\n  }\n}\n"
  },
  {
    "path": "components/page-header/demo/breadcrumb.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 带面包屑页头\n  en-US: Use with breadcrumbs\n---\n\n## zh-CN\n\n带面包屑页头，适合层级比较深的页面，让用户可以快速导航。\n\n## en-US\n\nWith breadcrumbs, it is suitable for deeper pages, allowing users to navigate quickly.\n"
  },
  {
    "path": "components/page-header/demo/breadcrumb.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';\nimport { NzPageHeaderModule } from 'ng-zorro-antd/page-header';\n\n@Component({\n  selector: 'nz-demo-page-header-breadcrumb',\n  imports: [NzBreadCrumbModule, NzPageHeaderModule],\n  template: `\n    <nz-page-header nzTitle=\"Title\" nzSubtitle=\"This is a subtitle\">\n      <nz-breadcrumb nz-page-header-breadcrumb>\n        <nz-breadcrumb-item>First-level Menu</nz-breadcrumb-item>\n        <nz-breadcrumb-item>\n          <a>Second-level Menu</a>\n        </nz-breadcrumb-item>\n        <nz-breadcrumb-item>Third-level Menu</nz-breadcrumb-item>\n      </nz-breadcrumb>\n    </nz-page-header>\n  `\n})\nexport class NzDemoPageHeaderBreadcrumbComponent {}\n"
  },
  {
    "path": "components/page-header/demo/content.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 组合示例\n  en-US: Complete example\n---\n\n## zh-CN\n\n使用了 PageHeader 提供的所有能力。\n\n## en-US\n\nUsed all the capabilities provided by PageHeader.\n"
  },
  {
    "path": "components/page-header/demo/content.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzAvatarModule } from 'ng-zorro-antd/avatar';\nimport { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzNoAnimationDirective } from 'ng-zorro-antd/core/animation';\nimport { NzDropdownModule } from 'ng-zorro-antd/dropdown';\nimport { NzGridModule } from 'ng-zorro-antd/grid';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzPageHeaderModule } from 'ng-zorro-antd/page-header';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\nimport { NzTagModule } from 'ng-zorro-antd/tag';\nimport { NzTypographyModule } from 'ng-zorro-antd/typography';\n\n@Component({\n  selector: 'nz-demo-page-header-content',\n  imports: [\n    NzAvatarModule,\n    NzBreadCrumbModule,\n    NzButtonModule,\n    NzDropdownModule,\n    NzGridModule,\n    NzIconModule,\n    NzPageHeaderModule,\n    NzSpaceModule,\n    NzTagModule,\n    NzTypographyModule,\n    NzNoAnimationDirective\n  ],\n  template: `\n    <nz-page-header>\n      <!--breadcrumb-->\n      <nz-breadcrumb nz-page-header-breadcrumb>\n        <nz-breadcrumb-item>First-level Menu</nz-breadcrumb-item>\n        <nz-breadcrumb-item>\n          <a>Second-level Menu</a>\n        </nz-breadcrumb-item>\n        <nz-breadcrumb-item>Third-level Menu</nz-breadcrumb-item>\n      </nz-breadcrumb>\n\n      <!--avatar-->\n      <nz-avatar nz-page-header-avatar nzSrc=\"https://avatars0.githubusercontent.com/u/22736418?s=88&v=4\" />\n\n      <!--title-->\n      <nz-page-header-title>Title</nz-page-header-title>\n\n      <!--subtitle-->\n      <nz-page-header-subtitle>This is a subtitle</nz-page-header-subtitle>\n\n      <!--tags-->\n      <nz-page-header-tags>\n        <nz-tag nzColor=\"blue\">Running</nz-tag>\n      </nz-page-header-tags>\n\n      <!--extra-->\n      <nz-page-header-extra>\n        <nz-space>\n          <button *nzSpaceItem nz-button>Operation</button>\n          <button *nzSpaceItem nz-button>Operation</button>\n          <button *nzSpaceItem nz-button nzType=\"primary\">Primary</button>\n          <button\n            *nzSpaceItem\n            nz-button\n            nzNoAnimation\n            nz-dropdown\n            [nzDropdownMenu]=\"menu\"\n            nzPlacement=\"bottomRight\"\n            style=\"border: none; padding: 0\"\n          >\n            <nz-icon nzType=\"more\" nzTheme=\"outline\" style=\"font-size: 20px; vertical-align: top;\" />\n          </button>\n        </nz-space>\n        <nz-dropdown-menu #menu=\"nzDropdownMenu\">\n          <ul nz-menu>\n            <li nz-menu-item>1st menu item length</li>\n            <li nz-menu-item>2nd menu item length</li>\n            <li nz-menu-item>3rd menu item length</li>\n          </ul>\n        </nz-dropdown-menu>\n      </nz-page-header-extra>\n\n      <!--content-->\n      <nz-page-header-content>\n        <div nz-row>\n          <div class=\"content\">\n            <p nz-paragraph>\n              Ant Design interprets the color system into two levels: a system-level color system and a product-level\n              color system.\n            </p>\n            <p nz-paragraph>\n              Ant Design's design team preferred to design with the HSB color model, which makes it easier for designers\n              to have a clear psychological expectation of color when adjusting colors, as well as facilitate\n              communication in teams.\n            </p>\n            <div class=\"content-link\">\n              <a>\n                <img src=\"https://gw.alipayobjects.com/zos/rmsportal/MjEImQtenlyueSmVEfUD.svg\" alt=\"start\" />\n                Quick Start\n              </a>\n              <a>\n                <img src=\"https://gw.alipayobjects.com/zos/rmsportal/NbuDUAuBlIApFuDvWiND.svg\" alt=\"info\" />\n                Product Info\n              </a>\n              <a>\n                <img src=\"https://gw.alipayobjects.com/zos/rmsportal/ohOEPSYdDTNnyMbGuyLb.svg\" alt=\"doc\" />\n                Product Doc\n              </a>\n            </div>\n          </div>\n          <div class=\"content-image\">\n            <img src=\"https://gw.alipayobjects.com/zos/antfincdn/K%24NnlsB%26hz/pageHeader.svg\" alt=\"content\" />\n          </div>\n        </div>\n      </nz-page-header-content>\n    </nz-page-header>\n  `,\n  styles: `\n    .content {\n      flex: 1;\n    }\n\n    .content p {\n      margin-bottom: 1em;\n    }\n\n    .content-link a {\n      margin-right: 16px;\n    }\n\n    .content-link a img {\n      margin-right: 8px;\n    }\n\n    .content-image {\n      margin: 0 0 0 60px;\n      display: flex;\n      align-items: center;\n    }\n\n    .content-image img {\n      width: 100%;\n    }\n\n    @media (max-width: 768px) {\n      .content-image {\n        flex: 100%;\n        margin: 24px 0 0;\n      }\n    }\n  `\n})\nexport class NzDemoPageHeaderContentComponent {}\n"
  },
  {
    "path": "components/page-header/demo/ghost.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 白底模式\n  en-US: white background mode\n---\n\n## zh-CN\n\n默认 PageHeader 是透明底色的。在某些情况下，PageHeader 需要自己的背景颜色。\n\n## en-US\n\nThe default PageHeader is a transparent background. In some cases, PageHeader needs its own background color.\n"
  },
  {
    "path": "components/page-header/demo/ghost.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzDescriptionsModule } from 'ng-zorro-antd/descriptions';\nimport { NzPageHeaderModule } from 'ng-zorro-antd/page-header';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\n\n@Component({\n  selector: 'nz-demo-page-header-ghost',\n  imports: [NzButtonModule, NzDescriptionsModule, NzPageHeaderModule, NzSpaceModule],\n  template: `\n    <nz-page-header nzBackIcon [nzGhost]=\"false\">\n      <nz-page-header-title>Title</nz-page-header-title>\n      <nz-page-header-subtitle>This is a subtitle</nz-page-header-subtitle>\n      <nz-page-header-extra>\n        <nz-space>\n          <button *nzSpaceItem nz-button>Operation</button>\n          <button *nzSpaceItem nz-button>Operation</button>\n          <button *nzSpaceItem nz-button nzType=\"primary\">Primary</button>\n        </nz-space>\n      </nz-page-header-extra>\n      <nz-page-header-content>\n        <nz-descriptions nzSize=\"small\" [nzColumn]=\"3\">\n          <nz-descriptions-item nzTitle=\"Created\" [nzSpan]=\"1\">Lili Qu</nz-descriptions-item>\n          <nz-descriptions-item nzTitle=\"Association\" [nzSpan]=\"1\"><a>421421</a></nz-descriptions-item>\n          <nz-descriptions-item nzTitle=\"Creation Time\" [nzSpan]=\"1\">2017-01-10</nz-descriptions-item>\n          <nz-descriptions-item nzTitle=\"Effective Time\" [nzSpan]=\"1\">2017-10-10</nz-descriptions-item>\n          <nz-descriptions-item nzTitle=\"Remarks\" [nzSpan]=\"2\">\n            Gonghu Road, Xihu District, Hangzhou, Zhejiang, China\n          </nz-descriptions-item>\n        </nz-descriptions>\n      </nz-page-header-content>\n    </nz-page-header>\n  `\n})\nexport class NzDemoPageHeaderGhostComponent {}\n"
  },
  {
    "path": "components/page-header/demo/responsive.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 响应式\n  en-US: responsive\n---\n\n## zh-CN\n\n在不同大小的屏幕下，应该有不同的表现\n\n## en-US\n\nUnder different screen sizes, there should be different performance\n"
  },
  {
    "path": "components/page-header/demo/responsive.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzDescriptionsModule } from 'ng-zorro-antd/descriptions';\nimport { NzPageHeaderModule } from 'ng-zorro-antd/page-header';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\nimport { NzStatisticModule } from 'ng-zorro-antd/statistic';\nimport { NzTabsModule } from 'ng-zorro-antd/tabs';\n\n@Component({\n  selector: 'nz-demo-page-header-responsive',\n  imports: [NzButtonModule, NzDescriptionsModule, NzPageHeaderModule, NzSpaceModule, NzStatisticModule, NzTabsModule],\n  template: `\n    <nz-page-header nzBackIcon>\n      <nz-page-header-title>Title</nz-page-header-title>\n      <nz-page-header-subtitle>This is a subtitle</nz-page-header-subtitle>\n      <nz-page-header-extra>\n        <nz-space>\n          <button *nzSpaceItem nz-button>Operation</button>\n          <button *nzSpaceItem nz-button>Operation</button>\n          <button *nzSpaceItem nz-button nzType=\"primary\">Primary</button>\n        </nz-space>\n      </nz-page-header-extra>\n      <nz-page-header-content>\n        <div class=\"content\">\n          <div class=\"main\">\n            <nz-descriptions nzSize=\"small\" [nzColumn]=\"2\">\n              <nz-descriptions-item nzTitle=\"Created\" [nzSpan]=\"1\">Lili Qu</nz-descriptions-item>\n              <nz-descriptions-item nzTitle=\"Association\" [nzSpan]=\"1\"><a>421421</a></nz-descriptions-item>\n              <nz-descriptions-item nzTitle=\"Creation Time\" [nzSpan]=\"1\">2017-01-10</nz-descriptions-item>\n              <nz-descriptions-item nzTitle=\"Effective Time\" [nzSpan]=\"1\">2017-10-10</nz-descriptions-item>\n              <nz-descriptions-item nzTitle=\"Remarks\" [nzSpan]=\"2\">\n                Gonghu Road, Xihu District, Hangzhou, Zhejiang, China\n              </nz-descriptions-item>\n            </nz-descriptions>\n          </div>\n          <div class=\"extra\">\n            <div>\n              <nz-statistic nzTitle=\"Status\" nzValue=\"Pending\" />\n              <nz-statistic nzTitle=\"Price\" [nzValue]=\"568.08\" nzPrefix=\"$\" style=\"margin: 0 32px\" />\n            </div>\n          </div>\n        </div>\n      </nz-page-header-content>\n      <nz-page-header-footer>\n        <nz-tabs [nzSelectedIndex]=\"1\">\n          <nz-tab nzTitle=\"Details\" />\n          <nz-tab nzTitle=\"Rule\" />\n        </nz-tabs>\n      </nz-page-header-footer>\n    </nz-page-header>\n  `,\n  styles: `\n    .content {\n      display: flex;\n    }\n\n    .extra > div {\n      display: flex;\n      width: max-content;\n      justify-content: flex-end;\n    }\n\n    @media (max-width: 576px) {\n      .content {\n        display: block;\n      }\n\n      .main {\n        width: 100%;\n        margin-bottom: 12px;\n      }\n\n      .extra {\n        width: 100%;\n        margin-left: 0;\n        text-align: left;\n      }\n    }\n  `\n})\nexport class NzDemoPageHeaderResponsiveComponent {}\n"
  },
  {
    "path": "components/page-header/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Navigation\ntitle: PageHeader\ncols: 1\ncover: 'https://gw.alipayobjects.com/zos/alicdn/6bKE0Cq0R/PageHeader.svg'\ndescription: A header with common actions and design elements built in.\n---\n\n## When To Use\n\nPageHeader can be used to highlight the page topic, display important information about the page, and carry the action items related to the current page (including page-level operations, inter-page navigation, etc.) It can also be used as inter-page navigation.\n\n## API\n\n```html\n<nz-page-header nzTitle=\"Page Title\"></nz-page-header>\n```\n\n### nz-page-header\n\n| Param          | Description                 | Type                          | Default value                                                                                                                                                                                                                                   | Global Config |\n| -------------- | --------------------------- | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |\n| `[nzGhost]`    | Make background transparent | `boolean`                     | `true`                                                                                                                                                                                                                                          | ✅            |\n| `[nzTitle]`    | Title string                | `string \\| TemplateRef<void>` | -                                                                                                                                                                                                                                               | -             |\n| `[nzSubtitle]` | SubTitle string             | `string \\| TemplateRef<void>` | -                                                                                                                                                                                                                                               | -             |\n| `[nzBackIcon]` | Custom back icon            | `string \\| TemplateRef<void>` | -                                                                                                                                                                                                                                               | -             |\n| `(nzBack)`     | Back icon click event       | `EventEmitter<void>`          | Call [Location#back](https://angular.dev/api/common/Location#back) when the event not subscribed（you need import [RouterModule](https://angular.dev/api/router/RouterModule) or register [Location](https://angular.dev/api/common/Location)） | -             |\n\n### Page header sections\n\n| Element                                    | Description                                              |\n| ------------------------------------------ | -------------------------------------------------------- |\n| `nz-page-header-title`                     | Title section                                            |\n| `nz-page-header-subtitle`                  | Subtitle section, `[nzTitle]` has high priority          |\n| `nz-page-header-content`                   | Content section, `[nzSubtitle]` has high priority        |\n| `nz-page-header-footer`                    | Footer section                                           |\n| `nz-page-header-tags`                      | Tags container after the title                           |\n| `nz-page-header-extra`                     | Operating area, at the end of the line of the title line |\n| `nz-breadcrumb[nz-page-header-breadcrumb]` | Breadcrumb section                                       |\n| `nz-avatar[nz-page-header-avatar]`         | Avatar section                                           |\n"
  },
  {
    "path": "components/page-header/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ntype: 导航\ntitle: PageHeader\ncols: 1\nsubtitle: 页头\ncover: 'https://gw.alipayobjects.com/zos/alicdn/6bKE0Cq0R/PageHeader.svg'\ndescription: 带有通用操作的页头。\n---\n\n## 何时使用\n\n页头位于页容器中，页容器顶部，起到了内容概览和引导页级操作的作用。包括由面包屑、标题、页面内容简介、页面级操作等、页面级导航组成。\n\n当需要使用户快速理解当前页是什么以及方便用户使用页面功能时使用，通常也可被用作页面间导航。\n\n## API\n\n```html\n<nz-page-header nzTitle=\"Page Title\"></nz-page-header>\n```\n\n### nz-page-header\n\n| 参数           | 说明               | 类型                          | 默认值                                                                                                                                                                                                                | 全局配置 |\n| -------------- | ------------------ | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |\n| `[nzGhost]`    | 使背景色透明       | `boolean`                     | `true`                                                                                                                                                                                                                | ✅       |\n| `[nzTitle]`    | title 文字         | `string \\| TemplateRef<void>` | -                                                                                                                                                                                                                     | -        |\n| `[nzSubtitle]` | subTitle 文字      | `string \\| TemplateRef<void>` | -                                                                                                                                                                                                                     | -        |\n| `[nzBackIcon]` | 自定义 back icon   | `string \\| TemplateRef<void>` | -                                                                                                                                                                                                                     | -        |\n| `(nzBack)`     | 返回按钮的点击事件 | `EventEmitter<void>`          | 未订阅该事件时默认调用 [Location#back](https://angular.cn/api/common/Location#back)（需要引入 [RouterModule](https://angular.cn/api/router/RouterModule) 或者注册 [Location](https://angular.cn/api/common/Location)) | -        |\n\n### Page header 组成部分\n\n| 元素                                       | 说明                                     |\n| ------------------------------------------ | ---------------------------------------- |\n| `nz-page-header-title`                     | title 部分，`[nzTitle]` 优先级更高       |\n| `nz-page-header-subtitle`                  | subtitle 部分，`[nzSubtitle]` 优先级更高 |\n| `nz-page-header-content`                   | 内容部分                                 |\n| `nz-page-header-footer`                    | 底部部分                                 |\n| `nz-page-header-tags`                      | title 旁的 tag 列表容器                  |\n| `nz-page-header-extra`                     | title 的行尾操作区部分                   |\n| `nz-breadcrumb[nz-page-header-breadcrumb]` | 面包屑部分                               |\n| `nz-avatar[nz-page-header-avatar]`         | 头像部分                                 |\n"
  },
  {
    "path": "components/page-header/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/page-header/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/page-header/page-header-cells.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive } from '@angular/core';\n\n@Directive({\n  selector: 'nz-page-header-title, [nz-page-header-title]',\n  exportAs: 'nzPageHeaderTitle',\n  host: {\n    class: 'ant-page-header-heading-title'\n  }\n})\nexport class NzPageHeaderTitleDirective {}\n\n@Directive({\n  selector: 'nz-page-header-subtitle, [nz-page-header-subtitle]',\n  exportAs: 'nzPageHeaderSubtitle',\n  host: {\n    class: 'ant-page-header-heading-sub-title'\n  }\n})\nexport class NzPageHeaderSubtitleDirective {}\n\n@Directive({\n  selector: 'nz-page-header-content, [nz-page-header-content]',\n  exportAs: 'nzPageHeaderContent',\n  host: {\n    class: 'ant-page-header-content'\n  }\n})\nexport class NzPageHeaderContentDirective {}\n\n@Directive({\n  selector: 'nz-page-header-tags, [nz-page-header-tags]',\n  exportAs: 'nzPageHeaderTags',\n  host: {\n    class: 'ant-page-header-heading-tags'\n  }\n})\nexport class NzPageHeaderTagDirective {}\n\n@Directive({\n  selector: 'nz-page-header-extra, [nz-page-header-extra]',\n  exportAs: 'nzPageHeaderExtra',\n  host: {\n    class: 'ant-page-header-heading-extra'\n  }\n})\nexport class NzPageHeaderExtraDirective {}\n\n@Directive({\n  selector: 'nz-page-header-footer, [nz-page-header-footer]',\n  exportAs: 'nzPageHeaderFooter',\n  host: {\n    class: 'ant-page-header-footer'\n  }\n})\nexport class NzPageHeaderFooterDirective {}\n\n@Directive({\n  selector: 'nz-breadcrumb[nz-page-header-breadcrumb]',\n  exportAs: 'nzPageHeaderBreadcrumb'\n})\nexport class NzPageHeaderBreadcrumbDirective {}\n\n@Directive({\n  selector: 'nz-avatar[nz-page-header-avatar]',\n  exportAs: 'nzPageHeaderAvatar'\n})\nexport class NzPageHeaderAvatarDirective {}\n"
  },
  {
    "path": "components/page-header/page-header.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport { Location } from '@angular/common';\nimport {\n  AfterViewInit,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ContentChild,\n  DestroyRef,\n  ElementRef,\n  EventEmitter,\n  inject,\n  Input,\n  OnInit,\n  Output,\n  TemplateRef,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { map } from 'rxjs/operators';\n\nimport { NzResizeObserver } from 'ng-zorro-antd/cdk/resize-observer';\nimport { NzConfigKey, NzConfigService, WithConfig } from 'ng-zorro-antd/core/config';\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nimport { NzPageHeaderBreadcrumbDirective, NzPageHeaderFooterDirective } from './page-header-cells';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'pageHeader';\n\n@Component({\n  selector: 'nz-page-header',\n  exportAs: 'nzPageHeader',\n  template: `\n    <ng-content select=\"nz-breadcrumb[nz-page-header-breadcrumb]\" />\n\n    <div class=\"ant-page-header-heading\">\n      <div class=\"ant-page-header-heading-left\">\n        <!--back-->\n        @if (nzBackIcon !== null && enableBackButton) {\n          <div (click)=\"onBack()\" class=\"ant-page-header-back\">\n            <div role=\"button\" tabindex=\"0\" class=\"ant-page-header-back-button\">\n              <ng-container *nzStringTemplateOutlet=\"nzBackIcon; let backIcon\">\n                <nz-icon [nzType]=\"backIcon || getBackIcon()\" nzTheme=\"outline\" />\n              </ng-container>\n            </div>\n          </div>\n        }\n\n        <!--avatar-->\n        <ng-content select=\"nz-avatar[nz-page-header-avatar]\" />\n        <!--title-->\n        @if (nzTitle) {\n          <span class=\"ant-page-header-heading-title\">\n            <ng-container *nzStringTemplateOutlet=\"nzTitle\">{{ nzTitle }}</ng-container>\n          </span>\n        } @else {\n          <ng-content select=\"nz-page-header-title, [nz-page-header-title]\" />\n        }\n\n        <!--subtitle-->\n        @if (nzSubtitle) {\n          <span class=\"ant-page-header-heading-sub-title\">\n            <ng-container *nzStringTemplateOutlet=\"nzSubtitle\">{{ nzSubtitle }}</ng-container>\n          </span>\n        } @else {\n          <ng-content select=\"nz-page-header-subtitle, [nz-page-header-subtitle]\" />\n        }\n        <ng-content select=\"nz-page-header-tags, [nz-page-header-tags]\" />\n      </div>\n\n      <ng-content select=\"nz-page-header-extra, [nz-page-header-extra]\" />\n    </div>\n\n    <ng-content select=\"nz-page-header-content, [nz-page-header-content]\" />\n    <ng-content select=\"nz-page-header-footer, [nz-page-header-footer]\" />\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  host: {\n    class: 'ant-page-header',\n    '[class.has-footer]': 'nzPageHeaderFooter',\n    '[class.ant-page-header-ghost]': 'nzGhost',\n    '[class.has-breadcrumb]': 'nzPageHeaderBreadcrumb',\n    '[class.ant-page-header-compact]': 'compact',\n    '[class.ant-page-header-rtl]': `dir === 'rtl'`\n  },\n  imports: [NzOutletModule, NzIconModule]\n})\nexport class NzPageHeaderComponent implements AfterViewInit, OnInit {\n  private location = inject(Location);\n  private destroyRef = inject(DestroyRef);\n\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  @Input() nzBackIcon: string | TemplateRef<void> | null = null;\n  @Input() nzTitle?: string | TemplateRef<void>;\n  @Input() nzSubtitle?: string | TemplateRef<void>;\n  @Input() @WithConfig() nzGhost: boolean = true;\n  @Output() readonly nzBack = new EventEmitter<void>();\n\n  @ContentChild(NzPageHeaderFooterDirective, { static: false })\n  nzPageHeaderFooter?: ElementRef<NzPageHeaderFooterDirective>;\n  @ContentChild(NzPageHeaderBreadcrumbDirective, { static: false })\n  nzPageHeaderBreadcrumb?: ElementRef<NzPageHeaderBreadcrumbDirective>;\n\n  compact = false;\n  dir: Direction = 'ltr';\n\n  enableBackButton = true;\n\n  constructor(\n    public nzConfigService: NzConfigService,\n    private elementRef: ElementRef,\n    private nzResizeObserver: NzResizeObserver,\n    private cdr: ChangeDetectorRef,\n    private directionality: Directionality\n  ) {}\n\n  ngOnInit(): void {\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((direction: Direction) => {\n      this.dir = direction;\n      this.cdr.detectChanges();\n    });\n    this.dir = this.directionality.value;\n  }\n\n  ngAfterViewInit(): void {\n    if (!this.nzBack.observers.length) {\n      this.enableBackButton = (this.location.getState() as NzSafeAny)?.navigationId > 1;\n      // Location is not an RxJS construct, as a result, we can't pipe it.\n      const subscription = this.location.subscribe(() => {\n        this.enableBackButton = true;\n        this.cdr.detectChanges();\n      });\n      this.destroyRef.onDestroy(() => subscription.unsubscribe());\n    }\n\n    this.nzResizeObserver\n      .observe(this.elementRef)\n      .pipe(\n        map(([entry]) => entry.contentRect.width),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe((width: number) => {\n        this.compact = width < 768;\n        this.cdr.markForCheck();\n      });\n  }\n\n  onBack(): void {\n    if (this.nzBack.observers.length) {\n      this.nzBack.emit();\n    } else {\n      this.location.back();\n    }\n  }\n\n  getBackIcon(): string {\n    if (this.dir === 'rtl') {\n      return 'arrow-right';\n    }\n    return 'arrow-left';\n  }\n}\n"
  },
  {
    "path": "components/page-header/page-header.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport {\n  NzPageHeaderAvatarDirective,\n  NzPageHeaderBreadcrumbDirective,\n  NzPageHeaderContentDirective,\n  NzPageHeaderExtraDirective,\n  NzPageHeaderFooterDirective,\n  NzPageHeaderSubtitleDirective,\n  NzPageHeaderTagDirective,\n  NzPageHeaderTitleDirective\n} from './page-header-cells';\nimport { NzPageHeaderComponent } from './page-header.component';\n\nconst NzPageHeaderCells = [\n  NzPageHeaderTitleDirective,\n  NzPageHeaderSubtitleDirective,\n  NzPageHeaderContentDirective,\n  NzPageHeaderTagDirective,\n  NzPageHeaderExtraDirective,\n  NzPageHeaderFooterDirective,\n  NzPageHeaderBreadcrumbDirective,\n  NzPageHeaderAvatarDirective\n];\n\n@NgModule({\n  imports: [NzPageHeaderComponent, NzPageHeaderCells],\n  exports: [NzPageHeaderComponent, NzPageHeaderCells]\n})\nexport class NzPageHeaderModule {}\n"
  },
  {
    "path": "components/page-header/page-header.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport { Location } from '@angular/common';\nimport { Component, DebugElement, provideZoneChangeDetection, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzDemoPageHeaderBasicComponent } from './demo/basic';\nimport { NzDemoPageHeaderBreadcrumbComponent } from './demo/breadcrumb';\nimport { NzDemoPageHeaderContentComponent } from './demo/content';\nimport { NzDemoPageHeaderGhostComponent } from './demo/ghost';\nimport { NzDemoPageHeaderResponsiveComponent } from './demo/responsive';\nimport { NzPageHeaderComponent } from './page-header.component';\n\ndescribe('page-header', () => {\n  let location: Location;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), provideNzIconsTesting(), provideZoneChangeDetection()]\n    });\n    location = TestBed.inject(Location);\n    spyOn(location, 'getState').and.returnValue({ navigationId: 2 });\n  });\n\n  it('should basic work', () => {\n    const fixture = TestBed.createComponent(NzDemoPageHeaderBasicComponent);\n    const pageHeader = fixture.debugElement.query(By.directive(NzPageHeaderComponent));\n    fixture.detectChanges();\n    expect(pageHeader.nativeElement.classList).toContain('ant-page-header');\n    expect(pageHeader.nativeElement.classList).toContain('ant-page-header-ghost');\n    expect(pageHeader.nativeElement.querySelector('.ant-page-header-heading-title')).toBeTruthy();\n    expect(pageHeader.nativeElement.querySelector('.ant-page-header-heading-sub-title')).toBeTruthy();\n  });\n\n  it('should displayed the back button if nzBack has observer', () => {\n    const fixture = TestBed.createComponent(NzDemoPageHeaderBasicComponent);\n    const pageHeader = fixture.debugElement.query(By.directive(NzPageHeaderComponent));\n    fixture.detectChanges();\n    const back = pageHeader.nativeElement.querySelector('.ant-page-header-back-button');\n    expect(back).toBeTruthy();\n  });\n\n  it('should ghost work', () => {\n    const fixture = TestBed.createComponent(NzDemoPageHeaderGhostComponent);\n    const pageHeader = fixture.debugElement.query(By.directive(NzPageHeaderComponent));\n    fixture.detectChanges();\n    expect(pageHeader.nativeElement.classList).toContain('ant-page-header');\n    expect(pageHeader.nativeElement.classList).not.toContain('ant-page-header-ghost');\n  });\n\n  it('should breadcrumb work', () => {\n    const fixture = TestBed.createComponent(NzDemoPageHeaderBreadcrumbComponent);\n    const pageHeader = fixture.debugElement.query(By.directive(NzPageHeaderComponent));\n    fixture.detectChanges();\n    expect(pageHeader.nativeElement.classList).toContain('has-breadcrumb');\n    expect(pageHeader.nativeElement.querySelector('nz-breadcrumb[nz-page-header-breadcrumb]')).toBeTruthy();\n  });\n\n  it('should default call location back when nzBack not has observers', () => {\n    const fixture = TestBed.createComponent(NzDemoPageHeaderResponsiveComponent);\n    const pageHeader = fixture.debugElement.query(By.directive(NzPageHeaderComponent));\n    spyOn(location, 'back');\n    fixture.detectChanges();\n    expect(location.back).not.toHaveBeenCalled();\n    const back = pageHeader.nativeElement.querySelector('.ant-page-header-back');\n    (back as HTMLElement).click();\n    fixture.detectChanges();\n    expect(location.back).toHaveBeenCalled();\n  });\n\n  it('should not show the back button if there is no history of navigation', fakeAsync(() => {\n    const fixture = TestBed.createComponent(NzDemoPageHeaderResponsiveComponent);\n    const pageHeader = fixture.debugElement.query(By.directive(NzPageHeaderComponent));\n    spyOn(location, 'getState').and.returnValue({ navigationId: 1 });\n    fixture.detectChanges();\n    pageHeader.componentInstance.ngAfterViewInit();\n    tick();\n    fixture.detectChanges();\n    const back = pageHeader.nativeElement.querySelector('.ant-page-header-back-button');\n    expect(back).toBeNull();\n  }));\n\n  it('should show the back button if there is history of navigation', fakeAsync(() => {\n    const fixture = TestBed.createComponent(NzDemoPageHeaderResponsiveComponent);\n    const pageHeader = fixture.debugElement.query(By.directive(NzPageHeaderComponent));\n    fixture.detectChanges();\n    pageHeader.componentInstance.ngAfterViewInit();\n    tick();\n    fixture.detectChanges();\n    const back = pageHeader.nativeElement.querySelector('.ant-page-header-back-button');\n    expect(back as HTMLDivElement).toBeTruthy();\n  }));\n\n  it('should content work', () => {\n    const fixture = TestBed.createComponent(NzDemoPageHeaderContentComponent);\n    const pageHeader = fixture.debugElement.query(By.directive(NzPageHeaderComponent));\n    fixture.detectChanges();\n    const content = pageHeader.nativeElement.querySelector('nz-page-header-content.ant-page-header-content');\n    expect(content).toBeTruthy();\n    expect((content as HTMLElement).children.length > 0).toBe(true);\n  });\n\n  it('should actions work', () => {\n    const fixture = TestBed.createComponent(NzDemoPageHeaderContentComponent);\n    const pageHeader = fixture.debugElement.query(By.directive(NzPageHeaderComponent));\n    fixture.detectChanges();\n    expect(pageHeader.nativeElement.querySelector('nz-page-header-extra.ant-page-header-heading-extra')).toBeTruthy();\n    expect(pageHeader.nativeElement.querySelector('nz-page-header-tags.ant-page-header-heading-tags')).toBeTruthy();\n  });\n\n  it('should footer work', () => {\n    const fixture = TestBed.createComponent(NzDemoPageHeaderResponsiveComponent);\n    const pageHeader = fixture.debugElement.query(By.directive(NzPageHeaderComponent));\n    fixture.detectChanges();\n    expect(pageHeader.nativeElement.classList).toContain('has-footer');\n    expect(pageHeader.nativeElement.querySelector('nz-page-header-footer.ant-page-header-footer')).toBeTruthy();\n  });\n\n  it('should avatar work', () => {\n    const fixture = TestBed.createComponent(NzDemoPageHeaderContentComponent);\n    const pageHeader = fixture.debugElement.query(By.directive(NzPageHeaderComponent));\n    fixture.detectChanges();\n    expect(pageHeader.nativeElement.querySelector('nz-avatar[nz-page-header-avatar]')).toBeTruthy();\n  });\n\n  it('should have an default back icon', () => {\n    const fixture = TestBed.createComponent(NzDemoPageHeaderBasicComponent);\n    const pageHeader = fixture.debugElement.query(By.directive(NzPageHeaderComponent));\n    fixture.detectChanges();\n    expect(pageHeader.nativeElement.querySelector('.ant-page-header-back .anticon-arrow-left')).toBeTruthy();\n  });\n\n  it('should does not have an default back icon', () => {\n    const fixture = TestBed.createComponent(NzDemoPageHeaderContentComponent);\n    const pageHeader = fixture.debugElement.query(By.directive(NzPageHeaderComponent));\n    fixture.detectChanges();\n    expect(pageHeader.nativeElement.querySelector('.ant-page-header-back')).toBeFalsy();\n  });\n\n  it('should nzBack work', () => {\n    const fixture = TestBed.createComponent(NzDemoPageHeaderBasicComponent);\n    const pageHeader = fixture.debugElement.query(By.directive(NzPageHeaderComponent));\n    const context = fixture.componentInstance;\n    spyOn(context, 'onBack');\n    fixture.detectChanges();\n    expect(context.onBack).not.toHaveBeenCalled();\n    const back = pageHeader.nativeElement.querySelector('.ant-page-header-back');\n    (back as HTMLElement).click();\n    fixture.detectChanges();\n    expect(context.onBack).toHaveBeenCalled();\n  });\n\n  describe('RTL', () => {\n    let fixture: ComponentFixture<NzDemoPageHeaderRtlComponent>;\n    let pageHeader: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzDemoPageHeaderRtlComponent);\n      pageHeader = fixture.debugElement.query(By.directive(NzPageHeaderComponent));\n    });\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n      expect(pageHeader.nativeElement.classList).toContain('ant-page-header-rtl');\n    });\n\n    it('should className correct after change Dir', () => {\n      fixture.detectChanges();\n      expect(pageHeader.nativeElement.classList).toContain('ant-page-header-rtl');\n\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n\n      expect(pageHeader.nativeElement.classList).not.toContain('ant-page-header-rtl');\n    });\n\n    it('should have an default back icon', () => {\n      fixture.detectChanges();\n      expect(pageHeader.nativeElement.querySelector('.ant-page-header-back .anticon-arrow-right')).toBeTruthy();\n    });\n  });\n});\n\n@Component({\n  imports: [BidiModule, NzDemoPageHeaderBasicComponent],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-demo-page-header-basic />\n    </div>\n  `\n})\nexport class NzDemoPageHeaderRtlComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n}\n"
  },
  {
    "path": "components/page-header/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './page-header.module';\nexport * from './page-header.component';\nexport * from './page-header-cells';\n"
  },
  {
    "path": "components/page-header/style/entry.less",
    "content": "@import './index.less';\n// style dependencies\n@import '../../divider/style/entry.less';\n@import '../../breadcrumb/style/entry.less';\n@import \"./patch\";\n"
  },
  {
    "path": "components/page-header/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@pageheader-prefix-cls: ~'@{ant-prefix}-page-header';\n\n.@{pageheader-prefix-cls} {\n  .reset-component();\n  position: relative;\n  padding: @page-header-padding-vertical @page-header-padding;\n  background-color: @component-background;\n\n  &-ghost {\n    background-color: @page-header-ghost-bg;\n  }\n\n  &.has-breadcrumb {\n    padding-top: @page-header-padding-breadcrumb;\n  }\n\n  &.has-footer {\n    padding-bottom: 0;\n  }\n\n  &-back {\n    margin-right: @margin-md;\n    font-size: 16px;\n    line-height: 1;\n\n    &-button {\n      .operation-unit();\n      color: @page-header-back-color;\n    }\n  }\n\n  .@{ant-prefix}-divider-vertical {\n    height: 14px;\n    margin: 0 @margin-sm;\n    vertical-align: middle;\n  }\n\n  .@{ant-prefix}-breadcrumb + &-heading {\n    margin-top: @margin-xs;\n  }\n\n  .text-overflow-ellipsis() {\n    overflow: hidden;\n    white-space: nowrap;\n    text-overflow: ellipsis;\n  }\n\n  &-heading {\n    display: flex;\n    justify-content: space-between;\n\n    &-left {\n      display: flex;\n      align-items: center;\n      margin: (@margin-xs / 2) 0;\n      overflow: hidden;\n    }\n\n    &-title {\n      margin-right: @margin-sm;\n      margin-bottom: 0;\n      color: @heading-color;\n      font-weight: 600;\n      font-size: @page-header-heading-title;\n      line-height: @height-base;\n      .text-overflow-ellipsis();\n    }\n\n    .@{ant-prefix}-avatar {\n      margin-right: @margin-sm;\n    }\n\n    &-sub-title {\n      margin-right: @margin-sm;\n      color: @text-color-secondary;\n      font-size: @page-header-heading-sub-title;\n      line-height: @line-height-base;\n      .text-overflow-ellipsis();\n    }\n\n    &-extra {\n      margin: (@margin-xs / 2) 0;\n      white-space: nowrap;\n\n      > * {\n        white-space: unset;\n      }\n    }\n  }\n\n  &-content {\n    padding-top: @page-header-content-padding-vertical;\n  }\n\n  &-footer {\n    margin-top: @margin-md;\n    .@{ant-prefix}-tabs {\n      > .@{ant-prefix}-tabs-nav {\n        margin: 0;\n\n        &::before {\n          border: none;\n        }\n      }\n\n      .@{ant-prefix}-tabs-tab {\n        padding-top: @padding-xs;\n        padding-bottom: @padding-xs;\n        font-size: @page-header-tabs-tab-font-size;\n      }\n    }\n  }\n\n  &-compact &-heading {\n    flex-wrap: wrap;\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/page-header/style/patch.less",
    "content": ".ant-page-header-back-button {\n  display: inline-block;\n  padding: 0;\n  line-height: inherit;\n  background: transparent;\n  border: 0;\n}\n\nnz-page-header,\nnz-page-header-content,\nnz-page-header-footer {\n  display: block;\n}\n"
  },
  {
    "path": "components/page-header/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@pageheader-prefix-cls: ~'@{ant-prefix}-page-header';\n\n.@{pageheader-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &-back {\n    .@{pageheader-prefix-cls}-rtl & {\n      float: right;\n      margin-right: 0;\n      margin-left: 16px;\n    }\n  }\n\n  &-heading {\n    &-title {\n      .@{pageheader-prefix-cls}-rtl & {\n        margin-right: 0;\n        margin-left: @margin-sm;\n      }\n    }\n\n    .@{ant-prefix}-avatar {\n      .@{pageheader-prefix-cls}-rtl & {\n        margin-right: 0;\n        margin-left: @margin-sm;\n      }\n    }\n\n    &-sub-title {\n      .@{pageheader-prefix-cls}-rtl & {\n        float: right;\n        margin-right: 0;\n        margin-left: 12px;\n      }\n    }\n\n    &-tags {\n      .@{pageheader-prefix-cls}-rtl & {\n        float: right;\n      }\n    }\n\n    &-extra {\n      .@{pageheader-prefix-cls}-rtl & {\n        float: left;\n      }\n\n      > * {\n        .@{pageheader-prefix-cls}-rtl & {\n          margin-right: @margin-sm;\n          margin-left: 0;\n        }\n      }\n\n      > *:first-child {\n        .@{pageheader-prefix-cls}-rtl & {\n          margin-right: 0;\n        }\n      }\n    }\n  }\n\n  &-footer {\n    .@{ant-prefix}-tabs-bar {\n      .@{ant-prefix}-tabs-nav {\n        .@{pageheader-prefix-cls}-rtl & {\n          float: right;\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/pagination/demo/align.md",
    "content": "---\norder: 10\nversion: 20.4.0\ntitle:\n  zh-CN: 基本\n  en-US: Align\n---\n\n## zh-CN\n\n使用 `nzAlign` 属性来设置分页器的水平对齐方式。\n\n## en-US\n\nuse `nzAlign` to align horizontally the pagination\n"
  },
  {
    "path": "components/pagination/demo/align.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzFlexModule } from 'ng-zorro-antd/flex';\nimport { NzPaginationModule } from 'ng-zorro-antd/pagination';\n\n@Component({\n  selector: 'nz-demo-pagination-align',\n  imports: [NzPaginationModule, NzFlexModule],\n  template: `\n    <div nz-flex nzVertical nzGap=\"2rem\">\n      <nz-pagination [nzPageIndex]=\"1\" [nzTotal]=\"50\" nzAlign=\"start\" />\n      <nz-pagination [nzPageIndex]=\"1\" [nzTotal]=\"50\" nzAlign=\"center\" />\n      <nz-pagination [nzPageIndex]=\"1\" [nzTotal]=\"50\" nzAlign=\"end\" />\n    </div>\n  `\n})\nexport class NzDemoPaginationAlignComponent {}\n"
  },
  {
    "path": "components/pagination/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n基础分页。\n\n## en-US\n\nBasic pagination.\n"
  },
  {
    "path": "components/pagination/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzPaginationModule } from 'ng-zorro-antd/pagination';\n\n@Component({\n  selector: 'nz-demo-pagination-basic',\n  imports: [NzPaginationModule],\n  template: `<nz-pagination [nzPageIndex]=\"1\" [nzTotal]=\"50\" />`\n})\nexport class NzDemoPaginationBasicComponent {}\n"
  },
  {
    "path": "components/pagination/demo/changer.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 改变\n  en-US: Changer\n---\n\n## zh-CN\n\n改变每页显示条目数。\n\n## en-US\n\nChange `nzPageSize`.\n"
  },
  {
    "path": "components/pagination/demo/changer.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzPaginationModule } from 'ng-zorro-antd/pagination';\n\n@Component({\n  selector: 'nz-demo-pagination-changer',\n  imports: [NzPaginationModule],\n  template: `\n    <nz-pagination [nzPageIndex]=\"3\" [nzTotal]=\"500\" nzShowSizeChanger [nzPageSize]=\"10\" />\n    <br />\n    <nz-pagination [nzPageIndex]=\"3\" [nzTotal]=\"500\" nzShowSizeChanger [nzPageSize]=\"10\" nzDisabled />\n  `\n})\nexport class NzDemoPaginationChangerComponent {}\n"
  },
  {
    "path": "components/pagination/demo/controlled.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 页码\n  en-US: Page Index\n---\n\n## zh-CN\n\n改变页码。\n\n## en-US\n\nChange page index number.\n"
  },
  {
    "path": "components/pagination/demo/controlled.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzPaginationModule } from 'ng-zorro-antd/pagination';\n\n@Component({\n  selector: 'nz-demo-pagination-controlled',\n  imports: [NzPaginationModule],\n  template: `<nz-pagination [nzPageIndex]=\"3\" [nzTotal]=\"50\" />`\n})\nexport class NzDemoPaginationControlledComponent {}\n"
  },
  {
    "path": "components/pagination/demo/item-render.md",
    "content": "---\norder: 10\ntitle:\n  zh-CN: 上一步和下一步\n  en-US: Prev and next\n---\n\n## zh-CN\n\n修改上一步和下一步为文字链接。\n\n## en-US\n\nUse text link for prev and next button.\n"
  },
  {
    "path": "components/pagination/demo/item-render.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzPaginationModule } from 'ng-zorro-antd/pagination';\n\n@Component({\n  selector: 'nz-demo-pagination-item-render',\n  imports: [NzPaginationModule],\n  template: `\n    <nz-pagination [nzPageIndex]=\"1\" [nzTotal]=\"500\" [nzItemRender]=\"renderItemTemplate\" />\n    <ng-template #renderItemTemplate let-type let-page=\"page\">\n      @switch (type) {\n        @case ('page') {\n          <a>{{ page }}</a>\n        }\n        @case ('prev') {\n          <a>Previous</a>\n        }\n        @case ('next') {\n          <a>Next</a>\n        }\n        @case ('prev_5') {\n          <a><<</a>\n        }\n        @case ('next_5') {\n          <a>>></a>\n        }\n      }\n    </ng-template>\n  `\n})\nexport class NzDemoPaginationItemRenderComponent {}\n"
  },
  {
    "path": "components/pagination/demo/jump.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 跳转\n  en-US: Jumper\n---\n\n## zh-CN\n\n快速跳转到某一页。\n\n## en-US\n\nJump to a page directly.\n"
  },
  {
    "path": "components/pagination/demo/jump.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzPaginationModule } from 'ng-zorro-antd/pagination';\n\n@Component({\n  selector: 'nz-demo-pagination-jump',\n  imports: [NzPaginationModule],\n  template: `\n    <nz-pagination [nzPageIndex]=\"2\" [nzTotal]=\"500\" nzShowQuickJumper />\n    <br />\n    <nz-pagination [nzPageIndex]=\"2\" [nzTotal]=\"500\" nzShowQuickJumper nzDisabled />\n  `\n})\nexport class NzDemoPaginationJumpComponent {}\n"
  },
  {
    "path": "components/pagination/demo/mini.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 迷你\n  en-US: Mini size\n---\n\n## zh-CN\n\n迷你版本。\n\n## en-US\n\nMini size pagination.\n"
  },
  {
    "path": "components/pagination/demo/mini.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzPaginationModule } from 'ng-zorro-antd/pagination';\n\n@Component({\n  selector: 'nz-demo-pagination-mini',\n  imports: [NzPaginationModule],\n  template: `\n    <nz-pagination [(nzPageIndex)]=\"current\" [nzTotal]=\"50\" nzSize=\"small\" />\n    <br />\n    <nz-pagination [(nzPageIndex)]=\"current\" [nzTotal]=\"50\" nzSize=\"small\" nzShowSizeChanger nzShowQuickJumper />\n    <br />\n    <nz-pagination [(nzPageIndex)]=\"current\" [nzTotal]=\"50\" nzSize=\"small\" [nzShowTotal]=\"totalTemplate\" />\n    <ng-template #totalTemplate let-total>Total {{ total }} items</ng-template>\n  `\n})\nexport class NzDemoPaginationMiniComponent {\n  current = 1;\n}\n"
  },
  {
    "path": "components/pagination/demo/more.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 更多\n  en-US: More\n---\n\n## zh-CN\n\n更多分页。\n\n## en-US\n\nMore pages.\n"
  },
  {
    "path": "components/pagination/demo/more.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzPaginationModule } from 'ng-zorro-antd/pagination';\n\n@Component({\n  selector: 'nz-demo-pagination-more',\n  imports: [NzPaginationModule],\n  template: `<nz-pagination [nzPageIndex]=\"1\" [nzTotal]=\"500\" />`\n})\nexport class NzDemoPaginationMoreComponent {}\n"
  },
  {
    "path": "components/pagination/demo/simple.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 简洁\n  en-US: Simple mode\n---\n\n## zh-CN\n\n简单的翻页。\n\n## en-US\n\nSimple mode.\n"
  },
  {
    "path": "components/pagination/demo/simple.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzPaginationModule } from 'ng-zorro-antd/pagination';\n\n@Component({\n  selector: 'nz-demo-pagination-simple',\n  imports: [NzPaginationModule],\n  template: `<nz-pagination [nzPageIndex]=\"2\" [nzTotal]=\"50\" nzSimple />`\n})\nexport class NzDemoPaginationSimpleComponent {}\n"
  },
  {
    "path": "components/pagination/demo/total.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 总数\n  en-US: Total number\n---\n\n## zh-CN\n\n通过设置 `nzShowTotal` 展示总共有多少数据。\n\n## en-US\n\nYou can show the total number of data by setting `nzShowTotal`.\n"
  },
  {
    "path": "components/pagination/demo/total.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzPaginationModule } from 'ng-zorro-antd/pagination';\n\n@Component({\n  selector: 'nz-demo-pagination-total',\n  imports: [NzPaginationModule],\n  template: `\n    <nz-pagination [nzPageIndex]=\"1\" [nzTotal]=\"85\" [nzPageSize]=\"20\" [nzShowTotal]=\"totalTemplate\" />\n    <br />\n    <nz-pagination [nzPageIndex]=\"1\" [nzTotal]=\"85\" [nzPageSize]=\"20\" [nzShowTotal]=\"rangeTemplate\" />\n    <ng-template #totalTemplate let-total>Total {{ total }} items</ng-template>\n    <ng-template #rangeTemplate let-range=\"range\" let-total>\n      {{ range[0] }}-{{ range[1] }} of {{ total }} items\n    </ng-template>\n  `\n})\nexport class NzDemoPaginationTotalComponent {}\n"
  },
  {
    "path": "components/pagination/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Navigation\ntitle: Pagination\ncols: 1\ncover: 'https://gw.alipayobjects.com/zos/alicdn/1vqv2bj68/Pagination.svg'\ndescription: A long list can be divided into several pages by `Pagination`, and only one page will be loaded at a time.\n---\n\n## When To Use\n\n- When it will take a long time to load/render all items.\n- If you want to browse the data by navigating through pages.\n\n## API\n\n```html\n<nz-pagination [nzPageIndex]=\"1\" [nzTotal]=\"50\"></nz-pagination>\n```\n\n### nz-pagination\n\n| Property               | Description                                                    | Type                                                                                         | Default            | Global Config | Version |\n| ---------------------- | -------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | ------------------ | ------------- | ------- |\n| `[nzTotal]`            | total number of data items                                     | `number`                                                                                     | `0`                | -             |\n| `[nzPageIndex]`        | current page number，double binding                            | `number`                                                                                     | `1`                | -             |\n| `[nzPageSize]`         | number of data items per page, double binding                  | `number`                                                                                     | `10`               | -             |\n| `[nzDisabled]`         | disable pagination                                             | `boolean`                                                                                    | `false`            | -             |\n| `[nzShowQuickJumper]`  | determine whether you can jump to pages directly               | `boolean`                                                                                    | `false`            | ✅            |\n| `[nzShowSizeChanger]`  | determine whether `nzPageSize` can be changed                  | `boolean`                                                                                    | `false`            | ✅            |\n| `[nzSimple]`           | whether to use simple mode                                     | `boolean`                                                                                    | -                  | ✅            |\n| `[nzSize]`             | specify the size of `nz-pagination`                            | `'small' \\| 'default'`                                                                       | `'default'`        | ✅            |\n| `[nzResponsive]`       | `Pagination` would resize according to the width of the window | `boolean`                                                                                    | `false`            | -             |\n| `[nzPageSizeOptions]`  | specify the sizeChanger options                                | `number[]`                                                                                   | `[10, 20, 30, 40]` | ✅            |\n| `[nzItemRender]`       | to customize item                                              | `TemplateRef<{ $implicit: 'page' \\| 'prev' \\| 'next'\\| 'prev_5'\\| 'next_5', page: number }>` | -                  | -             |\n| `[nzShowTotal]`        | to display the total number and range                          | `TemplateRef<{ $implicit: number, range: [ number, number ] }>`                              | -                  | -             |\n| `[nzHideOnSinglePage]` | Whether to hide pager on single page                           | `boolean`                                                                                    | `false`            | -             |\n| `[nzAlign]`            | Align                                                          | `NzPaginationAlign`                                                                          | `start`            | -             | 20.4.0  |\n| `(nzPageIndexChange)`  | current page number change callback                            | `EventEmitter<number>`                                                                       | -                  | -             |\n| `(nzPageSizeChange)`   | number of data items per page change callback                  | `EventEmitter<number>`                                                                       | -                  | -             |\n"
  },
  {
    "path": "components/pagination/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 分页\ntype: 导航\ntitle: Pagination\ncols: 1\ncover: 'https://gw.alipayobjects.com/zos/alicdn/1vqv2bj68/Pagination.svg'\ndescription: 分页器用于分隔长列表，每次只加载一个页面。\n---\n\n## 何时使用\n\n- 当加载/渲染所有数据将花费很多时间时；\n- 可切换页码浏览数据。\n\n## API\n\n```html\n<nz-pagination [nzPageIndex]=\"1\" [nzTotal]=\"50\"></nz-pagination>\n```\n\n### nz-pagination\n\n| 参数                   | 说明                                                       | 类型                                                                                         | 默认值             | 全局配置 | 版本   |\n| ---------------------- | ---------------------------------------------------------- | -------------------------------------------------------------------------------------------- | ------------------ | -------- | ------ |\n| `[nzTotal]`            | 数据总数                                                   | `number`                                                                                     | -                  | -        |\n| `[nzPageIndex]`        | 当前页数，可双向绑定                                       | `number`                                                                                     | `1`                | -        |\n| `[nzPageSize]`         | 每页条数，可双向绑定                                       | `number`                                                                                     | `10`               | -        |\n| `[nzDisabled]`         | 是否禁用                                                   | `boolean`                                                                                    | `false`            | -        |\n| `[nzShowQuickJumper]`  | 是否可以快速跳转至某页                                     | `boolean`                                                                                    | `false`            | ✅       |\n| `[nzShowSizeChanger]`  | 是否可以改变 `nzPageSize`                                  | `boolean`                                                                                    | `false`            | ✅       |\n| `[nzSimple]`           | 当添加该属性时，显示为简单分页                             | `boolean`                                                                                    | -                  | ✅       |\n| `[nzSize]`             | 当为`'small'` 时，是小尺寸分页                             | `'small' \\| 'default'`                                                                       | `'default'`        | ✅       |\n| `[nzResponsive]`       | 当 `nzSize` 未指定时，根据屏幕宽度自动调整尺寸             | `boolean`                                                                                    | `false`            | -        |\n| `[nzPageSizeOptions]`  | 指定每页可以显示多少条                                     | `number[]`                                                                                   | `[10, 20, 30, 40]` | ✅       |\n| `[nzItemRender]`       | 用于自定义页码的结构                                       | `TemplateRef<{ $implicit: 'page' \\| 'prev' \\| 'next'\\| 'prev_5'\\| 'next_5', page: number }>` | -                  | -        |\n| `[nzShowTotal]`        | 用于显示数据总量和当前数据范围，具体使用方式见代码演示部分 | `TemplateRef<{ $implicit: number, range: [ number, number ] }>`                              | -                  | -        |\n| `[nzHideOnSinglePage]` | 只有一页时是否隐藏分页器                                   | `boolean`                                                                                    | `false`            | -        |\n| `[nzAlign]`            | 对齐方式                                                   | `NzPaginationAlign`                                                                          | `start`            | -        | 20.4.0 |\n| `(nzPageIndexChange)`  | 页码改变的回调                                             | `EventEmitter<number>`                                                                       | -                  | -        |\n| `(nzPageSizeChange)`   | 每页条数改变的回调                                         | `EventEmitter<number>`                                                                       | -                  | -        |\n"
  },
  {
    "path": "components/pagination/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/pagination/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/pagination/pagination-default.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DestroyRef,\n  ElementRef,\n  EventEmitter,\n  inject,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  Renderer2,\n  SimpleChanges,\n  TemplateRef,\n  ViewChild,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { NzPaginationI18nInterface } from 'ng-zorro-antd/i18n';\n\nimport { NzPaginationItemComponent } from './pagination-item.component';\nimport { NzPaginationOptionsComponent } from './pagination-options.component';\nimport { PaginationItemRenderContext } from './pagination.types';\n\n@Component({\n  selector: 'nz-pagination-default',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    <ng-template #containerTemplate>\n      <ul>\n        @if (showTotal) {\n          <li class=\"ant-pagination-total-text\">\n            <ng-template\n              [ngTemplateOutlet]=\"showTotal\"\n              [ngTemplateOutletContext]=\"{ $implicit: total, range: ranges }\"\n            />\n          </li>\n        }\n\n        @for (page of listOfPageItem; track trackByPageItem($index, page)) {\n          <li\n            nz-pagination-item\n            [locale]=\"locale\"\n            [type]=\"page.type\"\n            [index]=\"page.index\"\n            [disabled]=\"!!page.disabled\"\n            [itemRender]=\"itemRender\"\n            [active]=\"pageIndex === page.index\"\n            (gotoIndex)=\"jumpPage($event)\"\n            (diffIndex)=\"jumpDiff($event)\"\n            [direction]=\"dir\"\n          ></li>\n        }\n\n        @if (showQuickJumper || showSizeChanger) {\n          <li\n            nz-pagination-options\n            [total]=\"total\"\n            [locale]=\"locale\"\n            [disabled]=\"disabled\"\n            [nzSize]=\"nzSize\"\n            [showSizeChanger]=\"showSizeChanger\"\n            [showQuickJumper]=\"showQuickJumper\"\n            [pageIndex]=\"pageIndex\"\n            [pageSize]=\"pageSize\"\n            [pageSizeOptions]=\"pageSizeOptions\"\n            (pageIndexChange)=\"onPageIndexChange($event)\"\n            (pageSizeChange)=\"onPageSizeChange($event)\"\n          ></li>\n        }\n      </ul>\n    </ng-template>\n  `,\n  imports: [NgTemplateOutlet, NzPaginationItemComponent, NzPaginationOptionsComponent],\n  host: {\n    '[class.ant-pagination-rtl]': \"dir === 'rtl'\"\n  }\n})\nexport class NzPaginationDefaultComponent implements OnChanges, OnInit {\n  private readonly cdr = inject(ChangeDetectorRef);\n  private readonly directionality = inject(Directionality);\n  private readonly destroyRef = inject(DestroyRef);\n\n  @ViewChild('containerTemplate', { static: true }) template!: TemplateRef<NzSafeAny>;\n  @Input() nzSize: 'default' | 'small' = 'default';\n  @Input() itemRender: TemplateRef<PaginationItemRenderContext> | null = null;\n  @Input() showTotal: TemplateRef<{ $implicit: number; range: [number, number] }> | null = null;\n  @Input() disabled = false;\n  @Input() locale!: NzPaginationI18nInterface;\n  @Input() showSizeChanger = false;\n  @Input() showQuickJumper = false;\n  @Input() total = 0;\n  @Input() pageIndex = 1;\n  @Input() pageSize = 10;\n  @Input() pageSizeOptions: number[] = [10, 20, 30, 40];\n  @Output() readonly pageIndexChange = new EventEmitter<number>();\n  @Output() readonly pageSizeChange = new EventEmitter<number>();\n  ranges = [0, 0];\n  listOfPageItem: Array<Partial<NzPaginationItemComponent>> = [];\n\n  dir: Direction = 'ltr';\n\n  constructor() {\n    const el: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement;\n    const renderer = inject(Renderer2);\n    renderer.removeChild(renderer.parentNode(el), el);\n  }\n\n  ngOnInit(): void {\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n      this.dir = direction;\n      this.cdr.detectChanges();\n    });\n    this.dir = this.directionality.value;\n  }\n\n  jumpPage(index: number): void {\n    this.onPageIndexChange(index);\n  }\n\n  jumpDiff(diff: number): void {\n    this.jumpPage(this.pageIndex + diff);\n  }\n\n  trackByPageItem(_: number, value: Partial<NzPaginationItemComponent>): string {\n    return `${value.type}-${value.index}`;\n  }\n\n  onPageIndexChange(index: number): void {\n    this.pageIndexChange.next(index);\n  }\n\n  onPageSizeChange(size: number): void {\n    this.pageSizeChange.next(size);\n  }\n\n  getLastIndex(total: number, pageSize: number): number {\n    return Math.ceil(total / pageSize);\n  }\n\n  buildIndexes(): void {\n    const lastIndex = this.getLastIndex(this.total, this.pageSize);\n    this.listOfPageItem = this.getListOfPageItem(this.pageIndex, lastIndex);\n  }\n\n  getListOfPageItem(pageIndex: number, lastIndex: number): Array<Partial<NzPaginationItemComponent>> {\n    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n    const concatWithPrevNext = (listOfPage: Array<Partial<NzPaginationItemComponent>>) => {\n      const prevItem = {\n        type: 'prev',\n        disabled: pageIndex === 1\n      };\n      const nextItem = {\n        type: 'next',\n        disabled: pageIndex === lastIndex\n      };\n      return [prevItem, ...listOfPage, nextItem];\n    };\n    const generatePage = (start: number, end: number): Array<Partial<NzPaginationItemComponent>> => {\n      const list = [];\n      for (let i = start; i <= end; i++) {\n        list.push({ index: i, type: 'page' });\n      }\n      return list;\n    };\n    if (lastIndex <= 9) {\n      return concatWithPrevNext(generatePage(1, lastIndex));\n    } else {\n      // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n      const generateRangeItem = (selected: number, last: number) => {\n        let listOfRange = [];\n        const prevFiveItem = {\n          type: 'prev_5'\n        };\n        const nextFiveItem = {\n          type: 'next_5'\n        };\n        const firstPageItem = generatePage(1, 1);\n        const lastPageItem = generatePage(lastIndex, lastIndex);\n        if (selected < 5) {\n          // If the 4th is selected, one more page will be displayed.\n          const maxLeft = selected === 4 ? 6 : 5;\n          listOfRange = [...generatePage(2, maxLeft), nextFiveItem];\n        } else if (selected < last - 3) {\n          listOfRange = [prevFiveItem, ...generatePage(selected - 2, selected + 2), nextFiveItem];\n        } else {\n          // If the 4th from last is selected, one more page will be displayed.\n          const minRight = selected === last - 3 ? last - 5 : last - 4;\n          listOfRange = [prevFiveItem, ...generatePage(minRight, last - 1)];\n        }\n        return [...firstPageItem, ...listOfRange, ...lastPageItem];\n      };\n      return concatWithPrevNext(generateRangeItem(pageIndex, lastIndex));\n    }\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { pageIndex, pageSize, total } = changes;\n    if (pageIndex || pageSize || total) {\n      this.ranges = [(this.pageIndex - 1) * this.pageSize + 1, Math.min(this.pageIndex * this.pageSize, this.total)];\n      this.buildIndexes();\n    }\n  }\n}\n"
  },
  {
    "path": "components/pagination/pagination-item.component.ts",
    "content": "/* eslint-disable */\n/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  EventEmitter,\n  Input,\n  OnChanges,\n  Output,\n  SimpleChanges,\n  TemplateRef,\n  ViewEncapsulation\n} from '@angular/core';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { NzPaginationI18nInterface } from 'ng-zorro-antd/i18n';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { PaginationItemRenderContext, PaginationItemType } from './pagination.types';\n\n@Component({\n  selector: 'li[nz-pagination-item]',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    <ng-template #renderItemTemplate let-type let-page=\"page\">\n      @switch (type) {\n        @case ('page') {\n          <a>{{ page }}</a>\n        }\n        @case ('prev') {\n          <button type=\"button\" [disabled]=\"disabled\" [attr.title]=\"locale.prev_page\" class=\"ant-pagination-item-link\">\n            @if (direction === 'rtl') {\n              <nz-icon nzType=\"right\" />\n            } @else {\n              <nz-icon nzType=\"left\" />\n            }\n          </button>\n        }\n        @case ('next') {\n          <button type=\"button\" [disabled]=\"disabled\" [attr.title]=\"locale.next_page\" class=\"ant-pagination-item-link\">\n            @if (direction === 'rtl') {\n              <nz-icon nzType=\"left\" />\n            } @else {\n              <nz-icon nzType=\"right\" />\n            }\n          </button>\n        }\n        @default {\n          <a class=\"ant-pagination-item-link\">\n            <div class=\"ant-pagination-item-container\">\n              @switch (type) {\n                @case ('prev_5') {\n                  @if (direction === 'rtl') {\n                    <nz-icon nzType=\"double-right\" class=\"ant-pagination-item-link-icon\" />\n                  } @else {\n                    <nz-icon nzType=\"double-left\" class=\"ant-pagination-item-link-icon\" />\n                  }\n                }\n                @case ('next_5') {\n                  @if (direction === 'rtl') {\n                    <nz-icon nzType=\"double-left\" class=\"ant-pagination-item-link-icon\" />\n                  } @else {\n                    <nz-icon nzType=\"double-right\" class=\"ant-pagination-item-link-icon\" />\n                  }\n                }\n              }\n              <span class=\"ant-pagination-item-ellipsis\">•••</span>\n            </div>\n          </a>\n        }\n      }\n    </ng-template>\n    <ng-template\n      [ngTemplateOutlet]=\"itemRender || renderItemTemplate\"\n      [ngTemplateOutletContext]=\"{ $implicit: type, page: index }\"\n    />\n  `,\n  host: {\n    '[class.ant-pagination-prev]': `type === 'prev'`,\n    '[class.ant-pagination-next]': `type === 'next'`,\n    '[class.ant-pagination-item]': `type === 'page'`,\n    '[class.ant-pagination-jump-prev]': `type === 'prev_5'`,\n    '[class.ant-pagination-jump-prev-custom-icon]': `type === 'prev_5'`,\n    '[class.ant-pagination-jump-next]': `type === 'next_5'`,\n    '[class.ant-pagination-jump-next-custom-icon]': `type === 'next_5'`,\n    '[class.ant-pagination-disabled]': 'disabled',\n    '[class.ant-pagination-item-active]': 'active',\n    '[attr.title]': 'title',\n    '(click)': 'clickItem()'\n  },\n  imports: [NzIconModule, NgTemplateOutlet]\n})\nexport class NzPaginationItemComponent implements OnChanges {\n  @Input() active = false;\n  @Input() locale!: NzPaginationI18nInterface;\n  @Input() index: number | null | undefined = null;\n  @Input() disabled = false;\n  @Input() direction = 'ltr';\n  @Input() type: PaginationItemType | string | null | undefined = null;\n  @Input() itemRender: TemplateRef<PaginationItemRenderContext> | null = null;\n  @Output() readonly diffIndex = new EventEmitter<number>();\n  @Output() readonly gotoIndex = new EventEmitter<number>();\n  title: string | null = null;\n\n  clickItem(): void {\n    if (!this.disabled) {\n      if (this.type === 'page') {\n        this.gotoIndex.emit(this.index!);\n      } else {\n        this.diffIndex.emit(\n          (\n            {\n              next: 1,\n              prev: -1,\n              prev_5: -5,\n              next_5: 5\n            } as NzSafeAny\n          )[this.type!]\n        );\n      }\n    }\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { locale, index, type } = changes;\n    if (locale || index || type) {\n      this.title = (\n        {\n          page: `${this.index}`,\n          next: this.locale?.next_page,\n          prev: this.locale?.prev_page,\n          prev_5: this.locale?.prev_5,\n          next_5: this.locale?.next_5\n        } as NzSafeAny\n      )[this.type!];\n    }\n  }\n}\n"
  },
  {
    "path": "components/pagination/pagination-options.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  EventEmitter,\n  Input,\n  OnChanges,\n  Output,\n  SimpleChanges,\n  ViewEncapsulation\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { toNumber } from 'ng-zorro-antd/core/util';\nimport { NzPaginationI18nInterface } from 'ng-zorro-antd/i18n';\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\n@Component({\n  selector: 'li[nz-pagination-options]',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    @if (showSizeChanger) {\n      <nz-select\n        class=\"ant-pagination-options-size-changer\"\n        [nzDisabled]=\"disabled\"\n        [nzSize]=\"nzSize\"\n        [ngModel]=\"pageSize\"\n        (ngModelChange)=\"onPageSizeChange($event)\"\n      >\n        @for (option of listOfPageSizeOption; track option.value) {\n          <nz-option [nzLabel]=\"option.label\" [nzValue]=\"option.value\" />\n        }\n      </nz-select>\n    }\n\n    @if (showQuickJumper) {\n      <div class=\"ant-pagination-options-quick-jumper\">\n        {{ locale.jump_to }}\n        <input [disabled]=\"disabled\" (keydown.enter)=\"jumpToPageViaInput($event)\" />\n        {{ locale.page }}\n      </div>\n    }\n  `,\n  host: { class: 'ant-pagination-options' },\n  imports: [NzSelectModule, FormsModule]\n})\nexport class NzPaginationOptionsComponent implements OnChanges {\n  @Input() nzSize: 'default' | 'small' = 'default';\n  @Input() disabled = false;\n  @Input() showSizeChanger = false;\n  @Input() showQuickJumper = false;\n  @Input() locale!: NzPaginationI18nInterface;\n  @Input() total = 0;\n  @Input() pageIndex = 1;\n  @Input() pageSize = 10;\n  @Input() pageSizeOptions: number[] = [];\n  @Output() readonly pageIndexChange = new EventEmitter<number>();\n  @Output() readonly pageSizeChange = new EventEmitter<number>();\n  listOfPageSizeOption: Array<{ value: number; label: string }> = [];\n\n  onPageSizeChange(size: number): void {\n    if (this.pageSize !== size) {\n      this.pageSizeChange.next(size);\n    }\n  }\n\n  jumpToPageViaInput($event: Event): void {\n    const target = $event.target as HTMLInputElement;\n    const index = Math.floor(toNumber(target.value, this.pageIndex));\n    this.pageIndexChange.next(index);\n    target.value = '';\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { pageSize, pageSizeOptions, locale } = changes;\n    if (pageSize || pageSizeOptions || locale) {\n      this.listOfPageSizeOption = [...new Set([...this.pageSizeOptions, this.pageSize])].map(item => ({\n        value: item,\n        label: `${item} ${this.locale.items_per_page}`\n      }));\n    }\n  }\n}\n"
  },
  {
    "path": "components/pagination/pagination-simple.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DestroyRef,\n  ElementRef,\n  EventEmitter,\n  inject,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  Renderer2,\n  SimpleChanges,\n  TemplateRef,\n  ViewChild,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { toNumber } from 'ng-zorro-antd/core/util';\nimport { NzPaginationI18nInterface } from 'ng-zorro-antd/i18n';\n\nimport { NzPaginationItemComponent } from './pagination-item.component';\nimport { PaginationItemRenderContext } from './pagination.types';\n\n@Component({\n  selector: 'nz-pagination-simple',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    <ng-template #containerTemplate>\n      <ul>\n        <li\n          nz-pagination-item\n          [locale]=\"locale\"\n          [attr.title]=\"locale.prev_page\"\n          [disabled]=\"isFirstIndex\"\n          [direction]=\"dir\"\n          (click)=\"prePage()\"\n          type=\"prev\"\n          [itemRender]=\"itemRender\"\n        ></li>\n        <li [attr.title]=\"pageIndex + '/' + lastIndex\" class=\"ant-pagination-simple-pager\">\n          <input [disabled]=\"disabled\" [value]=\"pageIndex\" (keydown.enter)=\"jumpToPageViaInput($event)\" size=\"3\" />\n          <span class=\"ant-pagination-slash\">/</span>\n          {{ lastIndex }}\n        </li>\n        <li\n          nz-pagination-item\n          [locale]=\"locale\"\n          [attr.title]=\"locale?.next_page\"\n          [disabled]=\"isLastIndex\"\n          [direction]=\"dir\"\n          (click)=\"nextPage()\"\n          type=\"next\"\n          [itemRender]=\"itemRender\"\n        ></li>\n      </ul>\n    </ng-template>\n  `,\n  imports: [NzPaginationItemComponent],\n  host: {\n    '[class.ant-pagination-rtl]': \"dir === 'rtl'\"\n  }\n})\nexport class NzPaginationSimpleComponent implements OnChanges, OnInit {\n  private readonly cdr = inject(ChangeDetectorRef);\n  private readonly directionality = inject(Directionality);\n  private readonly destroyRef = inject(DestroyRef);\n\n  @ViewChild('containerTemplate', { static: true }) template!: TemplateRef<NzSafeAny>;\n  @Input() itemRender: TemplateRef<PaginationItemRenderContext> | null = null;\n  @Input() disabled = false;\n  @Input() locale!: NzPaginationI18nInterface;\n  @Input() total = 0;\n  @Input() pageIndex = 1;\n  @Input() pageSize = 10;\n  @Output() readonly pageIndexChange = new EventEmitter<number>();\n  lastIndex = 0;\n  isFirstIndex = false;\n  isLastIndex = false;\n\n  dir: Direction = 'ltr';\n\n  constructor() {\n    const el: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement;\n    const renderer = inject(Renderer2);\n    renderer.removeChild(renderer.parentNode(el), el);\n  }\n\n  ngOnInit(): void {\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n      this.dir = direction;\n      this.cdr.detectChanges();\n    });\n    this.dir = this.directionality.value;\n  }\n\n  jumpToPageViaInput($event: Event): void {\n    const target = $event.target as HTMLInputElement;\n    const index = toNumber(target.value, this.pageIndex);\n    this.onPageIndexChange(index);\n    target.value = `${this.pageIndex}`;\n  }\n\n  prePage(): void {\n    this.onPageIndexChange(this.pageIndex - 1);\n  }\n\n  nextPage(): void {\n    this.onPageIndexChange(this.pageIndex + 1);\n  }\n\n  onPageIndexChange(index: number): void {\n    this.pageIndexChange.next(index);\n  }\n\n  updateBindingValue(): void {\n    this.lastIndex = Math.ceil(this.total / this.pageSize);\n    this.isFirstIndex = this.pageIndex === 1;\n    this.isLastIndex = this.pageIndex === this.lastIndex;\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { pageIndex, total, pageSize } = changes;\n    if (pageIndex || total || pageSize) {\n      this.updateBindingValue();\n    }\n  }\n}\n"
  },
  {
    "path": "components/pagination/pagination.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DestroyRef,\n  EventEmitter,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  SimpleChanges,\n  TemplateRef,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject,\n  input,\n  numberAttribute\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ReplaySubject } from 'rxjs';\n\nimport { NzConfigKey, NzConfigService, WithConfig } from 'ng-zorro-antd/core/config';\nimport { NzBreakpointEnum, NzBreakpointService, gridResponsiveMap } from 'ng-zorro-antd/core/services';\nimport { NzI18nService, NzPaginationI18nInterface } from 'ng-zorro-antd/i18n';\n\nimport { NzPaginationDefaultComponent } from './pagination-default.component';\nimport { NzPaginationSimpleComponent } from './pagination-simple.component';\nimport { PaginationItemRenderContext, type NzPaginationAlign } from './pagination.types';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'pagination';\n\n@Component({\n  selector: 'nz-pagination',\n  exportAs: 'nzPagination',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    @if (showPagination) {\n      @if (nzSimple) {\n        <ng-template [ngTemplateOutlet]=\"simplePagination.template\" />\n      } @else {\n        <ng-template [ngTemplateOutlet]=\"defaultPagination.template\" />\n      }\n    }\n\n    <nz-pagination-simple\n      #simplePagination\n      [disabled]=\"nzDisabled\"\n      [itemRender]=\"nzItemRender\"\n      [locale]=\"locale\"\n      [pageSize]=\"nzPageSize\"\n      [total]=\"nzTotal\"\n      [pageIndex]=\"nzPageIndex\"\n      (pageIndexChange)=\"onPageIndexChange($event)\"\n    />\n    <nz-pagination-default\n      #defaultPagination\n      [nzSize]=\"size\"\n      [itemRender]=\"nzItemRender\"\n      [showTotal]=\"nzShowTotal\"\n      [disabled]=\"nzDisabled\"\n      [locale]=\"locale\"\n      [showSizeChanger]=\"nzShowSizeChanger\"\n      [showQuickJumper]=\"nzShowQuickJumper\"\n      [total]=\"nzTotal\"\n      [pageIndex]=\"nzPageIndex\"\n      [pageSize]=\"nzPageSize\"\n      [pageSizeOptions]=\"nzPageSizeOptions\"\n      (pageIndexChange)=\"onPageIndexChange($event)\"\n      (pageSizeChange)=\"onPageSizeChange($event)\"\n    />\n  `,\n  host: {\n    class: 'ant-pagination',\n    '[class.ant-pagination-simple]': 'nzSimple',\n    '[class.ant-pagination-disabled]': 'nzDisabled',\n    '[class.ant-pagination-mini]': `!nzSimple && size === 'small'`,\n    '[class.ant-pagination-rtl]': `dir === 'rtl'`,\n    '[class.ant-pagination-start]': 'nzAlign() === \"start\"',\n    '[class.ant-pagination-center]': 'nzAlign() === \"center\"',\n    '[class.ant-pagination-end]': 'nzAlign() === \"end\"'\n  },\n  imports: [NgTemplateOutlet, NzPaginationSimpleComponent, NzPaginationDefaultComponent]\n})\nexport class NzPaginationComponent implements OnInit, OnChanges {\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  private readonly i18n = inject(NzI18nService);\n  private readonly cdr = inject(ChangeDetectorRef);\n  private readonly breakpointService = inject(NzBreakpointService);\n  protected readonly nzConfigService = inject(NzConfigService);\n  private readonly directionality = inject(Directionality);\n  private readonly destroyRef = inject(DestroyRef);\n\n  @Output() readonly nzPageSizeChange = new EventEmitter<number>();\n  @Output() readonly nzPageIndexChange = new EventEmitter<number>();\n  @Input() nzShowTotal: TemplateRef<{ $implicit: number; range: [number, number] }> | null = null;\n  @Input() nzItemRender: TemplateRef<PaginationItemRenderContext> | null = null;\n  @Input() @WithConfig() nzSize: 'default' | 'small' = 'default';\n  @Input() @WithConfig() nzPageSizeOptions: number[] = [10, 20, 30, 40];\n  @Input({ transform: booleanAttribute }) @WithConfig() nzShowSizeChanger = false;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzShowQuickJumper = false;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzSimple = false;\n  @Input({ transform: booleanAttribute }) nzDisabled = false;\n  @Input({ transform: booleanAttribute }) nzResponsive = false;\n  @Input({ transform: booleanAttribute }) nzHideOnSinglePage = false;\n  @Input({ transform: numberAttribute }) nzTotal = 0;\n  @Input({ transform: numberAttribute }) nzPageIndex = 1;\n  @Input({ transform: numberAttribute }) nzPageSize = 10;\n  readonly nzAlign = input<NzPaginationAlign>('start');\n\n  showPagination = true;\n  locale!: NzPaginationI18nInterface;\n  size: 'default' | 'small' = 'default';\n  dir: Direction = 'ltr';\n\n  private total$ = new ReplaySubject<number>(1);\n\n  validatePageIndex(value: number, lastIndex: number): number {\n    if (value > lastIndex) {\n      return lastIndex;\n    } else if (value < 1) {\n      return 1;\n    } else {\n      return value;\n    }\n  }\n\n  onPageIndexChange(index: number): void {\n    const lastIndex = this.getLastIndex(this.nzTotal, this.nzPageSize);\n    const validIndex = this.validatePageIndex(index, lastIndex);\n    if (validIndex !== this.nzPageIndex && !this.nzDisabled) {\n      this.nzPageIndex = validIndex;\n      this.nzPageIndexChange.emit(this.nzPageIndex);\n    }\n  }\n\n  onPageSizeChange(size: number): void {\n    this.nzPageSize = size;\n    this.nzPageSizeChange.emit(size);\n    const lastIndex = this.getLastIndex(this.nzTotal, this.nzPageSize);\n    if (this.nzPageIndex > lastIndex) {\n      this.onPageIndexChange(lastIndex);\n    }\n  }\n\n  onTotalChange(total: number): void {\n    const lastIndex = this.getLastIndex(total, this.nzPageSize);\n    if (this.nzPageIndex > lastIndex) {\n      Promise.resolve().then(() => {\n        this.onPageIndexChange(lastIndex);\n        this.cdr.markForCheck();\n      });\n    }\n  }\n\n  getLastIndex(total: number, pageSize: number): number {\n    return Math.ceil(total / pageSize);\n  }\n\n  ngOnInit(): void {\n    this.i18n.localeChange.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      this.locale = this.i18n.getLocaleData('Pagination');\n      this.cdr.markForCheck();\n    });\n\n    this.total$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(total => {\n      this.onTotalChange(total);\n    });\n\n    this.breakpointService\n      .subscribe(gridResponsiveMap)\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(bp => {\n        if (this.nzResponsive) {\n          this.size = bp === NzBreakpointEnum.xs ? 'small' : 'default';\n          this.cdr.markForCheck();\n        }\n      });\n\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n      this.dir = direction;\n      this.cdr.detectChanges();\n    });\n    this.dir = this.directionality.value;\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzHideOnSinglePage, nzTotal, nzPageSize, nzSize } = changes;\n    if (nzTotal) {\n      this.total$.next(this.nzTotal);\n    }\n    if (nzHideOnSinglePage || nzTotal || nzPageSize) {\n      this.showPagination =\n        (this.nzHideOnSinglePage && this.nzTotal > this.nzPageSize) || (this.nzTotal > 0 && !this.nzHideOnSinglePage);\n    }\n\n    if (nzSize) {\n      this.size = nzSize.currentValue;\n    }\n  }\n}\n"
  },
  {
    "path": "components/pagination/pagination.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzPaginationDefaultComponent } from './pagination-default.component';\nimport { NzPaginationItemComponent } from './pagination-item.component';\nimport { NzPaginationOptionsComponent } from './pagination-options.component';\nimport { NzPaginationSimpleComponent } from './pagination-simple.component';\nimport { NzPaginationComponent } from './pagination.component';\n\n@NgModule({\n  imports: [\n    NzPaginationComponent,\n    NzPaginationSimpleComponent,\n    NzPaginationOptionsComponent,\n    NzPaginationItemComponent,\n    NzPaginationDefaultComponent\n  ],\n  exports: [NzPaginationComponent]\n})\nexport class NzPaginationModule {}\n"
  },
  {
    "path": "components/pagination/pagination.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport { ENTER } from '@angular/cdk/keycodes';\nimport { Component, DebugElement, provideZoneChangeDetection, signal, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { createKeyboardEvent, dispatchKeyboardEvent } from 'ng-zorro-antd/core/testing';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport en_US from 'ng-zorro-antd/i18n/languages/en_US';\nimport { NzI18nService } from 'ng-zorro-antd/i18n/nz-i18n.service';\n\nimport { NzPaginationComponent } from './pagination.component';\nimport { NzPaginationModule } from './pagination.module';\nimport type { NzPaginationAlign } from './pagination.types';\n\ndeclare const viewport: NzSafeAny;\n\ndescribe('pagination', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), provideZoneChangeDetection()]\n    });\n  });\n\n  describe('pagination complex', () => {\n    let fixture: ComponentFixture<NzTestPaginationComponent>;\n    let testComponent: NzTestPaginationComponent;\n    let pagination: DebugElement;\n    let paginationElement: HTMLElement;\n    let paginationRootElement: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestPaginationComponent);\n      testComponent = fixture.debugElement.componentInstance;\n      pagination = fixture.debugElement.query(By.directive(NzPaginationComponent));\n      fixture.detectChanges();\n      paginationRootElement = pagination.nativeElement;\n      paginationElement = pagination.nativeElement.querySelector('ul')!;\n    });\n\n    describe('not simple mode', () => {\n      it('should className correct', () => {\n        fixture.detectChanges();\n        expect(paginationRootElement.classList.contains('ant-pagination')).toBe(true);\n        expect(paginationElement.firstElementChild!.classList.contains('ant-pagination-prev')).toBe(true);\n        expect(paginationElement.firstElementChild!.classList.contains('ant-pagination-disabled')).toBe(true);\n        expect(paginationElement.lastElementChild!.classList.contains('ant-pagination-next')).toBe(true);\n        const length = paginationElement.children.length;\n        const array = Array.prototype.slice.call(paginationElement.children).slice(1, length - 1);\n        expect(array[0].classList.contains('ant-pagination-item-active')).toBe(true);\n        expect(array.every((node: HTMLElement) => node.classList.contains('ant-pagination-item'))).toBe(true);\n      });\n\n      it('should small size className correct', () => {\n        testComponent.size = 'small';\n        fixture.detectChanges();\n        expect(paginationRootElement.classList.contains('ant-pagination-mini')).toBe(true);\n      });\n\n      it('should pageIndex change work', () => {\n        testComponent.pageIndex = 2;\n        fixture.detectChanges();\n        expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(0);\n        const length = paginationElement.children.length;\n        const array = Array.prototype.slice.call(paginationElement.children).slice(1, length - 1);\n        expect(array[1].classList.contains('ant-pagination-item-active')).toBe(true);\n      });\n\n      it('should pageIndex change not trigger when same', () => {\n        fixture.detectChanges();\n        expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(0);\n        const length = paginationElement.children.length;\n        const array = Array.prototype.slice.call(paginationElement.children).slice(1, length - 1);\n        expect(array[0].classList.contains('ant-pagination-item-active')).toBe(true);\n        array[0].click();\n        fixture.detectChanges();\n        expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(0);\n      });\n\n      it('should change pageIndex change pages list', () => {\n        fixture.detectChanges();\n        testComponent.total = 500;\n        fixture.detectChanges();\n        expect(paginationElement.children.length).toBe(9);\n        testComponent.pageIndex = 5;\n        fixture.detectChanges();\n        expect(paginationElement.children.length).toBe(11);\n      });\n\n      it('should pre button disabled', () => {\n        fixture.detectChanges();\n        expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(0);\n        (paginationElement.children[0] as HTMLElement).click();\n        fixture.detectChanges();\n        expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(0);\n        expect(testComponent.pageIndex).toBe(1);\n      });\n\n      it('should pre button work', () => {\n        testComponent.pageIndex = 5;\n        fixture.detectChanges();\n        expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(0);\n        (paginationElement.children[0] as HTMLElement).click();\n        fixture.detectChanges();\n        expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(1);\n        expect(testComponent.pageIndex).toBe(4);\n      });\n\n      it('should next button disabled', () => {\n        testComponent.pageIndex = 5;\n        fixture.detectChanges();\n        expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(0);\n        (paginationElement.lastElementChild as HTMLElement).click();\n        fixture.detectChanges();\n        expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(0);\n        expect(testComponent.pageIndex).toBe(5);\n      });\n\n      it('should next button work', () => {\n        fixture.detectChanges();\n        expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(0);\n        (paginationElement.lastElementChild as HTMLElement).click();\n        fixture.detectChanges();\n        expect(testComponent.pageIndex).toBe(2);\n        expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(1);\n      });\n\n      it('should click pageIndex work', () => {\n        fixture.detectChanges();\n        expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(0);\n        (paginationElement.children[3] as HTMLElement).click();\n        fixture.detectChanges();\n        expect(testComponent.pageIndex).toBe(3);\n        expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(1);\n      });\n\n      it('should total change style work', () => {\n        testComponent.total = 500;\n        fixture.detectChanges();\n        expect(paginationElement.children.length).toBe(9);\n      });\n\n      it('should next five work', () => {\n        testComponent.total = 500;\n        fixture.detectChanges();\n        testComponent.pageIndex = 46;\n        fixture.detectChanges();\n        (paginationElement.children[8] as HTMLElement).click();\n        fixture.detectChanges();\n        expect(testComponent.pageIndex).toBe(50);\n        expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(1);\n        expect(paginationElement.children.length).toBe(9);\n      });\n\n      it('should pre five work', () => {\n        testComponent.total = 500;\n        fixture.detectChanges();\n        testComponent.pageIndex = 5;\n        fixture.detectChanges();\n        expect(paginationElement.children.length).toBe(11);\n        (paginationElement.children[2] as HTMLElement).click();\n        fixture.detectChanges();\n        expect(testComponent.pageIndex).toBe(1);\n        expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(1);\n        expect(paginationElement.children.length).toBe(9);\n      });\n\n      it('should showSizeChanger work', async () => {\n        testComponent.total = 500;\n        testComponent.pageIndex = 50;\n        testComponent.showSizeChanger = true;\n        fixture.detectChanges();\n        await fixture.whenStable();\n\n        expect(paginationElement.children.length).toBe(10);\n        expect(paginationElement.lastElementChild!.classList.contains('ant-pagination-options')).toBe(true);\n      });\n\n      it('should change pageSize correct', () => {\n        testComponent.pageIndex = 5;\n        fixture.detectChanges();\n        testComponent.nzPaginationComponent.onPageSizeChange(20);\n        fixture.detectChanges();\n        expect(testComponent.pageIndex).toBe(3);\n        expect(testComponent.pageSizeChange).toHaveBeenCalledTimes(1);\n      });\n\n      it('should showQuickJumper work', () => {\n        testComponent.showQuickJumper = true;\n        fixture.detectChanges();\n        const input = pagination.nativeElement.querySelector('input');\n        input.value = 5;\n        fixture.detectChanges();\n        expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(0);\n        const event = createKeyboardEvent('keydown', ENTER, input, 'enter');\n        input.dispatchEvent(event);\n        dispatchKeyboardEvent(input, 'keydown', ENTER, input);\n        fixture.detectChanges();\n        expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(1);\n        expect(testComponent.pageIndex).toBe(5);\n        expect(input.value).toBe('');\n        dispatchKeyboardEvent(input, 'keydown', ENTER, input);\n        fixture.detectChanges();\n        expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(1);\n        expect(testComponent.pageIndex).toBe(5);\n        input.value = 'abc';\n        dispatchKeyboardEvent(input, 'keydown', ENTER, input);\n        fixture.detectChanges();\n        expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(1);\n        expect(testComponent.pageIndex).toBe(5);\n        input.value = -1;\n        dispatchKeyboardEvent(input, 'keydown', ENTER, input);\n        fixture.detectChanges();\n        expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(1);\n        expect(testComponent.pageIndex).toBe(5);\n        input.value = 10;\n        dispatchKeyboardEvent(input, 'keydown', ENTER, input);\n        fixture.detectChanges();\n        expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(1);\n        expect(testComponent.pageIndex).toBe(5);\n      });\n\n      it('should nzDisabled work', () => {\n        fixture.detectChanges();\n        testComponent.disabled = true;\n        fixture.detectChanges();\n        expect(paginationRootElement.classList.contains('ant-pagination-disabled')).toBe(true);\n      });\n    });\n\n    describe('simple mode', () => {\n      beforeEach(() => {\n        testComponent.simple = true;\n        fixture.detectChanges();\n        paginationRootElement = pagination.nativeElement;\n        paginationElement = pagination.nativeElement.querySelector('ul')!;\n      });\n      it('should simple className work', () => {\n        expect(paginationRootElement.classList.contains('ant-pagination-simple')).toBe(true);\n        expect(paginationElement.firstElementChild!.classList.contains('ant-pagination-prev')).toBe(true);\n        expect(paginationElement.lastElementChild!.classList.contains('ant-pagination-next')).toBe(true);\n      });\n      it('should simple pager jump', () => {\n        fixture.detectChanges();\n        const input = pagination.nativeElement.querySelector('input');\n        input.value = 5;\n        expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(0);\n        const event = createKeyboardEvent('keydown', ENTER, input, 'enter');\n        input.dispatchEvent(event);\n        dispatchKeyboardEvent(input, 'keydown', ENTER, input);\n        fixture.detectChanges();\n        expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(1);\n        expect(input.value).toBe('5');\n        expect(testComponent.pageIndex).toBe(5);\n        dispatchKeyboardEvent(input, 'keydown', ENTER, input);\n        fixture.detectChanges();\n        expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(1);\n        expect(input.value).toBe('5');\n        input.value = 100;\n        expect(testComponent.pageIndex).toBe(5);\n        dispatchKeyboardEvent(input, 'keydown', ENTER, input);\n        fixture.detectChanges();\n        expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(1);\n        expect(testComponent.pageIndex).toBe(5);\n      });\n    });\n    it('should zero total hide all', () => {\n      testComponent.total = 0;\n      fixture.detectChanges();\n      expect(pagination.nativeElement.innerText).toEqual('');\n    });\n    it('should be hidden pagination when total is 0 and nzHideOnSinglePage is true', () => {\n      (testComponent as NzTestPaginationComponent).total = 0;\n      (testComponent as NzTestPaginationComponent).hideOnSinglePage = true;\n      fixture.detectChanges();\n      expect(fixture.debugElement.nativeElement.querySelector('.ant-pagination').children.length).toBe(0);\n    });\n    it('should be display one more page when the 4th is selected', () => {\n      testComponent.total = 500;\n      testComponent.pageIndex = 4; // he 4th is selected\n      fixture.detectChanges();\n      expect(paginationElement.children.length).toBe(10);\n      testComponent.pageIndex = 3;\n      fixture.detectChanges();\n      expect(paginationElement.children.length).toBe(9);\n\n      testComponent.pageIndex = 47; // the 4th from last is selected\n      fixture.detectChanges();\n      expect(paginationElement.children.length).toBe(10);\n      testComponent.pageIndex = 48;\n      fixture.detectChanges();\n      expect(paginationElement.children.length).toBe(9);\n    });\n  });\n\n  describe('pagination render items', () => {\n    let fixture: ComponentFixture<NzTestPaginationRenderComponent>;\n    let pagination: DebugElement;\n    let paginationElement: HTMLElement;\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestPaginationRenderComponent);\n      pagination = fixture.debugElement.query(By.directive(NzPaginationComponent));\n      fixture.detectChanges();\n      paginationElement = pagination.nativeElement.querySelector('ul')!;\n    });\n    it('should render correct', () => {\n      fixture.detectChanges();\n      expect((paginationElement.firstElementChild as HTMLElement).innerText).toBe('Previous');\n      expect((paginationElement.lastElementChild as HTMLElement).innerText).toBe('Next');\n      expect((paginationElement.children[1] as HTMLElement).innerText).toBe('2');\n    });\n\n    it(\"should not have the class 'ant-pagination-center' or 'ant-pagination-end' but have the class 'ant-pagination-start'\", () => {\n      fixture.detectChanges();\n      expect(pagination.nativeElement.classList).not.toContain('ant-pagination-center');\n      expect(pagination.nativeElement.classList).not.toContain('ant-pagination-end');\n      expect(pagination.nativeElement.classList).toContain('ant-pagination-start');\n    });\n\n    it(\"should add the class 'ant-pagination-center' when nzAlign is 'center'\", () => {\n      fixture.detectChanges();\n      fixture.componentInstance.nzAlign.set('center');\n      fixture.detectChanges();\n      expect(pagination.nativeElement.classList).toContain('ant-pagination-center');\n    });\n\n    it(\"should add the class 'ant-pagination-end' when nzAlign is 'end'\", () => {\n      fixture.detectChanges();\n      fixture.componentInstance.nzAlign.set('end');\n      fixture.detectChanges();\n      expect(pagination.nativeElement.classList).toContain('ant-pagination-end');\n    });\n  });\n\n  describe('pagination total items', () => {\n    let fixture: ComponentFixture<NzTestPaginationTotalComponent>;\n    let testComponent: NzTestPaginationTotalComponent;\n    let pagination: DebugElement;\n    let paginationElement: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestPaginationTotalComponent);\n      testComponent = fixture.debugElement.componentInstance;\n      pagination = fixture.debugElement.query(By.directive(NzPaginationComponent));\n      fixture.detectChanges();\n      paginationElement = pagination.nativeElement.querySelector('ul')!;\n    });\n\n    it('should render correct', () => {\n      fixture.detectChanges();\n      expect((paginationElement.firstElementChild as HTMLElement).innerText.trim()).toBe('1-20 of 85 items');\n      testComponent.pageIndex = 2;\n      fixture.detectChanges();\n      expect((paginationElement.firstElementChild as HTMLElement).innerText.trim()).toBe('21-40 of 85 items');\n      testComponent.pageIndex = 5;\n      fixture.detectChanges();\n      expect((paginationElement.firstElementChild as HTMLElement).innerText.trim()).toBe('81-85 of 85 items');\n    });\n  });\n\n  it('should auto resize work', fakeAsync(() => {\n    const fixture = TestBed.createComponent(NzTestPaginationAutoResizeComponent);\n    const pagination = fixture.debugElement.query(By.directive(NzPaginationComponent));\n\n    viewport.set(1200, 350);\n    fixture.detectChanges();\n    let paginationElement = pagination.nativeElement;\n    expect(paginationElement.classList).not.toContain('ant-pagination-mini');\n\n    viewport.set(350, 350);\n    window.dispatchEvent(new Event('resize'));\n    fixture.detectChanges();\n    tick(1000);\n    fixture.detectChanges();\n    paginationElement = pagination.nativeElement;\n    expect(paginationElement.classList).toContain('ant-pagination-mini');\n    viewport.reset();\n  }));\n\n  it('#i18n', () => {\n    const fixture = TestBed.createComponent(NzTestPaginationComponent);\n    const dl = fixture.debugElement;\n    fixture.detectChanges();\n    TestBed.inject(NzI18nService).setLocale(en_US);\n    fixture.detectChanges();\n    const prevText = (dl.query(By.css('.ant-pagination-prev')).nativeElement as HTMLElement).title;\n    expect(prevText).toBe(en_US.Pagination.prev_page);\n    const nextText = (dl.query(By.css('.ant-pagination-next')).nativeElement as HTMLElement).title;\n    expect(nextText).toBe(en_US.Pagination.next_page);\n  });\n\n  describe('RTL', () => {\n    let fixture: ComponentFixture<NzTestPaginationRtlComponent>;\n    let pagination: DebugElement;\n    let paginationElement: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestPaginationRtlComponent);\n      pagination = fixture.debugElement.query(By.directive(NzPaginationComponent));\n      fixture.detectChanges();\n      paginationElement = pagination.nativeElement.querySelector('ul')!;\n    });\n\n    it('should pagination className correct on dir change', () => {\n      fixture.detectChanges();\n      expect(pagination.nativeElement.classList).toContain('ant-pagination-rtl');\n\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n      expect(pagination.nativeElement.classList).not.toContain('ant-pagination-rtl');\n    });\n\n    it('should render icons correct', () => {\n      fixture.detectChanges();\n      fixture.componentInstance.total = 500;\n      fixture.detectChanges();\n      fixture.componentInstance.pageIndex = 7;\n      fixture.detectChanges();\n      const prev = paginationElement.firstElementChild as HTMLElement;\n      const next = paginationElement.lastElementChild as HTMLElement;\n      expect(prev.querySelector('.anticon')?.classList.contains('anticon-right')).toBe(true);\n      expect(next.querySelector('.anticon')?.classList.contains('anticon-left')).toBe(true);\n\n      const prev_5 = paginationElement.querySelector('.ant-pagination-jump-prev') as HTMLElement;\n      const next_5 = paginationElement.querySelector('.ant-pagination-jump-next') as HTMLElement;\n\n      expect(prev_5.querySelector('.anticon')?.classList.contains('anticon-double-right')).toBe(true);\n      expect(next_5.querySelector('.anticon')?.classList.contains('anticon-double-left')).toBe(true);\n    });\n  });\n});\n\n@Component({\n  imports: [NzPaginationModule],\n  template: `\n    <nz-pagination\n      [nzSimple]=\"simple\"\n      [(nzPageIndex)]=\"pageIndex\"\n      [nzDisabled]=\"disabled\"\n      (nzPageIndexChange)=\"pageIndexChange($event)\"\n      [(nzPageSize)]=\"pageSize\"\n      (nzPageSizeChange)=\"pageSizeChange($event)\"\n      [nzSize]=\"size\"\n      [nzTotal]=\"total\"\n      [nzHideOnSinglePage]=\"hideOnSinglePage\"\n      [nzPageSizeOptions]=\"pageSizeOptions\"\n      [nzShowSizeChanger]=\"showSizeChanger\"\n      [nzShowQuickJumper]=\"showQuickJumper\"\n    />\n  `\n})\nexport class NzTestPaginationComponent {\n  @ViewChild(NzPaginationComponent, { static: false }) nzPaginationComponent!: NzPaginationComponent;\n  pageIndex = 1;\n  pageSize = 10;\n  total = 50;\n  disabled = false;\n  pageIndexChange = jasmine.createSpy<NzSafeAny>('pageIndexChange callback');\n  pageSizeChange = jasmine.createSpy<NzSafeAny>('pageSizeChange callback');\n  showQuickJumper = false;\n  showSizeChanger = false;\n  hideOnSinglePage = false;\n  pageSizeOptions = [10, 20, 30, 40];\n  simple = false;\n  size: 'default' | 'small' = 'default';\n}\n\n@Component({\n  imports: [NzPaginationModule],\n  template: `\n    <nz-pagination [nzPageIndex]=\"1\" [nzTotal]=\"50\" [nzItemRender]=\"renderItemTemplate\" [nzAlign]=\"nzAlign()\" />\n    <ng-template #renderItemTemplate let-type let-page=\"page\">\n      @switch (type) {\n        @case ('prev') {\n          <a>Previous</a>\n        }\n        @case ('next') {\n          <a>Next</a>\n        }\n        @case ('page') {\n          <a>{{ page * 2 }}</a>\n        }\n      }\n    </ng-template>\n  `\n})\nexport class NzTestPaginationRenderComponent {\n  nzAlign = signal<NzPaginationAlign>('start');\n}\n\n@Component({\n  imports: [NzPaginationModule],\n  template: `\n    <nz-pagination [(nzPageIndex)]=\"pageIndex\" [nzTotal]=\"85\" [nzPageSize]=\"20\" [nzShowTotal]=\"rangeTemplate\" />\n    <ng-template #rangeTemplate let-range=\"range\" let-total>\n      {{ range[0] }}-{{ range[1] }} of {{ total }} items\n    </ng-template>\n  `\n})\nexport class NzTestPaginationTotalComponent {\n  pageIndex = 1;\n}\n\n@Component({\n  imports: [NzPaginationModule],\n  template: `<nz-pagination nzResponsive />`\n})\nexport class NzTestPaginationAutoResizeComponent {}\n\n@Component({\n  imports: [BidiModule, NzPaginationModule],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-pagination [nzSimple]=\"false\" [(nzPageIndex)]=\"pageIndex\" [nzTotal]=\"total\" [(nzPageSize)]=\"pageSize\" />\n    </div>\n  `\n})\nexport class NzTestPaginationRtlComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n  pageIndex = 1;\n  pageSize = 10;\n  total = 50;\n}\n"
  },
  {
    "path": "components/pagination/pagination.types.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport interface PaginationItemRenderContext {\n  $implicit: PaginationItemType;\n  page: number;\n}\n\nexport type PaginationItemType = 'page' | 'prev' | 'next' | 'prev_5' | 'next_5';\n\nexport type NzPaginationAlign = 'start' | 'center' | 'end';\n"
  },
  {
    "path": "components/pagination/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './pagination.component';\nexport * from './pagination.module';\nexport * from './pagination.types';\nexport * from './pagination-simple.component';\nexport * from './pagination-options.component';\nexport * from './pagination-item.component';\nexport * from './pagination-default.component';\n"
  },
  {
    "path": "components/pagination/style/entry.less",
    "content": "@import './index.less';\n// style dependencies\n@import '../../select/style/entry.less';\n@import './patch.less';\n"
  },
  {
    "path": "components/pagination/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import '../../input/style/mixin';\n\n@pagination-prefix-cls: ~'@{ant-prefix}-pagination';\n\n.@{pagination-prefix-cls} {\n  .reset-component();\n  display: flex;\n\n  &-start {\n    justify-content: start;\n  }\n\n  &-center {\n    justify-content: center;\n  }\n\n  &-end {\n    justify-content: end;\n  }\n\n  ul,\n  ol {\n    margin: 0;\n    padding: 0;\n    list-style: none;\n  }\n\n  &::after {\n    display: block;\n    clear: both;\n    height: 0;\n    overflow: hidden;\n    visibility: hidden;\n    content: ' ';\n  }\n\n  &-total-text {\n    display: inline-block;\n    height: @pagination-item-size;\n    margin-right: 8px;\n    line-height: @pagination-item-size - 2px;\n    vertical-align: middle;\n  }\n\n  &-item {\n    display: inline-block;\n    min-width: @pagination-item-size;\n    height: @pagination-item-size;\n    margin-right: 8px;\n    font-family: @pagination-font-family;\n    line-height: @pagination-item-size - 2px;\n    text-align: center;\n    vertical-align: middle;\n    list-style: none;\n    background-color: @pagination-item-bg;\n    border: @border-width-base @border-style-base @border-color-base;\n    border-radius: @border-radius-base;\n    outline: 0;\n    cursor: pointer;\n    user-select: none;\n\n    a {\n      display: block;\n      padding: 0 6px;\n      color: @text-color;\n      transition: none;\n\n      &:hover {\n        text-decoration: none;\n      }\n    }\n\n    &:hover {\n      border-color: @primary-color;\n      transition: all 0.3s;\n\n      a {\n        color: @primary-color;\n      }\n    }\n\n    // cannot merge with `&:hover`\n    // see https://github.com/ant-design/ant-design/pull/34002\n    &:focus-visible {\n      border-color: @primary-color;\n      transition: all 0.3s;\n\n      a {\n        color: @primary-color;\n      }\n    }\n\n    &-active {\n      font-weight: @pagination-font-weight-active;\n      background: @pagination-item-bg-active;\n      border-color: @primary-color;\n\n      a {\n        color: @primary-color;\n      }\n\n      &:hover {\n        border-color: @primary-5;\n      }\n\n      &:focus-visible {\n        border-color: @primary-5;\n      }\n\n      &:hover a {\n        color: @primary-5;\n      }\n\n      &:focus-visible a {\n        color: @primary-5;\n      }\n    }\n  }\n\n  &-jump-prev,\n  &-jump-next {\n    outline: 0;\n    .@{pagination-prefix-cls}-item-container {\n      position: relative;\n\n      .@{pagination-prefix-cls}-item-link-icon {\n        color: @primary-color;\n        font-size: @font-size-sm;\n        letter-spacing: -1px;\n        opacity: 0;\n        transition: all 0.2s;\n\n        &-svg {\n          top: 0;\n          right: 0;\n          bottom: 0;\n          left: 0;\n          margin: auto;\n        }\n      }\n\n      .@{pagination-prefix-cls}-item-ellipsis {\n        position: absolute;\n        top: 0;\n        right: 0;\n        bottom: 0;\n        left: 0;\n        display: block;\n        margin: auto;\n        color: @disabled-color;\n        font-family: Arial, Helvetica, sans-serif;\n        letter-spacing: 2px;\n        text-align: center;\n        text-indent: 0.13em;\n        opacity: 1;\n        transition: all 0.2s;\n      }\n    }\n\n    &:hover {\n      .@{pagination-prefix-cls}-item-link-icon {\n        opacity: 1;\n      }\n      .@{pagination-prefix-cls}-item-ellipsis {\n        opacity: 0;\n      }\n    }\n\n    &:focus-visible {\n      .@{pagination-prefix-cls}-item-link-icon {\n        opacity: 1;\n      }\n      .@{pagination-prefix-cls}-item-ellipsis {\n        opacity: 0;\n      }\n    }\n  }\n\n  &-prev,\n  &-jump-prev,\n  &-jump-next {\n    margin-right: 8px;\n  }\n\n  &-prev,\n  &-next,\n  &-jump-prev,\n  &-jump-next {\n    display: inline-block;\n    min-width: @pagination-item-size;\n    height: @pagination-item-size;\n    color: @text-color;\n    font-family: @pagination-font-family;\n    line-height: @pagination-item-size;\n    text-align: center;\n    vertical-align: middle;\n    list-style: none;\n    border-radius: @border-radius-base;\n    cursor: pointer;\n    transition: all 0.3s;\n  }\n\n  &-prev,\n  &-next {\n    font-family: Arial, Helvetica, sans-serif;\n    outline: 0;\n\n    button {\n      color: @text-color;\n      cursor: pointer;\n      user-select: none;\n    }\n\n    &:hover button {\n      border-color: @primary-5;\n    }\n\n    .@{pagination-prefix-cls}-item-link {\n      display: block;\n      width: 100%;\n      height: 100%;\n      padding: 0;\n      font-size: 12px;\n      text-align: center;\n      background-color: @pagination-item-link-bg;\n      border: @border-width-base @border-style-base @border-color-base;\n      border-radius: @border-radius-base;\n      outline: none;\n      transition: all 0.3s;\n    }\n\n    &:focus-visible .@{pagination-prefix-cls}-item-link {\n      color: @primary-color;\n      border-color: @primary-color;\n    }\n\n    &:hover .@{pagination-prefix-cls}-item-link {\n      color: @primary-color;\n      border-color: @primary-color;\n    }\n  }\n\n  &-disabled {\n    &,\n    &:hover {\n      cursor: not-allowed;\n      .@{pagination-prefix-cls}-item-link {\n        color: @disabled-color;\n        border-color: @border-color-base;\n        cursor: not-allowed;\n      }\n    }\n\n    &:focus-visible {\n      cursor: not-allowed;\n      .@{pagination-prefix-cls}-item-link {\n        color: @disabled-color;\n        border-color: @border-color-base;\n        cursor: not-allowed;\n      }\n    }\n  }\n\n  &-slash {\n    margin: 0 10px 0 5px;\n  }\n\n  &-options {\n    display: inline-block;\n    margin-left: 16px;\n    vertical-align: middle;\n\n    // IE11 css hack. `*::-ms-backdrop,` is a must have\n    @media all and (-ms-high-contrast: none) {\n      *::-ms-backdrop,\n      & {\n        vertical-align: top;\n      }\n    }\n\n    &-size-changer.@{ant-prefix}-select {\n      display: inline-block;\n      width: auto;\n    }\n\n    &-quick-jumper {\n      display: inline-block;\n      height: @input-height-base;\n      margin-left: @margin-xs;\n      line-height: @input-height-base;\n      vertical-align: top;\n\n      input {\n        .input();\n\n        width: 50px;\n        height: @input-height-base;\n        margin: 0 8px;\n      }\n    }\n  }\n\n  &-simple &-prev,\n  &-simple &-next {\n    height: @pagination-item-size-sm;\n    line-height: @pagination-item-size-sm;\n    vertical-align: top;\n    .@{pagination-prefix-cls}-item-link {\n      height: @pagination-item-size-sm;\n      background-color: transparent;\n      border: 0;\n\n      &::after {\n        height: @pagination-item-size-sm;\n        line-height: @pagination-item-size-sm;\n      }\n    }\n  }\n\n  &-simple &-simple-pager {\n    display: inline-block;\n    height: @pagination-item-size-sm;\n    margin-right: 8px;\n\n    input {\n      box-sizing: border-box;\n      height: 100%;\n      margin-right: 8px;\n      padding: 0 6px;\n      text-align: center;\n      background-color: @pagination-item-input-bg;\n      border: @border-width-base @border-style-base @border-color-base;\n      border-radius: @border-radius-base;\n      outline: none;\n      transition: border-color 0.3s;\n\n      &:hover {\n        border-color: @primary-color;\n      }\n\n      &:focus {\n        border-color: @primary-color-hover;\n        box-shadow: @input-outline-offset @outline-blur-size @outline-width @primary-color-outline;\n      }\n\n      &[disabled] {\n        color: @disabled-color;\n        background: @disabled-bg;\n        border-color: @border-color-base;\n        cursor: not-allowed;\n      }\n    }\n  }\n\n  &&-mini &-total-text,\n  &&-mini &-simple-pager {\n    height: @pagination-item-size-sm;\n    line-height: @pagination-item-size-sm;\n  }\n\n  &&-mini &-item {\n    min-width: @pagination-item-size-sm;\n    height: @pagination-item-size-sm;\n    margin: 0;\n    line-height: @pagination-item-size-sm - 2px;\n  }\n\n  &&-mini &-item:not(&-item-active) {\n    background: transparent;\n    border-color: transparent;\n  }\n\n  &&-mini &-prev,\n  &&-mini &-next {\n    min-width: @pagination-item-size-sm;\n    height: @pagination-item-size-sm;\n    margin: 0;\n    line-height: @pagination-item-size-sm;\n  }\n\n  &&-mini &-prev &-item-link,\n  &&-mini &-next &-item-link {\n    background: transparent;\n    border-color: transparent;\n\n    &::after {\n      height: @pagination-item-size-sm;\n      line-height: @pagination-item-size-sm;\n    }\n  }\n\n  &&-mini &-jump-prev,\n  &&-mini &-jump-next {\n    height: @pagination-item-size-sm;\n    margin-right: 0;\n    line-height: @pagination-item-size-sm;\n  }\n\n  &&-mini &-options {\n    margin-left: 2px;\n\n    &-size-changer {\n      top: @pagination-mini-options-size-changer-top;\n    }\n\n    &-quick-jumper {\n      height: @pagination-item-size-sm;\n      line-height: @pagination-item-size-sm;\n\n      input {\n        .input-sm();\n\n        width: 44px;\n        height: @input-height-sm;\n      }\n    }\n  }\n\n  // ============================ Disabled ============================\n  &&-disabled {\n    cursor: not-allowed;\n\n    .@{pagination-prefix-cls}-item {\n      background: @disabled-bg;\n      border-color: @border-color-base;\n      cursor: not-allowed;\n\n      a {\n        color: @disabled-color;\n        background: transparent;\n        border: none;\n        cursor: not-allowed;\n      }\n\n      &-active {\n        background: @pagination-item-disabled-bg-active;\n\n        a {\n          color: @pagination-item-disabled-color-active;\n        }\n      }\n    }\n\n    .@{pagination-prefix-cls}-item-link {\n      color: @disabled-color;\n      background: @disabled-bg;\n      border-color: @border-color-base;\n      cursor: not-allowed;\n      .@{pagination-prefix-cls}-simple& {\n        background: transparent;\n      }\n    }\n\n    .@{pagination-prefix-cls}-item-link-icon {\n      opacity: 0;\n    }\n\n    .@{pagination-prefix-cls}-item-ellipsis {\n      opacity: 1;\n    }\n\n    .@{pagination-prefix-cls}-simple-pager {\n      color: @disabled-color;\n    }\n  }\n}\n\n@media only screen and (max-width: @screen-lg) {\n  .@{pagination-prefix-cls}-item {\n    &-after-jump-prev,\n    &-before-jump-next {\n      display: none;\n    }\n  }\n}\n\n@media only screen and (max-width: @screen-sm) {\n  .@{pagination-prefix-cls}-options {\n    display: none;\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/pagination/style/patch.less",
    "content": "nz-pagination {\n  display: block;\n}\n"
  },
  {
    "path": "components/pagination/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import '../../input/style/mixin';\n\n@pagination-prefix-cls: ~'@{ant-prefix}-pagination';\n\n.@{pagination-prefix-cls}-rtl {\n  .@{pagination-prefix-cls}-total-text {\n    margin-right: 0;\n    margin-left: 8px;\n  }\n\n  .@{pagination-prefix-cls}-item,\n  .@{pagination-prefix-cls}-prev,\n  .@{pagination-prefix-cls}-jump-prev,\n  .@{pagination-prefix-cls}-jump-next {\n    margin-right: 0;\n    margin-left: 8px;\n  }\n\n  .@{pagination-prefix-cls}-slash {\n    margin: 0 5px 0 10px;\n  }\n\n  .@{pagination-prefix-cls}-options {\n    margin-right: 16px;\n    margin-left: 0;\n\n    .@{pagination-prefix-cls}-options-size-changer.@{ant-prefix}-select {\n      margin-right: 0;\n      margin-left: 8px;\n    }\n\n    .@{pagination-prefix-cls}-options-quick-jumper {\n      margin-left: 0;\n    }\n  }\n\n  &.@{pagination-prefix-cls}-simple {\n    .@{pagination-prefix-cls}-simple-pager {\n      margin-right: 0;\n      margin-left: 8px;\n\n      input {\n        margin-right: 0;\n        margin-left: 8px;\n      }\n    }\n  }\n\n  &.@{pagination-prefix-cls}.mini .@{pagination-prefix-cls}-options {\n    margin-right: 2px;\n    margin-left: 0;\n  }\n}\n"
  },
  {
    "path": "components/pipes/demo/aggregate.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: nzAggregate\n  en-US: nzAggregate\n---\n\n## zh-CN\n\n数组的Sum、Min、Max、Average等聚合操作\n\n## en-US\n\nSum, Min, Max, Average and other operations on arrays\n"
  },
  {
    "path": "components/pipes/demo/aggregate.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzGridModule } from 'ng-zorro-antd/grid';\nimport { NzAggregatePipe } from 'ng-zorro-antd/pipes';\nimport { NzStatisticModule } from 'ng-zorro-antd/statistic';\n\n@Component({\n  selector: 'nz-demo-pipes-aggregate',\n  imports: [NzGridModule, NzStatisticModule, NzAggregatePipe],\n  template: `\n    <nz-row [nzGutter]=\"16\">\n      <nz-col [nzSpan]=\"6\">\n        <nz-statistic [nzValue]=\"[7, 8, 2, 3] | nzAggregate: 'max'\" nzTitle=\"Max [7, 8, 2, 3]\" />\n      </nz-col>\n      <nz-col [nzSpan]=\"6\">\n        <nz-statistic [nzValue]=\"[7, 8, 2, 3] | nzAggregate: 'min'\" nzTitle=\"Min [7, 8, 2, 3]\" />\n      </nz-col>\n      <nz-col [nzSpan]=\"6\">\n        <nz-statistic [nzValue]=\"[7, 8, 2, 3] | nzAggregate: 'sum'\" nzTitle=\"Sum [7, 8, 2, 3]\" />\n      </nz-col>\n      <nz-col [nzSpan]=\"6\">\n        <nz-statistic [nzValue]=\"[7, 8, 2, 3] | nzAggregate: 'avg'\" nzTitle=\"Avg [7, 8, 2, 3]\" />\n      </nz-col>\n    </nz-row>\n  `\n})\nexport class NzDemoPipesAggregateComponent {}\n"
  },
  {
    "path": "components/pipes/demo/bytes.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: nzBytes\n  en-US: nzBytes\n---\n\n## zh-CN\n\n存储单位的换算，增加可读性\n\n## en-US\n\nConversion of storage units to increase readability\n"
  },
  {
    "path": "components/pipes/demo/bytes.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzBytesPipe } from 'ng-zorro-antd/pipes';\n\n@Component({\n  selector: 'nz-demo-pipes-bytes',\n  imports: [NzBytesPipe],\n  template: `\n    <ul>\n      <li>{{ 200 | nzBytes }}</li>\n      <li>{{ 1024 | nzBytes }}</li>\n      <li>{{ 1048576 | nzBytes }}</li>\n      <li>{{ 1024 | nzBytes: 0 : 'KB' }}</li>\n      <li>{{ 1073741824 | nzBytes }}</li>\n      <li>{{ 1099511627776 | nzBytes }}</li>\n      <li>{{ 1073741824 | nzBytes: 0 : 'B' : 'MB' }}</li>\n    </ul>\n  `\n})\nexport class NzDemoPipesBytesComponent {}\n"
  },
  {
    "path": "components/pipes/demo/css-unit.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: nzToCssUnit\n  en-US: nzToCssUnit\n---\n\n## zh-CN\n\nCss 单位\n\n提示：如果条件允许，我们更推荐使用 Angular 内置语法，例如：\n\n```html\n<div [style.border-radius.px]=\"1\">px</div>\n<div [style.border-radius.%]=\"1\">%</div>\n<div [style.border-radius.rem]=\"1\">rem</div>\n```\n\n## en-US\n\nCss unit\n\nTip: If possible, we prefer to use Angular's built-in syntax, for example:\n\n```html\n<div [style.border-radius.px]=\"1\">px</div>\n<div [style.border-radius.%]=\"1\">%</div>\n<div [style.border-radius.rem]=\"1\">rem</div>\n```\n"
  },
  {
    "path": "components/pipes/demo/css-unit.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzToCssUnitPipe } from 'ng-zorro-antd/pipes';\nimport { NzSliderModule } from 'ng-zorro-antd/slider';\n\n@Component({\n  selector: 'nz-demo-pipes-css-unit',\n  imports: [FormsModule, NzSliderModule, NzToCssUnitPipe],\n  template: `\n    <nz-slider [(ngModel)]=\"radiusValue\" [nzMax]=\"100\" [nzMin]=\"0\" />\n\n    <div class=\"wrap\">\n      <div class=\"box\" [style.border-radius]=\"radiusValue | nzToCssUnit\">Default</div>\n      <div class=\"box\" [style.border-radius]=\"radiusValue | nzToCssUnit: '%'\">%</div>\n      <div class=\"box\" [style.border-radius]=\"radiusValue | nzToCssUnit: 'rem'\">rem</div>\n    </div>\n  `,\n  styles: `\n    .wrap {\n      display: flex;\n    }\n    .box {\n      margin-top: 20px;\n      margin-right: 20px;\n      text-align: center;\n      line-height: 50px;\n      color: #fff;\n      width: 50px;\n      height: 50px;\n      background: #4183c4;\n    }\n  `\n})\nexport class NzDemoPipesCssUnitComponent {\n  radiusValue = 0;\n}\n"
  },
  {
    "path": "components/pipes/demo/ellipsis.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: nzEllipsis\n  en-US: nzEllipsis\n---\n\n## zh-CN\n\n截断字符串，用指定的字符串结尾\n\n## en-US\n\nTruncate the string, ending with the specified string\n"
  },
  {
    "path": "components/pipes/demo/ellipsis.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzEllipsisPipe } from 'ng-zorro-antd/pipes';\n\n@Component({\n  selector: 'nz-demo-pipes-ellipsis',\n  imports: [FormsModule, NzInputModule, NzEllipsisPipe],\n  template: `\n    <input type=\"text\" nz-input [(ngModel)]=\"str\" />\n    <br />\n    <p>{{ str | nzEllipsis: 36 : '...' }}</p>\n  `,\n  styles: `\n    p {\n      padding: 8px 12px;\n    }\n  `\n})\nexport class NzDemoPipesEllipsisComponent {\n  str = 'Ant Design, a design language for background applications';\n}\n"
  },
  {
    "path": "components/pipes/demo/sanitizer.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: nzSanitizer\n  en-US: nzSanitizer\n---\n\n## zh-CN\n\nDomSanitizer 的 Pipe 实现\n\n```html\n<div [innerHTML]=\"html | nzSanitizer: 'html'\"></div>\n<div [style]=\"style | nzSanitizer: 'style'\"></div>\n<img [src]=\"url | nzSanitizer: 'url'\" />\n<iframe [src]=\"resourceUrl | nzSanitizer: 'resourceUrl'\"></iframe>\n```\n\n## en-US\n\nPipe implementation of DomSanitizer\n\n```html\n<div [innerHTML]=\"html | nzSanitizer: 'html'\"></div>\n<div [style]=\"style | nzSanitizer: 'style'\"></div>\n<img [src]=\"url | nzSanitizer: 'url'\" />\n<iframe [src]=\"resourceUrl | nzSanitizer: 'resourceUrl'\"></iframe>\n```\n"
  },
  {
    "path": "components/pipes/demo/sanitizer.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzSanitizerPipe } from 'ng-zorro-antd/pipes';\n\n@Component({\n  selector: 'nz-demo-pipes-sanitizer',\n  imports: [NzSanitizerPipe],\n  template: `<div [innerHTML]=\"html | nzSanitizer: 'html'\"></div>`\n})\nexport class NzDemoPipesSanitizerComponent {\n  html = `<span>I am <code>innerHTML</code></span>`;\n}\n"
  },
  {
    "path": "components/pipes/demo/trim.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: nzTrim\n  en-US: nzTrim\n---\n\n## zh-CN\n\n去除字符串左右空字符串\n\n## en-US\n\nStrip left and right empty string\n"
  },
  {
    "path": "components/pipes/demo/trim.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzTrimPipe } from 'ng-zorro-antd/pipes';\n\n@Component({\n  selector: 'nz-demo-pipes-trim',\n  imports: [FormsModule, NzInputModule, NzTrimPipe],\n  template: `\n    <input type=\"text\" nz-input [(ngModel)]=\"str\" />\n    <br />\n    <div>\n      <pre>{{ str }}</pre>\n    </div>\n    <div>\n      <pre>{{ str | nzTrim }}</pre>\n    </div>\n  `,\n  styles: `\n    div {\n      padding: 8px 12px;\n    }\n    pre {\n      display: inline-block;\n      background: #eee;\n    }\n  `\n})\nexport class NzDemoPipesTrimComponent {\n  str = ' Ant Design ';\n}\n"
  },
  {
    "path": "components/pipes/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: General\ntitle: Pipes\ncols: 1\nexperimental: true\ndescription: Common Pipe Collections.\n---\n\n## When To Use\n\nAfter importing Pipe, use it like Angular's built-in Pipe\n\n## API\n\n### nzBytes\n\n| Property  | Description                     | Type     | Default |\n| --------- | ------------------------------- | -------- | ------- |\n| `decimal` | Decimal                         | `number` | '0'     |\n| `from`    | Unit of current value           | `string` | 'B'     |\n| `to`      | Units converted to target value | `string` | ''      |\n\n### nzToCssUnit\n\n| Property      | Description  | Type     | Default |\n| ------------- | ------------ | -------- | ------- |\n| `defaultUnit` | Default Unit | `string` | 'px'    |\n\n### nzEllipsis\n\n| Property | Description       | Type     | Default |\n| -------- | ----------------- | -------- | ------- |\n| `length` | Truncate length   | `number` | ''      |\n| `suffix` | Replace character | `string` | ''      |\n\n### nzAggregate\n\n| Property | Description | Type                               | Default |\n| -------- | ----------- | ---------------------------------- | ------- |\n| `method` | Aggregation | `'sum' \\| 'max' \\| 'min' \\| 'avg'` | ''      |\n\n### nzSanitizer\n\n| Property | Description    | Type     | Default |\n| -------- | -------------- | -------- | ------- |\n| `type`   | sanitizer type | `string` | 'html'  |\n"
  },
  {
    "path": "components/pipes/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ntype: 通用\ntitle: Pipes\ncols: 1\nexperimental: true\ndescription: 常用 Pipes 集合。\n---\n\n## 何时使用\n\n引入 Pipe 后，像 angular 的默认 Pipe 一样使用\n\n## API\n\n### nzBytes\n\n| 参数      | 说明               | 类型     | 默认值 |\n| --------- | ------------------ | -------- | ------ |\n| `decimal` | 保留小数位         | `number` | '0'    |\n| `from`    | 当前值的单位       | `string` | 'B'    |\n| `to`      | 转换到目标值的单位 | `string` | ''     |\n\n### nzToCssUnit\n\n| 参数          | 说明     | 类型     | 默认值 |\n| ------------- | -------- | -------- | ------ |\n| `defaultUnit` | 默认单位 | `string` | 'px'   |\n\n### nzEllipsis\n\n| 参数     | 说明     | 类型     | 默认值 |\n| -------- | -------- | -------- | ------ |\n| `length` | 截取长度 | `number` | ''     |\n| `suffix` | 替换字符 | `string` | ''     |\n\n### nzAggregate\n\n| 参数     | 说明     | 类型                               | 默认值 |\n| -------- | -------- | ---------------------------------- | ------ |\n| `method` | 聚合方式 | `'sum' \\| 'max' \\| 'min' \\| 'avg'` | ''     |\n\n### nzSanitizer\n\n| 参数   | 说明           | 类型     | 默认值 |\n| ------ | -------------- | -------- | ------ |\n| `type` | sanitizer 类型 | `string` | 'html' |\n"
  },
  {
    "path": "components/pipes/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/pipes/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/pipes/nz-aggregate.pipe.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzAggregatePipe } from './nz-aggregate.pipe';\n\ndescribe('NzAggregatePipe', () => {\n  let nzAggregatePipe: NzAggregatePipe;\n\n  beforeEach(() => {\n    nzAggregatePipe = new NzAggregatePipe();\n  });\n  it('Should return 4', () => {\n    expect(nzAggregatePipe.transform([1, 2, 3, 4], 'max')).toEqual(4);\n  });\n\n  it('Should return 1', () => {\n    expect(nzAggregatePipe.transform([1], 'max')).toEqual(1);\n  });\n\n  it('Should return 1', () => {\n    expect(nzAggregatePipe.transform([1, 1], 'max')).toEqual(1);\n  });\n\n  it('Should return undefined', () => {\n    expect(nzAggregatePipe.transform([], 'max')).toBeUndefined();\n  });\n\n  it('Should return 1', () => {\n    expect(nzAggregatePipe.transform([1, 2, 3, 4], 'min')).toEqual(1);\n  });\n\n  it('Should return 2', () => {\n    expect(nzAggregatePipe.transform([4, 3, 2, 5], 'min')).toEqual(2);\n  });\n\n  it('Should return 1', () => {\n    expect(nzAggregatePipe.transform([1], 'min')).toEqual(1);\n  });\n\n  it('Should return 1', () => {\n    expect(nzAggregatePipe.transform([1, 1], 'min')).toEqual(1);\n  });\n\n  it('Should return undefined', () => {\n    expect(nzAggregatePipe.transform([], 'min')).toBeUndefined();\n  });\n\n  it('Should return 10', () => {\n    expect(nzAggregatePipe.transform([1, 2, 3, 4], 'sum')).toEqual(10);\n  });\n\n  it('Should return 1', () => {\n    expect(nzAggregatePipe.transform([1], 'sum')).toEqual(1);\n  });\n\n  it('Should return 2', () => {\n    expect(nzAggregatePipe.transform([1, 1], 'sum')).toEqual(2);\n  });\n\n  it('Should return 2.5', () => {\n    expect(nzAggregatePipe.transform([1, 2, 3, 4], 'avg')).toEqual(2.5);\n  });\n\n  it('Should return 1', () => {\n    expect(nzAggregatePipe.transform([1], 'avg')).toEqual(1);\n  });\n\n  it('Should return 1', () => {\n    expect(nzAggregatePipe.transform([1, 1], 'avg')).toEqual(1);\n  });\n\n  it('Should return undefined', () => {\n    expect(nzAggregatePipe.transform([], 'avg')).toBeUndefined();\n  });\n});\n"
  },
  {
    "path": "components/pipes/nz-aggregate.pipe.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Pipe, PipeTransform } from '@angular/core';\n\nimport { sum } from 'ng-zorro-antd/core/util';\n\nexport type AggregateMethod = 'sum' | 'max' | 'min' | 'avg';\n\n@Pipe({\n  name: 'nzAggregate'\n})\nexport class NzAggregatePipe implements PipeTransform {\n  transform(value: number[], method: AggregateMethod): undefined | number {\n    if (!Array.isArray(value)) {\n      return value;\n    }\n\n    if (value.length === 0) {\n      return undefined;\n    }\n\n    switch (method) {\n      case 'sum':\n        return sum(value);\n      case 'avg':\n        return sum(value) / value.length;\n      case 'max':\n        return Math.max(...value);\n      case 'min':\n        return Math.min(...value);\n      default:\n        throw Error(`Invalid Pipe Arguments: Aggregate pipe doesn't support this type`);\n    }\n  }\n}\n"
  },
  {
    "path": "components/pipes/nz-bytes.pipe.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ByteUnit, NzBytesPipe } from './nz-bytes.pipe';\n\ndescribe('NzBytesPipe', () => {\n  let pipe: NzBytesPipe;\n\n  beforeEach(() => {\n    pipe = new NzBytesPipe();\n  });\n\n  it('Should return 150 B', () => {\n    const result = pipe.transform(150, 0);\n    expect(result).toEqual('150 B');\n  });\n\n  it('Should return 155 B', () => {\n    const result = pipe.transform(155, 2);\n    expect(result).toEqual('155 B');\n  });\n\n  it('Should return 155 B', () => {\n    const result = pipe.transform(155, 1);\n    expect(result).toEqual('155 B');\n  });\n\n  it('Should return 1 kB', () => {\n    const result = pipe.transform(1024, 0);\n    expect(result).toEqual('1 kB');\n  });\n\n  it('Should return 1 kB #2', () => {\n    const result = pipe.transform(1, 0, 'kB');\n    expect(result).toEqual('1 kB');\n  });\n\n  it('Should return 1 kB #3', () => {\n    const result = pipe.transform(1, 0, 'KB');\n    expect(result).toEqual('1 kB');\n  });\n\n  it('Should return 890 kB', () => {\n    const kB = 1024 * 890;\n    const result = pipe.transform(kB, 0);\n    expect(result).toEqual('890 kB');\n  });\n\n  it('Should return 890 kB #2', () => {\n    const result = pipe.transform(890, 0, 'kB');\n    expect(result).toEqual('890 kB');\n  });\n\n  it('Should return 890 kB #3', () => {\n    const result = pipe.transform(890, 0, 'KB');\n    expect(result).toEqual('890 kB');\n  });\n\n  it('Should return 1023 kB', () => {\n    const kB = 1024 * 1023;\n    const result = pipe.transform(kB, 0);\n    expect(result).toEqual('1023 kB');\n  });\n\n  it('Should return 241 MB', () => {\n    const mb = 1024 * 1024 * 240.5691;\n    const result = pipe.transform(mb, 0);\n    expect(result).toEqual('241 MB');\n  });\n\n  it('Should return 241 MB', () => {\n    const mb = 240.5691 / 1024;\n    const result = pipe.transform(mb, 0, 'GB');\n    expect(result).toEqual('241 MB');\n  });\n\n  it('Should return 240.54 MB', () => {\n    const mb = 1024 * 1024 * 240.5411;\n    const result = pipe.transform(mb, 2);\n    expect(result).toEqual('240.54 MB');\n  });\n\n  it('Should return 1023 MB', () => {\n    const mb = 1024 * 1024 * 1023;\n    const result = pipe.transform(mb, 2);\n    expect(result).toEqual('1023 MB');\n  });\n\n  it('Should return 1023 MB #2', () => {\n    const kB = 1024 * 1023;\n    const result = pipe.transform(kB, 2, 'kB');\n    expect(result).toEqual('1023 MB');\n  });\n\n  it('Should return 1023 GB', () => {\n    const gb = 1024 * 1024 * 1024 * 1023;\n    const result = pipe.transform(gb, 2);\n    expect(result).toEqual('1023 GB');\n  });\n\n  it('Should return 1.03 TB', () => {\n    const gb = 1024 * 1024 * 1024 * 1059;\n    const result = pipe.transform(gb, 2);\n    expect(result).toEqual('1.03 TB');\n  });\n\n  it('Should return the input', () => {\n    expect(pipe.transform('a')).toEqual('a');\n  });\n\n  it('Should return 100 TB', () => {\n    const bytes = 100;\n    const unit = 'TB';\n    const result = NzBytesPipe.formatResult(bytes, unit);\n    expect(result).toEqual('100 TB');\n  });\n\n  it('Should return 1', () => {\n    const format = { max: Math.pow(1024, 4), prev: 'MB' as ByteUnit };\n    const bytes = 1024 * 1024 * 1024;\n    const result = NzBytesPipe.calculateResult(format, bytes);\n    expect(result).toEqual(1);\n  });\n\n  it('Should return 1024 MB, set output unit', () => {\n    const bytes = 1024 * 1024 * 1024;\n    const from = 'B' as ByteUnit;\n    const to = 'MB' as ByteUnit;\n    const result = pipe.transform(bytes, 0, from, to);\n    expect(result).toEqual('1024 MB');\n  });\n\n  it('Should return 1024 MB, from & to units are equals', () => {\n    const bytes = 1024;\n    const from = 'MB' as ByteUnit;\n    const to = 'MB' as ByteUnit;\n    const result = pipe.transform(bytes, 0, from, to);\n    expect(result).toEqual('1024 MB');\n  });\n});\n"
  },
  {
    "path": "components/pipes/nz-bytes.pipe.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Pipe, PipeTransform } from '@angular/core';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { isNumberFinite, toDecimal } from 'ng-zorro-antd/core/util';\n\nexport type ByteUnit = 'B' | 'kB' | 'KB' | 'MB' | 'GB' | 'TB';\n\n@Pipe({\n  name: 'nzBytes'\n})\nexport class NzBytesPipe implements PipeTransform {\n  static formats: Record<ByteUnit, { max: number; prev?: ByteUnit }> = {\n    B: { max: 1024 },\n    kB: { max: Math.pow(1024, 2), prev: 'B' },\n    KB: { max: Math.pow(1024, 2), prev: 'B' },\n    MB: { max: Math.pow(1024, 3), prev: 'kB' },\n    GB: { max: Math.pow(1024, 4), prev: 'MB' },\n    TB: { max: Number.MAX_SAFE_INTEGER, prev: 'GB' }\n  };\n\n  transform(input: NzSafeAny, decimal: number = 0, from: ByteUnit = 'B', to?: ByteUnit): NzSafeAny {\n    if (!(isNumberFinite(input) && isNumberFinite(decimal) && decimal % 1 === 0 && decimal >= 0)) {\n      return input;\n    }\n\n    let bytes = input;\n    let unit = from;\n    while (unit !== 'B') {\n      bytes *= 1024;\n      unit = NzBytesPipe.formats[unit].prev!;\n    }\n\n    if (to) {\n      const format = NzBytesPipe.formats[to];\n\n      const result = toDecimal(NzBytesPipe.calculateResult(format, bytes), decimal);\n\n      return NzBytesPipe.formatResult(result, to);\n    }\n\n    for (const key in NzBytesPipe.formats) {\n      if (NzBytesPipe.formats.hasOwnProperty(key)) {\n        const format = NzBytesPipe.formats[key as ByteUnit];\n        if (bytes < format.max) {\n          const result = toDecimal(NzBytesPipe.calculateResult(format, bytes), decimal);\n\n          return NzBytesPipe.formatResult(result, key);\n        }\n      }\n    }\n  }\n\n  static formatResult(result: number, unit: string): string {\n    return `${result} ${unit}`;\n  }\n\n  static calculateResult(format: { max: number; prev?: ByteUnit }, bytes: number): number {\n    const prev = format.prev ? NzBytesPipe.formats[format.prev] : undefined;\n    return prev ? bytes / prev.max : bytes;\n  }\n}\n"
  },
  {
    "path": "components/pipes/nz-css-unit.pipe.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzToCssUnitPipe } from './nz-css-unit.pipe';\n\ndescribe('NzToCssUnitPipe', () => {\n  let pipe: NzToCssUnitPipe;\n\n  beforeEach(() => {\n    pipe = new NzToCssUnitPipe();\n  });\n\n  describe('number', () => {\n    it('Should ToCssUnit', () => {\n      expect(pipe.transform(100)).toEqual('100px');\n    });\n\n    it('Should ToCssUnit', () => {\n      expect(pipe.transform(100, 'px')).toEqual('100px');\n    });\n\n    it('Should ToCssUnit but defaultUnit is defined', () => {\n      expect(pipe.transform(100, 'pt')).toEqual('100pt');\n    });\n  });\n\n  describe('string', () => {\n    it('Should ToCssUnit but typeof value is String', () => {\n      expect(pipe.transform('100px')).toEqual('100px');\n    });\n\n    it('Should ToCssUnit but defaultUnit is defined and typeof value is String', () => {\n      expect(pipe.transform('100px', 'pt')).toEqual('100px');\n    });\n  });\n});\n"
  },
  {
    "path": "components/pipes/nz-css-unit.pipe.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Pipe, PipeTransform } from '@angular/core';\n\n@Pipe({\n  name: 'nzToCssUnit'\n})\nexport class NzToCssUnitPipe implements PipeTransform {\n  transform(value: number | string, defaultUnit: string = 'px'): string {\n    return typeof value === 'number' ? `${value}${defaultUnit}` : value;\n  }\n}\n"
  },
  {
    "path": "components/pipes/nz-ellipsis.pipe.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzEllipsisPipe } from './nz-ellipsis.pipe';\n\ndescribe('NzEllipsisPipe', () => {\n  let pipe: NzEllipsisPipe;\n\n  beforeEach(() => {\n    pipe = new NzEllipsisPipe();\n  });\n\n  it('Should truncate', () => {\n    expect(pipe.transform('Hello World', 4, '')).toEqual('Hell');\n  });\n\n  it('Should return the input', () => {\n    expect(pipe.transform('Hello', 10)).toEqual('Hello');\n  });\n});\n"
  },
  {
    "path": "components/pipes/nz-ellipsis.pipe.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Pipe, PipeTransform } from '@angular/core';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\n@Pipe({\n  name: 'nzEllipsis'\n})\nexport class NzEllipsisPipe implements PipeTransform {\n  transform(value: NzSafeAny, length?: number, suffix: string = ''): NzSafeAny {\n    if (typeof value !== 'string') {\n      return value;\n    }\n\n    const len = typeof length === 'undefined' ? value.length : length;\n\n    if (value.length <= len) {\n      return value;\n    }\n\n    return value.substring(0, len) + suffix;\n  }\n}\n"
  },
  {
    "path": "components/pipes/nz-pipes.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzAggregatePipe } from './nz-aggregate.pipe';\nimport { NzBytesPipe } from './nz-bytes.pipe';\nimport { NzToCssUnitPipe } from './nz-css-unit.pipe';\nimport { NzEllipsisPipe } from './nz-ellipsis.pipe';\nimport { NzSanitizerPipe } from './nz-sanitizer.pipe';\nimport { NzTrimPipe } from './nz-trim.pipe';\n\nconst pipes = [NzToCssUnitPipe, NzSanitizerPipe, NzTrimPipe, NzBytesPipe, NzAggregatePipe, NzEllipsisPipe];\n\n@NgModule({\n  imports: [pipes],\n  exports: [pipes]\n})\nexport class NzPipesModule {}\n"
  },
  {
    "path": "components/pipes/nz-sanitizer.pipe.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { TestBed } from '@angular/core/testing';\nimport { BrowserModule } from '@angular/platform-browser';\n\nimport { NzSanitizerPipe } from './nz-sanitizer.pipe';\n\ndescribe('NzSanitizerPipe', () => {\n  let pipe: NzSanitizerPipe;\n  const htmlSnippet = '<div><p>hello world</p><div>';\n  const styleSnippet = 'height:50px;background-color: red';\n  const urlSnippet = 'https://img.alicdn.com/tfs/TB1Ly5oS3HqK1RjSZFPXXcwapXa-238-54.png';\n  const responseUrlSnippet = 'https://www.aliyun.com/';\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [NzSanitizerPipe],\n      imports: [BrowserModule]\n    });\n    pipe = TestBed.inject(NzSanitizerPipe);\n  });\n\n  it('Should sanitizer', () => {\n    expect(pipe).toBeTruthy();\n  });\n\n  it('Should sanitizer but type is html', () => {\n    expect(pipe.transform(htmlSnippet, 'html')).toBeTruthy();\n  });\n\n  it('Should sanitizer but type is style', () => {\n    expect(pipe.transform(styleSnippet, 'style')).toBeTruthy();\n  });\n\n  it('Should sanitizer but type is url', () => {\n    expect(pipe.transform(urlSnippet, 'url')).toBeTruthy();\n  });\n\n  it('Should sanitizer but type is resourceUrl', () => {\n    expect(pipe.transform(responseUrlSnippet, 'resourceUrl')).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "components/pipes/nz-sanitizer.pipe.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { inject, Pipe, PipeTransform } from '@angular/core';\nimport { DomSanitizer, SafeHtml, SafeResourceUrl, SafeStyle, SafeUrl } from '@angular/platform-browser';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\ntype DomSanitizerType = 'html' | 'style' | 'url' | 'resourceUrl';\n\n@Pipe({\n  name: 'nzSanitizer'\n})\nexport class NzSanitizerPipe implements PipeTransform {\n  protected sanitizer = inject(DomSanitizer);\n\n  transform(value: NzSafeAny, type: 'html'): SafeHtml;\n  transform(value: NzSafeAny, type: 'style'): SafeStyle;\n  transform(value: NzSafeAny, type: 'url'): SafeUrl;\n  transform(value: NzSafeAny, type: 'resourceUrl'): SafeResourceUrl;\n  transform(value: NzSafeAny, type: DomSanitizerType = 'html'): SafeHtml | SafeStyle | SafeUrl | SafeResourceUrl {\n    switch (type) {\n      case 'html':\n        return this.sanitizer.bypassSecurityTrustHtml(value);\n      case 'style':\n        return this.sanitizer.bypassSecurityTrustStyle(value);\n      case 'url':\n        return this.sanitizer.bypassSecurityTrustUrl(value);\n      case 'resourceUrl':\n        return this.sanitizer.bypassSecurityTrustResourceUrl(value);\n      default:\n        throw new Error(`Invalid safe type specified`);\n    }\n  }\n}\n"
  },
  {
    "path": "components/pipes/nz-trim.pipe.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzTrimPipe } from './nz-trim.pipe';\n\ndescribe('NzTrimPipe', () => {\n  let pipe: NzTrimPipe;\n\n  beforeEach(() => {\n    pipe = new NzTrimPipe();\n  });\n\n  it('Should trim whitespace from string', () => {\n    const result = pipe.transform('   foo bar   ');\n    expect(result).toEqual('foo bar');\n  });\n});\n"
  },
  {
    "path": "components/pipes/nz-trim.pipe.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Pipe, PipeTransform } from '@angular/core';\n\n@Pipe({\n  name: 'nzTrim'\n})\nexport class NzTrimPipe implements PipeTransform {\n  // TODO(chensimeng) trimEnd, trimStart\n  transform(text: string): string {\n    return text.trim();\n  }\n}\n"
  },
  {
    "path": "components/pipes/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './nz-aggregate.pipe';\nexport * from './nz-bytes.pipe';\nexport * from './nz-css-unit.pipe';\nexport * from './nz-ellipsis.pipe';\nexport * from './nz-pipes.module';\nexport * from './nz-sanitizer.pipe';\nexport * from './nz-trim.pipe';\n"
  },
  {
    "path": "components/popconfirm/demo/async.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 异步关闭\n  en-US: Asynchronously close\n---\n\n## zh-CN\n\n点击确定后异步关闭 Popconfirm，例如提交表单。\n\n## en-US\n\nAsynchronously close a popconfirm when a the OK button is pressed. For example, you can use this pattern when you submit a form.\n"
  },
  {
    "path": "components/popconfirm/demo/async.ts",
    "content": "import { Component } from '@angular/core';\nimport { Observable } from 'rxjs';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzMessageService } from 'ng-zorro-antd/message';\nimport { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm';\n\n@Component({\n  selector: 'nz-demo-popconfirm-async',\n  imports: [NzButtonModule, NzPopconfirmModule],\n  template: `\n    <button\n      nz-button\n      nzType=\"primary\"\n      nz-popconfirm\n      nzPopconfirmTitle=\"Title\"\n      [nzBeforeConfirm]=\"beforeConfirm\"\n      (nzOnConfirm)=\"confirm()\"\n      (nzOnCancel)=\"cancel()\"\n    >\n      Open Popconfirm with async logic\n    </button>\n  `\n})\nexport class NzDemoPopconfirmAsyncComponent {\n  constructor(private nzMessageService: NzMessageService) {}\n\n  cancel(): void {\n    this.nzMessageService.info('click cancel');\n  }\n\n  confirm(): void {\n    this.nzMessageService.info('click confirm');\n  }\n\n  beforeConfirm(): Observable<boolean> {\n    return new Observable(observer => {\n      setTimeout(() => {\n        observer.next(true);\n        observer.complete();\n      }, 3000);\n    });\n  }\n}\n"
  },
  {
    "path": "components/popconfirm/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n最简单的用法。\n\n## en-US\n\nThe basic example.\n"
  },
  {
    "path": "components/popconfirm/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzMessageService } from 'ng-zorro-antd/message';\nimport { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm';\n\n@Component({\n  selector: 'nz-demo-popconfirm-basic',\n  imports: [NzPopconfirmModule],\n  template: `\n    <a\n      nz-popconfirm\n      nzPopconfirmTitle=\"Are you sure delete this task?\"\n      (nzOnConfirm)=\"confirm()\"\n      (nzOnCancel)=\"cancel()\"\n    >\n      Delete\n    </a>\n  `\n})\nexport class NzDemoPopconfirmBasicComponent {\n  constructor(private nzMessageService: NzMessageService) {}\n\n  cancel(): void {\n    this.nzMessageService.info('click cancel');\n  }\n\n  confirm(): void {\n    this.nzMessageService.info('click confirm');\n  }\n}\n"
  },
  {
    "path": "components/popconfirm/demo/custom-icon.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 自定义 icon 图标\n  en-US: Customize icon\n---\n\n## zh-CN\n\n使用 `nzIcon` 自定义提示图标。\n\n## en-US\n\nSet `nzIcon` to customize the icon.\n"
  },
  {
    "path": "components/popconfirm/demo/custom-icon.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm';\n\n@Component({\n  selector: 'nz-demo-popconfirm-custom-icon',\n  imports: [NzIconModule, NzPopconfirmModule],\n  template: `\n    <a nz-popconfirm nzPopconfirmTitle=\"Are you sure?\" [nzIcon]=\"iconTpl\">Delete</a>\n    <ng-template #iconTpl>\n      <nz-icon nzType=\"question-circle-o\" style=\"color: red;\" />\n    </ng-template>\n  `\n})\nexport class NzDemoPopconfirmCustomIconComponent {}\n"
  },
  {
    "path": "components/popconfirm/demo/dynamic-trigger.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 条件触发\n  en-US: Conditional trigger\n---\n\n## zh-CN\n\n可以判断是否需要弹出。\n\n## en-US\n\nMake it pop up under some conditions.\n"
  },
  {
    "path": "components/popconfirm/demo/dynamic-trigger.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzMessageService } from 'ng-zorro-antd/message';\nimport { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm';\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\n\n@Component({\n  selector: 'nz-demo-popconfirm-dynamic-trigger',\n  imports: [FormsModule, NzPopconfirmModule, NzSwitchModule],\n  template: `\n    <a\n      nz-popconfirm\n      nzPopconfirmTitle=\"Are you sure delete this task?\"\n      [nzCondition]=\"switchValue\"\n      (nzOnConfirm)=\"confirm()\"\n      (nzOnCancel)=\"cancel()\"\n    >\n      Delete a task\n    </a>\n    <br />\n    <br />\n    Whether directly execute:\n    <nz-switch [(ngModel)]=\"switchValue\" />\n  `\n})\nexport class NzDemoPopconfirmDynamicTriggerComponent {\n  switchValue = false;\n\n  constructor(private nzMessageService: NzMessageService) {}\n\n  cancel(): void {\n    this.nzMessageService.info('click cancel');\n  }\n\n  confirm(): void {\n    this.nzMessageService.info('click confirm');\n  }\n}\n"
  },
  {
    "path": "components/popconfirm/demo/hide-arrow.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 隐藏箭头\n  en-US: Hide arrow\n---\n\n## zh-CN\n\n设置 `[nzPopconfirmShowArrow]=\"false\"` 隐藏箭头。\n\n## en-US\n\nSet `[nzPopconfirmShowArrow]=\"false\"` to hide arrow.\n"
  },
  {
    "path": "components/popconfirm/demo/hide-arrow.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm';\n\n@Component({\n  selector: 'nz-demo-popconfirm-hide-arrow',\n  imports: [NzPopconfirmModule],\n  template: `<a nz-popconfirm nzPopconfirmTitle=\"Are you sure?\" [nzPopconfirmShowArrow]=\"false\">Delete</a>`\n})\nexport class NzDemoPopconfirmHideArrowComponent {}\n"
  },
  {
    "path": "components/popconfirm/demo/locale.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 国际化\n  en-US: Locale text\n---\n\n## zh-CN\n\n使用 `okText` 和 `cancelText` 自定义按钮文字。\n\n## en-US\n\nSet `okText` and `cancelText` props to customise the button's labels.\n"
  },
  {
    "path": "components/popconfirm/demo/locale.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzMessageService } from 'ng-zorro-antd/message';\nimport { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm';\n\n@Component({\n  selector: 'nz-demo-popconfirm-locale',\n  imports: [NzPopconfirmModule],\n  template: `\n    <a\n      nz-popconfirm\n      nzPopconfirmTitle=\"Are you sure?\"\n      nzOkText=\"ok\"\n      nzCancelText=\"cancel\"\n      (nzOnConfirm)=\"confirm()\"\n      (nzOnCancel)=\"cancel()\"\n    >\n      delete\n    </a>\n  `\n})\nexport class NzDemoPopconfirmLocaleComponent {\n  constructor(private nzMessageService: NzMessageService) {}\n\n  cancel(): void {\n    this.nzMessageService.info('click cancel');\n  }\n\n  confirm(): void {\n    this.nzMessageService.info('click confirm');\n  }\n}\n"
  },
  {
    "path": "components/popconfirm/demo/placement.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 位置\n  en-US: Placement\n---\n\n## zh-CN\n\n位置有十二个方向。\n\n## en-US\n\nThere are 12 placement options available.\n"
  },
  {
    "path": "components/popconfirm/demo/placement.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzMessageService } from 'ng-zorro-antd/message';\nimport { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm';\n\n@Component({\n  selector: 'nz-demo-popconfirm-placement',\n  imports: [NzButtonModule, NzPopconfirmModule],\n  template: `\n    <div style=\"margin-left: 60px\">\n      <button\n        nz-popconfirm\n        nzPopconfirmTitle=\"Are you sure delete this task?\"\n        (nzOnConfirm)=\"confirm()\"\n        (nzOnCancel)=\"cancel()\"\n        nzPopconfirmPlacement=\"topLeft\"\n        nz-button\n      >\n        TL\n      </button>\n      <button\n        nz-popconfirm\n        nzPopconfirmTitle=\"Are you sure delete this task?\"\n        (nzOnConfirm)=\"confirm()\"\n        (nzOnCancel)=\"cancel()\"\n        nzPopconfirmPlacement=\"top\"\n        nz-button\n      >\n        Top\n      </button>\n      <button\n        nz-popconfirm\n        nzPopconfirmTitle=\"Are you sure delete this task?\"\n        (nzOnConfirm)=\"confirm()\"\n        (nzOnCancel)=\"cancel()\"\n        nzPopconfirmPlacement=\"topRight\"\n        nz-button\n      >\n        TR\n      </button>\n    </div>\n    <div style=\"width: 60px; float: left;\">\n      <button\n        nz-popconfirm\n        nzPopconfirmTitle=\"Are you sure delete this task?\"\n        (nzOnConfirm)=\"confirm()\"\n        (nzOnCancel)=\"cancel()\"\n        nzPopconfirmPlacement=\"leftTop\"\n        nz-button\n      >\n        LT\n      </button>\n      <button\n        nz-popconfirm\n        nzPopconfirmTitle=\"Are you sure delete this task?\"\n        (nzOnConfirm)=\"confirm()\"\n        (nzOnCancel)=\"cancel()\"\n        nzPopconfirmPlacement=\"left\"\n        nz-button\n      >\n        Left\n      </button>\n      <button\n        nz-popconfirm\n        nzPopconfirmTitle=\"Are you sure delete this task?\"\n        (nzOnConfirm)=\"confirm()\"\n        (nzOnCancel)=\"cancel()\"\n        nzPopconfirmPlacement=\"leftBottom\"\n        nz-button\n      >\n        LB\n      </button>\n    </div>\n    <div style=\"width: 60px; margin-left: 252px;\">\n      <button\n        nz-popconfirm\n        nzPopconfirmTitle=\"Are you sure delete this task?\"\n        (nzOnConfirm)=\"confirm()\"\n        (nzOnCancel)=\"cancel()\"\n        nzPopconfirmPlacement=\"rightTop\"\n        nz-button\n      >\n        RT\n      </button>\n      <button\n        nz-popconfirm\n        nzPopconfirmTitle=\"Are you sure delete this task?\"\n        (nzOnConfirm)=\"confirm()\"\n        (nzOnCancel)=\"cancel()\"\n        nzPopconfirmPlacement=\"right\"\n        nz-button\n      >\n        Right\n      </button>\n      <button\n        nz-popconfirm\n        nzPopconfirmTitle=\"Are you sure delete this task?\"\n        (nzOnConfirm)=\"confirm()\"\n        (nzOnCancel)=\"cancel()\"\n        nzPopconfirmPlacement=\"rightBottom\"\n        nz-button\n      >\n        RB\n      </button>\n    </div>\n    <div style=\"margin-left: 60px; clear: both;\">\n      <button\n        nz-popconfirm\n        nzPopconfirmTitle=\"Are you sure delete this task?\"\n        (nzOnConfirm)=\"confirm()\"\n        (nzOnCancel)=\"cancel()\"\n        nzPopconfirmPlacement=\"bottomLeft\"\n        nz-button\n      >\n        BL\n      </button>\n      <button\n        nz-popconfirm\n        nzPopconfirmTitle=\"Are you sure delete this task?\"\n        (nzOnConfirm)=\"confirm()\"\n        (nzOnCancel)=\"cancel()\"\n        nzPopconfirmPlacement=\"bottom\"\n        nz-button\n      >\n        Bottom\n      </button>\n      <button\n        nz-popconfirm\n        nzPopconfirmTitle=\"Are you sure delete this task?\"\n        (nzOnConfirm)=\"confirm()\"\n        (nzOnCancel)=\"cancel()\"\n        nzPopconfirmPlacement=\"bottomRight\"\n        nz-button\n      >\n        BR\n      </button>\n    </div>\n  `,\n  styles: `\n    button {\n      margin-right: 8px;\n      margin-bottom: 8px;\n      width: 70px;\n      text-align: center;\n      padding: 0;\n    }\n  `\n})\nexport class NzDemoPopconfirmPlacementComponent {\n  constructor(private nzMessageService: NzMessageService) {}\n\n  cancel(): void {\n    this.nzMessageService.info('click cancel');\n  }\n\n  confirm(): void {\n    this.nzMessageService.info('click confirm');\n  }\n}\n"
  },
  {
    "path": "components/popconfirm/demo/promise.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 基于 Promise 的异步关闭\n  en-US: Asynchronously close on Promise\n---\n\n## zh-CN\n\n点击确定后异步关闭 Popconfirm，例如提交表单。\n\n## en-US\n\nAsynchronously close a popconfirm when the OK button is pressed. For example, you can use this pattern when you submit a form.\n"
  },
  {
    "path": "components/popconfirm/demo/promise.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzMessageService } from 'ng-zorro-antd/message';\nimport { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm';\n\n@Component({\n  selector: 'nz-demo-popconfirm-promise',\n  imports: [NzButtonModule, NzPopconfirmModule],\n  template: `\n    <button\n      nz-button\n      nzType=\"primary\"\n      nz-popconfirm\n      nzPopconfirmTitle=\"Title\"\n      [nzBeforeConfirm]=\"beforeConfirm\"\n      (nzOnConfirm)=\"confirm()\"\n      (nzOnCancel)=\"cancel()\"\n    >\n      Open Popconfirm with Promise\n    </button>\n  `\n})\nexport class NzDemoPopconfirmPromiseComponent {\n  constructor(private nzMessageService: NzMessageService) {}\n\n  cancel(): void {\n    this.nzMessageService.info('click cancel');\n  }\n\n  confirm(): void {\n    this.nzMessageService.info('click confirm');\n  }\n\n  beforeConfirm(): Promise<boolean> {\n    return new Promise(resolve => {\n      setTimeout(() => {\n        resolve(true);\n      }, 3000);\n    });\n  }\n}\n"
  },
  {
    "path": "components/popconfirm/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Feedback\ntitle: Popconfirm\ncover: 'https://gw.alipayobjects.com/zos/alicdn/fjMCD9xRq/Popconfirm.svg'\ndescription: Pop up a bubble confirmation box for an action.\n---\n\n## When To Use\n\nA simple and compact dialog is used for asking for user confirmation.\n\nThe difference with the `confirm` modal dialog is that it's more lightweight than the static-popped full-screen confirm modal.\n\n## API\n\n### [nz-popconfirm]\n\n| Param                              | Description                                                         | Type                                                                                                                                                                              | Default value |\n| ---------------------------------- | ------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |\n| `[nzPopconfirmArrowPointAtCenter]` | Arrow point at center of the origin                                 | `boolean`                                                                                                                                                                         | `false`       |\n| `[nzPopconfirmTitle]`              | Title of the confirmation box                                       | `string \\| TemplateRef<void>`                                                                                                                                                     | -             |\n| `[nzPopconfirmTitleContext]`       | The context of confirmation box title                               | `object`                                                                                                                                                                          | -             |\n| `[nzPopconfirmTrigger]`            | Popconfirm trigger mode. If set to `null` it would not be triggered | `'click' \\| 'focus' \\| 'hover' \\| null`                                                                                                                                           | `'click'`     |\n| `[nzPopconfirmPlacement]`          | The position of the popconfirm relative to the target               | `'top' \\| 'left' \\| 'right' \\| 'bottom' \\| 'topLeft' \\| 'topRight' \\| 'bottomLeft' \\| 'bottomRight' \\| 'leftTop' \\| 'leftBottom' \\| 'rightTop' \\| 'rightBottom' \\| Array<string>` | `'top'`       |\n| `[nzPopconfirmOrigin]`             | Origin of the popconfirm                                            | `ElementRef`                                                                                                                                                                      | -             |\n| `[nzPopconfirmVisible]`            | Show or hide popconfirm                                             | `boolean`                                                                                                                                                                         | `false`       |\n| `[nzPopconfirmShowArrow]`          | Whether popconfirm has arrow                                        | `boolean`                                                                                                                                                                         | `true`        |\n| `(nzPopconfirmVisibleChange)`      | Callback of hide or show                                            | `EventEmitter<boolean>`                                                                                                                                                           | -             |\n| `[nzPopconfirmMouseEnterDelay]`    | Delay in seconds, before popconfirm is shown on mouse enter         | `number`                                                                                                                                                                          | `0.15`        |\n| `[nzPopconfirmMouseLeaveDelay]`    | Delay in seconds, before popconfirm is hidden on mouse leave        | `number`                                                                                                                                                                          | `0.1`         |\n| `[nzPopconfirmOverlayClassName]`   | Class name of the popconfirm card                                   | `string`                                                                                                                                                                          | -             |\n| `[nzPopconfirmOverlayStyle]`       | Style of the popconfirm card                                        | `object`                                                                                                                                                                          | -             |\n| `[nzPopconfirmBackdrop]`           | whether or not the overlay should attach a backdrop                 | `boolean`                                                                                                                                                                         | `false`       |\n\n| Param                   | Description                                                                                                                                                     | Type                                                                 | Default value | Global Config | Version |\n| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | ------------- | ------------- | ------- |\n| `[nzCancelText]`        | Text of the Cancel button (Deprecated, please use nzCancelButtonProps instead)                                                                                  | `string`                                                             | `'Cancel'`    | -             |\n| `[nzOkText]`            | Text of the Confirm button (Deprecated, please use nzOkButtonProps instead)                                                                                     | `string`                                                             | `'Confirm'`   | -             |\n| `[nzOkType]`            | Button `type` of the Confirm button (Deprecated, please use nzOkButtonProps instead)                                                                            | `'primary' \\| 'ghost' \\| 'dashed' \\| 'danger' \\| 'default'`          | `'primary'`   | -             |\n| `[nzOkDanger]`          | Danger status of the OK button. <i>Consistent with the `nzDanger` of the `nz-button`.</i> (Deprecated, please use nzOkButtonProps instead)                      | `boolean`                                                            | `false`       | -             |\n| `[nzOkDisabled]`        | prevents a user from interacting with the OK button. <i>Consistent with the `disabled` of the `nz-button`.</i> (Deprecated, please use nzOkButtonProps instead) | `boolean`                                                            | `false`       | -             |\n| `[nzOkButtonProps]`     | config object of the ok button                                                                                                                                  | `NzPopConfirmButtonProps`                                            | `null`        | -             | 20.0.0  |\n| `[nzCancelButtonProps]` | config object of the cancel button                                                                                                                              | `NzPopConfirmButtonProps`                                            | `null`        | -             | 20.0.0  |\n| `[nzCondition]`         | Whether to directly emit `onConfirm` without showing Popconfirm                                                                                                 | `boolean`                                                            | `false`       | -             |\n| `[nzIcon]`              | Customize icon of confirmation. Set to `null` to hide the icon                                                                                                  | `string \\| TemplateRef<void> \\| null`                                | -             | -             |\n| `[nzAutoFocus]`         | Autofocus a button                                                                                                                                              | `null \\| 'ok' \\| 'cancel'`                                           | `null`        | ✅            |\n| `[nzBeforeConfirm]`     | The hook before the confirmation operation, decides whether to continue responding to the `nzOnConfirm` callback, supports asynchronous verification.           | `(() => Observable<boolean> \\| Promise<boolean> \\| boolean) \\| null` | `null`        | -             |\n| `(nzOnCancel)`          | Callback of cancel                                                                                                                                              | `EventEmitter<void>`                                                 | -             | -             |\n| `(nzOnConfirm)`         | Callback of confirmation                                                                                                                                        | `EventEmitter<void>`                                                 | -             | -             |\n\nConsult [Tooltip's documentation](/components/tooltip/en#api) to find more APIs.\n\n## Note\n\nPlease ensure that the node of `[nz-popconfirm]` accepts `onMouseEnter`, `onMouseLeave`, `onFocus`, `onClick` events.\n\n## FAQ\n\n### Q: The overlay layer element does not follow the scroll position when scrolling\n\nBy default, the overlay layer element uses body as the scroll container. If using another scroll container, add the [CdkScrollable](https://material.angular.dev/cdk/scrolling/api#CdkScrollable) directive to the custom scroll container element.\nNote: You need to import the `CdkScrollable` directive or `ScrollingModule` module from `@angular/cdk/scrolling`.\n"
  },
  {
    "path": "components/popconfirm/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 气泡确认框\ntype: 反馈\ntitle: Popconfirm\ncover: 'https://gw.alipayobjects.com/zos/alicdn/fjMCD9xRq/Popconfirm.svg'\ndescription: 点击元素，弹出气泡式的确认框。\n---\n\n## 何时使用\n\n目标元素的操作需要用户进一步的确认时，在目标元素附近弹出浮层提示，询问用户。\n\n和 `confirm` 弹出的全屏居中模态对话框相比，交互形式更轻量。\n\n## API\n\n### [nz-popconfirm]\n\n| 参数                               | 说明                                     | 类型                                                                                                                                                                              | 默认值    |\n| ---------------------------------- | ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- |\n| `[nzPopconfirmArrowPointAtCenter]` | 箭头指向锚点的中心                       | `boolean`                                                                                                                                                                         | `false`   |\n| `[nzPopconfirmTitle]`              | 确认框的描述                             | `string \\| TemplateRef<void>`                                                                                                                                                     | -         |\n| `[nzPopconfirmTitleContext]`       | 确认框描述的上下文                       | `object`                                                                                                                                                                          | -         |\n| `[nzPopconfirmTrigger]`            | 触发行为，为 `null` 时不响应光标事件     | `'click' \\| 'focus' \\| 'hover' \\| null`                                                                                                                                           | `'click'` |\n| `[nzPopconfirmPlacement]`          | 气泡框位置                               | `'top' \\| 'left' \\| 'right' \\| 'bottom' \\| 'topLeft' \\| 'topRight' \\| 'bottomLeft' \\| 'bottomRight' \\| 'leftTop' \\| 'leftBottom' \\| 'rightTop' \\| 'rightBottom' \\| Array<string>` | `'top'`   |\n| `[nzPopconfirmOrigin]`             | 气泡框定位元素                           | `ElementRef`                                                                                                                                                                      | -         |\n| `[nzPopconfirmVisible]`            | 显示隐藏气泡框                           | `boolean`                                                                                                                                                                         | `false`   |\n| `[nzPopconfirmShowArrow]`          | 气泡框是否包含箭头                       | `boolean`                                                                                                                                                                         | `true`    |\n| `[nzPopconfirmPlacement]`          | 确认框位置                               | `'top' \\| 'left' \\| 'right' \\| 'bottom' \\| 'topLeft' \\| 'topRight' \\| 'bottomLeft' \\| 'bottomRight' \\| 'leftTop' \\| 'leftBottom' \\| 'rightTop' \\| 'rightBottom'`                  | `'top'`   |\n| `[nzPopconfirmOrigin]`             | 确认框定位元素                           | `ElementRef`                                                                                                                                                                      | -         |\n| `[nzPopconfirmVisible]`            | 显示隐藏确认框                           | `boolean`                                                                                                                                                                         | `false`   |\n| `(nzPopconfirmVisibleChange)`      | 显示隐藏的事件                           | `EventEmitter<boolean>`                                                                                                                                                           | -         |\n| `[nzPopconfirmMouseEnterDelay]`    | 鼠标移入后延时多少才显示确认框，单位：秒 | `number`                                                                                                                                                                          | `0.15`    |\n| `[nzPopconfirmMouseLeaveDelay]`    | 鼠标移出后延时多少才隐藏确认框，单位：秒 | `number`                                                                                                                                                                          | `0.1`     |\n| `[nzPopconfirmOverlayClassName]`   | 卡片类名                                 | `string`                                                                                                                                                                          | -         |\n| `[nzPopconfirmOverlayStyle]`       | 卡片样式                                 | `object`                                                                                                                                                                          | -         |\n| `[nzPopconfirmBackdrop]`           | 浮层是否应带有背景板                     | `boolean`                                                                                                                                                                         | `false`   |\n\n| 参数                    | 说明                                                                                                         | 类型                                                                 | 默认值      | 全局配置 | 版本   |\n| ----------------------- | ------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------- | ----------- | -------- | ------ |\n| `[nzCancelText]`        | 取消按钮文字 （已弃用，请使用 nzCancelButtonProps 代替)                                                      | `string`                                                             | `'取消'`    | -        |\n| `[nzOkText]`            | 确认按钮文字 （已弃用，请使用 nzOkButtonProps 代替)                                                          | `string`                                                             | `'确定'`    | -        |\n| `[nzOkType]`            | 确认按钮类型 （已弃用，请使用 nzOkButtonProps 代替)                                                          | `'primary' \\| 'ghost' \\| 'dashed' \\| 'default'`                      | `'primary'` | -        |\n| `[nzOkDanger]`          | 确认按钮是否为危险按钮。<i>与 `nz-button` 的 `nzDanger` 值保持一致</i>（已弃用，请使用 nzOkButtonProps 代替) | `boolean`                                                            | `false`     | -        |\n| `[nzOkDisabled]`        | 禁止与确认按钮交互。<i>与 `nz-button` 的 `disabled` 值保持一致</i>（已弃用，请使用 nzOkButtonProps 代替)     | `boolean`                                                            | `false`     | -        |\n| `[nzOkButtonProps]`     | 确定按钮的配置对象                                                                                           | `NzPopConfirmButtonProps`                                            | `null`      | -        | 20.0.0 |\n| `[nzCancelButtonProps]` | 取消按钮的配置对象                                                                                           | `NzPopConfirmButtonProps`                                            | `null`      | -        | 20.0.0 |\n| `[nzCondition]`         | 是否直接触发 `nzOnConfirm` 而不弹出框                                                                        | `boolean`                                                            | `false`     | -        |\n| `[nzIcon]`              | 自定义弹出框的 icon，设置为 `null` 时隐藏图标                                                                | `string \\| TemplateRef<void> \\| null`                                | -           | -        |\n| `[nzAutoFocus]`         | 按钮的自动聚焦                                                                                               | `null \\| 'ok' \\| 'cancel'`                                           | `null`      | ✅       |\n| `[nzBeforeConfirm]`     | 确认操作之前的钩子，决定是否继续响应 `nzOnConfirm` 回调，支持异步验证。                                      | `(() => Observable<boolean> \\| Promise<boolean> \\| boolean) \\| null` | `null`      | -        |\n| `(nzOnCancel)`          | 点击取消的回调                                                                                               | `EventEmitter<void>`                                                 | -           | -        |\n| `(nzOnConfirm)`         | 点击确认的回调                                                                                               | `EventEmitter<void>`                                                 | -           | -        |\n\n更多属性请参考 [Tooltip](/components/tooltip/zh#api)。\n\n## 注意\n\n请确保 `[nz-popconfirm]` 元素能接受 `onMouseEnter`、`onMouseLeave`、`onFocus`、`onClick` 事件。\n\n## FAQ\n\n### Q：滚动时浮层元素没有跟随滚动位置\n\n默认情况下，浮层元素使用 `body` 作为滚动容器，如果使用了其他滚动容器，在自定义滚动容器元素上添加 [CdkScrollable](https://material.angular.dev/cdk/scrolling/api#CdkScrollable) 指令。\n注意：您需要从 `@angular/cdk/scrolling` 导入 `CdkScrollable` 指令或 `ScrollingModule` 模块。\n"
  },
  {
    "path": "components/popconfirm/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/popconfirm/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/popconfirm/popconfirm-option.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzButtonType } from 'ng-zorro-antd/button';\n\nexport interface NzPopConfirmButton {\n  nzType: NzButtonType;\n  nzDanger: boolean;\n  nzDisabled: boolean;\n}\n\nexport type NzPopConfirmButtonProps = Partial<NzPopConfirmButton>;\n"
  },
  {
    "path": "components/popconfirm/popconfirm.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzPopconfirmComponent, NzPopconfirmDirective } from './popconfirm';\n\n@NgModule({\n  imports: [NzPopconfirmComponent, NzPopconfirmDirective],\n  exports: [NzPopconfirmComponent, NzPopconfirmDirective]\n})\nexport class NzPopconfirmModule {}\n"
  },
  {
    "path": "components/popconfirm/popconfirm.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport { Component, ElementRef, provideZoneChangeDetection, signal, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, inject, TestBed, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\nimport { Observable } from 'rxjs';\n\nimport { dispatchMouseEvent } from 'ng-zorro-antd/core/testing';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\nimport { NzAutoFocusType } from 'ng-zorro-antd/popconfirm/popconfirm';\nimport { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm/popconfirm.module';\n\nimport { NzPopConfirmButtonProps } from './popconfirm-option';\n\ndescribe('popconfirm', () => {\n  let fixture: ComponentFixture<NzPopconfirmTestNewComponent>;\n  let component: NzPopconfirmTestNewComponent;\n  let overlayContainer: OverlayContainer;\n  let overlayContainerElement: HTMLElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideNoopAnimations(), provideZoneChangeDetection()]\n    });\n    fixture = TestBed.createComponent(NzPopconfirmTestNewComponent);\n    component = fixture.componentInstance;\n    fixture.detectChanges();\n  });\n\n  beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n    overlayContainer = oc;\n    overlayContainerElement = oc.getContainerElement();\n  }));\n\n  afterEach(() => {\n    overlayContainer.ngOnDestroy();\n  });\n\n  function getTitleText(): Element | null {\n    return overlayContainerElement.querySelector('.ant-popover-message-title');\n  }\n\n  function getTooltipTrigger(index: number): HTMLButtonElement {\n    return overlayContainerElement.querySelectorAll('.ant-popover-buttons button')[index] as HTMLButtonElement;\n  }\n\n  function waitingForTooltipToggling(): void {\n    fixture.detectChanges();\n    tick(500);\n    fixture.detectChanges();\n  }\n\n  it('should support custom icon', fakeAsync(() => {\n    component.icon = 'question-circle';\n    const triggerElement = component.iconTemplate.nativeElement;\n    dispatchMouseEvent(triggerElement, 'click');\n    waitingForTooltipToggling();\n    expect(overlayContainerElement.querySelector('.anticon-exclamation-circle')).toBeFalsy();\n  }));\n\n  it('should hide icon when nzIcon is set to null', fakeAsync(() => {\n    component.icon = null;\n    const triggerElement = component.iconTemplate.nativeElement;\n    dispatchMouseEvent(triggerElement, 'click');\n    waitingForTooltipToggling();\n    expect(overlayContainerElement.querySelector('.ant-popover-message-icon')).toBeFalsy();\n  }));\n\n  it('should nzOk work', () => {\n    const triggerElement = component.stringTemplate.nativeElement;\n    dispatchMouseEvent(triggerElement, 'click');\n    fixture.detectChanges();\n    expect(getTooltipTrigger(0).textContent).toContain('cancel-text');\n    expect(getTooltipTrigger(1).textContent).toContain('ok-text');\n    expect(getTooltipTrigger(1).classList).not.toContain('ant-btn-primary');\n  });\n\n  it('should support nzOkType danger case', () => {\n    component.nzOkType = 'danger';\n    fixture.detectChanges();\n\n    const triggerElement = component.stringTemplate.nativeElement;\n    dispatchMouseEvent(triggerElement, 'click');\n    fixture.detectChanges();\n\n    expect(getTooltipTrigger(1).classList).toContain('ant-btn-dangerous');\n    expect(getTooltipTrigger(1).classList).toContain('ant-btn-primary');\n  });\n\n  it('should support nzOkDisabled case', () => {\n    component.nzOkDisabled = true;\n    fixture.detectChanges();\n\n    const triggerElement = component.stringTemplate.nativeElement;\n    dispatchMouseEvent(triggerElement, 'click');\n    fixture.detectChanges();\n\n    expect(getTooltipTrigger(1).disabled).toBeTrue();\n  });\n\n  it('should support nzOkButtonProps', () => {\n    fixture.detectChanges();\n    const triggerElement = component.stringTemplate.nativeElement;\n    dispatchMouseEvent(triggerElement, 'click');\n    component.nzOkButtonProps.update(props => ({ ...props, nzDisabled: true }));\n    fixture.detectChanges();\n    expect(getTooltipTrigger(1).disabled).toBeTrue();\n  });\n\n  it('should support nzCancelButtonProps and disabled the cancel button', () => {\n    fixture.detectChanges();\n    const triggerElement = component.stringTemplate.nativeElement;\n    dispatchMouseEvent(triggerElement, 'click');\n    expect(getTooltipTrigger(0).disabled).toBeFalse();\n    component.nzCancelButtonProps.update(props => ({ ...props, nzDisabled: true }));\n    fixture.detectChanges();\n    expect(getTooltipTrigger(0).disabled).toBeTrue();\n  });\n\n  it('should support nzCancelButtonProps and support danger on close button', () => {\n    fixture.detectChanges();\n    const triggerElement = component.stringTemplate.nativeElement;\n    dispatchMouseEvent(triggerElement, 'click');\n    component.nzCancelButtonProps.update(props => ({ ...props, nzDanger: true }));\n    fixture.detectChanges();\n    expect(getTooltipTrigger(0).classList).toContain('ant-btn-dangerous');\n  });\n\n  it('should cancel work', fakeAsync(() => {\n    const triggerElement = component.stringTemplate.nativeElement;\n\n    dispatchMouseEvent(triggerElement, 'click');\n    fixture.detectChanges();\n    expect(getTitleText()!.textContent).toContain('title-string');\n    expect(component.confirm).toHaveBeenCalledTimes(0);\n    expect(component.cancel).toHaveBeenCalledTimes(0);\n\n    dispatchMouseEvent(getTooltipTrigger(0), 'click');\n    waitingForTooltipToggling();\n    expect(component.confirm).toHaveBeenCalledTimes(0);\n    expect(component.cancel).toHaveBeenCalledTimes(1);\n    expect(getTitleText()).toBeNull();\n  }));\n\n  it('should confirm work', fakeAsync(() => {\n    const triggerElement = component.stringTemplate.nativeElement;\n\n    dispatchMouseEvent(triggerElement, 'click');\n    fixture.detectChanges();\n    expect(getTitleText()!.textContent).toContain('title-string');\n    expect(component.confirm).toHaveBeenCalledTimes(0);\n    expect(component.cancel).toHaveBeenCalledTimes(0);\n\n    dispatchMouseEvent(getTooltipTrigger(1), 'click');\n    waitingForTooltipToggling();\n    expect(component.confirm).toHaveBeenCalledTimes(1);\n    expect(component.cancel).toHaveBeenCalledTimes(0);\n    expect(getTitleText()).toBeNull();\n  }));\n\n  it('should autofocus work', fakeAsync(() => {\n    let focusElement;\n\n    focusElement = fixture.debugElement.query(By.css(':focus'));\n    expect(focusElement).toBeNull();\n\n    component.autoFocus = 'cancel';\n    fixture.detectChanges();\n    focusElement = fixture.debugElement.query(By.css(':focus'));\n    expect(focusElement?.nativeElement).toBe(getTooltipTrigger(0));\n\n    component.autoFocus = 'ok';\n    fixture.detectChanges();\n    focusElement = fixture.debugElement.query(By.css(':focus'));\n    expect(focusElement?.nativeElement).toBe(getTooltipTrigger(1));\n  }));\n\n  it('should condition work', fakeAsync(() => {\n    expect(component.confirm).toHaveBeenCalledTimes(0);\n    expect(component.cancel).toHaveBeenCalledTimes(0);\n\n    component.condition = true;\n    fixture.detectChanges();\n    const triggerElement = component.stringTemplate.nativeElement;\n\n    dispatchMouseEvent(triggerElement, 'click');\n    fixture.detectChanges();\n    expect(getTitleText()).toBeNull();\n    expect(component.confirm).toHaveBeenCalledTimes(1);\n    expect(component.cancel).toHaveBeenCalledTimes(0);\n  }));\n\n  it('should before confirm work', fakeAsync(() => {\n    const triggerElement = component.stringTemplate.nativeElement;\n\n    dispatchMouseEvent(triggerElement, 'click');\n    fixture.detectChanges();\n    expect(getTitleText()!.textContent).toContain('title-string');\n    expect(component.confirm).toHaveBeenCalledTimes(0);\n    expect(component.cancel).toHaveBeenCalledTimes(0);\n\n    component.beforeConfirm = () => false;\n    fixture.detectChanges();\n\n    dispatchMouseEvent(getTooltipTrigger(1), 'click');\n    waitingForTooltipToggling();\n    expect(component.confirm).toHaveBeenCalledTimes(0);\n    expect(component.cancel).toHaveBeenCalledTimes(0);\n    expect(getTitleText()!.textContent).toContain('title-string');\n  }));\n\n  it('should before confirm observable work', fakeAsync(() => {\n    const triggerElement = component.stringTemplate.nativeElement;\n\n    dispatchMouseEvent(triggerElement, 'click');\n    fixture.detectChanges();\n    expect(getTitleText()!.textContent).toContain('title-string');\n    expect(component.confirm).toHaveBeenCalledTimes(0);\n    expect(component.cancel).toHaveBeenCalledTimes(0);\n\n    component.beforeConfirm = () =>\n      new Observable(observer => {\n        setTimeout(() => {\n          observer.next(true);\n          observer.complete();\n        }, 200);\n      });\n\n    dispatchMouseEvent(getTooltipTrigger(1), 'click');\n    tick(200 + 10);\n    waitingForTooltipToggling();\n    expect(getTitleText()).toBeNull();\n    expect(component.confirm).toHaveBeenCalledTimes(1);\n    expect(component.cancel).toHaveBeenCalledTimes(0);\n  }));\n\n  it('should before confirm promise work', fakeAsync(() => {\n    const triggerElement = component.stringTemplate.nativeElement;\n\n    dispatchMouseEvent(triggerElement, 'click');\n    fixture.detectChanges();\n    expect(getTitleText()!.textContent).toContain('title-string');\n    expect(component.confirm).toHaveBeenCalledTimes(0);\n    expect(component.cancel).toHaveBeenCalledTimes(0);\n\n    component.beforeConfirm = () =>\n      new Promise(resolve => {\n        setTimeout(() => {\n          resolve(true);\n        }, 200);\n      });\n\n    dispatchMouseEvent(getTooltipTrigger(1), 'click');\n    tick(200 + 10);\n    waitingForTooltipToggling();\n    expect(getTitleText()).toBeNull();\n    expect(component.confirm).toHaveBeenCalledTimes(1);\n    expect(component.cancel).toHaveBeenCalledTimes(0);\n  }));\n\n  it('should nzPopconfirmShowArrow work', fakeAsync(() => {\n    const triggerElement = component.stringTemplate.nativeElement;\n    dispatchMouseEvent(triggerElement, 'click');\n\n    component.nzPopconfirmShowArrow = false;\n    fixture.detectChanges();\n    expect(overlayContainerElement.querySelector('.ant-popover-arrow')).toBeFalsy();\n\n    component.nzPopconfirmShowArrow = true;\n    fixture.detectChanges();\n    expect(overlayContainerElement.querySelector('.ant-popover-arrow')).toBeTruthy();\n  }));\n\n  it('should nzPopconfirmBackdrop work', fakeAsync(() => {\n    component.nzPopconfirmBackdrop = true;\n    fixture.detectChanges();\n    const triggerElement = component.stringTemplate.nativeElement;\n    dispatchMouseEvent(triggerElement, 'click');\n    fixture.detectChanges();\n    const boundingBox = overlayContainerElement.children[0];\n    expect(boundingBox.children[0].classList).toContain('cdk-overlay-backdrop');\n  }));\n\n  it('should change overlayClass when the nzPopconfirmOverlayClassName is changed', fakeAsync(() => {\n    const triggerElement = component.stringTemplate.nativeElement;\n\n    dispatchMouseEvent(triggerElement, 'click');\n    waitingForTooltipToggling();\n\n    component.class = 'testClass2';\n    fixture.detectChanges();\n\n    expect(overlayContainerElement.querySelector<HTMLElement>('.testClass')).toBeNull();\n    expect(overlayContainerElement.querySelector<HTMLElement>('.testClass2')).not.toBeNull();\n  }));\n\n  it('should nzPopconfirmOverlayClassName support classes listed in the string (space delimited)', fakeAsync(() => {\n    const triggerElement = component.stringTemplate.nativeElement;\n    component.class = 'testClass1 testClass2';\n\n    dispatchMouseEvent(triggerElement, 'click');\n    waitingForTooltipToggling();\n\n    expect(overlayContainerElement.querySelector('.testClass1.testClass2')).not.toBeNull();\n  }));\n});\n\n@Component({\n  imports: [NzPopconfirmModule],\n  template: `\n    <a\n      nz-popconfirm\n      #stringTemplate\n      nzPopconfirmTitle=\"title-string\"\n      nzOkText=\"ok-text\"\n      [nzOkType]=\"nzOkType\"\n      [nzOkDisabled]=\"nzOkDisabled\"\n      nzCancelText=\"cancel-text\"\n      [nzAutofocus]=\"autoFocus\"\n      [nzCondition]=\"condition\"\n      [nzBeforeConfirm]=\"beforeConfirm\"\n      [nzPopconfirmShowArrow]=\"nzPopconfirmShowArrow\"\n      [nzPopconfirmBackdrop]=\"nzPopconfirmBackdrop\"\n      [nzPopconfirmOverlayClassName]=\"class\"\n      (nzOnConfirm)=\"confirm()\"\n      (nzOnCancel)=\"cancel()\"\n      [nzOkButtonProps]=\"nzOkButtonProps()\"\n      [nzCancelButtonProps]=\"nzCancelButtonProps()\"\n    >\n      Delete\n    </a>\n    <a\n      nz-popconfirm\n      #templateTemplate\n      [nzIcon]=\"icon\"\n      [nzPopconfirmTitle]=\"titleTemplate\"\n      (nzOnConfirm)=\"confirm()\"\n      (nzOnCancel)=\"cancel()\"\n    >\n      Delete\n    </a>\n\n    <a nz-popconfirm #iconTemplate [nzIcon]=\"icon\">Delete</a>\n\n    <ng-template #titleTemplate>title-template</ng-template>\n  `\n})\nexport class NzPopconfirmTestNewComponent {\n  confirm = jasmine.createSpy('confirm');\n  cancel = jasmine.createSpy('cancel');\n  condition = false;\n  nzOkType: string = 'default';\n  nzOkDisabled: boolean = false;\n  nzCancelText = 'Cancel';\n  nzOkText = 'Ok';\n  nzOkButtonProps = signal<NzPopConfirmButtonProps>({ nzDisabled: false });\n  nzCancelButtonProps = signal<NzPopConfirmButtonProps>({ nzDisabled: false });\n  nzPopconfirmShowArrow = true;\n  icon: string | null | undefined = undefined;\n  nzPopconfirmBackdrop = false;\n  autoFocus: NzAutoFocusType = null;\n  beforeConfirm?: () => Observable<boolean> | Promise<boolean> | boolean = undefined;\n\n  @ViewChild('stringTemplate', { static: false }) stringTemplate!: ElementRef;\n  @ViewChild('templateTemplate', { static: false }) templateTemplate!: ElementRef;\n  @ViewChild('iconTemplate', { static: false }) iconTemplate!: ElementRef;\n\n  visible = false;\n  class = 'testClass';\n}\n"
  },
  {
    "path": "components/popconfirm/popconfirm.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { A11yModule } from '@angular/cdk/a11y';\nimport { OverlayModule } from '@angular/cdk/overlay';\nimport {\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  Component,\n  computed,\n  Directive,\n  DOCUMENT,\n  ElementRef,\n  EventEmitter,\n  inject,\n  input,\n  Input,\n  Output,\n  QueryList,\n  signal,\n  TemplateRef,\n  ViewChildren,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { filter, Observable, Subject } from 'rxjs';\nimport { finalize, first } from 'rxjs/operators';\n\nimport { NzButtonModule, NzButtonType } from 'ng-zorro-antd/button';\nimport { NzNoAnimationDirective } from 'ng-zorro-antd/core/animation';\nimport { NzConfigKey, WithConfig } from 'ng-zorro-antd/core/config';\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzOverlayModule } from 'ng-zorro-antd/core/overlay';\nimport { NgStyleInterface, NzTSType } from 'ng-zorro-antd/core/types';\nimport { wrapIntoObservable } from 'ng-zorro-antd/core/util';\nimport { NzI18nModule } from 'ng-zorro-antd/i18n';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzTooltipBaseDirective, NzTooltipComponent, NzTooltipTrigger, PropertyMapping } from 'ng-zorro-antd/tooltip';\n\nimport { NzPopConfirmButtonProps } from './popconfirm-option';\n\nexport type NzAutoFocusType = null | 'ok' | 'cancel';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'popconfirm';\n\n@Directive({\n  selector: '[nz-popconfirm]',\n  exportAs: 'nzPopconfirm',\n  host: {\n    '[class.ant-popover-open]': 'visible'\n  }\n})\nexport class NzPopconfirmDirective extends NzTooltipBaseDirective {\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  /* eslint-disable @angular-eslint/no-input-rename, @angular-eslint/no-output-rename */\n  @Input({ alias: 'nzPopconfirmArrowPointAtCenter', transform: booleanAttribute })\n  override arrowPointAtCenter?: boolean;\n  @Input('nzPopconfirmTitle') override title?: NzTSType;\n  @Input('nzPopconfirmTitleContext') titleContext?: object | null = null;\n  @Input('nz-popconfirm') override directiveTitle?: NzTSType | null;\n  @Input('nzPopconfirmTrigger') override trigger?: NzTooltipTrigger = 'click';\n  @Input('nzPopconfirmPlacement') override placement?: string | string[] = 'top';\n  @Input('nzPopconfirmOrigin') override origin?: ElementRef<HTMLElement>;\n  @Input('nzPopconfirmMouseEnterDelay') override mouseEnterDelay?: number;\n  @Input('nzPopconfirmMouseLeaveDelay') override mouseLeaveDelay?: number;\n  @Input('nzPopconfirmOverlayClassName') override overlayClassName?: string;\n  @Input('nzPopconfirmOverlayStyle') override overlayStyle?: NgStyleInterface;\n  @Input('nzPopconfirmVisible') override visible?: boolean;\n  @Input() nzBeforeConfirm?: () => Observable<boolean> | Promise<boolean> | boolean;\n  @Input() nzIcon?: string | TemplateRef<void> | null;\n  @Input({ transform: booleanAttribute }) nzCondition: boolean = false;\n  @Input({ transform: booleanAttribute }) nzPopconfirmShowArrow: boolean = true;\n  @Input() @WithConfig() nzPopconfirmBackdrop?: boolean = false;\n  @Input() @WithConfig() nzAutofocus: NzAutoFocusType = null;\n\n  nzOkText = input<string | null>(null);\n  nzOkType = input<string>('primary');\n  nzCancelText = input<string | null>(null);\n  nzOkButtonProps = input<null | NzPopConfirmButtonProps>(null);\n  nzCancelButtonProps = input<null | NzPopConfirmButtonProps>(null);\n  /**\n   * @deprecated v21\n   * please use the nzOkButton object input to describe option of the ok button\n   */\n  nzOkDisabled = input(false, { transform: booleanAttribute });\n  /**\n   * @deprecated v21\n   * please use the nzOkButton object input to describe option of the ok button\n   */\n  nzOkDanger = input(false, { transform: booleanAttribute });\n\n  private okButtonProps = computed(() => ({\n    ...this.nzOkButtonProps(),\n    nzType: this.nzOkButtonProps()?.nzType || this.nzOkType() === 'danger' ? 'primary' : this.nzOkType(),\n    nzDanger: this.nzOkDanger() || this.nzOkButtonProps()?.nzDanger || this.nzOkType() === 'danger',\n    nzDisabled: this.nzOkDisabled() || this.nzOkButtonProps()?.nzDisabled\n  }));\n  private cancelButtonProps = computed(() => ({\n    ...this.nzCancelButtonProps()\n  }));\n\n  override directiveContent?: NzTSType | null = null;\n  override content?: NzTSType | null = null;\n  override overlayClickable?: boolean;\n\n  @Output('nzPopconfirmVisibleChange') override readonly visibleChange = new EventEmitter<boolean>();\n  @Output() readonly nzOnCancel = new EventEmitter<void>();\n  @Output() readonly nzOnConfirm = new EventEmitter<void>();\n\n  protected override getProxyPropertyMap(): PropertyMapping {\n    return {\n      nzOkText: ['nzOkText', () => this.nzOkText],\n      nzCancelText: ['nzCancelText', () => this.nzCancelText],\n      nzOkButtonProps: ['nzOkButtonProps', () => this.okButtonProps],\n      nzCancelButtonProps: ['nzCancelButtonProps', () => this.cancelButtonProps],\n      nzBeforeConfirm: ['nzBeforeConfirm', () => this.nzBeforeConfirm],\n      nzCondition: ['nzCondition', () => this.nzCondition],\n      nzIcon: ['nzIcon', () => this.nzIcon],\n      nzPopconfirmShowArrow: ['nzPopconfirmShowArrow', () => this.nzPopconfirmShowArrow],\n      nzPopconfirmBackdrop: ['nzBackdrop', () => this.nzPopconfirmBackdrop],\n      nzPopconfirmContext: ['nzTitleContext', () => this.titleContext],\n      nzAutoFocus: ['nzAutoFocus', () => this.nzAutofocus],\n      ...super.getProxyPropertyMap()\n    };\n  }\n\n  constructor() {\n    super(NzPopconfirmComponent);\n  }\n\n  /**\n   * @override\n   */\n  protected override createComponent(): void {\n    super.createComponent();\n\n    (this.component as NzPopconfirmComponent).nzOnCancel.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      this.nzOnCancel.emit();\n    });\n    (this.component as NzPopconfirmComponent).nzOnConfirm.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      this.nzOnConfirm.emit();\n    });\n  }\n}\n\n@Component({\n  selector: 'nz-popconfirm',\n  exportAs: 'nzPopconfirmComponent',\n  template: `\n    <ng-template\n      #overlay=\"cdkConnectedOverlay\"\n      cdkConnectedOverlay\n      nzConnectedOverlay\n      [cdkConnectedOverlayHasBackdrop]=\"nzBackdrop\"\n      [cdkConnectedOverlayOrigin]=\"origin\"\n      (overlayOutsideClick)=\"onClickOutside($event)\"\n      (detach)=\"hide()\"\n      (positionChange)=\"onPositionChange($event)\"\n      [cdkConnectedOverlayPositions]=\"_positions\"\n      [cdkConnectedOverlayOpen]=\"_visible\"\n      [cdkConnectedOverlayPush]=\"cdkConnectedOverlayPush\"\n      [nzArrowPointAtCenter]=\"nzArrowPointAtCenter\"\n    >\n      <div\n        cdkTrapFocus\n        [cdkTrapFocusAutoCapture]=\"nzAutoFocus !== null\"\n        class=\"ant-popover\"\n        [class]=\"_classMap\"\n        [class.ant-popover-rtl]=\"dir() === 'rtl'\"\n        [style]=\"nzOverlayStyle\"\n        [nzNoAnimation]=\"!!noAnimation?.nzNoAnimation?.()\"\n        [animate.enter]=\"zoomAnimationEnter()\"\n        [animate.leave]=\"zoomAnimationLeave()\"\n      >\n        @if (nzPopconfirmShowArrow) {\n          <div class=\"ant-popover-arrow\"></div>\n        }\n        <div class=\"ant-popover-content\">\n          <div class=\"ant-popover-inner\">\n            <div>\n              <div class=\"ant-popover-inner-content\">\n                <div class=\"ant-popover-message\">\n                  @if (nzIcon !== null) {\n                    <span class=\"ant-popover-message-icon\">\n                      <ng-container *nzStringTemplateOutlet=\"nzIcon; let icon\">\n                        <nz-icon [nzType]=\"icon || 'exclamation-circle'\" nzTheme=\"fill\" />\n                      </ng-container>\n                    </span>\n                  }\n                  <div class=\"ant-popover-message-title\">\n                    <ng-container *nzStringTemplateOutlet=\"nzTitle; context: nzTitleContext\">\n                      {{ nzTitle }}\n                    </ng-container>\n                  </div>\n                </div>\n                <div class=\"ant-popover-buttons\">\n                  <button\n                    nz-button\n                    #cancelBtn\n                    nzSize=\"small\"\n                    [nzDanger]=\"nzCancelButtonProps()?.nzDanger\"\n                    (click)=\"onCancel()\"\n                    [disabled]=\"nzCancelButtonProps()?.nzDisabled\"\n                    [attr.cdkFocusInitial]=\"nzAutoFocus === 'cancel' || null\"\n                  >\n                    @let cancelText = nzCancelText() || ('Modal.cancelText' | nzI18n);\n                    {{ cancelText }}\n                  </button>\n                  <button\n                    nz-button\n                    #okBtn\n                    nzSize=\"small\"\n                    [nzType]=\"nzOkButtonProps().nzType\"\n                    [nzDanger]=\"nzOkButtonProps().nzDanger\"\n                    [nzLoading]=\"confirmLoading\"\n                    [disabled]=\"nzOkButtonProps().nzDisabled\"\n                    (click)=\"onConfirm()\"\n                    [attr.cdkFocusInitial]=\"nzAutoFocus === 'ok' || null\"\n                  >\n                    @let okText = nzOkText() || ('Modal.okText' | nzI18n);\n                    {{ okText }}\n                  </button>\n                </div>\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n    </ng-template>\n  `,\n  imports: [\n    OverlayModule,\n    NzOverlayModule,\n    A11yModule,\n    NzNoAnimationDirective,\n    NzOutletModule,\n    NzIconModule,\n    NzButtonModule,\n    NzI18nModule\n  ],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None\n})\nexport class NzPopconfirmComponent extends NzTooltipComponent {\n  protected override _animationPrefix = 'ant-zoom-big';\n  @ViewChildren('okBtn', { read: ElementRef }) okBtn!: QueryList<ElementRef>;\n  @ViewChildren('cancelBtn', { read: ElementRef }) cancelBtn!: QueryList<ElementRef>;\n\n  nzCondition = false;\n  nzPopconfirmShowArrow = true;\n  nzIcon?: string | TemplateRef<void> | null;\n  nzAutoFocus: NzAutoFocusType = null;\n  nzBeforeConfirm: (() => Observable<boolean> | Promise<boolean> | boolean) | null = null;\n\n  nzOkText = signal<string | null>(null);\n  nzCancelText = signal<string | null>(null);\n  nzOkButtonProps = signal<NzPopConfirmButtonProps & { nzType: NzButtonType }>({ nzType: 'primary' });\n  nzCancelButtonProps = signal<NzPopConfirmButtonProps | null>(null);\n\n  readonly nzOnCancel = new Subject<void>();\n  readonly nzOnConfirm = new Subject<void>();\n\n  protected override _trigger: NzTooltipTrigger = 'click';\n  private elementFocusedBeforeModalWasOpened: HTMLElement | null = null;\n  private document = inject(DOCUMENT);\n\n  override _prefix = 'ant-popover';\n\n  confirmLoading = false;\n\n  constructor() {\n    super();\n    this.destroyRef.onDestroy(() => {\n      this.nzVisibleChange.complete();\n    });\n  }\n\n  override show(): void {\n    if (!this.nzCondition) {\n      this.capturePreviouslyFocusedElement();\n      super.show();\n    } else {\n      this.onConfirm();\n    }\n  }\n\n  override hide(): void {\n    super.hide();\n    this.restoreFocus();\n  }\n\n  handleConfirm(): void {\n    this.nzOnConfirm.next();\n    super.hide();\n  }\n\n  onCancel(): void {\n    this.nzOnCancel.next();\n    super.hide();\n  }\n\n  onConfirm(): void {\n    if (this.nzBeforeConfirm) {\n      this.confirmLoading = true;\n      this.cdr.markForCheck();\n\n      wrapIntoObservable(this.nzBeforeConfirm())\n        .pipe(\n          first(),\n          filter(Boolean),\n          finalize(() => {\n            this.confirmLoading = false;\n            this.cdr.markForCheck();\n          })\n        )\n        .subscribe(() => this.handleConfirm());\n    } else {\n      this.handleConfirm();\n    }\n  }\n\n  private capturePreviouslyFocusedElement(): void {\n    if (this.document) {\n      this.elementFocusedBeforeModalWasOpened = this.document.activeElement as HTMLElement;\n    }\n  }\n\n  private restoreFocus(): void {\n    this.elementFocusedBeforeModalWasOpened?.focus();\n  }\n}\n"
  },
  {
    "path": "components/popconfirm/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './popconfirm';\nexport * from './popconfirm.module';\nexport * from './popconfirm-option';\n"
  },
  {
    "path": "components/popconfirm/style/entry.less",
    "content": "// style dependencies\n// deps-lint-skip: tooltip, popover\n@import '../../popover/style/entry.less';\n@import '../../button/style/entry.less';\n@import './patch';\n"
  },
  {
    "path": "components/popconfirm/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@popconfirm-prefix-cls: ~'@{ant-prefix}-popconfirm';\n\n.@{popconfirm-prefix-cls} {\n  z-index: @zindex-popoconfirm;\n}\n"
  },
  {
    "path": "components/popconfirm/style/patch.less",
    "content": ".ant-popover {\n  position: relative;\n}\n"
  },
  {
    "path": "components/popover/demo/arrow-point-at-center.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 箭头指向\n  en-US: Arrow pointing at the center\n---\n\n## zh-CN\n\n通过设置 `nzPopoverPlacement` ，可以箭头将指向目标元素的中心。\n\n## en-US\n\nBy specifying `nzPopoverPlacement` prop, the arrow can be point to the center of the target element.\n"
  },
  {
    "path": "components/popover/demo/arrow-point-at-center.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzNoAnimationDirective } from 'ng-zorro-antd/core/animation';\nimport { NzPopoverModule } from 'ng-zorro-antd/popover';\n\n@Component({\n  selector: 'nz-demo-popover-arrow-point-at-center',\n  imports: [NzButtonModule, NzPopoverModule, NzNoAnimationDirective],\n  template: `\n    <button nz-button nzPopoverTitle=\"Title\" nzPopoverContent=\"Content\" nzPopoverPlacement=\"topLeft\" nz-popover>\n      Align edge / 边缘对齐\n    </button>\n    <button\n      nz-button\n      nz-popover\n      nzPopoverTitle=\"Title\"\n      nzPopoverContent=\"Content\"\n      nzPopoverPlacement=\"topLeft\"\n      [nzPopoverArrowPointAtCenter]=\"true\"\n      nzNoAnimation\n    >\n      Arrow points to center / 箭头指向中心\n    </button>\n  `,\n  styles: `\n    button {\n      margin-right: 8px;\n      margin-bottom: 8px;\n    }\n  `\n})\nexport class NzDemoPopoverArrowPointAtCenterComponent {}\n"
  },
  {
    "path": "components/popover/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n最简单的用法，浮层的大小由内容区域决定。\n\n## en-US\n\nThe most basic example. The size of the floating layer depends on the contents region.\n"
  },
  {
    "path": "components/popover/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzPopoverModule } from 'ng-zorro-antd/popover';\n\n@Component({\n  selector: 'nz-demo-popover-basic',\n  imports: [NzButtonModule, NzPopoverModule],\n  template: `\n    <button nz-button nz-popover nzType=\"primary\" nzPopoverTitle=\"Title\" nzPopoverContent=\"Content\">Hover me</button>\n  `\n})\nexport class NzDemoPopoverBasicComponent {}\n"
  },
  {
    "path": "components/popover/demo/control.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 从浮层内关闭\n  en-US: Controlling the close of the dialog\n---\n\n## zh-CN\n\n使用 `nzPopoverVisible` 属性控制浮层显示。\n\n## en-US\n\nUse `nzPopoverVisible` prop to control the display of the card.\n"
  },
  {
    "path": "components/popover/demo/control.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzPopoverModule } from 'ng-zorro-antd/popover';\n\n@Component({\n  selector: 'nz-demo-popover-control',\n  imports: [NzButtonModule, NzPopoverModule],\n  template: `\n    <button\n      nz-button\n      nzType=\"primary\"\n      nz-popover\n      nzPopoverTitle=\"Title\"\n      [(nzPopoverVisible)]=\"visible\"\n      (nzPopoverVisibleChange)=\"change($event)\"\n      nzPopoverTrigger=\"click\"\n      [nzPopoverContent]=\"contentTemplate\"\n    >\n      Click me\n    </button>\n    <ng-template #contentTemplate>\n      <a (click)=\"clickMe()\">Close</a>\n    </ng-template>\n  `\n})\nexport class NzDemoPopoverControlComponent {\n  visible: boolean = false;\n\n  clickMe(): void {\n    this.visible = false;\n  }\n\n  change(value: boolean): void {\n    console.log(value);\n  }\n}\n"
  },
  {
    "path": "components/popover/demo/overlay.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 禁止通过蒙层关闭面板\n  en-US: Disable closing popover through mask\n---\n\n## zh-CN\n\n在 `nzPopoverTrigger` 为 `'click'` 时，通过设置 `nzPopoverOverlayClickable` 为 `false` 禁止通过点击蒙层关闭面板。\n\n## en-US\n\nSet `nzPopoverOverlayClickable` to be `false` to disable closing popover by clicking the mask when `nzPopoverTrigger` is `'click'`.\n"
  },
  {
    "path": "components/popover/demo/overlay.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzPopoverModule } from 'ng-zorro-antd/popover';\n\n@Component({\n  selector: 'nz-demo-popover-overlay',\n  imports: [NzButtonModule, NzPopoverModule],\n  template: `\n    <button\n      nz-button\n      nz-popover\n      nzType=\"primary\"\n      nzPopoverTitle=\"Title\"\n      nzPopoverTrigger=\"click\"\n      [nzPopoverContent]=\"contentTemplate\"\n      [nzPopoverOverlayClickable]=\"false\"\n      [nzPopoverVisible]=\"visible\"\n      (nzPopoverVisibleChange)=\"visibleChange($event)\"\n      >Click me</button\n    >\n    <ng-template #contentTemplate>\n      <button nz-button nzSize=\"small\" nzType=\"primary\" (click)=\"visibleChange(false)\"> Close me </button>\n    </ng-template>\n  `\n})\nexport class NzDemoPopoverOverlayComponent {\n  visible = false;\n\n  visibleChange(value: boolean): void {\n    this.visible = value;\n  }\n}\n"
  },
  {
    "path": "components/popover/demo/placement.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 位置\n  en-US: Placement\n---\n\n## zh-CN\n\n位置有十二个方向。\n\n## en-US\n\nThere are 12 `placement` options available.\n"
  },
  {
    "path": "components/popover/demo/placement.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzPopoverModule } from 'ng-zorro-antd/popover';\n\n@Component({\n  selector: 'nz-demo-popover-placement',\n  imports: [NzButtonModule, NzPopoverModule],\n  template: `\n    <div style=\"margin-left: 60px\">\n      <button\n        nz-button\n        nz-popover\n        nzPopoverTitle=\"Title\"\n        [nzPopoverContent]=\"contentTemplate\"\n        nzPopoverPlacement=\"topLeft\"\n      >\n        TL\n      </button>\n      <button nz-button nz-popover nzPopoverTitle=\"Title\" [nzPopoverContent]=\"contentTemplate\" nzPopoverPlacement=\"top\">\n        Top\n      </button>\n      <button\n        nz-button\n        nz-popover\n        nzPopoverTitle=\"Title\"\n        [nzPopoverContent]=\"contentTemplate\"\n        nzPopoverPlacement=\"topRight\"\n      >\n        TR\n      </button>\n    </div>\n    <div style=\"width: 60px; float: left;\">\n      <button\n        nz-button\n        nz-popover\n        nzPopoverTitle=\"Title\"\n        [nzPopoverContent]=\"contentTemplate\"\n        nzPopoverPlacement=\"leftTop\"\n      >\n        LT\n      </button>\n      <button\n        nz-button\n        nz-popover\n        nzPopoverTitle=\"Title\"\n        [nzPopoverContent]=\"contentTemplate\"\n        nzPopoverPlacement=\"left\"\n      >\n        Left\n      </button>\n      <button\n        nz-button\n        nz-popover\n        nzPopoverTitle=\"Title\"\n        [nzPopoverContent]=\"contentTemplate\"\n        nzPopoverPlacement=\"leftBottom\"\n      >\n        LB\n      </button>\n    </div>\n    <div style=\"width: 60px; margin-left: 252px;\">\n      <button\n        nz-button\n        nz-popover\n        nzPopoverTitle=\"Title\"\n        [nzPopoverContent]=\"contentTemplate\"\n        nzPopoverPlacement=\"rightTop\"\n      >\n        RT\n      </button>\n      <button\n        nz-button\n        nz-popover\n        nzPopoverTitle=\"Title\"\n        [nzPopoverContent]=\"contentTemplate\"\n        nzPopoverPlacement=\"right\"\n      >\n        Right\n      </button>\n      <button\n        nz-button\n        nz-popover\n        nzPopoverTitle=\"Title\"\n        [nzPopoverContent]=\"contentTemplate\"\n        nzPopoverPlacement=\"rightBottom\"\n      >\n        RB\n      </button>\n    </div>\n    <div style=\"margin-left: 60px; clear: both;\">\n      <button\n        nz-button\n        nz-popover\n        nzPopoverTitle=\"Title\"\n        [nzPopoverContent]=\"contentTemplate\"\n        nzPopoverPlacement=\"bottomLeft\"\n      >\n        BL\n      </button>\n      <button\n        nz-button\n        nz-popover\n        nzPopoverTitle=\"Title\"\n        [nzPopoverContent]=\"contentTemplate\"\n        nzPopoverPlacement=\"bottom\"\n      >\n        Bottom\n      </button>\n      <button\n        nz-button\n        nz-popover\n        nzPopoverTitle=\"Title\"\n        [nzPopoverContent]=\"contentTemplate\"\n        nzPopoverPlacement=\"bottomRight\"\n      >\n        BR\n      </button>\n    </div>\n    <ng-template #contentTemplate>\n      <div>\n        <p>Content</p>\n        <p>Content</p>\n      </div>\n    </ng-template>\n  `,\n  styles: `\n    button {\n      margin-right: 8px;\n      margin-bottom: 8px;\n      width: 70px;\n      text-align: center;\n      padding: 0;\n    }\n  `\n})\nexport class NzDemoPopoverPlacementComponent {}\n"
  },
  {
    "path": "components/popover/demo/template.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 模板渲染\n  en-US: Template\n---\n\n## zh-CN\n\n`nzPopoverContent` 与 `nzPopoverTitle` 可以传入 `TemplateRef<void>` 模板渲染。\n\n## en-US\n\n`nzPopoverContent` and `nzPopoverTitle` accept the type of `TemplateRef<void>`\n"
  },
  {
    "path": "components/popover/demo/template.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzPopoverModule } from 'ng-zorro-antd/popover';\n\n@Component({\n  selector: 'nz-demo-popover-template',\n  imports: [NzButtonModule, NzIconModule, NzPopoverModule],\n  template: `\n    <button nz-button nz-popover [nzPopoverTitle]=\"titleTemplate\" [nzPopoverContent]=\"contentTemplate\">\n      Render Template\n    </button>\n    <ng-template #titleTemplate>\n      <nz-icon nzType=\"close\" />\n      Title\n    </ng-template>\n    <ng-template #contentTemplate>\n      <nz-icon nzType=\"check\" />\n      Content\n    </ng-template>\n  `\n})\nexport class NzDemoPopoverTemplateComponent {}\n"
  },
  {
    "path": "components/popover/demo/trigger-type.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 三种触发方式\n  en-US: Three ways to trigger\n---\n\n## zh-CN\n\n鼠标移入、聚集、点击。\n\n## en-US\n\nMouse to click, focus and move in.\n"
  },
  {
    "path": "components/popover/demo/trigger-type.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzPopoverModule } from 'ng-zorro-antd/popover';\n\n@Component({\n  selector: 'nz-demo-popover-trigger-type',\n  imports: [NzButtonModule, NzPopoverModule],\n  template: `\n    <ng-template #contentTemplate>\n      <div>\n        <p>Content</p>\n        <p>Content</p>\n      </div>\n    </ng-template>\n    <button nz-button nz-popover nzPopoverTitle=\"Title\" [nzPopoverContent]=\"contentTemplate\" nzPopoverTrigger=\"click\">\n      Click me\n    </button>\n    <button nz-button nz-popover nzPopoverTitle=\"Title\" [nzPopoverContent]=\"contentTemplate\" nzPopoverTrigger=\"hover\">\n      Hover me\n    </button>\n    <button nz-button nz-popover nzPopoverTitle=\"Title\" [nzPopoverContent]=\"contentTemplate\" nzPopoverTrigger=\"focus\">\n      Focus me\n    </button>\n  `,\n  styles: `\n    button {\n      margin-right: 8px;\n    }\n  `\n})\nexport class NzDemoPopoverTriggerTypeComponent {}\n"
  },
  {
    "path": "components/popover/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Display\ntitle: Popover\ncover: 'https://gw.alipayobjects.com/zos/alicdn/1PNL1p_cO/Popover.svg'\ndescription: The floating card popped by clicking or hovering.\n---\n\n## When To Use\n\nA simple popup menu to provide extra information or operations.\n\nComparing with `Tooltip`, besides information `Popover` card can also provide action elements like links and buttons.\n\n## API\n\n### [nz-popover]\n\n| Param                           | Description                                                                        | Type                                                                                                                                                                              | Default value |\n| ------------------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |\n| `[nzPopoverArrowPointAtCenter]` | Arrow point at center of the origin                                                | `boolean`                                                                                                                                                                         | `false`       |\n| `[nzPopoverTitle]`              | Title of the popover                                                               | `string \\| TemplateRef<void>`                                                                                                                                                     | -             |\n| `[nzPopoverTitleContext]`       | The context of Title                                                               | `object`                                                                                                                                                                          | -             |\n| `[nzPopoverContent]`            | Content of the popover                                                             | `string \\| TemplateRef<void>`                                                                                                                                                     | -             |\n| `[nzPopoverContentContext]`     | The context of Content                                                             | `object`                                                                                                                                                                          | -             |\n| `[nzPopoverTrigger]`            | Popover trigger mode. If set to `null` it would not be triggered                   | `'click' \\| 'focus' \\| 'hover' \\| null`                                                                                                                                           | `'hover'`     |\n| `[nzPopoverPlacement]`          | The position of the popover relative to the target                                 | `'top' \\| 'left' \\| 'right' \\| 'bottom' \\| 'topLeft' \\| 'topRight' \\| 'bottomLeft' \\| 'bottomRight' \\| 'leftTop' \\| 'leftBottom' \\| 'rightTop' \\| 'rightBottom' \\| Array<string>` | `'top'`       |\n| `[nzPopoverOrigin]`             | Origin of the tooltip                                                              | `ElementRef`                                                                                                                                                                      | -             |\n| `[nzPopoverVisible]`            | Show or hide popover                                                               | `boolean`                                                                                                                                                                         | `false`       |\n| `(nzPopoverVisibleChange)`      | Callback of hide or show                                                           | `EventEmitter<boolean>`                                                                                                                                                           | -             |\n| `[nzPopoverMouseEnterDelay]`    | Delay in seconds, before popover is shown on mouse enter                           | `number`                                                                                                                                                                          | `0.15`        |\n| `[nzPopoverMouseLeaveDelay]`    | Delay in seconds, before popover is hidden on mouse leave                          | `number`                                                                                                                                                                          | `0.1`         |\n| `[nzPopoverOverlayClassName]`   | Class name of the popover card                                                     | `string`                                                                                                                                                                          | -             |\n| `[nzPopoverOverlayStyle]`       | Style of the popover card                                                          | `object`                                                                                                                                                                          | -             |\n| `[nzPopoverOverlayClickable]`   | Click the mask to close the bubble box. Only the `click` trigger behavior is valid | `boolean`                                                                                                                                                                         | `true`        |\n\nConsult [Tooltip's documentation](/components/tooltip/en#api) to find more APIs.\n| `[nzPopoverBackdrop]` | whether or not the overlay should attach a backdrop | `boolean` | `false` |\n\n## Note\n\nPlease ensure that the node of `[nz-popover]` accepts `onMouseEnter`, `onMouseLeave`, `onFocus`, `onClick` events.\n\n## FAQ\n\n### Q: The overlay layer element does not follow the scroll position when scrolling\n\nBy default, the overlay layer element uses body as the scroll container. If using another scroll container, add the [CdkScrollable](https://material.angular.dev/cdk/scrolling/api#CdkScrollable) directive to the custom scroll container element.\nNote: You need to import the `CdkScrollable` directive or `ScrollingModule` module from `@angular/cdk/scrolling`.\n"
  },
  {
    "path": "components/popover/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 气泡卡片\ntype: 数据展示\ntitle: Popover\ncover: 'https://gw.alipayobjects.com/zos/alicdn/1PNL1p_cO/Popover.svg'\ndescription: 点击/鼠标移入元素，弹出气泡式的卡片浮层。\n---\n\n## 何时使用\n\n当目标元素有进一步的描述和相关操作时，可以收纳到卡片中，根据用户的操作行为进行展现。\n\n和 `Tooltip` 的区别是，用户可以对浮层上的元素进行操作，因此它可以承载更复杂的内容，比如链接或按钮等。\n\n## API\n\n### [nz-popover]\n\n| 参数                            | 说明                                      | 类型                                                                                                                                                                              | 默认值    |\n| ------------------------------- | ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- |\n| `[nzPopoverArrowPointAtCenter]` | 箭头指向锚点的中心                        | `boolean`                                                                                                                                                                         | `false`   |\n| `[nzPopoverTitle]`              | 标题                                      | `string \\| TemplateRef<void>`                                                                                                                                                     | -         |\n| `[nzPopoverTitleContext]`       | 标题的上下文                              | `object`                                                                                                                                                                          | -         |\n| `[nzPopoverContent]`            | 用于定义内容                              | `string \\| TemplateRef<void>`                                                                                                                                                     | -         |\n| `[nzPopoverContentContext]`     | 内容的上下文                              | `object`                                                                                                                                                                          | -         |\n| `[nzPopoverTrigger]`            | 触发行为，为 `null` 时不响应光标事件      | `'click' \\| 'focus' \\| 'hover' \\| null`                                                                                                                                           | `'hover'` |\n| `[nzPopoverPlacement]`          | 气泡框位置                                | `'top' \\| 'left' \\| 'right' \\| 'bottom' \\| 'topLeft' \\| 'topRight' \\| 'bottomLeft' \\| 'bottomRight' \\| 'leftTop' \\| 'leftBottom' \\| 'rightTop' \\| 'rightBottom' \\| Array<string>` | `'top'`   |\n| `[nzPopoverOrigin]`             | 气泡框定位元素                            | `ElementRef`                                                                                                                                                                      | -         |\n| `[nzPopoverVisible]`            | 显示隐藏气泡框                            | `boolean`                                                                                                                                                                         | `false`   |\n| `(nzPopoverVisibleChange)`      | 显示隐藏的事件                            | `EventEmitter<boolean>`                                                                                                                                                           | -         |\n| `[nzPopoverMouseEnterDelay]`    | 鼠标移入后延时多少才显示气泡框，单位：秒  | `number`                                                                                                                                                                          | `0.15`    |\n| `[nzPopoverMouseLeaveDelay]`    | 鼠标移出后延时多少才隐藏气泡框，单位：秒  | `number`                                                                                                                                                                          | `0.1`     |\n| `[nzPopoverOverlayClassName]`   | 卡片类名                                  | `string`                                                                                                                                                                          | -         |\n| `[nzPopoverOverlayStyle]`       | 卡片样式                                  | `object`                                                                                                                                                                          | -         |\n| `[nzPopoverBackdrop]`           | 浮层是否应带有背景板                      | `boolean`                                                                                                                                                                         | `false`   |\n| `[nzPopoverOverlayClickable]`   | 点击蒙层关闭气泡框，仅`click`触发行为有效 | `boolean`                                                                                                                                                                         | `true`    |\n\n更多属性请参考 [Tooltip](/components/tooltip/zh#api)。\n\n## 注意\n\n请确保 `[nz-popover]` 元素能接受 `onMouseEnter`、`onMouseLeave`、`onFocus`、`onClick` 事件。\n\n## FAQ\n\n### Q：滚动时浮层元素没有跟随滚动位置\n\n默认情况下，浮层元素使用 `body` 作为滚动容器，如果使用了其他滚动容器，在自定义滚动容器元素上添加 [CdkScrollable](https://material.angular.dev/cdk/scrolling/api#CdkScrollable) 指令。\n注意：您需要从 `@angular/cdk/scrolling` 导入 `CdkScrollable` 指令或 `ScrollingModule` 模块。\n"
  },
  {
    "path": "components/popover/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/popover/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/popover/popover.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzPopoverComponent, NzPopoverDirective } from './popover';\n\n@NgModule({\n  imports: [NzPopoverDirective, NzPopoverComponent],\n  exports: [NzPopoverDirective, NzPopoverComponent]\n})\nexport class NzPopoverModule {}\n"
  },
  {
    "path": "components/popover/popover.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport { Component, ElementRef, provideZoneChangeDetection, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, inject, TestBed, tick } from '@angular/core/testing';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { dispatchMouseEvent } from 'ng-zorro-antd/core/testing';\n\nimport { NzPopoverDirective } from './popover';\nimport { NzPopoverModule } from './popover.module';\n\ndescribe('popover', () => {\n  let fixture: ComponentFixture<NzPopoverTestComponent>;\n  let component: NzPopoverTestComponent;\n  let overlayContainer: OverlayContainer;\n  let overlayContainerElement: HTMLElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), provideZoneChangeDetection()]\n    });\n    fixture = TestBed.createComponent(NzPopoverTestComponent);\n    component = fixture.componentInstance;\n    fixture.detectChanges();\n  });\n\n  beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n    overlayContainer = oc;\n    overlayContainerElement = oc.getContainerElement();\n  }));\n\n  afterEach(() => {\n    overlayContainer.ngOnDestroy();\n  });\n\n  function getTextContentOf(selector: string): string | null {\n    const el = overlayContainerElement.querySelector(selector);\n    return el && el.textContent ? el.textContent : null;\n  }\n\n  function getTitleTextContent(): string | null {\n    return getTextContentOf('.ant-popover-title');\n  }\n\n  function getInnerTextContent(): string | null {\n    return getTextContentOf('.ant-popover-inner-content');\n  }\n\n  function waitingForTooltipToggling(): void {\n    fixture.detectChanges();\n    tick(500);\n    fixture.detectChanges();\n  }\n\n  it('should support string', fakeAsync(() => {\n    const triggerElement = component.stringPopover.nativeElement;\n\n    expect(getTitleTextContent()).toBeNull();\n    expect(getInnerTextContent()).toBeNull();\n\n    dispatchMouseEvent(triggerElement, 'mouseenter');\n    waitingForTooltipToggling();\n    expect(getTitleTextContent()).toContain('title-string');\n    expect(getInnerTextContent()).toContain('content-string');\n\n    dispatchMouseEvent(triggerElement, 'mouseleave');\n    waitingForTooltipToggling();\n    expect(getTitleTextContent()).toBeNull();\n    expect(getInnerTextContent()).toBeNull();\n  }));\n\n  it('should support template', fakeAsync(() => {\n    const triggerElement = component.templatePopover.nativeElement;\n\n    expect(getTitleTextContent()).toBeNull();\n    expect(getInnerTextContent()).toBeNull();\n\n    dispatchMouseEvent(triggerElement, 'mouseenter');\n    waitingForTooltipToggling();\n    expect(getTitleTextContent()).toContain('title-template');\n    expect(getInnerTextContent()).toContain('content-template');\n\n    dispatchMouseEvent(triggerElement, 'mouseleave');\n    waitingForTooltipToggling();\n    expect(getTitleTextContent()).toBeNull();\n    expect(getInnerTextContent()).toBeNull();\n  }));\n\n  // changing content on the directive should be synced to the component\n  it('should set `setContent` proxy to `nzContent`', fakeAsync(() => {\n    const triggerElement = component.changePopover.nativeElement;\n\n    dispatchMouseEvent(triggerElement, 'mouseenter');\n    waitingForTooltipToggling();\n    expect(getInnerTextContent()).toContain('content');\n\n    component.content = 'changed-content';\n    fixture.detectChanges();\n    expect(getInnerTextContent()).toContain('changed-content');\n  }));\n\n  it('should nzPopoverBackdrop work', fakeAsync(() => {\n    const triggerElement = component.backdropPopover.nativeElement;\n    dispatchMouseEvent(triggerElement, 'click');\n    waitingForTooltipToggling();\n    const boundingBox = overlayContainerElement.children[0];\n    expect(boundingBox.children[0].classList).toContain('cdk-overlay-backdrop');\n  }));\n\n  it('should prohibit hiding popover when nzPopoverOverlayClickable is false', fakeAsync(() => {\n    const triggerElement = component.hideTemplate.nativeElement;\n\n    dispatchMouseEvent(triggerElement, 'click');\n    waitingForTooltipToggling();\n    expect(overlayContainerElement.textContent).toContain('content-string');\n\n    dispatchMouseEvent(document.body, 'click');\n    waitingForTooltipToggling();\n    expect(overlayContainerElement.textContent).toContain('content-string');\n  }));\n\n  it('should change overlayClass when the nzPopoverOverlayClassName is changed', fakeAsync(() => {\n    const triggerElement = component.stringPopover.nativeElement;\n\n    dispatchMouseEvent(triggerElement, 'mouseenter');\n    waitingForTooltipToggling();\n\n    component.class = 'testClass2';\n    fixture.detectChanges();\n\n    expect(overlayContainerElement.querySelector<HTMLElement>('.testClass')).toBeNull();\n    expect(overlayContainerElement.querySelector<HTMLElement>('.testClass2')).not.toBeNull();\n  }));\n\n  it('should nzPopoverOverlayClassName support classes listed in the string (space delimited)', fakeAsync(() => {\n    const triggerElement = component.stringPopover.nativeElement;\n    component.class = 'testClass1 testClass2';\n\n    dispatchMouseEvent(triggerElement, 'mouseenter');\n    waitingForTooltipToggling();\n\n    expect(overlayContainerElement.querySelector('.testClass1.testClass2')).not.toBeNull();\n  }));\n\n  it('should support context', fakeAsync(() => {\n    const triggerElement = component.contextPopover.nativeElement;\n\n    expect(getTitleTextContent()).toBeNull();\n    expect(getInnerTextContent()).toBeNull();\n    dispatchMouseEvent(triggerElement, 'mouseenter');\n    waitingForTooltipToggling();\n    expect(getTitleTextContent()).toContain('titleContextTest');\n    expect(getInnerTextContent()).toContain('contentContextTest');\n  }));\n});\n\n@Component({\n  imports: [NzPopoverModule],\n  template: `\n    <a\n      #stringPopover\n      nz-popover\n      nzPopoverTitle=\"title-string\"\n      nzPopoverContent=\"content-string\"\n      [nzPopoverOverlayClassName]=\"class\"\n      >Show</a\n    >\n\n    <a #templatePopover nz-popover [nzPopoverTitle]=\"templateTitle\" [nzPopoverContent]=\"templateContent\">Show</a>\n\n    <a #changePopover nz-popover nzPopoverTitle=\"title-change\" [nzPopoverContent]=\"content\"></a>\n\n    <a\n      #backdropPopover\n      nz-popover\n      nzPopoverContent=\"content-string\"\n      nzPopoverTrigger=\"click\"\n      [nzPopoverBackdrop]=\"true\"\n    ></a>\n\n    <a\n      #hideTemplate\n      nz-popover\n      nzPopoverContent=\"content-string\"\n      nzPopoverTrigger=\"click\"\n      [nzPopoverBackdrop]=\"true\"\n      [nzPopoverOverlayClickable]=\"false\"\n    >\n    </a>\n\n    <ng-template #templateTitle>title-template</ng-template>\n\n    <ng-template #templateContent>content-template</ng-template>\n\n    <a\n      #contextPopover\n      nz-popover\n      [nzPopoverTitle]=\"templateTitleContext\"\n      [nzPopoverContent]=\"templateContentContext\"\n      nzPopoverTitleContext=\"titleContextTest\"\n      nzPopoverContentContext=\"contentContextTest\"\n    >\n    </a>\n    <ng-template #templateTitleContext let-item>{{ item }}</ng-template>\n    <ng-template #templateContentContext let-item>{{ item }}</ng-template>\n  `\n})\nexport class NzPopoverTestComponent {\n  @ViewChild('stringPopover', { static: false }) stringPopover!: ElementRef;\n  @ViewChild('stringPopover', { static: false, read: NzPopoverDirective })\n  stringPopoverNzPopoverDirective!: NzPopoverDirective;\n\n  @ViewChild('templatePopover', { static: false }) templatePopover!: ElementRef;\n  @ViewChild('templatePopover', { static: false, read: NzPopoverDirective })\n  templatePopoverNzPopoverDirective!: NzPopoverDirective;\n\n  @ViewChild('changePopover', { static: true }) changePopover!: ElementRef;\n  @ViewChild('changePopover', { static: true, read: NzPopoverDirective })\n  changePopoverNzPopoverDirective!: NzPopoverDirective;\n\n  @ViewChild('hideTemplate', { static: false }) hideTemplate!: ElementRef;\n  @ViewChild('hideTemplate', { static: false, read: NzPopoverDirective })\n  hideTemplateDirective!: NzPopoverDirective;\n\n  @ViewChild('backdropPopover', { static: true }) backdropPopover!: ElementRef;\n\n  @ViewChild('contextPopover', { static: false }) contextPopover!: ElementRef;\n  @ViewChild('contextPopover', { static: false, read: NzPopoverDirective })\n  contextPopoverNzPopoverDirective!: NzPopoverDirective;\n\n  content = 'content';\n  visible = false;\n  class = 'testClass';\n}\n"
  },
  {
    "path": "components/popover/popover.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { OverlayModule } from '@angular/cdk/overlay';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  Directive,\n  ElementRef,\n  EventEmitter,\n  Input,\n  Output,\n  ViewEncapsulation,\n  booleanAttribute\n} from '@angular/core';\n\nimport { NzNoAnimationDirective } from 'ng-zorro-antd/core/animation';\nimport { NzConfigKey, WithConfig } from 'ng-zorro-antd/core/config';\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzOverlayModule } from 'ng-zorro-antd/core/overlay';\nimport { NgStyleInterface, NzSafeAny, NzTSType } from 'ng-zorro-antd/core/types';\nimport {\n  NzTooltipBaseDirective,\n  NzTooltipComponent,\n  NzTooltipTrigger,\n  PropertyMapping,\n  isTooltipEmpty\n} from 'ng-zorro-antd/tooltip';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'popover';\n\n@Directive({\n  selector: '[nz-popover]',\n  exportAs: 'nzPopover',\n  host: {\n    '[class.ant-popover-open]': 'visible'\n  }\n})\nexport class NzPopoverDirective extends NzTooltipBaseDirective {\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  /* eslint-disable @angular-eslint/no-input-rename, @angular-eslint/no-output-rename */\n  @Input({ alias: 'nzPopoverArrowPointAtCenter', transform: booleanAttribute }) override arrowPointAtCenter?: boolean;\n  @Input('nzPopoverTitle') override title?: NzTSType;\n  @Input('nzPopoverTitleContext') titleContext?: NzSafeAny | null = null;\n  @Input('nzPopoverContent') override content?: NzTSType;\n  @Input('nzPopoverContentContext') contentContext?: NzSafeAny | null = null;\n  @Input('nz-popover') override directiveTitle?: NzTSType | null;\n  @Input('nzPopoverTrigger') override trigger?: NzTooltipTrigger = 'hover';\n  @Input('nzPopoverPlacement') override placement?: string | string[] = 'top';\n  @Input('nzPopoverOrigin') override origin?: ElementRef<HTMLElement>;\n  @Input('nzPopoverVisible') override visible?: boolean;\n  @Input('nzPopoverMouseEnterDelay') override mouseEnterDelay?: number;\n  @Input('nzPopoverMouseLeaveDelay') override mouseLeaveDelay?: number;\n  @Input('nzPopoverOverlayClassName') override overlayClassName?: string;\n  @Input('nzPopoverOverlayStyle') override overlayStyle?: NgStyleInterface;\n  @Input('nzPopoverOverlayClickable') override overlayClickable?: boolean;\n\n  override directiveContent?: NzTSType | null = null;\n\n  @Input() @WithConfig() nzPopoverBackdrop?: boolean = false;\n\n  @Output('nzPopoverVisibleChange') override readonly visibleChange = new EventEmitter<boolean>();\n\n  protected override getProxyPropertyMap(): PropertyMapping {\n    return {\n      nzPopoverBackdrop: ['nzBackdrop', () => this.nzPopoverBackdrop],\n      titleContext: ['nzTitleContext', () => this.titleContext],\n      contentContext: ['nzContentContext', () => this.contentContext],\n      ...super.getProxyPropertyMap()\n    };\n  }\n\n  constructor() {\n    super(NzPopoverComponent);\n  }\n}\n\n@Component({\n  selector: 'nz-popover',\n  exportAs: 'nzPopoverComponent',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <ng-template\n      #overlay=\"cdkConnectedOverlay\"\n      cdkConnectedOverlay\n      nzConnectedOverlay\n      [cdkConnectedOverlayHasBackdrop]=\"hasBackdrop\"\n      [cdkConnectedOverlayOrigin]=\"origin\"\n      [cdkConnectedOverlayPositions]=\"_positions\"\n      [cdkConnectedOverlayOpen]=\"_visible\"\n      [cdkConnectedOverlayPush]=\"cdkConnectedOverlayPush\"\n      [nzArrowPointAtCenter]=\"nzArrowPointAtCenter\"\n      (overlayOutsideClick)=\"onClickOutside($event)\"\n      (detach)=\"hide()\"\n      (positionChange)=\"onPositionChange($event)\"\n    >\n      <div\n        class=\"ant-popover\"\n        [class.ant-popover-rtl]=\"dir() === 'rtl'\"\n        [class]=\"_classMap\"\n        [style]=\"nzOverlayStyle\"\n        [nzNoAnimation]=\"!!noAnimation?.nzNoAnimation?.()\"\n        [animate.enter]=\"zoomAnimationEnter()\"\n        [animate.leave]=\"zoomAnimationLeave()\"\n      >\n        <div class=\"ant-popover-arrow\"></div>\n        <div class=\"ant-popover-content\">\n          <div class=\"ant-popover-inner\" role=\"tooltip\">\n            <div>\n              @if (nzTitle) {\n                <div class=\"ant-popover-title\">\n                  <ng-container *nzStringTemplateOutlet=\"nzTitle; context: { $implicit: nzTitleContext }\">\n                    {{ nzTitle }}\n                  </ng-container>\n                </div>\n              }\n              <div class=\"ant-popover-inner-content\">\n                <ng-container *nzStringTemplateOutlet=\"nzContent; context: { $implicit: nzContentContext }\">\n                  {{ nzContent }}\n                </ng-container>\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n    </ng-template>\n  `,\n  imports: [OverlayModule, NzOverlayModule, NzNoAnimationDirective, NzOutletModule]\n})\nexport class NzPopoverComponent extends NzTooltipComponent {\n  override _animationPrefix = 'ant-zoom-big';\n  override _prefix = 'ant-popover';\n  nzContentContext: object | null = null;\n\n  get hasBackdrop(): boolean {\n    return this.nzTrigger === 'click' ? this.nzBackdrop : false;\n  }\n\n  protected override isEmpty(): boolean {\n    return isTooltipEmpty(this.nzTitle) && isTooltipEmpty(this.nzContent);\n  }\n}\n"
  },
  {
    "path": "components/popover/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './popover';\nexport * from './popover.module';\n"
  },
  {
    "path": "components/popover/style/customize.less",
    "content": "@import './index.less';\n\n.popover-customize-bg(@popover-prefix-cls, @popover-background);\n"
  },
  {
    "path": "components/popover/style/entry.less",
    "content": "@import './index.less';\n// style dependencies\n// deps-lint-skip: tooltip\n@import './patch';\n"
  },
  {
    "path": "components/popover/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import '../../style/core/motion/zoom';\n\n@popover-prefix-cls: ~'@{ant-prefix}-popover';\n\n.@{popover-prefix-cls} {\n  .reset-component();\n\n  --antd-arrow-background-color: @popover-bg;\n\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: @zindex-popover;\n  max-width: 100vw;\n  font-weight: normal;\n  white-space: normal;\n  text-align: left;\n  cursor: auto;\n  user-select: text;\n\n  &-content {\n    position: relative;\n  }\n\n  &::after {\n    position: absolute;\n    background: fade(@white, 1%);\n    content: '';\n  }\n\n  &-hidden {\n    display: none;\n  }\n\n  &-inner {\n    background-color: @popover-bg;\n    background-clip: padding-box;\n    border-radius: @border-radius-base;\n    box-shadow: @box-shadow-base;\n  }\n\n  @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {\n    /* IE10+ */\n    &-inner {\n      box-shadow: @box-shadow-base;\n    }\n  }\n\n  &-title {\n    min-width: @popover-min-width;\n    min-height: @popover-min-height;\n    margin: 0; // reset heading margin\n    padding: 5px @popover-padding-horizontal 4px;\n    color: @heading-color;\n    font-weight: 500;\n    border-bottom: 1px solid @border-color-split;\n  }\n\n  &-inner-content {\n    width: max-content;\n    max-width: 100%;\n    padding: @padding-sm @popover-padding-horizontal;\n    color: @popover-color;\n  }\n\n  &-message {\n    display: flex;\n    padding: 4px 0 12px;\n    color: @popover-color;\n    font-size: @font-size-base;\n\n    &-icon {\n      display: inline-block;\n      margin-right: 8px;\n      color: @warning-color;\n      font-size: @font-size-base;\n    }\n  }\n\n  &-buttons {\n    margin-bottom: 4px;\n    text-align: right;\n\n    button:not(:first-child) {\n      margin-left: 8px;\n    }\n  }\n\n  // Arrow Style\n  .placementArrow(@popover-arrow-width, 4px, @arrow-border-radius, var(--antd-arrow-background-color), @popover-arrow-box-shadow);\n}\n\n.generator-popover-preset-color(@i: length(@preset-colors)) when (@i > 0) {\n  .generator-popover-preset-color(@i - 1);\n  @color: extract(@preset-colors, @i);\n  @lightColor: '@{color}-6';\n\n  .@{popover-prefix-cls}-@{color} {\n    .@{popover-prefix-cls}-inner {\n      background-color: @@lightColor;\n    }\n\n    .@{popover-prefix-cls}-arrow {\n      background-color: @@lightColor;\n    }\n  }\n}\n\n.generator-popover-preset-color();\n\n// Animations\n.zoom-motion('zoom-big', antZoomBig);\n\n@import './rtl';\n"
  },
  {
    "path": "components/popover/style/patch.less",
    "content": ".ant-popover {\n  position: relative;\n}\n"
  },
  {
    "path": "components/popover/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@popover-prefix-cls: ~'@{ant-prefix}-popover';\n\n.@{popover-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n    text-align: right;\n  }\n\n  &-message {\n    &-icon {\n      .@{popover-prefix-cls}-rtl & {\n        margin-right: 0;\n        margin-left: 8px;\n      }\n    }\n\n    &-title {\n      .@{popover-prefix-cls}-rtl & {\n        padding-left: @padding-md;\n      }\n    }\n  }\n\n  &-buttons {\n    .@{popover-prefix-cls}-rtl & {\n      text-align: left;\n    }\n\n    button {\n      .@{popover-prefix-cls}-rtl & {\n        margin-right: 8px;\n        margin-left: 0;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/progress/demo/circle-mini.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 小型进度圈\n  en-US: Mini size circular progress bar\n---\n\n## zh-CN\n\n小一号的圈形进度。\n\n## en-US\n\nA smaller circular progress bar.\n"
  },
  {
    "path": "components/progress/demo/circle-mini.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzProgressModule } from 'ng-zorro-antd/progress';\n\n@Component({\n  selector: 'nz-demo-progress-circle-mini',\n  imports: [NzProgressModule],\n  template: `\n    <nz-progress [nzPercent]=\"75\" nzType=\"circle\" [nzWidth]=\"80\" />\n    <nz-progress [nzPercent]=\"70\" nzType=\"circle\" [nzWidth]=\"80\" nzStatus=\"exception\" />\n    <nz-progress [nzPercent]=\"100\" nzType=\"circle\" [nzWidth]=\"80\" />\n  `,\n  styles: `\n    nz-progress {\n      margin-right: 8px;\n      margin-bottom: 8px;\n      display: inline-block;\n    }\n  `\n})\nexport class NzDemoProgressCircleMiniComponent {}\n"
  },
  {
    "path": "components/progress/demo/circle.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 进度圈\n  en-US: Circular progress bar\n---\n\n## zh-CN\n\n圈形的进度。\n\n## en-US\n\nA circular progress bar.\n"
  },
  {
    "path": "components/progress/demo/circle.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzProgressModule } from 'ng-zorro-antd/progress';\n\n@Component({\n  selector: 'nz-demo-progress-circle',\n  imports: [NzProgressModule],\n  template: `\n    <nz-progress [nzPercent]=\"75\" nzType=\"circle\" />\n    <nz-progress [nzPercent]=\"70\" nzType=\"circle\" nzStatus=\"exception\" />\n    <nz-progress [nzPercent]=\"100\" nzType=\"circle\" />\n  `,\n  styles: `\n    nz-progress {\n      margin-right: 8px;\n      margin-bottom: 8px;\n      display: inline-block;\n    }\n  `\n})\nexport class NzDemoProgressCircleComponent {}\n"
  },
  {
    "path": "components/progress/demo/dashboard-layout.md",
    "content": "---\norder: 8\ndebug: true\ntitle:\n  zh-CN: 仪表盘样式\n  en-US: Dashboard Layout\n---\n\n## zh-CN\n\n仪表盘展示样式\n\n## en-US\n\nDashboard layout\n"
  },
  {
    "path": "components/progress/demo/dashboard-layout.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzProgressModule } from 'ng-zorro-antd/progress';\n\n@Component({\n  selector: 'nz-demo-progress-dashboard-layout',\n  imports: [NzProgressModule],\n  template: `\n    <nz-progress [nzPercent]=\"1\" nzType=\"dashboard\" [nzGapDegree]=\"90\" />\n    <nz-progress [nzPercent]=\"75\" nzType=\"dashboard\" [nzGapDegree]=\"180\" />\n    <nz-progress [nzPercent]=\"75\" nzType=\"dashboard\" [nzGapDegree]=\"295\" />\n    <nz-progress [nzPercent]=\"1\" nzType=\"dashboard\" [nzGapDegree]=\"340\" />\n  `\n})\nexport class NzDemoProgressDashboardLayoutComponent {}\n"
  },
  {
    "path": "components/progress/demo/dashboard.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 仪表盘\n  en-US: Dashboard\n---\n\n## zh-CN\n\n通过设置 `nzType=\"dashboard\"`，可以很方便地实现仪表盘样式的进度条。\n\n## en-US\n\nBy setting `nzType=\"dashboard\"`, you can get a dashboard style of progress easily.\n"
  },
  {
    "path": "components/progress/demo/dashboard.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzProgressModule } from 'ng-zorro-antd/progress';\n\n@Component({\n  selector: 'nz-demo-progress-dashboard',\n  imports: [NzProgressModule],\n  template: `<nz-progress [nzPercent]=\"75\" nzType=\"dashboard\" />`\n})\nexport class NzDemoProgressDashboardComponent {}\n"
  },
  {
    "path": "components/progress/demo/dynamic.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 动态展示\n  en-US: Dynamic\n---\n\n## zh-CN\n\n会动的进度条才是好进度条。\n\n## en-US\n\nA dynamic progress bar is better.\n"
  },
  {
    "path": "components/progress/demo/dynamic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzFlexModule } from 'ng-zorro-antd/flex';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzProgressModule } from 'ng-zorro-antd/progress';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\n\n@Component({\n  selector: 'nz-demo-progress-dynamic',\n  imports: [NzButtonModule, NzIconModule, NzFlexModule, NzProgressModule, NzSpaceModule],\n  template: `\n    <div nz-flex nzVertical nzGap=\"small\">\n      <nz-progress [nzPercent]=\"percent\" />\n      <nz-progress [nzPercent]=\"percent\" nzType=\"circle\" />\n      <nz-space-compact>\n        <button nz-button (click)=\"decline()\"><nz-icon nzType=\"minus\" /></button>\n        <button nz-button (click)=\"increase()\"><nz-icon nzType=\"plus\" /></button>\n      </nz-space-compact>\n    </div>\n  `\n})\nexport class NzDemoProgressDynamicComponent {\n  percent = 0;\n\n  increase(): void {\n    this.percent = Math.min(this.percent + 10, 100);\n  }\n\n  decline(): void {\n    this.percent = Math.max(this.percent - 10, 0);\n  }\n}\n"
  },
  {
    "path": "components/progress/demo/format.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 自定义文字格式\n  en-US: Custom text format\n---\n\n## zh-CN\n\n`nzFormat` 属性指定格式。\n\n## en-US\n\nYou can custom text format by setting `nzFormat`.\n"
  },
  {
    "path": "components/progress/demo/format.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzProgressModule } from 'ng-zorro-antd/progress';\n\n@Component({\n  selector: 'nz-demo-progress-format',\n  imports: [NzProgressModule],\n  template: `\n    <nz-progress [nzPercent]=\"75\" nzType=\"circle\" [nzFormat]=\"formatOne\" />\n    <nz-progress [nzPercent]=\"100\" nzType=\"circle\" [nzFormat]=\"formatTwo\" />\n  `,\n  styles: `\n    nz-progress {\n      margin-right: 8px;\n      margin-bottom: 8px;\n      display: inline-block;\n    }\n  `\n})\nexport class NzDemoProgressFormatComponent {\n  formatOne = (percent: number): string => `${percent} Days`;\n  formatTwo = (): string => `Done`;\n}\n"
  },
  {
    "path": "components/progress/demo/gradient.md",
    "content": "---\norder: 11\ntitle:\n  zh-CN: 自定义进度条渐变色\n  en-US: Custom line gradient\n---\n\n## zh-CN\n\n`linear-gradient` 的封装。推荐只传两种颜色。\n\n## en-US\n\nA package of `linear-gradient`. It is recommended to only pass two colors.\n"
  },
  {
    "path": "components/progress/demo/gradient.ts",
    "content": "import { Component, ViewEncapsulation } from '@angular/core';\n\nimport { NzProgressModule } from 'ng-zorro-antd/progress';\n\n@Component({\n  selector: 'nz-demo-progress-gradient',\n  imports: [NzProgressModule],\n  template: `\n    <nz-progress [nzPercent]=\"99.9\" [nzStrokeColor]=\"{ '0%': '#108ee9', '100%': '#87d068' }\" />\n    <nz-progress [nzPercent]=\"99.9\" [nzStrokeColor]=\"{ '0%': '#108ee9', '100%': '#87d068' }\" nzStatus=\"active\" />\n    <nz-progress\n      nzType=\"circle\"\n      [nzPercent]=\"90\"\n      [nzStrokeColor]=\"{ '0%': '#108ee9', '50%': '#2db7f5', '100%': '#87d068' }\"\n    />\n    <nz-progress nzType=\"dashboard\" [nzPercent]=\"100\" [nzStrokeColor]=\"{ '0%': '#108ee9', '100%': '#87d068' }\" />\n  `,\n  styles: `\n    .ant-progress {\n      margin-right: 8px;\n      margin-bottom: 8px;\n      display: inline-block;\n    }\n  `,\n  encapsulation: ViewEncapsulation.None\n})\nexport class NzDemoProgressGradientComponent {}\n"
  },
  {
    "path": "components/progress/demo/line-mini.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 小型进度条\n  en-US: Mini size progress bar\n---\n\n## zh-CN\n\n适合放在较狭窄的区域内。\n\n## en-US\n\nAppropriate for a narrow area.\n"
  },
  {
    "path": "components/progress/demo/line-mini.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzProgressModule } from 'ng-zorro-antd/progress';\n\n@Component({\n  selector: 'nz-demo-progress-line-mini',\n  imports: [NzProgressModule],\n  template: `\n    <div style=\"width: 170px;\">\n      <nz-progress [nzPercent]=\"30\" nzSize=\"small\" />\n      <nz-progress [nzPercent]=\"50\" nzSize=\"small\" nzStatus=\"active\" />\n      <nz-progress [nzPercent]=\"70\" nzSize=\"small\" nzStatus=\"exception\" />\n      <nz-progress [nzPercent]=\"100\" nzSize=\"small\" />\n      <nz-progress [nzPercent]=\"50\" nzSize=\"small\" [nzShowInfo]=\"false\" />\n    </div>\n  `\n})\nexport class NzDemoProgressLineMiniComponent {}\n"
  },
  {
    "path": "components/progress/demo/line.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 进度条\n  en-US: Progress bar\n---\n\n## zh-CN\n\n标准的进度条。\n\n## en-US\n\nA standard progress bar.\n"
  },
  {
    "path": "components/progress/demo/line.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzProgressModule } from 'ng-zorro-antd/progress';\n\n@Component({\n  selector: 'nz-demo-progress-line',\n  imports: [NzProgressModule],\n  template: `\n    <nz-progress [nzPercent]=\"30\" />\n    <nz-progress [nzPercent]=\"50\" nzStatus=\"active\" />\n    <nz-progress [nzPercent]=\"70\" nzStatus=\"exception\" />\n    <nz-progress [nzPercent]=\"100\" />\n    <nz-progress [nzPercent]=\"50\" [nzShowInfo]=\"false\" />\n  `\n})\nexport class NzDemoProgressLineComponent {}\n"
  },
  {
    "path": "components/progress/demo/round.md",
    "content": "---\norder: 10\ntitle:\n  zh-CN: 圆角/方角边缘\n  en-US: Square linecaps\n---\n\n## zh-CN\n\n通过设定 `nzStrokeLinecap='square|round'` 可以调整进度条边缘的形状。\n\n## en-US\n\nBy setting `nzStrokeLinecap='square'`, you can change the linecaps from round to square.\n"
  },
  {
    "path": "components/progress/demo/round.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzProgressModule } from 'ng-zorro-antd/progress';\n\n@Component({\n  selector: 'nz-demo-progress-round',\n  imports: [NzProgressModule],\n  template: `\n    <nz-progress nzStrokeLinecap=\"round\" nzPercent=\"75\" />\n    <nz-progress nzStrokeLinecap=\"round\" nzType=\"circle\" nzPercent=\"75\" />\n    <nz-progress nzStrokeLinecap=\"square\" nzType=\"dashboard\" nzPercent=\"75\" />\n  `\n})\nexport class NzDemoProgressRoundComponent {}\n"
  },
  {
    "path": "components/progress/demo/segment.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 分段进度条\n  en-US: Progress bar with success segment\n---\n\n## zh-CN\n\n标准的进度条。\n\n## en-US\n\nA standard progress bar.\n"
  },
  {
    "path": "components/progress/demo/segment.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzProgressModule } from 'ng-zorro-antd/progress';\nimport { NzTooltipModule } from 'ng-zorro-antd/tooltip';\n\n@Component({\n  selector: 'nz-demo-progress-segment',\n  imports: [NzProgressModule, NzTooltipModule],\n  template: `\n    <nz-progress\n      nz-tooltip\n      nzTooltipTitle=\"3 done / 3 in progress / 4 to do\"\n      [nzPercent]=\"60\"\n      [nzSuccessPercent]=\"30\"\n    />\n    <nz-progress\n      nz-tooltip\n      nzTooltipTitle=\"3 done / 3 in progress / 4 to do\"\n      nzType=\"circle\"\n      [nzPercent]=\"60\"\n      [nzSuccessPercent]=\"30\"\n    />\n    <nz-progress\n      nz-tooltip\n      nzTooltipTitle=\"3 done / 3 in progress / 4 to do\"\n      nzType=\"dashboard\"\n      [nzPercent]=\"60\"\n      [nzSuccessPercent]=\"30\"\n    />\n  `\n})\nexport class NzDemoProgressSegmentComponent {}\n"
  },
  {
    "path": "components/progress/demo/step.md",
    "content": "---\norder: 11\ntitle:\n  zh-CN: 步骤进度条\n  en-US: Progress bar with steps\n---\n\n## zh-CN\n\n带步骤的进度条。\n\n## en-US\n\nA progress bar with steps.\n"
  },
  {
    "path": "components/progress/demo/step.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzProgressModule } from 'ng-zorro-antd/progress';\n\n@Component({\n  selector: 'nz-demo-progress-step',\n  imports: [NzProgressModule],\n  template: `\n    <nz-progress [nzPercent]=\"50\" [nzSteps]=\"3\" nzStrokeColor=\"#1890ff\" />\n    <nz-progress [nzPercent]=\"30\" [nzSteps]=\"5\" nzStrokeColor=\"#1890ff\" />\n    <nz-progress [nzPercent]=\"100\" [nzSteps]=\"5\" nzStrokeColor=\"#1890ff\" nzSize=\"small\" />\n  `\n})\nexport class NzDemoProgressStepComponent {}\n"
  },
  {
    "path": "components/progress/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Feedback\ntitle: Progress\ncover: 'https://gw.alipayobjects.com/zos/alicdn/xqsDu4ZyR/Progress.svg'\ndescription: Display the current progress of an operation.\n---\n\n## When To Use\n\nIf it will take a long time to complete an operation, you can use `Progress` to show the current progress and status.\n\n- When an operation will interrupt the current interface, or it needs to run in the background for more than 2 seconds.\n- When you need to display the completion percentage of an operation.\n\n## API\n\n### nz-progress\n\n| Property             | Description                                                          | Type                                                                                   | Default                    | Global Config |\n| -------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | -------------------------- | ------------- |\n| `[nzType]`           | to set the type                                                      | `'line' \\| 'circle' \\| 'dashboard'`                                                    | `'line'`                   |               |\n| `[nzFormat]`         | template function of the content                                     | `(percent: number) => string \\| TemplateRef<{ $implicit: number }>`                    | `percent => percent + '%'` |               |\n| `[nzPercent]`        | to set the completion percentage                                     | `number`                                                                               | `0`                        |               |\n| `[nzShowInfo]`       | whether to display the progress value and the status icon            | `boolean`                                                                              | `true`                     | ✅            |\n| `[nzStatus]`         | to set the status of the Progress                                    | `'success' \\| 'exception' \\| 'active' \\| 'normal'`                                     | -                          |               |\n| `[nzStrokeLinecap]`  | to set the style of the progress linecap                             | `'round' \\| 'square'`                                                                  | `'round'`                  | ✅            |\n| `[nzStrokeColor]`    | color of progress bar, render linear-gradient when passing an object | `string \\| { from: string; to: string: direction: string; [percent: string]: string }` | -                          | ✅            |\n| `[nzSuccessPercent]` | segmented success percent                                            | `number`                                                                               | 0                          |               |\n\n### `nzType=\"line\"`\n\n| Property          | Description                                      | Type     | Default |\n| ----------------- | ------------------------------------------------ | -------- | ------- |\n| `[nzStrokeWidth]` | to set the width of the progress bar, unit: `px` | `number` | `8`     |\n| `[nzSteps]`       | the total step count                             | `number` | -       |\n\n### `nzType=\"circle\"`\n\n| Property          | Description                                                                         | Type     | Default | Global Config |\n| ----------------- | ----------------------------------------------------------------------------------- | -------- | ------- | ------------- |\n| `[nzWidth]`       | to set the canvas width of the circular progress bar, unit: `px`                    | `number` | `132`   |               |\n| `[nzStrokeWidth]` | to set the width of the circular progress bar, unit: percentage of the canvas width | `number` | `6`     | ✅            |\n\n### `nzType=\"dashboard\"`\n\n| Property          | Description                                                                          | Type                                     | Default | Global Config |\n| ----------------- | ------------------------------------------------------------------------------------ | ---------------------------------------- | ------- | ------------- |\n| `[nzWidth]`       | to set the canvas width of the dashboard progress bar, unit: `px`                    | `number`                                 | `132`   |               |\n| `[nzStrokeWidth]` | to set the width of the dashboard progress bar, unit: percentage of the canvas width | `number`                                 | `6`     | ✅            |\n| `[nzGapDegree]`   | the gap degree of half circle, 0 ~ 360                                               | `number`                                 | `0`     | ✅            |\n| `[nzGapPosition]` | the gap position                                                                     | `'top' \\| 'right' \\| 'bottom' \\| 'left'` | `'top'` | ✅            |\n"
  },
  {
    "path": "components/progress/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 进度条\ntype: 反馈\ntitle: Progress\ncover: 'https://gw.alipayobjects.com/zos/alicdn/xqsDu4ZyR/Progress.svg'\ndescription: 展示操作的当前进度。\n---\n\n## 何时使用\n\n在操作需要较长时间才能完成时，为用户显示该操作的当前进度和状态。\n\n- 当一个操作会打断当前界面，或者需要在后台运行，且耗时可能超过 2 秒时；\n- 当需要显示一个操作完成的百分比时。\n\n## API\n\n### nz-progress\n\n各类型通用的属性。\n\n| 属性                 | 说明                         | 类型                                                                                   | 默认值                     | 全局配置 |\n| -------------------- | ---------------------------- | -------------------------------------------------------------------------------------- | -------------------------- | -------- |\n| `[nzType]`           | 类型                         | `'line' \\| 'circle' \\| 'dashboard'`                                                    | `'line'`                   |          |\n| `[nzFormat]`         | 内容的模板函数               | `(percent: number) => string \\| TemplateRef<{ $implicit: number }>`                    | `percent => percent + '%'` |\n| `[nzPercent]`        | 百分比                       | `number`                                                                               | `0`                        |          |\n| `[nzShowInfo]`       | 是否显示进度数值或状态图标   | `boolean`                                                                              | `true`                     | ✅       |\n| `[nzStatus]`         | 状态                         | `'success' \\| 'exception' \\| 'active' \\| 'normal'`                                     | -                          |          |\n| `[nzStrokeLinecap]`  | 进度条端点形状               | `'round' \\| 'square'`                                                                  | `'round'`                  | ✅       |\n| `[nzStrokeColor]`    | 进度条颜色，传入对象时为渐变 | `string \\| { from: string; to: string: direction: string; [percent: string]: string }` | -                          | ✅       |\n| `[nzSuccessPercent]` | 已完成的分段百分比           | `number`                                                                               | 0                          |          |\n\n### `nzType=\"line\"`\n\n| 属性              | 说明                    | 类型     | 默认值 |\n| ----------------- | ----------------------- | -------- | ------ |\n| `[nzStrokeWidth]` | 进度条线的宽度，单位 px | `number` | `8`    |\n| `[nzSteps]`       | 进度条总共步数          | `number` | -      |\n\n### `nzType=\"circle\"`\n\n| 属性              | 说明                                             | 类型     | 默认值 | 全局配置 |\n| ----------------- | ------------------------------------------------ | -------- | ------ | -------- |\n| `[nzWidth]`       | 圆形进度条画布宽度，单位 px                      | `number` | `132`  |          |\n| `[nzStrokeWidth]` | 圆形进度条线的宽度，单位是进度条画布宽度的百分比 | `number` | `6`    | ✅       |\n\n### `nzType=\"dashboard\"`\n\n| 属性              | 说明                                               | 类型                                     | 默认值  | 全局配置 |\n| ----------------- | -------------------------------------------------- | ---------------------------------------- | ------- | -------- |\n| `[nzWidth]`       | 仪表盘进度条画布宽度，单位 px                      | `number`                                 | `132`   |          |\n| `[nzStrokeWidth]` | 仪表盘进度条线的宽度，单位是进度条画布宽度的百分比 | `number`                                 | `6`     | ✅       |\n| `[nzGapDegree]`   | 仪表盘进度条缺口角度，可取值 0 ~ 360               | `number`                                 | `0`     | ✅       |\n| `[nzGapPosition]` | 仪表盘进度条缺口位置                               | `'top' \\| 'right' \\| 'bottom' \\| 'left'` | `'top'` | ✅       |\n"
  },
  {
    "path": "components/progress/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/progress/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/progress/progress.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  Input,\n  OnChanges,\n  OnInit,\n  SimpleChanges,\n  ViewEncapsulation,\n  numberAttribute,\n  inject,\n  DestroyRef\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { NzConfigKey, onConfigChangeEventForComponent, WithConfig } from 'ng-zorro-antd/core/config';\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NgStyleInterface } from 'ng-zorro-antd/core/types';\nimport { isNotNil, numberAttributeWithZeroFallback } from 'ng-zorro-antd/core/util';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nimport {\n  NzProgressCirclePath,\n  NzProgressColorGradient,\n  NzProgressFormatter,\n  NzProgressGapPositionType,\n  NzProgressGradientProgress,\n  NzProgressStatusType,\n  NzProgressStepItem,\n  NzProgressStrokeColorType,\n  NzProgressStrokeLinecapType,\n  NzProgressTypeType\n} from './typings';\nimport { handleCircleGradient, handleLinearGradient } from './utils';\n\nlet gradientIdSeed = 0;\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'progress';\nconst statusIconNameMap = new Map([\n  ['success', 'check'],\n  ['exception', 'close']\n]);\nconst statusColorMap = new Map([\n  ['normal', '#108ee9'],\n  ['exception', '#ff5500'],\n  ['success', '#87d068']\n]);\nconst defaultFormatter: NzProgressFormatter = (p: number): string => `${p}%`;\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-progress',\n  exportAs: 'nzProgress',\n  imports: [NzIconModule, NzOutletModule, NgTemplateOutlet],\n  template: `\n    <ng-template #progressInfoTemplate>\n      @if (nzShowInfo) {\n        <span class=\"ant-progress-text\">\n          @if ((status === 'exception' || status === 'success') && !nzFormat) {\n            <nz-icon [nzType]=\"icon\" />\n          } @else {\n            <ng-container *nzStringTemplateOutlet=\"formatter; context: { $implicit: nzPercent }; let formatter\">\n              {{ formatter(nzPercent) }}\n            </ng-container>\n          }\n        </span>\n      }\n    </ng-template>\n\n    <div\n      [class]=\"'ant-progress ant-progress-status-' + status\"\n      [class.ant-progress-line]=\"nzType === 'line'\"\n      [class.ant-progress-small]=\"nzSize === 'small'\"\n      [class.ant-progress-default]=\"nzSize === 'default'\"\n      [class.ant-progress-show-info]=\"nzShowInfo\"\n      [class.ant-progress-circle]=\"isCircleStyle\"\n      [class.ant-progress-steps]=\"isSteps\"\n      [class.ant-progress-rtl]=\"dir === 'rtl'\"\n    >\n      @if (nzType === 'line') {\n        <div>\n          <!-- normal line style -->\n          @if (isSteps) {\n            <div class=\"ant-progress-steps-outer\">\n              @for (step of steps; track $index) {\n                <div class=\"ant-progress-steps-item\" [style]=\"step\"></div>\n              }\n              <ng-template [ngTemplateOutlet]=\"progressInfoTemplate\" />\n            </div>\n          } @else {\n            <div class=\"ant-progress-outer\">\n              <div class=\"ant-progress-inner\">\n                <div\n                  class=\"ant-progress-bg\"\n                  [style.width.%]=\"nzPercent\"\n                  [style.border-radius]=\"nzStrokeLinecap === 'round' ? '100px' : '0'\"\n                  [style.background]=\"!isGradient ? nzStrokeColor : null\"\n                  [style.background-image]=\"isGradient ? lineGradient : null\"\n                  [style.height.px]=\"strokeWidth\"\n                ></div>\n                @if (nzSuccessPercent || nzSuccessPercent === 0) {\n                  <div\n                    class=\"ant-progress-success-bg\"\n                    [style.width.%]=\"nzSuccessPercent\"\n                    [style.border-radius]=\"nzStrokeLinecap === 'round' ? '100px' : '0'\"\n                    [style.height.px]=\"strokeWidth\"\n                  ></div>\n                }\n              </div>\n            </div>\n            <ng-template [ngTemplateOutlet]=\"progressInfoTemplate\" />\n          }\n        </div>\n      }\n      <!-- line progress -->\n\n      <!-- circle / dashboard progress -->\n\n      @if (isCircleStyle) {\n        <div\n          [style.width.px]=\"this.nzWidth\"\n          [style.height.px]=\"this.nzWidth\"\n          [style.fontSize.px]=\"this.nzWidth * 0.15 + 6\"\n          class=\"ant-progress-inner\"\n          [class.ant-progress-circle-gradient]=\"isGradient\"\n        >\n          <svg class=\"ant-progress-circle \" viewBox=\"0 0 100 100\">\n            @if (isGradient) {\n              <defs>\n                <linearGradient [id]=\"'gradient-' + gradientId\" x1=\"100%\" y1=\"0%\" x2=\"0%\" y2=\"0%\">\n                  @for (i of circleGradient; track $index) {\n                    <stop [attr.offset]=\"i.offset\" [attr.stop-color]=\"i.color\" />\n                  }\n                </linearGradient>\n              </defs>\n            }\n\n            <path\n              class=\"ant-progress-circle-trail\"\n              stroke=\"#f3f3f3\"\n              fill-opacity=\"0\"\n              [attr.stroke-width]=\"strokeWidth\"\n              [attr.d]=\"pathString\"\n              [style]=\"trailPathStyle\"\n            />\n            @for (p of progressCirclePath; track $index) {\n              <path\n                class=\"ant-progress-circle-path\"\n                fill-opacity=\"0\"\n                [attr.d]=\"pathString\"\n                [attr.stroke-linecap]=\"nzStrokeLinecap\"\n                [attr.stroke]=\"p.stroke\"\n                [attr.stroke-width]=\"nzPercent ? strokeWidth : 0\"\n                [style]=\"p.strokePathStyle\"\n              />\n            }\n          </svg>\n          <ng-template [ngTemplateOutlet]=\"progressInfoTemplate\" />\n        </div>\n      }\n    </div>\n  `\n})\nexport class NzProgressComponent implements OnChanges, OnInit {\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  private readonly cdr = inject(ChangeDetectorRef);\n  private readonly directionality = inject(Directionality);\n  private readonly destroyRef = inject(DestroyRef);\n\n  @Input() @WithConfig() nzShowInfo: boolean = true;\n  @Input() nzWidth = 132;\n  @Input() @WithConfig() nzStrokeColor?: NzProgressStrokeColorType = undefined;\n  @Input() @WithConfig() nzSize: 'default' | 'small' = 'default';\n  @Input() nzFormat?: NzProgressFormatter;\n  @Input({ transform: numberAttributeWithZeroFallback }) nzSuccessPercent?: number;\n  @Input({ transform: numberAttribute }) nzPercent: number = 0;\n  @Input({ transform: numberAttributeWithZeroFallback }) @WithConfig() nzStrokeWidth?: number;\n  @Input({ transform: numberAttributeWithZeroFallback }) @WithConfig() nzGapDegree?: number;\n  @Input() nzStatus?: NzProgressStatusType;\n  @Input() nzType: NzProgressTypeType = 'line';\n  @Input() @WithConfig() nzGapPosition: NzProgressGapPositionType = 'top';\n  @Input() @WithConfig() nzStrokeLinecap: NzProgressStrokeLinecapType = 'round';\n\n  @Input({ transform: numberAttribute }) nzSteps: number = 0;\n\n  steps: NzProgressStepItem[] = [];\n\n  /** Gradient style when `nzType` is `line`. */\n  lineGradient: string | null = null;\n\n  /** If user uses gradient color. */\n  isGradient = false;\n\n  /** If the linear progress is a step progress. */\n  isSteps = false;\n\n  /**\n   * Each progress whose `nzType` is circle or dashboard should have unique id to\n   * define `<linearGradient>`.\n   */\n  gradientId = gradientIdSeed++;\n\n  /** Paths to rendered in the template. */\n  progressCirclePath: NzProgressCirclePath[] = [];\n  circleGradient?: Array<{ offset: string; color: string }>;\n  trailPathStyle: NgStyleInterface | null = null;\n  pathString?: string;\n  icon!: string;\n\n  dir: Direction = 'ltr';\n\n  get formatter(): NzProgressFormatter {\n    return this.nzFormat || defaultFormatter;\n  }\n\n  get status(): NzProgressStatusType {\n    return this.nzStatus || this.inferredStatus;\n  }\n\n  get strokeWidth(): number {\n    return this.nzStrokeWidth || (this.nzType === 'line' && this.nzSize !== 'small' ? 8 : 6);\n  }\n\n  get isCircleStyle(): boolean {\n    return this.nzType === 'circle' || this.nzType === 'dashboard';\n  }\n\n  private cachedStatus: NzProgressStatusType = 'normal';\n  private inferredStatus: NzProgressStatusType = 'normal';\n\n  constructor() {\n    onConfigChangeEventForComponent(NZ_CONFIG_MODULE_NAME, () => {\n      this.updateIcon();\n      this.setStrokeColor();\n      this.getCirclePaths();\n    });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const {\n      nzSteps,\n      nzGapPosition,\n      nzStrokeLinecap,\n      nzStrokeColor,\n      nzGapDegree,\n      nzType,\n      nzStatus,\n      nzPercent,\n      nzSuccessPercent,\n      nzStrokeWidth\n    } = changes;\n\n    if (nzStatus) {\n      this.cachedStatus = this.nzStatus || this.cachedStatus;\n    }\n\n    if (nzPercent || nzSuccessPercent) {\n      const fillAll = parseInt(this.nzPercent.toString(), 10) >= 100;\n      if (fillAll) {\n        if ((isNotNil(this.nzSuccessPercent) && this.nzSuccessPercent! >= 100) || this.nzSuccessPercent === undefined) {\n          this.inferredStatus = 'success';\n        }\n      } else {\n        this.inferredStatus = this.cachedStatus;\n      }\n    }\n\n    if (nzStatus || nzPercent || nzSuccessPercent || nzStrokeColor) {\n      this.updateIcon();\n    }\n\n    if (nzStrokeColor) {\n      this.setStrokeColor();\n    }\n\n    if (nzGapPosition || nzStrokeLinecap || nzGapDegree || nzType || nzPercent || nzStrokeColor || nzStrokeColor) {\n      this.getCirclePaths();\n    }\n\n    if (nzPercent || nzSteps || nzStrokeWidth) {\n      this.isSteps = this.nzSteps > 0;\n      if (this.isSteps) {\n        this.getSteps();\n      }\n    }\n  }\n\n  ngOnInit(): void {\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n      this.dir = direction;\n      this.cdr.detectChanges();\n    });\n    this.dir = this.directionality.value;\n  }\n\n  private updateIcon(): void {\n    const ret = statusIconNameMap.get(this.status);\n    this.icon = ret ? ret + (this.isCircleStyle ? '-o' : '-circle-fill') : '';\n  }\n\n  /**\n   * Calculate step render configs.\n   */\n  private getSteps(): void {\n    const current = Math.floor(this.nzSteps * (this.nzPercent / 100));\n    const stepWidth = this.nzSize === 'small' ? 2 : 14;\n\n    const steps = [];\n\n    for (let i = 0; i < this.nzSteps; i++) {\n      let color;\n      if (i <= current - 1) {\n        color = this.nzStrokeColor;\n      }\n      const stepStyle = {\n        backgroundColor: `${color}`,\n        width: `${stepWidth}px`,\n        height: `${this.strokeWidth}px`\n      };\n      steps.push(stepStyle);\n    }\n\n    this.steps = steps;\n  }\n\n  /**\n   * Calculate paths when the type is circle or dashboard.\n   */\n  private getCirclePaths(): void {\n    if (!this.isCircleStyle) {\n      return;\n    }\n\n    const values = isNotNil(this.nzSuccessPercent) ? [this.nzSuccessPercent!, this.nzPercent] : [this.nzPercent];\n\n    // Calculate shared styles.\n    const radius = 50 - this.strokeWidth / 2;\n    const gapPosition = this.nzGapPosition || (this.nzType === 'circle' ? 'top' : 'bottom');\n    const len = Math.PI * 2 * radius;\n    const gapDegree = this.nzGapDegree || (this.nzType === 'circle' ? 0 : 75);\n\n    let beginPositionX = 0;\n    let beginPositionY = -radius;\n    let endPositionX = 0;\n    let endPositionY = radius * -2;\n\n    switch (gapPosition) {\n      case 'left':\n        beginPositionX = -radius;\n        beginPositionY = 0;\n        endPositionX = radius * 2;\n        endPositionY = 0;\n        break;\n      case 'right':\n        beginPositionX = radius;\n        beginPositionY = 0;\n        endPositionX = radius * -2;\n        endPositionY = 0;\n        break;\n      case 'bottom':\n        beginPositionY = radius;\n        endPositionY = radius * 2;\n        break;\n      default:\n    }\n\n    this.pathString = `M 50,50 m ${beginPositionX},${beginPositionY}\n       a ${radius},${radius} 0 1 1 ${endPositionX},${-endPositionY}\n       a ${radius},${radius} 0 1 1 ${-endPositionX},${endPositionY}`;\n\n    this.trailPathStyle = {\n      strokeDasharray: `${len - gapDegree}px ${len}px`,\n      strokeDashoffset: `-${gapDegree / 2}px`,\n      transition: 'stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s'\n    };\n\n    // Calculate styles for each path.\n    this.progressCirclePath = values\n      .map((value, index) => {\n        const isSuccessPercent = values.length === 2 && index === 0;\n        return {\n          stroke: this.isGradient && !isSuccessPercent ? `url(#gradient-${this.gradientId})` : null,\n          strokePathStyle: {\n            stroke: !this.isGradient\n              ? isSuccessPercent\n                ? statusColorMap.get('success')\n                : (this.nzStrokeColor as string)\n              : null,\n            transition:\n              'stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s',\n            strokeDasharray: `${((value || 0) / 100) * (len - gapDegree)}px ${len}px`,\n            strokeDashoffset: `-${gapDegree / 2}px`\n          }\n        };\n      })\n      .reverse();\n  }\n\n  private setStrokeColor(): void {\n    const color = this.nzStrokeColor;\n    const isGradient = (this.isGradient = !!color && typeof color !== 'string');\n    if (isGradient && !this.isCircleStyle) {\n      this.lineGradient = handleLinearGradient(color as NzProgressColorGradient);\n    } else if (isGradient && this.isCircleStyle) {\n      this.circleGradient = handleCircleGradient(this.nzStrokeColor as NzProgressGradientProgress);\n    } else {\n      this.lineGradient = null;\n      this.circleGradient = [];\n    }\n  }\n}\n"
  },
  {
    "path": "components/progress/progress.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzProgressComponent } from './progress.component';\n\n@NgModule({\n  imports: [NzProgressComponent],\n  exports: [NzProgressComponent]\n})\nexport class NzProgressModule {}\n"
  },
  {
    "path": "components/progress/progress.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport { Component, DebugElement, provideZoneChangeDetection, TemplateRef, ViewChild } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { NzProgressComponent } from './progress.component';\nimport { NzProgressModule } from './progress.module';\nimport {\n  NzProgressFormatter,\n  NzProgressGapPositionType,\n  NzProgressStatusType,\n  NzProgressStrokeColorType,\n  NzProgressStrokeLinecapType\n} from './typings';\n\ndescribe('progress', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  describe('progress line', () => {\n    let fixture: ComponentFixture<NzTestProgressLineComponent>;\n    let testComponent: NzTestProgressLineComponent;\n    let progress: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestProgressLineComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n      progress = fixture.debugElement.query(By.directive(NzProgressComponent));\n    });\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n\n      const classNames = progress.nativeElement.firstElementChild.className;\n      expect(classNames).toContain('ant-progress');\n      expect(classNames).toContain('ant-progress-status-normal');\n      expect(classNames).toContain('ant-progress-line');\n      expect(classNames).toContain('ant-progress-show-info');\n    });\n\n    it('should percent work', () => {\n      fixture.detectChanges();\n      expect(progress.nativeElement.querySelector('.ant-progress-bg').style.width).toBe('0%');\n      expect(progress.nativeElement.querySelector('.ant-progress-bg').style.height).toBe('8px');\n      expect(progress.nativeElement.querySelector('.ant-progress-text').innerText.trim()).toBe('0%');\n      testComponent.percent = 50;\n      fixture.detectChanges();\n      expect(progress.nativeElement.querySelector('.ant-progress-bg').style.width).toBe('50%');\n      expect(progress.nativeElement.querySelector('.ant-progress-bg').style.height).toBe('8px');\n      expect(progress.nativeElement.querySelector('.ant-progress-text').innerText.trim()).toBe('50%');\n      testComponent.percent = 100;\n      testComponent.successPercent = 100;\n      fixture.detectChanges();\n      expect(progress.nativeElement.querySelector('.ant-progress-bg').style.width).toBe('100%');\n      expect(progress.nativeElement.querySelector('.ant-progress-bg').style.height).toBe('8px');\n      expect(progress.nativeElement.querySelector('.ant-progress-text').innerText.trim()).toBe('');\n      expect(progress.nativeElement.querySelector('.anticon-check-circle')).toBeDefined();\n    });\n\n    it('should successPercent', () => {\n      fixture.detectChanges();\n      expect(progress.nativeElement.querySelector('.ant-progress-success-bg').style.width).toBe('0%');\n      expect(progress.nativeElement.querySelector('.ant-progress-success-bg').style.height).toBe('8px');\n      testComponent.successPercent = 50;\n      fixture.detectChanges();\n      expect(progress.nativeElement.querySelector('.ant-progress-success-bg').style.width).toBe('50%');\n      expect(progress.nativeElement.querySelector('.ant-progress-success-bg').style.height).toBe('8px');\n    });\n\n    it('should successPercent forbidden inferred success', () => {\n      fixture.detectChanges();\n      testComponent.successPercent = 50;\n      testComponent.percent = 100;\n      fixture.detectChanges();\n      expect(progress.nativeElement.querySelector('.ant-progress')!.classList).not.toContain(\n        'ant-progress-status-success'\n      );\n    });\n\n    it('should formatter work', () => {\n      testComponent.formatter = (percent: number) => `${percent} percent`;\n      fixture.detectChanges();\n      expect(progress.nativeElement.querySelector('.ant-progress-text').innerText.trim()).toBe('0 percent');\n      testComponent.percent = 100;\n      fixture.detectChanges();\n      expect(progress.nativeElement.querySelector('.ant-progress-text').innerText.trim()).toBe('100 percent');\n\n      testComponent.formatter = testComponent.formatterTemplate;\n      fixture.detectChanges();\n      expect(progress.nativeElement.querySelector('.ant-progress-text').innerText.trim()).toBe('100 / 100');\n    });\n\n    it('should status work', () => {\n      fixture.detectChanges();\n      expect(progress.nativeElement.firstElementChild!.classList).toContain('ant-progress-status-normal');\n      const listOfStatus: NzProgressStatusType[] = ['success', 'exception', 'active', 'normal'];\n      testComponent.percent = 100;\n      listOfStatus.forEach(status => {\n        testComponent.status = status;\n        fixture.detectChanges();\n        expect(progress.nativeElement.firstElementChild!.classList).toContain(`ant-progress-status-${status}`);\n      });\n    });\n\n    it('should showInfo work', () => {\n      fixture.detectChanges();\n      expect(progress.nativeElement.firstElementChild!.classList).toContain('ant-progress-show-info');\n      expect(progress.nativeElement.querySelector('.ant-progress-text')).toBeDefined();\n      testComponent.showInfo = false;\n      fixture.detectChanges();\n      expect(progress.nativeElement.firstElementChild!.classList).not.toContain('ant-progress-show-info');\n      expect(progress.nativeElement.querySelector('.ant-progress-text')).toBeNull();\n    });\n\n    it('should strokeWidth work', () => {\n      fixture.detectChanges();\n      expect(progress.nativeElement.querySelector('.ant-progress-bg').style.height).toBe('8px');\n      expect(progress.nativeElement.querySelector('.ant-progress-success-bg').style.height).toBe('8px');\n      testComponent.strokeWidth = 6;\n      fixture.detectChanges();\n      expect(progress.nativeElement.querySelector('.ant-progress-bg').style.height).toBe('6px');\n      expect(progress.nativeElement.querySelector('.ant-progress-success-bg').style.height).toBe('6px');\n    });\n\n    it('should size work', () => {\n      fixture.detectChanges();\n      expect(progress.nativeElement.querySelector('.ant-progress-bg').style.height).toBe('8px');\n      expect(progress.nativeElement.querySelector('.ant-progress-success-bg').style.height).toBe('8px');\n      testComponent.size = 'small';\n      fixture.detectChanges();\n      expect(progress.nativeElement.firstElementChild!.classList).toContain('ant-progress-small');\n      expect(progress.nativeElement.querySelector('.ant-progress-bg').style.height).toBe('6px');\n      expect(progress.nativeElement.querySelector('.ant-progress-success-bg').style.height).toBe('6px');\n    });\n\n    it('should strokeLinecap work', () => {\n      fixture.detectChanges();\n      expect(progress.nativeElement.querySelector('.ant-progress-bg').style.borderRadius).toBe('100px');\n      expect(progress.nativeElement.querySelector('.ant-progress-success-bg').style.borderRadius).toBe('100px');\n      testComponent.strokeLinecap = 'square';\n      fixture.detectChanges();\n      expect(progress.nativeElement.querySelector('.ant-progress-bg').style.borderRadius).toBe('0px');\n      expect(progress.nativeElement.querySelector('.ant-progress-success-bg').style.borderRadius).toBe('0px');\n    });\n\n    it('should strokeColor work', () => {\n      fixture.detectChanges();\n      expect(progress.nativeElement.querySelector('.ant-progress-bg').style.background).toBe('');\n      testComponent.strokeColor = 'blue';\n      fixture.detectChanges();\n      expect(progress.nativeElement.querySelector('.ant-progress-bg').style.background).toBe('blue');\n    });\n\n    it('should strokeColor work with gradient', () => {\n      fixture.detectChanges();\n      const progressBar: HTMLDivElement = progress.nativeElement.querySelector('.ant-progress-bg')!;\n      expect(progressBar.style.background).toBe('');\n      testComponent.strokeColor = { '0%': '#108ee9', '100%': '#87d068' };\n      fixture.detectChanges();\n      expect(progressBar.style.background).toBe('');\n      expect(progressBar.style.backgroundImage).toBe(\n        'linear-gradient(to right, rgb(16, 142, 233) 0%, rgb(135, 208, 104) 100%)'\n      );\n\n      testComponent.strokeColor = { '0%': '#108ee9', '100%': '#87d068' };\n      fixture.detectChanges();\n      expect(progressBar.style.background).toBe('');\n      expect(progressBar.style.backgroundImage).toBe(\n        'linear-gradient(to right, rgb(16, 142, 233) 0%, rgb(135, 208, 104) 100%)'\n      );\n    });\n\n    it('should support steps mode', () => {\n      testComponent.steps = 5;\n      testComponent.percent = 50;\n      testComponent.strokeColor = '#108ee9';\n      fixture.detectChanges();\n\n      const steps = progress.nativeElement.querySelectorAll('.ant-progress-steps-item');\n\n      expect(steps.length).toBe(5);\n      expect((steps[0] as HTMLDivElement).style.backgroundColor).toBe('rgb(16, 142, 233)');\n      expect((steps[4] as HTMLDivElement).style.backgroundColor).toBeFalsy();\n\n      testComponent.percent = 80;\n      fixture.detectChanges();\n\n      expect((steps[4] as HTMLDivElement).style.backgroundColor).toBeFalsy();\n    });\n  });\n\n  describe('progress dashboard', () => {\n    let fixture: ComponentFixture<NzTestProgressDashBoardComponent>;\n    let testComponent: NzTestProgressDashBoardComponent;\n    let progress: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestProgressDashBoardComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n      progress = fixture.debugElement.query(By.directive(NzProgressComponent));\n    });\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n\n      const classNames = progress.nativeElement.firstElementChild.className;\n      expect(classNames).toContain('ant-progress');\n      expect(classNames).toContain('ant-progress-status-normal');\n      expect(classNames).toContain('ant-progress-circle');\n      expect(classNames).toContain('ant-progress-show-info');\n    });\n\n    it('should format work', () => {\n      testComponent.format = (percent: number) => `${percent} percent`;\n      fixture.detectChanges();\n      expect(progress.nativeElement.querySelector('.ant-progress-text').innerText.trim()).toBe('0 percent');\n      testComponent.percent = 100;\n      fixture.detectChanges();\n      expect(progress.nativeElement.querySelector('.ant-progress-text').innerText.trim()).toBe('100 percent');\n    });\n\n    it('should showInfo work', () => {\n      fixture.detectChanges();\n      expect(progress.nativeElement.firstElementChild!.classList).toContain('ant-progress-show-info');\n      expect(progress.nativeElement.querySelector('.ant-progress-text')).toBeDefined();\n      testComponent.showInfo = false;\n      fixture.detectChanges();\n      expect(progress.nativeElement.firstElementChild!.classList).not.toContain('ant-progress-show-info');\n      expect(progress.nativeElement.querySelector('.ant-progress-text')).toBeNull();\n    });\n\n    it('should percent work', () => {\n      fixture.detectChanges();\n      expect(progress.nativeElement.querySelector('.ant-progress-text').innerText.trim()).toBe('0%');\n      testComponent.percent = 50;\n      fixture.detectChanges();\n      expect(progress.nativeElement.querySelector('.ant-progress-text').innerText.trim()).toBe('50%');\n      testComponent.percent = 100;\n      fixture.detectChanges();\n      expect(progress.nativeElement.querySelector('.ant-progress-text').innerText.trim()).toBe('');\n      expect(progress.nativeElement.querySelector('.anticon-check-circle')).toBeDefined();\n    });\n\n    it('should width work', () => {\n      let styleText = '';\n\n      function getStyleText(): void {\n        styleText = progress.nativeElement.querySelector('.ant-progress-inner').style.cssText;\n      }\n\n      fixture.detectChanges();\n      getStyleText();\n      expect(styleText).toContain('width: 132px;');\n      expect(styleText).toContain('height: 132px;');\n      expect(styleText).toContain('font-size: 25.8px;');\n\n      testComponent.width = 100;\n      fixture.detectChanges();\n      getStyleText();\n      expect(styleText).toContain('width: 100px;');\n      expect(styleText).toContain('height: 100px;');\n      expect(styleText).toContain('font-size: 21px;');\n    });\n\n    it('should strokeWidth work', () => {\n      fixture.detectChanges();\n      expect(\n        progress.nativeElement.querySelector('.ant-progress-circle-trail').attributes.getNamedItem('stroke-width').value\n      ).toBe('6');\n      testComponent.strokeWidth = 10;\n      fixture.detectChanges();\n      expect(\n        progress.nativeElement.querySelector('.ant-progress-circle-trail').attributes.getNamedItem('stroke-width').value\n      ).toBe('10');\n    });\n\n    it('should strokeLinecap work', () => {\n      fixture.detectChanges();\n      expect(\n        progress.nativeElement.querySelector('.ant-progress-circle-path').attributes.getNamedItem('stroke-linecap')\n          .value\n      ).toBe('round');\n      testComponent.strokeLinecap = 'square';\n      fixture.detectChanges();\n      expect(\n        progress.nativeElement.querySelector('.ant-progress-circle-path').attributes.getNamedItem('stroke-linecap')\n          .value\n      ).toBe('square');\n    });\n  });\n\n  describe('progress circle', () => {\n    let fixture: ComponentFixture<NzTestProgressCircleComponent>;\n    let testComponent: NzTestProgressCircleComponent;\n    let progress: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestProgressCircleComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n      progress = fixture.debugElement.query(By.directive(NzProgressComponent));\n    });\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n\n      const classNames = progress.nativeElement.firstElementChild.className;\n      expect(classNames).toContain('ant-progress');\n      expect(classNames).toContain('ant-progress-status-normal');\n      expect(classNames).toContain('ant-progress-circle');\n      expect(classNames).toContain('ant-progress-show-info');\n    });\n\n    it('should gapDegree work', () => {\n      fixture.detectChanges();\n      expect(progress.nativeElement.querySelector('.ant-progress-circle-path').style.strokeDashoffset).toBe('0px');\n      testComponent.gapDegree = 120;\n      fixture.detectChanges();\n      expect(progress.nativeElement.querySelector('.ant-progress-circle-path').style.strokeDashoffset).toBe('-60px');\n    });\n\n    it('should gapPosition work', () => {\n      fixture.detectChanges();\n\n      function getPathD(): string {\n        return progress.nativeElement\n          .querySelector('.ant-progress-circle-path')\n          .attributes.getNamedItem('d')\n          .value.replace(/\\n\\s{2,}/g, ' ');\n      }\n\n      expect(getPathD()).toBe(`M 50,50 m 0,-47 a 47,47 0 1 1 0,94 a 47,47 0 1 1 0,-94`);\n\n      testComponent.gapPosition = 'left';\n      fixture.detectChanges();\n      expect(getPathD()).toBe(`M 50,50 m -47,0 a 47,47 0 1 1 94,0 a 47,47 0 1 1 -94,0`);\n\n      testComponent.gapPosition = 'right';\n      fixture.detectChanges();\n      expect(getPathD()).toBe(`M 50,50 m 47,0 a 47,47 0 1 1 -94,0 a 47,47 0 1 1 94,0`);\n\n      testComponent.gapPosition = 'bottom';\n      fixture.detectChanges();\n      expect(getPathD()).toBe(`M 50,50 m 0,47 a 47,47 0 1 1 0,-94 a 47,47 0 1 1 0,94`);\n\n      testComponent.gapPosition = 'top';\n      fixture.detectChanges();\n      expect(getPathD()).toBe(`M 50,50 m 0,-47 a 47,47 0 1 1 0,94 a 47,47 0 1 1 0,-94`);\n    });\n\n    it('should strokeLinecap work', () => {\n      fixture.detectChanges();\n      expect(\n        progress.nativeElement.querySelector('.ant-progress-circle-path').attributes.getNamedItem('stroke-linecap')\n          .value\n      ).toBe('round');\n      testComponent.strokeLinecap = 'square';\n      fixture.detectChanges();\n      expect(\n        progress.nativeElement.querySelector('.ant-progress-circle-path').attributes.getNamedItem('stroke-linecap')\n          .value\n      ).toBe('square');\n    });\n\n    it('should strokeColor work', () => {\n      fixture.detectChanges();\n      const path = progress.nativeElement.querySelector('.ant-progress-circle-path');\n      // No stroke property for built-in colors.\n      expect(path.attributes.getNamedItem('stroke')).toBeFalsy();\n      testComponent.strokeColor = 'blue';\n      fixture.detectChanges();\n      // TODO: don't why this is invalid in tests\n      // expect(path.attributes.getNamedItem('style').value).toContain('blue');\n    });\n\n    it('should strokeColor work with gradient', () => {\n      fixture.detectChanges();\n      // const path = progress.nativeElement.querySelector('.ant-progress-circle-path');\n      testComponent.strokeColor = { '0%': '#108ee9', '100%': '#87d068' };\n      fixture.detectChanges();\n      // expect(path.attributes.getNamedItem('stroke').value).toMatch(/url(#gradient-\\d)/);\n    });\n  });\n\n  describe('progress circle with successPercent', () => {\n    let fixture: ComponentFixture<NzTestProgressCircleSuccessComponent>;\n    let progress: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestProgressCircleSuccessComponent);\n      fixture.detectChanges();\n      progress = fixture.debugElement.query(By.directive(NzProgressComponent));\n    });\n\n    it('should success percent work', () => {\n      fixture.detectChanges();\n      expect(progress.nativeElement.querySelectorAll('.ant-progress-circle-path')[1].style.stroke).toBe(\n        'rgb(135, 208, 104)'\n      );\n    });\n  });\n\n  describe('RTL', () => {\n    let fixture: ComponentFixture<NzTestProgressRtlComponent>;\n    let progress: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestProgressRtlComponent);\n      fixture.detectChanges();\n      progress = fixture.debugElement.query(By.directive(NzProgressComponent));\n    });\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n      expect(progress.nativeElement.firstElementChild.classList).toContain('ant-progress-rtl');\n\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n\n      expect(progress.nativeElement.firstElementChild.classList).not.toContain('ant-progress-rtl');\n    });\n  });\n});\n\n@Component({\n  imports: [NzProgressModule],\n  template: `\n    <nz-progress\n      [nzSize]=\"size\"\n      [nzSuccessPercent]=\"successPercent\"\n      [nzFormat]=\"formatter\"\n      [nzStatus]=\"status\"\n      [nzShowInfo]=\"showInfo\"\n      [nzStrokeWidth]=\"strokeWidth\"\n      [nzPercent]=\"percent\"\n      [nzStrokeColor]=\"strokeColor\"\n      [nzStrokeLinecap]=\"strokeLinecap\"\n      [nzSteps]=\"steps\"\n    />\n    <ng-template #formatterTemplate let-percent>{{ percent }} / 100</ng-template>\n  `\n})\nexport class NzTestProgressLineComponent {\n  @ViewChild('formatterTemplate') formatterTemplate!: TemplateRef<{ $implicit: number }>;\n  size!: 'default' | 'small';\n  status?: NzProgressStatusType;\n  formatter?: NzProgressFormatter;\n  strokeWidth?: number;\n  percent = 0;\n  successPercent = 0;\n  showInfo = true;\n  strokeLinecap: NzProgressStrokeLinecapType = 'round';\n  steps?: number;\n  strokeColor?: NzProgressStrokeColorType;\n}\n\n@Component({\n  imports: [NzProgressModule],\n  template: `\n    <nz-progress\n      nzType=\"dashboard\"\n      [nzWidth]=\"width\"\n      [nzFormat]=\"format\"\n      [nzStatus]=\"status\"\n      [nzShowInfo]=\"showInfo\"\n      [nzStrokeWidth]=\"strokeWidth\"\n      [nzPercent]=\"percent\"\n      [nzStrokeLinecap]=\"strokeLinecap\"\n    />\n  `\n})\nexport class NzTestProgressDashBoardComponent {\n  status?: NzProgressStatusType;\n  format?: NzProgressFormatter;\n  strokeWidth?: number;\n  percent = 0;\n  showInfo = true;\n  width = 132;\n  strokeLinecap: NzProgressStrokeLinecapType = 'round';\n}\n\n@Component({\n  imports: [NzProgressModule],\n  template: `\n    <nz-progress\n      nzType=\"circle\"\n      [nzPercent]=\"75\"\n      [nzGapDegree]=\"gapDegree\"\n      [nzGapPosition]=\"gapPosition\"\n      [nzStrokeColor]=\"strokeColor\"\n      [nzStrokeLinecap]=\"strokeLinecap\"\n    />\n  `\n})\nexport class NzTestProgressCircleComponent {\n  gapDegree?: number;\n  gapPosition!: NzProgressGapPositionType;\n  strokeLinecap: NzProgressStrokeLinecapType = 'round';\n  strokeColor?: NzProgressStrokeColorType;\n}\n\n@Component({\n  imports: [NzProgressModule],\n  template: `<nz-progress nzType=\"circle\" [nzPercent]=\"75\" [nzSuccessPercent]=\"60\" />`\n})\nexport class NzTestProgressCircleSuccessComponent {}\n\n@Component({\n  imports: [BidiModule, NzProgressModule],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-progress nzType=\"circle\" [nzPercent]=\"75\" [nzSuccessPercent]=\"60\" />\n    </div>\n  `\n})\nexport class NzTestProgressRtlComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n}\n"
  },
  {
    "path": "components/progress/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport { NzProgressModule } from './progress.module';\nexport { NzProgressComponent } from './progress.component';\nexport * from './typings';\n"
  },
  {
    "path": "components/progress/style/entry.less",
    "content": "@import './index.less';\n"
  },
  {
    "path": "components/progress/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@progress-prefix-cls: ~'@{ant-prefix}-progress';\n\n.@{progress-prefix-cls} {\n  .reset-component();\n\n  display: inline-block;\n\n  &-line {\n    position: relative;\n    width: 100%;\n    font-size: @font-size-base;\n  }\n\n  &-steps {\n    display: inline-block;\n\n    &-outer {\n      display: flex;\n      flex-direction: row;\n      align-items: center;\n    }\n\n    &-item {\n      flex-shrink: 0;\n      min-width: 2px;\n      margin-right: 2px;\n      background: @progress-steps-item-bg;\n      transition: all 0.3s;\n\n      &-active {\n        background: @progress-default-color;\n      }\n    }\n  }\n\n  &-small&-line,\n  &-small&-line &-text .@{iconfont-css-prefix} {\n    font-size: @font-size-sm;\n  }\n\n  &-outer {\n    display: inline-block;\n    width: 100%;\n    margin-right: 0;\n    padding-right: 0;\n    .@{progress-prefix-cls}-show-info & {\n      margin-right: ~'calc(-2em - 8px)';\n      padding-right: ~'calc(2em + 8px)';\n    }\n  }\n\n  &-inner {\n    position: relative;\n    display: inline-block;\n    width: 100%;\n    overflow: hidden;\n    vertical-align: middle;\n    background-color: @progress-remaining-color;\n    border-radius: @progress-radius;\n  }\n\n  &-circle-trail {\n    stroke: @progress-remaining-color;\n  }\n\n  &-circle-path {\n    animation: ~'@{ant-prefix}-progress-appear' 0.3s;\n  }\n\n  &-inner:not(.@{ant-prefix}-progress-circle-gradient) {\n    .@{ant-prefix}-progress-circle-path {\n      stroke: @progress-default-color;\n    }\n  }\n\n  &-success-bg,\n  &-bg {\n    position: relative;\n    background-color: @progress-default-color;\n    border-radius: @progress-radius;\n    transition: all 0.4s @ease-out-circ 0s;\n  }\n\n  &-success-bg {\n    position: absolute;\n    top: 0;\n    left: 0;\n    background-color: @success-color;\n  }\n\n  &-text {\n    display: inline-block;\n    width: 2em;\n    margin-left: 8px;\n    color: @progress-info-text-color;\n    font-size: @progress-text-font-size;\n    line-height: 1;\n    white-space: nowrap;\n    text-align: left;\n    vertical-align: middle;\n    word-break: normal;\n    .@{iconfont-css-prefix} {\n      font-size: @font-size-base;\n    }\n  }\n\n  &-status-active {\n    .@{progress-prefix-cls}-bg::before {\n      position: absolute;\n      top: 0;\n      right: 0;\n      bottom: 0;\n      left: 0;\n      background: @component-background;\n      border-radius: 10px;\n      opacity: 0;\n      animation: ~'@{ant-prefix}-progress-active' 2.4s @ease-out-quint infinite;\n      content: '';\n    }\n  }\n\n  &-status-exception {\n    .@{progress-prefix-cls}-bg {\n      background-color: @error-color;\n    }\n    .@{progress-prefix-cls}-text {\n      color: @error-color;\n    }\n  }\n\n  &-status-exception &-inner:not(.@{progress-prefix-cls}-circle-gradient) {\n    .@{progress-prefix-cls}-circle-path {\n      stroke: @error-color;\n    }\n  }\n\n  &-status-success {\n    .@{progress-prefix-cls}-bg {\n      background-color: @success-color;\n    }\n    .@{progress-prefix-cls}-text {\n      color: @success-color;\n    }\n  }\n\n  &-status-success &-inner:not(.@{progress-prefix-cls}-circle-gradient) {\n    .@{progress-prefix-cls}-circle-path {\n      stroke: @success-color;\n    }\n  }\n\n  &-circle &-inner {\n    position: relative;\n    line-height: 1;\n    background-color: transparent;\n  }\n\n  &-circle &-text {\n    position: absolute;\n    top: 50%;\n    left: 50%;\n    width: 100%;\n    margin: 0;\n    padding: 0;\n    color: @progress-text-color;\n    font-size: @progress-circle-text-font-size;\n    line-height: 1;\n    white-space: normal;\n    text-align: center;\n    transform: translate(-50%, -50%);\n\n    .@{iconfont-css-prefix} {\n      font-size: (14 / 12em);\n    }\n  }\n\n  &-circle&-status-exception {\n    .@{progress-prefix-cls}-text {\n      color: @error-color;\n    }\n  }\n\n  &-circle&-status-success {\n    .@{progress-prefix-cls}-text {\n      color: @success-color;\n    }\n  }\n}\n\n@keyframes ~\"@{ant-prefix}-progress-active\" {\n  0% {\n    transform: translateX(-100%) scaleX(0);\n    opacity: 0.1;\n  }\n\n  20% {\n    transform: translateX(-100%) scaleX(0);\n    opacity: 0.5;\n  }\n\n  100% {\n    transform: translateX(0) scaleX(1);\n    opacity: 0;\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/progress/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@progress-prefix-cls: ~'@{ant-prefix}-progress';\n\n.@{progress-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &-outer {\n    .@{progress-prefix-cls}-show-info & {\n      .@{progress-prefix-cls}-rtl& {\n        margin-right: 0;\n        margin-left: ~'calc(-2em - 8px)';\n        padding-right: 0;\n        padding-left: ~'calc(2em + 8px)';\n      }\n    }\n  }\n\n  &-success-bg {\n    .@{progress-prefix-cls}-rtl & {\n      right: 0;\n      left: auto;\n    }\n  }\n\n  &-line &-text,\n  &-steps &-text {\n    .@{progress-prefix-cls}-rtl& {\n      margin-right: 8px;\n      margin-left: 0;\n      text-align: right;\n    }\n  }\n}\n"
  },
  {
    "path": "components/progress/typings.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { TemplateRef } from '@angular/core';\n\nimport { NgStyleInterface } from 'ng-zorro-antd/core/types';\n\nexport type NzProgressGapPositionType = 'top' | 'bottom' | 'left' | 'right';\n\nexport type NzProgressStatusType = 'success' | 'exception' | 'active' | 'normal';\n\nexport type NzProgressTypeType = 'line' | 'circle' | 'dashboard';\n\nexport type NzProgressStrokeLinecapType = 'round' | 'square';\n\nexport interface NzProgressGradientProgress {\n  [percent: string]: string;\n}\n\nexport interface NzProgressGradientFromTo {\n  from: string;\n  to: string;\n}\n\nexport type NzProgressColorGradient = { direction?: string } & (NzProgressGradientProgress | NzProgressGradientFromTo);\n\nexport type NzProgressStrokeColorType = string | NzProgressColorGradient;\n\nexport type NzProgressFormatter = ((percent: number) => string | null) | TemplateRef<{ $implicit: number }>;\n\nexport interface NzProgressCirclePath {\n  stroke: string | null;\n  strokePathStyle: NgStyleInterface;\n}\n\nexport interface NzProgressStepItem {\n  backgroundColor: string;\n  width: string;\n  height: string;\n}\n"
  },
  {
    "path": "components/progress/utils.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { handleCircleGradient, handleLinearGradient } from './utils';\n\n// https://github.com/ant-design/ant-design/blob/330a952a988a4ae18c201b464c51d5faeb714f7c/components/progress/__tests__/index.test.js#L74-L88.\ndescribe('progress util functions', () => {\n  it('get correct line-gradient', () => {\n    expect(handleLinearGradient({ from: 'test', to: 'test' })).toBe('linear-gradient(to right, test, test)');\n    expect(handleLinearGradient({})).toBe('linear-gradient(to right, #1890ff, #1890ff)');\n    expect(handleLinearGradient({ from: 'test', to: 'test', '0%': 'test' })).toBe('linear-gradient(to right, test 0%)');\n  });\n\n  it('get correct circle gradient', () => {\n    const gradientOne = handleCircleGradient({ '10%': 'test10', '30%': 'test30', '20%': 'test20' });\n    expect(gradientOne[0].color).toBe('test10');\n    expect(gradientOne[0].offset).toBe('10%');\n    expect(gradientOne[1].color).toBe('test20');\n    expect(gradientOne[1].offset).toBe('20%');\n  });\n});\n"
  },
  {
    "path": "components/progress/utils.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzProgressColorGradient, NzProgressGradientProgress } from './typings';\n\nfunction stripPercentToNumber(percent: string): number {\n  return +percent.replace('%', '');\n}\n\nexport const sortGradient = (gradients: NzProgressGradientProgress): Array<{ key: number; value: string }> => {\n  let tempArr: Array<{ key: number; value: string }> = [];\n\n  Object.keys(gradients).forEach(key => {\n    const value = gradients[key];\n    const formatKey = stripPercentToNumber(key);\n    if (!isNaN(formatKey)) {\n      tempArr.push({\n        key: formatKey,\n        value\n      });\n    }\n  });\n\n  tempArr = tempArr.sort((a, b) => a.key - b.key);\n  return tempArr;\n};\n\nexport const handleCircleGradient = (\n  strokeColor: NzProgressGradientProgress\n): Array<{ offset: string; color: string }> =>\n  sortGradient(strokeColor).map(({ key, value }) => ({ offset: `${key}%`, color: value }));\n\nexport const handleLinearGradient = (strokeColor: NzProgressColorGradient): string => {\n  const { from = '#1890ff', to = '#1890ff', direction = 'to right', ...rest } = strokeColor;\n  if (Object.keys(rest).length !== 0) {\n    const sortedGradients = sortGradient(rest as NzProgressGradientProgress)\n      .map(({ key, value }) => `${value} ${key}%`)\n      .join(', ');\n    return `linear-gradient(${direction}, ${sortedGradients})`;\n  }\n  return `linear-gradient(${direction}, ${from}, ${to})`;\n};\n"
  },
  {
    "path": "components/public_api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\n// https://github.com/ng-packagr/ng-packagr/issues/1655\nexport default void 0;\n"
  },
  {
    "path": "components/qr-code/demo/background.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 具有自定义背景颜色\n  en-US: With custom background color\n---\n\n## zh-CN\n\n自定义二维码的背景颜色。\n\n## en-US\n\nCustomize the background color of the QR Code.\n"
  },
  {
    "path": "components/qr-code/demo/background.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzQRCodeModule } from 'ng-zorro-antd/qr-code';\n\n@Component({\n  selector: 'nz-demo-qr-code-background',\n  imports: [NzQRCodeModule],\n  template: `\n    <nz-qrcode nzBgColor=\"#f6f6f6\" nzColor=\"#ff6600\" nzValue=\"https://ng.ant.design/\" />\n    <nz-qrcode nzBgColor=\"#f6f6f6\" nzColor=\"#1677ff\" nzValue=\"https://ng.ant.design/\" />\n  `,\n  styles: `\n    nz-qrcode {\n      margin-right: 12px;\n    }\n  `\n})\nexport class NzDemoQrCodeBackgroundComponent {}\n"
  },
  {
    "path": "components/qr-code/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n最简单的用法。\n\n## en-US\n\nThe simplest usage.\n"
  },
  {
    "path": "components/qr-code/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzQRCodeModule } from 'ng-zorro-antd/qr-code';\n\n@Component({\n  selector: 'nz-demo-qr-code-basic',\n  imports: [NzQRCodeModule],\n  template: `<nz-qrcode nzValue=\"https://ng.ant.design/\" />`\n})\nexport class NzDemoQrCodeBasicComponent {}\n"
  },
  {
    "path": "components/qr-code/demo/color.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 自定义颜色\n  en-US: Custom Color\n---\n\n## zh-CN\n\n通过设置 `nzColor` 自定义二维码颜色。\n\n## en-US\n\nCustomize QR code color.\n"
  },
  {
    "path": "components/qr-code/demo/color.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzQRCodeModule } from 'ng-zorro-antd/qr-code';\n\n@Component({\n  selector: 'nz-demo-qr-code-color',\n  imports: [NzQRCodeModule],\n  template: `\n    <nz-qrcode nzValue=\"https://ng.ant.design/\" nzColor=\"#ff6600\" />\n    <nz-qrcode nzValue=\"https://ng.ant.design/\" nzColor=\"#1677ff\" />\n  `,\n  styles: `\n    nz-qrcode {\n      margin-right: 12px;\n    }\n  `\n})\nexport class NzDemoQrCodeColorComponent {}\n"
  },
  {
    "path": "components/qr-code/demo/custom-status.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 自定义状态渲染器\n  en-US: custom status\n---\n\n## zh-CN\n\n可以通过 `nzStatusRender` 的值控制二维码不同状态的渲染逻辑。\n\n## en-US\n\nYou can control the rendering logic of the QR code in different states through the value of `nzStatusRender`.\n"
  },
  {
    "path": "components/qr-code/demo/custom-status.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzQRCodeModule } from 'ng-zorro-antd/qr-code';\n\n@Component({\n  selector: 'nz-demo-qr-code-custom-status',\n  imports: [NzQRCodeModule, NzIconModule],\n  template: `\n    <nz-qrcode nzValue=\"https://ng.ant.design/\" nzStatusRender=\"NgZorro\" />\n    <nz-qrcode nzValue=\"https://ng.ant.design/\" [nzStatusRender]=\"customTemplate\" />\n    <ng-template #customTemplate>\n      <div>\n        <nz-icon nzType=\"check-circle\" nzTheme=\"outline\" style=\"color: red\" />\n        success\n      </div>\n    </ng-template>\n  `,\n  styles: `\n    nz-qrcode {\n      margin-right: 12px;\n    }\n  `\n})\nexport class NzDemoQrCodeCustomStatusComponent {}\n"
  },
  {
    "path": "components/qr-code/demo/download.md",
    "content": "---\norder: 12\ntitle:\n  zh-CN: 下载二维码\n  en-US: Download QRCode\n---\n\n## zh-CN\n\n实现下载二维码。\n\n## en-US\n\nA way to download QRCode.\n"
  },
  {
    "path": "components/qr-code/demo/download.ts",
    "content": "import { Component, ViewChild, ElementRef } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzQRCodeModule } from 'ng-zorro-antd/qr-code';\n\n@Component({\n  selector: 'nz-demo-qr-code-download',\n  imports: [NzButtonModule, NzQRCodeModule],\n  template: `\n    <div id=\"download\">\n      <nz-qrcode nzValue=\"https://ng.ant.design/\" />\n      <a #download></a>\n      <button nz-button nzType=\"primary\" (click)=\"downloadImg()\">Download</button>\n    </div>\n  `,\n  styles: `\n    div {\n      display: flex;\n      align-items: flex-start;\n      flex-direction: column;\n    }\n\n    nz-qrcode {\n      margin-bottom: 12px;\n    }\n  `\n})\nexport class NzDemoQrCodeDownloadComponent {\n  @ViewChild('download', { static: false }) download!: ElementRef;\n\n  downloadImg(): void {\n    const canvas = document.getElementById('download')?.querySelector<HTMLCanvasElement>('canvas');\n    if (canvas) {\n      this.download.nativeElement.href = canvas.toDataURL('image/png');\n      this.download.nativeElement.download = 'ng-zorro-antd';\n      const event = new MouseEvent('click');\n      this.download.nativeElement.dispatchEvent(event);\n    }\n  }\n}\n"
  },
  {
    "path": "components/qr-code/demo/error-level.md",
    "content": "---\norder: 10\ntitle:\n  zh-CN: 容错等级\n  en-US: Error Level\n---\n\n## zh-CN\n\n通过设置 `nzLevel` 调整二维码容错。\n\n## en-US\n\nSet Error Level.\n"
  },
  {
    "path": "components/qr-code/demo/error-level.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzQRCodeModule } from 'ng-zorro-antd/qr-code';\nimport { NzSegmentedModule } from 'ng-zorro-antd/segmented';\n\n@Component({\n  selector: 'nz-demo-qr-code-error-level',\n  imports: [NzQRCodeModule, NzSegmentedModule, FormsModule],\n  template: `\n    <nz-qrcode nzValue=\"https://github.com/NG-ZORRO/ng-zorro-antd/issues\" [nzLevel]=\"errorLevel\" />\n    <nz-segmented [nzOptions]=\"options\" [(ngModel)]=\"errorLevel\" />\n  `,\n  styles: `\n    :host {\n      display: flex;\n      align-items: flex-start;\n      flex-direction: column;\n    }\n\n    nz-qrcode {\n      margin-bottom: 12px;\n    }\n  `\n})\nexport class NzDemoQrCodeErrorLevelComponent {\n  options: Array<'L' | 'M' | 'Q' | 'H'> = ['L', 'M', 'Q', 'H'];\n  errorLevel: 'L' | 'M' | 'Q' | 'H' = 'L';\n}\n"
  },
  {
    "path": "components/qr-code/demo/icon.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 带 icon 的例子\n  en-US: With Icon\n---\n\n## zh-CN\n\n带有 icon 的二维码。\n\n## en-US\n\nQRCode with icon.\n"
  },
  {
    "path": "components/qr-code/demo/icon.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzQRCodeModule } from 'ng-zorro-antd/qr-code';\n\n@Component({\n  selector: 'nz-demo-qr-code-icon',\n  imports: [NzQRCodeModule],\n  template: `\n    <nz-qrcode\n      nzValue=\"https://ng.ant.design/\"\n      nzIcon=\"https://img.alicdn.com/imgextra/i2/O1CN01TBIkzL1Nk3IBB0DLA_!!6000000001607-2-tps-106-120.png\"\n      nzLevel=\"H\"\n    />\n  `\n})\nexport class NzDemoQrCodeIconComponent {}\n"
  },
  {
    "path": "components/qr-code/demo/padding.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 带衬垫\n  en-US: With padding\n---\n\n## zh-CN\n\n自定义 QR 码的填充。\n\n## en-US\n\nCustomize the padding of the QR Code.\n"
  },
  {
    "path": "components/qr-code/demo/padding.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzQRCodeModule } from 'ng-zorro-antd/qr-code';\n\n@Component({\n  selector: 'nz-demo-qr-code-padding',\n  imports: [NzQRCodeModule],\n  template: `\n    <nz-qrcode [nzPadding]=\"2\" nzValue=\"https://ng.ant.design/\" />\n    <nz-qrcode nzType=\"svg\" [nzPadding]=\"2\" nzValue=\"https://ng.ant.design/\" />\n  `,\n  styles: `\n    nz-qrcode {\n      margin-right: 12px;\n      padding: 0;\n    }\n  `\n})\nexport class NzDemoQrCodePaddingComponent {}\n"
  },
  {
    "path": "components/qr-code/demo/status.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 不同的状态\n  en-US: Other Status\n---\n\n## zh-CN\n\n通过 `nzStatus` 的值控制二维码的状态，提供了 `active`、`expired`、`loading`、`scanned` 四个值。\n\n## en-US\n\nThe status can be controlled by the value `nzStatus`, four values of `active`, `expired`, `loading`, `scanned` are provided.\n"
  },
  {
    "path": "components/qr-code/demo/status.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzQRCodeModule } from 'ng-zorro-antd/qr-code';\n\n@Component({\n  selector: 'nz-demo-qr-code-status',\n  imports: [NzQRCodeModule],\n  template: `\n    <nz-qrcode nzValue=\"https://ng.ant.design/\" nzStatus=\"loading\" />\n    <nz-qrcode nzValue=\"https://ng.ant.design/\" nzStatus=\"expired\" (nzRefresh)=\"refresh($event)\" />\n    <nz-qrcode nzValue=\"https://ng.ant.design/\" nzStatus=\"scanned\" />\n  `,\n  styles: `\n    nz-qrcode {\n      margin-right: 12px;\n    }\n  `\n})\nexport class NzDemoQrCodeStatusComponent {\n  refresh(val: string): void {\n    console.log(val);\n  }\n}\n"
  },
  {
    "path": "components/qr-code/demo/type.md",
    "content": "---\norder: 5\nversion: 21.0.0\ntitle:\n  zh-CN: 自定义渲染类型\n  en-US: Custom Render Type\n---\n\n## zh-CN\n\n通过设置 `nzType` 自定义渲染结果，提供 `canvas` 和 `svg` 两个选项。\n\n## en-US\n\nCustomize the rendering results by `nzType`, provide options `canvas` and `svg`.\n"
  },
  {
    "path": "components/qr-code/demo/type.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzQRCodeModule } from 'ng-zorro-antd/qr-code';\n\n@Component({\n  selector: 'nz-demo-qr-code-type',\n  imports: [NzQRCodeModule],\n  template: `\n    <nz-qrcode nzValue=\"https://ng.ant.design/\" />\n    <nz-qrcode nzValue=\"https://ng.ant.design/\" nzType=\"svg\" />\n  `,\n  styles: `\n    nz-qrcode {\n      margin-right: 12px;\n    }\n  `\n})\nexport class NzDemoQrCodeTypeComponent {}\n"
  },
  {
    "path": "components/qr-code/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Display\ntitle: QRCode\ntag: 15.1.0\ncover: 'https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*cJopQrf0ncwAAAAAAAAAAAAADrJ8AQ/original'\ndescription: Convert text into QR codes, and support custom color and logo.\n---\n\n## When To Use\n\nUsed when the text needs to be converted into a QR Code.\n\n## API\n\n### nz-qrcode\n\n| Property           | Description                                                                                                  | Type                                        | Default     | Version           |\n| ------------------ | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------- | ----------- | ----------------- |\n| `[nzValue]`        | scanned text                                                                                                 | `string \\| string[]`                        | -           | `string[]`:21.0.0 |\n| `[nzType]`         | render type                                                                                                  | `'canvas'\\|'svg'`                           | `canvas`    | 21.0.0            |\n| `[nzColor]`        | QR code Color                                                                                                | `string`                                    | `'#000000'` |\n| `[nzBgColor]`      | QR code background color                                                                                     | `string`                                    | `'#FFFFFF'` |\n| `[nzSize]`         | QR code Size                                                                                                 | `number`                                    | `160`       |\n| `[nzPadding]`      | QR code Padding                                                                                              | `number`                                    | `0`         |\n| `[nzIcon]`         | Icon address in QR code                                                                                      | `string`                                    | -           |\n| `[nzIconSize]`     | The size of the icon in the QR code                                                                          | `number`                                    | `40`        |\n| `[nzBordered]`     | Whether has border style                                                                                     | `boolean`                                   | `true`      |\n| `[nzStatus]`       | QR code status                                                                                               | `'active'\\|'expired'\\|'loading'\\|'scanned'` | `'active'`  |\n| `[nzStatusRender]` | custom status                                                                                                | `TemplateRef<void> \\| string`               | -           |\n| `[nzLevel]`        | Error Code Level                                                                                             | `'L'\\|'M'\\|'Q'\\|'H'`                        | `'M'`       |\n| `[nzBoostLevel]`   | If enabled, the Error Correction Level of the result may be higher than the specified Error Correction Level | `boolean`                                   | `true`      | 21.0.0            |\n| `(nzRefresh)`      | callback                                                                                                     | `EventEmitter<string>`                      | -           |\n\n## Note\n\n### Invalid QR Code\n\n`nzValue` has a conservative upper limit of 738 or fewer strings. If error correction levels are used, the `nzValue`\nupper limit will be lowered.\n\n### QR Code error correction level\n\nThe ErrorLevel means that the QR code can be scanned normally after being blocked, and the maximum area that can be\nblocked is the error correction rate.\n\nGenerally, the QR code is divided into 4 error correction levels: Level `L` can correct about `7%` errors, Level `M` can\ncorrect about `15%` errors, Level `Q` can correct about `25%` errors, and Level `H` can correct about `30%` errors. When\nthe content encoding of the QR code carries less information, in other words, when the value link is short, set\ndifferent error correction levels, and the generated image will not change.\n\n> For more information, see\n> the: [https://www.qrcode.com/en/about/error_correction](https://www.qrcode.com/en/about/error_correction.html)\n"
  },
  {
    "path": "components/qr-code/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 二维码\ntype: 数据展示\ntitle: QRCode\ntag: 15.1.0\ncover: 'https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*cJopQrf0ncwAAAAAAAAAAAAADrJ8AQ/original'\ndescription: 能够将文本转换生成二维码的组件，支持自定义配色和 Logo 配置。\n---\n\n## 何时使用\n\n当需要将文本转换成为二维码时使用。\n\n## API\n\n### nz-qrcode\n\n| 参数               | 说明                                                               | 类型                                        | 默认值      | 版本              |\n| ------------------ | ------------------------------------------------------------------ | ------------------------------------------- | ----------- | ----------------- |\n| `[nzValue]`        | 扫描后的文本                                                       | `string \\| string[]`                        | -           | `string[]`:21.0.0 |\n| `[nzType]`         | 渲染类型                                                           | `'canvas'\\|'svg'`                           | `canvas`    | 21.0.0            |\n| `[nzColor]`        | 二维码颜色                                                         | `string`                                    | `'#000000'` |\n| `[nzBgColor]`      | 二维码背景颜色                                                     | `string`                                    | `'#FFFFFF'` |\n| `[nzSize]`         | 二维码大小                                                         | `number`                                    | `160`       |\n| `[nzPadding]`      | 二维码填充                                                         | `number`                                    | `0`         |\n| `[nzIcon]`         | 二维码中 icon 地址                                                 | `string`                                    | -           |\n| `[nzIconSize]`     | 二维码中 icon 大小                                                 | `number`                                    | `40`        |\n| `[nzBordered]`     | 是否有边框                                                         | `boolean`                                   | `true`      |\n| `[nzStatus]`       | 二维码状态                                                         | `'active'\\|'expired'\\|'loading'\\|'scanned'` | `'active'`  |\n| `[nzStatusRender]` | 自定义状态渲染器                                                   | `TemplateRef<void> \\| string`               | -           |\n| `[nzLevel]`        | 二维码容错等级                                                     | `'L'\\|'M'\\|'Q'\\|'H'`                        | `'M'`       |\n| `[nzBoostLevel]`   | 如果启用，自动提升纠错等级，结果的纠错级别可能会高于指定的纠错级别 | `boolean`                                   | `true`      | 21.0.0            |\n| `(nzRefresh)`      | 点击\"点击刷新\"的回调                                               | `EventEmitter<string>`                      | -           |\n\n## 注意\n\n### 二维码无法识别\n\n`nzValue` 保守的上限为 738 或更少的字符串。如果使用容错等级，`nzValue` 上限会降低。\n\n### 关于二维码容错等级\n\n容错等级也叫容错率，就是指二维码可以被遮挡后还能正常扫描，而这个能被遮挡的最大面积就是容错率。\n\n通常情况下二维码分为 4 个容错等级：`L级` 可纠正约 `7%` 错误、`M级` 可纠正约 `15%` 错误、`Q级` 可纠正约 `25%` 错误、`H级`\n可纠正约 `30%`\n错误。并不是所有位置都可以缺损，像最明显的三个角上的方框，直接影响初始定位。中间零散的部分是内容编码，可以容忍缺损。当二维码的内容编码携带信息比较少的时候，也就是链接比较短的时候，设置不同的容错等级，生成的图片不会发生变化。\n\n> 有关更多信息，可参阅相关资料：[https://www.qrcode.com/zh/about/error_correction](https://www.qrcode.com/zh/about/error_correction.html)\n"
  },
  {
    "path": "components/qr-code/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/qr-code/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/qr-code/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './qrcode.component';\nexport * from './qrcode.module';\n"
  },
  {
    "path": "components/qr-code/qrcode-canvas.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { AfterViewInit, ChangeDetectionStrategy, Component, effect, ElementRef, input, viewChild } from '@angular/core';\n\nimport { CrossOrigin, Excavation, Modules } from './typing';\nimport { DEFAULT_BACKGROUND_COLOR, DEFAULT_FRONT_COLOR, excavateModules, generatePath, isSupportPath2d } from './utils';\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  selector: 'nz-qrcode-canvas',\n  exportAs: 'nzQRCodeCanvas',\n  template: `\n    <canvas role=\"img\" #canvas></canvas>\n    @if (icon()) {\n      <img style=\"display:none;\" #image alt=\"QR-Code\" [attr.src]=\"this.icon()\" crossorigin=\"anonymous\" />\n    }\n  `,\n  styles: `\n    :host {\n      display: block;\n      line-height: 0;\n    }\n  `\n})\nexport class NzQrcodeCanvasComponent implements AfterViewInit {\n  canvas = viewChild.required<ElementRef<HTMLCanvasElement>>('canvas');\n  image = viewChild<ElementRef<HTMLImageElement>>('image');\n  readonly icon = input<string>('');\n  readonly margin = input<number>(0);\n  readonly cells = input<Modules>([]);\n  readonly numCells = input<number>(0);\n  readonly calculatedImageSettings = input<{\n    x: number;\n    y: number;\n    h: number;\n    w: number;\n    excavation: Excavation | null;\n    opacity: number;\n    crossOrigin: CrossOrigin;\n  } | null>(null);\n  readonly size = input<number>(160);\n  readonly color = input<string>(DEFAULT_FRONT_COLOR);\n  readonly bgColor = input<string>(DEFAULT_BACKGROUND_COLOR);\n\n  constructor() {\n    effect(() => {\n      this.icon();\n      this.margin();\n      this.cells();\n      this.numCells();\n      this.calculatedImageSettings();\n      this.size();\n      this.color();\n      this.bgColor();\n      if (!this.canvas()?.nativeElement) {\n        return;\n      }\n\n      this.render();\n    });\n  }\n\n  ngAfterViewInit(): void {\n    this.render();\n  }\n\n  private render(): void {\n    const canvas = this.canvas();\n    if (!canvas) {\n      return;\n    }\n\n    const ctx = canvas.nativeElement.getContext('2d') as CanvasRenderingContext2D;\n    if (!ctx) {\n      return;\n    }\n\n    this.setupCanvas(ctx);\n    this.drawQRCode(ctx);\n    this.handleImageLoading(ctx);\n  }\n\n  private setupCanvas(ctx: CanvasRenderingContext2D): void {\n    const canvas = this.canvas();\n    if (!canvas) {\n      return;\n    }\n\n    const pixelRatio = window.devicePixelRatio || 1;\n    canvas.nativeElement.height = canvas.nativeElement.width = this.size() * pixelRatio;\n    canvas.nativeElement.style.width = canvas.nativeElement.style.height = `${this.size()}px`;\n\n    const scale = (this.size() / this.numCells()) * pixelRatio;\n    ctx.scale(scale, scale);\n\n    ctx.fillStyle = this.bgColor();\n    ctx.fillRect(0, 0, this.numCells(), this.numCells());\n    ctx.fillStyle = this.color();\n  }\n\n  private drawQRCode(ctx: CanvasRenderingContext2D): void {\n    const cellsToDraw = this.getCellsToDraw();\n    const haveImageToRender = this.haveImageToRender();\n\n    if (!haveImageToRender) {\n      this.renderQRCode(ctx, cellsToDraw);\n    }\n  }\n\n  private getCellsToDraw(): Modules {\n    let cellsToDraw = this.cells();\n    const imageSettings = this.calculatedImageSettings();\n    if (this.haveImageToRender() && imageSettings && imageSettings.excavation) {\n      cellsToDraw = excavateModules(this.cells(), imageSettings.excavation);\n    }\n    return cellsToDraw;\n  }\n\n  private haveImageToRender(): boolean {\n    return this.calculatedImageSettings() != null && !!this.image();\n  }\n\n  private renderQRCode(ctx: CanvasRenderingContext2D, cells: Modules): void {\n    if (isSupportPath2d) {\n      ctx.fill(new Path2D(generatePath(cells, this.margin())));\n    } else {\n      cells.forEach((row, rdx) => {\n        row.forEach((cell, cdx) => {\n          if (cell) {\n            ctx.fillRect(cdx + this.margin(), rdx + this.margin(), 1, 1);\n          }\n        });\n      });\n    }\n  }\n\n  private handleImageLoading(ctx: CanvasRenderingContext2D): void {\n    if (!this.haveImageToRender()) {\n      return;\n    }\n\n    const image = this.image();\n    if (!image) {\n      return;\n    }\n\n    const onLoad = (): void => {\n      this.cleanupImageListeners(onLoad, onError);\n      this.onImageLoadSuccess(ctx);\n    };\n\n    const onError = (): void => {\n      this.cleanupImageListeners(onLoad, onError);\n      this.onImageLoadError(ctx);\n    };\n\n    image.nativeElement.addEventListener('load', onLoad);\n    image.nativeElement.addEventListener('error', onError);\n  }\n\n  private onImageLoadSuccess(ctx: CanvasRenderingContext2D): void {\n    const cellsToDraw = this.getCellsToDraw();\n    this.renderQRCode(ctx, cellsToDraw);\n\n    const imageSettings = this.calculatedImageSettings();\n    const image = this.image();\n    if (imageSettings && image) {\n      ctx.globalAlpha = imageSettings.opacity;\n      ctx.drawImage(\n        image.nativeElement,\n        imageSettings.x + this.margin(),\n        imageSettings.y + this.margin(),\n        imageSettings.w,\n        imageSettings.h\n      );\n    }\n  }\n\n  private onImageLoadError(ctx: CanvasRenderingContext2D): void {\n    const cellsToDraw = this.getCellsToDraw();\n    this.renderQRCode(ctx, cellsToDraw);\n  }\n\n  private cleanupImageListeners(onLoad: () => void, onError: () => void): void {\n    const image = this.image();\n    if (image?.nativeElement) {\n      image.nativeElement.removeEventListener('load', onLoad);\n      image.nativeElement.removeEventListener('error', onError);\n    }\n  }\n}\n"
  },
  {
    "path": "components/qr-code/qrcode-data.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport qrcodegen from './qrcodegen';\nimport { CrossOrigin, Excavation, ImageSettings, Modules } from './typing';\nimport { DEFAULT_LEVEL, ERROR_LEVEL_MAP, getImageSettings, getMarginSize } from './utils';\n\nimport QrSegment = qrcodegen.QrSegment;\nimport QrCode = qrcodegen.QrCode;\n\nexport const createQRCodeData = (\n  value: string | string[],\n  level = DEFAULT_LEVEL,\n  minVersion: number,\n  size: number,\n  boostLevel: boolean,\n  marginSize: number,\n  imageSettings?: ImageSettings\n): {\n  cells: Modules;\n  margin: number;\n  numCells: number;\n  calculatedImageSettings: null | {\n    x: number;\n    y: number;\n    h: number;\n    w: number;\n    excavation: Excavation | null;\n    opacity: number;\n    crossOrigin: CrossOrigin;\n  };\n  qrcode: QrCode;\n} => {\n  const cs = memoizedQrcode(value, level, minVersion, boostLevel);\n  const mg = getMarginSize(marginSize);\n  const ncs = cs.getModules().length + mg * 2;\n  const cis = getImageSettings(cs.getModules(), size, mg, imageSettings);\n\n  return {\n    cells: cs.getModules(),\n    margin: mg,\n    numCells: ncs,\n    calculatedImageSettings: cis,\n    qrcode: cs\n  };\n};\n\nexport const memoizedQrcode = (\n  value: string | string[],\n  level = DEFAULT_LEVEL,\n  minVersion: number,\n  boostLevel: boolean\n): QrCode => {\n  const values = Array.isArray(value) ? value : [value];\n  const segments = values.reduce<QrSegment[]>((acc, val) => {\n    acc.push(...QrSegment.makeSegments(val));\n    return acc;\n  }, []);\n  return qrcodegen.QrCode.encodeSegments(\n    segments,\n    ERROR_LEVEL_MAP[level],\n    minVersion,\n    undefined,\n    undefined,\n    boostLevel\n  );\n};\n"
  },
  {
    "path": "components/qr-code/qrcode-svg.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, effect, input } from '@angular/core';\n\nimport { CrossOrigin, Excavation, ImageSettings, Modules } from './typing';\nimport { DEFAULT_BACKGROUND_COLOR, DEFAULT_FRONT_COLOR, excavateModules, generatePath } from './utils';\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  selector: 'nz-qrcode-svg',\n  exportAs: 'nzQRCodeSVG',\n  template: `\n    <svg [attr.height]=\"size()\" [attr.width]=\"size()\" [attr.viewBox]=\"viewBox\" role=\"img\">\n      <path [attr.fill]=\"bgColor()\" [attr.d]=\"backgroundPath\" shapeRendering=\"crispEdges\" />\n      <path [attr.fill]=\"color()\" [attr.d]=\"foregroundPath\" shapeRendering=\"crispEdges\" />\n      @if (shouldShowIcon()) {\n        <image\n          [attr.href]=\"imageSettings()?.src\"\n          [attr.height]=\"calculatedImageSettings()?.h\"\n          [attr.width]=\"calculatedImageSettings()?.w\"\n          [attr.x]=\"getImageX()\"\n          [attr.y]=\"getImageY()\"\n          preserveAspectRatio=\"none\"\n          [attr.opacity]=\"calculatedImageSettings()?.opacity\"\n          [attr.crossOrigin]=\"calculatedImageSettings()?.crossOrigin\"\n        />\n      }\n    </svg>\n  `,\n  styles: `\n    :host {\n      display: block;\n      line-height: 0;\n    }\n  `\n})\nexport class NzQrcodeSvgComponent {\n  readonly icon = input<string>('');\n  readonly color = input<string>(DEFAULT_FRONT_COLOR);\n  readonly bgColor = input<string>(DEFAULT_BACKGROUND_COLOR);\n  readonly imageSettings = input<ImageSettings>();\n  readonly size = input<number>(160);\n  readonly margin = input<number>(0);\n  readonly calculatedImageSettings = input<{\n    x: number;\n    y: number;\n    h: number;\n    w: number;\n    excavation: Excavation | null;\n    opacity: number;\n    crossOrigin: CrossOrigin;\n  } | null>(null);\n  readonly cells = input<Modules>([]);\n  readonly numCells = input<number>(0);\n\n  viewBox: string = '';\n  backgroundPath: string = '';\n  foregroundPath: string = '';\n\n  constructor() {\n    effect(() => {\n      this.initializeViewBox();\n      this.generatePaths();\n    });\n  }\n\n  private initializeViewBox(): void {\n    this.viewBox = `0 0 ${this.numCells()} ${this.numCells()}`;\n    this.backgroundPath = `M0,0 h${this.numCells()}v${this.numCells()}H0z`;\n  }\n\n  private generatePaths(): void {\n    const cellsToDraw = this.getCellsToDraw();\n    this.foregroundPath = generatePath(cellsToDraw, this.margin());\n  }\n\n  private getCellsToDraw(): Modules {\n    if (this.shouldExcavateCells()) {\n      return excavateModules(this.cells(), this.calculatedImageSettings()!.excavation!);\n    }\n    return this.cells();\n  }\n\n  private shouldExcavateCells(): boolean {\n    const settings = this.calculatedImageSettings();\n    return settings !== null && !!this.icon() && settings.excavation !== null;\n  }\n\n  protected shouldShowIcon(): boolean {\n    return !!this.icon() && this.calculatedImageSettings() != null;\n  }\n\n  protected getImageX(): number {\n    return (this.calculatedImageSettings()?.x || 0) + this.margin();\n  }\n\n  protected getImageY(): number {\n    return (this.calculatedImageSettings()?.y || 0) + this.margin();\n  }\n}\n"
  },
  {
    "path": "components/qr-code/qrcode.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, DebugElement, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzQRCodeComponent } from './qrcode.component';\nimport { NzQRCodeModule } from './qrcode.module';\n\ndescribe('qrcode', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideZoneChangeDetection()]\n    });\n  });\n\n  describe('basic', () => {\n    let fixture: ComponentFixture<NzTestQrCodeBasicComponent>;\n    let testComponent: NzTestQrCodeBasicComponent;\n    let resultEl: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestQrCodeBasicComponent);\n      fixture.detectChanges();\n      testComponent = fixture.componentInstance;\n      resultEl = fixture.debugElement.query(By.directive(NzQRCodeComponent));\n    });\n\n    it('qr code bordered', () => {\n      testComponent.bordered = false;\n      fixture.detectChanges();\n      expect(resultEl.nativeElement.classList).not.toContain('ant-qrcode-border');\n    });\n\n    it('qr code width', () => {\n      testComponent.size = 200;\n      fixture.detectChanges();\n      const widthView = resultEl.nativeElement.querySelector('.ant-qrcode > nz-qrcode-canvas > canvas');\n      expect(widthView.style.width).toBe('200px');\n    });\n\n    it('qr code type', () => {\n      testComponent.type = 'svg';\n      fixture.detectChanges();\n      const widthView = resultEl.nativeElement.querySelector('.ant-qrcode > nz-qrcode-svg > svg');\n      expect(widthView.nodeName).toBe('svg');\n    });\n\n    it('qr code custom status', () => {\n      testComponent.statusRender = 'custom status';\n      fixture.detectChanges();\n      const statusView = resultEl.nativeElement.querySelector('.ant-qrcode-mask');\n      expect(statusView.innerText).toBe('custom status');\n    });\n\n    it('qr code status', () => {\n      const statusList: Array<'active' | 'expired' | 'loading' | 'scanned'> = ['expired', 'loading', 'scanned'];\n\n      for (let i = 0; i < statusList.length; i++) {\n        testComponent.status = statusList[i];\n        fixture.detectChanges();\n        const statusView = resultEl.nativeElement.querySelector('.ant-qrcode-mask');\n        if (i === 1) {\n          expect(statusView.firstElementChild.tagName).toBe('NZ-SPIN');\n        } else {\n          expect(statusView.firstElementChild.tagName).toBe('DIV');\n        }\n      }\n    });\n  });\n});\n\n@Component({\n  imports: [NzQRCodeModule],\n  template: `<nz-qrcode\n    [nzValue]=\"value\"\n    [nzSize]=\"size\"\n    [nzType]=\"type\"\n    [nzBordered]=\"bordered\"\n    [nzStatus]=\"status\"\n    [nzStatusRender]=\"statusRender\"\n  />`\n})\nexport class NzTestQrCodeBasicComponent {\n  value: string = 'https://ng.ant.design/';\n  type: 'svg' | 'canvas' = 'canvas';\n  size: number = 160;\n  bordered: boolean = true;\n  statusRender: string | null = null;\n  status: 'active' | 'expired' | 'loading' | 'scanned' = 'active';\n}\n"
  },
  {
    "path": "components/qr-code/qrcode.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  computed,\n  effect,\n  inject,\n  input,\n  output,\n  PLATFORM_ID,\n  signal,\n  Signal,\n  TemplateRef\n} from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { map } from 'rxjs/operators';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzStringTemplateOutletDirective } from 'ng-zorro-antd/core/outlet';\nimport { NzI18nService, NzQRCodeI18nInterface } from 'ng-zorro-antd/i18n';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzSpinModule } from 'ng-zorro-antd/spin';\n\nimport { NzQrcodeCanvasComponent } from './qrcode-canvas.component';\nimport { createQRCodeData } from './qrcode-data';\nimport { NzQrcodeSvgComponent } from './qrcode-svg.component';\nimport { CrossOrigin, ErrorCorrectionLevel, Excavation, ImageSettings, Modules } from './typing';\nimport { DEFAULT_BACKGROUND_COLOR, DEFAULT_FRONT_COLOR, DEFAULT_MINVERSION } from './utils';\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  selector: 'nz-qrcode',\n  exportAs: 'nzQRCode',\n  template: `\n    @if (!!nzStatusRender()) {\n      <div class=\"ant-qrcode-mask\">\n        <ng-container *nzStringTemplateOutlet=\"nzStatusRender()\">{{ nzStatusRender() }}</ng-container>\n      </div>\n    } @else if (nzStatus() !== 'active') {\n      <div class=\"ant-qrcode-mask\">\n        @switch (nzStatus()) {\n          @case ('loading') {\n            <nz-spin />\n          }\n          @case ('expired') {\n            <div>\n              <p class=\"ant-qrcode-expired\">{{ locale().expired }}</p>\n              <button nz-button nzType=\"link\" (click)=\"reloadQRCode()\">\n                <nz-icon nzType=\"reload\" nzTheme=\"outline\" />\n                <span>{{ locale().refresh }}</span>\n              </button>\n            </div>\n          }\n          @case ('scanned') {\n            <div>\n              <p class=\"ant-qrcode-expired\">{{ locale().scanned }}</p>\n            </div>\n          }\n        }\n      </div>\n    }\n\n    @if (isBrowser) {\n      @switch (nzType()) {\n        @case ('canvas') {\n          <nz-qrcode-canvas\n            [icon]=\"nzIcon()\"\n            [margin]=\"margin()\"\n            [cells]=\"cells()\"\n            [numCells]=\"numCells()\"\n            [calculatedImageSettings]=\"calculatedImageSettings()\"\n            [size]=\"nzSize()\"\n            [color]=\"nzColor()\"\n            [bgColor]=\"nzBgColor()\"\n          />\n        }\n        @case ('svg') {\n          <nz-qrcode-svg\n            [color]=\"nzColor()\"\n            [bgColor]=\"nzBgColor()\"\n            [icon]=\"nzIcon()\"\n            [margin]=\"margin()\"\n            [cells]=\"cells()\"\n            [numCells]=\"numCells()\"\n            [imageSettings]=\"imageSettings()\"\n            [calculatedImageSettings]=\"\n              calculatedImageSettings() || { x: 0, y: 0, h: 0, w: 0, excavation: null, opacity: 1, crossOrigin: '' }\n            \"\n            [size]=\"nzSize()\"\n          />\n        }\n      }\n    }\n  `,\n  host: {\n    class: 'ant-qrcode',\n    '[class.ant-qrcode-border]': `nzBordered()`,\n    '[style.background-color]': `nzBgColor()`\n  },\n  imports: [\n    NzSpinModule,\n    NzButtonModule,\n    NzIconModule,\n    NzStringTemplateOutletDirective,\n    NzQrcodeSvgComponent,\n    NzQrcodeCanvasComponent\n  ]\n})\nexport class NzQRCodeComponent {\n  private i18n = inject(NzI18nService);\n  locale = toSignal<NzQRCodeI18nInterface>(this.i18n.localeChange.pipe(map(() => this.i18n.getLocaleData('QRCode'))), {\n    requireSync: true\n  });\n  // https://github.com/angular/universal-starter/issues/538#issuecomment-365518693\n  // canvas is not supported by the SSR DOM\n  protected isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n  readonly nzValue = input<string | string[]>('');\n  readonly nzType = input<'svg' | 'canvas'>('canvas');\n  readonly nzColor = input<string>(DEFAULT_FRONT_COLOR);\n  readonly nzBgColor = input<string>(DEFAULT_BACKGROUND_COLOR);\n  readonly nzSize = input<number>(160);\n  readonly nzIcon = input<string>('');\n  readonly nzIconSize = input<number>(40);\n  readonly nzBordered = input<boolean>(true);\n  readonly nzStatus = input<'active' | 'expired' | 'loading' | 'scanned'>('active');\n  readonly nzLevel = input<ErrorCorrectionLevel>('M');\n  readonly nzStatusRender = input<TemplateRef<void> | string | null>(null);\n  readonly nzBoostLevel = input<boolean>(true);\n  readonly nzPadding = input<number>(0);\n\n  readonly nzRefresh = output<string>();\n\n  margin = signal<number>(0);\n  cells = signal<Modules>([]);\n  numCells = signal<number>(0);\n  calculatedImageSettings = signal<null | {\n    x: number;\n    y: number;\n    h: number;\n    w: number;\n    excavation: Excavation | null;\n    opacity: number;\n    crossOrigin: CrossOrigin;\n  }>(null);\n\n  protected imageSettings: Signal<ImageSettings> = computed(() => {\n    return {\n      src: this.nzIcon(),\n      x: undefined,\n      y: undefined,\n      height: this.nzIconSize() ?? 40,\n      width: this.nzIconSize() ?? 40,\n      excavate: true,\n      crossOrigin: 'anonymous'\n    };\n  });\n\n  constructor() {\n    effect(() => {\n      this.updateQRCodeData();\n    });\n  }\n\n  reloadQRCode(): void {\n    this.updateQRCodeData();\n    this.nzRefresh.emit('refresh');\n  }\n\n  updateQRCodeData(): void {\n    const { margin, cells, numCells, calculatedImageSettings } = createQRCodeData(\n      this.nzValue(),\n      this.nzLevel(),\n      DEFAULT_MINVERSION,\n      this.nzSize(),\n      this.nzBoostLevel(),\n      this.nzPadding(),\n      this.imageSettings()\n    );\n    this.margin.set(margin);\n    this.cells.set(cells);\n    this.numCells.set(numCells);\n    this.calculatedImageSettings.set(calculatedImageSettings);\n  }\n}\n"
  },
  {
    "path": "components/qr-code/qrcode.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzQRCodeComponent } from './qrcode.component';\n\n@NgModule({\n  imports: [NzQRCodeComponent],\n  exports: [NzQRCodeComponent]\n})\nexport class NzQRCodeModule {}\n"
  },
  {
    "path": "components/qr-code/qrcodegen.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\n/**\n * QR Code generator library (TypeScript)\n *\n * Copyright (c) Project Nayuki.\n * https://www.nayuki.io/page/qr-code-generator-library\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n'use strict';\n\n// eslint-disable-next-line @typescript-eslint/no-namespace\nnamespace qrcodegen {\n  type bit = number;\n  type byte = number;\n  type int = number;\n\n  /*---- QR Code symbol class ----*/\n\n  /*\n   * A QR Code symbol, which is a type of two-dimension barcode.\n   * Invented by Denso Wave and described in the ISO/IEC 18004 standard.\n   * Instances of this class represent an immutable square grid of dark and light cells.\n   * The class provides static factory functions to create a QR Code from text or binary data.\n   * The class covers the QR Code Model 2 specification, supporting all versions (sizes)\n   * from 1 to 40, all 4 error correction levels, and 4 character encoding modes.\n   *\n   * Ways to create a QR Code object:\n   * - High level: Take the payload data and call QrCode.encodeText() or QrCode.encodeBinary().\n   * - Mid level: Custom-make the list of segments and call QrCode.encodeSegments().\n   * - Low level: Custom-make the array of data codeword bytes (including\n   *   segment headers and final padding, excluding error correction codewords),\n   *   supply the appropriate version number, and call the QrCode() constructor.\n   * (Note that all ways require supplying the desired error correction level.)\n   */\n  export class QrCode {\n    /*-- Static factory functions (high level) --*/\n\n    // Returns a QR Code representing the given Unicode text string at the given error correction level.\n    // As a conservative upper bound, this function is guaranteed to succeed for strings that have 738 or fewer\n    // Unicode code points (not UTF-16 code units) if the low error correction level is used. The smallest possible\n    // QR Code version is automatically chosen for the output. The ECC level of the result may be higher than the\n    // ecl argument if it can be done without increasing the version.\n    public static encodeText(text: string, ecl: QrCode.Ecc): QrCode {\n      const segs: QrSegment[] = qrcodegen.QrSegment.makeSegments(text);\n      return QrCode.encodeSegments(segs, ecl);\n    }\n\n    // Returns a QR Code representing the given binary data at the given error correction level.\n    // This function always encodes using the binary segment mode, not any text mode. The maximum number of\n    // bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output.\n    // The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version.\n    public static encodeBinary(data: readonly byte[], ecl: QrCode.Ecc): QrCode {\n      const seg: QrSegment = qrcodegen.QrSegment.makeBytes(data);\n      return QrCode.encodeSegments([seg], ecl);\n    }\n\n    /*-- Static factory functions (mid level) --*/\n\n    // Returns a QR Code representing the given segments with the given encoding parameters.\n    // The smallest possible QR Code version within the given range is automatically\n    // chosen for the output. Iff boostEcl is true, then the ECC level of the result\n    // may be higher than the ecl argument if it can be done without increasing the\n    // version. The mask number is either between 0 to 7 (inclusive) to force that\n    // mask, or -1 to automatically choose an appropriate mask (which may be slow).\n    // This function allows the user to create a custom sequence of segments that switches\n    // between modes (such as alphanumeric and byte) to encode text in less space.\n    // This is a mid-level API; the high-level API is encodeText() and encodeBinary().\n    public static encodeSegments(\n      segs: readonly QrSegment[],\n      ecl: QrCode.Ecc,\n      minVersion: int = 1,\n      maxVersion: int = 40,\n      mask: int = -1,\n      boostEcl: boolean = true\n    ): QrCode {\n      if (\n        !(QrCode.MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= QrCode.MAX_VERSION) ||\n        mask < -1 ||\n        mask > 7\n      )\n        throw new RangeError('Invalid value');\n\n      // Find the minimal version number to use\n      let version: int;\n      let dataUsedBits: int;\n      for (version = minVersion; ; version++) {\n        const dataCapacityBits: int = QrCode.getNumDataCodewords(version, ecl) * 8; // Number of data bits available\n        const usedBits: number = QrSegment.getTotalBits(segs, version);\n        if (usedBits <= dataCapacityBits) {\n          dataUsedBits = usedBits;\n          break; // This version number is found to be suitable\n        }\n        if (version >= maxVersion)\n          // All versions in the range could not fit the given data\n          throw new RangeError('Data too long');\n      }\n\n      // Increase the error correction level while the data still fits in the current version number\n      for (const newEcl of [QrCode.Ecc.MEDIUM, QrCode.Ecc.QUARTILE, QrCode.Ecc.HIGH]) {\n        // From low to high\n        if (boostEcl && dataUsedBits <= QrCode.getNumDataCodewords(version, newEcl) * 8) ecl = newEcl;\n      }\n\n      // Concatenate all segments to create the data bit string\n      const bb: bit[] = [];\n      for (const seg of segs) {\n        appendBits(seg.mode.modeBits, 4, bb);\n        appendBits(seg.numChars, seg.mode.numCharCountBits(version), bb);\n        for (const b of seg.getData()) bb.push(b);\n      }\n      assert(bb.length == dataUsedBits);\n\n      // Add terminator and pad up to a byte if applicable\n      const dataCapacityBits: int = QrCode.getNumDataCodewords(version, ecl) * 8;\n      assert(bb.length <= dataCapacityBits);\n      appendBits(0, Math.min(4, dataCapacityBits - bb.length), bb);\n      appendBits(0, (8 - (bb.length % 8)) % 8, bb);\n      assert(bb.length % 8 == 0);\n\n      // Pad with alternating bytes until data capacity is reached\n      for (let padByte = 0xec; bb.length < dataCapacityBits; padByte ^= 0xec ^ 0x11) appendBits(padByte, 8, bb);\n\n      // Pack bits into bytes in big endian\n      const dataCodewords: byte[] = [];\n      while (dataCodewords.length * 8 < bb.length) dataCodewords.push(0);\n      bb.forEach((b: bit, i: int) => (dataCodewords[i >>> 3] |= b << (7 - (i & 7))));\n\n      // Create the QR Code object\n      return new QrCode(version, ecl, dataCodewords, mask);\n    }\n\n    /*-- Fields --*/\n\n    // The width and height of this QR Code, measured in modules, between\n    // 21 and 177 (inclusive). This is equal to version * 4 + 17.\n    public readonly size: int;\n\n    // The index of the mask pattern used in this QR Code, which is between 0 and 7 (inclusive).\n    // Even if a QR Code is created with automatic masking requested (mask = -1),\n    // the resulting object still has a mask value between 0 and 7.\n    public readonly mask: int;\n\n    // The modules of this QR Code (false = light, true = dark).\n    // Immutable after constructor finishes. Accessed through getModule().\n    private readonly modules: boolean[][] = [];\n\n    // Indicates function modules that are not subjected to masking. Discarded when constructor finishes.\n    private readonly isFunction: boolean[][] = [];\n\n    /*-- Constructor (low level) and fields --*/\n\n    // Creates a new QR Code with the given version number,\n    // error correction level, data codeword bytes, and mask number.\n    // This is a low-level API that most users should not use directly.\n    // A mid-level API is the encodeSegments() function.\n    public constructor(\n      // The version number of this QR Code, which is between 1 and 40 (inclusive).\n      // This determines the size of this barcode.\n      public readonly version: int,\n\n      // The error correction level used in this QR Code.\n      public readonly errorCorrectionLevel: QrCode.Ecc,\n\n      dataCodewords: readonly byte[],\n\n      msk: int\n    ) {\n      // Check scalar arguments\n      if (version < QrCode.MIN_VERSION || version > QrCode.MAX_VERSION)\n        throw new RangeError('Version value out of range');\n      if (msk < -1 || msk > 7) throw new RangeError('Mask value out of range');\n      this.size = version * 4 + 17;\n\n      // Initialize both grids to be size*size arrays of Boolean false\n      const row: boolean[] = [];\n      for (let i = 0; i < this.size; i++) row.push(false);\n      for (let i = 0; i < this.size; i++) {\n        this.modules.push(row.slice()); // Initially all light\n        this.isFunction.push(row.slice());\n      }\n\n      // Compute ECC, draw modules\n      this.drawFunctionPatterns();\n      const allCodewords: byte[] = this.addEccAndInterleave(dataCodewords);\n      this.drawCodewords(allCodewords);\n\n      // Do masking\n      if (msk == -1) {\n        // Automatically choose best mask\n        let minPenalty: int = 1000000000;\n        for (let i = 0; i < 8; i++) {\n          this.applyMask(i);\n          this.drawFormatBits(i);\n          const penalty: int = this.getPenaltyScore();\n          if (penalty < minPenalty) {\n            msk = i;\n            minPenalty = penalty;\n          }\n          this.applyMask(i); // Undoes the mask due to XOR\n        }\n      }\n      assert(msk >= 0 && msk <= 7);\n      this.mask = msk;\n      this.applyMask(msk); // Apply the final choice of mask\n      this.drawFormatBits(msk); // Overwrite old format bits\n\n      this.isFunction = [];\n    }\n\n    /*-- Accessor methods --*/\n\n    // Returns the color of the module (pixel) at the given coordinates, which is false\n    // for light or true for dark. The top left corner has the coordinates (x=0, y=0).\n    // If the given coordinates are out of bounds, then false (light) is returned.\n    public getModule(x: int, y: int): boolean {\n      return x >= 0 && x < this.size && y >= 0 && y < this.size && this.modules[y][x];\n    }\n\n    // Modified to expose modules for easy access\n    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n    public getModules() {\n      return this.modules;\n    }\n\n    /*-- Private helper methods for constructor: Drawing function modules --*/\n\n    // Reads this object's version field, and draws and marks all function modules.\n    private drawFunctionPatterns(): void {\n      // Draw horizontal and vertical timing patterns\n      for (let i = 0; i < this.size; i++) {\n        this.setFunctionModule(6, i, i % 2 == 0);\n        this.setFunctionModule(i, 6, i % 2 == 0);\n      }\n\n      // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)\n      this.drawFinderPattern(3, 3);\n      this.drawFinderPattern(this.size - 4, 3);\n      this.drawFinderPattern(3, this.size - 4);\n\n      // Draw numerous alignment patterns\n      const alignPatPos: int[] = this.getAlignmentPatternPositions();\n      const numAlign: int = alignPatPos.length;\n      for (let i = 0; i < numAlign; i++) {\n        for (let j = 0; j < numAlign; j++) {\n          // Don't draw on the three finder corners\n          if (!((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0)))\n            this.drawAlignmentPattern(alignPatPos[i], alignPatPos[j]);\n        }\n      }\n\n      // Draw configuration data\n      this.drawFormatBits(0); // Dummy mask value; overwritten later in the constructor\n      this.drawVersion();\n    }\n\n    // Draws two copies of the format bits (with its own error correction code)\n    // based on the given mask and this object's error correction level field.\n    private drawFormatBits(mask: int): void {\n      // Calculate error correction code and pack bits\n      const data: int = (this.errorCorrectionLevel.formatBits << 3) | mask; // errCorrLvl is uint2, mask is uint3\n      let rem: int = data;\n      for (let i = 0; i < 10; i++) rem = (rem << 1) ^ ((rem >>> 9) * 0x537);\n      const bits = ((data << 10) | rem) ^ 0x5412; // uint15\n      assert(bits >>> 15 == 0);\n\n      // Draw first copy\n      for (let i = 0; i <= 5; i++) this.setFunctionModule(8, i, getBit(bits, i));\n      this.setFunctionModule(8, 7, getBit(bits, 6));\n      this.setFunctionModule(8, 8, getBit(bits, 7));\n      this.setFunctionModule(7, 8, getBit(bits, 8));\n      for (let i = 9; i < 15; i++) this.setFunctionModule(14 - i, 8, getBit(bits, i));\n\n      // Draw second copy\n      for (let i = 0; i < 8; i++) this.setFunctionModule(this.size - 1 - i, 8, getBit(bits, i));\n      for (let i = 8; i < 15; i++) this.setFunctionModule(8, this.size - 15 + i, getBit(bits, i));\n      this.setFunctionModule(8, this.size - 8, true); // Always dark\n    }\n\n    // Draws two copies of the version bits (with its own error correction code),\n    // based on this object's version field, iff 7 <= version <= 40.\n    private drawVersion(): void {\n      if (this.version < 7) return;\n\n      // Calculate error correction code and pack bits\n      let rem: int = this.version; // version is uint6, in the range [7, 40]\n      for (let i = 0; i < 12; i++) rem = (rem << 1) ^ ((rem >>> 11) * 0x1f25);\n      const bits: int = (this.version << 12) | rem; // uint18\n      assert(bits >>> 18 == 0);\n\n      // Draw two copies\n      for (let i = 0; i < 18; i++) {\n        const color: boolean = getBit(bits, i);\n        const a: int = this.size - 11 + (i % 3);\n        const b: int = Math.floor(i / 3);\n        this.setFunctionModule(a, b, color);\n        this.setFunctionModule(b, a, color);\n      }\n    }\n\n    // Draws a 9*9 finder pattern including the border separator,\n    // with the center module at (x, y). Modules can be out of bounds.\n    private drawFinderPattern(x: int, y: int): void {\n      for (let dy = -4; dy <= 4; dy++) {\n        for (let dx = -4; dx <= 4; dx++) {\n          const dist: int = Math.max(Math.abs(dx), Math.abs(dy)); // Chebyshev/infinity norm\n          const xx: int = x + dx;\n          const yy: int = y + dy;\n          if (xx >= 0 && xx < this.size && yy >= 0 && yy < this.size)\n            this.setFunctionModule(xx, yy, dist != 2 && dist != 4);\n        }\n      }\n    }\n\n    // Draws a 5*5 alignment pattern, with the center module\n    // at (x, y). All modules must be in bounds.\n    private drawAlignmentPattern(x: int, y: int): void {\n      for (let dy = -2; dy <= 2; dy++) {\n        for (let dx = -2; dx <= 2; dx++)\n          this.setFunctionModule(x + dx, y + dy, Math.max(Math.abs(dx), Math.abs(dy)) != 1);\n      }\n    }\n\n    // Sets the color of a module and marks it as a function module.\n    // Only used by the constructor. Coordinates must be in bounds.\n    private setFunctionModule(x: int, y: int, isDark: boolean): void {\n      this.modules[y][x] = isDark;\n      this.isFunction[y][x] = true;\n    }\n\n    /*-- Private helper methods for constructor: Codewords and masking --*/\n\n    // Returns a new byte string representing the given data with the appropriate error correction\n    // codewords appended to it, based on this object's version and error correction level.\n    private addEccAndInterleave(data: readonly byte[]): byte[] {\n      const ver: int = this.version;\n      const ecl: QrCode.Ecc = this.errorCorrectionLevel;\n      if (data.length != QrCode.getNumDataCodewords(ver, ecl)) throw new RangeError('Invalid argument');\n\n      // Calculate parameter numbers\n      const numBlocks: int = QrCode.NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal][ver];\n      const blockEccLen: int = QrCode.ECC_CODEWORDS_PER_BLOCK[ecl.ordinal][ver];\n      const rawCodewords: int = Math.floor(QrCode.getNumRawDataModules(ver) / 8);\n      const numShortBlocks: int = numBlocks - (rawCodewords % numBlocks);\n      const shortBlockLen: int = Math.floor(rawCodewords / numBlocks);\n\n      // Split data into blocks and append ECC to each block\n      const blocks: byte[][] = [];\n      const rsDiv: byte[] = QrCode.reedSolomonComputeDivisor(blockEccLen);\n      for (let i = 0, k = 0; i < numBlocks; i++) {\n        const dat: byte[] = data.slice(k, k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1));\n        k += dat.length;\n        const ecc: byte[] = QrCode.reedSolomonComputeRemainder(dat, rsDiv);\n        if (i < numShortBlocks) dat.push(0);\n        blocks.push(dat.concat(ecc));\n      }\n\n      // Interleave (not concatenate) the bytes from every block into a single sequence\n      const result: byte[] = [];\n      for (let i = 0; i < blocks[0].length; i++) {\n        blocks.forEach((block, j) => {\n          // Skip the padding byte in short blocks\n          if (i != shortBlockLen - blockEccLen || j >= numShortBlocks) result.push(block[i]);\n        });\n      }\n      assert(result.length == rawCodewords);\n      return result;\n    }\n\n    // Draws the given sequence of 8-bit codewords (data and error correction) onto the entire\n    // data area of this QR Code. Function modules need to be marked off before this is called.\n    private drawCodewords(data: readonly byte[]): void {\n      if (data.length != Math.floor(QrCode.getNumRawDataModules(this.version) / 8))\n        throw new RangeError('Invalid argument');\n      let i: int = 0; // Bit index into the data\n      // Do the funny zigzag scan\n      for (let right = this.size - 1; right >= 1; right -= 2) {\n        // Index of right column in each column pair\n        if (right == 6) right = 5;\n        for (let vert = 0; vert < this.size; vert++) {\n          // Vertical counter\n          for (let j = 0; j < 2; j++) {\n            const x: int = right - j; // Actual x coordinate\n            const upward: boolean = ((right + 1) & 2) == 0;\n            const y: int = upward ? this.size - 1 - vert : vert; // Actual y coordinate\n            if (!this.isFunction[y][x] && i < data.length * 8) {\n              this.modules[y][x] = getBit(data[i >>> 3], 7 - (i & 7));\n              i++;\n            }\n            // If this QR Code has any remainder bits (0 to 7), they were assigned as\n            // 0/false/light by the constructor and are left unchanged by this method\n          }\n        }\n      }\n      assert(i == data.length * 8);\n    }\n\n    // XORs the codeword modules in this QR Code with the given mask pattern.\n    // The function modules must be marked and the codeword bits must be drawn\n    // before masking. Due to the arithmetic of XOR, calling applyMask() with\n    // the same mask value a second time will undo the mask. A final well-formed\n    // QR Code needs exactly one (not zero, two, etc.) mask applied.\n    private applyMask(mask: int): void {\n      if (mask < 0 || mask > 7) throw new RangeError('Mask value out of range');\n      for (let y = 0; y < this.size; y++) {\n        for (let x = 0; x < this.size; x++) {\n          let invert: boolean;\n          switch (mask) {\n            case 0:\n              invert = (x + y) % 2 == 0;\n              break;\n            case 1:\n              invert = y % 2 == 0;\n              break;\n            case 2:\n              invert = x % 3 == 0;\n              break;\n            case 3:\n              invert = (x + y) % 3 == 0;\n              break;\n            case 4:\n              invert = (Math.floor(x / 3) + Math.floor(y / 2)) % 2 == 0;\n              break;\n            case 5:\n              invert = ((x * y) % 2) + ((x * y) % 3) == 0;\n              break;\n            case 6:\n              invert = (((x * y) % 2) + ((x * y) % 3)) % 2 == 0;\n              break;\n            case 7:\n              invert = (((x + y) % 2) + ((x * y) % 3)) % 2 == 0;\n              break;\n            default:\n              throw new Error('Unreachable');\n          }\n          if (!this.isFunction[y][x] && invert) this.modules[y][x] = !this.modules[y][x];\n        }\n      }\n    }\n\n    // Calculates and returns the penalty score based on state of this QR Code's current modules.\n    // This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score.\n    private getPenaltyScore(): int {\n      let result: int = 0;\n\n      // Adjacent modules in row having same color, and finder-like patterns\n      for (let y = 0; y < this.size; y++) {\n        let runColor = false;\n        let runX = 0;\n        const runHistory = [0, 0, 0, 0, 0, 0, 0];\n        for (let x = 0; x < this.size; x++) {\n          if (this.modules[y][x] == runColor) {\n            runX++;\n            if (runX == 5) result += QrCode.PENALTY_N1;\n            else if (runX > 5) result++;\n          } else {\n            this.finderPenaltyAddHistory(runX, runHistory);\n            if (!runColor) result += this.finderPenaltyCountPatterns(runHistory) * QrCode.PENALTY_N3;\n            runColor = this.modules[y][x];\n            runX = 1;\n          }\n        }\n        result += this.finderPenaltyTerminateAndCount(runColor, runX, runHistory) * QrCode.PENALTY_N3;\n      }\n      // Adjacent modules in column having same color, and finder-like patterns\n      for (let x = 0; x < this.size; x++) {\n        let runColor = false;\n        let runY = 0;\n        const runHistory = [0, 0, 0, 0, 0, 0, 0];\n        for (let y = 0; y < this.size; y++) {\n          if (this.modules[y][x] == runColor) {\n            runY++;\n            if (runY == 5) result += QrCode.PENALTY_N1;\n            else if (runY > 5) result++;\n          } else {\n            this.finderPenaltyAddHistory(runY, runHistory);\n            if (!runColor) result += this.finderPenaltyCountPatterns(runHistory) * QrCode.PENALTY_N3;\n            runColor = this.modules[y][x];\n            runY = 1;\n          }\n        }\n        result += this.finderPenaltyTerminateAndCount(runColor, runY, runHistory) * QrCode.PENALTY_N3;\n      }\n\n      // 2*2 blocks of modules having same color\n      for (let y = 0; y < this.size - 1; y++) {\n        for (let x = 0; x < this.size - 1; x++) {\n          const color: boolean = this.modules[y][x];\n          if (color == this.modules[y][x + 1] && color == this.modules[y + 1][x] && color == this.modules[y + 1][x + 1])\n            result += QrCode.PENALTY_N2;\n        }\n      }\n\n      // Balance of dark and light modules\n      let dark: int = 0;\n      for (const row of this.modules) dark = row.reduce((sum, color) => sum + (color ? 1 : 0), dark);\n      const total: int = this.size * this.size; // Note that size is odd, so dark/total != 1/2\n      // Compute the smallest integer k >= 0 such that (45-5k)% <= dark/total <= (55+5k)%\n      const k: int = Math.ceil(Math.abs(dark * 20 - total * 10) / total) - 1;\n      assert(k >= 0 && k <= 9);\n      result += k * QrCode.PENALTY_N4;\n      assert(result >= 0 && result <= 2568888); // Non-tight upper bound based on default values of PENALTY_N1, ..., N4\n      return result;\n    }\n\n    /*-- Private helper functions --*/\n\n    // Returns an ascending list of positions of alignment patterns for this version number.\n    // Each position is in the range [0,177), and are used on both the x and y axes.\n    // This could be implemented as lookup table of 40 variable-length lists of integers.\n    private getAlignmentPatternPositions(): int[] {\n      if (this.version == 1) return [];\n      else {\n        const numAlign: int = Math.floor(this.version / 7) + 2;\n        const step: int = Math.floor((this.version * 8 + numAlign * 3 + 5) / (numAlign * 4 - 4)) * 2;\n        const result: int[] = [6];\n        for (let pos = this.size - 7; result.length < numAlign; pos -= step) result.splice(1, 0, pos);\n        return result;\n      }\n    }\n\n    // Returns the number of data bits that can be stored in a QR Code of the given version number, after\n    // all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8.\n    // The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table.\n    private static getNumRawDataModules(ver: int): int {\n      if (ver < QrCode.MIN_VERSION || ver > QrCode.MAX_VERSION) throw new RangeError('Version number out of range');\n      let result: int = (16 * ver + 128) * ver + 64;\n      if (ver >= 2) {\n        const numAlign: int = Math.floor(ver / 7) + 2;\n        result -= (25 * numAlign - 10) * numAlign - 55;\n        if (ver >= 7) result -= 36;\n      }\n      assert(result >= 208 && result <= 29648);\n      return result;\n    }\n\n    // Returns the number of 8-bit data (i.e. not error correction) codewords contained in any\n    // QR Code of the given version number and error correction level, with remainder bits discarded.\n    // This stateless pure function could be implemented as a (40*4)-cell lookup table.\n    private static getNumDataCodewords(ver: int, ecl: QrCode.Ecc): int {\n      return (\n        Math.floor(QrCode.getNumRawDataModules(ver) / 8) -\n        QrCode.ECC_CODEWORDS_PER_BLOCK[ecl.ordinal][ver] * QrCode.NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal][ver]\n      );\n    }\n\n    // Returns a Reed-Solomon ECC generator polynomial for the given degree. This could be\n    // implemented as a lookup table over all possible parameter values, instead of as an algorithm.\n    private static reedSolomonComputeDivisor(degree: int): byte[] {\n      if (degree < 1 || degree > 255) throw new RangeError('Degree out of range');\n      // Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1.\n      // For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array [255, 8, 93].\n      const result: byte[] = [];\n      for (let i = 0; i < degree - 1; i++) result.push(0);\n      result.push(1); // Start off with the monomial x^0\n\n      // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),\n      // and drop the highest monomial term which is always 1x^degree.\n      // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).\n      let root = 1;\n      for (let i = 0; i < degree; i++) {\n        // Multiply the current product by (x - r^i)\n        for (let j = 0; j < result.length; j++) {\n          result[j] = QrCode.reedSolomonMultiply(result[j], root);\n          if (j + 1 < result.length) result[j] ^= result[j + 1];\n        }\n        root = QrCode.reedSolomonMultiply(root, 0x02);\n      }\n      return result;\n    }\n\n    // Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials.\n    private static reedSolomonComputeRemainder(data: readonly byte[], divisor: readonly byte[]): byte[] {\n      const result: byte[] = divisor.map(_ => 0);\n      for (const b of data) {\n        // Polynomial division\n        const factor: byte = b ^ (result.shift() as byte);\n        result.push(0);\n        divisor.forEach((coef, i) => (result[i] ^= QrCode.reedSolomonMultiply(coef, factor)));\n      }\n      return result;\n    }\n\n    // Returns the product of the two given field elements modulo GF(2^8/0x11D). The arguments and result\n    // are unsigned 8-bit integers. This could be implemented as a lookup table of 256*256 entries of uint8.\n    private static reedSolomonMultiply(x: byte, y: byte): byte {\n      if (x >>> 8 != 0 || y >>> 8 != 0) throw new RangeError('Byte out of range');\n      // Russian peasant multiplication\n      let z: int = 0;\n      for (let i = 7; i >= 0; i--) {\n        z = (z << 1) ^ ((z >>> 7) * 0x11d);\n        z ^= ((y >>> i) & 1) * x;\n      }\n      assert(z >>> 8 == 0);\n      return z as byte;\n    }\n\n    // Can only be called immediately after a light run is added, and\n    // returns either 0, 1, or 2. A helper function for getPenaltyScore().\n    private finderPenaltyCountPatterns(runHistory: readonly int[]): int {\n      const n: int = runHistory[1];\n      assert(n <= this.size * 3);\n      const core: boolean =\n        n > 0 && runHistory[2] == n && runHistory[3] == n * 3 && runHistory[4] == n && runHistory[5] == n;\n      return (\n        (core && runHistory[0] >= n * 4 && runHistory[6] >= n ? 1 : 0) +\n        (core && runHistory[6] >= n * 4 && runHistory[0] >= n ? 1 : 0)\n      );\n    }\n\n    // Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore().\n    private finderPenaltyTerminateAndCount(currentRunColor: boolean, currentRunLength: int, runHistory: int[]): int {\n      if (currentRunColor) {\n        // Terminate dark run\n        this.finderPenaltyAddHistory(currentRunLength, runHistory);\n        currentRunLength = 0;\n      }\n      currentRunLength += this.size; // Add light border to final run\n      this.finderPenaltyAddHistory(currentRunLength, runHistory);\n      return this.finderPenaltyCountPatterns(runHistory);\n    }\n\n    // Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore().\n    private finderPenaltyAddHistory(currentRunLength: int, runHistory: int[]): void {\n      if (runHistory[0] == 0) currentRunLength += this.size; // Add light border to initial run\n      runHistory.pop();\n      runHistory.unshift(currentRunLength);\n    }\n\n    /*-- Constants and tables --*/\n\n    // The minimum version number supported in the QR Code Model 2 standard.\n    public static readonly MIN_VERSION: int = 1;\n    // The maximum version number supported in the QR Code Model 2 standard.\n    public static readonly MAX_VERSION: int = 40;\n\n    // For use in getPenaltyScore(), when evaluating which mask is best.\n    private static readonly PENALTY_N1: int = 3;\n    private static readonly PENALTY_N2: int = 3;\n    private static readonly PENALTY_N3: int = 40;\n    private static readonly PENALTY_N4: int = 10;\n\n    private static readonly ECC_CODEWORDS_PER_BLOCK: int[][] = [\n      // Version: (note that index 0 is for padding, and is set to an illegal value)\n      //0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40    Error correction level\n      [\n        -1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30,\n        30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30\n      ], // Low\n      [\n        -1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28,\n        28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28\n      ], // Medium\n      [\n        -1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30,\n        30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30\n      ], // Quartile\n      [\n        -1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30,\n        30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30\n      ] // High\n    ];\n\n    private static readonly NUM_ERROR_CORRECTION_BLOCKS: int[][] = [\n      // Version: (note that index 0 is for padding, and is set to an illegal value)\n      //0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40    Error correction level\n      [\n        -1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18,\n        19, 19, 20, 21, 22, 24, 25\n      ], // Low\n      [\n        -1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29,\n        31, 33, 35, 37, 38, 40, 43, 45, 47, 49\n      ], // Medium\n      [\n        -1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40,\n        43, 45, 48, 51, 53, 56, 59, 62, 65, 68\n      ], // Quartile\n      [\n        -1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45,\n        48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81\n      ] // High\n    ];\n  }\n\n  // Appends the given number of low-order bits of the given value\n  // to the given buffer. Requires 0 <= len <= 31 and 0 <= val < 2^len.\n  function appendBits(val: int, len: int, bb: bit[]): void {\n    if (len < 0 || len > 31 || val >>> len != 0) throw new RangeError('Value out of range');\n    for (\n      let i = len - 1;\n      i >= 0;\n      i-- // Append bit by bit\n    )\n      bb.push((val >>> i) & 1);\n  }\n\n  // Returns true iff the i'th bit of x is set to 1.\n  function getBit(x: int, i: int): boolean {\n    return ((x >>> i) & 1) != 0;\n  }\n\n  // Throws an exception if the given condition is false.\n  function assert(cond: boolean): void {\n    if (!cond) throw new Error('Assertion error');\n  }\n\n  /*---- Data segment class ----*/\n\n  /*\n   * A segment of character/binary/control data in a QR Code symbol.\n   * Instances of this class are immutable.\n   * The mid-level way to create a segment is to take the payload data\n   * and call a static factory function such as QrSegment.makeNumeric().\n   * The low-level way to create a segment is to custom-make the bit buffer\n   * and call the QrSegment() constructor with appropriate values.\n   * This segment class imposes no length restrictions, but QR Codes have restrictions.\n   * Even in the most favorable conditions, a QR Code can only hold 7089 characters of data.\n   * Any segment longer than this is meaningless for the purpose of generating QR Codes.\n   */\n  export class QrSegment {\n    /*-- Static factory functions (mid level) --*/\n\n    // Returns a segment representing the given binary data encoded in\n    // byte mode. All input byte arrays are acceptable. Any text string\n    // can be converted to UTF-8 bytes and encoded as a byte mode segment.\n    public static makeBytes(data: readonly byte[]): QrSegment {\n      const bb: bit[] = [];\n      for (const b of data) appendBits(b, 8, bb);\n      return new QrSegment(QrSegment.Mode.BYTE, data.length, bb);\n    }\n\n    // Returns a segment representing the given string of decimal digits encoded in numeric mode.\n    public static makeNumeric(digits: string): QrSegment {\n      if (!QrSegment.isNumeric(digits)) throw new RangeError('String contains non-numeric characters');\n      const bb: bit[] = [];\n      for (let i = 0; i < digits.length; ) {\n        // Consume up to 3 digits per iteration\n        const n: int = Math.min(digits.length - i, 3);\n        appendBits(parseInt(digits.substring(i, i + n), 10), n * 3 + 1, bb);\n        i += n;\n      }\n      return new QrSegment(QrSegment.Mode.NUMERIC, digits.length, bb);\n    }\n\n    // Returns a segment representing the given text string encoded in alphanumeric mode.\n    // The characters allowed are: 0 to 9, A to Z (uppercase only), space,\n    // dollar, percent, asterisk, plus, hyphen, period, slash, colon.\n    public static makeAlphanumeric(text: string): QrSegment {\n      if (!QrSegment.isAlphanumeric(text))\n        throw new RangeError('String contains unencodable characters in alphanumeric mode');\n      const bb: bit[] = [];\n      let i: int;\n      for (i = 0; i + 2 <= text.length; i += 2) {\n        // Process groups of 2\n        let temp: int = QrSegment.ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)) * 45;\n        temp += QrSegment.ALPHANUMERIC_CHARSET.indexOf(text.charAt(i + 1));\n        appendBits(temp, 11, bb);\n      }\n      if (i < text.length)\n        // 1 character remaining\n        appendBits(QrSegment.ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)), 6, bb);\n      return new QrSegment(QrSegment.Mode.ALPHANUMERIC, text.length, bb);\n    }\n\n    // Returns a new mutable list of zero or more segments to represent the given Unicode text string.\n    // The result may use various segment modes and switch modes to optimize the length of the bit stream.\n    public static makeSegments(text: string): QrSegment[] {\n      // Select the most efficient segment encoding automatically\n      if (text == '') return [];\n      else if (QrSegment.isNumeric(text)) return [QrSegment.makeNumeric(text)];\n      else if (QrSegment.isAlphanumeric(text)) return [QrSegment.makeAlphanumeric(text)];\n      else return [QrSegment.makeBytes(QrSegment.toUtf8ByteArray(text))];\n    }\n\n    // Returns a segment representing an Extended Channel Interpretation\n    // (ECI) designator with the given assignment value.\n    public static makeEci(assignVal: int): QrSegment {\n      const bb: bit[] = [];\n      if (assignVal < 0) throw new RangeError('ECI assignment value out of range');\n      else if (assignVal < 1 << 7) appendBits(assignVal, 8, bb);\n      else if (assignVal < 1 << 14) {\n        appendBits(0b10, 2, bb);\n        appendBits(assignVal, 14, bb);\n      } else if (assignVal < 1000000) {\n        appendBits(0b110, 3, bb);\n        appendBits(assignVal, 21, bb);\n      } else throw new RangeError('ECI assignment value out of range');\n      return new QrSegment(QrSegment.Mode.ECI, 0, bb);\n    }\n\n    // Tests whether the given string can be encoded as a segment in numeric mode.\n    // A string is encodable iff each character is in the range 0 to 9.\n    public static isNumeric(text: string): boolean {\n      return QrSegment.NUMERIC_REGEX.test(text);\n    }\n\n    // Tests whether the given string can be encoded as a segment in alphanumeric mode.\n    // A string is encodable iff each character is in the following set: 0 to 9, A to Z\n    // (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon.\n    public static isAlphanumeric(text: string): boolean {\n      return QrSegment.ALPHANUMERIC_REGEX.test(text);\n    }\n\n    /*-- Constructor (low level) and fields --*/\n\n    // Creates a new QR Code segment with the given attributes and data.\n    // The character count (numChars) must agree with the mode and the bit buffer length,\n    // but the constraint isn't checked. The given bit buffer is cloned and stored.\n    public constructor(\n      // The mode indicator of this segment.\n      public readonly mode: QrSegment.Mode,\n\n      // The length of this segment's unencoded data. Measured in characters for\n      // numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode.\n      // Always zero or positive. Not the same as the data's bit length.\n      public readonly numChars: int,\n\n      // The data bits of this segment. Accessed through getData().\n      private readonly bitData: bit[]\n    ) {\n      if (numChars < 0) throw new RangeError('Invalid argument');\n      this.bitData = bitData.slice(); // Make defensive copy\n    }\n\n    /*-- Methods --*/\n\n    // Returns a new copy of the data bits of this segment.\n    public getData(): bit[] {\n      return this.bitData.slice(); // Make defensive copy\n    }\n\n    // (Package-private) Calculates and returns the number of bits needed to encode the given segments at\n    // the given version. The result is infinity if a segment has too many characters to fit its length field.\n    public static getTotalBits(segs: readonly QrSegment[], version: int): number {\n      let result = 0;\n      for (const seg of segs) {\n        const ccbits: int = seg.mode.numCharCountBits(version);\n        if (seg.numChars >= 1 << ccbits) return Infinity; // The segment's length doesn't fit the field's bit width\n        result += 4 + ccbits + seg.bitData.length;\n      }\n      return result;\n    }\n\n    // Returns a new array of bytes representing the given string encoded in UTF-8.\n    private static toUtf8ByteArray(str: string): byte[] {\n      str = encodeURI(str);\n      const result: byte[] = [];\n      for (let i = 0; i < str.length; i++) {\n        if (str.charAt(i) != '%') result.push(str.charCodeAt(i));\n        else {\n          result.push(parseInt(str.substring(i + 1, i + 3), 16));\n          i += 2;\n        }\n      }\n      return result;\n    }\n\n    /*-- Constants --*/\n\n    // Describes precisely all strings that are encodable in numeric mode.\n    private static readonly NUMERIC_REGEX: RegExp = /^[0-9]*$/;\n\n    // Describes precisely all strings that are encodable in alphanumeric mode.\n    private static readonly ALPHANUMERIC_REGEX: RegExp = /^[A-Z0-9 $%*+./:-]*$/;\n\n    // The set of all legal characters in alphanumeric mode,\n    // where each character value maps to the index in the string.\n    private static readonly ALPHANUMERIC_CHARSET: string = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:';\n  }\n}\n\n/*---- Public helper enumeration ----*/\n// eslint-disable-next-line @typescript-eslint/no-namespace\nnamespace qrcodegen {\n  // eslint-disable-next-line @typescript-eslint/no-namespace\n  export namespace QrCode {\n    type int = number;\n\n    /*\n     * The error correction level in a QR Code symbol. Immutable.\n     */\n    export class Ecc {\n      /*-- Constants --*/\n\n      public static readonly LOW = new Ecc(0, 1); // The QR Code can tolerate about  7% erroneous codewords\n      public static readonly MEDIUM = new Ecc(1, 0); // The QR Code can tolerate about 15% erroneous codewords\n      public static readonly QUARTILE = new Ecc(2, 3); // The QR Code can tolerate about 25% erroneous codewords\n      public static readonly HIGH = new Ecc(3, 2); // The QR Code can tolerate about 30% erroneous codewords\n\n      /*-- Constructor and fields --*/\n\n      private constructor(\n        // In the range 0 to 3 (unsigned 2-bit integer).\n        public readonly ordinal: int,\n        // (Package-private) In the range 0 to 3 (unsigned 2-bit integer).\n        public readonly formatBits: int\n      ) {}\n    }\n  }\n}\n\n/*---- Public helper enumeration ----*/\n// eslint-disable-next-line @typescript-eslint/no-namespace\nnamespace qrcodegen {\n  // eslint-disable-next-line @typescript-eslint/no-namespace\n  export namespace QrSegment {\n    type int = number;\n\n    /*\n     * Describes how a segment's data bits are interpreted. Immutable.\n     */\n    export class Mode {\n      /*-- Constants --*/\n\n      public static readonly NUMERIC = new Mode(0x1, [10, 12, 14]);\n      public static readonly ALPHANUMERIC = new Mode(0x2, [9, 11, 13]);\n      public static readonly BYTE = new Mode(0x4, [8, 16, 16]);\n      public static readonly KANJI = new Mode(0x8, [8, 10, 12]);\n      public static readonly ECI = new Mode(0x7, [0, 0, 0]);\n\n      /*-- Constructor and fields --*/\n\n      private constructor(\n        // The mode indicator bits, which is a uint4 value (range 0 to 15).\n        public readonly modeBits: int,\n        // Number of character count bits for three different version ranges.\n        private readonly numBitsCharCount: [int, int, int]\n      ) {}\n\n      /*-- Method --*/\n\n      // (Package-private) Returns the bit width of the character count field for a segment in\n      // this mode in a QR Code at the given version number. The result is in the range [0, 16].\n      public numCharCountBits(ver: int): int {\n        return this.numBitsCharCount[Math.floor((ver + 7) / 17)];\n      }\n    }\n  }\n}\n\n// Modification to export for actual use\nexport default qrcodegen;\n"
  },
  {
    "path": "components/qr-code/style/entry.less",
    "content": "@import './index.less';"
  },
  {
    "path": "components/qr-code/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@qrcode-prefix-cls: ~'@{ant-prefix}-qrcode';\n\n.@{qrcode-prefix-cls} {\n  position: relative;\n  display: inline-block;\n  padding: @padding-sm;\n\n  &>canvas {\n    display: block;\n  }\n}\n\n.@{qrcode-prefix-cls}-border {\n  border: @border-width-base @border-style-base @border-color-split;\n  border-radius: @border-radius-base;\n}\n\n.@{qrcode-prefix-cls}-mask {\n  position: absolute;\n  top: 0;\n  right: 0;\n  z-index: 10;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  width: 100%;\n  height: 100%;\n  text-align: center;\n  background-color: fade(@white, 96%);\n}\n\n.@{qrcode-prefix-cls}-expired {\n  color: fade(@black, 85%);\n}\n"
  },
  {
    "path": "components/qr-code/typing.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport qrcodegen from './qrcodegen';\n\nimport Ecc = qrcodegen.QrCode.Ecc;\nimport QrCode = qrcodegen.QrCode;\n\nexport type Modules = ReturnType<QrCode['getModules']>;\nexport interface Excavation {\n  x: number;\n  y: number;\n  w: number;\n  h: number;\n}\nexport type ErrorCorrectionLevel = 'L' | 'M' | 'Q' | 'H';\nexport type CrossOrigin = 'anonymous' | 'use-credentials' | '' | undefined;\n\nexport type ERROR_LEVEL_MAPPED_TYPE = {\n  [index in ErrorCorrectionLevel]: Ecc;\n};\n\nexport interface ImageSettings {\n  /**\n   * The URI of the embedded image.\n   */\n  src: string;\n  /**\n   * The height, in pixels, of the image.\n   */\n  height: number;\n  /**\n   * The width, in pixels, of the image.\n   */\n  width: number;\n  /**\n   * Whether or not to \"excavate\" the modules around the embedded image. This\n   * means that any modules the embedded image overlaps will use the background\n   * color.\n   */\n  excavate: boolean;\n  /**\n   * The horizontal offset of the embedded image, starting from the top left corner.\n   * Will center if not specified.\n   */\n  x?: number;\n  /**\n   * The vertical offset of the embedded image, starting from the top left corner.\n   * Will center if not specified.\n   */\n  y?: number;\n  /**\n   * The opacity of the embedded image in the range of 0-1.\n   * @defaultValue 1\n   */\n  opacity?: number;\n  /**\n   * The cross-origin value to use when loading the image. This is used to\n   * ensure compatibility with CORS, particularly when extracting image data\n   * from QRCodeCanvas.\n   * Note: `undefined` is treated differently than the seemingly equivalent\n   * empty string. This is intended to align with HTML behavior where omitting\n   * the attribute behaves differently than the empty string.\n   */\n  crossOrigin?: CrossOrigin;\n}\n"
  },
  {
    "path": "components/qr-code/utils.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\n// ==========================================================\nimport qrcodegen from './qrcodegen';\nimport type {\n  CrossOrigin,\n  ERROR_LEVEL_MAPPED_TYPE,\n  ErrorCorrectionLevel,\n  Excavation,\n  ImageSettings,\n  Modules\n} from './typing';\n\nimport Ecc = qrcodegen.QrCode.Ecc;\n\n// =================== ERROR_LEVEL ==========================\nexport const ERROR_LEVEL_MAP: ERROR_LEVEL_MAPPED_TYPE = {\n  L: Ecc.LOW,\n  M: Ecc.MEDIUM,\n  Q: Ecc.QUARTILE,\n  H: Ecc.HIGH\n} as const;\n\n// =================== DEFAULT_VALUE ==========================\nexport const DEFAULT_LEVEL: ErrorCorrectionLevel = 'M';\nexport const DEFAULT_BACKGROUND_COLOR = '#FFFFFF';\nexport const DEFAULT_FRONT_COLOR = '#000000';\nexport const DEFAULT_MINVERSION = 1;\nexport const DEFAULT_IMG_SCALE = 0.1;\n\n// =================== UTILS ==========================\n/**\n * Generate a path string from modules\n * @param modules\n * @param margin\n * @returns\n */\nexport const generatePath = (modules: Modules, margin: number = 0): string => {\n  const ops: string[] = [];\n  modules.forEach((row, y) => {\n    let start: number | null = null;\n    row.forEach((cell, x) => {\n      if (!cell && start !== null) {\n        ops.push(`M${start + margin} ${y + margin}h${x - start}v1H${start + margin}z`);\n        start = null;\n        return;\n      }\n\n      if (x === row.length - 1) {\n        if (!cell) {\n          return;\n        }\n        if (start === null) {\n          ops.push(`M${x + margin},${y + margin} h1v1H${x + margin}z`);\n        } else {\n          ops.push(`M${start + margin},${y + margin} h${x + 1 - start}v1H${start + margin}z`);\n        }\n        return;\n      }\n\n      if (cell && start === null) {\n        start = x;\n      }\n    });\n  });\n  return ops.join('');\n};\n\n/**\n * Excavate modules\n * @param modules\n * @param excavation\n * @returns\n */\nexport const excavateModules = (modules: Modules, excavation: Excavation): Modules => {\n  return modules.slice().map((row, y) => {\n    if (y < excavation.y || y >= excavation.y + excavation.h) {\n      return row;\n    }\n    return row.map((cell, x) => {\n      if (x < excavation.x || x >= excavation.x + excavation.w) {\n        return cell;\n      }\n      return false;\n    });\n  });\n};\n\n/**\n * Get image settings\n * @param cells The modules of the QR code\n * @param size The size of the QR code\n * @param margin\n * @param imageSettings\n * @returns\n */\nexport const getImageSettings = (\n  cells: Modules,\n  size: number,\n  margin: number,\n  imageSettings?: ImageSettings\n): null | {\n  x: number;\n  y: number;\n  h: number;\n  w: number;\n  excavation: Excavation | null;\n  opacity: number;\n  crossOrigin: CrossOrigin;\n} => {\n  if (imageSettings == null) {\n    return null;\n  }\n  const numCells = cells.length + margin * 2;\n  const defaultSize = Math.floor(size * DEFAULT_IMG_SCALE);\n  const scale = numCells / size;\n  const w = (imageSettings.width || defaultSize) * scale;\n  const h = (imageSettings.height || defaultSize) * scale;\n  const x = imageSettings.x == null ? cells.length / 2 - w / 2 : imageSettings.x * scale;\n  const y = imageSettings.y == null ? cells.length / 2 - h / 2 : imageSettings.y * scale;\n  const opacity = imageSettings.opacity == null ? 1 : imageSettings.opacity;\n\n  let excavation = null;\n  if (imageSettings.excavate) {\n    const floorX = Math.floor(x);\n    const floorY = Math.floor(y);\n    const ceilW = Math.ceil(w + x - floorX);\n    const ceilH = Math.ceil(h + y - floorY);\n    excavation = { x: floorX, y: floorY, w: ceilW, h: ceilH };\n  }\n\n  const crossOrigin = imageSettings.crossOrigin;\n\n  return { x, y, h, w, excavation, opacity, crossOrigin };\n};\n\n/**\n * Get margin size\n * @param needMargin Whether need margin\n * @param marginSize Custom margin size\n * @returns\n */\nexport const getMarginSize = (marginSize: number): number => Math.max(Math.floor(marginSize), 0);\n\n/**\n * Check if Path2D is supported\n */\nexport const isSupportPath2d = (() => {\n  try {\n    new Path2D().addPath(new Path2D());\n  } catch {\n    return false;\n  }\n  return true;\n})();\n"
  },
  {
    "path": "components/radio/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n最简单的用法。\n\n## en-US\n\nThe simplest use.\n"
  },
  {
    "path": "components/radio/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\n\n@Component({\n  selector: 'nz-demo-radio-basic',\n  imports: [FormsModule, NzRadioModule],\n  template: `<label nz-radio ngModel>Radio</label>`\n})\nexport class NzDemoRadioBasicComponent {}\n"
  },
  {
    "path": "components/radio/demo/disable.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 不可用\n  en-US: Disabled\n---\n\n## zh-CN\n\n`nz-radio` 不可用。\n\n## en-US\n\n`nz-radio` unavailable.\n"
  },
  {
    "path": "components/radio/demo/disable.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\n\n@Component({\n  selector: 'nz-demo-radio-disable',\n  imports: [FormsModule, NzButtonModule, NzRadioModule],\n  template: `\n    <div>\n      <label nz-radio [nzDisabled]=\"disabled\">Disabled</label>\n      <br />\n      <label nz-radio [nzDisabled]=\"disabled\" [ngModel]=\"true\">Disabled</label>\n      <br />\n      <br />\n      <button nz-button nzType=\"primary\" (click)=\"disabled = !disabled\">Toggle disabled</button>\n    </div>\n  `\n})\nexport class NzDemoRadioDisableComponent {\n  disabled = true;\n}\n"
  },
  {
    "path": "components/radio/demo/radiobutton.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 按钮样式\n  en-US: Radio Style\n---\n\n## zh-CN\n\n按钮样式的单选组合。\n\n## en-US\n\nThe combination of radio button style.\n"
  },
  {
    "path": "components/radio/demo/radiobutton.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\n\n@Component({\n  selector: 'nz-demo-radio-radiobutton',\n  imports: [FormsModule, NzRadioModule],\n  template: `\n    <nz-radio-group [(ngModel)]=\"radioValue\">\n      <label nz-radio-button nzValue=\"A\">Hangzhou</label>\n      <label nz-radio-button nzValue=\"B\">Shanghai</label>\n      <label nz-radio-button nzValue=\"C\">Beijing</label>\n      <label nz-radio-button nzValue=\"D\">Chengdu</label>\n    </nz-radio-group>\n    <br />\n    <br />\n    <nz-radio-group [(ngModel)]=\"radioValue\">\n      <label nz-radio-button nzValue=\"A\">Hangzhou</label>\n      <label nz-radio-button nzValue=\"B\" nzDisabled>Shanghai</label>\n      <label nz-radio-button nzValue=\"C\">Beijing</label>\n      <label nz-radio-button nzValue=\"D\">Chengdu</label>\n    </nz-radio-group>\n    <br />\n    <br />\n    <nz-radio-group [(ngModel)]=\"radioValue\">\n      <label nz-radio-button nzValue=\"A\" nzDisabled>Hangzhou</label>\n      <label nz-radio-button nzValue=\"B\" nzDisabled>Shanghai</label>\n      <label nz-radio-button nzValue=\"C\" nzDisabled>Beijing</label>\n      <label nz-radio-button nzValue=\"D\" nzDisabled>Chengdu</label>\n    </nz-radio-group>\n  `\n})\nexport class NzDemoRadioRadiobuttonComponent {\n  radioValue = 'A';\n}\n"
  },
  {
    "path": "components/radio/demo/radiogroup-more.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: RadioGroup 垂直\n  en-US: Vertical RadioGroup\n---\n\n## zh-CN\n\n垂直的 `nz-radio-group`，配合更多输入框选项。\n\n## en-US\n\nVertical `nz-radio-group`, with more radios.\n"
  },
  {
    "path": "components/radio/demo/radiogroup-more.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\n\n@Component({\n  selector: 'nz-demo-radio-radiogroup-more',\n  imports: [FormsModule, NzInputModule, NzRadioModule],\n  template: `\n    <nz-radio-group [(ngModel)]=\"radioValue\">\n      <label nz-radio nzValue=\"A\">Option A</label>\n      <label nz-radio nzValue=\"B\">Option B</label>\n      <label nz-radio nzValue=\"C\">Option C</label>\n      <label nz-radio nzValue=\"M\">\n        More...\n        @if (radioValue === 'M') {\n          <input type=\"text\" nz-input />\n        }\n      </label>\n    </nz-radio-group>\n  `,\n  styles: `\n    [nz-radio] {\n      display: block;\n      height: 32px;\n      line-height: 32px;\n    }\n\n    input {\n      width: 100px;\n      margin-left: 10px;\n    }\n  `\n})\nexport class NzDemoRadioRadiogroupMoreComponent {\n  radioValue = 'A';\n}\n"
  },
  {
    "path": "components/radio/demo/radiogroup-options.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: RadioGroup 组合 - 配置方式\n  en-US: RadioGroup group - optional\n---\n\n## zh-CN\n\n通过配置 `options` 参数来渲染单选框。\n\n## en-US\n\nRender radios by configuring `options`.\n"
  },
  {
    "path": "components/radio/demo/radiogroup-options.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\n\n@Component({\n  selector: 'nz-demo-radio-radiogroup-options',\n  imports: [FormsModule, NzRadioModule],\n  template: `\n    <nz-radio-group [(ngModel)]=\"radioValue\">\n      @for (o of options; track o.value) {\n        <label nz-radio [nzValue]=\"o.value\">{{ o.label }}</label>\n      }\n    </nz-radio-group>\n    <nz-radio-group [(ngModel)]=\"radioValue\">\n      @for (o of options; track o.value) {\n        <label nz-radio [nzValue]=\"o.value\">{{ o.label }}</label>\n      }\n    </nz-radio-group>\n    <nz-radio-group [(ngModel)]=\"radioValue\">\n      @for (o of options; track o.value) {\n        <label nz-radio [nzValue]=\"o.value\">{{ o.label }}</label>\n      }\n    </nz-radio-group>\n  `\n})\nexport class NzDemoRadioRadiogroupOptionsComponent {\n  radioValue = 'Apple';\n  options = [\n    { label: 'Apple', value: 'Apple' },\n    { label: 'Pear', value: 'Pear' },\n    { label: 'Orange', value: 'Orange' }\n  ];\n}\n"
  },
  {
    "path": "components/radio/demo/radiogroup-with-name.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 单选组合 - 配合 name 使用\n  en-US: RadioGroup with name\n---\n\n## zh-CN\n\n可以为 `nz-radio-group` 配置 `nzName` 参数，为组合内的 input 元素赋予相同的 `name` 属性，使浏览器把 `nz-radio-group` 下的 `nz-radio` 真正看作是一组（例如可以通过方向键始终**在同一组内**更改选项）。\n\n## en-US\n\nPassing the `nzName` property to all `input[type=\"radio\"]` that are in the same RadioGroup. It is usually used to let the browser see your `nz-radio-group` as a real \"group\" and keep the default behavior. For example, using left/right keyboard arrow to change your selection that in the same `nz-radio-group`.\n"
  },
  {
    "path": "components/radio/demo/radiogroup-with-name.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\n\n@Component({\n  selector: 'nz-demo-radio-radiogroup-with-name',\n  imports: [FormsModule, NzRadioModule],\n  template: `\n    <nz-radio-group [(ngModel)]=\"radioValue\" nzName=\"radiogroup\">\n      <label nz-radio nzValue=\"A\">A</label>\n      <label nz-radio nzValue=\"B\">B</label>\n      <label nz-radio nzValue=\"C\">C</label>\n      <label nz-radio nzValue=\"D\">D</label>\n    </nz-radio-group>\n  `\n})\nexport class NzDemoRadioRadiogroupWithNameComponent {\n  radioValue = 'A';\n}\n"
  },
  {
    "path": "components/radio/demo/radiogroup.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 单选组合\n  en-US: Radio Group\n---\n\n## zh-CN\n\n一组互斥的 `nz-radio` 配合使用。\n\n## en-US\n\nA group of `nz-radio` components.\n"
  },
  {
    "path": "components/radio/demo/radiogroup.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\n\n@Component({\n  selector: 'nz-demo-radio-radiogroup',\n  imports: [FormsModule, NzRadioModule],\n  template: `\n    <nz-radio-group [(ngModel)]=\"radioValue\">\n      <label nz-radio nzValue=\"A\">A</label>\n      <label nz-radio nzValue=\"B\">B</label>\n      <label nz-radio nzValue=\"C\">C</label>\n      <label nz-radio nzValue=\"D\">D</label>\n    </nz-radio-group>\n  `\n})\nexport class NzDemoRadioRadiogroupComponent {\n  radioValue = 'A';\n}\n"
  },
  {
    "path": "components/radio/demo/size.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 大小\n  en-US: Size\n---\n\n## zh-CN\n\n大中小三种组合，可以和表单输入框进行对应配合。\n\n## en-US\n\nThere are three sizes available: large, medium, and small. It can coordinate with input box.\n"
  },
  {
    "path": "components/radio/demo/size.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\n\n@Component({\n  selector: 'nz-demo-radio-size',\n  imports: [FormsModule, NzRadioModule],\n  template: `\n    <nz-radio-group [(ngModel)]=\"radioValue\" nzSize=\"large\">\n      <label nz-radio-button nzValue=\"A\">Hangzhou</label>\n      <label nz-radio-button nzValue=\"B\">Shanghai</label>\n      <label nz-radio-button nzValue=\"C\">Beijing</label>\n      <label nz-radio-button nzValue=\"D\">Chengdu</label>\n    </nz-radio-group>\n    <br />\n    <br />\n    <nz-radio-group [(ngModel)]=\"radioValue\">\n      <label nz-radio-button nzValue=\"A\">Hangzhou</label>\n      <label nz-radio-button nzValue=\"B\">Shanghai</label>\n      <label nz-radio-button nzValue=\"C\">Beijing</label>\n      <label nz-radio-button nzValue=\"D\">Chengdu</label>\n    </nz-radio-group>\n    <br />\n    <br />\n    <nz-radio-group [(ngModel)]=\"radioValue\" nzSize=\"small\">\n      <label nz-radio-button nzValue=\"A\">Hangzhou</label>\n      <label nz-radio-button nzValue=\"B\">Shanghai</label>\n      <label nz-radio-button nzValue=\"C\">Beijing</label>\n      <label nz-radio-button nzValue=\"D\">Chengdu</label>\n    </nz-radio-group>\n  `\n})\nexport class NzDemoRadioSizeComponent {\n  radioValue = 'A';\n}\n"
  },
  {
    "path": "components/radio/demo/solid.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 填底的按钮样式\n  en-US: Solid radio button\n---\n\n## zh-CN\n\n实色填底的单选按钮样式。\n\n## en-US\n\nSolid radio button style.\n"
  },
  {
    "path": "components/radio/demo/solid.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\n\n@Component({\n  selector: 'nz-demo-radio-solid',\n  imports: [FormsModule, NzRadioModule],\n  template: `\n    <nz-radio-group [(ngModel)]=\"radioValue\" nzButtonStyle=\"solid\">\n      <label nz-radio-button nzValue=\"A\">Hangzhou</label>\n      <label nz-radio-button nzValue=\"B\">Shanghai</label>\n      <label nz-radio-button nzValue=\"C\">Beijing</label>\n      <label nz-radio-button nzValue=\"D\">Chengdu</label>\n    </nz-radio-group>\n  `\n})\nexport class NzDemoRadioSolidComponent {\n  radioValue = 'A';\n}\n"
  },
  {
    "path": "components/radio/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Entry\ntitle: Radio\ncover: 'https://gw.alipayobjects.com/zos/alicdn/8cYb5seNB/Radio.svg'\ndescription: Used to select a single state from multiple options.\n---\n\n## When To Use\n\n- Used to select a single state in multiple options.\n- The difference from Select is that Radio is visible to the user and can facilitate the comparison of choice, which means there shouldn't be too many of them.\n\n## API\n\n### [nz-radio] | [nz-radio-button]\n\n| Property          | Description                                                     | Type                    | Default |\n| ----------------- | --------------------------------------------------------------- | ----------------------- | ------- |\n| `[nzAutoFocus]`   | get focus when component mounted                                | `boolean`               | `false` |\n| `[nzDisabled]`    | Disable radio                                                   | `boolean`               | `false` |\n| `[ngModel]`       | Specifies whether the radio is selected, double binding         | `boolean`               | `false` |\n| `[nzValue]`       | use with `nz-radio-group`                                       | `any`                   | -       |\n| `(ngModelChange)` | The callback function that is triggered when the state changes. | `EventEmitter<boolean>` | -       |\n\n### nz-radio-group\n\nradio group，wrap a group of `nz-radio`。\n\n| Property          | Description                                                         | Type                              | Default     |\n| ----------------- | ------------------------------------------------------------------- | --------------------------------- | ----------- |\n| `[ngModel]`       | current selected `nz-radio` value, double binding                   | `any`                             | -           |\n| `[nzName]`        | The `name` property of all `input[type=\"radio\"]` children           | `string`                          | -           |\n| `[nzDisabled]`    | Disable all radio buttons                                           | `boolean`                         | `false`     |\n| `[nzSize]`        | Size, only on radio style                                           | `'large' \\| 'small' \\| 'default'` | `'default'` |\n| `(ngModelChange)` | the callback function when current selected `nz-radio` value change | `EventEmitter<string>`            | -           |\n| `[nzButtonStyle]` | style type of radio button                                          | `'outline' \\| 'solid'`            | `'outline'` |\n\n## Methods\n\n### [nz-radio]\n\nyou can get `NzRadioComponent` via `ViewChild`\n\n| Name      | Description  |\n| --------- | ------------ |\n| `blur()`  | remove focus |\n| `focus()` | get focus    |\n"
  },
  {
    "path": "components/radio/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 单选框\ntype: 数据录入\ntitle: Radio\ncover: 'https://gw.alipayobjects.com/zos/alicdn/8cYb5seNB/Radio.svg'\ndescription: 用于在多个备选项中选中单个状态。\n---\n\n## 何时使用\n\n- 用于在多个备选项中选中单个状态。\n- 和 Select 的区别是，Radio 所有选项默认可见，方便用户在比较中选择，因此选项不宜过多。\n\n## API\n\n### [nz-radio] | [nz-radio-button]\n\n| 参数              | 说明                                     | 类型                    | 默认值  |\n| ----------------- | ---------------------------------------- | ----------------------- | ------- |\n| `[nzAutoFocus]`   | 自动获取焦点                             | `boolean`               | `false` |\n| `[nzDisabled]`    | 设定 disable 状态                        | `boolean`               | `false` |\n| `[ngModel]`       | 指定当前是否选中，可双向绑定             | `boolean`               | `false` |\n| `[nzValue]`       | 设置 value，与 `nz-radio-group` 配合使用 | `any`                   | -       |\n| `(ngModelChange)` | 选中变化时回调                           | `EventEmitter<boolean>` | -       |\n\n### nz-radio-group\n\n单选框组合，用于包裹一组 `nz-radio`。\n\n| 参数              | 说明                                                         | 类型                              | 默认值      |\n| ----------------- | ------------------------------------------------------------ | --------------------------------- | ----------- |\n| `[ngModel]`       | 指定选中的 `nz-radio` 的 value 值                            | `any`                             | -           |\n| `[nzName]`        | `nz-radio-group` 下所有 `input[type=\"radio\"]` 的 `name` 属性 | `string`                          | -           |\n| `[nzDisabled]`    | 设定所有 `nz-radio` disable 状态                             | `boolean`                         | `false`     |\n| `[nzSize]`        | 大小，只对按钮样式生效                                       | `'large' \\| 'small' \\| 'default'` | `'default'` |\n| `(ngModelChange)` | 选中变化时回调                                               | `EventEmitter<boolean>`           | -           |\n| `[nzButtonStyle]` | RadioButton 的风格样式，目前有描边和填色两种风格             | `'outline' \\| 'solid'`            | `'outline'` |\n\n## 方法\n\n### [nz-radio]\n\n可以通过 `ViewChild` 等其他方式获取 `NzRadioComponent` 使用以下方法\n\n| 名称      | 描述     |\n| --------- | -------- |\n| `blur()`  | 移除焦点 |\n| `focus()` | 获取焦点 |\n"
  },
  {
    "path": "components/radio/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/radio/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/radio/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './radio-group.component';\nexport * from './radio.component';\nexport * from './radio.service';\nexport * from './radio.module';\n"
  },
  {
    "path": "components/radio/radio-group.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DestroyRef,\n  Input,\n  OnChanges,\n  OnInit,\n  SimpleChanges,\n  ViewEncapsulation,\n  booleanAttribute,\n  computed,\n  forwardRef,\n  inject,\n  signal\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\n\nimport { NZ_FORM_SIZE } from 'ng-zorro-antd/core/form';\nimport { NzSafeAny, NzSizeLDSType, OnChangeType, OnTouchedType } from 'ng-zorro-antd/core/types';\n\nimport { NzRadioService } from './radio.service';\n\nexport type NzRadioButtonStyle = 'outline' | 'solid';\n\n@Component({\n  selector: 'nz-radio-group',\n  exportAs: 'nzRadioGroup',\n  template: `<ng-content />`,\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  providers: [\n    NzRadioService,\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => NzRadioGroupComponent),\n      multi: true\n    }\n  ],\n  host: {\n    class: 'ant-radio-group',\n    '[class.ant-radio-group-large]': `finalSize() === 'large'`,\n    '[class.ant-radio-group-small]': `finalSize() === 'small'`,\n    '[class.ant-radio-group-solid]': `nzButtonStyle === 'solid'`,\n    '[class.ant-radio-group-rtl]': `dir() === 'rtl'`\n  }\n})\nexport class NzRadioGroupComponent implements OnInit, ControlValueAccessor, OnChanges {\n  private readonly cdr = inject(ChangeDetectorRef);\n  private readonly nzRadioService = inject(NzRadioService);\n  private readonly destroyRef = inject(DestroyRef);\n  private readonly nzFormSize = inject(NZ_FORM_SIZE, { optional: true });\n\n  private value: NzSafeAny | null = null;\n  private isNzDisableFirstChange: boolean = true;\n  onChange: OnChangeType = () => {};\n  onTouched: OnTouchedType = () => {};\n  @Input({ transform: booleanAttribute }) nzDisabled = false;\n  @Input() nzButtonStyle: NzRadioButtonStyle = 'outline';\n  @Input() nzSize: NzSizeLDSType = 'default';\n  @Input() nzName: string | null = null;\n\n  dir = inject(Directionality).valueSignal;\n\n  private readonly size = signal(this.nzSize);\n\n  protected readonly finalSize = computed(() => this.nzFormSize?.() || this.size());\n\n  ngOnInit(): void {\n    this.nzRadioService.selected$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(value => {\n      if (this.value !== value) {\n        this.value = value;\n        this.onChange(this.value);\n      }\n    });\n    this.nzRadioService.touched$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      Promise.resolve().then(() => this.onTouched());\n    });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzDisabled, nzName, nzSize } = changes;\n    if (nzDisabled) {\n      this.nzRadioService.setDisabled(this.nzDisabled);\n    }\n    if (nzName) {\n      this.nzRadioService.setName(this.nzName!);\n    }\n    if (nzSize) {\n      this.size.set(this.nzSize);\n    }\n  }\n\n  writeValue(value: NzSafeAny): void {\n    this.value = value;\n    this.nzRadioService.select(value);\n    this.cdr.markForCheck();\n  }\n\n  registerOnChange(fn: OnChangeType): void {\n    this.onChange = fn;\n  }\n\n  registerOnTouched(fn: OnTouchedType): void {\n    this.onTouched = fn;\n  }\n\n  setDisabledState(isDisabled: boolean): void {\n    this.nzDisabled = (this.isNzDisableFirstChange && this.nzDisabled) || isDisabled;\n    this.isNzDisableFirstChange = false;\n    this.nzRadioService.setDisabled(this.nzDisabled);\n    this.cdr.markForCheck();\n  }\n}\n"
  },
  {
    "path": "components/radio/radio.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { FocusMonitor } from '@angular/cdk/a11y';\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport {\n  AfterViewInit,\n  ChangeDetectionStrategy,\n  Component,\n  ElementRef,\n  Input,\n  OnInit,\n  ViewChild,\n  ViewEncapsulation,\n  booleanAttribute,\n  forwardRef,\n  inject,\n  DestroyRef,\n  NgZone,\n  ChangeDetectorRef\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\n\nimport { NzFormStatusService } from 'ng-zorro-antd/core/form';\nimport { NzSafeAny, OnChangeType, OnTouchedType } from 'ng-zorro-antd/core/types';\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\n\nimport { NzRadioService } from './radio.service';\n\n@Component({\n  selector: '[nz-radio],[nz-radio-button]',\n  exportAs: 'nzRadio',\n  template: `\n    <span\n      [class.ant-radio]=\"!isRadioButton\"\n      [class.ant-radio-checked]=\"isChecked && !isRadioButton\"\n      [class.ant-radio-disabled]=\"nzDisabled && !isRadioButton\"\n      [class.ant-radio-button]=\"isRadioButton\"\n      [class.ant-radio-button-checked]=\"isChecked && isRadioButton\"\n      [class.ant-radio-button-disabled]=\"nzDisabled && isRadioButton\"\n    >\n      <input\n        #inputElement\n        type=\"radio\"\n        [attr.autofocus]=\"nzAutoFocus ? 'autofocus' : null\"\n        [class.ant-radio-input]=\"!isRadioButton\"\n        [class.ant-radio-button-input]=\"isRadioButton\"\n        [disabled]=\"nzDisabled\"\n        [checked]=\"isChecked\"\n        [attr.name]=\"name\"\n      />\n      <span [class.ant-radio-inner]=\"!isRadioButton\" [class.ant-radio-button-inner]=\"isRadioButton\"></span>\n    </span>\n    <span><ng-content /></span>\n  `,\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => NzRadioComponent),\n      multi: true\n    }\n  ],\n  host: {\n    '[class.ant-radio-wrapper-in-form-item]': '!!nzFormStatusService',\n    '[class.ant-radio-wrapper]': '!isRadioButton',\n    '[class.ant-radio-button-wrapper]': 'isRadioButton',\n    '[class.ant-radio-wrapper-checked]': 'isChecked && !isRadioButton',\n    '[class.ant-radio-button-wrapper-checked]': 'isChecked && isRadioButton',\n    '[class.ant-radio-wrapper-disabled]': 'nzDisabled && !isRadioButton',\n    '[class.ant-radio-button-wrapper-disabled]': 'nzDisabled && isRadioButton',\n    '[class.ant-radio-wrapper-rtl]': `!isRadioButton && dir === 'rtl'`,\n    '[class.ant-radio-button-wrapper-rtl]': `isRadioButton && dir === 'rtl'`\n  }\n})\nexport class NzRadioComponent implements ControlValueAccessor, AfterViewInit, OnInit {\n  private readonly directionality = inject(Directionality);\n  private readonly nzRadioService = inject(NzRadioService, { optional: true });\n  private readonly ngZone = inject(NgZone);\n  private readonly elementRef = inject(ElementRef);\n  private readonly cdr = inject(ChangeDetectorRef);\n  private readonly focusMonitor = inject(FocusMonitor);\n  private readonly destroyRef = inject(DestroyRef);\n  readonly nzFormStatusService = inject(NzFormStatusService, { optional: true });\n\n  private isNgModel = false;\n  private isNzDisableFirstChange: boolean = true;\n  isChecked = false;\n  name: string | null = null;\n  onChange: OnChangeType = () => {};\n  onTouched: OnTouchedType = () => {};\n  @ViewChild('inputElement', { static: true }) inputElement!: ElementRef<HTMLInputElement>;\n  @Input() nzValue: NzSafeAny | null = null;\n  @Input({ transform: booleanAttribute }) nzDisabled = false;\n  @Input({ transform: booleanAttribute }) nzAutoFocus = false;\n  @Input({ alias: 'nz-radio-button', transform: booleanAttribute }) isRadioButton = false;\n\n  dir: Direction = 'ltr';\n\n  focus(): void {\n    this.focusMonitor.focusVia(this.inputElement!, 'keyboard');\n  }\n\n  blur(): void {\n    this.inputElement!.nativeElement.blur();\n  }\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      this.focusMonitor.stopMonitoring(this.elementRef);\n    });\n  }\n\n  setDisabledState(disabled: boolean): void {\n    this.nzDisabled = (this.isNzDisableFirstChange && this.nzDisabled) || disabled;\n    this.isNzDisableFirstChange = false;\n    this.cdr.markForCheck();\n  }\n\n  writeValue(value: boolean): void {\n    this.isChecked = value;\n    this.cdr.markForCheck();\n  }\n\n  registerOnChange(fn: OnChangeType): void {\n    this.isNgModel = true;\n    this.onChange = fn;\n  }\n\n  registerOnTouched(fn: OnTouchedType): void {\n    this.onTouched = fn;\n  }\n\n  ngOnInit(): void {\n    if (this.nzRadioService) {\n      this.nzRadioService.name$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(name => {\n        this.name = name;\n        this.cdr.markForCheck();\n      });\n      this.nzRadioService.disabled$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(disabled => {\n        this.nzDisabled = (this.isNzDisableFirstChange && this.nzDisabled) || disabled;\n        this.isNzDisableFirstChange = false;\n        this.cdr.markForCheck();\n      });\n      this.nzRadioService.selected$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(value => {\n        const isChecked = this.isChecked;\n        this.isChecked = this.nzValue === value;\n        // We don't have to run `onChange()` on each `nz-radio` button whenever the `selected$` emits.\n        // If we have 8 `nz-radio` buttons within the `nz-radio-group` and they're all connected with\n        // `ngModel` or `formControl` then `onChange()` will be called 8 times for each `nz-radio` button.\n        // We prevent this by checking if `isChecked` has been changed or not.\n        if (\n          this.isNgModel &&\n          isChecked !== this.isChecked &&\n          // We're only intereted if `isChecked` has been changed to `false` value to emit `false` to the ascendant form,\n          // since we already emit `true` within the `setupClickListener`.\n          this.isChecked === false\n        ) {\n          this.onChange(false);\n        }\n        this.cdr.markForCheck();\n      });\n    }\n    this.focusMonitor\n      .monitor(this.elementRef, true)\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(focusOrigin => {\n        if (!focusOrigin) {\n          Promise.resolve().then(() => this.onTouched());\n          if (this.nzRadioService) {\n            this.nzRadioService.touch();\n          }\n        }\n      });\n\n    this.directionality.change.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n      this.dir = direction;\n      this.cdr.detectChanges();\n    });\n\n    this.dir = this.directionality.value;\n\n    this.setupClickListener();\n  }\n\n  ngAfterViewInit(): void {\n    if (this.nzAutoFocus) {\n      this.focus();\n    }\n  }\n\n  private setupClickListener(): void {\n    fromEventOutsideAngular<MouseEvent>(this.elementRef.nativeElement, 'click')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(event => {\n        /** prevent label click triggered twice. **/\n        event.stopPropagation();\n        event.preventDefault();\n        if (this.nzDisabled || this.isChecked) {\n          return;\n        }\n        this.ngZone.run(() => {\n          this.focus();\n          this.nzRadioService?.select(this.nzValue);\n          if (this.isNgModel) {\n            this.isChecked = true;\n            this.onChange(true);\n          }\n          this.cdr.markForCheck();\n        });\n      });\n  }\n}\n"
  },
  {
    "path": "components/radio/radio.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzRadioGroupComponent } from './radio-group.component';\nimport { NzRadioComponent } from './radio.component';\n\n@NgModule({\n  imports: [NzRadioComponent, NzRadioGroupComponent],\n  exports: [NzRadioComponent, NzRadioGroupComponent]\n})\nexport class NzRadioModule {}\n"
  },
  {
    "path": "components/radio/radio.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Injectable } from '@angular/core';\nimport { ReplaySubject, Subject } from 'rxjs';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\n@Injectable()\nexport class NzRadioService {\n  selected$ = new ReplaySubject<NzSafeAny>(1);\n  touched$ = new Subject<void>();\n  disabled$ = new ReplaySubject<boolean>(1);\n  name$ = new ReplaySubject<string>(1);\n  touch(): void {\n    this.touched$.next();\n  }\n  select(value: NzSafeAny): void {\n    this.selected$.next(value);\n  }\n  setDisabled(value: boolean): void {\n    this.disabled$.next(value);\n  }\n  setName(value: string): void {\n    this.name$.next(value);\n  }\n}\n"
  },
  {
    "path": "components/radio/radio.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport { ApplicationRef, Component, DebugElement, provideZoneChangeDetection, signal, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing';\nimport { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\n\nimport { NZ_FORM_SIZE } from 'ng-zorro-antd/core/form';\nimport { createMouseEvent } from 'ng-zorro-antd/core/testing';\nimport { NzSizeLDSType } from 'ng-zorro-antd/core/types';\n\nimport { NzRadioGroupComponent } from './radio-group.component';\nimport { NzRadioComponent } from './radio.component';\nimport { NzRadioModule } from './radio.module';\n\ndescribe('radio', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  describe('single radio basic', () => {\n    let fixture: ComponentFixture<NzTestRadioSingleComponent>;\n    let testComponent: NzTestRadioSingleComponent;\n    let radio: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestRadioSingleComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n      radio = fixture.debugElement.query(By.directive(NzRadioComponent));\n    });\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n      expect(radio.nativeElement.classList).toContain('ant-radio-wrapper');\n      expect(radio.nativeElement.firstElementChild!.classList).toContain('ant-radio');\n      expect(radio.nativeElement.firstElementChild.lastElementChild.classList).toContain('ant-radio-inner');\n    });\n\n    it('should click work', fakeAsync(() => {\n      fixture.detectChanges();\n      expect(radio.nativeElement.firstElementChild!.classList).not.toContain('ant-radio-checked');\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(0);\n      radio.nativeElement.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(radio.nativeElement.firstElementChild!.classList).toContain('ant-radio-checked');\n      expect(testComponent.value).toBe(true);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(1);\n      radio.nativeElement.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(radio.nativeElement.firstElementChild!.classList).toContain('ant-radio-checked');\n      expect(testComponent.value).toBe(true);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(1);\n    }));\n\n    it('should disabled work', fakeAsync(() => {\n      testComponent.disabled = true;\n      fixture.detectChanges();\n      expect(radio.nativeElement.firstElementChild!.classList).not.toContain('ant-radio-checked');\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(0);\n      radio.nativeElement.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(radio.nativeElement.firstElementChild!.classList).not.toContain('ant-radio-checked');\n      expect(testComponent.value).toBe(false);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(0);\n    }));\n\n    it('should not run change detection if the radio is disabled', fakeAsync(() => {\n      testComponent.disabled = true;\n      fixture.detectChanges();\n      const appRef = TestBed.inject(ApplicationRef);\n      spyOn(appRef, 'tick');\n      const event = createMouseEvent('click');\n      spyOn(event, 'preventDefault');\n      spyOn(event, 'stopPropagation');\n      radio.nativeElement.dispatchEvent(event);\n      expect(event.preventDefault).toHaveBeenCalled();\n      expect(event.stopPropagation).toHaveBeenCalled();\n      expect(appRef.tick).not.toHaveBeenCalled();\n    }));\n\n    it('should autofocus work', () => {\n      fixture.detectChanges();\n      testComponent.autoFocus = true;\n      fixture.detectChanges();\n      expect(radio.nativeElement.querySelector('input').attributes.getNamedItem('autofocus').name).toBe('autofocus');\n      testComponent.autoFocus = false;\n      fixture.detectChanges();\n      expect(radio.nativeElement.querySelector('input').attributes.getNamedItem('autofocus')).toBe(null);\n    });\n\n    it('should focus and blur function work', () => {\n      fixture.detectChanges();\n      expect(radio.nativeElement.querySelector('input') === document.activeElement).toBe(false);\n      testComponent.nzRadioComponent.focus();\n      fixture.detectChanges();\n      expect(radio.nativeElement.querySelector('input') === document.activeElement).toBe(true);\n      testComponent.nzRadioComponent.blur();\n      fixture.detectChanges();\n      expect(radio.nativeElement.querySelector('input') === document.activeElement).toBe(false);\n    });\n  });\n\n  describe('single radio button', () => {\n    let fixture: ComponentFixture<NzTestRadioButtonComponent>;\n    let radio: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestRadioButtonComponent);\n      fixture.detectChanges();\n      radio = fixture.debugElement.query(By.directive(NzRadioComponent));\n    });\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n      expect(radio.nativeElement.classList).toContain('ant-radio-button-wrapper');\n      expect(radio.nativeElement.firstElementChild!.classList).toContain('ant-radio-button');\n      expect(radio.nativeElement.firstElementChild.lastElementChild.classList).toContain('ant-radio-button-inner');\n    });\n  });\n\n  describe('radio group', () => {\n    let fixture: ComponentFixture<NzTestRadioGroupComponent>;\n    let testComponent: NzTestRadioGroupComponent;\n    let radios: DebugElement[];\n    let radioGroup: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestRadioGroupComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n      radios = fixture.debugElement.queryAll(By.directive(NzRadioComponent));\n      radioGroup = fixture.debugElement.query(By.directive(NzRadioGroupComponent));\n    });\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n      expect(radioGroup.nativeElement.classList).toContain('ant-radio-group');\n    });\n\n    it('should click work', fakeAsync(() => {\n      fixture.detectChanges();\n      expect(testComponent.value).toBe('A');\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(0);\n      radios[1].nativeElement.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(radios[0].nativeElement.firstElementChild!.classList).not.toContain('ant-radio-button-checked');\n      expect(radios[1].nativeElement.firstElementChild!.classList).toContain('ant-radio-button-checked');\n      expect(testComponent.value).toBe('B');\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(1);\n      radios[1].nativeElement.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.value).toBe('B');\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(1);\n    }));\n\n    it('should disable work', fakeAsync(() => {\n      testComponent.disabled = true;\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(testComponent.value).toBe('A');\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(0);\n      radios[1].nativeElement.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(radios[1].nativeElement.firstElementChild!.classList).not.toContain('ant-radio-button-checked');\n      expect(testComponent.value).toBe('A');\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(0);\n    }));\n\n    it('should name work', fakeAsync(() => {\n      testComponent.name = 'test';\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(radios.every(radio => radio.nativeElement.querySelector('input').name === 'test')).toBe(true);\n    }));\n  });\n\n  describe('radio group disabled', () => {\n    let fixture: ComponentFixture<NzTestRadioGroupDisabledComponent>;\n    let testComponent: NzTestRadioGroupDisabledComponent;\n    let radios: DebugElement[];\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestRadioGroupDisabledComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n      radios = fixture.debugElement.queryAll(By.directive(NzRadioComponent));\n    });\n\n    it('should group disable work', fakeAsync(() => {\n      testComponent.disabled = true;\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.value).toBe('A');\n      radios[1].nativeElement.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(radios[1].nativeElement.firstElementChild!.classList).not.toContain('ant-radio-button-checked');\n      expect(testComponent.value).toBe('A');\n    }));\n\n    it('should single disable work', fakeAsync(() => {\n      testComponent.disabled = false;\n      fixture.detectChanges();\n      testComponent.singleDisabled = true;\n      fixture.detectChanges();\n      expect(testComponent.value).toBe('A');\n      radios[2].nativeElement.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(radios[2].nativeElement.firstElementChild!.classList).not.toContain('ant-radio-button-checked');\n      expect(testComponent.value).toBe('A');\n    }));\n  });\n\n  describe('radio group solid', () => {\n    let fixture: ComponentFixture<NzTestRadioGroupSolidComponent>;\n    let radioGroup: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestRadioGroupSolidComponent);\n      fixture.detectChanges();\n      radioGroup = fixture.debugElement.query(By.directive(NzRadioGroupComponent));\n    });\n\n    it('should support solid css', () => {\n      fixture.detectChanges();\n      expect(radioGroup.nativeElement.classList).toContain('ant-radio-group-solid');\n    });\n  });\n\n  describe('radio form', () => {\n    let fixture: ComponentFixture<NzTestRadioFormComponent>;\n    let testComponent: NzTestRadioFormComponent;\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestRadioFormComponent);\n      testComponent = fixture.componentInstance;\n    });\n\n    it('should be in pristine, untouched, and valid states and enable initially', fakeAsync(() => {\n      fixture.detectChanges();\n      flush();\n      const radio = fixture.debugElement.query(By.directive(NzRadioComponent));\n      const inputElement = radio.nativeElement.querySelector('input') as HTMLInputElement;\n      expect(radio.nativeElement.firstElementChild!.classList).not.toContain('ant-radio-disabled');\n      expect(inputElement.disabled).toBeFalsy();\n      expect(testComponent.formControl.valid).toBe(true);\n      expect(testComponent.formControl.pristine).toBe(true);\n      expect(testComponent.formControl.touched).toBe(false);\n    }));\n\n    it('should be disable if form is disable and nzDisable set to false initially', fakeAsync(() => {\n      testComponent.formControl.disable();\n      fixture.detectChanges();\n      flush();\n      const radio = fixture.debugElement.query(By.directive(NzRadioComponent));\n      const inputElement = radio.nativeElement.querySelector('input') as HTMLInputElement;\n      expect(radio.nativeElement.firstElementChild!.classList).toContain('ant-radio-disabled');\n      expect(inputElement.disabled).toBeTruthy();\n    }));\n\n    it('should set disabled work', fakeAsync(() => {\n      testComponent.disabled = true;\n      fixture.detectChanges();\n      flush();\n      const radio = fixture.debugElement.query(By.directive(NzRadioComponent));\n      const inputElement = radio.nativeElement.querySelector('input') as HTMLInputElement;\n      expect(radio.nativeElement.firstElementChild!.classList).toContain('ant-radio-disabled');\n      expect(inputElement.disabled).toBeTruthy();\n      expect(testComponent.formControl.value).toBe(false);\n      inputElement.click();\n      fixture.detectChanges();\n      expect(testComponent.formControl.value).toBe(false);\n\n      testComponent.enable();\n      fixture.detectChanges();\n      flush();\n      expect(radio.nativeElement.firstElementChild!.classList).not.toContain('ant-radio-disabled');\n      expect(inputElement.disabled).toBeFalsy();\n      inputElement.click();\n      fixture.detectChanges();\n      expect(testComponent.formControl.value).toBe(true);\n\n      testComponent.disable();\n      fixture.detectChanges();\n      flush();\n      expect(radio.nativeElement.firstElementChild!.classList).toContain('ant-radio-disabled');\n      expect(inputElement.disabled).toBeTruthy();\n      inputElement.click();\n      fixture.detectChanges();\n      expect(testComponent.formControl.value).toBe(true);\n    }));\n  });\n\n  describe('radio group form', () => {\n    let fixture: ComponentFixture<NzTestRadioGroupFormComponent>;\n    let testComponent: NzTestRadioGroupFormComponent;\n\n    beforeEach(fakeAsync(() => {\n      fixture = TestBed.createComponent(NzTestRadioGroupFormComponent);\n      testComponent = fixture.componentInstance;\n    }));\n\n    it('should be in pristine, untouched, and valid states initially', fakeAsync(() => {\n      fixture.detectChanges();\n      flush();\n      const radioGroup: NzRadioGroupComponent = fixture.debugElement.query(\n        By.directive(NzRadioGroupComponent)\n      ).componentInstance;\n      const radios = fixture.debugElement.queryAll(By.directive(NzRadioComponent));\n      const [firstRadios] = radios;\n      expect(testComponent.formControl.valid).toBe(true);\n      expect(testComponent.formControl.pristine).toBe(true);\n      expect(testComponent.formControl.touched).toBe(false);\n      expect(radioGroup.nzDisabled).toBeFalsy();\n      expect(firstRadios.componentInstance.nzDisabled).toBeTruthy();\n    }));\n\n    it('should be disable if form is disable and nzDisable set to false initially', fakeAsync(() => {\n      testComponent.formControl.disable();\n      fixture.detectChanges();\n      flush();\n      const radioGroup: NzRadioGroupComponent = fixture.debugElement.query(\n        By.directive(NzRadioGroupComponent)\n      ).componentInstance;\n      expect(radioGroup.nzDisabled).toBeTruthy();\n    }));\n\n    it('should set disabled work', fakeAsync(() => {\n      testComponent.nzDisabled = true;\n      fixture.detectChanges();\n      flush();\n      const radios = fixture.debugElement.queryAll(By.directive(NzRadioComponent));\n      const radioGroup: NzRadioGroupComponent = fixture.debugElement.query(\n        By.directive(NzRadioGroupComponent)\n      ).componentInstance;\n      expect(radioGroup.nzDisabled).toBeTruthy();\n      radios[0].nativeElement.click();\n      fixture.detectChanges();\n      expect(testComponent.formControl.value).toBe('B');\n\n      testComponent.enable();\n      fixture.detectChanges();\n      flush();\n\n      expect(radioGroup.nzDisabled).toBeFalsy();\n      radios[0].nativeElement.click();\n      fixture.detectChanges();\n      expect(testComponent.formControl.value).toBe('A');\n\n      testComponent.disable();\n      fixture.detectChanges();\n      flush();\n\n      expect(radioGroup.nzDisabled).toBeTruthy();\n      radios[1].nativeElement.click();\n      fixture.detectChanges();\n      expect(testComponent.formControl.value).toBe('A');\n    }));\n  });\n\n  describe('radio group disable form', () => {\n    it('expect not to thrown error', fakeAsync(() => {\n      expect(() => {\n        const fixture = TestBed.createComponent(NzTestRadioGroupDisabledFormComponent);\n        fixture.detectChanges();\n      }).not.toThrow();\n    }));\n  });\n\n  describe('ngModel on the `nz-radio` button', () => {\n    it('`onChange` of each `nz-radio` should emit correct values', () => {\n      const fixture = TestBed.createComponent(NzTestRadioGroupLabelNgModelComponent);\n      fixture.detectChanges();\n\n      const radios = fixture.debugElement.queryAll(By.directive(NzRadioComponent));\n\n      radios[0].nativeElement.click();\n      expect(fixture.componentInstance.items).toEqual([\n        { label: 'A', checked: true },\n        { label: 'B', checked: false },\n        { label: 'C', checked: false },\n        { label: 'D', checked: false }\n      ]);\n\n      radios[1].nativeElement.click();\n      expect(fixture.componentInstance.items).toEqual([\n        { label: 'A', checked: false },\n        { label: 'B', checked: true },\n        { label: 'C', checked: false },\n        { label: 'D', checked: false }\n      ]);\n    });\n  });\n\n  describe('RTL', () => {\n    it('should single radio className correct', () => {\n      const fixture = TestBed.createComponent(NzTestRadioSingleRtlComponent);\n      const radio = fixture.debugElement.query(By.directive(NzRadioComponent));\n      fixture.detectChanges();\n      expect(radio.nativeElement.className).toContain('ant-radio-wrapper-rtl');\n\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n      expect(radio.nativeElement.className).not.toContain('ant-radio-wrapper-rtl');\n    });\n\n    it('should radio button className correct', () => {\n      const fixture = TestBed.createComponent(NzTestRadioButtonRtlComponent);\n      const radio = fixture.debugElement.query(By.directive(NzRadioComponent));\n      fixture.detectChanges();\n      expect(radio.nativeElement.className).toContain('ant-radio-button-wrapper-rtl');\n\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n      expect(radio.nativeElement.className).not.toContain('ant-radio-button-wrapper-rtl');\n    });\n\n    it('should radio group className correct', () => {\n      const fixture = TestBed.createComponent(NzTestRadioGroupRtlComponent);\n      const radioGroup = fixture.debugElement.query(By.directive(NzRadioGroupComponent));\n      fixture.detectChanges();\n      expect(radioGroup.nativeElement.classList).toContain('ant-radio-group-rtl');\n\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n      expect(radioGroup.nativeElement.className).not.toContain('ant-radio-group-rtl');\n    });\n  });\n\n  describe('finalSize', () => {\n    let fixture: ComponentFixture<TestRadioGroupFinalSizeComponent>;\n    let radioGroupElement: HTMLElement;\n    let component: TestRadioGroupFinalSizeComponent;\n    const formSize = signal<NzSizeLDSType | undefined>(undefined);\n\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        providers: [{ provide: NZ_FORM_SIZE, useValue: formSize }]\n      });\n\n      fixture = TestBed.createComponent(TestRadioGroupFinalSizeComponent);\n      component = fixture.componentInstance;\n      radioGroupElement = fixture.debugElement.query(By.directive(NzRadioGroupComponent)).nativeElement;\n      fixture.detectChanges();\n    });\n\n    it('should prioritize formSize > nzSize', () => {\n      component.size = 'default';\n      formSize.set('large');\n      fixture.detectChanges();\n      expect(radioGroupElement.classList).toContain('ant-radio-group-large');\n\n      formSize.set('small');\n      fixture.detectChanges();\n      expect(radioGroupElement.classList).toContain('ant-radio-group-small');\n\n      formSize.set('default');\n      fixture.detectChanges();\n      expect(radioGroupElement.classList).not.toContain('ant-radio-group-large');\n      expect(radioGroupElement.classList).not.toContain('ant-radio-group-small');\n    });\n  });\n});\n\n@Component({\n  selector: 'nz-test-radio-single',\n  imports: [FormsModule, NzRadioModule],\n  template: `\n    <label\n      nz-radio\n      [(ngModel)]=\"value\"\n      (ngModelChange)=\"modelChange($event)\"\n      [nzDisabled]=\"disabled\"\n      [nzAutoFocus]=\"autoFocus\"\n    >\n      Radio\n    </label>\n  `\n})\nexport class NzTestRadioSingleComponent {\n  @ViewChild(NzRadioComponent, { static: false }) nzRadioComponent!: NzRadioComponent;\n  value = false;\n  autoFocus = false;\n  disabled = false;\n  modelChange = jasmine.createSpy('change callback');\n}\n\n@Component({\n  imports: [FormsModule, NzRadioModule],\n  template: `<label nz-radio-button>Radio</label>`\n})\nexport class NzTestRadioButtonComponent {}\n\n@Component({\n  selector: 'nz-test-radio-group',\n  imports: [FormsModule, NzRadioModule],\n  template: `\n    <nz-radio-group\n      [(ngModel)]=\"value\"\n      [nzName]=\"name\"\n      [nzDisabled]=\"disabled\"\n      (ngModelChange)=\"modelChange($event)\"\n      [nzSize]=\"size\"\n    >\n      <label nz-radio-button nzValue=\"A\">A</label>\n      <label nz-radio-button nzValue=\"B\">B</label>\n      <label nz-radio-button nzValue=\"C\">C</label>\n      <label nz-radio-button nzValue=\"D\">D</label>\n    </nz-radio-group>\n  `\n})\nexport class NzTestRadioGroupComponent {\n  size: NzSizeLDSType = 'default';\n  value = 'A';\n  disabled = false;\n  name!: string;\n  modelChange = jasmine.createSpy('change callback');\n}\n\n@Component({\n  imports: [ReactiveFormsModule, NzRadioModule],\n  template: `\n    <form>\n      <label nz-radio [formControl]=\"formControl\" [nzDisabled]=\"disabled\"></label>\n    </form>\n  `\n})\nexport class NzTestRadioFormComponent {\n  formControl = new FormControl(false);\n\n  disabled = false;\n\n  disable(): void {\n    this.formControl.disable();\n  }\n\n  enable(): void {\n    this.formControl.enable();\n  }\n}\n\n@Component({\n  imports: [ReactiveFormsModule, NzRadioModule],\n  template: `\n    <form>\n      <nz-radio-group [formControl]=\"formControl\" [nzDisabled]=\"nzDisabled\">\n        <label nz-radio-button nzValue=\"A\" [nzDisabled]=\"true\">A</label>\n        <label nz-radio-button nzValue=\"B\">B</label>\n        <label nz-radio-button nzValue=\"C\">C</label>\n        <label nz-radio-button nzValue=\"D\">D</label>\n      </nz-radio-group>\n    </form>\n  `\n})\nexport class NzTestRadioGroupFormComponent {\n  formControl = new FormControl('B');\n  nzDisabled = false;\n\n  disable(): void {\n    this.formControl.disable();\n  }\n\n  enable(): void {\n    this.formControl.enable();\n  }\n}\n\n/** https://github.com/NG-ZORRO/ng-zorro-antd/issues/1543 **/\n\n@Component({\n  imports: [FormsModule, NzRadioModule],\n  template: `\n    <nz-radio-group [(ngModel)]=\"value\" [nzName]=\"name\" [nzDisabled]=\"disabled\" [nzSize]=\"size\">\n      <label nz-radio-button nzValue=\"A\">A</label>\n      <label nz-radio-button nzValue=\"B\">B</label>\n      <label nz-radio-button nzValue=\"C\" [nzDisabled]=\"singleDisabled\">C</label>\n      <label nz-radio-button nzValue=\"D\">D</label>\n    </nz-radio-group>\n  `\n})\nexport class NzTestRadioGroupDisabledComponent {\n  size: NzSizeLDSType = 'default';\n  value = 'A';\n  disabled = false;\n  name!: string;\n  singleDisabled = false;\n}\n\n/** https://github.com/NG-ZORRO/ng-zorro-antd/issues/1735 **/\n@Component({\n  imports: [ReactiveFormsModule, NzRadioModule],\n  template: `\n    <form>\n      <nz-radio-group [formControl]=\"formControl\">\n        @for (val of radioValues; track val) {\n          <label nz-radio [nzValue]=\"val\">{{ val }}</label>\n        }\n      </nz-radio-group>\n    </form>\n  `\n})\nexport class NzTestRadioGroupDisabledFormComponent {\n  formControl = new FormControl({ value: 'B', disabled: true });\n  radioValues = ['A', 'B', 'C', 'D'];\n}\n\n@Component({\n  imports: [FormsModule, NzRadioModule],\n  template: `\n    <nz-radio-group [(ngModel)]=\"value\" nzButtonStyle=\"solid\">\n      <label nz-radio-button nzValue=\"A\">A</label>\n      <label nz-radio-button nzValue=\"B\">B</label>\n      <label nz-radio-button nzValue=\"C\" [nzDisabled]=\"singleDisabled\">C</label>\n      <label nz-radio-button nzValue=\"D\">D</label>\n    </nz-radio-group>\n  `\n})\nexport class NzTestRadioGroupSolidComponent {\n  value = 'A';\n  singleDisabled = false;\n}\n\n/** https://github.com/NG-ZORRO/ng-zorro-antd/issues/7254 */\n@Component({\n  imports: [FormsModule, NzRadioModule],\n  template: `\n    <nz-radio-group>\n      @for (item of items; track item) {\n        <label nz-radio [nzValue]=\"item.label\" [(ngModel)]=\"item.checked\">\n          {{ item.label }}\n        </label>\n      }\n    </nz-radio-group>\n  `\n})\nexport class NzTestRadioGroupLabelNgModelComponent {\n  items = [\n    {\n      label: 'A',\n      checked: false\n    },\n    {\n      label: 'B',\n      checked: false\n    },\n    {\n      label: 'C',\n      checked: false\n    },\n    {\n      label: 'D',\n      checked: false\n    }\n  ];\n}\n\n@Component({\n  imports: [BidiModule, NzTestRadioSingleComponent],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-test-radio-single />\n    </div>\n  `\n})\nexport class NzTestRadioSingleRtlComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n}\n\n@Component({\n  imports: [BidiModule, NzRadioModule],\n  template: `\n    <div [dir]=\"direction\">\n      <label nz-radio-button>Radio</label>\n    </div>\n  `\n})\nexport class NzTestRadioButtonRtlComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n}\n\n@Component({\n  imports: [BidiModule, NzTestRadioGroupComponent],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-test-radio-group />\n    </div>\n  `\n})\nexport class NzTestRadioGroupRtlComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n}\n\n@Component({\n  imports: [NzRadioModule],\n  template: `<nz-radio-group [nzSize]=\"size\" />`\n})\nexport class TestRadioGroupFinalSizeComponent {\n  size: NzSizeLDSType = 'default';\n}\n"
  },
  {
    "path": "components/radio/style/entry.less",
    "content": "@import './index.less';\n@import './patch.less';\n"
  },
  {
    "path": "components/radio/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@radio-prefix-cls: ~'@{ant-prefix}-radio';\n@radio-group-prefix-cls: ~'@{radio-prefix-cls}-group';\n@radio-inner-prefix-cls: ~'@{radio-prefix-cls}-inner';\n@radio-duration: 0.3s;\n@radio-focus-shadow: 0 0 0 3px @slider-handle-color-focus-shadow;\n@radio-button-focus-shadow: @radio-focus-shadow;\n\n.@{radio-group-prefix-cls} {\n  .reset-component();\n\n  display: inline-block;\n  font-size: 0;\n\n  .@{ant-prefix}-badge-count {\n    z-index: 1;\n  }\n\n  > .@{ant-prefix}-badge:not(:first-child) > .@{radio-prefix-cls}-button-wrapper {\n    border-left: none;\n  }\n}\n\n// 一般状态\n.@{radio-prefix-cls}-wrapper {\n  .reset-component();\n  position: relative;\n  display: inline-flex;\n  align-items: baseline;\n  margin-right: @radio-wrapper-margin-right;\n  cursor: pointer;\n\n  &-disabled {\n    cursor: not-allowed;\n  }\n\n  &::after {\n    display: inline-block;\n    width: 0;\n    overflow: hidden;\n    content: '\\a0';\n  }\n\n  &&-in-form-item {\n    input[type='radio'] {\n      width: 14px;\n      height: 14px;\n    }\n  }\n}\n\n.@{radio-prefix-cls} {\n  .reset-component();\n\n  position: relative;\n  top: @radio-top;\n  display: inline-block;\n  outline: none;\n  cursor: pointer;\n\n  .@{radio-prefix-cls}-wrapper:hover &,\n  &:hover .@{radio-inner-prefix-cls},\n  &-input:focus + .@{radio-inner-prefix-cls} {\n    border-color: @radio-dot-color;\n  }\n\n  &-input:focus + .@{radio-inner-prefix-cls} {\n    box-shadow: @radio-focus-shadow;\n  }\n\n  &-checked::after {\n    position: absolute;\n    top: 0;\n    left: 0;\n    width: 100%;\n    height: 100%;\n    border: 1px solid @radio-dot-color;\n    border-radius: 50%;\n    visibility: hidden;\n    animation: antRadioEffect 0.36s ease-in-out;\n    animation-fill-mode: both;\n    content: '';\n  }\n\n  &:hover::after,\n  .@{radio-prefix-cls}-wrapper:hover &::after {\n    visibility: visible;\n  }\n\n  &-inner {\n    &::after {\n      position: absolute;\n      top: 50%;\n      left: 50%;\n      display: block;\n      width: @radio-size;\n      height: @radio-size;\n      margin-top: -(@radio-size / 2);\n      margin-left: -(@radio-size / 2);\n      background-color: @radio-dot-color;\n      border-top: 0;\n      border-left: 0;\n      border-radius: @radio-size;\n      transform: scale(0);\n      opacity: 0;\n      transition: all @radio-duration @ease-in-out-circ;\n      content: ' ';\n    }\n\n    position: relative;\n    top: 0;\n    left: 0;\n    display: block;\n    width: @radio-size;\n    height: @radio-size;\n    background-color: @radio-button-bg;\n    border-color: @border-color-base;\n    border-style: solid;\n    border-width: @radio-border-width;\n    border-radius: 50%;\n    transition: all @radio-duration;\n  }\n\n  &-input {\n    position: absolute;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    z-index: 1;\n    cursor: pointer;\n    opacity: 0;\n  }\n\n  &&-disabled {\n    .@{radio-inner-prefix-cls} {\n      border-color: @border-color-base;\n    }\n  }\n}\n\n// 选中状态\n.@{radio-prefix-cls}-checked {\n  .@{radio-inner-prefix-cls} {\n    border-color: @radio-dot-color;\n\n    &::after {\n      transform: scale((unit(@radio-dot-size) / unit(@radio-size)));\n      opacity: 1;\n      transition: all @radio-duration @ease-in-out-circ;\n    }\n  }\n}\n\n.@{radio-prefix-cls}-disabled {\n  cursor: not-allowed;\n\n  .@{radio-inner-prefix-cls} {\n    background-color: @input-disabled-bg;\n    cursor: not-allowed;\n\n    &::after {\n      background-color: @radio-dot-disabled-color;\n    }\n  }\n\n  .@{radio-prefix-cls}-input {\n    cursor: not-allowed;\n  }\n\n  & + span {\n    color: @disabled-color;\n    cursor: not-allowed;\n  }\n}\n\nspan.@{radio-prefix-cls} + * {\n  padding-right: 8px;\n  padding-left: 8px;\n}\n\n.@{radio-prefix-cls}-button-wrapper {\n  position: relative;\n  display: inline-block;\n  height: @btn-height-base;\n  margin: 0;\n  padding: 0 @radio-button-padding-horizontal;\n  color: @radio-button-color;\n  font-size: @font-size-base;\n  line-height: @btn-height-base - 2px;\n  background: @radio-button-bg;\n  border: @border-width-base @border-style-base @border-color-base;\n  // strange align fix for chrome but works\n  // https://gw.alipayobjects.com/zos/rmsportal/VFTfKXJuogBAXcvfAUWJ.gif\n  border-top-width: @border-width-base + 0.02px;\n  border-left-width: 0;\n  cursor: pointer;\n  transition: color 0.3s, background 0.3s, border-color 0.3s, box-shadow 0.3s;\n\n  a {\n    color: @radio-button-color;\n  }\n\n  > .@{radio-prefix-cls}-button {\n    position: absolute;\n    top: 0;\n    left: 0;\n    z-index: -1;\n    width: 100%;\n    height: 100%;\n  }\n\n  .@{radio-group-prefix-cls}-large & {\n    height: @input-height-lg;\n    font-size: @font-size-lg;\n    line-height: @input-height-lg - 2px;\n  }\n\n  .@{radio-group-prefix-cls}-small & {\n    height: @input-height-sm;\n    padding: 0 @control-padding-horizontal-sm - 1px;\n    line-height: @input-height-sm - 2px;\n  }\n\n  &:not(:first-child) {\n    &::before {\n      position: absolute;\n      top: @border-width-base * -1;\n      left: -1px;\n      display: block;\n      box-sizing: content-box;\n      width: 1px;\n      height: 100%;\n      padding: @border-width-base 0;\n      background-color: @border-color-base;\n      transition: background-color 0.3s;\n      content: '';\n    }\n  }\n\n  &:first-child {\n    border-left: @border-width-base @border-style-base @border-color-base;\n    border-radius: @border-radius-base 0 0 @border-radius-base;\n  }\n\n  &:last-child {\n    border-radius: 0 @border-radius-base @border-radius-base 0;\n  }\n\n  &:first-child:last-child {\n    border-radius: @border-radius-base;\n  }\n\n  &:hover {\n    position: relative;\n    color: @radio-dot-color;\n  }\n\n  &:focus-within {\n    box-shadow: @radio-button-focus-shadow;\n  }\n\n  .@{radio-prefix-cls}-inner,\n  input[type='checkbox'],\n  input[type='radio'] {\n    width: 0;\n    height: 0;\n    opacity: 0;\n    pointer-events: none;\n  }\n\n  &-checked:not(&-disabled) {\n    z-index: 1;\n    color: @radio-dot-color;\n    background: @radio-button-checked-bg;\n    border-color: @radio-dot-color;\n\n    &::before {\n      background-color: @radio-dot-color;\n    }\n\n    &:first-child {\n      border-color: @radio-dot-color;\n    }\n\n    &:hover {\n      color: @radio-button-hover-color;\n      border-color: @radio-button-hover-color;\n\n      &::before {\n        background-color: @radio-button-hover-color;\n      }\n    }\n\n    &:active {\n      color: @radio-button-active-color;\n      border-color: @radio-button-active-color;\n\n      &::before {\n        background-color: @radio-button-active-color;\n      }\n    }\n\n    &:focus-within {\n      box-shadow: @radio-button-focus-shadow;\n    }\n  }\n\n  .@{radio-group-prefix-cls}-solid &-checked:not(&-disabled) {\n    color: @radio-solid-checked-color;\n    background: @radio-dot-color;\n    border-color: @radio-dot-color;\n\n    &:hover {\n      color: @radio-solid-checked-color;\n      background: @radio-button-hover-color;\n      border-color: @radio-button-hover-color;\n    }\n\n    &:active {\n      color: @radio-solid-checked-color;\n      background: @radio-button-active-color;\n      border-color: @radio-button-active-color;\n    }\n\n    &:focus-within {\n      box-shadow: @radio-button-focus-shadow;\n    }\n  }\n\n  &-disabled {\n    color: @disabled-color;\n    background-color: @input-disabled-bg;\n    border-color: @border-color-base;\n    cursor: not-allowed;\n\n    &:first-child,\n    &:hover {\n      color: @disabled-color;\n      background-color: @input-disabled-bg;\n      border-color: @border-color-base;\n    }\n\n    &:first-child {\n      border-left-color: @border-color-base;\n    }\n  }\n\n  &-disabled&-checked {\n    color: @radio-disabled-button-checked-color;\n    background-color: @radio-disabled-button-checked-bg;\n    border-color: @border-color-base;\n    box-shadow: none;\n  }\n}\n\n@keyframes antRadioEffect {\n  0% {\n    transform: scale(1);\n    opacity: 0.5;\n  }\n\n  100% {\n    transform: scale(1.6);\n    opacity: 0;\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/radio/style/patch.less",
    "content": ".ant-radio + span {\n  &:empty {\n    display: none;\n  }\n}\n"
  },
  {
    "path": "components/radio/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@radio-prefix-cls: ~'@{ant-prefix}-radio';\n@radio-group-prefix-cls: ~'@{radio-prefix-cls}-group';\n@radio-prefix-cls-button-wrapper: ~'@{radio-prefix-cls}-button-wrapper';\n\n.@{radio-group-prefix-cls} {\n  &&-rtl {\n    direction: rtl;\n  }\n}\n\n// 一般状态\n.@{radio-prefix-cls}-wrapper {\n  &&-rtl {\n    margin-right: 0;\n    margin-left: @radio-wrapper-margin-right;\n    direction: rtl;\n  }\n}\n\n.@{radio-prefix-cls-button-wrapper} {\n  &&-rtl {\n    border-right-width: 0;\n    border-left-width: @border-width-base;\n  }\n\n  &:not(:first-child) {\n    &::before {\n      .@{radio-prefix-cls-button-wrapper}.@{radio-prefix-cls-button-wrapper}-rtl& {\n        right: -1px;\n        left: 0;\n      }\n    }\n  }\n\n  &:first-child {\n    .@{radio-prefix-cls-button-wrapper}.@{radio-prefix-cls-button-wrapper}-rtl& {\n      border-right: @border-width-base @border-style-base @border-color-base;\n      border-radius: 0 @border-radius-base @border-radius-base 0;\n    }\n    .@{radio-prefix-cls-button-wrapper}-checked:not([class*=~\"' @{radio-prefix-cls}-button-wrapper-disabled'\"])& {\n      border-right-color: @radio-button-hover-color;\n    }\n  }\n\n  &:last-child {\n    .@{radio-prefix-cls-button-wrapper}.@{radio-prefix-cls-button-wrapper}-rtl& {\n      border-radius: @border-radius-base 0 0 @border-radius-base;\n    }\n  }\n\n  &-disabled {\n    &:first-child {\n      .@{radio-prefix-cls-button-wrapper}.@{radio-prefix-cls-button-wrapper}-rtl& {\n        border-right-color: @border-color-base;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/rate/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n最简单的用法。\n\n## en-US\n\nThe simplest usage.\n"
  },
  {
    "path": "components/rate/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzRateModule } from 'ng-zorro-antd/rate';\n\n@Component({\n  selector: 'nz-demo-rate-basic',\n  imports: [FormsModule, NzRateModule],\n  template: `<nz-rate [ngModel]=\"0\" />`\n})\nexport class NzDemoRateBasicComponent {}\n"
  },
  {
    "path": "components/rate/demo/character.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 其他字符\n  en-US: Other Character\n---\n\n## zh-CN\n\n可以将星星替换为其他字符，比如字母，数字，字体图标甚至中文。\n\n## en-US\n\nReplace the default star to other character like alphabet, digit, iconfont or even Chinese word.\n"
  },
  {
    "path": "components/rate/demo/character.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzRateModule } from 'ng-zorro-antd/rate';\n\n@Component({\n  selector: 'nz-demo-rate-character',\n  imports: [FormsModule, NzIconModule, NzRateModule],\n  template: `\n    <nz-rate [ngModel]=\"0\" nzAllowHalf [nzCharacter]=\"characterIcon\" />\n    <br />\n    <nz-rate [ngModel]=\"0\" nzAllowHalf class=\"large\" [nzCharacter]=\"characterEnLetter\" />\n    <br />\n    <nz-rate [ngModel]=\"0\" nzAllowHalf [nzCharacter]=\"characterZhLetter\" />\n    <ng-template #characterIcon><nz-icon nzType=\"heart\" /></ng-template>\n    <ng-template #characterZhLetter>好</ng-template>\n    <ng-template #characterEnLetter>A</ng-template>\n  `,\n  styles: `\n    .large ::ng-deep .ant-rate-star {\n      font-size: 36px;\n    }\n  `\n})\nexport class NzDemoRateCharacterComponent {}\n"
  },
  {
    "path": "components/rate/demo/clear.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 清除\n  en-US: Clear star\n---\n\n## zh-CN\n\n支持允许或者禁用清除。\n\n## en-US\n\nSupport set allow to clear star when click again.\n"
  },
  {
    "path": "components/rate/demo/clear.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzRateModule } from 'ng-zorro-antd/rate';\n\n@Component({\n  selector: 'nz-demo-rate-clear',\n  imports: [FormsModule, NzRateModule],\n  template: `\n    <nz-rate [(ngModel)]=\"value\" nzAllowHalf />\n    <span class=\"ant-rate-text\">allowClear: true</span>\n    <br />\n    <nz-rate [(ngModel)]=\"value\" nzAllowHalf [nzAllowClear]=\"false\" />\n    <span class=\"ant-rate-text\">allowClear: false</span>\n  `\n})\nexport class NzDemoRateClearComponent {\n  value = 0;\n}\n"
  },
  {
    "path": "components/rate/demo/customize.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 自定义字符\n  en-US: Customize Character\n---\n\n## zh-CN\n\n可以通过索引自定义每一个字符。\n\n## en-US\n\nEach character can be customized by index.\n"
  },
  {
    "path": "components/rate/demo/customize.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzRateModule } from 'ng-zorro-antd/rate';\n\n@Component({\n  selector: 'nz-demo-rate-customize',\n  imports: [FormsModule, NzIconModule, NzRateModule],\n  template: `\n    <nz-rate [ngModel]=\"2\" [nzCharacter]=\"characterNumber\" />\n    <br />\n    <nz-rate [ngModel]=\"3\" [nzCharacter]=\"characterIcon\" />\n    <br />\n    <ng-template #characterNumber let-index>\n      {{ index + 1 }}\n    </ng-template>\n    <ng-template #characterIcon let-index>\n      @switch (index) {\n        @case (0) {\n          <nz-icon nzType=\"frown\" />\n        }\n        @case (1) {\n          <nz-icon nzType=\"frown\" />\n        }\n        @case (2) {\n          <nz-icon nzType=\"meh\" />\n        }\n        @case (3) {\n          <nz-icon nzType=\"smile\" />\n        }\n        @case (4) {\n          <nz-icon nzType=\"smile\" />\n        }\n      }\n    </ng-template>\n  `,\n  styles: `\n    .large ::ng-deep .ant-rate-star {\n      font-size: 36px;\n    }\n  `\n})\nexport class NzDemoRateCustomizeComponent {}\n"
  },
  {
    "path": "components/rate/demo/disabled.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 只读\n  en-US: Read only\n---\n\n## zh-CN\n\n只读，无法进行鼠标交互。\n\n## en-US\n\nRead only, can't use mouse to interact.\n"
  },
  {
    "path": "components/rate/demo/disabled.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzRateModule } from 'ng-zorro-antd/rate';\n\n@Component({\n  selector: 'nz-demo-rate-disabled',\n  imports: [FormsModule, NzRateModule],\n  template: `<nz-rate [ngModel]=\"2\" nzDisabled />`\n})\nexport class NzDemoRateDisabledComponent {}\n"
  },
  {
    "path": "components/rate/demo/half.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 半星\n  en-US: Half star\n---\n\n## zh-CN\n\n支持选中半星。\n\n## en-US\n\nSupport select half star.\n"
  },
  {
    "path": "components/rate/demo/half.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzRateModule } from 'ng-zorro-antd/rate';\n\n@Component({\n  selector: 'nz-demo-rate-half',\n  imports: [FormsModule, NzRateModule],\n  template: `<nz-rate [ngModel]=\"2.5\" nzAllowHalf />`\n})\nexport class NzDemoRateHalfComponent {}\n"
  },
  {
    "path": "components/rate/demo/text.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 文案展现\n  en-US: Show copywriting\n---\n\n## zh-CN\n\n给评分组件加上文案展示。\n\n## en-US\n\nAdd copywriting in rate components.\n"
  },
  {
    "path": "components/rate/demo/text.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzRateModule } from 'ng-zorro-antd/rate';\n\n@Component({\n  selector: 'nz-demo-rate-text',\n  imports: [FormsModule, NzRateModule],\n  template: `\n    <nz-rate [(ngModel)]=\"value\" [nzTooltips]=\"tooltips\" />\n    @if (value) {\n      <span class=\"ant-rate-text\">{{ value ? tooltips[value - 1] : '' }}</span>\n    }\n  `\n})\nexport class NzDemoRateTextComponent {\n  readonly tooltips = ['terrible', 'bad', 'normal', 'good', 'wonderful'];\n  value = 3;\n}\n"
  },
  {
    "path": "components/rate/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Entry\ntitle: Rate\ncover: 'https://gw.alipayobjects.com/zos/alicdn/R5uiIWmxe/Rate.svg'\ndescription: Used for rating operation on something.\n---\n\n## When To Use\n\n- Show evaluation.\n- A quick rating operation on something.\n\n## API\n\n### nz-rate\n\n| Property            | Description                             | type                          | Default                     | Global Config |\n| ------------------- | --------------------------------------- | ----------------------------- | --------------------------- | ------------- |\n| `[nzAllowClear]`    | whether to allow clear when click again | `boolean`                     | `true`                      | ✅            |\n| `[nzAllowHalf]`     | whether to allow semi selection         | `boolean`                     | `false`                     | ✅            |\n| `[nzAutoFocus]`     | get focus when component mounted        | `boolean`                     | `false`                     |\n| `[nzCharacter]`     | custom character of rate                | `TemplateRef<void>`           | `<nz-icon nzType=\"star\" />` |\n| `[nzCount]`         | star count                              | `number`                      | `5`                         |\n| `[nzDisabled]`      | read only, unable to interact           | `boolean`                     | `false`                     |\n| `[nzTooltips]`      | Customize tooltip by each character     | `string[]`                    | `[]`                        |\n| `[ngModel]`         | current value , double binding          | `number`                      | -                           |\n| `(ngModelChange)`   | callback when select value              | `EventEmitter<number>`        | -                           |\n| `(nzOnBlur)`        | callback when component lose focus      | `EventEmitter<FocusEvent>`    | -                           |\n| `(nzOnFocus)`       | callback when component get focus       | `EventEmitter<FocusEvent>`    | -                           |\n| `(nzOnHoverChange)` | callback when hover / leave item        | `EventEmitter<number>`        | -                           |\n| `(nzOnKeyDown)`     | callback when keydown on component      | `EventEmitter<KeyboardEvent>` | -                           |\n\n#### Methods\n\n| Name      | Description  |\n| --------- | ------------ |\n| `blur()`  | remove focus |\n| `focus()` | get focus    |\n"
  },
  {
    "path": "components/rate/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 评分\ntype: 数据录入\ntitle: Rate\ncover: 'https://gw.alipayobjects.com/zos/alicdn/R5uiIWmxe/Rate.svg'\ndescription: 用于对事物进行评分操作。\n---\n\n## 何时使用\n\n- 对评价进行展示。\n- 对事物进行快速的评级操作。\n\n## API\n\n### nz-rate\n\n| 属性                | 说明                     | 类型                          | 默认值                      | 支持全局配置 |\n| ------------------- | ------------------------ | ----------------------------- | --------------------------- | ------------ |\n| `[nzAllowClear]`    | 是否允许再次点击后清除   | `boolean`                     | `true`                      | ✅           |\n| `[nzAllowHalf]`     | 是否允许半选             | `boolean`                     | `false`                     | ✅           |\n| `[nzAutoFocus]`     | 自动获取焦点             | `boolean`                     | `false`                     |\n| `[nzCharacter]`     | 自定义字符               | `TemplateRef<void>`           | `<nz-icon nzType=\"star\" />` |\n| `[nzCount]`         | star 总数                | `number`                      | `5`                         |\n| `[nzDisabled]`      | 只读，无法进行交互       | `boolean`                     | `false`                     |\n| `[nzTooltips]`      | 自定义每项的提示信息     | `string[]`                    | `[]`                        |\n| `[ngModel]`         | 当前数，可以双向绑定     | `number`                      | `0`                         |\n| `(ngModelChange)`   | 当前数改变时的回调       | `EventEmitter<number>`        | -                           |\n| `(nzOnBlur)`        | 失去焦点时的回调         | `EventEmitter<FocusEvent>`    | -                           |\n| `(nzOnFocus)`       | 获取焦点时的回调         | `EventEmitter<FocusEvent>`    | -                           |\n| `(nzOnHoverChange)` | 鼠标经过时数值变化的回调 | `EventEmitter<number>`        | -                           |\n| `(nzOnKeyDown)`     | 按键回调                 | `EventEmitter<KeyboardEvent>` | -                           |\n\n#### 方法\n\n| 名称      | 描述     |\n| --------- | -------- |\n| `blur()`  | 移除焦点 |\n| `focus()` | 获取焦点 |\n"
  },
  {
    "path": "components/rate/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/rate/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/rate/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './rate.component';\nexport * from './rate.module';\nexport * from './rate-item.component';\n"
  },
  {
    "path": "components/rate/rate-item.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  EventEmitter,\n  Input,\n  Output,\n  TemplateRef,\n  ViewEncapsulation,\n  booleanAttribute\n} from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: '[nz-rate-item]',\n  exportAs: 'nzRateItem',\n  template: `\n    <div\n      class=\"ant-rate-star-second\"\n      (mouseover)=\"hoverRate(false); $event.stopPropagation()\"\n      (click)=\"clickRate(false)\"\n    >\n      <ng-template\n        [ngTemplateOutlet]=\"character || defaultCharacter\"\n        [ngTemplateOutletContext]=\"{ $implicit: index }\"\n      />\n    </div>\n    <div class=\"ant-rate-star-first\" (mouseover)=\"hoverRate(true); $event.stopPropagation()\" (click)=\"clickRate(true)\">\n      <ng-template\n        [ngTemplateOutlet]=\"character || defaultCharacter\"\n        [ngTemplateOutletContext]=\"{ $implicit: index }\"\n      />\n    </div>\n\n    <ng-template #defaultCharacter>\n      <nz-icon nzType=\"star\" nzTheme=\"fill\" />\n    </ng-template>\n  `,\n  imports: [NgTemplateOutlet, NzIconModule]\n})\nexport class NzRateItemComponent {\n  @Input() character!: TemplateRef<{ $implicit: number }>;\n  @Input() index = 0;\n  @Input({ transform: booleanAttribute }) allowHalf: boolean = false;\n  @Output() readonly itemHover = new EventEmitter<boolean>();\n  @Output() readonly itemClick = new EventEmitter<boolean>();\n\n  hoverRate(isHalf: boolean): void {\n    this.itemHover.next(isHalf && this.allowHalf);\n  }\n\n  clickRate(isHalf: boolean): void {\n    this.itemClick.next(isHalf && this.allowHalf);\n  }\n}\n"
  },
  {
    "path": "components/rate/rate.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport { LEFT_ARROW, RIGHT_ARROW } from '@angular/cdk/keycodes';\nimport {\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DestroyRef,\n  ElementRef,\n  EventEmitter,\n  forwardRef,\n  inject,\n  Input,\n  NgZone,\n  numberAttribute,\n  OnChanges,\n  OnInit,\n  Output,\n  Renderer2,\n  SimpleChanges,\n  TemplateRef,\n  ViewChild,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\n\nimport { NzConfigKey, onConfigChangeEventForComponent, WithConfig } from 'ng-zorro-antd/core/config';\nimport { NgClassType, OnChangeType, OnTouchedType } from 'ng-zorro-antd/core/types';\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\nimport { NzTooltipModule } from 'ng-zorro-antd/tooltip';\n\nimport { NzRateItemComponent } from './rate-item.component';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'rate';\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-rate',\n  exportAs: 'nzRate',\n  template: `\n    <ul\n      #ulElement\n      class=\"ant-rate\"\n      [class.ant-rate-disabled]=\"nzDisabled\"\n      [class.ant-rate-rtl]=\"dir === 'rtl'\"\n      [class]=\"classMap\"\n      (keydown)=\"onKeyDown($event); $event.preventDefault()\"\n      (mouseleave)=\"onRateLeave(); $event.stopPropagation()\"\n      [tabindex]=\"nzDisabled ? -1 : 1\"\n    >\n      @for (star of starArray; track star) {\n        <li\n          class=\"ant-rate-star\"\n          [class]=\"starStyleArray[$index] || ''\"\n          nz-tooltip\n          [nzTooltipTitle]=\"nzTooltips[$index]\"\n        >\n          <div\n            nz-rate-item\n            [allowHalf]=\"nzAllowHalf\"\n            [character]=\"nzCharacter\"\n            [index]=\"$index\"\n            (itemHover)=\"onItemHover($index, $event)\"\n            (itemClick)=\"onItemClick($index, $event)\"\n          ></div>\n        </li>\n      }\n    </ul>\n  `,\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => NzRateComponent),\n      multi: true\n    }\n  ],\n  imports: [NzTooltipModule, NzRateItemComponent]\n})\nexport class NzRateComponent implements OnInit, ControlValueAccessor, OnChanges {\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  private readonly ngZone = inject(NgZone);\n  private readonly renderer = inject(Renderer2);\n  private readonly cdr = inject(ChangeDetectorRef);\n  private readonly directionality = inject(Directionality);\n  private readonly destroyRef = inject(DestroyRef);\n\n  @ViewChild('ulElement', { static: true }) ulElement!: ElementRef<HTMLUListElement>;\n\n  @Input({ transform: booleanAttribute }) @WithConfig() nzAllowClear: boolean = true;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzAllowHalf: boolean = false;\n  @Input({ transform: booleanAttribute }) nzDisabled: boolean = false;\n  @Input({ transform: booleanAttribute }) nzAutoFocus: boolean = false;\n  @Input() nzCharacter!: TemplateRef<{ $implicit: number }>;\n  @Input({ transform: numberAttribute }) nzCount: number = 5;\n  @Input() nzTooltips: string[] = [];\n  @Output() readonly nzOnBlur = new EventEmitter<FocusEvent>();\n  @Output() readonly nzOnFocus = new EventEmitter<FocusEvent>();\n  @Output() readonly nzOnHoverChange = new EventEmitter<number>();\n  @Output() readonly nzOnKeyDown = new EventEmitter<KeyboardEvent>();\n\n  classMap: NgClassType = {};\n  starArray: number[] = [];\n  starStyleArray: NgClassType[] = [];\n  dir: Direction = 'ltr';\n\n  private hasHalf = false;\n  private hoverValue = 0;\n  private isFocused = false;\n  private _value = 0;\n  private isNzDisableFirstChange: boolean = true;\n\n  get nzValue(): number {\n    return this._value;\n  }\n\n  set nzValue(input: number) {\n    if (this._value === input) {\n      return;\n    }\n\n    this._value = input;\n    this.hasHalf = !Number.isInteger(input) && this.nzAllowHalf;\n    this.hoverValue = Math.ceil(input);\n  }\n\n  constructor() {\n    onConfigChangeEventForComponent(NZ_CONFIG_MODULE_NAME, () => this.cdr.markForCheck());\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzAutoFocus, nzCount, nzValue } = changes;\n\n    if (nzAutoFocus && !nzAutoFocus.isFirstChange()) {\n      const el = this.ulElement.nativeElement;\n      if (this.nzAutoFocus && !this.nzDisabled) {\n        this.renderer.setAttribute(el, 'autofocus', 'autofocus');\n      } else {\n        this.renderer.removeAttribute(el, 'autofocus');\n      }\n    }\n\n    if (nzCount) {\n      this.updateStarArray();\n    }\n\n    if (nzValue) {\n      this.updateStarStyle();\n    }\n  }\n\n  ngOnInit(): void {\n    this.directionality.change.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((direction: Direction) => {\n      this.dir = direction;\n      this.cdr.detectChanges();\n    });\n\n    this.dir = this.directionality.value;\n\n    fromEventOutsideAngular<FocusEvent>(this.ulElement.nativeElement, 'focus')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(event => {\n        this.isFocused = true;\n        if (this.nzOnFocus.observers.length) {\n          this.ngZone.run(() => this.nzOnFocus.emit(event));\n        }\n      });\n\n    fromEventOutsideAngular<FocusEvent>(this.ulElement.nativeElement, 'blur')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(event => {\n        this.isFocused = false;\n        if (this.nzOnBlur.observers.length) {\n          this.ngZone.run(() => this.nzOnBlur.emit(event));\n        }\n      });\n  }\n\n  onItemClick(index: number, isHalf: boolean): void {\n    if (this.nzDisabled) {\n      return;\n    }\n\n    this.hoverValue = index + 1;\n\n    const actualValue = isHalf ? index + 0.5 : index + 1;\n\n    if (this.nzValue === actualValue) {\n      if (this.nzAllowClear) {\n        this.nzValue = 0;\n        this.onChange(this.nzValue);\n      }\n    } else {\n      this.nzValue = actualValue;\n      this.onChange(this.nzValue);\n    }\n\n    this.updateStarStyle();\n  }\n\n  onItemHover(index: number, isHalf: boolean): void {\n    if (this.nzDisabled) {\n      return;\n    }\n    if (this.hoverValue !== index + 1 || isHalf !== this.hasHalf) {\n      this.hoverValue = index + 1;\n      this.hasHalf = isHalf;\n      this.updateStarStyle();\n    }\n    this.nzOnHoverChange.emit(this.hoverValue);\n  }\n\n  onRateLeave(): void {\n    this.hasHalf = !Number.isInteger(this.nzValue);\n    this.hoverValue = Math.ceil(this.nzValue);\n    this.nzOnHoverChange.emit(this.hoverValue);\n    this.updateStarStyle();\n  }\n\n  focus(): void {\n    this.ulElement.nativeElement.focus();\n  }\n\n  blur(): void {\n    this.ulElement.nativeElement.blur();\n  }\n\n  onKeyDown(e: KeyboardEvent): void {\n    const oldVal = this.nzValue;\n\n    if (e.keyCode === RIGHT_ARROW && this.nzValue < this.nzCount) {\n      this.nzValue += this.nzAllowHalf ? 0.5 : 1;\n    } else if (e.keyCode === LEFT_ARROW && this.nzValue > 0) {\n      this.nzValue -= this.nzAllowHalf ? 0.5 : 1;\n    }\n\n    if (oldVal !== this.nzValue) {\n      this.onChange(this.nzValue);\n      this.nzOnKeyDown.emit(e);\n      this.updateStarStyle();\n      this.cdr.markForCheck();\n    }\n  }\n\n  private updateStarArray(): void {\n    this.starArray = Array(this.nzCount)\n      .fill(0)\n      .map((_, i) => i);\n\n    this.updateStarStyle();\n  }\n\n  private updateStarStyle(): void {\n    this.starStyleArray = this.starArray.map(i => {\n      const prefix = 'ant-rate-star';\n      const value = i + 1;\n      return {\n        [`${prefix}-full`]: value < this.hoverValue || (!this.hasHalf && value === this.hoverValue),\n        [`${prefix}-half`]: this.hasHalf && value === this.hoverValue,\n        [`${prefix}-active`]: this.hasHalf && value === this.hoverValue,\n        [`${prefix}-zero`]: value > this.hoverValue,\n        [`${prefix}-focused`]: this.hasHalf && value === this.hoverValue && this.isFocused\n      };\n    });\n  }\n\n  writeValue(value: number | null): void {\n    this.nzValue = value || 0;\n    this.updateStarArray();\n    this.cdr.markForCheck();\n  }\n\n  setDisabledState(isDisabled: boolean): void {\n    this.nzDisabled = (this.isNzDisableFirstChange && this.nzDisabled) || isDisabled;\n    this.isNzDisableFirstChange = false;\n    this.cdr.markForCheck();\n  }\n\n  registerOnChange(fn: OnChangeType): void {\n    this.onChange = fn;\n  }\n\n  registerOnTouched(fn: OnTouchedType): void {\n    this.onTouched = fn;\n  }\n\n  onChange: (value: number) => void = () => null;\n  onTouched: () => void = () => null;\n}\n"
  },
  {
    "path": "components/rate/rate.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzRateItemComponent } from './rate-item.component';\nimport { NzRateComponent } from './rate.component';\n\n@NgModule({\n  imports: [NzRateComponent, NzRateItemComponent],\n  exports: [NzRateComponent]\n})\nexport class NzRateModule {}\n"
  },
  {
    "path": "components/rate/rate.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport { LEFT_ARROW, RIGHT_ARROW } from '@angular/cdk/keycodes';\nimport { Component, DebugElement, provideZoneChangeDetection, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, flush, TestBed } from '@angular/core/testing';\nimport { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\n\nimport { dispatchFakeEvent, dispatchKeyboardEvent } from 'ng-zorro-antd/core/testing';\n\nimport { NzRateComponent } from './rate.component';\nimport { NzRateModule } from './rate.module';\n\ndescribe('rate', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  describe('basic rate', () => {\n    let fixture: ComponentFixture<NzTestRateBasicComponent>;\n    let testComponent: NzTestRateBasicComponent;\n    let rate: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestRateBasicComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n      rate = fixture.debugElement.query(By.directive(NzRateComponent));\n    });\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n      expect(rate.nativeElement.firstElementChild!.classList).toContain('ant-rate');\n    });\n\n    it('should set ngModel work', fakeAsync(() => {\n      fixture.detectChanges();\n      const children = Array.prototype.slice.call(rate.nativeElement.firstElementChild.children);\n      expect(children.every((item: HTMLElement) => item.classList.contains('ant-rate-star-zero'))).toBe(true);\n      testComponent.value = 5;\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(children.every((item: HTMLElement) => item.classList.contains('ant-rate-star-full'))).toBe(true);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(0);\n    }));\n\n    it('should click work', fakeAsync(() => {\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(0);\n      rate.nativeElement.firstElementChild.children[3].firstElementChild.firstElementChild.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(4);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(1);\n    }));\n\n    it('should allow half work', fakeAsync(() => {\n      testComponent.allowHalf = false;\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(0);\n      testComponent.value = 3.5;\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(rate.nativeElement.firstElementChild.children[3].classList).toContain('ant-rate-star-full');\n      expect(rate.nativeElement.firstElementChild.children[4].classList).toContain('ant-rate-star-zero');\n      flush();\n\n      testComponent.allowHalf = true;\n      testComponent.value = 0;\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      rate.nativeElement.firstElementChild.children[3].firstElementChild.children[1].click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(3.5);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(1);\n    }));\n\n    it('should allow clear work', fakeAsync(() => {\n      testComponent.allowClear = false;\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(0);\n      rate.nativeElement.firstElementChild.children[3].firstElementChild.firstElementChild.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(4);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(1);\n      rate.nativeElement.firstElementChild.children[3].firstElementChild.firstElementChild.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(4);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(1);\n      testComponent.allowClear = true;\n      fixture.detectChanges();\n      rate.nativeElement.firstElementChild.children[3].firstElementChild.firstElementChild.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(0);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(2);\n    }));\n\n    it('should disable work', fakeAsync(() => {\n      testComponent.disabled = true;\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(0);\n      rate.nativeElement.firstElementChild.children[3].firstElementChild.firstElementChild.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(0);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(0);\n    }));\n\n    it('should count work', fakeAsync(() => {\n      fixture.detectChanges();\n      expect(rate.nativeElement.firstElementChild.children.length).toBe(5);\n      expect(testComponent.value).toBe(0);\n      rate.nativeElement.firstElementChild.children[3].firstElementChild.firstElementChild.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(4);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(1);\n      testComponent.count = 10;\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(rate.nativeElement.firstElementChild.children.length).toBe(10);\n      expect(testComponent.value).toBe(4);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(1);\n    }));\n\n    it('should autofocus work', () => {\n      fixture.detectChanges();\n      testComponent.autoFocus = true;\n      fixture.detectChanges();\n      expect(rate.nativeElement.querySelector('ul').attributes.getNamedItem('autofocus').name).toBe('autofocus');\n      testComponent.autoFocus = false;\n      fixture.detectChanges();\n      expect(rate.nativeElement.querySelector('ul').attributes.getNamedItem('autofocus')).toBe(null);\n    });\n\n    it('should focus and blur function work', () => {\n      fixture.detectChanges();\n      expect(rate.nativeElement.querySelector('ul') === document.activeElement).toBe(false);\n      testComponent.nzRateComponent.focus();\n      fixture.detectChanges();\n      expect(rate.nativeElement.querySelector('ul') === document.activeElement).toBe(true);\n      testComponent.nzRateComponent.blur();\n      fixture.detectChanges();\n      expect(rate.nativeElement.querySelector('ul') === document.activeElement).toBe(false);\n    });\n\n    it('should hover rate work', () => {\n      fixture.detectChanges();\n      dispatchFakeEvent(\n        rate.nativeElement.firstElementChild.children[3].firstElementChild.firstElementChild,\n        'mouseover'\n      );\n      fixture.detectChanges();\n      expect(rate.nativeElement.firstElementChild.children[3].classList).toContain('ant-rate-star-full');\n      expect(testComponent.onHoverChange).toHaveBeenCalledWith(4);\n      expect(testComponent.onHoverChange).toHaveBeenCalledTimes(1);\n      dispatchFakeEvent(rate.nativeElement.firstElementChild.children[3].firstElementChild, 'mouseover');\n      fixture.detectChanges();\n      expect(testComponent.onHoverChange).toHaveBeenCalledTimes(1);\n      dispatchFakeEvent(rate.nativeElement.firstElementChild, 'mouseleave');\n      fixture.detectChanges();\n      expect(testComponent.onHoverChange).toHaveBeenCalledTimes(2);\n      expect(rate.nativeElement.firstElementChild.children[3].classList).toContain('ant-rate-star-zero');\n      testComponent.disabled = true;\n      fixture.detectChanges();\n      dispatchFakeEvent(rate.nativeElement.firstElementChild.children[2].firstElementChild, 'mouseover');\n      expect(testComponent.onHoverChange).toHaveBeenCalledTimes(2);\n    });\n\n    it('should keydown work', () => {\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(0);\n      dispatchKeyboardEvent(rate.nativeElement.firstElementChild, 'keydown', LEFT_ARROW);\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(0);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(0);\n      dispatchKeyboardEvent(rate.nativeElement.firstElementChild, 'keydown', RIGHT_ARROW);\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(1);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(1);\n      dispatchKeyboardEvent(rate.nativeElement.firstElementChild, 'keydown', LEFT_ARROW);\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(0);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(2);\n      testComponent.allowHalf = true;\n      fixture.detectChanges();\n      dispatchKeyboardEvent(rate.nativeElement.firstElementChild, 'keydown', RIGHT_ARROW);\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(0.5);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(3);\n      dispatchKeyboardEvent(rate.nativeElement.firstElementChild, 'keydown', LEFT_ARROW);\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(0);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(4);\n    });\n\n    it('should right keydown not dispatch change reached limit', fakeAsync(() => {\n      testComponent.value = 5;\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      dispatchKeyboardEvent(rate.nativeElement.firstElementChild, 'keydown', RIGHT_ARROW);\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(5);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(0);\n    }));\n  });\n\n  describe('rate form', () => {\n    let fixture: ComponentFixture<NzTestRateFormComponent>;\n    let testComponent: NzTestRateFormComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestRateFormComponent);\n      testComponent = fixture.componentInstance;\n    });\n\n    it('should be in pristine, untouched, and valid states and enable initially', fakeAsync(() => {\n      fixture.detectChanges();\n      flush();\n      const rate = fixture.debugElement.query(By.directive(NzRateComponent));\n      expect(testComponent.formControl.valid).toBe(true);\n      expect(testComponent.formControl.pristine).toBe(true);\n      expect(testComponent.formControl.touched).toBe(false);\n      expect(rate.nativeElement.firstElementChild!.classList).not.toContain('ant-rate-disabled');\n    }));\n\n    it('should be disable if form is enable and nzDisable set to true initially', fakeAsync(() => {\n      testComponent.disabled = true;\n      fixture.detectChanges();\n      flush();\n      const rate = fixture.debugElement.query(By.directive(NzRateComponent));\n      expect(rate.nativeElement.firstElementChild!.classList).toContain('ant-rate-disabled');\n    }));\n\n    it('should be disable if form is disable and nzDisable set to false initially', fakeAsync(() => {\n      testComponent.disable();\n      fixture.detectChanges();\n      flush();\n      const rate = fixture.debugElement.query(By.directive(NzRateComponent));\n      expect(rate.nativeElement.firstElementChild!.classList).toContain('ant-rate-disabled');\n    }));\n\n    it('should set disabled work', fakeAsync(() => {\n      testComponent.disabled = true;\n      fixture.detectChanges();\n      flush();\n\n      const rate = fixture.debugElement.query(By.directive(NzRateComponent));\n      expect(rate.nativeElement.firstElementChild!.classList).toContain('ant-rate-disabled');\n      expect(testComponent.formControl.value).toBe(1);\n      rate.nativeElement.firstElementChild.children[3].firstElementChild.firstElementChild.click();\n      fixture.detectChanges();\n      expect(testComponent.formControl.value).toBe(1);\n\n      testComponent.enable();\n      fixture.detectChanges();\n      flush();\n      expect(rate.nativeElement.firstElementChild!.classList).not.toContain('ant-rate-disabled');\n      rate.nativeElement.firstElementChild.children[3].firstElementChild.firstElementChild.click();\n      fixture.detectChanges();\n      expect(testComponent.formControl.value).toBe(4);\n\n      testComponent.disable();\n      fixture.detectChanges();\n      flush();\n      expect(rate.nativeElement.firstElementChild!.classList).toContain('ant-rate-disabled');\n      rate.nativeElement.firstElementChild.children[3].firstElementChild.firstElementChild.click();\n      fixture.detectChanges();\n      expect(testComponent.formControl.value).toBe(4);\n    }));\n  });\n\n  describe('RTL', () => {\n    let fixture: ComponentFixture<NzTestRateRtlComponent>;\n    let rate: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestRateRtlComponent);\n      fixture.detectChanges();\n      rate = fixture.debugElement.query(By.directive(NzRateComponent));\n    });\n\n    it('should className correct on dir change', fakeAsync(() => {\n      fixture.detectChanges();\n      expect(rate.nativeElement.firstElementChild!.classList).toContain('ant-rate-rtl');\n\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n      expect(rate.nativeElement.firstElementChild!.classList).not.toContain('ant-rate-rtl');\n    }));\n  });\n\n  describe('rate character', () => {\n    let fixture: ComponentFixture<NzTestRateCharacterComponent>;\n    let rate: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestRateCharacterComponent);\n      fixture.detectChanges();\n      rate = fixture.debugElement.query(By.directive(NzRateComponent));\n    });\n\n    it('should nzCharacter work', () => {\n      fixture.detectChanges();\n      const children = Array.prototype.slice.call(rate.nativeElement.firstElementChild.children) as HTMLElement[];\n      children.forEach((e, index) => {\n        expect(e.querySelector('.ant-rate-star-first')!.textContent).toContain(`${index + 1}`);\n        expect(e.querySelector('.ant-rate-star-second')!.textContent).toContain(`${index + 1}`);\n      });\n    });\n  });\n});\n\n@Component({\n  selector: 'nz-test-rate',\n  imports: [FormsModule, NzRateModule],\n  template: `\n    <nz-rate\n      [(ngModel)]=\"value\"\n      (ngModelChange)=\"modelChange($event)\"\n      (nzOnBlur)=\"onBlur($event)\"\n      (nzOnFocus)=\"onFocus($event)\"\n      (nzOnHoverChange)=\"onHoverChange($event)\"\n      (nzOnKeyDown)=\"onKeyDown($event)\"\n      [nzCount]=\"count\"\n      [nzAllowHalf]=\"allowHalf\"\n      [nzAllowClear]=\"allowClear\"\n      [nzDisabled]=\"disabled\"\n      [nzAutoFocus]=\"autoFocus\"\n    />\n  `\n})\nexport class NzTestRateBasicComponent {\n  @ViewChild(NzRateComponent, { static: false }) nzRateComponent!: NzRateComponent;\n  count = 5;\n  autoFocus = false;\n  allowHalf = false;\n  allowClear = false;\n  disabled = false;\n  value = 0;\n  modelChange = jasmine.createSpy('model change callback');\n  onBlur = jasmine.createSpy('blur callback');\n  onFocus = jasmine.createSpy('focus callback');\n  onHoverChange = jasmine.createSpy('hover change callback');\n  onKeyDown = jasmine.createSpy('keydown callback');\n}\n\n@Component({\n  imports: [ReactiveFormsModule, NzRateModule],\n  template: `\n    <form>\n      <nz-rate [formControl]=\"formControl\" [nzDisabled]=\"disabled\" />\n    </form>\n  `\n})\nexport class NzTestRateFormComponent {\n  formControl = new FormControl(1);\n\n  disabled = false;\n\n  disable(): void {\n    this.formControl.disable();\n  }\n\n  enable(): void {\n    this.formControl.enable();\n  }\n}\n\n@Component({\n  imports: [BidiModule, NzTestRateBasicComponent],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-test-rate />\n    </div>\n  `\n})\nexport class NzTestRateRtlComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n}\n\n@Component({\n  selector: 'nz-test-rate-character',\n  imports: [FormsModule, NzRateModule],\n  template: `\n    <nz-rate [(ngModel)]=\"value\" [nzCharacter]=\"characterTpl\" />\n    <ng-template #characterTpl let-index>\n      {{ index + 1 }}\n    </ng-template>\n  `\n})\nexport class NzTestRateCharacterComponent {\n  @ViewChild(NzRateComponent, { static: false }) nzRateComponent!: NzRateComponent;\n  value = 5;\n}\n"
  },
  {
    "path": "components/rate/style/entry.less",
    "content": "@import './index.less';\n// style dependencies\n@import '../../tooltip/style/entry.less';\n"
  },
  {
    "path": "components/rate/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@rate-prefix-cls: ~'@{ant-prefix}-rate';\n\n.@{rate-prefix-cls} {\n  .reset-component();\n\n  display: inline-block;\n  margin: 0;\n  padding: 0;\n  color: @rate-star-color;\n  font-size: @rate-star-size;\n  line-height: unset;\n  list-style: none;\n  outline: none;\n\n  &-disabled &-star {\n    cursor: default;\n\n    > div:hover {\n      transform: scale(1);\n    }\n  }\n\n  &-star {\n    position: relative;\n    display: inline-block;\n    color: inherit;\n    cursor: pointer;\n\n    &:not(:last-child) {\n      margin-right: 8px;\n    }\n\n    > div {\n      transition: all 0.3s, outline 0s;\n\n      &:hover {\n        transform: @rate-star-hover-scale;\n      }\n\n      &:focus {\n        outline: 0;\n      }\n\n      &:focus-visible {\n        outline: 1px dashed @rate-star-color;\n        transform: @rate-star-hover-scale;\n      }\n    }\n\n    &-first,\n    &-second {\n      color: @rate-star-bg;\n      transition: all 0.3s;\n      user-select: none;\n      .@{iconfont-css-prefix} {\n        vertical-align: middle;\n      }\n    }\n\n    &-first {\n      position: absolute;\n      top: 0;\n      left: 0;\n      width: 50%;\n      height: 100%;\n      overflow: hidden;\n      opacity: 0;\n    }\n\n    &-half &-first,\n    &-half &-second {\n      opacity: 1;\n    }\n\n    &-half &-first,\n    &-full &-second {\n      color: inherit;\n    }\n  }\n\n  &-text {\n    display: inline-block;\n    margin: 0 8px;\n    font-size: @font-size-base;\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/rate/style/index.tsx",
    "content": "import '../../style/index.less';\nimport './index.less';\n"
  },
  {
    "path": "components/rate/style/rtl.less",
    "content": ".@{rate-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &-star {\n    &:not(:last-child) {\n      .@{rate-prefix-cls}-rtl & {\n        margin-right: 0;\n        margin-left: 8px;\n      }\n    }\n\n    &-first {\n      .@{rate-prefix-cls}-rtl & {\n        right: 0;\n        left: auto;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/resizable/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本使用\n  en-US: Basic Usage\n---\n\n## zh-CN\n\n基本使用。\n\n## en-US\n\nBasic Usage.\n"
  },
  {
    "path": "components/resizable/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzResizableModule, NzResizeDirection, NzResizeEvent } from 'ng-zorro-antd/resizable';\n\n@Component({\n  selector: 'nz-demo-resizable-basic',\n  imports: [NzResizableModule],\n  template: `\n    <div\n      class=\"box\"\n      nz-resizable\n      [nzMaxWidth]=\"600\"\n      [nzMinWidth]=\"80\"\n      [nzMaxHeight]=\"200\"\n      [nzMinHeight]=\"80\"\n      [nzDisabled]=\"disabled\"\n      [style.height.px]=\"height\"\n      [style.width.px]=\"width\"\n      (nzResize)=\"onResize($event)\"\n    >\n      <nz-resize-handles />\n      content\n    </div>\n  `,\n  styles: `\n    :host {\n      display: block;\n      height: 200px;\n    }\n    .box {\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      background: #eee;\n      border: 1px solid #ddd;\n    }\n  `\n})\nexport class NzDemoResizableBasicComponent {\n  width = 400;\n  height = 200;\n  id = -1;\n  disabled = false;\n  resizeDirection: NzResizeDirection | null = null;\n\n  onResize({ width, height, direction }: NzResizeEvent): void {\n    cancelAnimationFrame(this.id);\n    this.id = requestAnimationFrame(() => {\n      this.width = width!;\n      this.height = height!;\n      this.resizeDirection = direction!;\n    });\n  }\n}\n"
  },
  {
    "path": "components/resizable/demo/customize.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 自定义\n  en-US: Customize\n---\n\n## zh-CN\n\n自定义拖拽柄样式。\n\n## en-US\n\nCustomize Handle。\n"
  },
  {
    "path": "components/resizable/demo/customize.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzResizableModule, NzResizeEvent } from 'ng-zorro-antd/resizable';\n\n@Component({\n  selector: 'nz-demo-resizable-customize',\n  imports: [NzIconModule, NzResizableModule],\n  template: `\n    <div class=\"box\" nz-resizable (nzResize)=\"onResize($event)\" [style.height.px]=\"height\" [style.width.px]=\"width\">\n      content\n      <nz-resize-handle nzDirection=\"bottomRight\">\n        <nz-icon class=\"bottom-right\" nzType=\"caret-up\" nzTheme=\"outline\" [nzRotate]=\"135\" />\n      </nz-resize-handle>\n      <nz-resize-handle nzDirection=\"right\">\n        <div class=\"right-wrap\">\n          <nz-icon class=\"right\" nzType=\"more\" nzTheme=\"outline\" />\n        </div>\n      </nz-resize-handle>\n    </div>\n  `,\n  styles: `\n    :host {\n      display: block;\n      height: 200px;\n    }\n\n    .box {\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      background: #eee;\n      border: 1px solid #ddd;\n    }\n\n    .bottom-right {\n      position: absolute;\n      top: 0;\n      left: 0;\n    }\n\n    .right-wrap {\n      height: 100%;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n    }\n\n    .right {\n      background: #fff;\n      border: 1px solid #ddd;\n      text-align: center;\n      font-size: 12px;\n      height: 20px;\n      line-height: 20px;\n    }\n  `\n})\nexport class NzDemoResizableCustomizeComponent {\n  width = 400;\n  height = 200;\n  id = -1;\n\n  onResize({ width, height }: NzResizeEvent): void {\n    cancelAnimationFrame(this.id);\n    this.id = requestAnimationFrame(() => {\n      this.width = width!;\n      this.height = height!;\n    });\n  }\n}\n"
  },
  {
    "path": "components/resizable/demo/drawer.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 抽屉\n  en-US: Drawer\n---\n\n## zh-CN\n\n调整抽屉宽度。\n\n## en-US\n\nResize the drawer width.\n"
  },
  {
    "path": "components/resizable/demo/drawer.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzDrawerModule } from 'ng-zorro-antd/drawer';\nimport { NzResizableModule, NzResizeEvent } from 'ng-zorro-antd/resizable';\n\n@Component({\n  selector: 'nz-demo-resizable-drawer',\n  imports: [NzButtonModule, NzDrawerModule, NzResizableModule],\n  template: `\n    <button nz-button nzType=\"primary\" (click)=\"open()\">Open</button>\n    <nz-drawer\n      [nzClosable]=\"false\"\n      [nzVisible]=\"visible\"\n      [nzBodyStyle]=\"{\n        padding: 0,\n        height: 'calc(100vh - 55px)'\n      }\"\n      [nzWidth]=\"width\"\n      nzPlacement=\"left\"\n      nzTitle=\"Resizable Drawer\"\n      (nzOnClose)=\"close()\"\n    >\n      <ng-container *nzDrawerContent>\n        @if (visible) {\n          <div class=\"drawer-body\" nz-resizable nzBounds=\"window\" [nzMinWidth]=\"256\" (nzResize)=\"onResize($event)\">\n            <nz-resize-handles [nzDirections]=\"['right']\" />\n            <p>Some contents...</p>\n            <p>Some contents...</p>\n            <p>Some contents...</p>\n          </div>\n        }\n      </ng-container>\n    </nz-drawer>\n  `,\n  styles: `\n    .drawer-body {\n      width: 100%;\n      height: 100%;\n      padding: 24px;\n    }\n  `\n})\nexport class NzDemoResizableDrawerComponent {\n  width = 256;\n  visible = false;\n  id = -1;\n\n  onResize({ width }: NzResizeEvent): void {\n    cancelAnimationFrame(this.id);\n    this.id = requestAnimationFrame(() => {\n      this.width = width!;\n    });\n  }\n\n  open(): void {\n    this.visible = true;\n  }\n\n  close(): void {\n    this.visible = false;\n  }\n}\n"
  },
  {
    "path": "components/resizable/demo/grid.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 栅格\n  en-US: Grid\n---\n\n## zh-CN\n\n配合栅格使用\n\n## en-US\n\nResize with grid.\n"
  },
  {
    "path": "components/resizable/demo/grid.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzGridModule } from 'ng-zorro-antd/grid';\nimport { NzResizableModule, NzResizeEvent, NzResizeHandleOption } from 'ng-zorro-antd/resizable';\n\n@Component({\n  selector: 'nz-demo-resizable-grid',\n  imports: [NzGridModule, NzResizableModule],\n  template: `\n    <div nz-row>\n      <div\n        class=\"col\"\n        nz-col\n        nz-resizable\n        (nzResize)=\"onResize($event)\"\n        [nzMinColumn]=\"3\"\n        [nzMaxColumn]=\"20\"\n        [nzGridColumnCount]=\"24\"\n        [nzSpan]=\"col\"\n      >\n        <nz-resize-handles [nzDirections]=\"directions\" />\n        col-{{ col }}\n      </div>\n      <div class=\"col right\" nz-col [nzSpan]=\"24 - col\">col-{{ 24 - col }}</div>\n    </div>\n  `,\n  styles: `\n    .col {\n      padding: 16px 0;\n      text-align: center;\n      border-radius: 0;\n      min-height: 30px;\n      margin-top: 8px;\n      margin-bottom: 8px;\n      background: rgba(0, 160, 233, 0.7);\n      color: #fff;\n    }\n\n    .col.right {\n      background: #00a0e9;\n    }\n  `\n})\nexport class NzDemoResizableGridComponent {\n  col = 8;\n  id = -1;\n  directions: NzResizeHandleOption[] = [\n    {\n      direction: 'right',\n      cursorType: 'grid'\n    }\n  ];\n\n  onResize({ col }: NzResizeEvent): void {\n    cancelAnimationFrame(this.id);\n    this.id = requestAnimationFrame(() => {\n      this.col = col!;\n    });\n  }\n}\n"
  },
  {
    "path": "components/resizable/demo/layout.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 布局\n  en-US: Layout\n---\n\n## zh-CN\n\n调整布局尺寸。\n\n## en-US\n\nLayout with resizable.\n"
  },
  {
    "path": "components/resizable/demo/layout.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzLayoutModule } from 'ng-zorro-antd/layout';\nimport { NzResizableModule, NzResizeEvent } from 'ng-zorro-antd/resizable';\n\n@Component({\n  selector: 'nz-demo-resizable-layout',\n  imports: [NzLayoutModule, NzResizableModule],\n  template: `\n    <nz-layout>\n      <nz-header>Header</nz-header>\n      <nz-layout>\n        <nz-sider\n          [nzWidth]=\"siderWidth\"\n          nz-resizable\n          [nzMinWidth]=\"50\"\n          [nzMaxWidth]=\"300\"\n          (nzResize)=\"onSideResize($event)\"\n        >\n          <nz-resize-handle nzDirection=\"right\" nzCursorType=\"grid\">\n            <div class=\"sider-resize-line\"></div>\n          </nz-resize-handle>\n          Sider\n        </nz-sider>\n        <nz-content>\n          <div\n            nz-resizable\n            class=\"resizable-box\"\n            [style.height.px]=\"contentHeight\"\n            [nzMaxHeight]=\"300\"\n            [nzMinHeight]=\"50\"\n            (nzResize)=\"onContentResize($event)\"\n          >\n            <nz-resize-handle nzDirection=\"bottom\" nzCursorType=\"grid\">\n              <div class=\"content-resize-line\"></div>\n            </nz-resize-handle>\n            Content 1\n          </div>\n          <div>Content 2</div>\n        </nz-content>\n      </nz-layout>\n    </nz-layout>\n  `,\n  styles: `\n    nz-header {\n      background: #7dbcea;\n      color: #fff;\n    }\n    nz-sider {\n      background: #3ba0e9;\n      color: #fff;\n    }\n\n    nz-sider.nz-resizable-resizing {\n      transition: none;\n    }\n\n    nz-content {\n      display: flex;\n      flex-direction: column;\n      background: rgba(16, 142, 233, 1);\n      height: 350px;\n      color: #fff;\n    }\n\n    nz-content > div {\n      width: 100%;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      flex: 1;\n    }\n\n    nz-content .resizable-box {\n      flex: none;\n    }\n\n    nz-content,\n    nz-header,\n    ::ng-deep nz-sider > .ant-layout-sider-children {\n      display: flex;\n      align-items: center;\n      justify-content: center;\n    }\n\n    .sider-resize-line {\n      height: 100%;\n      width: 5px;\n      border-right: 1px solid #e8e8e8;\n    }\n\n    .content-resize-line {\n      width: 100%;\n      height: 5px;\n      border-bottom: 1px solid #e8e8e8;\n    }\n  `\n})\nexport class NzDemoResizableLayoutComponent {\n  siderWidth = 120;\n  contentHeight = 200;\n  id = -1;\n\n  onSideResize({ width }: NzResizeEvent): void {\n    cancelAnimationFrame(this.id);\n    this.id = requestAnimationFrame(() => {\n      this.siderWidth = width!;\n    });\n  }\n\n  onContentResize({ height }: NzResizeEvent): void {\n    cancelAnimationFrame(this.id);\n    this.id = requestAnimationFrame(() => {\n      this.contentHeight = height!;\n    });\n  }\n}\n"
  },
  {
    "path": "components/resizable/demo/lock-aspect-ratio.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 锁定比例\n  en-US: Lock Aspect Ratio\n---\n\n## zh-CN\n\n锁定宽高比。\n\n## en-US\n\nLock the resize aspect ratio.\n"
  },
  {
    "path": "components/resizable/demo/lock-aspect-ratio.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzResizableModule, NzResizeEvent } from 'ng-zorro-antd/resizable';\n\n@Component({\n  selector: 'nz-demo-resizable-lock-aspect-ratio',\n  imports: [NzResizableModule],\n  template: `\n    <div\n      class=\"box\"\n      nz-resizable\n      nzLockAspectRatio\n      (nzResize)=\"onResize($event)\"\n      [style.height.px]=\"height\"\n      [style.width.px]=\"width\"\n    >\n      <nz-resize-handles />\n      content\n    </div>\n  `,\n  styles: `\n    :host {\n      display: block;\n      height: 200px;\n    }\n    .box {\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      background: #eee;\n      border: 1px solid #ddd;\n    }\n  `\n})\nexport class NzDemoResizableLockAspectRatioComponent {\n  width = 400;\n  height = 200;\n  id = -1;\n\n  onResize({ width, height }: NzResizeEvent): void {\n    cancelAnimationFrame(this.id);\n    this.id = requestAnimationFrame(() => {\n      this.width = width!;\n      this.height = height!;\n    });\n  }\n}\n"
  },
  {
    "path": "components/resizable/demo/preview.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 预览\n  en-US: Preview\n---\n\n## zh-CN\n\n在应用尺寸前预览。\n\n## en-US\n\nPreview before apply size.\n"
  },
  {
    "path": "components/resizable/demo/preview.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzResizableModule, NzResizeEvent } from 'ng-zorro-antd/resizable';\n\n@Component({\n  selector: 'nz-demo-resizable-preview',\n  imports: [NzResizableModule],\n  template: `\n    <div\n      class=\"box\"\n      nz-resizable\n      nzPreview\n      (nzResizeEnd)=\"onResize($event)\"\n      [style.height.px]=\"height\"\n      [style.width.px]=\"width\"\n    >\n      <nz-resize-handles />\n      content\n    </div>\n  `,\n  styles: `\n    :host {\n      display: block;\n      height: 200px;\n    }\n    .box {\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      background: #eee;\n      border: 1px solid #ddd;\n    }\n  `\n})\nexport class NzDemoResizablePreviewComponent {\n  width = 400;\n  height = 200;\n\n  onResize({ width, height }: NzResizeEvent): void {\n    this.width = width!;\n    this.height = height!;\n  }\n}\n"
  },
  {
    "path": "components/resizable/demo/table.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 表格\n  en-US: Table\n---\n\n## zh-CN\n\n调整表头宽度。\n\n## en-US\n\nResize the table header.\n"
  },
  {
    "path": "components/resizable/demo/table.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzResizableModule, NzResizeEvent } from 'ng-zorro-antd/resizable';\nimport { NzTableModule } from 'ng-zorro-antd/table';\n\n@Component({\n  selector: 'nz-demo-resizable-table',\n  imports: [NzResizableModule, NzTableModule],\n  template: `\n    <nz-table #basicTable [nzData]=\"listOfData\">\n      <thead>\n        <tr>\n          @for (col of cols; track col) {\n            @if (col.width) {\n              <th\n                nz-resizable\n                nzBounds=\"window\"\n                nzPreview\n                [nzWidth]=\"col.width\"\n                [nzMaxWidth]=\"256\"\n                [nzMinWidth]=\"60\"\n                (nzResizeEnd)=\"onResize($event, col.title)\"\n              >\n                {{ col.title }}\n                <nz-resize-handle nzDirection=\"right\">\n                  <div class=\"resize-trigger\"></div>\n                </nz-resize-handle>\n              </th>\n            } @else {\n              <th>\n                {{ col.title }}\n              </th>\n            }\n          }\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of basicTable.data; track data) {\n          <tr>\n            <td>{{ data.name }}</td>\n            <td>{{ data.age }}</td>\n            <td>{{ data.address }}</td>\n            <td>-</td>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n  `,\n  styles: `\n    .nz-resizable-preview {\n      border-width: 0;\n      border-right-width: 1px;\n    }\n  `\n})\nexport class NzDemoResizableTableComponent {\n  cols: Array<{ title: string; width?: string }> = [\n    {\n      title: 'Name',\n      width: '180px'\n    },\n    {\n      title: 'Age',\n      width: '180px'\n    },\n    {\n      title: 'Address',\n      width: '200px'\n    },\n    {\n      title: 'Actions'\n    }\n  ];\n\n  listOfData = [\n    {\n      key: '1',\n      name: 'John Brown',\n      age: 32,\n      address: 'New York No. 1 Lake Park'\n    },\n    {\n      key: '2',\n      name: 'Jim Green',\n      age: 42,\n      address: 'London No. 1 Lake Park'\n    },\n    {\n      key: '3',\n      name: 'Joe Black',\n      age: 32,\n      address: 'Sidney No. 1 Lake Park'\n    }\n  ];\n\n  onResize({ width }: NzResizeEvent, col: string): void {\n    this.cols = this.cols.map(e => (e.title === col ? { ...e, width: `${width}px` } : e));\n  }\n}\n"
  },
  {
    "path": "components/resizable/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Layout\ntitle: Resizable\ncols: 1\nexperimental: true\ndescription: Resize element.\n---\n\n## When To Use\n\nWhen you want to resize elements.\n\n- Support preview\n- Support Grids System\n- Support for custom handles and preview styles\n\n### Import Style\n\n```less\n@import 'node_modules/ng-zorro-antd/resizable/style/entry.less';\n```\n\n## API\n\n### [nz-resizable]\n\nResizable element the `position` attribute must be one of `'relative' | 'absolute' | 'fixed' |'sticky'`，default is `'relative'`.\n\n```ts\ninterface NzResizeEvent {\n  width?: number;\n  height?: number;\n  col?: number;\n  direction?: NzResizeDirection;\n  mouseEvent?: MouseEvent;\n}\n```\n\n| Property              | Description                                     | Type                                              | Default  |\n| --------------------- | ----------------------------------------------- | ------------------------------------------------- | -------- |\n| `[nzBounds]`          | Specifies resize boundaries.                    | `'window' \\| 'parent' \\| ElementRef<HTMLElement>` | `parent` |\n| `[nzMaxHeight]`       | Maximum height of resizable element             | `number`                                          | -        |\n| `[nzMaxWidth]`        | Maximum width of resizable element              | `number`                                          | -        |\n| `[nzMinHeight]`       | Minimum height of resizable element             | `number`                                          | `40`     |\n| `[nzMinWidth]`        | Minimum width of resizable element              | `number`                                          | `40`     |\n| `[nzGridColumnCount]` | Number of columns(-1 is not grid)               | `number`                                          | `-1`     |\n| `[nzMaxColumn]`       | Maximum Column                                  | `number`                                          | -        |\n| `[nzMinColumn]`       | Minimum Column                                  | `number`                                          | -        |\n| `[nzLockAspectRatio]` | Lock the aspect ratio based on the initial size | `boolean`                                         | `false`  |\n| `[nzPreview]`         | Enable preview when resizing                    | `boolean`                                         | `false`  |\n| `[nzDisabled]`        | Disable resize                                  | `boolean`                                         | `false`  |\n| `(nzResize)`          | Calls when Resizing                             | `EventEmitter<NzResizeEvent>`                     | -        |\n| `(nzResizeStart)`     | Calls when resize start                         | `EventEmitter<NzResizeEvent>`                     | -        |\n| `(nzResizeEnd)`       | Calls when resize end                           | `EventEmitter<NzResizeEvent>`                     | -        |\n\n### nz-resize-handle\n\nDefine handles and directions.\n\n```ts\ntype NzResizeDirection = 'top' | 'right' | 'bottom' | 'left' | 'topRight' | 'bottomRight' | 'bottomLeft' | 'topLeft';\ntype NzCursorType = 'window' | 'grid';\n```\n\n| Property         | Description                    | Type                | Default         |\n| ---------------- | ------------------------------ | ------------------- | --------------- |\n| `[nzDirection]`  | Set the direction of resizable | `NzResizeDirection` | `'bottomRight'` |\n| `[nzCursorType]` | Cursor type for handle         | `NzCursorType`      | `'window'`      |\n\n### nz-resize-handles\n\nSimpler way to define handles.\n\n```ts\ninterface NzResizeHandleOption {\n  direction: NzResizeDirection;\n  cursorType: NzCursorType;\n}\n```\n\n| Property         | Description                               | Type                                            | Default        |\n| ---------------- | ----------------------------------------- | ----------------------------------------------- | -------------- |\n| `[nzDirections]` | Allow handle directions or handle options | `<NzResizeDirection \\| NzResizeHandleOption>[]` | ALL DIRECTIONS |\n\n### Styling\n\nThe Component styles only contain the necessary positional properties and simple styles, you can customize the style by overriding the following class.\n\n- `.nz-resizable` The `nz-resizable` component namespace\n- `.nz-resizable-resizing` This class name that is added to `nz-resizable` while resizing\n- `.nz-resizable-preview` The ghost element's class name when enable preview\n- `.nz-resizable-handle-box-hover` This class name that is added to `nz-resize-handle` while mouse hover on `nz-resizable`\n- `.nz-resizable-handle` The `nz-resize-handle` component namespace and directions class name\n  - `.nz-resizable-handle-top`\n  - `.nz-resizable-handle-left`\n  - `.nz-resizable-handle-bottom`\n  - `.nz-resizable-handle-right`\n  - `.nz-resizable-handle-topRight`\n  - `.nz-resizable-handle-topLeft`\n  - `.nz-resizable-handle-bottomRight`\n  - `.nz-resizable-handle-bottomLeft`\n- `.nz-resizable-handle-cursor-type` Cursor type namespace for handle\n  - `.nz-resizable-handle-cursor-type-window`\n  - `.nz-resizable-handle-cursor-type-grid`\n"
  },
  {
    "path": "components/resizable/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ntype: 布局\ntitle: Resizable\nsubtitle: 调整尺寸\ncols: 1\nexperimental: true\ndescription: 调整元素尺寸。\n---\n\n## 何时使用\n\n当你想调整元素尺寸时.\n\n- 支持释放前预览提高性能\n- 支持栅格系统\n- 支持自定义调整手柄和预览样式\n\n### 引入样式\n\n```less\n@import 'node_modules/ng-zorro-antd/resizable/style/entry.less';\n```\n\n## API\n\n### [nz-resizable]\n\n声明在需要调整尺寸的元素上，元素 `position` 属性必须为 `'relative' | 'absolute' | 'fixed' |'sticky'` 之一，默认会自动设置为 `'relative'`。\n\n```ts\ninterface NzResizeEvent {\n  width?: number;\n  height?: number;\n  col?: number;\n  direction?: NzResizeDirection;\n  mouseEvent?: MouseEvent;\n}\n```\n\n| 参数                  | 说明                       | 类型                                              | 默认值   |\n| --------------------- | -------------------------- | ------------------------------------------------- | -------- |\n| `[nzBounds]`          | 调整尺寸的边界             | `'window' \\| 'parent' \\| ElementRef<HTMLElement>` | `parent` |\n| `[nzMaxHeight]`       | 最大高度(超过边界部分忽略) | `number`                                          | -        |\n| `[nzMaxWidth]`        | 最大宽度(超过边界部分忽略) | `number`                                          | -        |\n| `[nzMinHeight]`       | 最小高度                   | `number`                                          | `40`     |\n| `[nzMinWidth]`        | 最小宽度                   | `number`                                          | `40`     |\n| `[nzGridColumnCount]` | 栅格列数(-1 为不栅格)      | `number`                                          | `-1`     |\n| `[nzMaxColumn]`       | 栅格最大列数               | `number`                                          | -        |\n| `[nzMinColumn]`       | 栅格最小列数               | `number`                                          | -        |\n| `[nzLockAspectRatio]` | 锁定宽高比                 | `boolean`                                         | `false`  |\n| `[nzPreview]`         | 开启预览                   | `boolean`                                         | `false`  |\n| `[nzDisabled]`        | 禁用                       | `boolean`                                         | `false`  |\n| `(nzResize)`          | 调整尺寸时的事件           | `EventEmitter<NzResizeEvent>`                     | -        |\n| `(nzResizeStart)`     | 开始调整尺寸时的事件       | `EventEmitter<NzResizeEvent>`                     | -        |\n| `(nzResizeEnd)`       | 结束调整尺寸时的事件       | `EventEmitter<NzResizeEvent>`                     | -        |\n\n### nz-resize-handle\n\n定义调整手柄及方向。\n\n```ts\ntype NzResizeDirection = 'top' | 'right' | 'bottom' | 'left' | 'topRight' | 'bottomRight' | 'bottomLeft' | 'topLeft';\ntype NzCursorType = 'window' | 'grid';\n```\n\n| 参数             | 说明           | 类型                | 默认值          |\n| ---------------- | -------------- | ------------------- | --------------- |\n| `[nzDirection]`  | 调整方向       | `NzResizeDirection` | `'bottomRight'` |\n| `[nzCursorType]` | 手柄的光标类型 | `NzCursorType`      | `'window'`      |\n\n### nz-resize-handles\n\n定义调整手柄的快捷组件。\n\n```ts\ninterface NzResizeHandleOption {\n  direction: NzResizeDirection;\n  cursorType: NzCursorType;\n}\n```\n\n| 参数             | 说明                     | 类型                                            | 默认值   |\n| ---------------- | ------------------------ | ----------------------------------------------- | -------- |\n| `[nzDirections]` | 需要的手柄方向或手柄选项 | `<NzResizeDirection \\| NzResizeHandleOption>[]` | 所有方向 |\n\n### 样式\n\n组件样式只包含了必要的位置属性和简单的样式，你可以通过覆写下列类名自定义样式。\n\n- `.nz-resizable` `nz-resizable` 组件命名空间\n- `.nz-resizable-resizing` 正在调整尺寸时被添加到 `nz-resizable` 上\n- `.nz-resizable-preview` 开启预览时幽灵元素的类名\n- `.nz-resizable-handle-box-hover` 当鼠标悬停在 `nz-resizable` 上时被添加到 ` nz-resize-handle` 上。\n- `.nz-resizable-handle` 调整手柄命名空间及各方向类名\n  - `.nz-resizable-handle-top`\n  - `.nz-resizable-handle-left`\n  - `.nz-resizable-handle-bottom`\n  - `.nz-resizable-handle-right`\n  - `.nz-resizable-handle-topRight`\n  - `.nz-resizable-handle-topLeft`\n  - `.nz-resizable-handle-bottomRight`\n  - `.nz-resizable-handle-bottomLeft`\n- `.nz-resizable-handle-cursor-type` 手柄的光标类型命名空间\n  - `.nz-resizable-handle-cursor-type-window`\n  - `.nz-resizable-handle-cursor-type-grid`\n"
  },
  {
    "path": "components/resizable/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/resizable/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/resizable/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './resizable.module';\nexport * from './resizable.directive';\nexport * from './resizable.service';\nexport * from './resize-handles.component';\nexport * from './resize-handle.component';\nexport * from './resizable-utils';\n"
  },
  {
    "path": "components/resizable/resizable-utils.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { isTouchEvent } from 'ng-zorro-antd/core/util';\n\nexport function getEventWithPoint(event: MouseEvent | TouchEvent): MouseEvent | Touch {\n  return isTouchEvent(event) ? event.touches[0] || event.changedTouches[0] : (event as MouseEvent);\n}\n"
  },
  {
    "path": "components/resizable/resizable.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Platform } from '@angular/cdk/platform';\nimport {\n  AfterViewInit,\n  booleanAttribute,\n  DestroyRef,\n  Directive,\n  ElementRef,\n  EventEmitter,\n  inject,\n  Input,\n  NgZone,\n  numberAttribute,\n  OnDestroy,\n  Output,\n  Renderer2\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { filter } from 'rxjs/operators';\n\nimport { ensureInBounds, fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\n\nimport { getEventWithPoint } from './resizable-utils';\nimport { NzResizableService } from './resizable.service';\nimport { NzResizeDirection, NzResizeHandleMouseDownEvent } from './resize-handle.component';\n\nexport interface NzResizeEvent {\n  width?: number;\n  height?: number;\n  col?: number;\n  mouseEvent?: MouseEvent | TouchEvent;\n  direction?: NzResizeDirection;\n}\n\n@Directive({\n  selector: '[nz-resizable]',\n  exportAs: 'nzResizable',\n  providers: [NzResizableService],\n  host: {\n    class: 'nz-resizable',\n    '[class.nz-resizable-resizing]': 'resizing',\n    '[class.nz-resizable-disabled]': 'nzDisabled'\n  }\n})\nexport class NzResizableDirective implements AfterViewInit, OnDestroy {\n  private readonly elementRef = inject(ElementRef<HTMLElement>);\n  private readonly renderer = inject(Renderer2);\n  private readonly nzResizableService = inject(NzResizableService);\n  private readonly platform = inject(Platform);\n  private readonly ngZone = inject(NgZone);\n  private readonly destroyRef = inject(DestroyRef);\n\n  @Input() nzBounds: 'window' | 'parent' | ElementRef<HTMLElement> = 'parent';\n  @Input() nzMaxHeight?: number;\n  @Input() nzMaxWidth?: number;\n  @Input({ transform: numberAttribute }) nzMinHeight: number = 40;\n  @Input({ transform: numberAttribute }) nzMinWidth: number = 40;\n  @Input({ transform: numberAttribute }) nzGridColumnCount: number = -1;\n  @Input({ transform: numberAttribute }) nzMaxColumn: number = -1;\n  @Input({ transform: numberAttribute }) nzMinColumn: number = -1;\n  @Input({ transform: booleanAttribute }) nzLockAspectRatio: boolean = false;\n  @Input({ transform: booleanAttribute }) nzPreview: boolean = false;\n  @Input({ transform: booleanAttribute }) nzDisabled: boolean = false;\n  @Output() readonly nzResize = new EventEmitter<NzResizeEvent>();\n  @Output() readonly nzResizeEnd = new EventEmitter<NzResizeEvent>();\n  @Output() readonly nzResizeStart = new EventEmitter<NzResizeEvent>();\n\n  resizing = false;\n  private elRect!: DOMRect;\n  private currentHandleEvent: NzResizeHandleMouseDownEvent | null = null;\n  private ghostElement: HTMLDivElement | null = null;\n  private el!: HTMLElement;\n  private sizeCache: NzResizeEvent | null = null;\n\n  constructor() {\n    this.nzResizableService.handleMouseDownOutsideAngular$.pipe(takeUntilDestroyed()).subscribe(event => {\n      if (this.nzDisabled) {\n        return;\n      }\n      this.resizing = true;\n      this.nzResizableService.startResizing(event.mouseEvent);\n      this.currentHandleEvent = event;\n      if (this.nzResizeStart.observers.length) {\n        this.ngZone.run(() => this.nzResizeStart.emit({ mouseEvent: event.mouseEvent, direction: event.direction }));\n      }\n      this.elRect = this.el.getBoundingClientRect();\n    });\n\n    this.nzResizableService.documentMouseUpOutsideAngular$\n      .pipe(takeUntilDestroyed(), filter(Boolean))\n      .subscribe(event => {\n        if (this.resizing) {\n          this.resizing = false;\n          this.nzResizableService.documentMouseUpOutsideAngular$.next(null);\n          this.endResize(event);\n        }\n      });\n\n    this.nzResizableService.documentMouseMoveOutsideAngular$.pipe(takeUntilDestroyed()).subscribe(event => {\n      if (this.resizing) {\n        this.resize(event);\n      }\n    });\n  }\n\n  setPosition(): void {\n    const position = getComputedStyle(this.el).position;\n    if (position === 'static' || !position) {\n      this.renderer.setStyle(this.el, 'position', 'relative');\n    }\n  }\n\n  calcSize(width: number, height: number, ratio: number): NzResizeEvent {\n    let newWidth: number;\n    let newHeight: number;\n    let maxWidth: number;\n    let maxHeight: number;\n    let col = 0;\n    let spanWidth = 0;\n    let minWidth = this.nzMinWidth;\n    let boundWidth = Infinity;\n    let boundHeight = Infinity;\n    if (this.nzBounds === 'parent') {\n      const parent = this.renderer.parentNode(this.el);\n      if (parent instanceof HTMLElement) {\n        const parentRect = parent.getBoundingClientRect();\n        boundWidth = parentRect.width;\n        boundHeight = parentRect.height;\n      }\n    } else if (this.nzBounds === 'window') {\n      if (typeof window !== 'undefined') {\n        boundWidth = window.innerWidth;\n        boundHeight = window.innerHeight;\n      }\n    } else if (this.nzBounds && this.nzBounds.nativeElement && this.nzBounds.nativeElement instanceof HTMLElement) {\n      const boundsRect = this.nzBounds.nativeElement.getBoundingClientRect();\n      boundWidth = boundsRect.width;\n      boundHeight = boundsRect.height;\n    }\n\n    maxWidth = ensureInBounds(this.nzMaxWidth!, boundWidth);\n    // eslint-disable-next-line prefer-const\n    maxHeight = ensureInBounds(this.nzMaxHeight!, boundHeight);\n\n    if (this.nzGridColumnCount !== -1) {\n      spanWidth = maxWidth / this.nzGridColumnCount;\n      minWidth = this.nzMinColumn !== -1 ? spanWidth * this.nzMinColumn : minWidth;\n      maxWidth = this.nzMaxColumn !== -1 ? spanWidth * this.nzMaxColumn : maxWidth;\n    }\n\n    if (ratio !== -1) {\n      if (/(left|right)/i.test(this.currentHandleEvent!.direction)) {\n        newWidth = Math.min(Math.max(width, minWidth), maxWidth);\n        newHeight = Math.min(Math.max(newWidth / ratio, this.nzMinHeight), maxHeight);\n        if (newHeight >= maxHeight || newHeight <= this.nzMinHeight) {\n          newWidth = Math.min(Math.max(newHeight * ratio, minWidth), maxWidth);\n        }\n      } else {\n        newHeight = Math.min(Math.max(height, this.nzMinHeight), maxHeight);\n        newWidth = Math.min(Math.max(newHeight * ratio, minWidth), maxWidth);\n        if (newWidth >= maxWidth || newWidth <= minWidth) {\n          newHeight = Math.min(Math.max(newWidth / ratio, this.nzMinHeight), maxHeight);\n        }\n      }\n    } else {\n      newWidth = Math.min(Math.max(width, minWidth), maxWidth);\n      newHeight = Math.min(Math.max(height, this.nzMinHeight), maxHeight);\n    }\n\n    if (this.nzGridColumnCount !== -1) {\n      col = Math.round(newWidth / spanWidth);\n      newWidth = col * spanWidth;\n    }\n\n    return {\n      col,\n      width: newWidth,\n      height: newHeight\n    };\n  }\n\n  resize(event: MouseEvent | TouchEvent): void {\n    const elRect = this.elRect;\n    const resizeEvent = getEventWithPoint(event);\n    const handleEvent = getEventWithPoint(this.currentHandleEvent!.mouseEvent);\n    let width = elRect.width;\n    let height = elRect.height;\n    const ratio = this.nzLockAspectRatio ? width / height : -1;\n    switch (this.currentHandleEvent!.direction) {\n      case 'bottomRight':\n        width = resizeEvent.clientX - elRect.left;\n        height = resizeEvent.clientY - elRect.top;\n        break;\n      case 'bottomLeft':\n        width = elRect.width + handleEvent.clientX - resizeEvent.clientX;\n        height = resizeEvent.clientY - elRect.top;\n        break;\n      case 'topRight':\n        width = resizeEvent.clientX - elRect.left;\n        height = elRect.height + handleEvent.clientY - resizeEvent.clientY;\n        break;\n      case 'topLeft':\n        width = elRect.width + handleEvent.clientX - resizeEvent.clientX;\n        height = elRect.height + handleEvent.clientY - resizeEvent.clientY;\n        break;\n      case 'top':\n        height = elRect.height + handleEvent.clientY - resizeEvent.clientY;\n        break;\n      case 'right':\n        width = resizeEvent.clientX - elRect.left;\n        break;\n      case 'bottom':\n        height = resizeEvent.clientY - elRect.top;\n        break;\n      case 'left':\n        width = elRect.width + handleEvent.clientX - resizeEvent.clientX;\n    }\n    const size = this.calcSize(width, height, ratio);\n    this.sizeCache = { ...size };\n    // Re-enter the Angular zone and run the change detection only if there are any `nzResize` listeners,\n    // e.g.: `<div nz-resizable (nzResize)=\"...\"></div>`.\n    if (this.nzResize.observers.length) {\n      this.ngZone.run(() => {\n        this.nzResize.emit({\n          ...size,\n          mouseEvent: event,\n          direction: this.currentHandleEvent!.direction\n        });\n      });\n    }\n    if (this.nzPreview) {\n      this.previewResize(size);\n    }\n  }\n\n  endResize(event: MouseEvent | TouchEvent): void {\n    this.removeGhostElement();\n    const size = this.sizeCache\n      ? { ...this.sizeCache }\n      : {\n          width: this.elRect.width,\n          height: this.elRect.height\n        };\n    // Re-enter the Angular zone and run the change detection only if there are any `nzResizeEnd` listeners,\n    // e.g.: `<div nz-resizable (nzResizeEnd)=\"...\"></div>`.\n    if (this.nzResizeEnd.observers.length) {\n      this.ngZone.run(() => {\n        this.nzResizeEnd.emit({\n          ...size,\n          mouseEvent: event,\n          direction: this.currentHandleEvent!.direction\n        });\n      });\n    }\n    this.sizeCache = null;\n    this.currentHandleEvent = null;\n  }\n\n  previewResize({ width, height }: NzResizeEvent): void {\n    this.createGhostElement();\n    this.renderer.setStyle(this.ghostElement, 'width', `${width}px`);\n    this.renderer.setStyle(this.ghostElement, 'height', `${height}px`);\n  }\n\n  createGhostElement(): void {\n    if (!this.ghostElement) {\n      this.ghostElement = this.renderer.createElement('div');\n      this.renderer.setAttribute(this.ghostElement, 'class', 'nz-resizable-preview');\n    }\n    this.renderer.appendChild(this.el, this.ghostElement);\n  }\n\n  removeGhostElement(): void {\n    if (this.ghostElement) {\n      this.renderer.removeChild(this.el, this.ghostElement);\n    }\n  }\n\n  ngAfterViewInit(): void {\n    if (!this.platform.isBrowser) {\n      return;\n    }\n\n    this.el = this.elementRef.nativeElement;\n    this.setPosition();\n\n    fromEventOutsideAngular(this.el, 'mouseenter')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(() => {\n        this.nzResizableService.mouseEnteredOutsideAngular$.next(true);\n      });\n\n    fromEventOutsideAngular(this.el, 'mouseleave')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(() => {\n        this.nzResizableService.mouseEnteredOutsideAngular$.next(false);\n      });\n  }\n\n  ngOnDestroy(): void {\n    this.ghostElement = null;\n    this.sizeCache = null;\n  }\n}\n"
  },
  {
    "path": "components/resizable/resizable.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzResizableDirective } from './resizable.directive';\nimport { NzResizeHandleComponent } from './resize-handle.component';\nimport { NzResizeHandlesComponent } from './resize-handles.component';\n\n@NgModule({\n  imports: [NzResizableDirective, NzResizeHandleComponent, NzResizeHandlesComponent],\n  exports: [NzResizableDirective, NzResizeHandleComponent, NzResizeHandlesComponent]\n})\nexport class NzResizableModule {}\n"
  },
  {
    "path": "components/resizable/resizable.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { DOCUMENT, inject, Injectable, NgZone, OnDestroy } from '@angular/core';\nimport { Subject } from 'rxjs';\n\nimport { isTouchEvent } from 'ng-zorro-antd/core/util';\n\nimport { NzResizeHandleMouseDownEvent } from './resize-handle.component';\n\n@Injectable()\nexport class NzResizableService implements OnDestroy {\n  private readonly document: Document = inject(DOCUMENT);\n  private readonly ngZone = inject(NgZone);\n  private listeners = new Map<string, (event: MouseEvent | TouchEvent) => void>();\n\n  /**\n   * The `OutsideAngular` prefix means that the subject will emit events outside of the Angular zone,\n   * so that becomes a bit more descriptive for those who'll maintain the code in the future:\n   * ```ts\n   * nzResizableService.handleMouseDownOutsideAngular$.subscribe(event => {\n   *   console.log(Zone.current); // <root>\n   *   console.log(NgZone.isInAngularZone()); // false\n   * });\n   * ```\n   */\n  handleMouseDownOutsideAngular$ = new Subject<NzResizeHandleMouseDownEvent>();\n  documentMouseUpOutsideAngular$ = new Subject<MouseEvent | TouchEvent | null>();\n  documentMouseMoveOutsideAngular$ = new Subject<MouseEvent | TouchEvent>();\n  mouseEnteredOutsideAngular$ = new Subject<boolean>();\n\n  startResizing(event: MouseEvent | TouchEvent): void {\n    const _isTouchEvent = isTouchEvent(event);\n    this.clearListeners();\n    const moveEvent = _isTouchEvent ? 'touchmove' : 'mousemove';\n    const upEvent = _isTouchEvent ? 'touchend' : 'mouseup';\n    const moveEventHandler = (e: MouseEvent | TouchEvent): void => {\n      this.documentMouseMoveOutsideAngular$.next(e);\n    };\n    const upEventHandler = (e: MouseEvent | TouchEvent): void => {\n      this.documentMouseUpOutsideAngular$.next(e);\n      this.clearListeners();\n    };\n\n    this.listeners.set(moveEvent, moveEventHandler);\n    this.listeners.set(upEvent, upEventHandler);\n\n    this.ngZone.runOutsideAngular(() => {\n      this.listeners.forEach((handler, name) => {\n        this.document.addEventListener(name, handler as EventListener);\n      });\n    });\n  }\n\n  private clearListeners(): void {\n    this.listeners.forEach((handler, name) => {\n      this.document.removeEventListener(name, handler as EventListener);\n    });\n    this.listeners.clear();\n  }\n\n  ngOnDestroy(): void {\n    this.handleMouseDownOutsideAngular$.complete();\n    this.documentMouseUpOutsideAngular$.complete();\n    this.documentMouseMoveOutsideAngular$.complete();\n    this.mouseEnteredOutsideAngular$.complete();\n    this.clearListeners();\n  }\n}\n"
  },
  {
    "path": "components/resizable/resizable.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ApplicationRef, Component, ElementRef, NgZone, provideZoneChangeDetection, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { dispatchMouseEvent, dispatchTouchEvent, MockNgZone } from 'ng-zorro-antd/core/testing';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\nimport { NzResizableModule } from 'ng-zorro-antd/resizable/resizable.module';\n\nimport { NzDemoResizableBasicComponent } from './demo/basic';\nimport { NzDemoResizableCustomizeComponent } from './demo/customize';\nimport { NzDemoResizableGridComponent } from './demo/grid';\nimport { NzDemoResizableLockAspectRatioComponent } from './demo/lock-aspect-ratio';\nimport { NzDemoResizablePreviewComponent } from './demo/preview';\nimport { NzResizableDirective, NzResizeEvent } from './resizable.directive';\nimport { DEFAULT_RESIZE_DIRECTION } from './resize-handles.component';\n\ndescribe('resizable', () => {\n  let zone: MockNgZone;\n\n  beforeEach(fakeAsync(() => {\n    TestBed.configureTestingModule({\n      providers: [\n        // todo: use zoneless\n        provideZoneChangeDetection(),\n        provideNzIconsTesting(),\n        {\n          provide: NgZone,\n          useFactory: () => {\n            zone = new MockNgZone();\n            return zone;\n          }\n        }\n      ]\n    });\n  }));\n\n  describe('basic', () => {\n    let fixture: ComponentFixture<NzDemoResizableBasicComponent>;\n    let testComponent: NzDemoResizableBasicComponent;\n    let resizableEle: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzDemoResizableBasicComponent);\n      testComponent = fixture.debugElement.componentInstance;\n      resizableEle = fixture.debugElement.query(By.directive(NzResizableDirective)).nativeElement;\n      fixture.detectChanges();\n    });\n\n    it('should render handles', () => {\n      const handles = resizableEle.querySelectorAll('.nz-resizable-handle');\n      expect(handles.length).toBe(8);\n      handles.forEach(e => {\n        expect(DEFAULT_RESIZE_DIRECTION.some(d => e.classList.contains(`nz-resizable-handle-${d}`))).toBe(true);\n      });\n    });\n\n    it('should toggle the `nz-resizable-handle-box-hover` class when `mouseenter` and `mouseleave` events are fired and should not run change detection', () => {\n      const appRef = TestBed.inject(ApplicationRef);\n      spyOn(appRef, 'tick');\n      dispatchMouseEvent(resizableEle, 'mouseenter');\n      const handles = resizableEle.querySelectorAll('.nz-resizable-handle');\n      expect(handles.length).toBe(8);\n      handles.forEach(e => {\n        expect(e.classList).toContain('nz-resizable-handle-box-hover');\n      });\n      dispatchMouseEvent(resizableEle, 'mouseleave');\n      handles.forEach(e => {\n        expect(e.classList).not.toContain('nz-resizable-handle-box-hover');\n      });\n      expect(appRef.tick).toHaveBeenCalledTimes(0);\n    });\n\n    it('should not run change detection on `mousedown` event on the `nz-resize-handle`', () => {\n      const appRef = TestBed.inject(ApplicationRef);\n      spyOn(appRef, 'tick');\n      const nzResizeHandle = resizableEle.querySelector('nz-resize-handle')!;\n      dispatchMouseEvent(nzResizeHandle, 'mousedown');\n      expect(appRef.tick).toHaveBeenCalledTimes(0);\n    });\n\n    it('should maximum size work', done => {\n      const rect = resizableEle.getBoundingClientRect();\n      const handel = resizableEle.querySelector('.nz-resizable-handle-bottomRight') as HTMLElement;\n      mouseMoveTrigger(\n        handel,\n        {\n          x: rect.right,\n          y: rect.bottom\n        },\n        {\n          x: rect.right + 500,\n          y: rect.bottom + 200\n        }\n      );\n      zone.simulateZoneExit();\n      fixture.detectChanges();\n      fixture.detectChanges();\n      afterNextFrameRender(() => {\n        fixture.detectChanges();\n        expect(testComponent.width).toBe(600);\n        expect(testComponent.height).toBe(200);\n        done();\n      });\n    });\n\n    it('should minimum size work', done => {\n      const rect = resizableEle.getBoundingClientRect();\n      const handel = resizableEle.querySelector('.nz-resizable-handle-bottomRight') as HTMLElement;\n      mouseMoveTrigger(\n        handel,\n        {\n          x: rect.right,\n          y: rect.bottom\n        },\n        {\n          x: rect.right - 600,\n          y: rect.bottom - 200\n        }\n      );\n      fixture.detectChanges();\n      afterNextFrameRender(() => {\n        fixture.detectChanges();\n        expect(testComponent.width).toBe(80);\n        expect(testComponent.height).toBe(80);\n        done();\n      });\n    });\n\n    describe('should resize work', () => {\n      let rect: DOMRect;\n\n      beforeEach(() => {\n        testComponent.height = 200;\n        testComponent.width = 400;\n        fixture.detectChanges();\n        rect = resizableEle.getBoundingClientRect();\n        expect(testComponent.width).toBe(400);\n        expect(testComponent.height).toBe(200);\n      });\n\n      it('should touch event work', done => {\n        const handle = resizableEle.querySelector('.nz-resizable-handle-top') as HTMLElement;\n        touchMoveTrigger(\n          handle,\n          {\n            x: rect.left,\n            y: rect.top\n          },\n          {\n            x: rect.left,\n            y: rect.top + 100\n          }\n        );\n        fixture.detectChanges();\n        afterNextFrameRender(() => {\n          fixture.detectChanges();\n          expect(testComponent.height).toBeLessThanOrEqual(200);\n          expect(testComponent.height).toBeGreaterThanOrEqual(100);\n          expect(testComponent.resizeDirection).toEqual('top');\n          done();\n        });\n      });\n\n      /**\n       *  +---↓---+\n       *  |       |\n       *  +-------+\n       */\n      it('top', done => {\n        const handle = resizableEle.querySelector('.nz-resizable-handle-top') as HTMLElement;\n        mouseMoveTrigger(\n          handle,\n          {\n            x: rect.left,\n            y: rect.top\n          },\n          {\n            x: rect.left,\n            y: rect.top + 100\n          }\n        );\n        fixture.detectChanges();\n        afterNextFrameRender(() => {\n          fixture.detectChanges();\n          expect(testComponent.height).toBeLessThanOrEqual(200);\n          expect(testComponent.height).toBeGreaterThanOrEqual(100);\n          expect(testComponent.resizeDirection).toEqual('top');\n          done();\n        });\n      });\n\n      /**\n       *  +-------+\n       *  |       |\n       *  +---↑---+\n       */\n      it('bottom', done => {\n        const handle = resizableEle.querySelector('.nz-resizable-handle-bottom') as HTMLElement;\n        mouseMoveTrigger(\n          handle,\n          {\n            x: rect.left,\n            y: rect.bottom\n          },\n          {\n            x: rect.left,\n            y: rect.bottom - 100\n          }\n        );\n        fixture.detectChanges();\n        afterNextFrameRender(() => {\n          fixture.detectChanges();\n          expect(testComponent.height).toBeLessThanOrEqual(200);\n          expect(testComponent.height).toBeGreaterThanOrEqual(100);\n          expect(testComponent.resizeDirection).toEqual('bottom');\n          done();\n        });\n      });\n\n      /**\n       *  +-------+\n       *  →       |\n       *  +-------+\n       */\n      it('left', done => {\n        const handle = resizableEle.querySelector('.nz-resizable-handle-left') as HTMLElement;\n        mouseMoveTrigger(\n          handle,\n          {\n            x: rect.left,\n            y: rect.bottom\n          },\n          {\n            x: rect.left + 100,\n            y: rect.bottom\n          }\n        );\n        fixture.detectChanges();\n        afterNextFrameRender(() => {\n          fixture.detectChanges();\n          expect(testComponent.width).toBeLessThanOrEqual(400);\n          expect(testComponent.width).toBeGreaterThanOrEqual(300);\n          expect(testComponent.resizeDirection).toEqual('left');\n          done();\n        });\n      });\n\n      /**\n       *  +-------+\n       *  |       ←\n       *  +-------+\n       */\n      it('right', done => {\n        const handle = resizableEle.querySelector('.nz-resizable-handle-right') as HTMLElement;\n        mouseMoveTrigger(\n          handle,\n          {\n            x: rect.right,\n            y: rect.bottom\n          },\n          {\n            x: rect.right - 100,\n            y: rect.bottom\n          }\n        );\n        fixture.detectChanges();\n        afterNextFrameRender(() => {\n          fixture.detectChanges();\n          expect(testComponent.width).toBeLessThanOrEqual(400);\n          expect(testComponent.width).toBeGreaterThanOrEqual(300);\n          expect(testComponent.resizeDirection).toEqual('right');\n          done();\n        });\n      });\n\n      /**\n       *  +-------↙\n       *  |       |\n       *  +------+\n       */\n      it('topRight', done => {\n        const handle = resizableEle.querySelector('.nz-resizable-handle-topRight') as HTMLElement;\n        mouseMoveTrigger(\n          handle,\n          {\n            x: rect.right,\n            y: rect.top\n          },\n          {\n            x: rect.right - 100,\n            y: rect.top + 90\n          }\n        );\n        fixture.detectChanges();\n        afterNextFrameRender(() => {\n          fixture.detectChanges();\n          expect(testComponent.width).toBeLessThanOrEqual(400);\n          expect(testComponent.width).toBeGreaterThanOrEqual(300);\n          expect(testComponent.height).toBeLessThanOrEqual(210);\n          expect(testComponent.height).toBeGreaterThanOrEqual(100);\n          expect(testComponent.resizeDirection).toEqual('topRight');\n          done();\n        });\n      });\n\n      /**\n       *  ↘-------+\n       *  |       |\n       *  +-------+\n       */\n      it('topLeft', done => {\n        const handle = resizableEle.querySelector('.nz-resizable-handle-topLeft') as HTMLElement;\n        mouseMoveTrigger(\n          handle,\n          {\n            x: rect.left,\n            y: rect.top\n          },\n          {\n            x: rect.left + 100,\n            y: rect.top + 100\n          }\n        );\n        fixture.detectChanges();\n        afterNextFrameRender(() => {\n          fixture.detectChanges();\n          expect(testComponent.width).toBeLessThanOrEqual(400);\n          expect(testComponent.width).toBeGreaterThanOrEqual(300);\n          expect(testComponent.height).toBeLessThanOrEqual(200);\n          expect(testComponent.height).toBeGreaterThanOrEqual(100);\n          expect(testComponent.resizeDirection).toEqual('topLeft');\n          done();\n        });\n      });\n\n      /**\n       *  +-------+\n       *  |       |\n       *  +-------↖\n       */\n      it('bottomRight', done => {\n        const handle = resizableEle.querySelector('.nz-resizable-handle-bottomRight') as HTMLElement;\n        mouseMoveTrigger(\n          handle,\n          {\n            x: rect.right,\n            y: rect.bottom\n          },\n          {\n            x: rect.right - 100,\n            y: rect.bottom - 90\n          }\n        );\n        fixture.detectChanges();\n        afterNextFrameRender(() => {\n          fixture.detectChanges();\n          expect(testComponent.width).toBeLessThanOrEqual(400);\n          expect(testComponent.width).toBeGreaterThanOrEqual(300);\n          expect(testComponent.height).toBeLessThanOrEqual(190);\n          expect(testComponent.height).toBeGreaterThanOrEqual(100);\n          expect(testComponent.resizeDirection).toEqual('bottomRight');\n          done();\n        });\n      });\n\n      /**\n       *  +-------+\n       *  |       |\n       *  ↗-------+\n       */\n      it('bottomLeft', done => {\n        const handle = resizableEle.querySelector('.nz-resizable-handle-bottomLeft') as HTMLElement;\n        mouseMoveTrigger(\n          handle,\n          {\n            x: rect.left,\n            y: rect.bottom\n          },\n          {\n            x: rect.left + 100,\n            y: rect.bottom - 100\n          }\n        );\n        fixture.detectChanges();\n\n        afterNextFrameRender(() => {\n          fixture.detectChanges();\n          expect(testComponent.width).toBeLessThanOrEqual(400);\n          expect(testComponent.width).toBeGreaterThanOrEqual(300);\n          expect(testComponent.height).toBeLessThanOrEqual(200);\n          expect(testComponent.height).toBeGreaterThanOrEqual(100);\n          expect(testComponent.resizeDirection).toEqual('bottomLeft');\n          done();\n        });\n      });\n    });\n\n    it('should disabled work', done => {\n      testComponent.disabled = true;\n      fixture.detectChanges();\n      expect(resizableEle.classList).toContain(`nz-resizable-disabled`);\n      expect(testComponent.width).toBe(400);\n      const rect = resizableEle.getBoundingClientRect();\n      const handle = resizableEle.querySelector('.nz-resizable-handle-left') as HTMLElement;\n      mouseMoveTrigger(\n        handle,\n        {\n          x: rect.left,\n          y: rect.bottom\n        },\n        {\n          x: rect.left + 100,\n          y: rect.bottom\n        }\n      );\n      fixture.detectChanges();\n      afterNextFrameRender(() => {\n        fixture.detectChanges();\n        expect(testComponent.width).toBe(400);\n        done();\n      });\n    });\n  });\n\n  describe('customize', () => {\n    let fixture: ComponentFixture<NzDemoResizableCustomizeComponent>;\n    let testComponent: NzDemoResizableCustomizeComponent;\n    let resizableEle: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzDemoResizableCustomizeComponent);\n      testComponent = fixture.debugElement.componentInstance;\n      resizableEle = fixture.debugElement.query(By.directive(NzResizableDirective)).nativeElement;\n      fixture.detectChanges();\n    });\n\n    it('should customize handles', done => {\n      const bottomRightHandel = resizableEle.querySelector('.nz-resizable-handle-bottomRight') as HTMLElement;\n      expect(bottomRightHandel.querySelector('.bottom-right')).toBeTruthy();\n      const rightHandel = resizableEle.querySelector('.nz-resizable-handle-right') as HTMLElement;\n      expect(rightHandel.querySelector('.right-wrap')).toBeTruthy();\n\n      const rect = resizableEle.getBoundingClientRect();\n      mouseMoveTrigger(\n        bottomRightHandel,\n        {\n          x: rect.right,\n          y: rect.bottom\n        },\n        {\n          x: rect.right + 200,\n          y: rect.bottom\n        }\n      );\n      zone.simulateZoneExit();\n      fixture.detectChanges();\n      afterNextFrameRender(() => {\n        fixture.detectChanges();\n        zone.simulateZoneExit();\n        fixture.detectChanges();\n        expect(testComponent.width).toBeGreaterThanOrEqual(600);\n        done();\n      });\n    });\n  });\n\n  describe('lock aspect ratio', () => {\n    let fixture: ComponentFixture<NzDemoResizableLockAspectRatioComponent>;\n    let resizableEle: HTMLElement;\n    let testComponent: NzDemoResizableLockAspectRatioComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzDemoResizableLockAspectRatioComponent);\n      testComponent = fixture.debugElement.componentInstance;\n      resizableEle = fixture.debugElement.query(By.directive(NzResizableDirective)).nativeElement;\n      fixture.detectChanges();\n    });\n\n    it('should lock aspect ratio when resize', done => {\n      const rect = resizableEle.getBoundingClientRect();\n      const leftHandel = resizableEle.querySelector('.nz-resizable-handle-right') as HTMLElement;\n      const topHandel = resizableEle.querySelector('.nz-resizable-handle-top') as HTMLElement;\n      const bottomRightHandel = resizableEle.querySelector('.nz-resizable-handle-bottomRight') as HTMLElement;\n      const ratio = testComponent.width / testComponent.height;\n      mouseMoveTrigger(\n        leftHandel,\n        {\n          x: rect.right,\n          y: rect.bottom\n        },\n        {\n          x: rect.right + 100,\n          y: rect.bottom\n        }\n      );\n      fixture.detectChanges();\n      afterNextFrameRender(() => {\n        fixture.detectChanges();\n        mouseMoveTrigger(\n          bottomRightHandel,\n          {\n            x: rect.right,\n            y: rect.bottom\n          },\n          {\n            x: rect.right - 123,\n            y: rect.bottom - 321\n          }\n        );\n        fixture.detectChanges();\n        afterNextFrameRender(() => {\n          fixture.detectChanges();\n          mouseMoveTrigger(\n            topHandel,\n            {\n              x: rect.right,\n              y: rect.top\n            },\n            {\n              x: rect.right,\n              y: rect.top + 100\n            }\n          );\n          fixture.detectChanges();\n          afterNextFrameRender(() => {\n            fixture.detectChanges();\n            expect(Math.round(testComponent.width / testComponent.height)).toBe(ratio);\n            done();\n          });\n        });\n      });\n    });\n  });\n\n  describe('preview', () => {\n    let fixture: ComponentFixture<NzDemoResizablePreviewComponent>;\n    let resizableEle: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzDemoResizablePreviewComponent);\n      resizableEle = fixture.debugElement.query(By.directive(NzResizableDirective)).nativeElement;\n      fixture.detectChanges();\n    });\n\n    it('should preview work', () => {\n      const rect = resizableEle.getBoundingClientRect();\n      const handle = resizableEle.querySelector('.nz-resizable-handle-bottomRight') as HTMLElement;\n      dispatchMouseEvent(handle, 'mousedown', rect.right, rect.bottom);\n      dispatchMouseEvent(window.document, 'mousemove', rect.right + 20, rect.bottom + 20);\n      fixture.detectChanges();\n      const preview = resizableEle.querySelector('.nz-resizable-preview') as HTMLElement;\n      expect(preview).toBeTruthy();\n    });\n  });\n\n  describe('grid', () => {\n    let fixture: ComponentFixture<NzDemoResizableGridComponent>;\n    let resizableEle: HTMLElement;\n    let testComponent: NzDemoResizableGridComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzDemoResizableGridComponent);\n      testComponent = fixture.debugElement.componentInstance;\n      resizableEle = fixture.debugElement.query(By.directive(NzResizableDirective)).nativeElement;\n      fixture.detectChanges();\n    });\n\n    it('should grid work', done => {\n      const rect = resizableEle.getBoundingClientRect();\n      const handle = resizableEle.querySelector('.nz-resizable-handle-right') as HTMLElement;\n      mouseMoveTrigger(\n        handle,\n        {\n          x: rect.right,\n          y: rect.bottom\n        },\n        {\n          x: 0,\n          y: rect.bottom\n        }\n      );\n      fixture.detectChanges();\n      afterNextFrameRender(() => {\n        fixture.detectChanges();\n        expect(testComponent.col).toBe(3);\n        mouseMoveTrigger(\n          handle,\n          {\n            x: rect.right,\n            y: rect.bottom\n          },\n          {\n            x: 9999,\n            y: rect.bottom\n          }\n        );\n        fixture.detectChanges();\n        afterNextFrameRender(() => {\n          fixture.detectChanges();\n          expect(testComponent.col).toBe(20);\n          done();\n        });\n      });\n    });\n\n    it('should cursor type work', () => {\n      expect(resizableEle.querySelector('.nz-resizable-handle-cursor-type-window')).toBeFalsy();\n      expect(resizableEle.querySelector('.nz-resizable-handle-cursor-type-grid')).toBeTruthy();\n      testComponent.directions = [\n        {\n          direction: 'right',\n          cursorType: 'window'\n        }\n      ];\n      fixture.detectChanges();\n      expect(resizableEle.querySelector('.nz-resizable-handle-cursor-type-window')).toBeTruthy();\n      expect(resizableEle.querySelector('.nz-resizable-handle-cursor-type-grid')).toBeFalsy();\n    });\n  });\n\n  describe('bounds', () => {\n    let fixture: ComponentFixture<NzTestResizableBoundsComponent>;\n    let resizableEle: HTMLElement;\n    let testComponent: NzTestResizableBoundsComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestResizableBoundsComponent);\n      testComponent = fixture.debugElement.componentInstance;\n      resizableEle = fixture.debugElement.query(By.directive(NzResizableDirective)).nativeElement;\n      fixture.detectChanges();\n    });\n\n    it('should parent bounds work', done => {\n      const rect = resizableEle.getBoundingClientRect();\n      const handle = resizableEle.querySelector('.nz-resizable-handle-bottomRight') as HTMLElement;\n      mouseMoveTrigger(\n        handle,\n        {\n          x: rect.right,\n          y: rect.bottom\n        },\n        {\n          x: rect.right + 200,\n          y: rect.bottom + 200\n        }\n      );\n      fixture.detectChanges();\n\n      afterNextFrameRender(() => {\n        fixture.detectChanges();\n        expect(testComponent.width).toBe(200);\n        expect(testComponent.height).toBe(200);\n        done();\n      });\n    });\n\n    it('should element ref bounds work', done => {\n      const rect = resizableEle.getBoundingClientRect();\n      testComponent.bounds = testComponent.boxRef;\n      fixture.detectChanges();\n      const handle = resizableEle.querySelector('.nz-resizable-handle-bottomRight') as HTMLElement;\n      mouseMoveTrigger(\n        handle,\n        {\n          x: rect.right,\n          y: rect.bottom\n        },\n        {\n          x: rect.right + 300,\n          y: rect.bottom + 300\n        }\n      );\n      fixture.detectChanges();\n\n      afterNextFrameRender(() => {\n        fixture.detectChanges();\n        expect(testComponent.width).toBe(256);\n        expect(testComponent.height).toBe(256);\n        done();\n      });\n    });\n\n    it('should window bounds work', done => {\n      const rect = resizableEle.getBoundingClientRect();\n      testComponent.bounds = 'window';\n      fixture.detectChanges();\n      const handle = resizableEle.querySelector('.nz-resizable-handle-bottomRight') as HTMLElement;\n      mouseMoveTrigger(\n        handle,\n        {\n          x: rect.right,\n          y: rect.bottom\n        },\n        {\n          x: rect.right + window.innerWidth,\n          y: rect.bottom + window.innerHeight\n        }\n      );\n      fixture.detectChanges();\n\n      afterNextFrameRender(() => {\n        fixture.detectChanges();\n        expect(testComponent.width).toBe(300);\n        expect(testComponent.height).toBe(300);\n        testComponent.maxHeight = window.innerHeight * 2;\n        testComponent.maxWidth = window.innerWidth * 2;\n        fixture.detectChanges();\n        mouseMoveTrigger(\n          handle,\n          {\n            x: rect.right,\n            y: rect.bottom\n          },\n          {\n            x: rect.right + window.innerWidth,\n            y: rect.bottom + window.innerHeight\n          }\n        );\n        fixture.detectChanges();\n\n        afterNextFrameRender(() => {\n          fixture.detectChanges();\n          expect(testComponent.width).toBe(window.innerWidth);\n          expect(testComponent.height).toBe(window.innerHeight);\n          done();\n        });\n      });\n    });\n  });\n});\n\nfunction mouseMoveTrigger(el: HTMLElement, from: { x: number; y: number }, to: { x: number; y: number }): void {\n  dispatchMouseEvent(el, 'mousedown', from.x, from.y);\n  dispatchMouseEvent(window.document, 'mousemove', to.x, to.y);\n  dispatchMouseEvent(window.document, 'mouseup');\n}\n\nfunction touchMoveTrigger(el: HTMLElement, from: { x: number; y: number }, to: { x: number; y: number }): void {\n  dispatchTouchEvent(el, 'touchstart', from.x, from.y);\n  dispatchTouchEvent(window.document, 'touchmove', to.x, to.y);\n  dispatchTouchEvent(window.document, 'touchend');\n}\n\nfunction afterNextFrameRender(callbackFn: () => void): void {\n  setTimeout(callbackFn, 16);\n}\n\n@Component({\n  imports: [NzResizableModule],\n  template: `\n    <div class=\"box-ref\" #boxRef>\n      <div class=\"parent\">\n        <div\n          class=\"box\"\n          nz-resizable\n          [nzBounds]=\"bounds\"\n          [nzMaxWidth]=\"maxWidth\"\n          [nzMinWidth]=\"80\"\n          [nzMaxHeight]=\"maxHeight\"\n          [nzMinHeight]=\"80\"\n          [style.height.px]=\"height\"\n          [style.width.px]=\"width\"\n          (nzResize)=\"onResize($event)\"\n        >\n          <nz-resize-handles />\n          content\n        </div>\n      </div>\n    </div>\n  `,\n  styles: `\n    .box-ref {\n      width: 256px;\n      height: 256px;\n    }\n    .parent {\n      width: 200px;\n      height: 200px;\n    }\n  `\n})\nclass NzTestResizableBoundsComponent {\n  @ViewChild('boxRef', { static: false }) boxRef!: ElementRef<HTMLDivElement>;\n  bounds: 'window' | 'parent' | ElementRef = 'parent';\n  maxWidth = 300;\n  maxHeight = 300;\n  width = 100;\n  height = 100;\n  id = -1;\n\n  onResize({ width, height }: NzResizeEvent): void {\n    cancelAnimationFrame(this.id);\n    this.id = requestAnimationFrame(() => {\n      this.width = width!;\n      this.height = height!;\n    });\n  }\n}\n"
  },
  {
    "path": "components/resizable/resize-handle.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { normalizePassiveListenerOptions } from '@angular/cdk/platform';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  DestroyRef,\n  ElementRef,\n  EventEmitter,\n  inject,\n  Input,\n  OnInit,\n  Output,\n  Renderer2\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { merge } from 'rxjs';\n\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\n\nimport { NzResizableService } from './resizable.service';\n\nexport type NzCursorType = 'window' | 'grid';\n\nexport type NzResizeDirection =\n  | 'top'\n  | 'right'\n  | 'bottom'\n  | 'left'\n  | 'topRight'\n  | 'bottomRight'\n  | 'bottomLeft'\n  | 'topLeft';\n\nexport class NzResizeHandleMouseDownEvent {\n  constructor(\n    public direction: NzResizeDirection,\n    public mouseEvent: MouseEvent | TouchEvent\n  ) {}\n}\n\nconst passiveEventListenerOptions = normalizePassiveListenerOptions({ passive: true }) as AddEventListenerOptions;\n\n@Component({\n  selector: 'nz-resize-handle, [nz-resize-handle]',\n  exportAs: 'nzResizeHandle',\n  template: `<ng-content />`,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    class: 'nz-resizable-handle',\n    '[class.nz-resizable-handle-top]': `nzDirection === 'top'`,\n    '[class.nz-resizable-handle-right]': `nzDirection === 'right'`,\n    '[class.nz-resizable-handle-bottom]': `nzDirection === 'bottom'`,\n    '[class.nz-resizable-handle-left]': `nzDirection === 'left'`,\n    '[class.nz-resizable-handle-topRight]': `nzDirection === 'topRight'`,\n    '[class.nz-resizable-handle-bottomRight]': `nzDirection === 'bottomRight'`,\n    '[class.nz-resizable-handle-bottomLeft]': `nzDirection === 'bottomLeft'`,\n    '[class.nz-resizable-handle-topLeft]': `nzDirection === 'topLeft'`,\n    '[class.nz-resizable-handle-cursor-type-grid]': `nzCursorType === 'grid'`,\n    '[class.nz-resizable-handle-cursor-type-window]': `nzCursorType === 'window'`,\n    '(pointerdown)': 'onPointerDown($event)',\n    '(pointerup)': 'onPointerUp($event)'\n  }\n})\nexport class NzResizeHandleComponent implements OnInit {\n  private readonly nzResizableService = inject(NzResizableService);\n  private readonly renderer = inject(Renderer2);\n  private readonly el: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement;\n  private readonly destroyRef = inject(DestroyRef);\n\n  @Input() nzDirection: NzResizeDirection = 'bottomRight';\n  @Input() nzCursorType: NzCursorType = 'window';\n  @Output() readonly nzMouseDown = new EventEmitter<NzResizeHandleMouseDownEvent>();\n\n  ngOnInit(): void {\n    this.nzResizableService.mouseEnteredOutsideAngular$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(entered => {\n      if (entered) {\n        this.renderer.addClass(this.el, 'nz-resizable-handle-box-hover');\n      } else {\n        this.renderer.removeClass(this.el, 'nz-resizable-handle-box-hover');\n      }\n    });\n\n    // Note: since Chrome 56 defaults document level `touchstart` listener to passive.\n    // The element `touchstart` listener is not passive by default\n    // We never call `preventDefault()` on it, so we're safe making it passive too.\n    merge(\n      fromEventOutsideAngular<MouseEvent>(this.el, 'mousedown', passiveEventListenerOptions),\n      fromEventOutsideAngular<TouchEvent>(this.el, 'touchstart', passiveEventListenerOptions)\n    )\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(event => {\n        this.nzResizableService.handleMouseDownOutsideAngular$.next(\n          new NzResizeHandleMouseDownEvent(this.nzDirection, event)\n        );\n      });\n  }\n\n  onPointerDown(event: PointerEvent): void {\n    (event.target as HTMLElement).setPointerCapture(event.pointerId);\n  }\n\n  onPointerUp(event: PointerEvent): void {\n    (event.target as HTMLElement).releasePointerCapture(event.pointerId);\n  }\n}\n"
  },
  {
    "path": "components/resizable/resize-handles.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from '@angular/core';\n\nimport { NzCursorType, NzResizeDirection, NzResizeHandleComponent } from './resize-handle.component';\n\nexport const DEFAULT_RESIZE_DIRECTION: NzResizeDirection[] = [\n  'bottomRight',\n  'topRight',\n  'bottomLeft',\n  'topLeft',\n  'bottom',\n  'right',\n  'top',\n  'left'\n];\n\nexport interface NzResizeHandleOption {\n  direction: NzResizeDirection;\n  cursorType: NzCursorType;\n}\n\nfunction normalizeResizeHandleOptions(value: Array<NzResizeDirection | NzResizeHandleOption>): NzResizeHandleOption[] {\n  return value.map(val => {\n    if (typeof val === 'string') {\n      return {\n        direction: val,\n        cursorType: 'window'\n      };\n    }\n\n    return val;\n  });\n}\n\n@Component({\n  selector: 'nz-resize-handles',\n  exportAs: 'nzResizeHandles',\n  template: `\n    @for (option of resizeHandleOptions; track option) {\n      <nz-resize-handle [nzDirection]=\"option.direction\" [nzCursorType]=\"option.cursorType\" />\n    }\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  imports: [NzResizeHandleComponent]\n})\nexport class NzResizeHandlesComponent implements OnChanges {\n  @Input() nzDirections: Array<NzResizeDirection | NzResizeHandleOption> = DEFAULT_RESIZE_DIRECTION;\n\n  resizeHandleOptions = normalizeResizeHandleOptions(this.nzDirections);\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzDirections } = changes;\n    if (nzDirections) {\n      this.resizeHandleOptions = normalizeResizeHandleOptions(nzDirections.currentValue);\n    }\n  }\n}\n"
  },
  {
    "path": "components/resizable/style/entry.less",
    "content": "@import './index.less';\n\n"
  },
  {
    "path": "components/resizable/style/index.less",
    "content": "@resizable-prefix-cls: ~'nz-resizable';\n\n.@{resizable-prefix-cls} {\n  &-preview {\n    position: absolute;\n    top: 0;\n    left: 0;\n    z-index: 8;\n    border: 1px dashed #d1d1d1;\n  }\n\n  &-handle {\n    position: absolute;\n    z-index: 9;\n    user-select: none;\n\n    &-top {\n      top: -5px;\n      left: 0;\n      width: 100%;\n      height: 10px;\n    }\n\n    &-right {\n      top: 0;\n      right: -5px;\n      width: 10px;\n      height: 100%;\n    }\n\n    &-bottom {\n      bottom: -5px;\n      left: 0;\n      width: 100%;\n      height: 10px;\n    }\n\n    &-left {\n      top: 0;\n      left: -5px;\n      width: 10px;\n      height: 100%;\n    }\n\n    &-topRight {\n      top: -5px;\n      right: -5px;\n      z-index: 10;\n      width: 20px;\n      height: 20px;\n    }\n\n    &-bottomRight {\n      right: -5px;\n      bottom: -5px;\n      z-index: 10;\n      width: 20px;\n      height: 20px;\n    }\n\n    &-bottomLeft {\n      bottom: -5px;\n      left: -5px;\n      z-index: 10;\n      width: 20px;\n      height: 20px;\n    }\n\n    &-topLeft {\n      top: -5px;\n      left: -5px;\n      z-index: 10;\n      width: 20px;\n      height: 20px;\n    }\n  }\n\n  .@{resizable-prefix-cls}-handle {\n    &-cursor-type {\n      &-window {\n        &.@{resizable-prefix-cls}-handle {\n          &-top,\n          &-bottom {\n            cursor: ns-resize;\n          }\n\n          &-right,\n          &-left {\n            cursor: ew-resize;\n          }\n        }\n      }\n\n      &-grid {\n        &.@{resizable-prefix-cls}-handle {\n          &-top,\n          &-bottom {\n            cursor: row-resize;\n          }\n\n          &-right,\n          &-left {\n            cursor: col-resize;\n          }\n        }\n      }\n    }\n\n    &-bottomRight,\n    &-topLeft {\n      cursor: nwse-resize;\n    }\n\n    &-bottomLeft,\n    &-topRight {\n      cursor: nesw-resize;\n    }\n  }\n\n  &-disabled {\n    .@{resizable-prefix-cls} {\n      &-handle {\n        pointer-events: none;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/result/demo/custom.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 自定义 icon\n  en-US: Custom Icon\n---\n\n## zh-CN\n\n自定义 icon。\n\n## en-US\n\nCustom icon.\n"
  },
  {
    "path": "components/result/demo/custom.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzResultModule } from 'ng-zorro-antd/result';\n\n@Component({\n  selector: 'nz-demo-result-custom',\n  imports: [NzButtonModule, NzResultModule],\n  template: `\n    <nz-result nzIcon=\"smile-o\" nzTitle=\"Great, we have done all the operators!\">\n      <div nz-result-extra>\n        <button nz-button nzType=\"primary\">Next</button>\n      </div>\n    </nz-result>\n  `\n})\nexport class NzDemoResultCustomComponent {}\n"
  },
  {
    "path": "components/result/demo/error.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: Error\n  en-US: Error\n---\n\n## zh-CN\n\n复杂的错误反馈。\n\n## en-US\n\nComplex error feedback.\n"
  },
  {
    "path": "components/result/demo/error.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzResultModule } from 'ng-zorro-antd/result';\nimport { NzTypographyModule } from 'ng-zorro-antd/typography';\n\n@Component({\n  selector: 'nz-demo-result-error',\n  imports: [NzButtonModule, NzIconModule, NzResultModule, NzTypographyModule],\n  template: `\n    <nz-result\n      nzTitle=\"Submission Failed\"\n      nzStatus=\"error\"\n      nzSubTitle=\"Please check and modify the following information before resubmitting.\"\n    >\n      <div nz-result-content>\n        <div class=\"desc\">\n          <h4 nz-title>The content you submitted has the following error:</h4>\n          <p nz-paragraph>\n            <nz-icon nzType=\"close-circle\" />\n            Your account has been frozen\n            <a>Thaw immediately &gt;</a>\n          </p>\n          <p nz-paragraph>\n            <nz-icon nzType=\"close-circle\" />\n            Your account is not yet eligible to apply\n            <a>Apply immediately &gt;</a>\n          </p>\n        </div>\n      </div>\n      <div nz-result-extra>\n        <button nz-button nzType=\"primary\">Go Console</button>\n        <button nz-button>Buy Again</button>\n      </div>\n    </nz-result>\n  `\n})\nexport class NzDemoResultErrorComponent {}\n"
  },
  {
    "path": "components/result/demo/fof.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 404\n  en-US: 404\n---\n\n## zh-CN\n\n此页面未找到。\n\n## en-US\n\nThe page you visited does not exist.\n"
  },
  {
    "path": "components/result/demo/fof.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzResultModule } from 'ng-zorro-antd/result';\n\n@Component({\n  selector: 'nz-demo-result-fof',\n  imports: [NzButtonModule, NzResultModule],\n  template: `\n    <nz-result nzStatus=\"404\" nzTitle=\"404\" nzSubTitle=\"Sorry, the page you visited does not exist.\">\n      <div nz-result-extra>\n        <button nz-button nzType=\"primary\">Back Home</button>\n      </div>\n    </nz-result>\n  `\n})\nexport class NzDemoResultFofComponent {}\n"
  },
  {
    "path": "components/result/demo/foo.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 500\n  en-US: 500\n---\n\n## zh-CN\n\n服务器发生了错误。\n\n## en-US\n\nThere is an error on server.\n"
  },
  {
    "path": "components/result/demo/foo.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzResultModule } from 'ng-zorro-antd/result';\n\n@Component({\n  selector: 'nz-demo-result-foo',\n  imports: [NzButtonModule, NzResultModule],\n  template: `\n    <nz-result nzStatus=\"500\" nzTitle=\"500\" nzSubTitle=\"Sorry, there is an error on server.\">\n      <div nz-result-extra>\n        <button nz-button nzType=\"primary\">Back Home</button>\n      </div>\n    </nz-result>\n  `\n})\nexport class NzDemoResultFooComponent {}\n"
  },
  {
    "path": "components/result/demo/fot.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 403\n  en-US: 403\n---\n\n## zh-CN\n\n你没有此页面的访问权限。\n\n## en-US\n\nYou are not authorized to access this page.\n"
  },
  {
    "path": "components/result/demo/fot.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzResultModule } from 'ng-zorro-antd/result';\n\n@Component({\n  selector: 'nz-demo-result-fot',\n  imports: [NzButtonModule, NzResultModule],\n  template: `\n    <nz-result nzStatus=\"403\" nzTitle=\"403\" nzSubTitle=\"Sorry, you are not authorized to access this page.\">\n      <div nz-result-extra>\n        <button nz-button nzType=\"primary\">Back Home</button>\n      </div>\n    </nz-result>\n  `\n})\nexport class NzDemoResultFotComponent {}\n"
  },
  {
    "path": "components/result/demo/info.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: Info\n  en-US: Info\n---\n\n## zh-CN\n\n展示处理结果。\n\n## en-US\n\nShow processing results.\n"
  },
  {
    "path": "components/result/demo/info.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzResultModule } from 'ng-zorro-antd/result';\n\n@Component({\n  selector: 'nz-demo-result-info',\n  imports: [NzButtonModule, NzResultModule],\n  template: `\n    <nz-result nzStatus=\"info\" nzTitle=\"Your operation has been executed\">\n      <div nz-result-extra>\n        <button nz-button nzType=\"primary\">Go Console</button>\n      </div>\n    </nz-result>\n  `\n})\nexport class NzDemoResultInfoComponent {}\n"
  },
  {
    "path": "components/result/demo/success.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: Success\n  en-US: Success\n---\n\n## zh-CN\n\n成功的结果。\n\n## en-US\n\nShow successful results.\n"
  },
  {
    "path": "components/result/demo/success.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzResultModule } from 'ng-zorro-antd/result';\n\n@Component({\n  selector: 'nz-demo-result-success',\n  imports: [NzButtonModule, NzResultModule],\n  template: `\n    <nz-result\n      nzStatus=\"success\"\n      nzTitle=\"Successfully Purchased Cloud Server ECS!\"\n      nzSubTitle=\"Order number: 2017182818828182881 Cloud server configuration takes 1-5 minutes, please wait.\"\n    >\n      <div nz-result-extra>\n        <button nz-button nzType=\"primary\">Go Console</button>\n        <button nz-button>Buy Again</button>\n      </div>\n    </nz-result>\n  `\n})\nexport class NzDemoResultSuccessComponent {}\n"
  },
  {
    "path": "components/result/demo/warning.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: Warning\n  en-US: Warning\n---\n\n## zh-CN\n\n警告类型的结果。\n\n## en-US\n\nShow warning.\n"
  },
  {
    "path": "components/result/demo/warning.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzResultModule } from 'ng-zorro-antd/result';\n\n@Component({\n  selector: 'nz-demo-result-warning',\n  imports: [NzButtonModule, NzResultModule],\n  template: `\n    <nz-result nzStatus=\"warning\" nzTitle=\"There are some problems with your operation\">\n      <div nz-result-extra>\n        <button nz-button nzType=\"primary\">Go Console</button>\n      </div>\n    </nz-result>\n  `\n})\nexport class NzDemoResultWarningComponent {}\n"
  },
  {
    "path": "components/result/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Feedback\ntitle: Result\ncols: 1\ncover: 'https://gw.alipayobjects.com/zos/alicdn/9nepwjaLa/Result.svg'\ndescription: Used to feed back the results of a series of operational tasks.\n---\n\n## When To Use\n\nUse when important operations need to inform the user to process the results and the feedback is more complicated.\n\n## API\n\n### nz-result\n\n| Property     | Description                             | Type                                                                    | Default  |\n| ------------ | --------------------------------------- | ----------------------------------------------------------------------- | -------- |\n| `nzTitle`    | title                                   | `TemplateRef<void> \\| string`                                           | -        |\n| `nzSubTitle` | subTitle                                | `TemplateRef<void> \\| string`                                           | -        |\n| `nzStatus`   | result status, decides icons and colors | `'success' \\| 'error' \\| 'info' \\| 'warning'\\| '404' \\| '403' \\| '500'` | `'info'` |\n| `nzIcon`     | custom icon                             | `TemplateRef<void> \\| string`                                           | -        |\n| `nzExtra`    | operating area                          | `TemplateRef<void> \\| string`                                           | -        |\n\n### Counter Parts\n\nYou can use these directives as children of nz-result.\n\n| Directive                 | Description                              |\n| ------------------------- | ---------------------------------------- |\n| `[nz-result-icon]`        | custom icon                              |\n| `div[nz-result-title]`    | title                                    |\n| `div[nz-result-subtitle]` | subtitle                                 |\n| `div[nz-result-content]`  | contents, for detailed explanations      |\n| `div[nz-result-extra]`    | extra content, usually an operating area |\n"
  },
  {
    "path": "components/result/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ntype: 反馈\ntitle: Result\nsubtitle: 结果\ncols: 1\ncover: 'https://gw.alipayobjects.com/zos/alicdn/9nepwjaLa/Result.svg'\ndescription: 用于反馈一系列操作任务的处理结果。\n---\n\n## 何时使用\n\n当有重要操作需告知用户处理结果，且反馈内容较为复杂时使用。\n\n## API\n\n### nz-result\n\n| 属性         | 说明                       | 类型                                                                    | 默认值   |\n| ------------ | -------------------------- | ----------------------------------------------------------------------- | -------- |\n| `nzTitle`    | 标题                       | `TemplateRef<void> \\| string`                                           | -        |\n| `nzSubTitle` | 副标题                     | `TemplateRef<void> \\| string`                                           | -        |\n| `nzStatus`   | 结果的状态，决定图标和颜色 | `'success' \\| 'error' \\| 'info' \\| 'warning'\\| '404' \\| '403' \\| '500'` | `'info'` |\n| `nzIcon`     | 自定义 icon                | `TemplateRef<void> \\| string`                                           | -        |\n| `nzExtra`    | 操作区域                   | `TemplateRef<void> \\| string`                                           | -        |\n\n### 子元素\n\n你可以在 nz-result 中加入如下指令，它们的优先级低于上面的参数。\n\n| 元素                      | 说明                     |\n| ------------------------- | ------------------------ |\n| `[nz-result-icon]`        | 在顶部展示的大图标       |\n| `div[nz-result-title]`    | 标题                     |\n| `div[nz-result-subtitle]` | 副标题                   |\n| `div[nz-result-content]`  | 内容，可以展示详细的信息 |\n| `div[nz-result-extra]`    | 操作区域                 |\n"
  },
  {
    "path": "components/result/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/result/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/result/partial/not-found.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-result-not-found',\n  exportAs: 'nzResultNotFound',\n  template: `\n    <svg width=\"252\" height=\"294\">\n      <defs>\n        <path d=\"M0 .387h251.772v251.772H0z\" />\n      </defs>\n      <g fill=\"none\" fillRule=\"evenodd\">\n        <g transform=\"translate(0 .012)\">\n          <mask fill=\"#fff\" />\n          <path\n            d=\"M0 127.32v-2.095C0 56.279 55.892.387 124.838.387h2.096c68.946 0 124.838 55.892 124.838 124.838v2.096c0 68.946-55.892 124.838-124.838 124.838h-2.096C55.892 252.16 0 196.267 0 127.321\"\n            fill=\"#E4EBF7\"\n            mask=\"url(#b)\"\n          />\n        </g>\n        <path d=\"M39.755 130.84a8.276 8.276 0 1 1-16.468-1.66 8.276 8.276 0 0 1 16.468 1.66\" fill=\"#FFF\" />\n        <path d=\"M36.975 134.297l10.482 5.943M48.373 146.508l-12.648 10.788\" stroke=\"#FFF\" strokeWidth=\"2\" />\n        <path\n          d=\"M39.875 159.352a5.667 5.667 0 1 1-11.277-1.136 5.667 5.667 0 0 1 11.277 1.136M57.588 143.247a5.708 5.708 0 1 1-11.358-1.145 5.708 5.708 0 0 1 11.358 1.145M99.018 26.875l29.82-.014a4.587 4.587 0 1 0-.003-9.175l-29.82.013a4.587 4.587 0 1 0 .003 9.176M110.424 45.211l29.82-.013a4.588 4.588 0 0 0-.004-9.175l-29.82.013a4.587 4.587 0 1 0 .004 9.175\"\n          fill=\"#FFF\"\n        />\n        <path\n          d=\"M112.798 26.861v-.002l15.784-.006a4.588 4.588 0 1 0 .003 9.175l-15.783.007v-.002a4.586 4.586 0 0 0-.004-9.172M184.523 135.668c-.553 5.485-5.447 9.483-10.931 8.93-5.485-.553-9.483-5.448-8.93-10.932.552-5.485 5.447-9.483 10.932-8.93 5.485.553 9.483 5.447 8.93 10.932\"\n          fill=\"#FFF\"\n        />\n        <path d=\"M179.26 141.75l12.64 7.167M193.006 156.477l-15.255 13.011\" par stroke=\"#FFF\" strokeWidth=\"2\" />\n        <path\n          d=\"M184.668 170.057a6.835 6.835 0 1 1-13.6-1.372 6.835 6.835 0 0 1 13.6 1.372M203.34 153.325a6.885 6.885 0 1 1-13.7-1.382 6.885 6.885 0 0 1 13.7 1.382\"\n          fill=\"#FFF\"\n        />\n        <path\n          d=\"M151.931 192.324a2.222 2.222 0 1 1-4.444 0 2.222 2.222 0 0 1 4.444 0zM225.27 116.056a2.222 2.222 0 1 1-4.445 0 2.222 2.222 0 0 1 4.444 0zM216.38 151.08a2.223 2.223 0 1 1-4.446-.001 2.223 2.223 0 0 1 4.446 0zM176.917 107.636a2.223 2.223 0 1 1-4.445 0 2.223 2.223 0 0 1 4.445 0zM195.291 92.165a2.223 2.223 0 1 1-4.445 0 2.223 2.223 0 0 1 4.445 0zM202.058 180.711a2.223 2.223 0 1 1-4.446 0 2.223 2.223 0 0 1 4.446 0z\"\n          stroke=\"#FFF\"\n          strokeWidth=\"2\"\n        />\n        <path\n          stroke=\"#FFF\"\n          strokeWidth=\"2\"\n          d=\"M214.404 153.302l-1.912 20.184-10.928 5.99M173.661 174.792l-6.356 9.814h-11.36l-4.508 6.484M174.941 125.168v-15.804M220.824 117.25l-12.84 7.901-15.31-7.902V94.39\"\n        />\n        <path\n          d=\"M166.588 65.936h-3.951a4.756 4.756 0 0 1-4.743-4.742 4.756 4.756 0 0 1 4.743-4.743h3.951a4.756 4.756 0 0 1 4.743 4.743 4.756 4.756 0 0 1-4.743 4.742\"\n          fill=\"#FFF\"\n        />\n        <path\n          d=\"M174.823 30.03c0-16.281 13.198-29.48 29.48-29.48 16.28 0 29.48 13.199 29.48 29.48 0 16.28-13.2 29.48-29.48 29.48-16.282 0-29.48-13.2-29.48-29.48\"\n          fill=\"#1890FF\"\n        />\n        <path\n          d=\"M205.952 38.387c.5.5.785 1.142.785 1.928s-.286 1.465-.785 1.964c-.572.5-1.214.75-2 .75-.785 0-1.429-.285-1.929-.785-.572-.5-.82-1.143-.82-1.929s.248-1.428.82-1.928c.5-.5 1.144-.75 1.93-.75.785 0 1.462.25 1.999.75m4.285-19.463c1.428 1.249 2.143 2.963 2.143 5.142 0 1.712-.427 3.13-1.219 4.25-.067.096-.137.18-.218.265-.416.429-1.41 1.346-2.956 2.699a5.07 5.07 0 0 0-1.428 1.75 5.207 5.207 0 0 0-.536 2.357v.5h-4.107v-.5c0-1.357.215-2.536.714-3.5.464-.964 1.857-2.464 4.178-4.536l.43-.5c.643-.785.964-1.643.964-2.535 0-1.18-.358-2.108-1-2.785-.678-.68-1.643-1.001-2.858-1.001-1.536 0-2.642.464-3.357 1.43-.37.5-.621 1.135-.76 1.904a1.999 1.999 0 0 1-1.971 1.63h-.004c-1.277 0-2.257-1.183-1.98-2.43.337-1.518 1.02-2.78 2.073-3.784 1.536-1.5 3.607-2.25 6.25-2.25 2.32 0 4.214.607 5.642 1.894\"\n          fill=\"#FFF\"\n        />\n        <path\n          d=\"M52.04 76.131s21.81 5.36 27.307 15.945c5.575 10.74-6.352 9.26-15.73 4.935-10.86-5.008-24.7-11.822-11.577-20.88\"\n          fill=\"#FFB594\"\n        />\n        <path\n          d=\"M90.483 67.504l-.449 2.893c-.753.49-4.748-2.663-4.748-2.663l-1.645.748-1.346-5.684s6.815-4.589 8.917-5.018c2.452-.501 9.884.94 10.7 2.278 0 0 1.32.486-2.227.69-3.548.203-5.043.447-6.79 3.132-1.747 2.686-2.412 3.624-2.412 3.624\"\n          fill=\"#FFC6A0\"\n        />\n        <path\n          d=\"M128.055 111.367c-2.627-7.724-6.15-13.18-8.917-15.478-3.5-2.906-9.34-2.225-11.366-4.187-1.27-1.231-3.215-1.197-3.215-1.197s-14.98-3.158-16.828-3.479c-2.37-.41-2.124-.714-6.054-1.405-1.57-1.907-2.917-1.122-2.917-1.122l-7.11-1.383c-.853-1.472-2.423-1.023-2.423-1.023l-2.468-.897c-1.645 9.976-7.74 13.796-7.74 13.796 1.795 1.122 15.703 8.3 15.703 8.3l5.107 37.11s-3.321 5.694 1.346 9.109c0 0 19.883-3.743 34.921-.329 0 0 3.047-2.546.972-8.806.523-3.01 1.394-8.263 1.736-11.622.385.772 2.019 1.918 3.14 3.477 0 0 9.407-7.365 11.052-14.012-.832-.723-1.598-1.585-2.267-2.453-.567-.736-.358-2.056-.765-2.717-.669-1.084-1.804-1.378-1.907-1.682\"\n          fill=\"#FFF\"\n        />\n        <path\n          d=\"M101.09 289.998s4.295 2.041 7.354 1.021c2.821-.94 4.53.668 7.08 1.178 2.55.51 6.874 1.1 11.686-1.26-.103-5.51-6.889-3.98-11.96-6.713-2.563-1.38-3.784-4.722-3.598-8.799h-9.402s-1.392 10.52-1.16 14.573\"\n          fill=\"#CBD1D1\"\n        />\n        <path\n          d=\"M101.067 289.826s2.428 1.271 6.759.653c3.058-.437 3.712.481 7.423 1.031 3.712.55 10.724-.069 11.823-.894.413 1.1-.343 2.063-.343 2.063s-1.512.603-4.812.824c-2.03.136-5.8.291-7.607-.503-1.787-1.375-5.247-1.903-5.728-.241-3.918.95-7.355-.286-7.355-.286l-.16-2.647z\"\n          fill=\"#2B0849\"\n        />\n        <path d=\"M108.341 276.044h3.094s-.103 6.702 4.536 8.558c-4.64.618-8.558-2.303-7.63-8.558\" fill=\"#A4AABA\" />\n        <path\n          d=\"M57.542 272.401s-2.107 7.416-4.485 12.306c-1.798 3.695-4.225 7.492 5.465 7.492 6.648 0 8.953-.48 7.423-6.599-1.53-6.12.266-13.199.266-13.199h-8.669z\"\n          fill=\"#CBD1D1\"\n        />\n        <path\n          d=\"M51.476 289.793s2.097 1.169 6.633 1.169c6.083 0 8.249-1.65 8.249-1.65s.602 1.114-.619 2.165c-.993.855-3.597 1.591-7.39 1.546-4.145-.048-5.832-.566-6.736-1.168-.825-.55-.687-1.58-.137-2.062\"\n          fill=\"#2B0849\"\n        />\n        <path\n          d=\"M58.419 274.304s.033 1.519-.314 2.93c-.349 1.42-1.078 3.104-1.13 4.139-.058 1.151 4.537 1.58 5.155.034.62-1.547 1.294-6.427 1.913-7.252.619-.825-4.903-2.119-5.624.15\"\n          fill=\"#A4AABA\"\n        />\n        <path\n          d=\"M99.66 278.514l13.378.092s1.298-54.52 1.853-64.403c.554-9.882 3.776-43.364 1.002-63.128l-12.547-.644-22.849.78s-.434 3.966-1.195 9.976c-.063.496-.682.843-.749 1.365-.075.585.423 1.354.32 1.966-2.364 14.08-6.377 33.104-8.744 46.677-.116.666-1.234 1.009-1.458 2.691-.04.302.211 1.525.112 1.795-6.873 18.744-10.949 47.842-14.277 61.885l14.607-.014s2.197-8.57 4.03-16.97c2.811-12.886 23.111-85.01 23.111-85.01l3.016-.521 1.043 46.35s-.224 1.234.337 2.02c.56.785-.56 1.123-.392 2.244l.392 1.794s-.449 7.178-.898 11.89c-.448 4.71-.092 39.165-.092 39.165\"\n          fill=\"#7BB2F9\"\n        />\n        <path\n          d=\"M76.085 221.626c1.153.094 4.038-2.019 6.955-4.935M106.36 225.142s2.774-1.11 6.103-3.883\"\n          stroke=\"#648BD8\"\n          strokeWidth=\"1.051\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path d=\"M107.275 222.1s2.773-1.11 6.102-3.884\" stroke=\"#648BD8\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n        <path\n          d=\"M74.74 224.767s2.622-.591 6.505-3.365M86.03 151.634c-.27 3.106.3 8.525-4.336 9.123M103.625 149.88s.11 14.012-1.293 15.065c-2.219 1.664-2.99 1.944-2.99 1.944M99.79 150.438s.035 12.88-1.196 24.377M93.673 175.911s7.212-1.664 9.431-1.664M74.31 205.861a212.013 212.013 0 0 1-.979 4.56s-1.458 1.832-1.009 3.776c.449 1.944-.947 2.045-4.985 15.355-1.696 5.59-4.49 18.591-6.348 27.597l-.231 1.12M75.689 197.807a320.934 320.934 0 0 1-.882 4.754M82.591 152.233L81.395 162.7s-1.097.15-.5 2.244c.113 1.346-2.674 15.775-5.18 30.43M56.12 274.418h13.31\"\n          stroke=\"#648BD8\"\n          strokeWidth=\"1.051\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M116.241 148.22s-17.047-3.104-35.893.2c.158 2.514-.003 4.15-.003 4.15s14.687-2.818 35.67-.312c.252-2.355.226-4.038.226-4.038\"\n          fill=\"#192064\"\n        />\n        <path\n          d=\"M106.322 151.165l.003-4.911a.81.81 0 0 0-.778-.815c-2.44-.091-5.066-.108-7.836-.014a.818.818 0 0 0-.789.815l-.003 4.906a.81.81 0 0 0 .831.813c2.385-.06 4.973-.064 7.73.017a.815.815 0 0 0 .842-.81\"\n          fill=\"#FFF\"\n        />\n        <path\n          d=\"M105.207 150.233l.002-3.076a.642.642 0 0 0-.619-.646 94.321 94.321 0 0 0-5.866-.01.65.65 0 0 0-.63.647v3.072a.64.64 0 0 0 .654.644 121.12 121.12 0 0 1 5.794.011c.362.01.665-.28.665-.642\"\n          fill=\"#192064\"\n        />\n        <path\n          d=\"M100.263 275.415h12.338M101.436 270.53c.006 3.387.042 5.79.111 6.506M101.451 264.548a915.75 915.75 0 0 0-.015 4.337M100.986 174.965l.898 44.642s.673 1.57-.225 2.692c-.897 1.122 2.468.673.898 2.243-1.57 1.57.897 1.122 0 3.365-.596 1.489-.994 21.1-1.096 35.146\"\n          stroke=\"#648BD8\"\n          strokeWidth=\"1.051\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M46.876 83.427s-.516 6.045 7.223 5.552c11.2-.712 9.218-9.345 31.54-21.655-.786-2.708-2.447-4.744-2.447-4.744s-11.068 3.11-22.584 8.046c-6.766 2.9-13.395 6.352-13.732 12.801M104.46 91.057l.941-5.372-8.884-11.43-5.037 5.372-1.74 7.834a.321.321 0 0 0 .108.32c.965.8 6.5 5.013 14.347 3.544a.332.332 0 0 0 .264-.268\"\n          fill=\"#FFC6A0\"\n        />\n        <path\n          d=\"M93.942 79.387s-4.533-2.853-2.432-6.855c1.623-3.09 4.513 1.133 4.513 1.133s.52-3.642 3.121-3.642c.52-1.04 1.561-4.162 1.561-4.162s11.445 2.601 13.526 3.121c0 5.203-2.304 19.424-7.84 19.861-8.892.703-12.449-9.456-12.449-9.456\"\n          fill=\"#FFC6A0\"\n        />\n        <path\n          d=\"M113.874 73.446c2.601-2.081 3.47-9.722 3.47-9.722s-2.479-.49-6.64-2.05c-4.683-2.081-12.798-4.747-17.48.976-9.668 3.223-2.05 19.823-2.05 19.823l2.713-3.021s-3.935-3.287-2.08-6.243c2.17-3.462 3.92 1.073 3.92 1.073s.637-2.387 3.581-3.342c.355-.71 1.036-2.674 1.432-3.85a1.073 1.073 0 0 1 1.263-.704c2.4.558 8.677 2.019 11.356 2.662.522.125.871.615.82 1.15l-.305 3.248z\"\n          fill=\"#520038\"\n        />\n        <path\n          d=\"M104.977 76.064c-.103.61-.582 1.038-1.07.956-.489-.083-.801-.644-.698-1.254.103-.61.582-1.038 1.07-.956.488.082.8.644.698 1.254M112.132 77.694c-.103.61-.582 1.038-1.07.956-.488-.083-.8-.644-.698-1.254.103-.61.582-1.038 1.07-.956.488.082.8.643.698 1.254\"\n          fill=\"#552950\"\n        />\n        <path\n          stroke=\"#DB836E\"\n          strokeWidth=\"1.118\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n          d=\"M110.13 74.84l-.896 1.61-.298 4.357h-2.228\"\n        />\n        <path\n          d=\"M110.846 74.481s1.79-.716 2.506.537\"\n          stroke=\"#5C2552\"\n          strokeWidth=\"1.118\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M92.386 74.282s.477-1.114 1.113-.716c.637.398 1.274 1.433.558 1.99-.717.556.159 1.67.159 1.67\"\n          stroke=\"#DB836E\"\n          strokeWidth=\"1.118\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M103.287 72.93s1.83 1.113 4.137.954\"\n          stroke=\"#5C2552\"\n          strokeWidth=\"1.118\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M103.685 81.762s2.227 1.193 4.376 1.193M104.64 84.308s.954.398 1.511.318M94.693 81.205s2.308 7.4 10.424 7.639\"\n          stroke=\"#DB836E\"\n          strokeWidth=\"1.118\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M81.45 89.384s.45 5.647-4.935 12.787M69 82.654s-.726 9.282-8.204 14.206\"\n          stroke=\"#E4EBF7\"\n          strokeWidth=\"1.101\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M129.405 122.865s-5.272 7.403-9.422 10.768\"\n          stroke=\"#E4EBF7\"\n          strokeWidth=\"1.051\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M119.306 107.329s.452 4.366-2.127 32.062\"\n          stroke=\"#E4EBF7\"\n          strokeWidth=\"1.101\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M150.028 151.232h-49.837a1.01 1.01 0 0 1-1.01-1.01v-31.688c0-.557.452-1.01 1.01-1.01h49.837c.558 0 1.01.453 1.01 1.01v31.688a1.01 1.01 0 0 1-1.01 1.01\"\n          fill=\"#F2D7AD\"\n        />\n        <path d=\"M150.29 151.232h-19.863v-33.707h20.784v32.786a.92.92 0 0 1-.92.92\" fill=\"#F4D19D\" />\n        <path\n          d=\"M123.554 127.896H92.917a.518.518 0 0 1-.425-.816l6.38-9.113c.193-.277.51-.442.85-.442h31.092l-7.26 10.371z\"\n          fill=\"#F2D7AD\"\n        />\n        <path fill=\"#CC9B6E\" d=\"M123.689 128.447H99.25v-.519h24.169l7.183-10.26.424.298z\" />\n        <path\n          d=\"M158.298 127.896h-18.669a2.073 2.073 0 0 1-1.659-.83l-7.156-9.541h19.965c.49 0 .95.23 1.244.622l6.69 8.92a.519.519 0 0 1-.415.83\"\n          fill=\"#F4D19D\"\n        />\n        <path\n          fill=\"#CC9B6E\"\n          d=\"M157.847 128.479h-19.384l-7.857-10.475.415-.31 7.7 10.266h19.126zM130.554 150.685l-.032-8.177.519-.002.032 8.177z\"\n        />\n        <path\n          fill=\"#CC9B6E\"\n          d=\"M130.511 139.783l-.08-21.414.519-.002.08 21.414zM111.876 140.932l-.498-.143 1.479-5.167.498.143zM108.437 141.06l-2.679-2.935 2.665-3.434.41.318-2.397 3.089 2.384 2.612zM116.607 141.06l-.383-.35 2.383-2.612-2.397-3.089.41-.318 2.665 3.434z\"\n        />\n        <path\n          d=\"M154.316 131.892l-3.114-1.96.038 3.514-1.043.092c-1.682.115-3.634.23-4.789.23-1.902 0-2.693 2.258 2.23 2.648l-2.645-.596s-2.168 1.317.504 2.3c0 0-1.58 1.217.561 2.58-.584 3.504 5.247 4.058 7.122 3.59 1.876-.47 4.233-2.359 4.487-5.16.28-3.085-.89-5.432-3.35-7.238\"\n          fill=\"#FFC6A0\"\n        />\n        <path\n          d=\"M153.686 133.577s-6.522.47-8.36.372c-1.836-.098-1.904 2.19 2.359 2.264 3.739.15 5.451-.044 5.451-.044\"\n          stroke=\"#DB836E\"\n          strokeWidth=\"1.051\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M145.16 135.877c-1.85 1.346.561 2.355.561 2.355s3.478.898 6.73.617\"\n          stroke=\"#DB836E\"\n          strokeWidth=\"1.051\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M151.89 141.71s-6.28.111-6.73-2.132c-.223-1.346.45-1.402.45-1.402M146.114 140.868s-1.103 3.16 5.44 3.533M151.202 129.932v3.477M52.838 89.286c3.533-.337 8.423-1.248 13.582-7.754\"\n          stroke=\"#DB836E\"\n          strokeWidth=\"1.051\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M168.567 248.318a6.647 6.647 0 0 1-6.647-6.647v-66.466a6.647 6.647 0 1 1 13.294 0v66.466a6.647 6.647 0 0 1-6.647 6.647\"\n          fill=\"#5BA02E\"\n        />\n        <path\n          d=\"M176.543 247.653a6.647 6.647 0 0 1-6.646-6.647v-33.232a6.647 6.647 0 1 1 13.293 0v33.232a6.647 6.647 0 0 1-6.647 6.647\"\n          fill=\"#92C110\"\n        />\n        <path\n          d=\"M186.443 293.613H158.92a3.187 3.187 0 0 1-3.187-3.187v-46.134a3.187 3.187 0 0 1 3.187-3.187h27.524a3.187 3.187 0 0 1 3.187 3.187v46.134a3.187 3.187 0 0 1-3.187 3.187\"\n          fill=\"#F2D7AD\"\n        />\n        <path\n          d=\"M88.979 89.48s7.776 5.384 16.6 2.842\"\n          stroke=\"#E4EBF7\"\n          strokeWidth=\"1.101\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n      </g>\n    </svg>\n  `\n})\nexport class NzResultNotFoundComponent {}\n"
  },
  {
    "path": "components/result/partial/server-error.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-result-server-error',\n  exportAs: 'nzResultServerError',\n  template: `\n    <svg width=\"254\" height=\"294\">\n      <defs>\n        <path d=\"M0 .335h253.49v253.49H0z\" />\n        <path d=\"M0 293.665h253.49V.401H0z\" />\n      </defs>\n      <g fill=\"none\" fillRule=\"evenodd\">\n        <g transform=\"translate(0 .067)\">\n          <mask fill=\"#fff\" />\n          <path\n            d=\"M0 128.134v-2.11C0 56.608 56.273.334 125.69.334h2.11c69.416 0 125.69 56.274 125.69 125.69v2.11c0 69.417-56.274 125.69-125.69 125.69h-2.11C56.273 253.824 0 197.551 0 128.134\"\n            fill=\"#E4EBF7\"\n            mask=\"url(#b)\"\n          />\n        </g>\n        <path d=\"M39.989 132.108a8.332 8.332 0 1 1-16.581-1.671 8.332 8.332 0 0 1 16.58 1.671\" fill=\"#FFF\" />\n        <path d=\"M37.19 135.59l10.553 5.983M48.665 147.884l-12.734 10.861\" stroke=\"#FFF\" strokeWidth=\"2\" />\n        <path\n          d=\"M40.11 160.816a5.706 5.706 0 1 1-11.354-1.145 5.706 5.706 0 0 1 11.354 1.145M57.943 144.6a5.747 5.747 0 1 1-11.436-1.152 5.747 5.747 0 0 1 11.436 1.153M99.656 27.434l30.024-.013a4.619 4.619 0 1 0-.004-9.238l-30.024.013a4.62 4.62 0 0 0 .004 9.238M111.14 45.896l30.023-.013a4.62 4.62 0 1 0-.004-9.238l-30.024.013a4.619 4.619 0 1 0 .004 9.238\"\n          fill=\"#FFF\"\n        />\n        <path\n          d=\"M113.53 27.421v-.002l15.89-.007a4.619 4.619 0 1 0 .005 9.238l-15.892.007v-.002a4.618 4.618 0 0 0-.004-9.234M150.167 70.091h-3.979a4.789 4.789 0 0 1-4.774-4.775 4.788 4.788 0 0 1 4.774-4.774h3.979a4.789 4.789 0 0 1 4.775 4.774 4.789 4.789 0 0 1-4.775 4.775\"\n          fill=\"#FFF\"\n        />\n        <path\n          d=\"M171.687 30.234c0-16.392 13.289-29.68 29.681-29.68 16.392 0 29.68 13.288 29.68 29.68 0 16.393-13.288 29.681-29.68 29.681s-29.68-13.288-29.68-29.68\"\n          fill=\"#FF603B\"\n        />\n        <path\n          d=\"M203.557 19.435l-.676 15.035a1.514 1.514 0 0 1-3.026 0l-.675-15.035a2.19 2.19 0 1 1 4.377 0m-.264 19.378c.513.477.77 1.1.77 1.87s-.257 1.393-.77 1.907c-.55.476-1.21.733-1.943.733a2.545 2.545 0 0 1-1.87-.77c-.55-.514-.806-1.136-.806-1.87 0-.77.256-1.393.806-1.87.513-.513 1.137-.733 1.87-.733.77 0 1.43.22 1.943.733\"\n          fill=\"#FFF\"\n        />\n        <path\n          d=\"M119.3 133.275c4.426-.598 3.612-1.204 4.079-4.778.675-5.18-3.108-16.935-8.262-25.118-1.088-10.72-12.598-11.24-12.598-11.24s4.312 4.895 4.196 16.199c1.398 5.243.804 14.45.804 14.45s5.255 11.369 11.78 10.487\"\n          fill=\"#FFB594\"\n        />\n        <path\n          d=\"M100.944 91.61s1.463-.583 3.211.582c8.08 1.398 10.368 6.706 11.3 11.368 1.864 1.282 1.864 2.33 1.864 3.496.365.777 1.515 3.03 1.515 3.03s-7.225 1.748-10.954 6.758c-1.399-6.41-6.936-25.235-6.936-25.235\"\n          fill=\"#FFF\"\n        />\n        <path d=\"M94.008 90.5l1.019-5.815-9.23-11.874-5.233 5.581-2.593 9.863s8.39 5.128 16.037 2.246\" fill=\"#FFB594\" />\n        <path\n          d=\"M82.931 78.216s-4.557-2.868-2.445-6.892c1.632-3.107 4.537 1.139 4.537 1.139s.524-3.662 3.139-3.662c.523-1.046 1.569-4.184 1.569-4.184s11.507 2.615 13.6 3.138c-.001 5.23-2.317 19.529-7.884 19.969-8.94.706-12.516-9.508-12.516-9.508\"\n          fill=\"#FFC6A0\"\n        />\n        <path\n          d=\"M102.971 72.243c2.616-2.093 3.489-9.775 3.489-9.775s-2.492-.492-6.676-2.062c-4.708-2.092-12.867-4.771-17.575.982-9.54 4.41-2.062 19.93-2.062 19.93l2.729-3.037s-3.956-3.304-2.092-6.277c2.183-3.48 3.943 1.08 3.943 1.08s.64-2.4 3.6-3.36c.356-.714 1.04-2.69 1.44-3.872a1.08 1.08 0 0 1 1.27-.707c2.41.56 8.723 2.03 11.417 2.676.524.126.876.619.825 1.156l-.308 3.266z\"\n          fill=\"#520038\"\n        />\n        <path\n          d=\"M101.22 76.514c-.104.613-.585 1.044-1.076.96-.49-.082-.805-.646-.702-1.26.104-.613.585-1.044 1.076-.961.491.083.805.647.702 1.26M94.26 75.074c-.104.613-.585 1.044-1.076.96-.49-.082-.805-.646-.702-1.26.104-.613.585-1.044 1.076-.96.491.082.805.646.702 1.26\"\n          fill=\"#552950\"\n        />\n        <path\n          stroke=\"#DB836E\"\n          strokeWidth=\"1.063\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n          d=\"M99.206 73.644l-.9 1.62-.3 4.38h-2.24\"\n        />\n        <path\n          d=\"M99.926 73.284s1.8-.72 2.52.54\"\n          stroke=\"#5C2552\"\n          strokeWidth=\"1.117\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M81.367 73.084s.48-1.12 1.12-.72c.64.4 1.28 1.44.56 2s.16 1.68.16 1.68\"\n          stroke=\"#DB836E\"\n          strokeWidth=\"1.117\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M92.326 71.724s1.84 1.12 4.16.96\"\n          stroke=\"#5C2552\"\n          strokeWidth=\"1.117\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M92.726 80.604s2.24 1.2 4.4 1.2M93.686 83.164s.96.4 1.52.32M83.687 80.044s1.786 6.547 9.262 7.954\"\n          stroke=\"#DB836E\"\n          strokeWidth=\"1.063\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M95.548 91.663s-1.068 2.821-8.298 2.105c-7.23-.717-10.29-5.044-10.29-5.044\"\n          stroke=\"#E4EBF7\"\n          strokeWidth=\"1.136\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M78.126 87.478s6.526 4.972 16.47 2.486c0 0 9.577 1.02 11.536 5.322 5.36 11.77.543 36.835 0 39.962 3.496 4.055-.466 8.483-.466 8.483-15.624-3.548-35.81-.6-35.81-.6-4.849-3.546-1.223-9.044-1.223-9.044L62.38 110.32c-2.485-15.227.833-19.803 3.549-20.743 3.03-1.049 8.04-1.282 8.04-1.282.496-.058 1.08-.076 1.37-.233 2.36-1.282 2.787-.583 2.787-.583\"\n          fill=\"#FFF\"\n        />\n        <path\n          d=\"M65.828 89.81s-6.875.465-7.59 8.156c-.466 8.857 3.03 10.954 3.03 10.954s6.075 22.102 16.796 22.957c8.39-2.176 4.758-6.702 4.661-11.42-.233-11.304-7.108-16.897-7.108-16.897s-4.212-13.75-9.789-13.75\"\n          fill=\"#FFC6A0\"\n        />\n        <path\n          d=\"M71.716 124.225s.855 11.264 9.828 6.486c4.765-2.536 7.581-13.828 9.789-22.568 1.456-5.768 2.58-12.197 2.58-12.197l-4.973-1.709s-2.408 5.516-7.769 12.275c-4.335 5.467-9.144 11.11-9.455 17.713\"\n          fill=\"#FFC6A0\"\n        />\n        <path\n          d=\"M108.463 105.191s1.747 2.724-2.331 30.535c2.376 2.216 1.053 6.012-.233 7.51\"\n          stroke=\"#E4EBF7\"\n          strokeWidth=\"1.085\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M123.262 131.527s-.427 2.732-11.77 1.981c-15.187-1.006-25.326-3.25-25.326-3.25l.933-5.8s.723.215 9.71-.068c11.887-.373 18.714-6.07 24.964-1.022 4.039 3.263 1.489 8.16 1.489 8.16\"\n          fill=\"#FFC6A0\"\n        />\n        <path\n          d=\"M70.24 90.974s-5.593-4.739-11.054 2.68c-3.318 7.223.517 15.284 2.664 19.578-.31 3.729 2.33 4.311 2.33 4.311s.108.895 1.516 2.68c4.078-7.03 6.72-9.166 13.711-12.546-.328-.656-1.877-3.265-1.825-3.767.175-1.69-1.282-2.623-1.282-2.623s-.286-.156-1.165-2.738c-.788-2.313-2.036-5.177-4.895-7.575\"\n          fill=\"#FFF\"\n        />\n        <path\n          d=\"M90.232 288.027s4.855 2.308 8.313 1.155c3.188-1.063 5.12.755 8.002 1.331 2.881.577 7.769 1.243 13.207-1.424-.117-6.228-7.786-4.499-13.518-7.588-2.895-1.56-4.276-5.336-4.066-9.944H91.544s-1.573 11.89-1.312 16.47\"\n          fill=\"#CBD1D1\"\n        />\n        <path\n          d=\"M90.207 287.833s2.745 1.437 7.639.738c3.456-.494 3.223.66 7.418 1.282 4.195.621 13.092-.194 14.334-1.126.466 1.242-.388 2.33-.388 2.33s-1.709.682-5.438.932c-2.295.154-8.098.276-10.14-.621-2.02-1.554-4.894-1.515-6.06-.234-4.427 1.075-7.184-.31-7.184-.31l-.181-2.991z\"\n          fill=\"#2B0849\"\n        />\n        <path d=\"M98.429 272.257h3.496s-.117 7.574 5.127 9.671c-5.244.7-9.672-2.602-8.623-9.671\" fill=\"#A4AABA\" />\n        <path\n          d=\"M44.425 272.046s-2.208 7.774-4.702 12.899c-1.884 3.874-4.428 7.854 5.729 7.854 6.97 0 9.385-.503 7.782-6.917-1.604-6.415.279-13.836.279-13.836h-9.088z\"\n          fill=\"#CBD1D1\"\n        />\n        <path\n          d=\"M38.066 290.277s2.198 1.225 6.954 1.225c6.376 0 8.646-1.73 8.646-1.73s.63 1.168-.649 2.27c-1.04.897-3.77 1.668-7.745 1.621-4.347-.05-6.115-.593-7.062-1.224-.864-.577-.72-1.657-.144-2.162\"\n          fill=\"#2B0849\"\n        />\n        <path\n          d=\"M45.344 274.041s.035 1.592-.329 3.07c-.365 1.49-1.13 3.255-1.184 4.34-.061 1.206 4.755 1.657 5.403.036.65-1.622 1.357-6.737 2.006-7.602.648-.865-5.14-2.222-5.896.156\"\n          fill=\"#A4AABA\"\n        />\n        <path\n          d=\"M89.476 277.57l13.899.095s1.349-56.643 1.925-66.909c.576-10.267 3.923-45.052 1.042-65.585l-13.037-.669-23.737.81s-.452 4.12-1.243 10.365c-.065.515-.708.874-.777 1.417-.078.608.439 1.407.332 2.044-2.455 14.627-5.797 32.736-8.256 46.837-.121.693-1.282 1.048-1.515 2.796-.042.314.22 1.584.116 1.865-7.14 19.473-12.202 52.601-15.66 67.19l15.176-.015s2.282-10.145 4.185-18.871c2.922-13.389 24.012-88.32 24.012-88.32l3.133-.954-.158 48.568s-.233 1.282.35 2.098c.583.815-.581 1.167-.408 2.331l.408 1.864s-.466 7.458-.932 12.352c-.467 4.895 1.145 40.69 1.145 40.69\"\n          fill=\"#7BB2F9\"\n        />\n        <path\n          d=\"M64.57 218.881c1.197.099 4.195-2.097 7.225-5.127M96.024 222.534s2.881-1.152 6.34-4.034\"\n          stroke=\"#648BD8\"\n          strokeWidth=\"1.085\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M96.973 219.373s2.882-1.153 6.34-4.034\"\n          stroke=\"#648BD8\"\n          strokeWidth=\"1.032\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M63.172 222.144s2.724-.614 6.759-3.496M74.903 146.166c-.281 3.226.31 8.856-4.506 9.478M93.182 144.344s.115 14.557-1.344 15.65c-2.305 1.73-3.107 2.02-3.107 2.02M89.197 144.923s.269 13.144-1.01 25.088M83.525 170.71s6.81-1.051 9.116-1.051M46.026 270.045l-.892 4.538M46.937 263.289l-.815 4.157M62.725 202.503c-.33 1.618-.102 1.904-.449 3.438 0 0-2.756 1.903-2.29 3.923.466 2.02-.31 3.424-4.505 17.252-1.762 5.807-4.233 18.922-6.165 28.278-.03.144-.521 2.646-1.14 5.8M64.158 194.136c-.295 1.658-.6 3.31-.917 4.938M71.33 146.787l-1.244 10.877s-1.14.155-.519 2.33c.117 1.399-2.778 16.39-5.382 31.615M44.242 273.727H58.07\"\n          stroke=\"#648BD8\"\n          strokeWidth=\"1.085\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M106.18 142.117c-3.028-.489-18.825-2.744-36.219.2a.625.625 0 0 0-.518.644c.063 1.307.044 2.343.015 2.995a.617.617 0 0 0 .716.636c3.303-.534 17.037-2.412 35.664-.266.347.04.66-.214.692-.56.124-1.347.16-2.425.17-3.029a.616.616 0 0 0-.52-.62\"\n          fill=\"#192064\"\n        />\n        <path\n          d=\"M96.398 145.264l.003-5.102a.843.843 0 0 0-.809-.847 114.104 114.104 0 0 0-8.141-.014.85.85 0 0 0-.82.847l-.003 5.097c0 .476.388.857.864.845 2.478-.064 5.166-.067 8.03.017a.848.848 0 0 0 .876-.843\"\n          fill=\"#FFF\"\n        />\n        <path\n          d=\"M95.239 144.296l.002-3.195a.667.667 0 0 0-.643-.672c-1.9-.061-3.941-.073-6.094-.01a.675.675 0 0 0-.654.672l-.002 3.192c0 .376.305.677.68.669 1.859-.042 3.874-.043 6.02.012.376.01.69-.291.691-.668\"\n          fill=\"#192064\"\n        />\n        <path\n          d=\"M90.102 273.522h12.819M91.216 269.761c.006 3.519-.072 5.55 0 6.292M90.923 263.474c-.009 1.599-.016 2.558-.016 4.505M90.44 170.404l.932 46.38s.7 1.631-.233 2.796c-.932 1.166 2.564.7.932 2.33-1.63 1.633.933 1.166 0 3.497-.618 1.546-1.031 21.921-1.138 36.513\"\n          stroke=\"#648BD8\"\n          strokeWidth=\"1.085\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M73.736 98.665l2.214 4.312s2.098.816 1.865 2.68l.816 2.214M64.297 116.611c.233-.932 2.176-7.147 12.585-10.488M77.598 90.042s7.691 6.137 16.547 2.72\"\n          stroke=\"#E4EBF7\"\n          strokeWidth=\"1.085\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M91.974 86.954s5.476-.816 7.574-4.545c1.297-.345.72 2.212-.33 3.671-.7.971-1.01 1.554-1.01 1.554s.194.31.155.816c-.053.697-.175.653-.272 1.048-.081.335.108.657 0 1.049-.046.17-.198.5-.382.878-.12.249-.072.687-.2.948-.231.469-1.562 1.87-2.622 2.855-3.826 3.554-5.018 1.644-6.001-.408-.894-1.865-.661-5.127-.874-6.875-.35-2.914-2.622-3.03-1.923-4.429.343-.685 2.87.69 3.263 1.748.757 2.04 2.952 1.807 2.622 1.69\"\n          fill=\"#FFC6A0\"\n        />\n        <path\n          d=\"M99.8 82.429c-.465.077-.35.272-.97 1.243-.622.971-4.817 2.932-6.39 3.224-2.589.48-2.278-1.56-4.254-2.855-1.69-1.107-3.562-.638-1.398 1.398.99.932.932 1.107 1.398 3.205.335 1.506-.64 3.67.7 5.593\"\n          stroke=\"#DB836E\"\n          strokeWidth=\".774\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M79.543 108.673c-2.1 2.926-4.266 6.175-5.557 8.762\"\n          stroke=\"#E59788\"\n          strokeWidth=\".774\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M87.72 124.768s-2.098-1.942-5.127-2.719c-3.03-.777-3.574-.155-5.516.078-1.942.233-3.885-.932-3.652.7.233 1.63 5.05 1.01 5.206 2.097.155 1.087-6.37 2.796-8.313 2.175-.777.777.466 1.864 2.02 2.175.233 1.554 2.253 1.554 2.253 1.554s.699 1.01 2.641 1.088c2.486 1.32 8.934-.7 10.954-1.554 2.02-.855-.466-5.594-.466-5.594\"\n          fill=\"#FFC6A0\"\n        />\n        <path\n          d=\"M73.425 122.826s.66 1.127 3.167 1.418c2.315.27 2.563.583 2.563.583s-2.545 2.894-9.07 2.272M72.416 129.274s3.826.097 4.933-.718M74.98 130.75s1.961.136 3.36-.505M77.232 131.916s1.748.019 2.914-.505M73.328 122.321s-.595-1.032 1.262-.427c1.671.544 2.833.055 5.128.155 1.389.061 3.067-.297 3.982.15 1.606.784 3.632 2.181 3.632 2.181s10.526 1.204 19.033-1.127M78.864 108.104s-8.39 2.758-13.168 12.12\"\n          stroke=\"#E59788\"\n          strokeWidth=\".774\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M109.278 112.533s3.38-3.613 7.575-4.662\"\n          stroke=\"#E4EBF7\"\n          strokeWidth=\"1.085\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M107.375 123.006s9.697-2.745 11.445-.88\"\n          stroke=\"#E59788\"\n          strokeWidth=\".774\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M194.605 83.656l3.971-3.886M187.166 90.933l3.736-3.655M191.752 84.207l-4.462-4.56M198.453 91.057l-4.133-4.225M129.256 163.074l3.718-3.718M122.291 170.039l3.498-3.498M126.561 163.626l-4.27-4.27M132.975 170.039l-3.955-3.955\"\n          stroke=\"#BFCDDD\"\n          strokeWidth=\"2\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M190.156 211.779h-1.604a4.023 4.023 0 0 1-4.011-4.011V175.68a4.023 4.023 0 0 1 4.01-4.01h1.605a4.023 4.023 0 0 1 4.011 4.01v32.088a4.023 4.023 0 0 1-4.01 4.01\"\n          fill=\"#A3B4C6\"\n        />\n        <path\n          d=\"M237.824 212.977a4.813 4.813 0 0 1-4.813 4.813h-86.636a4.813 4.813 0 0 1 0-9.626h86.636a4.813 4.813 0 0 1 4.813 4.813\"\n          fill=\"#A3B4C6\"\n        />\n        <mask fill=\"#fff\" />\n        <path fill=\"#A3B4C6\" mask=\"url(#d)\" d=\"M154.098 190.096h70.513v-84.617h-70.513z\" />\n        <path\n          d=\"M224.928 190.096H153.78a3.219 3.219 0 0 1-3.208-3.209V167.92a3.219 3.219 0 0 1 3.208-3.21h71.148a3.219 3.219 0 0 1 3.209 3.21v18.967a3.219 3.219 0 0 1-3.21 3.209M224.928 130.832H153.78a3.218 3.218 0 0 1-3.208-3.208v-18.968a3.219 3.219 0 0 1 3.208-3.209h71.148a3.219 3.219 0 0 1 3.209 3.21v18.967a3.218 3.218 0 0 1-3.21 3.208\"\n          fill=\"#BFCDDD\"\n          mask=\"url(#d)\"\n        />\n        <path\n          d=\"M159.563 120.546a2.407 2.407 0 1 1 0-4.813 2.407 2.407 0 0 1 0 4.813M166.98 120.546a2.407 2.407 0 1 1 0-4.813 2.407 2.407 0 0 1 0 4.813M174.397 120.546a2.407 2.407 0 1 1 0-4.813 2.407 2.407 0 0 1 0 4.813M222.539 120.546h-22.461a.802.802 0 0 1-.802-.802v-3.208c0-.443.359-.803.802-.803h22.46c.444 0 .803.36.803.803v3.208c0 .443-.36.802-.802.802\"\n          fill=\"#FFF\"\n          mask=\"url(#d)\"\n        />\n        <path\n          d=\"M224.928 160.464H153.78a3.218 3.218 0 0 1-3.208-3.209v-18.967a3.219 3.219 0 0 1 3.208-3.209h71.148a3.219 3.219 0 0 1 3.209 3.209v18.967a3.218 3.218 0 0 1-3.21 3.209\"\n          fill=\"#BFCDDD\"\n          mask=\"url(#d)\"\n        />\n        <path\n          d=\"M173.455 130.832h49.301M164.984 130.832h6.089M155.952 130.832h6.75M173.837 160.613h49.3M165.365 160.613h6.089M155.57 160.613h6.751\"\n          stroke=\"#7C90A5\"\n          strokeWidth=\"1.124\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n          mask=\"url(#d)\"\n        />\n        <path\n          d=\"M159.563 151.038a2.407 2.407 0 1 1 0-4.814 2.407 2.407 0 0 1 0 4.814M166.98 151.038a2.407 2.407 0 1 1 0-4.814 2.407 2.407 0 0 1 0 4.814M174.397 151.038a2.407 2.407 0 1 1 .001-4.814 2.407 2.407 0 0 1 0 4.814M222.539 151.038h-22.461a.802.802 0 0 1-.802-.802v-3.209c0-.443.359-.802.802-.802h22.46c.444 0 .803.36.803.802v3.209c0 .443-.36.802-.802.802M159.563 179.987a2.407 2.407 0 1 1 0-4.813 2.407 2.407 0 0 1 0 4.813M166.98 179.987a2.407 2.407 0 1 1 0-4.813 2.407 2.407 0 0 1 0 4.813M174.397 179.987a2.407 2.407 0 1 1 0-4.813 2.407 2.407 0 0 1 0 4.813M222.539 179.987h-22.461a.802.802 0 0 1-.802-.802v-3.209c0-.443.359-.802.802-.802h22.46c.444 0 .803.36.803.802v3.209c0 .443-.36.802-.802.802\"\n          fill=\"#FFF\"\n          mask=\"url(#d)\"\n        />\n        <path\n          d=\"M203.04 221.108h-27.372a2.413 2.413 0 0 1-2.406-2.407v-11.448a2.414 2.414 0 0 1 2.406-2.407h27.372a2.414 2.414 0 0 1 2.407 2.407V218.7a2.413 2.413 0 0 1-2.407 2.407\"\n          fill=\"#BFCDDD\"\n          mask=\"url(#d)\"\n        />\n        <path\n          d=\"M177.259 207.217v11.52M201.05 207.217v11.52\"\n          stroke=\"#A3B4C6\"\n          strokeWidth=\"1.124\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n          mask=\"url(#d)\"\n        />\n        <path\n          d=\"M162.873 267.894a9.422 9.422 0 0 1-9.422-9.422v-14.82a9.423 9.423 0 0 1 18.845 0v14.82a9.423 9.423 0 0 1-9.423 9.422\"\n          fill=\"#5BA02E\"\n          mask=\"url(#d)\"\n        />\n        <path\n          d=\"M171.22 267.83a9.422 9.422 0 0 1-9.422-9.423v-3.438a9.423 9.423 0 0 1 18.845 0v3.438a9.423 9.423 0 0 1-9.422 9.423\"\n          fill=\"#92C110\"\n          mask=\"url(#d)\"\n        />\n        <path\n          d=\"M181.31 293.666h-27.712a3.209 3.209 0 0 1-3.209-3.21V269.79a3.209 3.209 0 0 1 3.209-3.21h27.711a3.209 3.209 0 0 1 3.209 3.21v20.668a3.209 3.209 0 0 1-3.209 3.209\"\n          fill=\"#F2D7AD\"\n          mask=\"url(#d)\"\n        />\n      </g>\n    </svg>\n  `\n})\nexport class NzResultServerErrorComponent {}\n"
  },
  {
    "path": "components/result/partial/unauthorized.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-result-unauthorized',\n  exportAs: 'nzResultUnauthorized',\n  template: `\n    <svg width=\"251\" height=\"294\">\n      <g fill=\"none\" fillRule=\"evenodd\">\n        <path\n          d=\"M0 129.023v-2.084C0 58.364 55.591 2.774 124.165 2.774h2.085c68.574 0 124.165 55.59 124.165 124.165v2.084c0 68.575-55.59 124.166-124.165 124.166h-2.085C55.591 253.189 0 197.598 0 129.023\"\n          fill=\"#E4EBF7\"\n        />\n        <path d=\"M41.417 132.92a8.231 8.231 0 1 1-16.38-1.65 8.231 8.231 0 0 1 16.38 1.65\" fill=\"#FFF\" />\n        <path d=\"M38.652 136.36l10.425 5.91M49.989 148.505l-12.58 10.73\" stroke=\"#FFF\" strokeWidth=\"2\" />\n        <path\n          d=\"M41.536 161.28a5.636 5.636 0 1 1-11.216-1.13 5.636 5.636 0 0 1 11.216 1.13M59.154 145.261a5.677 5.677 0 1 1-11.297-1.138 5.677 5.677 0 0 1 11.297 1.138M100.36 29.516l29.66-.013a4.562 4.562 0 1 0-.004-9.126l-29.66.013a4.563 4.563 0 0 0 .005 9.126M111.705 47.754l29.659-.013a4.563 4.563 0 1 0-.004-9.126l-29.66.013a4.563 4.563 0 1 0 .005 9.126\"\n          fill=\"#FFF\"\n        />\n        <path\n          d=\"M114.066 29.503V29.5l15.698-.007a4.563 4.563 0 1 0 .004 9.126l-15.698.007v-.002a4.562 4.562 0 0 0-.004-9.122M185.405 137.723c-.55 5.455-5.418 9.432-10.873 8.882-5.456-.55-9.432-5.418-8.882-10.873.55-5.455 5.418-9.432 10.873-8.882 5.455.55 9.432 5.418 8.882 10.873\"\n          fill=\"#FFF\"\n        />\n        <path d=\"M180.17 143.772l12.572 7.129M193.841 158.42L178.67 171.36\" stroke=\"#FFF\" strokeWidth=\"2\" />\n        <path\n          d=\"M185.55 171.926a6.798 6.798 0 1 1-13.528-1.363 6.798 6.798 0 0 1 13.527 1.363M204.12 155.285a6.848 6.848 0 1 1-13.627-1.375 6.848 6.848 0 0 1 13.626 1.375\"\n          fill=\"#FFF\"\n        />\n        <path\n          d=\"M152.988 194.074a2.21 2.21 0 1 1-4.42 0 2.21 2.21 0 0 1 4.42 0zM225.931 118.217a2.21 2.21 0 1 1-4.421 0 2.21 2.21 0 0 1 4.421 0zM217.09 153.051a2.21 2.21 0 1 1-4.421 0 2.21 2.21 0 0 1 4.42 0zM177.84 109.842a2.21 2.21 0 1 1-4.422 0 2.21 2.21 0 0 1 4.421 0zM196.114 94.454a2.21 2.21 0 1 1-4.421 0 2.21 2.21 0 0 1 4.421 0zM202.844 182.523a2.21 2.21 0 1 1-4.42 0 2.21 2.21 0 0 1 4.42 0z\"\n          stroke=\"#FFF\"\n          strokeWidth=\"2\"\n        />\n        <path\n          stroke=\"#FFF\"\n          strokeWidth=\"2\"\n          d=\"M215.125 155.262l-1.902 20.075-10.87 5.958M174.601 176.636l-6.322 9.761H156.98l-4.484 6.449M175.874 127.28V111.56M221.51 119.404l-12.77 7.859-15.228-7.86V96.668\"\n        />\n        <path\n          d=\"M180.68 29.32C180.68 13.128 193.806 0 210 0c16.193 0 29.32 13.127 29.32 29.32 0 16.194-13.127 29.322-29.32 29.322-16.193 0-29.32-13.128-29.32-29.321\"\n          fill=\"#A26EF4\"\n        />\n        <path\n          d=\"M221.45 41.706l-21.563-.125a1.744 1.744 0 0 1-1.734-1.754l.071-12.23a1.744 1.744 0 0 1 1.754-1.734l21.562.125c.964.006 1.74.791 1.735 1.755l-.071 12.229a1.744 1.744 0 0 1-1.754 1.734\"\n          fill=\"#FFF\"\n        />\n        <path\n          d=\"M215.106 29.192c-.015 2.577-2.049 4.654-4.543 4.64-2.494-.014-4.504-2.115-4.489-4.693l.04-6.925c.016-2.577 2.05-4.654 4.543-4.64 2.494.015 4.504 2.116 4.49 4.693l-.04 6.925zm-4.53-14.074a6.877 6.877 0 0 0-6.916 6.837l-.043 7.368a6.877 6.877 0 0 0 13.754.08l.042-7.368a6.878 6.878 0 0 0-6.837-6.917zM167.566 68.367h-3.93a4.73 4.73 0 0 1-4.717-4.717 4.73 4.73 0 0 1 4.717-4.717h3.93a4.73 4.73 0 0 1 4.717 4.717 4.73 4.73 0 0 1-4.717 4.717\"\n          fill=\"#FFF\"\n        />\n        <path\n          d=\"M168.214 248.838a6.611 6.611 0 0 1-6.61-6.611v-66.108a6.611 6.611 0 0 1 13.221 0v66.108a6.611 6.611 0 0 1-6.61 6.61\"\n          fill=\"#5BA02E\"\n        />\n        <path\n          d=\"M176.147 248.176a6.611 6.611 0 0 1-6.61-6.61v-33.054a6.611 6.611 0 1 1 13.221 0v33.053a6.611 6.611 0 0 1-6.61 6.611\"\n          fill=\"#92C110\"\n        />\n        <path\n          d=\"M185.994 293.89h-27.376a3.17 3.17 0 0 1-3.17-3.17v-45.887a3.17 3.17 0 0 1 3.17-3.17h27.376a3.17 3.17 0 0 1 3.17 3.17v45.886a3.17 3.17 0 0 1-3.17 3.17\"\n          fill=\"#F2D7AD\"\n        />\n        <path\n          d=\"M81.972 147.673s6.377-.927 17.566-1.28c11.729-.371 17.57 1.086 17.57 1.086s3.697-3.855.968-8.424c1.278-12.077 5.982-32.827.335-48.273-1.116-1.339-3.743-1.512-7.536-.62-1.337.315-7.147-.149-7.983-.1l-15.311-.347s-3.487-.17-8.035-.508c-1.512-.113-4.227-1.683-5.458-.338-.406.443-2.425 5.669-1.97 16.077l8.635 35.642s-3.141 3.61 1.219 7.085\"\n          fill=\"#FFF\"\n        />\n        <path\n          d=\"M75.768 73.325l-.9-6.397 11.982-6.52s7.302-.118 8.038 1.205c.737 1.324-5.616.993-5.616.993s-1.836 1.388-2.615 2.5c-1.654 2.363-.986 6.471-8.318 5.986-1.708.284-2.57 2.233-2.57 2.233\"\n          fill=\"#FFC6A0\"\n        />\n        <path\n          d=\"M52.44 77.672s14.217 9.406 24.973 14.444c1.061.497-2.094 16.183-11.892 11.811-7.436-3.318-20.162-8.44-21.482-14.496-.71-3.258 2.543-7.643 8.401-11.76M141.862 80.113s-6.693 2.999-13.844 6.876c-3.894 2.11-10.137 4.704-12.33 7.988-6.224 9.314 3.536 11.22 12.947 7.503 6.71-2.651 28.999-12.127 13.227-22.367\"\n          fill=\"#FFB594\"\n        />\n        <path\n          d=\"M76.166 66.36l3.06 3.881s-2.783 2.67-6.31 5.747c-7.103 6.195-12.803 14.296-15.995 16.44-3.966 2.662-9.754 3.314-12.177-.118-3.553-5.032.464-14.628 31.422-25.95\"\n          fill=\"#FFC6A0\"\n        />\n        <path\n          d=\"M64.674 85.116s-2.34 8.413-8.912 14.447c.652.548 18.586 10.51 22.144 10.056 5.238-.669 6.417-18.968 1.145-20.531-.702-.208-5.901-1.286-8.853-2.167-.87-.26-1.611-1.71-3.545-.936l-1.98-.869zM128.362 85.826s5.318 1.956 7.325 13.734c-.546.274-17.55 12.35-21.829 7.805-6.534-6.94-.766-17.393 4.275-18.61 4.646-1.121 5.03-1.37 10.23-2.929\"\n          fill=\"#FFF\"\n        />\n        <path\n          d=\"M78.18 94.656s.911 7.41-4.914 13.078\"\n          stroke=\"#E4EBF7\"\n          strokeWidth=\"1.051\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M87.397 94.68s3.124 2.572 10.263 2.572c7.14 0 9.074-3.437 9.074-3.437\"\n          stroke=\"#E4EBF7\"\n          strokeWidth=\".932\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M117.184 68.639l-6.781-6.177s-5.355-4.314-9.223-.893c-3.867 3.422 4.463 2.083 5.653 4.165 1.19 2.082.848 1.143-2.083.446-5.603-1.331-2.082.893 2.975 5.355 2.091 1.845 6.992.955 6.992.955l2.467-3.851z\"\n          fill=\"#FFC6A0\"\n        />\n        <path\n          d=\"M105.282 91.315l-.297-10.937-15.918-.027-.53 10.45c-.026.403.17.788.515.999 2.049 1.251 9.387 5.093 15.799.424.287-.21.443-.554.431-.91\"\n          fill=\"#FFB594\"\n        />\n        <path\n          d=\"M107.573 74.24c.817-1.147.982-9.118 1.015-11.928a1.046 1.046 0 0 0-.965-1.055l-4.62-.365c-7.71-1.044-17.071.624-18.253 6.346-5.482 5.813-.421 13.244-.421 13.244s1.963 3.566 4.305 6.791c.756 1.041.398-3.731 3.04-5.929 5.524-4.594 15.899-7.103 15.899-7.103\"\n          fill=\"#5C2552\"\n        />\n        <path\n          d=\"M88.426 83.206s2.685 6.202 11.602 6.522c7.82.28 8.973-7.008 7.434-17.505l-.909-5.483c-6.118-2.897-15.478.54-15.478.54s-.576 2.044-.19 5.504c-2.276 2.066-1.824 5.618-1.824 5.618s-.905-1.922-1.98-2.321c-.86-.32-1.897.089-2.322 1.98-1.04 4.632 3.667 5.145 3.667 5.145\"\n          fill=\"#FFC6A0\"\n        />\n        <path\n          stroke=\"#DB836E\"\n          strokeWidth=\"1.145\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n          d=\"M100.843 77.099l1.701-.928-1.015-4.324.674-1.406\"\n        />\n        <path\n          d=\"M105.546 74.092c-.022.713-.452 1.279-.96 1.263-.51-.016-.904-.607-.882-1.32.021-.713.452-1.278.96-1.263.51.016.904.607.882 1.32M97.592 74.349c-.022.713-.452 1.278-.961 1.263-.509-.016-.904-.607-.882-1.32.022-.713.452-1.279.961-1.263.51.016.904.606.882 1.32\"\n          fill=\"#552950\"\n        />\n        <path\n          d=\"M91.132 86.786s5.269 4.957 12.679 2.327\"\n          stroke=\"#DB836E\"\n          strokeWidth=\"1.145\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M99.776 81.903s-3.592.232-1.44-2.79c1.59-1.496 4.897-.46 4.897-.46s1.156 3.906-3.457 3.25\"\n          fill=\"#DB836E\"\n        />\n        <path\n          d=\"M102.88 70.6s2.483.84 3.402.715M93.883 71.975s2.492-1.144 4.778-1.073\"\n          stroke=\"#5C2552\"\n          strokeWidth=\"1.526\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M86.32 77.374s.961.879 1.458 2.106c-.377.48-1.033 1.152-.236 1.809M99.337 83.719s1.911.151 2.509-.254\"\n          stroke=\"#DB836E\"\n          strokeWidth=\"1.145\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M87.782 115.821l15.73-3.012M100.165 115.821l10.04-2.008\"\n          stroke=\"#E4EBF7\"\n          strokeWidth=\"1.051\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M66.508 86.763s-1.598 8.83-6.697 14.078\"\n          stroke=\"#E4EBF7\"\n          strokeWidth=\"1.114\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M128.31 87.934s3.013 4.121 4.06 11.785\"\n          stroke=\"#E4EBF7\"\n          strokeWidth=\"1.051\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M64.09 84.816s-6.03 9.912-13.607 9.903\"\n          stroke=\"#DB836E\"\n          strokeWidth=\".795\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M112.366 65.909l-.142 5.32s5.993 4.472 11.945 9.202c4.482 3.562 8.888 7.455 10.985 8.662 4.804 2.766 8.9 3.355 11.076 1.808 4.071-2.894 4.373-9.878-8.136-15.263-4.271-1.838-16.144-6.36-25.728-9.73\"\n          fill=\"#FFC6A0\"\n        />\n        <path\n          d=\"M130.532 85.488s4.588 5.757 11.619 6.214\"\n          stroke=\"#DB836E\"\n          strokeWidth=\".75\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M121.708 105.73s-.393 8.564-1.34 13.612\"\n          stroke=\"#E4EBF7\"\n          strokeWidth=\"1.051\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M115.784 161.512s-3.57-1.488-2.678-7.14\"\n          stroke=\"#648BD8\"\n          strokeWidth=\"1.051\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M101.52 290.246s4.326 2.057 7.408 1.03c2.842-.948 4.564.673 7.132 1.186 2.57.514 6.925 1.108 11.772-1.269-.104-5.551-6.939-4.01-12.048-6.763-2.582-1.39-3.812-4.757-3.625-8.863h-9.471s-1.402 10.596-1.169 14.68\"\n          fill=\"#CBD1D1\"\n        />\n        <path\n          d=\"M101.496 290.073s2.447 1.281 6.809.658c3.081-.44 3.74.485 7.479 1.039 3.739.554 10.802-.07 11.91-.9.415 1.108-.347 2.077-.347 2.077s-1.523.608-4.847.831c-2.045.137-5.843.293-7.663-.507-1.8-1.385-5.286-1.917-5.77-.243-3.947.958-7.41-.288-7.41-.288l-.16-2.667z\"\n          fill=\"#2B0849\"\n        />\n        <path d=\"M108.824 276.19h3.116s-.103 6.751 4.57 8.62c-4.673.624-8.62-2.32-7.686-8.62\" fill=\"#A4AABA\" />\n        <path\n          d=\"M57.65 272.52s-2.122 7.47-4.518 12.396c-1.811 3.724-4.255 7.548 5.505 7.548 6.698 0 9.02-.483 7.479-6.648-1.541-6.164.268-13.296.268-13.296H57.65z\"\n          fill=\"#CBD1D1\"\n        />\n        <path\n          d=\"M51.54 290.04s2.111 1.178 6.682 1.178c6.128 0 8.31-1.662 8.31-1.662s.605 1.122-.624 2.18c-1 .862-3.624 1.603-7.444 1.559-4.177-.049-5.876-.57-6.786-1.177-.831-.554-.692-1.593-.138-2.078\"\n          fill=\"#2B0849\"\n        />\n        <path\n          d=\"M58.533 274.438s.034 1.529-.315 2.95c-.352 1.431-1.087 3.127-1.139 4.17-.058 1.16 4.57 1.592 5.194.035.623-1.559 1.303-6.475 1.927-7.306.622-.831-4.94-2.135-5.667.15\"\n          fill=\"#A4AABA\"\n        />\n        <path\n          d=\"M100.885 277.015l13.306.092s1.291-54.228 1.843-64.056c.552-9.828 3.756-43.13.997-62.788l-12.48-.64-22.725.776s-.433 3.944-1.19 9.921c-.062.493-.677.838-.744 1.358-.075.582.42 1.347.318 1.956-2.35 14.003-6.343 32.926-8.697 46.425-.116.663-1.227 1.004-1.45 2.677-.04.3.21 1.516.112 1.785-6.836 18.643-10.89 47.584-14.2 61.551l14.528-.014s2.185-8.524 4.008-16.878c2.796-12.817 22.987-84.553 22.987-84.553l3-.517 1.037 46.1s-.223 1.228.334 2.008c.558.782-.556 1.117-.39 2.233l.39 1.784s-.446 7.14-.892 11.826c-.446 4.685-.092 38.954-.092 38.954\"\n          fill=\"#7BB2F9\"\n        />\n        <path\n          d=\"M77.438 220.434c1.146.094 4.016-2.008 6.916-4.91M107.55 223.931s2.758-1.103 6.069-3.862\"\n          stroke=\"#648BD8\"\n          strokeWidth=\"1.051\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M108.459 220.905s2.759-1.104 6.07-3.863\"\n          stroke=\"#648BD8\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M76.099 223.557s2.608-.587 6.47-3.346M87.33 150.82c-.27 3.088.297 8.478-4.315 9.073M104.829 149.075s.11 13.936-1.286 14.983c-2.207 1.655-2.975 1.934-2.975 1.934M101.014 149.63s.035 12.81-1.19 24.245M94.93 174.965s7.174-1.655 9.38-1.655M75.671 204.754c-.316 1.55-.64 3.067-.973 4.535 0 0-1.45 1.822-1.003 3.756.446 1.934-.943 2.034-4.96 15.273-1.686 5.559-4.464 18.49-6.313 27.447-.078.38-4.018 18.06-4.093 18.423M77.043 196.743a313.269 313.269 0 0 1-.877 4.729M83.908 151.414l-1.19 10.413s-1.091.148-.496 2.23c.111 1.34-2.66 15.692-5.153 30.267M57.58 272.94h13.238\"\n          stroke=\"#648BD8\"\n          strokeWidth=\"1.051\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n        <path\n          d=\"M117.377 147.423s-16.955-3.087-35.7.199c.157 2.501-.002 4.128-.002 4.128s14.607-2.802 35.476-.31c.251-2.342.226-4.017.226-4.017\"\n          fill=\"#192064\"\n        />\n        <path\n          d=\"M107.511 150.353l.004-4.885a.807.807 0 0 0-.774-.81c-2.428-.092-5.04-.108-7.795-.014a.814.814 0 0 0-.784.81l-.003 4.88c0 .456.371.82.827.808a140.76 140.76 0 0 1 7.688.017.81.81 0 0 0 .837-.806\"\n          fill=\"#FFF\"\n        />\n        <path\n          d=\"M106.402 149.426l.002-3.06a.64.64 0 0 0-.616-.643 94.135 94.135 0 0 0-5.834-.009.647.647 0 0 0-.626.643l-.001 3.056c0 .36.291.648.651.64 1.78-.04 3.708-.041 5.762.012.36.009.662-.279.662-.64\"\n          fill=\"#192064\"\n        />\n        <path\n          d=\"M101.485 273.933h12.272M102.652 269.075c.006 3.368.04 5.759.11 6.47M102.667 263.125c-.009 1.53-.015 2.98-.016 4.313M102.204 174.024l.893 44.402s.669 1.561-.224 2.677c-.892 1.116 2.455.67.893 2.231-1.562 1.562.893 1.116 0 3.347-.592 1.48-.988 20.987-1.09 34.956\"\n          stroke=\"#648BD8\"\n          strokeWidth=\"1.051\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n        />\n      </g>\n    </svg>\n  `\n})\nexport class NzResultUnauthorizedComponent {}\n"
  },
  {
    "path": "components/result/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './result.module';\nexport * from './result.component';\nexport * from './result-cells';\n\n// Making these partial components not visible to users but comprehensible to ng-packagr.\nexport { NzResultNotFoundComponent as ɵNzResultNotFoundComponent } from './partial/not-found';\nexport { NzResultServerErrorComponent as ɵNzResultServerErrorComponent } from './partial/server-error.component';\nexport { NzResultUnauthorizedComponent as ɵNzResultUnauthorizedComponent } from './partial/unauthorized';\n"
  },
  {
    "path": "components/result/result-cells.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive } from '@angular/core';\n\n@Directive({\n  selector: 'div[nz-result-title]',\n  exportAs: 'nzResultTitle',\n  host: {\n    class: 'ant-result-title'\n  }\n})\nexport class NzResultTitleDirective {}\n\n@Directive({\n  selector: 'div[nz-result-subtitle]',\n  exportAs: 'nzResultSubtitle',\n  host: {\n    class: 'ant-result-subtitle'\n  }\n})\nexport class NzResultSubtitleDirective {}\n\n@Directive({\n  selector: '[nz-result-icon]',\n  exportAs: 'nzResultIcon'\n})\nexport class NzResultIconDirective {}\n\n@Directive({\n  selector: 'div[nz-result-content]',\n  exportAs: 'nzResultContent',\n  host: {\n    class: 'ant-result-content'\n  }\n})\nexport class NzResultContentDirective {}\n\n@Directive({\n  selector: 'div[nz-result-extra]',\n  exportAs: 'nzResultExtra',\n  host: {\n    class: 'ant-result-extra'\n  }\n})\nexport class NzResultExtraDirective {}\n"
  },
  {
    "path": "components/result/result.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  computed,\n  inject,\n  input,\n  TemplateRef,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nimport { NzResultNotFoundComponent } from './partial/not-found';\nimport { NzResultServerErrorComponent } from './partial/server-error.component';\nimport { NzResultUnauthorizedComponent } from './partial/unauthorized';\n\nexport type NzResultIconType = 'success' | 'error' | 'info' | 'warning';\nexport type NzExceptionStatusType = '404' | '500' | '403';\nexport type NzResultStatusType = NzExceptionStatusType | NzResultIconType;\n\nconst IconMap: Record<NzResultIconType, string> = {\n  success: 'check-circle',\n  error: 'close-circle',\n  info: 'exclamation-circle',\n  warning: 'warning'\n};\nconst ExceptionStatus = ['404', '500', '403'];\n\n@Component({\n  selector: 'nz-result',\n  exportAs: 'nzResult',\n  template: `\n    <div class=\"ant-result-icon\">\n      @if (!isException()) {\n        @if (icon()) {\n          <ng-container *nzStringTemplateOutlet=\"icon(); let icon\">\n            <nz-icon [nzType]=\"icon\" nzTheme=\"fill\" />\n          </ng-container>\n        } @else {\n          <ng-content select=\"[nz-result-icon]\">\n            <nz-icon [nzType]=\"defaultIcon()\" nzTheme=\"fill\" />\n          </ng-content>\n        }\n      } @else {\n        @switch (nzStatus()) {\n          @case ('404') {\n            <nz-result-not-found />\n          }\n          @case ('500') {\n            <nz-result-server-error />\n          }\n          @case ('403') {\n            <nz-result-unauthorized />\n          }\n        }\n      }\n    </div>\n    @if (nzTitle()) {\n      <div class=\"ant-result-title\" *nzStringTemplateOutlet=\"nzTitle()\">\n        {{ nzTitle() }}\n      </div>\n    } @else {\n      <ng-content select=\"div[nz-result-title]\" />\n    }\n\n    @if (nzSubTitle()) {\n      <div class=\"ant-result-subtitle\" *nzStringTemplateOutlet=\"nzSubTitle()\">\n        {{ nzSubTitle() }}\n      </div>\n    } @else {\n      <ng-content select=\"div[nz-result-subtitle]\" />\n    }\n    <ng-content select=\"nz-result-content, [nz-result-content]\" />\n    @if (nzExtra()) {\n      <div class=\"ant-result-extra\" *nzStringTemplateOutlet=\"nzExtra()\">\n        {{ nzExtra() }}\n      </div>\n    } @else {\n      <ng-content select=\"div[nz-result-extra]\" />\n    }\n  `,\n  host: {\n    '[class]': 'class()'\n  },\n  imports: [\n    NzOutletModule,\n    NzIconModule,\n    NzResultNotFoundComponent,\n    NzResultServerErrorComponent,\n    NzResultUnauthorizedComponent\n  ],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None\n})\nexport class NzResultComponent {\n  private readonly dir = inject(Directionality).valueSignal;\n\n  readonly nzIcon = input<string | TemplateRef<void>>();\n  readonly nzTitle = input<string | TemplateRef<void>>();\n  readonly nzSubTitle = input<string | TemplateRef<void>>();\n  readonly nzExtra = input<string | TemplateRef<void>>();\n  readonly nzStatus = input<NzResultStatusType>('info');\n\n  protected readonly class = computed(() => {\n    return {\n      'ant-result': true,\n      [`ant-result-${this.nzStatus()}`]: true,\n      'ant-result-rtl': this.dir() === 'rtl'\n    };\n  });\n\n  readonly isException = computed(() => ExceptionStatus.indexOf(this.nzStatus()) !== -1);\n  readonly icon = computed(() => {\n    const icon = this.nzIcon();\n    return typeof icon === 'string' ? IconMap[icon as NzResultIconType] || icon : icon;\n  });\n  readonly defaultIcon = computed(() => IconMap[this.nzStatus() as NzResultIconType]);\n}\n"
  },
  {
    "path": "components/result/result.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzResultNotFoundComponent } from './partial/not-found';\nimport { NzResultServerErrorComponent } from './partial/server-error.component';\nimport { NzResultUnauthorizedComponent } from './partial/unauthorized';\nimport {\n  NzResultContentDirective,\n  NzResultExtraDirective,\n  NzResultIconDirective,\n  NzResultSubtitleDirective,\n  NzResultTitleDirective\n} from './result-cells';\nimport { NzResultComponent } from './result.component';\n\nconst partial = [NzResultNotFoundComponent, NzResultServerErrorComponent, NzResultUnauthorizedComponent];\n\nconst cellDirectives = [\n  NzResultContentDirective,\n  NzResultExtraDirective,\n  NzResultIconDirective,\n  NzResultSubtitleDirective,\n  NzResultTitleDirective\n];\n\n@NgModule({\n  imports: [NzResultComponent, ...cellDirectives, ...partial],\n  exports: [NzResultComponent, ...cellDirectives]\n})\nexport class NzResultModule {}\n"
  },
  {
    "path": "components/result/result.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Direction } from '@angular/cdk/bidi';\nimport { Component, DebugElement, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzResultComponent, NzResultStatusType } from './result.component';\nimport { NzResultModule } from './result.module';\n\n@Component({\n  selector: 'nz-test-basic-result',\n  imports: [NzIconModule, NzResultModule],\n  template: `\n    <nz-result [nzIcon]=\"icon\" [nzStatus]=\"status\" [nzTitle]=\"title\" [nzSubTitle]=\"subtitle\" [nzExtra]=\"extra\">\n      <nz-icon nz-result-icon nzType=\"up\" nzTheme=\"outline\" />\n      <div nz-result-title>Content Title</div>\n      <div nz-result-subtitle>Content SubTitle</div>\n      <div nz-result-content>Content</div>\n      <div nz-result-extra>Content Extra</div>\n    </nz-result>\n  `\n})\nexport class NzTestResultBasicComponent {\n  icon?: string = 'success';\n  title?: string = 'Title';\n  status: NzResultStatusType = 'error';\n  subtitle?: string = 'SubTitle';\n  extra?: string = 'Extra';\n}\n\n@Component({\n  imports: [BidiModule, NzTestResultBasicComponent],\n  template: `<nz-test-basic-result [dir]=\"direction\" />`\n})\nexport class NzTestResultRtlComponent {\n  direction: Direction = 'rtl';\n}\n\n@Component({\n  selector: 'nz-test-status-icon-result',\n  imports: [NzResultModule],\n  template: `<nz-result [nzStatus]=\"status\" nzTitle=\"Test Title\" />`\n})\nexport class NzTestResultStatusIconComponent {\n  status: NzResultStatusType = 'success';\n}\n\ndescribe('nz-result', () => {\n  describe('basic', () => {\n    let fixture: ComponentFixture<NzTestResultBasicComponent>;\n    let testComponent: NzTestResultBasicComponent;\n    let resultEl: DebugElement;\n\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        providers: [provideNzIconsTesting()]\n      });\n\n      fixture = TestBed.createComponent(NzTestResultBasicComponent);\n      testComponent = fixture.componentInstance;\n      resultEl = fixture.debugElement.query(By.directive(NzResultComponent));\n    });\n\n    it('should props work and overlap contents', () => {\n      fixture.detectChanges();\n\n      const iconView = resultEl.nativeElement.querySelector('.ant-result-icon');\n      const titleView = resultEl.nativeElement.querySelector('.ant-result-title');\n      const subTitleView = resultEl.nativeElement.querySelector('.ant-result-subtitle');\n      const extraView = resultEl.nativeElement.querySelector('.ant-result-extra');\n\n      expect(resultEl.nativeElement.classList).toContain('ant-result');\n      expect(resultEl.nativeElement.classList).toContain('ant-result-error'); // should status work\n      expect(iconView.firstElementChild.classList).toContain('anticon-check-circle'); // icon overlap status\n      expect(titleView.innerText).toBe('Title');\n      expect(subTitleView.innerText).toBe('SubTitle');\n      expect(extraView.innerText).toBe('Extra');\n    });\n\n    it('should content work', () => {\n      testComponent.icon = testComponent.title = testComponent.subtitle = testComponent.extra = undefined;\n      fixture.detectChanges();\n\n      const iconView = resultEl.nativeElement.querySelector('.ant-result-icon');\n      const titleView = resultEl.nativeElement.querySelector('.ant-result-title');\n      const subTitleView = resultEl.nativeElement.querySelector('.ant-result-subtitle');\n      const contentView = resultEl.nativeElement.querySelector('.ant-result-content');\n      const extraView = resultEl.nativeElement.querySelector('.ant-result-extra');\n\n      expect(resultEl.nativeElement.classList).toContain('ant-result');\n      expect(iconView.firstElementChild.classList).toContain('anticon-up');\n      expect(titleView.innerText).toBe('Content Title');\n      expect(subTitleView.innerText).toBe('Content SubTitle');\n      expect(contentView.innerText).toBe('Content');\n      expect(extraView.innerText).toBe('Content Extra');\n    });\n\n    it('should icon overlap status', () => {\n      testComponent.icon = 'smile-o';\n      fixture.detectChanges();\n\n      const iconView = resultEl.nativeElement.querySelector('.ant-result-icon');\n\n      expect(resultEl.nativeElement.classList).toContain('ant-result');\n      expect(resultEl.nativeElement.classList).toContain('ant-result-error'); // should status work\n      expect(iconView.firstElementChild.classList).toContain('anticon-smile-o');\n    });\n  });\n\n  describe('RTL', () => {\n    let fixture: ComponentFixture<NzTestResultRtlComponent>;\n    let resultEl: DebugElement;\n\n    beforeEach(() => {\n      // todo: use zoneless\n      TestBed.configureTestingModule({\n        providers: [provideNzIconsTesting(), provideZoneChangeDetection()]\n      });\n\n      fixture = TestBed.createComponent(NzTestResultRtlComponent);\n      fixture.detectChanges();\n      resultEl = fixture.debugElement.query(By.directive(NzResultComponent));\n    });\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n      expect(resultEl.nativeElement.classList).toContain('ant-result-rtl');\n\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n      expect(resultEl.nativeElement.className).not.toContain('ant-result-rtl');\n    });\n  });\n\n  describe('default icon from status', () => {\n    let fixture: ComponentFixture<NzTestResultStatusIconComponent>;\n    let testComponent: NzTestResultStatusIconComponent;\n    let resultEl: DebugElement;\n\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        providers: [provideNzIconsTesting()]\n      });\n\n      fixture = TestBed.createComponent(NzTestResultStatusIconComponent);\n      testComponent = fixture.componentInstance;\n      resultEl = fixture.debugElement.query(By.directive(NzResultComponent));\n    });\n\n    it('should show default icon based on status when nzIcon is not provided', () => {\n      testComponent.status = 'success';\n      fixture.detectChanges();\n\n      const iconView = resultEl.nativeElement.querySelector('.ant-result-icon');\n      expect(iconView.firstElementChild.classList).toContain('anticon-check-circle');\n    });\n\n    it('should show info icon when status is info', () => {\n      testComponent.status = 'info';\n      fixture.detectChanges();\n\n      const iconView = resultEl.nativeElement.querySelector('.ant-result-icon');\n      expect(iconView.firstElementChild.classList).toContain('anticon-exclamation-circle');\n    });\n\n    it('should show warning icon when status is warning', () => {\n      testComponent.status = 'warning';\n      fixture.detectChanges();\n\n      const iconView = resultEl.nativeElement.querySelector('.ant-result-icon');\n      expect(iconView.firstElementChild.classList).toContain('anticon-warning');\n    });\n\n    it('should show error icon when status is error', () => {\n      testComponent.status = 'error';\n      fixture.detectChanges();\n\n      const iconView = resultEl.nativeElement.querySelector('.ant-result-icon');\n      expect(iconView.firstElementChild.classList).toContain('anticon-close-circle');\n    });\n  });\n});\n"
  },
  {
    "path": "components/result/style/entry.less",
    "content": "@import \"./index.less\";\n@import \"./patch.less\";\n"
  },
  {
    "path": "components/result/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@result-prefix-cls: ~'@{ant-prefix}-result';\n\n.@{result-prefix-cls} {\n  padding: 48px 32px;\n  // status color\n  &-success &-icon > .@{iconfont-css-prefix} {\n    color: @success-color;\n  }\n\n  &-error &-icon > .@{iconfont-css-prefix} {\n    color: @error-color;\n  }\n\n  &-info &-icon > .@{iconfont-css-prefix} {\n    color: @info-color;\n  }\n\n  &-warning &-icon > .@{iconfont-css-prefix} {\n    color: @warning-color;\n  }\n\n  // Exception Status image\n  &-image {\n    width: 250px;\n    height: 295px;\n    margin: auto;\n  }\n\n  &-icon {\n    margin-bottom: 24px;\n    text-align: center;\n\n    > .@{iconfont-css-prefix} {\n      font-size: @result-icon-font-size;\n    }\n  }\n\n  &-title {\n    color: @heading-color;\n    font-size: @result-title-font-size;\n    line-height: 1.8;\n    text-align: center;\n  }\n\n  &-subtitle {\n    color: @text-color-secondary;\n    font-size: @result-subtitle-font-size;\n    line-height: 1.6;\n    text-align: center;\n  }\n\n  &-extra {\n    margin: @result-extra-margin;\n    text-align: center;\n\n    > * {\n      margin-right: 8px;\n\n      &:last-child {\n        margin-right: 0;\n      }\n    }\n  }\n\n  &-content {\n    margin-top: 24px;\n    padding: 24px 40px;\n    background-color: @background-color-light;\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/result/style/patch.less",
    "content": "nz-result {\n  display: block;\n}\n"
  },
  {
    "path": "components/result/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@result-prefix-cls: ~'@{ant-prefix}-result';\n\n.@{result-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &-extra {\n    > * {\n      .@{result-prefix-cls}-rtl & {\n        margin-right: 0;\n        margin-left: 8px;\n      }\n\n      &:last-child {\n        .@{result-prefix-cls}-rtl & {\n          margin-left: 0;\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/segmented/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic usage\n---\n\n## zh-CN\n\n最简单的用法。\n\n## en-US\n\nBasic Usage.\n"
  },
  {
    "path": "components/segmented/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzSegmentedModule } from 'ng-zorro-antd/segmented';\n\n@Component({\n  selector: 'nz-demo-segmented-basic',\n  imports: [NzSegmentedModule],\n  template: `<nz-segmented [nzOptions]=\"options\" (nzValueChange)=\"handleValueChange($event)\" />`\n})\nexport class NzDemoSegmentedBasicComponent {\n  options = ['Daily', 'Weekly', 'Monthly', 'Quarterly', 'Yearly'];\n\n  handleValueChange(e: string | number): void {\n    console.log(e);\n  }\n}\n"
  },
  {
    "path": "components/segmented/demo/block.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: Block 分段选择器\n  en-US: Block Segmented\n---\n\n## zh-CN\n\n`nzBlock` 属性使其适合父元素宽度。\n\n## en-US\n\n`nzBlock` property will make the `Segmented` fit to its parent width.\n"
  },
  {
    "path": "components/segmented/demo/block.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzSegmentedModule } from 'ng-zorro-antd/segmented';\n\n@Component({\n  selector: 'nz-demo-segmented-block',\n  imports: [NzSegmentedModule],\n  template: `<nz-segmented [nzOptions]=\"options\" [nzBlock]=\"true\" />`\n})\nexport class NzDemoSegmentedBlockComponent {\n  options = ['Daily', 'Weekly', 'Monthly', 'Quarterly', 'Yearly'];\n}\n"
  },
  {
    "path": "components/segmented/demo/custom.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 自定义渲染\n  en-US: Custom Render\n---\n\n## zh-CN\n\n自定义渲染每一个 Segmented Item。\n\n## en-US\n\nCustom render each Segmented Item.\n"
  },
  {
    "path": "components/segmented/demo/custom.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzAvatarModule } from 'ng-zorro-antd/avatar';\nimport { NzSegmentedModule } from 'ng-zorro-antd/segmented';\n\n@Component({\n  selector: 'nz-demo-segmented-custom',\n  imports: [NzAvatarModule, NzSegmentedModule],\n  template: `\n    <nz-segmented>\n      <label nz-segmented-item nzValue=\"user1\">\n        <nz-avatar nzSrc=\"https://api.dicebear.com/7.x/miniavs/svg?seed=8\" />\n        <div>User 1</div>\n      </label>\n      <label nz-segmented-item nzValue=\"user2\">\n        <nz-avatar nzText=\"K\" [style.background]=\"'#f56a00'\" />\n        <div>User 2</div>\n      </label>\n      <label nz-segmented-item nzValue=\"user3\">\n        <nz-avatar nzIcon=\"user\" [style.background]=\"'#87d068'\" />\n        <div>User 3</div>\n      </label>\n    </nz-segmented>\n\n    <br />\n    <br />\n\n    <nz-segmented>\n      <label nz-segmented-item nzValue=\"spring\">\n        <div>Spring</div>\n        <div>Jan-Mar</div>\n      </label>\n      <label nz-segmented-item nzValue=\"summer\">\n        <div>Summer</div>\n        <div>Apr-Jun</div>\n      </label>\n      <label nz-segmented-item nzValue=\"autumn\">\n        <div>Autumn</div>\n        <div>Jul-Sept</div>\n      </label>\n      <label nz-segmented-item nzValue=\"winter\">\n        <div>Winter</div>\n        <div>Oct-Dec</div>\n      </label>\n    </nz-segmented>\n  `,\n  styles: `\n    :host ::ng-deep .ant-segmented-item-label {\n      margin: 4px;\n    }\n  `\n})\nexport class NzDemoSegmentedCustomComponent {}\n"
  },
  {
    "path": "components/segmented/demo/disabled.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 不可用\n  en-US: Disabled\n---\n\n## zh-CN\n\nSegmented 不可用。\n\n## en-US\n\nDisabled Segmented.\n"
  },
  {
    "path": "components/segmented/demo/disabled.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzSegmentedModule } from 'ng-zorro-antd/segmented';\n\n@Component({\n  selector: 'nz-demo-segmented-disabled',\n  imports: [NzSegmentedModule],\n  template: `\n    <nz-segmented [nzOptions]=\"['Map', 'Transit', 'Satellite']\" nzDisabled />\n    <br />\n    <nz-segmented [nzOptions]=\"options\" />\n  `,\n  styles: `\n    .ant-segmented {\n      margin-bottom: 10px;\n    }\n  `\n})\nexport class NzDemoSegmentedDisabledComponent {\n  options = [\n    'Daily',\n    { label: 'Weekly', value: 'Weekly', disabled: true },\n    'Monthly',\n    { label: 'Quarterly', value: 'Quarterly', disabled: true },\n    'Yearly'\n  ];\n}\n"
  },
  {
    "path": "components/segmented/demo/dynamic.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 动态数据\n  en-US: Dynamic\n---\n\n## zh-CN\n\n动态加载数据。\n\n## en-US\n\nLoad `options` dynamically.\n"
  },
  {
    "path": "components/segmented/demo/dynamic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzSegmentedModule } from 'ng-zorro-antd/segmented';\n\nconst defaultOptions = ['Daily', 'Weekly', 'Monthly'];\n\n@Component({\n  selector: 'nz-demo-segmented-dynamic',\n  imports: [NzButtonModule, NzSegmentedModule],\n  template: `\n    <nz-segmented [nzOptions]=\"options\" />\n    <br />\n    <button nz-button nzType=\"primary\" [disabled]=\"moreLoaded\" (click)=\"handleLoadMore()\"> Load more options </button>\n  `,\n  styles: `\n    .ant-segmented {\n      margin-bottom: 10px;\n    }\n  `\n})\nexport class NzDemoSegmentedDynamicComponent {\n  options = [...defaultOptions];\n\n  moreLoaded = false;\n\n  handleLoadMore(): void {\n    this.moreLoaded = true;\n    this.options = [...defaultOptions, 'Quarterly', 'Yearly'];\n  }\n}\n"
  },
  {
    "path": "components/segmented/demo/icon.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 设置图标\n  en-US: With Icon\n---\n\n## zh-CN\n\n给 Segmented Item 设置 Icon。\n\n## en-US\n\nSet `icon` for Segmented Item.\n"
  },
  {
    "path": "components/segmented/demo/icon.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzSegmentedModule } from 'ng-zorro-antd/segmented';\n\n@Component({\n  selector: 'nz-demo-segmented-icon',\n  imports: [NzSegmentedModule],\n  template: `<nz-segmented [nzOptions]=\"options\" />`\n})\nexport class NzDemoSegmentedIconComponent {\n  options = [\n    { label: 'List', value: 'List', icon: 'bars' },\n    { label: 'Kanban', value: 'Kanban', icon: 'appstore' }\n  ];\n}\n"
  },
  {
    "path": "components/segmented/demo/shape.md",
    "content": "---\norder: 14\nversion: 20.3.0\ntitle:\n  zh-CN: 胶囊形状\n  en-US: Round Shape\n---\n\n## zh-CN\n\n胶囊型的 Segmented。\n\n## en-US\n\nRound shape of Segmented.\n"
  },
  {
    "path": "components/segmented/demo/shape.ts",
    "content": "import { Component, model } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSizeLDSType } from 'ng-zorro-antd/core/types';\nimport { NzSegmentedModule } from 'ng-zorro-antd/segmented';\n\n@Component({\n  selector: 'nz-demo-segmented-shape',\n  imports: [NzSegmentedModule, FormsModule],\n  template: `\n    <nz-segmented [nzOptions]=\"optionsSize\" [(ngModel)]=\"currentSize\" />\n    <nz-segmented [nzOptions]=\"options\" nzShape=\"round\" [nzSize]=\"currentSize()\" />\n  `,\n  styles: `\n    nz-segmented:first-child {\n      display: block;\n      width: fit-content;\n      margin-bottom: 16px;\n    }\n  `\n})\nexport class NzDemoSegmentedShapeComponent {\n  currentSize = model<NzSizeLDSType>('default');\n\n  optionsSize = [\n    { value: 'small', label: 'Small' },\n    { value: 'default', label: 'Medium' },\n    { value: 'large', label: 'Large' }\n  ];\n  options = [\n    { value: 'List', icon: 'bars' },\n    { value: 'Kanban', icon: 'appstore' }\n  ];\n}\n"
  },
  {
    "path": "components/segmented/demo/size.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 三种大小\n  en-US: Three sizes of Segmented\n---\n\n## zh-CN\n\n我们为 Segmented 组件定义了三种尺寸（大、默认、小），高度分别为 `40px`、`32px` 和 `24px`。\n\n## en-US\n\nThere are three sizes of an Segmented: `large` (40px), `default` (32px) and `small` (24px).\n"
  },
  {
    "path": "components/segmented/demo/size.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzSegmentedModule } from 'ng-zorro-antd/segmented';\n\n@Component({\n  selector: 'nz-demo-segmented-size',\n  imports: [NzSegmentedModule],\n  template: `\n    <nz-segmented [nzOptions]=\"options\" nzSize=\"small\" />\n    <br />\n    <nz-segmented [nzOptions]=\"options\" />\n    <br />\n    <nz-segmented [nzOptions]=\"options\" nzSize=\"large\" />\n  `,\n  styles: `\n    .ant-segmented {\n      margin-bottom: 10px;\n    }\n  `\n})\nexport class NzDemoSegmentedSizeComponent {\n  options = ['Daily', 'Weekly', 'Monthly', 'Quarterly', 'Yearly'];\n}\n"
  },
  {
    "path": "components/segmented/demo/value.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 受控模式\n  en-US: Controlled mode\n---\n\n## zh-CN\n\n通过 ngModel 指定选中的 value\n\n## en-US\n\nSet selected option via ngModel.\n"
  },
  {
    "path": "components/segmented/demo/value.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSegmentedModule } from 'ng-zorro-antd/segmented';\n\n@Component({\n  selector: 'nz-demo-segmented-value',\n  imports: [FormsModule, NzSegmentedModule],\n  template: `\n    <nz-segmented [nzOptions]=\"options\" [(ngModel)]=\"selectedValue\" (ngModelChange)=\"handleModelChange($event)\" />\n    <br />\n    Selected value: {{ selectedValue }}\n  `,\n  styles: `\n    .ant-segmented {\n      margin-bottom: 10px;\n    }\n  `\n})\nexport class NzDemoSegmentedValueComponent {\n  selectedValue = 'Weekly';\n  options = ['Daily', 'Weekly', 'Monthly', 'Quarterly', 'Yearly'];\n\n  handleModelChange(value: string): void {\n    console.log(value);\n  }\n}\n"
  },
  {
    "path": "components/segmented/demo/vertical.md",
    "content": "---\norder: 1\nversion: 20.2.0\ntitle:\n  zh-CN: 垂直方向\n  en-US: Vertical direction\n---\n\n## zh-CN\n\n垂直方向。\n\n## en-US\n\nMake it vertical.\n"
  },
  {
    "path": "components/segmented/demo/vertical.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzSegmentedModule } from 'ng-zorro-antd/segmented';\n\n@Component({\n  selector: 'nz-demo-segmented-vertical',\n  imports: [NzSegmentedModule],\n  template: `<nz-segmented [nzOptions]=\"options\" nzVertical />`\n})\nexport class NzDemoSegmentedVerticalComponent {\n  options = [\n    { value: 'List', icon: 'bars' },\n    { value: 'Kanban', icon: 'appstore' }\n  ];\n}\n"
  },
  {
    "path": "components/segmented/demo/with-icon-only.md",
    "content": "---\norder: 10\ntitle:\n  zh-CN: 只设置图标\n  en-US: With Icon only\n---\n\n## zh-CN\n\n在 Segmented Item 选项中只设置 Icon。\n\n## en-US\n\nSet `icon` without `label` for Segmented Item.\n"
  },
  {
    "path": "components/segmented/demo/with-icon-only.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzSegmentedModule, NzSegmentedOptions } from 'ng-zorro-antd/segmented';\n\n@Component({\n  selector: 'nz-demo-segmented-with-icon-only',\n  imports: [NzSegmentedModule],\n  template: `<nz-segmented [nzOptions]=\"options\" />`\n})\nexport class NzDemoSegmentedWithIconOnlyComponent {\n  options: NzSegmentedOptions = [\n    { value: 'List', icon: 'bars' },\n    { value: 'Kanban', icon: 'appstore' }\n  ];\n}\n"
  },
  {
    "path": "components/segmented/demo/with-name.md",
    "content": "---\norder: 11\ntitle:\n  zh-CN: 配合 name 使用\n  en-US: With name\n---\n\n## zh-CN\n\n可以为配置 `nzName` 参数，为组合内的 input 元素赋予相同的 `name` 属性，使浏览器把分段控制器下的 input 真正看作是一组（例如可以通过方向键始终在同一组内更改选项）。\n\n## en-US\n\nPassing the `nzName` property to all `input[type=\"radio\"]` that are in the same nz-segmented. It is usually used to let the browser see your nz-segmented as a real \"group\" and keep the default behavior. For example, using left/right keyboard arrow to change your selection that in the same Segmented.\n"
  },
  {
    "path": "components/segmented/demo/with-name.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzSegmentedModule } from 'ng-zorro-antd/segmented';\n\n@Component({\n  selector: 'nz-demo-segmented-with-name',\n  imports: [NzSegmentedModule],\n  template: `<nz-segmented [nzOptions]=\"options\" (nzValueChange)=\"handleValueChange($event)\" nzName=\"group\" />`\n})\nexport class NzDemoSegmentedWithNameComponent {\n  options = ['Daily', 'Weekly', 'Monthly', 'Quarterly', 'Yearly'];\n\n  handleValueChange(e: string | number): void {\n    console.log(e);\n  }\n}\n"
  },
  {
    "path": "components/segmented/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Display\ntitle: Segmented\ncover: 'https://gw.alipayobjects.com/zos/bmw-prod/a3ff040f-24ba-43e0-92e9-c845df1612ad.svg'\ndescription: Display multiple options and allow users to select a single option.\n---\n\n## When To Use\n\n- When displaying multiple options and user can select a single option;\n- When switching the selected option, the content of the associated area changes.\n\n## API\n\n### nz-segmented\n\n| Property          | Description                                               | Type                                                                                                          | Default   | Global Config | Version |\n| ----------------- | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | --------- | ------------- | ------- |\n| `[nzBlock]`       | Option to fit width to its parent\\'s width                | `boolean`                                                                                                     | `false`   |               |\n| `[nzDisabled]`    | Disable all segments                                      | `boolean`                                                                                                     | `false`   |               |\n| `[nzOptions]`     | Set children optional                                     | `string[] \\| number[] \\| Array<{ label: string; value: string \\| number; icon: string; disabled?: boolean }>` | -         |               |\n| `[nzSize]`        | The size of the Segmented                                 | `large \\| default \\| small`                                                                                   | -         | ✅            |\n| `[nzShape]`       | Shape of Segmented                                        | `default \\| round`                                                                                            | `default` | -             | 20.3.0  |\n| `[nzVertical]`    | Orientation                                               | `boolean`                                                                                                     | `false`   | -             | 20.2.0  |\n| `[nzName]`        | The name property of all `input[type=\"radio\"]` children   | `string`                                                                                                      | -         |               | 20.3.0  |\n| `[ngModel]`       | Value of the currently selected option                    | `string \\| number`                                                                                            | -         |               |\n| `(nzValueChange)` | Emits when value of the currently selected option changes | `EventEmitter<string \\| number>`                                                                              | -         |               |\n| `(ngModelChange)` | Emits when value of the currently selected option changes | `EventEmitter<string \\| number>`                                                                              | -         |               |\n\n### label[nz-segmented-item]\n\n| Property       | Description                | Type               | Default | Global Config |\n| -------------- | -------------------------- | ------------------ | ------- | ------------- |\n| `[nzIcon]`     | Icon in segmented item     | `string`           | -       |               |\n| `[nzValue]`    | Value of segmented item    | `string \\| number` | -       |               |\n| `[nzDisabled]` | Disable the segmented item | `boolean`          | `false` |               |\n"
  },
  {
    "path": "components/segmented/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 分段控制器\ntype: 数据展示\ntitle: Segmented\ncover: 'https://gw.alipayobjects.com/zos/bmw-prod/a3ff040f-24ba-43e0-92e9-c845df1612ad.svg'\ndescription: 用于展示多个选项并允许用户选择其中单个选项。\n---\n\n## 何时使用\n\n- 用于展示多个选项并允许用户选择其中单个选项；\n- 当切换选中选项时，关联区域的内容会发生变化。\n\n## API\n\n### nz-segmented\n\n| 参数              | 说明                                      | 类型                                                                                                           | 默认值    | 全局配置 | 版本   |\n| ----------------- | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------- | --------- | -------- | ------ |\n| `[nzBlock]`       | 将宽度调整为父元素宽度的选项              | `boolean`                                                                                                      | `false`   |          |\n| `[nzDisabled]`    | 是否禁用                                  | `boolean`                                                                                                      | `false`   |          |\n| `[nzOptions]`     | 数据化配置选项内容                        | `string[] \\| number[] \\| Array<{ label: string; value: string \\| number; icon: string; disabled?: boolean; }>` | -         |          |\n| `[nzSize]`        | 控件尺寸                                  | `large \\| default \\| small`                                                                                    | -         | ✅       |\n| `[nzShape]`       | 形状                                      | `default \\| round`                                                                                             | `default` | -        | 20.3.0 |\n| `[nzVertical]`    | 排列方向                                  | `boolean`                                                                                                      | `false`   | -        | 20.2.0 |\n| `[nzName]`        | 所有 `input[type=\"radio\"]` 的 `name` 属性 | `string`                                                                                                       | -         |          | 20.3.0 |\n| `[ngModel]`       | 当前选中项目的 value                      | `string \\| number`                                                                                             | -         |          |\n| `(nzValueChange)` | 当前选中项目变化时触发回调                | `EventEmitter<string \\| number>`                                                                               | -         |          |\n| `(ngModelChange)` | 当前选中项目变化时触发回调                | `EventEmitter<string \\| number>`                                                                               | -         |          |\n\n### label[nz-segmented-item]\n\n| 参数           | 说明     | 类型               | 默认值  | 全局配置 |\n| -------------- | -------- | ------------------ | ------- | -------- |\n| `[nzIcon]`     | 图标     | `string`           | -       |          |\n| `[nzValue]`    | 值       | `string \\| number` | -       |          |\n| `[nzDisabled]` | 是否禁用 | `boolean`          | `false` |          |\n"
  },
  {
    "path": "components/segmented/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/segmented/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/segmented/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport { NzSegmentedItemComponent } from './segmented-item.component';\nexport { NzSegmentedComponent } from './segmented.component';\nexport { NzSegmentedModule } from './segmented.module';\nexport * from './types';\n"
  },
  {
    "path": "components/segmented/segmented-item.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { DOWN_ARROW, LEFT_ARROW, RIGHT_ARROW, UP_ARROW } from '@angular/cdk/keycodes';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  Component,\n  computed,\n  DestroyRef,\n  ElementRef,\n  inject,\n  input,\n  OnInit,\n  signal,\n  TemplateRef,\n  viewChild,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';\nimport { of } from 'rxjs';\nimport { filter, map, switchMap, take, tap } from 'rxjs/operators';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nimport { NzSegmentedService } from './segmented.service';\n\n@Component({\n  selector: 'label[nz-segmented-item],label[nzSegmentedItem]',\n  exportAs: 'nzSegmentedItem',\n  imports: [NzIconModule, NgTemplateOutlet],\n  template: `\n    <input\n      class=\"ant-segmented-item-input\"\n      type=\"radio\"\n      [disabled]=\"finalDisabled()\"\n      [checked]=\"isChecked()\"\n      [attr.name]=\"name()\"\n      (click)=\"$event.stopPropagation()\"\n    />\n    <div class=\"ant-segmented-item-label\" [attr.aria-selected]=\"isChecked()\">\n      @if (nzIcon(); as icon) {\n        <span class=\"ant-segmented-item-icon\">\n          <nz-icon [nzType]=\"icon\" />\n        </span>\n        @if (hasLabel()) {\n          <span>\n            <ng-template [ngTemplateOutlet]=\"content\" />\n          </span>\n        }\n      } @else {\n        <ng-template [ngTemplateOutlet]=\"content\" />\n      }\n    </div>\n\n    <ng-template #content>\n      <ng-content />\n    </ng-template>\n  `,\n  host: {\n    class: 'ant-segmented-item',\n    '[class.ant-segmented-item-selected]': '!showThumb() && isChecked()',\n    '[class.ant-segmented-item-disabled]': 'finalDisabled()',\n    '(click)': 'handleClick()',\n    '(keydown)': 'handleKeydown($event)'\n  },\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None\n})\nexport class NzSegmentedItemComponent implements OnInit {\n  private readonly service = inject(NzSegmentedService);\n  private readonly elementRef = inject(ElementRef);\n  private readonly destroyRef = inject(DestroyRef);\n  private readonly templateRef = viewChild.required('content', { read: TemplateRef });\n\n  readonly nzValue = input.required<string | number>();\n  readonly nzIcon = input<string>();\n  readonly nzDisabled = input(false, { transform: booleanAttribute });\n  readonly hasLabel = computed(() =>\n    this.templateRef()\n      .createEmbeddedView({})\n      .rootNodes.some(node => node.textContent.trim().length > 0)\n  );\n\n  protected readonly showThumb = this.service.showThumb;\n  protected readonly name = this.service.name.asReadonly();\n  protected readonly isChecked = signal(false);\n  protected readonly parentDisabled = toSignal(this.service.disabled$, { initialValue: false });\n  readonly finalDisabled = computed(() => this.nzDisabled() || this.parentDisabled());\n\n  ngOnInit(): void {\n    this.service.selected$\n      .pipe(\n        tap(value => {\n          this.isChecked.set(false);\n          if (value === this.nzValue()) {\n            this.service.activated$.next(this.elementRef.nativeElement);\n          }\n        }),\n        switchMap(value => {\n          if (!this.service.animationEnabled()) {\n            return of(value);\n          }\n          return this.service.animating$.pipe(\n            filter(animating => !animating), // done\n            take(1),\n            map(() => value)\n          );\n        }),\n        filter(value => value === this.nzValue()),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(() => this.isChecked.set(true));\n  }\n\n  handleClick(): void {\n    if (!this.nzDisabled() && !this.parentDisabled()) {\n      this.service.selected$.next(this.nzValue());\n      this.service.change$.next(this.nzValue());\n    }\n  }\n\n  handleKeydown(event: KeyboardEvent): void {\n    if (this.finalDisabled()) {\n      return;\n    }\n    if (\n      event.keyCode === LEFT_ARROW ||\n      event.keyCode === RIGHT_ARROW ||\n      event.keyCode === UP_ARROW ||\n      event.keyCode === DOWN_ARROW\n    ) {\n      this.service.keydown$.next(event);\n    }\n  }\n}\n"
  },
  {
    "path": "components/segmented/segmented.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { DOWN_ARROW, LEFT_ARROW, RIGHT_ARROW, UP_ARROW } from '@angular/cdk/keycodes';\nimport {\n  afterNextRender,\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  Component,\n  computed,\n  contentChildren,\n  effect,\n  EventEmitter,\n  forwardRef,\n  inject,\n  Injector,\n  Input,\n  OnChanges,\n  Output,\n  signal,\n  SimpleChanges,\n  viewChildren,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { filter } from 'rxjs/operators';\n\nimport { withAnimationCheck } from 'ng-zorro-antd/core/animation';\nimport { NzConfigKey, WithConfig } from 'ng-zorro-antd/core/config';\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { requestAnimationFrame } from 'ng-zorro-antd/core/polyfill';\nimport { NgStyleInterface, NzSizeLDSType, OnChangeType, OnTouchedType } from 'ng-zorro-antd/core/types';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nimport { NzSegmentedItemComponent } from './segmented-item.component';\nimport { NzSegmentedService } from './segmented.service';\nimport { normalizeOptions, NzSegmentedOption, NzSegmentedOptions } from './types';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'segmented';\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-segmented',\n  exportAs: 'nzSegmented',\n  template: `\n    <!-- thumb motion div -->\n    <div class=\"ant-segmented-group\">\n      @if (showThumb()) {\n        <div\n          class=\"ant-segmented-thumb\"\n          [style]=\"thumbStyle()\"\n          [animate.enter]=\"thumbAnimationEnter()\"\n          (transitionend)=\"handleTransitionEnd($event)\"\n        ></div>\n      }\n\n      <ng-content>\n        @for (item of normalizedOptions; track item.value) {\n          <label nz-segmented-item [nzIcon]=\"item.icon\" [nzValue]=\"item.value\" [nzDisabled]=\"item.disabled\">\n            {{ item.label }}\n          </label>\n        }\n      </ng-content>\n    </div>\n  `,\n  host: {\n    class: 'ant-segmented',\n    '[class.ant-segmented-disabled]': 'nzDisabled',\n    '[class.ant-segmented-rtl]': `dir() === 'rtl'`,\n    '[class.ant-segmented-lg]': `nzSize === 'large'`,\n    '[class.ant-segmented-sm]': `nzSize === 'small'`,\n    '[class.ant-segmented-block]': `nzBlock`,\n    '[class.ant-segmented-vertical]': `nzVertical`,\n    '[class.ant-segmented-shape-round]': `nzShape === 'round'`,\n    // a11y\n    role: 'radiogroup',\n    'aria-label': 'segmented control',\n    '[attr.tabindex]': 'nzDisabled ? undefined : 0'\n  },\n  providers: [\n    NzSegmentedService,\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => NzSegmentedComponent),\n      multi: true\n    }\n  ],\n  imports: [NzIconModule, NzOutletModule, NzSegmentedItemComponent]\n})\nexport class NzSegmentedComponent implements OnChanges, ControlValueAccessor {\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  private readonly service = inject(NzSegmentedService);\n  private readonly injector = inject(Injector);\n  protected readonly dir = inject(Directionality).valueSignal;\n\n  @Input({ transform: booleanAttribute }) nzBlock: boolean = false;\n  @Input({ transform: booleanAttribute }) nzDisabled = false;\n  @Input() nzOptions: NzSegmentedOptions = [];\n  @Input({ transform: booleanAttribute }) nzVertical: boolean = false;\n  @Input() nzShape: 'default' | 'round' = 'default';\n  @Input() @WithConfig() nzSize: NzSizeLDSType = 'default';\n\n  /**\n   * @description set the `name` attribute of the segmented item native `input[type=\"radio\"]`\n   * @since 20.3.0\n   */\n  @Input() nzName?: string;\n\n  @Output() readonly nzValueChange = new EventEmitter<number | string>();\n\n  private viewItemCmps = viewChildren(NzSegmentedItemComponent);\n  private contentItemCmps = contentChildren(NzSegmentedItemComponent);\n  private renderedItemCmps = computed(() => this.viewItemCmps().concat(this.contentItemCmps()));\n  private isDisabledFirstChange = true;\n\n  protected value?: number | string;\n  protected readonly thumbStyle = signal<NgStyleInterface | null>(null);\n  protected readonly thumbAnimationEnter = withAnimationCheck(() => 'ant-segmented-thumb-motion-appear-active');\n  protected readonly showThumb = this.service.showThumb;\n  protected normalizedOptions: NzSegmentedOption[] = [];\n  protected onChange: OnChangeType = () => {};\n  protected onTouched: OnTouchedType = () => {};\n\n  constructor() {\n    this.service.selected$.pipe(takeUntilDestroyed()).subscribe(value => {\n      this.value = value;\n    });\n\n    this.service.activated$.pipe(takeUntilDestroyed()).subscribe(element => {\n      this.thumbStyle.update(prevStyle => {\n        const nextStyle = this.calcThumbStyle(element);\n\n        if (prevStyle && nextStyle) {\n          // Trigger animation to end position\n          requestAnimationFrame(() => {\n            this.thumbStyle.set(this.getThumbStyle(nextStyle));\n          });\n        } else if (nextStyle) {\n          return this.getThumbStyle(nextStyle);\n        }\n        return prevStyle;\n      });\n    });\n\n    this.service.change$.pipe(takeUntilDestroyed()).subscribe(value => {\n      this.nzValueChange.emit(value);\n      this.onChange(value);\n      this.service.animating$.next(true);\n    });\n\n    this.service.keydown$\n      .pipe(\n        filter(() => !this.nzDisabled),\n        takeUntilDestroyed()\n      )\n      .subscribe(event => this.onKeyDown(event));\n\n    afterNextRender(() => {\n      effect(\n        () => {\n          const itemCmps = this.renderedItemCmps();\n\n          if (!itemCmps.length) {\n            return;\n          }\n\n          if (\n            this.value === undefined || // If no value is set, select the first item\n            !itemCmps.some(item => item.nzValue() === this.value) // handle value not in options\n          ) {\n            this.service.selected$.next(itemCmps[0].nzValue());\n          }\n        },\n        { injector: this.injector }\n      );\n    });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzName, nzOptions, nzDisabled } = changes;\n    if (nzName) {\n      this.service.setName(this.nzName);\n    }\n    if (nzOptions) {\n      this.normalizedOptions = normalizeOptions(nzOptions.currentValue);\n    }\n    if (nzDisabled) {\n      this.service.disabled$.next(nzDisabled.currentValue);\n    }\n  }\n\n  private onOffset(offset: number): void {\n    const items = this.renderedItemCmps();\n    const total = items.length;\n    const originIndex = items.findIndex(item => item.nzValue() === this.value);\n    let nextIndex = (originIndex + offset + total) % total;\n\n    // find out the next non-disabled item\n    while (items[nextIndex].nzDisabled()) {\n      nextIndex = (nextIndex + Math.sign(offset) + total) % total;\n      // avoid circular loop\n      if (nextIndex === originIndex) {\n        break;\n      }\n    }\n\n    const nextOption = items[nextIndex];\n    if (nextOption) {\n      this.service.selected$.next(nextOption.nzValue());\n      this.service.change$.next(nextOption.nzValue());\n    }\n  }\n\n  // change selected item by direction keyboard interaction\n  private onKeyDown(event: KeyboardEvent): void {\n    switch (event.keyCode) {\n      case UP_ARROW:\n        this.onOffset(-1);\n        break;\n      case LEFT_ARROW:\n        this.onOffset(this.dir() === 'rtl' ? 1 : -1);\n        break;\n      case DOWN_ARROW:\n        this.onOffset(1);\n        break;\n      case RIGHT_ARROW:\n        this.onOffset(this.dir() === 'rtl' ? -1 : 1);\n        break;\n    }\n  }\n\n  writeValue(value: number | string): void {\n    this.service.selected$.next(value);\n  }\n\n  registerOnChange(fn: OnChangeType): void {\n    this.onChange = fn;\n  }\n\n  registerOnTouched(fn: OnTouchedType): void {\n    this.onTouched = fn;\n  }\n\n  setDisabledState(disabled: boolean): void {\n    this.nzDisabled = (this.isDisabledFirstChange && this.nzDisabled) || disabled;\n    this.isDisabledFirstChange = false;\n  }\n\n  /************* Thumb Animation *************/\n\n  private calcThumbStyle(element?: HTMLElement): NgStyleInterface | null {\n    if (!element || !element.offsetParent) {\n      return null;\n    }\n\n    const parentElement = element.parentElement;\n    if (!parentElement) {\n      return null;\n    }\n\n    const style: NgStyleInterface = {\n      left: element.offsetLeft,\n      right: parentElement.clientWidth - element.clientWidth - element.offsetLeft,\n      width: element.clientWidth,\n      top: element.offsetTop,\n      bottom: parentElement.clientHeight - element.clientHeight - element.offsetTop,\n      height: element.clientHeight\n    };\n\n    if (this.nzVertical) {\n      return {\n        left: 0,\n        right: 0,\n        width: 0,\n        top: style.top,\n        bottom: style.bottom,\n        height: style.height\n      };\n    }\n\n    return {\n      left: style.left,\n      right: style.right,\n      width: style.width,\n      top: 0,\n      bottom: 0,\n      height: 0\n    };\n  }\n\n  private getThumbStyle(targetStyle: NgStyleInterface): NgStyleInterface {\n    if (this.nzVertical) {\n      return {\n        transform: `translateY(${targetStyle.top}px)`,\n        width: '100%',\n        height: `${targetStyle.height}px`\n      };\n    }\n\n    const isRtl = this.dir() === 'rtl';\n    const transformValue = isRtl ? -targetStyle.right : targetStyle.left;\n\n    return {\n      transform: `translateX(${transformValue}px)`,\n      width: `${targetStyle.width}px`,\n      height: '100%'\n    };\n  }\n\n  protected handleTransitionEnd(event: TransitionEvent): void {\n    if (event.propertyName === 'transform') {\n      this.service.animating$.next(false);\n    }\n  }\n}\n"
  },
  {
    "path": "components/segmented/segmented.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzSegmentedItemComponent } from './segmented-item.component';\nimport { NzSegmentedComponent } from './segmented.component';\n\n@NgModule({\n  imports: [NzSegmentedComponent, NzSegmentedItemComponent],\n  exports: [NzSegmentedComponent, NzSegmentedItemComponent]\n})\nexport class NzSegmentedModule {}\n"
  },
  {
    "path": "components/segmented/segmented.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { _IdGenerator } from '@angular/cdk/a11y';\nimport { computed, DestroyRef, inject, Injectable, signal } from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { BehaviorSubject, ReplaySubject, Subject } from 'rxjs';\n\nimport { isAnimationEnabled } from 'ng-zorro-antd/core/animation';\n\n@Injectable()\nexport class NzSegmentedService {\n  private readonly defaultName = inject(_IdGenerator).getId('segmented_');\n\n  readonly name = signal<string | null>(this.defaultName);\n  readonly selected$ = new ReplaySubject<string | number>(1);\n  readonly activated$ = new ReplaySubject<HTMLElement>(1);\n  readonly change$ = new Subject<string | number>();\n  readonly disabled$ = new ReplaySubject<boolean>(1);\n  readonly animating$ = new BehaviorSubject<boolean>(false);\n  readonly keydown$ = new Subject<KeyboardEvent>();\n\n  private readonly _animating = toSignal(this.animating$, { initialValue: false });\n  readonly animationEnabled = isAnimationEnabled(() => true);\n  readonly showThumb = computed(() => this.animationEnabled() && this._animating());\n\n  constructor() {\n    inject(DestroyRef).onDestroy(() => {\n      this.selected$.complete();\n      this.activated$.complete();\n      this.change$.complete();\n      this.disabled$.complete();\n      this.animating$.complete();\n      this.keydown$.complete();\n    });\n  }\n\n  setName(name: string | null | undefined): void {\n    this.name.set(typeof name === 'undefined' ? this.defaultName : name);\n  }\n}\n"
  },
  {
    "path": "components/segmented/segmented.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule } from '@angular/cdk/bidi';\nimport { DOWN_ARROW, LEFT_ARROW, RIGHT_ARROW, UP_ARROW } from '@angular/cdk/keycodes';\nimport { Component, DebugElement, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';\nimport { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\n\nimport { provideNzNoAnimation } from 'ng-zorro-antd/core/animation';\nimport { dispatchEvent, dispatchKeyboardEvent, dispatchMouseEvent } from 'ng-zorro-antd/core/testing';\nimport { NzSizeLDSType } from 'ng-zorro-antd/core/types';\n\nimport { NzSegmentedComponent } from './segmented.component';\nimport { NzSegmentedModule } from './segmented.module';\nimport { NzSegmentedOptions } from './types';\n\ndescribe('segmented', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzNoAnimation(), provideZoneChangeDetection()]\n    });\n  });\n\n  describe('basic', () => {\n    let fixture: ComponentFixture<NzSegmentedTestComponent>;\n    let component: NzSegmentedTestComponent;\n    let segmentedComponent: DebugElement;\n\n    function getSegmentedOptionByIndex(index: number): HTMLElement {\n      return segmentedComponent.nativeElement.querySelectorAll('.ant-segmented-item')[index];\n    }\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzSegmentedTestComponent);\n      component = fixture.componentInstance;\n      spyOn(component, 'handleValueChange');\n      segmentedComponent = fixture.debugElement.query(By.directive(NzSegmentedComponent));\n      fixture.detectChanges();\n    });\n\n    it('should support block mode', () => {\n      const segmentedElement: HTMLElement = segmentedComponent.nativeElement;\n      expect(segmentedElement.classList).not.toContain('ant-segmented-block');\n      component.block = true;\n      fixture.detectChanges();\n      expect(segmentedElement.classList).toContain('ant-segmented-block');\n    });\n\n    it('should support size', () => {\n      const segmentedElement: HTMLElement = segmentedComponent.nativeElement;\n      component.size = 'large';\n      fixture.detectChanges();\n      expect(segmentedElement.classList).toContain('ant-segmented-lg');\n      component.size = 'small';\n      fixture.detectChanges();\n      expect(segmentedElement.classList).toContain('ant-segmented-sm');\n    });\n\n    it('should support vertical mode', () => {\n      const segmentedElement: HTMLElement = segmentedComponent.nativeElement;\n      expect(segmentedElement.classList).not.toContain('ant-segmented-vertical');\n      component.vertical = true;\n      fixture.detectChanges();\n      expect(segmentedElement.classList).toContain('ant-segmented-vertical');\n    });\n\n    it('should support round shape and trigger animation state on interaction', fakeAsync(() => {\n      const segmentedElement: HTMLElement = segmentedComponent.nativeElement;\n      expect(segmentedElement.classList).not.toContain('ant-segmented-shape-round');\n      component.shape = 'round';\n      fixture.detectChanges();\n      expect(segmentedElement.classList).toContain('ant-segmented-shape-round');\n      const theSecondElement = getSegmentedOptionByIndex(1);\n      tick(0);\n      fixture.detectChanges();\n      dispatchMouseEvent(theSecondElement, 'click');\n      tick(100);\n      fixture.detectChanges();\n      expect(segmentedElement.classList).toContain('ant-segmented-shape-round');\n    }));\n\n    it('should be auto selected the first option when if no value is set', async () => {\n      const theFirstElement = getSegmentedOptionByIndex(0);\n      await fixture.whenStable();\n      fixture.detectChanges();\n      expect(theFirstElement.classList).toContain('ant-segmented-item-selected');\n    });\n\n    it('should be change the value and emit an event by clicking', async () => {\n      const theFirstElement = getSegmentedOptionByIndex(0);\n      const theSecondElement = getSegmentedOptionByIndex(1);\n\n      await fixture.whenStable();\n      fixture.detectChanges();\n\n      expect(theFirstElement.classList).toContain('ant-segmented-item-selected');\n      expect(component.handleValueChange).toHaveBeenCalledTimes(0);\n\n      dispatchMouseEvent(theSecondElement, 'click');\n      await fixture.whenStable();\n      fixture.detectChanges();\n\n      expect(theFirstElement.classList).not.toContain('ant-segmented-item-selected');\n      expect(theSecondElement.classList).toContain('ant-segmented-item-selected');\n      expect(component.handleValueChange).toHaveBeenCalledTimes(1);\n      expect(component.handleValueChange).toHaveBeenCalledWith(2);\n    });\n\n    it('should support object options', async () => {\n      component.options = [\n        'Daily',\n        { label: 'Weekly', value: 'Weekly', disabled: true },\n        'Monthly',\n        { label: 'Quarterly', value: 'Quarterly', disabled: true },\n        'Yearly'\n      ];\n      fixture.detectChanges();\n      await fixture.whenStable();\n      fixture.detectChanges();\n\n      const theFirstElement = getSegmentedOptionByIndex(0);\n      const theSecondElement = getSegmentedOptionByIndex(1);\n      const theThirdElement = getSegmentedOptionByIndex(2);\n\n      expect(theFirstElement.classList).toContain('ant-segmented-item-selected');\n      expect(theSecondElement.classList).not.toContain('ant-segmented-item-selected');\n\n      dispatchMouseEvent(theSecondElement, 'click');\n      await fixture.whenStable();\n      fixture.detectChanges();\n\n      expect(theFirstElement.classList).toContain('ant-segmented-item-selected');\n      expect(theSecondElement.classList).not.toContain('ant-segmented-item-selected');\n\n      dispatchMouseEvent(theThirdElement, 'click');\n      await fixture.whenStable();\n      fixture.detectChanges();\n\n      expect(theFirstElement.classList).not.toContain('ant-segmented-item-selected');\n      expect(theThirdElement.classList).toContain('ant-segmented-item-selected');\n    });\n\n    it('should support disabled mode', async () => {\n      const theFirstElement = getSegmentedOptionByIndex(0);\n      const theSecondElement = getSegmentedOptionByIndex(1);\n\n      component.disabled = true;\n      fixture.detectChanges();\n      await fixture.whenStable();\n      fixture.detectChanges();\n\n      dispatchMouseEvent(theSecondElement, 'click');\n      await fixture.whenStable();\n      fixture.detectChanges();\n\n      expect(theFirstElement.classList).toContain('ant-segmented-item-selected');\n      expect(theSecondElement.classList).toContain('ant-segmented-item-disabled');\n      expect(theSecondElement.classList).not.toContain('ant-segmented-item-selected');\n    });\n\n    describe('keyboard interaction', () => {\n      let theFirstElement: HTMLElement;\n      let theSecondElement: HTMLElement;\n      let theThirdElement: HTMLElement;\n\n      beforeEach(() => {\n        fixture.detectChanges();\n        theFirstElement = getSegmentedOptionByIndex(0);\n        theSecondElement = getSegmentedOptionByIndex(1);\n        theThirdElement = getSegmentedOptionByIndex(2);\n      });\n\n      it('should right arrow works', fakeAsync(() => {\n        dispatchKeyboardEvent(theFirstElement, 'keydown', RIGHT_ARROW);\n        tick(100);\n        fixture.detectChanges();\n        expect(theFirstElement.classList).not.toContain('ant-segmented-item-selected');\n        expect(theSecondElement.classList).toContain('ant-segmented-item-selected');\n\n        dispatchKeyboardEvent(theSecondElement, 'keydown', RIGHT_ARROW);\n        tick(100);\n        fixture.detectChanges();\n        expect(theSecondElement.classList).not.toContain('ant-segmented-item-selected');\n        expect(theThirdElement.classList).toContain('ant-segmented-item-selected');\n\n        // when the last item is selected, the first item should be selected\n        dispatchKeyboardEvent(theThirdElement, 'keydown', RIGHT_ARROW);\n        tick(100);\n        fixture.detectChanges();\n        expect(theThirdElement.classList).not.toContain('ant-segmented-item-selected');\n        expect(theFirstElement.classList).toContain('ant-segmented-item-selected');\n      }));\n\n      it('should left arrow works', fakeAsync(() => {\n        // when the first item is selected, the last item should be selected\n        dispatchKeyboardEvent(theFirstElement, 'keydown', LEFT_ARROW);\n        tick(100);\n        fixture.detectChanges();\n        expect(theFirstElement.classList).not.toContain('ant-segmented-item-selected');\n        expect(theThirdElement.classList).toContain('ant-segmented-item-selected');\n\n        dispatchKeyboardEvent(theThirdElement, 'keydown', LEFT_ARROW);\n        tick(100);\n        fixture.detectChanges();\n        expect(theThirdElement.classList).not.toContain('ant-segmented-item-selected');\n        expect(theSecondElement.classList).toContain('ant-segmented-item-selected');\n\n        dispatchKeyboardEvent(theSecondElement, 'keydown', LEFT_ARROW);\n        tick(100);\n        fixture.detectChanges();\n        expect(theSecondElement.classList).not.toContain('ant-segmented-item-selected');\n        expect(theFirstElement.classList).toContain('ant-segmented-item-selected');\n      }));\n\n      it('should not work if the segmented component is disabled', fakeAsync(() => {\n        component.disabled = true;\n        fixture.detectChanges();\n\n        const offsetSpy = spyOn(segmentedComponent.componentInstance, 'onOffset');\n\n        dispatchKeyboardEvent(theFirstElement, 'keydown', LEFT_ARROW);\n        tick(100);\n        fixture.detectChanges();\n        expect(offsetSpy).not.toHaveBeenCalled();\n      }));\n\n      it('should not work if the segmented item is disabled', fakeAsync(() => {\n        component.options = [\n          {\n            value: 1,\n            label: '1',\n            disabled: true\n          },\n          {\n            value: 2,\n            label: '2'\n          },\n          {\n            value: 3,\n            label: '3'\n          }\n        ];\n        fixture.detectChanges();\n\n        const offsetSpy = spyOn(segmentedComponent.componentInstance, 'onOffset');\n\n        dispatchKeyboardEvent(theFirstElement, 'keydown', LEFT_ARROW);\n        tick(100);\n        fixture.detectChanges();\n        expect(offsetSpy).not.toHaveBeenCalled();\n      }));\n\n      it('should skip the disabled item', fakeAsync(() => {\n        component.options = [\n          {\n            value: 1,\n            label: '1'\n          },\n          {\n            value: 2,\n            label: '2',\n            disabled: true\n          },\n          {\n            value: 3,\n            label: '3'\n          }\n        ];\n        fixture.detectChanges();\n\n        dispatchKeyboardEvent(theFirstElement, 'keydown', RIGHT_ARROW);\n        tick(100);\n        fixture.detectChanges();\n        expect(theFirstElement.classList).not.toContain('ant-segmented-item-selected');\n        expect(theThirdElement.classList).toContain('ant-segmented-item-selected');\n\n        dispatchKeyboardEvent(theFirstElement, 'keydown', LEFT_ARROW);\n        tick(100);\n        fixture.detectChanges();\n        expect(theThirdElement.classList).not.toContain('ant-segmented-item-selected');\n        expect(theFirstElement.classList).toContain('ant-segmented-item-selected');\n      }));\n    });\n  });\n\n  describe('rtl', () => {\n    let fixture: ComponentFixture<NzSegmentedRtlTestComponent>;\n    let segmentedComponent: DebugElement;\n\n    function getSegmentedOptionByIndex(index: number): HTMLElement {\n      return segmentedComponent.nativeElement.querySelectorAll('.ant-segmented-item')[index];\n    }\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzSegmentedRtlTestComponent);\n      segmentedComponent = fixture.debugElement.query(By.directive(NzSegmentedComponent));\n      fixture.detectChanges();\n    });\n\n    describe('keyboard interaction', () => {\n      let theFirstElement: HTMLElement;\n      let theSecondElement: HTMLElement;\n      let theThirdElement: HTMLElement;\n\n      beforeEach(() => {\n        fixture.detectChanges();\n        theFirstElement = getSegmentedOptionByIndex(0);\n        theSecondElement = getSegmentedOptionByIndex(1);\n        theThirdElement = getSegmentedOptionByIndex(2);\n      });\n\n      it('should left arrow works in rtl mode', fakeAsync(() => {\n        dispatchKeyboardEvent(theFirstElement, 'keydown', LEFT_ARROW);\n        tick(100);\n        fixture.detectChanges();\n        expect(theFirstElement.classList).not.toContain('ant-segmented-item-selected');\n        expect(theSecondElement.classList).toContain('ant-segmented-item-selected');\n\n        dispatchKeyboardEvent(theSecondElement, 'keydown', LEFT_ARROW);\n        tick(100);\n        fixture.detectChanges();\n        expect(theSecondElement.classList).not.toContain('ant-segmented-item-selected');\n        expect(theThirdElement.classList).toContain('ant-segmented-item-selected');\n\n        // when the last item is selected, the first item should be selected\n        dispatchKeyboardEvent(theThirdElement, 'keydown', LEFT_ARROW);\n        tick(100);\n        fixture.detectChanges();\n        expect(theThirdElement.classList).not.toContain('ant-segmented-item-selected');\n        expect(theFirstElement.classList).toContain('ant-segmented-item-selected');\n      }));\n\n      it('should right arrow works in rtl mode', fakeAsync(() => {\n        // when the first item is selected, the last item should be selected\n        dispatchKeyboardEvent(theFirstElement, 'keydown', RIGHT_ARROW);\n        tick(100);\n        fixture.detectChanges();\n        expect(theFirstElement.classList).not.toContain('ant-segmented-item-selected');\n        expect(theThirdElement.classList).toContain('ant-segmented-item-selected');\n\n        dispatchKeyboardEvent(theThirdElement, 'keydown', RIGHT_ARROW);\n        tick(100);\n        fixture.detectChanges();\n        expect(theThirdElement.classList).not.toContain('ant-segmented-item-selected');\n        expect(theSecondElement.classList).toContain('ant-segmented-item-selected');\n\n        dispatchKeyboardEvent(theSecondElement, 'keydown', RIGHT_ARROW);\n        tick(100);\n        fixture.detectChanges();\n        expect(theSecondElement.classList).not.toContain('ant-segmented-item-selected');\n        expect(theFirstElement.classList).toContain('ant-segmented-item-selected');\n      }));\n    });\n  });\n\n  describe('DOM structure', () => {\n    let fixture: ComponentFixture<NzSegmentedDomStructureTestComponent>;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzSegmentedDomStructureTestComponent);\n      fixture.detectChanges();\n    });\n\n    it('should render an icon element and a text node with a wrapper element if the item is label-with-icon', () => {\n      const [withIcon] = fixture.debugElement.queryAll(By.css('.ant-segmented-item-label'));\n      expect(withIcon.children.length).toBe(2);\n      expect(withIcon.children[0].nativeElement.classList).toContain('ant-segmented-item-icon');\n      expect(withIcon.children[1].nativeElement.tagName).toBe('SPAN');\n      expect(withIcon.children[1].nativeElement.textContent.trim()).toBe('WithIcon');\n    });\n\n    it('should render a text node without wrapping elements if the item is label-only', () => {\n      const [, labelOnly] = fixture.debugElement.queryAll(By.css('.ant-segmented-item-label'));\n      expect(labelOnly.children.length).toBe(0);\n      expect(labelOnly.nativeElement.textContent.trim()).toBe('LabelOnly');\n    });\n\n    it('should render only one icon element if the item is icon-only', () => {\n      const [, , iconOnly] = fixture.debugElement.queryAll(By.css('.ant-segmented-item-label'));\n      expect(iconOnly.children.length).toBe(1);\n      expect(iconOnly.children[0].nativeElement.classList).toContain('ant-segmented-item-icon');\n    });\n  });\n\n  describe('ng model', () => {\n    let fixture: ComponentFixture<NzSegmentedNgModelTestComponent>;\n    let component: NzSegmentedNgModelTestComponent;\n    let segmentedComponent: DebugElement;\n\n    function getSegmentedOptionByIndex(index: number): HTMLElement {\n      return segmentedComponent.nativeElement.querySelectorAll('.ant-segmented-item')[index];\n    }\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzSegmentedNgModelTestComponent);\n      component = fixture.componentInstance;\n      spyOn(component, 'handleValueChange');\n      segmentedComponent = fixture.debugElement.query(By.directive(NzSegmentedComponent));\n      fixture.detectChanges();\n    });\n\n    it('should be support two-way binding', async () => {\n      const theFirstElement = getSegmentedOptionByIndex(0);\n      const theSecondElement = getSegmentedOptionByIndex(1);\n\n      await fixture.whenStable();\n      fixture.detectChanges();\n\n      expect(theFirstElement.classList).toContain('ant-segmented-item-selected');\n      expect(component.handleValueChange).toHaveBeenCalledTimes(0);\n\n      component.value = 2;\n      fixture.detectChanges();\n      await fixture.whenStable();\n      fixture.detectChanges();\n\n      expect(theFirstElement.classList).not.toContain('ant-segmented-item-selected');\n      expect(theSecondElement.classList).toContain('ant-segmented-item-selected');\n      expect(component.handleValueChange).toHaveBeenCalledTimes(0);\n\n      dispatchMouseEvent(theFirstElement, 'click');\n      await fixture.whenStable();\n      fixture.detectChanges();\n\n      expect(theFirstElement.classList).toContain('ant-segmented-item-selected');\n      expect(theSecondElement.classList).not.toContain('ant-segmented-item-selected');\n      expect(component.value).toBe(1);\n      expect(component.handleValueChange).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('reactive form', () => {\n    let fixture: ComponentFixture<NzSegmentedInReactiveFormTestComponent>;\n    let component: NzSegmentedInReactiveFormTestComponent;\n    let segmentedComponent: DebugElement;\n\n    function getSegmentedOptionByIndex(index: number): HTMLElement {\n      return segmentedComponent.nativeElement.querySelectorAll('.ant-segmented-item')[index];\n    }\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzSegmentedInReactiveFormTestComponent);\n      component = fixture.componentInstance;\n      segmentedComponent = fixture.debugElement.query(By.directive(NzSegmentedComponent));\n      fixture.detectChanges();\n    });\n\n    it('first change form control value should work', async () => {\n      const theSecondElement = getSegmentedOptionByIndex(1);\n      const theThirdElement = getSegmentedOptionByIndex(2);\n\n      expect(component.formControl.value).toBe('Weekly');\n\n      dispatchMouseEvent(theThirdElement, 'click');\n      await fixture.whenStable();\n      fixture.detectChanges();\n\n      expect(theSecondElement.classList).not.toContain('ant-segmented-item-selected');\n      expect(theThirdElement.classList).toContain('ant-segmented-item-selected');\n    });\n  });\n\n  describe('vertical segmented', () => {\n    let fixture: ComponentFixture<NzSegmentedVerticalTestComponent>;\n    let component: NzSegmentedVerticalTestComponent;\n    let segmentedComponent: DebugElement;\n\n    function getSegmentedOptionByIndex(index: number): HTMLElement {\n      return segmentedComponent.nativeElement.querySelectorAll('.ant-segmented-item')[index];\n    }\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzSegmentedVerticalTestComponent);\n      component = fixture.componentInstance;\n      spyOn(component, 'handleValueChange');\n      segmentedComponent = fixture.debugElement.query(By.directive(NzSegmentedComponent));\n      fixture.detectChanges();\n    });\n\n    it('should render in vertical mode', () => {\n      const segmentedElement: HTMLElement = segmentedComponent.nativeElement;\n      expect(segmentedElement.classList).toContain('ant-segmented-vertical');\n      const groupElement = segmentedElement.querySelector('.ant-segmented-group') as HTMLElement;\n      expect(groupElement).toBeTruthy();\n    });\n\n    it('should change selection in vertical mode', async () => {\n      const theFirstElement = getSegmentedOptionByIndex(0);\n      const theSecondElement = getSegmentedOptionByIndex(1);\n\n      await fixture.whenStable();\n      fixture.detectChanges();\n\n      expect(theFirstElement.classList).toContain('ant-segmented-item-selected');\n      expect(component.handleValueChange).toHaveBeenCalledTimes(0);\n\n      dispatchMouseEvent(theSecondElement, 'click');\n      await fixture.whenStable();\n      fixture.detectChanges();\n\n      expect(theFirstElement.classList).not.toContain('ant-segmented-item-selected');\n      expect(theSecondElement.classList).toContain('ant-segmented-item-selected');\n      expect(component.handleValueChange).toHaveBeenCalledTimes(1);\n      expect(component.handleValueChange).toHaveBeenCalledWith(2);\n    });\n\n    describe('keyboard interaction', () => {\n      let theFirstElement: HTMLElement;\n      let theSecondElement: HTMLElement;\n      let theThirdElement: HTMLElement;\n\n      beforeEach(() => {\n        fixture.detectChanges();\n        theFirstElement = getSegmentedOptionByIndex(0);\n        theSecondElement = getSegmentedOptionByIndex(1);\n        theThirdElement = getSegmentedOptionByIndex(2);\n      });\n\n      it('should down arrow works', fakeAsync(() => {\n        dispatchKeyboardEvent(theFirstElement, 'keydown', DOWN_ARROW);\n        tick(100);\n        fixture.detectChanges();\n        expect(theFirstElement.classList).not.toContain('ant-segmented-item-selected');\n        expect(theSecondElement.classList).toContain('ant-segmented-item-selected');\n\n        dispatchKeyboardEvent(theSecondElement, 'keydown', DOWN_ARROW);\n        tick(100);\n        fixture.detectChanges();\n        expect(theSecondElement.classList).not.toContain('ant-segmented-item-selected');\n        expect(theThirdElement.classList).toContain('ant-segmented-item-selected');\n\n        // when the last item is selected, the first item should be selected\n        dispatchKeyboardEvent(theThirdElement, 'keydown', DOWN_ARROW);\n        tick(100);\n        fixture.detectChanges();\n        expect(theThirdElement.classList).not.toContain('ant-segmented-item-selected');\n        expect(theFirstElement.classList).toContain('ant-segmented-item-selected');\n      }));\n\n      it('should up arrow works', fakeAsync(() => {\n        // when the first item is selected, the last item should be selected\n        dispatchKeyboardEvent(theFirstElement, 'keydown', UP_ARROW);\n        tick(100);\n        fixture.detectChanges();\n        expect(theFirstElement.classList).not.toContain('ant-segmented-item-selected');\n        expect(theThirdElement.classList).toContain('ant-segmented-item-selected');\n\n        dispatchKeyboardEvent(theThirdElement, 'keydown', UP_ARROW);\n        tick(100);\n        fixture.detectChanges();\n        expect(theThirdElement.classList).not.toContain('ant-segmented-item-selected');\n        expect(theSecondElement.classList).toContain('ant-segmented-item-selected');\n\n        dispatchKeyboardEvent(theSecondElement, 'keydown', UP_ARROW);\n        tick(100);\n        fixture.detectChanges();\n        expect(theSecondElement.classList).not.toContain('ant-segmented-item-selected');\n        expect(theFirstElement.classList).toContain('ant-segmented-item-selected');\n      }));\n    });\n  });\n\n  describe('a11y', () => {\n    let fixture: ComponentFixture<NzSegmentedTestComponent>;\n    let component: NzSegmentedTestComponent;\n    let segmentedComponent: DebugElement;\n\n    function getSegmentedOptionByIndex(index: number): HTMLElement {\n      return segmentedComponent.nativeElement.querySelectorAll('.ant-segmented-item')[index];\n    }\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzSegmentedTestComponent);\n      component = fixture.componentInstance;\n      segmentedComponent = fixture.debugElement.query(By.directive(NzSegmentedComponent));\n      fixture.detectChanges();\n    });\n\n    it('should have default radio group name', () => {\n      const theFirstElement = getSegmentedOptionByIndex(0);\n      expect(theFirstElement.querySelector('input')?.getAttribute('name')?.startsWith('segmented_')).toBe(true);\n    });\n\n    it('should support custom radio group name', () => {\n      component.name = 'custom_name';\n      fixture.detectChanges();\n      const theFirstElement = getSegmentedOptionByIndex(0);\n      expect(theFirstElement.querySelector('input')?.getAttribute('name')).toBe('custom_name');\n    });\n  });\n});\n\ndescribe('segmented animation', () => {\n  let fixture: ComponentFixture<NzSegmentedTestComponent>;\n  let component: NzSegmentedTestComponent;\n  let segmentedComponent: DebugElement;\n\n  function getSegmentedOptionByIndex(index: number): HTMLElement {\n    return segmentedComponent.nativeElement.querySelectorAll('.ant-segmented-item')[index];\n  }\n\n  function getThumbElement(): HTMLElement {\n    return segmentedComponent.nativeElement.querySelector('.ant-segmented-thumb');\n  }\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzSegmentedTestComponent);\n    component = fixture.componentInstance;\n    spyOn(component, 'handleValueChange');\n    segmentedComponent = fixture.debugElement.query(By.directive(NzSegmentedComponent));\n  });\n\n  it('should not render thumb element if not in animation', async () => {\n    await fixture.whenStable();\n    const segmentedComponentInstance = fixture.debugElement.query(By.directive(NzSegmentedComponent)).componentInstance;\n\n    expect(segmentedComponentInstance.showThumb()).toBeFalse();\n    expect(getThumbElement()).toBeFalsy();\n  });\n\n  it('should animate thumb correctly', async () => {\n    await fixture.whenStable();\n    const segmentedComponentInstance = fixture.debugElement.query(By.directive(NzSegmentedComponent)).componentInstance;\n    const theSecondElement = getSegmentedOptionByIndex(1);\n\n    dispatchMouseEvent(theSecondElement, 'click');\n    await fixture.whenStable();\n    expect(segmentedComponentInstance.showThumb()).toBeTrue();\n\n    const thumbElement = getThumbElement();\n    expect(thumbElement.style.transform).toContain('translateX');\n    expect(theSecondElement.classList).not.toContain('ant-segmented-item-selected');\n\n    dispatchEvent(thumbElement, new TransitionEvent('transitionend', { propertyName: 'transform' }));\n    await fixture.whenStable();\n    expect(segmentedComponentInstance.showThumb()).toBeFalse();\n    expect(theSecondElement.classList).toContain('ant-segmented-item-selected');\n  });\n\n  it('should animate thumb correctly in vertical mode', async () => {\n    component.vertical = true;\n    await fixture.whenStable();\n\n    const segmentedComponentInstance = fixture.debugElement.query(By.directive(NzSegmentedComponent)).componentInstance;\n    const theSecondElement = getSegmentedOptionByIndex(1);\n\n    dispatchMouseEvent(theSecondElement, 'click');\n    await fixture.whenStable();\n    expect(segmentedComponentInstance.showThumb()).toBeTrue();\n\n    const thumbElement = getThumbElement();\n    expect(thumbElement.style.transform).toContain('translateY');\n    expect(theSecondElement.classList).not.toContain('ant-segmented-item-selected');\n\n    dispatchEvent(thumbElement, new TransitionEvent('transitionend', { propertyName: 'transform' }));\n    await fixture.whenStable();\n    expect(segmentedComponentInstance.showThumb()).toBeFalse();\n    expect(theSecondElement.classList).toContain('ant-segmented-item-selected');\n  });\n});\n\n@Component({\n  imports: [FormsModule, NzSegmentedModule],\n  template: `\n    <nz-segmented\n      [nzSize]=\"size\"\n      [nzOptions]=\"options\"\n      [nzDisabled]=\"disabled\"\n      [nzBlock]=\"block\"\n      [nzVertical]=\"vertical\"\n      [nzShape]=\"shape\"\n      [nzName]=\"name\"\n      (nzValueChange)=\"handleValueChange($event)\"\n    />\n  `\n})\nexport class NzSegmentedTestComponent {\n  size: NzSizeLDSType = 'default';\n  options: NzSegmentedOptions = [1, 2, 3];\n  block = false;\n  disabled = false;\n  vertical = false;\n  shape: 'default' | 'round' = 'default';\n  name?: string;\n\n  handleValueChange(_e: string | number): void {\n    // empty\n  }\n}\n\n@Component({\n  imports: [NzSegmentedModule],\n  template: `<nz-segmented [nzOptions]=\"options\" />`\n})\nexport class NzSegmentedDomStructureTestComponent {\n  options: NzSegmentedOptions = [\n    { value: 'WithIcon', label: 'WithIcon', icon: 'bars' },\n    { value: 'LabelOnly', label: 'LabelOnly' },\n    { value: 'IconOnly', icon: 'bars' }\n  ];\n}\n\n@Component({\n  imports: [FormsModule, NzSegmentedModule],\n  template: `<nz-segmented [nzOptions]=\"options\" [(ngModel)]=\"value\" (ngModelChange)=\"handleValueChange($event)\" />`\n})\nexport class NzSegmentedNgModelTestComponent {\n  options: NzSegmentedOptions = [1, 2, 3];\n  value: number | string = 1;\n\n  handleValueChange(_e: string | number): void {\n    // empty\n  }\n}\n\n@Component({\n  imports: [ReactiveFormsModule, NzSegmentedModule],\n  template: `<nz-segmented [nzOptions]=\"options\" [formControl]=\"formControl\" />`\n})\nexport class NzSegmentedInReactiveFormTestComponent {\n  options = ['Daily', 'Weekly', 'Monthly', 'Quarterly', 'Yearly'];\n  formControl = new FormControl('Weekly');\n}\n\n@Component({\n  imports: [FormsModule, NzSegmentedModule],\n  template: `<nz-segmented [nzOptions]=\"options\" nzVertical (nzValueChange)=\"handleValueChange($event)\" />`\n})\nexport class NzSegmentedVerticalTestComponent {\n  options: NzSegmentedOptions = [1, 2, 3];\n\n  handleValueChange(_e: string | number): void {\n    // empty\n  }\n}\n\n@Component({\n  imports: [BidiModule, NzSegmentedModule],\n  template: `<nz-segmented [nzOptions]=\"options\" dir=\"rtl\" />`\n})\nexport class NzSegmentedRtlTestComponent {\n  options: NzSegmentedOptions = [1, 2, 3];\n}\n"
  },
  {
    "path": "components/segmented/style/entry.less",
    "content": "@import './index.less';\n"
  },
  {
    "path": "components/segmented/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import './mixins.less';\n\n@segmented-prefix-cls: ~'@{ant-prefix}-segmented';\n\n@segmented-container-padding: 2px;\n\n.@{segmented-prefix-cls} {\n  .reset-component();\n  display: inline-block;\n  padding: @segmented-container-padding;\n  color: @segmented-label-color;\n  background-color: @segmented-bg;\n  border-radius: @border-radius-base;\n  transition: all 0.3s @ease-in-out;\n\n  &-group {\n    position: relative;\n    display: flex;\n    align-items: stretch;\n    justify-items: flex-start;\n    width: 100%;\n  }\n\n  &-vertical {\n    .@{segmented-prefix-cls}-group {\n      flex-direction: column;\n    }\n\n    .@{segmented-prefix-cls}-thumb {\n      width: 100%;\n      height: 0;\n    }\n\n    .@{segmented-prefix-cls}-thumb-motion-appear-active {\n      transition:\n        transform @animation-duration-slow @ease-in-out,\n        height @animation-duration-slow @ease-in-out;\n      will-change: transform, height;\n    }\n  }\n\n  &-shape-round {\n    border-radius: 9999px;\n\n    .@{segmented-prefix-cls}-item {\n      border-radius: 9999px;\n    }\n\n    .@{segmented-prefix-cls}-thumb {\n      border-radius: 9999px;\n    }\n  }\n\n  // block styles\n  &&-block {\n    display: flex;\n  }\n\n  &&-block &-item {\n    flex: 1;\n    min-width: 0;\n  }\n\n  // hover/focus styles\n  &:not(&-disabled) {\n    &:hover,\n    &:focus {\n      background-color: @segmented-hover-bg;\n    }\n  }\n\n  // item styles\n  &-item {\n    position: relative;\n    text-align: center;\n    cursor: pointer;\n    transition: color 0.3s @ease-in-out;\n\n    &-selected {\n      .segmented-item-selected();\n      color: @segmented-label-hover-color;\n    }\n\n    &:hover,\n    &:focus {\n      color: @segmented-label-hover-color;\n    }\n\n    &-label {\n      min-height: @input-height-base - @segmented-container-padding * 2;\n      padding: 0 @input-padding-horizontal-base;\n      line-height: @input-height-base - @segmented-container-padding * 2;\n      .segmented-text-ellipsis();\n    }\n\n    // syntactic sugar to add `icon` for Segmented Item\n    &-icon + * {\n      margin-left: (@margin-sm / 2);\n    }\n\n    &-input {\n      position: absolute;\n      top: 0;\n      left: 0;\n      width: 0;\n      height: 0;\n      opacity: 0;\n      pointer-events: none;\n    }\n  }\n\n  // size styles\n  &&-lg &-item-label {\n    min-height: @input-height-lg - @segmented-container-padding * 2;\n    padding: 0 @input-padding-horizontal-lg;\n    font-size: @font-size-lg;\n    line-height: @input-height-lg - @segmented-container-padding * 2;\n  }\n\n  &&-sm &-item-label {\n    min-height: @input-height-sm - @segmented-container-padding * 2;\n    padding: 0 @input-padding-horizontal-sm;\n    line-height: @input-height-sm - @segmented-container-padding * 2;\n  }\n\n  // disabled styles\n  &-item-disabled {\n    .segmented-disabled-item();\n  }\n\n  // thumb styles\n  &-thumb {\n    .segmented-item-selected();\n\n    position: absolute;\n    inset-block-start: 0;\n    inset-inline-start: 0;\n    width: 0;\n    height: 100%;\n    padding: @padding-xss 0;\n  }\n\n  // transition effect when `appear-active`\n  &-thumb-motion-appear-active {\n    transition:\n      transform @animation-duration-slow @ease-in-out,\n      width @animation-duration-slow @ease-in-out;\n    will-change: transform, width;\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/segmented/style/mixins.less",
    "content": "// mixins\n.segmented-disabled-item {\n  &,\n  &:hover,\n  &:focus {\n    color: @disabled-color;\n    cursor: not-allowed;\n  }\n}\n\n.segmented-item-selected {\n  background-color: @segmented-selected-bg;\n  border-radius: @border-radius-base;\n  box-shadow: 0 2px 8px -2px fade(@black, 5%), 0 1px 4px -1px fade(@black, 7%),\n    0 0 1px 0 fade(@black, 8%);\n}\n\n.segmented-text-ellipsis {\n  overflow: hidden;\n  // handle text ellipsis\n  white-space: nowrap;\n  text-overflow: ellipsis;\n  word-break: keep-all;\n}\n"
  },
  {
    "path": "components/segmented/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@segmented-prefix-cls: ~'@{ant-prefix}-segmented';\n\n.@{segmented-prefix-cls} {\n  &&-rtl {\n    direction: rtl;\n  }\n\n  &&-rtl &-item-icon {\n    margin-right: 0;\n    margin-left: 6px;\n  }\n}\n"
  },
  {
    "path": "components/segmented/types.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport type NzSegmentedOption = {\n  value: string | number;\n  disabled?: boolean;\n} & (NzSegmentedWithLabel | NzSegmentedWithIcon);\n\nexport interface NzSegmentedWithLabel {\n  label: string;\n  icon?: string;\n}\n\nexport interface NzSegmentedWithIcon {\n  icon: string;\n  label?: string;\n}\n\nexport type NzSegmentedOptions = Array<NzSegmentedOption | string | number>;\n\nexport function normalizeOptions(unnormalized: NzSegmentedOptions): NzSegmentedOption[] {\n  return unnormalized.map(item => {\n    if (typeof item === 'string' || typeof item === 'number') {\n      return {\n        label: `${item}`,\n        value: item\n      };\n    }\n\n    return item;\n  });\n}\n"
  },
  {
    "path": "components/select/demo/automatic-tokenization.md",
    "content": "---\norder: 12\ntitle:\n  zh-CN: 自动分词\n  en-US: Automatic tokenization\n---\n\n## zh-CN\n\n试下复制 `露西,杰克` 到输入框里。只在 tags 和 multiple 模式下可用。\n\n## en-US\n\nTry to copy `Lucy,Jack` to the input. Only available in tags and multiple mode.\n"
  },
  {
    "path": "components/select/demo/automatic-tokenization.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\nfunction alphabet(): string[] {\n  const children: string[] = [];\n  for (let i = 10; i < 36; i++) {\n    children.push(i.toString(36) + i);\n  }\n  return children;\n}\n\n@Component({\n  selector: 'nz-demo-select-automatic-tokenization',\n  imports: [FormsModule, NzSelectModule],\n  template: `\n    <nz-select\n      [(ngModel)]=\"listOfTagOptions\"\n      nzMode=\"tags\"\n      [nzTokenSeparators]=\"[',']\"\n      nzPlaceHolder=\"automatic tokenization\"\n    >\n      @for (option of listOfOption; track option.value) {\n        <nz-option [nzLabel]=\"option.label\" [nzValue]=\"option.value\" />\n      }\n    </nz-select>\n  `,\n  styles: `\n    nz-select {\n      width: 100%;\n    }\n  `\n})\nexport class NzDemoSelectAutomaticTokenizationComponent {\n  readonly listOfOption: Array<{ label: string; value: string }> = alphabet().map(item => ({\n    label: item,\n    value: item\n  }));\n  listOfTagOptions: string[] = [];\n}\n"
  },
  {
    "path": "components/select/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本使用\n  en-US: Basic Usage\n---\n\n## zh-CN\n\n基本使用。\n\n## en-US\n\nBasic Usage.\n"
  },
  {
    "path": "components/select/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\n@Component({\n  selector: 'nz-demo-select-basic',\n  imports: [FormsModule, NzSelectModule],\n  template: `\n    <nz-select ngModel=\"lucy\">\n      <nz-option nzValue=\"jack\" nzLabel=\"Jack\" />\n      <nz-option nzValue=\"lucy\" nzLabel=\"Lucy\" />\n      <nz-option nzValue=\"disabled\" nzLabel=\"Disabled\" nzDisabled />\n    </nz-select>\n    <nz-select ngModel=\"lucy\" nzDisabled>\n      <nz-option nzValue=\"lucy\" nzLabel=\"Lucy\" />\n    </nz-select>\n    <nz-select ngModel=\"lucy\" nzLoading>\n      <nz-option nzValue=\"lucy\" nzLabel=\"Lucy\" />\n    </nz-select>\n    <nz-select ngModel=\"lucy\" nzAllowClear nzPlaceHolder=\"Choose\">\n      <nz-option nzValue=\"lucy\" nzLabel=\"Lucy\" />\n    </nz-select>\n  `,\n  styles: `\n    nz-select {\n      margin: 0 8px 10px 0;\n      width: 120px;\n    }\n  `\n})\nexport class NzDemoSelectBasicComponent {}\n"
  },
  {
    "path": "components/select/demo/big-data.md",
    "content": "---\norder: 20\ntitle:\n  zh-CN: 大量数据\n  en-US: Large amounts of data\n---\n\n## zh-CN\n\n组件使用了虚拟滚动技术，可以同时处理大量数据。\n\n## en-US\n\nWith the help of virtual scroll, select component can deal with Large amounts of data.\n"
  },
  {
    "path": "components/select/demo/big-data.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\nfunction alphabet(size: number): string[] {\n  const children: string[] = [];\n  for (let i = 10; i < size; i++) {\n    children.push(i.toString(36) + i);\n  }\n  return children;\n}\n\n@Component({\n  selector: 'nz-demo-select-big-data',\n  imports: [FormsModule, NzSelectModule],\n  template: `\n    <nz-select\n      nzMode=\"multiple\"\n      nzPlaceHolder=\"Please select\"\n      [nzOptions]=\"listOfOption\"\n      [(ngModel)]=\"listOfSelectedValue\"\n    />\n  `,\n  styles: `\n    nz-select {\n      width: 100%;\n    }\n  `\n})\nexport class NzDemoSelectBigDataComponent {\n  readonly listOfOption: Array<{ value: string; label: string }> = alphabet(10000).map(item => ({\n    label: item,\n    value: item\n  }));\n  listOfSelectedValue = ['a10', 'c12'];\n}\n"
  },
  {
    "path": "components/select/demo/coordinate.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 联动\n  en-US: coordinate\n---\n\n## zh-CN\n\n省市联动是典型的例子。\n\n推荐使用 [Cascader](/components/cascader/zh) 组件。\n\n## en-US\n\nCoordinating the selection of provinces and cities is a common use case and demonstrates how selection can be coordinated.\n\nUsing the [Cascader](/components/cascader/en) component is strongly recommended instead as it is more flexible and capable.\n"
  },
  {
    "path": "components/select/demo/coordinate.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\n@Component({\n  selector: 'nz-demo-select-coordinate',\n  imports: [FormsModule, NzSelectModule],\n  template: `\n    <nz-select [(ngModel)]=\"selectedProvince\" (ngModelChange)=\"provinceChange($event)\">\n      @for (p of provinceData; track p) {\n        <nz-option [nzValue]=\"p\" [nzLabel]=\"p\" />\n      }\n    </nz-select>\n    <nz-select [(ngModel)]=\"selectedCity\">\n      @for (c of cityData[selectedProvince]; track c) {\n        <nz-option [nzValue]=\"c\" [nzLabel]=\"c\" />\n      }\n    </nz-select>\n  `,\n  styles: `\n    nz-select {\n      margin-right: 8px;\n      width: 120px;\n    }\n  `\n})\nexport class NzDemoSelectCoordinateComponent {\n  selectedProvince = 'Zhejiang';\n  selectedCity = 'Hangzhou';\n  provinceData = ['Zhejiang', 'Jiangsu'];\n  cityData: { [place: string]: string[] } = {\n    Zhejiang: ['Hangzhou', 'Ningbo', 'Wenzhou'],\n    Jiangsu: ['Nanjing', 'Suzhou', 'Zhenjiang']\n  };\n\n  provinceChange(value: string): void {\n    this.selectedCity = this.cityData[value][0];\n  }\n}\n"
  },
  {
    "path": "components/select/demo/custom-content.md",
    "content": "---\norder: 17\ntitle:\n  zh-CN: 自定义下拉菜单内容\n  en-US: Custom Option Template\n---\n\n## zh-CN\n\n通过 `nzCustomContent` 自定义下拉菜单选项显示的内容。\n\n## en-US\n\nCustom the content of nz-option via `nzCustomContent`.\n"
  },
  {
    "path": "components/select/demo/custom-content.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\n@Component({\n  selector: 'nz-demo-select-custom-content',\n  imports: [FormsModule, NzIconModule, NzSelectModule],\n  template: `\n    <nz-select nzShowSearch nzAllowClear nzPlaceHolder=\"Select OS\" [(ngModel)]=\"selectedValue\">\n      <nz-option nzCustomContent nzLabel=\"Windows\" nzValue=\"windows\">\n        <nz-icon nzType=\"windows\" />\n        Windows\n      </nz-option>\n      <nz-option nzCustomContent nzLabel=\"Mac\" nzValue=\"mac\">\n        <nz-icon nzType=\"apple\" />\n        Mac\n      </nz-option>\n      <nz-option nzCustomContent nzLabel=\"Android\" nzValue=\"android\">\n        <nz-icon nzType=\"android\" />\n        Android\n      </nz-option>\n    </nz-select>\n  `,\n  styles: `\n    nz-select {\n      width: 200px;\n    }\n  `\n})\nexport class NzDemoSelectCustomContentComponent {\n  selectedValue = null;\n}\n"
  },
  {
    "path": "components/select/demo/custom-dropdown-menu.md",
    "content": "---\norder: 15\ntitle:\n  zh-CN: 扩展菜单\n  en-US: Custom dropdown\n---\n\n## zh-CN\n\n使用 `nzDropdownRender` 对下拉菜单进行自由扩展。\n\n## en-US\n\nCustomize the dropdown menu via `nzDropdownRender`.\n"
  },
  {
    "path": "components/select/demo/custom-dropdown-menu.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\n@Component({\n  selector: 'nz-demo-select-custom-dropdown-menu',\n  imports: [NzDividerModule, NzIconModule, NzInputModule, NzSelectModule],\n  template: `\n    <nz-select nzShowSearch nzAllowClear [nzDropdownRender]=\"renderTemplate\" nzPlaceHolder=\"custom dropdown render\">\n      @for (item of listOfItem; track item) {\n        <nz-option [nzLabel]=\"item\" [nzValue]=\"item\" />\n      }\n    </nz-select>\n    <ng-template #renderTemplate>\n      <nz-divider />\n      <div class=\"container\">\n        <input type=\"text\" nz-input #inputElement />\n        <a class=\"add-item\" (click)=\"addItem(inputElement)\">\n          <nz-icon nzType=\"plus\" />\n          Add item\n        </a>\n      </div>\n    </ng-template>\n  `,\n  styles: `\n    nz-select {\n      width: 240px;\n    }\n    nz-divider {\n      margin: 4px 0;\n    }\n    .container {\n      display: flex;\n      flex-wrap: nowrap;\n      padding: 8px;\n    }\n    .add-item {\n      flex: 0 0 auto;\n      padding: 8px;\n      display: block;\n    }\n  `\n})\nexport class NzDemoSelectCustomDropdownMenuComponent {\n  listOfItem = ['jack', 'lucy'];\n  index = 0;\n\n  addItem(input: HTMLInputElement): void {\n    const value = input.value;\n    if (this.listOfItem.indexOf(value) === -1) {\n      this.listOfItem = [...this.listOfItem, input.value || `New item ${this.index++}`];\n    }\n  }\n}\n"
  },
  {
    "path": "components/select/demo/custom-template.md",
    "content": "---\norder: 22\ntitle:\n  zh-CN: 自定义选择标签\n  en-US: Custom Top Render\n---\n\n## zh-CN\n\n通过 `nzCustomTemplate` 自定义 nz-select 显示的内容。\n\n## en-US\n\nCustom the content of nz-select via `nzCustomTemplate`.\n"
  },
  {
    "path": "components/select/demo/custom-template.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\n@Component({\n  selector: 'nz-demo-select-custom-template',\n  imports: [NzIconModule, NzSelectModule],\n  template: `\n    <nz-select nzAllowClear nzPlaceHolder=\"Select OS\" [nzCustomTemplate]=\"defaultTemplate\">\n      <nz-option nzLabel=\"Windows\" nzValue=\"windows\" />\n      <nz-option nzLabel=\"Apple\" nzValue=\"apple\" />\n      <nz-option nzLabel=\"Android\" nzValue=\"android\" />\n    </nz-select>\n    <ng-template #defaultTemplate let-selected>\n      <nz-icon [nzType]=\"selected.nzValue\" />\n      {{ selected.nzLabel }}\n    </ng-template>\n    <br />\n    <br />\n    <nz-select nzAllowClear nzPlaceHolder=\"Select OS\" nzMode=\"multiple\" [nzCustomTemplate]=\"multipleTemplate\">\n      <nz-option nzLabel=\"Windows\" nzValue=\"windows\" />\n      <nz-option nzLabel=\"Apple\" nzValue=\"apple\" />\n      <nz-option nzLabel=\"Android\" nzValue=\"android\" />\n    </nz-select>\n    <ng-template #multipleTemplate let-selected>\n      <div class=\"ant-select-selection-item-content\">\n        <nz-icon [nzType]=\"selected.nzValue\" />\n        {{ selected.nzLabel }}\n      </div>\n    </ng-template>\n  `,\n  styles: `\n    nz-select {\n      width: 100%;\n    }\n  `\n})\nexport class NzDemoSelectCustomTemplateComponent {}\n"
  },
  {
    "path": "components/select/demo/default-value.md",
    "content": "---\norder: 19\ntitle:\n  zh-CN: 默认数据\n  en-US: Default Value\n---\n\n## zh-CN\n\n当需要显示默认值，同时默认值又不在选项列表中时，可以使用 `nzHide` 在 `nz-option` 中将默认选项隐藏\n\n## en-US\n\nDisplay a default value that not in the option list with `nzHide` in `nz-option`\n"
  },
  {
    "path": "components/select/demo/default-value.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\n@Component({\n  selector: 'nz-demo-select-default-value',\n  imports: [FormsModule, NzSelectModule],\n  template: `\n    <nz-select nzMode=\"multiple\" nzPlaceHolder=\"Inserted are removed\" [(ngModel)]=\"listOfSelectedValue\">\n      @for (option of listOfOption; track option) {\n        <nz-option [nzLabel]=\"option\" [nzValue]=\"option\" />\n      }\n      @for (option of defaultOption; track option) {\n        <nz-option [nzLabel]=\"option\" [nzValue]=\"option\" nzHide />\n      }\n    </nz-select>\n    <br />\n    <br />\n    <nz-select [(ngModel)]=\"selectedValue\">\n      @for (option of listOfOption; track option) {\n        <nz-option [nzLabel]=\"option\" [nzValue]=\"option\" />\n      }\n      <nz-option nzLabel=\"Default Value\" nzValue=\"Default\" nzHide />\n    </nz-select>\n  `,\n  styles: `\n    nz-select {\n      width: 100%;\n    }\n  `\n})\nexport class NzDemoSelectDefaultValueComponent {\n  listOfOption = ['Option 01', 'Option 02'];\n  listOfSelectedValue = ['Default 01', 'Default 02'];\n  defaultOption = [...this.listOfSelectedValue];\n  selectedValue = 'Default';\n}\n"
  },
  {
    "path": "components/select/demo/hide-selected.md",
    "content": "---\norder: 16\ntitle:\n  zh-CN: 隐藏已选择选项\n  en-US: Hide Already Selected\n---\n\n## zh-CN\n\n通过 `nzHide` 隐藏下拉列表中已选择的选项。\n\n## en-US\n\nHide already selected options in the dropdown via `nzHide`.\n"
  },
  {
    "path": "components/select/demo/hide-selected.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\n@Component({\n  selector: 'nz-demo-select-hide-selected',\n  imports: [FormsModule, NzSelectModule],\n  template: `\n    <nz-select nzMode=\"multiple\" nzPlaceHolder=\"Inserted are removed\" [(ngModel)]=\"listOfSelected\">\n      @for (option of listOfOption; track option) {\n        <nz-option [nzLabel]=\"option\" [nzValue]=\"option\" [nzHide]=\"!isSelected(option)\" />\n      }\n    </nz-select>\n  `,\n  styles: `\n    nz-select {\n      width: 100%;\n    }\n  `\n})\nexport class NzDemoSelectHideSelectedComponent {\n  listOfOption = ['Apples', 'Nails', 'Bananas', 'Helicopters'];\n  listOfSelected: string[] = [];\n\n  isSelected(value: string): boolean {\n    return this.listOfSelected.indexOf(value) !== -1;\n  }\n}\n"
  },
  {
    "path": "components/select/demo/label-in-value.md",
    "content": "---\norder: 10\ntitle:\n  zh-CN: 获得选项的对象\n  en-US: Get option object of selected item\n---\n\n## zh-CN\n\n`ngModel` 取到的值为选中 `nz-option` 的 `nzValue` 值，当 `nzValue` 传入为一个对象时，`ngModel` 获取的值也是一个对象，`compareWith` 的用法参见 [SelectControlValueAccessor](https://angular.cn/api/forms/SelectControlValueAccessor)。\n\n## en-US\n\nThe value of `ngModel` comes from the `nzValue` of `nz-option`, when the `nzValue` of `nz-option` is an object, the `ngModel` will be an object too, the usage of `compareWith` is the same as [SelectControlValueAccessor](https://angular.dev/api/forms/SelectControlValueAccessor).\n"
  },
  {
    "path": "components/select/demo/label-in-value.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\ninterface Option {\n  label: string;\n  value: string;\n  age: number;\n}\n\n@Component({\n  selector: 'nz-demo-select-label-in-value',\n  imports: [FormsModule, NzSelectModule],\n  template: `\n    <p>The selected option's age is {{ selectedValue?.age }}</p>\n    <br />\n    <nz-select\n      [(ngModel)]=\"selectedValue\"\n      [compareWith]=\"compareFn\"\n      (ngModelChange)=\"log($event)\"\n      nzAllowClear\n      nzPlaceHolder=\"Choose\"\n    >\n      @for (option of optionList; track option) {\n        <nz-option [nzValue]=\"option\" [nzLabel]=\"option.label\" />\n      }\n    </nz-select>\n  `,\n  styles: `\n    nz-select {\n      width: 120px;\n    }\n  `\n})\nexport class NzDemoSelectLabelInValueComponent {\n  optionList: Option[] = [\n    { label: 'Lucy', value: 'lucy', age: 20 },\n    { label: 'Jack', value: 'jack', age: 22 }\n  ];\n  selectedValue: Option = { label: 'Jack', value: 'jack', age: 22 };\n  readonly compareFn = (o1: Option, o2: Option): boolean => (o1 && o2 ? o1.value === o2.value : o1 === o2);\n\n  log(value: Option): void {\n    console.log(value);\n  }\n}\n"
  },
  {
    "path": "components/select/demo/max-count.md",
    "content": "---\norder: 26\ntitle:\n  zh-CN: 最大选中数量\n  en-US: Max Count\n---\n\n## zh-CN\n\n你可以通过设置 `nzMaxMultipleCount` 约束最多可选中的数量，当超出限制时会变成禁止选中状态。\n\n## en-US\n\nYou can set the `nzMaxMultipleCount` prop to control the max number of items can be selected. When the limit is exceeded, the options will become disabled.\n"
  },
  {
    "path": "components/select/demo/max-count.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\nfunction alphabet(): string[] {\n  const children: string[] = [];\n  for (let i = 10; i < 36; i++) {\n    children.push(i.toString(36) + i);\n  }\n  return children;\n}\n\n@Component({\n  selector: 'nz-demo-select-max-count',\n  imports: [FormsModule, NzSelectModule],\n  template: `\n    <nz-select\n      [nzMaxMultipleCount]=\"3\"\n      nzMode=\"multiple\"\n      nzPlaceHolder=\"Please select\"\n      nzAllowClear\n      [nzShowArrow]=\"true\"\n      [(ngModel)]=\"listOfSelectedValue\"\n    >\n      @for (item of listOfOption; track item) {\n        <nz-option [nzLabel]=\"item\" [nzValue]=\"item\" />\n      }\n    </nz-select>\n  `,\n  styles: `\n    nz-select {\n      width: 100%;\n    }\n  `\n})\nexport class NzDemoSelectMaxCountComponent {\n  readonly listOfOption: string[] = alphabet();\n  listOfSelectedValue = ['a10', 'c12'];\n}\n"
  },
  {
    "path": "components/select/demo/multiple.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 多选\n  en-US: multiple selection\n---\n\n## zh-CN\n\n多选，从已有条目中选择，例子中通过 `nzMaxTagCount` 限制最多显示3个选项。\n\n## en-US\n\nMultiple selection, selecting from existing items, max 3 option will display at the same time by `nzMaxTagCount`.\n"
  },
  {
    "path": "components/select/demo/multiple.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\nfunction alphabet(): string[] {\n  const children: string[] = [];\n  for (let i = 10; i < 36; i++) {\n    children.push(i.toString(36) + i);\n  }\n  return children;\n}\n\n@Component({\n  selector: 'nz-demo-select-multiple',\n  imports: [FormsModule, NzSelectModule],\n  template: `\n    <nz-select\n      [nzMaxTagCount]=\"3\"\n      [nzMaxTagPlaceholder]=\"tagPlaceHolder\"\n      nzMode=\"multiple\"\n      nzAllowClear\n      nzPlaceHolder=\"Please select\"\n      [(ngModel)]=\"listOfSelectedValue\"\n    >\n      @for (item of listOfOption; track item) {\n        <nz-option [nzLabel]=\"item\" [nzValue]=\"item\" />\n      }\n    </nz-select>\n    <ng-template #tagPlaceHolder let-selectedList>and {{ selectedList.length }} more selected</ng-template>\n  `,\n  styles: `\n    nz-select {\n      width: 100%;\n    }\n  `\n})\nexport class NzDemoSelectMultipleComponent {\n  readonly listOfOption: string[] = alphabet();\n  listOfSelectedValue = ['a10', 'c12'];\n}\n"
  },
  {
    "path": "components/select/demo/optgroup.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 分组\n  en-US: Option Group\n---\n\n## zh-CN\n\n用 `nz-option-group` 进行选项分组。\n\n## en-US\n\nUsing `nz-option-group` to group the options.\n"
  },
  {
    "path": "components/select/demo/optgroup.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\n@Component({\n  selector: 'nz-demo-select-optgroup',\n  imports: [FormsModule, NzSelectModule],\n  template: `\n    <nz-select [(ngModel)]=\"selectedValue\" nzAllowClear nzPlaceHolder=\"Choose\" nzShowSearch>\n      <nz-option-group nzLabel=\"Manager\">\n        <nz-option nzValue=\"jack\" nzLabel=\"Jack\" />\n        <nz-option nzValue=\"lucy\" nzLabel=\"Lucy\" />\n      </nz-option-group>\n      <nz-option-group nzLabel=\"Engineer\">\n        <nz-option nzValue=\"tom\" nzLabel=\"Tom\" />\n      </nz-option-group>\n    </nz-select>\n  `,\n  styles: `\n    nz-select {\n      width: 120px;\n    }\n  `\n})\nexport class NzDemoSelectOptgroupComponent {\n  selectedValue = 'lucy';\n}\n"
  },
  {
    "path": "components/select/demo/options.md",
    "content": "---\norder: 23\ntitle:\n  zh-CN: 传入 Options\n  en-US: Input Options\n---\n\n## zh-CN\n\n通过 `nzOptions` 直接传入选项内容\n\n## en-US\n\nPass all options via `nzOptions`\n"
  },
  {
    "path": "components/select/demo/options.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\n@Component({\n  selector: 'nz-demo-select-options',\n  imports: [FormsModule, NzSelectModule],\n  template: `\n    <nz-select ngModel=\"lucy\" [nzOptions]=\"listOfOption\" />\n    <nz-select [(ngModel)]=\"selectedValue\" nzAllowClear nzPlaceHolder=\"Choose\" [nzOptions]=\"listOfGroupOption\" />\n  `,\n  styles: `\n    nz-select {\n      margin: 0 8px 10px 0;\n      width: 120px;\n    }\n  `\n})\nexport class NzDemoSelectOptionsComponent {\n  selectedValue = 'lucy';\n  readonly listOfOption = [\n    { label: 'Jack', value: 'jack' },\n    { label: 'Lucy', value: 'lucy' },\n    { label: 'disabled', value: 'disabled', disabled: true }\n  ];\n  readonly listOfGroupOption = [\n    { label: 'Jack', value: 'jack', groupLabel: 'Manager' },\n    { label: 'Lucy', value: 'lucy', groupLabel: 'Manager' },\n    { label: 'Tom', value: 'tom', groupLabel: 'Engineer' }\n  ];\n}\n"
  },
  {
    "path": "components/select/demo/placement.md",
    "content": "---\norder: 25\ntitle:\n  zh-CN: 弹出位置\n  en-US: Placement\n---\n\n## zh-CN\n\n可以通过 `placement` 手动指定弹出的位置。\n\n## en-US\n\nYou can manually specify the position of the popup via `placement`.\n"
  },
  {
    "path": "components/select/demo/placement.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\nimport { NzSelectModule, NzSelectPlacementType } from 'ng-zorro-antd/select';\n\n@Component({\n  selector: 'nz-demo-select-placement',\n  imports: [FormsModule, NzRadioModule, NzSelectModule],\n  template: `\n    <nz-radio-group [(ngModel)]=\"placement\">\n      <label nz-radio-button nzValue=\"topLeft\">topLeft</label>\n      <label nz-radio-button nzValue=\"topRight\">topRight</label>\n      <label nz-radio-button nzValue=\"bottomLeft\">bottomLeft</label>\n      <label nz-radio-button nzValue=\"bottomRight\">bottomRight</label>\n    </nz-radio-group>\n    <br />\n    <br />\n    <nz-select [(ngModel)]=\"selectedValue\" [nzDropdownMatchSelectWidth]=\"false\" [nzPlacement]=\"placement\">\n      <nz-option nzValue=\"HangZhou\" nzLabel=\"HangZhou #310000\" />\n      <nz-option nzValue=\"NingBo\" nzLabel=\"NingBo #315000\" />\n      <nz-option nzValue=\"WenZhou\" nzLabel=\"WenZhou #325000\" />\n    </nz-select>\n  `,\n  styles: `\n    nz-select {\n      width: 120px;\n    }\n  `\n})\nexport class NzDemoSelectPlacementComponent {\n  placement: NzSelectPlacementType = 'topLeft';\n  selectedValue = 'HangZhou';\n}\n"
  },
  {
    "path": "components/select/demo/prefix-and-suffix.md",
    "content": "---\norder: 14\ntitle:\n  zh-CN: 前后缀\n  en-US: Prefix and Suffix\n---\n\n## zh-CN\n\n自定义前缀 `nzPrefix` 和后缀图标 `nzSuffixIcon`。\n\n## en-US\n\nCustom `nzPrefix` and `nzSuffixIcon`.\n"
  },
  {
    "path": "components/select/demo/prefix-and-suffix.ts",
    "content": "import { Component, model } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzFlexModule } from 'ng-zorro-antd/flex';\nimport { NzSelectModule, NzSelectOptionInterface } from 'ng-zorro-antd/select';\n\n@Component({\n  selector: 'nz-demo-select-prefix-and-suffix',\n  imports: [FormsModule, NzSelectModule, NzFlexModule],\n  template: `\n    <nz-flex nzWrap=\"wrap\" nzGap=\"small\">\n      <nz-select [(ngModel)]=\"value\" nzAllowClear [style.width.px]=\"200\" nzPrefix=\"User\" [nzOptions]=\"options\" />\n      <nz-select [(ngModel)]=\"value\" nzAllowClear [style.width.px]=\"120\" nzSuffixIcon=\"smile\" [nzOptions]=\"options\" />\n      <nz-select\n        [(ngModel)]=\"value\"\n        nzAllowClear\n        [style.width.px]=\"120\"\n        nzSuffixIcon=\"meh\"\n        nzDisabled\n        [nzOptions]=\"options\"\n      />\n      <br />\n      <nz-select\n        [(ngModel)]=\"multipleValue\"\n        nzAllowClear\n        [style.width.px]=\"200\"\n        nzMode=\"tags\"\n        nzPrefix=\"User\"\n        [nzOptions]=\"options\"\n      />\n      <nz-select\n        [(ngModel)]=\"multipleValue\"\n        nzAllowClear\n        [style.width.px]=\"120\"\n        nzMode=\"tags\"\n        nzSuffixIcon=\"smile\"\n        [nzOptions]=\"options\"\n      />\n      <nz-select\n        [(ngModel)]=\"multipleValue\"\n        nzAllowClear\n        [style.width.px]=\"120\"\n        nzMode=\"tags\"\n        nzSuffixIcon=\"meh\"\n        nzDisabled\n        [nzOptions]=\"options\"\n      />\n    </nz-flex>\n  `\n})\nexport class NzDemoSelectPrefixAndSuffixComponent {\n  readonly options: NzSelectOptionInterface[] = [\n    { value: 'jack', label: 'Jack' },\n    { value: 'lucy', label: 'Lucy' },\n    { value: 'Yiminghe', label: 'yiminghe' },\n    { value: 'disabled', label: 'Disabled', disabled: true }\n  ];\n\n  value = model('lucy');\n  multipleValue = model(['lucy']);\n}\n"
  },
  {
    "path": "components/select/demo/scroll-load.md",
    "content": "---\norder: 18\ntitle:\n  zh-CN: 下拉加载\n  en-US: Load Data on Scroll\n---\n\n## zh-CN\n\n一个带有下拉加载远程数据的例子。\n\n## en-US\n\nLoad data on scroll.\n"
  },
  {
    "path": "components/select/demo/scroll-load.ts",
    "content": "import { HttpClient } from '@angular/common/http';\nimport { Component, OnInit } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { Observable, of } from 'rxjs';\nimport { catchError, map } from 'rxjs/operators';\n\nimport { NzSelectModule } from 'ng-zorro-antd/select';\nimport { NzSpinModule } from 'ng-zorro-antd/spin';\n\ninterface MockUser {\n  name: {\n    first: string;\n  };\n}\n\n@Component({\n  selector: 'nz-demo-select-scroll-load',\n  imports: [FormsModule, NzSelectModule, NzSpinModule],\n  template: `\n    <nz-select\n      [(ngModel)]=\"selectedUser\"\n      (nzScrollToBottom)=\"loadMore()\"\n      nzPlaceHolder=\"Select users\"\n      nzAllowClear\n      [nzDropdownRender]=\"renderTemplate\"\n    >\n      @for (item of optionList; track item) {\n        <nz-option [nzValue]=\"item\" [nzLabel]=\"item\" />\n      }\n    </nz-select>\n    <ng-template #renderTemplate>\n      @if (isLoading) {\n        <nz-spin />\n      }\n    </ng-template>\n  `,\n  styles: `\n    nz-select {\n      width: 100%;\n    }\n  `\n})\nexport class NzDemoSelectScrollLoadComponent implements OnInit {\n  readonly randomUserUrl: string = 'https://api.randomuser.me/?results=10';\n  optionList: string[] = [];\n  selectedUser: string | null = null;\n  isLoading = false;\n\n  constructor(private http: HttpClient) {}\n\n  ngOnInit(): void {\n    this.loadMore();\n  }\n\n  getRandomNameList(): Observable<string[]> {\n    return this.http\n      .get<{ results: MockUser[] }>(`${this.randomUserUrl}`)\n      .pipe(\n        map(res => res.results),\n        catchError(() => of<MockUser[]>([]))\n      )\n      .pipe(map(list => list.map(item => `${item.name.first}`)));\n  }\n\n  loadMore(): void {\n    this.isLoading = true;\n    this.getRandomNameList().subscribe(data => {\n      this.isLoading = false;\n      this.optionList = [...this.optionList, ...data];\n    });\n  }\n}\n"
  },
  {
    "path": "components/select/demo/search-box.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 搜索框\n  en-US: Search Box\n---\n\n## zh-CN\n\n搜索和远程数据结合。\n\n## en-US\n\nSearch with remote data.\n"
  },
  {
    "path": "components/select/demo/search-box.ts",
    "content": "import { HttpClient } from '@angular/common/http';\nimport { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\n@Component({\n  selector: 'nz-demo-select-search-box',\n  imports: [FormsModule, NzSelectModule],\n  template: `\n    <nz-select\n      nzShowSearch\n      nzServerSearch\n      nzPlaceHolder=\"input search text\"\n      [(ngModel)]=\"selectedValue\"\n      [nzShowArrow]=\"false\"\n      [nzFilterOption]=\"nzFilterOption\"\n      (nzOnSearch)=\"search($event)\"\n    >\n      @for (item of listOfOption; track item) {\n        <nz-option [nzLabel]=\"item\" [nzValue]=\"item\" />\n      }\n    </nz-select>\n  `,\n  styles: `\n    nz-select {\n      width: 200px;\n    }\n  `\n})\nexport class NzDemoSelectSearchBoxComponent {\n  selectedValue: string | null = null;\n  listOfOption: string[] = [];\n  readonly nzFilterOption = (): boolean => true;\n\n  constructor(private http: HttpClient) {}\n\n  search(value: string): void {\n    this.http\n      .jsonp<{ result: Array<[string, string]> }>(`https://suggest.taobao.com/sug?code=utf-8&q=${value}`, 'callback')\n      .subscribe(data => {\n        this.listOfOption = data.result.map(([item]) => item);\n      });\n  }\n}\n"
  },
  {
    "path": "components/select/demo/search.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 带搜索框\n  en-US: Select with search field\n---\n\n## zh-CN\n\n展开后可对选项进行搜索。\n\n## en-US\n\nSearch the options while expanded.\n"
  },
  {
    "path": "components/select/demo/search.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\n@Component({\n  selector: 'nz-demo-select-search',\n  imports: [FormsModule, NzSelectModule],\n  template: `\n    <nz-select nzShowSearch nzAllowClear nzPlaceHolder=\"Select a person\" [(ngModel)]=\"selectedValue\">\n      <nz-option nzLabel=\"Jack\" nzValue=\"jack\" />\n      <nz-option nzLabel=\"Lucy\" nzValue=\"lucy\" />\n      <nz-option nzLabel=\"Tom\" nzValue=\"tom\" />\n    </nz-select>\n  `,\n  styles: `\n    nz-select {\n      width: 200px;\n    }\n  `\n})\nexport class NzDemoSelectSearchComponent {\n  selectedValue = null;\n}\n"
  },
  {
    "path": "components/select/demo/select-users.md",
    "content": "---\norder: 13\ntitle:\n  zh-CN: 搜索用户\n  en-US: Search and Select Users\n---\n\n## zh-CN\n\n一个带有远程搜索，节流控制，请求时序控制，加载状态的多选示例。\n\n## en-US\n\nA complete multiple select sample with remote search, debounce fetch, ajax callback order flow, and loading state.\n"
  },
  {
    "path": "components/select/demo/select-users.ts",
    "content": "import { HttpClient } from '@angular/common/http';\nimport { Component, OnInit } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { BehaviorSubject, Observable, of } from 'rxjs';\nimport { catchError, debounceTime, map, switchMap } from 'rxjs/operators';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\ninterface MockUser {\n  name: {\n    first: string;\n  };\n}\n\n@Component({\n  selector: 'nz-demo-select-select-users',\n  imports: [FormsModule, NzIconModule, NzSelectModule],\n  template: `\n    <nz-select\n      nzMode=\"multiple\"\n      nzPlaceHolder=\"Select users\"\n      nzAllowClear\n      nzShowSearch\n      nzServerSearch\n      [(ngModel)]=\"selectedUser\"\n      (nzOnSearch)=\"onSearch($event)\"\n    >\n      @if (!loading) {\n        @for (o of optionList; track o) {\n          <nz-option [nzValue]=\"o\" [nzLabel]=\"o\" />\n        }\n      } @else {\n        <nz-option nzDisabled nzCustomContent>\n          <nz-icon nzType=\"loading\" class=\"loading-icon\" />\n          Loading Data...\n        </nz-option>\n      }\n    </nz-select>\n  `,\n  styles: `\n    nz-select {\n      width: 100%;\n    }\n\n    .loading-icon {\n      margin-right: 8px;\n    }\n  `\n})\nexport class NzDemoSelectSelectUsersComponent implements OnInit {\n  randomUserUrl = 'https://api.randomuser.me/?results=5';\n  searchChange$ = new BehaviorSubject('');\n  optionList: string[] = [];\n  selectedUser?: string;\n  loading = false;\n\n  onSearch(value: string): void {\n    this.loading = true;\n    this.searchChange$.next(value);\n  }\n\n  constructor(private http: HttpClient) {}\n\n  ngOnInit(): void {\n    this.searchChange$\n      .pipe(\n        debounceTime(500),\n        switchMap(name => this.getRandomNameList(name))\n      )\n      .subscribe(data => {\n        this.optionList = data;\n        this.loading = false;\n      });\n  }\n\n  getRandomNameList(name: string): Observable<string[]> {\n    return this.http.get<{ results: MockUser[] }>(`${this.randomUserUrl}`).pipe(\n      map(res => res.results),\n      catchError(() => of<MockUser[]>([])),\n      map(list => list.map(item => `${item.name.first} ${name}`))\n    );\n  }\n}\n"
  },
  {
    "path": "components/select/demo/size.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 三种大小\n  en-US: Sizes\n---\n\n## zh-CN\n\n三种大小的选择框，当 `nzSize` 分别为 `large` 和 `small` 时，输入框高度为 `40px` 和 `24px` ，默认高度为 `32px`。\n\n## en-US\n\nThe height of the input field for the select defaults to 32px. If `nzSize` is set to large, the height will be 40px, and if set to small, 24px.\n"
  },
  {
    "path": "components/select/demo/size.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\nimport { NzSelectModule, NzSelectSizeType } from 'ng-zorro-antd/select';\n\nfunction alphabet(): string[] {\n  const children: string[] = [];\n  for (let i = 10; i < 36; i++) {\n    children.push(i.toString(36) + i);\n  }\n  return children;\n}\n\n@Component({\n  selector: 'nz-demo-select-size',\n  imports: [FormsModule, NzSelectModule, NzRadioModule],\n  template: `\n    <nz-radio-group [(ngModel)]=\"size\">\n      <label nz-radio-button nzValue=\"large\">Large</label>\n      <label nz-radio-button nzValue=\"default\">Default</label>\n      <label nz-radio-button nzValue=\"small\">Small</label>\n    </nz-radio-group>\n    <br />\n    <br />\n    <nz-select [(ngModel)]=\"singleValue\" [nzSize]=\"size\">\n      @for (option of listOfOption; track option) {\n        <nz-option [nzLabel]=\"option\" [nzValue]=\"option\" />\n      }\n    </nz-select>\n    <br />\n    <br />\n    <nz-select [(ngModel)]=\"singleValue\" [nzSize]=\"size\" nzShowSearch>\n      @for (option of listOfOption; track option) {\n        <nz-option [nzLabel]=\"option\" [nzValue]=\"option\" />\n      }\n    </nz-select>\n    <br />\n    <br />\n    <nz-select [(ngModel)]=\"multipleValue\" [nzSize]=\"size\" nzMode=\"multiple\" nzPlaceHolder=\"Please select\">\n      @for (option of listOfOption; track option) {\n        <nz-option [nzLabel]=\"option\" [nzValue]=\"option\" />\n      }\n    </nz-select>\n    <br />\n    <br />\n    <nz-select [(ngModel)]=\"tagValue\" [nzSize]=\"size\" nzMode=\"tags\" nzPlaceHolder=\"Please select\">\n      @for (option of listOfOption; track option) {\n        <nz-option [nzLabel]=\"option\" [nzValue]=\"option\" />\n      }\n    </nz-select>\n  `,\n  styles: `\n    nz-select {\n      width: 100%;\n    }\n  `\n})\nexport class NzDemoSelectSizeComponent {\n  readonly listOfOption: string[] = alphabet();\n  size: NzSelectSizeType = 'default';\n  singleValue = 'a10';\n  multipleValue = ['a10', 'c12'];\n  tagValue = ['a10', 'c12', 'tag'];\n}\n"
  },
  {
    "path": "components/select/demo/status.md",
    "content": "---\norder: 24\ntitle:\n  zh-CN: 自定义状态\n  en-US: Status\n---\n\n## zh-CN\n\n使用 `nzStatus` 为 Select 添加状态，可选 `error` 或者 `warning`。\n\n## en-US\n\nAdd status to Select with `nzStatus`, which could be `error` or `warning`.\n"
  },
  {
    "path": "components/select/demo/status.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzSelectModule } from 'ng-zorro-antd/select';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\n\n@Component({\n  selector: 'nz-demo-select-status',\n  imports: [NzSelectModule, NzSpaceModule],\n  template: `\n    <nz-select nzStatus=\"error\" />\n    <br />\n    <br />\n    <nz-select nzStatus=\"warning\" />\n  `,\n  styles: `\n    nz-select {\n      width: 100%;\n    }\n  `\n})\nexport class NzDemoSelectStatusComponent {}\n"
  },
  {
    "path": "components/select/demo/tags.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 标签\n  en-US: Tags\n---\n\n## zh-CN\n\ntags select，随意输入的内容（scroll the menu）\n\n## en-US\n\nSelect with tags, transform input to tag (scroll the menu)\n"
  },
  {
    "path": "components/select/demo/tags.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\nfunction alphabet(): string[] {\n  const children: string[] = [];\n  for (let i = 10; i < 36; i++) {\n    children.push(i.toString(36) + i);\n  }\n  return children;\n}\n\n@Component({\n  selector: 'nz-demo-select-tags',\n  imports: [FormsModule, NzSelectModule],\n  template: `\n    <nz-select nzMode=\"tags\" nzPlaceHolder=\"Tag Mode\" [(ngModel)]=\"listOfTagOptions\">\n      @for (option of listOfOption; track option) {\n        <nz-option [nzLabel]=\"option\" [nzValue]=\"option\" />\n      }\n    </nz-select>\n  `,\n  styles: `\n    nz-select {\n      width: 100%;\n    }\n  `\n})\nexport class NzDemoSelectTagsComponent {\n  readonly listOfOption: string[] = alphabet();\n  listOfTagOptions: string[] = [];\n}\n"
  },
  {
    "path": "components/select/demo/variant.md",
    "content": "---\norder: 21\nversion: 20.0.0\ntitle:\n  zh-CN: 形态变体\n  en-US: Variants\n---\n\n## zh-CN\n\nSelect 形态变体，可选 `outlined`、`filled`、`borderless`、`underlined` 四种形态。\n\n## en-US\n\nVariants of Select, there are four variants: `outlined`, `filled`, `borderless` and `underlined`.\n"
  },
  {
    "path": "components/select/demo/variant.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzFlexDirective } from 'ng-zorro-antd/flex';\nimport { NzSelectModule } from 'ng-zorro-antd/select';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\n\n@Component({\n  selector: 'nz-demo-select-variant',\n  imports: [FormsModule, NzSelectModule, NzSpaceModule, NzFlexDirective],\n  template: `\n    <div nz-flex nzGap=\"large\">\n      <nz-space nzDirection=\"vertical\" style=\"flex: 1\">\n        <nz-select *nzSpaceItem ngModel=\"lucy\" [nzOptions]=\"options\" />\n        <nz-select *nzSpaceItem ngModel=\"lucy\" nzVariant=\"filled\" [nzOptions]=\"options\" />\n        <nz-select *nzSpaceItem ngModel=\"lucy\" nzVariant=\"borderless\" [nzOptions]=\"options\" />\n        <nz-select *nzSpaceItem ngModel=\"lucy\" nzVariant=\"underlined\" [nzOptions]=\"options\" />\n      </nz-space>\n      <nz-space nzDirection=\"vertical\" style=\"flex: 1\">\n        <nz-select *nzSpaceItem nzMode=\"multiple\" [ngModel]=\"['lucy']\" [nzOptions]=\"options\" />\n        <nz-select *nzSpaceItem nzMode=\"multiple\" [ngModel]=\"['lucy']\" nzVariant=\"filled\" [nzOptions]=\"options\" />\n        <nz-select *nzSpaceItem nzMode=\"multiple\" [ngModel]=\"['lucy']\" nzVariant=\"borderless\" [nzOptions]=\"options\" />\n        <nz-select *nzSpaceItem nzMode=\"multiple\" [ngModel]=\"['lucy']\" nzVariant=\"underlined\" [nzOptions]=\"options\" />\n      </nz-space>\n    </div>\n  `,\n  styles: `\n    nz-space {\n      flex: 1;\n    }\n\n    nz-select {\n      width: 100%;\n    }\n  `\n})\nexport class NzDemoSelectVariantComponent {\n  options = [\n    { label: 'Jack', value: 'jack' },\n    { label: 'Lucy', value: 'lucy' },\n    { label: 'Disabled', value: 'disabled', disabled: true }\n  ];\n}\n"
  },
  {
    "path": "components/select/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Entry\ntitle: Select\ncover: 'https://gw.alipayobjects.com/zos/alicdn/_0XzgOis7/Select.svg'\ndescription: A dropdown menu for displaying choices.\n---\n\n## When To Use\n\n- A dropdown menu for displaying choices - an elegant alternative to the native `<select>` element.\n- Utilizing [Radio](/components/radio/en) is recommended when there are fewer total options (less than 5).\n- You probably need [AutoComplete](/components/auto-complete) if you're looking for an input box that can be typed or selected.\n\n## API\n\n```html\n<nz-select>\n  <nz-option nzValue=\"lucy\" nzLabel=\"Lucy\"></nz-option>\n</nz-select>\n```\n\n### nz-select\n\n| Property                       | Description                                                                                                                                                                                                     | Type                                                                                                                                                                      | Default                                                 | Global Config | Version |\n| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ------------- | ------- |\n| `[nzId]`                       | input id attribute inside the component                                                                                                                                                                         | `string`                                                                                                                                                                  | -                                                       |\n| `[ngModel]`                    | Current selected nz-option value, double binding.                                                                                                                                                               | `any \\| any[]`                                                                                                                                                            | -                                                       |\n| `[compareWith]`                | Same as [SelectControlValueAccessor](https://angular.dev/api/forms/SelectControlValueAccessor)                                                                                                                  | `(o1: any, o2: any) => boolean`                                                                                                                                           | `(o1: any, o2: any) => o1===o2`                         |\n| `[nzAutoClearSearchValue]`     | Whether the current search will be cleared on selecting an item. Only applies when `mode` is set to `multiple` or `tags`.                                                                                       | `boolean`                                                                                                                                                                 | `true`                                                  |\n| `[nzAllowClear]`               | Show clear button.                                                                                                                                                                                              | `boolean`                                                                                                                                                                 | `false`                                                 |\n| `[nzBackdrop]`                 | whether or not the overlay should attach a backdrop                                                                                                                                                             | `boolean`                                                                                                                                                                 | `false`                                                 |\n| `[nzVariant]`                  | Variants of Select                                                                                                                                                                                              | `'outlined' \\| 'borderless' \\| 'filled' \\| 'underlined'`                                                                                                                  | `'outlined'`                                            | ✅            | 20.0.0  |\n| `[nzOpen]`                     | dropdown expand state, double binding                                                                                                                                                                           | `boolean`                                                                                                                                                                 | `false`                                                 |\n| `[nzAutoFocus]`                | Get focus by default                                                                                                                                                                                            | `boolean`                                                                                                                                                                 | `false`                                                 |\n| `[nzDisabled]`                 | Whether disabled select                                                                                                                                                                                         | `boolean`                                                                                                                                                                 | `false`                                                 |\n| `[nzDropdownClassName]`        | className of dropdown menu                                                                                                                                                                                      | `string \\| string[]`                                                                                                                                                      | -                                                       |\n| `[nzDropdownMatchSelectWidth]` | Whether dropdown's width is same width than select.                                                                                                                                                             | `boolean`                                                                                                                                                                 | `true`                                                  |\n| `[nzDropdownStyle]`            | style of dropdown menu                                                                                                                                                                                          | `object`                                                                                                                                                                  | -                                                       |\n| `[nzCustomTemplate]`           | The custom template of select                                                                                                                                                                                   | `TemplateRef<{ $implicit: NzOptionComponent }>`                                                                                                                           | -                                                       |\n| `[nzServerSearch]`             | nz-option will not be filtered when set to true                                                                                                                                                                 | `boolean`                                                                                                                                                                 | `false`                                                 |\n| `[nzFilterOption]`             | Filter options against it. The function will receive two arguments, `inputValue` and `option`, if the function returns `true`, the option will be included in the filtered set; Otherwise, it will be excluded. | `(input?: string, option?: NzOptionComponent) => boolean;`                                                                                                                | -                                                       |\n| `[nzMaxMultipleCount]`         | Max selected option can be selected                                                                                                                                                                             | `number`                                                                                                                                                                  | `Infinity`                                              |\n| `[nzMode]`                     | Set mode of Select                                                                                                                                                                                              | `'multiple' \\| 'tags' \\| 'default'`                                                                                                                                       | `'default'`                                             |\n| `[nzNotFoundContent]`          | Specify content to show when no result matches..                                                                                                                                                                | `string \\| TemplateRef<void>`                                                                                                                                             | `'Not Found'`                                           |\n| `[nzPlaceHolder]`              | Placeholder of select                                                                                                                                                                                           | `string`                                                                                                                                                                  | -                                                       |\n| `[nzShowArrow]`                | Whether to show the drop-down arrow                                                                                                                                                                             | `boolean`                                                                                                                                                                 | `true`(for single select), `false`(for multiple select) |\n| `[nzShowSearch]`               | Whether show search input in single mode.                                                                                                                                                                       | `boolean`                                                                                                                                                                 | `false`                                                 |\n| `[nzSize]`                     | Size of Select input                                                                                                                                                                                            | `'large' \\| 'small' \\| 'default'`                                                                                                                                         | `'default'`                                             |\n| `[nzStatus]`                   | Set validation status                                                                                                                                                                                           | `'error' \\| 'warning'`                                                                                                                                                    | -                                                       |\n| `[nzPrefix]`                   | The custom prefix                                                                                                                                                                                               | `TemplateRef<any> \\| string`                                                                                                                                              | -                                                       |\n| `[nzSuffixIcon]`               | The custom suffix icon                                                                                                                                                                                          | `TemplateRef<any> \\| string`                                                                                                                                              | -                                                       | ✅            |\n| `[nzRemoveIcon]`               | The custom remove icon                                                                                                                                                                                          | `TemplateRef<any>`                                                                                                                                                        | -                                                       |\n| `[nzClearIcon]`                | The custom clear icon                                                                                                                                                                                           | `TemplateRef<any>`                                                                                                                                                        | -                                                       |\n| `[nzMenuItemSelectedIcon]`     | The custom menuItemSelected icon                                                                                                                                                                                | `TemplateRef<any>`                                                                                                                                                        | -                                                       |\n| `[nzTokenSeparators]`          | Separator used to tokenize on tag/multiple mode                                                                                                                                                                 | `string[]`                                                                                                                                                                | `[]`                                                    |\n| `[nzLoading]`                  | indicate loading state                                                                                                                                                                                          | `boolean`                                                                                                                                                                 | false                                                   |\n| `[nzMaxTagCount]`              | Max tag count to show                                                                                                                                                                                           | `number`                                                                                                                                                                  | -                                                       |\n| `[nzOptions]`                  | use nzOptions or `nz-option` to pass options to the select                                                                                                                                                      | `Array<{ label: string \\| number \\| TemplateRef<any>; value: any; key?: string \\| number; disabled?: boolean; hide?: boolean; groupLabel?: string \\| TemplateRef<any>;}>` | -                                                       |\n| `[nzMaxTagPlaceholder]`        | Placeholder for not showing tags                                                                                                                                                                                | `TemplateRef<{ $implicit: any[] }>`                                                                                                                                       | -                                                       |\n| `[nzOptionHeightPx]`           | Each option height inside the dropdown                                                                                                                                                                          | `number`                                                                                                                                                                  | `32`                                                    | ✅            |\n| `[nzOptionOverflowSize]`       | Max option size inside the dropdown, overflow when exceed the size                                                                                                                                              | `number`                                                                                                                                                                  | `8`                                                     |\n| `[nzSelectOnTab]`              | Allows to select an item with TAB key                                                                                                                                                                           | `boolean`                                                                                                                                                                 | `false`                                                 |\n| `(ngModelChange)`              | Current selected nz-option value change callback.                                                                                                                                                               | `EventEmitter<any[]>`                                                                                                                                                     | -                                                       |\n| `(nzOpenChange)`               | dropdown expand change callback                                                                                                                                                                                 | `EventEmitter<boolean>`                                                                                                                                                   | `false`                                                 |\n| `(nzScrollToBottom)`           | Called when dropdown scrolls to bottom                                                                                                                                                                          | `EventEmitter<any>`                                                                                                                                                       | -                                                       |\n| `(nzOnSearch)`                 | Callback function that is fired when input changed.                                                                                                                                                             | `EventEmitter<string>`                                                                                                                                                    | -                                                       |\n| `(nzOnClear)`                  | Callback function that clear the selected items                                                                                                                                                                 | `EventEmitter<any>`                                                                                                                                                       | -                                                       | -             | 20.0.0  |\n| `(nzFocus)`                    | focus callback                                                                                                                                                                                                  | `EventEmitter<any>`                                                                                                                                                       | -                                                       |\n| `(nzBlur)`                     | blur callback                                                                                                                                                                                                   | `EventEmitter<any>`                                                                                                                                                       | -                                                       |\n\n### nz-option\n\n| Property            | Description                                                                                                                 | Type                | Default |\n| ------------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------- | ------- |\n| `[nzDisabled]`      | Disable this option                                                                                                         | `boolean`           | `false` |\n| `[nzTitle]`         | Native title hint on this option                                                                                            | `string \\| number`  | -       |\n| `[nzLabel]`         | The text show in nz-select and dropdown menu                                                                                | `string \\| number`  | -       |\n| `[nzValue]`         | The value passed to ngModel of nz-select                                                                                    | `any `              | -       |\n| `[nzKey]`           | Should be passed when typeof nzValue - Object. Key will be used for performance optimizations                               | `string \\| number ` | -       |\n| `[nzHide]`          | Whether hide the option in the option list                                                                                  | `boolean`           | `false` |\n| `[nzCustomContent]` | Whether custom nz-option content in dropdown menu, the ng-content in nz-option will replace nzLabel when it was set to true | `boolean`           | `false` |\n\n### nz-option-group\n\n| Property    | Description | Type                                    | Default |\n| ----------- | ----------- | --------------------------------------- | ------- |\n| `[nzLabel]` | Group label | `string \\| number \\| TemplateRef<void>` | -       |\n\n## Methods\n\n### nz-select\n\n| Name      | Description  |\n| --------- | ------------ |\n| `blur()`  | Remove focus |\n| `focus()` | Get focus    |\n\n## FAQ\n\n### Q: The overlay layer element does not follow the scroll position when scrolling\n\nBy default, the overlay layer element uses body as the scroll container. If using another scroll container, add the [CdkScrollable](https://material.angular.dev/cdk/scrolling/api#CdkScrollable) directive to the custom scroll container element.\nNote: You need to import the `CdkScrollable` directive or `ScrollingModule` module from `@angular/cdk/scrolling`.\n"
  },
  {
    "path": "components/select/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 选择器\ntype: 数据录入\ntitle: Select\ncover: 'https://gw.alipayobjects.com/zos/alicdn/_0XzgOis7/Select.svg'\ndescription: 下拉选择器。\n---\n\n## 何时使用\n\n- 弹出一个下拉菜单给用户选择操作，用于代替原生的选择器，或者需要一个更优雅的多选器时。\n- 当选项少时（少于 5 项），建议直接将选项平铺，使用 [Radio](/components/radio/zh) 是更好的选择。\n- 如果你在寻找一个可输可选的输入框，那你可能需要 [AutoComplete](/components/auto-complete/zh)。\n\n## API\n\n```html\n<nz-select>\n  <nz-option nzValue=\"lucy\" nzLabel=\"Lucy\"></nz-option>\n</nz-select>\n```\n\n### nz-select\n\n| 参数                           | 说明                                                                                                                                             | 类型                                                                                                                                                                      | 默认值                          | 全局配置 | 版本   |\n| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | -------- | ------ |\n| `[nzId]`                       | 组件内部 input 的 id 值                                                                                                                          | `string`                                                                                                                                                                  | -                               |\n| `[ngModel]`                    | 当前选中的 nz-option 的 nzValue 值，可双向绑定，当 `nzMode` 为 `multiple` 或 `tags` 时，ngModel 为数组                                           | `any \\| any[]`                                                                                                                                                            | -                               |\n| `[compareWith]`                | 与 [SelectControlValueAccessor](https://angular.cn/api/forms/SelectControlValueAccessor) 相同                                                    | `(o1: any, o2: any) => boolean`                                                                                                                                           | `(o1: any, o2: any) => o1===o2` |\n| `[nzAutoClearSearchValue]`     | 是否在选中项后清空搜索框，只在 `mode` 为 `multiple` 或 `tags` 时有效。                                                                           | `boolean`                                                                                                                                                                 | `true`                          |\n| `[nzAllowClear]`               | 支持清除                                                                                                                                         | `boolean`                                                                                                                                                                 | `false`                         |\n| `[nzBackdrop]`                 | 浮层是否应带有背景板                                                                                                                             | `boolean`                                                                                                                                                                 | `false`                         |\n| `[nzVariant]`                  | 形态变体                                                                                                                                         | `'outlined' \\| 'borderless' \\| 'filled' \\| 'underlined'`                                                                                                                  | `'outlined'`                    | ✅       | 20.0.0 |\n| `[nzOpen]`                     | 下拉菜单是否打开，可双向绑定                                                                                                                     | `boolean`                                                                                                                                                                 | `false`                         |\n| `[nzAutoFocus]`                | 默认获取焦点                                                                                                                                     | `boolean`                                                                                                                                                                 | `false`                         |\n| `[nzDisabled]`                 | 是否禁用                                                                                                                                         | `boolean`                                                                                                                                                                 | `false`                         |\n| `[nzDropdownClassName]`        | 下拉菜单的 className 属性                                                                                                                        | `string \\| string[]`                                                                                                                                                      | -                               |\n| `[nzDropdownMatchSelectWidth]` | 下拉菜单和选择器同宽                                                                                                                             | `boolean`                                                                                                                                                                 | `true`                          |\n| `[nzDropdownStyle]`            | 下拉菜单的 style 属性                                                                                                                            | `object`                                                                                                                                                                  | -                               |\n| `[nzCustomTemplate]`           | 自定义选择框的 Template 内容                                                                                                                     | `TemplateRef<{ $implicit: NzOptionComponent }>`                                                                                                                           | -                               |\n| `[nzServerSearch]`             | 是否使用服务端搜索，当为 true 时，将不再在前端对 nz-option 进行过滤                                                                              | `boolean`                                                                                                                                                                 | `false`                         |\n| `[nzFilterOption]`             | 是否根据输入项进行筛选。当其为一个函数时，会接收 `inputValue` `option` 两个参数，当 `option` 符合筛选条件时，应返回 `true`，反之则返回 `false`。 | `(input?: string, option?: NzOptionComponent) => boolean;`                                                                                                                | -                               |\n| `[nzMaxMultipleCount]`         | 最多选中多少个标签                                                                                                                               | `number`                                                                                                                                                                  | `Infinity`                      |\n| `[nzMode]`                     | 设置 nz-select 的模式                                                                                                                            | `'multiple' \\| 'tags' \\| 'default'`                                                                                                                                       | `'default'`                     |\n| `[nzNotFoundContent]`          | 当下拉列表为空时显示的内容                                                                                                                       | `string \\| TemplateRef<void>`                                                                                                                                             | -                               |\n| `[nzPlaceHolder]`              | 选择框默认文字                                                                                                                                   | `string`                                                                                                                                                                  | -                               |\n| `[nzShowArrow]`                | 是否显示下拉小箭头                                                                                                                               | `boolean`                                                                                                                                                                 | 单选为 `true`，多选为 `false`   |\n| `[nzShowSearch]`               | 使单选模式可搜索                                                                                                                                 | `boolean`                                                                                                                                                                 | `false`                         |\n| `[nzSize]`                     | 选择框大小                                                                                                                                       | `'large' \\| 'small' \\| 'default'`                                                                                                                                         | `'default'`                     |\n| `[nzStatus]`                   | 设置校验状态                                                                                                                                     | `'error' \\| 'warning'`                                                                                                                                                    | -                               |\n| `[nzPreix]`                    | 自定义的选择框前缀                                                                                                                               | `TemplateRef<any> \\| string`                                                                                                                                              | -                               |\n| `[nzSuffixIcon]`               | 自定义的选择框后缀图标                                                                                                                           | `TemplateRef<any> \\| string`                                                                                                                                              | -                               | ✅       |\n| `[nzRemoveIcon]`               | 自定义的多选框清除图标                                                                                                                           | `TemplateRef<any>`                                                                                                                                                        | -                               |\n| `[nzClearIcon]`                | 自定义的多选框清空图标                                                                                                                           | `TemplateRef<any>`                                                                                                                                                        | -                               |\n| `[nzMenuItemSelectedIcon]`     | 自定义当前选中的条目图标                                                                                                                         | `TemplateRef<any>`                                                                                                                                                        | -                               |\n| `[nzTokenSeparators]`          | 在 tags 和 multiple 模式下自动分词的分隔符                                                                                                       | `string[]`                                                                                                                                                                | `[]`                            |\n| `[nzLoading]`                  | 加载中状态                                                                                                                                       | `boolean`                                                                                                                                                                 | `false`                         |\n| `[nzMaxTagCount]`              | 最多显示多少个 tag                                                                                                                               | `number`                                                                                                                                                                  | -                               |\n| `[nzMaxTagPlaceholder]`        | 隐藏 tag 时显示的内容                                                                                                                            | `TemplateRef<{ $implicit: any[] }>`                                                                                                                                       | -                               |\n| `[nzOptions]`                  | option 列表，可以取代 nz-option，用法参见例子                                                                                                    | `Array<{ label: string \\| number \\| TemplateRef<any>; value: any; key?: string \\| number; disabled?: boolean; hide?: boolean; groupLabel?: string \\| TemplateRef<any>;}>` | -                               |\n| `[nzOptionHeightPx]`           | 下拉菜单中每个 Option 的高度                                                                                                                     | `number`                                                                                                                                                                  | `32`                            | ✅       |\n| `[nzOptionOverflowSize]`       | 下拉菜单中最多展示的 Option 个数，超出部分滚动                                                                                                   | `number`                                                                                                                                                                  | `8`                             |\n| `[nzSelectOnTab]`              | 允许使用 TAB 键选择项目                                                                                                                          | `boolean`                                                                                                                                                                 | `false`                         |\n| `(ngModelChange)`              | 选中的 nz-option 发生变化时，调用此函数                                                                                                          | `EventEmitter<any[]>`                                                                                                                                                     | -                               |\n| `(nzOpenChange)`               | 下拉菜单打开状态变化回调                                                                                                                         | `EventEmitter<boolean>`                                                                                                                                                   | -                               |\n| `(nzScrollToBottom)`           | 下拉列表滚动到底部的回调                                                                                                                         | `EventEmitter<any>`                                                                                                                                                       | -                               |\n| `(nzOnSearch)`                 | 文本框值变化时回调                                                                                                                               | `EventEmitter<string>`                                                                                                                                                    | -                               |\n| `(nzOnClear)`                  | 清空已选项时触发的回调函数。                                                                                                                     | `EventEmitter<any>`                                                                                                                                                       | -                               | -        | 20.0.0 |\n| `(nzFocus)`                    | focus 时回调                                                                                                                                     | `EventEmitter<any>`                                                                                                                                                       | -                               |\n| `(nzBlur)`                     | blur 时回调                                                                                                                                      | `EventEmitter<any>`                                                                                                                                                       | -                               |\n\n### nz-option\n\n| 参数                | 说明                                                                                             | 类型               | 默认值  |\n| ------------------- | ------------------------------------------------------------------------------------------------ | ------------------ | ------- |\n| `[nzDisabled]`      | 是否禁用                                                                                         | `boolean`          | `false` |\n| `[nzTitle]`         | 选项上的原生 title 提示                                                                          | `string \\| number` | -       |\n| `[nzLabel]`         | 选中该 nz-option 后，nz-select 中显示的文字                                                      | `string \\| number` | -       |\n| `[nzValue]`         | nz-select 中 ngModel 的值                                                                        | `any`              | -       |\n| `[nzKey]`           | nz-select 中 ngModel 的值                                                                        | `string \\| number` | -       |\n| `[nzHide]`          | 是否在选项列表中隐藏该选项                                                                       | `boolean`          | `false` |\n| `[nzCustomContent]` | 是否自定义在下拉菜单中的 Template 内容，当为 true 时，nz-option 包裹的内容将直接渲染在下拉菜单中 | `boolean`          | `false` |\n\n### nz-option-group\n\n| 参数        | 说明 | 类型                                    | 默认值 |\n| ----------- | ---- | --------------------------------------- | ------ |\n| `[nzLabel]` | 组名 | `string \\| number \\| TemplateRef<void>` | -      |\n\n## 方法\n\n### nz-select\n\n| 名称      | 说明     |\n| --------- | -------- |\n| `blur()`  | 取消焦点 |\n| `focus()` | 获取焦点 |\n\n## FAQ\n\n### Q：滚动时浮层元素没有跟随滚动位置\n\n默认情况下，浮层元素使用 `body` 作为滚动容器，如果使用了其他滚动容器，在自定义滚动容器元素上添加 [CdkScrollable](https://material.angular.dev/cdk/scrolling/api#CdkScrollable) 指令。\n注意：您需要从 `@angular/cdk/scrolling` 导入 `CdkScrollable` 指令或 `ScrollingModule` 模块。\n"
  },
  {
    "path": "components/select/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/select/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/select/option-container.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { OverlayModule } from '@angular/cdk/overlay';\nimport { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';\nimport { isPlatformBrowser, NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterViewInit,\n  ChangeDetectionStrategy,\n  Component,\n  EventEmitter,\n  inject,\n  Input,\n  NgZone,\n  OnChanges,\n  Output,\n  PLATFORM_ID,\n  SimpleChanges,\n  TemplateRef,\n  ViewChild,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { NzOverlayModule } from 'ng-zorro-antd/core/overlay';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { NzEmptyModule } from 'ng-zorro-antd/empty';\n\nimport { NzOptionItemGroupComponent } from './option-item-group.component';\nimport { NzOptionItemComponent } from './option-item.component';\nimport { NzSelectItemInterface, NzSelectModeType } from './select.types';\n\n@Component({\n  selector: 'nz-option-container',\n  exportAs: 'nzOptionContainer',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <div>\n      @if (listOfContainerItem.length === 0) {\n        <div class=\"ant-select-item-empty\">\n          <nz-embed-empty nzComponentName=\"select\" [specificContent]=\"notFoundContent!\" />\n        </div>\n      }\n      <cdk-virtual-scroll-viewport\n        [class.full-width]=\"!matchWidth\"\n        [itemSize]=\"itemSize\"\n        [maxBufferPx]=\"itemSize * maxItemLength\"\n        [minBufferPx]=\"itemSize * maxItemLength\"\n        (scrolledIndexChange)=\"onScrolledIndexChange($event)\"\n        [style.height.px]=\"listOfContainerItem.length * itemSize\"\n        [style.max-height.px]=\"itemSize * maxItemLength\"\n      >\n        <ng-template\n          cdkVirtualFor\n          [cdkVirtualForOf]=\"listOfContainerItem\"\n          [cdkVirtualForTrackBy]=\"trackValue\"\n          [cdkVirtualForTemplateCacheSize]=\"0\"\n          let-item\n        >\n          @switch (item.type) {\n            @case ('group') {\n              <nz-option-item-group [nzLabel]=\"item.groupLabel ?? null\" />\n            }\n            @case ('item') {\n              <nz-option-item\n                [icon]=\"menuItemSelectedIcon\"\n                [customContent]=\"item.nzCustomContent\"\n                [template]=\"item.template ?? null\"\n                [grouped]=\"!!item.groupLabel\"\n                [disabled]=\"\n                  item.nzDisabled || (isMaxMultipleCountReached && !listOfSelectedValue.includes(item['nzValue']))\n                \"\n                [showState]=\"mode === 'tags' || mode === 'multiple'\"\n                [title]=\"item.nzTitle\"\n                [label]=\"item.nzLabel\"\n                [compareWith]=\"compareWith\"\n                [activatedValue]=\"activatedValue\"\n                [listOfSelectedValue]=\"listOfSelectedValue\"\n                [value]=\"item.nzValue\"\n                (itemHover)=\"onItemHover($event)\"\n                (itemClick)=\"onItemClick($event)\"\n              />\n            }\n          }\n        </ng-template>\n      </cdk-virtual-scroll-viewport>\n      <ng-template [ngTemplateOutlet]=\"dropdownRender\" />\n    </div>\n  `,\n  host: { class: 'ant-select-dropdown' },\n  imports: [\n    NzEmptyModule,\n    NzOptionItemGroupComponent,\n    NzOptionItemComponent,\n    NgTemplateOutlet,\n    OverlayModule,\n    NzOverlayModule\n  ]\n})\nexport class NzOptionContainerComponent implements OnChanges, AfterViewInit {\n  private readonly ngZone = inject(NgZone);\n  private readonly platformId = inject(PLATFORM_ID);\n\n  @Input() notFoundContent: string | TemplateRef<NzSafeAny> | undefined = undefined;\n  @Input() menuItemSelectedIcon: TemplateRef<NzSafeAny> | null = null;\n  @Input() dropdownRender: TemplateRef<NzSafeAny> | null = null;\n  @Input() activatedValue: NzSafeAny | null = null;\n  @Input() listOfSelectedValue: NzSafeAny[] = [];\n  @Input() compareWith!: (o1: NzSafeAny, o2: NzSafeAny) => boolean;\n  @Input() mode: NzSelectModeType = 'default';\n  @Input() matchWidth = true;\n  @Input() itemSize = 32;\n  @Input() maxItemLength = 8;\n  @Input() isMaxMultipleCountReached = false;\n  @Input() listOfContainerItem: NzSelectItemInterface[] = [];\n  @Output() readonly itemClick = new EventEmitter<NzSafeAny>();\n  @Output() readonly scrollToBottom = new EventEmitter<void>();\n  @ViewChild(CdkVirtualScrollViewport, { static: true }) cdkVirtualScrollViewport!: CdkVirtualScrollViewport;\n  private scrolledIndex = 0;\n\n  onItemClick(value: NzSafeAny): void {\n    this.itemClick.emit(value);\n  }\n\n  onItemHover(value: NzSafeAny): void {\n    // TODO: keydown.enter won't activate this value\n    this.activatedValue = value;\n  }\n\n  trackValue(_index: number, option: NzSelectItemInterface): NzSafeAny {\n    return option.key;\n  }\n\n  onScrolledIndexChange(index: number): void {\n    this.scrolledIndex = index;\n    if (index === this.listOfContainerItem.length - this.maxItemLength - 1) {\n      this.scrollToBottom.emit();\n    }\n  }\n\n  scrollToActivatedValue(): void {\n    const index = this.listOfContainerItem.findIndex(item => this.compareWith(item.key, this.activatedValue));\n    if (index < this.scrolledIndex || index >= this.scrolledIndex + this.maxItemLength) {\n      this.cdkVirtualScrollViewport.scrollToIndex(index || 0);\n    }\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { listOfContainerItem, activatedValue } = changes;\n    if (listOfContainerItem || activatedValue) {\n      this.scrollToActivatedValue();\n    }\n  }\n\n  ngAfterViewInit(): void {\n    if (isPlatformBrowser(this.platformId)) {\n      this.ngZone.runOutsideAngular(() => setTimeout(() => this.scrollToActivatedValue()));\n    }\n  }\n}\n"
  },
  {
    "path": "components/select/option-group.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, Input, OnChanges, TemplateRef, ViewEncapsulation } from '@angular/core';\nimport { Subject } from 'rxjs';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\n@Component({\n  selector: 'nz-option-group',\n  exportAs: 'nzOptionGroup',\n  template: `<ng-content />`,\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class NzOptionGroupComponent implements OnChanges {\n  @Input() nzLabel: string | number | TemplateRef<NzSafeAny> | null = null;\n  changes = new Subject<void>();\n  ngOnChanges(): void {\n    this.changes.next();\n  }\n}\n"
  },
  {
    "path": "components/select/option-item-group.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, Input, TemplateRef, ViewEncapsulation } from '@angular/core';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\n@Component({\n  selector: 'nz-option-item-group',\n  template: `<ng-container *nzStringTemplateOutlet=\"nzLabel\">{{ nzLabel }}</ng-container>`,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  host: {\n    class: 'ant-select-item ant-select-item-group'\n  },\n  imports: [NzOutletModule]\n})\nexport class NzOptionItemGroupComponent {\n  @Input() nzLabel: string | number | TemplateRef<NzSafeAny> | null = null;\n}\n"
  },
  {
    "path": "components/select/option-item.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  Component,\n  DestroyRef,\n  ElementRef,\n  EventEmitter,\n  inject,\n  Input,\n  NgZone,\n  OnChanges,\n  OnInit,\n  Output,\n  SimpleChanges,\n  TemplateRef,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-option-item',\n  template: `\n    <div class=\"ant-select-item-option-content\">\n      @if (customContent) {\n        <ng-template [ngTemplateOutlet]=\"template\" />\n      } @else {\n        {{ label }}\n      }\n    </div>\n    @if (showState && selected) {\n      <div class=\"ant-select-item-option-state\" unselectable=\"on\">\n        @if (!icon) {\n          <nz-icon nzType=\"check\" class=\"ant-select-selected-icon\" />\n        } @else {\n          <ng-template [ngTemplateOutlet]=\"icon\" />\n        }\n      </div>\n    }\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  host: {\n    class: 'ant-select-item ant-select-item-option',\n    '[attr.title]': 'title',\n    '[class.ant-select-item-option-grouped]': 'grouped',\n    '[class.ant-select-item-option-selected]': 'selected && !disabled',\n    '[class.ant-select-item-option-disabled]': 'disabled',\n    '[class.ant-select-item-option-active]': 'activated && !disabled'\n  },\n  imports: [NgTemplateOutlet, NzIconModule]\n})\nexport class NzOptionItemComponent implements OnChanges, OnInit {\n  private readonly el: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement;\n  private readonly ngZone = inject(NgZone);\n  private readonly destroyRef = inject(DestroyRef);\n\n  selected = false;\n  activated = false;\n  @Input() grouped = false;\n  @Input({ transform: booleanAttribute }) customContent = false;\n  @Input() template: TemplateRef<NzSafeAny> | null = null;\n  @Input() disabled = false;\n  @Input() showState = false;\n  @Input() title?: string | number | null;\n  @Input() label: string | number | null = null;\n  @Input() value: NzSafeAny | null = null;\n  @Input() activatedValue: NzSafeAny | null = null;\n  @Input() listOfSelectedValue: NzSafeAny[] = [];\n  @Input() icon: TemplateRef<NzSafeAny> | null = null;\n  @Input() compareWith!: (o1: NzSafeAny, o2: NzSafeAny) => boolean;\n  @Output() readonly itemClick = new EventEmitter<NzSafeAny>();\n  @Output() readonly itemHover = new EventEmitter<NzSafeAny>();\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { value, activatedValue, listOfSelectedValue } = changes;\n    if (value || listOfSelectedValue) {\n      this.selected = this.listOfSelectedValue.some(v => this.compareWith(v, this.value));\n    }\n    if (value || activatedValue) {\n      this.activated = this.compareWith(this.activatedValue, this.value);\n    }\n  }\n\n  ngOnInit(): void {\n    fromEventOutsideAngular(this.el, 'click')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(() => {\n        if (!this.disabled) {\n          this.ngZone.run(() => this.itemClick.emit(this.value));\n        }\n      });\n\n    fromEventOutsideAngular(this.el, 'mouseenter')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(() => {\n        if (!this.disabled) {\n          this.ngZone.run(() => this.itemHover.emit(this.value));\n        }\n      });\n  }\n}\n"
  },
  {
    "path": "components/select/option.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  Input,\n  OnChanges,\n  OnInit,\n  TemplateRef,\n  ViewChild,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject,\n  DestroyRef\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Subject } from 'rxjs';\nimport { startWith } from 'rxjs/operators';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzOptionGroupComponent } from './option-group.component';\n\n@Component({\n  selector: 'nz-option',\n  exportAs: 'nzOption',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    <ng-template>\n      <ng-content />\n    </ng-template>\n  `\n})\nexport class NzOptionComponent implements OnChanges, OnInit {\n  private readonly destroyRef = inject(DestroyRef);\n  private readonly nzOptionGroupComponent = inject(NzOptionGroupComponent, { optional: true });\n\n  changes = new Subject<void>();\n  groupLabel?: string | number | TemplateRef<NzSafeAny> | null = null;\n  @ViewChild(TemplateRef, { static: true }) template!: TemplateRef<NzSafeAny>;\n  @Input() nzTitle?: string | number | null;\n  @Input() nzLabel: string | number | null = null;\n  @Input() nzValue: NzSafeAny | null = null;\n  @Input() nzKey?: string | number;\n  @Input({ transform: booleanAttribute }) nzDisabled = false;\n  @Input({ transform: booleanAttribute }) nzHide = false;\n  @Input({ transform: booleanAttribute }) nzCustomContent = false;\n\n  ngOnInit(): void {\n    this.nzOptionGroupComponent?.changes.pipe(startWith(true), takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      this.groupLabel = this.nzOptionGroupComponent?.nzLabel;\n    });\n  }\n\n  ngOnChanges(): void {\n    this.changes.next();\n  }\n}\n"
  },
  {
    "path": "components/select/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './option-group.component';\nexport * from './option-container.component';\nexport * from './option.component';\nexport * from './select.component';\nexport * from './select.module';\nexport * from './option-item.component';\nexport * from './option-item-group.component';\nexport * from './select-top-control.component';\nexport * from './select-search.component';\nexport * from './select-item.component';\nexport * from './select-clear.component';\nexport * from './select-arrow.component';\nexport * from './select-placeholder.component';\nexport * from './select.types';\n"
  },
  {
    "path": "components/select/select-arrow.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, Input, TemplateRef, ViewEncapsulation } from '@angular/core';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { numberAttributeWithInfinityFallback } from 'ng-zorro-antd/core/util';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-select-arrow',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    @if (isMaxMultipleCountSet) {\n      <span>{{ listOfValue.length }} / {{ nzMaxMultipleCount }}</span>\n    }\n    @if (loading) {\n      <nz-icon nzType=\"loading\" />\n    } @else {\n      @if (showArrow && !suffixIcon) {\n        @if (search) {\n          <nz-icon nzType=\"search\" />\n        } @else {\n          <nz-icon nzType=\"down\" />\n        }\n      } @else {\n        <ng-container *nzStringTemplateOutlet=\"suffixIcon; let suffixIcon\">\n          <nz-icon [nzType]=\"suffixIcon\" />\n        </ng-container>\n      }\n    }\n    <ng-container *nzStringTemplateOutlet=\"feedbackIcon\">{{ feedbackIcon }}</ng-container>\n  `,\n  host: {\n    class: 'ant-select-arrow',\n    '[class.ant-select-arrow-loading]': 'loading'\n  },\n  imports: [NzIconModule, NzOutletModule]\n})\nexport class NzSelectArrowComponent {\n  @Input() listOfValue: NzSafeAny[] = [];\n  @Input() loading = false;\n  @Input() search = false;\n  @Input() showArrow = false;\n  @Input() isMaxMultipleCountSet = false;\n  @Input() suffixIcon: TemplateRef<NzSafeAny> | string | null = null;\n  @Input() feedbackIcon: TemplateRef<NzSafeAny> | string | null = null;\n  @Input({ transform: numberAttributeWithInfinityFallback }) nzMaxMultipleCount = Infinity;\n}\n"
  },
  {
    "path": "components/select/select-clear.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  EventEmitter,\n  Input,\n  Output,\n  TemplateRef,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-select-clear',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    @if (clearIcon) {\n      <ng-template [ngTemplateOutlet]=\"clearIcon\" />\n    } @else {\n      <nz-icon nzType=\"close-circle\" nzTheme=\"fill\" class=\"ant-select-close-icon\" />\n    }\n  `,\n  host: {\n    class: 'ant-select-clear',\n    '(click)': 'onClick($event)'\n  },\n  imports: [NgTemplateOutlet, NzIconModule]\n})\nexport class NzSelectClearComponent {\n  @Input() clearIcon: TemplateRef<NzSafeAny> | null = null;\n  @Output() readonly clear = new EventEmitter<MouseEvent>();\n\n  onClick(e: MouseEvent): void {\n    e.preventDefault();\n    e.stopPropagation();\n    this.clear.emit(e);\n  }\n}\n"
  },
  {
    "path": "components/select/select-item.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  Component,\n  EventEmitter,\n  Input,\n  Output,\n  TemplateRef,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-select-item',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    <ng-container *nzStringTemplateOutlet=\"contentTemplateOutlet; context: templateOutletContext\">\n      @if (displayLabelInHtml) {\n        <span [class.ant-select-selection-item-content]=\"deletable\" [innerHTML]=\"label\"></span>\n      } @else {\n        <span [class.ant-select-selection-item-content]=\"deletable\">{{ label }}</span>\n      }\n    </ng-container>\n    @if (deletable && !disabled) {\n      <span class=\"ant-select-selection-item-remove\" (click)=\"onDelete($event)\">\n        @if (!removeIcon) {\n          <nz-icon nzType=\"close\" />\n        } @else {\n          <ng-template [ngTemplateOutlet]=\"removeIcon\" />\n        }\n      </span>\n    }\n  `,\n  host: {\n    class: 'ant-select-selection-item',\n    '[attr.title]': 'label',\n    '[class.ant-select-selection-item-disabled]': 'disabled'\n  },\n  imports: [NgTemplateOutlet, NzOutletModule, NzIconModule]\n})\nexport class NzSelectItemComponent {\n  @Input({ transform: booleanAttribute }) disabled = false;\n  @Input() label: string | number | null | undefined = null;\n  /**\n   * @internal Internally used, please do not use it directly.\n   * @description Whether the label is in HTML format.\n   */\n  @Input({ transform: booleanAttribute }) displayLabelInHtml = false;\n  @Input({ transform: booleanAttribute }) deletable = false;\n  @Input() removeIcon: TemplateRef<NzSafeAny> | null = null;\n  @Input() contentTemplateOutletContext: NzSafeAny | null = null;\n  @Input() contentTemplateOutlet: string | TemplateRef<NzSafeAny> | null = null;\n  @Output() readonly delete = new EventEmitter<MouseEvent>();\n\n  protected get templateOutletContext(): NzSafeAny {\n    return {\n      $implicit: this.contentTemplateOutletContext,\n      ...this.contentTemplateOutletContext\n    };\n  }\n\n  onDelete(e: MouseEvent): void {\n    e.preventDefault();\n    e.stopPropagation();\n    if (!this.disabled) {\n      this.delete.next(e);\n    }\n  }\n}\n"
  },
  {
    "path": "components/select/select-placeholder.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, Input, TemplateRef, ViewEncapsulation } from '@angular/core';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\n@Component({\n  selector: 'nz-select-placeholder',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    <ng-container *nzStringTemplateOutlet=\"placeholder\">\n      {{ placeholder }}\n    </ng-container>\n  `,\n  host: { class: 'ant-select-selection-placeholder' },\n  imports: [NzOutletModule]\n})\nexport class NzSelectPlaceholderComponent {\n  @Input() placeholder: TemplateRef<NzSafeAny> | string | null = null;\n}\n"
  },
  {
    "path": "components/select/select-search.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { FocusMonitor } from '@angular/cdk/a11y';\nimport {\n  afterNextRender,\n  ChangeDetectionStrategy,\n  Component,\n  ElementRef,\n  EventEmitter,\n  inject,\n  Input,\n  OnChanges,\n  Output,\n  Renderer2,\n  SimpleChanges,\n  ViewChild,\n  ViewEncapsulation\n} from '@angular/core';\nimport { COMPOSITION_BUFFER_MODE, FormsModule } from '@angular/forms';\n\n@Component({\n  selector: 'nz-select-search',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    <input\n      #inputElement\n      [attr.id]=\"nzId\"\n      autocomplete=\"off\"\n      class=\"ant-select-selection-search-input\"\n      [ngModel]=\"value\"\n      [attr.autofocus]=\"autofocus ? 'autofocus' : null\"\n      [disabled]=\"disabled\"\n      [style.opacity]=\"showInput ? null : 0\"\n      (ngModelChange)=\"onValueChange($event)\"\n      (compositionstart)=\"setCompositionState(true)\"\n      (compositionend)=\"setCompositionState(false)\"\n    />\n    @if (mirrorSync) {\n      <span #mirrorElement class=\"ant-select-selection-search-mirror\"></span>\n    }\n  `,\n  host: {\n    class: 'ant-select-selection-search',\n    '[style.width.px]': 'mirrorSync ? 0 : null'\n  },\n  providers: [{ provide: COMPOSITION_BUFFER_MODE, useValue: false }],\n  imports: [FormsModule]\n})\nexport class NzSelectSearchComponent implements OnChanges {\n  private readonly elementRef = inject(ElementRef);\n  private readonly renderer = inject(Renderer2);\n  private readonly focusMonitor = inject(FocusMonitor);\n\n  @Input() nzId: string | null = null;\n  @Input() disabled = false;\n  @Input() mirrorSync = false;\n  @Input() showInput = true;\n  @Input() focusTrigger = false;\n  @Input() value = '';\n  @Input() autofocus = false;\n  @Output() readonly valueChange = new EventEmitter<string>();\n  @Output() readonly isComposingChange = new EventEmitter<boolean>();\n  @ViewChild('inputElement', { static: true }) inputElement!: ElementRef;\n  @ViewChild('mirrorElement', { static: false }) mirrorElement?: ElementRef;\n\n  constructor() {\n    afterNextRender(() => {\n      if (this.mirrorSync) {\n        this.syncMirrorWidth();\n      }\n      if (this.autofocus) {\n        this.focus();\n      }\n    });\n  }\n\n  setCompositionState(isComposing: boolean): void {\n    this.isComposingChange.next(isComposing);\n  }\n\n  onValueChange(value: string): void {\n    this.value = value;\n    this.valueChange.next(value);\n    if (this.mirrorSync) {\n      this.syncMirrorWidth();\n    }\n  }\n\n  clearInputValue(): void {\n    const inputDOM = this.inputElement.nativeElement;\n    inputDOM.value = '';\n    this.onValueChange('');\n  }\n\n  syncMirrorWidth(): void {\n    const mirrorDOM = this.mirrorElement!.nativeElement;\n    const hostDOM = this.elementRef.nativeElement;\n    const inputDOM = this.inputElement.nativeElement;\n    this.renderer.removeStyle(hostDOM, 'width');\n    this.renderer.setProperty(mirrorDOM, 'textContent', `${inputDOM.value}\\u00a0`);\n    this.renderer.setStyle(hostDOM, 'width', `${mirrorDOM.scrollWidth}px`);\n  }\n\n  focus(): void {\n    this.focusMonitor.focusVia(this.inputElement, 'keyboard');\n  }\n\n  blur(): void {\n    this.inputElement.nativeElement.blur();\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const inputDOM = this.inputElement.nativeElement;\n    const { focusTrigger, showInput } = changes;\n\n    if (showInput) {\n      if (this.showInput) {\n        this.renderer.removeAttribute(inputDOM, 'readonly');\n      } else {\n        this.renderer.setAttribute(inputDOM, 'readonly', 'readonly');\n      }\n    }\n\n    // IE11 cannot input value if focused before removing readonly\n    if (focusTrigger && focusTrigger.currentValue === true && focusTrigger.previousValue === false) {\n      inputDOM.focus();\n    }\n  }\n}\n"
  },
  {
    "path": "components/select/select-top-control.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BACKSPACE } from '@angular/cdk/keycodes';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  DestroyRef,\n  ElementRef,\n  EventEmitter,\n  inject,\n  Input,\n  NgZone,\n  numberAttribute,\n  OnChanges,\n  OnInit,\n  Output,\n  SimpleChanges,\n  TemplateRef,\n  ViewChild,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { NzNoAnimationDirective } from 'ng-zorro-antd/core/animation';\nimport { NzStringTemplateOutletDirective } from 'ng-zorro-antd/core/outlet';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\n\nimport { NzSelectItemComponent } from './select-item.component';\nimport { NzSelectPlaceholderComponent } from './select-placeholder.component';\nimport { NzSelectSearchComponent } from './select-search.component';\nimport { NzSelectItemInterface, NzSelectModeType, NzSelectTopControlItemType } from './select.types';\n\n@Component({\n  selector: 'nz-select-top-control',\n  exportAs: 'nzSelectTopControl',\n  imports: [\n    NzSelectSearchComponent,\n    NzSelectItemComponent,\n    NzSelectPlaceholderComponent,\n    NzStringTemplateOutletDirective\n  ],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    @if (prefix) {\n      <div class=\"ant-select-prefix\">\n        <ng-container *nzStringTemplateOutlet=\"prefix\">{{ prefix }}</ng-container>\n      </div>\n    }\n    <span class=\"ant-select-selection-wrap\">\n      <!--single mode-->\n      @switch (mode) {\n        @case ('default') {\n          <nz-select-search\n            [nzId]=\"nzId\"\n            [disabled]=\"disabled\"\n            [value]=\"inputValue!\"\n            [showInput]=\"showSearch\"\n            [mirrorSync]=\"false\"\n            [autofocus]=\"autofocus\"\n            [focusTrigger]=\"open\"\n            (isComposingChange)=\"isComposingChange($event)\"\n            (valueChange)=\"onInputValueChange($event)\"\n          />\n          @if (isShowSingleLabel) {\n            <nz-select-item\n              [removeIcon]=\"removeIcon\"\n              [label]=\"listOfTopItem[0].nzLabel\"\n              [contentTemplateOutlet]=\"customTemplate\"\n              [contentTemplateOutletContext]=\"listOfTopItem[0]\"\n            />\n          }\n        }\n        @default {\n          <div class=\"ant-select-selection-overflow\">\n            <!--multiple or tags mode-->\n            @for (item of listOfSlicedItem; track item.nzValue) {\n              <div class=\"ant-select-selection-overflow-item\">\n                <nz-select-item\n                  [removeIcon]=\"removeIcon\"\n                  [label]=\"item.nzLabel\"\n                  [disabled]=\"item.nzDisabled || disabled\"\n                  [contentTemplateOutlet]=\"item.contentTemplateOutlet\"\n                  deletable\n                  [contentTemplateOutletContext]=\"item.contentTemplateOutletContext\"\n                  (delete)=\"onDeleteItem(item.contentTemplateOutletContext)\"\n                />\n              </div>\n            }\n            <div class=\"ant-select-selection-overflow-item ant-select-selection-overflow-item-suffix\">\n              <nz-select-search\n                [nzId]=\"nzId\"\n                [disabled]=\"disabled\"\n                [value]=\"inputValue!\"\n                [autofocus]=\"autofocus\"\n                [showInput]=\"true\"\n                [mirrorSync]=\"true\"\n                [focusTrigger]=\"open\"\n                (isComposingChange)=\"isComposingChange($event)\"\n                (valueChange)=\"onInputValueChange($event)\"\n              />\n            </div>\n          </div>\n        }\n      }\n      @if (isShowPlaceholder) {\n        <nz-select-placeholder [placeholder]=\"placeHolder\" />\n      }\n    </span>\n  `,\n  host: {\n    class: 'ant-select-selector'\n  }\n})\nexport class NzSelectTopControlComponent implements OnChanges, OnInit {\n  private readonly destroyRef = inject(DestroyRef);\n  private readonly elementRef = inject(ElementRef<HTMLElement>);\n  private readonly ngZone = inject(NgZone);\n  readonly noAnimation = inject(NzNoAnimationDirective, { host: true, optional: true });\n\n  @Input() nzId: string | null = null;\n  @Input() showSearch = false;\n  @Input() placeHolder: string | TemplateRef<NzSafeAny> | null = null;\n  @Input() open = false;\n  @Input({ transform: numberAttribute }) maxTagCount: number = Infinity;\n  @Input() autofocus = false;\n  @Input() disabled = false;\n  @Input() mode: NzSelectModeType = 'default';\n  @Input() customTemplate: TemplateRef<{ $implicit: NzSelectItemInterface }> | null = null;\n  @Input() maxTagPlaceholder: TemplateRef<{ $implicit: NzSafeAny[] }> | null = null;\n  @Input() removeIcon: TemplateRef<NzSafeAny> | null = null;\n  @Input() listOfTopItem: NzSelectItemInterface[] = [];\n  @Input() tokenSeparators: string[] = [];\n  @Input() prefix: TemplateRef<NzSafeAny> | string | null = null;\n  @Output() readonly tokenize = new EventEmitter<string[]>();\n  @Output() readonly inputValueChange = new EventEmitter<string>();\n  @Output() readonly deleteItem = new EventEmitter<NzSelectItemInterface>();\n  @ViewChild(NzSelectSearchComponent) nzSelectSearchComponent!: NzSelectSearchComponent;\n  listOfSlicedItem: NzSelectTopControlItemType[] = [];\n  isShowPlaceholder = true;\n  isShowSingleLabel = false;\n  isComposing = false;\n  inputValue: string | null = null;\n\n  updateTemplateVariable(): void {\n    const isSelectedValueEmpty = this.listOfTopItem.length === 0;\n    this.isShowPlaceholder = isSelectedValueEmpty && !this.isComposing && !this.inputValue;\n    this.isShowSingleLabel = !isSelectedValueEmpty && !this.isComposing && !this.inputValue;\n  }\n\n  isComposingChange(isComposing: boolean): void {\n    this.isComposing = isComposing;\n    this.updateTemplateVariable();\n  }\n\n  onInputValueChange(value: string): void {\n    if (value !== this.inputValue) {\n      this.inputValue = value;\n      this.updateTemplateVariable();\n      this.inputValueChange.emit(value);\n      this.tokenSeparate(value, this.tokenSeparators);\n    }\n  }\n\n  tokenSeparate(inputValue: string, tokenSeparators: string[]): void {\n    const includesSeparators = (str: string, separators: string[]): boolean => {\n      // eslint-disable-next-line @typescript-eslint/prefer-for-of\n      for (let i = 0; i < separators.length; ++i) {\n        if (str.lastIndexOf(separators[i]) > 0) {\n          return true;\n        }\n      }\n      return false;\n    };\n    const splitBySeparators = (str: string, separators: string[]): string[] => {\n      const reg = new RegExp(`[${separators.join()}]`);\n      const array = str.split(reg).filter(token => token);\n      return [...new Set(array)];\n    };\n    if (\n      inputValue &&\n      inputValue.length &&\n      tokenSeparators.length &&\n      this.mode !== 'default' &&\n      includesSeparators(inputValue, tokenSeparators)\n    ) {\n      const listOfLabel = splitBySeparators(inputValue, tokenSeparators);\n      this.tokenize.next(listOfLabel);\n    }\n  }\n\n  clearInputValue(): void {\n    this.nzSelectSearchComponent?.clearInputValue();\n  }\n\n  focus(): void {\n    this.nzSelectSearchComponent?.focus();\n  }\n\n  blur(): void {\n    this.nzSelectSearchComponent?.blur();\n  }\n\n  onDeleteItem(item: NzSelectItemInterface): void {\n    if (!this.disabled && !item.nzDisabled) {\n      this.deleteItem.next(item);\n    }\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { listOfTopItem, maxTagCount, customTemplate, maxTagPlaceholder } = changes;\n    if (listOfTopItem) {\n      this.updateTemplateVariable();\n    }\n    if (listOfTopItem || maxTagCount || customTemplate || maxTagPlaceholder) {\n      const listOfSlicedItem: NzSelectTopControlItemType[] = this.listOfTopItem.slice(0, this.maxTagCount).map(o => ({\n        nzLabel: o.nzLabel,\n        nzValue: o.nzValue,\n        nzDisabled: o.nzDisabled,\n        contentTemplateOutlet: this.customTemplate,\n        contentTemplateOutletContext: o\n      }));\n      if (this.listOfTopItem.length > this.maxTagCount) {\n        const exceededLabel = `+ ${this.listOfTopItem.length - this.maxTagCount} ...`;\n        const listOfSelectedValue = this.listOfTopItem.map(item => item.nzValue);\n        const exceededItem = {\n          nzLabel: exceededLabel,\n          nzValue: '$$__nz_exceeded_item',\n          nzDisabled: true,\n          contentTemplateOutlet: this.maxTagPlaceholder,\n          contentTemplateOutletContext: listOfSelectedValue.slice(this.maxTagCount)\n        };\n        listOfSlicedItem.push(exceededItem);\n      }\n      this.listOfSlicedItem = listOfSlicedItem;\n    }\n  }\n\n  ngOnInit(): void {\n    fromEventOutsideAngular<MouseEvent>(this.elementRef.nativeElement, 'click')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(event => {\n        // `HTMLElement.focus()` is a native DOM API that doesn't require Angular to run change detection.\n        if (event.target !== this.nzSelectSearchComponent.inputElement.nativeElement) {\n          this.nzSelectSearchComponent.focus();\n        }\n      });\n\n    fromEventOutsideAngular<KeyboardEvent>(this.elementRef.nativeElement, 'keydown')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(event => {\n        if (event.target instanceof HTMLInputElement) {\n          const inputValue = event.target.value;\n\n          if (event.keyCode === BACKSPACE && this.mode !== 'default' && !inputValue && this.listOfTopItem.length > 0) {\n            event.preventDefault();\n            // Run change detection only if the user has pressed the `Backspace` key and the following condition is met.\n            this.ngZone.run(() => this.onDeleteItem(this.listOfTopItem[this.listOfTopItem.length - 1]));\n          }\n        }\n      });\n  }\n}\n"
  },
  {
    "path": "components/select/select.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { FocusMonitor } from '@angular/cdk/a11y';\nimport { Directionality } from '@angular/cdk/bidi';\nimport { DOWN_ARROW, ENTER, ESCAPE, SPACE, TAB, UP_ARROW } from '@angular/cdk/keycodes';\nimport {\n  CdkConnectedOverlay,\n  CdkOverlayOrigin,\n  ConnectedOverlayPositionChange,\n  ConnectionPositionPair\n} from '@angular/cdk/overlay';\nimport { _getEventTarget, Platform } from '@angular/cdk/platform';\nimport {\n  AfterContentInit,\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  computed,\n  ContentChildren,\n  DestroyRef,\n  ElementRef,\n  EventEmitter,\n  forwardRef,\n  inject,\n  Input,\n  NgZone,\n  OnChanges,\n  OnInit,\n  Output,\n  output,\n  QueryList,\n  Renderer2,\n  signal,\n  SimpleChanges,\n  TemplateRef,\n  ViewChild,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { BehaviorSubject, combineLatest, merge, of as observableOf } from 'rxjs';\nimport { distinctUntilChanged, map, startWith, switchMap, withLatestFrom } from 'rxjs/operators';\n\nimport { NzNoAnimationDirective, slideAnimationEnter, slideAnimationLeave } from 'ng-zorro-antd/core/animation';\nimport { NzConfigKey, onConfigChangeEventForComponent, WithConfig } from 'ng-zorro-antd/core/config';\nimport {\n  NZ_FORM_SIZE,\n  NZ_FORM_VARIANT,\n  NzFormItemFeedbackIconComponent,\n  NzFormNoStatusService,\n  NzFormStatusService\n} from 'ng-zorro-antd/core/form';\nimport { getPlacementName, NzOverlayModule, POSITION_MAP, POSITION_TYPE } from 'ng-zorro-antd/core/overlay';\nimport { cancelAnimationFrame, requestAnimationFrame } from 'ng-zorro-antd/core/polyfill';\nimport {\n  NgClassInterface,\n  NzSafeAny,\n  NzSizeLDSType,\n  NzStatus,\n  NzValidateStatus,\n  NzVariant,\n  OnChangeType,\n  OnTouchedType\n} from 'ng-zorro-antd/core/types';\nimport {\n  fromEventOutsideAngular,\n  getStatusClassNames,\n  isNotNil,\n  numberAttributeWithInfinityFallback\n} from 'ng-zorro-antd/core/util';\nimport { NZ_SPACE_COMPACT_ITEM_TYPE, NZ_SPACE_COMPACT_SIZE, NzSpaceCompactItemDirective } from 'ng-zorro-antd/space';\n\nimport { NzOptionContainerComponent } from './option-container.component';\nimport { NzOptionGroupComponent } from './option-group.component';\nimport { NzOptionComponent } from './option.component';\nimport { NzSelectArrowComponent } from './select-arrow.component';\nimport { NzSelectClearComponent } from './select-clear.component';\nimport { NzSelectTopControlComponent } from './select-top-control.component';\nimport {\n  NzFilterOptionType,\n  NzSelectItemInterface,\n  NzSelectModeType,\n  NzSelectOptionInterface,\n  NzSelectPlacementType\n} from './select.types';\n\nconst defaultFilterOption: NzFilterOptionType = (searchValue: string, item: NzSelectItemInterface): boolean => {\n  if (item && item.nzLabel) {\n    return item.nzLabel.toString().toLowerCase().indexOf(searchValue.toLowerCase()) > -1;\n  } else {\n    return false;\n  }\n};\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'select';\n\nexport type NzSelectSizeType = NzSizeLDSType;\n\n@Component({\n  selector: 'nz-select',\n  exportAs: 'nzSelect',\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => NzSelectComponent),\n      multi: true\n    },\n    { provide: NZ_SPACE_COMPACT_ITEM_TYPE, useValue: 'select' }\n  ],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <nz-select-top-control\n      cdkOverlayOrigin\n      #origin=\"cdkOverlayOrigin\"\n      [nzId]=\"nzId\"\n      [open]=\"nzOpen\"\n      [disabled]=\"nzDisabled\"\n      [mode]=\"nzMode\"\n      [nzNoAnimation]=\"noAnimation?.nzNoAnimation?.()\"\n      [maxTagPlaceholder]=\"nzMaxTagPlaceholder\"\n      [removeIcon]=\"nzRemoveIcon\"\n      [placeHolder]=\"nzPlaceHolder\"\n      [maxTagCount]=\"nzMaxTagCount\"\n      [customTemplate]=\"nzCustomTemplate\"\n      [tokenSeparators]=\"nzTokenSeparators\"\n      [showSearch]=\"nzShowSearch\"\n      [autofocus]=\"nzAutoFocus\"\n      [listOfTopItem]=\"listOfTopItem\"\n      [prefix]=\"nzPrefix\"\n      (inputValueChange)=\"onInputValueChange($event)\"\n      (tokenize)=\"onTokenSeparate($event)\"\n      (deleteItem)=\"onItemDelete($event)\"\n      (keydown)=\"onKeyDown($event)\"\n    />\n    @if (showArrow || (hasFeedback && !!status) || isMaxMultipleCountSet) {\n      <nz-select-arrow\n        [showArrow]=\"nzShowArrow\"\n        [loading]=\"nzLoading\"\n        [search]=\"nzOpen && nzShowSearch\"\n        [suffixIcon]=\"nzSuffixIcon\"\n        [feedbackIcon]=\"feedbackIconTpl\"\n        [nzMaxMultipleCount]=\"nzMaxMultipleCount\"\n        [listOfValue]=\"listOfValue\"\n        [isMaxMultipleCountSet]=\"isMaxMultipleCountSet\"\n      >\n        <ng-template #feedbackIconTpl>\n          @if (hasFeedback && !!status) {\n            <nz-form-item-feedback-icon [status]=\"status\" />\n          }\n        </ng-template>\n      </nz-select-arrow>\n    }\n\n    @if (nzAllowClear && !nzDisabled && listOfValue.length) {\n      <nz-select-clear [clearIcon]=\"nzClearIcon\" (clear)=\"onClearSelection()\" />\n    }\n    <ng-template\n      cdkConnectedOverlay\n      nzConnectedOverlay\n      [cdkConnectedOverlayHasBackdrop]=\"nzBackdrop\"\n      [cdkConnectedOverlayMinWidth]=\"$any(nzDropdownMatchSelectWidth ? null : triggerWidth)\"\n      [cdkConnectedOverlayWidth]=\"$any(nzDropdownMatchSelectWidth ? triggerWidth : null)\"\n      [cdkConnectedOverlayOrigin]=\"origin\"\n      cdkConnectedOverlayTransformOriginOn=\".ant-select-dropdown\"\n      [cdkConnectedOverlayPanelClass]=\"nzDropdownClassName!\"\n      [cdkConnectedOverlayOpen]=\"nzOpen\"\n      [cdkConnectedOverlayPositions]=\"positions\"\n      (overlayOutsideClick)=\"onClickOutside($event)\"\n      (detach)=\"setOpenState(false)\"\n      (positionChange)=\"onPositionChange($event)\"\n    >\n      <nz-option-container\n        [style]=\"nzDropdownStyle\"\n        [itemSize]=\"nzOptionHeightPx\"\n        [maxItemLength]=\"nzOptionOverflowSize\"\n        [matchWidth]=\"nzDropdownMatchSelectWidth\"\n        [class.ant-select-dropdown-placement-bottomLeft]=\"dropdownPosition === 'bottomLeft'\"\n        [class.ant-select-dropdown-placement-topLeft]=\"dropdownPosition === 'topLeft'\"\n        [class.ant-select-dropdown-placement-bottomRight]=\"dropdownPosition === 'bottomRight'\"\n        [class.ant-select-dropdown-placement-topRight]=\"dropdownPosition === 'topRight'\"\n        [animate.enter]=\"selectAnimationEnter()\"\n        [animate.leave]=\"selectAnimationLeave()\"\n        [nzNoAnimation]=\"!!noAnimation?.nzNoAnimation?.()\"\n        [listOfContainerItem]=\"listOfContainerItem\"\n        [menuItemSelectedIcon]=\"nzMenuItemSelectedIcon\"\n        [notFoundContent]=\"nzNotFoundContent\"\n        [activatedValue]=\"activatedValue\"\n        [listOfSelectedValue]=\"listOfValue\"\n        [dropdownRender]=\"nzDropdownRender\"\n        [compareWith]=\"compareWith\"\n        [mode]=\"nzMode\"\n        [isMaxMultipleCountReached]=\"isMaxMultipleCountReached\"\n        (keydown)=\"onKeyDown($event)\"\n        (itemClick)=\"onItemClick($event)\"\n        (scrollToBottom)=\"nzScrollToBottom.emit()\"\n      />\n    </ng-template>\n  `,\n  host: {\n    class: 'ant-select',\n    '[class.ant-select-in-form-item]': '!!nzFormStatusService',\n    '[class.ant-select-lg]': 'finalSize() === \"large\"',\n    '[class.ant-select-sm]': 'finalSize() === \"small\"',\n    '[class.ant-select-show-arrow]': `showArrow`,\n    '[class.ant-select-disabled]': 'nzDisabled',\n    '[class.ant-select-show-search]': `(nzShowSearch || nzMode !== 'default') && !nzDisabled`,\n    '[class.ant-select-allow-clear]': 'nzAllowClear',\n    '[class.ant-select-borderless]': `finalVariant() === 'borderless'`,\n    '[class.ant-select-filled]': `finalVariant() === 'filled'`,\n    '[class.ant-select-underlined]': `finalVariant() === 'underlined'`,\n    '[class.ant-select-open]': 'nzOpen',\n    '[class.ant-select-focused]': 'nzOpen || focused',\n    '[class.ant-select-single]': `nzMode === 'default'`,\n    '[class.ant-select-multiple]': `nzMode !== 'default'`,\n    '[class.ant-select-rtl]': `dir() === 'rtl'`\n  },\n  hostDirectives: [NzSpaceCompactItemDirective],\n  imports: [\n    NzSelectTopControlComponent,\n    CdkOverlayOrigin,\n    NzNoAnimationDirective,\n    NzSelectArrowComponent,\n    NzFormItemFeedbackIconComponent,\n    NzSelectClearComponent,\n    CdkConnectedOverlay,\n    NzOverlayModule,\n    NzOptionContainerComponent\n  ]\n})\nexport class NzSelectComponent implements ControlValueAccessor, OnInit, AfterContentInit, OnChanges {\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  private readonly ngZone = inject(NgZone);\n  private readonly cdr = inject(ChangeDetectorRef);\n  private readonly host = inject(ElementRef<HTMLElement>);\n  private readonly renderer = inject(Renderer2);\n  private readonly platform = inject(Platform);\n  private readonly focusMonitor = inject(FocusMonitor);\n  private readonly destroyRef = inject(DestroyRef);\n\n  noAnimation = inject(NzNoAnimationDirective, { host: true, optional: true });\n  protected nzFormStatusService = inject(NzFormStatusService, { optional: true });\n  private nzFormNoStatusService = inject(NzFormNoStatusService, { optional: true });\n\n  @Input() nzId: string | null = null;\n  @Input() nzSize: NzSelectSizeType = 'default';\n  @Input() nzStatus: NzStatus = '';\n  @Input() @WithConfig() nzVariant: NzVariant | undefined = undefined;\n  @Input() @WithConfig() nzOptionHeightPx = 32;\n  @Input() nzOptionOverflowSize = 8;\n  @Input() nzDropdownClassName: string[] | string | null = null;\n  @Input() nzDropdownMatchSelectWidth = true;\n  @Input() nzDropdownStyle: Record<string, string> | null = null;\n  @Input() nzNotFoundContent: string | TemplateRef<NzSafeAny> | undefined = undefined;\n  @Input() nzPlaceHolder: string | TemplateRef<NzSafeAny> | null = null;\n  @Input() nzPlacement: NzSelectPlacementType | null = null;\n  @Input() nzMaxTagCount = Infinity;\n  @Input() nzDropdownRender: TemplateRef<NzSafeAny> | null = null;\n  @Input() nzCustomTemplate: TemplateRef<{ $implicit: NzSelectItemInterface }> | null = null;\n  @Input() nzPrefix: TemplateRef<NzSafeAny> | string | null = null;\n  @Input()\n  @WithConfig()\n  nzSuffixIcon: TemplateRef<NzSafeAny> | string | null = null;\n  @Input() nzClearIcon: TemplateRef<NzSafeAny> | null = null;\n  @Input() nzRemoveIcon: TemplateRef<NzSafeAny> | null = null;\n  @Input() nzMenuItemSelectedIcon: TemplateRef<NzSafeAny> | null = null;\n  @Input() nzTokenSeparators: string[] = [];\n  @Input() nzMaxTagPlaceholder: TemplateRef<{ $implicit: NzSafeAny[] }> | null = null;\n  @Input({ transform: numberAttributeWithInfinityFallback }) nzMaxMultipleCount = Infinity;\n  @Input() nzMode: NzSelectModeType = 'default';\n  @Input() nzFilterOption: NzFilterOptionType = defaultFilterOption;\n  @Input() compareWith: (o1: NzSafeAny, o2: NzSafeAny) => boolean = (o1: NzSafeAny, o2: NzSafeAny) => o1 === o2;\n  @Input({ transform: booleanAttribute }) nzAllowClear = false;\n  @Input({ transform: booleanAttribute }) nzShowSearch = false;\n  @Input({ transform: booleanAttribute }) nzLoading = false;\n  @Input({ transform: booleanAttribute }) nzAutoFocus = false;\n  @Input({ transform: booleanAttribute }) nzAutoClearSearchValue = true;\n  @Input({ transform: booleanAttribute }) nzServerSearch = false;\n  @Input({ transform: booleanAttribute }) nzDisabled = false;\n  @Input({ transform: booleanAttribute }) nzOpen = false;\n  @Input({ transform: booleanAttribute }) nzSelectOnTab = false;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzBackdrop = false;\n  @Input() nzOptions: NzSelectOptionInterface[] = [];\n  @Input({ transform: booleanAttribute }) nzShowArrow: boolean = true;\n\n  get showArrow(): boolean {\n    return this.nzShowArrow || !!this.nzSuffixIcon;\n  }\n\n  get isMultiple(): boolean {\n    return this.nzMode === 'multiple' || this.nzMode === 'tags';\n  }\n\n  get isMaxMultipleCountSet(): boolean {\n    return this.isMultiple && this.nzMaxMultipleCount !== Infinity;\n  }\n\n  get isMaxMultipleCountReached(): boolean {\n    return this.nzMaxMultipleCount !== Infinity && this.listOfValue.length === this.nzMaxMultipleCount;\n  }\n\n  @Output() readonly nzOnSearch = new EventEmitter<string>();\n  @Output() readonly nzScrollToBottom = new EventEmitter<void>();\n  @Output() readonly nzOpenChange = new EventEmitter<boolean>();\n  @Output() readonly nzBlur = new EventEmitter<void>();\n  @Output() readonly nzFocus = new EventEmitter<void>();\n  readonly nzOnClear = output<void>();\n  @ViewChild(CdkOverlayOrigin, { static: true, read: ElementRef }) originElement!: ElementRef;\n  @ViewChild(CdkConnectedOverlay, { static: true }) cdkConnectedOverlay!: CdkConnectedOverlay;\n  @ViewChild(NzSelectTopControlComponent, { static: true }) nzSelectTopControlComponent!: NzSelectTopControlComponent;\n  @ContentChildren(NzOptionComponent, { descendants: true }) listOfNzOptionComponent!: QueryList<NzOptionComponent>;\n  @ContentChildren(NzOptionGroupComponent, { descendants: true })\n  listOfNzOptionGroupComponent!: QueryList<NzOptionGroupComponent>;\n  @ViewChild(NzOptionGroupComponent, { static: true, read: ElementRef }) nzOptionGroupComponentElement!: ElementRef;\n  @ViewChild(NzSelectTopControlComponent, { static: true, read: ElementRef })\n  nzSelectTopControlComponentElement!: ElementRef;\n\n  protected finalSize = computed(() => {\n    if (this.formSize?.()) {\n      return this.formSize();\n    }\n    if (this.compactSize) {\n      return this.compactSize();\n    }\n    return this.size();\n  });\n\n  protected readonly finalVariant = computed(() => this.variant() || this.formVariant?.() || 'outlined');\n  private size = signal<NzSizeLDSType>(this.nzSize);\n  private variant = signal<NzVariant | undefined>(this.nzVariant);\n  private readonly formSize = inject(NZ_FORM_SIZE, { optional: true });\n  private readonly formVariant = inject(NZ_FORM_VARIANT, { optional: true });\n  private compactSize = inject(NZ_SPACE_COMPACT_SIZE, { optional: true });\n  private listOfValue$ = new BehaviorSubject<NzSafeAny[]>([]);\n  private listOfTemplateItem$ = new BehaviorSubject<NzSelectItemInterface[]>([]);\n  private listOfTagAndTemplateItem: NzSelectItemInterface[] = [];\n  private searchValue: string = '';\n  private isReactiveDriven = false;\n  private value: NzSafeAny | NzSafeAny[];\n  private requestId: number = -1;\n  private isNzDisableFirstChange: boolean = true;\n\n  onChange: OnChangeType = () => {};\n  onTouched: OnTouchedType = () => {};\n  dropdownPosition: NzSelectPlacementType = 'bottomLeft';\n  triggerWidth: number | null = null;\n  listOfContainerItem: NzSelectItemInterface[] = [];\n  listOfTopItem: NzSelectItemInterface[] = [];\n  activatedValue: NzSafeAny | null = null;\n  listOfValue: NzSafeAny[] = [];\n  focused = false;\n  protected readonly dir = inject(Directionality).valueSignal;\n  positions: ConnectionPositionPair[] = [];\n\n  protected readonly selectAnimationEnter = slideAnimationEnter();\n  protected readonly selectAnimationLeave = slideAnimationLeave();\n\n  // status\n  prefixCls: string = 'ant-select';\n  statusCls: NgClassInterface = {};\n  status: NzValidateStatus = '';\n  hasFeedback: boolean = false;\n\n  generateTagItem(value: string): NzSelectItemInterface {\n    return {\n      nzValue: value,\n      nzLabel: value,\n      type: 'item'\n    };\n  }\n\n  onItemClick(value: NzSafeAny): void {\n    this.activatedValue = value;\n    if (this.nzMode === 'default') {\n      if (this.listOfValue.length === 0 || !this.compareWith(this.listOfValue[0], value)) {\n        this.updateListOfValue([value]);\n      }\n      this.setOpenState(false);\n    } else {\n      const targetIndex = this.listOfValue.findIndex(o => this.compareWith(o, value));\n      if (targetIndex !== -1) {\n        const listOfValueAfterRemoved = this.listOfValue.filter((_, i) => i !== targetIndex);\n        this.updateListOfValue(listOfValueAfterRemoved);\n      } else if (this.listOfValue.length < this.nzMaxMultipleCount) {\n        const listOfValueAfterAdded = [...this.listOfValue, value];\n        this.updateListOfValue(listOfValueAfterAdded);\n      }\n      this.focus();\n      if (this.nzAutoClearSearchValue) {\n        this.clearInput();\n      }\n    }\n  }\n\n  onItemDelete(item: NzSelectItemInterface): void {\n    const listOfSelectedValue = this.listOfValue.filter(v => !this.compareWith(v, item.nzValue));\n    this.updateListOfValue(listOfSelectedValue);\n    this.clearInput();\n  }\n\n  updateListOfContainerItem(): void {\n    let listOfContainerItem = this.listOfTagAndTemplateItem\n      .filter(item => !item.nzHide)\n      .filter(item => {\n        if (!this.nzServerSearch && this.searchValue) {\n          return this.nzFilterOption(this.searchValue, item);\n        } else {\n          return true;\n        }\n      });\n    if (this.nzMode === 'tags' && this.searchValue) {\n      const matchedItem = this.listOfTagAndTemplateItem.find(item => item.nzLabel === this.searchValue);\n      if (!matchedItem) {\n        const tagItem = this.generateTagItem(this.searchValue);\n        listOfContainerItem = [tagItem, ...listOfContainerItem];\n        this.activatedValue = tagItem.nzValue;\n      } else {\n        this.activatedValue = matchedItem.nzValue;\n      }\n    }\n    const activatedItem =\n      listOfContainerItem.find(item => item.nzLabel === this.searchValue) ||\n      listOfContainerItem.find(item => this.compareWith(item.nzValue, this.activatedValue)) ||\n      listOfContainerItem.find(item => this.compareWith(item.nzValue, this.listOfValue[0])) ||\n      listOfContainerItem[0];\n    this.activatedValue = (activatedItem && activatedItem.nzValue) || null;\n    let listOfGroupLabel: Array<string | number | TemplateRef<NzSafeAny> | null> = [];\n    if (this.isReactiveDriven) {\n      listOfGroupLabel = [...new Set(this.nzOptions.filter(o => o.groupLabel).map(o => o.groupLabel!))];\n    } else {\n      if (this.listOfNzOptionGroupComponent) {\n        listOfGroupLabel = this.listOfNzOptionGroupComponent.map(o => o.nzLabel);\n      }\n    }\n    /** insert group item **/\n    listOfGroupLabel.forEach(label => {\n      const index = listOfContainerItem.findIndex(item => label === item.groupLabel);\n      if (index > -1) {\n        const groupItem = { groupLabel: label, type: 'group', key: label } as NzSelectItemInterface;\n        listOfContainerItem.splice(index, 0, groupItem);\n      }\n    });\n    this.listOfContainerItem = [...listOfContainerItem];\n    this.updateCdkConnectedOverlayPositions();\n  }\n\n  clearInput(): void {\n    this.nzSelectTopControlComponent.clearInputValue();\n  }\n\n  updateListOfValue(listOfValue: NzSafeAny[]): void {\n    const covertListToModel = (list: NzSafeAny[], mode: NzSelectModeType): NzSafeAny[] | NzSafeAny => {\n      if (mode === 'default') {\n        if (list.length > 0) {\n          return list[0];\n        } else {\n          return null;\n        }\n      } else {\n        return list;\n      }\n    };\n    const model = covertListToModel(listOfValue, this.nzMode);\n    if (this.value !== model) {\n      this.listOfValue = listOfValue;\n      this.listOfValue$.next(listOfValue);\n      this.value = model;\n      this.onChange(this.value);\n    }\n  }\n\n  onTokenSeparate(listOfLabel: string[]): void {\n    const listOfMatchedValue = this.listOfTagAndTemplateItem\n      .filter(item => listOfLabel.findIndex(label => label === item.nzLabel) !== -1)\n      .map(item => item.nzValue)\n      .filter(item => this.listOfValue.findIndex(v => this.compareWith(v, item)) === -1);\n    /**\n     * Limit the number of selected items to nzMaxMultipleCount\n     */\n    const limitWithinMaxCount = <T>(value: T[]): T[] =>\n      this.isMaxMultipleCountSet ? value.slice(0, this.nzMaxMultipleCount) : value;\n\n    if (this.nzMode === 'multiple') {\n      const updateValue = limitWithinMaxCount([...this.listOfValue, ...listOfMatchedValue]);\n      this.updateListOfValue(updateValue);\n    } else if (this.nzMode === 'tags') {\n      const listOfUnMatchedLabel = listOfLabel.filter(\n        label => this.listOfTagAndTemplateItem.findIndex(item => item.nzLabel === label) === -1\n      );\n      const updateValue = limitWithinMaxCount([...this.listOfValue, ...listOfMatchedValue, ...listOfUnMatchedLabel]);\n      this.updateListOfValue(updateValue);\n    }\n    this.clearInput();\n  }\n\n  onKeyDown(e: KeyboardEvent): void {\n    if (this.nzDisabled) {\n      return;\n    }\n    const listOfFilteredOptionNotDisabled = this.listOfContainerItem\n      .filter(item => item.type === 'item')\n      .filter(item => !item.nzDisabled);\n    const activatedIndex = listOfFilteredOptionNotDisabled.findIndex(item =>\n      this.compareWith(item.nzValue, this.activatedValue)\n    );\n    switch (e.keyCode) {\n      case UP_ARROW:\n        e.preventDefault();\n        if (this.nzOpen && listOfFilteredOptionNotDisabled.length > 0) {\n          const preIndex = activatedIndex > 0 ? activatedIndex - 1 : listOfFilteredOptionNotDisabled.length - 1;\n          this.activatedValue = listOfFilteredOptionNotDisabled[preIndex].nzValue;\n        }\n        break;\n      case DOWN_ARROW:\n        e.preventDefault();\n        if (this.nzOpen && listOfFilteredOptionNotDisabled.length > 0) {\n          const nextIndex = activatedIndex < listOfFilteredOptionNotDisabled.length - 1 ? activatedIndex + 1 : 0;\n          this.activatedValue = listOfFilteredOptionNotDisabled[nextIndex].nzValue;\n        } else {\n          this.setOpenState(true);\n        }\n        break;\n      case ENTER:\n        e.preventDefault();\n        if (this.nzOpen) {\n          if (isNotNil(this.activatedValue) && activatedIndex !== -1) {\n            this.onItemClick(this.activatedValue);\n          }\n        } else {\n          this.setOpenState(true);\n        }\n        break;\n      case SPACE:\n        if (!this.nzOpen) {\n          this.setOpenState(true);\n          e.preventDefault();\n        }\n        break;\n      case TAB:\n        if (this.nzSelectOnTab) {\n          if (this.nzOpen) {\n            e.preventDefault();\n            if (isNotNil(this.activatedValue)) {\n              this.onItemClick(this.activatedValue);\n            }\n          }\n        } else {\n          this.setOpenState(false);\n        }\n        break;\n      case ESCAPE:\n        /**\n         * Skip the ESCAPE processing, it will be handled in {@link onOverlayKeyDown}.\n         */\n        break;\n      default:\n        if (!this.nzOpen) {\n          this.setOpenState(true);\n        }\n    }\n  }\n\n  setOpenState(value: boolean): void {\n    if (this.nzOpen !== value) {\n      this.nzOpen = value;\n      this.nzOpenChange.emit(value);\n      this.onOpenChange();\n      this.cdr.markForCheck();\n    }\n  }\n\n  onOpenChange(): void {\n    this.updateCdkConnectedOverlayStatus();\n    if (this.nzAutoClearSearchValue || !this.isMultiple) {\n      this.clearInput();\n    }\n  }\n\n  onInputValueChange(value: string): void {\n    this.searchValue = value;\n    this.updateListOfContainerItem();\n    this.nzOnSearch.emit(value);\n    this.updateCdkConnectedOverlayPositions();\n  }\n\n  onClearSelection(): void {\n    this.updateListOfValue([]);\n    this.nzOnClear.emit();\n  }\n\n  onClickOutside(event: MouseEvent): void {\n    const target = _getEventTarget(event);\n    if (!this.host.nativeElement.contains(target as Node)) {\n      this.setOpenState(false);\n    }\n  }\n\n  focus(): void {\n    this.nzSelectTopControlComponent.focus();\n  }\n\n  blur(): void {\n    this.nzSelectTopControlComponent.blur();\n  }\n\n  onPositionChange(position: ConnectedOverlayPositionChange): void {\n    const placement = getPlacementName(position);\n    this.dropdownPosition = placement as NzSelectPlacementType;\n  }\n\n  updateCdkConnectedOverlayStatus(): void {\n    if (this.platform.isBrowser && this.originElement.nativeElement) {\n      const triggerWidth = this.triggerWidth;\n      cancelAnimationFrame(this.requestId);\n      this.requestId = requestAnimationFrame(() => {\n        // Blink triggers style and layout pipelines anytime the `getBoundingClientRect()` is called, which may cause a\n        // frame drop. That's why it's scheduled through the `requestAnimationFrame` to unload the composite thread.\n        this.triggerWidth = this.originElement.nativeElement.getBoundingClientRect().width;\n        if (triggerWidth !== this.triggerWidth) {\n          // The `requestAnimationFrame` will trigger change detection, but we're inside an `OnPush` component which won't have\n          // the `ChecksEnabled` state. Calling `markForCheck()` will allow Angular to run the change detection from the root component\n          // down to the `nz-select`. But we'll trigger only local change detection if the `triggerWidth` has been changed.\n          this.cdr.detectChanges();\n        }\n      });\n    }\n  }\n\n  updateCdkConnectedOverlayPositions(): void {\n    requestAnimationFrame(() => {\n      this.cdkConnectedOverlay?.overlayRef?.updatePosition();\n    });\n  }\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      cancelAnimationFrame(this.requestId);\n      this.focusMonitor.stopMonitoring(this.host);\n    });\n\n    onConfigChangeEventForComponent(NZ_CONFIG_MODULE_NAME, () => {\n      this.size.set(this.nzSize);\n      this.cdr.markForCheck();\n    });\n  }\n\n  writeValue(modelValue: NzSafeAny | NzSafeAny[]): void {\n    /** https://github.com/angular/angular/issues/14988 **/\n    if (this.value !== modelValue) {\n      this.value = modelValue;\n      const covertModelToList = (model: NzSafeAny[] | NzSafeAny, mode: NzSelectModeType): NzSafeAny[] => {\n        if (model === null || model === undefined) {\n          return [];\n        } else if (mode === 'default') {\n          return [model];\n        } else {\n          return model;\n        }\n      };\n      const listOfValue = covertModelToList(modelValue, this.nzMode);\n      this.listOfValue = listOfValue;\n      this.listOfValue$.next(listOfValue);\n      this.cdr.markForCheck();\n    }\n  }\n\n  registerOnChange(fn: OnChangeType): void {\n    this.onChange = fn;\n  }\n\n  registerOnTouched(fn: OnTouchedType): void {\n    this.onTouched = fn;\n  }\n\n  setDisabledState(disabled: boolean): void {\n    this.nzDisabled = (this.isNzDisableFirstChange && this.nzDisabled) || disabled;\n    this.isNzDisableFirstChange = false;\n    if (this.nzDisabled) {\n      this.setOpenState(false);\n    }\n    this.cdr.markForCheck();\n  }\n\n  ngOnChanges({ nzOpen, nzDisabled, nzOptions, nzStatus, nzPlacement, nzSize, nzVariant }: SimpleChanges): void {\n    if (nzOpen) {\n      this.onOpenChange();\n    }\n    if (nzDisabled && this.nzDisabled) {\n      this.setOpenState(false);\n    }\n    if (nzOptions) {\n      this.isReactiveDriven = true;\n      const listOfOptions = this.nzOptions || [];\n      const listOfTransformedItem = listOfOptions.map(item => {\n        return {\n          template: item.label instanceof TemplateRef ? item.label : null,\n          nzTitle: this.getTitle(item.title, item.label),\n          nzLabel: typeof item.label === 'string' || typeof item.label === 'number' ? item.label : null,\n          nzValue: item.value,\n          nzDisabled: item.disabled || false,\n          nzHide: item.hide || false,\n          nzCustomContent: item.label instanceof TemplateRef,\n          groupLabel: item.groupLabel || null,\n          type: 'item',\n          key: item.key === undefined ? item.value : item.key\n        };\n      });\n      this.listOfTemplateItem$.next(listOfTransformedItem);\n    }\n    if (nzStatus) {\n      this.setStatusStyles(this.nzStatus, this.hasFeedback);\n    }\n    if (nzPlacement) {\n      const { currentValue } = nzPlacement;\n      this.dropdownPosition = currentValue as NzSelectPlacementType;\n      const listOfPlacement = ['bottomLeft', 'topLeft', 'bottomRight', 'topRight'];\n      if (currentValue && listOfPlacement.includes(currentValue)) {\n        this.positions = [POSITION_MAP[currentValue as POSITION_TYPE]];\n      } else {\n        this.positions = listOfPlacement.map(e => POSITION_MAP[e as POSITION_TYPE]);\n      }\n    }\n    if (nzSize) {\n      this.size.set(nzSize.currentValue);\n    }\n    if (nzVariant) {\n      this.variant.set(nzVariant.currentValue);\n    }\n  }\n\n  ngOnInit(): void {\n    this.nzFormStatusService?.formStatusChanges\n      .pipe(\n        distinctUntilChanged((pre, cur) => {\n          return pre.status === cur.status && pre.hasFeedback === cur.hasFeedback;\n        }),\n        withLatestFrom(this.nzFormNoStatusService ? this.nzFormNoStatusService.noFormStatus : observableOf(false)),\n        map(([{ status, hasFeedback }, noStatus]) => ({ status: noStatus ? '' : status, hasFeedback })),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(({ status, hasFeedback }) => {\n        this.setStatusStyles(status, hasFeedback);\n      });\n\n    this.focusMonitor\n      .monitor(this.host, true)\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(focusOrigin => {\n        if (!focusOrigin) {\n          this.focused = false;\n          this.cdr.markForCheck();\n          this.nzBlur.emit();\n          Promise.resolve().then(() => {\n            this.onTouched();\n          });\n        } else {\n          this.focused = true;\n          this.cdr.markForCheck();\n          this.nzFocus.emit();\n        }\n      });\n    combineLatest([this.listOfValue$, this.listOfTemplateItem$])\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(([listOfSelectedValue, listOfTemplateItem]) => {\n        const listOfTagItem = listOfSelectedValue\n          .filter(() => this.nzMode === 'tags')\n          .filter(value => listOfTemplateItem.findIndex(o => this.compareWith(o.nzValue, value)) === -1)\n          .map(\n            value => this.listOfTopItem.find(o => this.compareWith(o.nzValue, value)) || this.generateTagItem(value)\n          );\n        this.listOfTagAndTemplateItem = [...listOfTemplateItem, ...listOfTagItem];\n        this.listOfTopItem = this.listOfValue\n          .map(\n            v =>\n              [...this.listOfTagAndTemplateItem, ...this.listOfTopItem].find(item => this.compareWith(v, item.nzValue))!\n          )\n          .filter(item => !!item);\n        this.updateListOfContainerItem();\n      });\n\n    fromEventOutsideAngular(this.host.nativeElement, 'click')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(() => {\n        if ((this.nzOpen && this.nzShowSearch) || this.nzDisabled) {\n          return;\n        }\n\n        this.ngZone.run(() => this.setOpenState(!this.nzOpen));\n      });\n\n    // Caretaker note: we could've added this listener within the template `(overlayKeydown)=\"...\"`,\n    // but with this approach, it'll run change detection on each keyboard click, and also it'll run\n    // `markForCheck()` internally, which means the whole component tree (starting from the root and\n    // going down to the select component) will be re-checked and updated (if needed).\n    // This is safe to do that manually since `setOpenState()` calls `markForCheck()` if needed.\n    this.cdkConnectedOverlay.overlayKeydown.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(event => {\n      if (event.keyCode === ESCAPE) {\n        this.setOpenState(false);\n      }\n    });\n  }\n\n  ngAfterContentInit(): void {\n    if (!this.isReactiveDriven) {\n      merge(this.listOfNzOptionGroupComponent.changes, this.listOfNzOptionComponent.changes)\n        .pipe(\n          startWith(true),\n          switchMap(() =>\n            merge(\n              ...[\n                this.listOfNzOptionComponent.changes,\n                this.listOfNzOptionGroupComponent.changes,\n                ...this.listOfNzOptionComponent.map(option => option.changes),\n                ...this.listOfNzOptionGroupComponent.map(option => option.changes)\n              ]\n            ).pipe(startWith(true))\n          ),\n          takeUntilDestroyed(this.destroyRef)\n        )\n        .subscribe(() => {\n          const listOfOptionInterface = this.listOfNzOptionComponent.toArray().map(item => {\n            const { template, nzLabel, nzValue, nzKey, nzDisabled, nzHide, nzCustomContent, groupLabel } = item;\n            return {\n              template,\n              nzLabel,\n              nzValue,\n              nzDisabled,\n              nzHide,\n              nzCustomContent,\n              groupLabel,\n              nzTitle: this.getTitle(item.nzTitle, item.nzLabel),\n              type: 'item',\n              key: nzKey === undefined ? nzValue : nzKey\n            };\n          });\n          this.listOfTemplateItem$.next(listOfOptionInterface);\n          this.cdr.markForCheck();\n        });\n    }\n  }\n\n  private setStatusStyles(status: NzValidateStatus, hasFeedback: boolean): void {\n    this.status = status;\n    this.hasFeedback = hasFeedback;\n    this.cdr.markForCheck();\n    // render status if nzStatus is set\n    this.statusCls = getStatusClassNames(this.prefixCls, status, hasFeedback);\n    Object.keys(this.statusCls).forEach(status => {\n      if (this.statusCls[status]) {\n        this.renderer.addClass(this.host.nativeElement, status);\n      } else {\n        this.renderer.removeClass(this.host.nativeElement, status);\n      }\n    });\n  }\n\n  private getTitle(title: NzSelectOptionInterface['title'], label: NzSelectOptionInterface['label']): string {\n    let rawTitle: string = undefined!;\n    if (title === undefined) {\n      if (typeof label === 'string' || typeof label === 'number') {\n        rawTitle = label.toString();\n      }\n    } else if (typeof title === 'string' || typeof title === 'number') {\n      rawTitle = title.toString();\n    }\n\n    return rawTitle;\n  }\n}\n"
  },
  {
    "path": "components/select/select.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzOptionContainerComponent } from './option-container.component';\nimport { NzOptionGroupComponent } from './option-group.component';\nimport { NzOptionItemGroupComponent } from './option-item-group.component';\nimport { NzOptionItemComponent } from './option-item.component';\nimport { NzOptionComponent } from './option.component';\nimport { NzSelectArrowComponent } from './select-arrow.component';\nimport { NzSelectClearComponent } from './select-clear.component';\nimport { NzSelectItemComponent } from './select-item.component';\nimport { NzSelectPlaceholderComponent } from './select-placeholder.component';\nimport { NzSelectSearchComponent } from './select-search.component';\nimport { NzSelectTopControlComponent } from './select-top-control.component';\nimport { NzSelectComponent } from './select.component';\n\n@NgModule({\n  imports: [\n    NzOptionComponent,\n    NzSelectComponent,\n    NzOptionContainerComponent,\n    NzOptionGroupComponent,\n    NzOptionItemComponent,\n    NzSelectTopControlComponent,\n    NzSelectSearchComponent,\n    NzSelectItemComponent,\n    NzSelectClearComponent,\n    NzSelectArrowComponent,\n    NzSelectPlaceholderComponent,\n    NzOptionItemGroupComponent\n  ],\n  exports: [\n    NzOptionComponent,\n    NzSelectComponent,\n    NzOptionGroupComponent,\n    NzSelectArrowComponent,\n    NzSelectClearComponent,\n    NzSelectItemComponent,\n    NzSelectPlaceholderComponent,\n    NzSelectSearchComponent\n  ]\n})\nexport class NzSelectModule {}\n"
  },
  {
    "path": "components/select/select.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BACKSPACE, DOWN_ARROW, ENTER, ESCAPE, SPACE, TAB, UP_ARROW } from '@angular/cdk/keycodes';\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport {\n  ApplicationRef,\n  Component,\n  provideZoneChangeDetection,\n  signal,\n  TemplateRef,\n  ViewChild,\n  WritableSignal\n} from '@angular/core';\nimport { ComponentFixture, fakeAsync, flush, inject, TestBed, tick } from '@angular/core/testing';\nimport { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { NZ_FORM_SIZE, NZ_FORM_VARIANT } from 'ng-zorro-antd/core/form';\nimport { dispatchFakeEvent, dispatchKeyboardEvent, dispatchMouseEvent } from 'ng-zorro-antd/core/testing';\nimport { NzSafeAny, NzSizeLDSType, NzStatus, NzVariant } from 'ng-zorro-antd/core/types';\nimport { NzFormControlStatusType, NzFormModule } from 'ng-zorro-antd/form';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\nimport { NZ_SPACE_COMPACT_SIZE } from 'ng-zorro-antd/space';\n\nimport { NzSelectSearchComponent } from './select-search.component';\nimport { NzSelectTopControlComponent } from './select-top-control.component';\nimport { NzSelectComponent, NzSelectSizeType } from './select.component';\nimport { NzSelectModule } from './select.module';\nimport {\n  NzFilterOptionType,\n  NzSelectItemInterface,\n  NzSelectModeType,\n  NzSelectOptionInterface,\n  NzSelectPlacementType\n} from './select.types';\n\ndescribe('select', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideNoopAnimations(), provideZoneChangeDetection()]\n    });\n  });\n\n  describe('default template mode', () => {\n    let component: TestSelectTemplateDefaultComponent;\n    let fixture: ComponentFixture<TestSelectTemplateDefaultComponent>;\n    let selectElement!: HTMLElement;\n    let overlayContainerElement: HTMLElement;\n\n    function flushChanges(): void {\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n    }\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(TestSelectTemplateDefaultComponent);\n      component = fixture.componentInstance;\n      fixture.detectChanges();\n      selectElement = fixture.debugElement.query(By.directive(NzSelectComponent)).nativeElement;\n    });\n\n    beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n      overlayContainerElement = oc.getContainerElement();\n    }));\n\n    it('should classname correct', () => {\n      expect(selectElement.classList).toContain('ant-select');\n      expect(selectElement.classList).toContain('ant-select-single');\n    });\n\n    it('should nzSize work', () => {\n      component.nzSize = 'large';\n      fixture.detectChanges();\n      expect(selectElement.classList).toContain('ant-select-lg');\n      component.nzSize = 'small';\n      fixture.detectChanges();\n      expect(selectElement.classList).toContain('ant-select-sm');\n    });\n\n    it('should nzPlaceHolder work', () => {\n      expect(selectElement.querySelector('.ant-select-selection-placeholder')!.textContent!.trim()).toBe('');\n      component.nzPlaceHolder = 'placeholder';\n      fixture.detectChanges();\n      expect(selectElement.querySelector('.ant-select-selection-placeholder')!.textContent?.trim()).toContain(\n        'placeholder'\n      );\n    });\n\n    it('should nzDropdownRender work', () => {\n      component.nzOpen = true;\n      fixture.detectChanges();\n      expect(document.getElementsByClassName('dropdown-render').length).toBe(0);\n      component.nzDropdownRender = component.dropdownTemplate;\n      fixture.detectChanges();\n      expect(document.getElementsByClassName('dropdown-render')[0]!.textContent?.trim()).toBe('dropdownRender');\n    });\n\n    it('should ngModel match nzLabel', fakeAsync(() => {\n      component.listOfOption = [{ nzValue: 'test_value', nzLabel: 'test_label' }];\n      fixture.detectChanges();\n      expect(selectElement.querySelector('nz-select-item')).toBeFalsy();\n      component.value = 'test_value';\n      flushChanges();\n      expect(selectElement.querySelector('nz-select-item')!.textContent?.trim()).toBe('test_label');\n      component.listOfOption = [];\n      fixture.detectChanges();\n      expect(selectElement.querySelector('nz-select-item')!.textContent?.trim()).toBe('test_label');\n      expect(component.valueChange).not.toHaveBeenCalled();\n    }));\n\n    it('should ngModelChange trigger when click option', fakeAsync(() => {\n      component.listOfOption = [\n        { nzValue: 'test_01', nzLabel: 'test_01' },\n        { nzValue: 'test_02', nzLabel: 'test_02' }\n      ];\n      component.value = 'test_01';\n      component.nzOpen = true;\n      flushChanges();\n      const listOfContainerItem = document.querySelectorAll('nz-option-item');\n      dispatchMouseEvent(listOfContainerItem[1], 'click');\n      flushChanges();\n      expect(component.valueChange).toHaveBeenCalledTimes(1);\n      expect(component.valueChange).toHaveBeenCalledWith('test_02');\n      expect(component.openChange).toHaveBeenCalledTimes(1);\n      expect(component.openChange).toHaveBeenCalledWith(false);\n    }));\n\n    it('should ngModelChange trigger when click clear icon', fakeAsync(() => {\n      component.listOfOption = [{ nzValue: 'test_value', nzLabel: 'test_label' }];\n      component.value = 'test_value';\n      flushChanges();\n      expect(selectElement.querySelector('nz-select-clear')).toBeFalsy();\n      component.nzAllowClear = true;\n      fixture.detectChanges();\n      dispatchMouseEvent(selectElement.querySelector('nz-select-clear')!, 'click');\n      fixture.detectChanges();\n      expect(component.valueChange).toHaveBeenCalledTimes(1);\n      expect(component.valueChange).toHaveBeenCalledWith(null);\n    }));\n\n    it('should nzOpenChange trigger correct times', () => {\n      component.nzOpen = true;\n      fixture.detectChanges();\n      expect(component.openChange).not.toHaveBeenCalled();\n      const topSelectElement = selectElement.querySelector('.ant-select-selector')!;\n      dispatchFakeEvent(topSelectElement, 'click');\n      fixture.detectChanges();\n      expect(component.openChange).toHaveBeenCalledTimes(1);\n      expect(component.openChange).toHaveBeenCalledWith(false);\n      dispatchFakeEvent(topSelectElement, 'click');\n      fixture.detectChanges();\n      expect(component.openChange).toHaveBeenCalledTimes(2);\n      expect(component.openChange).toHaveBeenCalledWith(true);\n    });\n\n    it('should click input not close in searching mode', () => {\n      component.nzShowSearch = true;\n      fixture.detectChanges();\n      const topSelectElement = selectElement.querySelector('.ant-select-selector')!;\n      dispatchFakeEvent(topSelectElement, 'click');\n      fixture.detectChanges();\n      expect(component.openChange).toHaveBeenCalledTimes(1);\n      expect(component.openChange).toHaveBeenCalledWith(true);\n      dispatchFakeEvent(topSelectElement, 'click');\n      fixture.detectChanges();\n      expect(component.openChange).toHaveBeenCalledTimes(1);\n    });\n\n    it('should nzCustomTemplate works', fakeAsync(() => {\n      component.listOfOption = [{ nzValue: 'value', nzLabel: 'label' }];\n      fixture.detectChanges();\n      expect(selectElement.querySelector('nz-select-item')).toBeFalsy();\n      component.value = 'value';\n      component.nzCustomTemplate = component.customTemplate;\n      flushChanges();\n      expect(selectElement.querySelector('nz-select-item')!.textContent?.trim()).toBe('selected: label');\n    }));\n\n    it('should nzShowArrow works', () => {\n      expect(selectElement.querySelector('nz-select-arrow')).toBeTruthy();\n      component.nzShowArrow = false;\n      fixture.detectChanges();\n      expect(selectElement.querySelector('nz-select-arrow')).toBeFalsy();\n    });\n\n    it('should nzPrefix works', () => {\n      component.nzPrefix = 'prefix';\n      fixture.detectChanges();\n      expect(selectElement.querySelector('.ant-select-prefix')!.textContent?.trim()).toBe('prefix');\n\n      component.nzPrefix = component.affixTemplate;\n      fixture.detectChanges();\n      expect(selectElement.querySelector('.ant-select-prefix')!.textContent?.trim()).toBe('icon');\n    });\n\n    it('should nzSuffixIcon works', () => {\n      expect(selectElement.querySelector('.anticon-down')).toBeTruthy();\n      component.nzSuffixIcon = component.affixTemplate;\n      fixture.detectChanges();\n      expect(selectElement.querySelector('nz-select-arrow')!.textContent?.trim()).toBe('icon');\n    });\n\n    it('should nzClearIcon works', fakeAsync(() => {\n      component.nzAllowClear = true;\n      component.listOfOption = [{ nzValue: 'value', nzLabel: 'label' }];\n      component.value = 'value';\n      flushChanges();\n      expect(selectElement.querySelector('.anticon-close-circle')).toBeTruthy();\n      component.nzClearIcon = component.affixTemplate;\n      fixture.detectChanges();\n      expect(selectElement.querySelector('nz-select-clear')!.textContent?.trim()).toBe('icon');\n    }));\n\n    it('should nzShowSearch works', fakeAsync(() => {\n      component.listOfOption = [\n        { nzValue: 'test_01', nzLabel: 'test_01' },\n        { nzValue: 'test_02', nzLabel: 'test_02' }\n      ];\n      component.nzShowSearch = true;\n      component.nzOpen = true;\n      fixture.detectChanges();\n      const inputElement = selectElement.querySelector('input')!;\n      inputElement.value = 'test';\n      dispatchFakeEvent(inputElement, 'input');\n      flushChanges();\n      expect(component.searchValueChange).toHaveBeenCalledWith('test');\n      expect(document.querySelectorAll('nz-option-item').length).toBe(2);\n      inputElement.value = '02';\n      dispatchFakeEvent(inputElement, 'input');\n      flushChanges();\n      expect(document.querySelectorAll('nz-option-item').length).toBe(1);\n    }));\n\n    it('should nzFilterOption works', fakeAsync(() => {\n      component.listOfOption = [\n        { nzValue: 'test_01', nzLabel: 'test_01' },\n        { nzValue: 'test_02', nzLabel: 'test_02' },\n        { nzValue: 'test_03', nzLabel: 'test_03' }\n      ];\n      component.nzShowSearch = true;\n      component.nzFilterOption = () => true;\n      component.nzOpen = true;\n      fixture.detectChanges();\n      const inputElement = selectElement.querySelector('input')!;\n      inputElement.value = '02';\n      dispatchFakeEvent(inputElement, 'input');\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(document.querySelectorAll('nz-option-item').length).toBe(3);\n    }));\n\n    it('should compareWith works', fakeAsync(() => {\n      component.listOfOption = [{ nzValue: { value: 'test_value' }, nzLabel: 'test_label' }];\n      fixture.detectChanges();\n      expect(selectElement.querySelector('nz-select-item')).toBeFalsy();\n      component.value = { value: 'test_value' };\n      component.compareWith = (o1: NzSafeAny, o2: NzSafeAny) => (o1 && o2 ? o1.value === o2.value : o1 === o2);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(selectElement.querySelector('nz-select-item')!.textContent?.trim()).toBe('test_label');\n    }));\n\n    describe('should nzVariant works', () => {\n      it('filled', () => {\n        fixture.detectChanges();\n        expect(selectElement.classList).not.toContain('ant-select-filled');\n        component.nzVariant = 'filled';\n        fixture.detectChanges();\n        expect(selectElement.classList).toContain('ant-select-filled');\n      });\n\n      it('borderless', () => {\n        fixture.detectChanges();\n        expect(selectElement.classList).not.toContain('ant-select-borderless');\n        component.nzVariant = 'borderless';\n        fixture.detectChanges();\n        expect(selectElement.classList).toContain('ant-select-borderless');\n      });\n\n      it('underlined', () => {\n        fixture.detectChanges();\n        expect(selectElement.classList).not.toContain('ant-select-underlined');\n        component.nzVariant = 'underlined';\n        fixture.detectChanges();\n        expect(selectElement.classList).toContain('ant-select-underlined');\n      });\n    });\n\n    it('should nzAutoFocus works', () => {\n      component.nzAutoFocus = true;\n      fixture.detectChanges();\n      expect(selectElement.querySelector('input')!.attributes.getNamedItem('autofocus')!.name).toBe('autofocus');\n      component.nzAutoFocus = false;\n      fixture.detectChanges();\n      expect(selectElement.querySelector('input')!.attributes.getNamedItem('autofocus')).toBeFalsy();\n    });\n\n    it('should nzServerSearch works', fakeAsync(() => {\n      component.listOfOption = [\n        { nzValue: '1', nzLabel: '1' },\n        { nzValue: '2', nzLabel: '2' },\n        { nzValue: '3', nzLabel: '3' }\n      ];\n      component.nzServerSearch = true;\n      component.nzShowSearch = true;\n      component.nzOpen = true;\n      fixture.detectChanges();\n      const inputElement = selectElement.querySelector('input')!;\n      inputElement.value = '02';\n      dispatchFakeEvent(inputElement, 'input');\n      flushChanges();\n      expect(document.querySelectorAll('nz-option-item').length).toBe(3);\n    }));\n\n    it('should nzDisabled works', fakeAsync(() => {\n      component.nzDisabled = true;\n      flushChanges();\n      expect(selectElement.classList).toContain('ant-select-disabled');\n      expect(selectElement.querySelector('input')!.getAttribute('disabled')).toBe('');\n    }));\n\n    it('should nzTitle works', fakeAsync(() => {\n      component.listOfOption = [\n        { nzValue: '1', nzLabel: '1' },\n        { nzValue: '2', nzLabel: '2', nzTitle: '-' },\n        { nzValue: '3', nzLabel: '3', nzTitle: null }\n      ];\n      component.nzOpen = true;\n      flushChanges();\n      expect((document.querySelectorAll('nz-option-item')[0] as HTMLElement)?.title).toBe('1');\n      expect((document.querySelectorAll('nz-option-item')[1] as HTMLElement)?.title).toBe('-');\n      expect((document.querySelectorAll('nz-option-item')[2] as HTMLElement)?.title).toBeFalsy();\n    }));\n\n    it('should select option by enter', fakeAsync(() => {\n      component.listOfOption = [\n        { nzValue: 'value', nzLabel: 'label' },\n        { nzValue: 'disabledValue', nzLabel: 'disabledLabel', nzDisabled: true }\n      ];\n      component.nzShowSearch = true;\n      component.nzOpen = true;\n\n      fixture.detectChanges();\n      const inputElement = selectElement.querySelector('input')!;\n      inputElement.value = 'label';\n\n      dispatchFakeEvent(inputElement, 'input');\n      flushChanges();\n      expect(component.searchValueChange).toHaveBeenCalledWith('label');\n\n      dispatchKeyboardEvent(inputElement, 'keydown', ENTER, inputElement);\n      flushChanges();\n      expect(component.value).toBe('value');\n    }));\n\n    it('should nzDisabled option works', fakeAsync(() => {\n      component.listOfOption = [\n        { nzValue: 'value', nzLabel: 'label' },\n        { nzValue: 'disabledValue', nzLabel: 'disabledLabel', nzDisabled: true }\n      ];\n      component.nzShowSearch = true;\n      component.nzOpen = true;\n\n      fixture.detectChanges();\n      const inputElement = selectElement.querySelector('input')!;\n      inputElement.value = 'disabled';\n\n      dispatchFakeEvent(inputElement, 'input');\n      flushChanges();\n      expect(component.searchValueChange).toHaveBeenCalledWith('disabled');\n\n      dispatchKeyboardEvent(inputElement, 'keydown', ENTER, inputElement);\n      flushChanges();\n      expect(component.value).not.toBe('disabledValue');\n    }));\n\n    it('should nzBackdrop works', fakeAsync(() => {\n      component.nzOpen = true;\n      component.nzBackdrop = true;\n      flushChanges();\n      const boundingBox = overlayContainerElement.children[0];\n      expect(boundingBox.children[0].classList).toContain('cdk-overlay-backdrop');\n    }));\n\n    it('should close dropdown when ESC keydown', fakeAsync(() => {\n      component.nzOpen = true;\n      flushChanges();\n      dispatchKeyboardEvent(overlayContainerElement, 'keydown', ESCAPE, overlayContainerElement);\n      flushChanges();\n      expect(component.nzOpen).toBe(false);\n    }));\n\n    it('should keydown up arrow and down arrow', fakeAsync(() => {\n      component.listOfOption = [\n        { nzValue: 'value_01', nzLabel: 'label_01' },\n        { nzValue: 'value_02', nzLabel: 'label_02', nzDisabled: true },\n        { nzValue: 'value_03', nzLabel: 'label_03' }\n      ];\n      component.value = 'value_01';\n      component.nzOpen = true;\n      flushChanges();\n      const inputElement = selectElement.querySelector('input')!;\n      dispatchKeyboardEvent(inputElement, 'keydown', UP_ARROW, inputElement);\n      flushChanges();\n      expect(document.querySelectorAll('nz-option-item')[2]!.classList).toContain('ant-select-item-option-active');\n      dispatchKeyboardEvent(inputElement, 'keydown', DOWN_ARROW, inputElement);\n      flushChanges();\n      expect(document.querySelectorAll('nz-option-item')[0]!.classList).toContain('ant-select-item-option-active');\n      dispatchKeyboardEvent(inputElement, 'keydown', DOWN_ARROW, inputElement);\n      flushChanges();\n      dispatchKeyboardEvent(inputElement, 'keydown', ENTER, inputElement);\n      flushChanges();\n      expect(component.valueChange).toHaveBeenCalledWith('value_03');\n      flushChanges();\n      dispatchKeyboardEvent(inputElement, 'keydown', SPACE, inputElement);\n      flushChanges();\n      expect(component.openChange).toHaveBeenCalledWith(false);\n      dispatchKeyboardEvent(inputElement, 'keydown', SPACE, inputElement);\n      flushChanges();\n      expect(component.openChange).toHaveBeenCalledWith(true);\n      dispatchKeyboardEvent(inputElement, 'keydown', TAB, inputElement);\n      flushChanges();\n      expect(component.openChange).toHaveBeenCalledWith(false);\n      expect(component.openChange).toHaveBeenCalledTimes(3);\n    }));\n\n    it('should not throw error with keydown up arrow and down arrow event when listOfOption is empty', fakeAsync(() => {\n      component.listOfOption = [];\n      component.nzOpen = true;\n      flushChanges();\n      const inputElement = selectElement.querySelector('input')!;\n      dispatchKeyboardEvent(inputElement, 'keydown', UP_ARROW, inputElement);\n      flushChanges();\n      dispatchKeyboardEvent(inputElement, 'keydown', DOWN_ARROW, inputElement);\n      flushChanges();\n      expect(component.valueChange).toHaveBeenCalledTimes(0);\n    }));\n\n    it('should mouseenter activated option work', fakeAsync(() => {\n      component.listOfOption = [\n        { nzValue: 'value_01', nzLabel: 'label_01' },\n        { nzValue: 'value_02', nzLabel: 'label_02', nzDisabled: true },\n        { nzValue: 'value_03', nzLabel: 'label_03' }\n      ];\n      component.nzOpen = true;\n      flushChanges();\n      const targetItem = document.querySelectorAll('nz-option-item')[2]!;\n      expect(targetItem.classList).not.toContain('ant-select-item-option-active');\n      dispatchFakeEvent(targetItem, 'mouseenter');\n      flushChanges();\n      expect(targetItem.classList).toContain('ant-select-item-option-active');\n    }));\n\n    it('should group item change work', fakeAsync(() => {\n      component.listOfGroup = [{ nzLabel: 'group-1', children: [{ nzValue: 'value_01', nzLabel: 'label_01' }] }];\n      component.nzOpen = true;\n      flushChanges();\n      expect(document.querySelectorAll('nz-option-item')!.length).toBe(1);\n      expect(document.querySelectorAll('nz-option-item-group')!.length).toBe(1);\n      component.listOfGroup = [\n        {\n          nzLabel: 'group-1',\n          children: [\n            { nzValue: 'value_01', nzLabel: 'label_01' },\n            { nzValue: 'value_02', nzLabel: 'label_02' }\n          ]\n        },\n        {\n          nzLabel: 'group-2',\n          children: [{ nzValue: 'value_03', nzLabel: 'label_03' }]\n        }\n      ];\n      flushChanges();\n      expect(document.querySelectorAll('nz-option-item')!.length).toBe(3);\n      expect(document.querySelectorAll('nz-option-item-group')!.length).toBe(2);\n      expect(document.querySelectorAll('nz-option-item-group')[0]!.textContent?.trim()).toBe('group-1');\n      expect(document.querySelectorAll('nz-option-item')[0].textContent?.trim()).toBe('label_01');\n      component.listOfGroup[0].nzLabel = 'change-group';\n      component.listOfGroup[0].children[0].nzLabel = 'change-label';\n      fixture.detectChanges();\n      expect(document.querySelectorAll('nz-option-item-group')[0]!.textContent?.trim()).toBe('change-group');\n      expect(document.querySelectorAll('nz-option-item')[0].textContent?.trim()).toBe('change-label');\n    }));\n\n    it('should group item sort be right', fakeAsync(() => {\n      component.listOfGroup = [\n        {\n          nzLabel: 'group-1',\n          children: [\n            { nzValue: 'value_01', nzLabel: 'label_01' },\n            { nzValue: 'value_02', nzLabel: 'label_02' }\n          ]\n        },\n        {\n          nzLabel: 'group-2',\n          children: [\n            { nzValue: 'value_03', nzLabel: 'label_03' },\n            { nzValue: 'value_04', nzLabel: 'label_04' }\n          ]\n        }\n      ];\n      component.nzOpen = true;\n      flushChanges();\n      expect(\n        document\n          .querySelectorAll('nz-option-item')[0]\n          .parentElement!.querySelector('nz-option-item')!\n          .nextElementSibling!.textContent?.trim()\n      ).toBe('label_02');\n    }));\n\n    it('should have selected class if item was selected', fakeAsync(() => {\n      component.listOfOption = [\n        { nzValue: 0, nzLabel: 'Falsy value' },\n        { nzValue: 'Truthy value', nzLabel: 'Truthy value' },\n        { nzValue: 'disabled', nzLabel: 'disabled', nzDisabled: true },\n        { nzValue: undefined, nzLabel: 'undefined' },\n        { nzValue: null, nzLabel: 'null' }\n      ];\n      component.nzOpen = true;\n      component.value = 0;\n      flushChanges();\n      expect(document.querySelectorAll('nz-option-item.ant-select-item-option-selected').length).toBe(1);\n      expect(document.querySelectorAll('nz-option-item.ant-select-item-option-selected')[0].textContent?.trim()).toBe(\n        'Falsy value'\n      );\n      component.value = 'Truthy value';\n      flushChanges();\n      expect(document.querySelectorAll('nz-option-item.ant-select-item-option-selected').length).toBe(1);\n      expect(document.querySelectorAll('nz-option-item.ant-select-item-option-selected')[0].textContent?.trim()).toBe(\n        'Truthy value'\n      );\n      ['disabled', undefined, null].forEach(value => {\n        component.value = value;\n        flushChanges();\n        expect(document.querySelectorAll('nz-option-item.ant-select-item-option-selected').length).toBe(0);\n      });\n    }));\n\n    it('should select item on TAB when nzSelectOnTab is true', fakeAsync(() => {\n      component.nzSelectOnTab = true;\n      component.listOfOption = [\n        { nzValue: 'value_01', nzLabel: 'label_01' },\n        { nzValue: 'value_02', nzLabel: 'label_02' },\n        { nzValue: 'value_03', nzLabel: 'label_03' }\n      ];\n      component.nzOpen = true;\n      flushChanges();\n      const inputElement = selectElement.querySelector('input')!;\n      dispatchKeyboardEvent(inputElement, 'keydown', TAB, inputElement);\n      flushChanges();\n      expect(component.valueChange).toHaveBeenCalledWith('value_01');\n      flushChanges();\n      expect(component.openChange).toHaveBeenCalledWith(false);\n      expect(component.openChange).toHaveBeenCalledTimes(1);\n    }));\n\n    it('should close select and keep the same value on TAB when nzSelectOnTab is default(false)', fakeAsync(() => {\n      component.listOfOption = [\n        { nzValue: 'value_01', nzLabel: 'label_01' },\n        { nzValue: 'value_02', nzLabel: 'label_02' },\n        { nzValue: 'value_03', nzLabel: 'label_03' }\n      ];\n      component.value = 'value_02';\n      component.nzOpen = true;\n      flushChanges();\n      const inputElement = selectElement.querySelector('input')!;\n      dispatchKeyboardEvent(inputElement, 'keydown', TAB, inputElement);\n      flushChanges();\n      expect(component.valueChange).not.toHaveBeenCalled();\n      flushChanges();\n      expect(component.openChange).toHaveBeenCalledWith(false);\n      expect(component.openChange).toHaveBeenCalledTimes(1);\n    }));\n  });\n\n  describe('multiple template mode', () => {\n    let component: TestSelectTemplateMultipleComponent;\n    let fixture: ComponentFixture<TestSelectTemplateMultipleComponent>;\n    let selectElement!: HTMLElement;\n    let overlayContainerElement: HTMLElement;\n\n    function flushChanges(): void {\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n    }\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(TestSelectTemplateMultipleComponent);\n      component = fixture.componentInstance;\n      selectElement = fixture.debugElement.query(By.directive(NzSelectComponent)).nativeElement;\n      fixture.detectChanges();\n      overlayContainerElement = TestBed.inject(OverlayContainer).getContainerElement();\n    });\n\n    it('should classname correct', () => {\n      expect(selectElement.classList).toContain('ant-select-multiple');\n    });\n\n    it('should ngModel works', fakeAsync(() => {\n      component.listOfOption = [\n        { nzValue: 'value_01', nzLabel: 'label_01' },\n        { nzValue: 'value_02', nzLabel: 'label_02' }\n      ];\n      component.value = ['value_01', 'value_02'];\n      flushChanges();\n      let listOfSelectItem = selectElement.querySelectorAll('nz-select-item')!;\n      expect(listOfSelectItem.length).toBe(2);\n      expect(listOfSelectItem[0].textContent?.trim()).toBe('label_01');\n      expect(listOfSelectItem[1].textContent?.trim()).toBe('label_02');\n      component.listOfOption = [{ nzValue: 'value_01', nzLabel: 'label_01' }];\n      fixture.detectChanges();\n      listOfSelectItem = selectElement.querySelectorAll('nz-select-item')!;\n      expect(listOfSelectItem.length).toBe(2);\n      expect(listOfSelectItem[0].textContent?.trim()).toBe('label_01');\n      expect(listOfSelectItem[1].textContent?.trim()).toBe('label_02');\n      expect(component.valueChange).not.toHaveBeenCalled();\n    }));\n\n    it('should click option work', fakeAsync(() => {\n      component.nzOpen = true;\n      component.listOfOption = [\n        { nzValue: 'test_01', nzLabel: 'test_01' },\n        { nzValue: 'test_02', nzLabel: 'test_02' }\n      ];\n      component.value = ['test_01'];\n      flushChanges();\n      const listOfContainerItem = document.querySelectorAll('nz-option-item');\n      dispatchMouseEvent(listOfContainerItem[1], 'click');\n      flushChanges();\n      expect(component.valueChange).toHaveBeenCalledTimes(1);\n      expect(component.value.length).toBe(2);\n      dispatchMouseEvent(listOfContainerItem[1], 'click');\n      flushChanges();\n      expect(component.valueChange).toHaveBeenCalledTimes(2);\n      expect(component.value.length).toBe(1);\n      expect(component.value[0]).toBe('test_01');\n      expect(component.openChange).not.toHaveBeenCalled();\n    }));\n\n    it('should compareWith works', fakeAsync(() => {\n      component.listOfOption = [{ nzValue: { value: 'value' }, nzLabel: 'label' }];\n      fixture.detectChanges();\n      expect(selectElement.querySelectorAll('nz-select-item').length).toBe(0);\n      component.value = [{ value: 'value' }];\n      component.compareWith = (o1: NzSafeAny, o2: NzSafeAny) => (o1 && o2 ? o1.value === o2.value : o1 === o2);\n      flushChanges();\n      expect(selectElement.querySelectorAll('nz-select-item').length).toBe(1);\n      expect(selectElement.querySelectorAll('nz-select-item')[0].textContent?.trim()).toBe('label');\n    }));\n\n    it('should nzMenuItemSelectedIcon works', fakeAsync(() => {\n      component.listOfOption = [{ nzValue: 'value', nzLabel: 'label' }];\n      component.value = ['value'];\n      component.nzOpen = true;\n      flushChanges();\n      expect(document.querySelectorAll('.ant-select-selected-icon').length).toBe(1);\n      component.nzMenuItemSelectedIcon = component.iconTemplate;\n      fixture.detectChanges();\n      expect(document.querySelectorAll('.ant-select-selected-icon').length).toBe(0);\n      expect(document.querySelector('.ant-select-item-option-state')!.textContent?.trim()).toBe('icon');\n    }));\n\n    it('should removeIcon works', fakeAsync(() => {\n      component.listOfOption = [{ nzValue: 'value', nzLabel: 'label' }];\n      component.value = ['value'];\n      flushChanges();\n      expect(selectElement.querySelector('.anticon-close')).toBeTruthy();\n      component.nzRemoveIcon = component.iconTemplate;\n      fixture.detectChanges();\n      expect(selectElement.querySelector('.ant-select-selection-item-remove')!.textContent?.trim()).toBe('icon');\n    }));\n\n    it('should removeIcon click works', fakeAsync(() => {\n      component.listOfOption = [{ nzValue: 'value', nzLabel: 'label' }];\n      component.value = ['value'];\n      flushChanges();\n      dispatchFakeEvent(selectElement.querySelector('.anticon-close')!, 'click');\n      flushChanges();\n      expect(component.value.length).toBe(0);\n    }));\n\n    it('should backspace works', fakeAsync(() => {\n      component.listOfOption = [{ nzValue: 'value', nzLabel: 'label' }];\n      component.value = ['value'];\n      flushChanges();\n      const inputElement = selectElement.querySelector('input')!;\n      dispatchKeyboardEvent(inputElement, 'keydown', BACKSPACE, inputElement);\n      flushChanges();\n      expect(component.value.length).toBe(0);\n    }));\n\n    it('should nzTokenSeparators work', fakeAsync(() => {\n      component.listOfOption = [\n        { nzValue: 'test_01', nzLabel: 'label_01' },\n        { nzValue: 'test_02', nzLabel: 'label_02' }\n      ];\n      component.value = [];\n      component.nzTokenSeparators = [','];\n      flushChanges();\n      const inputElement = selectElement.querySelector('input')!;\n      inputElement.value = 'label_01,test_02';\n      dispatchFakeEvent(inputElement, 'input');\n      flushChanges();\n      expect(component.value.length).toBe(1);\n      expect(component.value[0]).toBe('test_01');\n    }));\n\n    it('should nzMaxMultipleCount work', fakeAsync(() => {\n      component.nzOpen = true;\n      component.listOfOption = [\n        { nzValue: 'test_01', nzLabel: 'test_01' },\n        { nzValue: 'test_02', nzLabel: 'test_02' }\n      ];\n      component.value = [];\n      component.nzMaxMultipleCount = 1;\n      flushChanges();\n      const listOfContainerItem = document.querySelectorAll('nz-option-item');\n      dispatchMouseEvent(listOfContainerItem[0], 'click');\n      flushChanges();\n      expect(component.value.length).toBe(1);\n      dispatchMouseEvent(listOfContainerItem[1], 'click');\n      flushChanges();\n      expect(component.value.length).toBe(1);\n      expect(component.value[0]).toBe('test_01');\n    }));\n\n    it('should nzAutoClearSearchValue work', fakeAsync(() => {\n      component.nzOpen = true;\n      component.listOfOption = [\n        { nzValue: 'test_01', nzLabel: 'test_01' },\n        { nzValue: 'test_02', nzLabel: 'test_02' }\n      ];\n      flushChanges();\n      const listOfContainerItem = document.querySelectorAll('nz-option-item');\n      const inputElement = selectElement.querySelector('input')!;\n      inputElement.value = 'test';\n      dispatchFakeEvent(inputElement, 'input');\n      dispatchMouseEvent(listOfContainerItem[0], 'click');\n      flushChanges();\n      expect(inputElement.value).toBe('');\n      component.nzAutoClearSearchValue = false;\n      flushChanges();\n      inputElement.value = 'test';\n      dispatchFakeEvent(inputElement, 'input');\n      dispatchMouseEvent(listOfContainerItem[0], 'click');\n      flushChanges();\n      expect(inputElement.value).toBe('test');\n    }));\n\n    it('should nzAutoClearSearchValue work when cdkOverlay send emit close', fakeAsync(() => {\n      component.nzOpen = true;\n      component.listOfOption = [\n        { nzValue: 'test_01', nzLabel: 'test_01' },\n        { nzValue: 'test_02', nzLabel: 'test_02' }\n      ];\n      flushChanges();\n      const listOfContainerItem = document.querySelectorAll('nz-option-item');\n      const inputElement = selectElement.querySelector('input')!;\n      inputElement.value = 'test';\n      dispatchFakeEvent(inputElement, 'input');\n      dispatchMouseEvent(listOfContainerItem[0], 'click');\n      flushChanges();\n      expect(inputElement.value).toBe('');\n      component.nzAutoClearSearchValue = false;\n      flushChanges();\n      inputElement.value = 'test';\n      dispatchFakeEvent(inputElement, 'input');\n      dispatchKeyboardEvent(overlayContainerElement, 'keydown', ESCAPE, overlayContainerElement);\n      flushChanges();\n      expect(inputElement.value).toBe('test');\n    }));\n  });\n\n  describe('tags template mode', () => {\n    let component: TestSelectTemplateTagsComponent;\n    let fixture: ComponentFixture<TestSelectTemplateTagsComponent>;\n    let selectElement!: HTMLElement;\n\n    function flushChanges(): void {\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n    }\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(TestSelectTemplateTagsComponent);\n      component = fixture.componentInstance;\n      fixture.detectChanges();\n      selectElement = fixture.debugElement.query(By.directive(NzSelectComponent)).nativeElement;\n    });\n\n    it('should classname correct', () => {\n      expect(selectElement.classList).toContain('ant-select-multiple');\n    });\n\n    it('should nzTokenSeparators works', fakeAsync(() => {\n      component.listOfOption = [\n        { nzValue: 'test_01', nzLabel: 'label_01' },\n        { nzValue: 'test_02', nzLabel: 'label_02' }\n      ];\n      component.value = [];\n      component.nzTokenSeparators = [','];\n      flushChanges();\n      const inputElement = selectElement.querySelector('input')!;\n      inputElement.value = 'label_01,test_02';\n      dispatchFakeEvent(inputElement, 'input');\n      flushChanges();\n      expect(component.value.length).toBe(2);\n      expect(component.value[0]).toBe('test_01');\n      expect(component.value[1]).toBe('test_02');\n    }));\n\n    it('should nzMaxTagCount works', fakeAsync(() => {\n      component.listOfOption = [\n        { nzValue: 'test_01', nzLabel: 'label_01' },\n        { nzValue: 'test_02', nzLabel: 'label_02' },\n        { nzValue: 'test_03', nzLabel: 'label_03' },\n        { nzValue: 'test_04', nzLabel: 'label_04' }\n      ];\n      component.value = ['test_01', 'test_02', 'test_03', 'test_04'];\n      component.nzMaxTagCount = 2;\n      flushChanges();\n      const listOfItem = selectElement.querySelectorAll('nz-select-item');\n      expect(listOfItem.length).toBe(3);\n      expect(listOfItem[2].querySelector('.ant-select-selection-item-content')!.textContent?.trim()).toBe('+ 2 ...');\n      component.nzMaxTagPlaceholder = component.tagTemplate;\n      fixture.detectChanges();\n      expect(listOfItem[2].textContent?.trim()).toBe('and 2 more selected');\n    }));\n  });\n\n  describe('default reactive mode', () => {\n    let component: TestSelectReactiveDefaultComponent;\n    let fixture: ComponentFixture<TestSelectReactiveDefaultComponent>;\n    let selectElement!: HTMLElement;\n\n    function flushChanges(): void {\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n    }\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(TestSelectReactiveDefaultComponent);\n      component = fixture.componentInstance;\n      fixture.detectChanges();\n      selectElement = fixture.debugElement.query(By.directive(NzSelectComponent)).nativeElement;\n    });\n\n    it('should ngModel match nzLabel', fakeAsync(() => {\n      component.listOfOption = [{ value: 'test_value', label: 'test_label' }];\n      fixture.detectChanges();\n      expect(selectElement.querySelector('nz-select-item')).toBeFalsy();\n      component.value = 'test_value';\n      flushChanges();\n      expect(selectElement.querySelector('nz-select-item')!.textContent?.trim()).toBe('test_label');\n      component.listOfOption = [];\n      fixture.detectChanges();\n      expect(selectElement.querySelector('nz-select-item')!.textContent?.trim()).toBe('test_label');\n      expect(component.valueChange).not.toHaveBeenCalled();\n    }));\n\n    it('should ngModelChange trigger when click option', fakeAsync(() => {\n      component.listOfOption = [\n        { value: 'test_01', label: 'test_01' },\n        { value: 'test_02', label: 'test_02' }\n      ];\n      component.value = 'test_01';\n      component.nzOpen = true;\n      flushChanges();\n      const listOfContainerItem = document.querySelectorAll('nz-option-item');\n      dispatchMouseEvent(listOfContainerItem[1], 'click');\n      flushChanges();\n      expect(component.valueChange).toHaveBeenCalledTimes(1);\n      expect(component.valueChange).toHaveBeenCalledWith('test_02');\n      expect(component.openChange).toHaveBeenCalledTimes(1);\n      expect(component.openChange).toHaveBeenCalledWith(false);\n    }));\n\n    it('should ngModelChange trigger when click clear icon', fakeAsync(() => {\n      component.listOfOption = [{ value: 'test_value', label: 'test_label' }];\n      component.value = 'test_value';\n      flushChanges();\n      expect(selectElement.querySelector('nz-select-clear')).toBeFalsy();\n      component.nzAllowClear = true;\n      fixture.detectChanges();\n      dispatchMouseEvent(selectElement.querySelector('nz-select-clear')!, 'click');\n      fixture.detectChanges();\n      expect(component.valueChange).toHaveBeenCalledTimes(1);\n      expect(component.valueChange).toHaveBeenCalledWith(null);\n    }));\n\n    it('should call the event emitter nzOnClear when click on te clear icon', fakeAsync(() => {\n      component.listOfOption = [{ value: 'test_value', label: 'test_label' }];\n      component.value = 'test_value';\n      flushChanges();\n      expect(selectElement.querySelector('nz-select-clear')).toBeFalsy();\n      component.nzAllowClear = true;\n      fixture.detectChanges();\n      dispatchMouseEvent(selectElement.querySelector('nz-select-clear')!, 'click');\n      fixture.detectChanges();\n      expect(component.onClear).toHaveBeenCalled();\n    }));\n\n    it('should nzCustomTemplate works', fakeAsync(() => {\n      component.listOfOption = [{ value: 'value', label: 'label' }];\n      fixture.detectChanges();\n      expect(selectElement.querySelector('nz-select-item')).toBeFalsy();\n      component.value = 'value';\n      component.nzCustomTemplate = component.customTemplate;\n      flushChanges();\n      expect(selectElement.querySelector('nz-select-item')!.textContent?.trim()).toBe('selected: label');\n    }));\n\n    it('should nzShowSearch works', fakeAsync(() => {\n      component.listOfOption = [\n        { value: 'test_01', label: 'test_01' },\n        { value: 'test_02', label: 'test_02' }\n      ];\n      component.nzShowSearch = true;\n      component.nzOpen = true;\n      fixture.detectChanges();\n      const inputElement = selectElement.querySelector('input')!;\n      inputElement.value = 'test';\n      dispatchFakeEvent(inputElement, 'input');\n      flushChanges();\n      expect(component.searchValueChange).toHaveBeenCalledWith('test');\n      expect(document.querySelectorAll('nz-option-item').length).toBe(2);\n      inputElement.value = '02';\n      dispatchFakeEvent(inputElement, 'input');\n      flushChanges();\n      expect(document.querySelectorAll('nz-option-item').length).toBe(1);\n    }));\n\n    it('should nzFilterOption works', fakeAsync(() => {\n      component.listOfOption = [\n        { value: 'test_01', label: 'test_01' },\n        { value: 'test_02', label: 'test_02' },\n        { value: 'test_03', label: 'test_03' }\n      ];\n      component.nzShowSearch = true;\n      component.nzFilterOption = () => true;\n      component.nzOpen = true;\n      fixture.detectChanges();\n      const inputElement = selectElement.querySelector('input')!;\n      inputElement.value = '02';\n      dispatchFakeEvent(inputElement, 'input');\n      flushChanges();\n      expect(document.querySelectorAll('nz-option-item').length).toBe(3);\n    }));\n\n    it('should compareWith works', fakeAsync(() => {\n      component.listOfOption = [{ value: { value: 'test_value' }, label: 'test_label' }];\n      fixture.detectChanges();\n      expect(selectElement.querySelector('nz-select-item')).toBeFalsy();\n      component.value = { value: 'test_value' };\n      component.compareWith = (o1: NzSafeAny, o2: NzSafeAny) => (o1 && o2 ? o1.value === o2.value : o1 === o2);\n      flushChanges();\n      expect(selectElement.querySelector('nz-select-item')!.textContent?.trim()).toBe('test_label');\n    }));\n\n    it('should nzServerSearch works', fakeAsync(() => {\n      component.listOfOption = [\n        { value: '1', label: '1' },\n        { value: '2', label: '2' },\n        { value: '3', label: '3' }\n      ];\n      component.nzServerSearch = true;\n      component.nzShowSearch = true;\n      component.nzOpen = true;\n      fixture.detectChanges();\n      const inputElement = selectElement.querySelector('input')!;\n      inputElement.value = '02';\n      dispatchFakeEvent(inputElement, 'input');\n      flushChanges();\n      expect(document.querySelectorAll('nz-option-item').length).toBe(3);\n    }));\n\n    it('should keydown up arrow and down arrow', fakeAsync(() => {\n      component.listOfOption = [\n        { value: 'value_01', label: 'label_01' },\n        { value: 'value_02', label: 'label_02', disabled: true },\n        { value: 'value_03', label: 'label_03' }\n      ];\n      component.value = 'value_01';\n      component.nzOpen = true;\n      flushChanges();\n      const inputElement = selectElement.querySelector('input')!;\n      dispatchKeyboardEvent(inputElement, 'keydown', UP_ARROW, inputElement);\n      flushChanges();\n      expect(document.querySelectorAll('nz-option-item')[2]!.classList).toContain('ant-select-item-option-active');\n      dispatchKeyboardEvent(inputElement, 'keydown', DOWN_ARROW, inputElement);\n      flushChanges();\n      expect(document.querySelectorAll('nz-option-item')[0]!.classList).toContain('ant-select-item-option-active');\n      dispatchKeyboardEvent(inputElement, 'keydown', DOWN_ARROW, inputElement);\n      flushChanges();\n      dispatchKeyboardEvent(inputElement, 'keydown', ENTER, inputElement);\n      flushChanges();\n      expect(component.valueChange).toHaveBeenCalledWith('value_03');\n      flushChanges();\n      dispatchKeyboardEvent(inputElement, 'keydown', SPACE, inputElement);\n      flushChanges();\n      expect(component.openChange).toHaveBeenCalledWith(false);\n      dispatchKeyboardEvent(inputElement, 'keydown', SPACE, inputElement);\n      flushChanges();\n      expect(component.openChange).toHaveBeenCalledWith(true);\n      dispatchKeyboardEvent(inputElement, 'keydown', TAB, inputElement);\n      flushChanges();\n      expect(component.openChange).toHaveBeenCalledWith(false);\n      expect(component.openChange).toHaveBeenCalledTimes(3);\n    }));\n\n    it('should mouseenter activated option work', fakeAsync(() => {\n      component.listOfOption = [\n        { value: 'value_01', label: 'label_01' },\n        { value: 'value_02', label: 'label_02', disabled: true },\n        { value: 'value_03', label: 'label_03' }\n      ];\n      component.nzOpen = true;\n      flushChanges();\n      const targetItem = document.querySelectorAll('nz-option-item')[2]!;\n      expect(targetItem.classList).not.toContain('ant-select-item-option-active');\n      dispatchFakeEvent(targetItem, 'mouseenter');\n      flushChanges();\n      expect(targetItem.classList).toContain('ant-select-item-option-active');\n    }));\n\n    it('should group item change work', fakeAsync(() => {\n      component.listOfOption = [{ groupLabel: 'group-1', value: 'value_01', label: 'label_01' }];\n      component.nzOpen = true;\n      flushChanges();\n      expect(document.querySelectorAll('nz-option-item')!.length).toBe(1);\n      expect(document.querySelectorAll('nz-option-item-group')!.length).toBe(1);\n      component.listOfOption = [\n        { value: 'value_01', label: 'label_01', groupLabel: 'group-1' },\n        { value: 'value_02', label: 'label_02', groupLabel: 'group-1' },\n        { value: 'value_03', label: 'label_03', groupLabel: 'group-2' }\n      ];\n      flushChanges();\n      expect(document.querySelectorAll('nz-option-item')!.length).toBe(3);\n      expect(document.querySelectorAll('nz-option-item-group')!.length).toBe(2);\n      expect(document.querySelectorAll('nz-option-item-group')[0]!.textContent?.trim()).toBe('group-1');\n      expect(document.querySelectorAll('nz-option-item')[0].textContent?.trim()).toBe('label_01');\n      component.listOfOption = [{ groupLabel: 'change-group', value: 'value_01', label: 'change-label' }];\n\n      fixture.detectChanges();\n      expect(document.querySelectorAll('nz-option-item-group')[0]!.textContent?.trim()).toBe('change-group');\n      expect(document.querySelectorAll('nz-option-item')[0].textContent?.trim()).toBe('change-label');\n    }));\n\n    it('should nzAutoClearSearchValue in default mode not work when set to false', fakeAsync(() => {\n      component.nzOpen = true;\n      component.listOfOption = [\n        { value: 'test_01', label: 'test_01' },\n        { value: 'test_02', label: 'test_02' }\n      ];\n      component.nzAutoClearSearchValue = false;\n      flushChanges();\n      const listOfContainerItem = document.querySelectorAll('nz-option-item');\n      const inputElement = selectElement.querySelector('input')!;\n\n      flushChanges();\n      inputElement.value = 'test';\n      dispatchFakeEvent(inputElement, 'input');\n      dispatchMouseEvent(listOfContainerItem[0], 'click');\n      flushChanges();\n      expect(inputElement.value).toBe('');\n    }));\n\n    it('should group item sort be right', fakeAsync(() => {\n      component.listOfOption = [\n        { value: 'value_01', label: 'label_01', groupLabel: 'group-1' },\n        { value: 'value_02', label: 'label_02', groupLabel: 'group-1' },\n        { value: 'value_03', label: 'label_03', groupLabel: 'group-2' },\n        { value: 'value_04', label: 'label_04', groupLabel: 'group-2' }\n      ];\n      component.nzOpen = true;\n      flushChanges();\n      expect(\n        document\n          .querySelectorAll('nz-option-item')[0]\n          .parentElement!.querySelector('nz-option-item')!\n          .nextElementSibling!.textContent?.trim()\n      ).toBe('label_02');\n    }));\n  });\n\n  describe('multiple reactive mode', () => {\n    let component: TestSelectReactiveMultipleComponent;\n    let fixture: ComponentFixture<TestSelectReactiveMultipleComponent>;\n    let selectComponent: NzSelectComponent;\n    let selectElement!: HTMLElement;\n    let overlayContainerElement: HTMLElement;\n\n    function flushChanges(): void {\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n    }\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(TestSelectReactiveMultipleComponent);\n      component = fixture.componentInstance;\n      fixture.detectChanges();\n      selectComponent = fixture.debugElement.query(By.directive(NzSelectComponent)).componentInstance;\n      selectElement = fixture.debugElement.query(By.directive(NzSelectComponent)).nativeElement;\n      overlayContainerElement = TestBed.inject(OverlayContainer).getContainerElement();\n    });\n\n    it('should ngModel works', fakeAsync(() => {\n      component.listOfOption = [\n        { value: 'value_01', label: 'label_01' },\n        { value: 'value_02', label: 'label_02' }\n      ];\n      component.value = ['value_01', 'value_02'];\n      flushChanges();\n      let listOfSelectItem = selectElement.querySelectorAll('nz-select-item')!;\n      expect(listOfSelectItem.length).toBe(2);\n      expect(listOfSelectItem[0].textContent?.trim()).toBe('label_01');\n      expect(listOfSelectItem[1].textContent?.trim()).toBe('label_02');\n      component.listOfOption = [{ value: 'value_01', label: 'label_01' }];\n      fixture.detectChanges();\n      listOfSelectItem = selectElement.querySelectorAll('nz-select-item')!;\n      expect(listOfSelectItem.length).toBe(2);\n      expect(listOfSelectItem[0].textContent?.trim()).toBe('label_01');\n      expect(listOfSelectItem[1].textContent?.trim()).toBe('label_02');\n      expect(component.valueChange).not.toHaveBeenCalled();\n    }));\n\n    it('should click option work', fakeAsync(() => {\n      component.nzOpen = true;\n      component.listOfOption = [\n        { value: 'test_01', label: 'test_01' },\n        { value: 'test_02', label: 'test_02' }\n      ];\n      component.value = ['test_01'];\n      flushChanges();\n      const listOfContainerItem = document.querySelectorAll('nz-option-item');\n      dispatchMouseEvent(listOfContainerItem[1], 'click');\n      flushChanges();\n      expect(component.valueChange).toHaveBeenCalledTimes(1);\n      expect(component.value.length).toBe(2);\n      dispatchMouseEvent(listOfContainerItem[1], 'click');\n      flushChanges();\n      expect(component.valueChange).toHaveBeenCalledTimes(2);\n      expect(component.value.length).toBe(1);\n      expect(component.value[0]).toBe('test_01');\n      expect(component.openChange).not.toHaveBeenCalled();\n    }));\n\n    it('should compareWith works', fakeAsync(() => {\n      component.listOfOption = [{ value: { value: 'value' }, label: 'label' }];\n      fixture.detectChanges();\n      expect(selectElement.querySelectorAll('nz-select-item').length).toBe(0);\n      component.value = [{ value: 'value' }];\n      component.compareWith = (o1: NzSafeAny, o2: NzSafeAny) => (o1 && o2 ? o1.value === o2.value : o1 === o2);\n      flushChanges();\n      expect(selectElement.querySelectorAll('nz-select-item').length).toBe(1);\n      expect(selectElement.querySelectorAll('nz-select-item')[0].textContent?.trim()).toBe('label');\n    }));\n\n    it('should nzMenuItemSelectedIcon works', fakeAsync(() => {\n      component.listOfOption = [{ value: 'value', label: 'label' }];\n      component.value = ['value'];\n      component.nzOpen = true;\n      flushChanges();\n      expect(document.querySelectorAll('.ant-select-selected-icon').length).toBe(1);\n      component.nzMenuItemSelectedIcon = component.iconTemplate;\n      fixture.detectChanges();\n      expect(document.querySelectorAll('.ant-select-selected-icon').length).toBe(0);\n      expect(document.querySelector('.ant-select-item-option-state')!.textContent?.trim()).toBe('icon');\n    }));\n\n    it('should removeIcon works', fakeAsync(() => {\n      component.listOfOption = [{ value: 'value', label: 'label' }];\n      component.value = ['value'];\n      flushChanges();\n      expect(selectElement.querySelector('.anticon-close')).toBeTruthy();\n      component.nzRemoveIcon = component.iconTemplate;\n      fixture.detectChanges();\n      expect(selectElement.querySelector('.ant-select-selection-item-remove')!.textContent?.trim()).toBe('icon');\n    }));\n\n    it('should removeIcon click works', fakeAsync(() => {\n      component.listOfOption = [{ value: 'value', label: 'label' }];\n      component.value = ['value'];\n      flushChanges();\n      dispatchFakeEvent(selectElement.querySelector('.anticon-close')!, 'click');\n      flushChanges();\n      expect(component.value.length).toBe(0);\n    }));\n\n    it('should backspace works', fakeAsync(() => {\n      component.listOfOption = [{ value: 'value', label: 'label' }];\n      component.value = ['value'];\n      flushChanges();\n      const inputElement = selectElement.querySelector('input')!;\n      dispatchKeyboardEvent(inputElement, 'keydown', BACKSPACE, inputElement);\n      flushChanges();\n      expect(component.value.length).toBe(0);\n    }));\n\n    it('should nzTokenSeparators work', fakeAsync(() => {\n      component.listOfOption = [\n        { value: 'test_01', label: 'label_01' },\n        { value: 'test_02', label: 'label_02' }\n      ];\n      component.value = [];\n      component.nzTokenSeparators = [','];\n      flushChanges();\n      const inputElement = selectElement.querySelector('input')!;\n      inputElement.value = 'label_01,test_02';\n      dispatchFakeEvent(inputElement, 'input');\n      flushChanges();\n      expect(component.value.length).toBe(1);\n      expect(component.value[0]).toBe('test_01');\n    }));\n\n    it('should nzTokenSeparators + nzMaxMultipleCount work', fakeAsync(() => {\n      component.nzMaxMultipleCount = 1;\n      component.listOfOption = [\n        { value: 'test_01', label: 'label_01' },\n        { value: 'test_02', label: 'label_02' }\n      ];\n      component.value = [];\n      component.nzTokenSeparators = [','];\n      flushChanges();\n      const inputElement = selectElement.querySelector('input')!;\n      inputElement.value = 'label_01,label_02';\n      dispatchFakeEvent(inputElement, 'input');\n      flushChanges();\n      expect(component.value.length).toBe(1);\n      expect(component.value[0]).toBe('test_01');\n    }));\n\n    it('should nzMaxMultipleCount work', fakeAsync(() => {\n      component.nzOpen = true;\n      component.listOfOption = [\n        { value: 'test_01', label: 'test_01' },\n        { value: 'test_02', label: 'test_02' }\n      ];\n      component.value = [];\n      component.nzMaxMultipleCount = 1;\n      flushChanges();\n      const listOfContainerItem = document.querySelectorAll('nz-option-item');\n      dispatchMouseEvent(listOfContainerItem[0], 'click');\n      flushChanges();\n      expect(component.value.length).toBe(1);\n      dispatchMouseEvent(listOfContainerItem[1], 'click');\n      flushChanges();\n      expect(component.value.length).toBe(1);\n      expect(component.value[0]).toBe('test_01');\n      expect(listOfContainerItem[1]).toHaveClass('ant-select-item-option-disabled');\n    }));\n\n    it('should isMaxMultipleCountSet work correct', () => {\n      component.nzMaxMultipleCount = Infinity;\n      fixture.detectChanges();\n      expect(selectComponent.isMaxMultipleCountSet).toBeFalsy();\n\n      component.nzMaxMultipleCount = 1;\n      fixture.detectChanges();\n      expect(selectComponent.isMaxMultipleCountSet).toBeTruthy();\n\n      component.nzMode = 'default';\n      fixture.detectChanges();\n      expect(selectComponent.isMaxMultipleCountSet).toBeFalsy();\n    });\n\n    it('should isMaxMultipleCountReached be set correctly when click options', fakeAsync(() => {\n      component.nzOpen = true;\n      component.listOfOption = [\n        { value: 'test_01', label: 'test_01' },\n        { value: 'test_02', label: 'test_02' }\n      ];\n      component.value = [];\n      component.nzMaxMultipleCount = 1;\n      flushChanges();\n      expect(selectComponent.isMaxMultipleCountReached).toBeFalsy();\n      const listOfContainerItem = document.querySelectorAll('nz-option-item');\n      dispatchMouseEvent(listOfContainerItem[0], 'click');\n      flushChanges();\n      expect(selectComponent.isMaxMultipleCountReached).toBeTruthy();\n    }));\n\n    it('should isMaxMultipleCountReached be set correctly when change the ng model value', fakeAsync(() => {\n      const options = [\n        { value: 'test_01', label: 'test_01' },\n        { value: 'test_02', label: 'test_02' }\n      ];\n      component.nzOpen = true;\n      component.listOfOption = options;\n      component.value = [];\n      component.nzMaxMultipleCount = 1;\n      flushChanges();\n      const listOfContainerItem = document.querySelectorAll('nz-option-item');\n      expect(selectComponent.isMaxMultipleCountReached).toBeFalsy();\n      selectComponent.writeValue([options[0]]);\n      flushChanges();\n      expect(selectComponent.isMaxMultipleCountReached).toBeTruthy();\n      expect(listOfContainerItem[1]).toHaveClass('ant-select-item-option-disabled');\n      selectComponent.writeValue([]);\n      flushChanges();\n      expect(selectComponent.isMaxMultipleCountReached).toBeFalsy();\n      expect(listOfContainerItem[0]).not.toHaveClass('ant-select-item-option-disabled');\n      expect(listOfContainerItem[1]).not.toHaveClass('ant-select-item-option-disabled');\n    }));\n\n    it('should show nzShowArrow component when nzMaxMultipleCount is not Infinity', () => {\n      component.nzMaxMultipleCount = 1;\n      fixture.detectChanges();\n      expect(selectElement.querySelector('nz-select-arrow')).toBeTruthy();\n    });\n\n    it('should nzAutoClearSearchValue work', fakeAsync(() => {\n      component.nzOpen = true;\n      component.listOfOption = [\n        { value: 'test_01', label: 'test_01' },\n        { value: 'test_02', label: 'test_02' }\n      ];\n      flushChanges();\n      const listOfContainerItem = document.querySelectorAll('nz-option-item');\n      const inputElement = selectElement.querySelector('input')!;\n      inputElement.value = 'test';\n      dispatchFakeEvent(inputElement, 'input');\n      dispatchMouseEvent(listOfContainerItem[0], 'click');\n      flushChanges();\n      expect(inputElement.value).toBe('');\n      component.nzAutoClearSearchValue = false;\n      flushChanges();\n      inputElement.value = 'test';\n      dispatchFakeEvent(inputElement, 'input');\n      dispatchMouseEvent(listOfContainerItem[0], 'click');\n      flushChanges();\n      expect(inputElement.value).toBe('test');\n    }));\n\n    it('should nzAutoClearSearchValue work when cdkOverlay send emit close', fakeAsync(() => {\n      component.nzOpen = true;\n      component.listOfOption = [\n        { value: 'test_01', label: 'test_01' },\n        { value: 'test_02', label: 'test_02' }\n      ];\n      flushChanges();\n      const listOfContainerItem = document.querySelectorAll('nz-option-item');\n      const inputElement = selectElement.querySelector('input')!;\n      inputElement.value = 'test';\n      dispatchFakeEvent(inputElement, 'input');\n      dispatchMouseEvent(listOfContainerItem[0], 'click');\n      flushChanges();\n      expect(inputElement.value).toBe('');\n      component.nzAutoClearSearchValue = false;\n      flushChanges();\n      inputElement.value = 'test';\n      dispatchFakeEvent(inputElement, 'input');\n      dispatchKeyboardEvent(overlayContainerElement, 'keydown', ESCAPE, overlayContainerElement);\n      fixture.detectChanges();\n      flushChanges();\n      fixture.detectChanges();\n      expect(inputElement.value).toBe('test');\n    }));\n  });\n\n  describe('tags reactive mode', () => {\n    let component: TestSelectReactiveTagsComponent;\n    let fixture: ComponentFixture<TestSelectReactiveTagsComponent>;\n    let selectElement!: HTMLElement;\n\n    function flushChanges(): void {\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n    }\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(TestSelectReactiveTagsComponent);\n      component = fixture.componentInstance;\n      fixture.detectChanges();\n      selectElement = fixture.debugElement.query(By.directive(NzSelectComponent)).nativeElement;\n    });\n\n    it('should nzTokenSeparators works', fakeAsync(() => {\n      component.listOfOption = [\n        { value: 'test_01', label: 'label_01' },\n        { value: 'test_02', label: 'label_02' }\n      ];\n      component.value = [];\n      component.nzTokenSeparators = [','];\n      flushChanges();\n      const inputElement = selectElement.querySelector('input')!;\n      inputElement.value = 'label_01,test_02';\n      dispatchFakeEvent(inputElement, 'input');\n      flushChanges();\n      expect(component.value.length).toBe(2);\n      expect(component.value[0]).toBe('test_01');\n      expect(component.value[1]).toBe('test_02');\n    }));\n\n    it('should nzTokenSeparators + nzMaxMultipleCount work', fakeAsync(() => {\n      component.nzMaxMultipleCount = 1;\n      component.listOfOption = [\n        { value: 'test_01', label: 'label_01' },\n        { value: 'test_02', label: 'label_02' }\n      ];\n      component.value = [];\n      component.nzTokenSeparators = [','];\n      flushChanges();\n      const inputElement = selectElement.querySelector('input')!;\n      inputElement.value = 'label_01,label_02';\n      dispatchFakeEvent(inputElement, 'input');\n      flushChanges();\n      expect(component.value.length).toBe(1);\n      expect(component.value[0]).toBe('test_01');\n    }));\n\n    it('should nzMaxTagCount works', fakeAsync(() => {\n      component.listOfOption = [\n        { value: 'test_01', label: 'label_01' },\n        { value: 'test_02', label: 'label_02' },\n        { value: 'test_03', label: 'label_03' },\n        { value: 'test_04', label: 'label_04' }\n      ];\n      component.value = ['test_01', 'test_02', 'test_03', 'test_04'];\n      component.nzMaxTagCount = 2;\n      flushChanges();\n      const listOfItem = selectElement.querySelectorAll('nz-select-item');\n      expect(listOfItem.length).toBe(3);\n      expect(listOfItem[2].querySelector('.ant-select-selection-item-content')!.textContent?.trim()).toBe('+ 2 ...');\n      component.nzMaxTagPlaceholder = component.tagTemplate;\n      fixture.detectChanges();\n      expect(listOfItem[2].textContent?.trim()).toBe('and 2 more selected');\n    }));\n  });\n\n  describe('change detection', () => {\n    let component: TestSelectTemplateDefaultComponent;\n    let fixture: ComponentFixture<TestSelectTemplateDefaultComponent>;\n    let selectComponent: NzSelectComponent;\n    let overlayContainerElement: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(TestSelectTemplateDefaultComponent);\n      component = fixture.componentInstance;\n      fixture.detectChanges();\n      selectComponent = fixture.debugElement.query(By.directive(NzSelectComponent)).componentInstance;\n    });\n\n    beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n      overlayContainerElement = oc.getContainerElement();\n    }));\n\n    it('should not run change detection if the `triggerWidth` has not been changed', fakeAsync(() => {\n      const detectChangesSpy = spyOn(selectComponent['cdr'], 'detectChanges').and.callThrough();\n      // const requestAnimationFrameSpy = spyOn(window, 'requestAnimationFrame').and.callThrough(); this test is totally unstable, depends upon the order of execution\n\n      component.nzOpen = true;\n      fixture.detectChanges();\n      // The `requestAnimationFrame` is simulated as `setTimeout(..., 16)` inside the `fakeAsync`.\n      tick(16);\n\n      dispatchKeyboardEvent(overlayContainerElement, 'keydown', ESCAPE, overlayContainerElement);\n      fixture.detectChanges();\n      flush();\n\n      expect(component.nzOpen).toEqual(false);\n\n      component.nzOpen = true;\n      fixture.detectChanges();\n      tick(16);\n\n      // Ensure that the `detectChanges()` have been called only once since the `triggerWidth` hasn't been changed.\n      expect(detectChangesSpy).toHaveBeenCalledTimes(1);\n      // expect(requestAnimationFrameSpy).toHaveBeenCalledTimes(2);\n    }));\n\n    it('should not run change detection when `nz-select-top-control` is clicked and should focus the `nz-select-search`', () => {\n      const appRef = TestBed.inject(ApplicationRef);\n      spyOn(appRef, 'tick');\n\n      const nzSelectSearch = fixture.debugElement.query(By.directive(NzSelectSearchComponent));\n      spyOn(nzSelectSearch.componentInstance, 'focus');\n\n      const nzSelectTopControl = fixture.debugElement.query(By.directive(NzSelectTopControlComponent));\n      dispatchMouseEvent(nzSelectTopControl.nativeElement, 'click');\n\n      expect(appRef.tick).toHaveBeenCalledTimes(0);\n      expect(nzSelectSearch.componentInstance.focus).toHaveBeenCalled();\n    });\n\n    it('should not run change detection when non-backspace button is pressed on the `nz-select-top-control`', () => {\n      const appRef = TestBed.inject(ApplicationRef);\n      spyOn(appRef, 'tick');\n\n      const nzSelectTopControl = fixture.debugElement.query(By.directive(NzSelectTopControlComponent));\n      dispatchKeyboardEvent(nzSelectTopControl.nativeElement, 'keydown', TAB, nzSelectTopControl.nativeElement);\n\n      expect(appRef.tick).toHaveBeenCalledTimes(0);\n    });\n  });\n\n  describe('status', () => {\n    let component: TestSelectStatusComponent;\n    let fixture: ComponentFixture<TestSelectStatusComponent>;\n    let selectElement!: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(TestSelectStatusComponent);\n      component = fixture.componentInstance;\n      fixture.detectChanges();\n      selectElement = fixture.debugElement.query(By.directive(NzSelectComponent)).nativeElement;\n    });\n\n    it('should classname correct', () => {\n      fixture.detectChanges();\n      expect(selectElement.classList).toContain('ant-select-status-error');\n\n      component.status = 'warning';\n      fixture.detectChanges();\n      expect(selectElement.classList).toContain('ant-select-status-warning');\n\n      component.status = '';\n      fixture.detectChanges();\n      expect(selectElement.classList).not.toContain('ant-select-status-warning');\n    });\n  });\n\n  describe('in form', () => {\n    let component: TestSelectInFormComponent;\n    let fixture: ComponentFixture<TestSelectInFormComponent>;\n\n    function flushChanges(): void {\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n    }\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(TestSelectInFormComponent);\n      component = fixture.componentInstance;\n      fixture.detectChanges();\n    });\n\n    it('should classname correct and be disable initially', () => {\n      const selectElement = fixture.debugElement.query(By.directive(NzSelectComponent)).nativeElement;\n      const inputElement = fixture.debugElement.query(By.css('input')).nativeElement as HTMLInputElement;\n\n      expect(inputElement.disabled).toBeFalsy();\n      expect(selectElement.classList).not.toContain('ant-select-disabled');\n      expect(selectElement.classList).toContain('ant-select-status-error');\n      expect(selectElement.classList).toContain('ant-select-in-form-item');\n      expect(selectElement.querySelector('nz-form-item-feedback-icon')).toBeTruthy();\n\n      component.status = 'warning';\n      fixture.detectChanges();\n      expect(selectElement.classList).toContain('ant-select-status-warning');\n\n      component.status = 'success';\n      fixture.detectChanges();\n      expect(selectElement.classList).toContain('ant-select-status-success');\n\n      component.feedback = false;\n      fixture.detectChanges();\n      expect(selectElement.querySelector('nz-form-item-feedback-icon')).toBeNull();\n    });\n\n    it('should be disable by default even if form is enable', fakeAsync(() => {\n      component.disabled = true;\n      flushChanges();\n      const selectElement = fixture.debugElement.query(By.directive(NzSelectComponent)).nativeElement;\n      const inputElement = fixture.debugElement.query(By.css('input')).nativeElement as HTMLInputElement;\n      expect(inputElement.disabled).toBeTruthy();\n      expect(selectElement.classList).toContain('ant-select-disabled');\n    }));\n\n    it('should be disable if form is disabled and nzDisabled set to false', fakeAsync(() => {\n      component.disable();\n      flushChanges();\n      const selectElement = fixture.debugElement.query(By.directive(NzSelectComponent)).nativeElement;\n      const inputElement = fixture.debugElement.query(By.css('input')).nativeElement as HTMLInputElement;\n      expect(inputElement.disabled).toBeTruthy();\n      expect(selectElement.classList).toContain('ant-select-disabled');\n    }));\n  });\n\n  describe('placement', () => {\n    let component: TestSelectTemplateDefaultComponent;\n    let fixture: ComponentFixture<TestSelectTemplateDefaultComponent>;\n    let overlayContainerElement: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(TestSelectTemplateDefaultComponent);\n      component = fixture.componentInstance;\n      fixture.detectChanges();\n    });\n\n    beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n      overlayContainerElement = oc.getContainerElement();\n    }));\n\n    it('should nzPlacement work', fakeAsync(() => {\n      component.nzOpen = true;\n      fixture.detectChanges();\n      let element = overlayContainerElement.querySelector('.ant-select-dropdown') as HTMLElement;\n      expect(element.classList.contains('ant-select-dropdown-placement-bottomLeft')).toBe(true);\n      expect(element.classList.contains('ant-select-dropdown-placement-bottomRight')).toBe(false);\n      expect(element.classList.contains('ant-select-dropdown-placement-topLeft')).toBe(false);\n      expect(element.classList.contains('ant-select-dropdown-placement-topRight')).toBe(false);\n      component.nzOpen = false;\n      component.nzPlacement = 'bottomRight';\n      fixture.detectChanges();\n      component.nzOpen = true;\n      tick();\n      fixture.detectChanges();\n      element = overlayContainerElement.querySelector('.ant-select-dropdown') as HTMLElement;\n      expect(element.classList.contains('ant-select-dropdown-placement-bottomLeft')).toBe(false);\n      expect(element.classList.contains('ant-select-dropdown-placement-bottomRight')).toBe(true);\n      expect(element.classList.contains('ant-select-dropdown-placement-topLeft')).toBe(false);\n      expect(element.classList.contains('ant-select-dropdown-placement-topRight')).toBe(false);\n      component.nzOpen = false;\n      component.nzPlacement = 'topLeft';\n      fixture.detectChanges();\n      component.nzOpen = true;\n      tick();\n      fixture.detectChanges();\n      element = overlayContainerElement.querySelector('.ant-select-dropdown') as HTMLElement;\n      expect(element.classList.contains('ant-select-dropdown-placement-bottomLeft')).toBe(false);\n      expect(element.classList.contains('ant-select-dropdown-placement-bottomRight')).toBe(false);\n      expect(element.classList.contains('ant-select-dropdown-placement-topLeft')).toBe(true);\n      expect(element.classList.contains('ant-select-dropdown-placement-topRight')).toBe(false);\n      component.nzOpen = false;\n      component.nzPlacement = 'topRight';\n      fixture.detectChanges();\n      component.nzOpen = true;\n      tick();\n      fixture.detectChanges();\n      element = overlayContainerElement.querySelector('.ant-select-dropdown') as HTMLElement;\n      expect(element.classList.contains('ant-select-dropdown-placement-bottomLeft')).toBe(false);\n      expect(element.classList.contains('ant-select-dropdown-placement-bottomRight')).toBe(false);\n      expect(element.classList.contains('ant-select-dropdown-placement-topLeft')).toBe(false);\n      expect(element.classList.contains('ant-select-dropdown-placement-topRight')).toBe(true);\n      component.nzOpen = false;\n      fixture.detectChanges();\n      flush();\n    }));\n  });\n});\n\ndescribe('select finalSize', () => {\n  let fixture: ComponentFixture<TestSelectFinalSizeComponent>;\n  let selectElement: HTMLElement;\n  let compactSizeSignal: WritableSignal<NzSizeLDSType>;\n  let formSizeSignal: WritableSignal<NzSizeLDSType>;\n\n  beforeEach(() => {\n    compactSizeSignal = signal<NzSizeLDSType>('large');\n    formSizeSignal = signal<NzSizeLDSType>('default');\n  });\n  afterEach(() => {\n    TestBed.resetTestingModule();\n  });\n\n  it('should set correctly the size from the formSize signal', () => {\n    TestBed.configureTestingModule({\n      providers: [\n        { provide: NZ_FORM_SIZE, useValue: formSizeSignal },\n        { provide: NZ_SPACE_COMPACT_SIZE, useValue: compactSizeSignal }\n      ]\n    });\n    fixture = TestBed.createComponent(TestSelectFinalSizeComponent);\n    selectElement = fixture.debugElement.query(By.directive(NzSelectComponent)).nativeElement;\n    fixture.detectChanges();\n    formSizeSignal.set('large');\n    fixture.detectChanges();\n    expect(selectElement.classList).toContain('ant-select-lg');\n  });\n  it('should set correctly the size from the compactSize signal', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_SPACE_COMPACT_SIZE, useValue: compactSizeSignal }]\n    });\n    fixture = TestBed.createComponent(TestSelectFinalSizeComponent);\n    selectElement = fixture.debugElement.query(By.directive(NzSelectComponent)).nativeElement;\n    fixture.detectChanges();\n    expect(selectElement.classList).toContain('ant-select-lg');\n  });\n  it('should set correctly the size from the component input', () => {\n    fixture = TestBed.createComponent(TestSelectFinalSizeComponent);\n    selectElement = fixture.debugElement.query(By.directive(NzSelectComponent)).nativeElement;\n    fixture.componentInstance.size = 'large';\n    fixture.detectChanges();\n    expect(selectElement.classList).toContain('ant-select-lg');\n  });\n});\n\ndescribe('select finalVariant', () => {\n  let fixture: ComponentFixture<TestSelectFinalVariantComponent>;\n  let selectElement: HTMLElement;\n  let formVariantSignal: WritableSignal<NzVariant>;\n\n  beforeEach(() => {\n    formVariantSignal = signal<NzVariant>('outlined');\n  });\n\n  afterEach(() => {\n    TestBed.resetTestingModule();\n  });\n\n  it('should use formVariant when nzVariant is not set (undefined by default)', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_FORM_VARIANT, useValue: formVariantSignal }]\n    });\n    fixture = TestBed.createComponent(TestSelectFinalVariantComponent);\n    selectElement = fixture.debugElement.query(By.directive(NzSelectComponent)).nativeElement;\n    fixture.detectChanges();\n    formVariantSignal.set('filled');\n    fixture.detectChanges();\n    expect(selectElement.classList).toContain('ant-select-filled');\n  });\n\n  it('should use nzVariant over formVariant when nzVariant is explicitly set', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_FORM_VARIANT, useValue: formVariantSignal }]\n    });\n    fixture = TestBed.createComponent(TestSelectFinalVariantComponent);\n    selectElement = fixture.debugElement.query(By.directive(NzSelectComponent)).nativeElement;\n    fixture.componentInstance.variant.set('borderless');\n    fixture.detectChanges();\n    formVariantSignal.set('filled');\n    fixture.detectChanges();\n    expect(selectElement.classList).toContain('ant-select-borderless');\n    expect(selectElement.classList).not.toContain('ant-select-filled');\n  });\n\n  it('should use nzVariant outlined over formVariant when explicitly set', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_FORM_VARIANT, useValue: formVariantSignal }]\n    });\n    fixture = TestBed.createComponent(TestSelectFinalVariantComponent);\n    selectElement = fixture.debugElement.query(By.directive(NzSelectComponent)).nativeElement;\n    fixture.componentInstance.variant.set('outlined');\n    fixture.detectChanges();\n    formVariantSignal.set('filled');\n    fixture.detectChanges();\n    expect(selectElement.classList).not.toContain('ant-select-filled');\n  });\n\n  it('should use nzVariant when no formVariant is provided', () => {\n    fixture = TestBed.createComponent(TestSelectFinalVariantComponent);\n    selectElement = fixture.debugElement.query(By.directive(NzSelectComponent)).nativeElement;\n    fixture.componentInstance.variant.set('filled');\n    fixture.detectChanges();\n    expect(selectElement.classList).toContain('ant-select-filled');\n  });\n\n  it('should default to outlined when neither nzVariant nor formVariant is set', () => {\n    fixture = TestBed.createComponent(TestSelectFinalVariantComponent);\n    selectElement = fixture.debugElement.query(By.directive(NzSelectComponent)).nativeElement;\n    fixture.detectChanges();\n    expect(selectElement.classList).not.toContain('ant-select-filled');\n    expect(selectElement.classList).not.toContain('ant-select-borderless');\n    expect(selectElement.classList).not.toContain('ant-select-underlined');\n  });\n});\n\n@Component({\n  imports: [FormsModule, NzSelectModule],\n  template: `\n    <nz-select\n      nzMode=\"default\"\n      [(ngModel)]=\"value\"\n      [nzSize]=\"nzSize\"\n      [nzDropdownMatchSelectWidth]=\"nzDropdownMatchSelectWidth\"\n      [nzPlaceHolder]=\"nzPlaceHolder\"\n      [nzDropdownRender]=\"nzDropdownRender\"\n      [nzCustomTemplate]=\"nzCustomTemplate ?? null\"\n      [nzPrefix]=\"nzPrefix\"\n      [nzSuffixIcon]=\"nzSuffixIcon\"\n      [nzClearIcon]=\"nzClearIcon\"\n      [nzShowArrow]=\"nzShowArrow\"\n      [nzFilterOption]=\"nzFilterOption\"\n      [compareWith]=\"compareWith\"\n      [nzAllowClear]=\"nzAllowClear\"\n      [nzVariant]=\"nzVariant\"\n      [nzShowSearch]=\"nzShowSearch\"\n      [nzLoading]=\"nzLoading\"\n      [nzAutoFocus]=\"nzAutoFocus\"\n      [nzServerSearch]=\"nzServerSearch\"\n      [nzDisabled]=\"nzDisabled\"\n      [nzBackdrop]=\"nzBackdrop\"\n      [(nzOpen)]=\"nzOpen\"\n      [nzPlacement]=\"nzPlacement\"\n      [nzSelectOnTab]=\"nzSelectOnTab\"\n      [nzMaxMultipleCount]=\"nzMaxMultipleCount\"\n      (ngModelChange)=\"valueChange($event)\"\n      (nzOnSearch)=\"searchValueChange($event)\"\n      (nzOpenChange)=\"openChange($event)\"\n    >\n      @for (o of listOfOption; track o) {\n        <nz-option\n          [nzValue]=\"o.nzValue\"\n          [nzLabel]=\"o.nzLabel\"\n          [nzTitle]=\"o.nzTitle\"\n          [nzDisabled]=\"o.nzDisabled\"\n          [nzHide]=\"o.nzHide\"\n        />\n      }\n      @for (group of listOfGroup; track group) {\n        <nz-option-group [nzLabel]=\"group.nzLabel\">\n          @for (o of group.children; track o) {\n            <nz-option\n              [nzValue]=\"o.nzValue\"\n              [nzLabel]=\"o.nzLabel\"\n              [nzTitle]=\"o.nzTitle\"\n              [nzDisabled]=\"o.nzDisabled\"\n              [nzHide]=\"o.nzHide\"\n            />\n          }\n        </nz-option-group>\n      }\n    </nz-select>\n    <ng-template #dropdownTemplate><div class=\"dropdown-render\">dropdownRender</div></ng-template>\n    <ng-template #customTemplate let-selected>selected: {{ selected.nzLabel }}</ng-template>\n    <ng-template #affixTemplate>icon</ng-template>\n  `\n})\nexport class TestSelectTemplateDefaultComponent {\n  @ViewChild('dropdownTemplate') dropdownTemplate!: TemplateRef<NzSafeAny>;\n  @ViewChild('customTemplate') customTemplate!: TemplateRef<NzSafeAny>;\n  @ViewChild('affixTemplate') affixTemplate!: TemplateRef<NzSafeAny>;\n  value: NzSafeAny | null = null;\n  valueChange = jasmine.createSpy<NzSafeAny>('valueChange');\n  openChange = jasmine.createSpy<NzSafeAny>('openChange');\n  searchValueChange = jasmine.createSpy<NzSafeAny>('searchValueChange');\n  listOfGroup: Array<{ nzLabel: string | TemplateRef<NzSafeAny> | null; children: NzSelectItemInterface[] }> = [];\n  listOfOption: NzSelectItemInterface[] = [];\n  nzSize: NzSelectSizeType = 'default';\n  nzDropdownMatchSelectWidth = true;\n  nzPlaceHolder: string | TemplateRef<NzSafeAny> | null = null;\n  nzDropdownRender: TemplateRef<NzSafeAny> | null = null;\n  nzCustomTemplate?: TemplateRef<{ $implicit: NzSelectItemInterface }>;\n  nzPrefix: string | TemplateRef<NzSafeAny> | null = null;\n  nzSuffixIcon: string | TemplateRef<NzSafeAny> | null = null;\n  nzClearIcon: TemplateRef<NzSafeAny> | null = null;\n  nzShowArrow = true;\n  nzMaxMultipleCount: number = Infinity;\n  nzFilterOption: NzFilterOptionType = (searchValue: string, item: NzSelectItemInterface): boolean => {\n    if (item && item.nzLabel) {\n      return item.nzLabel.toString().toLowerCase().indexOf(searchValue.toLowerCase()) > -1;\n    } else {\n      return false;\n    }\n  };\n  compareWith: (o1: NzSafeAny, o2: NzSafeAny) => boolean = (o1: NzSafeAny, o2: NzSafeAny) => o1 === o2;\n  nzAllowClear = false;\n  nzVariant: NzVariant | undefined = undefined;\n  nzShowSearch = false;\n  nzLoading = false;\n  nzAutoFocus = false;\n  nzServerSearch = false;\n  nzDisabled = false;\n  nzOpen = false;\n  nzBackdrop = false;\n  nzSelectOnTab = false;\n  nzPlacement: NzSelectPlacementType | null = 'bottomLeft';\n}\n\n@Component({\n  imports: [FormsModule, NzSelectModule],\n  template: `\n    <nz-select\n      nzMode=\"multiple\"\n      [(ngModel)]=\"value\"\n      [nzMenuItemSelectedIcon]=\"nzMenuItemSelectedIcon\"\n      [nzTokenSeparators]=\"nzTokenSeparators\"\n      [nzRemoveIcon]=\"nzRemoveIcon\"\n      [nzMaxMultipleCount]=\"nzMaxMultipleCount\"\n      [compareWith]=\"compareWith\"\n      [nzAutoClearSearchValue]=\"nzAutoClearSearchValue\"\n      [(nzOpen)]=\"nzOpen\"\n      (ngModelChange)=\"valueChange($event)\"\n      (nzOpenChange)=\"valueChange($event)\"\n    >\n      @for (o of listOfOption; track o) {\n        <nz-option [nzValue]=\"o.nzValue\" [nzLabel]=\"o.nzLabel\" [nzDisabled]=\"o.nzDisabled\" [nzHide]=\"o.nzHide\" />\n      }\n    </nz-select>\n    <ng-template #iconTemplate>icon</ng-template>\n  `\n})\nexport class TestSelectTemplateMultipleComponent {\n  @ViewChild('iconTemplate') iconTemplate!: TemplateRef<NzSafeAny>;\n  listOfOption: NzSelectItemInterface[] = [];\n  value: NzSafeAny[] = [];\n  nzOpen = false;\n  valueChange = jasmine.createSpy<NzSafeAny>('valueChange');\n  openChange = jasmine.createSpy<NzSafeAny>('openChange');\n  nzMenuItemSelectedIcon: TemplateRef<NzSafeAny> | null = null;\n  nzRemoveIcon: TemplateRef<NzSafeAny> | null = null;\n  nzTokenSeparators: string[] = [];\n  nzMaxMultipleCount = Infinity;\n  compareWith: (o1: NzSafeAny, o2: NzSafeAny) => boolean = (o1: NzSafeAny, o2: NzSafeAny) => o1 === o2;\n  nzAutoClearSearchValue = true;\n}\n\n@Component({\n  imports: [FormsModule, NzSelectModule],\n  template: `\n    <nz-select\n      nzMode=\"tags\"\n      [(ngModel)]=\"value\"\n      [nzSize]=\"nzSize\"\n      [nzMaxTagCount]=\"nzMaxTagCount\"\n      [nzTokenSeparators]=\"nzTokenSeparators\"\n      [nzMaxTagPlaceholder]=\"nzMaxTagPlaceholder\"\n      (ngModelChange)=\"valueChange($event)\"\n    >\n      @for (o of listOfOption; track o) {\n        <nz-option [nzValue]=\"o.nzValue\" [nzLabel]=\"o.nzLabel\" [nzDisabled]=\"o.nzDisabled\" [nzHide]=\"o.nzHide\" />\n      }\n    </nz-select>\n    <ng-template #tagTemplate let-selectedList>and {{ selectedList.length }} more selected</ng-template>\n  `\n})\nexport class TestSelectTemplateTagsComponent {\n  @ViewChild('tagTemplate') tagTemplate!: TemplateRef<NzSafeAny>;\n  nzSize: NzSelectSizeType = 'default';\n  nzMaxTagCount = Infinity;\n  value: NzSafeAny[] = [];\n  listOfOption: NzSelectItemInterface[] = [];\n  valueChange = jasmine.createSpy('valueChange');\n  nzTokenSeparators: string[] = [];\n  nzMaxTagPlaceholder!: TemplateRef<{ $implicit: NzSafeAny[] }>;\n}\n\n@Component({\n  imports: [FormsModule, NzSelectModule],\n  template: `\n    <nz-select\n      nzMode=\"default\"\n      [(ngModel)]=\"value\"\n      [nzOptions]=\"listOfOption\"\n      [nzSize]=\"nzSize\"\n      [nzDropdownMatchSelectWidth]=\"nzDropdownMatchSelectWidth\"\n      [nzPlaceHolder]=\"nzPlaceHolder\"\n      [nzDropdownRender]=\"nzDropdownRender\"\n      [nzCustomTemplate]=\"nzCustomTemplate ?? null\"\n      [nzSuffixIcon]=\"nzSuffixIcon\"\n      [nzClearIcon]=\"nzClearIcon\"\n      [nzShowArrow]=\"nzShowArrow\"\n      [nzFilterOption]=\"nzFilterOption\"\n      [compareWith]=\"compareWith\"\n      [nzAllowClear]=\"nzAllowClear\"\n      [nzShowSearch]=\"nzShowSearch\"\n      [nzLoading]=\"nzLoading\"\n      [nzAutoFocus]=\"nzAutoFocus\"\n      [nzServerSearch]=\"nzServerSearch\"\n      [nzDisabled]=\"nzDisabled\"\n      [nzAutoClearSearchValue]=\"nzAutoClearSearchValue\"\n      [(nzOpen)]=\"nzOpen\"\n      (ngModelChange)=\"valueChange($event)\"\n      (nzOnSearch)=\"searchValueChange($event)\"\n      (nzOpenChange)=\"openChange($event)\"\n      (nzOnClear)=\"onClear()\"\n    />\n    <ng-template #dropdownTemplate><div class=\"dropdown-render\">dropdownRender</div></ng-template>\n    <ng-template #customTemplate let-selected>selected: {{ selected.nzLabel }}</ng-template>\n    <ng-template #suffixIconTemplate>icon</ng-template>\n  `\n})\nexport class TestSelectReactiveDefaultComponent {\n  @ViewChild('dropdownTemplate') dropdownTemplate!: TemplateRef<NzSafeAny>;\n  @ViewChild('customTemplate') customTemplate!: TemplateRef<NzSafeAny>;\n  @ViewChild('suffixIconTemplate') suffixIconTemplate!: TemplateRef<NzSafeAny>;\n  value: NzSafeAny | null = null;\n  valueChange = jasmine.createSpy<NzSafeAny>('valueChange');\n  openChange = jasmine.createSpy<NzSafeAny>('openChange');\n  nzAutoClearSearchValue = true;\n\n  onClear = jasmine.createSpy<NzSafeAny>('onClear');\n  searchValueChange = jasmine.createSpy<NzSafeAny>('searchValueChange');\n  listOfOption: NzSelectOptionInterface[] = [];\n  nzSize: NzSelectSizeType = 'default';\n  nzDropdownMatchSelectWidth = true;\n  nzPlaceHolder: string | TemplateRef<NzSafeAny> | null = null;\n  nzDropdownRender: TemplateRef<NzSafeAny> | null = null;\n  nzCustomTemplate?: TemplateRef<{ $implicit: NzSelectItemInterface }>;\n  nzSuffixIcon: TemplateRef<NzSafeAny> | null = null;\n  nzClearIcon: TemplateRef<NzSafeAny> | null = null;\n  nzShowArrow = true;\n  nzFilterOption: NzFilterOptionType = (searchValue: string, item: NzSelectItemInterface): boolean => {\n    if (item && item.nzLabel) {\n      return item.nzLabel.toString().toLowerCase().indexOf(searchValue.toLowerCase()) > -1;\n    } else {\n      return false;\n    }\n  };\n  compareWith: (o1: NzSafeAny, o2: NzSafeAny) => boolean = (o1: NzSafeAny, o2: NzSafeAny) => o1 === o2;\n  nzAllowClear = false;\n  nzShowSearch = false;\n  nzLoading = false;\n  nzAutoFocus = false;\n  nzServerSearch = false;\n  nzDisabled = false;\n  nzOpen = false;\n}\n\n@Component({\n  imports: [FormsModule, NzSelectModule],\n  template: `\n    <nz-select\n      [nzMode]=\"nzMode\"\n      [(ngModel)]=\"value\"\n      [nzOptions]=\"listOfOption\"\n      [nzMenuItemSelectedIcon]=\"nzMenuItemSelectedIcon\"\n      [nzTokenSeparators]=\"nzTokenSeparators\"\n      [nzRemoveIcon]=\"nzRemoveIcon\"\n      [nzMaxMultipleCount]=\"nzMaxMultipleCount\"\n      [compareWith]=\"compareWith\"\n      [nzAutoClearSearchValue]=\"nzAutoClearSearchValue\"\n      [(nzOpen)]=\"nzOpen\"\n      (ngModelChange)=\"valueChange($event)\"\n      (nzOpenChange)=\"valueChange($event)\"\n    />\n    <ng-template #iconTemplate>icon</ng-template>\n  `\n})\nexport class TestSelectReactiveMultipleComponent {\n  @ViewChild('iconTemplate') iconTemplate!: TemplateRef<NzSafeAny>;\n  listOfOption: NzSelectOptionInterface[] = [];\n  value: NzSafeAny[] = [];\n  nzOpen = false;\n  valueChange = jasmine.createSpy('valueChange');\n  openChange = jasmine.createSpy('openChange');\n  nzMenuItemSelectedIcon: TemplateRef<NzSafeAny> | null = null;\n  nzRemoveIcon: TemplateRef<NzSafeAny> | null = null;\n  nzTokenSeparators: string[] = [];\n  nzMaxMultipleCount = Infinity;\n  nzMode: NzSelectModeType = 'multiple';\n  compareWith: (o1: NzSafeAny, o2: NzSafeAny) => boolean = (o1: NzSafeAny, o2: NzSafeAny) => o1 === o2;\n  nzAutoClearSearchValue = true;\n}\n\n@Component({\n  imports: [FormsModule, NzSelectModule],\n  template: `\n    <nz-select\n      nzMode=\"tags\"\n      [(ngModel)]=\"value\"\n      [nzOptions]=\"listOfOption\"\n      [nzSize]=\"nzSize\"\n      [nzMaxTagCount]=\"nzMaxTagCount\"\n      [nzMaxMultipleCount]=\"nzMaxMultipleCount\"\n      [nzTokenSeparators]=\"nzTokenSeparators\"\n      [nzMaxTagPlaceholder]=\"nzMaxTagPlaceholder ?? null\"\n      (ngModelChange)=\"valueChange($event)\"\n    />\n    <ng-template #tagTemplate let-selectedList>and {{ selectedList.length }} more selected</ng-template>\n  `\n})\nexport class TestSelectReactiveTagsComponent {\n  @ViewChild('tagTemplate') tagTemplate?: TemplateRef<NzSafeAny>;\n  nzSize: NzSelectSizeType = 'default';\n  nzMaxTagCount = Infinity;\n  value: NzSafeAny[] = [];\n  listOfOption: NzSelectOptionInterface[] = [];\n  valueChange = jasmine.createSpy('valueChange');\n  nzTokenSeparators: string[] = [];\n  nzMaxTagPlaceholder?: TemplateRef<NzSafeAny>;\n  nzMaxMultipleCount?: number;\n}\n\n@Component({\n  imports: [NzSelectModule],\n  template: `<nz-select [nzStatus]=\"status\" />`\n})\nexport class TestSelectStatusComponent {\n  status: NzStatus = 'error';\n}\n\n@Component({\n  imports: [ReactiveFormsModule, NzFormModule, NzSelectModule],\n  template: `\n    <form nz-form [formGroup]=\"selectForm\">\n      <nz-form-item>\n        <nz-form-control [nzHasFeedback]=\"feedback\" [nzValidateStatus]=\"status\">\n          <nz-select formControlName=\"selectControl\" [nzOptions]=\"[]\" [nzDisabled]=\"disabled\" />\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `\n})\nexport class TestSelectInFormComponent {\n  selectForm = new FormGroup({\n    selectControl: new FormControl(null)\n  });\n  status: NzFormControlStatusType = 'error';\n  feedback = true;\n\n  disabled = false;\n\n  disable(): void {\n    this.selectForm.disable();\n  }\n\n  enable(): void {\n    this.selectForm.enable();\n  }\n}\n\n@Component({\n  imports: [NzSelectModule],\n  template: `<nz-select [nzSize]=\"size\" />`\n})\nexport class TestSelectFinalSizeComponent {\n  size: NzSelectSizeType = 'default';\n}\n\n@Component({\n  imports: [NzSelectModule],\n  template: `<nz-select [nzVariant]=\"variant()\" />`\n})\nexport class TestSelectFinalVariantComponent {\n  readonly variant = signal<NzVariant | undefined>(undefined);\n}\n"
  },
  {
    "path": "components/select/select.types.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { TemplateRef } from '@angular/core';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nexport type NzSelectModeType = 'default' | 'multiple' | 'tags';\nexport interface NzSelectItemInterface {\n  template?: TemplateRef<NzSafeAny> | null;\n  nzLabel: string | number | null;\n  nzValue: NzSafeAny | null;\n  nzTitle?: string | number | null;\n  nzDisabled?: boolean;\n  nzHide?: boolean;\n  nzCustomContent?: boolean;\n  groupLabel?: string | number | TemplateRef<NzSafeAny> | null;\n  type?: string;\n  key?: NzSafeAny;\n}\n\nexport interface NzSelectOptionInterface {\n  label: string | number | null | TemplateRef<NzSafeAny>;\n  value: NzSafeAny | null;\n  title?: string | number | null;\n  disabled?: boolean;\n  hide?: boolean;\n  groupLabel?: string | number | TemplateRef<NzSafeAny> | null;\n  key?: string | number;\n}\n\nexport type NzSelectTopControlItemType = Partial<NzSelectItemInterface> & {\n  contentTemplateOutlet: TemplateRef<NzSafeAny> | null;\n  contentTemplateOutletContext: NzSafeAny;\n};\n\nexport type NzFilterOptionType = (input: string, option: NzSelectItemInterface) => boolean;\n\nexport type NzSelectPlacementType = 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight';\n"
  },
  {
    "path": "components/select/style/entry.less",
    "content": "@import './index.less';\n// style dependencies\n@import '../../empty/style/entry.less';\n@import './patch.less';\n"
  },
  {
    "path": "components/select/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import '../../input/style/mixin';\n@import './single';\n@import './multiple';\n@import './status';\n\n@select-prefix-cls: ~'@{ant-prefix}-select';\n\n.select-selector() {\n  position: relative;\n  background-color: @select-background;\n  border: @border-width-base @border-style-base @select-border-color;\n  border-radius: @control-border-radius;\n  transition: all 0.3s @ease-in-out;\n\n  input {\n    cursor: pointer;\n  }\n\n  .@{select-prefix-cls}-prefix {\n    flex: none;\n    margin-inline-end: @select-select-affix-padding;\n  }\n\n  .@{select-prefix-cls}-selection-wrap {\n    position: relative;\n    display: flex;\n    width: 100%;\n    min-width: 0;\n\n    &::after {\n      width: 0;\n      overflow: hidden;\n      content: '\\a0';\n    }\n  }\n\n  .@{select-prefix-cls}-show-search& {\n    cursor: text;\n\n    input {\n      cursor: auto;\n    }\n  }\n\n  .@{select-prefix-cls}-disabled& {\n    color: @disabled-color;\n    background: @input-disabled-bg;\n    cursor: not-allowed;\n\n    .@{select-prefix-cls}-multiple& {\n      background: @select-multiple-disabled-background;\n    }\n\n    input {\n      cursor: not-allowed;\n    }\n  }\n}\n\n/* Reset search input style */\n.select-search-input-without-border() {\n  .@{select-prefix-cls}-selection-search-input {\n    margin: 0;\n    padding: 0;\n    font-family: inherit;\n    background: transparent;\n    border: none;\n    outline: none;\n    appearance: none;\n\n    &::-webkit-search-cancel-button {\n      display: none;\n      appearance: none;\n    }\n  }\n}\n\n.@{select-prefix-cls} {\n  .reset-component();\n  position: relative;\n  display: inline-flex;\n  cursor: pointer;\n\n  &:not(&-customize-input) &-selector {\n    .select-selector();\n    .select-search-input-without-border();\n  }\n\n  &:not(&-disabled):hover &-selector {\n    .hover();\n  }\n\n  &:not(&-disabled)&-focused &-selector {\n    .active();\n  }\n\n  // ======================== Selection ========================\n  &-selection-item {\n    position: relative;\n    flex: 1;\n    overflow: hidden;\n    font-weight: normal;\n    white-space: nowrap;\n    text-overflow: ellipsis;\n    user-select: none;\n\n    // IE11 css hack. `*::-ms-backdrop,` is a must have\n    @media all and (-ms-high-contrast: none) {\n      *::-ms-backdrop,\n      & {\n        flex: auto;\n      }\n    }\n  }\n\n  // ======================= Placeholder =======================\n  &-selection-placeholder {\n    flex: 1;\n    overflow: hidden;\n    color: @input-placeholder-color;\n    white-space: nowrap;\n    text-overflow: ellipsis;\n    pointer-events: none;\n\n    // IE11 css hack. `*::-ms-backdrop,` is a must have\n    @media all and (-ms-high-contrast: none) {\n      *::-ms-backdrop,\n      & {\n        flex: auto;\n      }\n    }\n  }\n\n  // ========================== Arrow ==========================\n  &-arrow {\n    .iconfont-mixin();\n    position: absolute;\n    top: 50%;\n    inset-inline-start: auto;\n    inset-inline-end: @input-padding-horizontal-base;\n    display: flex;\n    align-items: center;\n    height: @font-size-icon;\n    margin-top: (-@font-size-icon / 2);\n    color: @disabled-color;\n    font-size: @font-size-icon;\n    line-height: 1;\n    text-align: center;\n    pointer-events: none;\n\n    .@{iconfont-css-prefix} {\n      vertical-align: top;\n      transition: transform 0.3s;\n\n      > svg {\n        vertical-align: top;\n      }\n\n      &:not(.@{select-prefix-cls}-suffix) {\n        pointer-events: auto;\n      }\n    }\n\n    .@{select-prefix-cls}-disabled & {\n      cursor: not-allowed;\n    }\n\n    > *:not(:last-child) {\n      margin-inline-end: @padding-xs;\n    }\n  }\n\n  // ========================== Clear ==========================\n  &-clear {\n    position: absolute;\n    top: 50%;\n    z-index: 1;\n    display: inline-block;\n    width: @font-size-icon;\n    height: @font-size-icon;\n    margin-top: (-@font-size-icon / 2);\n    color: @disabled-color;\n    font-size: @font-size-icon;\n    font-style: normal;\n    line-height: 1;\n    text-align: center;\n    text-transform: none;\n    background: @select-clear-background;\n    // https://github.com/ant-design/ant-design/issues/54205\n    // Force GPU compositing on Safari to prevent flickering on opacity/transform transitions\n    transform: translateZ(0);\n    cursor: pointer;\n    opacity: 0;\n    transition:\n      color 0.3s ease,\n      opacity 0.15s ease;\n    inset-inline-start: auto;\n    inset-inline-end: @input-padding-horizontal-base;\n    text-rendering: auto;\n\n    &::before {\n      display: block;\n    }\n\n    &:hover {\n      color: @text-color-secondary;\n    }\n\n    .@{select-prefix-cls}:hover & {\n      opacity: 1;\n    }\n  }\n\n  // ========================== Popup ==========================\n  &-dropdown {\n    .reset-component();\n    position: absolute;\n    top: -9999px;\n    z-index: @zindex-dropdown;\n    box-sizing: border-box;\n    padding: @padding-xss;\n    overflow: hidden;\n    font-size: @font-size-base;\n    // Fix select render lag of long text in chrome\n    // https://github.com/ant-design/ant-design/issues/11456\n    // https://github.com/ant-design/ant-design/issues/11843\n    font-variant: initial;\n    background-color: @select-dropdown-bg;\n    border-radius: @border-radius-base;\n    outline: none;\n    box-shadow: @box-shadow-base;\n\n    &.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-bottomLeft,\n    &.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-bottomLeft {\n      animation-name: antSlideUpIn;\n    }\n\n    &.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-topLeft,\n    &.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-topLeft {\n      animation-name: antSlideDownIn;\n    }\n\n    &.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-bottomLeft {\n      animation-name: antSlideUpOut;\n    }\n\n    &.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-topLeft {\n      animation-name: antSlideDownOut;\n    }\n\n    &-hidden {\n      display: none;\n    }\n\n    &-empty {\n      color: @disabled-color;\n    }\n  }\n\n  // ========================= Options =========================\n  .item() {\n    position: relative;\n    display: block;\n    min-height: @select-dropdown-height;\n    padding: @select-dropdown-vertical-padding @control-padding-horizontal;\n    color: @text-color;\n    font-weight: normal;\n    font-size: @select-dropdown-font-size;\n    line-height: @select-dropdown-line-height;\n  }\n\n  &-item-empty {\n    .item();\n    color: @disabled-color;\n  }\n\n  &-item {\n    .item();\n\n    cursor: pointer;\n    transition: background 0.3s ease;\n\n    // =========== Group ============\n    &-group {\n      color: @text-color-secondary;\n      font-size: @font-size-sm;\n      cursor: default;\n    }\n\n    // =========== Option ===========\n    &-option {\n      display: flex;\n\n      &-content {\n        flex: auto;\n        overflow: hidden;\n        white-space: nowrap;\n        text-overflow: ellipsis;\n      }\n\n      &-state {\n        flex: none;\n        user-select: none;\n      }\n\n      &-active:not(&-disabled) {\n        background-color: @select-item-active-bg;\n      }\n\n      &-selected:not(&-disabled) {\n        color: @select-item-selected-color;\n        font-weight: @select-item-selected-font-weight;\n        background-color: @select-item-selected-bg;\n\n        .@{select-prefix-cls}-item-option-state {\n          color: @primary-color;\n        }\n      }\n\n      &-disabled {\n        &.@{select-prefix-cls}-item-option-selected {\n          background-color: @select-multiple-disabled-background;\n        }\n\n        color: @disabled-color;\n        cursor: not-allowed;\n      }\n\n      &-grouped {\n        padding-inline-start: @control-padding-horizontal * 2;\n      }\n    }\n  }\n\n  // ============================================================\n  // ==                          Size                          ==\n  // ============================================================\n  &-lg {\n    font-size: @font-size-lg;\n  }\n\n  // no border style\n  &&-borderless,\n  &&-borderless:hover,\n  &&-borderless:focus,\n  &&-borderless&-focused,\n  &&-borderless&-disabled,\n  &&-borderless&[disabled] {\n    .@{select-prefix-cls}-selector {\n      background-color: transparent;\n      border-color: transparent;\n      box-shadow: none;\n    }\n  }\n\n  // filled style\n  &&-filled &-selector {\n    background-color: @input-variant-filled-bg;\n    border-color: transparent;\n    box-shadow: none;\n  }\n\n  &&-filled:hover &-selector {\n    background-color: @input-variant-filled-hover-bg;\n    border-color: transparent;\n    box-shadow: none;\n  }\n\n  &&-filled:focus,\n  &&-filled&-focused {\n    .@{select-prefix-cls}-selector {\n      .active();\n      background-color: transparent;\n      box-shadow: none;\n    }\n  }\n\n  &&-filled&-disabled,\n  &&-filled&[disabled] {\n    .@{select-prefix-cls}-selector {\n      .disabled();\n    }\n  }\n\n  // underlined style\n  &&-underlined,\n  &&-underlined:hover,\n  &&-underlined:focus,\n  &&-underlined&-focused,\n  &&-underlined&-disabled,\n  &&-underlined&[disabled] {\n    .@{select-prefix-cls}-selector {\n      background-color: transparent;\n      border-width: 0 0 @border-width-base;\n      border-radius: 0;\n      box-shadow: none;\n    }\n  }\n\n  &&-underlined:hover:not(&-focused):not(:focus) &-selector {\n    border-color: @input-border-color;\n  }\n\n\n  &&-in-form-item {\n    width: 100%;\n  }\n\n  // ===================== Compact Item Styles =====================\n  .compact-item(@select-prefix-cls, ~'@{select-prefix-cls}-selector', ~'@{select-prefix-cls}-focused');\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/select/style/multiple.less",
    "content": "@import (reference) '../../style/themes/index';\n\n@select-prefix-cls: ~'@{ant-prefix}-select';\n\n@select-overflow-prefix-cls: ~'@{select-prefix-cls}-selection-overflow';\n\n// Multiple select specific variables\n@select-internal-fixed-item-margin: calc(@padding-xss / 2);\n@select-multiple-base-padding: max(calc(@padding-xss - @line-width), 0px);\n@select-multiple-container-padding: max(calc(@select-multiple-base-padding - @select-internal-fixed-item-margin), 0px);\n@select-item-dist: calc(calc(@select-height - @select-multiple-item-height) / 2 - @line-width);\n@select-multiple-selector-bg-disabled: @input-disabled-bg;\n\n/**\n * Get multiple selector needed style. The calculation:\n *\n * ContainerPadding = BasePadding - ItemMargin\n *\n * Border:                    ╔═══════════════════════════╗                 ┬\n * ContainerPadding:          ║                           ║                 │\n *                            ╟───────────────────────────╢     ┬           │\n * Item Margin:               ║                           ║     │           │\n *                            ║             ┌──────────┐  ║     │           │\n * Item(multipleItemHeight):  ║ BasePadding │   Item   │  ║  Overflow  Container(ControlHeight)\n *                            ║             └──────────┘  ║     │           │\n * Item Margin:               ║                           ║     │           │\n *                            ╟───────────────────────────╢     ┴           │\n * ContainerPadding:          ║                           ║                 │\n * Border:                    ╚═══════════════════════════╝                 ┴\n */\n\n// Multiple selector utilities based on CSS-in-JS getMultipleSelectorUnit function\n.getMultipleSelectorUnit(@item-height, @base-padding, @container-padding) {\n  @result-item-height: @item-height;\n  @result-item-line-height: calc(@item-height - @line-width * 2);\n  @result-base-padding: @base-padding;\n  @result-container-padding: @container-padding;\n}\n\n// Utility to calculate select item distance\n.getSelectItemStyle(@select-height, @multiple-item-height) {\n  @select-item-dist: calc(calc(@select-height - @multiple-item-height) / 2 - @line-width);\n}\n\n// Overflow styles\n.genOverflowStyle() {\n  // Overflow container\n  .@{select-overflow-prefix-cls} {\n    position: relative;\n    display: flex;\n    flex: auto;\n    flex-wrap: wrap;\n    max-width: 100%;\n\n    &-item {\n      display: inline-flex;\n      flex: none;\n      align-self: center;\n      // https://github.com/ant-design/ant-design/issues/54179\n      max-width: calc(100% - 4px);\n    }\n  }\n\n  // Selection items\n  .@{select-prefix-cls}-selection-item {\n    display: flex;\n    flex: none;\n    align-self: center;\n    box-sizing: border-box;\n    max-width: 100%;\n    background: @select-selection-item-bg;\n    border: @line-width @border-style-base @select-selection-item-border-color;\n    border-radius: @border-radius-sm;\n    cursor: default;\n    transition:\n      font-size @animation-duration-slow,\n      line-height @animation-duration-slow,\n      height @animation-duration-slow;\n    margin-block: @select-internal-fixed-item-margin;\n    margin-inline-end: calc(@select-internal-fixed-item-margin * 2);\n    padding-inline-start: @padding-xs;\n    padding-inline-end: calc(@padding-xs / 2);\n\n    .@{select-prefix-cls}-disabled& {\n      color: @select-multiple-item-disabled-color;\n      border-color: @select-multiple-item-disabled-border-color;\n      cursor: not-allowed;\n    }\n\n    // Content\n    &-content {\n      display: inline-block;\n      overflow: hidden;\n      white-space: pre; // fix whitespace wrapping. custom tags display all whitespace within.\n      text-overflow: ellipsis;\n      margin-inline-end: calc(@padding-xs / 2);\n    }\n\n    &-remove {\n      .iconfont-mixin();\n      display: inline-flex;\n      align-items: center;\n      color: @text-color-secondary;\n      font-weight: bold;\n      font-size: 10px;\n      line-height: inherit;\n      cursor: pointer;\n\n      > .@{iconfont-css-prefix} {\n        vertical-align: -0.2em;\n      }\n\n      &:hover {\n        color: @icon-color-hover;\n      }\n    }\n  }\n}\n\n// Selection styles\n.genSelectionStyle(@select-height, @multiple-item-height, @base-padding, @container-padding, @border-radius) {\n  .getSelectItemStyle(@select-height, @multiple-item-height);\n  .getMultipleSelectorUnit(@multiple-item-height, @base-padding, @container-padding);\n\n  // Selector container\n  .@{select-prefix-cls}-selector {\n    display: flex;\n    align-items: center;\n    width: 100%;\n    height: 100%;\n    // Multiple is little different that horizontal is follow the vertical\n    padding-inline: @base-padding;\n    padding-block: @container-padding;\n    border-radius: @border-radius;\n\n    .@{select-prefix-cls}-disabled& {\n      background: @select-multiple-selector-bg-disabled;\n      cursor: not-allowed;\n    }\n\n    &::after {\n      display: inline-block;\n      width: 0;\n      margin: @select-internal-fixed-item-margin 0;\n      line-height: @multiple-item-height;\n      visibility: hidden;\n      content: '\\a0';\n    }\n  }\n\n  // Selection items with calculated height\n  .@{select-prefix-cls}-selection-item {\n    height: @multiple-item-height;\n    line-height: calc(@multiple-item-height - @line-width * 2);\n  }\n\n  // Selection wrap\n  .@{select-prefix-cls}-selection-wrap {\n    align-self: flex-start;\n\n    &::after {\n      line-height: @multiple-item-height;\n      margin-block: @select-internal-fixed-item-margin;\n    }\n  }\n\n  // Prefix adjustments\n  .@{select-prefix-cls}-prefix {\n    margin-inline-start: calc(@input-padding-horizontal-base - @base-padding);\n  }\n\n  // Overflow item spacing\n  .@{select-overflow-prefix-cls}-item + .@{select-overflow-prefix-cls}-item,\n  .@{select-prefix-cls}-prefix + .@{select-prefix-cls}-selection-wrap {\n    .@{select-prefix-cls}-selection-search {\n      margin-inline-start: 0;\n    }\n    .@{select-prefix-cls}-selection-placeholder {\n      inset-inline-start: 0;\n    }\n  }\n\n  // https://github.com/ant-design/ant-design/issues/44754\n  // Same as `wrap:after`\n  .@{select-overflow-prefix-cls}-item-suffix {\n    min-height: @multiple-item-height;\n    margin-block: @select-internal-fixed-item-margin;\n  }\n\n  // Search input\n  .@{select-prefix-cls}-selection-search {\n    position: relative;\n    display: inline-flex;\n    max-width: 100%;\n    margin-inline-start: calc(@input-padding-horizontal-base - @select-item-dist);\n\n    &-input,\n    &-mirror {\n      height: @multiple-item-height;\n      font-family: @font-family;\n      line-height: @multiple-item-height;\n      transition: all @animation-duration-slow;\n    }\n\n    &-input {\n      width: 100%;\n      min-width: 4.1px; // fix search cursor missing\n    }\n\n    &-mirror {\n      position: absolute;\n      top: 0;\n      z-index: 999;\n      white-space: pre; // fix whitespace wrapping caused width calculation bug\n      visibility: hidden;\n      inset-inline-start: 0;\n      inset-inline-end: auto;\n    }\n  }\n\n  // Placeholder\n  .@{select-prefix-cls}-selection-placeholder {\n    position: absolute;\n    top: 50%;\n    inset-inline-start: calc(@input-padding-horizontal-base - @base-padding);\n    inset-inline-end: @input-padding-horizontal-base;\n    transform: translateY(-50%);\n    transition: all @animation-duration-slow;\n  }\n}\n\n// ============================================================\n// ==                          Size                          ==\n// ============================================================\n.genSizeStyle(@suffix, @multiple-item-height, @border-radius, @border-radius-sm, @select-height, @font-size: @font-size-base) {\n  @merged-cls: ~'@{select-prefix-cls}@{suffix}';\n\n  // Calculate padding values\n  @base-padding: max(calc(@padding-xss - @line-width), 0px);\n  @container-padding: max(calc(@base-padding - @select-internal-fixed-item-margin), 0px);\n\n  .@{select-prefix-cls}-multiple.@{merged-cls} {\n    font-size: @font-size;\n\n    // Include overflow styles\n    .genOverflowStyle();\n\n    // Include selection styles with calculated values\n    .genSelectionStyle(@select-height, @multiple-item-height, @base-padding, @container-padding, @border-radius);\n\n    // Selector specific styles\n    .@{select-prefix-cls}-selector {\n      .@{select-prefix-cls}-show-search& {\n        cursor: text;\n      }\n    }\n\n    // Show arrow and allow clear states\n    &.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selector,\n    &.@{select-prefix-cls}-allow-clear .@{select-prefix-cls}-selector {\n      padding-inline-end: calc(@font-size-icon + @control-padding-horizontal);\n    }\n  }\n}\n\n// Main multiple style generation - equivalent to genMultipleStyle function\n.genMultipleStyle() {\n  // ======================== Default ========================\n  .genSizeStyle('', @select-multiple-item-height, @border-radius-base, @border-radius-sm, @select-height);\n\n  // ======================== Small ========================\n  // stylelint-disable-next-line less/no-duplicate-variables\n  .genSizeStyle('-sm', @select-multiple-item-height-sm, @border-radius-sm, @border-radius-sm, @input-height-sm);\n\n  // Size small need additional set padding\n  .@{select-prefix-cls}-multiple.@{select-prefix-cls}-sm {\n    .@{select-prefix-cls}-selection-placeholder {\n      inset-inline: calc(@control-padding-horizontal-sm - @line-width);\n    }\n\n    // https://github.com/ant-design/ant-design/issues/29559\n    .@{select-prefix-cls}-selection-search {\n      margin-inline-start: 2px; // magic number\n    }\n  }\n\n  // ======================== Large ========================\n  // stylelint-disable-next-line less/no-duplicate-variables\n  .genSizeStyle('-lg', @select-multiple-item-height-lg, @border-radius-lg, @border-radius-base, @input-height-lg, @font-size-lg);\n}\n\n.genMultipleStyle();\n"
  },
  {
    "path": "components/select/style/patch.less",
    "content": ".ant-select-dropdown {\n  top: 100%;\n  left: 0;\n  display: block;\n  width: 100%;\n  margin-top: 4px;\n  margin-bottom: 4px;\n\n  .cdk-virtual-scroll-content-wrapper {\n    right: 0;\n  }\n\n  .full-width {\n    contain: initial;\n\n    .cdk-virtual-scroll-content-wrapper {\n      position: static;\n    }\n\n    .cdk-virtual-scroll-spacer {\n      position: absolute;\n      top: 0;\n      width: 1px;\n    }\n  }\n}\n"
  },
  {
    "path": "components/select/style/rtl.less",
    "content": "@select-prefix-cls: ~'@{ant-prefix}-select';\n\n.@{select-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &-dropdown {\n    &-rtl {\n      direction: rtl;\n    }\n  }\n}\n"
  },
  {
    "path": "components/select/style/single.less",
    "content": "@import (reference) '../../style/themes/index';\n\n@select-prefix-cls: ~'@{ant-prefix}-select';\n\n.genSizeStyle(@suffix, @control-height, @font-size, @border-radius) {\n  @merged-cls: ~'@{select-prefix-cls}@{suffix}';\n  @select-height-without-border: @control-height - 2 * @line-width;\n  @show-arrow-padding-inline-end: ceil(@font-size * 1.25);\n\n  &.@{merged-cls} {\n    height: @control-height;\n    font-size: @font-size;\n\n    // ========================= Selector =========================\n    .@{select-prefix-cls}-selector {\n      display: flex;\n      flex: 1 1 auto;\n      border-radius: @border-radius;\n\n      .@{select-prefix-cls}-selection-wrap::after {\n        line-height: @select-height-without-border;\n      }\n\n      .@{select-prefix-cls}-selection-search {\n        position: absolute;\n        width: 100%;\n        inset: 0;\n\n        &-input {\n          width: 100%;\n          appearance: textfield;\n        }\n      }\n\n      .@{select-prefix-cls}-selection-item,\n      .@{select-prefix-cls}-selection-placeholder {\n        display: block;\n        align-self: center;\n        padding: 0;\n        line-height: @select-height-without-border;\n        transition:\n          all 0.3s,\n          visibility 0s;\n      }\n\n      .@{select-prefix-cls}-selection-placeholder {\n        transition: none;\n        pointer-events: none;\n      }\n\n      // For common baseline align\n      &::after,\n      /* For '' value baseline align */\n    .@{select-prefix-cls}-selection-item::after,\n      /* For undefined value baseline align */\n    .@{select-prefix-cls}-selection-placeholder::after {\n        display: inline-block;\n        width: 0;\n        visibility: hidden;\n        content: '\\a0';\n      }\n    }\n\n    // With arrow should provides `padding-inline-end` to show the arrow\n    &.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-item,\n    &.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-search,\n    &.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-placeholder {\n      padding-inline-end: @show-arrow-padding-inline-end;\n    }\n\n    // Opacity selection if open\n    &.@{select-prefix-cls}-open .@{select-prefix-cls}-selection-item {\n      color: @input-placeholder-color;\n    }\n\n    // ========================== Input ==========================\n    // We only change the style of non-customize input which is only support by `combobox` mode.\n    // Not customize\n    &:not(.@{select-prefix-cls}-customize-input) {\n      .@{select-prefix-cls}-selector {\n        align-items: center;\n        width: 100%;\n        height: 100%;\n        padding: 0 @input-padding-horizontal-base;\n\n        .@{select-prefix-cls}-selection-search-input {\n          height: @select-height-without-border;\n          font-size: @font-size-base;\n        }\n\n        &::after {\n          line-height: @select-height-without-border;\n        }\n      }\n    }\n\n    &.@{select-prefix-cls}-customize-input {\n      .@{select-prefix-cls}-selector {\n        &::after {\n          display: none;\n        }\n\n        .@{select-prefix-cls}-selection-search {\n          position: static;\n          width: 100%;\n        }\n\n        .@{select-prefix-cls}-selection-placeholder {\n          position: absolute;\n          padding: 0 @input-padding-horizontal-base;\n          inset-inline-start: 0;\n          inset-inline-end: 0;\n\n          &::after {\n            display: none;\n          }\n        }\n      }\n    }\n  }\n}\n\n.@{select-prefix-cls}-single {\n  .genSizeStyle('', @input-height-base, @font-size-base, @border-radius-base);\n\n  // ======================== Small ========================\n  // Shared\n  // stylelint-disable-next-line less/no-duplicate-variables\n  .genSizeStyle('-sm', @input-height-sm, @font-size-base, @border-radius-sm);\n\n  // Padding\n  &.@{select-prefix-cls}-sm {\n    &:not(.@{select-prefix-cls}-customize-input) {\n      .@{select-prefix-cls}-selector {\n        padding: 0 @input-padding-horizontal-sm;\n      }\n\n      // With arrow should provides `padding-inline-end` to show the arrow\n      &.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-search {\n        padding-inline-end: @input-padding-horizontal-sm + @font-size-base * 1.5;\n      }\n\n      &.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-item,\n      &.@{select-prefix-cls}-show-arrow .@{select-prefix-cls}-selection-placeholder {\n        padding-inline-end: @font-size-base * 1.5;\n      }\n    }\n  }\n\n  // ======================== Large ========================\n  // Shared\n  // stylelint-disable-next-line less/no-duplicate-variables\n  .genSizeStyle('-lg', @select-single-item-height-lg, @font-size-lg, @border-radius-lg);\n}\n"
  },
  {
    "path": "components/select/style/status.less",
    "content": "@import '../../input/style/mixin';\n\n@select-prefix-cls: ~'@{ant-prefix}-select';\n@pagination-prefix-cls: ~'@{ant-prefix}-pagination';\n\n.select-status-color(\n  @text-color;\n  @border-color;\n  @background-color;\n  @hoverBorderColor;\n  @outlineColor;\n) {\n  &.@{select-prefix-cls}:not(.@{select-prefix-cls}-disabled):not(.@{select-prefix-cls}-customize-input):not(.@{pagination-prefix-cls}-size-changer) {\n    .@{select-prefix-cls}-selector {\n      background-color: @background-color;\n      border-color: @border-color !important;\n    }\n    &.@{select-prefix-cls}-open .@{select-prefix-cls}-selector,\n    &.@{select-prefix-cls}-focused .@{select-prefix-cls}-selector {\n      .active(@border-color, @hoverBorderColor, @outlineColor);\n    }\n  }\n}\n\n.@{select-prefix-cls} {\n  &-status-error {\n    .select-status-color(@error-color, @error-color, @select-background, @error-color-hover, @error-color-outline);\n  }\n\n  &-status-warning {\n    .select-status-color(@warning-color, @warning-color, @input-bg, @warning-color-hover, @warning-color-outline);\n  }\n\n  &-status-error,\n  &-status-warning,\n  &-status-success,\n  &-status-validating {\n    &.@{select-prefix-cls}-has-feedback {\n      //.@{prefix-cls}-arrow,\n      .@{select-prefix-cls}-clear {\n        inset-inline-end: 32px;\n      }\n\n      .@{select-prefix-cls}-selection-selected-value {\n        padding-inline-end: 42px;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/skeleton/demo/active.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 动画效果\n  en-US: Active Animation\n---\n\n## zh-CN\n\n显示动画效果。\n\n## en-US\n\nDisplay active animation.\n"
  },
  {
    "path": "components/skeleton/demo/active.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzSkeletonModule } from 'ng-zorro-antd/skeleton';\n\n@Component({\n  selector: 'nz-demo-skeleton-active',\n  imports: [NzSkeletonModule],\n  template: `<nz-skeleton [nzActive]=\"true\" />`\n})\nexport class NzDemoSkeletonActiveComponent {}\n"
  },
  {
    "path": "components/skeleton/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n最简单的用法。\n\n## en-US\n\nBasic usage.\n"
  },
  {
    "path": "components/skeleton/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzSkeletonModule } from 'ng-zorro-antd/skeleton';\n\n@Component({\n  selector: 'nz-demo-skeleton-basic',\n  imports: [NzSkeletonModule],\n  template: `<nz-skeleton />`\n})\nexport class NzDemoSkeletonBasicComponent {}\n"
  },
  {
    "path": "components/skeleton/demo/children.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 包含子组件\n  en-US: Contains sub component\n---\n\n## zh-CN\n\n加载占位图包含子组件。\n\n## en-US\n\nSkeleton contains sub component.\n"
  },
  {
    "path": "components/skeleton/demo/children.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzSkeletonModule } from 'ng-zorro-antd/skeleton';\n\n@Component({\n  selector: 'nz-demo-skeleton-children',\n  imports: [NzButtonModule, NzSkeletonModule],\n  template: `\n    <div class=\"article\">\n      <nz-skeleton [nzLoading]=\"loading\">\n        <h4>Ant Design, a design language</h4>\n        <p>\n          We supply a series of design principles, practical patterns and high quality design resources (Sketch and\n          Axure), to help people create their product prototypes beautifully and efficiently.\n        </p>\n      </nz-skeleton>\n      <button nz-button (click)=\"showSkeleton()\" [disabled]=\"loading\">Show Skeleton</button>\n    </div>\n  `,\n  styles: `\n    .article h4 {\n      margin-bottom: 16px;\n    }\n    .article button {\n      margin-top: 16px;\n    }\n  `\n})\nexport class NzDemoSkeletonChildrenComponent {\n  loading = false;\n\n  showSkeleton(): void {\n    this.loading = true;\n    setTimeout(() => {\n      this.loading = false;\n    }, 3000);\n  }\n}\n"
  },
  {
    "path": "components/skeleton/demo/complex.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 复杂的组合\n  en-US: Complex combination\n---\n\n## zh-CN\n\n更复杂的组合。\n\n## en-US\n\nComplex combination with avatar and multiple paragraphs.\n"
  },
  {
    "path": "components/skeleton/demo/complex.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzSkeletonModule } from 'ng-zorro-antd/skeleton';\n\n@Component({\n  selector: 'nz-demo-skeleton-complex',\n  imports: [NzSkeletonModule],\n  template: `<nz-skeleton [nzAvatar]=\"true\" [nzParagraph]=\"{ rows: 4 }\" />`\n})\nexport class NzDemoSkeletonComplexComponent {}\n"
  },
  {
    "path": "components/skeleton/demo/element.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 按钮/头像/输入框/图像\n  en-US: Button/Avatar/Input/Image\n---\n\n## zh-CN\n\n骨架按钮、头像、输入框和图像。\n\n## en-US\n\nSkeleton button, avatar, input and image.\n"
  },
  {
    "path": "components/skeleton/demo/element.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\nimport { NzGridModule } from 'ng-zorro-antd/grid';\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\nimport {\n  NzSkeletonAvatarShape,\n  NzSkeletonButtonShape,\n  NzSkeletonInputSize,\n  NzSkeletonModule\n} from 'ng-zorro-antd/skeleton';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\n\n@Component({\n  selector: 'nz-demo-skeleton-element',\n  imports: [FormsModule, NzDividerModule, NzGridModule, NzSkeletonModule, NzRadioModule, NzSpaceModule, NzSwitchModule],\n  template: `\n    <nz-space nzSize=\"middle\">\n      <nz-skeleton-element\n        *nzSpaceItem\n        nzType=\"button\"\n        [nzActive]=\"elementActive\"\n        [nzSize]=\"elementSize\"\n        [nzShape]=\"buttonShape\"\n      />\n      <nz-skeleton-element\n        *nzSpaceItem\n        nzType=\"avatar\"\n        [nzActive]=\"elementActive\"\n        [nzSize]=\"elementSize\"\n        [nzShape]=\"avatarShape\"\n      />\n      <nz-skeleton-element\n        *nzSpaceItem\n        nzType=\"input\"\n        [nzActive]=\"elementActive\"\n        [nzSize]=\"elementSize\"\n        style=\"width:200px\"\n      />\n    </nz-space>\n    <br />\n    <br />\n    <nz-skeleton-element nzType=\"image\" [nzActive]=\"elementActive\" />\n    <nz-divider />\n    <div nz-row nzAlign=\"middle\" [nzGutter]=\"8\">\n      <div nz-col nzSpan=\"10\">\n        Size:\n        <nz-radio-group [(ngModel)]=\"elementSize\">\n          <label nz-radio-button nzValue=\"default\">Default</label>\n          <label nz-radio-button nzValue=\"large\">Large</label>\n          <label nz-radio-button nzValue=\"small\">Small</label>\n        </nz-radio-group>\n      </div>\n      <div nz-col nzSpan=\"5\">\n        Active:\n        <nz-switch [(ngModel)]=\"elementActive\" />\n      </div>\n    </div>\n    <br />\n    <br />\n    <div nz-row nzAlign=\"middle\" [nzGutter]=\"8\">\n      <div nz-col nzSpan=\"10\">\n        Button Shape:\n        <nz-radio-group [(ngModel)]=\"buttonShape\">\n          <label nz-radio-button nzValue=\"default\">Default</label>\n          <label nz-radio-button nzValue=\"square\">Square</label>\n          <label nz-radio-button nzValue=\"circle\">Circle</label>\n          <label nz-radio-button nzValue=\"round\">Round</label>\n        </nz-radio-group>\n      </div>\n      <div nz-col nzSpan=\"10\">\n        Avatar Shape:\n        <nz-radio-group [(ngModel)]=\"avatarShape\">\n          <label nz-radio-button nzValue=\"circle\">Circle</label>\n          <label nz-radio-button nzValue=\"square\">Square</label>\n        </nz-radio-group>\n      </div>\n    </div>\n  `\n})\nexport class NzDemoSkeletonElementComponent {\n  elementActive = false;\n  buttonShape: NzSkeletonButtonShape = 'default';\n  avatarShape: NzSkeletonAvatarShape = 'circle';\n  elementSize: NzSkeletonInputSize = 'default';\n}\n"
  },
  {
    "path": "components/skeleton/demo/list.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 列表样例\n  en-US: List Sample\n---\n\n## zh-CN\n\n在列表组件中使用加载占位符。\n\n## en-US\n\nUse skeleton in list component.\n"
  },
  {
    "path": "components/skeleton/demo/list.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzListModule } from 'ng-zorro-antd/list';\nimport { NzSkeletonModule } from 'ng-zorro-antd/skeleton';\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\n\n@Component({\n  selector: 'nz-demo-skeleton-list',\n  imports: [FormsModule, NzIconModule, NzListModule, NzSkeletonModule, NzSwitchModule],\n  template: `\n    <nz-switch [(ngModel)]=\"loading\" />\n    <nz-list [nzDataSource]=\"listData\" [nzRenderItem]=\"item\" nzItemLayout=\"vertical\">\n      <ng-template #item let-item>\n        <nz-list-item\n          [nzContent]=\"loading ? ' ' : item.content\"\n          [nzActions]=\"loading ? [] : [starAction, likeAction, msgAction]\"\n          [nzExtra]=\"loading ? null : extra\"\n        >\n          <nz-skeleton [nzLoading]=\"loading\" [nzActive]=\"true\" [nzAvatar]=\"true\">\n            <ng-template #starAction>\n              <nz-icon nzType=\"star-o\" style=\"margin-right: 8px;\" />\n              156\n            </ng-template>\n            <ng-template #likeAction>\n              <nz-icon nzType=\"like-o\" style=\"margin-right: 8px;\" />\n              156\n            </ng-template>\n            <ng-template #msgAction>\n              <nz-icon nzType=\"message\" style=\"margin-right: 8px;\" />\n              2\n            </ng-template>\n            <nz-list-item-meta [nzAvatar]=\"item.avatar\" [nzTitle]=\"nzTitle\" [nzDescription]=\"item.description\">\n              <ng-template #nzTitle>\n                <a href=\"{{ item.href }}\">{{ item.title }}</a>\n              </ng-template>\n            </nz-list-item-meta>\n            <ng-template #extra>\n              <img width=\"272\" alt=\"logo\" src=\"https://gw.alipayobjects.com/zos/rmsportal/mqaQswcyDLcXyDKnZfES.png\" />\n            </ng-template>\n          </nz-skeleton>\n        </nz-list-item>\n      </ng-template>\n    </nz-list>\n  `\n})\nexport class NzDemoSkeletonListComponent {\n  loading = true;\n  listData = new Array(3).fill({}).map((_i, index) => ({\n    href: 'https://ng.ant.design',\n    title: `ant design part ${index}`,\n    avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',\n    description: 'Ant Design, a design language for background applications, is refined by Ant UED Team.',\n    content:\n      'We supply a series of design principles, practical patterns and high quality design resources ' +\n      '(Sketch and Axure), to help people create their product prototypes beautifully and efficiently.'\n  }));\n}\n"
  },
  {
    "path": "components/skeleton/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Feedback\ntitle: Skeleton\ncols: 1\ncover: 'https://gw.alipayobjects.com/zos/alicdn/KpcciCJgv/Skeleton.svg'\ndescription: Provide a placeholder while you wait for content to load or visualize content that doesn't exist yet.\n---\n\n## When To Use\n\n- When resource needs long time loading, like low network speed.\n- The component contains information, such as a List or Card.\n- Only works when loading data for the first time.\n- Could be replaced by Spin in any situation but can provide a better user experience.\n\n## API\n\n### nz-skeleton\n\n| Property        | Description                                         | Type                             | Default |\n| --------------- | --------------------------------------------------- | -------------------------------- | ------- |\n| `[nzActive]`    | Show animation effect                               | `boolean`                        | `false` |\n| `[nzAvatar]`    | Show avatar placeholder                             | `boolean \\| NzSkeletonAvatar`    | `false` |\n| `[nzLoading]`   | Display the skeleton when `true`                    | `boolean`                        | -       |\n| `[nzParagraph]` | Show the paragraph placeholder                      | `boolean \\| NzSkeletonParagraph` | `true`  |\n| `[nzTitle]`     | Show the title placeholder                          | `boolean \\| NzSkeletonTitle`     | `true`  |\n| `[nzRound]`     | Show the paragraph and the title radius when `true` | `boolean`                        | `false` |\n\n### NzSkeletonAvatar\n\n| Property | Description          | Type                                        | Default |\n| -------- | -------------------- | ------------------------------------------- | ------- |\n| `size`   | Set the avatar size  | `number \\| 'large' \\| 'small' \\| 'default'` | -       |\n| `shape`  | Set the avatar shape | `'circle' \\| 'square'`                      | -       |\n\n### NzSkeletonTitle\n\n| Property | Description         | Type               | Default |\n| -------- | ------------------- | ------------------ | ------- |\n| `width`  | Set the title width | `number \\| string` | -       |\n\n### NzSkeletonParagraph\n\n| Property | Description                                                                                                                      | Type                                          | Default |\n| -------- | -------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- | ------- |\n| `rows`   | Set the row count of the paragraph                                                                                               | `number`                                      | -       |\n| `width`  | Set the width of the paragraph. When width is an Array, it can set the width of each row. Otherwise, only set the last row width | `number \\| string \\| Array<number \\| string>` | -       |\n\n### nz-skeleton-element [nzType=\"button\"]\n\n| Property     | Description           | Type                                           | Default     |\n| ------------ | --------------------- | ---------------------------------------------- | ----------- |\n| `[nzActive]` | Show animation effect | `boolean`                                      | `false`     |\n| `[nzSize]`   | Set the size          | `'large' \\| 'small' \\| 'default'`              | `'default'` |\n| `[nzShape]`  | Set the shape         | `'square' \\| 'circle' \\| 'round' \\| 'default'` | `'default'` |\n\n### nz-skeleton-element [nzType=\"avatar\"]\n\n| Property     | Description           | Type                                        | Default     |\n| ------------ | --------------------- | ------------------------------------------- | ----------- |\n| `[nzActive]` | Show animation effect | `boolean`                                   | `false`     |\n| `[nzSize]`   | Set the size          | `number \\| 'large' \\| 'small' \\| 'default'` | `'default'` |\n| `[nzShape]`  | Set the shape         | `'circle' \\| 'square'`                      | `'square'`  |\n\n### nz-skeleton-element [nzType=\"input\"]\n\n| Property     | Description           | Type                              | Default     |\n| ------------ | --------------------- | --------------------------------- | ----------- |\n| `[nzActive]` | Show animation effect | `boolean`                         | `false`     |\n| `[nzSize]`   | Set the size          | `'large' \\| 'small' \\| 'default'` | `'default'` |\n\n### nz-skeleton-element [nzType=\"image\"]\n\n| Property     | Description           | Type      | Default |\n| ------------ | --------------------- | --------- | ------- |\n| `[nzActive]` | Show animation effect | `boolean` | `false` |\n"
  },
  {
    "path": "components/skeleton/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 骨架屏\ntype: 反馈\ntitle: Skeleton\ncols: 1\ncover: 'https://gw.alipayobjects.com/zos/alicdn/KpcciCJgv/Skeleton.svg'\ndescription: 在需要等待加载内容的位置提供一个占位图形组合。\n---\n\n## 何时使用\n\n- 网络较慢，需要长时间等待加载处理的情况下。\n- 图文信息内容较多的列表/卡片中。\n- 只适合用在第一次加载数据的场景。\n- 可以被 Spin 完全代替，但是在可用的场景下可以比 Spin 提供更好的视觉效果和用户体验。\n\n## API\n\n### nz-skeleton\n\n| 属性            | 说明                                           | 类型                             | 默认值  |\n| --------------- | ---------------------------------------------- | -------------------------------- | ------- |\n| `[nzActive]`    | 是否展示动画效果                               | `boolean`                        | `false` |\n| `[nzAvatar]`    | 是否显示头像占位图                             | `boolean \\| NzSkeletonAvatar`    | `false` |\n| `[nzLoading]`   | 为 `true` 时，显示占位图。反之则直接展示子组件 | `boolean`                        | -       |\n| `[nzParagraph]` | 是否显示段落占位图                             | `boolean \\| NzSkeletonParagraph` | `true`  |\n| `[nzTitle]`     | 是否显示标题占位图                             | `boolean \\| NzSkeletonTitle`     | `true`  |\n| `[nzRound]`     | 为 `true` 时，段落和标题显示圆角               | `boolean`                        | `false` |\n\n### NzSkeletonAvatar\n\n| 属性    | 说明                 | 类型                                        | 默认值 |\n| ------- | -------------------- | ------------------------------------------- | ------ |\n| `size`  | 设置头像占位图的大小 | `number \\| 'large' \\| 'small' \\| 'default'` | -      |\n| `shape` | 指定头像的形状       | `'circle' \\| 'square'`                      | -      |\n\n### NzSkeletonTitle\n\n| 属性    | 说明                 | 类型               | 默认值 |\n| ------- | -------------------- | ------------------ | ------ |\n| `width` | 设置标题占位图的宽度 | `number \\| string` | -      |\n\n### NzSkeletonParagraph\n\n| 属性    | 说明                                                                       | 类型                                          | 默认值 |\n| ------- | -------------------------------------------------------------------------- | --------------------------------------------- | ------ |\n| `rows`  | 设置段落占位图的行数                                                       | `number`                                      | -      |\n| `width` | 设置标题占位图的宽度，若为数组时则为对应的每行宽度，反之则是最后一行的宽度 | `number \\| string \\| Array<number \\| string>` | -      |\n\n### nz-skeleton-element [nzType=\"button\"]\n\n| 属性         | 说明             | 类型                                           | 默认值      |\n| ------------ | ---------------- | ---------------------------------------------- | ----------- |\n| `[nzActive]` | 是否展示动画效果 | `boolean`                                      | `false`     |\n| `[nzSize]`   | 大小             | `'large' \\| 'small' \\| 'default'`              | `'default'` |\n| `[nzShape]`  | 形状             | `'square' \\| 'circle' \\| 'round' \\| 'default'` | `'default'` |\n\n### nz-skeleton-element [nzType=\"avatar\"]\n\n| 属性         | 说明             | 类型                                        | 默认值      |\n| ------------ | ---------------- | ------------------------------------------- | ----------- |\n| `[nzActive]` | 是否展示动画效果 | `boolean`                                   | `false`     |\n| `[nzSize]`   | 大小             | `number \\| 'large' \\| 'small' \\| 'default'` | `'default'` |\n| `[nzShape]`  | 形状             | `'circle' \\| 'square'`                      | `'square'`  |\n\n### nz-skeleton-element [nzType=\"input\"]\n\n| 属性         | 说明             | 类型                              | 默认值      |\n| ------------ | ---------------- | --------------------------------- | ----------- |\n| `[nzActive]` | 是否展示动画效果 | `boolean`                         | `false`     |\n| `[nzSize]`   | 大小             | `'large' \\| 'small' \\| 'default'` | `'default'` |\n\n### nz-skeleton-element [nzType=\"image\"]\n\n| 属性         | 说明             | 类型      | 默认值  |\n| ------------ | ---------------- | --------- | ------- |\n| `[nzActive]` | 是否展示动画效果 | `boolean` | `false` |\n"
  },
  {
    "path": "components/skeleton/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/skeleton/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/skeleton/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './skeleton.component';\nexport * from './skeleton.module';\nexport * from './skeleton.type';\nexport * from './skeleton-element.component';\n"
  },
  {
    "path": "components/skeleton/skeleton-element.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  Directive,\n  Input,\n  OnChanges,\n  SimpleChanges,\n  booleanAttribute\n} from '@angular/core';\n\nimport {\n  NzSkeletonAvatarShape,\n  NzSkeletonAvatarSize,\n  NzSkeletonButtonShape,\n  NzSkeletonButtonSize,\n  NzSkeletonInputSize\n} from './skeleton.type';\n\n@Directive({\n  selector: 'nz-skeleton-element',\n  host: {\n    class: 'ant-skeleton ant-skeleton-element',\n    '[class.ant-skeleton-active]': 'nzActive',\n    '[class.ant-skeleton-block]': 'nzBlock'\n  }\n})\nexport class NzSkeletonElementDirective {\n  @Input({ transform: booleanAttribute }) nzActive: boolean = false;\n  @Input() nzType!: 'button' | 'input' | 'avatar' | 'image';\n  @Input({ transform: booleanAttribute }) nzBlock: boolean = false;\n}\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  // eslint-disable-next-line @angular-eslint/component-selector\n  selector: 'nz-skeleton-element[nzType=\"button\"]',\n  template: `\n    <span\n      class=\"ant-skeleton-button\"\n      [class.ant-skeleton-button-square]=\"nzShape === 'square'\"\n      [class.ant-skeleton-button-round]=\"nzShape === 'round'\"\n      [class.ant-skeleton-button-circle]=\"nzShape === 'circle'\"\n      [class.ant-skeleton-button-lg]=\"nzSize === 'large'\"\n      [class.ant-skeleton-button-sm]=\"nzSize === 'small'\"\n    ></span>\n  `\n})\nexport class NzSkeletonElementButtonComponent {\n  @Input() nzShape: NzSkeletonButtonShape = 'default';\n  @Input() nzSize: NzSkeletonButtonSize = 'default';\n}\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  // eslint-disable-next-line @angular-eslint/component-selector\n  selector: 'nz-skeleton-element[nzType=\"avatar\"]',\n  template: `\n    <span\n      class=\"ant-skeleton-avatar\"\n      [class.ant-skeleton-avatar-square]=\"nzShape === 'square'\"\n      [class.ant-skeleton-avatar-circle]=\"nzShape === 'circle'\"\n      [class.ant-skeleton-avatar-lg]=\"nzSize === 'large'\"\n      [class.ant-skeleton-avatar-sm]=\"nzSize === 'small'\"\n      [style]=\"styleMap\"\n    ></span>\n  `\n})\nexport class NzSkeletonElementAvatarComponent implements OnChanges {\n  @Input() nzShape: NzSkeletonAvatarShape = 'circle';\n  @Input() nzSize: NzSkeletonAvatarSize = 'default';\n\n  styleMap = {};\n\n  ngOnChanges(changes: SimpleChanges): void {\n    if (changes.nzSize && typeof this.nzSize === 'number') {\n      const sideLength = `${this.nzSize}px`;\n      this.styleMap = { width: sideLength, height: sideLength, 'line-height': sideLength };\n    } else {\n      this.styleMap = {};\n    }\n  }\n}\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  // eslint-disable-next-line @angular-eslint/component-selector\n  selector: 'nz-skeleton-element[nzType=\"input\"]',\n  template: `\n    <span\n      class=\"ant-skeleton-input\"\n      [class.ant-skeleton-input-lg]=\"nzSize === 'large'\"\n      [class.ant-skeleton-input-sm]=\"nzSize === 'small'\"\n    ></span>\n  `\n})\nexport class NzSkeletonElementInputComponent {\n  @Input() nzSize: NzSkeletonInputSize = 'default';\n}\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  // eslint-disable-next-line @angular-eslint/component-selector\n  selector: 'nz-skeleton-element[nzType=\"image\"]',\n  template: `\n    <span class=\"ant-skeleton-image\">\n      <svg class=\"ant-skeleton-image-svg\" viewBox=\"0 0 1098 1024\" xmlns=\"http://www.w3.org/2000/svg\">\n        <path\n          d=\"M365.714286 329.142857q0 45.714286-32.036571 77.677714t-77.677714 32.036571-77.677714-32.036571-32.036571-77.677714 32.036571-77.677714 77.677714-32.036571 77.677714 32.036571 32.036571 77.677714zM950.857143 548.571429l0 256-804.571429 0 0-109.714286 182.857143-182.857143 91.428571 91.428571 292.571429-292.571429zM1005.714286 146.285714l-914.285714 0q-7.460571 0-12.873143 5.412571t-5.412571 12.873143l0 694.857143q0 7.460571 5.412571 12.873143t12.873143 5.412571l914.285714 0q7.460571 0 12.873143-5.412571t5.412571-12.873143l0-694.857143q0-7.460571-5.412571-12.873143t-12.873143-5.412571zM1097.142857 164.571429l0 694.857143q0 37.741714-26.843429 64.585143t-64.585143 26.843429l-914.285714 0q-37.741714 0-64.585143-26.843429t-26.843429-64.585143l0-694.857143q0-37.741714 26.843429-64.585143t64.585143-26.843429l914.285714 0q37.741714 0 64.585143 26.843429t26.843429 64.585143z\"\n          class=\"ant-skeleton-image-path\"\n        />\n      </svg>\n    </span>\n  `\n})\nexport class NzSkeletonElementImageComponent {}\n"
  },
  {
    "path": "components/skeleton/skeleton.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  inject,\n  Input,\n  OnChanges,\n  OnInit,\n  SimpleChanges,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { toCssPixel } from 'ng-zorro-antd/core/util';\n\nimport { NzSkeletonElementAvatarComponent, NzSkeletonElementDirective } from './skeleton-element.component';\nimport {\n  NzSkeletonAvatar,\n  NzSkeletonAvatarShape,\n  NzSkeletonAvatarSize,\n  NzSkeletonParagraph,\n  NzSkeletonTitle\n} from './skeleton.type';\n\n@Component({\n  selector: 'nz-skeleton',\n  exportAs: 'nzSkeleton',\n  host: {\n    class: 'ant-skeleton',\n    '[class.ant-skeleton-with-avatar]': '!!nzAvatar',\n    '[class.ant-skeleton-active]': 'nzActive',\n    '[class.ant-skeleton-round]': 'nzRound'\n  },\n  template: `\n    @if (nzLoading) {\n      @if (!!nzAvatar) {\n        <div class=\"ant-skeleton-header\">\n          <nz-skeleton-element\n            nzType=\"avatar\"\n            [nzSize]=\"avatar.size || 'default'\"\n            [nzShape]=\"avatar.shape || 'circle'\"\n          />\n        </div>\n      }\n      <div class=\"ant-skeleton-content\">\n        @if (!!nzTitle) {\n          <h3 class=\"ant-skeleton-title\" [style.width]=\"toCSSUnit(title.width)\"></h3>\n        }\n        @if (!!nzParagraph) {\n          <ul class=\"ant-skeleton-paragraph\">\n            @for (row of rowsList; track row) {\n              <li [style.width]=\"toCSSUnit(widthList[$index])\"></li>\n            }\n          </ul>\n        }\n      </div>\n    } @else {\n      <ng-content />\n    }\n  `,\n  imports: [NzSkeletonElementDirective, NzSkeletonElementAvatarComponent],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None\n})\nexport class NzSkeletonComponent implements OnInit, OnChanges {\n  private cdr = inject(ChangeDetectorRef);\n\n  @Input({ transform: booleanAttribute }) nzActive = false;\n  @Input({ transform: booleanAttribute }) nzLoading = true;\n  @Input({ transform: booleanAttribute }) nzRound = false;\n  @Input() nzTitle: NzSkeletonTitle | boolean = true;\n  @Input() nzAvatar: NzSkeletonAvatar | boolean = false;\n  @Input() nzParagraph: NzSkeletonParagraph | boolean = true;\n\n  title!: NzSkeletonTitle;\n  avatar!: NzSkeletonAvatar;\n  paragraph!: NzSkeletonParagraph;\n  rowsList: number[] = [];\n  widthList: Array<number | string> = [];\n\n  protected toCSSUnit(value: number | string = ''): string {\n    return toCssPixel(value);\n  }\n\n  private getTitleProps(): NzSkeletonTitle {\n    const hasAvatar = !!this.nzAvatar;\n    const hasParagraph = !!this.nzParagraph;\n    let width = '';\n    if (!hasAvatar && hasParagraph) {\n      width = '38%';\n    } else if (hasAvatar && hasParagraph) {\n      width = '50%';\n    }\n    return { width, ...this.getProps(this.nzTitle) };\n  }\n\n  private getAvatarProps(): NzSkeletonAvatar {\n    const shape: NzSkeletonAvatarShape = !!this.nzTitle && !this.nzParagraph ? 'square' : 'circle';\n    const size: NzSkeletonAvatarSize = 'large';\n    return { shape, size, ...this.getProps(this.nzAvatar) };\n  }\n\n  private getParagraphProps(): NzSkeletonParagraph {\n    const hasAvatar = !!this.nzAvatar;\n    const hasTitle = !!this.nzTitle;\n    const basicProps: NzSkeletonParagraph = {};\n    // Width\n    if (!hasAvatar || !hasTitle) {\n      basicProps.width = '61%';\n    }\n    // Rows\n    if (!hasAvatar && hasTitle) {\n      basicProps.rows = 3;\n    } else {\n      basicProps.rows = 2;\n    }\n    return { ...basicProps, ...this.getProps(this.nzParagraph) };\n  }\n\n  private getProps<T>(prop: T | boolean | undefined): T | {} {\n    return prop && typeof prop === 'object' ? prop : {};\n  }\n\n  private getWidthList(): Array<number | string> {\n    const { width, rows } = this.paragraph;\n    let widthList: Array<string | number> = [];\n    if (width && Array.isArray(width)) {\n      widthList = width;\n    } else if (width && !Array.isArray(width)) {\n      widthList = [];\n      widthList[rows! - 1] = width;\n    }\n    return widthList;\n  }\n\n  private updateProps(): void {\n    this.title = this.getTitleProps();\n    this.avatar = this.getAvatarProps();\n    this.paragraph = this.getParagraphProps();\n    this.rowsList = [...Array(this.paragraph.rows)];\n    this.widthList = this.getWidthList();\n    this.cdr.markForCheck();\n  }\n\n  ngOnInit(): void {\n    this.updateProps();\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    if (changes.nzTitle || changes.nzAvatar || changes.nzParagraph) {\n      this.updateProps();\n    }\n  }\n}\n"
  },
  {
    "path": "components/skeleton/skeleton.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport {\n  NzSkeletonElementAvatarComponent,\n  NzSkeletonElementButtonComponent,\n  NzSkeletonElementDirective,\n  NzSkeletonElementImageComponent,\n  NzSkeletonElementInputComponent\n} from './skeleton-element.component';\nimport { NzSkeletonComponent } from './skeleton.component';\n\n@NgModule({\n  imports: [\n    NzSkeletonElementDirective,\n    NzSkeletonComponent,\n    NzSkeletonElementButtonComponent,\n    NzSkeletonElementAvatarComponent,\n    NzSkeletonElementImageComponent,\n    NzSkeletonElementInputComponent\n  ],\n  exports: [\n    NzSkeletonElementDirective,\n    NzSkeletonComponent,\n    NzSkeletonElementButtonComponent,\n    NzSkeletonElementAvatarComponent,\n    NzSkeletonElementImageComponent,\n    NzSkeletonElementInputComponent\n  ]\n})\nexport class NzSkeletonModule {}\n"
  },
  {
    "path": "components/skeleton/skeleton.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, DebugElement, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzSkeletonModule } from './skeleton.module';\nimport {\n  NzSkeletonAvatar,\n  NzSkeletonAvatarShape,\n  NzSkeletonAvatarSize,\n  NzSkeletonButtonShape,\n  NzSkeletonButtonSize,\n  NzSkeletonInputSize,\n  NzSkeletonParagraph,\n  NzSkeletonTitle\n} from './skeleton.type';\n\ndescribe('skeleton', () => {\n  let fixture: ComponentFixture<NzTestSkeletonComponent>;\n  let testComp: NzTestSkeletonComponent;\n  let dl: DebugElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzTestSkeletonComponent);\n    testComp = fixture.componentInstance;\n    dl = fixture.debugElement;\n    fixture.detectChanges();\n  });\n\n  describe('#nzActive', () => {\n    it('should active work', () => {\n      expect(dl.nativeElement.querySelector('.ant-skeleton-active')).toBeFalsy();\n      testComp.nzActive = true;\n      fixture.detectChanges();\n      expect(dl.nativeElement.querySelector('.ant-skeleton-active')).toBeTruthy();\n    });\n  });\n\n  describe('#nzTitle', () => {\n    it('should basic width prop work', () => {\n      expect(dl.nativeElement.querySelector('.ant-skeleton-title')).toBeFalsy();\n      testComp.nzTitle = true;\n      testComp.nzAvatar = false;\n      testComp.nzParagraph = true;\n      fixture.detectChanges();\n      expect(dl.nativeElement.querySelector('.ant-skeleton-title').style.width).toBe('38%');\n      testComp.nzAvatar = true;\n      fixture.detectChanges();\n      expect(dl.nativeElement.querySelector('.ant-skeleton-title').style.width).toBe('50%');\n      testComp.nzParagraph = false;\n      fixture.detectChanges();\n      expect(dl.nativeElement.querySelector('.ant-skeleton-title').style.width).toBe('');\n    });\n    it('should customize width props work', () => {\n      testComp.nzTitle = true;\n      fixture.detectChanges();\n      expect(dl.nativeElement.querySelector('.ant-skeleton-title').style.width).toBe('');\n      testComp.nzTitle = { width: '50%' };\n      fixture.detectChanges();\n      expect(dl.nativeElement.querySelector('.ant-skeleton-title').style.width).toBe('50%');\n      testComp.nzTitle = { width: 200 };\n      fixture.detectChanges();\n      expect(dl.nativeElement.querySelector('.ant-skeleton-title').style.width).toBe('200px');\n    });\n  });\n\n  describe('#nzAvatar', () => {\n    it('should basic avatar props work', () => {\n      testComp.nzTitle = true;\n      testComp.nzAvatar = true;\n      testComp.nzParagraph = false;\n      fixture.detectChanges();\n      expect(dl.nativeElement.querySelector('.ant-skeleton-avatar-square')).toBeTruthy();\n      expect(dl.nativeElement.querySelector('.ant-skeleton-with-avatar')).toBeTruthy();\n      testComp.nzParagraph = true;\n      fixture.detectChanges();\n      expect(dl.nativeElement.querySelector('.ant-skeleton-avatar-circle')).toBeTruthy();\n    });\n    for (const type of ['square', 'circle']) {\n      it(`should customize shape ${type} work`, () => {\n        testComp.nzAvatar = { shape: type } as NzSkeletonAvatar;\n        fixture.detectChanges();\n        expect(dl.query(By.css(`.ant-skeleton-avatar-${type}`)) !== null).toBe(true);\n      });\n    }\n    for (const type of [\n      { size: 'large', cls: 'lg' },\n      { size: 'small', cls: 'sm' }\n    ]) {\n      it(`should customize size ${type.size} work`, () => {\n        testComp.nzAvatar = { size: type.size } as NzSkeletonAvatar;\n        fixture.detectChanges();\n        expect(dl.query(By.css(`.ant-skeleton-avatar-${type.cls}`)) !== null).toBe(true);\n      });\n    }\n  });\n\n  describe('#nzParagraph', () => {\n    it('should basic rows and width work', () => {\n      testComp.nzTitle = true;\n      testComp.nzAvatar = true;\n      testComp.nzParagraph = true;\n      fixture.detectChanges();\n      let paragraphs = dl.nativeElement.querySelectorAll('.ant-skeleton-paragraph > li');\n      expect(paragraphs.length).toBe(2);\n      expect(paragraphs[0].style.width).toBe('');\n      expect(paragraphs[1].style.width).toBe('');\n      testComp.nzAvatar = false;\n      fixture.detectChanges();\n      paragraphs = dl.nativeElement.querySelectorAll('.ant-skeleton-paragraph > li');\n      expect(paragraphs.length).toBe(3);\n      expect(paragraphs[1].style.width).toBe('');\n      expect(paragraphs[2].style.width).toBe('61%');\n    });\n    it('should width type is string or number work', () => {\n      testComp.nzParagraph = { width: 100 };\n      fixture.detectChanges();\n      let paragraphs = dl.nativeElement.querySelectorAll('.ant-skeleton-paragraph > li');\n      expect(paragraphs[0].style.width).toBe('');\n      expect(paragraphs[1].style.width).toBe('100px');\n      expect(paragraphs[2]).toBeFalsy();\n      testComp.nzParagraph = { width: 100, rows: 3 };\n      fixture.detectChanges();\n      paragraphs = dl.nativeElement.querySelectorAll('.ant-skeleton-paragraph > li');\n      expect(paragraphs[1].style.width).toBe('');\n      expect(paragraphs[2].style.width).toBe('100px');\n    });\n    it('should define width type is Array work', () => {\n      testComp.nzParagraph = { width: [200, '100px', '90%'] };\n      fixture.detectChanges();\n      let paragraphs = dl.nativeElement.querySelectorAll('.ant-skeleton-paragraph > li');\n      expect(paragraphs[0].style.width).toBe('200px');\n      expect(paragraphs[1].style.width).toBe('100px');\n      expect(paragraphs[2]).toBeFalsy();\n      testComp.nzParagraph = { width: [200, '100px', '90%'], rows: 4 };\n      fixture.detectChanges();\n      paragraphs = dl.nativeElement.querySelectorAll('.ant-skeleton-paragraph > li');\n      expect(paragraphs[2].style.width).toBe('90%');\n      expect(paragraphs[3].style.width).toBe('');\n    });\n  });\n\n  describe('#nzRound', () => {\n    it('should round work', () => {\n      expect(dl.nativeElement.querySelector('.ant-skeleton-round')).toBeFalsy();\n      testComp.nzRound = true;\n      fixture.detectChanges();\n      expect(dl.nativeElement.querySelector('.ant-skeleton-round')).toBeTruthy();\n    });\n  });\n});\n\ndescribe('skeleton element', () => {\n  let fixture: ComponentFixture<NzTestSkeletonElementComponent>;\n  let testComp: NzTestSkeletonElementComponent;\n  let dl: DebugElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzTestSkeletonElementComponent);\n    testComp = fixture.componentInstance;\n    dl = fixture.debugElement;\n    fixture.detectChanges();\n  });\n\n  it('should nzActive work', () => {\n    expect(dl.nativeElement.querySelector('.ant-skeleton-active')).toBeFalsy();\n    testComp.nzActive = true;\n    fixture.detectChanges();\n    expect(dl.nativeElement.querySelector('.ant-skeleton-active')).toBeTruthy();\n    testComp.useSuite = 4;\n    fixture.detectChanges();\n    expect(dl.nativeElement.querySelector('.ant-skeleton-active')).toBeTruthy();\n  });\n\n  it('should nzSize work', () => {\n    expect(dl.nativeElement.querySelector('.ant-skeleton-avatar-lg')).toBeFalsy();\n    testComp.nzSize = 'large';\n    fixture.detectChanges();\n    expect(dl.nativeElement.querySelector('.ant-skeleton-avatar-lg')).toBeTruthy();\n    testComp.nzSize = 40;\n    fixture.detectChanges();\n    expect(dl.nativeElement.querySelector('.ant-skeleton-avatar').style.width).toBe('40px');\n    expect(dl.nativeElement.querySelector('.ant-skeleton-avatar').style.height).toBe('40px');\n    expect(dl.nativeElement.querySelector('.ant-skeleton-avatar').style.lineHeight).toBe('40px');\n    // number size only work in 'avatar' type\n    testComp.useSuite = 2;\n    fixture.detectChanges();\n    expect(dl.nativeElement.querySelector('.ant-skeleton-button').style.width).toBeFalsy();\n  });\n\n  it('should nzShape work', () => {\n    fixture.detectChanges();\n    expect(dl.nativeElement.querySelector('.ant-skeleton-avatar-circle')).toBeNull();\n    testComp.nzShape = 'circle';\n    fixture.detectChanges();\n    expect(dl.nativeElement.querySelector('.ant-skeleton-avatar-circle')).toBeTruthy();\n    testComp.nzShape = 'square';\n    fixture.detectChanges();\n    expect(dl.nativeElement.querySelector('.ant-skeleton-avatar-square')).toBeTruthy();\n\n    testComp.useSuite = 2;\n    testComp.nzShape = 'round';\n    fixture.detectChanges();\n    expect(dl.nativeElement.querySelector('.ant-skeleton-button-round')).toBeTruthy();\n  });\n\n  it('should image svg work', () => {\n    fixture.detectChanges();\n    expect(dl.nativeElement.querySelector('svg')).toBeNull();\n    testComp.useSuite = 4;\n    fixture.detectChanges();\n    expect(dl.nativeElement.querySelector('svg')).toBeTruthy();\n  });\n});\n\n@Component({\n  imports: [NzSkeletonModule],\n  template: `\n    <nz-skeleton\n      [nzActive]=\"nzActive\"\n      [nzAvatar]=\"nzAvatar\"\n      [nzTitle]=\"nzTitle\"\n      [nzParagraph]=\"nzParagraph\"\n      [nzRound]=\"nzRound\"\n    />\n  `\n})\nexport class NzTestSkeletonComponent {\n  nzActive: boolean = false;\n  nzRound: boolean = false;\n  nzAvatar: NzSkeletonAvatar | boolean = false;\n  nzTitle: NzSkeletonTitle | boolean = false;\n  nzParagraph: NzSkeletonParagraph | boolean = false;\n}\n\n@Component({\n  imports: [NzSkeletonModule],\n  template: `\n    @switch (useSuite) {\n      @case (1) {\n        <nz-skeleton-element nzType=\"avatar\" [nzActive]=\"nzActive\" [nzSize]=\"nzSize\" [nzShape]=\"$any(nzShape)\" />\n      }\n      @case (2) {\n        <nz-skeleton-element nzType=\"button\" [nzActive]=\"nzActive\" [nzSize]=\"$any(nzSize)\" [nzShape]=\"nzShape\" />\n      }\n      @case (3) {\n        <nz-skeleton-element nzType=\"input\" [nzActive]=\"nzActive\" [nzSize]=\"$any(nzSize)\" />\n      }\n      @case (4) {\n        <nz-skeleton-element nzType=\"image\" [nzActive]=\"nzActive\" />\n      }\n    }\n  `\n})\nexport class NzTestSkeletonElementComponent {\n  useSuite = 1;\n  nzActive: boolean = false;\n  nzSize: NzSkeletonAvatarSize | NzSkeletonButtonSize | NzSkeletonInputSize = 'default';\n  nzShape: NzSkeletonAvatarShape | NzSkeletonButtonShape = 'default';\n}\n"
  },
  {
    "path": "components/skeleton/skeleton.type.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport type NzSkeletonParagraphWidth = number | string | Array<number | string>;\nexport type NzSkeletonButtonShape = 'square' | 'circle' | 'round' | 'default';\nexport type NzSkeletonAvatarShape = 'square' | 'circle';\nexport type NzSkeletonInputSize = 'large' | 'small' | 'default';\nexport type NzSkeletonButtonSize = NzSkeletonInputSize;\nexport type NzSkeletonAvatarSize = NzSkeletonInputSize | number;\n\nexport interface NzSkeletonAvatar {\n  size?: NzSkeletonAvatarSize;\n  shape?: NzSkeletonAvatarShape;\n}\n\nexport interface NzSkeletonTitle {\n  width?: number | string;\n}\n\nexport interface NzSkeletonParagraph {\n  rows?: number;\n  width?: NzSkeletonParagraphWidth;\n}\n"
  },
  {
    "path": "components/skeleton/style/entry.less",
    "content": "@import './index.less';\n"
  },
  {
    "path": "components/skeleton/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@skeleton-prefix-cls: ~'@{ant-prefix}-skeleton';\n@skeleton-avatar-prefix-cls: ~'@{skeleton-prefix-cls}-avatar';\n@skeleton-title-prefix-cls: ~'@{skeleton-prefix-cls}-title';\n@skeleton-paragraph-prefix-cls: ~'@{skeleton-prefix-cls}-paragraph';\n@skeleton-button-prefix-cls: ~'@{skeleton-prefix-cls}-button';\n@skeleton-input-prefix-cls: ~'@{skeleton-prefix-cls}-input';\n@skeleton-image-prefix-cls: ~'@{skeleton-prefix-cls}-image';\n@skeleton-block-radius: @border-radius-base;\n\n.@{skeleton-prefix-cls} {\n  display: table;\n  width: 100%;\n\n  &-header {\n    display: table-cell;\n    padding-right: @padding-md;\n    vertical-align: top;\n\n    // Avatar\n    .@{skeleton-avatar-prefix-cls} {\n      .skeleton-element-avatar();\n    }\n  }\n\n  &-content {\n    display: table-cell;\n    width: 100%;\n    vertical-align: top;\n\n    // Title\n    .@{skeleton-title-prefix-cls} {\n      width: 100%;\n      height: @skeleton-title-height;\n      background: @skeleton-color;\n      border-radius: @skeleton-block-radius;\n\n      + .@{skeleton-paragraph-prefix-cls} {\n        margin-top: @skeleton-title-paragraph-margin-top;\n      }\n    }\n\n    // paragraph\n    .@{skeleton-paragraph-prefix-cls} {\n      padding: 0;\n\n      > li {\n        width: 100%;\n        height: @skeleton-paragraph-li-height;\n        list-style: none;\n        background: @skeleton-color;\n        border-radius: @skeleton-block-radius;\n\n        &:last-child:not(:first-child):not(:nth-child(2)) {\n          width: 61%;\n        }\n\n        + li {\n          margin-top: @skeleton-paragraph-li-margin-top;\n        }\n      }\n    }\n  }\n\n  &-with-avatar &-content {\n    // Title\n    .@{skeleton-title-prefix-cls} {\n      margin-top: @margin-sm;\n\n      + .@{skeleton-paragraph-prefix-cls} {\n        margin-top: @skeleton-paragraph-margin-top;\n      }\n    }\n  }\n\n  &-round &-content {\n    .@{skeleton-title-prefix-cls},\n    .@{skeleton-paragraph-prefix-cls} > li {\n      border-radius: 100px;\n    }\n  }\n\n  // With active animation\n  &-active {\n    .@{skeleton-title-prefix-cls},\n    .@{skeleton-paragraph-prefix-cls} > li,\n    .@{skeleton-avatar-prefix-cls},\n    .@{skeleton-button-prefix-cls},\n    .@{skeleton-input-prefix-cls},\n    .@{skeleton-image-prefix-cls} {\n      .skeleton-color();\n    }\n  }\n\n  // Skeleton Block Button, Input\n  &.@{skeleton-prefix-cls}-block {\n    width: 100%;\n\n    .@{skeleton-button-prefix-cls} {\n      width: 100%;\n    }\n\n    .@{skeleton-input-prefix-cls} {\n      width: 100%;\n    }\n  }\n\n  // Skeleton element\n  &-element {\n    display: inline-block;\n    width: auto;\n\n    .@{skeleton-button-prefix-cls} {\n      .skeleton-element-button();\n    }\n\n    .@{skeleton-avatar-prefix-cls} {\n      .skeleton-element-avatar();\n    }\n\n    .@{skeleton-input-prefix-cls} {\n      .skeleton-element-input();\n    }\n\n    .@{skeleton-image-prefix-cls} {\n      .skeleton-element-image();\n    }\n  }\n}\n// Button\n.skeleton-element-button() {\n  display: inline-block;\n  vertical-align: top;\n  background: @skeleton-color;\n  border-radius: @border-radius-base;\n\n  .skeleton-element-button-size(@btn-height-base);\n\n  &-lg {\n    .skeleton-element-button-size(@btn-height-lg);\n  }\n\n  &-sm {\n    .skeleton-element-button-size(@btn-height-sm);\n  }\n}\n// Avatar\n.skeleton-element-avatar() {\n  display: inline-block;\n  vertical-align: top;\n  background: @skeleton-color;\n\n  .skeleton-element-avatar-size(@avatar-size-base);\n\n  &-lg {\n    .skeleton-element-avatar-size(@avatar-size-lg);\n  }\n\n  &-sm {\n    .skeleton-element-avatar-size(@avatar-size-sm);\n  }\n}\n\n// Input\n.skeleton-element-input() {\n  display: inline-block;\n  vertical-align: top;\n  background: @skeleton-color;\n\n  .skeleton-element-input-size(@input-height-base);\n\n  &-lg {\n    .skeleton-element-input-size(@input-height-lg);\n  }\n\n  &-sm {\n    .skeleton-element-input-size(@input-height-sm);\n  }\n}\n\n// Image\n.skeleton-element-image() {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  vertical-align: top;\n  background: @skeleton-color;\n\n  .skeleton-element-image-size(@image-size-base*2);\n\n  &-path {\n    fill: #bfbfbf;\n  }\n\n  &-svg {\n    .skeleton-element-image-size(@image-size-base);\n    max-width: @image-size-base * 4;\n    max-height: @image-size-base * 4;\n  }\n}\n\n.skeleton-element-avatar-size(@size) {\n  width: @size;\n  .skeleton-element-common-size(@size);\n\n  &.@{skeleton-avatar-prefix-cls}-circle {\n    border-radius: 50%;\n  }\n}\n\n.skeleton-element-button-size(@size) {\n  width: @size * 2;\n  min-width: @size * 2;\n  .skeleton-element-common-size(@size);\n\n  &.@{skeleton-button-prefix-cls}-square {\n    width: @size;\n    min-width: @size;\n  }\n\n  &.@{skeleton-button-prefix-cls}-circle {\n    width: @size;\n    min-width: @size;\n    border-radius: 50%;\n  }\n\n  &.@{skeleton-button-prefix-cls}-round {\n    border-radius: @size;\n  }\n}\n\n.skeleton-element-input-size(@size) {\n  width: @size * 5;\n  min-width: @size * 5;\n  .skeleton-element-common-size(@size);\n}\n\n.skeleton-element-image-size(@size) {\n  width: @size;\n  .skeleton-element-common-size(@size);\n\n  &.@{skeleton-image-prefix-cls}-circle {\n    border-radius: 50%;\n  }\n}\n\n.skeleton-element-common-size(@size) {\n  height: @size;\n  line-height: @size;\n}\n\n.skeleton-color() {\n  position: relative;\n  // fix https://github.com/ant-design/ant-design/issues/36444\n  // https://monshin.github.io/202109/css/safari-border-radius-overflow-hidden/\n  /* stylelint-disable-next-line property-no-vendor-prefix,value-no-vendor-prefix */\n  z-index: 0;\n  overflow: hidden;\n  background: transparent;\n\n  &::after {\n    position: absolute;\n    top: 0;\n    right: -150%;\n    bottom: 0;\n    left: -150%;\n    background: linear-gradient(\n      90deg,\n      @skeleton-color 25%,\n      @skeleton-to-color 37%,\n      @skeleton-color 63%\n    );\n    animation: ~'@{skeleton-prefix-cls}-loading' 1.4s ease infinite;\n    content: '';\n  }\n}\n\n@keyframes ~\"@{skeleton-prefix-cls}-loading\" {\n  0% {\n    transform: translateX(-37.5%);\n  }\n\n  100% {\n    transform: translateX(37.5%);\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/skeleton/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@skeleton-prefix-cls: ~'@{ant-prefix}-skeleton';\n@skeleton-avatar-prefix-cls: ~'@{skeleton-prefix-cls}-avatar';\n@skeleton-title-prefix-cls: ~'@{skeleton-prefix-cls}-title';\n@skeleton-paragraph-prefix-cls: ~'@{skeleton-prefix-cls}-paragraph';\n\n.@{skeleton-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &-header {\n    .@{skeleton-prefix-cls}-rtl & {\n      padding-right: 0;\n      padding-left: 16px;\n    }\n  }\n\n  // With active animation\n  &.@{skeleton-prefix-cls}-active {\n    & .@{skeleton-prefix-cls}-content {\n      .@{skeleton-title-prefix-cls},\n      .@{skeleton-paragraph-prefix-cls} > li {\n        .@{skeleton-prefix-cls}-rtl& {\n          animation-name: ~'@{skeleton-prefix-cls}-loading-rtl';\n        }\n      }\n    }\n\n    .@{skeleton-avatar-prefix-cls} {\n      .@{skeleton-prefix-cls}-rtl& {\n        animation-name: ~'@{skeleton-prefix-cls}-loading-rtl';\n      }\n    }\n  }\n}\n\n@keyframes ~\"@{skeleton-prefix-cls}-loading-rtl\" {\n  0% {\n    background-position: 0% 50%;\n  }\n\n  100% {\n    background-position: 100% 50%;\n  }\n}\n"
  },
  {
    "path": "components/slider/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n基本滑动条。当 `nzRange` 为 `true` 时，渲染为双滑块。当 `nzDisabled` 为 `true` 时，滑块处于不可用状态。\n\n## en-US\n\nBasic slider. When `nzRange` is `true`, display as dual thumb mode. When `nzDisabled` is `true`, the slider will not be interactive.\n"
  },
  {
    "path": "components/slider/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSliderModule } from 'ng-zorro-antd/slider';\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\n\n@Component({\n  selector: 'nz-demo-slider-basic',\n  imports: [FormsModule, NzSliderModule, NzSwitchModule],\n  template: `\n    <nz-slider [(ngModel)]=\"value1\" [nzDisabled]=\"disabled\" />\n    <nz-slider nzRange [(ngModel)]=\"value2\" [nzDisabled]=\"disabled\" />\n    Disabled:\n    <nz-switch nzSize=\"small\" [(ngModel)]=\"disabled\" />\n  `\n})\nexport class NzDemoSliderBasicComponent {\n  disabled = false;\n  value1 = 30;\n  value2 = [20, 50];\n}\n"
  },
  {
    "path": "components/slider/demo/event.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 事件\n  en-US: Event\n---\n\n## zh-CN\n\n当 Slider 的值发生改变时，会触发 `nzOnChange` 事件，并把改变后的值作为参数传入。在 `onmouseup` 时，会触发 `nzOnAfterChange` 事件，并把当前值作为参数传入。\n\n## en-US\n\nThe `nzOnChange` callback function will fire when the user changes the slider's value. The `nzOnAfterChange` callback function will fire when `onmouseup` fired.\n"
  },
  {
    "path": "components/slider/demo/event.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSliderModule } from 'ng-zorro-antd/slider';\n\n@Component({\n  selector: 'nz-demo-slider-event',\n  imports: [FormsModule, NzSliderModule],\n  template: `\n    <nz-slider [(ngModel)]=\"singleValue\" (ngModelChange)=\"onChange($event)\" (nzOnAfterChange)=\"onAfterChange($event)\" />\n    <nz-slider\n      nzRange\n      [nzStep]=\"10\"\n      [(ngModel)]=\"rangeValue\"\n      (ngModelChange)=\"onChange($event)\"\n      (nzOnAfterChange)=\"onAfterChange($event)\"\n    />\n  `\n})\nexport class NzDemoSliderEventComponent {\n  singleValue = 30;\n  rangeValue = [20, 50];\n\n  onChange(value: number): void {\n    console.log(`onChange: ${value}`);\n  }\n\n  onAfterChange(value: number[] | number): void {\n    console.log(`onAfterChange: ${value}`);\n  }\n}\n"
  },
  {
    "path": "components/slider/demo/icon-slider.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 带 icon 的滑块\n  en-US: Slider with icon\n---\n\n## zh-CN\n\n滑块左右可以设置图标来表达业务含义。\n\n## en-US\n\nYou can add an icon beside the slider to make it meaningful.\n"
  },
  {
    "path": "components/slider/demo/icon-slider.ts",
    "content": "import { Component, OnInit } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzSliderModule } from 'ng-zorro-antd/slider';\n\n@Component({\n  selector: 'nz-demo-slider-icon-slider',\n  imports: [FormsModule, NzIconModule, NzSliderModule],\n  template: `\n    <div class=\"icon-wrapper test-class\">\n      <nz-icon nzType=\"frown\" [class.icon-highlight]=\"preHighLight\" />\n      <nz-slider [nzMin]=\"0\" [nzMax]=\"20\" [(ngModel)]=\"sliderValue\" />\n      <nz-icon nzType=\"smile\" [class.icon-highlight]=\"nextHighLight\" />\n    </div>\n  `,\n  styles: `\n    .icon-wrapper {\n      position: relative;\n      padding: 0 30px;\n    }\n\n    nz-icon {\n      position: absolute;\n      top: -2px;\n      width: 16px;\n      height: 16px;\n      line-height: 1;\n      font-size: 16px;\n      color: rgba(0, 0, 0, 0.25);\n    }\n\n    nz-icon:first-child {\n      left: 0;\n    }\n\n    nz-icon:last-child {\n      right: 0;\n    }\n\n    .icon-highlight {\n      color: rgba(0, 0, 0, 0.45);\n    }\n  `\n})\nexport class NzDemoSliderIconSliderComponent implements OnInit {\n  min = 0;\n  max = 20;\n  mid = parseFloat(((this.max - this.min) / 2).toFixed(5));\n  preHighLight = false;\n  nextHighLight = false;\n  _sliderValue = 0;\n\n  set sliderValue(value: number) {\n    this._sliderValue = value;\n    this.highlightIcon();\n  }\n\n  get sliderValue(): number {\n    return this._sliderValue;\n  }\n\n  ngOnInit(): void {\n    this.sliderValue = 0;\n  }\n\n  highlightIcon(): void {\n    const lower = this._sliderValue >= this.mid;\n    this.preHighLight = !lower;\n    this.nextHighLight = lower;\n  }\n}\n"
  },
  {
    "path": "components/slider/demo/input-number.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 带输入框的滑块\n  en-US: Slider with InputNumber\n---\n\n## zh-CN\n\n和 [数字输入框](/components/input-number/) 组件保持同步。\n\n## en-US\n\nSynchronize with [InptNumber](/components/input-number/) component.\n"
  },
  {
    "path": "components/slider/demo/input-number.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzGridModule } from 'ng-zorro-antd/grid';\nimport { NzInputNumberModule } from 'ng-zorro-antd/input-number';\nimport { NzSliderModule } from 'ng-zorro-antd/slider';\n\n@Component({\n  selector: 'nz-demo-slider-input-number',\n  imports: [FormsModule, NzGridModule, NzInputNumberModule, NzSliderModule],\n  template: `\n    <nz-row nzGutter=\"8\">\n      <nz-col nzSpan=\"12\">\n        <nz-slider [nzMin]=\"1\" [nzMax]=\"20\" [(ngModel)]=\"value1\" />\n      </nz-col>\n      <div nz-col nzSpan=\"4\">\n        <nz-input-number [nzMin]=\"1\" [nzMax]=\"20\" [(ngModel)]=\"value1\" />\n      </div>\n    </nz-row>\n\n    <nz-row nzGutter=\"8\">\n      <nz-col nzSpan=\"12\">\n        <nz-slider [nzMin]=\"0\" [nzMax]=\"1\" [nzStep]=\"0.01\" [(ngModel)]=\"value2\" />\n      </nz-col>\n      <nz-col nzSpan=\"4\">\n        <nz-input-number [nzMin]=\"0\" [nzMax]=\"1\" [nzStep]=\"0.01\" [(ngModel)]=\"value2\" />\n      </nz-col>\n    </nz-row>\n  `\n})\nexport class NzDemoSliderInputNumberComponent {\n  value1 = 1;\n  value2 = 0;\n}\n"
  },
  {
    "path": "components/slider/demo/mark.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 带标签的滑块\n  en-US: Graduated slider\n---\n\n## zh-CN\n\n使用 `nzMarks` 属性标注分段式滑块，使用 `ngModel` 指定滑块位置。当 `nzIncluded = false` 时，表明不同标记间为并列关系。当 `nzStep = null` 时，Slider 的可选值仅有 `nzMarks` 标出来的部分。\n\n## en-US\n\nUsing `nzMarks` property to mark a graduated slider, use `ngModel` to specify the position of thumb. When `nzIncluded` is false, means that different thumbs are coordinated. When `nzStep` is null, users can only slide the thumbs onto marks.\n"
  },
  {
    "path": "components/slider/demo/mark.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzMarks, NzSliderModule } from 'ng-zorro-antd/slider';\n\n@Component({\n  selector: 'nz-demo-slider-mark',\n  imports: [FormsModule, NzButtonModule, NzSliderModule],\n  template: `\n    <h4>included=true</h4>\n    <nz-slider [nzMarks]=\"marks\" [ngModel]=\"37\" />\n    <nz-slider [nzMarks]=\"marks\" nzIncluded nzRange [ngModel]=\"[26, 37]\" />\n    <h4>included=false</h4>\n    <nz-slider [nzMarks]=\"marks\" [nzIncluded]=\"false\" [ngModel]=\"37\" />\n    <h4>marks & step</h4>\n    <nz-slider [nzMarks]=\"marks\" [nzStep]=\"10\" [ngModel]=\"37\" />\n    <h4>step=null || dots=true</h4>\n    <nz-slider [nzMarks]=\"marks\" [nzStep]=\"null\" [ngModel]=\"37\" />\n    <nz-slider [nzMarks]=\"marks\" nzDots [ngModel]=\"37\" />\n    Change nzMarks dynamically:\n    <button nz-button (click)=\"changeMarks()\">Change nzMarks</button>\n  `,\n  styles: `\n    h4 {\n      margin: 0 0 16px;\n    }\n\n    .ant-slider-with-marks {\n      margin-bottom: 44px;\n    }\n  `\n})\nexport class NzDemoSliderMarkComponent {\n  marks: NzMarks = {\n    0: '0°C',\n    26: '26°C',\n    37: '37°C',\n    100: {\n      style: {\n        color: '#f50'\n      },\n      label: '<strong>100°C</strong>'\n    }\n  };\n\n  changeMarks(): void {\n    this.marks = {\n      20: '20%',\n      99: '99%'\n    };\n  }\n}\n"
  },
  {
    "path": "components/slider/demo/reverse.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 反向\n  en-US: Reverse\n---\n\n## zh-CN\n\n设置 `nzReverse` 可以将滑动条置反。\n\n## en-US\n\nUsing `nzReverse` to render slider reversely.\n"
  },
  {
    "path": "components/slider/demo/reverse.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzMarks, NzSliderModule } from 'ng-zorro-antd/slider';\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\n\n@Component({\n  selector: 'nz-demo-slider-reverse',\n  imports: [FormsModule, NzSliderModule, NzSwitchModule],\n  template: `\n    <nz-slider [ngModel]=\"30\" [nzReverse]=\"reverse\" />\n    <nz-slider nzRange [ngModel]=\"[20, 50]\" [nzReverse]=\"reverse\" />\n    <nz-slider [nzMarks]=\"marks\" [ngModel]=\"30\" [nzReverse]=\"reverse\" />\n    Reversed:\n    <nz-switch nzSize=\"small\" [(ngModel)]=\"reverse\" />\n  `,\n  styles: `\n    .ant-slider-with-marks {\n      margin-bottom: 44px;\n    }\n  `\n})\nexport class NzDemoSliderReverseComponent {\n  reverse = true;\n\n  marks: NzMarks = {\n    0: '0°C',\n    26: '26°C',\n    37: '37°C',\n    100: {\n      style: {\n        color: '#f50'\n      },\n      label: '<strong>100°C</strong>'\n    }\n  };\n}\n"
  },
  {
    "path": "components/slider/demo/tip-formatter.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 自定义提示\n  en-US: Customerize tooltip\n---\n\n## zh-CN\n\n使用 `nzTipFormatter` 可以格式化 `Tooltip` 的内容，设置 `nzTipFormatter = null`，则隐藏 `Tooltip`。\n\n## en-US\n\nUse `nzTipFormatter` to format content of `Toolip`. If `nzTipFormatter` is null, hide it.\n"
  },
  {
    "path": "components/slider/demo/tip-formatter.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzSliderModule } from 'ng-zorro-antd/slider';\n\n@Component({\n  selector: 'nz-demo-slider-tip-formatter',\n  imports: [NzSliderModule],\n  template: `\n    <nz-slider [nzTipFormatter]=\"formatter\" />\n    <nz-slider [nzTipFormatter]=\"null\" />\n    <nz-slider [nzTipFormatter]=\"titleTemplate\" />\n    <ng-template #titleTemplate let-value>\n      <span>Slider value: {{ value }}</span>\n    </ng-template>\n  `\n})\nexport class NzDemoSliderTipFormatterComponent {\n  formatter(value: number): string {\n    return `${value}%`;\n  }\n}\n"
  },
  {
    "path": "components/slider/demo/tooltip.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 控制 Tooltip 的显示\n  en-US: Control visibility of Tooltip\n---\n\n## zh-CN\n\n当 `nzTooltipVisible` 为 `always` 时，将始终显示 Tooltip，为 `never` 时反之则始终不显示，即使在拖动、移入时也是如此。\n\n## en-US\n\nWhen `nzTooltipVisible` is `always`, Tooltip will show always. And set to `never`, tooltip would never show, even when user is dragging or hovering.\n"
  },
  {
    "path": "components/slider/demo/tooltip.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzSliderModule } from 'ng-zorro-antd/slider';\n\n@Component({\n  selector: 'nz-demo-slider-tooltip',\n  imports: [NzSliderModule],\n  template: `\n    <nz-slider nzTooltipVisible=\"always\" />\n    <nz-slider nzTooltipVisible=\"never\" />\n  `\n})\nexport class NzDemoSliderTooltipComponent {}\n"
  },
  {
    "path": "components/slider/demo/vertical.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 垂直\n  en-US: Vertical\n---\n\n## zh-CN\n\n垂直方向的 Slider。\n\n## en-US\n\nThe vertical Slider.\n"
  },
  {
    "path": "components/slider/demo/vertical.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSliderModule } from 'ng-zorro-antd/slider';\n\n@Component({\n  selector: 'nz-demo-slider-vertical',\n  imports: [FormsModule, NzSliderModule],\n  template: `\n    <div [style]=\"{ height: '300px' }\">\n      <div [style]=\"style\">\n        <nz-slider nzVertical [ngModel]=\"30\" />\n      </div>\n      <div [style]=\"style\">\n        <nz-slider nzVertical nzRange [nzStep]=\"10\" [ngModel]=\"[20, 50]\" />\n      </div>\n      <div [style]=\"style\">\n        <nz-slider nzVertical nzRange [nzMarks]=\"marks\" [ngModel]=\"[26, 37]\" />\n      </div>\n    </div>\n  `\n})\nexport class NzDemoSliderVerticalComponent {\n  style = {\n    float: 'left',\n    height: '300px',\n    marginLeft: '70px'\n  };\n\n  marks = {\n    0: '0°C',\n    26: '26°C',\n    37: '37°C',\n    100: {\n      style: {\n        color: '#f50'\n      },\n      label: '<strong>100°C</strong>'\n    }\n  };\n}\n"
  },
  {
    "path": "components/slider/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Entry\ntitle: Slider\ncover: 'https://gw.alipayobjects.com/zos/alicdn/HZ3meFc6W/Silder.svg'\ndescription: A Slider component for displaying current value and intervals in range.\n---\n\n## When To Use\n\nTo input a value in a range.\n\n## API\n\n### nz-slider\n\n| Property               | Description                                                                                                                                          | Type                                             | Default                                                                          |\n| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | -------------------------------------------------------------------------------- |\n| `[nzDisabled]`         | If true, the slider will not be interactable.                                                                                                        | `boolean`                                        | `false`                                                                          |\n| `[nzDots]`             | Whether the thumb can drag over tick only.                                                                                                           | `boolean`                                        | `false`                                                                          |\n| `[nzIncluded]`         | Make effect when `marks` not null，`true` means containment and `false` means coordinative                                                           | `boolean`                                        | `true`                                                                           |\n| `[nzMarks]`            | Tick mark of Slider, type of key must be `number`, and must in closed interval `[min, max]` ，each mark can declare its own style.                   | `object`                                         | `{ number: string/HTML }` or `{ number: { style: object, label: string/HTML } }` |\n| `[nzMax]`              | The maximum value the slider can slide to                                                                                                            | `number`                                         | `100`                                                                            |\n| `[nzMin]`              | The minimum value the slider can slide to.                                                                                                           | `number`                                         | `0`                                                                              |\n| `[nzRange]`            | dual thumb mode                                                                                                                                      | `boolean`                                        | `false`                                                                          |\n| `[nzStep]`             | The granularity the slider can step through values. Must greater than 0, and be divided by (max - min) . When `marks` no null, `step` can be `null`. | `number \\| null`                                 | `1`                                                                              |\n| `[nzTipFormatter]`     | Slider will pass its value to `tipFormatter`, and display its value in Tooltip, and hide Tooltip when return value is null.                          | `(value: number) => string \\| TemplateRef<void>` | -                                                                                |\n| `[ngModel]`            | The value of slider. When `range` is `false`, use `number`, otherwise, use `[number, number]`                                                        | `number \\| number[]`                             | -                                                                                |\n| `[nzVertical]`         | If true, the slider will be vertical.                                                                                                                | `boolean`                                        | `false`                                                                          |\n| `[nzReverse]`          | Reverse the component                                                                                                                                | `boolean`                                        | `false`                                                                          |\n| `[nzTooltipVisible]`   | When set to `always` tooltips are always displayed. When set to `never` they are never displayed                                                     | `'default' \\| 'always' \\| 'never'`               | `'default'`                                                                      |\n| `[nzTooltipPlacement]` | Set the default placement of Tooltip                                                                                                                 | `string`                                         |                                                                                  |\n| `(nzOnAfterChange)`    | Fire when `onmouseup` is fired.                                                                                                                      | `EventEmitter<number[] \\| number>`               | -                                                                                |\n| `(ngModelChange)`      | Callback function that is fired when the user changes the slider's value.                                                                            | `EventEmitter<number[] \\| number>`               | -                                                                                |\n"
  },
  {
    "path": "components/slider/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 滑动输入条\ntype: 数据录入\ntitle: Slider\ncover: 'https://gw.alipayobjects.com/zos/alicdn/HZ3meFc6W/Silder.svg'\ndescription: 滑动型输入器，展示当前值和可选范围。\n---\n\n## 何时使用\n\n当用户需要在数值区间/自定义区间内进行选择时，可为连续或离散值。\n\n## API\n\n### nz-slider\n\n| 参数                   | 说明                                                                                                                                               | 类型                                             | 默认值                                                                           |\n| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | -------------------------------------------------------------------------------- |\n| `[nzDisabled]`         | 值为 `true` 时，滑块为禁用状态                                                                                                                     | `boolean`                                        | `false`                                                                          |\n| `[nzDots]`             | 是否只能拖拽到刻度上                                                                                                                               | `boolean`                                        | `false`                                                                          |\n| `[nzIncluded]`         | `marks` 不为空对象时有效，值为 true 时表示值为包含关系，false 表示并列                                                                             | `boolean`                                        | `true`                                                                           |\n| `[nzMarks]`            | 刻度标记，key 的类型必须为 `number` 且取值在闭区间 `[min, max]` 内，每个标签可以单独设置样式                                                       | `object`                                         | `{ number: string/HTML }` or `{ number: { style: object, label: string/HTML } }` |\n| `[nzMax]`              | 最大值                                                                                                                                             | `number`                                         | `100`                                                                            |\n| `[nzMin]`              | 最小值                                                                                                                                             | `number`                                         | `0`                                                                              |\n| `[nzRange]`            | 双滑块模式                                                                                                                                         | `boolean`                                        | `false`                                                                          |\n| `[nzStep]`             | 步长，取值必须大于 0，并且可被 (max - min) 整除。当 `marks` 不为空对象时，可以设置 `step` 为 `null`，此时 Slider 的可选值仅有 marks 标出来的部分。 | `number \\| null`                                 | `1`                                                                              |\n| `[nzTipFormatter]`     | Slider 会把当前值传给 `nzTipFormatter`，并在 Tooltip 中显示 `nzTipFormatter` 的返回值，若为 null，则隐藏 Tooltip。                                 | `(value: number) => string \\| TemplateRef<void>` | -                                                                                |\n| `[ngModel]`            | 设置当前取值。当 `range` 为 `false` 时，使用 `number`，否则用 `[number, number]`                                                                   | `number \\| number[]`                             | -                                                                                |\n| `[nzVertical]`         | 值为 `true` 时，Slider 为垂直方向                                                                                                                  | `boolean`                                        | `false`                                                                          |\n| `[nzReverse]`          | 反向坐标轴                                                                                                                                         | `boolean`                                        | `false`                                                                          |\n| `[nzTooltipVisible]`   | 值为 `always` 时总是显示，值为 `never` 时在任何情况下都不显示                                                                                      | `'default' \\| 'always' \\| 'never'`               | `'default'`                                                                      |\n| `[nzTooltipPlacement]` | 设置 Tooltip 的默认位置。                                                                                                                          | `string`                                         |                                                                                  |\n| `(nzOnAfterChange)`    | 与 `onmouseup` 触发时机一致，把当前值作为参数传入。                                                                                                | `EventEmitter<number[] \\| number>`               | -                                                                                |\n| `(ngModelChange)`      | 当 Slider 的值发生改变时，会触发 ngModelChange 事件，并把改变后的值作为参数传入。                                                                  | `EventEmitter<number[] \\| number>>`              | -                                                                                |\n"
  },
  {
    "path": "components/slider/handle.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction } from '@angular/cdk/bidi';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ElementRef,\n  Input,\n  OnChanges,\n  SimpleChanges,\n  TemplateRef,\n  ViewChild,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject\n} from '@angular/core';\n\nimport { NgStyleInterface, NzTSType } from 'ng-zorro-antd/core/types';\nimport { numberAttributeWithZeroFallback } from 'ng-zorro-antd/core/util';\nimport { NzTooltipDirective, NzTooltipModule } from 'ng-zorro-antd/tooltip';\n\nimport { NzSliderShowTooltip } from './typings';\n\n@Component({\n  selector: 'nz-slider-handle',\n  exportAs: 'nzSliderHandle',\n  template: `\n    <div\n      #handle\n      class=\"ant-slider-handle\"\n      tabindex=\"0\"\n      nz-tooltip\n      [style]=\"style\"\n      [nzTooltipTitle]=\"tooltipFormatter === null || tooltipVisible === 'never' ? null : tooltipTitle\"\n      [nzTooltipTitleContext]=\"{ $implicit: value }\"\n      [nzTooltipTrigger]=\"null\"\n      [nzTooltipPlacement]=\"tooltipPlacement\"\n    ></div>\n  `,\n  host: {\n    '(mouseenter)': 'enterHandle()',\n    '(mouseleave)': 'leaveHandle()'\n  },\n  imports: [NzTooltipModule],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None\n})\nexport class NzSliderHandleComponent implements OnChanges {\n  private cdr = inject(ChangeDetectorRef);\n\n  @ViewChild('handle', { static: false }) handleEl?: ElementRef;\n  @ViewChild(NzTooltipDirective, { static: false }) tooltip?: NzTooltipDirective;\n\n  @Input({ transform: booleanAttribute }) vertical?: boolean;\n  @Input({ transform: booleanAttribute }) reverse?: boolean;\n  @Input({ transform: numberAttributeWithZeroFallback }) offset?: number;\n  @Input({ transform: numberAttributeWithZeroFallback }) value?: number;\n  @Input() tooltipVisible: NzSliderShowTooltip = 'default';\n  @Input() tooltipPlacement?: string;\n  @Input() tooltipFormatter?: null | ((value: number) => string) | TemplateRef<void>;\n  @Input({ transform: booleanAttribute }) active = false;\n  @Input() dir: Direction = 'ltr';\n  @Input() dragging?: boolean;\n\n  tooltipTitle?: NzTSType;\n  style: NgStyleInterface = {};\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { offset, value, active, tooltipVisible, reverse, dir } = changes;\n\n    if (offset || reverse || dir) {\n      this.updateStyle();\n    }\n\n    if (value) {\n      this.updateTooltipTitle();\n      this.updateTooltipPosition();\n    }\n\n    if (active) {\n      if (active.currentValue) {\n        this.toggleTooltip(true);\n      } else {\n        this.toggleTooltip(false);\n      }\n    }\n\n    if (tooltipVisible?.currentValue === 'always') {\n      Promise.resolve().then(() => this.toggleTooltip(true, true));\n    }\n  }\n\n  enterHandle = (): void => {\n    if (!this.dragging) {\n      this.toggleTooltip(true);\n      this.updateTooltipPosition();\n      this.cdr.detectChanges();\n    }\n  };\n\n  leaveHandle = (): void => {\n    if (!this.dragging) {\n      this.toggleTooltip(false);\n      this.cdr.detectChanges();\n    }\n  };\n\n  focus(): void {\n    this.handleEl?.nativeElement.focus();\n  }\n\n  private toggleTooltip(show: boolean, force: boolean = false): void {\n    if (!force && (this.tooltipVisible !== 'default' || !this.tooltip)) {\n      return;\n    }\n\n    if (show) {\n      this.tooltip?.show();\n    } else {\n      this.tooltip?.hide();\n    }\n  }\n\n  private updateTooltipTitle(): void {\n    if (this.tooltipFormatter) {\n      this.tooltipTitle =\n        typeof this.tooltipFormatter === 'function' ? this.tooltipFormatter(this.value!) : this.tooltipFormatter;\n    } else {\n      this.tooltipTitle = `${this.value}`;\n    }\n  }\n\n  private updateTooltipPosition(): void {\n    if (this.tooltip) {\n      Promise.resolve().then(() => this.tooltip?.updatePosition());\n    }\n  }\n\n  private updateStyle(): void {\n    if (this.vertical) {\n      this.style = {\n        [this.reverse ? 'top' : 'bottom']: `${this.offset}%`,\n        [this.reverse ? 'bottom' : 'top']: 'auto',\n        transform: this.reverse ? null : `translateY(+50%)`\n      };\n    } else {\n      this.style = {\n        ...this.getHorizontalStylePosition(),\n        transform: `translateX(${this.reverse ? (this.dir === 'rtl' ? '-' : '+') : this.dir === 'rtl' ? '+' : '-'}50%)`\n      };\n    }\n    this.cdr.markForCheck();\n  }\n\n  private getHorizontalStylePosition(): { left: string; right: string } {\n    let left = this.reverse ? 'auto' : `${this.offset}%`;\n    let right = this.reverse ? `${this.offset}%` : 'auto';\n    if (this.dir === 'rtl') {\n      [left, right] = [right, left];\n    }\n    return { left, right };\n  }\n}\n"
  },
  {
    "path": "components/slider/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/slider/marks.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  Input,\n  OnChanges,\n  SimpleChanges,\n  ViewEncapsulation,\n  booleanAttribute,\n  numberAttribute\n} from '@angular/core';\n\nimport { NgStyleInterface } from 'ng-zorro-antd/core/types';\n\nimport { NzDisplayedMark, NzExtendedMark, NzMark, NzMarkObj } from './typings';\n\n@Component({\n  selector: 'nz-slider-marks',\n  exportAs: 'nzSliderMarks',\n  template: `\n    @for (attr of marks; track attr.value) {\n      <span\n        class=\"ant-slider-mark-text\"\n        [class.ant-slider-mark-active]=\"attr.active\"\n        [style]=\"attr.style\"\n        [innerHTML]=\"attr.label\"\n      ></span>\n    }\n  `,\n  host: {\n    class: 'ant-slider-mark'\n  },\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None\n})\nexport class NzSliderMarksComponent implements OnChanges {\n  @Input() lowerBound: number | null = null;\n  @Input() upperBound: number | null = null;\n  @Input() marksArray: NzExtendedMark[] = [];\n  @Input({ transform: numberAttribute }) min!: number;\n  @Input({ transform: numberAttribute }) max!: number;\n  @Input({ transform: booleanAttribute }) vertical = false;\n  @Input({ transform: booleanAttribute }) included = false;\n  @Input({ transform: booleanAttribute }) reverse!: boolean;\n\n  marks: NzDisplayedMark[] = [];\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { marksArray, lowerBound, upperBound, reverse } = changes;\n\n    if (marksArray || reverse) {\n      this.buildMarks();\n    }\n\n    if (marksArray || lowerBound || upperBound || reverse) {\n      this.togglePointActive();\n    }\n  }\n\n  private buildMarks(): void {\n    const range = this.max - this.min;\n\n    this.marks = this.marksArray.map(mark => {\n      const { value, offset, config } = mark;\n      const style = this.getMarkStyles(value, range, config);\n      const label = isConfigObject(config) ? config.label : config;\n\n      return {\n        label,\n        offset,\n        style,\n        value,\n        config,\n        active: false\n      };\n    });\n  }\n\n  private getMarkStyles(value: number, range: number, config: NzMark): NgStyleInterface {\n    let style;\n    const markValue = this.reverse ? this.max + this.min - value : value;\n\n    if (this.vertical) {\n      style = {\n        marginBottom: '-50%',\n        bottom: `${((markValue - this.min) / range) * 100}%`\n      };\n    } else {\n      style = {\n        transform: `translate3d(-50%, 0, 0)`,\n        left: `${((markValue - this.min) / range) * 100}%`\n      };\n    }\n\n    if (isConfigObject(config) && config.style) {\n      style = { ...style, ...config.style };\n    }\n\n    return style;\n  }\n\n  private togglePointActive(): void {\n    if (this.marks && this.lowerBound !== null && this.upperBound !== null) {\n      this.marks.forEach(mark => {\n        const value = mark.value;\n        mark.active = this.included\n          ? value <= this.upperBound! && value >= this.lowerBound!\n          : value === this.upperBound;\n      });\n    }\n  }\n}\n\nfunction isConfigObject(config: NzMark): config is NzMarkObj {\n  return typeof config !== 'string';\n}\n"
  },
  {
    "path": "components/slider/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/slider/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport { NzSliderComponent } from './slider.component';\nexport { NzSliderModule } from './slider.module';\nexport { NzSliderHandleComponent as ɵNzSliderHandleComponent } from './handle.component';\nexport { NzSliderMarksComponent as ɵNzSliderMarksComponent } from './marks.component';\nexport { NzSliderStepComponent as ɵNzSliderStepComponent } from './step.component';\nexport { NzSliderTrackComponent as ɵNzSliderTrackComponent } from './track.component';\nexport type { NzSliderTrackStyle } from './track.component';\nexport * from './typings';\n"
  },
  {
    "path": "components/slider/slider.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport { DOWN_ARROW, LEFT_ARROW, RIGHT_ARROW, UP_ARROW } from '@angular/cdk/keycodes';\nimport { Platform } from '@angular/cdk/platform';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ElementRef,\n  EventEmitter,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  QueryList,\n  SimpleChanges,\n  TemplateRef,\n  ViewChildren,\n  ViewEncapsulation,\n  booleanAttribute,\n  forwardRef,\n  numberAttribute,\n  signal,\n  inject,\n  DestroyRef\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { Observable, Subscription, fromEvent, merge } from 'rxjs';\nimport { distinctUntilChanged, filter, map, takeUntil, tap } from 'rxjs/operators';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport {\n  MouseTouchObserverConfig,\n  arraysEqual,\n  ensureNumberInRange,\n  getElementOffset,\n  getPercent,\n  getPrecision,\n  isNil,\n  numberAttributeWithZeroFallback,\n  silentEvent\n} from 'ng-zorro-antd/core/util';\n\nimport { NzSliderHandleComponent } from './handle.component';\nimport { NzSliderMarksComponent } from './marks.component';\nimport { NzSliderStepComponent } from './step.component';\nimport { NzSliderTrackComponent } from './track.component';\nimport { NzExtendedMark, NzMarks, NzSliderHandler, NzSliderShowTooltip, NzSliderValue } from './typings';\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-slider',\n  exportAs: 'nzSlider',\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => NzSliderComponent),\n      multi: true\n    }\n  ],\n  template: `\n    <div class=\"ant-slider-rail\"></div>\n    <nz-slider-track\n      [vertical]=\"nzVertical\"\n      [included]=\"nzIncluded\"\n      [offset]=\"track.offset!\"\n      [length]=\"track.length!\"\n      [reverse]=\"nzReverse\"\n      [dir]=\"dir\"\n    />\n    @if (marksArray) {\n      <nz-slider-step\n        [vertical]=\"nzVertical\"\n        [min]=\"nzMin\"\n        [max]=\"nzMax\"\n        [lowerBound]=\"$any(bounds.lower)\"\n        [upperBound]=\"$any(bounds.upper)\"\n        [marksArray]=\"marksArray\"\n        [included]=\"nzIncluded\"\n        [reverse]=\"nzReverse\"\n      />\n    }\n    @for (handle of handles; track handle.value) {\n      <nz-slider-handle\n        [vertical]=\"nzVertical\"\n        [reverse]=\"nzReverse\"\n        [offset]=\"handle.offset!\"\n        [value]=\"handle.value!\"\n        [active]=\"handle.active\"\n        [tooltipFormatter]=\"nzTipFormatter\"\n        [tooltipVisible]=\"nzTooltipVisible\"\n        [tooltipPlacement]=\"nzTooltipPlacement\"\n        [dragging]=\"dragging()\"\n        [dir]=\"dir\"\n        (focusin)=\"onHandleFocusIn($index)\"\n      />\n    }\n    @if (marksArray) {\n      <nz-slider-marks\n        [vertical]=\"nzVertical\"\n        [min]=\"nzMin\"\n        [max]=\"nzMax\"\n        [lowerBound]=\"$any(bounds.lower)\"\n        [upperBound]=\"$any(bounds.upper)\"\n        [marksArray]=\"marksArray\"\n        [included]=\"nzIncluded\"\n        [reverse]=\"nzReverse\"\n      />\n    }\n  `,\n  imports: [NzSliderTrackComponent, NzSliderStepComponent, NzSliderHandleComponent, NzSliderMarksComponent],\n  host: {\n    class: 'ant-slider',\n    '[class.ant-slider-rtl]': `dir === 'rtl'`,\n    '[class.ant-slider-disabled]': 'nzDisabled',\n    '[class.ant-slider-vertical]': 'nzVertical',\n    '[class.ant-slider-with-marks]': 'marksArray',\n    '(keydown)': 'onKeyDown($event)'\n  }\n})\nexport class NzSliderComponent implements ControlValueAccessor, OnInit, OnChanges {\n  public slider = inject(ElementRef<HTMLElement>);\n  private destroyRef = inject(DestroyRef);\n  private cdr = inject(ChangeDetectorRef);\n  private platform = inject(Platform);\n  private directionality = inject(Directionality);\n\n  @ViewChildren(NzSliderHandleComponent) handlerComponents!: QueryList<NzSliderHandleComponent>;\n\n  @Input({ transform: booleanAttribute }) nzDisabled = false;\n  @Input({ transform: booleanAttribute }) nzDots: boolean = false;\n  @Input({ transform: booleanAttribute }) nzIncluded: boolean = true;\n  @Input({ transform: booleanAttribute }) nzRange: boolean = false;\n  @Input({ transform: booleanAttribute }) nzVertical: boolean = false;\n  @Input({ transform: booleanAttribute }) nzReverse: boolean = false;\n  @Input() nzDefaultValue?: NzSliderValue;\n  @Input() nzMarks: NzMarks | null = null;\n  @Input({ transform: numberAttribute }) nzMax = 100;\n  @Input({ transform: numberAttribute }) nzMin = 0;\n  @Input({ transform: numberAttributeWithZeroFallback }) nzStep: number = 1;\n  @Input() nzTooltipVisible: NzSliderShowTooltip = 'default';\n  @Input() nzTooltipPlacement: string = 'top';\n  @Input() nzTipFormatter?: null | ((value: number) => string) | TemplateRef<void>;\n\n  @Output() readonly nzOnAfterChange = new EventEmitter<NzSliderValue>();\n\n  value: NzSliderValue | null = null;\n  cacheSliderStart: number | null = null;\n  cacheSliderLength: number | null = null;\n  activeValueIndex: number | undefined = undefined; // Current activated handle's index ONLY for range=true\n  track: { offset: null | number; length: null | number } = { offset: null, length: null }; // Track's offset and length\n  handles: NzSliderHandler[] = []; // Handles' offset\n  marksArray: NzExtendedMark[] | null = null; // \"steps\" in array type with more data & FILTER out the invalid mark\n  bounds: { lower: NzSliderValue | null; upper: NzSliderValue | null } = { lower: null, upper: null }; // now for nz-slider-step\n  dir: Direction = 'ltr';\n\n  readonly dragging = signal(false);\n  private dragStart$?: Observable<number>;\n  private dragMove$?: Observable<number>;\n  private dragEnd$?: Observable<Event>;\n  private dragStart_?: Subscription | null;\n  private dragMove_?: Subscription | null;\n  private dragEnd_?: Subscription | null;\n  private isNzDisableFirstChange = true;\n\n  ngOnInit(): void {\n    this.dir = this.directionality.value;\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n      this.dir = direction;\n      this.cdr.detectChanges();\n      this.updateTrackAndHandles();\n      this.onValueChange(this.getValue(true));\n    });\n\n    this.handles = generateHandlers(this.nzRange ? 2 : 1);\n    this.marksArray = this.nzMarks ? this.generateMarkItems(this.nzMarks) : null;\n    this.bindDraggingHandlers();\n    this.toggleDragDisabled(this.nzDisabled);\n\n    if (this.getValue() === null) {\n      this.setValue(this.formatValue(null));\n    }\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzDisabled, nzMarks, nzRange } = changes;\n\n    if (nzDisabled && !nzDisabled.firstChange) {\n      this.toggleDragDisabled(nzDisabled.currentValue);\n    } else if (nzMarks && !nzMarks.firstChange) {\n      this.marksArray = this.nzMarks ? this.generateMarkItems(this.nzMarks) : null;\n    } else if (nzRange && !nzRange.firstChange) {\n      this.handles = generateHandlers(nzRange.currentValue ? 2 : 1);\n      this.setValue(this.formatValue(null));\n    }\n  }\n\n  writeValue(val: NzSliderValue | null): void {\n    this.setValue(val, true);\n  }\n\n  onValueChange(_value: NzSliderValue): void {}\n\n  onTouched(): void {}\n\n  registerOnChange(fn: (value: NzSliderValue) => void): void {\n    this.onValueChange = fn;\n  }\n\n  registerOnTouched(fn: () => void): void {\n    this.onTouched = fn;\n  }\n\n  setDisabledState(isDisabled: boolean): void {\n    this.nzDisabled = (this.isNzDisableFirstChange && this.nzDisabled) || isDisabled;\n    this.isNzDisableFirstChange = false;\n    this.toggleDragDisabled(this.nzDisabled);\n    this.cdr.markForCheck();\n  }\n\n  /**\n   * Event handler is only triggered when a slider handler is focused.\n   */\n  onKeyDown(e: KeyboardEvent): void {\n    if (this.nzDisabled) {\n      return;\n    }\n\n    const code = e.keyCode;\n    const isIncrease = code === RIGHT_ARROW || code === UP_ARROW;\n    const isDecrease = code === LEFT_ARROW || code === DOWN_ARROW;\n\n    if (!(isIncrease || isDecrease)) {\n      return;\n    }\n\n    e.preventDefault();\n\n    const step = (isDecrease ? -this.nzStep : this.nzStep) * (this.nzReverse ? -1 : 1) * (this.dir === 'rtl' ? -1 : 1);\n    const newVal = this.nzRange\n      ? (this.value as number[])[this.activeValueIndex!] + step\n      : (this.value as number) + step;\n    this.setActiveValue(ensureNumberInRange(newVal, this.nzMin, this.nzMax));\n    this.nzOnAfterChange.emit(this.getValue(true));\n  }\n\n  onHandleFocusIn(index: number): void {\n    this.activeValueIndex = index;\n  }\n\n  private setValue(value: NzSliderValue | null, isWriteValue: boolean = false): void {\n    if (isWriteValue) {\n      this.value = this.formatValue(value);\n      this.updateTrackAndHandles();\n    } else if (!valuesEqual(this.value!, value!)) {\n      this.value = value;\n      this.updateTrackAndHandles();\n      this.onValueChange(this.getValue(true));\n    }\n  }\n\n  private getValue(cloneAndSort: boolean = false): NzSliderValue {\n    if (cloneAndSort && this.value && isValueRange(this.value)) {\n      return [...this.value].sort((a, b) => a - b);\n    }\n    return this.value!;\n  }\n\n  /**\n   * Clone & sort current value and convert them to offsets, then return the new one.\n   */\n  private getValueToOffset(value?: NzSliderValue): NzSliderValue {\n    let normalizedValue = value;\n\n    if (typeof normalizedValue === 'undefined') {\n      normalizedValue = this.getValue(true);\n    }\n\n    return isValueRange(normalizedValue)\n      ? normalizedValue.map(val => this.valueToOffset(val))\n      : this.valueToOffset(normalizedValue);\n  }\n\n  /**\n   * Find the closest value to be activated.\n   */\n  private setActiveValueIndex(pointerValue: number): void {\n    const value = this.getValue();\n    if (isValueRange(value)) {\n      let minimal: number | null = null;\n      let gap: number;\n      let activeIndex = -1;\n      value.forEach((val, index) => {\n        gap = Math.abs(pointerValue - val);\n        if (minimal === null || gap < minimal!) {\n          minimal = gap;\n          activeIndex = index;\n        }\n      });\n      this.activeValueIndex = activeIndex;\n      this.handlerComponents.toArray()[activeIndex].focus();\n    } else {\n      this.handlerComponents.toArray()[0].focus();\n    }\n  }\n\n  private setActiveValue(pointerValue: number): void {\n    if (isValueRange(this.value!)) {\n      const newValue = [...this.value];\n      newValue[this.activeValueIndex!] = pointerValue;\n      this.setValue(newValue);\n    } else {\n      this.setValue(pointerValue);\n    }\n  }\n\n  /**\n   * Update track and handles' position and length.\n   */\n  private updateTrackAndHandles(): void {\n    const value = this.getValue();\n    const offset = this.getValueToOffset(value);\n    const valueSorted = this.getValue(true);\n    const offsetSorted = this.getValueToOffset(valueSorted);\n    const boundParts = isValueRange(valueSorted) ? valueSorted : [0, valueSorted];\n    const trackParts = isValueRange(offsetSorted)\n      ? [offsetSorted[0], offsetSorted[1] - offsetSorted[0]]\n      : [0, offsetSorted];\n\n    this.handles.forEach((handle, index) => {\n      handle.offset = isValueRange(offset) ? offset[index] : offset;\n      handle.value = isValueRange(value) ? value[index] : value || 0;\n    });\n\n    [this.bounds.lower, this.bounds.upper] = boundParts;\n    [this.track.offset, this.track.length] = trackParts;\n\n    this.cdr.markForCheck();\n  }\n\n  private onDragStart(value: number): void {\n    this.toggleDragMoving(true);\n    this.cacheSliderProperty();\n    this.setActiveValueIndex(this.getLogicalValue(value));\n    this.setActiveValue(this.getLogicalValue(value));\n    this.showHandleTooltip(this.nzRange ? this.activeValueIndex : 0);\n  }\n\n  private onDragMove(value: number): void {\n    this.setActiveValue(this.getLogicalValue(value));\n    this.cdr.markForCheck();\n  }\n\n  private getLogicalValue(value: number): number {\n    if (this.nzReverse) {\n      if (!this.nzVertical && this.dir === 'rtl') {\n        return value;\n      }\n      return this.nzMax - value + this.nzMin;\n    }\n    if (!this.nzVertical && this.dir === 'rtl') {\n      return this.nzMax - value + this.nzMin;\n    }\n\n    return value;\n  }\n\n  private onDragEnd(): void {\n    this.nzOnAfterChange.emit(this.getValue(true));\n    this.toggleDragMoving(false);\n    this.cacheSliderProperty(true);\n    this.hideAllHandleTooltip();\n    this.cdr.markForCheck();\n  }\n\n  /**\n   * Create user interactions handles.\n   */\n  private bindDraggingHandlers(): void {\n    if (!this.platform.isBrowser) {\n      return;\n    }\n    const pluckFunc: (keys: string[]) => (event: Event) => number = keys => (event: Event) =>\n      keys.reduce((acc: NzSafeAny, key: string) => acc[key] || acc, event);\n    const sliderDOM: HTMLElement = this.slider.nativeElement;\n    const orientField = this.nzVertical ? 'pageY' : 'pageX';\n    const mouse: MouseTouchObserverConfig = {\n      start: 'mousedown',\n      move: 'mousemove',\n      end: 'mouseup',\n      pluckKey: [orientField]\n    };\n    const touch: MouseTouchObserverConfig = {\n      start: 'touchstart',\n      move: 'touchmove',\n      end: 'touchend',\n      pluckKey: ['touches', '0', orientField],\n      filter: (e: MouseEvent | TouchEvent) => e instanceof TouchEvent\n    };\n\n    [mouse, touch].forEach(source => {\n      const { start, move, end, pluckKey, filter: filterFunc = () => true } = source;\n\n      source.startPlucked$ = fromEvent(sliderDOM, start).pipe(\n        filter(filterFunc),\n        tap(silentEvent),\n        map(pluckFunc(pluckKey)),\n        map((position: number) => this.findClosestValue(position))\n      );\n      source.end$ = fromEvent(document, end);\n      source.moveResolved$ = fromEvent(document, move).pipe(\n        filter(filterFunc),\n        tap(silentEvent),\n        map(pluckFunc(pluckKey)),\n        distinctUntilChanged(),\n        map((position: number) => this.findClosestValue(position)),\n        distinctUntilChanged(),\n        takeUntil(source.end$)\n      );\n    });\n\n    this.dragStart$ = merge(mouse.startPlucked$!, touch.startPlucked$!);\n    this.dragMove$ = merge(mouse.moveResolved$!, touch.moveResolved$!);\n    this.dragEnd$ = merge(mouse.end$!, touch.end$!);\n  }\n\n  private subscribeDrag(periods: string[] = ['start', 'move', 'end']): void {\n    if (periods.indexOf('start') !== -1 && this.dragStart$ && !this.dragStart_) {\n      this.dragStart_ = this.dragStart$\n        .pipe(takeUntilDestroyed(this.destroyRef))\n        .subscribe(this.onDragStart.bind(this));\n    }\n\n    if (periods.indexOf('move') !== -1 && this.dragMove$ && !this.dragMove_) {\n      this.dragMove_ = this.dragMove$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(this.onDragMove.bind(this));\n    }\n\n    if (periods.indexOf('end') !== -1 && this.dragEnd$ && !this.dragEnd_) {\n      this.dragEnd_ = this.dragEnd$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(this.onDragEnd.bind(this));\n    }\n  }\n\n  private unsubscribeDrag(periods: string[] = ['start', 'move', 'end']): void {\n    if (periods.includes('start')) {\n      this.dragStart_?.unsubscribe();\n      this.dragStart_ = null;\n    }\n\n    if (periods.includes('move')) {\n      this.dragMove_?.unsubscribe();\n      this.dragMove_ = null;\n    }\n\n    if (periods.includes('end')) {\n      this.dragEnd_?.unsubscribe();\n      this.dragEnd_ = null;\n    }\n  }\n\n  private toggleDragMoving(movable: boolean): void {\n    const periods = ['move', 'end'];\n    if (movable) {\n      this.dragging.set(true);\n      this.subscribeDrag(periods);\n    } else {\n      this.dragging.set(false);\n      this.unsubscribeDrag(periods);\n    }\n  }\n\n  private toggleDragDisabled(disabled: boolean): void {\n    if (disabled) {\n      this.unsubscribeDrag();\n    } else {\n      this.subscribeDrag(['start']);\n    }\n  }\n\n  private findClosestValue(position: number): number {\n    const sliderStart = this.getSliderStartPosition();\n    const sliderLength = this.getSliderLength();\n    const ratio = ensureNumberInRange((position - sliderStart) / sliderLength, 0, 1);\n    const val = (this.nzMax - this.nzMin) * (this.nzVertical ? 1 - ratio : ratio) + this.nzMin;\n    const points =\n      this.nzMarks === null\n        ? []\n        : Object.keys(this.nzMarks)\n            .map(parseFloat)\n            .sort((a, b) => a - b);\n\n    if (this.nzStep !== 0 && !this.nzDots) {\n      const closestOne = Math.round(val / this.nzStep) * this.nzStep;\n      points.push(closestOne);\n    }\n\n    const gaps = points.map(point => Math.abs(val - point));\n    const closest = points[gaps.indexOf(Math.min(...gaps))];\n\n    return this.nzStep === 0 ? closest : parseFloat(closest.toFixed(getPrecision(this.nzStep)));\n  }\n\n  private valueToOffset(value: number): number {\n    return getPercent(this.nzMin, this.nzMax, value);\n  }\n\n  private getSliderStartPosition(): number {\n    if (this.cacheSliderStart !== null) {\n      return this.cacheSliderStart;\n    }\n    const offset = getElementOffset(this.slider.nativeElement);\n    return this.nzVertical ? offset.top : offset.left;\n  }\n\n  private getSliderLength(): number {\n    if (this.cacheSliderLength !== null) {\n      return this.cacheSliderLength;\n    }\n    const sliderDOM = this.slider.nativeElement;\n    return this.nzVertical ? sliderDOM.clientHeight : sliderDOM.clientWidth;\n  }\n\n  /**\n   * Cache DOM layout/reflow operations for performance (may not necessary?)\n   */\n  private cacheSliderProperty(remove: boolean = false): void {\n    this.cacheSliderStart = remove ? null : this.getSliderStartPosition();\n    this.cacheSliderLength = remove ? null : this.getSliderLength();\n  }\n\n  private formatValue(value: NzSliderValue | null): NzSliderValue {\n    if (isNil(value)) {\n      return this.nzRange ? [this.nzMin, this.nzMax] : this.nzMin;\n    } else if (assertValueValid(value, this.nzRange)) {\n      return isValueRange(value)\n        ? value.map(val => ensureNumberInRange(val, this.nzMin, this.nzMax))\n        : ensureNumberInRange(value, this.nzMin, this.nzMax);\n    } else {\n      return this.nzDefaultValue ? this.nzDefaultValue : this.nzRange ? [this.nzMin, this.nzMax] : this.nzMin;\n    }\n  }\n\n  /**\n   * Show one handle's tooltip and hide others'.\n   */\n  private showHandleTooltip(handleIndex: number = 0): void {\n    this.handles.forEach((handle, index) => (handle.active = index === handleIndex));\n  }\n\n  private hideAllHandleTooltip(): void {\n    this.handles.forEach(handle => (handle.active = false));\n  }\n\n  private generateMarkItems(marks: NzMarks): NzExtendedMark[] | null {\n    const marksArray: NzExtendedMark[] = [];\n    for (const key in marks) {\n      if (marks.hasOwnProperty(key)) {\n        const mark = marks[key];\n        const val = typeof key === 'number' ? key : parseFloat(key);\n        if (val >= this.nzMin && val <= this.nzMax) {\n          marksArray.push({ value: val, offset: this.valueToOffset(val), config: mark });\n        }\n      }\n    }\n    return marksArray.length ? marksArray : null;\n  }\n}\n\nfunction getValueTypeNotMatchError(): Error {\n  return new Error(\n    `The \"nzRange\" can't match the \"ngModel\"'s type, please check these properties: \"nzRange\", \"ngModel\", \"nzDefaultValue\".`\n  );\n}\n\nfunction isValueRange(value: NzSliderValue): value is number[] {\n  if (value instanceof Array) {\n    return value.length === 2;\n  } else {\n    return false;\n  }\n}\n\nfunction generateHandlers(amount: number): NzSliderHandler[] {\n  return Array(amount)\n    .fill(0)\n    .map(() => ({ offset: null, value: null, active: false }));\n}\n\n/**\n * Check if value is valid and throw error if value-type/range not match.\n */\nfunction assertValueValid(value: NzSliderValue, isRange?: boolean): boolean {\n  if ((!isValueRange(value) && isNaN(value)) || (isValueRange(value) && value.some(v => isNaN(v)))) {\n    return false;\n  }\n  return assertValueTypeMatch(value, isRange);\n}\n\n/**\n * Assert that if `this.nzRange` is `true`, value is also a range, vice versa.\n */\nfunction assertValueTypeMatch(value: NzSliderValue, isRange: boolean = false): boolean {\n  if (isValueRange(value) !== isRange) {\n    throw getValueTypeNotMatchError();\n  }\n  return true;\n}\n\nfunction valuesEqual(valA: NzSliderValue, valB: NzSliderValue): boolean {\n  if (typeof valA !== typeof valB) {\n    return false;\n  }\n  return isValueRange(valA) && isValueRange(valB) ? arraysEqual<number>(valA, valB) : valA === valB;\n}\n"
  },
  {
    "path": "components/slider/slider.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzSliderHandleComponent } from './handle.component';\nimport { NzSliderMarksComponent } from './marks.component';\nimport { NzSliderComponent } from './slider.component';\nimport { NzSliderStepComponent } from './step.component';\nimport { NzSliderTrackComponent } from './track.component';\n\n@NgModule({\n  imports: [\n    NzSliderComponent,\n    NzSliderTrackComponent,\n    NzSliderHandleComponent,\n    NzSliderStepComponent,\n    NzSliderMarksComponent\n  ],\n  exports: [\n    NzSliderComponent,\n    NzSliderTrackComponent,\n    NzSliderHandleComponent,\n    NzSliderStepComponent,\n    NzSliderMarksComponent\n  ]\n})\nexport class NzSliderModule {}\n"
  },
  {
    "path": "components/slider/slider.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport { DOWN_ARROW, LEFT_ARROW, RIGHT_ARROW, UP_ARROW } from '@angular/cdk/keycodes';\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport { Component, DebugElement, provideZoneChangeDetection, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, inject, TestBed, tick } from '@angular/core/testing';\nimport { AbstractControl, FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { dispatchFakeEvent, dispatchKeyboardEvent, dispatchMouseEvent } from 'ng-zorro-antd/core/testing';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzSliderComponent } from './slider.component';\nimport { NzSliderModule } from './slider.module';\nimport { NzSliderShowTooltip } from './typings';\n\ndescribe('slider', () => {\n  let sliderDebugElement: DebugElement;\n  let sliderNativeElement: HTMLElement;\n  let sliderInstance: NzSliderComponent;\n  let overlayContainerElement: HTMLElement;\n\n  function getReferenceFromFixture(fixture: ComponentFixture<NzSafeAny>): void {\n    sliderDebugElement = fixture.debugElement.query(By.directive(NzSliderComponent));\n    sliderInstance = sliderDebugElement.componentInstance;\n    sliderNativeElement = sliderInstance.slider.nativeElement;\n  }\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideNoopAnimations(), provideZoneChangeDetection()]\n    });\n  });\n\n  describe('basic', () => {\n    let fixture: ComponentFixture<NzTestSliderComponent>;\n    let trackFillElement: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestSliderComponent);\n      fixture.detectChanges();\n\n      getReferenceFromFixture(fixture);\n      trackFillElement = sliderNativeElement.querySelector('.ant-slider-track') as HTMLElement;\n    });\n\n    it('should set the default values', () => {\n      expect(sliderInstance.value).toBe(0);\n      expect(sliderInstance.nzMin).toBe(0);\n      expect(sliderInstance.nzMax).toBe(100);\n    });\n\n    it('should update the value on a click', () => {\n      expect(sliderInstance.value).toBe(0);\n\n      dispatchClickEventSequence(sliderNativeElement, 0.19);\n\n      expect(sliderInstance.value).toBe(19);\n    });\n\n    it('should update the value on a slide', () => {\n      expect(sliderInstance.value).toBe(0);\n\n      dispatchSlideEventSequence(sliderNativeElement, 0, 0.89);\n\n      expect(sliderInstance.value).toBe(89);\n    });\n\n    it('should set the value as min when sliding before the track', () => {\n      expect(sliderInstance.value).toBe(0);\n\n      dispatchSlideEventSequence(sliderNativeElement, 0, -1.33);\n\n      expect(sliderInstance.value).toBe(0);\n    });\n\n    it('should set the value as max when sliding past the track', () => {\n      expect(sliderInstance.value).toBe(0);\n\n      dispatchSlideEventSequence(sliderNativeElement, 0, 1.75);\n\n      expect(sliderInstance.value).toBe(100);\n    });\n\n    it('should update the track fill on click', () => {\n      expect(trackFillElement.style.width).toBe('0%');\n\n      dispatchClickEventSequence(sliderNativeElement, 0.39);\n      fixture.detectChanges();\n\n      expect(trackFillElement.style.width).toBe('39%');\n    });\n\n    it('should update the track fill on slide', () => {\n      expect(trackFillElement.style.width).toBe('0%');\n\n      dispatchSlideEventSequence(sliderNativeElement, 0, 0.86);\n      fixture.detectChanges();\n\n      expect(trackFillElement.style.width).toBe('86%');\n    });\n\n    it('should not change value without emitting a change event', () => {\n      const onChangeSpy = jasmine.createSpy('slider onChange');\n\n      sliderInstance.nzOnAfterChange.subscribe(onChangeSpy);\n      sliderInstance.value = 50;\n      fixture.detectChanges();\n\n      dispatchSlideStartEvent(sliderNativeElement, 0);\n      fixture.detectChanges();\n\n      dispatchSlideEvent(sliderNativeElement, 10);\n      fixture.detectChanges();\n\n      dispatchSlideEndEvent(sliderNativeElement, 10);\n      fixture.detectChanges();\n\n      expect(onChangeSpy).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('disabled', () => {\n    let fixture: ComponentFixture<NzTestSliderComponent>;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestSliderComponent);\n      fixture.componentInstance.disabled = true;\n      fixture.detectChanges();\n\n      getReferenceFromFixture(fixture);\n    });\n\n    it('should not change the value on click when disabled', () => {\n      expect(sliderInstance.value).toBe(0);\n\n      dispatchClickEventSequence(sliderNativeElement, 0.63);\n\n      expect(sliderInstance.value).toBe(0);\n    });\n\n    it('should not change the value on slide when disabled', () => {\n      expect(sliderInstance.value).toBe(0);\n\n      dispatchSlideEventSequence(sliderNativeElement, 0, 0.5);\n\n      expect(sliderInstance.value).toBe(0);\n    });\n\n    it('should not emit change when disabled', () => {\n      const onChangeSpy = jasmine.createSpy('slider onChange');\n      sliderInstance.nzOnAfterChange.subscribe(onChangeSpy);\n\n      dispatchSlideEventSequence(sliderNativeElement, 0, 0.5);\n\n      expect(onChangeSpy).toHaveBeenCalledTimes(0);\n    });\n\n    it('should add the ant-slider-disabled class when disabled', () => {\n      expect(sliderNativeElement.classList).toContain('ant-slider-disabled');\n    });\n  });\n\n  describe('show tooltip', () => {\n    let fixture: ComponentFixture<SliderShowTooltipComponent>;\n    let testComponent: SliderShowTooltipComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(SliderShowTooltipComponent);\n      fixture.detectChanges();\n\n      testComponent = fixture.componentInstance;\n      sliderDebugElement = fixture.debugElement.query(By.directive(NzSliderComponent));\n      sliderInstance = sliderDebugElement.injector.get<NzSliderComponent>(NzSliderComponent);\n      sliderNativeElement = sliderInstance.slider.nativeElement;\n    });\n\n    beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n      overlayContainerElement = oc.getContainerElement();\n    }));\n\n    it('should always display tooltips if set to `always`', fakeAsync(() => {\n      testComponent.show = 'always';\n      fixture.detectChanges();\n      tick(400);\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent).toContain('0');\n\n      dispatchClickEventSequence(sliderNativeElement, 0.13);\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent).toContain('13');\n\n      // Always show tooltip even when the handle is not hovered.\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent).toContain('13');\n\n      tick(400);\n    }));\n\n    it('should never display tooltips if set to `never`', fakeAsync(() => {\n      const handlerHost = sliderNativeElement.querySelector('nz-slider-handle')!;\n\n      testComponent.show = 'never';\n      tick(400);\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent).not.toContain('0');\n\n      dispatchClickEventSequence(sliderNativeElement, 0.13);\n      fixture.detectChanges();\n\n      // Do not show tooltip even when the handle is hovered.\n      dispatchMouseEvent(handlerHost, 'mouseenter');\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent).not.toContain('13');\n    }));\n  });\n\n  describe('show template tooltip', () => {\n    let fixture: ComponentFixture<SliderShowTemplateTooltipComponent>;\n    let testComponent: SliderShowTemplateTooltipComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(SliderShowTemplateTooltipComponent);\n      fixture.detectChanges();\n\n      testComponent = fixture.componentInstance;\n      sliderDebugElement = fixture.debugElement.query(By.directive(NzSliderComponent));\n      sliderInstance = sliderDebugElement.injector.get<NzSliderComponent>(NzSliderComponent);\n      sliderNativeElement = sliderInstance.slider.nativeElement;\n    });\n\n    beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n      overlayContainerElement = oc.getContainerElement();\n    }));\n\n    it('should preview template tooltip', fakeAsync(() => {\n      testComponent.show = 'always';\n      fixture.detectChanges();\n      tick(400);\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent).toContain('Slider value: 0');\n\n      dispatchClickEventSequence(sliderNativeElement, 0.13);\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent).toContain('Slider value: 13');\n\n      // Always show tooltip even when the handle is not hovered.\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent).toContain('Slider value: 13');\n\n      tick(400);\n    }));\n  });\n\n  describe('setting value', () => {\n    let fixture: ComponentFixture<SliderWithValueComponent>;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(SliderWithValueComponent);\n      fixture.detectChanges();\n\n      sliderDebugElement = fixture.debugElement.query(By.directive(NzSliderComponent));\n      sliderInstance = sliderDebugElement.injector.get<NzSliderComponent>(NzSliderComponent);\n      sliderNativeElement = sliderInstance.slider.nativeElement;\n    });\n\n    it('should set the default value from the attribute', () => {\n      fixture.whenStable().then(() => expect(sliderInstance.value).toBe(26));\n    });\n\n    it('should set the correct value on click', () => {\n      dispatchClickEventSequence(sliderNativeElement, 0.92);\n      fixture.detectChanges();\n\n      // On a slider with default max and min the value should be approximately equal to the\n      // percentage clicked. This should be the case regardless of what the original set value was.\n      expect(sliderInstance.value).toBe(92);\n    });\n\n    it('should set the correct value on slide', () => {\n      dispatchSlideEventSequence(sliderNativeElement, 0, 0.32);\n      fixture.detectChanges();\n\n      expect(sliderInstance.value).toBe(32);\n    });\n  });\n\n  describe('marks', () => {\n    let fixture: ComponentFixture<SliderWithMarksComponent>;\n    let markListElement: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(SliderWithMarksComponent);\n      fixture.detectChanges();\n\n      getReferenceFromFixture(fixture);\n      markListElement = sliderNativeElement.querySelector('.ant-slider-mark') as HTMLElement;\n    });\n\n    it('should have start mark at the start', () => {\n      const value0Mark = markListElement.children[0] as HTMLElement;\n\n      expect(value0Mark.style.left).toEqual('0%');\n    });\n\n    it('should have end mark at the end', () => {\n      const value100Mark = markListElement.children[1] as HTMLElement;\n\n      expect(value100Mark.style.left).toEqual('100%');\n    });\n  });\n\n  describe('step', () => {\n    let fixture: ComponentFixture<SliderWithStepComponent>;\n    let trackFillElement: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(SliderWithStepComponent);\n      fixture.detectChanges();\n\n      sliderDebugElement = fixture.debugElement.query(By.directive(NzSliderComponent));\n      sliderInstance = sliderDebugElement.injector.get<NzSliderComponent>(NzSliderComponent);\n      sliderNativeElement = sliderInstance.slider.nativeElement;\n      trackFillElement = sliderNativeElement.querySelector('.ant-slider-track') as HTMLElement;\n    });\n\n    it('should set the correct step value on click', () => {\n      expect(sliderInstance.value).toBe(0);\n\n      dispatchClickEventSequence(sliderNativeElement, 0.13);\n      fixture.detectChanges();\n\n      expect(sliderInstance.value).toBe(25);\n    });\n\n    it('should snap the fill to a step on click', () => {\n      dispatchClickEventSequence(sliderNativeElement, 0.66);\n      fixture.detectChanges();\n\n      // The closest step is at 75% of the slider.\n      expect(trackFillElement.style.width).toBe('75%');\n    });\n\n    it('should set the correct step value on slide', () => {\n      dispatchSlideEventSequence(sliderNativeElement, 0, 0.07);\n      fixture.detectChanges();\n\n      expect(sliderInstance.value).toBe(0);\n    });\n\n    it('should snap the thumb and fill to a step on slide', () => {\n      dispatchSlideEventSequence(sliderNativeElement, 0, 0.88);\n      fixture.detectChanges();\n\n      // The closest snap is at the end of the slider.\n      expect(trackFillElement.style.width).toBe('100%');\n    });\n\n    // TODO: Pass this testing by increase precision\n    xit('should round the value inside the label based on the provided step', () => {\n      const testStep = (step: number, expected: string): void => {\n        fixture.componentInstance.step = step;\n        fixture.detectChanges();\n        dispatchSlideEventSequence(sliderNativeElement, 0, 0.333333);\n\n        expect(sliderInstance.value!.toString()).toBe(expected);\n      };\n\n      testStep(1, '33');\n      testStep(0.1, '33.3'); // TODO: not passing currently\n      testStep(0.01, '33.33'); // TODO: not passing currently\n      testStep(0.001, '33.333'); // TODO: not passing currently\n    });\n\n    it('should not add decimals to the value if it is a whole number', () => {\n      fixture.componentInstance.step = 0.1;\n      fixture.detectChanges();\n\n      dispatchSlideEventSequence(sliderNativeElement, 0, 1);\n\n      expect(sliderInstance.value).toBe(100);\n    });\n  });\n\n  describe('min and max', () => {\n    let fixture: ComponentFixture<SliderWithMinAndMaxComponent>;\n    let trackFillElement: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(SliderWithMinAndMaxComponent);\n      fixture.detectChanges();\n\n      getReferenceFromFixture(fixture);\n      trackFillElement = sliderNativeElement.querySelector('.ant-slider-track') as HTMLElement;\n    });\n\n    it('should set the default values from the attributes', () => {\n      expect(sliderInstance.value).toBe(4);\n      expect(sliderInstance.nzMin).toBe(4);\n      expect(sliderInstance.nzMax).toBe(6);\n    });\n\n    it('should set the correct value on click', () => {\n      dispatchClickEventSequence(sliderNativeElement, 0.09);\n      fixture.detectChanges();\n\n      // Computed by multiplying the difference between the min and the max by the percentage from\n      // the click and adding that to the minimum.\n      const value = Math.round((6 - 4) * 0.09 + 4);\n      expect(sliderInstance.value).toBe(value);\n    });\n\n    it('should set the correct value on slide', () => {\n      dispatchSlideEventSequence(sliderNativeElement, 0, 0.62);\n      fixture.detectChanges();\n\n      // Computed by multiplying the difference between the min and the max by the percentage from\n      // the click and adding that to the minimum.\n      const value = Math.round((6 - 4) * 0.62 + 4);\n      expect(sliderInstance.value).toBe(value);\n    });\n\n    it('should snap the fill to the nearest value on click', () => {\n      dispatchClickEventSequence(sliderNativeElement, 0.68);\n      fixture.detectChanges();\n\n      // The closest snap is halfway on the slider.\n      expect(trackFillElement.style.width).toBe('50%');\n    });\n\n    it('should snap the fill to the nearest value on slide', () => {\n      dispatchSlideEventSequence(sliderNativeElement, 0, 0.74);\n      fixture.detectChanges();\n\n      // The closest snap is at the halfway point on the slider.\n      expect(trackFillElement.style.width).toBe('50%');\n    });\n  });\n\n  describe('min and max and a value smaller than min', () => {\n    let fixture: ComponentFixture<SliderWithValueSmallerThanMinComponent>;\n    let trackFillElement: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(SliderWithValueSmallerThanMinComponent);\n      fixture.detectChanges();\n\n      getReferenceFromFixture(fixture);\n      trackFillElement = sliderNativeElement.querySelector('.ant-slider-track') as HTMLElement;\n    });\n\n    it('should set the value equal to the min value', () => {\n      expect(sliderInstance.value).toBe(4);\n      expect(sliderInstance.nzMin).toBe(4);\n      expect(sliderInstance.nzMax).toBe(6);\n    });\n\n    it('should set the fill to the min value', () => {\n      expect(trackFillElement.style.width).toBe('0%');\n    });\n  });\n\n  describe('min and max and a value greater than max', () => {\n    let fixture: ComponentFixture<SliderWithValueGreaterThanMaxComponent>;\n    let trackFillElement: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(SliderWithValueGreaterThanMaxComponent);\n      fixture.detectChanges();\n\n      getReferenceFromFixture(fixture);\n      trackFillElement = sliderNativeElement.querySelector('.ant-slider-track') as HTMLElement;\n    });\n\n    it('should set the value equal to the max value', () => {\n      fixture.whenStable().then(() => {\n        expect(sliderInstance.value).toBe(6);\n        expect(sliderInstance.nzMin).toBe(4);\n        expect(sliderInstance.nzMax).toBe(6);\n      });\n    });\n\n    it('should set the fill to the max value', () => {\n      fixture.whenStable().then(() => {\n        fixture.detectChanges();\n        expect(trackFillElement.style.width).toBe('100%');\n      });\n    });\n  });\n\n  describe('min and max and value is zero', () => {\n    let fixture: ComponentFixture<SliderWithValueZeroComponent>;\n    let trackFillElement: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(SliderWithValueZeroComponent);\n      fixture.detectChanges();\n\n      getReferenceFromFixture(fixture);\n      trackFillElement = sliderNativeElement.querySelector('.ant-slider-track') as HTMLElement;\n    });\n\n    it('should set the value equal to the middle value', () => {\n      fixture.whenStable().then(() => {\n        expect(sliderInstance.value).toBe(0);\n        expect(sliderInstance.nzMin).toBe(-5);\n        expect(sliderInstance.nzMax).toBe(5);\n      });\n    });\n\n    it('should set the fill to the middle value', () => {\n      fixture.whenStable().then(() => {\n        fixture.detectChanges();\n        expect(trackFillElement.style.width).toBe('50%');\n      });\n    });\n  });\n\n  describe('vertical', () => {\n    let fixture: ComponentFixture<VerticalSliderComponent>;\n    let trackFillElement: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(VerticalSliderComponent);\n      fixture.detectChanges();\n\n      sliderDebugElement = fixture.debugElement.query(By.directive(NzSliderComponent));\n      sliderInstance = sliderDebugElement.injector.get<NzSliderComponent>(NzSliderComponent);\n      sliderNativeElement = sliderInstance.slider.nativeElement;\n      trackFillElement = sliderNativeElement.querySelector('.ant-slider-track') as HTMLElement;\n    });\n\n    it('updates value on click', () => {\n      dispatchClickEventSequence(sliderNativeElement, 0.3);\n      fixture.detectChanges();\n\n      // It behaves differently in CI and local environment (Windows 10, chrome).\n      expect(sliderInstance.value).toBeCloseTo(71, -1);\n    });\n\n    it('should update the track fill on click', () => {\n      expect(trackFillElement.style.height).toBe('0%');\n\n      dispatchClickEventSequence(sliderNativeElement, 0.39);\n      fixture.detectChanges();\n\n      expect(parseInt(trackFillElement.style.height!, 10)).toBeCloseTo(62, -1);\n    });\n\n    it('should have ant-slider-vertical class', () => {\n      expect(sliderNativeElement.classList).toContain('ant-slider-vertical');\n    });\n  });\n\n  describe('reverse', () => {\n    let fixture: ComponentFixture<ReverseSliderComponent>;\n    let sliderDebugElements: DebugElement[];\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(ReverseSliderComponent);\n      fixture.detectChanges();\n\n      sliderDebugElements = fixture.debugElement.queryAll(By.directive(NzSliderComponent));\n    });\n\n    it('should reverse work', () => {\n      const trackElement = (sliderDebugElements[0].nativeElement as HTMLElement).querySelector(\n        '.ant-slider-track'\n      ) as HTMLElement;\n      expect(trackElement.style.right).toBe('0%');\n\n      const rangeTrackElement = (sliderDebugElements[1].nativeElement as HTMLElement).querySelector(\n        '.ant-slider-track'\n      ) as HTMLElement;\n      expect(trackElement.style.right).toBe('0%');\n      expect(rangeTrackElement.style.width).toBe('100%');\n\n      const verticalTrackElement = (sliderDebugElements[2].nativeElement as HTMLElement).querySelector(\n        '.ant-slider-track'\n      ) as HTMLElement;\n      expect(verticalTrackElement.style.top).toBe('0%');\n    });\n\n    it('should respond to keyboard event reversely', () => {\n      getReferenceFromFixture(fixture);\n\n      dispatchKeyboardEvent(sliderNativeElement, 'keydown', LEFT_ARROW);\n      dispatchKeyboardEvent(sliderNativeElement, 'keydown', RIGHT_ARROW);\n      dispatchKeyboardEvent(sliderNativeElement, 'keydown', DOWN_ARROW);\n      dispatchKeyboardEvent(sliderNativeElement, 'keydown', UP_ARROW);\n      dispatchKeyboardEvent(sliderNativeElement, 'keydown', LEFT_ARROW);\n\n      fixture.detectChanges();\n\n      const trackElement = (sliderDebugElements[0].nativeElement as HTMLElement).querySelector(\n        '.ant-slider-track'\n      ) as HTMLElement;\n      expect(trackElement.style.width).toBe('1%');\n    });\n\n    it('should reverse marks', () => {\n      const markList = (sliderDebugElements[0].nativeElement as HTMLElement).querySelector(\n        '.ant-slider-mark'\n      ) as HTMLElement;\n      const value0Mark = markList.children[0] as HTMLElement;\n      const value100Mark = markList.children[1] as HTMLElement;\n\n      expect(value0Mark.style.left).toEqual('100%');\n      expect(value100Mark.style.left).toEqual('0%');\n    });\n\n    it('should reverse steps', () => {\n      const stepList = (sliderDebugElements[0].nativeElement as HTMLElement).querySelector(\n        '.ant-slider-step'\n      ) as HTMLElement;\n      const value0Step = stepList.children[0] as HTMLElement;\n      const value100Step = stepList.children[1] as HTMLElement;\n\n      expect(value0Step.style.left).toEqual('100%');\n      expect(value100Step.style.left).toEqual('0%');\n    });\n  });\n\n  describe('reverse and min and max', () => {\n    let fixture: ComponentFixture<ReverseSliderWithMinAndMaxComponent>;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(ReverseSliderWithMinAndMaxComponent);\n      fixture.detectChanges();\n\n      getReferenceFromFixture(fixture);\n    });\n\n    it('should set the correct maximum value', () => {\n      dispatchClickEventSequence(sliderNativeElement, 0);\n      fixture.detectChanges();\n\n      expect(sliderInstance.value).toEqual(6);\n    });\n\n    it('should set the correct minimum value', () => {\n      dispatchClickEventSequence(sliderNativeElement, 1);\n      fixture.detectChanges();\n\n      expect(sliderInstance.value).toEqual(4);\n    });\n  });\n\n  describe('mixed usage', () => {\n    let fixture: ComponentFixture<MixedSliderComponent>;\n    let trackFillElement: HTMLElement;\n    let testComponent: MixedSliderComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(MixedSliderComponent);\n      fixture.detectChanges();\n\n      testComponent = fixture.componentInstance;\n      getReferenceFromFixture(fixture);\n      trackFillElement = sliderNativeElement.querySelector('.ant-slider-track') as HTMLElement;\n    });\n\n    beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n      overlayContainerElement = oc.getContainerElement();\n    }));\n\n    it('update the correct range value and show correct steps format', () => {\n      expect(sliderNativeElement.textContent).toContain('(22%)');\n      expect(sliderNativeElement.textContent).toContain('(36%)');\n\n      testComponent.range = true;\n      fixture.detectChanges();\n\n      dispatchClickEventSequence(sliderNativeElement, 0.1);\n\n      // Potentially a bug of jasmine or karma. Event handler makes calling stack destroyed.\n      // dispatchClickEventSequence(sliderNativeElement, 0.8);\n      fixture.detectChanges();\n\n      expect(sliderInstance.value).toEqual([10, 100]);\n    });\n\n    it(\"should/shouldn't be included\", () => {\n      dispatchClickEventSequence(sliderNativeElement, 0.33);\n      fixture.detectChanges();\n      expect(trackFillElement.style.left).toBe('0%');\n      expect(trackFillElement.style.width).toBe('33%');\n      expect(trackFillElement.style.visibility).toBe('visible');\n\n      testComponent.included = false;\n      fixture.detectChanges();\n      expect(trackFillElement.style.visibility).toBe('hidden');\n    });\n\n    it('should stop at one mark other than step, and show correct tooltip', () => {\n      testComponent.step = 10;\n      fixture.detectChanges();\n\n      dispatchSlideEventSequence(sliderNativeElement, 0.15, 0.34, true);\n      fixture.detectChanges();\n      expect(sliderInstance.value).toBe(36);\n      expect(overlayContainerElement.textContent).toContain('VALUE-36');\n    });\n\n    it('should stop at new steps when step=null or dots=true', () => {\n      testComponent.marks = { 15: { style: { color: 'red' }, label: '15' }, 33: '33' } as any; // eslint-disable-line @typescript-eslint/no-explicit-any\n      testComponent.step = null;\n      fixture.detectChanges();\n\n      dispatchSlideEventSequence(sliderNativeElement, 0, 0.09);\n      fixture.detectChanges();\n      expect(sliderInstance.value).toBe(15);\n\n      testComponent.step = 1;\n      testComponent.dots = true;\n      fixture.detectChanges();\n\n      dispatchSlideEventSequence(sliderNativeElement, 0, 0.66);\n      fixture.detectChanges();\n      expect(sliderInstance.value).toBe(33);\n    });\n\n    it('should show/hide tooltip when enter/leave a handler', fakeAsync(() => {\n      const handlerHost = sliderNativeElement.querySelector('nz-slider-handle')!;\n\n      dispatchClickEventSequence(sliderNativeElement, 0.13);\n      fixture.detectChanges();\n\n      dispatchMouseEvent(handlerHost, 'mouseenter');\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent).toContain('VALUE-13');\n\n      dispatchMouseEvent(handlerHost, 'mouseleave');\n      tick(400); // wait for tooltip's animations\n      expect(overlayContainerElement.textContent).not.toContain('VALUE-13');\n    }));\n\n    // fix #5699, Slider should work with decimals as well\n    it('should work with decimals', fakeAsync(() => {\n      testComponent.marks = {\n        0.5: '0.5',\n        0.8: '0.8',\n        1: '1',\n        1.2: '1.2',\n        1.5: '1.5',\n        2: '2'\n      };\n      testComponent.min = 0.5;\n      testComponent.max = 2;\n      testComponent.step = null;\n      fixture.detectChanges();\n\n      dispatchClickEventSequence(sliderNativeElement, 0.13);\n      fixture.detectChanges();\n      expect(sliderInstance.value).toBe(0.8);\n\n      dispatchClickEventSequence(sliderNativeElement, 0.6);\n      fixture.detectChanges();\n      expect(sliderInstance.value).toBe(1.5);\n    }));\n  });\n\n  describe('slider as a custom form control', () => {\n    let fixture: ComponentFixture<SliderWithFormControlComponent>;\n    let testComponent: SliderWithFormControlComponent;\n    let sliderControl: AbstractControl;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(SliderWithFormControlComponent);\n      fixture.detectChanges();\n\n      testComponent = fixture.componentInstance;\n      sliderControl = testComponent.formControl;\n      getReferenceFromFixture(fixture);\n    });\n\n    it('should have correct initial value', fakeAsync(() => {\n      fixture.detectChanges();\n      const firstElementChildSlider = sliderDebugElement.nativeElement.firstElementChild;\n      expect(sliderInstance.value).toBe(42);\n      expect(firstElementChildSlider!.classList).not.toContain('ant-slider-disabled');\n    }));\n\n    it('should not update the control when the value is updated', () => {\n      expect(sliderControl.value).toBe(42);\n\n      sliderInstance.value = 11;\n      fixture.detectChanges();\n      expect(sliderControl.value).toBe(42);\n    });\n\n    it('should update the control', () => {\n      expect(sliderControl.value).toBe(42);\n\n      dispatchClickEventSequence(sliderNativeElement, 0.76);\n      fixture.detectChanges();\n      expect(sliderControl.value).toBe(76);\n\n      dispatchSlideEventSequence(sliderNativeElement, 0.42, 0.19);\n      fixture.detectChanges();\n      expect(sliderControl.value).toBe(19);\n\n      sliderControl.setValue(7);\n      fixture.detectChanges();\n      expect(sliderControl.value).toBe(7);\n      expect(sliderInstance.value).toBe(7);\n    });\n    it('should be disable initially even if nzDisable is set to false', () => {\n      testComponent.disable();\n      fixture.detectChanges();\n      const sliderElement = sliderDebugElement.nativeElement;\n\n      expect(sliderElement!.classList).toContain('ant-slider-disabled');\n      expect(sliderInstance.nzDisabled).toBe(true);\n    });\n    it('should disable work', () => {\n      testComponent.disabled = true;\n      fixture.detectChanges();\n      const sliderElement = sliderDebugElement.nativeElement;\n\n      expect(sliderElement!.classList).toContain('ant-slider-disabled');\n      expect(sliderInstance.nzDisabled).toBe(true);\n      expect(sliderControl.value).toBe(42);\n      dispatchClickEventSequence(sliderNativeElement, 0.76);\n      fixture.detectChanges();\n      expect(sliderControl.value).toBe(42);\n\n      testComponent.enable();\n      fixture.detectChanges();\n      expect(sliderElement!.classList).not.toContain('ant-slider-disabled');\n      expect(sliderInstance.nzDisabled).toBe(false);\n      dispatchClickEventSequence(sliderNativeElement, 0.76);\n      fixture.detectChanges();\n      expect(sliderControl.value).toBe(76);\n\n      testComponent.disable();\n      fixture.detectChanges();\n      expect(sliderElement!.classList).toContain('ant-slider-disabled');\n      expect(sliderInstance.nzDisabled).toBe(true);\n      dispatchSlideEventSequence(sliderNativeElement, 0.42, 0.19);\n      fixture.detectChanges();\n      expect(sliderControl.value).toBe(76);\n    });\n\n    it('should have the correct control state initially and after interaction', () => {\n      // The control should start off valid, pristine, and untouched.\n      expect(sliderControl.valid).toBe(true);\n      expect(sliderControl.pristine).toBe(true);\n      expect(sliderControl.touched).toBe(false);\n\n      // After changing the value, the control should become dirty (not pristine),\n      // but remain untouched.\n      dispatchClickEventSequence(sliderNativeElement, 0.5);\n      fixture.detectChanges();\n\n      expect(sliderControl.valid).toBe(true);\n      expect(sliderControl.pristine).toBe(false);\n      expect(sliderControl.touched).toBe(false);\n\n      // If the control has been visited due to interaction, the control should remain\n      // dirty and now also be touched.\n      sliderInstance.onTouched();\n      fixture.detectChanges();\n\n      expect(sliderControl.valid).toBe(true);\n      expect(sliderControl.pristine).toBe(false);\n      expect(sliderControl.touched).toBe(true);\n    });\n  });\n\n  describe('support keyboard event', () => {\n    let fixture: ComponentFixture<NzTestSliderKeyboardComponent>;\n    let testComponent: NzTestSliderKeyboardComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestSliderKeyboardComponent);\n      testComponent = fixture.componentInstance;\n      fixture.detectChanges();\n\n      getReferenceFromFixture(fixture);\n    });\n\n    it('should work for non-range slider', () => {\n      dispatchKeyboardEvent(sliderNativeElement, 'keydown', RIGHT_ARROW);\n      dispatchKeyboardEvent(sliderNativeElement, 'keydown', RIGHT_ARROW);\n      dispatchKeyboardEvent(sliderNativeElement, 'keydown', LEFT_ARROW);\n\n      expect(sliderInstance.value).toBe(1);\n    });\n\n    it('should work for range slider', () => {\n      testComponent.range = true;\n      sliderInstance.activeValueIndex = 0;\n      fixture.detectChanges();\n\n      dispatchKeyboardEvent(sliderNativeElement, 'keydown', RIGHT_ARROW);\n      dispatchKeyboardEvent(sliderNativeElement, 'keydown', RIGHT_ARROW);\n      fixture.detectChanges();\n\n      expect(sliderInstance.value).toEqual([2, 100]);\n\n      sliderInstance.activeValueIndex = 1;\n      dispatchKeyboardEvent(sliderNativeElement, 'keydown', LEFT_ARROW);\n      fixture.detectChanges();\n\n      expect(sliderInstance.value).toEqual([2, 99]);\n    });\n\n    it('should trigger nzOnAfterChange', () => {\n      const onChangeSpy = jasmine.createSpy('slider onChange');\n\n      sliderInstance.nzOnAfterChange.subscribe(onChangeSpy);\n      dispatchKeyboardEvent(sliderNativeElement, 'keydown', RIGHT_ARROW);\n      fixture.detectChanges();\n\n      expect(onChangeSpy).toHaveBeenCalledTimes(1);\n    });\n\n    it('should work for range slider when activeValueIndex is undefined', () => {\n      testComponent.range = true;\n      fixture.detectChanges();\n\n      const handleElements = sliderNativeElement.querySelectorAll('nz-slider-handle');\n      expect(handleElements.length).toBe(2);\n\n      dispatchFakeEvent(handleElements[0]!, 'focusin');\n      dispatchKeyboardEvent(sliderNativeElement, 'keydown', RIGHT_ARROW);\n      fixture.detectChanges();\n\n      expect(sliderInstance.value).toEqual([1, 100]);\n\n      dispatchFakeEvent(handleElements[1]!, 'focusin');\n      dispatchKeyboardEvent(sliderNativeElement, 'keydown', LEFT_ARROW);\n      fixture.detectChanges();\n\n      expect(sliderInstance.value).toEqual([1, 99]);\n    });\n\n    it('should not respond to keyboard event when disabled', () => {\n      expect(sliderInstance.value).toBe(0);\n\n      dispatchKeyboardEvent(sliderNativeElement, 'keydown', RIGHT_ARROW);\n      expect(sliderInstance.value).toBe(1);\n\n      testComponent.disabled = true;\n      fixture.detectChanges();\n      dispatchKeyboardEvent(sliderNativeElement, 'keydown', RIGHT_ARROW);\n      expect(sliderInstance.value).toBe(1);\n\n      testComponent.disabled = false;\n      fixture.detectChanges();\n      dispatchKeyboardEvent(sliderNativeElement, 'keydown', RIGHT_ARROW);\n      expect(sliderInstance.value).toBe(2);\n    });\n  });\n\n  describe('RTL', () => {\n    let fixture: ComponentFixture<NzTestSliderRtlComponent>;\n    let trackFillElement: HTMLElement;\n    let trackHandleElement: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestSliderRtlComponent);\n      fixture.detectChanges();\n\n      getReferenceFromFixture(fixture);\n      trackFillElement = sliderNativeElement.querySelector('.ant-slider-track') as HTMLElement;\n      trackHandleElement = sliderNativeElement.querySelector('.ant-slider-handle') as HTMLElement;\n    });\n\n    it('should className correct on dir change', fakeAsync(() => {\n      expect(sliderNativeElement.classList).toContain('ant-slider-rtl');\n\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n      expect(sliderNativeElement.classList).not.toContain('ant-slider-rtl');\n    }));\n\n    it('should update the track fill on click', fakeAsync(() => {\n      expect(trackFillElement.style.width).toBe('0%');\n\n      dispatchClickEventSequence(sliderNativeElement, 0.39, true);\n      fixture.detectChanges();\n\n      expect(trackFillElement.style.width).toBe('39%');\n    }));\n\n    it('should update track fill style on direction change', () => {\n      expect(trackFillElement.style.left).toBe('auto');\n      expect(trackFillElement.style.right).toBe('0%');\n\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n\n      expect(trackFillElement.style.left).toBe('0%');\n      expect(trackFillElement.style.right).toBe('auto');\n    });\n\n    it('should update track handle style on direction change', () => {\n      dispatchClickEventSequence(sliderNativeElement, 0.39, true);\n      fixture.detectChanges();\n\n      expect(trackHandleElement.style.left).toBe('auto');\n      expect(trackHandleElement.style.right).toBe('39%');\n\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n\n      expect(trackHandleElement.style.right).toBe('auto');\n      expect(trackHandleElement.style.left).toBe('39%');\n    });\n  });\n});\n\nconst styles = `\n  ::ng-deep .ant-slider { display: block; position: relative; width: 100px; height: 12px; }\n  ::ng-deep .ant-slider .ant-slider-rail { position: absolute; width: 100%; height: 4px; }\n  ::ng-deep .ant-slider .ant-slider-track { position: absolute; height: 4px; }\n  ::ng-deep .ant-slider .ant-slider-handle { position: absolute; margin-left: -7px; margin-top: -5px; width: 14px; height: 14px; }\n\n  ::ng-deep .ant-slider-vertical { height: 100px; width: 12px; }\n  ::ng-deep .ant-slider-vertical .ant-slider-rail { height: 100%; width: 4px; }\n  ::ng-deep .ant-slider-vertical .ant-slider-track { width: 4px; }\n`;\n\n@Component({\n  imports: [NzSliderModule],\n  template: `<nz-slider [nzDisabled]=\"disabled\" />`,\n  styles: [styles]\n})\nclass NzTestSliderComponent {\n  disabled = false;\n}\n\n@Component({\n  imports: [NzSliderModule],\n  template: `<nz-slider [nzMin]=\"min\" [nzMax]=\"max\" />`,\n  styles: [styles]\n})\nclass SliderWithMinAndMaxComponent {\n  min = 4;\n  max = 6;\n}\n\n@Component({\n  imports: [FormsModule, NzSliderModule],\n  template: `<nz-slider [ngModel]=\"26\" />`,\n  styles: [styles]\n})\nclass SliderWithValueComponent {}\n\n@Component({\n  imports: [NzSliderModule],\n  template: `<nz-slider [nzMarks]=\"marks\" />`\n})\nclass SliderWithMarksComponent {\n  marks: Record<number, string> = { 100: '(100%)', 0: '(0%)' };\n}\n\n@Component({\n  imports: [NzSliderModule],\n  template: `<nz-slider [nzStep]=\"step\" />`,\n  styles: [styles]\n})\nclass SliderWithStepComponent {\n  step = 25;\n}\n\n@Component({\n  imports: [FormsModule, NzSliderModule],\n  template: `<nz-slider [ngModel]=\"3\" [nzMin]=\"4\" [nzMax]=\"6\" />`,\n  styles: [styles]\n})\nclass SliderWithValueSmallerThanMinComponent {}\n\n@Component({\n  imports: [FormsModule, NzSliderModule],\n  template: `<nz-slider [ngModel]=\"0\" [nzMin]=\"-5\" [nzMax]=\"5\" />`,\n  styles: [styles]\n})\nclass SliderWithValueZeroComponent {}\n\n@Component({\n  imports: [FormsModule, NzSliderModule],\n  template: `<nz-slider [ngModel]=\"7\" [nzMin]=\"4\" [nzMax]=\"6\" />`,\n  styles: [styles]\n})\nclass SliderWithValueGreaterThanMaxComponent {}\n\n@Component({\n  imports: [NzSliderModule],\n  template: `<nz-slider nzVertical />`,\n  styles: [styles]\n})\nclass VerticalSliderComponent {}\n\n@Component({\n  imports: [NzSliderModule],\n  template: `\n    <nz-slider nzReverse [nzMarks]=\"marks\" />\n    <nz-slider nzReverse nzRange />\n    <nz-slider nzVertical nzReverse />\n  `\n})\nclass ReverseSliderComponent {\n  marks: Record<number, string> = { 100: '(100%)', 0: '(0%)' };\n}\n\n@Component({\n  imports: [NzSliderModule],\n  template: `<nz-slider [nzMin]=\"4\" [nzMax]=\"6\" nzReverse />`,\n  styles: [styles]\n})\nclass ReverseSliderWithMinAndMaxComponent {}\n\n@Component({\n  imports: [NzSliderModule],\n  template: `\n    <nz-slider\n      [nzRange]=\"range\"\n      [nzStep]=\"step\"\n      [nzMarks]=\"marks\"\n      [nzDots]=\"dots\"\n      [nzIncluded]=\"included\"\n      [nzTipFormatter]=\"tipFormatter\"\n      [nzMin]=\"min\"\n      [nzMax]=\"max\"\n    />\n  `,\n  styles: [styles]\n})\nclass MixedSliderComponent {\n  dots = false;\n  included = true;\n  marks: Record<number, string> = { 22: '(22%)', 36: '(36%)' };\n  max = 100;\n  min = 0;\n  range = false;\n  step: number | null = 1;\n\n  tipFormatter(value: number): string {\n    return `VALUE-${value}`;\n  }\n}\n\n@Component({\n  imports: [ReactiveFormsModule, NzSliderModule],\n  template: `\n    <form>\n      <nz-slider [formControl]=\"formControl\" [nzDisabled]=\"disabled\" />\n    </form>\n  `,\n  styles: [styles]\n})\nclass SliderWithFormControlComponent {\n  formControl = new FormControl(42);\n\n  disabled = false;\n\n  disable(): void {\n    this.formControl.disable();\n  }\n\n  enable(): void {\n    this.formControl.enable();\n  }\n}\n\n@Component({\n  imports: [FormsModule, NzSliderModule],\n  template: `<nz-slider [nzTooltipVisible]=\"show\" [ngModel]=\"value\" />`\n})\nclass SliderShowTooltipComponent {\n  show: NzSliderShowTooltip = 'default';\n\n  value = 0;\n}\n\n@Component({\n  imports: [NzSliderModule],\n  template: `<nz-slider [nzRange]=\"range\" [nzDisabled]=\"disabled\" />`\n})\nclass NzTestSliderKeyboardComponent {\n  range = false;\n  disabled = false;\n}\n\n@Component({\n  imports: [FormsModule, NzSliderModule],\n  template: `\n    <nz-slider [nzTooltipVisible]=\"show\" [ngModel]=\"value\" [nzTipFormatter]=\"titleTemplate\" />\n    <ng-template #titleTemplate let-value>\n      <span>Slider value: {{ value }}</span>\n    </ng-template>\n  `\n})\nclass SliderShowTemplateTooltipComponent {\n  show: NzSliderShowTooltip = 'default';\n  value = 0;\n}\n\n/**\n * Dispatches a click event sequence (consisting of moueseenter, click) from an element.\n * Note: The mouse event truncates the position for the click.\n *\n * @param sliderElement The sliderDOM element from which the event will be dispatched.\n * @param percentage The percentage of the slider where the click should occur. Used to find the\n * physical location of the click.\n * @param isRtl Whether or not in RTL direction\n */\nfunction dispatchClickEventSequence(sliderElement: HTMLElement, percentage: number, isRtl: boolean = false): void {\n  const trackElement = sliderElement.querySelector('.ant-slider-rail')!;\n  const dimensions = trackElement.getBoundingClientRect();\n  const x = dimensions.left + dimensions.width * (isRtl ? 1 - percentage : percentage);\n  const y = dimensions.top + dimensions.height * (isRtl ? 1 - percentage : percentage);\n\n  dispatchMouseenterEvent(sliderElement);\n  dispatchMouseEvent(sliderElement, 'mousedown', x, y);\n  dispatchMouseEvent(document, 'mouseup', x, y);\n}\n\n/**\n * Dispatches a slide event sequence (consisting of slidestart, slide, slideend) from an element.\n *\n * @param sliderElement The sliderDOM element from which the event will be dispatched.\n * @param startPercent The percentage of the slider where the slide will begin.\n * @param endPercent The percentage of the slider where the slide will end.\n * @param stick Whether stick on and not mouseup when move at the end\n */\nfunction dispatchSlideEventSequence(\n  sliderElement: HTMLElement,\n  startPercent: number,\n  endPercent: number,\n  stick: boolean = false\n): void {\n  dispatchMouseenterEvent(sliderElement);\n  dispatchSlideStartEvent(sliderElement, startPercent);\n  dispatchSlideEvent(sliderElement, startPercent);\n  dispatchSlideEvent(sliderElement, endPercent);\n  if (!stick) {\n    dispatchSlideEndEvent(sliderElement, endPercent);\n  }\n}\n\n/**\n * Dispatches a slide event from an element.\n *\n * @param sliderElement The sliderDOM element from which the event will be dispatched.\n * @param percent The percentage of the slider where the slide will happen.\n */\nfunction dispatchSlideEvent(sliderElement: HTMLElement, percent: number): void {\n  const trackElement = sliderElement.querySelector('.ant-slider-rail')!;\n  const dimensions = trackElement.getBoundingClientRect();\n  const x = dimensions.left + dimensions.width * percent;\n  const y = dimensions.top + dimensions.height * percent;\n\n  dispatchMouseEvent(document, 'mousemove', x, y);\n}\n\n/**\n * Dispatches a slidestart event from an element.\n *\n * @param sliderElement The sliderDOM element from which the event will be dispatched.\n * @param percent The percentage of the slider where the slide will begin.\n */\nfunction dispatchSlideStartEvent(sliderElement: HTMLElement, percent: number): void {\n  const trackElement = sliderElement.querySelector('.ant-slider-rail')!;\n  const dimensions = trackElement.getBoundingClientRect();\n  const x = dimensions.left + dimensions.width * percent;\n  const y = dimensions.top + dimensions.height * percent;\n\n  dispatchMouseenterEvent(sliderElement);\n\n  dispatchMouseEvent(sliderElement, 'mousedown', x, y);\n}\n\n/**\n * Dispatches a slideend event from an element.\n *\n * @param sliderElement The sliderDOM element from which the event will be dispatched.\n * @param percent The percentage of the slider where the slide will end.\n */\nfunction dispatchSlideEndEvent(sliderElement: HTMLElement, percent: number): void {\n  const trackElement = sliderElement.querySelector('.ant-slider-rail')!;\n  const dimensions = trackElement.getBoundingClientRect();\n  const x = dimensions.left + dimensions.width * percent;\n  const y = dimensions.top + dimensions.height * percent;\n\n  dispatchMouseEvent(document, 'mouseup', x, y);\n}\n\n/**\n * Dispatches a mouseenter event from an element.\n * Note: The mouse event truncates the position for the click.\n *\n * @param element The element from which the event will be dispatched.\n */\nfunction dispatchMouseenterEvent(element: HTMLElement): void {\n  const dimensions = element.getBoundingClientRect();\n  const y = dimensions.top;\n  const x = dimensions.left;\n\n  dispatchMouseEvent(element, 'mouseenter', x, y);\n}\n\n@Component({\n  imports: [BidiModule, NzSliderModule],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-slider />\n    </div>\n  `\n})\nexport class NzTestSliderRtlComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n}\n"
  },
  {
    "path": "components/slider/step.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  Component,\n  Input,\n  numberAttribute,\n  OnChanges,\n  SimpleChanges,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { NzDisplayedStep, NzExtendedMark } from './typings';\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-slider-step',\n  exportAs: 'nzSliderStep',\n  template: `\n    @for (step of steps; track step.value) {\n      <span class=\"ant-slider-dot\" [class.ant-slider-dot-active]=\"step.active\" [style]=\"step.style!\"></span>\n    }\n  `,\n  host: {\n    class: 'ant-slider-step'\n  }\n})\nexport class NzSliderStepComponent implements OnChanges {\n  @Input() lowerBound: number | null = null;\n  @Input() upperBound: number | null = null;\n  @Input() marksArray: NzExtendedMark[] = [];\n  @Input({ transform: numberAttribute }) min!: number;\n  @Input({ transform: numberAttribute }) max!: number;\n  @Input({ transform: booleanAttribute }) vertical = false;\n  @Input({ transform: booleanAttribute }) included = false;\n  @Input({ transform: booleanAttribute }) reverse!: boolean;\n\n  steps: NzDisplayedStep[] = [];\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { marksArray, lowerBound, upperBound, reverse } = changes;\n\n    if (marksArray || reverse) {\n      this.buildSteps();\n    }\n    if (marksArray || lowerBound || upperBound || reverse) {\n      this.togglePointActive();\n    }\n  }\n\n  private buildSteps(): void {\n    const orient = this.vertical ? 'bottom' : 'left';\n\n    this.steps = this.marksArray.map(mark => {\n      const { value, config } = mark;\n      let offset = mark.offset;\n      const range = this.max - this.min;\n\n      if (this.reverse) {\n        offset = ((this.max - value) / range) * 100;\n      }\n\n      return {\n        value,\n        offset,\n        config,\n        active: false,\n        style: {\n          [orient]: `${offset}%`,\n          transform: this.vertical ? 'translateY(50%)' : 'translateX(-50%)'\n        }\n      };\n    });\n  }\n\n  private togglePointActive(): void {\n    if (this.steps && this.lowerBound !== null && this.upperBound !== null) {\n      this.steps.forEach(step => {\n        const value = step.value;\n        step.active = this.included\n          ? value <= this.upperBound! && value >= this.lowerBound!\n          : value === this.upperBound;\n      });\n    }\n  }\n}\n"
  },
  {
    "path": "components/slider/style/entry.less",
    "content": "@import './index.less';\n@import './patch.less';\n// style dependencies\n@import '../../tooltip/style/entry.less';\n"
  },
  {
    "path": "components/slider/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@slider-prefix-cls: ~'@{ant-prefix}-slider';\n\n.@{slider-prefix-cls} {\n  .reset-component();\n\n  position: relative;\n  height: 12px;\n  margin: @slider-margin;\n  padding: 4px 0;\n  cursor: pointer;\n  touch-action: none;\n\n  .vertical();\n\n  &-with-marks {\n    margin-bottom: 28px;\n  }\n\n  &-rail {\n    position: absolute;\n    width: 100%;\n    height: 4px;\n    background-color: @slider-rail-background-color;\n    border-radius: @border-radius-base;\n    transition: background-color 0.3s;\n  }\n\n  &-track {\n    position: absolute;\n    height: 4px;\n    background-color: @slider-track-background-color;\n    border-radius: @border-radius-base;\n    transition: background-color 0.3s;\n  }\n\n  &-handle {\n    position: absolute;\n    width: @slider-handle-size;\n    height: @slider-handle-size;\n    margin-top: @slider-handle-margin-top;\n    background-color: @slider-handle-background-color;\n    border: solid @slider-handle-border-width @slider-handle-color;\n    border-radius: 50%;\n    box-shadow: @slider-handle-shadow;\n    cursor: pointer;\n    transition: border-color 0.3s, box-shadow 0.6s,\n      transform 0.3s cubic-bezier(0.18, 0.89, 0.32, 1.28);\n\n    // &-dragging&-dragging&-dragging {\n    //   border-color: @slider-handle-color-focus;\n    //   box-shadow: 0 0 0 5px @slider-handle-color-focus-shadow;\n    // }\n    &-dragging {\n      z-index: 1;\n    }\n\n    &:focus {\n      border-color: @slider-handle-color-focus;\n      outline: none;\n      box-shadow: 0 0 0 5px @slider-handle-color-focus-shadow;\n    }\n\n    &.@{ant-prefix}-tooltip-open {\n      border-color: @slider-handle-color-tooltip-open;\n    }\n\n    &::after {\n      position: absolute;\n      top: -6px;\n      right: -6px;\n      bottom: -6px;\n      left: -6px;\n      content: '';\n    }\n  }\n\n  &:hover {\n    .@{slider-prefix-cls}-rail {\n      background-color: @slider-rail-background-color-hover;\n    }\n    .@{slider-prefix-cls}-track {\n      background-color: @slider-track-background-color-hover;\n    }\n    .@{slider-prefix-cls}-handle:not(.@{ant-prefix}-tooltip-open) {\n      border-color: @slider-handle-color-hover;\n    }\n  }\n\n  &-mark {\n    position: absolute;\n    top: 14px;\n    left: 0;\n    width: 100%;\n    font-size: @font-size-base;\n  }\n\n  &-mark-text {\n    position: absolute;\n    display: inline-block;\n    color: @text-color-secondary;\n    text-align: center;\n    word-break: keep-all;\n    cursor: pointer;\n    user-select: none;\n\n    &-active {\n      color: @text-color;\n    }\n  }\n\n  &-step {\n    position: absolute;\n    width: 100%;\n    height: 4px;\n    background: transparent;\n    pointer-events: none;\n  }\n\n  &-dot {\n    position: absolute;\n    top: -2px;\n    width: 8px;\n    height: 8px;\n    background-color: @component-background;\n    border: 2px solid @slider-dot-border-color;\n    border-radius: 50%;\n    cursor: pointer;\n\n    &-active {\n      border-color: @slider-dot-border-color-active;\n    }\n  }\n\n  &-disabled {\n    cursor: not-allowed;\n\n    .@{slider-prefix-cls}-rail {\n      background-color: @slider-rail-background-color !important;\n    }\n\n    .@{slider-prefix-cls}-track {\n      background-color: @slider-disabled-color !important;\n    }\n\n    .@{slider-prefix-cls}-handle,\n    .@{slider-prefix-cls}-dot {\n      background-color: @component-background;\n      border-color: @slider-disabled-color !important;\n      box-shadow: none;\n      cursor: not-allowed;\n    }\n\n    .@{slider-prefix-cls}-mark-text,\n    .@{slider-prefix-cls}-dot {\n      cursor: not-allowed !important;\n    }\n  }\n}\n\n.vertical() {\n  &-vertical {\n    width: 12px;\n    height: 100%;\n    margin: 6px 10px;\n    padding: 0 4px;\n\n    .@{slider-prefix-cls}-rail {\n      width: 4px;\n      height: 100%;\n    }\n\n    .@{slider-prefix-cls}-track {\n      width: 4px;\n    }\n\n    .@{slider-prefix-cls}-handle {\n      margin-top: -6px; // we chould consider border width as well: (10 + 2 ) / 2\n      margin-left: @slider-handle-margin-left;\n    }\n\n    .@{slider-prefix-cls}-mark {\n      top: 0;\n      left: 12px;\n      width: 18px;\n      height: 100%;\n    }\n\n    .@{slider-prefix-cls}-mark-text {\n      left: 4px;\n      white-space: nowrap;\n    }\n\n    .@{slider-prefix-cls}-step {\n      width: 4px;\n      height: 100%;\n    }\n\n    .@{slider-prefix-cls}-dot {\n      top: auto;\n      margin-left: -2px;\n    }\n  }\n\n  &-tooltip {\n    // https://github.com/ant-design/ant-design/issues/20014\n    .@{ant-prefix}-tooltip-inner {\n      min-width: unset;\n    }\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/slider/style/patch.less",
    "content": ".ant-slider {\n  display: block;\n}\n"
  },
  {
    "path": "components/slider/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@slider-prefix-cls: ~'@{ant-prefix}-slider';\n\n.@{slider-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &-mark {\n    .@{slider-prefix-cls}-rtl & {\n      right: 0;\n      left: auto;\n    }\n  }\n}\n\n.vertical() {\n  &-vertical {\n    .@{slider-prefix-cls}-handle {\n      .@{slider-prefix-cls}-rtl& {\n        margin-right: -5px;\n        margin-left: 0;\n      }\n    }\n\n    .@{slider-prefix-cls}-mark {\n      .@{slider-prefix-cls}-rtl& {\n        right: 12px;\n        left: auto;\n      }\n    }\n\n    .@{slider-prefix-cls}-mark-text {\n      .@{slider-prefix-cls}-rtl& {\n        right: 4px;\n        left: auto;\n      }\n    }\n\n    .@{slider-prefix-cls}-dot {\n      .@{slider-prefix-cls}-rtl& {\n        right: 2px;\n        left: auto;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/slider/track.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction } from '@angular/cdk/bidi';\nimport {\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  Component,\n  Input,\n  numberAttribute,\n  OnChanges,\n  ViewEncapsulation\n} from '@angular/core';\n\nexport interface NzSliderTrackStyle {\n  bottom?: string | null;\n  height?: string | null;\n  left?: string | null;\n  right?: string | null;\n  width?: string | null;\n  visibility?: string;\n}\n\n@Component({\n  selector: 'nz-slider-track',\n  exportAs: 'nzSliderTrack',\n  template: `<div class=\"ant-slider-track\" [style]=\"style\"></div>`,\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class NzSliderTrackComponent implements OnChanges {\n  @Input({ transform: numberAttribute }) offset: number = 0;\n  @Input({ transform: booleanAttribute }) reverse: boolean = false;\n  @Input() dir: Direction = 'ltr';\n  @Input({ transform: numberAttribute }) length: number = 0;\n  @Input({ transform: booleanAttribute }) vertical = false;\n  @Input({ transform: booleanAttribute }) included = false;\n\n  style: NzSliderTrackStyle = {};\n\n  ngOnChanges(): void {\n    const visibility = this.included ? 'visible' : 'hidden';\n\n    if (this.vertical) {\n      this.style = {\n        [this.reverse ? 'top' : 'bottom']: `${this.offset}%`,\n        [this.reverse ? 'bottom' : 'top']: 'auto',\n        height: `${this.length}%`,\n        visibility\n      };\n    } else {\n      this.style = {\n        ...this.getHorizontalStylePosition(),\n        width: `${this.length}%`,\n        visibility\n      };\n    }\n  }\n\n  private getHorizontalStylePosition(): { left: string; right: string } {\n    let left = this.reverse ? 'auto' : `${this.offset}%`;\n    let right = this.reverse ? `${this.offset}%` : 'auto';\n    if (this.dir === 'rtl') {\n      [left, right] = [right, left];\n    }\n    return { left, right };\n  }\n}\n"
  },
  {
    "path": "components/slider/typings.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport type NzMark = string | NzMarkObj;\n\nexport interface NzMarkObj {\n  style?: object;\n  label: string;\n}\n\nexport class NzMarks {\n  [key: string]: NzMark;\n}\n\n/**\n * Processed steps that would be passed to sub components.\n */\nexport interface NzExtendedMark {\n  value: number;\n  offset: number;\n  config: NzMark;\n}\n\n/**\n * Marks that would be rendered.\n */\nexport interface NzDisplayedMark extends NzExtendedMark {\n  active: boolean;\n  label: string;\n  style?: object;\n}\n\n/**\n * Steps that would be rendered.\n */\nexport interface NzDisplayedStep extends NzExtendedMark {\n  active: boolean;\n  style?: object;\n}\n\nexport type NzSliderShowTooltip = 'always' | 'never' | 'default';\n\nexport type NzSliderValue = number[] | number;\n\nexport interface NzSliderHandler {\n  offset: number | null;\n  value: number | null;\n  active: boolean;\n}\n"
  },
  {
    "path": "components/space/demo/align.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 对齐\n  en-US: Align\n---\n\n## zh-CN\n\n设置对齐模式。\n\n## en-US\n\nConfig item align.\n"
  },
  {
    "path": "components/space/demo/align.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\n\n@Component({\n  selector: 'nz-demo-space-align',\n  imports: [NzButtonModule, NzSpaceModule],\n  template: `\n    <div class=\"space-align-container\">\n      <div nz-space nzAlign=\"center\" class=\"space-align-block\">\n        <ng-container *nzSpaceItem>center</ng-container>\n        <button *nzSpaceItem nz-button nzType=\"primary\">Button</button>\n        <span *nzSpaceItem class=\"mock-block\">Block</span>\n      </div>\n\n      <div nz-space nzAlign=\"start\" class=\"space-align-block\">\n        <ng-container *nzSpaceItem>start</ng-container>\n        <button *nzSpaceItem nz-button nzType=\"primary\">Button</button>\n        <span *nzSpaceItem class=\"mock-block\">Block</span>\n      </div>\n\n      <div nz-space nzAlign=\"end\" class=\"space-align-block\">\n        <ng-container *nzSpaceItem>end</ng-container>\n        <button *nzSpaceItem nz-button nzType=\"primary\">Button</button>\n        <span *nzSpaceItem class=\"mock-block\">Block</span>\n      </div>\n\n      <div nz-space nzAlign=\"baseline\" class=\"space-align-block\">\n        <ng-container *nzSpaceItem>baseline</ng-container>\n        <button *nzSpaceItem nz-button nzType=\"primary\">Button</button>\n        <span *nzSpaceItem class=\"mock-block\">Block</span>\n      </div>\n    </div>\n  `,\n  styles: `\n    .space-align-container {\n      display: flex;\n      align-items: flex-start;\n      flex-wrap: wrap;\n    }\n    .space-align-block {\n      margin: 8px 4px;\n      border: 1px solid #40a9ff;\n      padding: 4px;\n      flex: none;\n    }\n    .space-align-block .mock-block {\n      display: inline-block;\n      padding: 32px 8px 16px;\n      background: rgba(150, 150, 150, 0.2);\n    }\n  `\n})\nexport class NzDemoSpaceAlignComponent {}\n"
  },
  {
    "path": "components/space/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本用法\n  en-US: Basic Usage\n---\n\n## zh-CN\n\n相邻组件水平间距。\n\n## en-US\n\nCrowded components horizontal spacing.\n"
  },
  {
    "path": "components/space/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\nimport { NzUploadModule } from 'ng-zorro-antd/upload';\n\n@Component({\n  selector: 'nz-demo-space-basic',\n  imports: [NzButtonModule, NzIconModule, NzSpaceModule, NzPopconfirmModule, NzUploadModule],\n  template: `\n    <nz-space>\n      <button *nzSpaceItem nz-button nzType=\"primary\">Button</button>\n      <nz-upload *nzSpaceItem nzAction=\"https://www.mocky.io/v2/5cc8019d300000980a055e76\">\n        <button nz-button>\n          <nz-icon nzType=\"upload\" />\n          Click to Upload\n        </button>\n      </nz-upload>\n      <button\n        *nzSpaceItem\n        nz-button\n        nz-popconfirm\n        nzOkText=\"Yes\"\n        nzCancelText=\"No\"\n        nzPopconfirmTitle=\"Are you sure delete this task?\"\n      >\n        Confirm\n      </button>\n    </nz-space>\n  `\n})\nexport class NzDemoSpaceBasicComponent {}\n"
  },
  {
    "path": "components/space/demo/compact-button-vertical.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 垂直方向紧凑布局\n  en-US: Vertical Compact Mode\n---\n\n## zh-CN\n\n垂直方向的紧凑布局，目前仅支持 Button 组合。\n\n## en-US\n\nVertical Mode for Space.Compact, support Button only.\n"
  },
  {
    "path": "components/space/demo/compact-button-vertical.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\n\n@Component({\n  selector: 'nz-demo-space-compact-button-vertical',\n  imports: [NzSpaceModule, NzButtonModule],\n  template: `\n    <nz-space>\n      <nz-space-compact *nzSpaceItem nzDirection=\"vertical\">\n        <button nz-button>Button 1</button>\n        <button nz-button>Button 2</button>\n        <button nz-button>Button 3</button>\n      </nz-space-compact>\n      <nz-space-compact *nzSpaceItem nzDirection=\"vertical\">\n        <button nz-button nzType=\"dashed\">Button 1</button>\n        <button nz-button nzType=\"dashed\">Button 2</button>\n        <button nz-button nzType=\"dashed\">Button 3</button>\n      </nz-space-compact>\n      <nz-space-compact *nzSpaceItem nzDirection=\"vertical\">\n        <button nz-button nzType=\"primary\">Button 1</button>\n        <button nz-button nzType=\"primary\">Button 2</button>\n        <button nz-button nzType=\"primary\">Button 3</button>\n      </nz-space-compact>\n    </nz-space>\n  `\n})\nexport class NzDemoSpaceCompactButtonVerticalComponent {}\n"
  },
  {
    "path": "components/space/demo/compact-buttons.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: Button 紧凑布局\n  en-US: Button Compact Mode\n---\n\n## zh-CN\n\nButton 组件紧凑排列的示例。\n\n## en-US\n\nButton component compact example.\n"
  },
  {
    "path": "components/space/demo/compact-buttons.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzDropdownModule } from 'ng-zorro-antd/dropdown';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\nimport { NzTooltipModule } from 'ng-zorro-antd/tooltip';\n\n@Component({\n  selector: 'nz-demo-space-compact-buttons',\n  imports: [NzSpaceModule, NzButtonModule, NzIconModule, NzDropdownModule, NzTooltipModule],\n  template: `\n    <nz-space-compact nzBlock>\n      <button nz-button nz-tooltip nzTooltipTitle=\"Like\">\n        <nz-icon nzType=\"like\" />\n      </button>\n      <button nz-button nz-tooltip nzTooltipTitle=\"Comment\">\n        <nz-icon nzType=\"comment\" />\n      </button>\n      <button nz-button nz-tooltip nzTooltipTitle=\"Star\">\n        <nz-icon nzType=\"star\" />\n      </button>\n      <button nz-button nz-tooltip nzTooltipTitle=\"Heart\">\n        <nz-icon nzType=\"heart\" />\n      </button>\n      <button nz-button nz-tooltip nzTooltipTitle=\"Share\">\n        <nz-icon nzType=\"share-alt\" />\n      </button>\n      <button nz-button nz-tooltip nzTooltipTitle=\"Download\">\n        <nz-icon nzType=\"download\" />\n      </button>\n      <nz-dropdown-menu #menu>\n        <ul nz-menu>\n          <li nz-menu-item>\n            <a>1st item</a>\n          </li>\n          <li nz-menu-item>\n            <a>2nd item</a>\n          </li>\n          <li nz-menu-item>\n            <a>3rd item</a>\n          </li>\n        </ul>\n      </nz-dropdown-menu>\n      <button nz-button nz-dropdown [nzDropdownMenu]=\"menu\">\n        <nz-icon nzType=\"ellipsis\" />\n      </button>\n    </nz-space-compact>\n    <br />\n    <nz-space-compact nzBlock>\n      <button nz-button nzType=\"primary\">Button 1</button>\n      <button nz-button nzType=\"primary\">Button 2</button>\n      <button nz-button nzType=\"primary\">Button 3</button>\n      <button nz-button nzType=\"primary\">Button 4</button>\n      <button nz-button nzType=\"primary\" disabled nz-tooltip nzTooltipTitle=\"Tooltip\">\n        <nz-icon nzType=\"download\" />\n      </button>\n      <button nz-button nzType=\"primary\" nz-tooltip nzTooltipTitle=\"Tooltip\">\n        <nz-icon nzType=\"download\" />\n      </button>\n    </nz-space-compact>\n    <br />\n    <nz-space-compact nzBlock>\n      <button nz-button>Button 1</button>\n      <button nz-button>Button 2</button>\n      <button nz-button>Button 3</button>\n      <button nz-button disabled nz-tooltip nzTooltipTitle=\"Tooltip\">\n        <nz-icon nzType=\"download\" />\n      </button>\n      <button nz-button nz-tooltip nzTooltipTitle=\"Tooltip\">\n        <nz-icon nzType=\"download\" />\n      </button>\n      <button nz-button nzType=\"primary\">Button 4</button>\n      <nz-dropdown-menu #menu>\n        <ul nz-menu>\n          <li nz-menu-item>\n            <a>1st item</a>\n          </li>\n          <li nz-menu-item>\n            <a>2nd item</a>\n          </li>\n          <li nz-menu-item>\n            <a>3rd item</a>\n          </li>\n        </ul>\n      </nz-dropdown-menu>\n      <button nz-button nzType=\"primary\" nz-dropdown [nzDropdownMenu]=\"menu\">\n        <nz-icon nzType=\"ellipsis\" />\n      </button>\n    </nz-space-compact>\n  `\n})\nexport class NzDemoSpaceCompactButtonsComponent {}\n"
  },
  {
    "path": "components/space/demo/compact.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 紧凑布局组合\n  en-US: Compact Mode\n---\n\n## zh-CN\n\n使用 `<nz-space-compact>` 让表单组件之间紧凑连接且合并边框。\n\n## en-US\n\nCompact Mode for form component.\n"
  },
  {
    "path": "components/space/demo/compact.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzAutocompleteModule } from 'ng-zorro-antd/auto-complete';\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzCascaderModule, NzCascaderOption } from 'ng-zorro-antd/cascader';\nimport { NzDatePickerModule } from 'ng-zorro-antd/date-picker';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzInputNumberModule } from 'ng-zorro-antd/input-number';\nimport { NzSelectModule } from 'ng-zorro-antd/select';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\nimport { NzTimePickerModule } from 'ng-zorro-antd/time-picker';\nimport { NzTooltipModule } from 'ng-zorro-antd/tooltip';\nimport { NzTreeSelectModule } from 'ng-zorro-antd/tree-select';\n\n@Component({\n  selector: 'nz-demo-space-compact',\n  imports: [\n    NzSpaceModule,\n    NzButtonModule,\n    NzIconModule,\n    NzInputModule,\n    NzInputNumberModule,\n    NzSelectModule,\n    NzCascaderModule,\n    NzTreeSelectModule,\n    NzDatePickerModule,\n    NzTimePickerModule,\n    NzAutocompleteModule,\n    NzTooltipModule,\n    FormsModule\n  ],\n  template: `\n    <nz-space-compact nzBlock>\n      <input nz-input value=\"0571\" [style.width.%]=\"20\" />\n      <input nz-input value=\"26888888\" [style.width.%]=\"30\" />\n    </nz-space-compact>\n    <br />\n    <nz-space-compact nzBlock nzSize=\"small\">\n      <input nz-input value=\"https://ng.ant.design\" [style.width]=\"'calc(100% - 200px)'\" />\n      <button nz-button nzType=\"primary\">Submit</button>\n    </nz-space-compact>\n    <br />\n    <nz-space-compact nzBlock>\n      <input nz-input value=\"https://ng.ant.design\" [style.width]=\"'calc(100% - 200px)'\" />\n      <button nz-button nzType=\"primary\">Submit</button>\n    </nz-space-compact>\n    <br />\n    <nz-space-compact nzBlock>\n      <input nz-input value=\"git@github.com:NG-ZORRO/ng-zorro-antd.git\" [style.width]=\"'calc(100% - 200px)'\" />\n      <button nz-button nz-tooltip nzTooltipTitle=\"copy git url\">\n        <nz-icon nzType=\"copy\" />\n      </button>\n    </nz-space-compact>\n    <br />\n    <nz-space-compact nzBlock>\n      <nz-select ngModel=\"Zhejianggggg\">\n        <nz-option nzLabel=\"Zhejianggggg\" nzValue=\"Zhejianggggg\" />\n        <nz-option nzLabel=\"Jiangsu\" nzValue=\"Jiangsu\" />\n      </nz-select>\n      <input nz-input value=\"Xihu District, Hangzhou\" [style.width.%]=\"50\" />\n    </nz-space-compact>\n    <br />\n    <nz-space-compact nzBlock>\n      <nz-input-search [style.width.%]=\"30\">\n        <input nz-input value=\"0571\" />\n      </nz-input-search>\n      <nz-input-search [style.width.%]=\"50\">\n        <input nz-input value=\"26888888\" />\n      </nz-input-search>\n      <nz-input-search [style.width.%]=\"20\">\n        <input nz-input value=\"+1\" />\n      </nz-input-search>\n    </nz-space-compact>\n    <br />\n    <nz-space-compact nzBlock>\n      <nz-select nzMode=\"multiple\" [ngModel]=\"['Zhejianggggg']\" [style.width.%]=\"50\">\n        <nz-option nzLabel=\"Zhejianggggg\" nzValue=\"Zhejianggggg\" />\n        <nz-option nzLabel=\"Jiangsu\" nzValue=\"Jiangsu\" />\n      </nz-select>\n      <input nz-input value=\"Xihu District, Hangzhou\" [style.width.%]=\"50\" />\n    </nz-space-compact>\n    <br />\n    <nz-space-compact nzBlock>\n      <nz-select ngModel=\"Option1\">\n        <nz-option nzLabel=\"Option1\" nzValue=\"Option1\" />\n        <nz-option nzLabel=\"Option2\" nzValue=\"Option2\" />\n      </nz-select>\n      <input nz-input value=\"input content\" [style.width.%]=\"50\" />\n      <nz-input-number [ngModel]=\"12\" />\n    </nz-space-compact>\n    <br />\n    <nz-space-compact nzBlock>\n      <input nz-input value=\"input content\" [style.width.%]=\"50\" />\n      <nz-date-picker [style.width.%]=\"50\" />\n    </nz-space-compact>\n    <br />\n    <nz-space-compact nzBlock>\n      <nz-range-picker [style.width.%]=\"70\" />\n      <input nz-input value=\"input content\" [style.width.%]=\"30\" />\n      <button nz-button nzType=\"primary\">查询</button>\n    </nz-space-compact>\n    <br />\n    <nz-space-compact nzBlock>\n      <input nz-input value=\"input content\" [style.width.%]=\"30\" />\n      <nz-range-picker [style.width.%]=\"70\" />\n    </nz-space-compact>\n    <br />\n    <nz-space-compact nzBlock>\n      <nz-select ngModel=\"Option1-1\">\n        <nz-option nzLabel=\"Option1-1\" nzValue=\"Option1-1\" />\n        <nz-option nzLabel=\"Option2-1\" nzValue=\"Option2-1\" />\n      </nz-select>\n      <nz-select ngModel=\"Option1-2\">\n        <nz-option nzLabel=\"Option1-2\" nzValue=\"Option1-2\" />\n        <nz-option nzLabel=\"Option2-2\" nzValue=\"Option2-2\" />\n      </nz-select>\n    </nz-space-compact>\n    <br />\n    <nz-space-compact nzBlock>\n      <nz-select ngModel=\"1\">\n        <nz-option nzLabel=\"Between\" nzValue=\"1\" />\n        <nz-option nzLabel=\"Except\" nzValue=\"2\" />\n      </nz-select>\n      <input nz-input placeholder=\"Minimum\" style=\"width: 100px; text-align: center\" />\n      <input\n        nz-input\n        class=\"site-input-split\"\n        style=\"\n          width: 30px;\n          border-left: 0;\n          border-right: 0;\n          pointer-events: none\n        \"\n        placeholder=\"~\"\n        disabled\n      />\n      <input nz-input class=\"site-input-right\" style=\"width: 100px; text-align: center\" placeholder=\"Maximum\" />\n    </nz-space-compact>\n    <br />\n    <nz-space-compact nzBlock>\n      <nz-select ngModel=\"Sign Up\" [style.width.%]=\"30\">\n        <nz-option nzLabel=\"Sign Up\" nzValue=\"Sign Up\" />\n        <nz-option nzLabel=\"Sign In\" nzValue=\"Sign In\" />\n      </nz-select>\n      <nz-autocomplete #auto [nzDataSource]=\"['text 1', 'text 2']\" />\n      <input nz-input placeholder=\"Email\" [nzAutocomplete]=\"auto\" [style.width.%]=\"70\" />\n    </nz-space-compact>\n    <br />\n    <nz-space-compact nzBlock>\n      <nz-time-picker [style.width.%]=\"70\" />\n      <nz-cascader [nzOptions]=\"cascaderOptions\" nzPlaceholder=\"Select Address\" [style.width.%]=\"70\" />\n    </nz-space-compact>\n    <br />\n    <nz-space-compact nzBlock>\n      <nz-tree-select\n        [nzNodes]=\"nodes\"\n        nzShowSearch\n        nzPlaceHolder=\"Please select\"\n        ngModel=\"10010\"\n        nzDefaultExpandAll\n        [style.width.%]=\"60\"\n      />\n      <button nz-button nzType=\"primary\">Submit</button>\n    </nz-space-compact>\n    <br />\n    <nz-space-compact nzBlock>\n      <nz-input-wrapper nzAddOnBefore=\"Http://\" nzAddOnAfter=\".com\" [style.width.%]=\"50\">\n        <input nz-input placeholder=\"input here\" />\n      </nz-input-wrapper>\n      <nz-input-number>\n        <span nzInputPrefix>$</span>\n      </nz-input-number>\n      <nz-input-number>\n        <span nzInputAddonBefore>$</span>\n      </nz-input-number>\n    </nz-space-compact>\n  `,\n  styles: `\n    .site-input-split {\n      background-color: #fff;\n    }\n\n    .site-input-right:not(.ant-input-rtl) {\n      border-left-width: 0;\n    }\n\n    .site-input-right:not(.ant-input-rtl):hover,\n    .site-input-right:not(.ant-input-rtl):focus {\n      border-left-width: 1px;\n    }\n\n    .site-input-right.ant-input-rtl {\n      border-right-width: 0;\n    }\n\n    .site-input-right.ant-input-rtl:hover,\n    .site-input-right.ant-input-rtl:focus {\n      border-right-width: 1px;\n    }\n  `\n})\nexport class NzDemoSpaceCompactComponent {\n  cascaderOptions: NzCascaderOption[] = [\n    {\n      value: 'zhejiang',\n      label: 'Zhejiang',\n      children: [\n        {\n          value: 'hangzhou',\n          label: 'Hangzhou',\n          children: [\n            {\n              value: 'xihu',\n              label: 'West Lake',\n              isLeaf: true\n            }\n          ]\n        }\n      ]\n    },\n    {\n      value: 'jiangsu',\n      label: 'Jiangsu',\n      children: [\n        {\n          value: 'nanjing',\n          label: 'Nanjing',\n          children: [\n            {\n              value: 'zhonghuamen',\n              label: 'Zhong Hua Men',\n              isLeaf: true\n            }\n          ]\n        }\n      ]\n    }\n  ];\n\n  nodes = [\n    {\n      title: 'parent 1',\n      key: '100',\n      children: [\n        {\n          title: 'parent 1-0',\n          key: '1001',\n          children: [\n            { title: 'leaf 1-0-0', key: '10010', isLeaf: true },\n            { title: 'leaf 1-0-1', key: '10011', isLeaf: true }\n          ]\n        },\n        {\n          title: 'parent 1-1',\n          key: '1002',\n          children: [{ title: 'leaf 1-1-0', key: '10020', isLeaf: true }]\n        }\n      ]\n    }\n  ];\n}\n"
  },
  {
    "path": "components/space/demo/customize.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 自定义尺寸\n  en-US: Customize Size\n---\n\n## zh-CN\n\n自定义间距大小。\n\n## en-US\n\nCustom spacing size.\n"
  },
  {
    "path": "components/space/demo/customize.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzSliderModule } from 'ng-zorro-antd/slider';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\n\n@Component({\n  selector: 'nz-demo-space-customize',\n  imports: [FormsModule, NzButtonModule, NzSpaceModule, NzSliderModule],\n  template: `\n    <nz-slider [(ngModel)]=\"size\" />\n    <nz-space [nzSize]=\"size\">\n      <button *nzSpaceItem nz-button nzType=\"primary\">Button</button>\n      <button *nzSpaceItem nz-button nzType=\"default\">Default</button>\n      <button *nzSpaceItem nz-button nzType=\"dashed\">Dashed</button>\n      <a *nzSpaceItem nz-button nzType=\"link\">Link</a>\n    </nz-space>\n  `\n})\nexport class NzDemoSpaceCustomizeComponent {\n  size = 8;\n}\n"
  },
  {
    "path": "components/space/demo/size.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 间距大小\n  en-US: Space Size\n---\n\n## zh-CN\n\n间距预设大、中、小三种大小。\n\n通过设置 `nzSize` 为 `large` `middle` 分别把间距设为大、中间距。若不设置 `nzSize`，则间距为小。\n\n## en-US\n\n`large`, `middle` and `small` preset sizes.\n\nSet the `nzSize` to `large` and `middle` by setting size to large and middle respectively. If `size` is not set, the spacing is `small`.\n"
  },
  {
    "path": "components/space/demo/size.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\nimport { NzSpaceModule, NzSpaceSize } from 'ng-zorro-antd/space';\n\n@Component({\n  selector: 'nz-demo-space-size',\n  imports: [FormsModule, NzButtonModule, NzRadioModule, NzSpaceModule],\n  template: `\n    <nz-radio-group [(ngModel)]=\"size\">\n      <label nz-radio nzValue=\"small\">Small</label>\n      <label nz-radio nzValue=\"middle\">Middle</label>\n      <label nz-radio nzValue=\"large\">Large</label>\n    </nz-radio-group>\n    <nz-space [nzSize]=\"size\">\n      <button *nzSpaceItem nz-button nzType=\"primary\">Button</button>\n      <button *nzSpaceItem nz-button nzType=\"default\">Default</button>\n      <button *nzSpaceItem nz-button nzType=\"dashed\">Dashed</button>\n      <a *nzSpaceItem nz-button nzType=\"link\">Link</a>\n    </nz-space>\n  `\n})\nexport class NzDemoSpaceSizeComponent {\n  size: NzSpaceSize = 'small';\n}\n"
  },
  {
    "path": "components/space/demo/split.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 分隔符\n  en-US: Split\n---\n\n## zh-CN\n\n相邻组件分隔符。\n\n## en-US\n\nCrowded components split.\n"
  },
  {
    "path": "components/space/demo/split.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\n\n@Component({\n  selector: 'nz-demo-space-split',\n  imports: [NzDividerModule, NzSpaceModule],\n  template: `\n    <nz-space [nzSplit]=\"spaceSplit\">\n      <ng-template #spaceSplit>\n        <nz-divider nzType=\"vertical\" />\n      </ng-template>\n\n      <a *nzSpaceItem>Link</a>\n      <a *nzSpaceItem>Link</a>\n      <a *nzSpaceItem>Link</a>\n    </nz-space>\n  `\n})\nexport class NzDemoSpaceSplitComponent {\n  size = 8;\n}\n"
  },
  {
    "path": "components/space/demo/vertical.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 垂直间距\n  en-US: Vertical Space\n---\n\n## zh-CN\n\n相邻组件垂直间距。\n\n可以设置 `width: 100%` 独占一行。\n\n## en-US\n\nCrowded components vertical spacing.\n"
  },
  {
    "path": "components/space/demo/vertical.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzCardModule } from 'ng-zorro-antd/card';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\n\n@Component({\n  selector: 'nz-demo-space-vertical',\n  imports: [NzCardModule, NzSpaceModule],\n  template: `\n    <nz-space nzDirection=\"vertical\">\n      <nz-card *nzSpaceItem nzTitle=\"Card\" style=\"width: 300px\">\n        <p>Card content</p>\n        <p>Card content</p>\n      </nz-card>\n      <nz-card *nzSpaceItem nzTitle=\"Card\" style=\"width: 300px\">\n        <p>Card content</p>\n        <p>Card content</p>\n      </nz-card>\n    </nz-space>\n  `\n})\nexport class NzDemoSpaceVerticalComponent {}\n"
  },
  {
    "path": "components/space/demo/wrap.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 换行\n  en-US: Wrap\n---\n\n## zh-CN\n\n自动换行。\n\n## en-US\n\nAuto wrap line.\n"
  },
  {
    "path": "components/space/demo/wrap.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\n\n@Component({\n  selector: 'nz-demo-space-wrap',\n  imports: [NzButtonModule, NzSpaceModule],\n  template: `\n    <nz-space [nzSize]=\"[8, 16]\" nzWrap>\n      @for (item of items; track $index) {\n        <button *nzSpaceItem nz-button>Button</button>\n      }\n    </nz-space>\n  `\n})\nexport class NzDemoSpaceWrapComponent {\n  items = new Array(20).fill(null);\n}\n"
  },
  {
    "path": "components/space/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Layout\ncols: 1\ntitle: Space\ncover: 'https://gw.alipayobjects.com/zos/antfincdn/wc6%263gJ0Y8/Space.svg'\ndescription: Set components spacing.\n---\n\n## When To Use\n\n- Avoid components clinging together and set a unified space.\n- Use `<nz-space-compact>` when child form components are compactly connected and the border is collapsed.\n\nThe difference with Flex component is:\n\n- Space is used to set the spacing between inline elements. It will add a wrapper element for each child element for inline alignment. Suitable for equidistant arrangement of multiple child elements in rows and columns.\n- Flex is used to set the layout of block-level elements. It does not add a wrapper element. Suitable for layout of child elements in vertical or horizontal direction, and provides more flexibility and control.\n\n## API\n\n### nz-space\n\n| Property        | Description                                 | Type                                         | Default        | Global Config |\n| --------------- | ------------------------------------------- | -------------------------------------------- | -------------- | ------------- |\n| `[nzSize]`      | The space size                              | `NzSpaceSize \\| NzSpaceSize[]`               | `'small'`      | ✅            |\n| `[nzDirection]` | The space direction                         | `'vertical' \\| 'horizontal'`                 | `'horizontal'` |               |\n| `[nzAlign]`     | Align items                                 | `'start' \\| 'end' \\| 'baseline' \\| 'center'` | -              |               |\n| `[nzWrap]`      | Auto wrap line, when `horizontal` effective | `boolean`                                    | `false`        |               |\n| `[nzSplit]`     | Set split                                   | `TemplateRef \\| string`                      | -              |               |\n\n#### Interfaces\n\n```ts\ntype NzSpaceSize = 'small' | 'middle' | 'large' | number;\n```\n\n### nz-space-compact\n\nUse `<nz-space-compact>` when child form components are compactly connected and the border is collapsed. The supported components are：\n\n- Button\n- Cascader\n- DatePicker\n- Input\n- Select\n- TimePicker\n- TreeSelect\n\n| Property        | Description                                | Type                              | Default        | Global Config |\n| --------------- | ------------------------------------------ | --------------------------------- | -------------- | ------------- |\n| `[nzBlock]`     | Option to fit width to its parent\\'s width | `boolean`                         | `false`        |               |\n| `[nzDirection]` | Set direction of layout                    | `'vertical' \\| 'horizontal'`      | `'horizontal'` |               |\n| `[nzSize]`      | Set child component size                   | `'large' \\| 'small' \\| 'default'` | `'default'`    |               |\n"
  },
  {
    "path": "components/space/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ntype: 布局\nsubtitle: 间距\ntitle: Space\ncols: 1\ncover: 'https://gw.alipayobjects.com/zos/antfincdn/wc6%263gJ0Y8/Space.svg'\ndescription: 设置组件之间的间距。\n---\n\n## 何时使用\n\n避免组件紧贴在一起，拉开统一的空间。\n\n- 适合行内元素的水平间距。\n- 可以设置各种水平对齐方式。\n- 需要表单组件之间紧凑连接且合并边框时，使用 `<nz-space-compact>`。\n\n与 Flex 组件的区别：\n\n- Space 为内联元素提供间距，其本身会为每一个子元素添加包裹元素用于内联对齐。适用于行、列中多个子元素的等距排列。\n- Flex 为块级元素提供间距，其本身不会添加包裹元素。适用于垂直或水平方向上的子元素布局，并提供了更多的灵活性和控制能力。\n\n## API\n\n### nz-space\n\n| 参数            | 说明                                   | 类型                                         | 默认值         | 支持全局配置 |\n| --------------- | -------------------------------------- | -------------------------------------------- | -------------- | ------------ |\n| `[nzSize]`      | 间距大小                               | `NzSpaceSize \\| NzSpaceSize[]`               | `'small'`      | ✅           |\n| `[nzDirection]` | 间距方向                               | `'vertical' \\| 'horizontal'`                 | `'horizontal'` |              |\n| `[nzAlign]`     | 对齐方式                               | `'start' \\| 'end' \\| 'baseline' \\| 'center'` | -              |              |\n| `[nzWrap]`      | 是否自动换行，仅在 `horizontal` 时有效 | `boolean`                                    | `false`        |              |\n| `[nzSplit]`     | 设置分隔符                             | `TemplateRef \\| string`                      | -              |              |\n\n#### Interfaces\n\n```ts\ntype NzSpaceSize = 'small' | 'middle' | 'large' | number;\n```\n\n### nz-space-compact\n\n需要表单组件之间紧凑连接且合并边框时，使用 `<nz-space-compact>`。支持的组件有：\n\n- Button\n- Cascader\n- DatePicker\n- Input\n- Select\n- TimePicker\n- TreeSelect\n\n| 参数            | 说明                         | 类型                              | 默认值         | 支持全局配置 |\n| --------------- | ---------------------------- | --------------------------------- | -------------- | ------------ |\n| `[nzBlock]`     | 将宽度调整为父元素宽度的选项 | `boolean`                         | `false`        |              |\n| `[nzDirection]` | 指定排列方向                 | `'vertical' \\| 'horizontal'`      | `'horizontal'` |              |\n| `[nzSize]`      | 子组件大小                   | `'large' \\| 'small' \\| 'default'` | `'default'`    |              |\n"
  },
  {
    "path": "components/space/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/space/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/space/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './space-compact-item.directive';\nexport * from './space-compact.component';\nexport * from './space-compact.token';\nexport * from './space-item.directive';\nexport * from './space.component';\nexport * from './space.module';\nexport * from './types';\n"
  },
  {
    "path": "components/space/space-compact-item.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { afterNextRender, computed, DestroyRef, Directive, ElementRef, inject } from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\n\nimport { NzSpaceCompactComponent } from './space-compact.component';\nimport { NZ_SPACE_COMPACT_ITEM_TYPE, NZ_SPACE_COMPACT_ITEMS } from './space-compact.token';\n\n@Directive({\n  exportAs: 'nzSpaceCompactItem',\n  host: {\n    '[class]': 'class()'\n  }\n})\nexport class NzSpaceCompactItemDirective {\n  /**\n   * Ancestor component injected from the parent.\n   * Note that it is not necessarily the direct parent component.\n   */\n  private readonly spaceCompactCmp = inject(NzSpaceCompactComponent, { host: true, optional: true });\n  private readonly items = inject(NZ_SPACE_COMPACT_ITEMS, { host: true, optional: true });\n  private readonly type = inject(NZ_SPACE_COMPACT_ITEM_TYPE);\n  private readonly elementRef: ElementRef<HTMLElement> = inject(ElementRef);\n  private readonly directionality = inject(Directionality);\n  private readonly dir = toSignal(this.directionality.change, { initialValue: this.directionality.value });\n\n  private get parentElement(): HTMLElement | null {\n    return this.elementRef.nativeElement?.parentElement;\n  }\n\n  protected class = computed(() => {\n    // Only handle when the parent is space compact component\n    if (!this.spaceCompactCmp || !this.items) return null;\n    // Ensure that the injected ancestor component's elements are parent elements\n    if (this.parentElement !== this.spaceCompactCmp!.elementRef.nativeElement) return null;\n\n    const items = this.items();\n    const direction = this.spaceCompactCmp.nzDirection();\n    const classes = [compactItemClassOf(this.type, direction, this.dir() === 'rtl')];\n    const index = items.indexOf(this);\n    const firstIndex = items.findIndex(element => element);\n    // Array [empty, item]\n    // In this case, the index of the first valid element is not 0,\n    // so we need to use findIndex to find the index value of the first valid element.\n    if (index === firstIndex) {\n      classes.push(compactFirstItemClassOf(this.type, direction));\n    }\n    if (index === items.length - 1) {\n      classes.push(compactLastItemClassOf(this.type, direction));\n    }\n\n    return classes;\n  });\n\n  constructor() {\n    if (!this.spaceCompactCmp || !this.items) return;\n\n    afterNextRender(() => {\n      // Ensure that the injected ancestor component's elements are parent elements\n      if (this.parentElement === this.spaceCompactCmp!.elementRef.nativeElement) {\n        const index = Array.from(this.parentElement.children).indexOf(this.elementRef.nativeElement);\n        this.items!.update(value => {\n          const newValue = value.slice();\n          newValue.splice(index, 0, this);\n          return newValue;\n        });\n      }\n    });\n\n    inject(DestroyRef).onDestroy(() => {\n      this.items?.update(value => value.filter(o => o !== this));\n    });\n  }\n}\n\nfunction generateCompactClass(\n  type: string,\n  direction: 'vertical' | 'horizontal',\n  position: 'item' | 'first-item' | 'last-item'\n): string {\n  const directionPrefix = direction === 'vertical' ? 'vertical-' : '';\n  return `ant-${type}-compact-${directionPrefix}${position}`;\n}\n\nfunction compactItemClassOf(type: string, direction: 'vertical' | 'horizontal', rtl?: boolean): string {\n  const rtlSuffix = rtl ? '-rtl' : '';\n  return `${generateCompactClass(type, direction, 'item')}${rtlSuffix}`;\n}\n\nfunction compactFirstItemClassOf(type: string, direction: 'vertical' | 'horizontal'): string {\n  return generateCompactClass(type, direction, 'first-item');\n}\n\nfunction compactLastItemClassOf(type: string, direction: 'vertical' | 'horizontal'): string {\n  return generateCompactClass(type, direction, 'last-item');\n}\n"
  },
  {
    "path": "components/space/space-compact.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ApplicationRef, Component, provideZoneChangeDetection, signal, type WritableSignal } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzCascaderModule } from 'ng-zorro-antd/cascader';\nimport { provideNzNoAnimation } from 'ng-zorro-antd/core/animation';\nimport { NZ_FORM_SIZE } from 'ng-zorro-antd/core/form';\nimport { NzSizeLDSType } from 'ng-zorro-antd/core/types';\nimport { NzDatePickerModule } from 'ng-zorro-antd/date-picker';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzInputNumberModule } from 'ng-zorro-antd/input-number';\nimport { NzSelectModule } from 'ng-zorro-antd/select';\nimport { NzTimePickerModule } from 'ng-zorro-antd/time-picker';\nimport { NzTreeSelectModule } from 'ng-zorro-antd/tree-select';\n\nimport { NzSpaceCompactComponent } from './space-compact.component';\nimport { NzSpaceModule } from './space.module';\nimport { NzSpaceDirection } from './types';\n\ndescribe('space compact', () => {\n  let component: SpaceCompactTestComponent;\n  let fixture: ComponentFixture<SpaceCompactTestComponent>;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), provideZoneChangeDetection()]\n    });\n    fixture = TestBed.createComponent(SpaceCompactTestComponent);\n    component = fixture.componentInstance;\n    fixture.autoDetectChanges();\n  });\n\n  it('should render all child components', () => {\n    const spaceCompactElement: HTMLElement = fixture.nativeElement;\n    const nzInput = spaceCompactElement.querySelector('input[nz-input]');\n    const nzInputWrapper = spaceCompactElement.querySelector('nz-input-wrapper');\n    const nzInputGroup = spaceCompactElement.querySelector('nz-input-group');\n    const nzInputNumber = spaceCompactElement.querySelector('nz-input-number');\n    const nzDatePicker = spaceCompactElement.querySelector('nz-date-picker');\n    const nzRangePicker = spaceCompactElement.querySelector('nz-range-picker');\n    const nzTimePicker = spaceCompactElement.querySelector('nz-time-picker');\n    const nzCascader = spaceCompactElement.querySelector('nz-cascader');\n    const nzSelect = spaceCompactElement.querySelector('nz-select');\n    const nzTreeSelect = spaceCompactElement.querySelector('nz-tree-select');\n    const nzButton = spaceCompactElement.querySelector('button[nz-button]');\n\n    expect(nzInput).toBeTruthy();\n    expect(nzInputNumber).toBeTruthy();\n    expect(nzInputWrapper).toBeTruthy();\n    expect(nzInputGroup).toBeTruthy();\n    expect(nzDatePicker).toBeTruthy();\n    expect(nzRangePicker).toBeTruthy();\n    expect(nzTimePicker).toBeTruthy();\n    expect(nzCascader).toBeTruthy();\n    expect(nzSelect).toBeTruthy();\n    expect(nzTreeSelect).toBeTruthy();\n    expect(nzButton).toBeTruthy();\n\n    expect(nzInput!.classList).toContain('ant-input-compact-item');\n    expect(nzInputWrapper!.classList).toContain('ant-input-compact-item');\n    expect(nzInputWrapper!.querySelector('input.ant-input-compact-item')).toBeFalsy();\n    expect(nzInputGroup!.classList).toContain('ant-input-compact-item');\n\n    expect(nzInputNumber!.classList).toContain('ant-input-number-compact-item');\n\n    expect(nzDatePicker!.classList).toContain('ant-picker-compact-item');\n    expect(nzRangePicker!.classList).toContain('ant-picker-compact-item');\n    expect(nzTimePicker!.classList).toContain('ant-picker-compact-item');\n\n    expect(nzCascader!.classList).toContain('ant-select-compact-item');\n    expect(nzSelect!.classList).toContain('ant-select-compact-item');\n    expect(nzTreeSelect!.classList).toContain('ant-select-compact-item');\n\n    expect(nzButton!.classList).toContain('ant-btn-compact-item');\n  });\n\n  it('should be possible to switch compact first / last classes', async () => {\n    const spaceCompactElement: HTMLElement = fixture.nativeElement;\n    const nzInput = spaceCompactElement.querySelector('input[nz-input]');\n    const nzInputWrapper = spaceCompactElement.querySelector('nz-input-wrapper');\n    const nzTreeSelect = spaceCompactElement.querySelector('nz-tree-select');\n    const nzButton = spaceCompactElement.querySelector('button[nz-button]');\n\n    await Promise.resolve();\n\n    expect(nzInput!.classList).toContain('ant-input-compact-first-item');\n    expect(nzButton!.classList).toContain('ant-btn-compact-last-item');\n    expect(nzInputWrapper!.classList).not.toContain('ant-input-compact-first-item');\n    expect(nzTreeSelect!.classList).not.toContain('ant-select-compact-last-item');\n\n    component.showFirst = false;\n    component.showLast = false;\n    fixture.detectChanges();\n\n    await Promise.resolve();\n\n    expect(nzInputWrapper!.classList).toContain('ant-input-compact-first-item');\n    expect(nzTreeSelect!.classList).toContain('ant-select-compact-last-item');\n  });\n\n  it('should be apply size class', () => {\n    const spaceCompactElement: HTMLElement = fixture.nativeElement;\n    const nzInput = spaceCompactElement.querySelector('input[nz-input]');\n    const nzInputWrapper = spaceCompactElement.querySelector('nz-input-wrapper');\n    const nzInputNumber = spaceCompactElement.querySelector('nz-input-number');\n    const nzDatePicker = spaceCompactElement.querySelector('nz-date-picker');\n    const nzRangePicker = spaceCompactElement.querySelector('nz-range-picker');\n    const nzTimePicker = spaceCompactElement.querySelector('nz-time-picker');\n    const nzCascader = spaceCompactElement.querySelector('nz-cascader');\n    const nzSelect = spaceCompactElement.querySelector('nz-select');\n    const nzTreeSelect = spaceCompactElement.querySelector('nz-tree-select');\n    const nzButton = spaceCompactElement.querySelector('button[nz-button]');\n\n    component.size = 'small';\n    fixture.detectChanges();\n\n    expect(nzInput!.classList).toContain('ant-input-sm');\n    expect(nzInputWrapper!.classList).toContain('ant-input-group-wrapper-sm');\n    expect(nzInputWrapper!.querySelector('.ant-input-affix-wrapper-sm')).toBeTruthy();\n    expect(nzInputWrapper!.querySelector('input.ant-input-sm')).toBeTruthy();\n    expect(nzInputNumber!.classList).toContain('ant-input-number-sm');\n    expect(nzDatePicker!.classList).toContain('ant-picker-small');\n    expect(nzRangePicker!.classList).toContain('ant-picker-small');\n    expect(nzTimePicker!.classList).toContain('ant-picker-small');\n    expect(nzCascader!.classList).toContain('ant-select-sm');\n    expect(nzSelect!.classList).toContain('ant-select-sm');\n    expect(nzTreeSelect!.classList).toContain('ant-select-sm');\n    expect(nzButton!.classList).toContain('ant-btn-sm');\n\n    component.size = 'large';\n    fixture.detectChanges();\n\n    expect(nzInput!.classList).toContain('ant-input-lg');\n    expect(nzInputWrapper!.classList).toContain('ant-input-group-wrapper-lg');\n    expect(nzInputWrapper!.querySelector('.ant-input-affix-wrapper-lg')).toBeTruthy();\n    expect(nzInputWrapper!.querySelector('input.ant-input-lg')).toBeTruthy();\n    expect(nzInputNumber!.classList).toContain('ant-input-number-lg');\n    expect(nzDatePicker!.classList).toContain('ant-picker-large');\n    expect(nzRangePicker!.classList).toContain('ant-picker-large');\n    expect(nzTimePicker!.classList).toContain('ant-picker-large');\n    expect(nzCascader!.classList).toContain('ant-select-lg');\n    expect(nzSelect!.classList).toContain('ant-select-lg');\n    expect(nzTreeSelect!.classList).toContain('ant-select-lg');\n    expect(nzButton!.classList).toContain('ant-btn-lg');\n  });\n\n  it('should apply block class when nzBlock is true', () => {\n    const spaceCompactElement = fixture.nativeElement;\n    expect(spaceCompactElement.querySelector('.ant-space-compact').classList).not.toContain('ant-space-compact-block');\n\n    component.block = true;\n    fixture.detectChanges();\n\n    expect(spaceCompactElement.querySelector('.ant-space-compact').classList).toContain('ant-space-compact-block');\n  });\n});\n\ndescribe('space compact direction', () => {\n  let component: SpaceCompactDirectionTestComponent;\n  let fixture: ComponentFixture<SpaceCompactDirectionTestComponent>;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), provideZoneChangeDetection()]\n    });\n    fixture = TestBed.createComponent(SpaceCompactDirectionTestComponent);\n    component = fixture.componentInstance;\n    fixture.detectChanges();\n  });\n\n  it('should be apply direction classes', () => {\n    const spaceCompactElement = fixture.nativeElement;\n    expect(spaceCompactElement.querySelector('.ant-space-compact').classList).not.toContain(\n      'ant-space-compact-vertical'\n    );\n\n    component.direction = 'vertical';\n    fixture.detectChanges();\n\n    expect(spaceCompactElement.querySelector('.ant-space-compact').classList).toContain('ant-space-compact-vertical');\n  });\n\n  it('should be apply direction classes for child components', () => {\n    // Running change detection (first time)\n    TestBed.inject(ApplicationRef).tick();\n    // detect signal changes\n    fixture.detectChanges();\n\n    const spaceCompactElement: HTMLElement = fixture.nativeElement;\n    const nzButtons = spaceCompactElement.querySelectorAll('button[nz-button]');\n    const [firstBtn, lastBtn] = Array.from(nzButtons);\n\n    expect(firstBtn.classList).toContain('ant-btn-compact-item');\n    expect(firstBtn.classList).toContain('ant-btn-compact-first-item');\n    expect(lastBtn.classList).toContain('ant-btn-compact-item');\n    expect(lastBtn.classList).toContain('ant-btn-compact-last-item');\n\n    expect(firstBtn.classList).not.toContain('ant-btn-compact-vertical-item');\n    expect(firstBtn.classList).not.toContain('ant-btn-compact-vertical-first-item');\n    expect(lastBtn.classList).not.toContain('ant-btn-compact-vertical-item');\n    expect(lastBtn.classList).not.toContain('ant-btn-compact-vertical-last-item');\n\n    component.direction = 'vertical';\n    fixture.detectChanges();\n\n    expect(firstBtn.classList).not.toContain('ant-btn-compact-item');\n    expect(firstBtn.classList).not.toContain('ant-btn-compact-first-item');\n    expect(lastBtn.classList).not.toContain('ant-btn-compact-item');\n    expect(lastBtn.classList).not.toContain('ant-btn-compact-last-item');\n\n    expect(firstBtn.classList).toContain('ant-btn-compact-vertical-item');\n    expect(firstBtn.classList).toContain('ant-btn-compact-vertical-first-item');\n    expect(lastBtn.classList).toContain('ant-btn-compact-vertical-item');\n    expect(lastBtn.classList).toContain('ant-btn-compact-vertical-last-item');\n  });\n});\n\n@Component({\n  imports: [\n    NzSpaceModule,\n    NzButtonModule,\n    NzInputModule,\n    NzInputNumberModule,\n    NzSelectModule,\n    NzCascaderModule,\n    NzTreeSelectModule,\n    NzDatePickerModule,\n    NzTimePickerModule\n  ],\n  template: `\n    <nz-space-compact [nzSize]=\"size\" [nzBlock]=\"block\">\n      @if (showFirst) {\n        <input nz-input />\n      }\n      <nz-input-wrapper>\n        <span nzInputAddonBefore>Before</span>\n        <span nzInputPrefix>Prefix</span>\n        <input nz-input />\n      </nz-input-wrapper>\n      <nz-input-group><input nz-input /></nz-input-group>\n      <nz-input-number />\n      <nz-date-picker />\n      <nz-range-picker />\n      <nz-time-picker />\n      <nz-cascader [nzOptions]=\"[]\" />\n      <nz-select />\n      <nz-tree-select [nzNodes]=\"[]\" />\n      @if (showLast) {\n        <button nz-button nzType=\"primary\">btn</button>\n      }\n    </nz-space-compact>\n  `\n})\nclass SpaceCompactTestComponent {\n  block: boolean = false;\n  size: NzSizeLDSType = 'default';\n  showFirst = true;\n  showLast = true;\n}\n\n@Component({\n  imports: [NzSpaceModule, NzButtonModule],\n  template: `\n    <nz-space-compact [nzDirection]=\"direction\">\n      <button nz-button nzType=\"primary\">btn</button>\n      <button nz-button nzType=\"primary\">btn</button>\n    </nz-space-compact>\n  `\n})\nclass SpaceCompactDirectionTestComponent {\n  direction: NzSpaceDirection = 'horizontal';\n}\n\ndescribe('finalSize', () => {\n  let fixture: ComponentFixture<SpaceCompactTestComponent>;\n  let spaceCompactElement: HTMLElement;\n  let formSizeSignal: WritableSignal<NzSizeLDSType>;\n\n  beforeEach(() => {\n    formSizeSignal = signal<NzSizeLDSType>('default');\n  });\n\n  afterEach(() => {\n    TestBed.resetTestingModule();\n  });\n\n  it('should set correctly the size from the formSize signal', () => {\n    TestBed.configureTestingModule({\n      providers: [\n        provideNzNoAnimation(),\n        provideZoneChangeDetection(),\n        { provide: NZ_FORM_SIZE, useValue: formSizeSignal }\n      ]\n    });\n    fixture = TestBed.createComponent(SpaceCompactTestComponent);\n    spaceCompactElement = fixture.debugElement.query(By.directive(NzSpaceCompactComponent)).nativeElement;\n    fixture.detectChanges();\n\n    formSizeSignal.set('small');\n    fixture.detectChanges();\n\n    const nzInput = spaceCompactElement.querySelector('input[nz-input]');\n    const nzButton = spaceCompactElement.querySelector('button[nz-button]');\n\n    expect(nzInput!.classList).toContain('ant-input-sm');\n    expect(nzButton!.classList).toContain('ant-btn-sm');\n  });\n\n  it('should set correctly the size from the component input', () => {\n    TestBed.configureTestingModule({\n      providers: [provideNzNoAnimation(), provideZoneChangeDetection()]\n    });\n    fixture = TestBed.createComponent(SpaceCompactTestComponent);\n    spaceCompactElement = fixture.debugElement.query(By.directive(NzSpaceCompactComponent)).nativeElement;\n    fixture.componentInstance.size = 'large';\n    fixture.detectChanges();\n\n    const nzInput = spaceCompactElement.querySelector('input[nz-input]');\n    const nzButton = spaceCompactElement.querySelector('button[nz-button]');\n\n    expect(nzInput!.classList).toContain('ant-input-lg');\n    expect(nzButton!.classList).toContain('ant-btn-lg');\n  });\n\n  it('should prioritize formSize over component input size', () => {\n    TestBed.configureTestingModule({\n      providers: [\n        provideNzNoAnimation(),\n        provideZoneChangeDetection(),\n        { provide: NZ_FORM_SIZE, useValue: formSizeSignal }\n      ]\n    });\n    fixture = TestBed.createComponent(SpaceCompactTestComponent);\n    spaceCompactElement = fixture.debugElement.query(By.directive(NzSpaceCompactComponent)).nativeElement;\n    fixture.componentInstance.size = 'large';\n    fixture.detectChanges();\n\n    formSizeSignal.set('small');\n    fixture.detectChanges();\n\n    const nzInput = spaceCompactElement.querySelector('input[nz-input]');\n    const nzButton = spaceCompactElement.querySelector('button[nz-button]');\n\n    expect(nzInput!.classList).toContain('ant-input-sm');\n    expect(nzInput!.classList).not.toContain('ant-input-lg');\n    expect(nzButton!.classList).toContain('ant-btn-sm');\n    expect(nzButton!.classList).not.toContain('ant-btn-lg');\n  });\n});\n"
  },
  {
    "path": "components/space/space-compact.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  Component,\n  computed,\n  ElementRef,\n  inject,\n  input,\n  signal\n} from '@angular/core';\n\nimport { NZ_FORM_SIZE } from 'ng-zorro-antd/core/form';\nimport { NzSizeLDSType } from 'ng-zorro-antd/core/types';\n\nimport { NZ_SPACE_COMPACT_ITEMS, NZ_SPACE_COMPACT_SIZE } from './space-compact.token';\n\n@Component({\n  selector: 'nz-space-compact',\n  exportAs: 'nzSpaceCompact',\n  template: `<ng-content />`,\n  host: {\n    class: 'ant-space-compact',\n    '[class.ant-space-compact-block]': `nzBlock()`,\n    '[class.ant-space-compact-vertical]': `nzDirection() === 'vertical'`\n  },\n  providers: [\n    { provide: NZ_SPACE_COMPACT_SIZE, useFactory: () => inject(NzSpaceCompactComponent).finalSize },\n    { provide: NZ_SPACE_COMPACT_ITEMS, useFactory: () => signal([]) }\n  ],\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class NzSpaceCompactComponent {\n  private readonly formSize = inject(NZ_FORM_SIZE, { optional: true });\n  readonly nzBlock = input(false, { transform: booleanAttribute });\n  readonly nzDirection = input<'vertical' | 'horizontal'>('horizontal');\n  readonly nzSize = input<NzSizeLDSType>('default');\n  readonly elementRef: ElementRef<HTMLElement> = inject(ElementRef);\n  protected readonly finalSize = computed(() => this.formSize?.() || this.nzSize());\n}\n"
  },
  {
    "path": "components/space/space-compact.token.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { InjectionToken, Signal, WritableSignal } from '@angular/core';\n\nimport { NzSizeLDSType } from 'ng-zorro-antd/core/types';\n\nimport type { NzSpaceCompactItemDirective } from './space-compact-item.directive';\n\nexport const NZ_SPACE_COMPACT_SIZE = new InjectionToken<Signal<NzSizeLDSType>>(\n  typeof ngDevMode !== 'undefined' && ngDevMode ? 'nz-space-compact-size' : ''\n);\nexport const NZ_SPACE_COMPACT_ITEMS = new InjectionToken<WritableSignal<NzSpaceCompactItemDirective[]>>(\n  typeof ngDevMode !== 'undefined' && ngDevMode ? 'nz-space-compact-items' : ''\n);\nexport const NZ_SPACE_COMPACT_ITEM_TYPE = new InjectionToken<string>(\n  typeof ngDevMode !== 'undefined' && ngDevMode ? 'nz-space-compact-item-type' : ''\n);\n"
  },
  {
    "path": "components/space/space-item.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive } from '@angular/core';\n\n@Directive({\n  selector: '[nzSpaceItem]'\n})\nexport class NzSpaceItemDirective {}\n"
  },
  {
    "path": "components/space/space.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\nimport { NzSpaceAlign, NzSpaceDirection, NzSpaceSize } from 'ng-zorro-antd/space';\nimport { NzSpaceComponent } from 'ng-zorro-antd/space/space.component';\n\nimport { NzSpaceModule } from './space.module';\n\ndescribe('space', () => {\n  let component: SpaceTestComponent;\n  let fixture: ComponentFixture<SpaceTestComponent>;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(SpaceTestComponent);\n    component = fixture.componentInstance;\n    component.size = 'small';\n    component.direction = 'horizontal';\n    fixture.detectChanges();\n  });\n\n  it('should render size', () => {\n    const spaceComponent = fixture.debugElement.query(By.directive(NzSpaceComponent));\n    const spaceElement = spaceComponent.nativeElement as HTMLElement;\n\n    // default size is 'small'\n    expect(spaceElement.style.columnGap).toBe('8px');\n    expect(spaceElement.style.rowGap).toBe('8px');\n\n    component.size = 'middle';\n    fixture.detectChanges();\n    expect(spaceElement.style.columnGap).toBe('16px');\n    expect(spaceElement.style.rowGap).toBe('16px');\n\n    component.size = 'large';\n    fixture.detectChanges();\n    expect(spaceElement.style.columnGap).toBe('24px');\n    expect(spaceElement.style.rowGap).toBe('24px');\n  });\n\n  it('should render customize size', () => {\n    const spaceComponent = fixture.debugElement.query(By.directive(NzSpaceComponent));\n    const spaceElement = spaceComponent.nativeElement as HTMLElement;\n\n    component.size = 36;\n    fixture.detectChanges();\n    expect(spaceElement.style.columnGap).toBe('36px');\n    expect(spaceElement.style.rowGap).toBe('36px');\n\n    component.size = [36, 18];\n    fixture.detectChanges();\n    expect(spaceElement.style.columnGap).toBe('36px');\n    expect(spaceElement.style.rowGap).toBe('18px');\n  });\n\n  it('should wrap', () => {\n    const spaceComponent = fixture.debugElement.query(By.directive(NzSpaceComponent));\n    const spaceElement = spaceComponent.nativeElement as HTMLElement;\n\n    // default wrap is false\n    expect(spaceElement.style.flexWrap).toBeFalsy();\n\n    component.wrap = true;\n    fixture.detectChanges();\n\n    expect(spaceElement.style.flexWrap).toBe('wrap');\n  });\n\n  it('should set direction', () => {\n    const spaceComponent = fixture.debugElement.query(By.directive(NzSpaceComponent));\n    const spaceElement = spaceComponent.nativeElement as HTMLElement;\n\n    component.direction = 'vertical';\n    fixture.detectChanges();\n    expect(spaceElement.classList).toContain('ant-space-vertical');\n\n    component.direction = 'horizontal';\n    fixture.detectChanges();\n    expect(spaceElement.classList).toContain('ant-space-horizontal');\n  });\n\n  it('should set align', () => {\n    component.direction = 'vertical';\n    fixture.detectChanges();\n\n    const spaceComponent = fixture.debugElement.query(By.directive(NzSpaceComponent));\n    const spaceNativeElement = spaceComponent.nativeElement as HTMLElement;\n    expect(spaceNativeElement.classList).toContain('ant-space-vertical');\n\n    spaceNativeElement.classList.forEach(className => {\n      expect(className.indexOf('ant-space-align') === -1).toBe(true);\n    });\n\n    component.direction = 'horizontal';\n    fixture.detectChanges();\n\n    expect(spaceNativeElement.classList).toContain('ant-space-align-center');\n\n    component.align = 'end';\n    fixture.detectChanges();\n\n    expect(spaceNativeElement.classList).toContain('ant-space-align-end');\n  });\n\n  it('should render split', () => {\n    component.showSplit = true;\n    fixture.detectChanges();\n\n    const spaceComponent = fixture.debugElement.query(By.directive(NzSpaceComponent));\n    const spaceElement = spaceComponent.nativeElement as HTMLElement;\n    let items = fixture.debugElement.queryAll(By.css('.ant-space-item'));\n    let splits = fixture.debugElement.queryAll(By.css('.ant-space-split'));\n\n    expect(items.length).toBe(2);\n    expect(splits.length).toBe(1);\n    expect(spaceElement.style.columnGap).toBe('8px');\n    expect(spaceElement.style.rowGap).toBe('8px');\n\n    component.show = true;\n    fixture.detectChanges();\n\n    items = fixture.debugElement.queryAll(By.css('.ant-space-item'));\n    splits = fixture.debugElement.queryAll(By.css('.ant-space-split'));\n\n    expect(items.length).toBe(3);\n    expect(splits.length).toBe(2);\n    expect(spaceElement.style.columnGap).toBe('8px');\n    expect(spaceElement.style.rowGap).toBe('8px');\n  });\n});\n\n@Component({\n  imports: [NzSpaceModule],\n  template: `\n    <nz-space\n      [nzSplit]=\"showSplit ? spaceSplit : null\"\n      [nzSize]=\"size\"\n      [nzDirection]=\"direction\"\n      [nzAlign]=\"align\"\n      [nzWrap]=\"wrap\"\n    >\n      <div *nzSpaceItem>item</div>\n      <div *nzSpaceItem>item</div>\n      @if (show) {\n        <div *nzSpaceItem>item</div>\n      }\n    </nz-space>\n\n    <ng-template #spaceSplit>|</ng-template>\n  `\n})\nclass SpaceTestComponent {\n  size: NzSpaceSize | [NzSpaceSize, NzSpaceSize] = 'small';\n  direction: NzSpaceDirection = 'horizontal';\n  show = false;\n  align?: NzSpaceAlign;\n  wrap?: boolean;\n  showSplit = false;\n}\n"
  },
  {
    "path": "components/space/space.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterContentInit,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ContentChildren,\n  DestroyRef,\n  Input,\n  OnChanges,\n  QueryList,\n  SimpleChanges,\n  TemplateRef,\n  booleanAttribute,\n  inject\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { NzConfigKey, NzConfigService, WithConfig } from 'ng-zorro-antd/core/config';\nimport { NzStringTemplateOutletDirective } from 'ng-zorro-antd/core/outlet';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzSpaceItemDirective } from './space-item.directive';\nimport { NzSpaceAlign, NzSpaceDirection, NzSpaceSize, NzSpaceType } from './types';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'space';\nconst SPACE_SIZE: Record<NzSpaceType, number> = {\n  small: 8,\n  middle: 16,\n  large: 24\n};\n\n@Component({\n  selector: 'nz-space, [nz-space]',\n  exportAs: 'nzSpace',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    <ng-content />\n    @for (item of items; track item) {\n      <div class=\"ant-space-item\">\n        <ng-container [ngTemplateOutlet]=\"item\" />\n      </div>\n      @if (nzSplit && !$last) {\n        <span class=\"ant-space-split\">\n          <ng-template [nzStringTemplateOutlet]=\"nzSplit\" [nzStringTemplateOutletContext]=\"{ $implicit: $index }\">{{\n            nzSplit\n          }}</ng-template>\n        </span>\n      }\n    }\n  `,\n  host: {\n    class: 'ant-space',\n    '[class.ant-space-horizontal]': 'nzDirection === \"horizontal\"',\n    '[class.ant-space-vertical]': 'nzDirection === \"vertical\"',\n    '[class.ant-space-align-start]': 'mergedAlign === \"start\"',\n    '[class.ant-space-align-end]': 'mergedAlign === \"end\"',\n    '[class.ant-space-align-center]': 'mergedAlign === \"center\"',\n    '[class.ant-space-align-baseline]': 'mergedAlign === \"baseline\"',\n    '[style.flex-wrap]': 'nzWrap ? \"wrap\" : null',\n    '[style.column-gap.px]': 'horizontalSize',\n    '[style.row-gap.px]': 'verticalSize'\n  },\n  imports: [NgTemplateOutlet, NzStringTemplateOutletDirective]\n})\nexport class NzSpaceComponent implements OnChanges, AfterContentInit {\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  nzConfigService = inject(NzConfigService);\n  private cdr = inject(ChangeDetectorRef);\n  private destroyRef = inject(DestroyRef);\n\n  @Input() nzDirection: NzSpaceDirection = 'horizontal';\n  @Input() nzAlign?: NzSpaceAlign;\n  @Input() nzSplit: TemplateRef<{ $implicit: number }> | string | null = null;\n  @Input({ transform: booleanAttribute }) nzWrap: boolean = false;\n  @Input() @WithConfig() nzSize: NzSpaceSize | [NzSpaceSize, NzSpaceSize] = 'small';\n\n  @ContentChildren(NzSpaceItemDirective, { read: TemplateRef }) items!: QueryList<TemplateRef<NzSafeAny>>;\n\n  mergedAlign?: NzSpaceAlign;\n  horizontalSize!: number;\n  verticalSize!: number;\n\n  constructor() {\n    this.updateSpaceSize();\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzSize } = changes;\n    if (nzSize) {\n      this.updateSpaceSize();\n    }\n    this.mergedAlign = this.nzAlign === undefined && this.nzDirection === 'horizontal' ? 'center' : this.nzAlign;\n  }\n\n  ngAfterContentInit(): void {\n    this.items.changes.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      this.cdr.markForCheck();\n    });\n  }\n\n  private updateSpaceSize(): void {\n    const { horizontalSize, verticalSize } = normalizeSpaceSize(this.nzSize);\n    this.horizontalSize = horizontalSize;\n    this.verticalSize = verticalSize;\n  }\n}\n\nfunction normalizeSpaceSize(size: NzSpaceSize | [NzSpaceSize, NzSpaceSize]): {\n  horizontalSize: number;\n  verticalSize: number;\n} {\n  const [horizontalSize, verticalSize] = (Array.isArray(size) ? size : ([size, size] as const)).map(s =>\n    typeof s === 'number' ? s : SPACE_SIZE[s]\n  );\n  return { horizontalSize, verticalSize };\n}\n"
  },
  {
    "path": "components/space/space.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzSpaceCompactComponent } from './space-compact.component';\nimport { NzSpaceItemDirective } from './space-item.directive';\nimport { NzSpaceComponent } from './space.component';\n\n@NgModule({\n  imports: [NzSpaceComponent, NzSpaceItemDirective, NzSpaceCompactComponent],\n  exports: [NzSpaceComponent, NzSpaceItemDirective, NzSpaceCompactComponent]\n})\nexport class NzSpaceModule {}\n"
  },
  {
    "path": "components/space/style/compact.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@space-compact-prefix-cls: ~'@{ant-prefix}-space-compact';\n\n.@{space-compact-prefix-cls} {\n  display: inline-flex;\n\n  &-block {\n    display: flex;\n    width: 100%;\n  }\n\n  &-vertical {\n    flex-direction: column;\n  }\n}\n"
  },
  {
    "path": "components/space/style/entry.less",
    "content": "@import './index.less';\n@import './patch.less';"
  },
  {
    "path": "components/space/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@space-prefix-cls: ~'@{ant-prefix}-space';\n@space-item-prefix-cls: ~'@{ant-prefix}-space-item';\n\n.@{space-prefix-cls} {\n  display: inline-flex;\n\n  &-vertical {\n    flex-direction: column;\n  }\n\n  &-align {\n    &-center {\n      align-items: center;\n    }\n\n    &-start {\n      align-items: flex-start;\n    }\n\n    &-end {\n      align-items: flex-end;\n    }\n\n    &-baseline {\n      align-items: baseline;\n    }\n  }\n}\n\n.@{space-item-prefix-cls} {\n  &:empty {\n    display: none;\n  }\n}\n\n@import './compact';\n@import './rtl';\n"
  },
  {
    "path": "components/space/style/patch.less",
    "content": "nz-space-item {\n  display: block;\n}"
  },
  {
    "path": "components/space/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@space-prefix-cls: ~'@{ant-prefix}-space';\n\n.@{space-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &-compact-rtl {\n    direction: rtl;\n  }\n}\n"
  },
  {
    "path": "components/space/types.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport type NzSpaceDirection = 'vertical' | 'horizontal';\nexport type NzSpaceAlign = 'start' | 'end' | 'center' | 'baseline';\nexport type NzSpaceType = 'small' | 'middle' | 'large';\nexport type NzSpaceSize = NzSpaceType | number;\n"
  },
  {
    "path": "components/spin/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本用法\n  en-US: Basic Usage\n---\n\n## zh-CN\n\n一个简单的 loading 状态。\n\n## en-US\n\nA simple loading status.\n"
  },
  {
    "path": "components/spin/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzSpinModule } from 'ng-zorro-antd/spin';\n\n@Component({\n  selector: 'nz-demo-spin-basic',\n  imports: [NzSpinModule],\n  template: `<nz-spin nzSimple />`\n})\nexport class NzDemoSpinBasicComponent {}\n"
  },
  {
    "path": "components/spin/demo/custom-indicator.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 自定义指示符\n  en-US: Custom spinning indicator\n---\n\n## zh-CN\n\n使用自定义指示符。\n\n## en-US\n\nUse custom loading indicator.\n"
  },
  {
    "path": "components/spin/demo/custom-indicator.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzSpinModule } from 'ng-zorro-antd/spin';\n\n@Component({\n  selector: 'nz-demo-spin-custom-indicator',\n  imports: [NzIconModule, NzSpinModule],\n  template: `\n    <ng-template #indicatorTemplate><nz-icon nzType=\"loading\" /></ng-template>\n    <nz-spin nzSimple [nzIndicator]=\"indicatorTemplate\" />\n  `,\n  styles: `\n    nz-icon {\n      font-size: 24px;\n    }\n  `\n})\nexport class NzDemoSpinCustomIndicatorComponent {}\n"
  },
  {
    "path": "components/spin/demo/delay-and-debounce.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 延迟\n  en-US: delay\n---\n\n## zh-CN\n\n延迟显示 loading 效果。当 spinning 状态在 `nzDelay` 时间内结束，则不显示 loading 状态。\n\n## en-US\n\nSpecifies a delay for loading state. If `spinning` ends during delay, loading status won't appear.\n"
  },
  {
    "path": "components/spin/demo/delay-and-debounce.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzAlertModule } from 'ng-zorro-antd/alert';\nimport { NzSpinModule } from 'ng-zorro-antd/spin';\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\n\n@Component({\n  selector: 'nz-demo-spin-delay-and-debounce',\n  imports: [FormsModule, NzAlertModule, NzSpinModule, NzSwitchModule],\n  template: `\n    <nz-spin [nzSpinning]=\"isSpinning\" [nzDelay]=\"500\">\n      <nz-alert\n        nzType=\"info\"\n        nzMessage=\"Alert message title\"\n        nzDescription=\"Further details about the context of this alert.\"\n      />\n    </nz-spin>\n    <br />\n    <div>\n      Loading state：\n      <nz-switch [(ngModel)]=\"isSpinning\" />\n    </div>\n  `\n})\nexport class NzDemoSpinDelayAndDebounceComponent {\n  isSpinning = false;\n}\n"
  },
  {
    "path": "components/spin/demo/inside.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 容器\n  en-US: Inside a container\n---\n\n## zh-CN\n\n放入一个容器中。\n\n## en-US\n\nSpin in a container.\n"
  },
  {
    "path": "components/spin/demo/inside.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzSpinModule } from 'ng-zorro-antd/spin';\n\n@Component({\n  selector: 'nz-demo-spin-inside',\n  imports: [NzSpinModule],\n  template: `\n    <div class=\"container\">\n      <nz-spin nzSimple />\n    </div>\n  `,\n  styles: `\n    .container {\n      text-align: center;\n      background: rgba(0, 0, 0, 0.05);\n      border-radius: 4px;\n      padding: 30px 50px;\n      margin: 20px 0;\n    }\n  `\n})\nexport class NzDemoSpinInsideComponent {}\n"
  },
  {
    "path": "components/spin/demo/nested.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 卡片加载中\n  en-US: Embedded mode\n---\n\n## zh-CN\n\n可以直接把内容内嵌到 `nz-spin` 中，将现有容器变为加载状态。\n\n## en-US\n\nEmbedding content into `nz-spin` will alter it into loading state.\n"
  },
  {
    "path": "components/spin/demo/nested.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzAlertModule } from 'ng-zorro-antd/alert';\nimport { NzSpinModule } from 'ng-zorro-antd/spin';\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\n\n@Component({\n  selector: 'nz-demo-spin-nested',\n  imports: [FormsModule, NzAlertModule, NzSpinModule, NzSwitchModule],\n  template: `\n    <nz-spin [nzSpinning]=\"isSpinning\">\n      <nz-alert\n        nzType=\"info\"\n        nzMessage=\"Alert message title\"\n        nzDescription=\"Further details about the context of this alert.\"\n      />\n    </nz-spin>\n    <br />\n    <div>\n      Loading state：\n      <nz-switch [(ngModel)]=\"isSpinning\" />\n    </div>\n  `\n})\nexport class NzDemoSpinNestedComponent {\n  isSpinning = false;\n}\n"
  },
  {
    "path": "components/spin/demo/size.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 各种大小\n  en-US: Size\n---\n\n## zh-CN\n\n小的用于文本加载，默认用于卡片容器级加载，大的用于**页面级**加载。\n\n## en-US\n\nA small `Spin` use in loading text, default `Spin` use in loading card-level block, and large `Spin` use in loading **page**.\n"
  },
  {
    "path": "components/spin/demo/size.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzSpinModule } from 'ng-zorro-antd/spin';\n\n@Component({\n  selector: 'nz-demo-spin-size',\n  imports: [NzSpinModule],\n  template: `\n    <nz-spin nzSimple nzSize=\"small\" />\n    <nz-spin nzSimple />\n    <nz-spin nzSimple nzSize=\"large\" />\n  `,\n  styles: `\n    nz-spin {\n      display: inline-block;\n      margin-right: 16px;\n    }\n  `\n})\nexport class NzDemoSpinSizeComponent {}\n"
  },
  {
    "path": "components/spin/demo/tip.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 自定义描述文案\n  en-US: Customized description\n---\n\n## zh-CN\n\n自定义描述文案。\n\n## en-US\n\nCustomized description content.\n"
  },
  {
    "path": "components/spin/demo/tip.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzAlertModule } from 'ng-zorro-antd/alert';\nimport { NzSpinModule } from 'ng-zorro-antd/spin';\n\n@Component({\n  selector: 'nz-demo-spin-tip',\n  imports: [NzAlertModule, NzSpinModule],\n  template: `\n    <nz-spin nzTip=\"Loading...\">\n      <nz-alert\n        nzType=\"info\"\n        nzMessage=\"Alert message title\"\n        nzDescription=\"Further details about the context of this alert.\"\n      />\n    </nz-spin>\n  `\n})\nexport class NzDemoSpinTipComponent {}\n"
  },
  {
    "path": "components/spin/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Feedback\ntitle: Spin\ncover: 'https://gw.alipayobjects.com/zos/alicdn/LBcJqCPRv/Spin.svg'\ndescription: Used for the loading status of a page or a block.\n---\n\n## When To Use\n\nWhen part of the page is waiting for asynchronous data or during a rendering process, an appropriate loading animation can effectively alleviate users' inquietude.\n\n## API\n\n### nz-spin\n\n| Property        | Description                                                                             | Type                              | Default Value | Global Config |\n| --------------- | --------------------------------------------------------------------------------------- | --------------------------------- | ------------- | ------------- |\n| `[nzDelay]`     | specifies a delay in milliseconds for loading state (prevent flush), unit: milliseconds | `number`                          | -             |\n| `[nzIndicator]` | the spinning indicator                                                                  | `TemplateRef<void>`               | -             | ✅            |\n| `[nzSize]`      | size of Spin                                                                            | `'large' \\| 'small' \\| 'default'` | `'default'`   |\n| `[nzSpinning]`  | whether Spin is spinning                                                                | `boolean`                         | `true`        |\n| `[nzSimple]`    | whether Spin has no children                                                            | `boolean`                         | `false`       |\n| `[nzTip]`       | customize description content when Spin has children                                    | `string`                          | -             |\n"
  },
  {
    "path": "components/spin/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ntype: 反馈\ntitle: Spin\nsubtitle: 加载中\ncover: 'https://gw.alipayobjects.com/zos/alicdn/LBcJqCPRv/Spin.svg'\ndescription: 用于页面和区块的加载中状态。\n---\n\n## 何时使用\n\n页面局部处于等待异步数据或正在渲染过程时，合适的加载动效会有效缓解用户的焦虑。\n\n## API\n\n### nz-spin\n\n| 参数            | 说明                                           | 类型                              | 默认值      | 全局配置 |\n| --------------- | ---------------------------------------------- | --------------------------------- | ----------- | -------- |\n| `[nzDelay]`     | 延迟显示加载效果的时间（防止闪烁），单位：毫秒 | `number`                          | -           |\n| `[nzIndicator]` | 加载指示符                                     | `TemplateRef<void>`               | -           | ✅       |\n| `[nzSize]`      | 组件大小                                       | `'large' \\| 'small' \\| 'default'` | `'default'` |\n| `[nzSpinning]`  | 是否旋转                                       | `boolean`                         | `true`      |\n| `[nzSimple]`    | 是否包裹元素                                   | `boolean`                         | `false`     |\n| `[nzTip]`       | 当作为包裹元素时，可以自定义描述文案           | `string`                          | -           |\n"
  },
  {
    "path": "components/spin/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/spin/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/spin/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './spin.component';\nexport * from './spin.module';\n"
  },
  {
    "path": "components/spin/spin.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectorRef,\n  Component,\n  Input,\n  OnChanges,\n  OnInit,\n  SimpleChanges,\n  TemplateRef,\n  ViewEncapsulation,\n  booleanAttribute,\n  numberAttribute,\n  inject,\n  DestroyRef,\n  signal\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { BehaviorSubject, Observable, of, ReplaySubject } from 'rxjs';\nimport { distinctUntilChanged, startWith, switchMap } from 'rxjs/operators';\n\nimport { NzConfigKey, onConfigChangeEventForComponent, WithConfig } from 'ng-zorro-antd/core/config';\nimport { NzSafeAny, NzSizeLDSType } from 'ng-zorro-antd/core/types';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'spin';\n\n@Component({\n  selector: 'nz-spin',\n  exportAs: 'nzSpin',\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <ng-template #defaultTemplate>\n      <span class=\"ant-spin-dot ant-spin-dot-spin\">\n        <i class=\"ant-spin-dot-item\"></i>\n        <i class=\"ant-spin-dot-item\"></i>\n        <i class=\"ant-spin-dot-item\"></i>\n        <i class=\"ant-spin-dot-item\"></i>\n      </span>\n    </ng-template>\n    @if (isLoading()) {\n      <div>\n        <div\n          class=\"ant-spin ant-spin-spinning\"\n          [class.ant-spin-rtl]=\"dir === 'rtl'\"\n          [class.ant-spin-lg]=\"nzSize === 'large'\"\n          [class.ant-spin-sm]=\"nzSize === 'small'\"\n          [class.ant-spin-show-text]=\"nzTip\"\n        >\n          <ng-template [ngTemplateOutlet]=\"nzIndicator || defaultTemplate\" />\n          @if (nzTip) {\n            <div class=\"ant-spin-text\">{{ nzTip }}</div>\n          }\n        </div>\n      </div>\n    }\n    @if (!nzSimple) {\n      <div class=\"ant-spin-container\" [class.ant-spin-blur]=\"isLoading()\">\n        <ng-content />\n      </div>\n    }\n  `,\n  host: {\n    '[class.ant-spin-nested-loading]': '!nzSimple'\n  },\n  imports: [NgTemplateOutlet]\n})\nexport class NzSpinComponent implements OnChanges, OnInit {\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  private cdr = inject(ChangeDetectorRef);\n  private directionality = inject(Directionality);\n  private destroyRef = inject(DestroyRef);\n\n  @Input() @WithConfig() nzIndicator: TemplateRef<NzSafeAny> | null = null;\n  @Input() nzSize: NzSizeLDSType = 'default';\n  @Input() nzTip: string | null = null;\n  @Input({ transform: numberAttribute }) nzDelay = 0;\n  @Input({ transform: booleanAttribute }) nzSimple = false;\n  @Input({ transform: booleanAttribute }) nzSpinning = true;\n  private spinning$ = new BehaviorSubject(this.nzSpinning);\n  private delay$ = new ReplaySubject<number>(1);\n\n  readonly isLoading = signal(false);\n\n  dir: Direction = 'ltr';\n\n  constructor() {\n    onConfigChangeEventForComponent(NZ_CONFIG_MODULE_NAME, () => this.cdr.markForCheck());\n  }\n\n  ngOnInit(): void {\n    this.delay$\n      .pipe(\n        startWith(this.nzDelay),\n        distinctUntilChanged(),\n        switchMap(delay =>\n          // This construct is used to reduce RxJS dependencies.\n          // It previously used `debounce(() => timer())`, but consumers may not\n          // use these RxJS functions at all, causing them to still be bundled\n          // into the main bundle unnecessarily.\n          this.spinning$.pipe(\n            switchMap(spinning => {\n              if (delay === 0 || !spinning) {\n                return of(spinning);\n              }\n              return new Observable<boolean>(subscriber => {\n                const timeoutId = setTimeout(() => subscriber.next(spinning), delay);\n                return () => clearTimeout(timeoutId);\n              });\n            })\n          )\n        ),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(isLoading => {\n        this.isLoading.set(isLoading);\n      });\n\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n      this.dir = direction;\n      this.cdr.detectChanges();\n    });\n\n    this.dir = this.directionality.value;\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzSpinning, nzDelay } = changes;\n    if (nzSpinning) {\n      this.spinning$.next(this.nzSpinning);\n    }\n    if (nzDelay) {\n      this.delay$.next(this.nzDelay);\n    }\n  }\n}\n"
  },
  {
    "path": "components/spin/spin.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzSpinComponent } from './spin.component';\n\n@NgModule({\n  imports: [NzSpinComponent],\n  exports: [NzSpinComponent]\n})\nexport class NzSpinModule {}\n"
  },
  {
    "path": "components/spin/spin.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport { Component, DebugElement, provideZoneChangeDetection, TemplateRef, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { NzConfigService } from 'ng-zorro-antd/core/config';\nimport { NzSafeAny, NzSizeLDSType } from 'ng-zorro-antd/core/types';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzSpinComponent } from './spin.component';\nimport { NzSpinModule } from './spin.module';\n\ndescribe('spin', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideZoneChangeDetection()]\n    });\n  });\n\n  describe('spin basic', () => {\n    let fixture: ComponentFixture<NzTestSpinBasicComponent>;\n    let testComponent: NzTestSpinBasicComponent;\n    let spin: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestSpinBasicComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n      spin = fixture.debugElement.query(By.directive(NzSpinComponent));\n    });\n\n    it('should className correct', fakeAsync(() => {\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n      expect(spin.nativeElement.querySelector('.ant-spin').firstElementChild!.classList).toContain('ant-spin-dot');\n    }));\n\n    it('should size work', fakeAsync(() => {\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      testComponent.size = 'small';\n      fixture.detectChanges();\n      expect(spin.nativeElement.querySelector('.ant-spin').classList).toContain('ant-spin-sm');\n      testComponent.size = 'large';\n      fixture.detectChanges();\n      expect(spin.nativeElement.querySelector('.ant-spin').classList).toContain('ant-spin-lg');\n    }));\n\n    it('should spinning work', fakeAsync(() => {\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      testComponent.spinning = false;\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(spin.nativeElement.querySelector('.ant-spin')).toBeNull();\n      testComponent.spinning = true;\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(spin.nativeElement.querySelector('.ant-spin')).toBeDefined();\n    }));\n\n    it('should indicator work', () => {\n      fixture.detectChanges();\n      expect(spin.nativeElement.querySelector('.ant-spin-dot')).toBeDefined();\n\n      testComponent.indicator = testComponent.indicatorTemplate;\n      fixture.detectChanges();\n      expect(spin.nativeElement.querySelector('.ant-spin-dot')).toBeNull();\n      expect(spin.nativeElement.querySelector('.anticon-loading')).toBeDefined();\n    });\n\n    it('should global config indicator work', () => {\n      fixture.detectChanges();\n      expect(spin.nativeElement.querySelector('.ant-spin-dot')).toBeDefined();\n\n      testComponent.nzConfigService.set('spin', { nzIndicator: testComponent.indicatorTemplate });\n      fixture.detectChanges();\n      expect(spin.nativeElement.querySelector('.ant-spin-dot')).toBeNull();\n      expect(spin.nativeElement.querySelector('.anticon-loading')).toBeDefined();\n    });\n\n    it('should delay work', fakeAsync(() => {\n      testComponent.delay = 500;\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n\n      // true -> false\n      // This should work immediately\n      testComponent.spinning = false;\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(spin.nativeElement.querySelector('.ant-spin')).toBeNull();\n\n      // false -> true\n      // This should be debounced\n      testComponent.spinning = true;\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(spin.nativeElement.querySelector('.ant-spin')).toBeNull();\n\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n      expect(spin.nativeElement.querySelector('.ant-spin')).toBeDefined();\n    }));\n\n    it('should wrapper work', fakeAsync(() => {\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(spin.nativeElement.querySelector('.ant-spin').classList).toContain('ant-spin-spinning');\n      expect(spin.nativeElement.querySelector('.ant-spin-container')).toBeDefined();\n      testComponent.simple = true;\n      fixture.detectChanges();\n      expect(spin.nativeElement.querySelector('.ant-spin-container')).toBeNull();\n    }));\n\n    it('should tip work', fakeAsync(() => {\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(spin.nativeElement.querySelector('.ant-spin-text')).toBeNull();\n      testComponent.tip = 'tip';\n      fixture.detectChanges();\n      expect(spin.nativeElement.querySelector('.ant-spin-text').innerText).toBe('tip');\n    }));\n  });\n\n  describe('RTL', () => {\n    it('should className correct on dir change', () => {\n      const fixture = TestBed.createComponent(NzTestSpinRtlComponent);\n      const spin = fixture.debugElement.query(By.directive(NzSpinComponent));\n      fixture.detectChanges();\n      expect(spin.nativeElement.querySelector('.ant-spin').classList).toContain('ant-spin-rtl');\n\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n      expect(spin.nativeElement.querySelector('.ant-spin').classList).not.toContain('ant-spin-rtl');\n    });\n  });\n});\n\n@Component({\n  selector: 'nz-test-basic-spin',\n  imports: [NzIconModule, NzSpinModule],\n  template: `\n    <ng-template #indicatorTemplate><nz-icon nzType=\"loading\" style=\"font-size: 24px;\" /></ng-template>\n    <nz-spin\n      [nzTip]=\"tip\"\n      [nzSize]=\"size\"\n      [nzDelay]=\"delay\"\n      [nzSpinning]=\"spinning\"\n      [nzSimple]=\"simple\"\n      [nzIndicator]=\"indicator\"\n    >\n      <div>test</div>\n    </nz-spin>\n  `\n})\nexport class NzTestSpinBasicComponent {\n  @ViewChild('indicatorTemplate', { static: false }) indicatorTemplate!: TemplateRef<void>;\n\n  size: NzSizeLDSType = 'default';\n  delay = 0;\n  spinning = true;\n  indicator!: TemplateRef<NzSafeAny>;\n  tip!: string;\n  simple = false;\n\n  constructor(public nzConfigService: NzConfigService) {}\n}\n\n@Component({\n  imports: [BidiModule, NzTestSpinBasicComponent],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-test-basic-spin />\n    </div>\n  `\n})\nexport class NzTestSpinRtlComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n}\n"
  },
  {
    "path": "components/spin/style/entry.less",
    "content": "@import './index.less';\n@import './patch.less';\n"
  },
  {
    "path": "components/spin/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@spin-prefix-cls: ~'@{ant-prefix}-spin';\n@spin-dot-default: @text-color-secondary;\n\n.@{spin-prefix-cls} {\n  .reset-component();\n\n  position: absolute;\n  display: none;\n  color: @primary-color;\n  font-size: 0;\n  text-align: center;\n  vertical-align: middle;\n  opacity: 0;\n  transition: transform 0.3s @ease-in-out-circ;\n\n  &-spinning {\n    position: static;\n    display: inline-block;\n    opacity: 1;\n  }\n\n  &-nested-loading {\n    position: relative;\n    > div > .@{spin-prefix-cls} {\n      position: absolute;\n      top: 0;\n      left: 0;\n      z-index: 4;\n      display: block;\n      width: 100%;\n      height: 100%;\n      max-height: 400px;\n      .@{spin-prefix-cls}-dot {\n        position: absolute;\n        top: 50%;\n        left: 50%;\n        margin: -(@spin-dot-size / 2);\n      }\n      .@{spin-prefix-cls}-text {\n        position: absolute;\n        top: 50%;\n        width: 100%;\n        padding-top: ((@spin-dot-size - @font-size-base) / 2) + 2px;\n        font-size: @font-size-base;\n        text-shadow: 0 1px 2px @shadow-color-inverse;\n      }\n      &.@{spin-prefix-cls}-show-text .@{spin-prefix-cls}-dot {\n        margin-top: -(@spin-dot-size / 2) - 10px;\n      }\n    }\n\n    > div > .@{spin-prefix-cls}-sm {\n      .@{spin-prefix-cls}-dot {\n        margin: -(@spin-dot-size-sm / 2);\n      }\n      .@{spin-prefix-cls}-text {\n        padding-top: ((@spin-dot-size-sm - @font-size-base) / 2) + 2px;\n      }\n      &.@{spin-prefix-cls}-show-text .@{spin-prefix-cls}-dot {\n        margin-top: -(@spin-dot-size-sm / 2) - 10px;\n      }\n    }\n\n    > div > .@{spin-prefix-cls}-lg {\n      .@{spin-prefix-cls}-dot {\n        margin: -(@spin-dot-size-lg / 2);\n      }\n      .@{spin-prefix-cls}-text {\n        padding-top: ((@spin-dot-size-lg - @font-size-base) / 2) + 2px;\n      }\n      &.@{spin-prefix-cls}-show-text .@{spin-prefix-cls}-dot {\n        margin-top: -(@spin-dot-size-lg / 2) - 10px;\n      }\n    }\n  }\n\n  &-container {\n    position: relative;\n    transition: opacity 0.3s;\n\n    &::after {\n      position: absolute;\n      top: 0;\n      right: 0;\n      bottom: 0;\n      left: 0;\n      z-index: 10;\n      display: ~'none \\9';\n      width: 100%;\n      height: 100%;\n      background: @component-background;\n      opacity: 0;\n      transition: all 0.3s;\n      content: '';\n      pointer-events: none;\n    }\n  }\n\n  &-blur {\n    clear: both;\n    opacity: 0.5;\n    user-select: none;\n    pointer-events: none;\n\n    &::after {\n      opacity: 0.4;\n      pointer-events: auto;\n    }\n  }\n\n  // tip\n  // ------------------------------\n  &-tip {\n    color: @spin-dot-default;\n  }\n\n  // dots\n  // ------------------------------\n\n  &-dot {\n    position: relative;\n    display: inline-block;\n    font-size: @spin-dot-size;\n\n    .square(1em);\n\n    &-item {\n      position: absolute;\n      display: block;\n      width: 9px;\n      height: 9px;\n      background-color: @primary-color;\n      border-radius: 100%;\n      transform: scale(0.75);\n      transform-origin: 50% 50%;\n      opacity: 0.3;\n      animation: antSpinMove 1s infinite linear alternate;\n\n      &:nth-child(1) {\n        top: 0;\n        left: 0;\n      }\n\n      &:nth-child(2) {\n        top: 0;\n        right: 0;\n        animation-delay: 0.4s;\n      }\n\n      &:nth-child(3) {\n        right: 0;\n        bottom: 0;\n        animation-delay: 0.8s;\n      }\n\n      &:nth-child(4) {\n        bottom: 0;\n        left: 0;\n        animation-delay: 1.2s;\n      }\n    }\n\n    &-spin {\n      transform: rotate(0deg);\n      animation: antRotate 1.2s infinite linear;\n    }\n  }\n\n  // Sizes\n  // ------------------------------\n\n  // small\n  &-sm &-dot {\n    font-size: @spin-dot-size-sm;\n\n    i {\n      width: 6px;\n      height: 6px;\n    }\n  }\n\n  // large\n  &-lg &-dot {\n    font-size: @spin-dot-size-lg;\n\n    i {\n      width: 14px;\n      height: 14px;\n    }\n  }\n\n  &&-show-text &-text {\n    display: block;\n  }\n}\n\n@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {\n  /* IE10+ */\n  .@{spin-prefix-cls}-blur {\n    background: @component-background;\n    opacity: 0.5;\n  }\n}\n\n@keyframes antSpinMove {\n  to {\n    opacity: 1;\n  }\n}\n\n@keyframes antRotate {\n  to {\n    transform: rotate(360deg);\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/spin/style/patch.less",
    "content": "nz-spin {\n  display: block;\n}\n"
  },
  {
    "path": "components/spin/style/rtl.less",
    "content": ".@{spin-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &-dot {\n    &-spin {\n      .@{spin-prefix-cls}-rtl & {\n        transform: rotate(-45deg);\n        animation-name: antRotateRtl;\n      }\n    }\n  }\n}\n\n@keyframes antRotateRtl {\n  to {\n    transform: rotate(-405deg);\n  }\n}\n"
  },
  {
    "path": "components/splitter/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本用法\n  en-US: Basic\n---\n\n## zh-CN\n\n初始化面板大小，面板大小限制。\n\n## en-US\n\nInitialize panel size, panel size limit.\n"
  },
  {
    "path": "components/splitter/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzSplitterModule } from 'ng-zorro-antd/splitter';\n\n@Component({\n  selector: 'nz-demo-splitter-basic',\n  imports: [NzSplitterModule],\n  template: `\n    <nz-splitter>\n      <nz-splitter-panel nzDefaultSize=\"40%\" nzMin=\"20%\" nzMax=\"70%\">\n        <div class=\"box\">First</div>\n      </nz-splitter-panel>\n      <nz-splitter-panel>\n        <div class=\"box\">Second</div>\n      </nz-splitter-panel>\n    </nz-splitter>\n  `,\n  styles: `\n    nz-splitter {\n      height: 200px;\n      box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);\n    }\n\n    .box {\n      height: 100%;\n      display: flex;\n      justify-content: center;\n      align-items: center;\n    }\n  `\n})\nexport class NzDemoSplitterBasicComponent {}\n"
  },
  {
    "path": "components/splitter/demo/collapsible.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 可折叠\n  en-US: Collapsible\n---\n\n## zh-CN\n\n配置 `nzCollapsible` 提供快捷收缩能力。可以通过 `nzMin` 限制收缩后不能通过拖拽展开。\n\n## en-US\n\nSet `nzCollapsible` to enable collapse. Can through `nzMin` to limit dragging to expand when collapsed.\n"
  },
  {
    "path": "components/splitter/demo/collapsible.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzSplitterModule } from 'ng-zorro-antd/splitter';\n\n@Component({\n  selector: 'nz-demo-splitter-collapsible',\n  imports: [NzSplitterModule],\n  template: `\n    <nz-splitter>\n      <nz-splitter-panel nzMin=\"20%\" [nzCollapsible]=\"true\">\n        <div class=\"box\">First</div>\n      </nz-splitter-panel>\n      <nz-splitter-panel [nzCollapsible]=\"true\">\n        <div class=\"box\">Second</div>\n      </nz-splitter-panel>\n    </nz-splitter>\n    <br />\n    <nz-splitter nzLayout=\"vertical\">\n      <nz-splitter-panel nzMin=\"20%\" [nzCollapsible]=\"true\">\n        <div class=\"box\">First</div>\n      </nz-splitter-panel>\n      <nz-splitter-panel [nzCollapsible]=\"true\">\n        <div class=\"box\">Second</div>\n      </nz-splitter-panel>\n    </nz-splitter>\n  `,\n  styles: `\n    nz-splitter {\n      height: 200px;\n      box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);\n    }\n\n    .box {\n      height: 100%;\n      display: flex;\n      justify-content: center;\n      align-items: center;\n    }\n  `\n})\nexport class NzDemoSplitterCollapsibleComponent {}\n"
  },
  {
    "path": "components/splitter/demo/complex.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 复杂组合\n  en-US: Complex combination\n---\n\n## zh-CN\n\n复杂组合面板，快捷折叠，禁止改变大小。\n\n## en-US\n\nComplex combination panel, quick folding, prohibited from changing size.\n"
  },
  {
    "path": "components/splitter/demo/complex.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzSplitterModule } from 'ng-zorro-antd/splitter';\n\n@Component({\n  selector: 'nz-demo-splitter-complex',\n  imports: [NzSplitterModule],\n  template: `\n    <nz-splitter>\n      <nz-splitter-panel [nzCollapsible]=\"true\">\n        <div class=\"box\">Left</div>\n      </nz-splitter-panel>\n      <nz-splitter-panel>\n        <nz-splitter nzLayout=\"vertical\">\n          <nz-splitter-panel>\n            <div class=\"box\">Top</div>\n          </nz-splitter-panel>\n          <nz-splitter-panel>\n            <div class=\"box\">Bottom</div>\n          </nz-splitter-panel>\n        </nz-splitter>\n      </nz-splitter-panel>\n    </nz-splitter>\n  `,\n  styles: `\n    nz-splitter {\n      height: 300px;\n      box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);\n    }\n\n    .box {\n      height: 100%;\n      display: flex;\n      justify-content: center;\n      align-items: center;\n    }\n  `\n})\nexport class NzDemoSplitterComplexComponent {}\n"
  },
  {
    "path": "components/splitter/demo/control.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 受控模式\n  en-US: Control Mode\n---\n\n## zh-CN\n\n受控调整尺寸。当 Panel 之间任意一方禁用 `nzResizable`，则其拖拽将被禁用。\n\n## en-US\n\nControl the size of the splitter. When one of the panels disables `nzResizable`, dragging will be disabled.\n"
  },
  {
    "path": "components/splitter/demo/control.ts",
    "content": "import { Component, model, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzFlexModule } from 'ng-zorro-antd/flex';\nimport { NzSplitterModule } from 'ng-zorro-antd/splitter';\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\n\n@Component({\n  selector: 'nz-demo-splitter-control',\n  imports: [FormsModule, NzButtonModule, NzFlexModule, NzSplitterModule, NzSwitchModule],\n  template: `\n    <nz-flex nzGap=\"middle\" nzVertical>\n      <nz-splitter (nzResize)=\"setSizes($event)\">\n        <nz-splitter-panel [nzSize]=\"sizes()[0]\" [nzResizable]=\"resizable()\">\n          <div class=\"box\">First</div>\n        </nz-splitter-panel>\n        <nz-splitter-panel [nzSize]=\"sizes()[1]\">\n          <div class=\"box\">Second</div>\n        </nz-splitter-panel>\n      </nz-splitter>\n      <nz-flex nzJustify=\"space-between\">\n        <nz-switch nzCheckedChildren=\"Enabled\" nzUnCheckedChildren=\"Disabled\" [(ngModel)]=\"resizable\" />\n        <button nz-button (click)=\"sizes.set(['50%', '50%'])\">Reset</button>\n      </nz-flex>\n    </nz-flex>\n  `,\n  styles: `\n    nz-splitter {\n      height: 200px;\n      box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);\n    }\n\n    .box {\n      height: 100%;\n      display: flex;\n      justify-content: center;\n      align-items: center;\n    }\n  `\n})\nexport class NzDemoSplitterControlComponent {\n  resizable = model(true);\n  sizes = signal<Array<number | string>>(['50%', '50%']);\n\n  setSizes(sizes: Array<number | string>): void {\n    console.log('output', sizes);\n    this.sizes.set(sizes);\n  }\n}\n"
  },
  {
    "path": "components/splitter/demo/lazy.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 延迟渲染模式\n  en-US: Lazy\n---\n\n## zh-CN\n\n延迟渲染模式，拖拽时不会立即更新大小，而是等到松手时才更新。\n\n## en-US\n\nLazy mode, dragging does not update the size immediately, but updates when released.\n"
  },
  {
    "path": "components/splitter/demo/lazy.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzSplitterModule } from 'ng-zorro-antd/splitter';\n\n@Component({\n  selector: 'nz-demo-splitter-lazy',\n  imports: [NzSplitterModule],\n  template: `\n    <nz-splitter nzLazy>\n      <nz-splitter-panel nzDefaultSize=\"40%\" nzMin=\"20%\" nzMax=\"70%\">\n        <div class=\"box\">First</div>\n      </nz-splitter-panel>\n      <nz-splitter-panel>\n        <div class=\"box\">Second</div>\n      </nz-splitter-panel>\n    </nz-splitter>\n    <br />\n    <nz-splitter nzLazy nzLayout=\"vertical\">\n      <nz-splitter-panel nzDefaultSize=\"40%\" nzMin=\"30%\" nzMax=\"70%\">\n        <div class=\"box\">First</div>\n      </nz-splitter-panel>\n      <nz-splitter-panel>\n        <div class=\"box\">Second</div>\n      </nz-splitter-panel>\n    </nz-splitter>\n  `,\n  styles: `\n    nz-splitter {\n      height: 200px;\n      box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);\n    }\n\n    .box {\n      height: 100%;\n      display: flex;\n      justify-content: center;\n      align-items: center;\n    }\n  `\n})\nexport class NzDemoSplitterLazyComponent {}\n"
  },
  {
    "path": "components/splitter/demo/multiple.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 多面板\n  en-US: Multiple Panels\n---\n\n## zh-CN\n\n多面板。\n\n## en-US\n\nMultiple panels.\n"
  },
  {
    "path": "components/splitter/demo/multiple.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzSplitterModule } from 'ng-zorro-antd/splitter';\n\n@Component({\n  selector: 'nz-demo-splitter-multiple',\n  imports: [NzSplitterModule],\n  template: `\n    <nz-splitter>\n      <nz-splitter-panel [nzCollapsible]=\"true\">\n        <div class=\"box\">Panel 1</div>\n      </nz-splitter-panel>\n      <nz-splitter-panel [nzCollapsible]=\"{ start: true }\">\n        <div class=\"box\">Panel 2</div>\n      </nz-splitter-panel>\n      <nz-splitter-panel>\n        <div class=\"box\">Panel 3</div>\n      </nz-splitter-panel>\n    </nz-splitter>\n  `,\n  styles: `\n    nz-splitter {\n      height: 200px;\n      box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);\n    }\n\n    .box {\n      height: 100%;\n      display: flex;\n      justify-content: center;\n      align-items: center;\n    }\n  `\n})\nexport class NzDemoSplitterMultipleComponent {}\n"
  },
  {
    "path": "components/splitter/demo/vertical.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 垂直方向\n  en-US: Vertical\n---\n\n## zh-CN\n\n使用垂直布局。\n\n## en-US\n\nUse vertical layout.\n"
  },
  {
    "path": "components/splitter/demo/vertical.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzSplitterModule } from 'ng-zorro-antd/splitter';\n\n@Component({\n  selector: 'nz-demo-splitter-vertical',\n  imports: [NzSplitterModule],\n  template: `\n    <nz-splitter nzLayout=\"vertical\">\n      <nz-splitter-panel>\n        <div class=\"box\">First</div>\n      </nz-splitter-panel>\n      <nz-splitter-panel>\n        <div class=\"box\">Second</div>\n      </nz-splitter-panel>\n    </nz-splitter>\n  `,\n  styles: `\n    nz-splitter {\n      height: 300px;\n      box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);\n    }\n\n    .box {\n      height: 100%;\n      display: flex;\n      justify-content: center;\n      align-items: center;\n    }\n  `\n})\nexport class NzDemoSplitterVerticalComponent {}\n"
  },
  {
    "path": "components/splitter/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Layout\ntitle: Splitter\ntag: 19.2.0\ncover: 'https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*f0SISaETY0wAAAAAAAAAAAAADrJ8AQ/original'\ndescription: Splits the area into multiple horizontal or vertical sides.\n---\n\n## When To Use\n\nThe Splitter component can be used to separate areas horizontally or vertically.\nYou can freely drag the splitter to adjust the size of each side, while also being able to specify its minimum and\nmaximum width and height.\n\n## API\n\n### nz-splitter\n\n| Property          | Description                     | Type                         | Default        |\n| ----------------- | ------------------------------- | ---------------------------- | -------------- |\n| `[nzLayout]`      | Layout direction                | `'horizontal' \\| 'vertical'` | `'horizontal'` |\n| `[nzLazy]`        | Lazy Mode                       | `boolean`                    | `false`        |\n| `(nzResizeStart)` | Callback before dragging starts | `EventEmitter<number[]>`     | -              |\n| `(nzResize)`      | Panel size change callback      | `EventEmitter<number[]>`     | -              |\n| `(nzResizeEnd)`   | Drag end callback               | `EventEmitter<number[]>`     | -              |\n\n### nz-splitter-panel\n\n| Property          | Description                                                     | Type                                             | Default |\n| ----------------- | --------------------------------------------------------------- | ------------------------------------------------ | ------- |\n| `[nzDefaultSize]` | Initial panel size support number for px or 'percent%' usage    | `number \\| string`                               | -       |\n| `[nzMin]`         | Minimum threshold support number for px or 'percent%' usage     | `number \\| string`                               | -       |\n| `[nzMax]`         | Maximum threshold support number for px or 'percent%' usage     | `number \\| string`                               | -       |\n| `[nzSize]`        | Controlled panel size support number for px or 'percent%' usage | `number \\| string`                               | -       |\n| `[nzCollapsible]` | Quick folding                                                   | `boolean  \\| { start?: boolean; end?: boolean }` | `false` |\n| `[nzResizable]`   | Whether to enable drag and drop                                 | `boolean`                                        | `true`  |\n"
  },
  {
    "path": "components/splitter/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ntype: 布局\ntitle: Splitter\nsubtitle: 分隔面板\ntag: 19.2.0\ncover: 'https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*f0SISaETY0wAAAAAAAAAAAAADrJ8AQ/original'\ndescription: 自由切分指定区域。\n---\n\n## 何时使用\n\n- 可以水平或垂直地分隔区域。\n- 当需要自由拖拽调整各区域大小。\n- 当需要指定区域的最大最小宽高时。\n\n## API\n\n### nz-splitter\n\n| 参数              | 说明             | 类型                         | 默认值         |\n| ----------------- | ---------------- | ---------------------------- | -------------- |\n| `[nzLayout]`      | 布局方向         | `'horizontal' \\| 'vertical'` | `'horizontal'` |\n| `[nzLazy]`        | 延迟渲染模式     | `boolean`                    | `false`        |\n| `(nzResizeStart)` | 开始拖拽之前回调 | `EventEmitter<number[]>`     | -              |\n| `(nzResize)`      | 面板大小变化回调 | `EventEmitter<number[]>`     | -              |\n| `(nzResizeEnd)`   | 拖拽结束回调     | `EventEmitter<number[]>`     | -              |\n\n### nz-splitter-panel\n\n| 参数              | 说明                                              | 类型                                             | 默认值  |\n| ----------------- | ------------------------------------------------- | ------------------------------------------------ | ------- |\n| `[nzDefaultSize]` | 初始面板大小，支持数字 px 或者文字 '百分比%' 类型 | `number \\| string`                               | -       |\n| `[nzMin]`         | 最小阈值，支持数字 px 或者文字 '百分比%' 类型     | `number \\| string`                               | -       |\n| `[nzMax]`         | 最大阈值，支持数字 px 或者文字 '百分比%' 类型     | `number \\| string`                               | -       |\n| `[nzSize]`        | 受控面板大小，支持数字 px 或者文字 '百分比%' 类型 | `number \\| string`                               | -       |\n| `[nzCollapsible]` | 快速折叠                                          | `boolean  \\| { start?: boolean; end?: boolean }` | `false` |\n| `[nzResizable]`   | 是否开启拖拽伸缩                                  | `boolean`                                        | `true`  |\n"
  },
  {
    "path": "components/splitter/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/splitter/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/splitter/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './splitter.component';\nexport * from './splitter-panel.component';\nexport * from './splitter.module';\nexport * from './typings';\n"
  },
  {
    "path": "components/splitter/splitter-bar.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { coerceCssPixelValue } from '@angular/cdk/coercion';\nimport { ChangeDetectionStrategy, Component, computed, input, output, ViewEncapsulation } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { getEventWithPoint } from 'ng-zorro-antd/resizable';\n\nimport { NzSplitterCollapseOption } from './typings';\n\n@Component({\n  selector: '[nz-splitter-bar]',\n  imports: [NzIconModule],\n  template: `\n    @if (lazy()) {\n      @let preview = active() && !!this.constrainedOffset();\n      <div\n        class=\"ant-splitter-bar-preview\"\n        [class.ant-splitter-bar-preview-active]=\"preview\"\n        [style.transform]=\"preview ? previewTransform() : null\"\n      ></div>\n    }\n\n    <div\n      class=\"ant-splitter-bar-dragger\"\n      [class.ant-splitter-bar-dragger-disabled]=\"!resizable()\"\n      [class.ant-splitter-bar-dragger-active]=\"active()\"\n      (mousedown)=\"resizeStartEvent($event)\"\n      (touchstart)=\"resizeStartEvent($event)\"\n    ></div>\n\n    @if (collapsible()?.start) {\n      <div class=\"ant-splitter-bar-collapse-bar ant-splitter-bar-collapse-bar-start\" (click)=\"collapseEvent('start')\">\n        <nz-icon\n          [nzType]=\"vertical() ? 'up' : 'left'\"\n          class=\"ant-splitter-bar-collapse-icon ant-splitter-bar-collapse-start\"\n        />\n      </div>\n    }\n\n    @if (collapsible()?.end) {\n      <div class=\"ant-splitter-bar-collapse-bar ant-splitter-bar-collapse-bar-end\" (click)=\"collapseEvent('end')\">\n        <nz-icon\n          [nzType]=\"vertical() ? 'down' : 'right'\"\n          class=\"ant-splitter-bar-collapse-icon ant-splitter-bar-collapse-end\"\n        />\n      </div>\n    }\n  `,\n  host: {\n    role: 'separator',\n    class: 'ant-splitter-bar',\n    '[attr.aria-valuenow]': 'getValidNumber(ariaNow())',\n    '[attr.aria-valuemin]': 'getValidNumber(ariaMin())',\n    '[attr.aria-valuemax]': 'getValidNumber(ariaMax())'\n  },\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class NzSplitterBarComponent {\n  readonly ariaNow = input.required<number>();\n  readonly ariaMin = input.required<number>();\n  readonly ariaMax = input.required<number>();\n  readonly active = input(false);\n  readonly resizable = input(true);\n  readonly vertical = input<boolean>();\n  readonly lazy = input(false);\n  readonly collapsible = input<NzSplitterCollapseOption>();\n  readonly constrainedOffset = input<number>();\n\n  readonly offsetStart = output<[x: number, y: number]>();\n  readonly collapse = output<'start' | 'end'>();\n\n  protected readonly previewTransform = computed(() => {\n    const offset = coerceCssPixelValue(this.constrainedOffset());\n    return this.vertical() ? `translateY(${offset})` : `translateX(${offset})`;\n  });\n\n  protected resizeStartEvent(event: MouseEvent | TouchEvent): void {\n    if (this.resizable()) {\n      const { pageX, pageY } = getEventWithPoint(event);\n      this.offsetStart.emit([pageX, pageY]);\n    }\n  }\n\n  protected collapseEvent(type: 'start' | 'end'): void {\n    this.collapse.emit(type);\n  }\n\n  protected getValidNumber(num: number | undefined): number {\n    return typeof num === 'number' && !isNaN(num) ? Math.round(num) : 0;\n  }\n}\n"
  },
  {
    "path": "components/splitter/splitter-panel.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  input,\n  TemplateRef,\n  Component,\n  ViewEncapsulation,\n  viewChild,\n  booleanAttribute,\n  ChangeDetectionStrategy\n} from '@angular/core';\n\nimport { NzSplitterCollapsible } from './typings';\n\n@Component({\n  selector: 'nz-splitter-panel',\n  exportAs: 'nzSplitterPanel',\n  template: `\n    <ng-template #contentTemplate>\n      <ng-content />\n    </ng-template>\n  `,\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class NzSplitterPanelComponent {\n  readonly nzDefaultSize = input<number | string>();\n  readonly nzMin = input<number | string>();\n  readonly nzMax = input<number | string>();\n  readonly nzSize = input<number | string>();\n  readonly nzCollapsible = input<NzSplitterCollapsible>(false);\n  readonly nzResizable = input(true, { transform: booleanAttribute });\n  readonly contentTemplate = viewChild.required<TemplateRef<void>>('contentTemplate');\n}\n"
  },
  {
    "path": "components/splitter/splitter.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { coerceCssPixelValue } from '@angular/cdk/coercion';\nimport { normalizePassiveListenerOptions } from '@angular/cdk/platform';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  Component,\n  computed,\n  contentChildren,\n  DOCUMENT,\n  ElementRef,\n  inject,\n  input,\n  linkedSignal,\n  output,\n  signal,\n  ViewEncapsulation\n} from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { map, merge, Subject, takeUntil } from 'rxjs';\nimport { pairwise, startWith } from 'rxjs/operators';\n\nimport { NzResizeObserver } from 'ng-zorro-antd/cdk/resize-observer';\nimport { NzDestroyService } from 'ng-zorro-antd/core/services';\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\nimport { getEventWithPoint } from 'ng-zorro-antd/resizable';\n\nimport { NzSplitterBarComponent } from './splitter-bar.component';\nimport { NzSplitterPanelComponent } from './splitter-panel.component';\nimport { NzSplitterCollapseOption, NzSplitterLayout } from './typings';\nimport { coerceCollapsible, getPercentValue, isPercent } from './utils';\n\ninterface PanelSize {\n  // Calculated size of the panel in pixels, constrained by the min and max size.\n  size: string | number | undefined;\n  // Size in pixels\n  postPxSize: number;\n  // The percentage size of the panel, calculated based on the container size.\n  percentage: number;\n  // Original min size of the panel set by the user.\n  min: string | number | undefined;\n  // Original max size of the panel set by the user.\n  max: string | number | undefined;\n  // Post processed min size of the panel in percentage.\n  postPercentMinSize: number;\n  // Post processed max size of the panel in percentage.\n  postPercentMaxSize: number;\n}\n\ninterface ResizableInfo {\n  resizable: boolean;\n  collapsible: Required<NzSplitterCollapseOption>;\n}\n\nconst passiveEventListenerOptions = normalizePassiveListenerOptions({ passive: true });\n\n@Component({\n  selector: 'nz-splitter',\n  exportAs: 'nzSplitter',\n  template: `\n    @for (panel of panelProps(); track $index) {\n      @let size = sizes()[$index];\n      @let flexBasis = !!size.size ? size.size : 'auto';\n      @let flexGrow = !!size.size ? 0 : 1;\n      <div\n        class=\"ant-splitter-panel\"\n        [class.ant-splitter-panel-hidden]=\"size.postPxSize === 0\"\n        [style.flex-basis]=\"flexBasis\"\n        [style.flex-grow]=\"flexGrow\"\n      >\n        <ng-container *ngTemplateOutlet=\"panel.contentTemplate\" />\n      </div>\n\n      @if (!$last) {\n        @let resizableInfo = resizableInfos()[$index];\n        @let ariaInfo = ariaInfos()[$index];\n        <div\n          nz-splitter-bar\n          [ariaNow]=\"ariaInfo.ariaNow\"\n          [ariaMin]=\"ariaInfo.ariaMin\"\n          [ariaMax]=\"ariaInfo.ariaMax\"\n          [resizable]=\"resizableInfo.resizable\"\n          [collapsible]=\"resizableInfo.collapsible\"\n          [active]=\"movingIndex()?.index === $index\"\n          [vertical]=\"nzLayout() === 'vertical'\"\n          [lazy]=\"nzLazy()\"\n          [constrainedOffset]=\"constrainedOffset()\"\n          (offsetStart)=\"startResize($index, $event)\"\n          (collapse)=\"collapse($index, $event)\"\n        ></div>\n      }\n    }\n\n    <!-- Fake mask for cursor -->\n    @if (movingIndex() !== null) {\n      <div\n        aria-hidden\n        class=\"ant-splitter-mask\"\n        [class.ant-splitter-mask-horizontal]=\"nzLayout() === 'horizontal'\"\n        [class.ant-splitter-mask-vertical]=\"nzLayout() === 'vertical'\"\n      ></div>\n    }\n  `,\n  imports: [NgTemplateOutlet, NzSplitterBarComponent],\n  providers: [NzDestroyService],\n  host: {\n    class: 'ant-splitter',\n    '[class.ant-splitter-horizontal]': 'nzLayout() === \"horizontal\"',\n    '[class.ant-splitter-vertical]': 'nzLayout() === \"vertical\"',\n    '[class.ant-splitter-rtl]': 'dir() === \"rtl\"'\n  },\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class NzSplitterComponent {\n  /** ------------------- Props ------------------- */\n  readonly nzLayout = input<NzSplitterLayout>('horizontal');\n  readonly nzLazy = input(false, { transform: booleanAttribute });\n  readonly nzResizeStart = output<number[]>();\n  readonly nzResize = output<number[]>();\n  readonly nzResizeEnd = output<number[]>();\n\n  protected readonly destroy$ = inject(NzDestroyService);\n  protected readonly elementRef = inject<ElementRef<HTMLElement>>(ElementRef);\n  protected readonly directionality = inject(Directionality);\n  protected readonly resizeObserver = inject(NzResizeObserver);\n  protected readonly document = inject(DOCUMENT);\n\n  protected readonly dir = toSignal(this.directionality.change, { initialValue: this.directionality.value });\n\n  /** ------------------- Panels ------------------- */\n  // Get all panels from content children\n  protected readonly panels = contentChildren(NzSplitterPanelComponent);\n  // Subscribe to the change of properties\n  protected readonly panelProps = computed(() =>\n    this.panels().map(panel => ({\n      defaultSize: panel.nzDefaultSize(),\n      size: panel.nzSize(),\n      min: panel.nzMin(),\n      max: panel.nzMax(),\n      resizable: panel.nzResizable(),\n      collapsible: coerceCollapsible(panel.nzCollapsible()),\n      contentTemplate: panel.contentTemplate()\n    }))\n  );\n\n  /** ------------------- Sizes ------------------- */\n  /**\n   * Observe the size of the container.\n   */\n  private readonly containerBox = toSignal(\n    this.resizeObserver.observe(this.elementRef).pipe(\n      map(([item]) => item.target as HTMLElement),\n      map(el => ({ width: el.clientWidth, height: el.clientHeight }))\n    ),\n    {\n      initialValue: {\n        width: this.elementRef.nativeElement.clientWidth || 0,\n        height: this.elementRef.nativeElement.clientHeight || 0\n      }\n    }\n  );\n  /**\n   * The size of the container, used to calculate the percentage size and flex basis of each panel.\n   */\n  protected readonly containerSize = computed(() =>\n    this.nzLayout() === 'horizontal' ? this.containerBox().width : this.containerBox().height\n  );\n  /**\n   * Derived from defaultSize of each panel.\n   * After that it will be updated by the resize event with **real** size in pixels.\n   */\n  protected readonly innerSizes = linkedSignal({\n    source: this.panelProps,\n    computation: source => source.map(panel => panel.defaultSize)\n  });\n  /**\n   * Calculate the size of each panel based on the container size and the percentage size.\n   */\n  protected readonly sizes = computed(() => {\n    let emptyCount = 0;\n    const containerSize = this.containerSize();\n    const innerSizes = this.innerSizes();\n    /**\n     * Get the calculated size, min and max percentage of each panel\n     */\n    const sizes = this.panelProps().map((panel, index) => {\n      const size = panel.size ?? innerSizes[index];\n\n      // Calculate the percentage size of each panel.\n      let percentage: number | undefined;\n      if (isPercent(size)) {\n        percentage = getPercentValue(size);\n      } else if (size || size === 0) {\n        const num = Number(size);\n        if (!isNaN(num)) {\n          percentage = num / containerSize;\n        }\n      } else {\n        percentage = undefined;\n        emptyCount++;\n      }\n\n      // Calculate the min and max percentage size of each panel.\n      const minSize = panel.min;\n      const maxSize = panel.max;\n      const postPercentMinSize = isPercent(minSize) ? getPercentValue(minSize) : (minSize || 0) / containerSize;\n      const postPercentMaxSize = isPercent(maxSize)\n        ? getPercentValue(maxSize)\n        : (maxSize || containerSize) / containerSize;\n\n      return {\n        size,\n        percentage,\n        min: minSize,\n        max: maxSize,\n        postPercentMinSize,\n        postPercentMaxSize\n      } as PanelSize;\n    });\n\n    /**\n     * Normalize the percentage size of each panel if the total percentage is larger than 1 or smaller than 1.\n     */\n    const totalPercentage = sizes.reduce((acc, { percentage }) => acc + (percentage ?? 0), 0);\n\n    for (const size of sizes) {\n      if (totalPercentage > 1 && !emptyCount) {\n        // If total percentage is larger than 1, we will scale it down.\n        const scale = 1 / totalPercentage;\n        size.percentage = size.percentage === undefined ? 0 : size.percentage * scale;\n      } else {\n        // If total percentage is smaller than 1, we will fill the rest.\n        const averagePercentage = (1 - totalPercentage) / emptyCount;\n        size.percentage = size.percentage === undefined ? averagePercentage : size.percentage;\n      }\n\n      size.postPxSize = size.percentage * containerSize;\n      size.size = containerSize ? coerceCssPixelValue(size.postPxSize) : size.size;\n    }\n\n    return sizes;\n  });\n\n  protected readonly ariaInfos = computed(() => {\n    const stackSizes: number[] = [];\n    const ariaInfos: Array<{ ariaNow: number; ariaMin: number; ariaMax: number }> = [];\n    const sizes = this.sizes();\n\n    let stack = 0;\n    for (const size of sizes) {\n      stack += size.percentage;\n      stackSizes.push(stack);\n    }\n\n    for (let i = 0; i < sizes.length - 1; i += 1) {\n      const ariaMinStart = (stackSizes[i - 1] || 0) + sizes[i].postPercentMinSize;\n      const ariaMinEnd = (stackSizes[i + 1] || 100) - sizes[i + 1].postPercentMaxSize;\n\n      const ariaMaxStart = (stackSizes[i - 1] || 0) + sizes[i].postPercentMaxSize;\n      const ariaMaxEnd = (stackSizes[i + 1] || 100) - sizes[i + 1].postPercentMinSize;\n\n      ariaInfos.push({\n        ariaNow: stackSizes[i] * 100,\n        ariaMin: Math.max(ariaMinStart, ariaMinEnd) * 100,\n        ariaMax: Math.min(ariaMaxStart, ariaMaxEnd) * 100\n      });\n    }\n\n    return ariaInfos;\n  });\n\n  private getPxSizes(): number[] {\n    return this.sizes().map(s => s.postPxSize);\n  }\n\n  /** ------------------ Resize ------------------ */\n  /**\n   * The index of the panel that is being resized.\n   * @note Mark the moving splitter bar as activated to show the dragging effect even if the mouse is outside the\n   * splitter container.\n   */\n  protected readonly movingIndex = signal<{ index: number; confirmed: boolean } | null>(null);\n  /**\n   * The offset of preview position (lazy mode) when dragging the splitter bar.\n   * Constrained by the min and max size of the target panel.\n   */\n  protected readonly constrainedOffset = signal<number>(0);\n  /**\n   * The resizable information of each splitter bar.\n   */\n  protected readonly resizableInfos = computed(() => {\n    const items = this.panelProps();\n    const pxSizes = this.getPxSizes();\n\n    const resizeInfos: ResizableInfo[] = [];\n\n    for (let i = 0; i < items.length - 1; i += 1) {\n      const prevItem = items[i];\n      const nextItem = items[i + 1];\n      const prevSize = pxSizes[i];\n      const nextSize = pxSizes[i + 1];\n\n      const { resizable: prevResizable = true, min: prevMin, collapsible: prevCollapsible } = prevItem;\n      const { resizable: nextResizable = true, min: nextMin, collapsible: nextCollapsible } = nextItem;\n\n      const mergedResizable =\n        // Both need to be resizable\n        prevResizable &&\n        nextResizable &&\n        // Prev is not collapsed and limit min size\n        (prevSize !== 0 || !prevMin) &&\n        // Next is not collapsed and limit min size\n        (nextSize !== 0 || !nextMin);\n\n      const startCollapsible =\n        // Self is collapsible\n        (prevCollapsible.end && prevSize > 0) ||\n        // Collapsed and can be collapsed\n        (nextCollapsible.start && nextSize === 0 && prevSize > 0);\n\n      const endCollapsible =\n        // Self is collapsible\n        (nextCollapsible.start && nextSize > 0) ||\n        // Collapsed and can be collapsed\n        (prevCollapsible.end && prevSize === 0 && nextSize > 0);\n\n      resizeInfos[i] = {\n        resizable: mergedResizable,\n        collapsible: {\n          start: !!(this.dir() === 'rtl' ? endCollapsible : startCollapsible),\n          end: !!(this.dir() === 'rtl' ? startCollapsible : endCollapsible)\n        }\n      };\n    }\n\n    return resizeInfos;\n  });\n\n  /**\n   * Handle the resize start event for the specified panel.\n   * @param index The index of the panel.\n   * @param startPos The start position of the resize event.\n   */\n  protected startResize(index: number, startPos: [x: number, y: number]): void {\n    this.movingIndex.set({ index, confirmed: false });\n    this.nzResizeStart.emit(this.getPxSizes());\n    const end$ = new Subject<void>();\n\n    // Updated constraint calculation\n    const getConstrainedOffset = (rawOffset: number): number => {\n      const { percentage, postPercentMinSize, postPercentMaxSize } = this.sizes()[index];\n      const [ariaNow, ariaMin, ariaMax] = [percentage, postPercentMinSize, postPercentMaxSize].map(p => p * 100);\n\n      const containerSize = this.containerSize();\n      const currentPos = (containerSize * ariaNow) / 100;\n      const newPos = currentPos + rawOffset;\n\n      // Calculate available space\n      const minAllowed = Math.max(0, (containerSize * ariaMin) / 100);\n      const maxAllowed = Math.min(containerSize, (containerSize * ariaMax) / 100);\n\n      // Constrain new position within bounds\n      const clampedPos = Math.max(minAllowed, Math.min(maxAllowed, newPos));\n      return clampedPos - currentPos;\n    };\n\n    const handleLazyMove = (offset: number): void => {\n      this.constrainedOffset.set(getConstrainedOffset(offset));\n    };\n\n    const handleLazyEnd = (): void => {\n      this.updateOffset(index, this.constrainedOffset());\n      this.constrainedOffset.set(0);\n    };\n\n    // resizing\n    merge(\n      fromEventOutsideAngular<MouseEvent>(this.document, 'mousemove', passiveEventListenerOptions),\n      fromEventOutsideAngular<TouchEvent>(this.document, 'touchmove', passiveEventListenerOptions)\n    )\n      .pipe(\n        map(event => getEventWithPoint(event)),\n        map(({ pageX, pageY }) => (this.nzLayout() === 'horizontal' ? pageX - startPos[0] : pageY - startPos[1])),\n        // flip the offset if the direction is rtl\n        map(offset => (this.nzLayout() === 'horizontal' && this.dir() === 'rtl' ? -offset : offset)),\n        startWith(0),\n        pairwise(),\n        takeUntil(merge(end$, this.destroy$))\n      )\n      .subscribe(([prev, next]) => {\n        if (this.nzLazy() && next !== 0) {\n          handleLazyMove(next);\n        } else {\n          const deltaOffset = next - prev;\n          // filter out the 0 delta offset\n          if (deltaOffset !== 0) {\n            this.updateOffset(index, deltaOffset);\n          }\n        }\n      });\n\n    // resize end\n    merge(\n      fromEventOutsideAngular<MouseEvent>(this.document, 'mouseup'),\n      fromEventOutsideAngular<TouchEvent>(this.document, 'touchend')\n    )\n      .pipe(takeUntil(merge(end$, this.destroy$)))\n      .subscribe(() => {\n        if (this.nzLazy()) {\n          handleLazyEnd();\n        }\n        this.movingIndex.set(null);\n        this.nzResizeEnd.emit(this.getPxSizes());\n        end$.next();\n      });\n  }\n\n  /**\n   * Update the sizes of specified panels based on the move offset.\n   * @param index The index of the panel.\n   * @param offset The move offset in pixels.\n   */\n  private updateOffset(index: number, offset: number): void {\n    const containerSize = this.containerSize();\n    const limitSizes = this.sizes().map(p => [p.min, p.max]);\n    const pxSizes = this.sizes().map(p => p.percentage * containerSize);\n\n    const getLimitSize = (size: string | number | undefined, defaultLimit: number): number => {\n      if (typeof size === 'string') {\n        return getPercentValue(size) * containerSize;\n      }\n      return size ?? defaultLimit;\n    };\n\n    // First time trigger move index update is not sync in the state\n    let confirmedIndex: number | null = null;\n    const movingIndex = this.movingIndex();\n    // we need to know what the real index is\n    if ((!movingIndex || !movingIndex.confirmed) && offset !== 0) {\n      // search for the real index\n      if (offset > 0) {\n        confirmedIndex = index;\n        this.movingIndex.set({ index, confirmed: true });\n      } else {\n        for (let i = index; i >= 0; i -= 1) {\n          if (pxSizes[i] > 0 && this.resizableInfos()[i].resizable) {\n            confirmedIndex = i;\n            this.movingIndex.set({ index: i, confirmed: true });\n            break;\n          }\n        }\n      }\n    }\n\n    const mergedIndex = confirmedIndex ?? index;\n    const nextIndex = mergedIndex + 1;\n\n    // Get boundary\n    const startMinSize = getLimitSize(limitSizes[mergedIndex][0], 0);\n    const endMinSize = getLimitSize(limitSizes[nextIndex][0], 0);\n    const startMaxSize = getLimitSize(limitSizes[mergedIndex][1], containerSize);\n    const endMaxSize = getLimitSize(limitSizes[nextIndex][1], containerSize);\n\n    let mergedOffset = offset;\n\n    // Align with the boundary\n    if (pxSizes[mergedIndex] + mergedOffset < startMinSize) {\n      mergedOffset = startMinSize - pxSizes[mergedIndex];\n    }\n    if (pxSizes[nextIndex] - mergedOffset < endMinSize) {\n      mergedOffset = pxSizes[nextIndex] - endMinSize;\n    }\n    if (pxSizes[mergedIndex] + mergedOffset > startMaxSize) {\n      mergedOffset = startMaxSize - pxSizes[mergedIndex];\n    }\n    if (pxSizes[nextIndex] - mergedOffset > endMaxSize) {\n      mergedOffset = pxSizes[nextIndex] - endMaxSize;\n    }\n\n    // Do offset\n    pxSizes[mergedIndex] += mergedOffset;\n    pxSizes[nextIndex] -= mergedOffset;\n    this.innerSizes.set(pxSizes);\n    this.nzResize.emit(pxSizes);\n  }\n\n  /** ------------------ Resize ------------------ */\n  /**\n   * Record the original size of the collapsed panel.\n   * Used to restore the size when the panel is expanded back.\n   */\n  private readonly cacheCollapsedSize: number[] = [];\n\n  /**\n   * Collapse the specified panel.\n   * @param index The index of the panel to collapse.\n   * @param type The type of collapse, either `start` or `end`.\n   */\n  protected collapse(index: number, type: 'start' | 'end'): void {\n    const containerSize = this.containerSize();\n    const limitSizes = this.sizes().map(p => [p.min, p.max]);\n    const currentSizes = this.sizes().map(p => p.percentage * containerSize);\n    const adjustedType = this.dir() === 'rtl' ? (type === 'start' ? 'end' : 'start') : type;\n\n    const currentIndex = adjustedType === 'start' ? index : index + 1;\n    const targetIndex = adjustedType == 'start' ? index + 1 : index;\n    const currentSize = currentSizes[currentIndex];\n    const targetSize = currentSizes[targetIndex];\n\n    const getLimitSize = (size: string | number | undefined, defaultLimit: number): number => {\n      if (typeof size === 'string') {\n        return getPercentValue(size) * containerSize;\n      }\n      return size ?? defaultLimit;\n    };\n\n    if (currentSize !== 0 && targetSize !== 0) {\n      // Collapse directly\n      currentSizes[currentIndex] = 0;\n      currentSizes[targetIndex] += currentSize;\n      this.cacheCollapsedSize[index] = currentSize;\n    } else {\n      const totalSize = currentSize + targetSize;\n\n      const currentSizeMin = getLimitSize(limitSizes[currentIndex][0], 0);\n      const currentSizeMax = getLimitSize(limitSizes[currentIndex][1], containerSize);\n      const targetSizeMin = getLimitSize(limitSizes[targetIndex][0], 0);\n      const targetSizeMax = getLimitSize(limitSizes[targetIndex][1], containerSize);\n\n      const limitStart = Math.max(currentSizeMin, totalSize - targetSizeMax);\n      const limitEnd = Math.min(currentSizeMax, totalSize - targetSizeMin);\n      const halfOffset = (limitEnd - limitStart) / 2;\n\n      const targetCacheCollapsedSize = this.cacheCollapsedSize[index];\n      const currentCacheCollapsedSize = totalSize - targetCacheCollapsedSize;\n\n      const shouldUseCache =\n        targetCacheCollapsedSize &&\n        targetCacheCollapsedSize <= targetSizeMax &&\n        targetCacheCollapsedSize >= targetSizeMin &&\n        currentCacheCollapsedSize <= currentSizeMax &&\n        currentCacheCollapsedSize >= currentSizeMin;\n\n      if (shouldUseCache) {\n        currentSizes[targetIndex] = targetCacheCollapsedSize;\n        currentSizes[currentIndex] = currentCacheCollapsedSize;\n      } else {\n        currentSizes[currentIndex] -= halfOffset;\n        currentSizes[targetIndex] += halfOffset;\n      }\n    }\n\n    this.innerSizes.set(currentSizes);\n    this.nzResize.emit(currentSizes);\n    this.nzResizeEnd.emit(currentSizes);\n  }\n}\n"
  },
  {
    "path": "components/splitter/splitter.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzSplitterPanelComponent } from './splitter-panel.component';\nimport { NzSplitterComponent } from './splitter.component';\n\n@NgModule({\n  imports: [NzSplitterComponent, NzSplitterPanelComponent],\n  exports: [NzSplitterComponent, NzSplitterPanelComponent]\n})\nexport class NzSplitterModule {}\n"
  },
  {
    "path": "components/splitter/splitter.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Direction, Directionality } from '@angular/cdk/bidi';\nimport { Component, DebugElement, DOCUMENT, NgZone, signal } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { Subject } from 'rxjs';\n\nimport { dispatchMouseEvent, dispatchTouchEvent, MockNgZone } from 'ng-zorro-antd/core/testing';\n\nimport { NzSplitterModule } from './splitter.module';\nimport { NzSplitterCollapsible } from './typings';\n\ninterface PanelProps {\n  defaultSize?: number | string;\n  min?: number | string;\n  max?: number | string;\n  size?: number | string;\n  resizable?: boolean;\n  collapsible?: NzSplitterCollapsible;\n}\n\n@Component({\n  imports: [BidiModule, NzSplitterModule],\n  template: `\n    <nz-splitter\n      [nzLazy]=\"lazy()\"\n      [nzLayout]=\"vertical() ? 'vertical' : 'horizontal'\"\n      (nzResizeStart)=\"onResizeStart($event)\"\n      (nzResize)=\"onResize($event)\"\n      (nzResizeEnd)=\"onResizeEnd($event)\"\n    >\n      @for (panel of panels(); track $index) {\n        <nz-splitter-panel\n          [nzDefaultSize]=\"panel.defaultSize\"\n          [nzMin]=\"panel.min\"\n          [nzMax]=\"panel.max\"\n          [nzSize]=\"panel.size\"\n          [nzResizable]=\"panel.resizable ?? true\"\n          [nzCollapsible]=\"panel.collapsible ?? false\"\n        >\n          {{ $index }}\n        </nz-splitter-panel>\n      }\n    </nz-splitter>\n  `,\n  styles: `\n    @import '../style/testing.less';\n    @import './style/entry.less';\n\n    :host nz-splitter {\n      height: 100px;\n      width: 100px;\n    }\n  `\n})\nclass NzSplitterTestComponent {\n  readonly vertical = signal(false);\n  readonly lazy = signal(false);\n  readonly panels = signal<PanelProps[]>([{}, {}]);\n  readonly onResizeStart = (_sizes: number[]): void => void 0;\n  readonly onResize = (_sizes: number[]): void => void 0;\n  readonly onResizeEnd = (_sizes: number[]): void => void 0;\n}\n\nclass MockDirectionality {\n  value: Direction = 'rtl';\n  change = new Subject();\n}\n\n/* -------------------------- Test Cases -------------------------- */\ndescribe('nz-splitter', () => {\n  let fixture: ComponentFixture<NzSplitterTestComponent>;\n  let component: NzSplitterTestComponent;\n  let container: DebugElement;\n  let document: Document;\n\n  function getDragger(index: number = 0): HTMLElement {\n    return container.queryAll(By.css('.ant-splitter-bar-dragger'))[index].nativeElement as HTMLElement;\n  }\n\n  function getDraggerPosition(dragger: HTMLElement): { x: number; y: number } {\n    const { left, right, top, bottom } = dragger.getBoundingClientRect();\n    const x = (left + right) / 2;\n    const y = (top + bottom) / 2;\n    return { x, y };\n  }\n\n  function getDraggerAndPos(index: number = 0): { dragger: HTMLElement; x: number; y: number } {\n    const dragger = getDragger(index);\n    return { dragger, ...getDraggerPosition(dragger) };\n  }\n\n  function mouseMoveTrigger(dragger: HTMLElement, from: { x: number; y: number }, to: { x: number; y: number }): void {\n    dispatchMouseEvent(dragger, 'mousedown', from.x, from.y);\n    fixture.detectChanges();\n    dispatchMouseEvent(document, 'mousemove', to.x, to.y);\n    fixture.detectChanges();\n    dispatchMouseEvent(document, 'mouseup', to.x, to.y);\n    fixture.detectChanges();\n  }\n\n  function drag(dragger: HTMLElement, f1: (x: number) => number, f2: (y: number) => number = y => y): void {\n    const { x, y } = getDraggerPosition(dragger);\n    mouseMoveTrigger(dragger, { x, y }, { x: f1(x), y: f2(y) });\n  }\n\n  function getPanelFlexBasis(dl: DebugElement): string {\n    const el = dl.nativeElement as HTMLElement;\n    return el.style.flexBasis;\n  }\n\n  describe('basic', () => {\n    let zone: MockNgZone;\n\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        providers: [\n          {\n            provide: NgZone,\n            useFactory: () => {\n              zone = new MockNgZone();\n              return zone;\n            }\n          }\n        ]\n      });\n      fixture = TestBed.createComponent(NzSplitterTestComponent);\n      document = TestBed.inject(DOCUMENT);\n      container = fixture.debugElement;\n      component = fixture.componentInstance;\n    });\n\n    it('should correct render', () => {\n      fixture.detectChanges();\n      expect(container.query(By.css('.ant-splitter'))).toBeTruthy();\n      expect(container.queryAll(By.css('.ant-splitter-panel'))).toHaveSize(2);\n      expect(container.query(By.css('.ant-splitter-bar'))).toBeTruthy();\n    });\n\n    it('should correct render panel size', async () => {\n      component.panels.set([{ size: 20 }, { size: '45%' }, {}]);\n      await fixture.whenStable();\n\n      const panels = container.queryAll(By.css('.ant-splitter-panel'));\n      expect(getPanelFlexBasis(panels?.[0])).toBe('20px');\n      expect(getPanelFlexBasis(panels?.[1])).toBe('45px');\n      expect(getPanelFlexBasis(panels?.[2])).toBe('35px');\n    });\n\n    it('should layout work', async () => {\n      await fixture.whenStable();\n      expect(container.query(By.css('.ant-splitter.ant-splitter-horizontal'))).toBeTruthy();\n\n      component.vertical.set(true);\n      await fixture.whenStable();\n      expect(container.query(By.css('.ant-splitter.ant-splitter-vertical'))).toBeTruthy();\n    });\n\n    it('should resizable work', async () => {\n      component.panels.set([{ size: 20 }, { resizable: false }, {}]);\n      await fixture.whenStable();\n      expect(container.queryAll(By.css('.ant-splitter-bar-dragger'))).toHaveSize(2);\n      expect(container.queryAll(By.css('.ant-splitter-bar-dragger-disabled'))).toHaveSize(2);\n\n      component.panels.set([{ size: 20 }, {}, { resizable: false }]);\n      await fixture.whenStable();\n      expect(container.queryAll(By.css('.ant-splitter-bar-dragger'))).toHaveSize(2);\n      expect(container.queryAll(By.css('.ant-splitter-bar-dragger-disabled'))).toHaveSize(1);\n    });\n\n    describe('drag', () => {\n      beforeEach(() => {\n        spyOn(component, 'onResizeStart');\n        spyOn(component, 'onResize');\n        spyOn(component, 'onResizeEnd');\n      });\n\n      it('should mouse move work', async () => {\n        component.panels.set([{}, {}]);\n        await fixture.whenStable();\n\n        const { dragger, x, y } = getDraggerAndPos();\n\n        // right\n        dispatchMouseEvent(dragger, 'mousedown', x, y);\n        await fixture.whenStable();\n        expect(dragger.classList).toContain('ant-splitter-bar-dragger-active');\n        expect(component.onResizeStart).toHaveBeenCalledWith([50, 50]);\n\n        dispatchMouseEvent(dragger, 'mousemove', x + 40, y);\n        await fixture.whenStable();\n        expect(component.onResize).toHaveBeenCalledWith([90, 10]);\n        expect(component.onResizeEnd).not.toHaveBeenCalled();\n\n        dispatchMouseEvent(dragger, 'mouseup', x + 40, y);\n        await fixture.whenStable();\n        expect(component.onResizeEnd).toHaveBeenCalledWith([90, 10]);\n\n        // left\n        dispatchMouseEvent(dragger, 'mousedown', x + 40, y);\n        await fixture.whenStable();\n        dispatchMouseEvent(dragger, 'mousemove', x - 240, y);\n        await fixture.whenStable();\n        expect(component.onResize).toHaveBeenCalledWith([0, 100]);\n        dispatchMouseEvent(dragger, 'mouseup');\n        await fixture.whenStable();\n        expect(component.onResizeEnd).toHaveBeenCalledWith([0, 100]);\n      });\n\n      it('should touch move work', async () => {\n        component.panels.set([{}, {}]);\n        await fixture.whenStable();\n\n        const { dragger, x, y } = getDraggerAndPos();\n\n        // right\n        dispatchTouchEvent(dragger, 'touchstart', x, y);\n        await fixture.whenStable();\n        expect(dragger.classList).toContain('ant-splitter-bar-dragger-active');\n        expect(component.onResizeStart).toHaveBeenCalledWith([50, 50]);\n\n        dispatchTouchEvent(document, 'touchmove', x + 40, y);\n        await fixture.whenStable();\n        expect(component.onResize).toHaveBeenCalledWith([90, 10]);\n        expect(component.onResizeEnd).not.toHaveBeenCalled();\n\n        dispatchTouchEvent(document, 'touchend', x + 40, y);\n        await fixture.whenStable();\n        expect(component.onResizeEnd).toHaveBeenCalledWith([90, 10]);\n\n        // left\n        dispatchTouchEvent(dragger, 'touchstart', x + 40, y);\n        await fixture.whenStable();\n\n        dispatchTouchEvent(document, 'touchmove', x - 240, y);\n        await fixture.whenStable();\n        expect(component.onResize).toHaveBeenCalledWith([0, 100]);\n        dispatchTouchEvent(document, 'touchend');\n        await fixture.whenStable();\n        expect(component.onResizeEnd).toHaveBeenCalledWith([0, 100]);\n      });\n\n      it('with min', async () => {\n        component.panels.set([{ min: 10 }, {}]);\n        await fixture.whenStable();\n\n        drag(getDragger(), x => x - 100);\n        expect(component.onResize).toHaveBeenCalledWith([10, 90]);\n        expect(component.onResizeEnd).toHaveBeenCalledWith([10, 90]);\n      });\n\n      it('with max', async () => {\n        component.panels.set([{ max: 90 }, {}]);\n        await fixture.whenStable();\n\n        drag(getDragger(), x => x + 100);\n        expect(component.onResize).toHaveBeenCalledWith([90, 10]);\n        expect(component.onResizeEnd).toHaveBeenCalledWith([90, 10]);\n      });\n\n      it('both panel has min and max', async () => {\n        component.panels.set([\n          { min: 10, max: 80 },\n          { min: 10, max: 80 }\n        ]);\n        await fixture.whenStable();\n\n        drag(getDragger(), x => x - 100);\n        expect(component.onResize).toHaveBeenCalledWith([20, 80]);\n        expect(component.onResizeEnd).toHaveBeenCalledWith([20, 80]);\n\n        drag(getDragger(), x => x + 100);\n        expect(component.onResize).toHaveBeenCalledWith([80, 20]);\n        expect(component.onResizeEnd).toHaveBeenCalledWith([80, 20]);\n      });\n\n      it('[true, 0, true] can be move left', async () => {\n        component.panels.set([{}, { defaultSize: 0 }, {}]);\n        await fixture.whenStable();\n\n        drag(getDragger(1), x => x - 100);\n        expect(component.onResize).toHaveBeenCalledWith([0, 50, 50]);\n        expect(component.onResizeEnd).toHaveBeenCalledWith([0, 50, 50]);\n      });\n\n      it('[false, 0, true] can not be move left', async () => {\n        component.panels.set([{ resizable: false }, { defaultSize: 0 }, {}]);\n        await fixture.whenStable();\n\n        drag(getDragger(1), x => x - 100);\n        expect(component.onResize).toHaveBeenCalledWith([50, 0, 50]);\n        expect(component.onResizeEnd).toHaveBeenCalledWith([50, 0, 50]);\n      });\n    });\n\n    describe('collapsible', () => {\n      function expectClick(button: HTMLElement, sizes: number[]): void {\n        button.click();\n        fixture.detectChanges();\n        expect(component.onResize).toHaveBeenCalledWith(sizes);\n        expect(component.onResizeEnd).toHaveBeenCalledWith(sizes);\n      }\n\n      beforeEach(() => {\n        spyOn(component, 'onResize');\n        spyOn(component, 'onResizeEnd');\n      });\n\n      it('basic', async () => {\n        component.panels.set([{ size: 20, collapsible: true }, { collapsible: true }]);\n        await fixture.whenStable();\n\n        expect(container.queryAll(By.css('.ant-splitter-bar-collapse-icon'))).toHaveSize(2);\n        expect(container.query(By.css('.ant-splitter-bar-collapse-start'))).toBeTruthy();\n        expect(container.query(By.css('.ant-splitter-bar-collapse-end'))).toBeTruthy();\n\n        component.panels.set([\n          {\n            size: 20,\n            collapsible: true\n          },\n          {\n            collapsible: true\n          },\n          {}\n        ]);\n        await fixture.whenStable();\n        expect(container.queryAll(By.css('.ant-splitter-bar-collapse-start'))).toHaveSize(2);\n        expect(container.queryAll(By.css('.ant-splitter-bar-collapse-end'))).toHaveSize(1);\n      });\n\n      it('collapsible - true', async () => {\n        component.panels.set([\n          {\n            size: 20,\n            collapsible: true\n          },\n          {}\n        ]);\n        await fixture.whenStable();\n\n        const startBtn = container.query(By.css('.ant-splitter-bar-collapse-start'))!.nativeElement as HTMLElement;\n        startBtn.click();\n        fixture.detectChanges();\n\n        expect(component.onResize).toHaveBeenCalledWith([0, 100]);\n        expect(component.onResizeEnd).toHaveBeenCalledWith([0, 100]);\n      });\n\n      it('collapsible - start:true', async () => {\n        component.panels.set([\n          {},\n          {\n            size: 20,\n            collapsible: {\n              start: true\n            }\n          },\n          {}\n        ]);\n        await fixture.whenStable();\n\n        expect(container.query(By.css('.ant-splitter-bar-collapse-start'))).toBeFalsy();\n        expect(container.query(By.css('.ant-splitter-bar-collapse-end'))).toBeTruthy();\n\n        const endBtn = container.query(By.css('.ant-splitter-bar-collapse-end'))!.nativeElement as HTMLElement;\n        endBtn.click();\n        await fixture.whenStable();\n\n        expect(component.onResize).toHaveBeenCalledWith([60, 0, 40]);\n        expect(component.onResizeEnd).toHaveBeenCalledWith([60, 0, 40]);\n      });\n\n      it('collapsible - end:true', async () => {\n        component.panels.set([\n          {},\n          {\n            size: 20,\n            collapsible: {\n              end: true\n            }\n          },\n          {}\n        ]);\n        await fixture.whenStable();\n\n        expect(container.query(By.css('.ant-splitter-bar-collapse-start'))).toBeTruthy();\n        expect(container.query(By.css('.ant-splitter-bar-collapse-end'))).toBeFalsy();\n\n        const startBtn = container.query(By.css('.ant-splitter-bar-collapse-start'))!.nativeElement as HTMLElement;\n        startBtn.click();\n        await fixture.whenStable();\n\n        expect(component.onResize).toHaveBeenCalledWith([40, 0, 60]);\n        expect(component.onResizeEnd).toHaveBeenCalledWith([40, 0, 60]);\n      });\n\n      it('both collapsible', async () => {\n        component.panels.set([\n          {\n            collapsible: true\n          },\n          {\n            collapsible: true\n          }\n        ]);\n        await fixture.whenStable();\n\n        const startBtn = container.query(By.css('.ant-splitter-bar-collapse-start'))!.nativeElement as HTMLElement;\n        const endBtn = container.query(By.css('.ant-splitter-bar-collapse-end'))!.nativeElement as HTMLElement;\n\n        expectClick(startBtn, [0, 100]);\n        expectClick(endBtn, [50, 50]);\n        expectClick(endBtn, [100, 0]);\n        expectClick(startBtn, [50, 50]);\n      });\n\n      it('collapsible with cache', async () => {\n        component.panels.set([\n          {\n            defaultSize: 20,\n            collapsible: true,\n            min: 10\n          },\n          {\n            collapsible: true,\n            min: '80%'\n          }\n        ]);\n        await fixture.whenStable();\n\n        const startBtn = container.query(By.css('.ant-splitter-bar-collapse-start'))!.nativeElement as HTMLElement;\n        const endBtn = container.query(By.css('.ant-splitter-bar-collapse-end'))!.nativeElement as HTMLElement;\n\n        // Collapse left\n        expectClick(startBtn, [0, 100]);\n        expect(container.query(By.css('.ant-splitter-bar-dragger-disabled'))).toBeTruthy();\n        // Collapse back\n        expectClick(endBtn, [20, 80]);\n        expect(container.query(By.css('.ant-splitter-bar-dragger-disabled'))).toBeFalsy();\n        // Collapse right\n        expectClick(endBtn, [100, 0]);\n        expect(container.query(By.css('.ant-splitter-bar-dragger-disabled'))).toBeTruthy();\n      });\n\n      it('collapsible with fallback', async () => {\n        component.panels.set([\n          {\n            defaultSize: 10,\n            collapsible: true,\n            min: 15\n          },\n          {\n            collapsible: true,\n            min: '80%'\n          }\n        ]);\n        await fixture.whenStable();\n\n        const startBtn = container.query(By.css('.ant-splitter-bar-collapse-start'))!.nativeElement as HTMLElement;\n        const endBtn = container.query(By.css('.ant-splitter-bar-collapse-end'))!.nativeElement as HTMLElement;\n\n        // Collapse left\n        expectClick(startBtn, [0, 100]);\n        expect(container.query(By.css('.ant-splitter-bar-dragger-disabled'))).toBeTruthy();\n        // Collapse back\n        expectClick(endBtn, [2.5, 97.5]);\n        expect(container.query(By.css('.ant-splitter-bar-dragger-disabled'))).toBeFalsy();\n        // Collapse right\n        expectClick(endBtn, [100, 0]);\n        expect(container.query(By.css('.ant-splitter-bar-dragger-disabled'))).toBeTruthy();\n      });\n    });\n\n    describe('lazy', async () => {\n      beforeEach(() => {\n        component.lazy.set(true);\n        component.panels.set([\n          {\n            defaultSize: '50%',\n            min: '30%',\n            max: '70%'\n          },\n          {\n            defaultSize: '50%',\n            min: '30%',\n            max: '70%'\n          }\n        ]);\n\n        spyOn(component, 'onResizeStart');\n        spyOn(component, 'onResize');\n        spyOn(component, 'onResizeEnd');\n      });\n\n      it('should only update after mouse up', async () => {\n        await fixture.whenStable();\n        const { dragger, x, y } = getDraggerAndPos();\n\n        // right\n        dispatchMouseEvent(dragger, 'mousedown', x, y);\n        await fixture.whenStable();\n        expect(dragger.classList).toContain('ant-splitter-bar-dragger-active');\n        expect(component.onResizeStart).toHaveBeenCalledWith([50, 50]);\n\n        dispatchMouseEvent(document, 'mousemove', x + 100, y);\n        await fixture.whenStable();\n        expect(component.onResize).not.toHaveBeenCalled();\n\n        dispatchMouseEvent(document, 'mouseup', x + 100, y);\n        expect(component.onResize).toHaveBeenCalledWith([70, 30]);\n        expect(component.onResizeEnd).toHaveBeenCalledWith([70, 30]);\n\n        // left\n        dispatchMouseEvent(dragger, 'mousedown', x + 100, y);\n        await fixture.whenStable();\n\n        dispatchMouseEvent(document, 'mousemove', x, y);\n        await fixture.whenStable();\n        expect(component.onResize).toHaveBeenCalledTimes(1);\n\n        dispatchMouseEvent(document, 'mouseup', x, y);\n        expect(component.onResize).toHaveBeenCalledWith([30, 70]);\n        expect(component.onResizeEnd).toHaveBeenCalledWith([30, 70]);\n      });\n\n      it('should work with touch events', async () => {\n        await fixture.whenStable();\n        const { dragger, x, y } = getDraggerAndPos();\n\n        // right\n        dispatchTouchEvent(dragger, 'touchstart', x, y);\n        await fixture.whenStable();\n        expect(dragger.classList).toContain('ant-splitter-bar-dragger-active');\n        expect(component.onResizeStart).toHaveBeenCalledWith([50, 50]);\n\n        dispatchTouchEvent(document, 'touchmove', x + 100, y);\n        await fixture.whenStable();\n        expect(component.onResize).not.toHaveBeenCalled();\n\n        dispatchTouchEvent(document, 'touchend', x + 100, y);\n        expect(component.onResize).toHaveBeenCalledWith([70, 30]);\n        expect(component.onResizeEnd).toHaveBeenCalledWith([70, 30]);\n\n        // left\n        dispatchTouchEvent(dragger, 'touchstart', x + 100, y);\n        await fixture.whenStable();\n\n        dispatchTouchEvent(document, 'touchmove', x, y);\n        await fixture.whenStable();\n        expect(component.onResize).toHaveBeenCalledTimes(1);\n\n        dispatchTouchEvent(document, 'touchend', x, y);\n        expect(component.onResize).toHaveBeenCalledWith([30, 70]);\n        expect(component.onResizeEnd).toHaveBeenCalledWith([30, 70]);\n      });\n\n      it('should work with vertical layout', async () => {\n        component.vertical.set(true);\n        await fixture.whenStable();\n\n        function dragWithMouse(f: (y: number) => number): void {\n          const { dragger, x, y } = getDraggerAndPos();\n          dispatchMouseEvent(dragger, 'mousedown', x, y);\n          dispatchMouseEvent(dragger, 'mousemove', x, f(y));\n          dispatchMouseEvent(dragger, 'mouseup', x, f(y));\n        }\n\n        function dragWithTouch(f: (y: number) => number): void {\n          const { dragger, x, y } = getDraggerAndPos();\n          dispatchTouchEvent(dragger, 'touchstart', x, y);\n          dispatchTouchEvent(document, 'touchmove', x, f(y));\n          dispatchTouchEvent(document, 'touchend', x, f(y));\n        }\n\n        // down\n        dragWithMouse(y => y + 100);\n        expect(component.onResize).toHaveBeenCalledWith([70, 30]);\n\n        // up\n        dragWithMouse(y => y - 100);\n        expect(component.onResize).toHaveBeenCalledWith([30, 70]);\n\n        // touch drag down\n        dragWithTouch(y => y + 100);\n        expect(component.onResize).toHaveBeenCalledWith([70, 30]);\n\n        // touch drag up\n        dragWithTouch(y => y - 100);\n        expect(component.onResize).toHaveBeenCalledWith([30, 70]);\n      });\n    });\n  });\n\n  describe('directionality', () => {\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        providers: [\n          {\n            provide: Directionality,\n            useClass: MockDirectionality\n          }\n        ]\n      });\n      fixture = TestBed.createComponent(NzSplitterTestComponent);\n      container = fixture.debugElement;\n      component = fixture.componentInstance;\n\n      spyOn(component, 'onResize');\n      spyOn(component, 'onResizeEnd');\n    });\n\n    it('rtl', async () => {\n      component.panels.set([{}, {}]);\n      await fixture.whenStable();\n\n      const splitter = container.query(By.css('.ant-splitter'))!.nativeElement as HTMLElement;\n      expect(splitter.classList).toContain('ant-splitter-rtl');\n\n      drag(getDragger(), x => x - 40);\n      expect(component.onResize).toHaveBeenCalledWith([90, 10]);\n      expect(component.onResizeEnd).toHaveBeenCalledWith([90, 10]);\n    });\n  });\n});\n"
  },
  {
    "path": "components/splitter/style/entry.less",
    "content": "@import './index.less';\n@import './patch.less';\n"
  },
  {
    "path": "components/splitter/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@splitter-prefix-cls: ~'@{ant-prefix}-splitter';\n\n.@{splitter-prefix-cls} {\n  .reset-component();\n  display: flex;\n  align-items: stretch;\n\n  box-sizing: border-box;\n  width: 100%;\n  height: 100%;\n  margin: 0;\n  padding: 0;\n  color: @text-color;\n  font-size: @font-size-base;\n  font-family: @font-family;\n  line-height: @line-height-base;\n  list-style: none;\n\n  @half-trigger-size: calc(@splitter-split-trigger-size / 2);\n\n  &-horizontal {\n    flex-direction: row;\n  }\n\n  &-vertical {\n    flex-direction: column;\n  }\n\n  &-panel {\n    box-sizing: border-box;\n    padding: 0 1px;\n    overflow: auto;\n    scrollbar-width: thin;\n\n    &-hidden {\n      padding: 0;\n      overflow: hidden;\n    }\n\n    &:has(.@{splitter-prefix-cls}:only-child) {\n      overflow: hidden;\n    }\n  }\n\n  &-bar {\n    position: relative;\n    flex: none;\n    user-select: none;\n\n    &-preview {\n      position: absolute;\n      z-index: 1;\n      display: none;\n      background: @primary-color;\n      opacity: 0.2;\n      transition: none;\n      pointer-events: none;\n\n      &-active {\n        display: block;\n      }\n    }\n\n    // ======================= Dragger =======================\n    &-dragger {\n      position: absolute;\n      top: 50%;\n      left: 50%;\n      z-index: 1;\n      transform: translate(-50%, -50%);\n\n      // Hover background\n      &::before {\n        position: absolute;\n        top: 50%;\n        left: 50%;\n        background: @splitter-bar-bg;\n        transform: translate(-50%, -50%);\n        content: '';\n      }\n\n      // Hover\n      &:hover:not(&-active) {\n        &::before {\n          background: @splitter-bar-hover-bg;\n        }\n      }\n\n      // Spinner\n      &::after {\n        position: absolute;\n        top: 50%;\n        left: 50%;\n        background: @fill-color;\n        transform: translate(-50%, -50%);\n        content: '';\n      }\n\n      // Active\n      &-active {\n        z-index: 2;\n\n        &::before {\n          background: @splitter-bar-active-bg;\n        }\n      }\n    }\n\n    &:hover &-collapse-bar, &:active &-collapse-bar {\n      opacity: 1;\n    }\n  }\n\n  // Disabled\n  & > &-bar > &-bar-dragger&-bar-dragger-disabled {\n    z-index: 0;\n\n    &, &:hover, &-active {\n      cursor: default;\n\n      &::before {\n        background: @splitter-bar-bg;\n      }\n    }\n\n    &::after {\n      display: none;\n    }\n  }\n\n  // ======================= Collapse =======================\n  &-bar-collapse-bar {\n    position: absolute;\n    top: 50%;\n    left: 50%;\n    z-index: 1000;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    color: @text-color;\n    font-size: @font-size-sm;\n    background: @splitter-bar-bg;\n    border-radius: @border-radius-sm;\n    transform: translate(-50%, -50%);\n    cursor: pointer;\n    opacity: 0;\n\n    &:hover {\n      background: @splitter-bar-hover-bg;\n    }\n\n    &:active {\n      background: @splitter-bar-active-bg;\n    }\n  }\n\n  &-horizontal > &-bar {\n    width: 0;\n  }\n\n  &-horizontal > &-bar &-bar-dragger {\n    width: @splitter-split-trigger-size;\n    height: 100%;\n    cursor: col-resize;\n  }\n\n  &-horizontal > &-bar &-bar-dragger::before {\n    width: @splitter-split-bar-size;\n    height: 100%;\n  }\n\n  &-horizontal > &-bar &-bar-dragger::after {\n    width: @splitter-split-bar-size;\n    height: @splitter-split-bar-draggable-size;\n  }\n\n  &-horizontal > &-bar &-bar-preview {\n    width: @splitter-split-bar-size;\n    height: 100%;\n  }\n\n  &-horizontal > &-bar &-bar-collapse-bar {\n    width: @font-size-sm;\n    height: @splitter-split-bar-collapsible-size;\n  }\n\n  &-horizontal > &-bar &-bar-collapse-bar-start {\n    right: @half-trigger-size;\n    left: auto;\n    transform: translateY(-50%);\n  }\n\n  &-horizontal > &-bar &-bar-collapse-bar-end {\n    right: auto;\n    left: @half-trigger-size;\n    transform: translateY(-50%);\n  }\n\n  &-vertical > &-bar {\n    height: 0;\n  }\n\n  &-vertical > &-bar &-bar-dragger {\n    width: 100%;\n    height: @splitter-split-trigger-size;\n    cursor: row-resize;\n\n    &:has(&-disabled) {\n      cursor: default;\n    }\n  }\n\n  &-vertical > &-bar &-bar-dragger::before {\n    width: 100%;\n    height: @splitter-split-bar-size;\n  }\n\n  &-vertical > &-bar &-bar-dragger::after {\n    width: @splitter-split-bar-draggable-size;\n    height: @splitter-split-bar-size;\n  }\n\n  &-vertical > &-bar &-bar-preview {\n    width: 100%;\n    height: @splitter-split-bar-size;\n  }\n\n  &-vertical > &-bar &-bar-collapse-bar {\n    width: 24px;\n    height: @font-size-sm;\n  }\n\n  &-vertical > &-bar &-bar-collapse-bar-start {\n    top: auto;\n    bottom: @half-trigger-size;\n    transform: translateX(-50%);\n  }\n\n  &-vertical > &-bar &-bar-collapse-bar-end {\n    top: @half-trigger-size;\n    bottom: auto;\n    transform: translateX(-50%);\n  }\n\n  // ======================= Mask =======================\n  // Util dom for handle cursor\n  &-mask {\n    position: fixed;\n    z-index: 1000;\n    inset: 0;\n\n    &-horizontal {\n      cursor: col-resize;\n    }\n\n    &-vertical {\n      cursor: row-resize;\n    }\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/splitter/style/patch.less",
    "content": "nz-splitter {\n  display: block;\n}\n"
  },
  {
    "path": "components/splitter/style/rtl.less",
    "content": ".@{splitter-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &-dot {\n    &-spin {\n      .@{splitter-prefix-cls}-rtl & {\n        transform: rotate(-45deg);\n        animation-name: antRotateRtl;\n      }\n    }\n  }\n}\n\n@keyframes antRotateRtl {\n  to {\n    transform: rotate(-405deg);\n  }\n}\n"
  },
  {
    "path": "components/splitter/typings.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport type NzSplitterLayout = 'horizontal' | 'vertical';\nexport type NzSplitterCollapsible = boolean | NzSplitterCollapseOption;\n\nexport interface NzSplitterCollapseOption {\n  start?: boolean;\n  end?: boolean;\n}\n"
  },
  {
    "path": "components/splitter/utils.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzSplitterCollapseOption, NzSplitterCollapsible } from './typings';\n\n/**\n * Get the percentage value of the string. (e.g. '50%' => 0.5)\n * @param str\n */\nexport function getPercentValue(str: string): number {\n  return Number(str.slice(0, -1)) / 100;\n}\n\n/**\n * Check if the size is percentage.\n * @param size\n */\nexport function isPercent(size: string | number | undefined): size is string {\n  return typeof size === 'string' && size.endsWith('%');\n}\n\n/**\n * Coerce the panel collapsible option to the NzSplitterCollapseOption type.\n */\nexport function coerceCollapsible(collapsible: NzSplitterCollapsible): NzSplitterCollapseOption {\n  if (collapsible && typeof collapsible === 'object') {\n    return collapsible;\n  }\n\n  const mergedCollapsible = !!collapsible;\n  return {\n    start: mergedCollapsible,\n    end: mergedCollapsible\n  };\n}\n"
  },
  {
    "path": "components/statistic/countdown.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, DebugElement, TemplateRef, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { NzStatisticValueType } from 'ng-zorro-antd/statistic/typings';\n\nimport { NzCountdownComponent } from './countdown.component';\nimport { NzStatisticModule } from './statistic.module';\n\ndescribe('nz-countdown', () => {\n  let fixture: ComponentFixture<NzTestCountdownComponent>;\n  let testComponent: NzTestCountdownComponent;\n  let countdownEl: DebugElement;\n\n  describe('basic', () => {\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestCountdownComponent);\n      testComponent = fixture.componentInstance;\n      countdownEl = fixture.debugElement.query(By.directive(NzCountdownComponent));\n    });\n\n    it('should render time', fakeAsync(() => {\n      testComponent.resetTimerWithFormat('HH:mm:ss');\n      fixture.detectChanges();\n      tick(100);\n      fixture.detectChanges();\n      expect(countdownEl.nativeElement.querySelector('.ant-statistic-content-value').innerText).toBe('48:00:29');\n      testComponent.countdown.stopTimer();\n    }));\n\n    it('should stop timer when nzValue is earlier than current', fakeAsync(() => {\n      const beforeTime = new Date().getTime() - 1000 * 1000;\n      const spyOnStop = spyOn(testComponent.countdown, 'stopTimer');\n      testComponent.value = beforeTime;\n\n      fixture.detectChanges();\n      tick(100);\n      fixture.detectChanges();\n      expect(countdownEl.nativeElement.querySelector('.ant-statistic-content-value').innerText).toBe('00:00:00');\n      expect(spyOnStop).toHaveBeenCalledTimes(1);\n    }));\n\n    it('should support template', fakeAsync(() => {\n      testComponent.resetWithTemplate();\n      fixture.detectChanges();\n      tick(100);\n      fixture.detectChanges();\n\n      expect(countdownEl.nativeElement.querySelector('.ant-statistic-content-value').innerText).toBe('172829900');\n      testComponent.countdown.stopTimer();\n    }));\n\n    it('should stop timer and emit event', fakeAsync(() => {\n      testComponent.value = new Date().getTime() + 1000 * 2;\n      fixture.detectChanges();\n      tick(3000);\n      fixture.detectChanges();\n      expect(testComponent.finished).toBe(1);\n    }));\n  });\n});\n\n@Component({\n  imports: [NzStatisticModule],\n  template: `\n    <nz-countdown\n      nzTitle=\"Countdown\"\n      [nzValue]=\"value\"\n      [nzFormat]=\"format\"\n      [nzValueTemplate]=\"template\"\n      (nzCountdownFinish)=\"onFinish()\"\n    />\n    <ng-template #tpl let-diff>\n      {{ diff }}\n    </ng-template>\n  `\n})\nexport class NzTestCountdownComponent {\n  @ViewChild(NzCountdownComponent, { static: true }) countdown!: NzCountdownComponent;\n  @ViewChild('tpl', { static: true }) tpl!: TemplateRef<{ $implicit: NzStatisticValueType }>;\n\n  format!: string;\n  value?: number;\n  template?: TemplateRef<{ $implicit: NzStatisticValueType }>;\n  finished = 0;\n\n  resetTimerWithFormat(format: string): void {\n    this.format = format;\n    this.value = new Date().getTime() + 1000 * 60 * 60 * 24 * 2 + 1000 * 30;\n  }\n\n  resetWithTemplate(): void {\n    this.template = this.tpl;\n    this.value = new Date().getTime() + 1000 * 60 * 60 * 24 * 2 + 1000 * 30;\n  }\n\n  onFinish(): void {\n    this.finished += 1;\n  }\n}\n"
  },
  {
    "path": "components/statistic/countdown.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Platform } from '@angular/cdk/platform';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  EventEmitter,\n  inject,\n  Input,\n  NgZone,\n  OnChanges,\n  OnInit,\n  Output,\n  SimpleChanges,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { NzPipesModule } from 'ng-zorro-antd/core/pipe';\n\nimport { NzStatisticComponent } from './statistic.component';\n\nconst REFRESH_INTERVAL = 1000 / 30;\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-countdown',\n  exportAs: 'nzCountdown',\n  template: `\n    <nz-statistic\n      [nzValue]=\"diff\"\n      [nzValueStyle]=\"nzValueStyle\"\n      [nzValueTemplate]=\"nzValueTemplate || countDownTpl\"\n      [nzTitle]=\"nzTitle\"\n      [nzPrefix]=\"nzPrefix\"\n      [nzSuffix]=\"nzSuffix\"\n    />\n\n    <ng-template #countDownTpl>{{ diff | nzTimeRange: nzFormat }}</ng-template>\n  `,\n  imports: [NzStatisticComponent, NzPipesModule]\n})\nexport class NzCountdownComponent extends NzStatisticComponent implements OnInit, OnChanges {\n  private ngZone = inject(NgZone);\n  private platform = inject(Platform);\n\n  @Input() nzFormat: string = 'HH:mm:ss';\n  @Output() readonly nzCountdownFinish = new EventEmitter<void>();\n\n  diff!: number;\n\n  private target: number = 0;\n  private intervalId: ReturnType<typeof setInterval> | null = null;\n\n  constructor() {\n    super();\n\n    this.destroyRef.onDestroy(() => {\n      this.stopTimer();\n    });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzValue } = changes;\n    if (nzValue) {\n      this.target = Number(nzValue.currentValue);\n      if (!nzValue.isFirstChange()) {\n        this.syncTimer();\n      }\n    }\n  }\n\n  override ngOnInit(): void {\n    super.ngOnInit();\n    this.syncTimer();\n  }\n\n  syncTimer(): void {\n    if (this.target >= Date.now()) {\n      this.startTimer();\n    } else {\n      this.stopTimer();\n    }\n  }\n\n  startTimer(): void {\n    if (this.platform.isBrowser) {\n      this.ngZone.runOutsideAngular(() => {\n        this.stopTimer();\n        this.intervalId = setInterval(() => {\n          this.updateValue();\n          this.cdr.detectChanges();\n        }, REFRESH_INTERVAL);\n      });\n    }\n  }\n\n  stopTimer(): void {\n    if (this.intervalId) {\n      clearInterval(this.intervalId);\n      this.intervalId = null;\n    }\n  }\n\n  /**\n   * Update time that should be displayed on the screen.\n   */\n  protected updateValue(): void {\n    this.diff = Math.max(this.target - Date.now(), 0);\n\n    if (this.diff === 0) {\n      this.stopTimer();\n\n      if (this.nzCountdownFinish.observers.length) {\n        this.ngZone.run(() => this.nzCountdownFinish.emit());\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/statistic/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本用法\n  en-US: Basic Usage\n---\n\n## zh-CN\n\n简单的展示。\n\n## en-US\n\nSimplest Usage.\n"
  },
  {
    "path": "components/statistic/demo/basic.ts",
    "content": "import { DecimalPipe } from '@angular/common';\nimport { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzGridModule } from 'ng-zorro-antd/grid';\nimport { NzStatisticModule } from 'ng-zorro-antd/statistic';\n\n@Component({\n  selector: 'nz-demo-statistic-basic',\n  imports: [DecimalPipe, NzButtonModule, NzGridModule, NzStatisticModule],\n  template: `\n    <nz-row [nzGutter]=\"16\">\n      <nz-col [nzSpan]=\"12\">\n        <nz-statistic [nzValue]=\"(1949101 | number)!\" nzTitle=\"Active Users\" />\n      </nz-col>\n      <nz-col [nzSpan]=\"12\">\n        <nz-statistic [nzValue]=\"(2019.111 | number: '1.0-2')!\" nzTitle=\"Account Balance (CNY)\" />\n        <button nz-button nzType=\"primary\" [style.margin-top.px]=\"16\">Recharge</button>\n      </nz-col>\n      <nz-col [nzSpan]=\"12\">\n        <nz-statistic [nzValue]=\"(112893 | number: '1.0-2')!\" nzTitle=\"Active Users\" nzLoading />\n      </nz-col>\n    </nz-row>\n  `\n})\nexport class NzDemoStatisticBasicComponent {}\n"
  },
  {
    "path": "components/statistic/demo/card.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 在卡片中使用\n  en-US: In Card\n---\n\n## zh-CN\n\n在卡片中展示统计数值。\n\n## en-US\n\nDisplay statistic data in Card.\n"
  },
  {
    "path": "components/statistic/demo/card.ts",
    "content": "import { DecimalPipe } from '@angular/common';\nimport { Component } from '@angular/core';\n\nimport { NzCardModule } from 'ng-zorro-antd/card';\nimport { NzGridModule } from 'ng-zorro-antd/grid';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzStatisticModule } from 'ng-zorro-antd/statistic';\n\n@Component({\n  selector: 'nz-demo-statistic-card',\n  imports: [DecimalPipe, NzCardModule, NzGridModule, NzIconModule, NzStatisticModule],\n  template: `\n    <div style=\"background: #ECECEC; padding: 30px;\">\n      <nz-row [nzGutter]=\"16\">\n        <nz-col [nzSpan]=\"12\">\n          <nz-card>\n            <nz-statistic\n              [nzValue]=\"(11.28 | number: '1.0-2')!\"\n              nzTitle=\"Active\"\n              [nzPrefix]=\"prefixTplOne\"\n              nzSuffix=\"%\"\n              [nzValueStyle]=\"{ color: '#3F8600' }\"\n            />\n            <ng-template #prefixTplOne><nz-icon nzType=\"arrow-up\" /></ng-template>\n          </nz-card>\n        </nz-col>\n        <nz-col [nzSpan]=\"12\">\n          <nz-card>\n            <nz-statistic\n              [nzValue]=\"(9.3 | number: '1.0-2')!\"\n              nzTitle=\"Idle\"\n              [nzPrefix]=\"prefixTplTwo\"\n              nzSuffix=\"%\"\n              [nzValueStyle]=\"{ color: '#CF1322' }\"\n            />\n            <ng-template #prefixTplTwo><nz-icon nzType=\"arrow-down\" /></ng-template>\n          </nz-card>\n        </nz-col>\n      </nz-row>\n    </div>\n  `\n})\nexport class NzDemoStatisticCardComponent {}\n"
  },
  {
    "path": "components/statistic/demo/countdown.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 倒计时\n  en-US: Countdown\n---\n\n## zh-CN\n\n倒计时组件。\n\n## en-US\n\nCountdown component.\n"
  },
  {
    "path": "components/statistic/demo/countdown.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzGridModule } from 'ng-zorro-antd/grid';\nimport { NzStatisticModule } from 'ng-zorro-antd/statistic';\n\n@Component({\n  selector: 'nz-demo-statistic-countdown',\n  imports: [NzGridModule, NzStatisticModule],\n  template: `\n    <nz-row [nzGutter]=\"16\">\n      <nz-col [nzSpan]=\"12\">\n        <nz-countdown [nzValue]=\"deadline\" nzTitle=\"Countdown\" />\n      </nz-col>\n      <nz-col [nzSpan]=\"12\">\n        <nz-countdown [nzValue]=\"deadline\" nzTitle=\"Million Seconds\" nzFormat=\"HH:mm:ss:SSS\" />\n      </nz-col>\n      <nz-col [nzSpan]=\"24\" style=\"margin-top: 32px;\">\n        <nz-countdown [nzValue]=\"deadline\" nzTitle=\"Day Level\" nzFormat=\"D 天 H 时 m 分 s 秒\" />\n      </nz-col>\n    </nz-row>\n  `\n})\nexport class NzDemoStatisticCountdownComponent {\n  deadline = Date.now() + 1000 * 60 * 60 * 24 * 2 + 1000 * 30;\n}\n"
  },
  {
    "path": "components/statistic/demo/unit.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 单位\n  en-US: Unit\n---\n\n## zh-CN\n\n通过前缀和后缀添加单位。\n\n## en-US\n\nAdd unit through `nzPrefix` and `nzSuffix`.\n"
  },
  {
    "path": "components/statistic/demo/unit.ts",
    "content": "import { DecimalPipe } from '@angular/common';\nimport { Component } from '@angular/core';\n\nimport { NzGridModule } from 'ng-zorro-antd/grid';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzStatisticModule } from 'ng-zorro-antd/statistic';\n\n@Component({\n  selector: 'nz-demo-statistic-unit',\n  imports: [DecimalPipe, NzGridModule, NzIconModule, NzStatisticModule],\n  template: `\n    <nz-row [nzGutter]=\"16\">\n      <nz-col [nzSpan]=\"12\">\n        <nz-statistic [nzValue]=\"(1128 | number)!\" nzTitle=\"Feedback\" [nzPrefix]=\"prefixTpl\" />\n        <ng-template #prefixTpl><nz-icon nzType=\"like\" /></ng-template>\n      </nz-col>\n      <nz-col [nzSpan]=\"12\">\n        <nz-statistic [nzValue]=\"93\" nzTitle=\"Unmerged\" nzSuffix=\"/ 100\" />\n      </nz-col>\n    </nz-row>\n  `\n})\nexport class NzDemoStatisticUnitComponent {}\n"
  },
  {
    "path": "components/statistic/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Display\ntitle: Statistic\ncover: 'https://gw.alipayobjects.com/zos/antfincdn/rcBNhLBrKbE/Statistic.svg'\ndescription: Display statistic number.\n---\n\n## When To Use\n\n- When want to highlight some data.\n- When want to display statistic data with description.\n\n## API\n\n### nz-statistic\n\n| Property            | Description                        | Type                                           | Default |\n| ------------------- | ---------------------------------- | ---------------------------------------------- | ------- |\n| `[nzPrefix]`        | Prefix of Value                    | `string \\| TemplateRef<void>`                  | -       |\n| `[nzSuffix]`        | Suffix of Value                    | `string \\| TemplateRef<void>`                  | -       |\n| `[nzTitle]`         | Title                              | `string \\| TemplateRef<void>`                  | -       |\n| `[nzValue]`         | Value                              | `string \\| number`                             | -       |\n| `[nzValueStyle]`    | Value CSS style                    | `Object`                                       | -       |\n| `[nzValueTemplate]` | Custom template to render a number | `TemplateRef<{ $implicit: string \\| number }>` | -       |\n| `[nzLoading]`       | Loading status of Statistic        | `boolean`                                      | `false` |\n\n### nz-countdown\n\n| Property              | Description                      | Type                                 | Default      |\n| --------------------- | -------------------------------- | ------------------------------------ | ------------ |\n| `[nzFormat]`          | Format string                    | `string`                             | `'HH:mm:ss'` |\n| `[nzPrefix]`          | Prefix of Value                  | `string \\| TemplateRef<void>`        | -            |\n| `[nzSuffix]`          | Suffix of Value                  | `string \\| TemplateRef<void>`        | -            |\n| `[nzTitle]`           | Title                            | `string \\| TemplateRef<void>`        | -            |\n| `[nzValue]`           | Target time in timestamp form    | `string \\| number`                   | -            |\n| `[nzValueTemplate]`   | Custom template to render a time | `TemplateRef<{ $implicit: number }>` | -            |\n| `(nzCountdownFinish)` | Emit when countdown finishes     | `void`                               | -            |\n\n### nzFormat\n\n| Token | Description |\n| ----- | ----------- |\n| `Y`   | Year        |\n| `M`   | Month       |\n| `D`   | Date        |\n| `H`   | Hour        |\n| `m`   | Minute      |\n| `s`   | Second      |\n| `S`   | Millisecond |\n"
  },
  {
    "path": "components/statistic/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ntitle: Statistic\nsubtitle: 统计\ntype: 数据展示\ncover: 'https://gw.alipayobjects.com/zos/antfincdn/rcBNhLBrKbE/Statistic.svg'\ndescription: 展示统计数字。\n---\n\n## 何时使用\n\n- 当需要突出某个或某组数字时。\n- 当需要展示带描述的统计类数据时使用。\n\n## API\n\n### nz-statistic\n\n| 参数                | 说明           | 类型                                           | 默认值  |\n| ------------------- | -------------- | ---------------------------------------------- | ------- |\n| `[nzPrefix]`        | 设置数值的前缀 | `string \\| TemplateRef<void>`                  | -       |\n| `[nzSuffix]`        | 设置数值的后缀 | `string \\| TemplateRef<void>`                  | -       |\n| `[nzTitle]`         | 数值的标题     | `string \\| TemplateRef<void>`                  | -       |\n| `[nzValue]`         | 数值内容       | `string \\| number`                             | -       |\n| `[nzValueStyle]`    | 设置数值的样式 | `Object`                                       | -       |\n| `[nzValueTemplate]` | 自定义数值展示 | `TemplateRef<{ $implicit: string \\| number }>` | -       |\n| `[nzLoading]`       | 数值是否加载中 | `boolean`                                      | `false` |\n\n### nz-countdown\n\n| 参数                  | 说明                   | 类型                                 | 默认值       |\n| --------------------- | ---------------------- | ------------------------------------ | ------------ |\n| `[nzFormat]`          | 格式化倒计时展示       | `string`                             | `'HH:mm:ss'` |\n| `[nzPrefix]`          | 设置数值的前缀         | `string \\| TemplateRef<void>`        | -            |\n| `[nzSuffix]`          | 设置数值的后缀         | `string \\| TemplateRef<void>`        | -            |\n| `[nzTitle]`           | 数值的标题             | `string \\| TemplateRef<void>`        | -            |\n| `[nzValue]`           | 时间戳格式的目标时间   | `string \\| number`                   | -            |\n| `[nzValueTemplate]`   | 自定义时间展示         | `TemplateRef<{ $implicit: number }>` | -            |\n| `(nzCountdownFinish)` | 当倒计时完成时发出事件 | `void`                               | -            |\n\n### nzFormat\n\n| 占位符 | 描述 |\n| ------ | ---- |\n| `Y`    | 年   |\n| `M`    | 月   |\n| `D`    | 日   |\n| `H`    | 时   |\n| `m`    | 分   |\n| `s`    | 秒   |\n| `S`    | 毫秒 |\n"
  },
  {
    "path": "components/statistic/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/statistic/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/statistic/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './countdown.component';\nexport * from './statistic-content-value.component';\nexport * from './statistic.component';\nexport * from './statistic.module';\n"
  },
  {
    "path": "components/statistic/statistic-content-value.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { DecimalPipe } from '@angular/common';\nimport { Component, DebugElement, TemplateRef, ViewChild } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { NzStatisticValueType } from 'ng-zorro-antd/statistic/typings';\n\nimport { NzStatisticContentValueComponent } from './statistic-content-value.component';\nimport { NzStatisticModule } from './statistic.module';\n\ndescribe('nz-statistic-content-value', () => {\n  let fixture: ComponentFixture<NzTestNumberComponent>;\n  let testComponent: NzTestNumberComponent;\n  let numberEl: DebugElement;\n\n  describe('basic', () => {\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestNumberComponent);\n      testComponent = fixture.componentInstance;\n      numberEl = fixture.debugElement.query(By.directive(NzStatisticContentValueComponent));\n    });\n\n    it('should have correct class', () => {\n      fixture.detectChanges();\n      expect(numberEl.nativeElement.classList.contains('ant-statistic-content-value')).toBeTruthy();\n    });\n\n    it('should render number', () => {\n      // Int with group separator, decimal.\n      testComponent.value = 12345.012;\n      fixture.detectChanges();\n      expect(numberEl.nativeElement.querySelector('.ant-statistic-content-value-int').innerText).toBe('12,345');\n      expect(numberEl.nativeElement.querySelector('.ant-statistic-content-value-decimal').innerText).toBe('.012');\n    });\n\n    it('should support template', () => {\n      testComponent.template = testComponent.tpl;\n      testComponent.value = 12345.012;\n      fixture.detectChanges();\n      expect(numberEl.nativeElement.querySelector('.ant-statistic-content-value-int')).toBeFalsy();\n      expect(numberEl.nativeElement.querySelector('.ant-statistic-content-value-decimal')).toBeFalsy();\n      expect(numberEl.nativeElement.innerText).toBe(\"It's 12,345.012\");\n    });\n  });\n});\n\n@Component({\n  imports: [DecimalPipe, NzStatisticModule],\n  template: `\n    <nz-statistic-content-value [nzValue]=\"(value | number)!\" [nzValueTemplate]=\"template\" />\n    <ng-template #tpl let-value>It's {{ value }}</ng-template>\n  `\n})\nexport class NzTestNumberComponent {\n  @ViewChild('tpl', { static: true }) tpl?: TemplateRef<{ $implicit: NzStatisticValueType }>;\n\n  value = 1;\n  template?: TemplateRef<{ $implicit: NzStatisticValueType }>;\n}\n"
  },
  {
    "path": "components/statistic/statistic-content-value.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { getLocaleNumberSymbol, NgTemplateOutlet, NumberSymbol } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  inject,\n  Input,\n  LOCALE_ID,\n  OnChanges,\n  TemplateRef,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { NzStatisticValueType } from './typings';\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-statistic-content-value',\n  exportAs: 'nzStatisticContentValue',\n  template: `\n    @if (nzValueTemplate) {\n      <ng-container [ngTemplateOutlet]=\"nzValueTemplate\" [ngTemplateOutletContext]=\"{ $implicit: nzValue }\" />\n    } @else {\n      @if (displayInt) {\n        <span class=\"ant-statistic-content-value-int\">{{ displayInt }}</span>\n      }\n      @if (displayDecimal) {\n        <span class=\"ant-statistic-content-value-decimal\">{{ displayDecimal }}</span>\n      }\n    }\n  `,\n  imports: [NgTemplateOutlet],\n  host: {\n    class: 'ant-statistic-content-value'\n  }\n})\nexport class NzStatisticContentValueComponent implements OnChanges {\n  @Input() nzValue?: NzStatisticValueType;\n  @Input() nzValueTemplate?: TemplateRef<{ $implicit: NzStatisticValueType }>;\n\n  displayInt = '';\n  displayDecimal = '';\n\n  private locale_id = inject(LOCALE_ID);\n\n  ngOnChanges(): void {\n    this.formatNumber();\n  }\n\n  private formatNumber(): void {\n    const decimalSeparator: string =\n      typeof this.nzValue === 'number' ? '.' : getLocaleNumberSymbol(this.locale_id, NumberSymbol.Decimal);\n    const value = String(this.nzValue);\n    const [int, decimal] = value.split(decimalSeparator);\n\n    this.displayInt = int;\n    this.displayDecimal = decimal ? `${decimalSeparator}${decimal}` : '';\n  }\n}\n"
  },
  {
    "path": "components/statistic/statistic.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport { Component, DebugElement, provideZoneChangeDetection, ViewChild } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzStatisticComponent } from './statistic.component';\nimport { NzStatisticModule } from './statistic.module';\n\ndescribe('statistic', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideZoneChangeDetection()]\n    });\n  });\n\n  describe('basic', () => {\n    let fixture: ComponentFixture<NzTestStatisticComponent>;\n    let testComponent: NzTestStatisticComponent;\n    let statisticEl: DebugElement;\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestStatisticComponent);\n      testComponent = fixture.componentInstance;\n      statisticEl = fixture.debugElement.query(By.directive(NzStatisticComponent));\n    });\n\n    it('should render title, prefix and suffix', () => {\n      fixture.detectChanges();\n      expect(statisticEl.nativeElement.querySelector('.ant-statistic-title').innerText).toBe('title');\n      expect(statisticEl.nativeElement.querySelector('.ant-statistic-content-prefix')).toBeFalsy();\n      expect(statisticEl.nativeElement.querySelector('.ant-statistic-content-suffix')).toBeFalsy();\n\n      testComponent.prefix = 'prefix';\n      testComponent.suffix = 'suffix';\n      fixture.detectChanges();\n      expect(statisticEl.nativeElement.querySelector('.ant-statistic-content-prefix').innerText).toBe('prefix');\n      expect(statisticEl.nativeElement.querySelector('.ant-statistic-content-suffix').innerText).toBe('suffix');\n    });\n\n    it('should render skeleton', () => {\n      expect(statisticEl.nativeElement.querySelector('.ant-statistic-skeleton')).toBeFalsy();\n      testComponent.loading = true;\n      fixture.detectChanges();\n      expect(statisticEl.nativeElement.querySelector('.ant-statistic-skeleton')).toBeTruthy();\n    });\n  });\n\n  describe('RTL', () => {\n    let fixture: ComponentFixture<NzTestStatisticRtlComponent>;\n    let statisticEl: DebugElement;\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestStatisticRtlComponent);\n      statisticEl = fixture.debugElement.query(By.directive(NzStatisticComponent));\n    });\n\n    it('should className correct on dir change', () => {\n      fixture.detectChanges();\n      expect(statisticEl.nativeElement.classList).toContain('ant-statistic-rtl');\n\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n      expect(statisticEl.nativeElement.classList).not.toContain('ant-statistic-rtl');\n    });\n  });\n});\n\n@Component({\n  imports: [NzStatisticModule],\n  template: `\n    <nz-statistic [nzValue]=\"123.45\" [nzTitle]=\"title\" [nzSuffix]=\"suffix\" [nzPrefix]=\"prefix\" [nzLoading]=\"loading\" />\n  `\n})\nexport class NzTestStatisticComponent {\n  title = 'title';\n  prefix = '';\n  suffix = '';\n  loading = false;\n}\n\n@Component({\n  imports: [BidiModule, NzStatisticModule],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-statistic [nzValue]=\"123.45\" nzTitle=\"test title\" />\n    </div>\n  `\n})\nexport class NzTestStatisticRtlComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n}\n"
  },
  {
    "path": "components/statistic/statistic.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DestroyRef,\n  Input,\n  OnInit,\n  TemplateRef,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NgStyleInterface } from 'ng-zorro-antd/core/types';\nimport { NzSkeletonModule } from 'ng-zorro-antd/skeleton';\n\nimport { NzStatisticContentValueComponent } from './statistic-content-value.component';\nimport { NzStatisticValueType } from './typings';\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-statistic',\n  exportAs: 'nzStatistic',\n  template: `\n    <div class=\"ant-statistic-title\">\n      <ng-container *nzStringTemplateOutlet=\"nzTitle\">{{ nzTitle }}</ng-container>\n    </div>\n    @if (nzLoading) {\n      <nz-skeleton class=\"ant-statistic-skeleton\" [nzParagraph]=\"false\" />\n    } @else {\n      <div class=\"ant-statistic-content\" [style]=\"nzValueStyle\">\n        @if (nzPrefix) {\n          <span class=\"ant-statistic-content-prefix\">\n            <ng-container *nzStringTemplateOutlet=\"nzPrefix\">{{ nzPrefix }}</ng-container>\n          </span>\n        }\n        <nz-statistic-content-value [nzValue]=\"nzValue\" [nzValueTemplate]=\"nzValueTemplate\" />\n        @if (nzSuffix) {\n          <span class=\"ant-statistic-content-suffix\">\n            <ng-container *nzStringTemplateOutlet=\"nzSuffix\">{{ nzSuffix }}</ng-container>\n          </span>\n        }\n      </div>\n    }\n  `,\n  host: {\n    class: 'ant-statistic',\n    '[class.ant-statistic-rtl]': `dir === 'rtl'`\n  },\n  imports: [NzSkeletonModule, NzStatisticContentValueComponent, NzOutletModule]\n})\nexport class NzStatisticComponent implements OnInit {\n  @Input() nzPrefix?: string | TemplateRef<void>;\n  @Input() nzSuffix?: string | TemplateRef<void>;\n  @Input() nzTitle?: string | TemplateRef<void>;\n  @Input() nzValue?: NzStatisticValueType;\n  @Input() nzValueStyle: NgStyleInterface = {};\n  @Input() nzValueTemplate?: TemplateRef<{ $implicit: NzStatisticValueType }>;\n  @Input({ transform: booleanAttribute }) nzLoading: boolean = false;\n  dir: Direction = 'ltr';\n\n  protected cdr = inject(ChangeDetectorRef);\n  protected destroyRef = inject(DestroyRef);\n  private directionality = inject(Directionality);\n\n  ngOnInit(): void {\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n      this.dir = direction;\n      this.cdr.detectChanges();\n    });\n\n    this.dir = this.directionality.value;\n  }\n}\n"
  },
  {
    "path": "components/statistic/statistic.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzCountdownComponent } from './countdown.component';\nimport { NzStatisticContentValueComponent } from './statistic-content-value.component';\nimport { NzStatisticComponent } from './statistic.component';\n\n@NgModule({\n  imports: [NzStatisticComponent, NzCountdownComponent, NzStatisticContentValueComponent],\n  exports: [NzStatisticComponent, NzCountdownComponent, NzStatisticContentValueComponent]\n})\nexport class NzStatisticModule {}\n"
  },
  {
    "path": "components/statistic/style/entry.less",
    "content": "@import './index.less';\n"
  },
  {
    "path": "components/statistic/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@statistic-prefix-cls: ~'@{ant-prefix}-statistic';\n\n.@{statistic-prefix-cls} {\n  .reset-component();\n\n  &-title {\n    margin-bottom: @margin-xss;\n    color: @text-color-secondary;\n    font-size: @statistic-title-font-size;\n  }\n\n  &-skeleton {\n    padding-top: @padding-md;\n  }\n\n  &-content {\n    color: @heading-color;\n    font-size: @statistic-content-font-size;\n    font-family: @statistic-font-family;\n\n    &-value {\n      display: inline-block;\n      direction: ltr;\n    }\n\n    &-prefix,\n    &-suffix {\n      display: inline-block;\n    }\n\n    &-prefix {\n      margin-right: 4px;\n    }\n\n    &-suffix {\n      margin-left: 4px;\n    }\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/statistic/style/rtl.less",
    "content": ".@{statistic-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &-content {\n    &-prefix {\n      .@{statistic-prefix-cls}-rtl & {\n        margin-right: 0;\n        margin-left: 4px;\n      }\n    }\n\n    &-suffix {\n      .@{statistic-prefix-cls}-rtl & {\n        margin-right: 4px;\n        margin-left: 0;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/statistic/typings.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport type NzStatisticValueType = number | string;\n"
  },
  {
    "path": "components/steps/demo/clickable.md",
    "content": "---\norder: 10\ntitle:\n  zh-CN: 可点击\n  en-US: Clickable\n---\n\n## zh-CN\n\n订阅 `(nzIndexChange)` 后，Steps 变为可点击状态。\n\n## en-US\n\nsubscribe `(nzIndexChange)` makes Steps clickable.\n"
  },
  {
    "path": "components/steps/demo/clickable.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\nimport { NzStepsModule } from 'ng-zorro-antd/steps';\n\n@Component({\n  selector: 'nz-demo-steps-clickable',\n  imports: [NzDividerModule, NzStepsModule],\n  template: `\n    <nz-steps [nzCurrent]=\"index\" (nzIndexChange)=\"onIndexChange($event)\">\n      <nz-step nzTitle=\"Finished\" [nzDisabled]=\"disable\" nzDescription=\"This is a description.\" />\n      <nz-step nzTitle=\"In Progress\" nzDescription=\"This is a description.\" />\n      <nz-step nzTitle=\"Waiting\" nzDescription=\"This is a description.\" />\n    </nz-steps>\n    <nz-divider />\n    <nz-steps nzDirection=\"vertical\" [nzCurrent]=\"index\" (nzIndexChange)=\"onIndexChange($event)\">\n      <nz-step nzTitle=\"Finished\" nzDescription=\"This is a description.\" />\n      <nz-step nzTitle=\"In Progress\" nzDescription=\"This is a description.\" />\n      <nz-step nzTitle=\"Waiting\" nzDescription=\"This is a description.\" />\n    </nz-steps>\n  `\n})\nexport class NzDemoStepsClickableComponent {\n  index = 0;\n  disable = false;\n  onIndexChange(index: number): void {\n    this.index = index;\n  }\n}\n"
  },
  {
    "path": "components/steps/demo/customized-progress-dot.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 自定义点状步骤条\n  en-US: Customized Dot Style\n---\n\n## zh-CN\n\n为点状步骤条增加自定义展示。\n\n## en-US\n\nYou can customize the display for Steps with progress dot style.\n"
  },
  {
    "path": "components/steps/demo/customized-progress-dot.ts",
    "content": "import { NgTemplateOutlet } from '@angular/common';\nimport { Component } from '@angular/core';\n\nimport { NzPopoverModule } from 'ng-zorro-antd/popover';\nimport { NzStepsModule } from 'ng-zorro-antd/steps';\n\n@Component({\n  selector: 'nz-demo-steps-customized-progress-dot',\n  imports: [NgTemplateOutlet, NzStepsModule, NzPopoverModule],\n  template: `\n    <nz-steps [nzCurrent]=\"1\" [nzProgressDot]=\"progressTemplate\">\n      <nz-step nzTitle=\"Finished\" nzDescription=\"You can hover on the dot.\" />\n      <nz-step nzTitle=\"In Progress\" nzDescription=\"You can hover on the dot.\" />\n      <nz-step nzTitle=\"Waiting\" nzDescription=\"You can hover on the dot.\" />\n      <nz-step nzTitle=\"Waiting\" nzDescription=\"You can hover on the dot.\" />\n    </nz-steps>\n    <ng-template #progressTemplate let-dot let-status=\"status\" let-index=\"index\">\n      <span nz-popover nzPopoverContent=\"steps {{ index }} status: {{ status }}\" style=\"margin-left: -100%;\">\n        <ng-template [ngTemplateOutlet]=\"dot\" />\n      </span>\n    </ng-template>\n  `\n})\nexport class NzDemoStepsCustomizedProgressDotComponent {}\n"
  },
  {
    "path": "components/steps/demo/error.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 步骤运行错误\n  en-US: Error status\n---\n\n## zh-CN\n\n使用 `nz-steps` 的 `nzStatus` 属性来指定当前步骤的状态。\n\n## en-US\n\nBy using `nzStatus` of `nz-steps`, you can specify the state for current step.\n"
  },
  {
    "path": "components/steps/demo/error.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzStepsModule } from 'ng-zorro-antd/steps';\n\n@Component({\n  selector: 'nz-demo-steps-error',\n  imports: [NzStepsModule],\n  template: `\n    <nz-steps [nzCurrent]=\"1\" nzStatus=\"error\">\n      <nz-step nzTitle=\"Finished\" nzDescription=\"This is a description.\" />\n      <nz-step nzTitle=\"In Progress\" nzDescription=\"This is a description.\" />\n      <nz-step nzTitle=\"Waiting\" nzDescription=\"This is a description.\" />\n    </nz-steps>\n  `\n})\nexport class NzDemoStepsErrorComponent {}\n"
  },
  {
    "path": "components/steps/demo/icon.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 带图标的步骤条\n  en-US: With icon\n---\n\n## zh-CN\n\n通过设置 `nz-step` 的 `nzIcon` 属性，可以启用自定义图标。\n\n## en-US\n\nYou can use your own custom icons by setting the property `nzIcon` for `nz-step`. Old API is still compatible but we strongly suggest the new API.\n"
  },
  {
    "path": "components/steps/demo/icon.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzStepsModule } from 'ng-zorro-antd/steps';\n\n@Component({\n  selector: 'nz-demo-steps-icon',\n  imports: [NzIconModule, NzStepsModule],\n  template: `\n    <nz-steps>\n      <nz-step nzTitle=\"Login\" nzStatus=\"finish\" nzIcon=\"user\" />\n      <nz-step nzTitle=\"Verification\" nzStatus=\"finish\" nzIcon=\"solution\" />\n      <nz-step nzTitle=\"Pay\" nzStatus=\"process\" nzIcon=\"loading\" />\n      <nz-step nzTitle=\"Done\" nzStatus=\"wait\" [nzIcon]=\"iconTemplate\" />\n      <ng-template #iconTemplate><nz-icon nzType=\"smile\" /></ng-template>\n    </nz-steps>\n  `\n})\nexport class NzDemoStepsIconComponent {}\n"
  },
  {
    "path": "components/steps/demo/nav.md",
    "content": "---\norder: 11\ntitle:\n  zh-CN: 导航步骤\n  en-US: Navigation Steps\n---\n\n## zh-CN\n\n导航类型的步骤条。\n\n## en-US\n\nNavigation steps.\n"
  },
  {
    "path": "components/steps/demo/nav.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzStepsModule } from 'ng-zorro-antd/steps';\n\n@Component({\n  selector: 'nz-demo-steps-nav',\n  imports: [NzStepsModule],\n  template: `\n    <nz-steps nzType=\"navigation\" nzSize=\"small\" [nzCurrent]=\"index\" (nzIndexChange)=\"onIndexChange($event)\">\n      <nz-step nzTitle=\"Step 1\" nzSubtitle=\"00:00:05\" nzStatus=\"finish\" nzDescription=\"This is a description.\" />\n      <nz-step nzTitle=\"Step 2\" nzSubtitle=\"00:01:02\" nzStatus=\"process\" nzDescription=\"This is a description.\" />\n      <nz-step\n        nzTitle=\"Step 3\"\n        nzSubtitle=\"waiting for long long time\"\n        nzStatus=\"wait\"\n        nzDescription=\"This is a description.\"\n      />\n    </nz-steps>\n    <nz-steps nzType=\"navigation\" [nzCurrent]=\"index\" (nzIndexChange)=\"onIndexChange($event)\">\n      <nz-step nzTitle=\"Step 1\" nzStatus=\"finish\" />\n      <nz-step nzTitle=\"Step 2\" nzStatus=\"process\" />\n      <nz-step nzTitle=\"Step 3\" nzStatus=\"wait\" />\n      <nz-step nzTitle=\"Step 4\" nzStatus=\"wait\" />\n    </nz-steps>\n    <nz-steps nzType=\"navigation\" nzSize=\"small\" [nzCurrent]=\"index\" (nzIndexChange)=\"onIndexChange($event)\">\n      <nz-step nzTitle=\"finish 1\" nzStatus=\"finish\" />\n      <nz-step nzTitle=\"finish 2\" nzStatus=\"finish\" />\n      <nz-step nzTitle=\"current process\" nzStatus=\"process\" />\n      <nz-step nzTitle=\"wait\" nzStatus=\"wait\" nzDisabled />\n    </nz-steps>\n  `,\n  styles: `\n    nz-steps {\n      margin-bottom: 60px;\n      box-shadow: rgb(232, 232, 232) 0 -1px 0 0 inset;\n    }\n  `\n})\nexport class NzDemoStepsNavComponent {\n  index = 0;\n\n  onIndexChange(event: number): void {\n    this.index = event;\n  }\n}\n"
  },
  {
    "path": "components/steps/demo/progress-dot.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 点状步骤条\n  en-US: Dot Style\n---\n\n## zh-CN\n\n包含步骤点的进度条。\n\n## en-US\n\nSteps with progress dot style.\n"
  },
  {
    "path": "components/steps/demo/progress-dot.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\nimport { NzStepsModule } from 'ng-zorro-antd/steps';\n\n@Component({\n  selector: 'nz-demo-steps-progress-dot',\n  imports: [NzDividerModule, NzStepsModule],\n  template: `\n    <nz-steps [nzCurrent]=\"1\" nzProgressDot>\n      <nz-step nzTitle=\"Finished\" nzDescription=\"This is a description.\" />\n      <nz-step nzTitle=\"In Progress\" nzDescription=\"This is a description.\" />\n      <nz-step nzTitle=\"Waiting\" nzDescription=\"This is a description.\" />\n    </nz-steps>\n    <nz-divider />\n    <nz-steps [nzCurrent]=\"1\" nzProgressDot nzDirection=\"vertical\">\n      <nz-step nzTitle=\"Finished\" nzDescription=\"This is a description. This is a description.\" />\n      <nz-step nzTitle=\"Finished\" nzDescription=\"This is a description. This is a description.\" />\n      <nz-step nzTitle=\"In Progress\" nzDescription=\"This is a description. This is a description.\" />\n      <nz-step nzTitle=\"Waiting\" nzDescription=\"This is a description.\" />\n      <nz-step nzTitle=\"Waiting\" nzDescription=\"This is a description.\" />\n    </nz-steps>\n  `\n})\nexport class NzDemoStepsProgressDotComponent {}\n"
  },
  {
    "path": "components/steps/demo/progress.md",
    "content": "---\norder: 12\ntitle:\n  zh-CN: 带有进度的步骤\n  en-US: Steps with progress\n---\n\n## zh-CN\n\n异步执行的步骤带有圆形进度条。\n\n## en-US\n\nAsynchronous steps with circular progress bar.\n"
  },
  {
    "path": "components/steps/demo/progress.ts",
    "content": "import { Component } from '@angular/core';\nimport { merge, Observable, timer } from 'rxjs';\nimport { delay, finalize, map, scan } from 'rxjs/operators';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzStepsModule } from 'ng-zorro-antd/steps';\n\ninterface SyncStep {\n  id: number;\n  title: string;\n  description: string;\n  async: false;\n  percentage: null;\n}\n\ninterface AsyncStep {\n  id: number;\n  title: string;\n  description: string;\n  async: true;\n  percentage: number;\n}\n\ntype Step = SyncStep | AsyncStep;\n\nfunction mockAsyncStep(): Observable<number> {\n  const subStep1 = timer(600).pipe(map(() => 25));\n  const subStep2 = subStep1.pipe(delay(600));\n  const subStep3 = subStep2.pipe(delay(600));\n  const subStep4 = subStep3.pipe(delay(600));\n  return merge(subStep1, subStep2, subStep3, subStep4).pipe(scan((a, b) => a + b));\n}\n\n@Component({\n  selector: 'nz-demo-steps-progress',\n  imports: [NzButtonModule, NzStepsModule],\n  template: `\n    <nz-steps [nzCurrent]=\"current\">\n      @for (step of this.steps; track step.id) {\n        <nz-step\n          [nzTitle]=\"step.title\"\n          [nzDescription]=\"step.description\"\n          [nzPercentage]=\"step.async ? step.percentage : null\"\n        />\n      }\n    </nz-steps>\n    <div class=\"steps-action\">\n      @if (current > 0) {\n        <button nz-button nzType=\"default\" (click)=\"pre()\">\n          <span>Previous</span>\n        </button>\n      }\n      @if (current < 2) {\n        <button nz-button nzType=\"default\" (click)=\"next()\" [nzLoading]=\"processing\">\n          <span>Next</span>\n        </button>\n      }\n      @if (current === 2) {\n        <button nz-button nzType=\"primary\" (click)=\"done()\" [nzLoading]=\"processing\">\n          <span>Done</span>\n        </button>\n      }\n    </div>\n  `,\n  styles: `\n    .steps-action {\n      margin-top: 36px;\n    }\n\n    button {\n      margin-right: 8px;\n    }\n  `\n})\nexport class NzDemoStepsProgressComponent {\n  steps: Step[] = [\n    {\n      id: 1,\n      title: `Step 1`,\n      description: `This step is synchronous.`,\n      async: false,\n      percentage: null\n    },\n    {\n      id: 2,\n      title: `Step 2`,\n      description: `This step is asynchronous.`,\n      async: true,\n      percentage: 0\n    },\n    {\n      id: 3,\n      title: `Step 3`,\n      description: `This step is asynchronous.`,\n      async: true,\n      percentage: 0\n    }\n  ];\n  current = 0;\n  processing = false;\n\n  pre(): void {\n    this.current -= 1;\n  }\n\n  next(): void {\n    this.loadingAndStep();\n  }\n\n  done(): void {\n    this.loadingAndStep();\n    console.log('done');\n  }\n\n  loadingAndStep(): void {\n    if (this.current < this.steps.length) {\n      const step = this.steps[this.current];\n      if (step.async) {\n        this.processing = true;\n        mockAsyncStep()\n          .pipe(\n            finalize(() => {\n              step.percentage = 0;\n              this.processing = false;\n              this.current += 1;\n            })\n          )\n          .subscribe(p => {\n            step.percentage = p;\n          });\n      } else {\n        this.current += 1;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/steps/demo/simple.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本用法\n  en-US: Basic\n---\n\n## zh-CN\n\n简单的步骤条。\n\n## en-US\n\nThe most basic step bar.\n"
  },
  {
    "path": "components/steps/demo/simple.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzStepsModule } from 'ng-zorro-antd/steps';\n\n@Component({\n  selector: 'nz-demo-steps-simple',\n  imports: [NzStepsModule],\n  template: `\n    <nz-steps [nzCurrent]=\"1\">\n      <nz-step nzTitle=\"Finished\" nzDescription=\"This is a description.\" />\n      <nz-step nzTitle=\"In Progress\" nzSubtitle=\"Left 00:00:08\" nzDescription=\"This is a description.\" />\n      <nz-step nzTitle=\"Waiting\" nzDescription=\"This is a description.\" />\n    </nz-steps>\n  `\n})\nexport class NzDemoStepsSimpleComponent {}\n"
  },
  {
    "path": "components/steps/demo/small-size.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 迷你版\n  en-US: Mini version\n---\n\n## zh-CN\n\n迷你版的步骤条，通过设置 `<nz-steps nzSize=\"small\">` 启用.\n\n## en-US\n\nBy setting like this: `<nz-steps nzSize=\"small\">`, you can get a mini version.\n"
  },
  {
    "path": "components/steps/demo/small-size.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzStepsModule } from 'ng-zorro-antd/steps';\n\n@Component({\n  selector: 'nz-demo-steps-small-size',\n  imports: [NzStepsModule],\n  template: `\n    <nz-steps [nzCurrent]=\"current\" nzSize=\"small\">\n      <nz-step nzTitle=\"Finished\" />\n      <nz-step nzTitle=\"In Progress\" />\n      <nz-step nzTitle=\"Waiting\" />\n    </nz-steps>\n  `\n})\nexport class NzDemoStepsSmallSizeComponent {\n  current = 1;\n}\n"
  },
  {
    "path": "components/steps/demo/start-index.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 起始序号\n  en-US: Starting Index\n---\n\n## zh-CN\n\n通过 `nzStartIndex` 来设置步骤条的起始序号. 请注意 `nzCurrent` 也应该有对应的偏移.\n\n## en-US\n\nBy setting `nzStartIndex` to change starting index of a step component. Be sure to add an offset to `nzCurrent` as well.\n"
  },
  {
    "path": "components/steps/demo/start-index.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzStepsModule } from 'ng-zorro-antd/steps';\n\n@Component({\n  selector: 'nz-demo-steps-start-index',\n  imports: [NzStepsModule],\n  template: `\n    <nz-steps [nzCurrent]=\"current\" [nzStartIndex]=\"3\" nzSize=\"small\">\n      <nz-step nzTitle=\"Finished\" />\n      <nz-step nzTitle=\"In Progress\" />\n      <nz-step nzTitle=\"Waiting\" />\n    </nz-steps>\n  `\n})\nexport class NzDemoStepsStartIndexComponent {\n  current = 3;\n}\n"
  },
  {
    "path": "components/steps/demo/step-next.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 步骤切换\n  en-US: Switch Step\n---\n\n## zh-CN\n\n通常配合内容及按钮使用，表示一个流程的处理进度。\n\n## en-US\n\nCooperate with the content and buttons, to represent the progress of a process.\n"
  },
  {
    "path": "components/steps/demo/step-next.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzStepsModule } from 'ng-zorro-antd/steps';\n\n@Component({\n  selector: 'nz-demo-steps-step-next',\n  imports: [NzButtonModule, NzStepsModule],\n  template: `\n    <nz-steps [nzCurrent]=\"current\">\n      <nz-step nzTitle=\"Finished\" />\n      <nz-step nzTitle=\"In Progress\" />\n      <nz-step nzTitle=\"Waiting\" />\n    </nz-steps>\n\n    <div class=\"steps-content\">{{ index }}</div>\n    <div class=\"steps-action\">\n      @if (current > 0) {\n        <button nz-button nzType=\"default\" (click)=\"pre()\">\n          <span>Previous</span>\n        </button>\n      }\n      @if (current < 2) {\n        <button nz-button nzType=\"default\" (click)=\"next()\">\n          <span>Next</span>\n        </button>\n      }\n      @if (current === 2) {\n        <button nz-button nzType=\"primary\" (click)=\"done()\">\n          <span>Done</span>\n        </button>\n      }\n    </div>\n  `,\n  styles: `\n    .steps-content {\n      margin-top: 16px;\n      border: 1px dashed #e9e9e9;\n      border-radius: 6px;\n      background-color: #fafafa;\n      min-height: 200px;\n      text-align: center;\n      padding-top: 80px;\n    }\n\n    .steps-action {\n      margin-top: 24px;\n    }\n\n    button {\n      margin-right: 8px;\n    }\n  `\n})\nexport class NzDemoStepsStepNextComponent {\n  current = 0;\n\n  index = 'First-content';\n\n  pre(): void {\n    this.current -= 1;\n    this.changeContent();\n  }\n\n  next(): void {\n    this.current += 1;\n    this.changeContent();\n  }\n\n  done(): void {\n    console.log('done');\n  }\n\n  changeContent(): void {\n    switch (this.current) {\n      case 0: {\n        this.index = 'First-content';\n        break;\n      }\n      case 1: {\n        this.index = 'Second-content';\n        break;\n      }\n      case 2: {\n        this.index = 'third-content';\n        break;\n      }\n      default: {\n        this.index = 'error';\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/steps/demo/vertical-small.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 竖直方向的小型步骤条\n  en-US: Vertical mini version\n---\n\n## zh-CN\n\n简单的竖直方向的小型步骤条。\n\n## en-US\n\nA simple mini version step bar in the vertical direction.\n"
  },
  {
    "path": "components/steps/demo/vertical-small.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzStepsModule } from 'ng-zorro-antd/steps';\n\n@Component({\n  selector: 'nz-demo-steps-vertical-small',\n  imports: [NzStepsModule],\n  template: `\n    <nz-steps [nzCurrent]=\"1\" nzDirection=\"vertical\" nzSize=\"small\">\n      <nz-step nzTitle=\"Finished\" nzDescription=\"This is a description.\" />\n      <nz-step nzTitle=\"In Progress\" nzDescription=\"This is a description.\" />\n      <nz-step nzTitle=\"Waiting\" nzDescription=\"This is a description.\" />\n    </nz-steps>\n  `\n})\nexport class NzDemoStepsVerticalSmallComponent {}\n"
  },
  {
    "path": "components/steps/demo/vertical.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 竖直方向的步骤条\n  en-US: Vertical\n---\n\n## zh-CN\n\n简单的竖直方向的步骤条。\n\n## en-US\n\nA simple step bar in the vertical direction.\n"
  },
  {
    "path": "components/steps/demo/vertical.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzStepsModule } from 'ng-zorro-antd/steps';\n\n@Component({\n  selector: 'nz-demo-steps-vertical',\n  imports: [NzStepsModule],\n  template: `\n    <nz-steps [nzCurrent]=\"1\" nzDirection=\"vertical\">\n      <nz-step nzTitle=\"Finished\" nzDescription=\"This is a description.\" />\n      <nz-step nzTitle=\"In Progress\" nzDescription=\"This is a description.\" />\n      <nz-step nzTitle=\"Waiting\" nzDescription=\"This is a description.\" />\n    </nz-steps>\n  `\n})\nexport class NzDemoStepsVerticalComponent {}\n"
  },
  {
    "path": "components/steps/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Navigation\ncols: 1\ntitle: Steps\ncover: 'https://gw.alipayobjects.com/zos/antfincdn/UZYqMizXHaj/Steps.svg'\ndescription: A navigation bar that guides users through the steps of a task.\n---\n\n## When To Use\n\nWhen a given task is complicated or has a certain sequence in the series of subtasks, we can decompose it into several steps to make things easier.\n\n## API\n\n```html\n<nz-steps>\n  <nz-step nzTitle=\"first step\"></nz-step>\n  <nz-step nzTitle=\"second step\"></nz-step>\n  <nz-step nzTitle=\"third step\"></nz-step>\n</nz-steps>\n```\n\n### nz-steps\n\nThe whole of the step bar.\n\n| Property             | Description                                                                                                         | Type                                                                                      | Default        |\n| -------------------- | ------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | -------------- |\n| `[nzType]`           | type of steps, can be set to one of the following values: `default`, `navigation`                                   | `'default' \\| 'navigation'`                                                               | `'default'`    |\n| `[nzCurrent]`        | To set the current step, counting from 0. You can overwrite this state by using `nzStatus` of `nz-step`             | `number`                                                                                  | `0`            |\n| `[nzDirection]`      | To specify the direction of the step bar, `horizontal` and `vertical` are currently supported                       | `'vertical' \\| 'horizontal'`                                                              | `'horizontal'` |\n| `[nzLabelPlacement]` | Support vertical title and description                                                                              | `'vertical' \\| 'horizontal'`                                                              | `'horizontal'` |\n| `[nzProgressDot]`    | Steps with progress dot style, customize the progress dot by setting it with TemplateRef                            | `boolean \\| TemplateRef<{ $implicit: TemplateRef<void>, status: string, index: number }>` | `false`        |\n| `[nzSize]`           | To specify the size of the step bar, `default` and `small` are currently supported                                  | `'small' \\| 'default'`                                                                    | `'default'`    |\n| `[nzStatus]`         | To specify the status of current step, can be set to one of the following values: `wait` `process` `finish` `error` | `'wait' \\| 'process' \\| 'finish' \\| 'error'`                                              | `'process'`    |\n| `[nzStartIndex]`     | To specify the starting number                                                                                      | `number`                                                                                  | `0`            |\n| `(nzIndexChange)`    | Trigger event when step click                                                                                       | `number`                                                                                  | -              |\n\n### nz-step\n\nA single step in the step bar.\n\n| Property          | Description                                                                                                                                                | Type                                                                                    | Default  |\n| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | -------- |\n| `[nzDescription]` | description of the step, optional property                                                                                                                 | `string \\| TemplateRef<void>`                                                           | -        |\n| `[nzIcon]`        | icon of the step, optional property                                                                                                                        | `string \\| string[] \\| Set<string> \\| { [klass: string]: any; }` \\| `TemplateRef<void>` | -        |\n| `[nzStatus]`      | to specify the status. It will be automatically set by `nzCurrent` of `nz-steps` if not configured. Optional values are: `wait` `process` `finish` `error` | `'wait' \\| 'process' \\| 'finish' \\| 'error'`                                            | `'wait'` |\n| `[nzTitle]`       | title of the step                                                                                                                                          | `string \\| TemplateRef<void>`                                                           | -        |\n| `[nzSubtitle]`    | subTitle of the step                                                                                                                                       | `string \\| TemplateRef<void>`                                                           | -        |\n| `[nzDisabled]`    | disable click                                                                                                                                              | `boolean`                                                                               | `false`  |\n| `[nzPercentage]`  | Progress percentage of the step in `process` status (only works on basic Steps)                                                                            | `number`                                                                                | -        |\n"
  },
  {
    "path": "components/steps/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 步骤条\ntype: 导航\ncols: 1\ntitle: Steps\ncover: 'https://gw.alipayobjects.com/zos/antfincdn/UZYqMizXHaj/Steps.svg'\ndescription: 引导用户按照流程完成任务的导航条。\n---\n\n## 何时使用\n\n当任务复杂或者存在先后关系时，将其分解成一系列步骤，从而简化任务。\n\n## API\n\n```html\n<nz-steps>\n  <nz-step nzTitle=\"第一步\"></nz-step>\n  <nz-step nzTitle=\"第二步\"></nz-step>\n  <nz-step nzTitle=\"第三步\"></nz-step>\n</nz-steps>\n```\n\n### nz-steps\n\n整体步骤条。\n\n| 参数                 | 说明                                                                                 | 类型                                                                                      | 默认值         |\n| -------------------- | ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------- | -------------- |\n| `[nzType]`           | 步骤条类型，有 `default` 和 `navigation` 两种                                        | `'default' \\| 'navigation'`                                                               | `'default'`    |\n| `[nzCurrent]`        | 指定当前步骤，从 0 开始记数。在子 `nz-step` 元素中，可以通过 `nzStatus` 属性覆盖状态 | `number`                                                                                  | `0`            |\n| `[nzDirection]`      | 指定步骤条方向。目前支持水平（`horizontal`）和竖直（`vertical`）两种方向             | `'vertical' \\| 'horizontal'`                                                              | `'horizontal'` |\n| `[nzLabelPlacement]` | 指定标签放置位置，默认水平放图标右侧，可选 `vertical` 放图标下方                     | `'vertical' \\| 'horizontal'`                                                              | `'horizontal'` |\n| `[nzProgressDot]`    | 点状步骤条，可以设置为一个 TemplateRef                                               | `boolean \\| TemplateRef<{ $implicit: TemplateRef<void>, status: string, index: number }>` | `false`        |\n| `[nzSize]`           | 指定大小，目前支持普通（`default`）和迷你（`small`）                                 | `'small' \\| 'default'`                                                                    | `'default'`    |\n| `[nzStatus]`         | 指定当前步骤的状态，可选 `wait` `process` `finish` `error`                           | `'wait' \\| 'process' \\| 'finish' \\| 'error'`                                              | `'process'`    |\n| `[nzStartIndex]`     | 指定起始位置的序号                                                                   | `number`                                                                                  | `0`            |\n| `(nzIndexChange)`    | 点击单个步骤时触发的事件                                                             | `number`                                                                                  | -              |\n\n### nz-step\n\n步骤条内的每一个步骤。\n\n| 参数              | 说明                                                                                                                 | 类型                                                                                    | 默认值   |\n| ----------------- | -------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | -------- |\n| `[nzDescription]` | 步骤的详情描述，可选                                                                                                 | `string \\| TemplateRef<void>`                                                           | -        |\n| `[nzIcon]`        | 步骤图标的类型，可选                                                                                                 | `string \\| string[] \\| Set<string> \\| { [klass: string]: any; }` \\| `TemplateRef<void>` | -        |\n| `[nzStatus]`      | 指定状态。当不配置该属性时，会使用 `nz-steps` 的 `nzCurrent` 来自动指定状态。可选：`wait` `process` `finish` `error` | `'wait' \\| 'process' \\| 'finish' \\| 'error'`                                            | `'wait'` |\n| `[nzTitle]`       | 标题                                                                                                                 | `string \\| TemplateRef<void>`                                                           | -        |\n| `[nzSubtitle]`    | 子标题                                                                                                               | `string \\| TemplateRef<void>`                                                           | -        |\n| `[nzDisabled]`    | 禁用点击                                                                                                             | `boolean`                                                                               | `false`  |\n| `[nzPercentage]`  | 当前状态为 `process` 的步骤所显示的进度条进度（只对基本类型的 `nz-steps` 生效）                                      | `number`                                                                                | -        |\n"
  },
  {
    "path": "components/steps/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/steps/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/steps/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './steps.component';\nexport * from './step.component';\nexport * from './steps.module';\n"
  },
  {
    "path": "components/steps/step.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ElementRef,\n  Input,\n  OnInit,\n  TemplateRef,\n  ViewChild,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject,\n  DestroyRef\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Subject } from 'rxjs';\nimport { filter } from 'rxjs/operators';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NgClassType, NzSizeDSType } from 'ng-zorro-antd/core/types';\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzProgressFormatter, NzProgressModule } from 'ng-zorro-antd/progress';\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-step',\n  exportAs: 'nzStep',\n  template: `\n    <div\n      #itemContainer\n      class=\"ant-steps-item-container\"\n      [attr.role]=\"clickable && !nzDisabled ? 'button' : null\"\n      [tabindex]=\"clickable && !nzDisabled ? 0 : null\"\n    >\n      @if (!last) {\n        <div class=\"ant-steps-item-tail\"></div>\n      }\n      <div class=\"ant-steps-item-icon\">\n        @if (!showProcessDot) {\n          @if (showProgress) {\n            <div class=\"ant-steps-progress-icon\">\n              <nz-progress\n                [nzPercent]=\"nzPercentage\"\n                nzType=\"circle\"\n                [nzWidth]=\"nzSize === 'small' ? 32 : 40\"\n                [nzFormat]=\"nullProcessFormat\"\n                [nzStrokeWidth]=\"4\"\n              />\n            </div>\n          }\n          @if (nzStatus === 'finish' && !nzIcon) {\n            <span class=\"ant-steps-icon\"><nz-icon nzType=\"check\" /></span>\n          }\n          @if (nzStatus === 'error') {\n            <span class=\"ant-steps-icon\"><nz-icon nzType=\"close\" /></span>\n          }\n          @if ((nzStatus === 'process' || nzStatus === 'wait') && !nzIcon) {\n            <span class=\"ant-steps-icon\">\n              {{ index + 1 }}\n            </span>\n          }\n          @if (nzIcon) {\n            <span class=\"ant-steps-icon\">\n              <ng-container *nzStringTemplateOutlet=\"nzIcon; let icon\">\n                <nz-icon [nzType]=\"icon\" />\n              </ng-container>\n            </span>\n          }\n        }\n        @if (showProcessDot) {\n          <span class=\"ant-steps-icon\">\n            <ng-template #processDotTemplate>\n              <span class=\"ant-steps-icon-dot\"></span>\n            </ng-template>\n            <ng-template\n              [ngTemplateOutlet]=\"customProcessTemplate || processDotTemplate\"\n              [ngTemplateOutletContext]=\"{\n                $implicit: processDotTemplate,\n                status: nzStatus,\n                index: index\n              }\"\n            />\n          </span>\n        }\n      </div>\n      <div class=\"ant-steps-item-content\">\n        <div class=\"ant-steps-item-title\">\n          <ng-container *nzStringTemplateOutlet=\"nzTitle\">{{ nzTitle }}</ng-container>\n          @if (nzSubtitle) {\n            <div class=\"ant-steps-item-subtitle\">\n              <ng-container *nzStringTemplateOutlet=\"nzSubtitle\">{{ nzSubtitle }}</ng-container>\n            </div>\n          }\n        </div>\n        <div class=\"ant-steps-item-description\">\n          <ng-container *nzStringTemplateOutlet=\"nzDescription\">{{ nzDescription }}</ng-container>\n        </div>\n      </div>\n    </div>\n  `,\n  host: {\n    class: 'ant-steps-item',\n    '[class.ant-steps-item-wait]': 'nzStatus === \"wait\"',\n    '[class.ant-steps-item-process]': 'nzStatus === \"process\"',\n    '[class.ant-steps-item-finish]': 'nzStatus === \"finish\"',\n    '[class.ant-steps-item-error]': 'nzStatus === \"error\"',\n    '[class.ant-steps-item-active]': 'currentIndex === index',\n    '[class.ant-steps-item-disabled]': 'nzDisabled',\n    '[class.ant-steps-item-custom]': '!!nzIcon',\n    '[class.ant-steps-next-error]': '(outStatus === \"error\") && (currentIndex === index + 1)'\n  },\n  imports: [NzProgressModule, NzIconModule, NzOutletModule, NgTemplateOutlet]\n})\nexport class NzStepComponent implements OnInit {\n  private cdr = inject(ChangeDetectorRef);\n  private destroyRef = inject(DestroyRef);\n\n  @ViewChild('processDotTemplate', { static: false }) processDotTemplate?: TemplateRef<void>;\n  @ViewChild('itemContainer', { static: true }) itemContainer!: ElementRef<HTMLElement>;\n\n  @Input() nzTitle?: string | TemplateRef<void>;\n  @Input() nzSubtitle?: string | TemplateRef<void>;\n  @Input() nzDescription?: string | TemplateRef<void>;\n  @Input({ transform: booleanAttribute }) nzDisabled = false;\n  @Input() nzPercentage: number | null = null;\n  @Input() nzSize: NzSizeDSType = 'default';\n\n  @Input()\n  get nzStatus(): string {\n    return this._status;\n  }\n\n  set nzStatus(status: string) {\n    this._status = status;\n    this.isCustomStatus = true;\n  }\n\n  isCustomStatus = false;\n  private _status = 'wait';\n\n  @Input()\n  get nzIcon(): NgClassType | TemplateRef<void> | undefined {\n    return this._icon;\n  }\n\n  set nzIcon(value: NgClassType | TemplateRef<void> | undefined) {\n    if (!(value instanceof TemplateRef)) {\n      this.oldAPIIcon = typeof value === 'string' && value.indexOf('anticon') > -1;\n    }\n    this._icon = value;\n  }\n\n  oldAPIIcon = true;\n  private _icon?: NgClassType | TemplateRef<void>;\n\n  customProcessTemplate?: TemplateRef<{ $implicit: TemplateRef<void>; status: string; index: number }>; // Set by parent.\n  direction = 'horizontal';\n  index = 0;\n  last = false;\n  outStatus = 'process';\n  showProcessDot = false;\n  clickable = false;\n\n  clickOutsideAngular$ = new Subject<number>();\n\n  readonly nullProcessFormat: NzProgressFormatter = () => null;\n\n  get showProgress(): boolean {\n    return (\n      this.nzPercentage !== null &&\n      !this.nzIcon &&\n      this.nzStatus === 'process' &&\n      this.nzPercentage >= 0 &&\n      this.nzPercentage <= 100\n    );\n  }\n\n  get currentIndex(): number {\n    return this._currentIndex;\n  }\n\n  set currentIndex(current: number) {\n    this._currentIndex = current;\n    if (!this.isCustomStatus) {\n      this._status = current > this.index ? 'finish' : current === this.index ? this.outStatus || '' : 'wait';\n    }\n  }\n\n  private _currentIndex = 0;\n\n  ngOnInit(): void {\n    fromEventOutsideAngular(this.itemContainer.nativeElement, 'click')\n      .pipe(\n        filter(() => this.clickable && this.currentIndex !== this.index && !this.nzDisabled),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(() => {\n        this.clickOutsideAngular$.next(this.index);\n      });\n  }\n\n  enable(): void {\n    this.nzDisabled = false;\n    this.cdr.markForCheck();\n  }\n\n  disable(): void {\n    this.nzDisabled = true;\n    this.cdr.markForCheck();\n  }\n\n  markForCheck(): void {\n    this.cdr.markForCheck();\n  }\n}\n"
  },
  {
    "path": "components/steps/steps.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport {\n  AfterContentInit,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ContentChildren,\n  DestroyRef,\n  EventEmitter,\n  inject,\n  Input,\n  NgZone,\n  OnChanges,\n  OnInit,\n  Output,\n  QueryList,\n  SimpleChanges,\n  TemplateRef,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Subscription, merge } from 'rxjs';\nimport { startWith } from 'rxjs/operators';\n\nimport { BooleanInput, NzSizeDSType } from 'ng-zorro-antd/core/types';\nimport { toBoolean } from 'ng-zorro-antd/core/util';\n\nimport { NzStepComponent } from './step.component';\n\nexport type NzDirectionType = 'horizontal' | 'vertical';\nexport type NzStatusType = 'wait' | 'process' | 'finish' | 'error';\nexport type NzProgressDotTemplate = TemplateRef<{ $implicit: TemplateRef<void>; status: string; index: number }>;\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-steps',\n  exportAs: 'nzSteps',\n  template: `<ng-content />`,\n  host: {\n    class: 'ant-steps',\n    '[class.ant-steps-horizontal]': `nzDirection === 'horizontal'`,\n    '[class.ant-steps-vertical]': `nzDirection === 'vertical'`,\n    '[class.ant-steps-label-horizontal]': `nzDirection === 'horizontal'`,\n    '[class.ant-steps-label-vertical]': `(showProcessDot || nzLabelPlacement === 'vertical') && nzDirection === 'horizontal'`,\n    '[class.ant-steps-dot]': 'showProcessDot',\n    '[class.ant-steps-small]': `nzSize === 'small'`,\n    '[class.ant-steps-navigation]': `nzType === 'navigation'`,\n    '[class.ant-steps-rtl]': `dir === 'rtl'`,\n    '[class.ant-steps-with-progress]': 'showProgress'\n  }\n})\nexport class NzStepsComponent implements OnChanges, OnInit, AfterContentInit {\n  static ngAcceptInputType_nzProgressDot: BooleanInput | NzProgressDotTemplate | undefined | null;\n\n  private cdr = inject(ChangeDetectorRef);\n  private ngZone = inject(NgZone);\n  private directionality = inject(Directionality);\n  private destroyRef = inject(DestroyRef);\n\n  @ContentChildren(NzStepComponent) steps!: QueryList<NzStepComponent>;\n\n  @Input() nzCurrent = 0;\n  @Input() nzDirection: NzDirectionType = 'horizontal';\n  @Input() nzLabelPlacement: 'horizontal' | 'vertical' = 'horizontal';\n  @Input() nzType: 'default' | 'navigation' = 'default';\n  @Input() nzSize: NzSizeDSType = 'default';\n  @Input() nzStartIndex = 0;\n  @Input() nzStatus: NzStatusType = 'process';\n\n  @Input()\n  set nzProgressDot(value: boolean | NzProgressDotTemplate | undefined | null) {\n    if (value instanceof TemplateRef) {\n      this.showProcessDot = true;\n      this.customProcessDotTemplate = value;\n    } else {\n      this.showProcessDot = toBoolean(value);\n    }\n    this.updateChildrenSteps();\n  }\n\n  @Output() readonly nzIndexChange = new EventEmitter<number>();\n\n  private indexChangeSubscription = Subscription.EMPTY;\n\n  showProcessDot = false;\n  showProgress = false;\n  customProcessDotTemplate?: TemplateRef<{ $implicit: TemplateRef<void>; status: string; index: number }>;\n  dir: Direction = 'ltr';\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzStartIndex, nzDirection, nzStatus, nzCurrent, nzSize } = changes;\n    if (nzStartIndex || nzDirection || nzStatus || nzCurrent || nzSize) {\n      this.updateChildrenSteps();\n    }\n  }\n\n  ngOnInit(): void {\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n      this.dir = direction;\n      this.cdr.detectChanges();\n    });\n\n    this.dir = this.directionality.value;\n    this.updateChildrenSteps();\n  }\n\n  ngAfterContentInit(): void {\n    if (this.steps) {\n      this.steps.changes.pipe(startWith(null), takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n        this.updateHostProgressClass();\n        this.updateChildrenSteps();\n      });\n    }\n  }\n\n  private updateHostProgressClass(): void {\n    if (this.steps && !this.showProcessDot) {\n      this.showProgress = !!this.steps.toArray().find(step => step.nzPercentage !== null);\n    }\n  }\n\n  private updateChildrenSteps(): void {\n    if (this.steps) {\n      const length = this.steps.length;\n      this.steps.toArray().forEach((step, index) => {\n        Promise.resolve().then(() => {\n          step.nzSize = this.nzSize;\n          step.outStatus = this.nzStatus;\n          step.showProcessDot = this.showProcessDot;\n          if (this.customProcessDotTemplate) {\n            step.customProcessTemplate = this.customProcessDotTemplate;\n          }\n          step.clickable = this.nzIndexChange.observers.length > 0;\n          step.direction = this.nzDirection;\n          step.index = index + this.nzStartIndex;\n          step.currentIndex = this.nzCurrent;\n          step.last = length === index + 1;\n          step.markForCheck();\n        });\n      });\n      this.indexChangeSubscription.unsubscribe();\n      this.indexChangeSubscription = merge(...this.steps.map(step => step.clickOutsideAngular$))\n        .pipe(takeUntilDestroyed(this.destroyRef))\n        .subscribe(index => {\n          if (this.nzIndexChange.observers.length) {\n            this.ngZone.run(() => this.nzIndexChange.emit(index));\n          }\n        });\n    }\n  }\n}\n"
  },
  {
    "path": "components/steps/steps.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzStepComponent } from './step.component';\nimport { NzStepsComponent } from './steps.component';\n\n@NgModule({\n  imports: [NzStepsComponent, NzStepComponent],\n  exports: [NzStepsComponent, NzStepComponent]\n})\nexport class NzStepsModule {}\n"
  },
  {
    "path": "components/steps/steps.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DebugElement,\n  OnInit,\n  provideZoneChangeDetection,\n  TemplateRef,\n  ViewChild\n} from '@angular/core';\nimport { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { BooleanInput, NzDirectionVHType, NzSizeDSType } from 'ng-zorro-antd/core/types';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzDemoStepsClickableComponent } from './demo/clickable';\nimport { NzDemoStepsNavComponent } from './demo/nav';\nimport { NzStepComponent } from './step.component';\nimport { NzProgressDotTemplate, NzStatusType, NzStepsComponent } from './steps.component';\nimport { NzStepsModule } from './steps.module';\n\ndescribe('steps', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideZoneChangeDetection()]\n    });\n  });\n\n  describe('outer steps', () => {\n    let fixture: ComponentFixture<NzTestOuterStepsComponent>;\n    let testComponent: NzTestOuterStepsComponent;\n    let outStep: DebugElement;\n    let innerSteps: DebugElement[];\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestOuterStepsComponent);\n      testComponent = fixture.componentInstance;\n      outStep = fixture.debugElement.query(By.directive(NzStepsComponent));\n      innerSteps = fixture.debugElement.queryAll(By.directive(NzStepComponent));\n    });\n\n    it('should init className correct', fakeAsync(() => {\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(outStep.nativeElement.className).toBe('ant-steps ant-steps-horizontal ant-steps-label-horizontal');\n      expect(innerSteps[0].nativeElement.className).toBe('ant-steps-item ant-steps-item-active ant-steps-item-process');\n      expect(innerSteps[1].nativeElement.className).toBe('ant-steps-item ant-steps-item-wait');\n      expect(innerSteps[2].nativeElement.className).toBe('ant-steps-item ant-steps-item-wait');\n    }));\n\n    it('should current change correct', fakeAsync(() => {\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      testComponent.current = 1;\n      testComponent.cdr.markForCheck();\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(innerSteps[0].nativeElement.className).toBe('ant-steps-item ant-steps-item-finish');\n      expect(innerSteps[1].nativeElement.className).toBe('ant-steps-item ant-steps-item-process ant-steps-item-active');\n      expect(innerSteps[2].nativeElement.className).toBe('ant-steps-item ant-steps-item-wait');\n    }));\n\n    it('should tail display correct', fakeAsync(() => {\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(innerSteps[0].nativeElement.querySelector('.ant-steps-item-tail')).toBeTruthy();\n      expect(innerSteps[1].nativeElement.querySelector('.ant-steps-item-tail')).toBeTruthy();\n      expect(innerSteps[2].nativeElement.querySelector('.ant-steps-item-tail')).toBeFalsy();\n    }));\n\n    it('should title correct', () => {\n      fixture.detectChanges();\n      expect(innerSteps[0].nativeElement.querySelector('.ant-steps-item-title').innerText.trim()).toBe('0title');\n      expect(innerSteps[1].nativeElement.querySelector('.ant-steps-item-title').innerText.trim()).toBe('1title');\n      expect(innerSteps[2].nativeElement.querySelector('.ant-steps-item-title').innerText.trim()).toBe('2title');\n    });\n\n    it('should subtitle correct', () => {\n      testComponent.subtitle = '0subtitle';\n      fixture.detectChanges();\n      expect(innerSteps[0].nativeElement.querySelector('.ant-steps-item-subtitle').innerText.trim()).toBe('0subtitle');\n      expect(innerSteps[1].nativeElement.querySelector('.ant-steps-item-subtitle')).toBeFalsy();\n      expect(innerSteps[2].nativeElement.querySelector('.ant-steps-item-subtitle')).toBeFalsy();\n      testComponent.subtitle = undefined;\n      fixture.detectChanges();\n    });\n\n    it('should description correct', () => {\n      fixture.detectChanges();\n      expect(innerSteps[0].nativeElement.querySelector('.ant-steps-item-description').innerText.trim()).toBe(\n        '0description'\n      );\n      expect(innerSteps[1].nativeElement.querySelector('.ant-steps-item-description').innerText.trim()).toBe(\n        '1description'\n      );\n      expect(innerSteps[2].nativeElement.querySelector('.ant-steps-item-description').innerText.trim()).toBe(\n        '2description'\n      );\n    });\n\n    it('should icon display correct', () => {\n      fixture.detectChanges();\n      expect(\n        innerSteps[0].nativeElement\n          .querySelector('.ant-steps-item-icon')\n          .firstElementChild!.classList.contains('ant-steps-icon')\n      ).toBe(true);\n      expect(\n        innerSteps[1].nativeElement\n          .querySelector('.ant-steps-item-icon')\n          .firstElementChild!.classList.contains('ant-steps-icon')\n      ).toBe(true);\n      expect(\n        innerSteps[2].nativeElement\n          .querySelector('.ant-steps-item-icon')\n          .firstElementChild!.classList.contains('ant-steps-icon')\n      ).toBe(true);\n    });\n\n    it('should size display correct', () => {\n      fixture.detectChanges();\n      testComponent.size = 'small';\n      testComponent.cdr.markForCheck();\n      fixture.detectChanges();\n      expect(outStep.nativeElement.className).toBe(\n        'ant-steps ant-steps-horizontal ant-steps-label-horizontal ant-steps-small'\n      );\n    });\n\n    it('should direction display correct', () => {\n      fixture.detectChanges();\n      testComponent.direction = 'vertical';\n      testComponent.cdr.markForCheck();\n      fixture.detectChanges();\n      expect(outStep.nativeElement.className).toBe('ant-steps ant-steps-vertical');\n    });\n\n    it('should label placement display correct', () => {\n      fixture.detectChanges();\n      testComponent.labelPlacement = 'vertical';\n      testComponent.cdr.markForCheck();\n      fixture.detectChanges();\n      expect(outStep.nativeElement.classList).toContain('ant-steps-label-vertical');\n    });\n\n    it('should status display correct', fakeAsync(() => {\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      testComponent.status = 'wait';\n      testComponent.cdr.markForCheck();\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(innerSteps[0].nativeElement.className).toBe('ant-steps-item ant-steps-item-active ant-steps-item-wait');\n      testComponent.status = 'finish';\n      testComponent.cdr.markForCheck();\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(innerSteps[0].nativeElement.className).toBe('ant-steps-item ant-steps-item-active ant-steps-item-finish');\n      testComponent.status = 'error';\n      testComponent.current = 1;\n      testComponent.cdr.markForCheck();\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(innerSteps[1].nativeElement.className).toBe('ant-steps-item ant-steps-item-error ant-steps-item-active');\n      expect(innerSteps[0].nativeElement.className).toBe('ant-steps-item ant-steps-item-finish ant-steps-next-error');\n    }));\n\n    it('should processDot display correct', fakeAsync(() => {\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      testComponent.progressDot = true;\n      testComponent.cdr.markForCheck();\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(outStep.nativeElement.classList.contains('ant-steps-dot')).toBe(true);\n      expect(\n        innerSteps[0].nativeElement\n          .querySelector('.ant-steps-icon')\n          .firstElementChild!.classList.contains('ant-steps-icon-dot')\n      ).toBe(true);\n      expect(\n        innerSteps[1].nativeElement\n          .querySelector('.ant-steps-icon')\n          .firstElementChild!.classList.contains('ant-steps-icon-dot')\n      ).toBe(true);\n      expect(\n        innerSteps[2].nativeElement\n          .querySelector('.ant-steps-icon')\n          .firstElementChild!.classList.contains('ant-steps-icon-dot')\n      ).toBe(true);\n    }));\n\n    it('should processDot template display correct', fakeAsync(() => {\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      testComponent.progressDot = testComponent.progressTemplate!;\n      testComponent.cdr.markForCheck();\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(outStep.nativeElement.classList.contains('ant-steps-dot')).toBe(true);\n      expect(innerSteps[0].nativeElement.querySelector('.ant-steps-icon').firstElementChild.innerText.trim()).toBe(\n        'process0'\n      );\n      expect(innerSteps[1].nativeElement.querySelector('.ant-steps-icon').firstElementChild.innerText.trim()).toBe(\n        'wait1'\n      );\n      expect(innerSteps[2].nativeElement.querySelector('.ant-steps-icon').firstElementChild.innerText.trim()).toBe(\n        'wait2'\n      );\n      expect(\n        innerSteps[0].nativeElement\n          .querySelector('.ant-steps-icon')\n          .lastElementChild.classList.contains('ant-steps-icon-dot')\n      ).toBe(true);\n      expect(\n        innerSteps[1].nativeElement\n          .querySelector('.ant-steps-icon')\n          .lastElementChild.classList.contains('ant-steps-icon-dot')\n      ).toBe(true);\n      expect(\n        innerSteps[2].nativeElement\n          .querySelector('.ant-steps-icon')\n          .lastElementChild.classList.contains('ant-steps-icon-dot')\n      ).toBe(true);\n    }));\n\n    it('should support custom starting index', fakeAsync(() => {\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      testComponent.startIndex = 3;\n      testComponent.current = 3;\n      testComponent.cdr.markForCheck();\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(innerSteps[0].nativeElement.className).toBe('ant-steps-item ant-steps-item-active ant-steps-item-process');\n      expect(innerSteps[1].nativeElement.className).toBe('ant-steps-item ant-steps-item-wait');\n      expect(innerSteps[2].nativeElement.className).toBe('ant-steps-item ant-steps-item-wait');\n      expect(innerSteps[0].nativeElement.querySelector('.ant-steps-icon').innerText.trim()).toBe('4');\n      expect(innerSteps[1].nativeElement.querySelector('.ant-steps-icon').innerText.trim()).toBe('5');\n      expect(innerSteps[2].nativeElement.querySelector('.ant-steps-icon').innerText.trim()).toBe('6');\n    }));\n  });\n\n  describe('inner step string', () => {\n    let fixture: ComponentFixture<NzTestInnerStepStringComponent>;\n    let testComponent: NzTestInnerStepStringComponent;\n    let innerSteps: DebugElement[];\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestInnerStepStringComponent);\n      testComponent = fixture.debugElement.componentInstance;\n      innerSteps = fixture.debugElement.queryAll(By.directive(NzStepComponent));\n    });\n\n    it('should status display correct', () => {\n      fixture.detectChanges();\n      expect(innerSteps[0].nativeElement.classList).toContain('ant-steps-item-process');\n      expect(innerSteps[1].nativeElement.classList).toContain('ant-steps-item-process');\n      expect(innerSteps[2].nativeElement.classList).toContain('ant-steps-item-process');\n      testComponent.status = 'wait';\n      fixture.detectChanges();\n      expect(innerSteps[0].nativeElement.classList).toContain('ant-steps-item-wait');\n      expect(innerSteps[1].nativeElement.classList).toContain('ant-steps-item-wait');\n      expect(innerSteps[2].nativeElement.classList).toContain('ant-steps-item-wait');\n    });\n\n    it('should title display correct', () => {\n      fixture.detectChanges();\n      expect(innerSteps[0].nativeElement.querySelector('.ant-steps-item-title').innerText.trim()).toBe('title');\n      expect(innerSteps[1].nativeElement.querySelector('.ant-steps-item-title').innerText.trim()).toBe('title');\n      expect(innerSteps[2].nativeElement.querySelector('.ant-steps-item-title').innerText.trim()).toBe('title');\n    });\n\n    it('should description display correct', () => {\n      fixture.detectChanges();\n      expect(innerSteps[0].nativeElement.querySelector('.ant-steps-item-description').innerText.trim()).toBe(\n        'description'\n      );\n      expect(innerSteps[1].nativeElement.querySelector('.ant-steps-item-description').innerText.trim()).toBe(\n        'description'\n      );\n      expect(innerSteps[2].nativeElement.querySelector('.ant-steps-item-description').innerText.trim()).toBe(\n        'description'\n      );\n    });\n\n    it('should icon display correct', () => {\n      fixture.detectChanges();\n      expect(innerSteps[0].nativeElement.querySelector('.ant-steps-icon').firstElementChild.className).toBe(\n        'anticon anticon-user'\n      );\n      expect(innerSteps[1].nativeElement.querySelector('.ant-steps-icon').firstElementChild.className).toBe(\n        'anticon anticon-user'\n      );\n      expect(innerSteps[2].nativeElement.querySelector('.ant-steps-icon').firstElementChild.className).toBe(\n        'anticon anticon-user'\n      );\n    });\n  });\n\n  describe('inner step template', () => {\n    let fixture: ComponentFixture<NzTestInnerStepTemplateComponent>;\n    let innerSteps: DebugElement[];\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestInnerStepTemplateComponent);\n      innerSteps = fixture.debugElement.queryAll(By.directive(NzStepComponent));\n    });\n\n    it('should title display correct', () => {\n      fixture.detectChanges();\n      expect(innerSteps[0].nativeElement.querySelector('.ant-steps-item-title').innerText.trim()).toBe('titleTemplate');\n      expect(innerSteps[1].nativeElement.querySelector('.ant-steps-item-title').innerText.trim()).toBe('titleTemplate');\n      expect(innerSteps[2].nativeElement.querySelector('.ant-steps-item-title').innerText.trim()).toBe('titleTemplate');\n    });\n\n    it('should description display correct', () => {\n      fixture.detectChanges();\n      expect(innerSteps[0].nativeElement.querySelector('.ant-steps-item-description').innerText.trim()).toBe(\n        'descriptionTemplate'\n      );\n      expect(innerSteps[1].nativeElement.querySelector('.ant-steps-item-description').innerText.trim()).toBe(\n        'descriptionTemplate'\n      );\n      expect(innerSteps[2].nativeElement.querySelector('.ant-steps-item-description').innerText.trim()).toBe(\n        'descriptionTemplate'\n      );\n    });\n\n    it('should icon display correct', () => {\n      fixture.detectChanges();\n      expect(innerSteps[0].nativeElement.querySelector('.ant-steps-icon').firstElementChild.className).toContain(\n        'anticon-smile-o'\n      );\n      expect(innerSteps[1].nativeElement.querySelector('.ant-steps-icon').firstElementChild.className).toContain(\n        'anticon-smile-o'\n      );\n      expect(innerSteps[2].nativeElement.querySelector('.ant-steps-icon').firstElementChild.className).toContain(\n        'anticon-smile-o'\n      );\n    });\n  });\n\n  describe('step ng for', () => {\n    it('should title display correct', () => {\n      TestBed.createComponent(NzTestStepForComponent).detectChanges();\n    });\n\n    it('should push works correct', () => {\n      const comp = TestBed.createComponent(NzTestStepForComponent);\n      comp.detectChanges();\n      comp.debugElement.componentInstance.updateSteps();\n      comp.detectChanges();\n    });\n  });\n\n  describe('step async assign steps', () => {\n    it('should allow steps assigned asynchronously', fakeAsync(() => {\n      const fixture: ComponentFixture<NzTestStepAsyncComponent> = TestBed.createComponent(NzTestStepAsyncComponent);\n      let innerSteps: DebugElement[];\n\n      fixture.detectChanges();\n      innerSteps = fixture.debugElement.queryAll(By.directive(NzStepComponent));\n      expect(innerSteps.length).toBe(0);\n\n      tick(1000);\n      fixture.detectChanges();\n      tick();\n      innerSteps = fixture.debugElement.queryAll(By.directive(NzStepComponent));\n      fixture.detectChanges();\n      expect(innerSteps.length).toBe(3);\n      expect(innerSteps[0].nativeElement.className).toBe('ant-steps-item ant-steps-item-finish');\n      expect(innerSteps[1].nativeElement.className).toBe('ant-steps-item ant-steps-item-active ant-steps-item-process');\n      expect(innerSteps[0].nativeElement.querySelector('.ant-steps-icon').innerText.trim()).toBe('');\n      expect(innerSteps[1].nativeElement.querySelector('.ant-steps-icon').innerText.trim()).toBe('2');\n      expect(innerSteps[2].nativeElement.querySelector('.ant-steps-icon').innerText.trim()).toBe('3');\n    }));\n  });\n\n  describe('step clickable', () => {\n    let fixture: ComponentFixture<NzDemoStepsClickableComponent>;\n    let testComponent: NzDemoStepsClickableComponent;\n    let innerSteps: DebugElement[];\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzDemoStepsClickableComponent);\n      testComponent = fixture.debugElement.componentInstance;\n      innerSteps = fixture.debugElement.queryAll(By.directive(NzStepComponent));\n    });\n\n    it('should clickable', fakeAsync(() => {\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      innerSteps\n        .map(step => step.nativeElement.querySelector('.ant-steps-item-container'))\n        .forEach((e: HTMLElement) => {\n          expect(e.getAttribute('role')).toBe('button');\n        });\n    }));\n\n    it('should output work', fakeAsync(() => {\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      spyOn(testComponent, 'onIndexChange');\n      innerSteps[1].nativeElement.querySelector('.ant-steps-item-container').click();\n      fixture.detectChanges();\n      expect(testComponent.onIndexChange).toHaveBeenCalledWith(1);\n    }));\n\n    it('should disable work', fakeAsync(() => {\n      testComponent.disable = true;\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      const step = innerSteps[0].nativeElement.querySelector('.ant-steps-item-container') as HTMLElement;\n      expect(step.getAttribute('role')).not.toBe('button');\n      spyOn(testComponent, 'onIndexChange');\n      step.click();\n      fixture.detectChanges();\n      expect(testComponent.onIndexChange).not.toHaveBeenCalled();\n    }));\n\n    it(\"should can't click when status is process\", fakeAsync(() => {\n      testComponent.disable = false;\n      testComponent.index = 0;\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      spyOn(testComponent, 'onIndexChange');\n      innerSteps[0].nativeElement.click();\n      fixture.detectChanges();\n      expect(testComponent.onIndexChange).not.toHaveBeenCalled();\n    }));\n\n    it('should enable and disable work', fakeAsync(() => {\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      innerSteps[1].componentInstance.disable();\n      fixture.detectChanges();\n      spyOn(testComponent, 'onIndexChange');\n      innerSteps[1].nativeElement.querySelector('.ant-steps-item-container').click();\n      fixture.detectChanges();\n      expect(testComponent.onIndexChange).not.toHaveBeenCalled();\n      innerSteps[1].componentInstance.enable();\n      fixture.detectChanges();\n      innerSteps[1].nativeElement.querySelector('.ant-steps-item-container').click();\n      fixture.detectChanges();\n      expect(testComponent.onIndexChange).toHaveBeenCalledTimes(1);\n      expect(testComponent.onIndexChange).toHaveBeenCalledWith(1);\n    }));\n  });\n\n  describe('navigation', () => {\n    let fixture: ComponentFixture<NzDemoStepsNavComponent>;\n    let steps: DebugElement[];\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzDemoStepsNavComponent);\n      steps = fixture.debugElement.queryAll(By.directive(NzStepsComponent));\n    });\n\n    it('should clickable', fakeAsync(() => {\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n\n      steps\n        .map(step => step.nativeElement)\n        .forEach((e: HTMLElement) => {\n          expect(e.classList).toContain('ant-steps-navigation');\n        });\n    }));\n  });\n  describe('RTL', () => {\n    it('should className correct on dir change', fakeAsync(() => {\n      const fixture = TestBed.createComponent(NzTestOuterStepsRtlComponent);\n      const outStep = fixture.debugElement.query(By.directive(NzStepsComponent));\n      fixture.componentInstance.direction = 'rtl';\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(outStep.nativeElement.classList).toContain('ant-steps-rtl');\n\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n      expect(outStep.nativeElement.classList).not.toContain('ant-steps-rtl');\n    }));\n  });\n});\n\n@Component({\n  selector: 'nz-test-outer-steps',\n  imports: [NgTemplateOutlet, NzStepsModule],\n  template: `\n    <nz-steps\n      [nzCurrent]=\"current\"\n      [nzDirection]=\"direction\"\n      [nzLabelPlacement]=\"labelPlacement\"\n      [nzSize]=\"size\"\n      [nzStatus]=\"status\"\n      [nzProgressDot]=\"progressDot\"\n      [nzStartIndex]=\"startIndex\"\n    >\n      <nz-step nzTitle=\"0title\" [nzSubtitle]=\"subtitle\" nzDescription=\"0description\" />\n      <nz-step nzTitle=\"1title\" nzDescription=\"1description\" />\n      <nz-step nzTitle=\"2title\" nzDescription=\"2description\" />\n    </nz-steps>\n    <ng-template #progressTemplate let-dot let-status=\"status\" let-index=\"index\">\n      <span class=\"insert-span\">{{ status }}{{ index }}</span>\n      <ng-template [ngTemplateOutlet]=\"dot\" />\n    </ng-template>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class NzTestOuterStepsComponent {\n  @ViewChild('progressTemplate', { static: false }) progressTemplate?: NzProgressDotTemplate;\n  current = 0;\n  direction: NzDirectionVHType = 'horizontal';\n  labelPlacement: NzDirectionVHType = 'horizontal';\n  size: NzSizeDSType = 'default';\n  status: NzStatusType = 'process';\n  subtitle?: string | TemplateRef<void>;\n  progressDot: BooleanInput | NzProgressDotTemplate | undefined | null = false;\n  startIndex = 0;\n  constructor(public cdr: ChangeDetectorRef) {}\n}\n\n@Component({\n  imports: [NzIconModule, NzStepsModule],\n  template: `\n    <nz-steps [nzCurrent]=\"current\">\n      <nz-step [nzTitle]=\"title\" [nzDescription]=\"description\" [nzIcon]=\"icon\" [nzStatus]=\"status\" />\n      <nz-step [nzTitle]=\"title\" [nzDescription]=\"description\" [nzIcon]=\"icon\" [nzStatus]=\"status\" />\n      <nz-step [nzTitle]=\"title\" [nzDescription]=\"description\" [nzIcon]=\"icon\" [nzStatus]=\"status\" />\n    </nz-steps>\n    <ng-template #titleTemplate>titleTemplate</ng-template>\n    <ng-template #descriptionTemplate>descriptionTemplate</ng-template>\n    <ng-template #iconTemplate><nz-icon nzType=\"smile-o\" /></ng-template>\n  `\n})\nexport class NzTestInnerStepStringComponent {\n  @ViewChild('titleTemplate', { static: false }) titleTemplate?: TemplateRef<void>;\n  @ViewChild('descriptionTemplate', { static: false }) descriptionTemplate?: TemplateRef<void>;\n  @ViewChild('iconTemplate', { static: false }) iconTemplate?: TemplateRef<void>;\n  status = 'process';\n  current = 1;\n  icon = 'user';\n  title = 'title';\n  description = 'description';\n}\n\n@Component({\n  imports: [NzIconModule, NzStepsModule],\n  template: `\n    <nz-steps [nzCurrent]=\"1\">\n      <nz-step [nzTitle]=\"titleTemplate\" [nzDescription]=\"descriptionTemplate\" [nzIcon]=\"iconTemplate\" />\n      <nz-step [nzTitle]=\"titleTemplate\" [nzDescription]=\"descriptionTemplate\" [nzIcon]=\"iconTemplate\" />\n      <nz-step [nzTitle]=\"titleTemplate\" [nzDescription]=\"descriptionTemplate\" [nzIcon]=\"iconTemplate\" />\n    </nz-steps>\n    <ng-template #titleTemplate>titleTemplate</ng-template>\n    <ng-template #descriptionTemplate>descriptionTemplate</ng-template>\n    <ng-template #iconTemplate><nz-icon nzType=\"smile-o\" /></ng-template>\n  `\n})\nexport class NzTestInnerStepTemplateComponent {}\n\n@Component({\n  imports: [NzStepsModule],\n  template: `\n    <nz-steps>\n      @for (step of steps; track step) {\n        <nz-step />\n      }\n    </nz-steps>\n  `\n})\nexport class NzTestStepForComponent {\n  steps = [1, 2, 3];\n  updateSteps(): void {\n    this.steps.push(4);\n  }\n}\n\n@Component({\n  imports: [NzStepsModule],\n  template: `\n    <nz-steps [nzCurrent]=\"1\">\n      @for (step of steps; track step) {\n        <nz-step />\n      }\n    </nz-steps>\n  `\n})\nexport class NzTestStepAsyncComponent implements OnInit {\n  steps: number[] = [];\n\n  ngOnInit(): void {\n    setTimeout(() => {\n      this.steps = [1, 2, 3];\n    }, 1000);\n  }\n}\n\n@Component({\n  imports: [BidiModule, NzTestOuterStepsComponent],\n  template: `<nz-test-outer-steps [dir]=\"direction\" />`\n})\nexport class NzTestOuterStepsRtlComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n}\n"
  },
  {
    "path": "components/steps/style/compatibility.less",
    "content": ".@{steps-prefix-cls}-flex-not-supported {\n  &.@{steps-prefix-cls}-horizontal.@{steps-prefix-cls}-label-horizontal {\n    .@{steps-prefix-cls}-item {\n      margin-left: -16px;\n      padding-left: 16px;\n      background: @steps-background;\n    }\n\n    &.@{steps-prefix-cls}-small .@{steps-prefix-cls}-item {\n      margin-left: -12px;\n      padding-left: 12px;\n    }\n  }\n\n  &.@{steps-prefix-cls}-dot {\n    .@{steps-prefix-cls}-item {\n      &:last-child {\n        overflow: hidden;\n\n        .@{steps-prefix-cls}-icon-dot::after {\n          right: -200px;\n          width: 200px;\n        }\n      }\n\n      .@{steps-prefix-cls}-icon-dot::before,\n      .@{steps-prefix-cls}-icon-dot::after {\n        position: absolute;\n        top: 0;\n        left: -10px;\n        width: 10px;\n        height: 8px;\n        background: @steps-background;\n        content: '';\n      }\n\n      .@{steps-prefix-cls}-icon-dot::after {\n        right: -10px;\n        left: auto;\n      }\n    }\n\n    .@{steps-prefix-cls}-item-wait\n      .@{steps-prefix-cls}-item-icon\n      > .@{steps-prefix-cls}-icon\n      .@{steps-prefix-cls}-icon-dot {\n      background: #ccc;\n    }\n  }\n}\n"
  },
  {
    "path": "components/steps/style/custom-icon.less",
    "content": ".@{steps-prefix-cls}-item-custom {\n  > .@{steps-prefix-cls}-item-container > .@{steps-prefix-cls}-item-icon {\n    height: auto;\n    background: none;\n    border: 0;\n    > .@{steps-prefix-cls}-icon {\n      top: @steps-icon-custom-top;\n      left: 0.5px;\n      width: @steps-icon-custom-size;\n      height: @steps-icon-custom-size;\n      font-size: @steps-icon-custom-font-size;\n      line-height: @steps-icon-custom-size;\n    }\n  }\n  &.@{steps-prefix-cls}-item-process {\n    .@{steps-prefix-cls}-item-icon > .@{steps-prefix-cls}-icon {\n      color: @process-icon-color;\n    }\n  }\n}\n\n// Only adjust horizontal customize icon width\n.@{steps-prefix-cls} {\n  &:not(.@{steps-prefix-cls}-vertical) {\n    .@{steps-prefix-cls}-item-custom {\n      .@{steps-prefix-cls}-item-icon {\n        width: auto;\n        background: none;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/steps/style/entry.less",
    "content": "@import './index.less';\n"
  },
  {
    "path": "components/steps/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@steps-prefix-cls: ~'@{ant-prefix}-steps';\n@process-icon-color: @primary-color;\n@process-title-color: @heading-color;\n@process-description-color: @text-color;\n@process-icon-text-color: @text-color-inverse;\n@wait-icon-color: @disabled-color;\n@wait-title-color: @text-color-secondary;\n@wait-description-color: @wait-title-color;\n@wait-tail-color: @process-tail-color;\n@finish-icon-color: @process-icon-color;\n@finish-title-color: @text-color;\n@finish-description-color: @text-color-secondary;\n@finish-tail-color: @primary-color;\n@error-icon-color: @error-color;\n@error-title-color: @error-color;\n@error-description-color: @error-color;\n@error-tail-color: @wait-tail-color;\n@steps-nav-active-color: @primary-color;\n\n.@{steps-prefix-cls} {\n  .reset-component();\n\n  display: flex;\n  width: 100%;\n  font-size: 0;\n  text-align: initial;\n}\n\n.@{steps-prefix-cls}-item {\n  position: relative;\n  display: inline-block;\n  flex: 1;\n  overflow: hidden;\n  vertical-align: top;\n\n  &-container {\n    outline: none;\n  }\n\n  &:last-child {\n    flex: none;\n  }\n\n  &:last-child > &-container > &-tail,\n  &:last-child > &-container > &-content > &-title::after {\n    display: none;\n  }\n\n  &-icon,\n  &-content {\n    display: inline-block;\n    vertical-align: top;\n  }\n\n  &-icon {\n    width: @steps-icon-size;\n    height: @steps-icon-size;\n    margin: @steps-icon-margin;\n    font-size: @steps-icon-font-size;\n    font-family: @font-family;\n    line-height: @steps-icon-size;\n    text-align: center;\n    border: @border-width-base @border-style-base @wait-icon-color;\n    border-radius: @steps-icon-size;\n    transition: background-color 0.3s, border-color 0.3s;\n\n    .@{steps-prefix-cls}-icon {\n      position: relative;\n      top: @steps-icon-top;\n      color: @primary-color;\n      line-height: 1;\n    }\n  }\n\n  &-tail {\n    position: absolute;\n    top: 12px;\n    left: 0;\n    width: 100%;\n    padding: 0 10px;\n\n    &::after {\n      display: inline-block;\n      width: 100%;\n      height: 1px;\n      background: @border-color-split;\n      border-radius: 1px;\n      transition: background 0.3s;\n      content: '';\n    }\n  }\n\n  &-title {\n    position: relative;\n    display: inline-block;\n    padding-right: 16px;\n    color: @text-color;\n    font-size: @font-size-lg;\n    line-height: @steps-title-line-height;\n\n    &::after {\n      position: absolute;\n      top: (@steps-title-line-height / 2);\n      left: 100%;\n      display: block;\n      width: 9999px;\n      height: 1px;\n      background: @wait-tail-color;\n      content: '';\n    }\n  }\n\n  &-subtitle {\n    display: inline;\n    margin-left: 8px;\n    color: @text-color-secondary;\n    font-weight: normal;\n    font-size: @font-size-base;\n  }\n\n  &-description {\n    color: @text-color-secondary;\n    font-size: @font-size-base;\n  }\n  .step-item-status(wait);\n  .step-item-status(process);\n\n  &-process > &-container > &-icon {\n    background: @process-icon-color;\n    .@{steps-prefix-cls}-icon {\n      color: @process-icon-text-color;\n    }\n  }\n\n  &-process > &-container > &-title {\n    font-weight: 500;\n  }\n  .step-item-status(finish);\n  .step-item-status(error);\n\n  &.@{steps-prefix-cls}-next-error .@{steps-prefix-cls}-item-title::after {\n    background: @error-icon-color;\n  }\n\n  &-disabled {\n    cursor: not-allowed;\n  }\n}\n\n// ===================== Clickable =====================\n.@{steps-prefix-cls} .@{steps-prefix-cls}-item {\n  &:not(.@{steps-prefix-cls}-item-active) {\n    & > .@{steps-prefix-cls}-item-container[role='button'] {\n      cursor: pointer;\n\n      .@{steps-prefix-cls}-item {\n        &-title,\n        &-subtitle,\n        &-description,\n        &-icon .@{steps-prefix-cls}-icon {\n          transition: color 0.3s;\n        }\n      }\n\n      &:hover {\n        .@{steps-prefix-cls}-item {\n          &-title,\n          &-subtitle,\n          &-description {\n            color: @primary-color;\n          }\n        }\n      }\n    }\n\n    &:not(.@{steps-prefix-cls}-item-process) {\n      & > .@{steps-prefix-cls}-item-container[role='button']:hover {\n        .@{steps-prefix-cls}-item {\n          &-icon {\n            border-color: @primary-color;\n\n            .@{steps-prefix-cls}-icon {\n              color: @primary-color;\n            }\n          }\n        }\n      }\n    }\n  }\n}\n\n.@{steps-prefix-cls}-horizontal:not(.@{steps-prefix-cls}-label-vertical) {\n  .@{steps-prefix-cls}-item {\n    padding-left: 16px;\n    white-space: nowrap;\n\n    &:first-child {\n      padding-left: 0;\n    }\n    &:last-child .@{steps-prefix-cls}-item-title {\n      padding-right: 0;\n    }\n\n    &-tail {\n      display: none;\n    }\n\n    &-description {\n      max-width: @steps-description-max-width;\n      white-space: normal;\n    }\n  }\n}\n\n.step-item-status(@status) {\n  @icon-color: '@{status}-icon-color';\n  @title-color: '@{status}-title-color';\n  @description-color: '@{status}-description-color';\n  @tail-color: '@{status}-tail-color';\n  &-@{status} &-icon {\n    background-color: @steps-background;\n    border-color: @@icon-color;\n    > .@{steps-prefix-cls}-icon {\n      color: @@icon-color;\n      .@{steps-prefix-cls}-icon-dot {\n        background: @@icon-color;\n      }\n    }\n  }\n  &-@{status} > &-container > &-content > &-title {\n    color: @@title-color;\n\n    &::after {\n      background-color: @@tail-color;\n    }\n  }\n  &-@{status} > &-container > &-content > &-description {\n    color: @@description-color;\n  }\n  &-@{status} > &-container > &-tail::after {\n    background-color: @@tail-color;\n  }\n}\n\n@import './custom-icon';\n@import './small';\n@import './vertical';\n@import './label-placement';\n@import './progress-dot';\n@import './nav';\n@import './rtl';\n@import './progress.less';\n"
  },
  {
    "path": "components/steps/style/label-placement.less",
    "content": ".@{steps-prefix-cls}-label-vertical {\n  .@{steps-prefix-cls}-item {\n    overflow: visible;\n\n    &-tail {\n      margin-left: 58px;\n      padding: 3.5px 24px;\n    }\n\n    &-content {\n      display: block;\n      width: ((@steps-icon-size / 2) + 42px) * 2;\n      margin-top: 8px;\n      text-align: center;\n    }\n\n    &-icon {\n      display: inline-block;\n      margin-left: 42px;\n    }\n\n    &-title {\n      padding-right: 0;\n      padding-left: 0;\n\n      &::after {\n        display: none;\n      }\n    }\n\n    &-subtitle {\n      display: block;\n      margin-bottom: 4px;\n      margin-left: 0;\n      line-height: @line-height-base;\n    }\n  }\n  &.@{steps-prefix-cls}-small:not(.@{steps-prefix-cls}-dot) {\n    .@{steps-prefix-cls}-item {\n      &-icon {\n        margin-left: 46px;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/steps/style/nav.less",
    "content": ".@{steps-prefix-cls}-navigation {\n  padding-top: 12px;\n\n  &.@{steps-prefix-cls}-small {\n    .@{steps-prefix-cls}-item {\n      &-container {\n        margin-left: -12px;\n      }\n    }\n  }\n\n  .@{steps-prefix-cls}-item {\n    overflow: visible;\n    text-align: center;\n\n    &-container {\n      display: inline-block;\n      height: 100%;\n      margin-left: -16px;\n      padding-bottom: 12px;\n      text-align: left;\n      transition: opacity 0.3s;\n\n      .@{steps-prefix-cls}-item-content {\n        max-width: @steps-nav-content-max-width;\n      }\n\n      .@{steps-prefix-cls}-item-title {\n        max-width: 100%;\n        padding-right: 0;\n        overflow: hidden;\n        white-space: nowrap;\n        text-overflow: ellipsis;\n\n        &::after {\n          display: none;\n        }\n      }\n    }\n\n    &:not(.@{steps-prefix-cls}-item-active) {\n      .@{steps-prefix-cls}-item-container[role='button'] {\n        cursor: pointer;\n\n        &:hover {\n          opacity: 0.85;\n        }\n      }\n    }\n\n    &:last-child {\n      flex: 1;\n\n      &::after {\n        display: none;\n      }\n    }\n\n    &::after {\n      position: absolute;\n      top: 50%;\n      left: 100%;\n      display: inline-block;\n      width: 12px;\n      height: 12px;\n      margin-top: -14px;\n      margin-left: -2px;\n      border: 1px solid @steps-nav-arrow-color;\n      border-bottom: none;\n      border-left: none;\n      transform: rotate(45deg);\n      content: '';\n    }\n\n    &::before {\n      position: absolute;\n      bottom: 0;\n      left: 50%;\n      display: inline-block;\n      width: 0;\n      height: 2px;\n      background-color: @steps-nav-active-color;\n      transition: width 0.3s, left 0.3s;\n      transition-timing-function: ease-out;\n      content: '';\n    }\n  }\n\n  .@{steps-prefix-cls}-item.@{steps-prefix-cls}-item-active::before {\n    left: 0;\n    width: 100%;\n  }\n}\n\n.@{steps-prefix-cls}-navigation.@{steps-prefix-cls}-vertical {\n  > .@{steps-prefix-cls}-item {\n    margin-right: 0 !important;\n\n    &::before {\n      display: none;\n    }\n    &.@{steps-prefix-cls}-item-active::before {\n      top: 0;\n      right: 0;\n      left: unset;\n      display: block;\n      width: 3px;\n      height: calc(100% - 24px);\n    }\n\n    &::after {\n      position: relative;\n      top: -2px;\n      left: 50%;\n      display: block;\n      width: 8px;\n      height: 8px;\n      margin-bottom: 8px;\n      text-align: center;\n      transform: rotate(135deg);\n    }\n    > .@{steps-prefix-cls}-item-container > .@{steps-prefix-cls}-item-tail {\n      visibility: hidden;\n    }\n  }\n}\n\n.@{steps-prefix-cls}-navigation.@{steps-prefix-cls}-horizontal {\n  > .@{steps-prefix-cls}-item\n    > .@{steps-prefix-cls}-item-container\n    > .@{steps-prefix-cls}-item-tail {\n    visibility: hidden;\n  }\n}\n"
  },
  {
    "path": "components/steps/style/progress-dot.less",
    "content": ".@{steps-prefix-cls}-dot,\n.@{steps-prefix-cls}-dot.@{steps-prefix-cls}-small {\n  .@{steps-prefix-cls}-item {\n    &-title {\n      line-height: @line-height-base;\n    }\n\n    &-tail {\n      top: @steps-dot-top;\n      width: 100%;\n      margin: 0 0 0 (@steps-description-max-width / 2);\n      padding: 0;\n\n      &::after {\n        width: ~'calc(100% - 20px)';\n        height: 3px;\n        margin-left: 12px;\n      }\n    }\n    &:first-child .@{steps-prefix-cls}-icon-dot {\n      left: 2px;\n    }\n\n    &-icon {\n      width: @steps-dot-size;\n      height: @steps-dot-size;\n      margin-left: 67px;\n      padding-right: 0;\n      line-height: @steps-dot-size;\n      background: transparent;\n      border: 0;\n\n      .@{steps-prefix-cls}-icon-dot {\n        position: relative;\n        float: left;\n        width: 100%;\n        height: 100%;\n        border-radius: 100px;\n        transition: all 0.3s;\n\n        /* expand hover area */\n        &::after {\n          position: absolute;\n          top: -12px;\n          left: -26px;\n          width: 60px;\n          height: 32px;\n          background: fade(@black, 0.1%);\n          content: '';\n        }\n      }\n    }\n\n    &-content {\n      width: @steps-description-max-width;\n    }\n    &-process .@{steps-prefix-cls}-item-icon {\n      position: relative;\n      top: -1px;\n      width: @steps-current-dot-size;\n      height: @steps-current-dot-size;\n      line-height: @steps-current-dot-size;\n      background: none;\n    }\n    &-process .@{steps-prefix-cls}-icon {\n      &:first-child .@{steps-prefix-cls}-icon-dot {\n        left: 0;\n      }\n    }\n  }\n}\n\n.@{steps-prefix-cls}-vertical.@{steps-prefix-cls}-dot {\n  .@{steps-prefix-cls}-item-icon {\n    margin-top: 13px;\n    margin-left: 0;\n    background: none;\n  }\n\n  // https://github.com/ant-design/ant-design/issues/18354\n  .@{steps-prefix-cls}-item > .@{steps-prefix-cls}-item-container > .@{steps-prefix-cls}-item-tail {\n    top: 6.5px;\n    left: -9px;\n    margin: 0;\n    padding: 22px 0 4px;\n  }\n\n  &.@{steps-prefix-cls}-small {\n    .@{steps-prefix-cls}-item-icon {\n      margin-top: 10px;\n    }\n\n    .@{steps-prefix-cls}-item\n      > .@{steps-prefix-cls}-item-container\n      > .@{steps-prefix-cls}-item-tail {\n      top: 3.5px;\n    }\n  }\n\n  .@{steps-prefix-cls}-item:first-child .@{steps-prefix-cls}-icon-dot {\n    left: 0;\n  }\n  .@{steps-prefix-cls}-item-content {\n    width: inherit;\n  }\n  .@{steps-prefix-cls}-item-process\n    .@{steps-prefix-cls}-item-container\n    .@{steps-prefix-cls}-item-icon\n    .@{steps-prefix-cls}-icon-dot {\n    top: -1px;\n    left: -1px;\n  }\n}\n"
  },
  {
    "path": "components/steps/style/progress.less",
    "content": "@progress-prefix-cls: ~'@{ant-prefix}-progress';\n\n.@{steps-prefix-cls}-with-progress {\n  .@{steps-prefix-cls}-item {\n    padding-top: 4px;\n\n    & > .@{steps-prefix-cls}-item-container > .@{steps-prefix-cls}-item-tail {\n      top: 4px;\n      left: @steps-vertical-tail-width + 3;\n    }\n  }\n\n  &,\n  &.@{steps-prefix-cls}-small {\n    &.@{steps-prefix-cls}-horizontal .@{steps-prefix-cls}-item:first-child {\n      padding-bottom: 4px;\n      padding-left: 4px;\n    }\n  }\n\n  &.@{steps-prefix-cls}-small\n    > .@{steps-prefix-cls}-item\n    > .@{steps-prefix-cls}-item-container\n    > .@{steps-prefix-cls}-item-tail {\n    left: @steps-vertical-tail-width-sm + 3;\n  }\n\n  &.@{steps-prefix-cls}-vertical .@{steps-prefix-cls}-item {\n    padding-left: 4px;\n  }\n\n  &.@{steps-prefix-cls}-label-vertical {\n    .@{steps-prefix-cls}-item .@{steps-prefix-cls}-item-tail {\n      top: 14px !important;\n    }\n  }\n\n  .@{steps-prefix-cls}-item-icon {\n    position: relative;\n\n    .@{progress-prefix-cls} {\n      position: absolute;\n      top: -5px;\n      right: -5px;\n      bottom: -5px;\n      left: -5px;\n    }\n  }\n}\n"
  },
  {
    "path": "components/steps/style/rtl.less",
    "content": ".@{steps-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n}\n\n.@{steps-prefix-cls}-item {\n  &-icon {\n    .@{steps-prefix-cls}.@{steps-prefix-cls}-rtl & {\n      margin-right: 0;\n      margin-left: 8px;\n    }\n  }\n\n  &-tail {\n    .@{steps-prefix-cls}-rtl & {\n      right: 0;\n      left: auto;\n    }\n  }\n\n  &-title {\n    .@{steps-prefix-cls}-rtl & {\n      padding-right: 0;\n      padding-left: 16px;\n    }\n\n    .@{steps-prefix-cls}-item-subtitle {\n      .@{steps-prefix-cls}-rtl & {\n        float: left;\n        margin-right: 8px;\n        margin-left: 0;\n      }\n    }\n\n    &::after {\n      .@{steps-prefix-cls}-rtl & {\n        right: 100%;\n        left: auto;\n      }\n    }\n  }\n}\n\n.@{steps-prefix-cls}-horizontal:not(.@{steps-prefix-cls}-label-vertical) {\n  .@{steps-prefix-cls}-item {\n    .@{steps-prefix-cls}-rtl& {\n      padding-right: 16px;\n      padding-left: 0;\n    }\n\n    &:first-child {\n      .@{steps-prefix-cls}-rtl& {\n        padding-right: 0;\n      }\n    }\n\n    &:last-child .@{steps-prefix-cls}-item-title {\n      .@{steps-prefix-cls}-rtl& {\n        padding-left: 0;\n      }\n    }\n  }\n}\n\n// custom-icon\n.@{steps-prefix-cls}-item-custom {\n  .@{steps-prefix-cls}-item-icon {\n    > .@{steps-prefix-cls}-icon {\n      .@{steps-prefix-cls}-rtl & {\n        right: 0.5px;\n        left: auto;\n      }\n    }\n  }\n}\n\n// nav\n.@{steps-prefix-cls}-navigation {\n  &.@{steps-prefix-cls}-small {\n    .@{steps-prefix-cls}-item {\n      &-container {\n        .@{steps-prefix-cls}-rtl& {\n          margin-right: -12px;\n          margin-left: 0;\n        }\n      }\n    }\n  }\n\n  .@{steps-prefix-cls}-item {\n    &-container {\n      .@{steps-prefix-cls}-rtl& {\n        margin-right: -16px;\n        margin-left: 0;\n        text-align: right;\n      }\n\n      .@{steps-prefix-cls}-item-title {\n        .@{steps-prefix-cls}-rtl& {\n          padding-left: 0;\n        }\n      }\n    }\n\n    &::after {\n      .@{steps-prefix-cls}-rtl& {\n        right: 100%;\n        left: auto;\n        margin-right: -2px;\n        margin-left: 0;\n        transform: rotate(225deg);\n      }\n    }\n  }\n}\n\n// small\n.@{steps-prefix-cls}-small {\n  &.@{steps-prefix-cls}-horizontal:not(.@{steps-prefix-cls}-label-vertical)\n    .@{steps-prefix-cls}-item {\n    .@{steps-prefix-cls}-rtl& {\n      padding-right: 12px;\n      padding-left: 0;\n    }\n\n    &:first-child {\n      .@{steps-prefix-cls}-rtl& {\n        padding-right: 0;\n      }\n    }\n  }\n\n  .@{steps-prefix-cls}-item-title {\n    .@{steps-prefix-cls}-rtl& {\n      padding-right: 0;\n      padding-left: 12px;\n    }\n  }\n}\n\n// vertical\n.@{steps-prefix-cls}-vertical {\n  > .@{steps-prefix-cls}-item {\n    .@{steps-prefix-cls}-item-icon {\n      .@{steps-prefix-cls}-rtl& {\n        float: right;\n        margin-right: 0;\n        margin-left: @steps-vertical-icon-width;\n      }\n    }\n  }\n\n  > .@{steps-prefix-cls}-item\n    > .@{steps-prefix-cls}-item-container\n    > .@{steps-prefix-cls}-item-tail {\n    .@{steps-prefix-cls}-rtl& {\n      right: @steps-vertical-tail-width;\n      left: auto;\n    }\n  }\n\n  &.@{steps-prefix-cls}-small .@{steps-prefix-cls}-item-container {\n    .@{steps-prefix-cls}-item-tail {\n      .@{steps-prefix-cls}-rtl& {\n        right: @steps-vertical-tail-width-sm;\n        left: auto;\n      }\n    }\n  }\n}\n\n// label\n.@{steps-prefix-cls}-label-vertical {\n  .@{steps-prefix-cls}-item {\n    &-title {\n      .@{steps-prefix-cls}-rtl& {\n        padding-left: 0;\n      }\n    }\n  }\n}\n\n// progress-dot\n.@{steps-prefix-cls}-dot,\n.@{steps-prefix-cls}-dot.@{steps-prefix-cls}-small {\n  .@{steps-prefix-cls}-item {\n    &-tail {\n      .@{steps-prefix-cls}-rtl& {\n        margin: 0 (@steps-description-max-width / 2) 0 0;\n      }\n\n      &::after {\n        .@{steps-prefix-cls}-rtl& {\n          margin-right: 12px;\n          margin-left: 0;\n        }\n      }\n    }\n\n    &:first-child .@{steps-prefix-cls}-icon-dot {\n      .@{steps-prefix-cls}-rtl& {\n        right: 2px;\n        left: auto;\n      }\n    }\n\n    &-icon {\n      .@{steps-prefix-cls}-rtl& {\n        margin-right: 67px;\n        margin-left: 0;\n      }\n\n      .@{steps-prefix-cls}-icon-dot {\n        .@{steps-prefix-cls}-rtl& {\n          float: right;\n        }\n\n        /* expand hover area */\n        &::after {\n          .@{steps-prefix-cls}-rtl& {\n            right: -26px;\n            left: auto;\n          }\n        }\n      }\n    }\n  }\n}\n\n.@{steps-prefix-cls}-vertical.@{steps-prefix-cls}-dot {\n  .@{steps-prefix-cls}-item-icon {\n    .@{steps-prefix-cls}-rtl& {\n      margin-right: 0;\n      margin-left: 16px;\n    }\n  }\n\n  // https://github.com/ant-design/ant-design/issues/18354\n  .@{steps-prefix-cls}-item > .@{steps-prefix-cls}-item-container > .@{steps-prefix-cls}-item-tail {\n    .@{steps-prefix-cls}-rtl& {\n      right: -9px;\n      left: auto;\n    }\n  }\n\n  .@{steps-prefix-cls}-item:first-child .@{steps-prefix-cls}-icon-dot {\n    .@{steps-prefix-cls}-rtl& {\n      right: 0;\n      left: auto;\n    }\n  }\n\n  .@{steps-prefix-cls}-item-process .@{steps-prefix-cls}-icon-dot {\n    .@{steps-prefix-cls}-rtl& {\n      right: -2px;\n      left: auto;\n    }\n  }\n}\n\n// RTL Steps with progress\n.@{steps-prefix-cls}-rtl.@{steps-prefix-cls}-with-progress {\n  &.@{steps-prefix-cls}-vertical > .@{steps-prefix-cls}-item {\n    padding-right: 4px;\n    > .@{steps-prefix-cls}-item-container > .@{steps-prefix-cls}-item-tail {\n      right: @steps-vertical-tail-width + 3;\n    }\n  }\n\n  &.@{steps-prefix-cls}-small.@{steps-prefix-cls}-vertical > .@{steps-prefix-cls}-item {\n    > .@{steps-prefix-cls}-item-container > .@{steps-prefix-cls}-item-tail {\n      right: @steps-vertical-tail-width-sm + 3;\n    }\n  }\n\n  &.@{steps-prefix-cls}-horizontal.@{steps-prefix-cls}-label-horizontal {\n    .@{steps-prefix-cls}-item:first-child {\n      padding-right: 4px;\n      padding-left: 0;\n\n      &.@{steps-prefix-cls}-item-active {\n        padding-right: 4px;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/steps/style/small.less",
    "content": ".@{steps-prefix-cls}-small {\n  &.@{steps-prefix-cls}-horizontal:not(.@{steps-prefix-cls}-label-vertical)\n    .@{steps-prefix-cls}-item {\n    padding-left: 12px;\n\n    &:first-child {\n      padding-left: 0;\n    }\n  }\n  .@{steps-prefix-cls}-item-icon {\n    width: @steps-small-icon-size;\n    height: @steps-small-icon-size;\n    margin: @steps-small-icon-margin;\n    font-size: @font-size-sm;\n    line-height: @steps-small-icon-size;\n    text-align: center;\n    border-radius: @steps-small-icon-size;\n  }\n  .@{steps-prefix-cls}-item-title {\n    padding-right: 12px;\n    font-size: @font-size-base;\n    line-height: @steps-small-icon-size;\n\n    &::after {\n      top: (@steps-small-icon-size / 2);\n    }\n  }\n  .@{steps-prefix-cls}-item-description {\n    color: @text-color-secondary;\n    font-size: @font-size-base;\n  }\n  .@{steps-prefix-cls}-item-tail {\n    top: 8px;\n  }\n  .@{steps-prefix-cls}-item-custom .@{steps-prefix-cls}-item-icon {\n    width: inherit;\n    height: inherit;\n    line-height: inherit;\n    background: none;\n    border: 0;\n    border-radius: 0;\n    > .@{steps-prefix-cls}-icon {\n      font-size: @steps-small-icon-size;\n      line-height: @steps-small-icon-size;\n      transform: none;\n    }\n  }\n}\n"
  },
  {
    "path": "components/steps/style/vertical.less",
    "content": ".@{steps-prefix-cls}-vertical {\n  display: flex;\n  flex-direction: column;\n\n  > .@{steps-prefix-cls}-item {\n    display: block;\n    flex: 1 0 auto;\n    padding-left: 0;\n    overflow: visible;\n\n    .@{steps-prefix-cls}-item-icon {\n      float: left;\n      margin-right: @steps-vertical-icon-width;\n    }\n\n    .@{steps-prefix-cls}-item-content {\n      display: block;\n      min-height: 48px;\n      overflow: hidden;\n    }\n\n    .@{steps-prefix-cls}-item-title {\n      line-height: @steps-icon-size;\n    }\n\n    .@{steps-prefix-cls}-item-description {\n      padding-bottom: 12px;\n    }\n  }\n\n  > .@{steps-prefix-cls}-item\n    > .@{steps-prefix-cls}-item-container\n    > .@{steps-prefix-cls}-item-tail {\n    position: absolute;\n    top: 0;\n    left: @steps-vertical-tail-width - 1; // line width\n    width: 1px;\n    height: 100%;\n    padding: @steps-icon-size + 6px 0 6px;\n\n    &::after {\n      width: 1px;\n      height: 100%;\n    }\n  }\n\n  > .@{steps-prefix-cls}-item:not(:last-child)\n    > .@{steps-prefix-cls}-item-container\n    > .@{steps-prefix-cls}-item-tail {\n    display: block;\n  }\n\n  > .@{steps-prefix-cls}-item\n    > .@{steps-prefix-cls}-item-container\n    > .@{steps-prefix-cls}-item-content\n    > .@{steps-prefix-cls}-item-title {\n    &::after {\n      display: none;\n    }\n  }\n\n  &.@{steps-prefix-cls}-small .@{steps-prefix-cls}-item-container {\n    .@{steps-prefix-cls}-item-tail {\n      position: absolute;\n      top: 0;\n      left: @steps-vertical-tail-width-sm - 1; // line width\n      padding: @steps-small-icon-size + 6px 0 6px;\n    }\n    .@{steps-prefix-cls}-item-title {\n      line-height: @steps-small-icon-size;\n    }\n  }\n}\n"
  },
  {
    "path": "components/style/aliyun.less",
    "content": "@root-entry-name: default;\n\n@import './themes/aliyun.less';\n@import './core/index';\n"
  },
  {
    "path": "components/style/color/bezierEasing.js",
    "content": "var NEWTON_ITERATIONS = 4;\nvar NEWTON_MIN_SLOPE = 0.001;\nvar SUBDIVISION_PRECISION = 0.0000001;\nvar SUBDIVISION_MAX_ITERATIONS = 10;\n\nvar kSplineTableSize = 11;\nvar kSampleStepSize = 1.0 / (kSplineTableSize - 1.0);\n\nvar float32ArraySupported = typeof Float32Array === 'function';\n\nfunction A(aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; }\nfunction B(aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; }\nfunction C(aA1) { return 3.0 * aA1; }\n\n// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.\nfunction calcBezier(aT, aA1, aA2) { return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT; }\n\n// Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.\nfunction getSlope(aT, aA1, aA2) { return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1); }\n\nfunction binarySubdivide(aX, aA, aB, mX1, mX2) {\n  var currentX, currentT, i = 0;\n  do {\n    currentT = aA + (aB - aA) / 2.0;\n    currentX = calcBezier(currentT, mX1, mX2) - aX;\n    if (currentX > 0.0) {\n      aB = currentT;\n    } else {\n      aA = currentT;\n    }\n  } while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS);\n  return currentT;\n}\n\nfunction newtonRaphsonIterate(aX, aGuessT, mX1, mX2) {\n  for (var i = 0; i < NEWTON_ITERATIONS; ++i) {\n    var currentSlope = getSlope(aGuessT, mX1, mX2);\n    if (currentSlope === 0.0) {\n      return aGuessT;\n    }\n    var currentX = calcBezier(aGuessT, mX1, mX2) - aX;\n    aGuessT -= currentX / currentSlope;\n  }\n  return aGuessT;\n}\n\nvar BezierEasing = function (mX1, mY1, mX2, mY2) {\n  if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) {\n    throw new Error('bezier x values must be in [0, 1] range');\n  }\n\n  // Precompute samples table\n  var sampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize);\n  if (mX1 !== mY1 || mX2 !== mY2) {\n    for (var i = 0; i < kSplineTableSize; ++i) {\n      sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2);\n    }\n  }\n\n  function getTForX(aX) {\n    var intervalStart = 0.0;\n    var currentSample = 1;\n    var lastSample = kSplineTableSize - 1;\n\n    for (; currentSample !== lastSample && sampleValues[currentSample] <= aX; ++currentSample) {\n      intervalStart += kSampleStepSize;\n    }\n    --currentSample;\n\n    // Interpolate to provide an initial guess for t\n    var dist = (aX - sampleValues[currentSample]) / (sampleValues[currentSample + 1] - sampleValues[currentSample]);\n    var guessForT = intervalStart + dist * kSampleStepSize;\n\n    var initialSlope = getSlope(guessForT, mX1, mX2);\n    if (initialSlope >= NEWTON_MIN_SLOPE) {\n      return newtonRaphsonIterate(aX, guessForT, mX1, mX2);\n    } else if (initialSlope === 0.0) {\n      return guessForT;\n    } else {\n      return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, mX1, mX2);\n    }\n  }\n\n  return function BezierEasing(x) {\n    if (mX1 === mY1 && mX2 === mY2) {\n      return x; // linear\n    }\n    // Because JavaScript number are imprecise, we should guarantee the extremes are right.\n    if (x === 0) {\n      return 0;\n    }\n    if (x === 1) {\n      return 1;\n    }\n    return calcBezier(getTForX(x), mY1, mY2);\n  };\n};\n\nmodule.exports = {\n  install: function (less, pluginManager, functions) {\n    functions.add('colorEasing', BezierEasing(0.26, 0.09, 0.37, 0.18));\n  }\n};\n"
  },
  {
    "path": "components/style/color/bezierEasing.less",
    "content": "@plugin \"./bezierEasing\";\n"
  },
  {
    "path": "components/style/color/colorPalette.js",
    "content": "const tinycolor = require('./tinycolor2');\n\nvar hueStep = 2;\nvar saturationStep = 0.16;\nvar saturationStep2 = 0.05;\nvar brightnessStep1 = 0.05;\nvar brightnessStep2 = 0.15;\nvar lightColorCount = 5;\nvar darkColorCount = 4;\n\nvar getHue = function (hsv, i, isLight) {\n  var hue;\n  if (hsv.h >= 60 && hsv.h <= 240) {\n    hue = isLight ? hsv.h - hueStep * i : hsv.h + hueStep * i;\n  } else {\n    hue = isLight ? hsv.h + hueStep * i : hsv.h - hueStep * i;\n  }\n  if (hue < 0) {\n    hue += 360;\n  } else if (hue >= 360) {\n    hue -= 360;\n  }\n  return Math.round(hue);\n};\nvar getSaturation = function (hsv, i, isLight) {\n  // grey color don't change saturation\n  if (hsv.h === 0 && hsv.s === 0) {\n    return hsv.s;\n  }\n  var saturation;\n  if (isLight) {\n    saturation = hsv.s - saturationStep * i;\n  } else if (i === darkColorCount) {\n    saturation = hsv.s + saturationStep;\n  } else {\n    saturation = hsv.s + saturationStep2 * i;\n  }\n  if (saturation > 1) {\n    saturation = 1;\n  }\n  if (isLight && i === lightColorCount && saturation > 0.1) {\n    saturation = 0.1;\n  }\n  if (saturation < 0.06) {\n    saturation = 0.06;\n  }\n  return Number(saturation.toFixed(2));\n};\nvar getValue = function (hsv, i, isLight) {\n  var value;\n  if (isLight) {\n    value = hsv.v + brightnessStep1 * i;\n  } else {\n    value = hsv.v - brightnessStep2 * i\n  }\n  if (value > 1) {\n    value = 1;\n  }\n  return Number(value.toFixed(2))\n};\n\nmodule.exports = {\n  install: function (less, pluginManager, functions) {\n    functions.add('colorPalette', function (colorRef, indexRef) {\n      var color = colorRef.value;\n      var index = indexRef.value;\n      var isLight = index <= 6;\n      var hsv = tinycolor(color).toHsv();\n      var i = isLight ? lightColorCount + 1 - index : index - lightColorCount - 1;\n      var hex = tinycolor({\n        h: getHue(hsv, i, isLight),\n        s: getSaturation(hsv, i, isLight),\n        v: getValue(hsv, i, isLight),\n      }).toHex();\n      return new less.tree.Color(hex);\n    });\n  }\n};\n"
  },
  {
    "path": "components/style/color/colorPalette.less",
    "content": "/* stylelint-disable no-duplicate-selectors */\n@import \"bezierEasing\";\n@import \"tinyColor\";\n\n@plugin \"./colorPalette\";\n"
  },
  {
    "path": "components/style/color/colors.less",
    "content": "@import 'colorPalette';\n\n// color palettes\n@blue-base: #1890ff;\n@blue-1: color(colorPalette('@{blue-6}', 1));\n@blue-2: color(colorPalette('@{blue-6}', 2));\n@blue-3: color(colorPalette('@{blue-6}', 3));\n@blue-4: color(colorPalette('@{blue-6}', 4));\n@blue-5: color(colorPalette('@{blue-6}', 5));\n@blue-6: @blue-base;\n@blue-7: color(colorPalette('@{blue-6}', 7));\n@blue-8: color(colorPalette('@{blue-6}', 8));\n@blue-9: color(colorPalette('@{blue-6}', 9));\n@blue-10: color(colorPalette('@{blue-6}', 10));\n\n@purple-base: #722ed1;\n@purple-1: color(colorPalette('@{purple-6}', 1));\n@purple-2: color(colorPalette('@{purple-6}', 2));\n@purple-3: color(colorPalette('@{purple-6}', 3));\n@purple-4: color(colorPalette('@{purple-6}', 4));\n@purple-5: color(colorPalette('@{purple-6}', 5));\n@purple-6: @purple-base;\n@purple-7: color(colorPalette('@{purple-6}', 7));\n@purple-8: color(colorPalette('@{purple-6}', 8));\n@purple-9: color(colorPalette('@{purple-6}', 9));\n@purple-10: color(colorPalette('@{purple-6}', 10));\n\n@cyan-base: #13c2c2;\n@cyan-1: color(colorPalette('@{cyan-6}', 1));\n@cyan-2: color(colorPalette('@{cyan-6}', 2));\n@cyan-3: color(colorPalette('@{cyan-6}', 3));\n@cyan-4: color(colorPalette('@{cyan-6}', 4));\n@cyan-5: color(colorPalette('@{cyan-6}', 5));\n@cyan-6: @cyan-base;\n@cyan-7: color(colorPalette('@{cyan-6}', 7));\n@cyan-8: color(colorPalette('@{cyan-6}', 8));\n@cyan-9: color(colorPalette('@{cyan-6}', 9));\n@cyan-10: color(colorPalette('@{cyan-6}', 10));\n\n@green-base: #52c41a;\n@green-1: color(colorPalette('@{green-6}', 1));\n@green-2: color(colorPalette('@{green-6}', 2));\n@green-3: color(colorPalette('@{green-6}', 3));\n@green-4: color(colorPalette('@{green-6}', 4));\n@green-5: color(colorPalette('@{green-6}', 5));\n@green-6: @green-base;\n@green-7: color(colorPalette('@{green-6}', 7));\n@green-8: color(colorPalette('@{green-6}', 8));\n@green-9: color(colorPalette('@{green-6}', 9));\n@green-10: color(colorPalette('@{green-6}', 10));\n\n@magenta-base: #eb2f96;\n@magenta-1: color(colorPalette('@{magenta-6}', 1));\n@magenta-2: color(colorPalette('@{magenta-6}', 2));\n@magenta-3: color(colorPalette('@{magenta-6}', 3));\n@magenta-4: color(colorPalette('@{magenta-6}', 4));\n@magenta-5: color(colorPalette('@{magenta-6}', 5));\n@magenta-6: @magenta-base;\n@magenta-7: color(colorPalette('@{magenta-6}', 7));\n@magenta-8: color(colorPalette('@{magenta-6}', 8));\n@magenta-9: color(colorPalette('@{magenta-6}', 9));\n@magenta-10: color(colorPalette('@{magenta-6}', 10));\n\n// alias of magenta\n@pink-base: #eb2f96;\n@pink-1: color(colorPalette('@{pink-6}', 1));\n@pink-2: color(colorPalette('@{pink-6}', 2));\n@pink-3: color(colorPalette('@{pink-6}', 3));\n@pink-4: color(colorPalette('@{pink-6}', 4));\n@pink-5: color(colorPalette('@{pink-6}', 5));\n@pink-6: @pink-base;\n@pink-7: color(colorPalette('@{pink-6}', 7));\n@pink-8: color(colorPalette('@{pink-6}', 8));\n@pink-9: color(colorPalette('@{pink-6}', 9));\n@pink-10: color(colorPalette('@{pink-6}', 10));\n\n@red-base: #f5222d;\n@red-1: color(colorPalette('@{red-6}', 1));\n@red-2: color(colorPalette('@{red-6}', 2));\n@red-3: color(colorPalette('@{red-6}', 3));\n@red-4: color(colorPalette('@{red-6}', 4));\n@red-5: color(colorPalette('@{red-6}', 5));\n@red-6: @red-base;\n@red-7: color(colorPalette('@{red-6}', 7));\n@red-8: color(colorPalette('@{red-6}', 8));\n@red-9: color(colorPalette('@{red-6}', 9));\n@red-10: color(colorPalette('@{red-6}', 10));\n\n@orange-base: #fa8c16;\n@orange-1: color(colorPalette('@{orange-6}', 1));\n@orange-2: color(colorPalette('@{orange-6}', 2));\n@orange-3: color(colorPalette('@{orange-6}', 3));\n@orange-4: color(colorPalette('@{orange-6}', 4));\n@orange-5: color(colorPalette('@{orange-6}', 5));\n@orange-6: @orange-base;\n@orange-7: color(colorPalette('@{orange-6}', 7));\n@orange-8: color(colorPalette('@{orange-6}', 8));\n@orange-9: color(colorPalette('@{orange-6}', 9));\n@orange-10: color(colorPalette('@{orange-6}', 10));\n\n@yellow-base: #fadb14;\n@yellow-1: color(colorPalette('@{yellow-6}', 1));\n@yellow-2: color(colorPalette('@{yellow-6}', 2));\n@yellow-3: color(colorPalette('@{yellow-6}', 3));\n@yellow-4: color(colorPalette('@{yellow-6}', 4));\n@yellow-5: color(colorPalette('@{yellow-6}', 5));\n@yellow-6: @yellow-base;\n@yellow-7: color(colorPalette('@{yellow-6}', 7));\n@yellow-8: color(colorPalette('@{yellow-6}', 8));\n@yellow-9: color(colorPalette('@{yellow-6}', 9));\n@yellow-10: color(colorPalette('@{yellow-6}', 10));\n\n@volcano-base: #fa541c;\n@volcano-1: color(colorPalette('@{volcano-6}', 1));\n@volcano-2: color(colorPalette('@{volcano-6}', 2));\n@volcano-3: color(colorPalette('@{volcano-6}', 3));\n@volcano-4: color(colorPalette('@{volcano-6}', 4));\n@volcano-5: color(colorPalette('@{volcano-6}', 5));\n@volcano-6: @volcano-base;\n@volcano-7: color(colorPalette('@{volcano-6}', 7));\n@volcano-8: color(colorPalette('@{volcano-6}', 8));\n@volcano-9: color(colorPalette('@{volcano-6}', 9));\n@volcano-10: color(colorPalette('@{volcano-6}', 10));\n\n@geekblue-base: #2f54eb;\n@geekblue-1: color(colorPalette('@{geekblue-6}', 1));\n@geekblue-2: color(colorPalette('@{geekblue-6}', 2));\n@geekblue-3: color(colorPalette('@{geekblue-6}', 3));\n@geekblue-4: color(colorPalette('@{geekblue-6}', 4));\n@geekblue-5: color(colorPalette('@{geekblue-6}', 5));\n@geekblue-6: @geekblue-base;\n@geekblue-7: color(colorPalette('@{geekblue-6}', 7));\n@geekblue-8: color(colorPalette('@{geekblue-6}', 8));\n@geekblue-9: color(colorPalette('@{geekblue-6}', 9));\n@geekblue-10: color(colorPalette('@{geekblue-6}', 10));\n\n@lime-base: #a0d911;\n@lime-1: color(colorPalette('@{lime-6}', 1));\n@lime-2: color(colorPalette('@{lime-6}', 2));\n@lime-3: color(colorPalette('@{lime-6}', 3));\n@lime-4: color(colorPalette('@{lime-6}', 4));\n@lime-5: color(colorPalette('@{lime-6}', 5));\n@lime-6: @lime-base;\n@lime-7: color(colorPalette('@{lime-6}', 7));\n@lime-8: color(colorPalette('@{lime-6}', 8));\n@lime-9: color(colorPalette('@{lime-6}', 9));\n@lime-10: color(colorPalette('@{lime-6}', 10));\n\n@gold-base: #faad14;\n@gold-1: color(colorPalette('@{gold-6}', 1));\n@gold-2: color(colorPalette('@{gold-6}', 2));\n@gold-3: color(colorPalette('@{gold-6}', 3));\n@gold-4: color(colorPalette('@{gold-6}', 4));\n@gold-5: color(colorPalette('@{gold-6}', 5));\n@gold-6: @gold-base;\n@gold-7: color(colorPalette('@{gold-6}', 7));\n@gold-8: color(colorPalette('@{gold-6}', 8));\n@gold-9: color(colorPalette('@{gold-6}', 9));\n@gold-10: color(colorPalette('@{gold-6}', 10));\n\n@preset-colors: pink, magenta, red, volcano, orange, yellow, gold, cyan, lime, green, blue, geekblue,\n  purple;\n"
  },
  {
    "path": "components/style/color/tinyColor.js",
    "content": "const tinycolor = require('./tinycolor2');\n\nmodule.exports = {\n  install: function (less, pluginManager, functions) {\n    functions.add('tinycolor', function (...args) {\n      return tinycolor(...args.map(ref => ref.value));\n    });\n  }\n};\n"
  },
  {
    "path": "components/style/color/tinyColor.less",
    "content": "@plugin \"./tinyColor\";\n"
  },
  {
    "path": "components/style/color/tinycolor2.js",
    "content": "// TinyColor v1.4.1\n// https://github.com/bgrins/TinyColor\n// 2016-07-07, Brian Grinstead, MIT License\nvar trimLeft = /^\\s+/,\n  trimRight = /\\s+$/,\n  tinyCounter = 0,\n  mathRound = Math.round,\n  mathMin = Math.min,\n  mathMax = Math.max,\n  mathRandom = Math.random;\n\nfunction tinycolor(color, opts) {\n\n  color = (color) ? color : '';\n  opts = opts || {};\n\n  // If input is already a tinycolor, return itself\n  if (color instanceof tinycolor) {\n    return color;\n  }\n  // If we are called as a function, call using new instead\n  if (!(this instanceof tinycolor)) {\n    return new tinycolor(color, opts);\n  }\n\n  var rgb = inputToRGB(color);\n  this._originalInput = color,\n    this._r = rgb.r,\n    this._g = rgb.g,\n    this._b = rgb.b,\n    this._a = rgb.a,\n    this._roundA = mathRound(100 * this._a) / 100,\n    this._format = opts.format || rgb.format;\n  this._gradientType = opts.gradientType;\n\n  // Don't let the range of [0,255] come back in [0,1].\n  // Potentially lose a little bit of precision here, but will fix issues where\n  // .5 gets interpreted as half of the total, instead of half of 1\n  // If it was supposed to be 128, this was already taken care of by inputToRgb\n  if (this._r < 1) { this._r = mathRound(this._r); }\n  if (this._g < 1) { this._g = mathRound(this._g); }\n  if (this._b < 1) { this._b = mathRound(this._b); }\n\n  this._ok = rgb.ok;\n  this._tc_id = tinyCounter++;\n}\n\ntinycolor.prototype = {\n  isDark: function () {\n    return this.getBrightness() < 128;\n  },\n  isLight: function () {\n    return !this.isDark();\n  },\n  isValid: function () {\n    return this._ok;\n  },\n  getOriginalInput: function () {\n    return this._originalInput;\n  },\n  getFormat: function () {\n    return this._format;\n  },\n  getAlpha: function () {\n    return this._a;\n  },\n  getBrightness: function () {\n    //http://www.w3.org/TR/AERT#color-contrast\n    var rgb = this.toRgb();\n    return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000;\n  },\n  getLuminance: function () {\n    //http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef\n    var rgb = this.toRgb();\n    var RsRGB, GsRGB, BsRGB, R, G, B;\n    RsRGB = rgb.r / 255;\n    GsRGB = rgb.g / 255;\n    BsRGB = rgb.b / 255;\n\n    if (RsRGB <= 0.03928) { R = RsRGB / 12.92; } else { R = Math.pow(((RsRGB + 0.055) / 1.055), 2.4); }\n    if (GsRGB <= 0.03928) { G = GsRGB / 12.92; } else { G = Math.pow(((GsRGB + 0.055) / 1.055), 2.4); }\n    if (BsRGB <= 0.03928) { B = BsRGB / 12.92; } else { B = Math.pow(((BsRGB + 0.055) / 1.055), 2.4); }\n    return (0.2126 * R) + (0.7152 * G) + (0.0722 * B);\n  },\n  setAlpha: function (value) {\n    this._a = boundAlpha(value);\n    this._roundA = mathRound(100 * this._a) / 100;\n    return this;\n  },\n  toHsv: function () {\n    var hsv = rgbToHsv(this._r, this._g, this._b);\n    return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: this._a };\n  },\n  toHsvString: function () {\n    var hsv = rgbToHsv(this._r, this._g, this._b);\n    var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100);\n    return (this._a == 1) ?\n      \"hsv(\" + h + \", \" + s + \"%, \" + v + \"%)\" :\n      \"hsva(\" + h + \", \" + s + \"%, \" + v + \"%, \" + this._roundA + \")\";\n  },\n  toHsl: function () {\n    var hsl = rgbToHsl(this._r, this._g, this._b);\n    return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: this._a };\n  },\n  toHslString: function () {\n    var hsl = rgbToHsl(this._r, this._g, this._b);\n    var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100);\n    return (this._a == 1) ?\n      \"hsl(\" + h + \", \" + s + \"%, \" + l + \"%)\" :\n      \"hsla(\" + h + \", \" + s + \"%, \" + l + \"%, \" + this._roundA + \")\";\n  },\n  toHex: function (allow3Char) {\n    return rgbToHex(this._r, this._g, this._b, allow3Char);\n  },\n  toHexString: function (allow3Char) {\n    return '#' + this.toHex(allow3Char);\n  },\n  toHex8: function (allow4Char) {\n    return rgbaToHex(this._r, this._g, this._b, this._a, allow4Char);\n  },\n  toHex8String: function (allow4Char) {\n    return '#' + this.toHex8(allow4Char);\n  },\n  toRgb: function () {\n    return { r: mathRound(this._r), g: mathRound(this._g), b: mathRound(this._b), a: this._a };\n  },\n  toRgbString: function () {\n    return (this._a == 1) ?\n      \"rgb(\" + mathRound(this._r) + \", \" + mathRound(this._g) + \", \" + mathRound(this._b) + \")\" :\n      \"rgba(\" + mathRound(this._r) + \", \" + mathRound(this._g) + \", \" + mathRound(this._b) + \", \" + this._roundA + \")\";\n  },\n  toPercentageRgb: function () {\n    return { r: mathRound(bound01(this._r, 255) * 100) + \"%\", g: mathRound(bound01(this._g, 255) * 100) + \"%\", b: mathRound(bound01(this._b, 255) * 100) + \"%\", a: this._a };\n  },\n  toPercentageRgbString: function () {\n    return (this._a == 1) ?\n      \"rgb(\" + mathRound(bound01(this._r, 255) * 100) + \"%, \" + mathRound(bound01(this._g, 255) * 100) + \"%, \" + mathRound(bound01(this._b, 255) * 100) + \"%)\" :\n      \"rgba(\" + mathRound(bound01(this._r, 255) * 100) + \"%, \" + mathRound(bound01(this._g, 255) * 100) + \"%, \" + mathRound(bound01(this._b, 255) * 100) + \"%, \" + this._roundA + \")\";\n  },\n  toName: function () {\n    if (this._a === 0) {\n      return \"transparent\";\n    }\n\n    if (this._a < 1) {\n      return false;\n    }\n\n    return hexNames[rgbToHex(this._r, this._g, this._b, true)] || false;\n  },\n  toFilter: function (secondColor) {\n    var hex8String = '#' + rgbaToArgbHex(this._r, this._g, this._b, this._a);\n    var secondHex8String = hex8String;\n    var gradientType = this._gradientType ? \"GradientType = 1, \" : \"\";\n\n    if (secondColor) {\n      var s = tinycolor(secondColor);\n      secondHex8String = '#' + rgbaToArgbHex(s._r, s._g, s._b, s._a);\n    }\n\n    return \"progid:DXImageTransform.Microsoft.gradient(\" + gradientType + \"startColorstr=\" + hex8String + \",endColorstr=\" + secondHex8String + \")\";\n  },\n  toString: function (format) {\n    var formatSet = !!format;\n    format = format || this._format;\n\n    var formattedString = false;\n    var hasAlpha = this._a < 1 && this._a >= 0;\n    var needsAlphaFormat = !formatSet && hasAlpha && (format === \"hex\" || format === \"hex6\" || format === \"hex3\" || format === \"hex4\" || format === \"hex8\" || format === \"name\");\n\n    if (needsAlphaFormat) {\n      // Special case for \"transparent\", all other non-alpha formats\n      // will return rgba when there is transparency.\n      if (format === \"name\" && this._a === 0) {\n        return this.toName();\n      }\n      return this.toRgbString();\n    }\n    if (format === \"rgb\") {\n      formattedString = this.toRgbString();\n    }\n    if (format === \"prgb\") {\n      formattedString = this.toPercentageRgbString();\n    }\n    if (format === \"hex\" || format === \"hex6\") {\n      formattedString = this.toHexString();\n    }\n    if (format === \"hex3\") {\n      formattedString = this.toHexString(true);\n    }\n    if (format === \"hex4\") {\n      formattedString = this.toHex8String(true);\n    }\n    if (format === \"hex8\") {\n      formattedString = this.toHex8String();\n    }\n    if (format === \"name\") {\n      formattedString = this.toName();\n    }\n    if (format === \"hsl\") {\n      formattedString = this.toHslString();\n    }\n    if (format === \"hsv\") {\n      formattedString = this.toHsvString();\n    }\n\n    return formattedString || this.toHexString();\n  },\n  clone: function () {\n    return tinycolor(this.toString());\n  },\n\n  _applyModification: function (fn, args) {\n    var color = fn.apply(null, [this].concat([].slice.call(args)));\n    this._r = color._r;\n    this._g = color._g;\n    this._b = color._b;\n    this.setAlpha(color._a);\n    return this;\n  },\n  lighten: function () {\n    return this._applyModification(lighten, arguments);\n  },\n  brighten: function () {\n    return this._applyModification(brighten, arguments);\n  },\n  darken: function () {\n    return this._applyModification(darken, arguments);\n  },\n  desaturate: function () {\n    return this._applyModification(desaturate, arguments);\n  },\n  saturate: function () {\n    return this._applyModification(saturate, arguments);\n  },\n  greyscale: function () {\n    return this._applyModification(greyscale, arguments);\n  },\n  spin: function () {\n    return this._applyModification(spin, arguments);\n  },\n\n  _applyCombination: function (fn, args) {\n    return fn.apply(null, [this].concat([].slice.call(args)));\n  },\n  analogous: function () {\n    return this._applyCombination(analogous, arguments);\n  },\n  complement: function () {\n    return this._applyCombination(complement, arguments);\n  },\n  monochromatic: function () {\n    return this._applyCombination(monochromatic, arguments);\n  },\n  splitcomplement: function () {\n    return this._applyCombination(splitcomplement, arguments);\n  },\n  triad: function () {\n    return this._applyCombination(triad, arguments);\n  },\n  tetrad: function () {\n    return this._applyCombination(tetrad, arguments);\n  }\n};\n\n// If input is an object, force 1 into \"1.0\" to handle ratios properly\n// String input requires \"1.0\" as input, so 1 will be treated as 1\ntinycolor.fromRatio = function (color, opts) {\n  if (typeof color == \"object\") {\n    var newColor = {};\n    for (var i in color) {\n      if (color.hasOwnProperty(i)) {\n        if (i === \"a\") {\n          newColor[i] = color[i];\n        }\n        else {\n          newColor[i] = convertToPercentage(color[i]);\n        }\n      }\n    }\n    color = newColor;\n  }\n\n  return tinycolor(color, opts);\n};\n\n// Given a string or object, convert that input to RGB\n// Possible string inputs:\n//\n//     \"red\"\n//     \"#f00\" or \"f00\"\n//     \"#ff0000\" or \"ff0000\"\n//     \"#ff000000\" or \"ff000000\"\n//     \"rgb 255 0 0\" or \"rgb (255, 0, 0)\"\n//     \"rgb 1.0 0 0\" or \"rgb (1, 0, 0)\"\n//     \"rgba (255, 0, 0, 1)\" or \"rgba 255, 0, 0, 1\"\n//     \"rgba (1.0, 0, 0, 1)\" or \"rgba 1.0, 0, 0, 1\"\n//     \"hsl(0, 100%, 50%)\" or \"hsl 0 100% 50%\"\n//     \"hsla(0, 100%, 50%, 1)\" or \"hsla 0 100% 50%, 1\"\n//     \"hsv(0, 100%, 100%)\" or \"hsv 0 100% 100%\"\n//\nfunction inputToRGB(color) {\n\n  var rgb = { r: 0, g: 0, b: 0 };\n  var a = 1;\n  var s = null;\n  var v = null;\n  var l = null;\n  var ok = false;\n  var format = false;\n\n  if (typeof color == \"string\") {\n    color = stringInputToObject(color);\n  }\n\n  if (typeof color == \"object\") {\n    if (isValidCSSUnit(color.r) && isValidCSSUnit(color.g) && isValidCSSUnit(color.b)) {\n      rgb = rgbToRgb(color.r, color.g, color.b);\n      ok = true;\n      format = String(color.r).substr(-1) === \"%\" ? \"prgb\" : \"rgb\";\n    }\n    else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.v)) {\n      s = convertToPercentage(color.s);\n      v = convertToPercentage(color.v);\n      rgb = hsvToRgb(color.h, s, v);\n      ok = true;\n      format = \"hsv\";\n    }\n    else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.l)) {\n      s = convertToPercentage(color.s);\n      l = convertToPercentage(color.l);\n      rgb = hslToRgb(color.h, s, l);\n      ok = true;\n      format = \"hsl\";\n    }\n\n    if (color.hasOwnProperty(\"a\")) {\n      a = color.a;\n    }\n  }\n\n  a = boundAlpha(a);\n\n  return {\n    ok: ok,\n    format: color.format || format,\n    r: mathMin(255, mathMax(rgb.r, 0)),\n    g: mathMin(255, mathMax(rgb.g, 0)),\n    b: mathMin(255, mathMax(rgb.b, 0)),\n    a: a\n  };\n}\n\n// Conversion Functions\n// --------------------\n\n// rgbToHsl, rgbToHsv, hslToRgb, hsvToRgb modified from:\n// <http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript>\n\n// rgbToRgb\n// Handle bounds / percentage checking to conform to CSS color spec\n// <http://www.w3.org/TR/css3-color/>\n// *Assumes:* r, g, b in [0, 255] or [0, 1]\n// *Returns:* { r, g, b } in [0, 255]\nfunction rgbToRgb(r, g, b) {\n  return {\n    r: bound01(r, 255) * 255,\n    g: bound01(g, 255) * 255,\n    b: bound01(b, 255) * 255\n  };\n}\n\n// rgbToHsl\n// Converts an RGB color value to HSL.\n// *Assumes:* r, g, and b are contained in [0, 255] or [0, 1]\n// *Returns:* { h, s, l } in [0,1]\nfunction rgbToHsl(r, g, b) {\n\n  r = bound01(r, 255);\n  g = bound01(g, 255);\n  b = bound01(b, 255);\n\n  var max = mathMax(r, g, b), min = mathMin(r, g, b);\n  var h, s, l = (max + min) / 2;\n\n  if (max == min) {\n    h = s = 0; // achromatic\n  }\n  else {\n    var d = max - min;\n    s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n    switch (max) {\n      case r: h = (g - b) / d + (g < b ? 6 : 0); break;\n      case g: h = (b - r) / d + 2; break;\n      case b: h = (r - g) / d + 4; break;\n    }\n\n    h /= 6;\n  }\n\n  return { h: h, s: s, l: l };\n}\n\n// hslToRgb\n// Converts an HSL color value to RGB.\n// *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100]\n// *Returns:* { r, g, b } in the set [0, 255]\nfunction hslToRgb(h, s, l) {\n  var r, g, b;\n\n  h = bound01(h, 360);\n  s = bound01(s, 100);\n  l = bound01(l, 100);\n\n  function hue2rgb(p, q, t) {\n    if (t < 0) t += 1;\n    if (t > 1) t -= 1;\n    if (t < 1 / 6) return p + (q - p) * 6 * t;\n    if (t < 1 / 2) return q;\n    if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;\n    return p;\n  }\n\n  if (s === 0) {\n    r = g = b = l; // achromatic\n  }\n  else {\n    var q = l < 0.5 ? l * (1 + s) : l + s - l * s;\n    var p = 2 * l - q;\n    r = hue2rgb(p, q, h + 1 / 3);\n    g = hue2rgb(p, q, h);\n    b = hue2rgb(p, q, h - 1 / 3);\n  }\n\n  return { r: r * 255, g: g * 255, b: b * 255 };\n}\n\n// rgbToHsv\n// Converts an RGB color value to HSV\n// *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1]\n// *Returns:* { h, s, v } in [0,1]\nfunction rgbToHsv(r, g, b) {\n\n  r = bound01(r, 255);\n  g = bound01(g, 255);\n  b = bound01(b, 255);\n\n  var max = mathMax(r, g, b), min = mathMin(r, g, b);\n  var h, s, v = max;\n\n  var d = max - min;\n  s = max === 0 ? 0 : d / max;\n\n  if (max == min) {\n    h = 0; // achromatic\n  }\n  else {\n    switch (max) {\n      case r: h = (g - b) / d + (g < b ? 6 : 0); break;\n      case g: h = (b - r) / d + 2; break;\n      case b: h = (r - g) / d + 4; break;\n    }\n    h /= 6;\n  }\n  return { h: h, s: s, v: v };\n}\n\n// hsvToRgb\n// Converts an HSV color value to RGB.\n// *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100]\n// *Returns:* { r, g, b } in the set [0, 255]\nfunction hsvToRgb(h, s, v) {\n\n  h = bound01(h, 360) * 6;\n  s = bound01(s, 100);\n  v = bound01(v, 100);\n\n  var i = Math.floor(h),\n    f = h - i,\n    p = v * (1 - s),\n    q = v * (1 - f * s),\n    t = v * (1 - (1 - f) * s),\n    mod = i % 6,\n    r = [v, q, p, p, t, v][mod],\n    g = [t, v, v, q, p, p][mod],\n    b = [p, p, t, v, v, q][mod];\n\n  return { r: r * 255, g: g * 255, b: b * 255 };\n}\n\n// rgbToHex\n// Converts an RGB color to hex\n// Assumes r, g, and b are contained in the set [0, 255]\n// Returns a 3 or 6 character hex\nfunction rgbToHex(r, g, b, allow3Char) {\n\n  var hex = [\n    pad2(mathRound(r).toString(16)),\n    pad2(mathRound(g).toString(16)),\n    pad2(mathRound(b).toString(16))\n  ];\n\n  // Return a 3 character hex if possible\n  if (allow3Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) {\n    return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0);\n  }\n\n  return hex.join(\"\");\n}\n\n// rgbaToHex\n// Converts an RGBA color plus alpha transparency to hex\n// Assumes r, g, b are contained in the set [0, 255] and\n// a in [0, 1]. Returns a 4 or 8 character rgba hex\nfunction rgbaToHex(r, g, b, a, allow4Char) {\n\n  var hex = [\n    pad2(mathRound(r).toString(16)),\n    pad2(mathRound(g).toString(16)),\n    pad2(mathRound(b).toString(16)),\n    pad2(convertDecimalToHex(a))\n  ];\n\n  // Return a 4 character hex if possible\n  if (allow4Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1) && hex[3].charAt(0) == hex[3].charAt(1)) {\n    return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0) + hex[3].charAt(0);\n  }\n\n  return hex.join(\"\");\n}\n\n// rgbaToArgbHex\n// Converts an RGBA color to an ARGB Hex8 string\n// Rarely used, but required for \"toFilter()\"\nfunction rgbaToArgbHex(r, g, b, a) {\n\n  var hex = [\n    pad2(convertDecimalToHex(a)),\n    pad2(mathRound(r).toString(16)),\n    pad2(mathRound(g).toString(16)),\n    pad2(mathRound(b).toString(16))\n  ];\n\n  return hex.join(\"\");\n}\n\n// equals\n// Can be called with any tinycolor input\ntinycolor.equals = function (color1, color2) {\n  if (!color1 || !color2) { return false; }\n  return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString();\n};\n\ntinycolor.random = function () {\n  return tinycolor.fromRatio({\n    r: mathRandom(),\n    g: mathRandom(),\n    b: mathRandom()\n  });\n};\n\n// Modification Functions\n// ----------------------\n// Thanks to less.js for some of the basics here\n// <https://github.com/cloudhead/less.js/blob/master/lib/less/functions.js>\n\nfunction desaturate(color, amount) {\n  amount = (amount === 0) ? 0 : (amount || 10);\n  var hsl = tinycolor(color).toHsl();\n  hsl.s -= amount / 100;\n  hsl.s = clamp01(hsl.s);\n  return tinycolor(hsl);\n}\n\nfunction saturate(color, amount) {\n  amount = (amount === 0) ? 0 : (amount || 10);\n  var hsl = tinycolor(color).toHsl();\n  hsl.s += amount / 100;\n  hsl.s = clamp01(hsl.s);\n  return tinycolor(hsl);\n}\n\nfunction greyscale(color) {\n  return tinycolor(color).desaturate(100);\n}\n\nfunction lighten(color, amount) {\n  amount = (amount === 0) ? 0 : (amount || 10);\n  var hsl = tinycolor(color).toHsl();\n  hsl.l += amount / 100;\n  hsl.l = clamp01(hsl.l);\n  return tinycolor(hsl);\n}\n\nfunction brighten(color, amount) {\n  amount = (amount === 0) ? 0 : (amount || 10);\n  var rgb = tinycolor(color).toRgb();\n  rgb.r = mathMax(0, mathMin(255, rgb.r - mathRound(255 * - (amount / 100))));\n  rgb.g = mathMax(0, mathMin(255, rgb.g - mathRound(255 * - (amount / 100))));\n  rgb.b = mathMax(0, mathMin(255, rgb.b - mathRound(255 * - (amount / 100))));\n  return tinycolor(rgb);\n}\n\nfunction darken(color, amount) {\n  amount = (amount === 0) ? 0 : (amount || 10);\n  var hsl = tinycolor(color).toHsl();\n  hsl.l -= amount / 100;\n  hsl.l = clamp01(hsl.l);\n  return tinycolor(hsl);\n}\n\n// Spin takes a positive or negative amount within [-360, 360] indicating the change of hue.\n// Values outside of this range will be wrapped into this range.\nfunction spin(color, amount) {\n  var hsl = tinycolor(color).toHsl();\n  var hue = (hsl.h + amount) % 360;\n  hsl.h = hue < 0 ? 360 + hue : hue;\n  return tinycolor(hsl);\n}\n\n// Combination Functions\n// ---------------------\n// Thanks to jQuery xColor for some of the ideas behind these\n// <https://github.com/infusion/jQuery-xcolor/blob/master/jquery.xcolor.js>\n\nfunction complement(color) {\n  var hsl = tinycolor(color).toHsl();\n  hsl.h = (hsl.h + 180) % 360;\n  return tinycolor(hsl);\n}\n\nfunction triad(color) {\n  var hsl = tinycolor(color).toHsl();\n  var h = hsl.h;\n  return [\n    tinycolor(color),\n    tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }),\n    tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l })\n  ];\n}\n\nfunction tetrad(color) {\n  var hsl = tinycolor(color).toHsl();\n  var h = hsl.h;\n  return [\n    tinycolor(color),\n    tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }),\n    tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }),\n    tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l })\n  ];\n}\n\nfunction splitcomplement(color) {\n  var hsl = tinycolor(color).toHsl();\n  var h = hsl.h;\n  return [\n    tinycolor(color),\n    tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l }),\n    tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l })\n  ];\n}\n\nfunction analogous(color, results, slices) {\n  results = results || 6;\n  slices = slices || 30;\n\n  var hsl = tinycolor(color).toHsl();\n  var part = 360 / slices;\n  var ret = [tinycolor(color)];\n\n  for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results;) {\n    hsl.h = (hsl.h + part) % 360;\n    ret.push(tinycolor(hsl));\n  }\n  return ret;\n}\n\nfunction monochromatic(color, results) {\n  results = results || 6;\n  var hsv = tinycolor(color).toHsv();\n  var h = hsv.h, s = hsv.s, v = hsv.v;\n  var ret = [];\n  var modification = 1 / results;\n\n  while (results--) {\n    ret.push(tinycolor({ h: h, s: s, v: v }));\n    v = (v + modification) % 1;\n  }\n\n  return ret;\n}\n\n// Utility Functions\n// ---------------------\n\ntinycolor.mix = function (color1, color2, amount) {\n  amount = (amount === 0) ? 0 : (amount || 50);\n\n  var rgb1 = tinycolor(color1).toRgb();\n  var rgb2 = tinycolor(color2).toRgb();\n\n  var p = amount / 100;\n\n  var rgba = {\n    r: ((rgb2.r - rgb1.r) * p) + rgb1.r,\n    g: ((rgb2.g - rgb1.g) * p) + rgb1.g,\n    b: ((rgb2.b - rgb1.b) * p) + rgb1.b,\n    a: ((rgb2.a - rgb1.a) * p) + rgb1.a\n  };\n\n  return tinycolor(rgba);\n};\n\n// Readability Functions\n// ---------------------\n// <http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef (WCAG Version 2)\n\n// contrast\n// Analyze the 2 colors and returns the color contrast defined by (WCAG Version 2)\ntinycolor.readability = function (color1, color2) {\n  var c1 = tinycolor(color1);\n  var c2 = tinycolor(color2);\n  return (Math.max(c1.getLuminance(), c2.getLuminance()) + 0.05) / (Math.min(c1.getLuminance(), c2.getLuminance()) + 0.05);\n};\n\n// isReadable\n// Ensure that foreground and background color combinations meet WCAG2 guidelines.\n// The third argument is an optional Object.\n//      the 'level' property states 'AA' or 'AAA' - if missing or invalid, it defaults to 'AA';\n//      the 'size' property states 'large' or 'small' - if missing or invalid, it defaults to 'small'.\n// If the entire object is absent, isReadable defaults to {level:\"AA\",size:\"small\"}.\n\n// *Example*\n//    tinycolor.isReadable(\"#000\", \"#111\") => false\n//    tinycolor.isReadable(\"#000\", \"#111\",{level:\"AA\",size:\"large\"}) => false\ntinycolor.isReadable = function (color1, color2, wcag2) {\n  var readability = tinycolor.readability(color1, color2);\n  var wcag2Parms, out;\n\n  out = false;\n\n  wcag2Parms = validateWCAG2Parms(wcag2);\n  switch (wcag2Parms.level + wcag2Parms.size) {\n    case \"AAsmall\":\n    case \"AAAlarge\":\n      out = readability >= 4.5;\n      break;\n    case \"AAlarge\":\n      out = readability >= 3;\n      break;\n    case \"AAAsmall\":\n      out = readability >= 7;\n      break;\n  }\n  return out;\n\n};\n\n// mostReadable\n// Given a base color and a list of possible foreground or background\n// colors for that base, returns the most readable color.\n// Optionally returns Black or White if the most readable color is unreadable.\n// *Example*\n//    tinycolor.mostReadable(tinycolor.mostReadable(\"#123\", [\"#124\", \"#125\"],{includeFallbackColors:false}).toHexString(); // \"#112255\"\n//    tinycolor.mostReadable(tinycolor.mostReadable(\"#123\", [\"#124\", \"#125\"],{includeFallbackColors:true}).toHexString();  // \"#ffffff\"\n//    tinycolor.mostReadable(\"#a8015a\", [\"#faf3f3\"],{includeFallbackColors:true,level:\"AAA\",size:\"large\"}).toHexString(); // \"#faf3f3\"\n//    tinycolor.mostReadable(\"#a8015a\", [\"#faf3f3\"],{includeFallbackColors:true,level:\"AAA\",size:\"small\"}).toHexString(); // \"#ffffff\"\ntinycolor.mostReadable = function (baseColor, colorList, args) {\n  var bestColor = null;\n  var bestScore = 0;\n  var readability;\n  var includeFallbackColors, level, size;\n  args = args || {};\n  includeFallbackColors = args.includeFallbackColors;\n  level = args.level;\n  size = args.size;\n\n  for (var i = 0; i < colorList.length; i++) {\n    readability = tinycolor.readability(baseColor, colorList[i]);\n    if (readability > bestScore) {\n      bestScore = readability;\n      bestColor = tinycolor(colorList[i]);\n    }\n  }\n\n  if (tinycolor.isReadable(baseColor, bestColor, { \"level\": level, \"size\": size }) || !includeFallbackColors) {\n    return bestColor;\n  }\n  else {\n    args.includeFallbackColors = false;\n    return tinycolor.mostReadable(baseColor, [\"#fff\", \"#000\"], args);\n  }\n};\n\n// Big List of Colors\n// ------------------\n// <http://www.w3.org/TR/css3-color/#svg-color>\nvar names = tinycolor.names = {\n  aliceblue: \"f0f8ff\",\n  antiquewhite: \"faebd7\",\n  aqua: \"0ff\",\n  aquamarine: \"7fffd4\",\n  azure: \"f0ffff\",\n  beige: \"f5f5dc\",\n  bisque: \"ffe4c4\",\n  black: \"000\",\n  blanchedalmond: \"ffebcd\",\n  blue: \"00f\",\n  blueviolet: \"8a2be2\",\n  brown: \"a52a2a\",\n  burlywood: \"deb887\",\n  burntsienna: \"ea7e5d\",\n  cadetblue: \"5f9ea0\",\n  chartreuse: \"7fff00\",\n  chocolate: \"d2691e\",\n  coral: \"ff7f50\",\n  cornflowerblue: \"6495ed\",\n  cornsilk: \"fff8dc\",\n  crimson: \"dc143c\",\n  cyan: \"0ff\",\n  darkblue: \"00008b\",\n  darkcyan: \"008b8b\",\n  darkgoldenrod: \"b8860b\",\n  darkgray: \"a9a9a9\",\n  darkgreen: \"006400\",\n  darkgrey: \"a9a9a9\",\n  darkkhaki: \"bdb76b\",\n  darkmagenta: \"8b008b\",\n  darkolivegreen: \"556b2f\",\n  darkorange: \"ff8c00\",\n  darkorchid: \"9932cc\",\n  darkred: \"8b0000\",\n  darksalmon: \"e9967a\",\n  darkseagreen: \"8fbc8f\",\n  darkslateblue: \"483d8b\",\n  darkslategray: \"2f4f4f\",\n  darkslategrey: \"2f4f4f\",\n  darkturquoise: \"00ced1\",\n  darkviolet: \"9400d3\",\n  deeppink: \"ff1493\",\n  deepskyblue: \"00bfff\",\n  dimgray: \"696969\",\n  dimgrey: \"696969\",\n  dodgerblue: \"1e90ff\",\n  firebrick: \"b22222\",\n  floralwhite: \"fffaf0\",\n  forestgreen: \"228b22\",\n  fuchsia: \"f0f\",\n  gainsboro: \"dcdcdc\",\n  ghostwhite: \"f8f8ff\",\n  gold: \"ffd700\",\n  goldenrod: \"daa520\",\n  gray: \"808080\",\n  green: \"008000\",\n  greenyellow: \"adff2f\",\n  grey: \"808080\",\n  honeydew: \"f0fff0\",\n  hotpink: \"ff69b4\",\n  indianred: \"cd5c5c\",\n  indigo: \"4b0082\",\n  ivory: \"fffff0\",\n  khaki: \"f0e68c\",\n  lavender: \"e6e6fa\",\n  lavenderblush: \"fff0f5\",\n  lawngreen: \"7cfc00\",\n  lemonchiffon: \"fffacd\",\n  lightblue: \"add8e6\",\n  lightcoral: \"f08080\",\n  lightcyan: \"e0ffff\",\n  lightgoldenrodyellow: \"fafad2\",\n  lightgray: \"d3d3d3\",\n  lightgreen: \"90ee90\",\n  lightgrey: \"d3d3d3\",\n  lightpink: \"ffb6c1\",\n  lightsalmon: \"ffa07a\",\n  lightseagreen: \"20b2aa\",\n  lightskyblue: \"87cefa\",\n  lightslategray: \"789\",\n  lightslategrey: \"789\",\n  lightsteelblue: \"b0c4de\",\n  lightyellow: \"ffffe0\",\n  lime: \"0f0\",\n  limegreen: \"32cd32\",\n  linen: \"faf0e6\",\n  magenta: \"f0f\",\n  maroon: \"800000\",\n  mediumaquamarine: \"66cdaa\",\n  mediumblue: \"0000cd\",\n  mediumorchid: \"ba55d3\",\n  mediumpurple: \"9370db\",\n  mediumseagreen: \"3cb371\",\n  mediumslateblue: \"7b68ee\",\n  mediumspringgreen: \"00fa9a\",\n  mediumturquoise: \"48d1cc\",\n  mediumvioletred: \"c71585\",\n  midnightblue: \"191970\",\n  mintcream: \"f5fffa\",\n  mistyrose: \"ffe4e1\",\n  moccasin: \"ffe4b5\",\n  navajowhite: \"ffdead\",\n  navy: \"000080\",\n  oldlace: \"fdf5e6\",\n  olive: \"808000\",\n  olivedrab: \"6b8e23\",\n  orange: \"ffa500\",\n  orangered: \"ff4500\",\n  orchid: \"da70d6\",\n  palegoldenrod: \"eee8aa\",\n  palegreen: \"98fb98\",\n  paleturquoise: \"afeeee\",\n  palevioletred: \"db7093\",\n  papayawhip: \"ffefd5\",\n  peachpuff: \"ffdab9\",\n  peru: \"cd853f\",\n  pink: \"ffc0cb\",\n  plum: \"dda0dd\",\n  powderblue: \"b0e0e6\",\n  purple: \"800080\",\n  rebeccapurple: \"663399\",\n  red: \"f00\",\n  rosybrown: \"bc8f8f\",\n  royalblue: \"4169e1\",\n  saddlebrown: \"8b4513\",\n  salmon: \"fa8072\",\n  sandybrown: \"f4a460\",\n  seagreen: \"2e8b57\",\n  seashell: \"fff5ee\",\n  sienna: \"a0522d\",\n  silver: \"c0c0c0\",\n  skyblue: \"87ceeb\",\n  slateblue: \"6a5acd\",\n  slategray: \"708090\",\n  slategrey: \"708090\",\n  snow: \"fffafa\",\n  springgreen: \"00ff7f\",\n  steelblue: \"4682b4\",\n  tan: \"d2b48c\",\n  teal: \"008080\",\n  thistle: \"d8bfd8\",\n  tomato: \"ff6347\",\n  turquoise: \"40e0d0\",\n  violet: \"ee82ee\",\n  wheat: \"f5deb3\",\n  white: \"fff\",\n  whitesmoke: \"f5f5f5\",\n  yellow: \"ff0\",\n  yellowgreen: \"9acd32\"\n};\n\n// Make it easy to access colors via hexNames[hex]\nvar hexNames = tinycolor.hexNames = flip(names);\n\n// Utilities\n// ---------\n\n// { 'name1': 'val1' } becomes { 'val1': 'name1' }\nfunction flip(o) {\n  var flipped = {};\n  for (var i in o) {\n    if (o.hasOwnProperty(i)) {\n      flipped[o[i]] = i;\n    }\n  }\n  return flipped;\n}\n\n// Return a valid alpha value [0,1] with all invalid values being set to 1\nfunction boundAlpha(a) {\n  a = parseFloat(a);\n\n  if (isNaN(a) || a < 0 || a > 1) {\n    a = 1;\n  }\n\n  return a;\n}\n\n// Take input from [0, n] and return it as [0, 1]\nfunction bound01(n, max) {\n  if (isOnePointZero(n)) { n = \"100%\"; }\n\n  var processPercent = isPercentage(n);\n  n = mathMin(max, mathMax(0, parseFloat(n)));\n\n  // Automatically convert percentage into number\n  if (processPercent) {\n    n = parseInt(n * max, 10) / 100;\n  }\n\n  // Handle floating point rounding errors\n  if ((Math.abs(n - max) < 0.000001)) {\n    return 1;\n  }\n\n  // Convert into [0, 1] range if it isn't already\n  return (n % max) / parseFloat(max);\n}\n\n// Force a number between 0 and 1\nfunction clamp01(val) {\n  return mathMin(1, mathMax(0, val));\n}\n\n// Parse a base-16 hex value into a base-10 integer\nfunction parseIntFromHex(val) {\n  return parseInt(val, 16);\n}\n\n// Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1\n// <http://stackoverflow.com/questions/7422072/javascript-how-to-detect-number-as-a-decimal-including-1-0>\nfunction isOnePointZero(n) {\n  return typeof n == \"string\" && n.indexOf('.') != -1 && parseFloat(n) === 1;\n}\n\n// Check to see if string passed in is a percentage\nfunction isPercentage(n) {\n  return typeof n === \"string\" && n.indexOf('%') != -1;\n}\n\n// Force a hex value to have 2 characters\nfunction pad2(c) {\n  return c.length == 1 ? '0' + c : '' + c;\n}\n\n// Replace a decimal with it's percentage value\nfunction convertToPercentage(n) {\n  if (n <= 1) {\n    n = (n * 100) + \"%\";\n  }\n\n  return n;\n}\n\n// Converts a decimal to a hex value\nfunction convertDecimalToHex(d) {\n  return Math.round(parseFloat(d) * 255).toString(16);\n}\n// Converts a hex value to a decimal\nfunction convertHexToDecimal(h) {\n  return (parseIntFromHex(h) / 255);\n}\n\nvar matchers = (function () {\n\n  // <http://www.w3.org/TR/css3-values/#integers>\n  var CSS_INTEGER = \"[-\\\\+]?\\\\d+%?\";\n\n  // <http://www.w3.org/TR/css3-values/#number-value>\n  var CSS_NUMBER = \"[-\\\\+]?\\\\d*\\\\.\\\\d+%?\";\n\n  // Allow positive/negative integer/number.  Don't capture the either/or, just the entire outcome.\n  var CSS_UNIT = \"(?:\" + CSS_NUMBER + \")|(?:\" + CSS_INTEGER + \")\";\n\n  // Actual matching.\n  // Parentheses and commas are optional, but not required.\n  // Whitespace can take the place of commas or opening paren\n  var PERMISSIVE_MATCH3 = \"[\\\\s|\\\\(]+(\" + CSS_UNIT + \")[,|\\\\s]+(\" + CSS_UNIT + \")[,|\\\\s]+(\" + CSS_UNIT + \")\\\\s*\\\\)?\";\n  var PERMISSIVE_MATCH4 = \"[\\\\s|\\\\(]+(\" + CSS_UNIT + \")[,|\\\\s]+(\" + CSS_UNIT + \")[,|\\\\s]+(\" + CSS_UNIT + \")[,|\\\\s]+(\" + CSS_UNIT + \")\\\\s*\\\\)?\";\n\n  return {\n    CSS_UNIT: new RegExp(CSS_UNIT),\n    rgb: new RegExp(\"rgb\" + PERMISSIVE_MATCH3),\n    rgba: new RegExp(\"rgba\" + PERMISSIVE_MATCH4),\n    hsl: new RegExp(\"hsl\" + PERMISSIVE_MATCH3),\n    hsla: new RegExp(\"hsla\" + PERMISSIVE_MATCH4),\n    hsv: new RegExp(\"hsv\" + PERMISSIVE_MATCH3),\n    hsva: new RegExp(\"hsva\" + PERMISSIVE_MATCH4),\n    hex3: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,\n    hex6: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,\n    hex4: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,\n    hex8: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/\n  };\n})();\n\n// isValidCSSUnit\n// Take in a single string / number and check to see if it looks like a CSS unit\n// (see matchers above for definition).\nfunction isValidCSSUnit(color) {\n  return !!matchers.CSS_UNIT.exec(color);\n}\n\n// stringInputToObject\n// Permissive string parsing.  Take in a number of formats, and output an object\n// based on detected format.  Returns { r, g, b } or { h, s, l } or { h, s, v}\nfunction stringInputToObject(color) {\n\n  color = color.replace(trimLeft, '').replace(trimRight, '').toLowerCase();\n  var named = false;\n  if (names[color]) {\n    color = names[color];\n    named = true;\n  }\n  else if (color == 'transparent') {\n    return { r: 0, g: 0, b: 0, a: 0, format: \"name\" };\n  }\n\n  // Try to match string input using regular expressions.\n  // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360]\n  // Just return an object and let the conversion functions handle that.\n  // This way the result will be the same whether the tinycolor is initialized with string or object.\n  var match;\n  if ((match = matchers.rgb.exec(color))) {\n    return { r: match[1], g: match[2], b: match[3] };\n  }\n  if ((match = matchers.rgba.exec(color))) {\n    return { r: match[1], g: match[2], b: match[3], a: match[4] };\n  }\n  if ((match = matchers.hsl.exec(color))) {\n    return { h: match[1], s: match[2], l: match[3] };\n  }\n  if ((match = matchers.hsla.exec(color))) {\n    return { h: match[1], s: match[2], l: match[3], a: match[4] };\n  }\n  if ((match = matchers.hsv.exec(color))) {\n    return { h: match[1], s: match[2], v: match[3] };\n  }\n  if ((match = matchers.hsva.exec(color))) {\n    return { h: match[1], s: match[2], v: match[3], a: match[4] };\n  }\n  if ((match = matchers.hex8.exec(color))) {\n    return {\n      r: parseIntFromHex(match[1]),\n      g: parseIntFromHex(match[2]),\n      b: parseIntFromHex(match[3]),\n      a: convertHexToDecimal(match[4]),\n      format: named ? \"name\" : \"hex8\"\n    };\n  }\n  if ((match = matchers.hex6.exec(color))) {\n    return {\n      r: parseIntFromHex(match[1]),\n      g: parseIntFromHex(match[2]),\n      b: parseIntFromHex(match[3]),\n      format: named ? \"name\" : \"hex\"\n    };\n  }\n  if ((match = matchers.hex4.exec(color))) {\n    return {\n      r: parseIntFromHex(match[1] + '' + match[1]),\n      g: parseIntFromHex(match[2] + '' + match[2]),\n      b: parseIntFromHex(match[3] + '' + match[3]),\n      a: convertHexToDecimal(match[4] + '' + match[4]),\n      format: named ? \"name\" : \"hex8\"\n    };\n  }\n  if ((match = matchers.hex3.exec(color))) {\n    return {\n      r: parseIntFromHex(match[1] + '' + match[1]),\n      g: parseIntFromHex(match[2] + '' + match[2]),\n      b: parseIntFromHex(match[3] + '' + match[3]),\n      format: named ? \"name\" : \"hex\"\n    };\n  }\n\n  return false;\n}\n\nfunction validateWCAG2Parms(parms) {\n  // return valid WCAG2 parms for isReadable.\n  // If input parms are invalid, return {\"level\":\"AA\", \"size\":\"small\"}\n  var level, size;\n  parms = parms || { \"level\": \"AA\", \"size\": \"small\" };\n  level = (parms.level || \"AA\").toUpperCase();\n  size = (parms.size || \"small\").toLowerCase();\n  if (level !== \"AA\" && level !== \"AAA\") {\n    level = \"AA\";\n  }\n  if (size !== \"small\" && size !== \"large\") {\n    size = \"small\";\n  }\n  return { \"level\": level, \"size\": size };\n}\n\nmodule.exports = tinycolor;\n"
  },
  {
    "path": "components/style/compact.less",
    "content": "@root-entry-name: default;\n\n@import './themes/compact.less';\n@import './core/index';\n"
  },
  {
    "path": "components/style/core/base.less",
    "content": "// Config global less under antd\n[class^=~'@{ant-prefix}-'],\n[class*=~' @{ant-prefix}-'] {\n  // remove the clear button of a text input control in IE10+\n  &::-ms-clear,\n  input::-ms-clear,\n  input::-ms-reveal {\n    display: none;\n  }\n}\n"
  },
  {
    "path": "components/style/core/global.less",
    "content": "/* stylelint-disable property-no-vendor-prefix, at-rule-no-vendor-prefix */\n\n// Reboot\n//\n// Normalization of HTML elements, manually forked from Normalize.css to remove\n// styles targeting irrelevant browsers while applying new styles.\n//\n// Normalize is licensed MIT. https://github.com/necolas/normalize.css\n\n// HTML & Body reset\n@{html-selector},\nbody {\n  .square(100%);\n}\n\n// remove the clear button of a text input control in IE10+\ninput::-ms-clear,\ninput::-ms-reveal {\n  display: none;\n}\n\n// Document\n//\n// 1. Change from `box-sizing: content-box` so that `width` is not affected by `padding` or `border`.\n// 2. Change the default font family in all browsers.\n// 3. Correct the line height in all browsers.\n// 4. Prevent adjustments of font size after orientation changes in IE on Windows Phone and in iOS.\n// 5. Setting @viewport causes scrollbars to overlap content in IE11 and Edge, so\n//    we force a non-overlapping, non-auto-hiding scrollbar to counteract.\n// 6. Change the default tap highlight to be completely transparent in iOS.\n\n*,\n*::before,\n*::after {\n  box-sizing: border-box; // 1\n}\n\n@{html-selector} {\n  font-family: sans-serif; // 2\n  line-height: 1.15; // 3\n  -webkit-text-size-adjust: 100%; // 4\n  -ms-text-size-adjust: 100%; // 4\n  -ms-overflow-style: scrollbar; // 5\n  -webkit-tap-highlight-color: rgba(0, 0, 0, 0); // 6\n}\n\n// Body\n//\n// 1. remove the margin in all browsers.\n// 2. As a best practice, apply a default `body-background`.\n\nbody {\n  margin: 0; // 1\n  color: @text-color;\n  font-size: @font-size-base;\n  font-family: @font-family;\n  font-variant: @font-variant-base;\n  line-height: @line-height-base;\n  background-color: @body-background; // 2\n  font-feature-settings: @font-feature-settings-base;\n}\n\n// Suppress the focus outline on elements that cannot be accessed via keyboard.\n// This prevents an unwanted focus outline from appearing around elements that\n// might still respond to pointer events.\n//\n// Credit: https://github.com/suitcss/base\n[tabindex='-1']:focus {\n  outline: none !important;\n}\n\n//\n// Content grouping\n//\n\nhr {\n  box-sizing: content-box;\n  height: 0;\n  overflow: visible;\n}\n\n//\n// Typography\n//\n\n// remove top margins from headings\n//\n// By default, `<h1>`-`<h6>` all receive top and bottom margins. We nuke the top\n// margin for easier control within type scales as it avoids margin collapsing.\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n  margin-top: 0;\n  margin-bottom: 0.5em;\n  color: @heading-color;\n  font-weight: 500;\n}\n\n// Reset margins on paragraphs\n//\n// Similarly, the top margin on `<p>`s get reset. However, we also reset the\n// bottom margin to use `em` units instead of `em`.\np {\n  margin-top: 0;\n  margin-bottom: 1em;\n}\n\n// Abbreviations\n//\n// 1. remove the bottom border in Firefox 39-.\n// 2. Add the correct text decoration in Chrome, Edge, Opera, and Safari.\n// 3. Add explicit cursor to indicate changed behavior.\n// 4. Duplicate behavior to the data-* attribute for our tooltip plugin\n\nabbr[title],\nabbr[data-original-title] {\n  // 4\n  text-decoration: underline; // 2\n  text-decoration: underline dotted; // 2\n  border-bottom: 0; // 1\n  cursor: help; // 3\n}\n\naddress {\n  margin-bottom: 1em;\n  font-style: normal;\n  line-height: inherit;\n}\n\ninput[type='text'],\ninput[type='password'],\ninput[type='number'],\ntextarea {\n  -webkit-appearance: none;\n}\n\nol,\nul,\ndl {\n  margin-top: 0;\n  margin-bottom: 1em;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n  margin-bottom: 0;\n}\n\ndt {\n  font-weight: 500;\n}\n\ndd {\n  margin-bottom: 0.5em;\n  margin-left: 0; // Undo browser default\n}\n\nblockquote {\n  margin: 0 0 1em;\n}\n\ndfn {\n  font-style: italic; // Add the correct font style in Android 4.3-\n}\n\nb,\nstrong {\n  font-weight: bolder; // Add the correct font weight in Chrome, Edge, and Safari\n}\n\nsmall {\n  font-size: 80%; // Add the correct font size in all browsers\n}\n\n//\n// Prevent `sub` and `sup` elements from affecting the line height in\n// all browsers.\n//\n\nsub,\nsup {\n  position: relative;\n  font-size: 75%;\n  line-height: 0;\n  vertical-align: baseline;\n}\n\nsub {\n  bottom: -0.25em;\n}\n\nsup {\n  top: -0.5em;\n}\n\n//\n// Links\n//\n\na {\n  color: @link-color;\n  text-decoration: @link-decoration;\n  background-color: transparent; // remove the gray background on active links in IE 10.\n  outline: none;\n  cursor: pointer;\n  transition: color 0.3s;\n  -webkit-text-decoration-skip: objects; // remove gaps in links underline in iOS 8+ and Safari 8+.\n\n  &:hover {\n    color: @link-hover-color;\n  }\n\n  &:active {\n    color: @link-active-color;\n  }\n\n  &:active,\n  &:hover {\n    text-decoration: @link-hover-decoration;\n    outline: 0;\n  }\n\n  // https://github.com/ant-design/ant-design/issues/22503\n  &:focus {\n    text-decoration: @link-focus-decoration;\n    outline: @link-focus-outline;\n  }\n\n  &[disabled] {\n    color: @disabled-color;\n    cursor: not-allowed;\n  }\n}\n\n//\n// Code\n//\n\npre,\ncode,\nkbd,\nsamp {\n  font-size: 1em; // Correct the odd `em` font sizing in all browsers.\n  font-family: @code-family;\n}\n\npre {\n  // remove browser default top margin\n  margin-top: 0;\n  // Reset browser default of `1em` to use `em`s\n  margin-bottom: 1em;\n  // Don't allow content to break outside\n  overflow: auto;\n}\n\n//\n// Figures\n//\nfigure {\n  // Apply a consistent margin strategy (matches our type styles).\n  margin: 0 0 1em;\n}\n\n//\n// Images and content\n//\n\nimg {\n  vertical-align: middle;\n  border-style: none;\n}\n\n// Avoid 300ms click delay on touch devices that support the `touch-action` CSS property.\n//\n// In particular, unlike most other browsers, IE11+Edge on Windows 10 on touch devices and IE Mobile 10-11\n// DON'T remove the click delay when `<meta name=\"viewport\" content=\"width=device-width\">` is present.\n// However, they DO support emoving the click delay via `touch-action: manipulation`.\n// See:\n// * https://getbootstrap.com/docs/4.0/content/reboot/#click-delay-optimization-for-touch\n// * http://caniuse.com/#feat=css-touch-action\n// * https://patrickhlauke.github.io/touch/tests/results/#suppressing-300ms-delay\n\na,\narea,\nbutton,\n[role='button'],\ninput:not([type='range']),\nlabel,\nselect,\nsummary,\ntextarea {\n  touch-action: manipulation;\n}\n\n//\n// Tables\n//\n\ntable {\n  border-collapse: collapse; // Prevent double borders\n}\n\ncaption {\n  padding-top: 0.75em;\n  padding-bottom: 0.3em;\n  color: @text-color-secondary;\n  text-align: left;\n  caption-side: bottom;\n}\n\n//\n// Forms\n//\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n  margin: 0; // remove the margin in Firefox and Safari\n  color: inherit;\n  font-size: inherit;\n  font-family: inherit;\n  line-height: inherit;\n}\n\nbutton,\ninput {\n  overflow: visible; // Show the overflow in Edge\n}\n\nbutton,\nselect {\n  text-transform: none; // remove the inheritance of text transform in Firefox\n}\n\n// 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` controls in Android 4.\n// 2. Correct the inability to style clickable types in iOS and Safari.\nbutton,\n@{html-selector} [type=\"button\"], /* 1 */\n[type=\"reset\"],\n[type=\"submit\"] {\n  -webkit-appearance: button; // 2\n}\n\n// remove inner border and padding from Firefox, but don't restore the outline like Normalize.\nbutton::-moz-focus-inner,\n[type='button']::-moz-focus-inner,\n[type='reset']::-moz-focus-inner,\n[type='submit']::-moz-focus-inner {\n  padding: 0;\n  border-style: none;\n}\n\ninput[type='radio'],\ninput[type='checkbox'] {\n  box-sizing: border-box;\n  padding: 0;\n}\n\ninput[type='date'],\ninput[type='time'],\ninput[type='datetime-local'],\ninput[type='month'] {\n  // remove the default appearance of temporal inputs to avoid a Mobile Safari\n  // bug where setting a custom line-height prevents text from being vertically\n  // centered within the input.\n  // See https://bugs.webkit.org/show_bug.cgi?id=139848\n  // and https://github.com/twbs/bootstrap/issues/11266\n  -webkit-appearance: listbox;\n}\n\ntextarea {\n  overflow: auto;\n  // Textareas should really only resize vertically so they don't break their (horizontal) containers.\n  resize: vertical;\n}\n\nfieldset {\n  // Browsers set a default `min-width: min-content;` on fieldsets,\n  // unlike e.g. `<div>`s, which have `min-width: 0;` by default.\n  // So we reset that to ensure fieldsets behave more like a standard block element.\n  // See https://github.com/twbs/bootstrap/issues/12359\n  // and https://html.spec.whatwg.org/multipage/#the-fieldset-and-legend-elements\n  min-width: 0;\n  margin: 0;\n  // Reset the default outline behavior of fieldsets so they don't affect page layout.\n  padding: 0;\n  border: 0;\n}\n\nlegend {\n  display: block;\n  width: 100%;\n  max-width: 100%;\n  margin-bottom: 0.5em;\n  padding: 0;\n  color: inherit;\n  font-size: 1.5em;\n  line-height: inherit;\n  white-space: normal;\n}\n\nprogress {\n  vertical-align: baseline; // Add the correct vertical alignment in Chrome, Firefox, and Opera.\n}\n\n// Correct the cursor style of incement and decement buttons in Chrome.\n[type='number']::-webkit-inner-spin-button,\n[type='number']::-webkit-outer-spin-button {\n  height: auto;\n}\n\n[type='search'] {\n  // This overrides the extra rounded corners on search inputs in iOS so that our\n  // `.form-control` class can properly style them. Note that this cannot simply\n  // be added to `.form-control` as it's not specific enough. For details, see\n  // https://github.com/twbs/bootstrap/issues/11586.\n  outline-offset: -2px;\n  -webkit-appearance: none;\n}\n\n//\n// remove the inner padding and cancel buttons in Chrome and Safari on macOS.\n//\n\n[type='search']::-webkit-search-cancel-button,\n[type='search']::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\n\n//\n// 1. Correct the inability to style clickable types in iOS and Safari.\n// 2. Change font properties to `inherit` in Safari.\n//\n\n::-webkit-file-upload-button {\n  font: inherit; // 2\n  -webkit-appearance: button; // 1\n}\n\n//\n// Correct element displays\n//\n\noutput {\n  display: inline-block;\n}\n\nsummary {\n  display: list-item; // Add the correct display in all browsers\n}\n\ntemplate {\n  display: none;\n}\n\n// Always hide an element with the `hidden` HTML attribute (from PureCSS).\n[hidden] {\n  display: none !important;\n}\n\n::selection {\n  color: @text-color-inverse;\n  background: @text-selection-bg;\n}\n\n// Utility classes\n.clearfix {\n  .clearfix();\n}\n"
  },
  {
    "path": "components/style/core/iconfont.less",
    "content": "@import '../themes/index';\n@import '../mixins/iconfont';\n\n.@{iconfont-css-prefix} {\n  .iconfont-mixin();\n\n  // https://github.com/ant-design/ant-design/issues/33703\n  & > & {\n    line-height: 0;\n    vertical-align: 0;\n  }\n\n  &[tabindex] {\n    cursor: pointer;\n  }\n}\n\n.@{iconfont-css-prefix}-spin,\n.@{iconfont-css-prefix}-spin::before {\n  display: inline-block;\n  animation: loadingCircle 1s infinite linear;\n}\n"
  },
  {
    "path": "components/style/core/index.less",
    "content": "@import '../mixins/index';\n@import 'base';\n@import 'global';\n@import 'iconfont';\n@import 'motion';\n"
  },
  {
    "path": "components/style/core/motion/fade.less",
    "content": "@import (reference) '../../themes/index';\n@import './util';\n\n.fade-motion(@className, @timing-function, @duration: @animation-duration-base) {\n  @name: ~'@{ant-prefix}-@{className}-motion';\n\n  .make-motion-enter(@name, antFadeIn, @timing-function, @duration);\n  .make-motion-leave(@name, antFadeOut, @timing-function, @duration);\n}\n\n@keyframes antFadeIn {\n  0% {\n    opacity: 0;\n  }\n\n  100% {\n    opacity: 1;\n  }\n}\n\n@keyframes antFadeOut {\n  0% {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n  }\n}\n"
  },
  {
    "path": "components/style/core/motion/move.less",
    "content": ".move-motion(@className, @keyframeName) {\n  @name: ~'@{ant-prefix}-@{className}';\n  .make-motion(@name, @keyframeName);\n  .@{name}-enter,\n  .@{name}-appear {\n    opacity: 0;\n    animation-timing-function: @ease-out-circ;\n  }\n  .@{name}-leave {\n    animation-timing-function: @ease-in-circ;\n  }\n}\n\n.move-motion(move-up, antMoveUp);\n.move-motion(move-down, antMoveDown);\n.move-motion(move-left, antMoveLeft);\n.move-motion(move-right, antMoveRight);\n\n@keyframes antMoveDownIn {\n  0% {\n    transform: translateY(100%);\n    transform-origin: 0 0;\n    opacity: 0;\n  }\n\n  100% {\n    transform: translateY(0%);\n    transform-origin: 0 0;\n    opacity: 1;\n  }\n}\n\n@keyframes antMoveDownOut {\n  0% {\n    transform: translateY(0%);\n    transform-origin: 0 0;\n    opacity: 1;\n  }\n\n  100% {\n    transform: translateY(100%);\n    transform-origin: 0 0;\n    opacity: 0;\n  }\n}\n\n@keyframes antMoveLeftIn {\n  0% {\n    transform: translateX(-100%);\n    transform-origin: 0 0;\n    opacity: 0;\n  }\n\n  100% {\n    transform: translateX(0%);\n    transform-origin: 0 0;\n    opacity: 1;\n  }\n}\n\n@keyframes antMoveLeftOut {\n  0% {\n    transform: translateX(0%);\n    transform-origin: 0 0;\n    opacity: 1;\n  }\n\n  100% {\n    transform: translateX(-100%);\n    transform-origin: 0 0;\n    opacity: 0;\n  }\n}\n\n@keyframes antMoveRightIn {\n  0% {\n    transform: translateX(100%);\n    transform-origin: 0 0;\n    opacity: 0;\n  }\n\n  100% {\n    transform: translateX(0%);\n    transform-origin: 0 0;\n    opacity: 1;\n  }\n}\n\n@keyframes antMoveRightOut {\n  0% {\n    transform: translateX(0%);\n    transform-origin: 0 0;\n    opacity: 1;\n  }\n\n  100% {\n    transform: translateX(100%);\n    transform-origin: 0 0;\n    opacity: 0;\n  }\n}\n\n@keyframes antMoveUpIn {\n  0% {\n    transform: translateY(-100%);\n    transform-origin: 0 0;\n    opacity: 0;\n  }\n\n  100% {\n    transform: translateY(0%);\n    transform-origin: 0 0;\n    opacity: 1;\n  }\n}\n\n@keyframes antMoveUpOut {\n  0% {\n    transform: translateY(0%);\n    transform-origin: 0 0;\n    opacity: 1;\n  }\n\n  100% {\n    transform: translateY(-100%);\n    transform-origin: 0 0;\n    opacity: 0;\n  }\n}\n"
  },
  {
    "path": "components/style/core/motion/other.less",
    "content": "@keyframes loadingCircle {\n  100% {\n    transform: rotate(360deg);\n  }\n}\n\n@click-animating-true: ~\"[@{ant-prefix}-click-animating='true']\";\n@click-animating-with-extra-node-true: ~\"[@{ant-prefix}-click-animating-without-extra-node='true']\";\n\n@{click-animating-true},\n@{click-animating-with-extra-node-true} {\n  position: relative;\n}\n\nhtml {\n  --antd-wave-shadow-color: @primary-color;\n  --scroll-bar: 0;\n}\n\n@click-animating-with-extra-node-true-after: ~'@{click-animating-with-extra-node-true}::after';\n\n@{click-animating-with-extra-node-true-after},\n.@{ant-prefix}-click-animating-node {\n  position: absolute;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  display: block;\n  border-radius: inherit;\n  box-shadow: 0 0 0 0 @primary-color;\n  box-shadow: 0 0 0 0 var(--antd-wave-shadow-color);\n  opacity: 0.2;\n  animation: fadeEffect 2s @ease-out-circ, waveEffect 0.4s @ease-out-circ;\n  animation-fill-mode: forwards;\n  content: '';\n  pointer-events: none;\n}\n\n@keyframes waveEffect {\n  100% {\n    box-shadow: 0 0 0 @primary-color;\n    box-shadow: 0 0 0 @wave-animation-width var(--antd-wave-shadow-color);\n  }\n}\n\n@keyframes fadeEffect {\n  100% {\n    opacity: 0;\n  }\n}\n"
  },
  {
    "path": "components/style/core/motion/slide.less",
    "content": ".slide-motion(@className, @keyframeName) {\n  @name: ~'@{ant-prefix}-@{className}';\n  .make-motion(@name, @keyframeName);\n  .@{name}-enter,\n  .@{name}-appear {\n    transform: scale(0);\n    transform-origin: 0% 0%;\n    opacity: 0;\n    animation-timing-function: @ease-out-quint;\n  }\n  .@{name}-leave {\n    animation-timing-function: @ease-in-quint;\n  }\n}\n\n.slide-motion(slide-up, antSlideUp);\n.slide-motion(slide-down, antSlideDown);\n.slide-motion(slide-left, antSlideLeft);\n.slide-motion(slide-right, antSlideRight);\n\n@keyframes antSlideUpIn {\n  0% {\n    transform: scaleY(0.8);\n    transform-origin: 0% 0%;\n    opacity: 0;\n  }\n\n  100% {\n    transform: scaleY(1);\n    transform-origin: 0% 0%;\n    opacity: 1;\n  }\n}\n\n@keyframes antSlideUpOut {\n  0% {\n    transform: scaleY(1);\n    transform-origin: 0% 0%;\n    opacity: 1;\n  }\n\n  100% {\n    transform: scaleY(0.8);\n    transform-origin: 0% 0%;\n    opacity: 0;\n  }\n}\n\n@keyframes antSlideDownIn {\n  0% {\n    transform: scaleY(0.8);\n    transform-origin: 100% 100%;\n    opacity: 0;\n  }\n\n  100% {\n    transform: scaleY(1);\n    transform-origin: 100% 100%;\n    opacity: 1;\n  }\n}\n\n@keyframes antSlideDownOut {\n  0% {\n    transform: scaleY(1);\n    transform-origin: 100% 100%;\n    opacity: 1;\n  }\n\n  100% {\n    transform: scaleY(0.8);\n    transform-origin: 100% 100%;\n    opacity: 0;\n  }\n}\n\n@keyframes antSlideLeftIn {\n  0% {\n    transform: scaleX(0.8);\n    transform-origin: 0% 0%;\n    opacity: 0;\n  }\n\n  100% {\n    transform: scaleX(1);\n    transform-origin: 0% 0%;\n    opacity: 1;\n  }\n}\n\n@keyframes antSlideLeftOut {\n  0% {\n    transform: scaleX(1);\n    transform-origin: 0% 0%;\n    opacity: 1;\n  }\n\n  100% {\n    transform: scaleX(0.8);\n    transform-origin: 0% 0%;\n    opacity: 0;\n  }\n}\n\n@keyframes antSlideRightIn {\n  0% {\n    transform: scaleX(0.8);\n    transform-origin: 100% 0%;\n    opacity: 0;\n  }\n\n  100% {\n    transform: scaleX(1);\n    transform-origin: 100% 0%;\n    opacity: 1;\n  }\n}\n\n@keyframes antSlideRightOut {\n  0% {\n    transform: scaleX(1);\n    transform-origin: 100% 0%;\n    opacity: 1;\n  }\n\n  100% {\n    transform: scaleX(0.8);\n    transform-origin: 100% 0%;\n    opacity: 0;\n  }\n}\n"
  },
  {
    "path": "components/style/core/motion/swing.less",
    "content": ".swing-motion(@className, @keyframeName) {\n  .@{className}-enter,\n  .@{className}-appear {\n    .motion-common();\n\n    animation-play-state: paused;\n  }\n  .@{className}-enter.@{className}-enter-active,\n  .@{className}-appear.@{className}-appear-active {\n    animation-name: ~'@{keyframeName}In';\n    animation-play-state: running;\n  }\n}\n\n.swing-motion(swing, antSwing);\n\n@keyframes antSwingIn {\n  0%,\n  100% {\n    transform: translateX(0);\n  }\n\n  20% {\n    transform: translateX(-10px);\n  }\n\n  40% {\n    transform: translateX(10px);\n  }\n\n  60% {\n    transform: translateX(-5px);\n  }\n\n  80% {\n    transform: translateX(5px);\n  }\n}\n"
  },
  {
    "path": "components/style/core/motion/util.less",
    "content": "@import (reference) '../../themes/index';\n\n.make-motion-enter(@name, @keyframeName, @timing-function, @duration: @animation-duration-base) {\n  .@{name}-enter {\n    animation-name: @keyframeName;\n    animation-duration: @duration;\n    animation-timing-function: @timing-function;\n    animation-fill-mode: both;\n  }\n}\n\n.make-motion-leave(@name, @keyframeName, @timing-function, @duration: @animation-duration-base) {\n  .@{name}-leave {\n    animation-name: @keyframeName;\n    animation-duration: @duration;\n    animation-timing-function: @timing-function;\n    animation-fill-mode: both;\n  }\n}\n"
  },
  {
    "path": "components/style/core/motion/zoom.less",
    "content": ".zoom-motion(@className, @keyframeName, @duration: @animation-duration-base) {\n  @name: ~'@{ant-prefix}-@{className}';\n  .make-motion(@name, @keyframeName, @duration);\n  .@{name}-enter,\n  .@{name}-appear {\n    transform: scale(0);\n    opacity: 0;\n    animation-timing-function: @ease-out-circ;\n\n    &-prepare {\n      transform: none;\n    }\n  }\n  .@{name}-leave {\n    animation-timing-function: @ease-in-out-circ;\n  }\n}\n\n@keyframes antZoomIn {\n  0% {\n    transform: scale(0.2);\n    opacity: 0;\n  }\n\n  100% {\n    transform: scale(1);\n    opacity: 1;\n  }\n}\n\n@keyframes antZoomOut {\n  0% {\n    transform: scale(1);\n  }\n\n  100% {\n    transform: scale(0.2);\n    opacity: 0;\n  }\n}\n\n@keyframes antZoomBigIn {\n  0% {\n    transform: scale(0.8);\n    opacity: 0;\n  }\n\n  100% {\n    transform: scale(1);\n    opacity: 1;\n  }\n}\n\n@keyframes antZoomBigOut {\n  0% {\n    transform: scale(1);\n  }\n\n  100% {\n    transform: scale(0.8);\n    opacity: 0;\n  }\n}\n\n@keyframes antZoomUpIn {\n  0% {\n    transform: scale(0.8);\n    transform-origin: 50% 0%;\n    opacity: 0;\n  }\n\n  100% {\n    transform: scale(1);\n    transform-origin: 50% 0%;\n  }\n}\n\n@keyframes antZoomUpOut {\n  0% {\n    transform: scale(1);\n    transform-origin: 50% 0%;\n  }\n\n  100% {\n    transform: scale(0.8);\n    transform-origin: 50% 0%;\n    opacity: 0;\n  }\n}\n\n@keyframes antZoomLeftIn {\n  0% {\n    transform: scale(0.8);\n    transform-origin: 0% 50%;\n    opacity: 0;\n  }\n\n  100% {\n    transform: scale(1);\n    transform-origin: 0% 50%;\n  }\n}\n\n@keyframes antZoomLeftOut {\n  0% {\n    transform: scale(1);\n    transform-origin: 0% 50%;\n  }\n\n  100% {\n    transform: scale(0.8);\n    transform-origin: 0% 50%;\n    opacity: 0;\n  }\n}\n\n@keyframes antZoomRightIn {\n  0% {\n    transform: scale(0.8);\n    transform-origin: 100% 50%;\n    opacity: 0;\n  }\n\n  100% {\n    transform: scale(1);\n    transform-origin: 100% 50%;\n  }\n}\n\n@keyframes antZoomRightOut {\n  0% {\n    transform: scale(1);\n    transform-origin: 100% 50%;\n  }\n\n  100% {\n    transform: scale(0.8);\n    transform-origin: 100% 50%;\n    opacity: 0;\n  }\n}\n\n@keyframes antZoomDownIn {\n  0% {\n    transform: scale(0.8);\n    transform-origin: 50% 100%;\n    opacity: 0;\n  }\n\n  100% {\n    transform: scale(1);\n    transform-origin: 50% 100%;\n  }\n}\n\n@keyframes antZoomDownOut {\n  0% {\n    transform: scale(1);\n    transform-origin: 50% 100%;\n  }\n\n  100% {\n    transform: scale(0.8);\n    transform-origin: 50% 100%;\n    opacity: 0;\n  }\n}\n"
  },
  {
    "path": "components/style/core/motion.less",
    "content": "// @import '../mixins/motion'; This has moved to theme/xxx inside.\n@import 'motion/fade';\n@import 'motion/move';\n@import 'motion/other';\n@import 'motion/slide';\n@import 'motion/zoom';\n\n// For common/openAnimation\n.ant-motion-collapse-legacy {\n  overflow: hidden;\n\n  &-active {\n    transition: height @animation-duration-base @ease-in-out,\n      opacity @animation-duration-base @ease-in-out !important;\n  }\n}\n\n.ant-motion-collapse {\n  overflow: hidden;\n  transition: height @animation-duration-base @ease-in-out,\n    opacity @animation-duration-base @ease-in-out !important;\n}\n"
  },
  {
    "path": "components/style/dark.less",
    "content": "@root-entry-name: default;\n\n@import './themes/dark.less';\n@import './core/index';\n"
  },
  {
    "path": "components/style/default.less",
    "content": "// This is same as `index.less` but given `root-entry-name` for `dist/antd.less` usage\n@root-entry-name: default;\n\n@import './index';\n"
  },
  {
    "path": "components/style/entry.less",
    "content": "@import './index.less';\n@import './patch.less';\n"
  },
  {
    "path": "components/style/index.less",
    "content": "@import './themes/index';\n@import './core/index';\n"
  },
  {
    "path": "components/style/mixins/box.less",
    "content": ".box(@position: absolute) {\n  position: @position;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n}\n"
  },
  {
    "path": "components/style/mixins/clearfix.less",
    "content": "// mixins for clearfix\n// ------------------------\n.clearfix() {\n  // https://github.com/ant-design/ant-design/issues/21301#issuecomment-583955229\n  &::before {\n    display: table;\n    content: '';\n  }\n\n  &::after {\n    // https://github.com/ant-design/ant-design/issues/21864\n    display: table;\n    clear: both;\n    content: '';\n  }\n}\n"
  },
  {
    "path": "components/style/mixins/compact-item-vertical.less",
    "content": ".compact-item-vertical-border-radius(@prefix-cls) {\n  &-item:not(&-first-item):not(&-last-item) {\n    border-radius: 0;\n  }\n\n  &-item&-first-item:not(&-last-item) {\n    border-bottom-right-radius: 0;\n    border-bottom-left-radius: 0;\n  }\n\n  &-item&-last-item:not(&-first-item) {\n    border-top-left-radius: 0;\n    border-top-right-radius: 0;\n  }\n}\n\n.compact-item-vertical-border(@prefix-cls) {\n  // border collapse\n  &-item:not(&-last-item) {\n    margin-bottom: -@border-width-base;\n  }\n\n  &-item {\n    &:hover,\n    &:focus,\n    &:active {\n      z-index: 2;\n    }\n\n    &[disabled] {\n      z-index: 0;\n    }\n  }\n}\n\n.compact-item-vertical(@prefix-cls) {\n  &-compact-vertical {\n    .compact-item-vertical-border(@prefix-cls);\n    .compact-item-vertical-border-radius(@prefix-cls);\n  }\n}\n"
  },
  {
    "path": "components/style/mixins/compact-item.less",
    "content": ".compact-item-border-radius(@prefix-cls, @bordered-item-cls: null) {\n  & when (@bordered-item-cls = null) {\n    // border-radius\n    &-item:not(&-first-item):not(&-last-item).@{prefix-cls} {\n      border-radius: 0;\n    }\n\n    &-item.@{prefix-cls}&-first-item:not(&-last-item):not(&-item-rtl) {\n      border-top-right-radius: 0;\n      border-bottom-right-radius: 0;\n    }\n\n    &-item.@{prefix-cls}&-last-item:not(&-first-item):not(&-item-rtl) {\n      border-top-left-radius: 0;\n      border-bottom-left-radius: 0;\n    }\n\n    // ----------rtl for first item----------\n    &-item.@{prefix-cls}&-item-rtl&-first-item:not(&-last-item) {\n      border-top-left-radius: 0;\n      border-bottom-left-radius: 0;\n    }\n\n    // ----------rtl for last item----------\n    &-item.@{prefix-cls}&-item-rtl&-last-item:not(&-first-item) {\n      border-top-right-radius: 0;\n      border-bottom-right-radius: 0;\n    }\n  }\n\n  & when (not (@bordered-item-cls = null)) {\n    // border-radius\n    &-item:not(&-first-item):not(&-last-item).@{prefix-cls} .@{bordered-item-cls} {\n      border-radius: 0;\n    }\n\n    &-item&-first-item.@{prefix-cls}:not(&-last-item):not(&-item-rtl) .@{bordered-item-cls} {\n      border-top-right-radius: 0;\n      border-bottom-right-radius: 0;\n    }\n\n    &-item&-last-item.@{prefix-cls}:not(&-first-item):not(&-item-rtl) .@{bordered-item-cls} {\n      border-top-left-radius: 0;\n      border-bottom-left-radius: 0;\n    }\n\n    // ----------rtl for first item----------\n    &-item.@{prefix-cls}&-first-item&-item-rtl:not(&-last-item) .@{bordered-item-cls} {\n      border-top-left-radius: 0;\n      border-bottom-left-radius: 0;\n    }\n\n    // ----------rtl for last item----------\n    &-item.@{prefix-cls}&-last-item&-item-rtl:not(&-first-item) .@{bordered-item-cls} {\n      border-top-right-radius: 0;\n      border-bottom-right-radius: 0;\n    }\n  }\n}\n\n.compact-item-border(@prefix-cls, @bordered-item-cls: null, @special-open-cls) {\n  & when (@bordered-item-cls = null) {\n    // border collapse\n    &-item:not(&-last-item):not(&-item-rtl) {\n      margin-right: -@border-width-base;\n    }\n\n    // rtl border collapse\n    &-item:not(&-last-item)&-item-rtl {\n      margin-left: -@border-width-base;\n    }\n\n    &-item {\n      &:hover,\n      &:focus,\n      &:active {\n        z-index: 2;\n      }\n\n      // Select has an extra focus className\n      & when (not (@special-item-cls = null)) {\n        &.@{special-item-cls} {\n          z-index: 2;\n        }\n      }\n\n      &[disabled] {\n        z-index: 0;\n      }\n    }\n  }\n\n  & when (not (@bordered-item-cls = null)) {\n    // border collapse\n    &-item:not(&-last-item) {\n      margin-right: -@border-width-base;\n\n      &.@{prefix-cls}-compact-item-rtl {\n        margin-right: 0;\n        margin-left: -@border-width-base;\n      }\n    }\n\n    &-item {\n      &:hover,\n      &:focus,\n      &:active {\n        > * {\n          z-index: 2;\n        }\n      }\n\n      // Select has an special focus-item\n      & when (not (@special-item-cls = null)) {\n        &.@{special-item-cls} > * {\n          z-index: 2;\n        }\n      }\n\n      &[disabled] > * {\n        z-index: 0;\n      }\n    }\n  }\n}\n\n.compact-item(@prefix-cls, @bordered-item-cls: null, @special-item-cls: null) {\n  &-compact {\n    .compact-item-border(@prefix-cls, @bordered-item-cls, @special-item-cls);\n\n    .compact-item-border-radius(@prefix-cls, @bordered-item-cls);\n  }\n}\n"
  },
  {
    "path": "components/style/mixins/compatibility.less",
    "content": "// Compatibility for browsers.\n\n// Placeholder text\n.placeholder(@color: @input-placeholder-color) {\n  &::placeholder {\n    color: @color;\n    user-select: none; // https://github.com/ant-design/ant-design/pull/32639\n  }\n\n  &:placeholder-shown {\n    text-overflow: ellipsis;\n  }\n}\n"
  },
  {
    "path": "components/style/mixins/customize.less",
    "content": "// customize dark components background in popover containers(like Modal, Drawer, Card, Popover, Popconfirm, Notification, ...)\n// for dark theme\n.popover-customize-bg(@containerClass, @background: @popover-background, @prefix: @ant-prefix)\n  when\n  (@theme = dark) {\n  @picker-prefix-cls: ~'@{prefix}-picker';\n  @slider-prefix-cls: ~'@{prefix}-slider';\n  @anchor-prefix-cls: ~'@{prefix}-anchor';\n  @collapse-prefix-cls: ~'@{prefix}-collapse';\n  @tab-prefix-cls: ~'@{prefix}-tabs';\n  @timeline-prefix-cls: ~'@{prefix}-timeline';\n  @tree-prefix-cls: ~'@{prefix}-tree';\n  @card-prefix-cls: ~'@{prefix}-card';\n  @badge-prefix-cls: ~'@{prefix}-badge';\n  @transfer-prefix-cls: ~'@{prefix}-transfer';\n  @calendar-prefix-cls: ~'@{prefix}-picker-calendar';\n  @calendar-picker-prefix-cls: ~'@{prefix}-picker';\n  @table-prefix-cls: ~'@{prefix}-table';\n\n  @popover-border: @border-width-base @border-style-base @popover-customize-border-color;\n\n  .@{containerClass} {\n    .@{picker-prefix-cls}-clear,\n    .@{slider-prefix-cls}-handle,\n    .@{anchor-prefix-cls}-wrapper,\n    .@{collapse-prefix-cls}-content,\n    .@{timeline-prefix-cls}-item-head,\n    .@{card-prefix-cls} {\n      background-color: @background;\n    }\n\n    .@{transfer-prefix-cls} {\n      &-list {\n        &-header {\n          background: @background;\n          border-bottom: @popover-border;\n        }\n        &-content-item:not(.@{transfer-prefix-cls}-list-content-item-disabled):hover {\n          background-color: @item-hover-bg;\n        }\n      }\n    }\n\n    tr.@{table-prefix-cls}-expanded-row {\n      &,\n      &:hover {\n        > td {\n          background: #272727;\n        }\n      }\n    }\n    .@{table-prefix-cls}.@{table-prefix-cls}-small {\n      thead {\n        > tr {\n          > th {\n            background-color: @background;\n            border-bottom: @popover-border;\n          }\n        }\n      }\n    }\n    .@{table-prefix-cls} {\n      background-color: @background;\n      .@{table-prefix-cls}-row-expand-icon {\n        border: @popover-border;\n      }\n\n      tfoot {\n        > tr {\n          > th,\n          > td {\n            border-bottom: @popover-border;\n          }\n        }\n      }\n\n      thead {\n        > tr {\n          > th {\n            background-color: #272727;\n            border-bottom: @popover-border;\n          }\n        }\n      }\n\n      tbody {\n        > tr {\n          > td {\n            border-bottom: @popover-border;\n            &.@{table-prefix-cls}-cell-fix-left,\n            &.@{table-prefix-cls}-cell-fix-right {\n              background-color: @background;\n            }\n          }\n          &.@{table-prefix-cls}-row:hover {\n            > td {\n              background: @table-header-sort-active-bg;\n            }\n          }\n        }\n      }\n      &.@{table-prefix-cls}-bordered {\n        .@{table-prefix-cls}-title {\n          border: @popover-border;\n        }\n\n        // ============================= Cell =============================\n        thead > tr > th,\n        tbody > tr > td,\n        tfoot > tr > th,\n        tfoot > tr > td {\n          border-right: @popover-border;\n        }\n\n        // Fixed right should provides additional border\n        .@{table-prefix-cls}-cell-fix-right-first::after {\n          border-right: @popover-border;\n        }\n\n        // ============================ Header ============================\n        table > {\n          thead {\n            > tr:not(:last-child) > th {\n              border-bottom: @border-width-base @border-style-base @border-color-split;\n            }\n          }\n        }\n\n        // =========================== Content ============================\n        .@{table-prefix-cls}-container {\n          border: @popover-border;\n        }\n\n        // ========================== Expandable ==========================\n        .@{table-prefix-cls}-expanded-row-fixed {\n          &::after {\n            border-right: @popover-border;\n          }\n        }\n\n        .@{table-prefix-cls}-footer {\n          border: @popover-border;\n        }\n      }\n      .@{table-prefix-cls}-filter-trigger-container-open {\n        background-color: #525252;\n      }\n    }\n\n    .@{calendar-prefix-cls}-full {\n      background-color: @background;\n      .@{calendar-picker-prefix-cls}-panel {\n        background-color: @background;\n        .@{calendar-prefix-cls}-date {\n          border-top: 2px solid @popover-customize-border-color;\n        }\n      }\n    }\n\n    .@{tab-prefix-cls} {\n      &.@{tab-prefix-cls}-card .@{tab-prefix-cls}-card-bar .@{tab-prefix-cls}-tab-active {\n        background-color: @background;\n        border-bottom: @border-width-base solid @background;\n      }\n    }\n\n    .@{badge-prefix-cls} {\n      &-count {\n        box-shadow: 0 0 0 1px @background;\n      }\n    }\n\n    .@{tree-prefix-cls} {\n      &-show-line {\n        .@{tree-prefix-cls}-switcher {\n          background: @background;\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/style/mixins/iconfont.less",
    "content": ".iconfont-mixin() {\n  display: inline-flex;\n  align-items: center;\n  color: @icon-color;\n  font-style: normal;\n  line-height: 0;\n  text-align: center;\n  text-transform: none;\n  vertical-align: -0.125em; // for SVG icon, see https://blog.prototypr.io/align-svg-icons-to-text-and-say-goodbye-to-font-icons-d44b3d7b26b4\n  text-rendering: optimizelegibility;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n\n  > * {\n    line-height: 1;\n  }\n\n  svg {\n    display: inline-block;\n  }\n\n  &::before {\n    display: none; // dont display old icon.\n  }\n\n  & &-icon {\n    display: block;\n  }\n}\n"
  },
  {
    "path": "components/style/mixins/index.less",
    "content": "// Mixins\n// --------------------------------------------------\n@import 'size';\n@import 'compatibility';\n@import 'clearfix';\n@import 'iconfont';\n@import 'typography';\n@import 'customize';\n@import 'box';\n@import 'modal-mask';\n@import 'motion';\n@import 'reset';\n@import 'operation-unit';\n@import 'rounded-arrow';\n@import 'placement-arrow';\n@import 'compact-item';\n@import 'compact-item-vertical';\n"
  },
  {
    "path": "components/style/mixins/modal-mask.less",
    "content": "@import 'box';\n\n.modal-mask() {\n  pointer-events: none;\n\n  &.@{ant-prefix}-zoom-enter,\n  &.@{ant-prefix}-zoom-appear {\n    transform: none; // reset scale avoid mousePosition bug\n    opacity: 0;\n    animation-duration: @animation-duration-slow;\n    user-select: none; // https://github.com/ant-design/ant-design/issues/11777\n  }\n\n  &-mask {\n    .box(fixed);\n    z-index: @zindex-modal-mask;\n    height: 100%;\n    background-color: @modal-mask-bg;\n\n    &-hidden {\n      display: none;\n    }\n  }\n\n  &-wrap {\n    .box(fixed);\n    overflow: auto;\n    outline: 0;\n  }\n}\n"
  },
  {
    "path": "components/style/mixins/motion.less",
    "content": ".motion-common(@duration: @animation-duration-base) {\n  animation-duration: @duration;\n  animation-fill-mode: both;\n}\n\n.motion-common-leave(@duration: @animation-duration-base) {\n  animation-duration: @duration;\n  animation-fill-mode: both;\n}\n\n.make-motion(@className, @keyframeName, @duration: @animation-duration-base) {\n  .@{className}-enter,\n  .@{className}-appear {\n    .motion-common(@duration);\n\n    animation-play-state: paused;\n  }\n  .@{className}-leave {\n    .motion-common-leave(@duration);\n\n    animation-play-state: paused;\n  }\n  .@{className}-enter.@{className}-enter-active,\n  .@{className}-appear.@{className}-appear-active {\n    animation-name: ~'@{keyframeName}In';\n    animation-play-state: running;\n  }\n  .@{className}-leave.@{className}-leave-active {\n    animation-name: ~'@{keyframeName}Out';\n    animation-play-state: running;\n    pointer-events: none;\n  }\n}\n"
  },
  {
    "path": "components/style/mixins/operation-unit.less",
    "content": ".operation-unit() {\n  color: @link-color;\n  outline: none;\n  cursor: pointer;\n  transition: color 0.3s;\n\n  &:focus-visible,\n  &:hover {\n    color: @link-hover-color;\n  }\n\n  &:active {\n    color: @link-active-color;\n  }\n}\n"
  },
  {
    "path": "components/style/mixins/placement-arrow.less",
    "content": ".placementArrow(\n  @arrow-size,\n  @border-radius-outer,\n  @border-radius-inner,\n  @bg-color: var(--antd-arrow-background-color),\n  @box-shadow: none\n) {\n  // internal variables\n  @arrow-distance: 0px;\n  @arrow-offset-horizontal: 16px;\n\n  // ============================ Basic ============================\n  &-arrow {\n    position: absolute;\n    z-index: 1; // lift it up so the menu wouldn't cask shadow on it\n    display: block;\n\n    .roundedArrow(@arrow-size, @border-radius-outer, @border-radius-inner, @bg-color, @box-shadow);\n\n    &::before {\n      background: @bg-color;\n    }\n  }\n\n  // ========================== Placement ==========================\n  // Here handle the arrow position and rotate stuff\n  // >>>>> Top\n  &-placement-top > &-arrow,\n  &-placement-topLeft > &-arrow,\n  &-placement-topRight > &-arrow {\n    bottom: @arrow-distance;\n    transform: translateY(100%) rotate(180deg);\n  }\n\n  &-placement-top > &-arrow {\n    left: 50%;\n    transform: translateX(-50%) translateY(100%) rotate(180deg);\n  }\n\n  &-placement-topLeft > &-arrow {\n    left: @arrow-offset-horizontal;\n  }\n\n  &-placement-topRight > &-arrow {\n    right: @arrow-offset-horizontal;\n  }\n\n  // >>>>> Bottom\n  &-placement-bottom > &-arrow,\n  &-placement-bottomLeft > &-arrow,\n  &-placement-bottomRight > &-arrow {\n    top: @arrow-distance;\n    transform: translateY(-100%);\n  }\n\n  &-placement-bottom > &-arrow {\n    left: 50%;\n    transform: translateX(-50%) translateY(-100%);\n  }\n\n  &-placement-bottomLeft > &-arrow {\n    left: @arrow-offset-horizontal;\n  }\n\n  &-placement-bottomRight > &-arrow {\n    right: @arrow-offset-horizontal;\n  }\n\n  // >>>>> Left\n  &-placement-left > &-arrow,\n  &-placement-leftTop > &-arrow,\n  &-placement-leftBottom > &-arrow {\n    right: @arrow-distance;\n    transform: translateX(100%) rotate(90deg);\n  }\n\n  &-placement-left > &-arrow {\n    top: 50%;\n    transform: translateY(-50%) translateX(100%) rotate(90deg);\n  }\n\n  &-placement-leftTop > &-arrow {\n    top: @arrow-offset-horizontal;\n  }\n\n  &-placement-leftBottom > &-arrow {\n    bottom: @arrow-offset-horizontal;\n  }\n\n  // >>>>> Right\n  &-placement-right > &-arrow,\n  &-placement-rightTop > &-arrow,\n  &-placement-rightBottom > &-arrow {\n    left: @arrow-distance;\n    transform: translateX(-100%) rotate(-90deg);\n  }\n\n  &-placement-right > &-arrow {\n    top: 50%;\n    transform: translateY(-50%) translateX(-100%) rotate(-90deg);\n  }\n\n  &-placement-rightTop > &-arrow {\n    top: @arrow-offset-horizontal;\n  }\n\n  &-placement-rightBottom > &-arrow {\n    bottom: @arrow-offset-horizontal;\n  }\n}"
  },
  {
    "path": "components/style/mixins/reset.less",
    "content": ".reset-component() {\n  box-sizing: border-box;\n  margin: 0;\n  padding: 0;\n  color: @text-color;\n  font-size: @font-size-base;\n  font-variant: @font-variant-base;\n  line-height: @line-height-base;\n  list-style: none;\n  font-feature-settings: @font-feature-settings-base;\n}\n"
  },
  {
    "path": "components/style/mixins/rounded-arrow.less",
    "content": ".roundedArrow(\n  @arrow-size,\n  @border-radius-outer,\n  @border-radius-inner,\n  @bg-color: var(--antd-arrow-background-color),\n  @box-shadow: none\n) {\n  @unit-width: (unit(@arrow-size) / 2);\n  @border-radius-outer-without-unit: unit(@border-radius-outer);\n  @border-radius-inner-without-unit: unit(@border-radius-inner);\n\n  @a-x: 0;\n  @a-y: @unit-width;\n  @b-x: ((@border-radius-outer-without-unit * 1) / sqrt(2));\n  @b-y: (@unit-width - @border-radius-outer-without-unit * (1 - 1 / sqrt(2)));\n  @c-x: (@unit-width - @border-radius-inner-without-unit * (1 / sqrt(2)));\n  @c-y: (@border-radius-outer-without-unit * (sqrt(2) - 1) + @border-radius-inner-without-unit * (1 / sqrt(2)));\n  @d-x: 2 * @unit-width - @c-x;\n  @d-y: @c-y;\n  @e-x: 2 * @unit-width - @b-x;\n  @e-y: @b-y;\n  @f-x: 2 * @unit-width - @a-x;\n  @f-y: @a-y;\n\n  @arrow-shadow-width: @unit-width * sqrt(2) + @border-radius-outer * (sqrt(2) - 2);\n\n  // polygon offset\n  @polygon-offset: @border-radius-outer * (sqrt(2) - 1);\n  @polygon-right: @arrow-size - @polygon-offset;\n  @arrow-polygon: polygon(@polygon-offset 100%, 50% @polygon-offset, @polygon-right 100%, @polygon-offset 100%);\n  @arrow-path: path('M @{a-x} @{a-y} A @{border-radius-outer-without-unit} @{border-radius-outer-without-unit} 0 0 0 @{b-x} @{b-y} L @{c-x} @{c-y} A @{border-radius-inner-without-unit} @{border-radius-inner-without-unit} 0 0 1 @{d-x} @{d-y} L @{e-x} @{e-y} A @{border-radius-outer-without-unit} @{border-radius-outer-without-unit} 0 0 0 @{f-x} @{f-y} Z');\n\n  width: @arrow-size;\n  height: @arrow-size;\n  overflow: hidden;\n  pointer-events: none;\n\n  &::before {\n    position: absolute;\n    bottom: 0;\n    width: @arrow-size;\n    height: calc(@arrow-size / 2);\n    background: @bg-color;\n    content: '';\n    clip-path: @arrow-polygon; // For browser that do not support path()\n    clip-path: @arrow-path;\n    inset-inline-start: 0;\n  }\n\n  &::after {\n    position: absolute;\n    bottom: 0;\n    z-index: 0;\n    width: @arrow-shadow-width;\n    height: @arrow-shadow-width;\n    margin: auto;\n    background: transparent;\n    border-radius: 0 0 @border-radius-inner;\n    box-shadow: @box-shadow;\n    transform: translateY(50%) rotate(-135deg);\n    content: '';\n    inset-inline: 0;\n  }\n}\n"
  },
  {
    "path": "components/style/mixins/size.less",
    "content": "// Sizing shortcuts\n\n.size(@width; @height) {\n  width: @width;\n  height: @height;\n}\n\n.square(@size) {\n  .size(@size; @size);\n}\n"
  },
  {
    "path": "components/style/mixins/typography.less",
    "content": "// =============== Common ===============\n.typography-paragraph() {\n  margin-bottom: 1em;\n}\n\n.typography-title(@fontSize; @fontWeight; @lineHeight; @headingColor; @headingMarginBottom;) {\n  margin-bottom: @headingMarginBottom;\n  color: @headingColor;\n  font-weight: @fontWeight;\n  font-size: @fontSize;\n  line-height: @lineHeight;\n}\n\n.typography-title-1() {\n  .typography-title(\n    @heading-1-size,\n    @typography-title-font-weight,\n    1.23,\n    @heading-color,\n    @typography-title-margin-bottom\n  );\n}\n.typography-title-2() {\n  .typography-title(\n    @heading-2-size,\n    @typography-title-font-weight,\n    1.35,\n    @heading-color,\n    @typography-title-margin-bottom\n  );\n}\n.typography-title-3() {\n  .typography-title(\n    @heading-3-size,\n    @typography-title-font-weight,\n    1.35,\n    @heading-color,\n    @typography-title-margin-bottom\n  );\n}\n.typography-title-4() {\n  .typography-title(\n    @heading-4-size,\n    @typography-title-font-weight,\n    1.4,\n    @heading-color,\n    @typography-title-margin-bottom\n  );\n}\n.typography-title-5() {\n  .typography-title(\n    @heading-5-size,\n    @typography-title-font-weight,\n    1.5,\n    @heading-color,\n    @typography-title-margin-bottom\n  );\n}\n"
  },
  {
    "path": "components/style/patch.less",
    "content": "@import './themes/@{root-entry-name}.less';\n\n// cdk overlay\n.cdk-overlay-container,\n.cdk-global-overlay-wrapper {\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  pointer-events: none;\n}\n\n.cdk-overlay-container {\n  position: fixed;\n  z-index: 1000;\n}\n\n.cdk-overlay-container:empty {\n  display: none;\n}\n\n.cdk-global-overlay-wrapper {\n  position: absolute;\n  z-index: 1000;\n  display: flex;\n}\n\n.cdk-overlay-pane {\n  position: absolute;\n  z-index: 1000;\n  display: flex;\n  box-sizing: border-box;\n  max-width: 100%;\n  max-height: 100%;\n  pointer-events: auto;\n}\n\n.cdk-overlay-backdrop {\n  position: absolute;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1000;\n  opacity: 0;\n  transition: opacity 400ms cubic-bezier(0.25, 0.8, 0.25, 1);\n  pointer-events: auto;\n  -webkit-tap-highlight-color: rgb(0, 0, 0, 0);\n}\n\n.cdk-overlay-backdrop.cdk-overlay-backdrop-showing {\n  opacity: 1;\n}\n\n.cdk-high-contrast-active .cdk-overlay-backdrop.cdk-overlay-backdrop-showing {\n  opacity: 0.6;\n}\n\n.cdk-overlay-dark-backdrop {\n  background: rgb(0, 0, 0, 0.32);\n}\n\n.cdk-overlay-transparent-backdrop {\n  visibility: hidden;\n  opacity: 1;\n  transition: visibility 1ms linear, opacity 1ms linear;\n}\n\n.cdk-overlay-transparent-backdrop.cdk-overlay-backdrop-showing {\n  visibility: visible;\n  opacity: 0;\n}\n\n.cdk-overlay-backdrop-noop-animation {\n  transition: none;\n}\n\n.cdk-overlay-connected-position-bounding-box {\n  position: absolute;\n  z-index: 1000;\n  display: flex;\n  flex-direction: column;\n  min-width: 1px;\n  min-height: 1px;\n}\n\n.cdk-global-scrollblock {\n  position: fixed;\n  width: 100%;\n  overflow-y: scroll;\n}\n\n// cdk a11y\n.cdk-visually-hidden {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\n  overflow: hidden;\n  border: 0;\n  outline: 0;\n  /* stylelint-disable property-no-vendor-prefix */\n  -webkit-appearance: none;\n  -moz-appearance: none;\n  /* stylelint-enable property-no-vendor-prefix */\n}\n\n.nz-overlay-transparent-backdrop {\n  &,\n  &.cdk-overlay-backdrop-showing {\n    opacity: 0;\n  }\n}\n\n.nz-animate-disabled {\n  // badge\n  &.ant-scroll-number-only {\n    transition: none;\n    animation: none;\n  }\n\n  // drawer\n  &.ant-drawer {\n    &.ant-drawer-open .ant-drawer-mask {\n      transition: none;\n      animation: none;\n    }\n\n    & > * {\n      transition: none;\n    }\n  }\n\n  // modal\n  .ant-modal-mask,\n  .ant-modal {\n    transition: none;\n    animation: none;\n\n    &.zoom-enter,\n    &.zoom-leave,\n    &.zoom-enter-active,\n    &.zoom-leave-active {\n      transition: none;\n      animation: none;\n    }\n  }\n\n  // menu\n  &.ant-menu {\n    transition: none;\n\n    .ant-menu-item,\n    .ant-menu-submenu-title {\n      transition: none;\n    }\n\n    .ant-menu-item .anticon,\n    .ant-menu-submenu-title .anticon {\n      transition: none;\n\n      & + span {\n        transition: none;\n      }\n    }\n  }\n\n  // tabs\n  &.ant-tabs {\n    .ant-tabs-top-content.ant-tabs-content-animated,\n    .ant-tabs-bottom-content.ant-tabs-content-animated,\n    .ant-tabs-top-content > .ant-tabs-tabpane,\n    .ant-tabs-bottom-content > .ant-tabs-tabpane,\n    &.ant-tabs-left .ant-tabs-ink-bar-animated,\n    &.ant-tabs-right .ant-tabs-ink-bar-animated,\n    &.ant-tabs-top .ant-tabs-ink-bar-animated,\n    &.ant-tabs-bottom .ant-tabs-ink-bar-animated {\n      transition: none;\n    }\n  }\n\n  // collapse\n  &.ant-collapse > .ant-collapse-item > .ant-collapse-header .ant-collapse-arrow svg {\n    transition: none;\n  }\n\n  // tooltip, popover, popconfirm\n  &.ant-tooltip, &.ant-popover {\n    animation: none;\n  }\n\n  // submenu popup\n  &.ant-menu-submenu {\n    transition: none;\n    animation: none;\n  }\n}\n\n// Note: Force GPU rendering to prevent sub-pixel rendering issues at default zoom levels.\n// Without this, floating-point precision loss during transform calculations may cause visible gaps\n// between the arrow and popup content.\n.ant-tooltip.ant-zoom-big-fast-enter,\n.ant-tooltip.ant-zoom-big-fast-leave {\n  .ant-tooltip-arrow {\n    will-change: transform;\n  }\n}\n\n.ant-popover.ant-zoom-big-enter,\n.ant-popover.ant-zoom-big-leave {\n  .ant-popover-arrow {\n    will-change: transform;\n  }\n}"
  },
  {
    "path": "components/style/testing.less",
    "content": "// This file is only used to set the @root-entry-name variable in a test environment.\n\n@import './default.less';\n"
  },
  {
    "path": "components/style/themes/aliyun.less",
    "content": "// Generated by @ant-design/aliyun-theme\n\n@font-size-sm: 12px;\n@font-size-base: 12px;\n@font-size-icon: 12px;\n@primary-color: #0070cc;\n@border-radius-base: 0;\n@border-radius-sm: 0;\n@border-radius-lg: 0;\n@text-color: fade(#000, 65%);\n@text-color-secondary: fade(#000, 45%);\n@background-color-base: hsv(0, 0, 96%);\n@success-color: #1e8e3e;\n@error-color: #d93026;\n@warning-color: #ffc440;\n@info-color: @primary-color;\n@danger-color: @error-color;\n@processing-color: @primary-color;\n@border-color-base: #dedede;\n@border-color-split: #dedede;\n@outline-width: 0;\n@outline-color: #737373;\n@input-height-lg: 36px;\n@input-height-base: 32px;\n@input-height-sm: 24px;\n@input-hover-border-color: #737373;\n@form-item-margin-bottom: 16px;\n@btn-default-bg: #fafafa;\n@btn-default-border: #dedede;\n@btn-danger-color: #fff;\n@btn-danger-bg: @error-color;\n@btn-danger-border: @error-color;\n@switch-color: @success-color;\n@table-header-bg: #fafafa;\n@table-row-hover-bg: #fafafa;\n@table-padding-vertical: 15px;\n@badge-color: @error-color;\n@breadcrumb-base-color: @text-color;\n@breadcrumb-last-item-color: @text-color-secondary;\n@slider-rail-background-color: @background-color-base;\n@slider-rail-background-color-hover: #e1e1e1;\n@slider-track-background-color: @primary-color;\n@slider-track-background-color-hover: @primary-color;\n@slider-handle-border-width: 1px;\n@slider-handle-color: #dedede;\n@slider-handle-color-hover: #dedede;\n@slider-handle-color-focus: #dedede;\n@slider-handle-color-tooltip-open: #ddd;\n@slider-handle-color-focus-shadow: transparent;\n@slider-handle-shadow: 1px 1px 4px 0 rgba(0,0,0,.13);\n@alert-success-border-color: #dff4e5;\n@alert-success-bg-color: #dff4e5;\n@alert-info-border-color: #e5f3ff;\n@alert-info-bg-color: #e5f3ff;\n@alert-error-border-color: #fcebea;\n@alert-error-bg-color: #fcebea;\n@alert-warning-border-color: #fff7db;\n@alert-warning-bg-color: #fff7db;\n@radio-button-bg: transparent;\n@radio-button-checked-bg: transparent;\n@progress-radius: 0;\n@tabs-card-gutter: -1px;\n@tabs-card-tab-active-border-top: 2px solid @primary-color;\n@layout-body-background: #fafafa;\n\n// Patch\n@line-height-base: 1.5717;\n@input-padding-vertical-lg: 8px;\n@input-padding-vertical-base: 6px;\n"
  },
  {
    "path": "components/style/themes/compact.less",
    "content": "@import './default.less';\n\n@line-height-base: 1.66667;\n@line-height-lg: 1.5715;\n@mode: compact;\n@font-size-base: 12px;\n@font-size-lg: @font-size-base + 2px;\n\n// default paddings\n@default-padding-lg: 24px; // containers\n@default-padding-md: 16px; // small containers and buttons\n@default-padding-sm: 12px; // Form controls and items\n@default-padding-xs: 8px; // small items\n@default-padding-xss: 4px; // more small\n\n// vertical paddings\n@padding-lg: 16px; // containers\n@padding-md: 8px; // small containers and buttons\n@padding-sm: 8px; // Form controls and items\n@padding-xs: 4px; // small items\n@padding-xss: 0px; // more small\n\n// vertical padding for all form controls\n@control-padding-horizontal: @padding-sm;\n@control-padding-horizontal-sm: @default-padding-xs;\n\n// vertical margins\n@margin-lg: 16px; // containers\n@margin-md: 8px; // small containers and buttons\n@margin-sm: 8px; // Form controls and items\n@margin-xs: 4px; // small items\n@margin-xss: 0px; // more small\n\n// height rules\n@height-base: 28px;\n@height-lg: 32px;\n@height-sm: 22px;\n\n// Button\n// ---\n@btn-padding-horizontal-base: @default-padding-sm - 1px;\n@btn-padding-horizontal-lg: @btn-padding-horizontal-base;\n@btn-padding-horizontal-sm: @default-padding-xs - 1px;\n@btn-square-only-icon-size-lg: 16px;\n@btn-square-only-icon-size: 14px;\n@btn-square-only-icon-size-sm: 12px;\n\n// Breadcrumb\n// ---\n@breadcrumb-font-size: @font-size-base;\n@breadcrumb-icon-font-size: @font-size-base;\n\n//Dropdown\n@dropdown-line-height: 18px;\n\n// Menu\n@menu-item-padding-horizontal: 12px;\n@menu-horizontal-line-height: 38px;\n@menu-inline-toplevel-item-height: 32px;\n@menu-item-height: 32px;\n@menu-item-vertical-margin: 0px;\n@menu-item-boundary-margin: 0px;\n@menu-icon-margin-right: 8px;\n\n// Checkbox\n@checkbox-size: 14px;\n@checkbox-group-item-margin-right: 6px;\n\n// picker\n@picker-panel-cell-height: 22px;\n@picker-panel-cell-width: 32px;\n@picker-text-height: 32px;\n@picker-time-panel-cell-height: 24px;\n@picker-panel-without-time-cell-height: 48px;\n\n// Form\n// ---\n@form-item-margin-bottom: 16px;\n@form-vertical-label-padding: 0 0 4px;\n\n// Rate\n// ---\n@rate-star-size: 16px;\n\n// Radio\n// ---\n@radio-size: 14px;\n@radio-wrapper-margin-right: 6px;\n\n// Switch\n// ---\n@switch-height: 20px;\n@switch-sm-height: 14px;\n@switch-min-width: 40px;\n@switch-sm-min-width: 24px;\n@switch-inner-margin-min: 4px;\n@switch-inner-margin-max: 22px;\n\n// Slider\n// ---\n@slider-handle-size: 12px;\n@slider-handle-margin-top: -4px;\n\n// Input\n// ---\n@input-padding-vertical-base: round(\n  max(\n    (round(((@input-height-base - @font-size-base * @line-height-base) / 2) * 10) / 10) -\n      @border-width-base,\n    2px\n  )\n);\n@input-padding-horizontal-lg: 11px;\n\n// PageHeader\n// ---\n@page-header-padding: 16px;\n@page-header-padding-vertical: 8px;\n@page-header-heading-title: 16px;\n@page-header-heading-sub-title: 12px;\n@page-header-tabs-tab-font-size: 14px;\n\n// Pagination\n// ---\n@pagination-mini-options-size-changer-top: 1px;\n@pagination-item-size-sm: 22px;\n\n// Cascader\n// ----\n@cascader-dropdown-line-height: @dropdown-line-height;\n\n// Select\n// ---\n@select-dropdown-height: @height-base;\n@select-single-item-height-lg: 32px;\n@select-multiple-item-height: @input-height-base - max(@input-padding-vertical-base, 4) * 2; // Normal 24px\n@select-multiple-item-height-lg: 24px;\n@select-multiple-item-spacing-half: 3px;\n\n// Tree\n// ---\n@tree-title-height: 20px;\n\n// Transfer\n// ---\n@transfer-item-padding-vertical: 3px;\n@transfer-list-search-icon-top: 8px;\n@transfer-header-height: 36px;\n\n// Comment\n// ---\n@comment-actions-margin-bottom: 0px;\n@comment-actions-margin-top: @margin-xs;\n@comment-content-detail-p-margin-bottom: 0px;\n\n// Steps\n// ---\n@steps-icon-size: 24px;\n@steps-icon-custom-size: 20px;\n@steps-icon-custom-font-size: 20px;\n@steps-icon-custom-top: 2px;\n@steps-icon-margin: 2px 8px 2px 0;\n@steps-icon-font-size: @font-size-base;\n@steps-dot-top: 4px;\n@steps-icon-top: 0px;\n@steps-small-icon-size: 20px;\n@steps-vertical-icon-width: 12px;\n@steps-vertical-tail-width: 12px;\n@steps-vertical-tail-width-sm: 10px;\n// Collapse\n// ---\n//@collapse-header-padding-extra: 32px;\n@collapse-content-padding: @padding-md @padding-lg;\n\n// List\n// ---\n@list-item-meta-description-font-size: @font-size-sm;\n@list-item-padding-sm: 4px 12px;\n@list-item-padding-lg: 12px 16px;\n\n// Drawer\n// ---\n@drawer-header-padding: 11px @padding-lg;\n@drawer-footer-padding-vertical: @padding-sm;\n@drawer-footer-padding-horizontal: @padding-sm;\n@drawer-header-close-size: 44px;\n\n// Modal\n// --\n@modal-header-padding-vertical: 11px;\n@modal-header-padding: @modal-header-padding-vertical @modal-header-padding-horizontal;\n@modal-footer-padding-vertical: @padding-sm;\n@modal-header-close-size: @modal-header-title-line-height + 2 * @modal-header-padding-vertical;\n@modal-confirm-body-padding: 24px 24px 16px;\n\n// Message\n// ---\n@message-notice-content-padding: 8px 16px;\n\n// popover\n// --\n@popover-min-height: 28px;\n@popover-padding-horizontal: @default-padding-sm;\n\n// Card\n// ---\n@card-head-height: 36px;\n@card-head-font-size: @card-head-font-size-sm;\n@card-head-padding: 8.5px;\n@card-padding-base: 12px;\n@card-padding-base-sm: @card-padding-base;\n@card-head-height-sm: 30px;\n@card-head-padding-sm: 6px;\n@card-actions-li-margin: 4px 0;\n@card-head-tabs-margin-bottom: -9px;\n\n// Table\n// ---\n@table-padding-vertical: 12px;\n@table-padding-horizontal: 8px;\n@table-padding-vertical-md: 8px;\n@table-padding-horizontal-md: 8px;\n@table-padding-vertical-sm: 4px;\n@table-padding-horizontal-sm: 4px;\n@table-selection-column-width: 32px;\n\n// Statistic\n// ---\n@statistic-content-font-size: 20px;\n\n// Alert\n// ---\n@alert-with-description-no-icon-padding-vertical: 7px;\n@alert-with-description-padding-vertical: 11px;\n@alert-icon-top: 7px + @font-size-base * (@line-height-base / 2) - (@font-size-base / 2);\n@alert-with-description-icon-size: 20px;\n\n// Skeleton\n// ---\n@skeleton-paragraph-margin-top: 20px;\n@skeleton-paragraph-li-margin-top: 12px;\n@skeleton-paragraph-li-height: 14px;\n@skeleton-title-height: 14px;\n@skeleton-title-paragraph-margin-top: 20px;\n\n// Descriptions\n@descriptions-title-margin-bottom: 8px;\n@descriptions-default-padding: 12px @padding-lg;\n@descriptions-item-padding-bottom: @padding-xs;\n\n// Avatar\n// ---\n@avatar-size-base: 28px;\n@avatar-size-lg: 32px;\n@avatar-size-sm: 22px;\n@avatar-font-size-base: 16px;\n@avatar-font-size-lg: 20px;\n@avatar-font-size-sm: 12px;\n\n// Badge\n// ---\n@badge-height: 18px;\n\n// Tag\n// ---\n@tag-line-height: 18px;\n\n// Notification\n// ---\n@notification-padding-vertical: 12px;\n@notification-padding-horizontal: 16px;\n\n// Result\n// ---\n@result-title-font-size: 20px;\n@result-icon-font-size: 64px;\n@result-extra-margin: 24px 0 0 0;\n\n// Anchor\n// ---\n@anchor-link-top: 4px;\n@anchor-link-left: 16px;\n@anchor-link-padding: @anchor-link-top 0 @anchor-link-top @anchor-link-left;\n\n// Tabs\n// ---\n@tabs-card-horizontal-padding: 4px @padding-md;\n\n// Progress\n// ---\n@progress-circle-text-font-size: 0.833333em;\n\n// Image\n// ---\n@image-size-base: 48px;\n@image-font-size-base: 24px;\n"
  },
  {
    "path": "components/style/themes/dark.less",
    "content": "@import './default.less';\n\n@theme: dark;\n// color palettes\n@blue-1: mix(color(colorPalette('@{blue-base}', 8)), @component-background, 15%);\n@blue-2: mix(color(colorPalette('@{blue-base}', 7)), @component-background, 25%);\n@blue-3: mix(@blue-base, @component-background, 30%);\n@blue-4: mix(@blue-base, @component-background, 45%);\n@blue-5: mix(@blue-base, @component-background, 65%);\n@blue-6: mix(@blue-base, @component-background, 85%);\n@blue-7: mix(color(colorPalette('@{blue-base}', 5)), @component-background, 90%);\n@blue-8: mix(color(colorPalette('@{blue-base}', 4)), @component-background, 95%);\n@blue-9: mix(color(colorPalette('@{blue-base}', 3)), @component-background, 97%);\n@blue-10: mix(color(colorPalette('@{blue-base}', 2)), @component-background, 98%);\n\n@purple-1: mix(color(colorPalette('@{purple-base}', 8)), @component-background, 15%);\n@purple-2: mix(color(colorPalette('@{purple-base}', 7)), @component-background, 25%);\n@purple-3: mix(@purple-base, @component-background, 30%);\n@purple-4: mix(@purple-base, @component-background, 45%);\n@purple-5: mix(@purple-base, @component-background, 65%);\n@purple-6: mix(@purple-base, @component-background, 85%);\n@purple-7: mix(color(colorPalette('@{purple-base}', 5)), @component-background, 90%);\n@purple-8: mix(color(colorPalette('@{purple-base}', 4)), @component-background, 95%);\n@purple-9: mix(color(colorPalette('@{purple-base}', 3)), @component-background, 97%);\n@purple-10: mix(color(colorPalette('@{purple-base}', 2)), @component-background, 98%);\n\n@cyan-1: mix(color(colorPalette('@{cyan-base}', 8)), @component-background, 15%);\n@cyan-2: mix(color(colorPalette('@{cyan-base}', 7)), @component-background, 25%);\n@cyan-3: mix(@cyan-base, @component-background, 30%);\n@cyan-4: mix(@cyan-base, @component-background, 45%);\n@cyan-5: mix(@cyan-base, @component-background, 65%);\n@cyan-6: mix(@cyan-base, @component-background, 85%);\n@cyan-7: mix(color(colorPalette('@{cyan-base}', 5)), @component-background, 90%);\n@cyan-8: mix(color(colorPalette('@{cyan-base}', 4)), @component-background, 95%);\n@cyan-9: mix(color(colorPalette('@{cyan-base}', 3)), @component-background, 97%);\n@cyan-10: mix(color(colorPalette('@{cyan-base}', 2)), @component-background, 98%);\n\n@green-1: mix(color(colorPalette('@{green-base}', 8)), @component-background, 15%);\n@green-2: mix(color(colorPalette('@{green-base}', 7)), @component-background, 25%);\n@green-3: mix(@green-base, @component-background, 30%);\n@green-4: mix(@green-base, @component-background, 45%);\n@green-5: mix(@green-base, @component-background, 65%);\n@green-6: mix(@green-base, @component-background, 85%);\n@green-7: mix(color(colorPalette('@{green-base}', 5)), @component-background, 90%);\n@green-8: mix(color(colorPalette('@{green-base}', 4)), @component-background, 95%);\n@green-9: mix(color(colorPalette('@{green-base}', 3)), @component-background, 97%);\n@green-10: mix(color(colorPalette('@{green-base}', 2)), @component-background, 98%);\n\n@magenta-1: mix(color(colorPalette('@{magenta-base}', 8)), @component-background, 15%);\n@magenta-2: mix(color(colorPalette('@{magenta-base}', 7)), @component-background, 25%);\n@magenta-3: mix(@magenta-base, @component-background, 30%);\n@magenta-4: mix(@magenta-base, @component-background, 45%);\n@magenta-5: mix(@magenta-base, @component-background, 65%);\n@magenta-6: mix(@magenta-base, @component-background, 85%);\n@magenta-7: mix(color(colorPalette('@{magenta-base}', 5)), @component-background, 90%);\n@magenta-8: mix(color(colorPalette('@{magenta-base}', 4)), @component-background, 95%);\n@magenta-9: mix(color(colorPalette('@{magenta-base}', 3)), @component-background, 97%);\n@magenta-10: mix(color(colorPalette('@{magenta-base}', 2)), @component-background, 98%);\n\n@pink-1: mix(color(colorPalette('@{pink-base}', 8)), @component-background, 15%);\n@pink-2: mix(color(colorPalette('@{pink-base}', 7)), @component-background, 25%);\n@pink-3: mix(@pink-base, @component-background, 30%);\n@pink-4: mix(@pink-base, @component-background, 45%);\n@pink-5: mix(@pink-base, @component-background, 65%);\n@pink-6: mix(@pink-base, @component-background, 85%);\n@pink-7: mix(color(colorPalette('@{pink-base}', 5)), @component-background, 90%);\n@pink-8: mix(color(colorPalette('@{pink-base}', 4)), @component-background, 95%);\n@pink-9: mix(color(colorPalette('@{pink-base}', 3)), @component-background, 97%);\n@pink-10: mix(color(colorPalette('@{pink-base}', 2)), @component-background, 98%);\n\n@red-1: mix(color(colorPalette('@{red-base}', 8)), @component-background, 15%);\n@red-2: mix(color(colorPalette('@{red-base}', 7)), @component-background, 25%);\n@red-3: mix(@red-base, @component-background, 30%);\n@red-4: mix(@red-base, @component-background, 45%);\n@red-5: mix(@red-base, @component-background, 65%);\n@red-6: mix(@red-base, @component-background, 85%);\n@red-7: mix(color(colorPalette('@{red-base}', 5)), @component-background, 90%);\n@red-8: mix(color(colorPalette('@{red-base}', 4)), @component-background, 95%);\n@red-9: mix(color(colorPalette('@{red-base}', 3)), @component-background, 97%);\n@red-10: mix(color(colorPalette('@{red-base}', 2)), @component-background, 98%);\n\n@orange-1: mix(color(colorPalette('@{orange-base}', 8)), @component-background, 15%);\n@orange-2: mix(color(colorPalette('@{orange-base}', 7)), @component-background, 25%);\n@orange-3: mix(@orange-base, @component-background, 30%);\n@orange-4: mix(@orange-base, @component-background, 45%);\n@orange-5: mix(@orange-base, @component-background, 65%);\n@orange-6: mix(@orange-base, @component-background, 85%);\n@orange-7: mix(color(colorPalette('@{orange-base}', 5)), @component-background, 90%);\n@orange-8: mix(color(colorPalette('@{orange-base}', 4)), @component-background, 95%);\n@orange-9: mix(color(colorPalette('@{orange-base}', 3)), @component-background, 97%);\n@orange-10: mix(color(colorPalette('@{orange-base}', 2)), @component-background, 98%);\n\n@yellow-1: mix(color(colorPalette('@{yellow-base}', 8)), @component-background, 15%);\n@yellow-2: mix(color(colorPalette('@{yellow-base}', 7)), @component-background, 25%);\n@yellow-3: mix(@yellow-base, @component-background, 30%);\n@yellow-4: mix(@yellow-base, @component-background, 45%);\n@yellow-5: mix(@yellow-base, @component-background, 65%);\n@yellow-6: mix(@yellow-base, @component-background, 85%);\n@yellow-7: mix(color(colorPalette('@{yellow-base}', 5)), @component-background, 90%);\n@yellow-8: mix(color(colorPalette('@{yellow-base}', 4)), @component-background, 95%);\n@yellow-9: mix(color(colorPalette('@{yellow-base}', 3)), @component-background, 97%);\n@yellow-10: mix(color(colorPalette('@{yellow-base}', 2)), @component-background, 98%);\n\n@volcano-1: mix(color(colorPalette('@{volcano-base}', 8)), @component-background, 15%);\n@volcano-2: mix(color(colorPalette('@{volcano-base}', 7)), @component-background, 25%);\n@volcano-3: mix(@volcano-base, @component-background, 30%);\n@volcano-4: mix(@volcano-base, @component-background, 45%);\n@volcano-5: mix(@volcano-base, @component-background, 65%);\n@volcano-6: mix(@volcano-base, @component-background, 85%);\n@volcano-7: mix(color(colorPalette('@{volcano-base}', 5)), @component-background, 90%);\n@volcano-8: mix(color(colorPalette('@{volcano-base}', 4)), @component-background, 95%);\n@volcano-9: mix(color(colorPalette('@{volcano-base}', 3)), @component-background, 97%);\n@volcano-10: mix(color(colorPalette('@{volcano-base}', 2)), @component-background, 98%);\n\n@geekblue-1: mix(color(colorPalette('@{geekblue-base}', 8)), @component-background, 15%);\n@geekblue-2: mix(color(colorPalette('@{geekblue-base}', 7)), @component-background, 25%);\n@geekblue-3: mix(@geekblue-base, @component-background, 30%);\n@geekblue-4: mix(@geekblue-base, @component-background, 45%);\n@geekblue-5: mix(@geekblue-base, @component-background, 65%);\n@geekblue-6: mix(@geekblue-base, @component-background, 85%);\n@geekblue-7: mix(color(colorPalette('@{geekblue-base}', 5)), @component-background, 90%);\n@geekblue-8: mix(color(colorPalette('@{geekblue-base}', 4)), @component-background, 95%);\n@geekblue-9: mix(color(colorPalette('@{geekblue-base}', 3)), @component-background, 97%);\n@geekblue-10: mix(color(colorPalette('@{geekblue-base}', 2)), @component-background, 98%);\n\n@lime-1: mix(color(colorPalette('@{lime-base}', 8)), @component-background, 15%);\n@lime-2: mix(color(colorPalette('@{lime-base}', 7)), @component-background, 25%);\n@lime-3: mix(@lime-base, @component-background, 30%);\n@lime-4: mix(@lime-base, @component-background, 45%);\n@lime-5: mix(@lime-base, @component-background, 65%);\n@lime-6: mix(@lime-base, @component-background, 85%);\n@lime-7: mix(color(colorPalette('@{lime-base}', 5)), @component-background, 90%);\n@lime-8: mix(color(colorPalette('@{lime-base}', 4)), @component-background, 95%);\n@lime-9: mix(color(colorPalette('@{lime-base}', 3)), @component-background, 97%);\n@lime-10: mix(color(colorPalette('@{lime-base}', 2)), @component-background, 98%);\n\n@gold-1: mix(color(colorPalette('@{gold-base}', 8)), @component-background, 15%);\n@gold-2: mix(color(colorPalette('@{gold-base}', 7)), @component-background, 25%);\n@gold-3: mix(@gold-base, @component-background, 30%);\n@gold-4: mix(@gold-base, @component-background, 45%);\n@gold-5: mix(@gold-base, @component-background, 65%);\n@gold-6: mix(@gold-base, @component-background, 85%);\n@gold-7: mix(color(colorPalette('@{gold-base}', 5)), @component-background, 90%);\n@gold-8: mix(color(colorPalette('@{gold-base}', 4)), @component-background, 95%);\n@gold-9: mix(color(colorPalette('@{gold-base}', 3)), @component-background, 97%);\n@gold-10: mix(color(colorPalette('@{gold-base}', 2)), @component-background, 98%);\n\n// Color used by default to control hover and active backgrounds and for\n// alert info backgrounds.\n@primary-1: mix(color(colorPalette('@{primary-color}', 8)), @component-background, 15%);\n@primary-2: mix(color(colorPalette('@{primary-color}', 7)), @component-background, 25%);\n@primary-3: mix(@primary-color, @component-background, 30%);\n@primary-4: mix(@primary-color, @component-background, 45%);\n@primary-5: mix(@primary-color, @component-background, 65%);\n@primary-6: @primary-color;\n@primary-7: mix(color(colorPalette('@{primary-color}', 5)), @component-background, 90%);\n@primary-8: mix(color(colorPalette('@{primary-color}', 4)), @component-background, 95%);\n@primary-9: mix(color(colorPalette('@{primary-color}', 3)), @component-background, 97%);\n@primary-10: mix(color(colorPalette('@{primary-color}', 2)), @component-background, 98%);\n\n// Layer background\n@popover-background: #1f1f1f;\n@popover-customize-border-color: #3a3a3a;\n@body-background: @black;\n@component-background: #141414;\n\n@text-color: fade(@white, 85%);\n@text-color-secondary: fade(@white, 45%);\n@text-color-inverse: @white;\n@icon-color-hover: fade(@white, 75%);\n@heading-color: fade(@white, 85%);\n\n// The background colors for active and hover states for things like\n// list items or table cells.\n@item-active-bg: @primary-1;\n@item-hover-bg: fade(@white, 8%);\n@fill-color: rgba(255, 255, 255, 0.15);\n\n// Border color\n@border-color-base: #434343; // base border outline a component\n@border-color-split: #303030; // split border inside a component\n\n@background-color-light: fade(@white, 4%); // background of header and selected item\n@background-color-base: fade(@white, 8%); // Default grey background color\n\n// Disabled states\n@disabled-color: fade(@white, 30%);\n@disabled-bg: @background-color-base;\n@disabled-color-dark: fade(@white, 30%);\n\n// Tree\n// ---\n@tree-bg: transparent;\n\n// List\n// ---\n@list-customize-card-bg: transparent;\n\n// Shadow\n// ---\n@shadow-color: rgba(0, 0, 0, 0.45);\n@shadow-color-inverse: @component-background;\n@box-shadow-base: @shadow-2;\n@shadow-1-up: 0 -6px 16px -8px rgba(0, 0, 0, 0.32), 0 -9px 28px 0 rgba(0, 0, 0, 0.2),\n  0 -12px 48px 16px rgba(0, 0, 0, 0.12);\n@shadow-1-down: 0 6px 16px -8px rgba(0, 0, 0, 0.32), 0 9px 28px 0 rgba(0, 0, 0, 0.2),\n  0 12px 48px 16px rgba(0, 0, 0, 0.12);\n@shadow-1-right: 6px 0 16px -8px rgba(0, 0, 0, 0.32), 9px 0 28px 0 rgba(0, 0, 0, 0.2),\n  12px 0 48px 16px rgba(0, 0, 0, 0.12);\n@shadow-2: 0 3px 6px -4px rgba(0, 0, 0, 0.48), 0 6px 16px 0 rgba(0, 0, 0, 0.32),\n  0 9px 28px 8px rgba(0, 0, 0, 0.2);\n\n// Buttons\n// ---\n@btn-shadow: 0 2px 0 rgba(0, 0, 0, 0.015);\n@btn-primary-shadow: 0 2px 0 rgba(0, 0, 0, 0.045);\n@btn-text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12);\n\n@btn-default-bg: transparent;\n\n@btn-default-ghost-color: @text-color;\n@btn-default-ghost-border: fade(@white, 25%);\n\n@btn-text-hover-bg: rgba(255, 255, 255, 0.03);\n\n// Checkbox\n// ---\n@checkbox-check-bg: transparent;\n\n// Descriptions\n// ---\n@descriptions-bg: @background-color-light;\n\n// Divider\n// ---\n@divider-color: rgba(255, 255, 255, 12%);\n\n// Modal\n// ---\n@modal-header-bg: @popover-background;\n@modal-header-border-color-split: @border-color-split;\n@modal-content-bg: @popover-background;\n@modal-footer-border-color-split: @border-color-split;\n\n// Radio\n// ---\n@radio-solid-checked-color: @white;\n@radio-dot-disabled-color: fade(@white, 20%);\n\n// Radio buttons\n// ---\n@radio-disabled-button-checked-bg: fade(@white, 20%);\n@radio-disabled-button-checked-color: @disabled-color;\n\n// Layout\n// ---\n@layout-body-background: @body-background;\n@layout-header-background: @popover-background;\n@layout-trigger-background: #262626;\n\n// Input\n// ---\n@input-bg: transparent;\n@input-placeholder-color: fade(@white, 30%);\n@input-icon-color: fade(@white, 30%);\n@input-number-handler-active-bg: @item-hover-bg;\n@input-icon-hover-color: fade(@white, 85%);\n@input-variant-filled-bg: @background-color-light;\n@input-variant-filled-hover-bg: @background-color-base;\n\n// Select\n// ---\n@select-background: transparent;\n@select-dropdown-bg: @popover-background;\n@select-clear-background: @component-background;\n@select-selection-item-bg: fade(@white, 8);\n@select-selection-item-border-color: @border-color-split;\n@select-multiple-disabled-background: @component-background;\n@select-multiple-item-disabled-color: #595959;\n@select-multiple-item-disabled-border-color: @popover-background;\n@select-multiple-item-filled-bg: @component-background;\n\n// Cascader\n// ---\n@cascader-bg: transparent;\n@cascader-menu-bg: @popover-background;\n@cascader-menu-border-color-split: @border-color-split;\n\n// Tooltip\n// ---\n// Tooltip background color\n@tooltip-bg: #434343;\n\n// Menu\n// ---\n// dark theme\n@menu-dark-inline-submenu-bg: @component-background;\n@menu-dark-bg: @popover-background;\n@menu-popup-bg: @popover-background;\n\n// Message\n// ---\n@message-notice-content-bg: @popover-background;\n\n// Notification\n@notification-bg: @popover-background;\n\n// LINK\n@link-hover-color: @primary-5;\n@link-active-color: @primary-7;\n\n// Splitter\n// --\n@splitter-bar-bg: rgba(255, 255, 255, 0.08);\n@splitter-bar-hover-bg: #111a2c;\n@splitter-bar-active-bg: #112545;\n\n// Table\n// --\n@table-header-bg: #1d1d1d;\n@table-body-sort-bg: fade(@white, 1%);\n@table-row-hover-bg: #262626;\n@table-header-cell-split-color: fade(@white, 8%);\n@table-header-sort-bg: #262626;\n@table-header-filter-active-bg: #434343;\n@table-header-sort-active-bg: #303030;\n@table-fixed-header-sort-active-bg: #222;\n@table-filter-btns-bg: @popover-background;\n@table-expanded-row-bg: @table-header-bg;\n@table-filter-dropdown-bg: @popover-background;\n@table-expand-icon-bg: transparent;\n\n// Tag\n// ---\n@info-color-deprecated-bg: @primary-1;\n@info-color-deprecated-border: @primary-3;\n@success-color-deprecated-bg: @green-1;\n@success-color-deprecated-border: @green-3;\n@warning-color-deprecated-bg: @orange-1;\n@warning-color-deprecated-border: @orange-3;\n@error-color-deprecated-bg: @red-1;\n@error-color-deprecated-border: @red-3;\n\n// TimePicker\n// ---\n@picker-basic-cell-hover-with-range-color: darken(@primary-color, 35%);\n@picker-basic-cell-disabled-bg: #303030;\n@picker-border-color: @border-color-split;\n@picker-bg: transparent;\n@picker-date-hover-range-border-color: darken(@primary-color, 20%);\n\n// Dropdown\n// ---\n@dropdown-menu-bg: @popover-background;\n@dropdown-menu-submenu-disabled-bg: transparent;\n\n// Steps\n// ---\n@steps-nav-arrow-color: fade(@white, 20%);\n@steps-background: transparent;\n\n// Avatar\n// ---\n@avatar-bg: fade(@white, 30%);\n\n// Progress\n// ---\n@progress-steps-item-bg: fade(@white, 8%);\n\n// Calendar\n// ---\n@calendar-bg: @popover-background;\n@calendar-input-bg: @calendar-bg;\n@calendar-border-color: transparent;\n@calendar-full-bg: @component-background;\n\n// Badge\n// ---\n@badge-text-color: @white;\n\n// Popover\n@popover-bg: @popover-background;\n\n// Drawer\n@drawer-bg: @popover-background;\n\n// Card\n// ---\n@card-actions-background: @component-background;\n@card-skeleton-bg: #303030;\n@card-shadow: 0 1px 2px -2px rgba(0, 0, 0, 0.64), 0 3px 6px 0 rgba(0, 0, 0, 0.48),\n  0 5px 12px 4px rgba(0, 0, 0, 0.36);\n\n// Transfer\n// ---\n@transfer-item-hover-bg: #262626;\n\n// Comment\n// ---\n@comment-bg: transparent;\n@comment-author-time-color: fade(@white, 30%);\n@comment-action-hover-color: fade(@white, 65%);\n\n// Rate\n// ---\n@rate-star-bg: fade(@white, 12%);\n\n// Switch\n// ---\n@switch-bg: @white;\n\n// Pagination\n// ---\n@pagination-item-bg: transparent;\n@pagination-item-bg-active: transparent;\n@pagination-item-link-bg: transparent;\n@pagination-item-disabled-bg-active: fade(@white, 25%);\n@pagination-item-disabled-color-active: @black;\n@pagination-item-input-bg: @pagination-item-bg;\n\n// PageHeader\n// ---\n@page-header-back-color: @icon-color;\n@page-header-ghost-bg: transparent;\n\n// Slider\n// ---\n@slider-rail-background-color: #262626;\n@slider-rail-background-color-hover: @border-color-base;\n@slider-dot-border-color: @border-color-split;\n@slider-dot-border-color-active: @primary-4;\n\n// Skeleton\n// ---\n@skeleton-to-color: fade(@white, 16%);\n\n// Alert\n// ---\n@alert-success-border-color: @green-3;\n@alert-success-bg-color: @green-1;\n@alert-success-icon-color: @success-color;\n@alert-info-border-color: @primary-3;\n@alert-info-bg-color: @primary-1;\n@alert-info-icon-color: @info-color;\n@alert-warning-border-color: @gold-3;\n@alert-warning-bg-color: @gold-1;\n@alert-warning-icon-color: @warning-color;\n@alert-error-border-color: @red-3;\n@alert-error-bg-color: @red-1;\n@alert-error-icon-color: @error-color;\n\n// Timeline\n// ---\n@timeline-color: @border-color-split;\n@timeline-dot-color: @primary-color;\n\n// Mentions\n// ---\n@mentions-dropdown-bg: @popover-background;\n\n// Segmented\n// ---\n@segmented-bg: fade(@black, 25%);\n@segmented-hover-bg: fade(@black, 45%);\n@segmented-selected-bg: #333333;\n@segmented-label-color: fade(@white, 65%);\n@segmented-label-hover-color: fade(@white, 85%);\n"
  },
  {
    "path": "components/style/themes/default.less",
    "content": "/* stylelint-disable at-rule-empty-line-before,at-rule-name-space-after,at-rule-no-unknown */\n@import '../color/colors';\n\n@theme: default;\n\n// The prefix to use on all css classes from ant.\n@ant-prefix: ant;\n\n// An override for the html selector for theme prefixes\n@html-selector: html;\n\n// [CSS-VARIABLE-REPLACE-BEGIN: html-variables]\n// [CSS-VARIABLE-REPLACE-END: html-variables]\n\n// -------- Colors -----------\n// >>> Primary\n@primary-color: @blue-6;\n@primary-color-hover: color(colorPalette('@{primary-color}', 5));\n@primary-color-active: color(colorPalette('@{primary-color}', 7));\n@primary-color-outline: fade(@primary-color, @outline-fade);\n\n@processing-color: @blue-6;\n\n// >>> Info\n@info-color: @primary-color;\n@info-color-deprecated-bg: color(colorPalette('@{info-color}', 1));\n@info-color-deprecated-border: color(colorPalette('@{info-color}', 3));\n\n// >>> Success\n@success-color: @green-6;\n@success-color-hover: color(colorPalette('@{success-color}', 5));\n@success-color-active: color(colorPalette('@{success-color}', 7));\n@success-color-outline: fade(@success-color, @outline-fade);\n@success-color-deprecated-bg: color(colorPalette('@{success-color}', 1));\n@success-color-deprecated-border: color(colorPalette('@{success-color}', 3));\n\n// >>> Warning\n@warning-color: @gold-6;\n@warning-color-hover: color(colorPalette('@{warning-color}', 5));\n@warning-color-active: color(colorPalette('@{warning-color}', 7));\n@warning-color-outline: fade(@warning-color, @outline-fade);\n@warning-color-deprecated-bg: color(colorPalette('@{warning-color}', 1));\n@warning-color-deprecated-border: color(colorPalette('@{warning-color}', 3));\n\n// >>> Error\n@error-color: @red-5;\n@error-color-hover: color(colorPalette('@{error-color}', 5));\n@error-color-active: color(colorPalette('@{error-color}', 7));\n@error-color-outline: fade(@error-color, @outline-fade);\n@error-color-deprecated-bg: color(colorPalette('@{error-color}', 1));\n@error-color-deprecated-border: color(colorPalette('@{error-color}', 3));\n\n@highlight-color: @red-5;\n@normal-color: #d9d9d9;\n@white: #fff;\n@black: #000;\n\n// Color used by default to control hover and active backgrounds and for\n// alert info backgrounds.\n@primary-1: color(colorPalette('@{primary-color}', 1)); // replace tint(@primary-color, 90%)\n@primary-2: color(colorPalette('@{primary-color}', 2)); // replace tint(@primary-color, 80%)\n@primary-3: color(colorPalette('@{primary-color}', 3)); // unused\n@primary-4: color(colorPalette('@{primary-color}', 4)); // unused\n@primary-5: color(\n  colorPalette('@{primary-color}', 5)\n); // color used to control the text color in many active and hover states, replace tint(@primary-color, 20%)\n@primary-6: @primary-color; // color used to control the text color of active buttons, don't use, use @primary-color\n@primary-7: color(colorPalette('@{primary-color}', 7)); // replace shade(@primary-color, 5%)\n@primary-8: color(colorPalette('@{primary-color}', 8)); // unused\n@primary-9: color(colorPalette('@{primary-color}', 9)); // unused\n@primary-10: color(colorPalette('@{primary-color}', 10)); // unused\n\n// Base Scaffolding Variables\n// ---\n\n// Background color for `<body>`\n@body-background: #fff;\n// Base background color for most components\n@component-background: #fff;\n// Popover background color\n@popover-background: @component-background;\n@popover-customize-border-color: @border-color-split;\n@font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,\n  'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',\n  'Noto Color Emoji';\n@code-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;\n@text-color: fade(@black, 85%);\n@text-color-secondary: fade(@black, 45%);\n@text-color-inverse: @white;\n@icon-color: inherit;\n@icon-color-hover: fade(@black, 75%);\n@heading-color: fade(@black, 85%);\n@text-color-dark: fade(@white, 85%);\n@text-color-secondary-dark: fade(@white, 65%);\n@text-selection-bg: @primary-color;\n@font-variant-base: tabular-nums;\n@font-feature-settings-base: 'tnum';\n@font-size-base: 14px;\n@font-size-lg: @font-size-base + 2px;\n@font-size-sm: 12px;\n@font-size-icon: @font-size-sm;\n@heading-1-size: ceil(@font-size-base * 2.71);\n@heading-2-size: ceil(@font-size-base * 2.14);\n@heading-3-size: ceil(@font-size-base * 1.71);\n@heading-4-size: ceil(@font-size-base * 1.42);\n@heading-5-size: ceil(@font-size-base * 1.14);\n// https://github.com/ant-design/ant-design/issues/20210\n@line-height-base: 1.5715;\n@line-height-lg: 1.5;\n@line-width: 1px;\n@line-width-focus: calc(@line-width * 3);\n@border-radius-base: 2px;\n@border-radius-sm: 2px;\n@border-radius-lg: 4px;\n\n// control border\n@control-border-radius: @border-radius-base;\n\n// arrow border\n@arrow-border-radius: 2px;\n\n// vertical paddings\n@padding-lg: 24px; // containers\n@padding-md: 16px; // small containers and buttons\n@padding-sm: 12px; // Form controls and items\n@padding-xs: 8px; // small items\n@padding-xss: 4px; // more small\n\n// vertical padding for all form controls\n@control-padding-horizontal: @padding-sm;\n@control-padding-horizontal-sm: @padding-xs;\n\n// vertical margins\n@margin-lg: 24px; // containers\n@margin-md: 16px; // small containers and buttons\n@margin-sm: 12px; // Form controls and items\n@margin-xs: 8px; // small items\n@margin-xss: 4px; // more small\n\n// height rules\n@height-base: 32px;\n@height-lg: 40px;\n@height-sm: 24px;\n\n// The background colors for active and hover states for things like\n// list items or table cells.\n@item-active-bg: @primary-1;\n@item-hover-bg: #f5f5f5;\n@fill-color: rgba(0, 0, 0, 0.15);\n\n// ICONFONT\n@iconfont-css-prefix: anticon;\n\n// LINK\n@link-color: @primary-color;\n@link-hover-color: color(colorPalette('@{link-color}', 5));\n@link-active-color: color(colorPalette('@{link-color}', 7));\n@link-decoration: none;\n@link-hover-decoration: none;\n@link-focus-decoration: none;\n@link-focus-outline: 0;\n\n// Animation\n@ease-base-out: cubic-bezier(0.7, 0.3, 0.1, 1);\n@ease-base-in: cubic-bezier(0.9, 0, 0.3, 0.7);\n@ease-out: cubic-bezier(0.215, 0.61, 0.355, 1);\n@ease-in: cubic-bezier(0.55, 0.055, 0.675, 0.19);\n@ease-in-out: cubic-bezier(0.645, 0.045, 0.355, 1);\n@ease-out-back: cubic-bezier(0.12, 0.4, 0.29, 1.46);\n@ease-in-back: cubic-bezier(0.71, -0.46, 0.88, 0.6);\n@ease-in-out-back: cubic-bezier(0.71, -0.46, 0.29, 1.46);\n@ease-out-circ: cubic-bezier(0.08, 0.82, 0.17, 1);\n@ease-in-circ: cubic-bezier(0.6, 0.04, 0.98, 0.34);\n@ease-in-out-circ: cubic-bezier(0.78, 0.14, 0.15, 0.86);\n@ease-out-quint: cubic-bezier(0.23, 1, 0.32, 1);\n@ease-in-quint: cubic-bezier(0.755, 0.05, 0.855, 0.06);\n@ease-in-out-quint: cubic-bezier(0.86, 0, 0.07, 1);\n\n// Border color\n@border-color-base: hsv(0, 0, 85%); // base border outline a component\n@border-color-split: hsv(0, 0, 94%); // split border inside a component\n@border-color-inverse: @white;\n@border-color-primary: @primary-3;\n@border-width-base: 1px; // width of the border for a component\n@border-style-base: solid; // style of a components border\n\n// Outline\n@outline-blur-size: 0;\n@outline-width: 2px;\n@outline-color: @primary-color; // No use anymore\n@outline-fade: 20%;\n\n@background-color-light: hsv(0, 0, 98%); // background of header and selected item\n@background-color-base: hsv(0, 0, 96%); // Default grey background color\n@background-color-dark: hsv(0, 0, 94%); // dark grey background color\n\n// Disabled states\n@disabled-color: fade(#000, 25%);\n@disabled-bg: @background-color-base;\n@disabled-active-bg: tint(@black, 90%);\n@disabled-color-dark: fade(#fff, 35%);\n\n// Shadow\n@shadow-color: rgba(0, 0, 0, 0.15);\n@shadow-color-inverse: @component-background;\n@box-shadow-base: @shadow-2;\n@shadow-1-up: 0 -6px 16px -8px rgba(0, 0, 0, 0.08), 0 -9px 28px 0 rgba(0, 0, 0, 0.05),\n  0 -12px 48px 16px rgba(0, 0, 0, 0.03);\n@shadow-1-down: 0 6px 16px -8px rgba(0, 0, 0, 0.08), 0 9px 28px 0 rgba(0, 0, 0, 0.05),\n  0 12px 48px 16px rgba(0, 0, 0, 0.03);\n@shadow-1-left: -6px 0 16px -8px rgba(0, 0, 0, 0.08), -9px 0 28px 0 rgba(0, 0, 0, 0.05),\n  -12px 0 48px 16px rgba(0, 0, 0, 0.03);\n@shadow-1-right: 6px 0 16px -8px rgba(0, 0, 0, 0.08), 9px 0 28px 0 rgba(0, 0, 0, 0.05),\n  12px 0 48px 16px rgba(0, 0, 0, 0.03);\n@shadow-2: 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, 0.08),\n  0 9px 28px 8px rgba(0, 0, 0, 0.05);\n\n// Buttons\n@btn-font-weight: 400;\n@btn-border-radius-base: @border-radius-base;\n@btn-border-radius-sm: @border-radius-base;\n@btn-border-width: @border-width-base;\n@btn-border-style: @border-style-base;\n@btn-shadow: 0 2px 0 rgba(0, 0, 0, 0.015);\n@btn-primary-shadow: 0 2px 0 rgba(0, 0, 0, 0.045);\n@btn-text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12);\n\n@btn-primary-color: #fff;\n@btn-primary-bg: @primary-color;\n\n@btn-default-color: @text-color;\n@btn-default-bg: @component-background;\n@btn-default-border: @border-color-base;\n\n@btn-danger-color: #fff;\n@btn-danger-bg: @error-color;\n@btn-danger-border: @error-color;\n\n@btn-disable-color: @disabled-color;\n@btn-disable-bg: @disabled-bg;\n@btn-disable-border: @border-color-base;\n\n@btn-default-ghost-color: @component-background;\n@btn-default-ghost-bg: transparent;\n@btn-default-ghost-border: @component-background;\n\n@btn-font-size-lg: @font-size-lg;\n@btn-font-size-sm: @font-size-base;\n@btn-padding-horizontal-base: @padding-md - 1px;\n@btn-padding-horizontal-lg: @btn-padding-horizontal-base;\n@btn-padding-horizontal-sm: @padding-xs - 1px;\n\n@btn-height-base: @height-base;\n@btn-height-lg: @height-lg;\n@btn-height-sm: @height-sm;\n\n@btn-line-height: @line-height-base;\n\n@btn-circle-size: @btn-height-base;\n@btn-circle-size-lg: @btn-height-lg;\n@btn-circle-size-sm: @btn-height-sm;\n\n@btn-square-size: @btn-height-base;\n@btn-square-size-lg: @btn-height-lg;\n@btn-square-size-sm: @btn-height-sm;\n@btn-square-only-icon-size: @font-size-base + 2px;\n@btn-square-only-icon-size-sm: @font-size-base;\n@btn-square-only-icon-size-lg: @btn-font-size-lg + 2px;\n\n@btn-group-border: @primary-5;\n\n@btn-link-hover-bg: transparent;\n@btn-text-hover-bg: rgba(0, 0, 0, 0.018);\n\n// Checkbox\n@checkbox-size: 16px;\n@checkbox-color: @primary-color;\n@checkbox-check-color: #fff;\n@checkbox-check-bg: @checkbox-check-color;\n@checkbox-border-width: @border-width-base;\n@checkbox-border-radius: @border-radius-sm;\n@checkbox-group-item-margin-right: 8px;\n\n// Descriptions\n@descriptions-bg: #fafafa;\n@descriptions-title-margin-bottom: 20px;\n@descriptions-default-padding: @padding-md @padding-lg;\n@descriptions-middle-padding: @padding-sm @padding-lg;\n@descriptions-small-padding: @padding-xs @padding-md;\n@descriptions-item-padding-bottom: @padding-md;\n@descriptions-item-trailing-colon: true;\n@descriptions-item-label-colon-margin-right: 8px;\n@descriptions-item-label-colon-margin-left: 2px;\n@descriptions-extra-color: @text-color;\n\n// Divider\n@divider-text-padding: 1em;\n@divider-orientation-margin: 5%;\n@divider-color: rgba(0, 0, 0, 6%);\n@divider-vertical-gutter: 8px;\n\n// Dropdown\n@dropdown-selected-color: @primary-color;\n@dropdown-menu-submenu-disabled-bg: @component-background;\n@dropdown-selected-bg: @item-active-bg;\n\n// Empty\n@empty-font-size: @font-size-base;\n\n// Radio\n@radio-size: 16px;\n@radio-top: 0.2em;\n@radio-border-width: 1px;\n@radio-dot-size: @radio-size - 8px;\n@radio-dot-color: @primary-color;\n@radio-dot-disabled-color: fade(@black, 20%);\n@radio-solid-checked-color: @component-background;\n\n// Radio buttons\n@radio-button-bg: @btn-default-bg;\n@radio-button-checked-bg: @btn-default-bg;\n@radio-button-color: @btn-default-color;\n@radio-button-hover-color: @primary-5;\n@radio-button-active-color: @primary-7;\n@radio-button-padding-horizontal: @padding-md - 1px;\n@radio-disabled-button-checked-bg: @disabled-active-bg;\n@radio-disabled-button-checked-color: @disabled-color;\n@radio-wrapper-margin-right: 8px;\n\n// Media queries breakpoints\n// @screen-xs and @screen-xs-min is not used in Grid\n// smallest break point is @screen-md\n@screen-xs: 480px;\n@screen-xs-min: @screen-xs;\n// 👆 Extra small screen / phone\n\n// 👇 Small screen / tablet\n@screen-sm: 576px;\n@screen-sm-min: @screen-sm;\n\n// Medium screen / desktop\n@screen-md: 768px;\n@screen-md-min: @screen-md;\n\n// Large screen / wide desktop\n@screen-lg: 992px;\n@screen-lg-min: @screen-lg;\n\n// Extra large screen / full hd\n@screen-xl: 1200px;\n@screen-xl-min: @screen-xl;\n\n// Extra extra large screen / large desktop\n@screen-xxl: 1600px;\n@screen-xxl-min: @screen-xxl;\n\n// provide a maximum\n@screen-xs-max: (@screen-sm-min - 1px);\n@screen-sm-max: (@screen-md-min - 1px);\n@screen-md-max: (@screen-lg-min - 1px);\n@screen-lg-max: (@screen-xl-min - 1px);\n@screen-xl-max: (@screen-xxl-min - 1px);\n\n// Grid system\n@grid-columns: 24;\n\n// Layout\n@layout-body-background: #f0f2f5;\n@layout-header-background: #001529;\n@layout-header-height: 64px;\n@layout-header-padding: 0 50px;\n@layout-header-color: @text-color;\n@layout-footer-padding: 24px 50px;\n@layout-footer-background: @layout-body-background;\n@layout-sider-background: @layout-header-background;\n@layout-trigger-height: 48px;\n@layout-trigger-background: #002140;\n@layout-trigger-color: #fff;\n@layout-zero-trigger-width: 36px;\n@layout-zero-trigger-height: 42px;\n// Layout light theme\n@layout-sider-background-light: #fff;\n@layout-trigger-background-light: #fff;\n@layout-trigger-color-light: @text-color;\n\n// z-index list, order by `z-index`\n@zindex-badge: auto;\n@zindex-table-fixed: 2;\n@zindex-affix: 10;\n@zindex-picker-panel: 10;\n@zindex-popup-close: 10;\n@zindex-modal: 1000;\n@zindex-modal-mask: 1000;\n@zindex-message: 1010;\n@zindex-notification: 1010;\n@zindex-popover: 1030;\n@zindex-dropdown: 1050;\n@zindex-picker: 1050;\n@zindex-popoconfirm: 1060;\n@zindex-tooltip: 1070;\n@zindex-image: 1080;\n\n// Animation\n@animation-duration-slow: 0.3s; // Modal\n@animation-duration-base: 0.2s;\n@animation-duration-fast: 0.1s; // Tooltip\n\n//CollapsePanel\n@collapse-panel-border-radius: @border-radius-base;\n\n//Dropdown\n@dropdown-menu-bg: @component-background;\n@dropdown-vertical-padding: 5px;\n@dropdown-edge-child-vertical-padding: 4px;\n@dropdown-font-size: @font-size-base;\n@dropdown-line-height: 22px;\n\n// Form\n// ---\n@label-required-color: @highlight-color;\n@label-color: @heading-color;\n@form-warning-input-bg: @input-bg;\n@form-item-margin-bottom: 24px;\n@form-item-trailing-colon: true;\n@form-vertical-label-padding: 0 0 8px;\n@form-vertical-label-margin: 0;\n@form-item-label-font-size: @font-size-base;\n@form-item-label-height: @input-height-base;\n@form-item-label-colon-margin-right: 8px;\n@form-item-label-colon-margin-left: 2px;\n@form-error-input-bg: @input-bg;\n\n// Input\n// ---\n@input-height-base: @height-base;\n@input-height-lg: @height-lg;\n@input-height-sm: @height-sm;\n@input-padding-horizontal: @control-padding-horizontal - @line-width;\n@input-padding-horizontal-base: @input-padding-horizontal;\n@input-padding-horizontal-sm: @control-padding-horizontal-sm - @line-width;\n@input-padding-horizontal-lg: @input-padding-horizontal;\n@input-padding-vertical-base: max(\n  (round(((@input-height-base - @font-size-base * @line-height-base) / 2) * 10) / 10) -\n    @border-width-base,\n  3px\n);\n@input-padding-vertical-sm: max(\n  (round(((@input-height-sm - @font-size-base * @line-height-base) / 2) * 10) / 10) -\n    @border-width-base,\n  0\n);\n@input-padding-vertical-lg: (\n    ceil(((@input-height-lg - @font-size-lg * @line-height-base) / 2) * 10) / 10\n  ) - @border-width-base;\n@input-placeholder-color: hsv(0, 0, 75%);\n@input-color: @text-color;\n@input-icon-color: @input-color;\n@input-border-color: @border-color-base;\n@input-bg: @component-background;\n@input-number-hover-border-color: @input-hover-border-color;\n@input-number-handler-active-bg: #f4f4f4;\n@input-number-handler-hover-bg: @primary-5;\n@input-number-handler-bg: @component-background;\n@input-number-handler-border-color: @border-color-base;\n@input-addon-bg: @background-color-light;\n@input-hover-border-color: @primary-5;\n@input-disabled-bg: @disabled-bg;\n@input-outline-offset: 0 0;\n@input-icon-hover-color: fade(@black, 85%);\n@input-disabled-color: @disabled-color;\n@input-variant-filled-bg: @background-color-base;\n@input-variant-filled-hover-bg: @background-color-dark;\n\n// Mentions\n// ---\n@mentions-dropdown-bg: @component-background;\n@mentions-dropdown-menu-item-hover-bg: @mentions-dropdown-bg;\n\n// Select\n// ---\n@select-height: @input-height-base;\n@select-border-color: @border-color-base;\n@select-item-selected-color: @text-color;\n@select-item-selected-font-weight: 600;\n@select-dropdown-bg: @component-background;\n@select-item-selected-bg: @primary-1;\n@select-item-active-bg: @item-hover-bg;\n@select-dropdown-vertical-padding: @dropdown-vertical-padding;\n@select-dropdown-font-size: @dropdown-font-size;\n@select-dropdown-line-height: @dropdown-line-height;\n@select-dropdown-height: 32px;\n@select-background: @component-background;\n@select-clear-background: @select-background;\n@select-selection-item-bg: @background-color-base;\n@select-selection-item-border-color: @border-color-split;\n@select-single-item-height-lg: 40px;\n@select-multiple-item-height: @input-height-base - @input-padding-vertical-base * 2; // Normal 24px\n@select-multiple-item-height-sm: @input-height-sm - @input-padding-vertical-base * 2;\n@select-multiple-item-height-lg: 32px;\n@select-multiple-item-spacing-half: ceil((@input-padding-vertical-base / 2));\n@select-multiple-disabled-background: @input-disabled-bg;\n@select-multiple-item-disabled-color: #bfbfbf;\n@select-multiple-item-disabled-border-color: @select-border-color;\n@select-multiple-item-filled-bg: @component-background;\n@select-select-affix-padding: 4px;\n\n// Cascader\n// ---\n@cascader-bg: @component-background;\n@cascader-item-selected-bg: @primary-1;\n@cascader-menu-bg: @component-background;\n@cascader-menu-border-color-split: @border-color-split;\n\n// Cascader\n// ----\n@cascader-dropdown-vertical-padding: @dropdown-vertical-padding;\n@cascader-dropdown-edge-child-vertical-padding: @dropdown-edge-child-vertical-padding;\n@cascader-dropdown-font-size: @dropdown-font-size;\n@cascader-dropdown-line-height: @dropdown-line-height;\n\n// Anchor\n// ---\n@anchor-bg: transparent;\n@anchor-border-color: @border-color-split;\n@anchor-link-top: 4px;\n@anchor-link-left: 16px;\n@anchor-link-padding: @anchor-link-top 0 @anchor-link-top @anchor-link-left;\n\n// Tooltip\n// ---\n// Tooltip max width\n@tooltip-max-width: 250px;\n// Tooltip text color\n@tooltip-color: #fff;\n// Tooltip background color\n@tooltip-bg: rgba(0, 0, 0, 0.75);\n// Tooltip arrow width\n@tooltip-arrow-width: 16px;\n// Tooltip distance with trigger\n@tooltip-distance: @tooltip-arrow-width - 1px + 4px;\n// Tooltip arrow color\n@tooltip-arrow-color: @tooltip-bg;\n@tooltip-border-radius: @border-radius-base;\n\n// Popover\n// ---\n// Popover body background color\n@popover-bg: @component-background;\n// Popover text color\n@popover-color: @text-color;\n// Popover maximum width\n@popover-min-width: 177px;\n@popover-min-height: 32px;\n// Popover arrow width\n@popover-arrow-width: @tooltip-arrow-width;\n// Popover arrow color\n@popover-arrow-color: @popover-bg;\n// Popover arrow box shadow\n@popover-arrow-box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.05);\n// Popover outer arrow color\n@popover-arrow-outer-color: @popover-bg;\n// Popover distance with trigger\n@popover-distance: calc(@popover-arrow-width / 2 + @margin-xss);\n@popover-padding-horizontal: @padding-md;\n\n// Modal\n// --\n@modal-header-padding-vertical: @padding-md;\n@modal-header-padding-horizontal: @padding-lg;\n@modal-body-padding: @padding-lg;\n@modal-header-bg: @component-background;\n@modal-header-padding: @modal-header-padding-vertical @modal-header-padding-horizontal;\n@modal-header-border-width: @border-width-base;\n@modal-header-border-style: @border-style-base;\n@modal-header-title-line-height: 22px;\n@modal-header-title-font-size: @font-size-lg;\n@modal-header-border-color-split: @border-color-split;\n@modal-header-close-size: @modal-header-title-line-height + 2 * @modal-header-padding-vertical;\n@modal-content-bg: @component-background;\n@modal-heading-color: @heading-color;\n@modal-close-color: @text-color-secondary;\n@modal-footer-bg: transparent;\n@modal-footer-border-color-split: @border-color-split;\n@modal-footer-border-style: @border-style-base;\n@modal-footer-padding-vertical: 10px;\n@modal-footer-padding-horizontal: 16px;\n@modal-footer-border-width: @border-width-base;\n@modal-mask-bg: fade(@black, 45%);\n@modal-confirm-body-padding: 32px 32px 24px;\n@modal-confirm-title-font-size: @font-size-lg;\n@modal-border-radius: @border-radius-base;\n\n// Progress\n// --\n@progress-default-color: @processing-color;\n@progress-remaining-color: @background-color-base;\n@progress-info-text-color: @progress-text-color;\n@progress-radius: 100px;\n@progress-steps-item-bg: #f3f3f3;\n@progress-text-font-size: 1em;\n@progress-text-color: @text-color; // This is for circle text color, should be renamed better\n@progress-circle-text-font-size: 1em;\n// Menu\n// ---\n@menu-inline-toplevel-item-height: 40px;\n@menu-item-height: 40px;\n@menu-item-group-height: @line-height-base;\n@menu-collapsed-width: 80px;\n@menu-bg: @component-background;\n@menu-popup-bg: @component-background;\n@menu-item-color: @text-color;\n@menu-inline-submenu-bg: @background-color-light;\n@menu-highlight-color: @primary-color;\n@menu-highlight-danger-color: @error-color;\n@menu-item-active-bg: @primary-1;\n@menu-item-active-danger-bg: @red-1;\n@menu-item-active-border-width: 3px;\n@menu-item-group-title-color: @text-color-secondary;\n@menu-item-vertical-margin: 4px;\n@menu-item-font-size: @font-size-base;\n@menu-item-boundary-margin: 8px;\n@menu-item-padding-horizontal: 20px;\n@menu-item-padding: 0 @menu-item-padding-horizontal;\n@menu-horizontal-line-height: 46px;\n@menu-icon-margin-right: 10px;\n@menu-icon-size: @menu-item-font-size;\n@menu-icon-size-lg: @font-size-lg;\n@menu-item-group-title-font-size: @menu-item-font-size;\n\n// dark theme\n@menu-dark-color: @text-color-secondary-dark;\n@menu-dark-danger-color: @error-color;\n@menu-dark-bg: @layout-header-background;\n@menu-dark-arrow-color: #fff;\n@menu-dark-inline-submenu-bg: #000c17;\n@menu-dark-highlight-color: #fff;\n@menu-dark-item-active-bg: @primary-color;\n@menu-dark-item-active-danger-bg: @error-color;\n@menu-dark-selected-item-icon-color: @white;\n@menu-dark-selected-item-text-color: @white;\n@menu-dark-item-hover-bg: transparent;\n// Spin\n// ---\n@spin-dot-size-sm: 14px;\n@spin-dot-size: 20px;\n@spin-dot-size-lg: 32px;\n\n// Splitter\n// ---\n@splitter-split-bar-size: 2px;\n@splitter-split-trigger-size: 6px;\n@splitter-split-bar-draggable-size: 20px;\n@splitter-split-bar-collapsible-size: 24px;\n@splitter-resize-spinner-size: 20px;\n@splitter-bar-bg: rgba(0, 0, 0, 0.04);\n@splitter-bar-hover-bg: #e6f4ff;\n@splitter-bar-active-bg: #bae0ff;\n\n// Table\n// --\n@table-bg: @component-background;\n@table-header-bg: @background-color-light;\n@table-header-color: @heading-color;\n@table-header-sort-bg: @background-color-base;\n@table-body-sort-bg: #fafafa;\n@table-row-hover-bg: @background-color-light;\n@table-selected-row-color: inherit;\n@table-selected-row-bg: @primary-1;\n@table-body-selected-sort-bg: @table-selected-row-bg;\n@table-selected-row-hover-bg: darken(@table-selected-row-bg, 2%);\n@table-expanded-row-bg: #fbfbfb;\n@table-padding-vertical: 16px;\n@table-padding-horizontal: 16px;\n@table-padding-vertical-md: (@table-padding-vertical * 3 / 4);\n@table-padding-horizontal-md: (@table-padding-horizontal / 2);\n@table-padding-vertical-sm: (@table-padding-vertical / 2);\n@table-padding-horizontal-sm: (@table-padding-horizontal / 2);\n@table-border-color: @border-color-split;\n@table-border-radius-base: @border-radius-base;\n@table-footer-bg: @background-color-light;\n@table-footer-color: @heading-color;\n@table-header-bg-sm: @table-header-bg;\n@table-font-size: @font-size-base;\n@table-font-size-md: @table-font-size;\n@table-font-size-sm: @table-font-size;\n@table-header-cell-split-color: rgba(0, 0, 0, 0.06);\n// Sorter\n// Legacy: `table-header-sort-active-bg` is used for hover not real active\n@table-header-sort-active-bg: rgba(0, 0, 0, 0.04);\n@table-fixed-header-sort-active-bg: hsv(0, 0, 96%);\n\n// Filter\n@table-header-filter-active-bg: rgba(0, 0, 0, 0.04);\n@table-filter-btns-bg: inherit;\n@table-filter-dropdown-bg: @component-background;\n@table-expand-icon-bg: @component-background;\n@table-selection-column-width: 32px;\n// Sticky\n@table-sticky-scroll-bar-bg: fade(#000, 35%);\n@table-sticky-scroll-bar-radius: 4px;\n\n// Tag\n// --\n@tag-border-radius: @border-radius-base;\n@tag-default-bg: @background-color-light;\n@tag-default-color: @text-color;\n@tag-font-size: @font-size-sm;\n@tag-line-height: 20px;\n\n// TimePicker\n// ---\n@picker-bg: @component-background;\n@picker-basic-cell-hover-color: @item-hover-bg;\n@picker-basic-cell-active-with-range-color: @primary-1;\n@picker-basic-cell-hover-with-range-color: lighten(@primary-color, 35%);\n@picker-basic-cell-disabled-bg: rgba(0, 0, 0, 0.04);\n@picker-border-color: @border-color-split;\n@picker-date-hover-range-border-color: lighten(@primary-color, 20%);\n@picker-date-hover-range-color: @picker-basic-cell-hover-with-range-color;\n@picker-time-panel-column-width: 56px;\n@picker-time-panel-column-height: 224px;\n@picker-time-panel-cell-height: 28px;\n@picker-panel-cell-height: 24px;\n@picker-panel-cell-width: 36px;\n@picker-text-height: 40px;\n@picker-panel-without-time-cell-height: 66px;\n\n// Calendar\n// ---\n@calendar-bg: @component-background;\n@calendar-input-bg: @input-bg;\n@calendar-border-color: @border-color-inverse;\n@calendar-item-active-bg: @item-active-bg;\n@calendar-column-active-bg: fade(@calendar-item-active-bg, 20%);\n@calendar-full-bg: @calendar-bg;\n@calendar-full-panel-bg: @calendar-full-bg;\n\n// Carousel\n// ---\n@carousel-dot-width: 16px;\n@carousel-dot-height: 3px;\n@carousel-dot-active-width: 24px;\n\n// Badge\n// ---\n@badge-height: 20px;\n@badge-height-sm: 14px;\n@badge-dot-size: 6px;\n@badge-font-size: @font-size-sm;\n@badge-font-size-sm: @font-size-sm;\n@badge-font-weight: normal;\n@badge-status-size: 6px;\n@badge-text-color: @component-background;\n@badge-color: @highlight-color;\n\n// Rate\n// ---\n@rate-star-color: @yellow-6;\n@rate-star-bg: @border-color-split;\n@rate-star-size: 20px;\n@rate-star-hover-scale: scale(1.1);\n\n// Card\n// ---\n@card-head-color: @heading-color;\n@card-head-background: transparent;\n@card-head-font-size: @font-size-lg;\n@card-head-font-size-sm: @font-size-base;\n@card-head-padding: 16px;\n@card-head-padding-sm: (@card-head-padding / 2);\n@card-head-height: 48px;\n@card-head-height-sm: 36px;\n@card-inner-head-padding: 12px;\n@card-padding-base: 24px;\n@card-padding-base-sm: (@card-padding-base / 2);\n@card-actions-background: @component-background;\n@card-actions-li-margin: 12px 0;\n@card-skeleton-bg: #cfd8dc;\n@card-background: @component-background;\n@card-shadow: 0 1px 2px -2px rgba(0, 0, 0, 0.16), 0 3px 6px 0 rgba(0, 0, 0, 0.12),\n  0 5px 12px 4px rgba(0, 0, 0, 0.09);\n@card-radius: @border-radius-base;\n@card-head-tabs-margin-bottom: -17px;\n@card-head-extra-color: @text-color;\n\n// Comment\n// ---\n@comment-bg: inherit;\n@comment-padding-base: @padding-md 0;\n@comment-nest-indent: 44px;\n@comment-font-size-base: @font-size-base;\n@comment-font-size-sm: @font-size-sm;\n@comment-author-name-color: @text-color-secondary;\n@comment-author-time-color: #ccc;\n@comment-action-color: @text-color-secondary;\n@comment-action-hover-color: #595959;\n@comment-actions-margin-bottom: inherit;\n@comment-actions-margin-top: @margin-sm;\n@comment-content-detail-p-margin-bottom: inherit;\n\n// Tabs\n// ---\n@tabs-card-head-background: @background-color-light;\n@tabs-card-height: 40px;\n@tabs-card-active-color: @primary-color;\n@tabs-card-horizontal-padding: (\n    (@tabs-card-height - floor(@font-size-base * @line-height-base)) / 2\n  ) - @border-width-base @padding-md;\n@tabs-card-horizontal-padding-sm: 6px @padding-md;\n@tabs-card-horizontal-padding-lg: 7px @padding-md 6px;\n@tabs-title-font-size: @font-size-base;\n@tabs-title-font-size-lg: @font-size-lg;\n@tabs-title-font-size-sm: @font-size-base;\n@tabs-ink-bar-color: @primary-color;\n@tabs-bar-margin: 0 0 @margin-md 0;\n@tabs-horizontal-gutter: 32px;\n@tabs-horizontal-margin: 0 0 0 @tabs-horizontal-gutter;\n@tabs-horizontal-margin-rtl: 0 0 0 32px;\n@tabs-horizontal-padding: @padding-sm 0;\n@tabs-horizontal-padding-lg: @padding-md 0;\n@tabs-horizontal-padding-sm: @padding-xs 0;\n@tabs-vertical-padding: @padding-xs @padding-lg;\n@tabs-vertical-margin: @margin-md 0 0 0;\n@tabs-scrolling-size: 32px;\n@tabs-highlight-color: @primary-color;\n@tabs-hover-color: @primary-5;\n@tabs-active-color: @primary-7;\n@tabs-card-gutter: 2px;\n@tabs-card-tab-active-border-top: 2px solid transparent;\n\n// Avatar\n// ---\n@avatar-size-base: 32px;\n@avatar-size-lg: 40px;\n@avatar-size-sm: 24px;\n@avatar-font-size-base: 18px;\n@avatar-font-size-lg: 24px;\n@avatar-font-size-sm: 14px;\n@avatar-bg: #ccc;\n@avatar-color: #fff;\n@avatar-border-radius: @border-radius-base;\n@avatar-group-overlapping: -8px;\n@avatar-group-space: 3px;\n@avatar-group-border-color: #fff;\n\n// Switch\n// ---\n@switch-height: 22px;\n@switch-sm-height: 16px;\n@switch-min-width: 44px;\n@switch-sm-min-width: 28px;\n@switch-disabled-opacity: 0.4;\n@switch-color: @primary-color;\n@switch-bg: @component-background;\n@switch-shadow-color: fade(#00230b, 20%);\n@switch-padding: 2px;\n@switch-inner-margin-min: ceil(@switch-height * 0.3);\n@switch-inner-margin-max: ceil(@switch-height * 1.1);\n@switch-sm-inner-margin-min: ceil(@switch-sm-height * 0.3);\n@switch-sm-inner-margin-max: ceil(@switch-sm-height * 1.1);\n\n// Pagination\n// ---\n@pagination-item-bg: @component-background;\n@pagination-item-size: @height-base;\n@pagination-item-size-sm: 24px;\n@pagination-font-family: @font-family;\n@pagination-font-weight-active: 500;\n@pagination-item-bg-active: @component-background;\n@pagination-item-link-bg: @component-background;\n@pagination-item-disabled-color-active: @disabled-color;\n@pagination-item-disabled-bg-active: @disabled-active-bg;\n@pagination-item-input-bg: @component-background;\n@pagination-mini-options-size-changer-top: 0px;\n\n// PageHeader\n// ---\n@page-header-padding: @padding-lg;\n@page-header-padding-vertical: @padding-md;\n@page-header-padding-breadcrumb: @padding-sm;\n@page-header-content-padding-vertical: @padding-sm;\n@page-header-back-color: #000;\n@page-header-ghost-bg: inherit;\n@page-header-heading-title: @heading-4-size;\n@page-header-heading-sub-title: 14px;\n@page-header-tabs-tab-font-size: 16px;\n\n// Breadcrumb\n// ---\n@breadcrumb-base-color: @text-color-secondary;\n@breadcrumb-last-item-color: @text-color;\n@breadcrumb-font-size: @font-size-base;\n@breadcrumb-icon-font-size: @font-size-base;\n@breadcrumb-link-color: @text-color-secondary;\n@breadcrumb-link-color-hover: @text-color;\n@breadcrumb-separator-color: @text-color-secondary;\n@breadcrumb-separator-margin: 0 @padding-xs;\n\n// Slider\n// ---\n@slider-margin: 10px 6px 10px;\n@slider-rail-background-color: @background-color-base;\n@slider-rail-background-color-hover: #e1e1e1;\n@slider-track-background-color: @primary-3;\n@slider-track-background-color-hover: @primary-4;\n@slider-handle-border-width: 2px;\n@slider-handle-background-color: @component-background;\n@slider-handle-color: @primary-3;\n@slider-handle-color-hover: @primary-4;\n@slider-handle-color-focus: tint(@primary-color, 20%);\n@slider-handle-color-focus-shadow: fade(@primary-color, 12%);\n@slider-handle-color-tooltip-open: @primary-color;\n@slider-handle-size: 14px;\n@slider-handle-margin-top: -5px;\n@slider-handle-margin-left: -5px;\n@slider-handle-shadow: 0;\n@slider-dot-border-color: @border-color-split;\n@slider-dot-border-color-active: tint(@primary-color, 50%);\n@slider-disabled-color: @disabled-color;\n@slider-disabled-background-color: @component-background;\n\n// Tree\n// ---\n@tree-bg: @component-background;\n@tree-title-height: 24px;\n@tree-child-padding: 18px;\n@tree-directory-selected-color: #fff;\n@tree-directory-selected-bg: @primary-color;\n@tree-node-hover-bg: @item-hover-bg;\n@tree-node-selected-bg: @primary-2;\n\n// Collapse\n// ---\n@collapse-header-padding: @padding-sm @padding-md;\n@collapse-header-padding-extra: 40px;\n@collapse-header-bg: @background-color-light;\n@collapse-content-padding: @padding-md;\n@collapse-content-bg: @component-background;\n@collapse-header-arrow-left: 16px;\n\n// Skeleton\n// ---\n@skeleton-color: rgba(190, 190, 190, 0.2);\n@skeleton-to-color: shade(@skeleton-color, 5%);\n@skeleton-paragraph-margin-top: 28px;\n@skeleton-paragraph-li-margin-top: @margin-md;\n@skeleton-paragraph-li-height: 16px;\n@skeleton-title-height: 16px;\n@skeleton-title-paragraph-margin-top: @margin-lg;\n\n// Transfer\n// ---\n@transfer-header-height: 40px;\n@transfer-item-height: @height-base;\n@transfer-disabled-bg: @disabled-bg;\n@transfer-list-height: 200px;\n@transfer-item-hover-bg: @item-hover-bg;\n@transfer-item-selected-hover-bg: darken(@item-active-bg, 2%);\n@transfer-item-padding-vertical: 6px;\n@transfer-list-search-icon-top: 12px;\n\n// Message\n// ---\n@message-notice-content-padding: 10px 16px;\n@message-notice-content-bg: @component-background;\n// Motion\n// ---\n@wave-animation-width: 6px;\n\n// Alert\n// ---\n@alert-success-border-color: colorPalette('@{success-color}', 3);\n@alert-success-bg-color: colorPalette('@{success-color}', 1);\n@alert-success-icon-color: @success-color;\n@alert-info-border-color: colorPalette('@{info-color}', 3);\n@alert-info-bg-color: colorPalette('@{info-color}', 1);\n@alert-info-icon-color: @info-color;\n@alert-warning-border-color: colorPalette('@{warning-color}', 3);\n@alert-warning-bg-color: colorPalette('@{warning-color}', 1);\n@alert-warning-icon-color: @warning-color;\n@alert-error-border-color: colorPalette('@{error-color}', 3);\n@alert-error-bg-color: colorPalette('@{error-color}', 1);\n@alert-error-icon-color: @error-color;\n@alert-message-color: @heading-color;\n@alert-text-color: @text-color;\n@alert-close-color: @text-color-secondary;\n@alert-close-hover-color: @icon-color-hover;\n@alert-padding-vertical: @padding-xs;\n@alert-padding-horizontal: @padding-md - 1px;\n@alert-no-icon-padding-vertical: @padding-xs;\n@alert-with-description-no-icon-padding-vertical: @padding-md - 1px;\n@alert-with-description-padding-vertical: @padding-md - 1px;\n@alert-with-description-padding: @alert-with-description-padding-vertical 15px\n  @alert-with-description-no-icon-padding-vertical @alert-with-description-icon-size;\n@alert-icon-top: 8px + @font-size-base * (@line-height-base / 2) - (@font-size-base / 2);\n@alert-with-description-icon-size: 24px;\n\n// List\n// ---\n@list-header-background: transparent;\n@list-footer-background: transparent;\n@list-empty-text-padding: @padding-md;\n@list-item-padding: @padding-sm 0;\n@list-item-padding-sm: @padding-xs @padding-md;\n@list-item-padding-lg: 16px 24px;\n@list-item-meta-margin-bottom: @padding-md;\n@list-item-meta-avatar-margin-right: @padding-md;\n@list-item-meta-title-margin-bottom: @padding-sm;\n@list-customize-card-bg: @component-background;\n@list-item-meta-description-font-size: @font-size-base;\n\n// Statistic\n// ---\n@statistic-title-font-size: @font-size-base;\n@statistic-content-font-size: 24px;\n@statistic-unit-font-size: 24px;\n@statistic-font-family: @font-family;\n\n// Drawer\n// ---\n@drawer-header-padding: @padding-md @padding-lg;\n@drawer-body-padding: @padding-lg;\n@drawer-bg: @component-background;\n@drawer-footer-padding-vertical: @modal-footer-padding-vertical;\n@drawer-footer-padding-horizontal: @modal-footer-padding-horizontal;\n@drawer-header-close-size: 56px;\n@drawer-title-font-size: @font-size-lg;\n@drawer-title-line-height: 22px;\n\n// Timeline\n// ---\n@timeline-width: 2px;\n@timeline-color: @border-color-split;\n@timeline-dot-border-width: 2px;\n@timeline-dot-color: @primary-color;\n@timeline-dot-bg: @component-background;\n@timeline-item-padding-bottom: 20px;\n\n// Typography\n// ---\n@typography-title-font-weight: 600;\n@typography-title-margin-top: 1.2em;\n@typography-title-margin-bottom: 0.5em;\n\n// Upload\n// ---\n@upload-actions-color: @text-color-secondary;\n\n// Steps\n// ---\n@process-tail-color: @border-color-split;\n@steps-nav-arrow-color: fade(@black, 25%);\n@steps-background: @component-background;\n@steps-icon-size: 32px;\n@steps-icon-custom-size: @steps-icon-size;\n@steps-icon-custom-top: 0px;\n@steps-icon-custom-font-size: 24px;\n@steps-icon-top: -0.5px;\n@steps-icon-font-size: @font-size-lg;\n@steps-icon-margin: 0 8px 0 0;\n@steps-title-line-height: @height-base;\n@steps-small-icon-size: 24px;\n@steps-small-icon-margin: 0 8px 0 0;\n@steps-dot-size: 8px;\n@steps-dot-top: 2px;\n@steps-current-dot-size: 10px;\n@steps-description-max-width: 140px;\n@steps-nav-content-max-width: auto;\n@steps-vertical-icon-width: 16px;\n@steps-vertical-tail-width: 16px;\n@steps-vertical-tail-width-sm: 12px;\n\n// Notification\n// ---\n@notification-bg: @component-background;\n@notification-padding-vertical: 16px;\n@notification-padding-horizontal: 24px;\n\n// Result\n// ---\n@result-title-font-size: 24px;\n@result-subtitle-font-size: @font-size-base;\n@result-icon-font-size: 72px;\n@result-extra-margin: 24px 0 0 0;\n\n// Image\n// ---\n@image-size-base: 48px;\n@image-font-size-base: 24px;\n@image-bg: #f5f5f5;\n@image-color: #fff;\n@image-mask-font-size: 16px;\n@image-preview-operation-size: 18px;\n@image-preview-operation-color: @text-color-dark;\n@image-preview-operation-disabled-color: fade(@image-preview-operation-color, 25%);\n\n// Segmented\n// ---\n@segmented-bg: fade(@black, 4%);\n@segmented-hover-bg: fade(@black, 6%);\n@segmented-selected-bg: @white;\n@segmented-label-color: fade(@black, 65%);\n@segmented-label-hover-color: #262626;\n"
  },
  {
    "path": "components/style/themes/index.less",
    "content": "// Default using variable as entry to support site variable version\n// This will be replaced in webpack bundle\n// @root-entry-name: variable;\n\n// @import './default.less';\n// @import './variable.less';\n@import './@{root-entry-name}.less';\n"
  },
  {
    "path": "components/style/themes/variable.less",
    "content": "/* stylelint-disable at-rule-empty-line-before,at-rule-name-space-after,at-rule-no-unknown */\n@import '../color/colors';\n\n@theme: variable;\n\n// The prefix to use on all css classes from ant.\n@ant-prefix: ant;\n\n// An override for the html selector for theme prefixes\n@html-selector: html;\n\n@{html-selector} {\n  @base-primary: @blue-6;\n\n  // ========= Primary Color =========\n  --@{ant-prefix}-primary-color: @base-primary;\n  --@{ant-prefix}-primary-color-hover: color(colorPalette('@{base-primary}', 5));\n  --@{ant-prefix}-primary-color-active: color(colorPalette('@{base-primary}', 7));\n  --@{ant-prefix}-primary-color-outline: fade(@base-primary, @outline-fade);\n\n  // Legacy\n  @legacy-primary-1: color(colorPalette('@{base-primary}', 1));\n\n  --@{ant-prefix}-primary-1: @legacy-primary-1;\n  --@{ant-prefix}-primary-2: color(colorPalette('@{base-primary}', 2));\n  --@{ant-prefix}-primary-3: color(colorPalette('@{base-primary}', 3));\n  --@{ant-prefix}-primary-4: color(colorPalette('@{base-primary}', 4));\n  --@{ant-prefix}-primary-5: color(colorPalette('@{base-primary}', 5));\n  --@{ant-prefix}-primary-6: @base-primary;\n  --@{ant-prefix}-primary-7: color(colorPalette('@{base-primary}', 7));\n\n  // Deprecated\n  --@{ant-prefix}-primary-color-deprecated-pure: ~'';\n  --@{ant-prefix}-primary-color-deprecated-l-35: lighten(@base-primary, 35%);\n  --@{ant-prefix}-primary-color-deprecated-l-20: lighten(@base-primary, 20%);\n  --@{ant-prefix}-primary-color-deprecated-t-20: tint(@base-primary, 20%);\n  --@{ant-prefix}-primary-color-deprecated-t-50: tint(@base-primary, 50%);\n  --@{ant-prefix}-primary-color-deprecated-f-12: fade(@base-primary, 12%);\n  --@{ant-prefix}-primary-color-active-deprecated-f-30: fade(@legacy-primary-1, 30%);\n  --@{ant-prefix}-primary-color-active-deprecated-d-02: darken(@legacy-primary-1, 2%);\n\n  // ========= Success Color =========\n  --@{ant-prefix}-success-color: @green-6;\n  --@{ant-prefix}-success-color-hover: color(colorPalette('@{green-6}', 5));\n  --@{ant-prefix}-success-color-active: color(colorPalette('@{green-6}', 7));\n  --@{ant-prefix}-success-color-outline: fade(@green-6, @outline-fade);\n  --@{ant-prefix}-success-color-deprecated-bg: colorPalette('@{green-6}', 1);\n  --@{ant-prefix}-success-color-deprecated-border: colorPalette('@{green-6}', 3);\n\n  // ========== Error Color ==========\n  --@{ant-prefix}-error-color: @red-5;\n  --@{ant-prefix}-error-color-hover: color(colorPalette('@{red-5}', 5));\n  --@{ant-prefix}-error-color-active: color(colorPalette('@{red-5}', 7));\n  --@{ant-prefix}-error-color-outline: fade(@red-5, @outline-fade);\n  --@{ant-prefix}-error-color-deprecated-bg: colorPalette('@{red-5}', 1);\n  --@{ant-prefix}-error-color-deprecated-border: colorPalette('@{red-5}', 3);\n\n  // ========= Warning Color =========\n  --@{ant-prefix}-warning-color: @gold-6;\n  --@{ant-prefix}-warning-color-hover: color(colorPalette('@{gold-6}', 5));\n  --@{ant-prefix}-warning-color-active: color(colorPalette('@{gold-6}', 7));\n  --@{ant-prefix}-warning-color-outline: fade(@gold-6, @outline-fade);\n  --@{ant-prefix}-warning-color-deprecated-bg: colorPalette('@{gold-6}', 1);\n  --@{ant-prefix}-warning-color-deprecated-border: colorPalette('@{gold-6}', 3);\n\n  // ========== Info Color ===========\n  --@{ant-prefix}-info-color: @base-primary;\n  --@{ant-prefix}-info-color-deprecated-bg: colorPalette('@{base-primary}', 1);\n  --@{ant-prefix}-info-color-deprecated-border: colorPalette('@{base-primary}', 3);\n}\n\n// -------- Colors -----------\n// >>> Primary\n@primary-color: ~'var(--@{ant-prefix}-primary-color)';\n@primary-color-hover: ~'var(--@{ant-prefix}-primary-color-hover)';\n@primary-color-active: ~'var(--@{ant-prefix}-primary-color-active)';\n@primary-color-outline: ~'var(--@{ant-prefix}-primary-color-outline)';\n\n@processing-color: @primary-color;\n\n// >>> Info\n@info-color: ~'var(--@{ant-prefix}-info-color)';\n@info-color-deprecated-bg: ~'var(--@{ant-prefix}-info-color-deprecated-bg)';\n@info-color-deprecated-border: ~'var(--@{ant-prefix}-info-color-deprecated-border)';\n\n// >>> Success\n@success-color: ~'var(--@{ant-prefix}-success-color)';\n@success-color-hover: ~'var(--@{ant-prefix}-success-color-hover)';\n@success-color-active: ~'var(--@{ant-prefix}-success-color-active)';\n@success-color-outline: ~'var(--@{ant-prefix}-success-color-outline)';\n@success-color-deprecated-bg: ~'var(--@{ant-prefix}-success-color-deprecated-bg)';\n@success-color-deprecated-border: ~'var(--@{ant-prefix}-success-color-deprecated-border)';\n\n// >>> Warning\n@warning-color: ~'var(--@{ant-prefix}-warning-color)';\n@warning-color-hover: ~'var(--@{ant-prefix}-warning-color-hover)';\n@warning-color-active: ~'var(--@{ant-prefix}-warning-color-active)';\n@warning-color-outline: ~'var(--@{ant-prefix}-warning-color-outline)';\n@warning-color-deprecated-bg: ~'var(--@{ant-prefix}-warning-color-deprecated-bg)';\n@warning-color-deprecated-border: ~'var(--@{ant-prefix}-warning-color-deprecated-border)';\n\n// >>> Error\n@error-color: ~'var(--@{ant-prefix}-error-color)';\n@error-color-hover: ~'var(--@{ant-prefix}-error-color-hover)';\n@error-color-active: ~'var(--@{ant-prefix}-error-color-active)';\n@error-color-outline: ~'var(--@{ant-prefix}-error-color-outline)';\n@error-color-deprecated-bg: ~'var(--@{ant-prefix}-error-color-deprecated-bg)';\n@error-color-deprecated-border: ~'var(--@{ant-prefix}-error-color-deprecated-border)';\n\n@highlight-color: @red-5;\n@normal-color: #d9d9d9;\n@white: #fff;\n@black: #000;\n\n// Color used by default to control hover and active backgrounds and for\n// alert info backgrounds.\n@primary-1: ~'var(--@{ant-prefix}-primary-1)'; // replace tint(@primary-color, 90%)\n@primary-2: ~'var(--@{ant-prefix}-primary-2)'; // replace tint(@primary-color, 80%)\n@primary-3: ~'var(--@{ant-prefix}-primary-3)'; // unused\n@primary-4: ~'var(--@{ant-prefix}-primary-4)'; // unused\n@primary-5: ~'var(--@{ant-prefix}-primary-5)'; // color used to control the text color in many active and hover states, replace tint(@primary-color, 20%)\n@primary-6: ~'var(--@{ant-prefix}-primary-6)'; // color used to control the text color of active buttons, don't use, use @primary-color\n@primary-7: ~'var(--@{ant-prefix}-primary-7)'; // replace shade(@primary-color, 5%)\n@primary-8: color(colorPalette('@{primary-color}', 8)); // unused\n@primary-9: color(colorPalette('@{primary-color}', 9)); // unused\n@primary-10: color(colorPalette('@{primary-color}', 10)); // unused\n\n// Base Scaffolding Variables\n// ---\n\n// Background color for `<body>`\n@body-background: #fff;\n// Base background color for most components\n@component-background: #fff;\n// Popover background color\n@popover-background: @component-background;\n@popover-customize-border-color: @border-color-split;\n@font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,\n  'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',\n  'Noto Color Emoji';\n@code-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;\n@text-color: fade(@black, 85%);\n@text-color-secondary: fade(@black, 45%);\n@text-color-inverse: @white;\n@icon-color: inherit;\n@icon-color-hover: fade(@black, 75%);\n@heading-color: fade(@black, 85%);\n@text-color-dark: fade(@white, 85%);\n@text-color-secondary-dark: fade(@white, 65%);\n@text-selection-bg: @primary-color;\n@font-variant-base: tabular-nums;\n@font-feature-settings-base: 'tnum';\n@font-size-base: 14px;\n@font-size-lg: @font-size-base + 2px;\n@font-size-sm: 12px;\n@font-size-icon: @font-size-sm;\n@heading-1-size: ceil(@font-size-base * 2.71);\n@heading-2-size: ceil(@font-size-base * 2.14);\n@heading-3-size: ceil(@font-size-base * 1.71);\n@heading-4-size: ceil(@font-size-base * 1.42);\n@heading-5-size: ceil(@font-size-base * 1.14);\n// https://github.com/ant-design/ant-design/issues/20210\n@line-height-base: 1.5715;\n@line-height-lg: 1.5;\n@line-width: 1px;\n@line-width-focus: calc(@line-width * 3);\n@border-radius-base: 2px;\n@border-radius-sm: 2px;\n@border-radius-lg: 4px;\n\n// control border\n@control-border-radius: @border-radius-base;\n\n// arrow border\n@arrow-border-radius: @border-radius-sm;\n\n// vertical paddings\n@padding-lg: 24px; // containers\n@padding-md: 16px; // small containers and buttons\n@padding-sm: 12px; // Form controls and items\n@padding-xs: 8px; // small items\n@padding-xss: 4px; // more small\n\n// vertical padding for all form controls\n@control-padding-horizontal: @padding-sm;\n@control-padding-horizontal-sm: @padding-xs;\n\n// vertical margins\n@margin-lg: 24px; // containers\n@margin-md: 16px; // small containers and buttons\n@margin-sm: 12px; // Form controls and items\n@margin-xs: 8px; // small items\n@margin-xss: 4px; // more small\n\n// height rules\n@height-base: 32px;\n@height-lg: 40px;\n@height-sm: 24px;\n\n// The background colors for active and hover states for things like\n// list items or table cells.\n@item-active-bg: @primary-1;\n@item-hover-bg: #f5f5f5;\n@fill-color: rgba(0, 0, 0, 0.15);\n\n// ICONFONT\n@iconfont-css-prefix: anticon;\n\n// LINK\n@link-color: @primary-color;\n@link-hover-color: @primary-color-hover;\n@link-active-color: @primary-color-active;\n@link-decoration: none;\n@link-hover-decoration: none;\n@link-focus-decoration: none;\n@link-focus-outline: 0;\n\n// Animation\n@ease-base-out: cubic-bezier(0.7, 0.3, 0.1, 1);\n@ease-base-in: cubic-bezier(0.9, 0, 0.3, 0.7);\n@ease-out: cubic-bezier(0.215, 0.61, 0.355, 1);\n@ease-in: cubic-bezier(0.55, 0.055, 0.675, 0.19);\n@ease-in-out: cubic-bezier(0.645, 0.045, 0.355, 1);\n@ease-out-back: cubic-bezier(0.12, 0.4, 0.29, 1.46);\n@ease-in-back: cubic-bezier(0.71, -0.46, 0.88, 0.6);\n@ease-in-out-back: cubic-bezier(0.71, -0.46, 0.29, 1.46);\n@ease-out-circ: cubic-bezier(0.08, 0.82, 0.17, 1);\n@ease-in-circ: cubic-bezier(0.6, 0.04, 0.98, 0.34);\n@ease-in-out-circ: cubic-bezier(0.78, 0.14, 0.15, 0.86);\n@ease-out-quint: cubic-bezier(0.23, 1, 0.32, 1);\n@ease-in-quint: cubic-bezier(0.755, 0.05, 0.855, 0.06);\n@ease-in-out-quint: cubic-bezier(0.86, 0, 0.07, 1);\n\n// Border color\n@border-color-base: hsv(0, 0, 85%); // base border outline a component\n@border-color-split: rgba(0, 0, 0, 0.06); // split border inside a component\n@border-color-inverse: @white;\n@border-color-primary: @primary-3;\n@border-width-base: 1px; // width of the border for a component\n@border-style-base: solid; // style of a components border\n\n// Outline\n@outline-blur-size: 0;\n@outline-width: 2px;\n@outline-color: @primary-color; // No use anymore\n@outline-fade: 20%;\n\n@background-color-light: hsv(0, 0, 98%); // background of header and selected item\n@background-color-base: hsv(0, 0, 96%); // Default grey background color\n@background-color-dark: hsv(0, 0, 94%); // dark grey background color\n\n// Disabled states\n@disabled-color: fade(#000, 25%);\n@disabled-bg: @background-color-base;\n@disabled-active-bg: tint(@black, 90%);\n@disabled-color-dark: fade(#fff, 35%);\n\n// Shadow\n@shadow-color: rgba(0, 0, 0, 0.15);\n@shadow-color-inverse: @component-background;\n@box-shadow-base: @shadow-2;\n@shadow-1-up: 0 -6px 16px -8px rgba(0, 0, 0, 0.08), 0 -9px 28px 0 rgba(0, 0, 0, 0.05),\n  0 -12px 48px 16px rgba(0, 0, 0, 0.03);\n@shadow-1-down: 0 6px 16px -8px rgba(0, 0, 0, 0.08), 0 9px 28px 0 rgba(0, 0, 0, 0.05),\n  0 12px 48px 16px rgba(0, 0, 0, 0.03);\n@shadow-1-left: -6px 0 16px -8px rgba(0, 0, 0, 0.08), -9px 0 28px 0 rgba(0, 0, 0, 0.05),\n  -12px 0 48px 16px rgba(0, 0, 0, 0.03);\n@shadow-1-right: 6px 0 16px -8px rgba(0, 0, 0, 0.08), 9px 0 28px 0 rgba(0, 0, 0, 0.05),\n  12px 0 48px 16px rgba(0, 0, 0, 0.03);\n@shadow-2: 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, 0.08),\n  0 9px 28px 8px rgba(0, 0, 0, 0.05);\n\n// Buttons\n@btn-font-weight: 400;\n@btn-border-radius-base: @border-radius-base;\n@btn-border-radius-sm: @border-radius-base;\n@btn-border-width: @border-width-base;\n@btn-border-style: @border-style-base;\n@btn-shadow: 0 2px 0 rgba(0, 0, 0, 0.015);\n@btn-primary-shadow: 0 2px 0 rgba(0, 0, 0, 0.045);\n@btn-text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12);\n\n@btn-primary-color: #fff;\n@btn-primary-bg: @primary-color;\n\n@btn-default-color: @text-color;\n@btn-default-bg: @component-background;\n@btn-default-border: @border-color-base;\n\n@btn-danger-color: #fff;\n@btn-danger-bg: @error-color;\n@btn-danger-border: @error-color;\n\n@btn-disable-color: @disabled-color;\n@btn-disable-bg: @disabled-bg;\n@btn-disable-border: @border-color-base;\n\n@btn-default-ghost-color: @component-background;\n@btn-default-ghost-bg: transparent;\n@btn-default-ghost-border: @component-background;\n\n@btn-font-size-lg: @font-size-lg;\n@btn-font-size-sm: @font-size-base;\n@btn-padding-horizontal-base: @padding-md - 1px;\n@btn-padding-horizontal-lg: @btn-padding-horizontal-base;\n@btn-padding-horizontal-sm: @padding-xs - 1px;\n\n@btn-height-base: @height-base;\n@btn-height-lg: @height-lg;\n@btn-height-sm: @height-sm;\n\n@btn-line-height: @line-height-base;\n\n@btn-circle-size: @btn-height-base;\n@btn-circle-size-lg: @btn-height-lg;\n@btn-circle-size-sm: @btn-height-sm;\n\n@btn-square-size: @btn-height-base;\n@btn-square-size-lg: @btn-height-lg;\n@btn-square-size-sm: @btn-height-sm;\n@btn-square-only-icon-size: @font-size-base + 2px;\n@btn-square-only-icon-size-sm: @font-size-base;\n@btn-square-only-icon-size-lg: @btn-font-size-lg + 2px;\n\n@btn-group-border: @primary-5;\n\n@btn-link-hover-bg: transparent;\n@btn-text-hover-bg: rgba(0, 0, 0, 0.018);\n\n// Checkbox\n@checkbox-size: 16px;\n@checkbox-color: @primary-color;\n@checkbox-check-color: #fff;\n@checkbox-check-bg: @checkbox-check-color;\n@checkbox-border-width: @border-width-base;\n@checkbox-border-radius: @border-radius-sm;\n@checkbox-group-item-margin-right: 8px;\n\n// Descriptions\n@descriptions-bg: #fafafa;\n@descriptions-title-margin-bottom: 20px;\n@descriptions-default-padding: @padding-md @padding-lg;\n@descriptions-middle-padding: @padding-sm @padding-lg;\n@descriptions-small-padding: @padding-xs @padding-md;\n@descriptions-item-padding-bottom: @padding-md;\n@descriptions-item-trailing-colon: true;\n@descriptions-item-label-colon-margin-right: 8px;\n@descriptions-item-label-colon-margin-left: 2px;\n@descriptions-extra-color: @text-color;\n\n// Divider\n@divider-text-padding: 1em;\n@divider-orientation-margin: 5%;\n@divider-color: rgba(0, 0, 0, 6%);\n@divider-vertical-gutter: 8px;\n\n// Dropdown\n@dropdown-selected-color: @primary-color;\n@dropdown-menu-submenu-disabled-bg: @component-background;\n@dropdown-selected-bg: @item-active-bg;\n\n// Empty\n@empty-font-size: @font-size-base;\n\n// Radio\n@radio-size: 16px;\n@radio-top: 0.2em;\n@radio-border-width: 1px;\n@radio-dot-size: @radio-size - 8px;\n@radio-dot-color: @primary-color;\n@radio-dot-disabled-color: fade(@black, 20%);\n@radio-solid-checked-color: @component-background;\n\n// Radio buttons\n@radio-button-bg: @btn-default-bg;\n@radio-button-checked-bg: @btn-default-bg;\n@radio-button-color: @btn-default-color;\n@radio-button-hover-color: @primary-5;\n@radio-button-active-color: @primary-7;\n@radio-button-padding-horizontal: @padding-md - 1px;\n@radio-disabled-button-checked-bg: @disabled-active-bg;\n@radio-disabled-button-checked-color: @disabled-color;\n@radio-wrapper-margin-right: 8px;\n\n// Media queries breakpoints\n// @screen-xs and @screen-xs-min is not used in Grid\n// smallest break point is @screen-md\n@screen-xs: 480px;\n@screen-xs-min: @screen-xs;\n// 👆 Extra small screen / phone\n\n// 👇 Small screen / tablet\n@screen-sm: 576px;\n@screen-sm-min: @screen-sm;\n\n// Medium screen / desktop\n@screen-md: 768px;\n@screen-md-min: @screen-md;\n\n// Large screen / wide desktop\n@screen-lg: 992px;\n@screen-lg-min: @screen-lg;\n\n// Extra large screen / full hd\n@screen-xl: 1200px;\n@screen-xl-min: @screen-xl;\n\n// Extra extra large screen / large desktop\n@screen-xxl: 1600px;\n@screen-xxl-min: @screen-xxl;\n\n// provide a maximum\n@screen-xs-max: (@screen-sm-min - 1px);\n@screen-sm-max: (@screen-md-min - 1px);\n@screen-md-max: (@screen-lg-min - 1px);\n@screen-lg-max: (@screen-xl-min - 1px);\n@screen-xl-max: (@screen-xxl-min - 1px);\n\n// Grid system\n@grid-columns: 24;\n\n// Layout\n@layout-body-background: #f0f2f5;\n@layout-header-background: #001529;\n@layout-header-height: 64px;\n@layout-header-padding: 0 50px;\n@layout-header-color: @text-color;\n@layout-footer-padding: 24px 50px;\n@layout-footer-background: @layout-body-background;\n@layout-sider-background: @layout-header-background;\n@layout-trigger-height: 48px;\n@layout-trigger-background: #002140;\n@layout-trigger-color: #fff;\n@layout-zero-trigger-width: 36px;\n@layout-zero-trigger-height: 42px;\n// Layout light theme\n@layout-sider-background-light: #fff;\n@layout-trigger-background-light: #fff;\n@layout-trigger-color-light: @text-color;\n\n// z-index list, order by `z-index`\n@zindex-badge: auto;\n@zindex-table-fixed: 2;\n@zindex-affix: 10;\n@zindex-picker-panel: 10;\n@zindex-popup-close: 10;\n@zindex-modal: 1000;\n@zindex-modal-mask: 1000;\n@zindex-message: 1010;\n@zindex-notification: 1010;\n@zindex-popover: 1030;\n@zindex-dropdown: 1050;\n@zindex-picker: 1050;\n@zindex-popoconfirm: 1060;\n@zindex-tooltip: 1070;\n@zindex-image: 1080;\n\n// Animation\n@animation-duration-slow: 0.3s; // Modal\n@animation-duration-base: 0.2s;\n@animation-duration-fast: 0.1s; // Tooltip\n\n//CollapsePanel\n@collapse-panel-border-radius: @border-radius-base;\n\n//Dropdown\n@dropdown-menu-bg: @component-background;\n@dropdown-vertical-padding: 5px;\n@dropdown-edge-child-vertical-padding: 4px;\n@dropdown-font-size: @font-size-base;\n@dropdown-line-height: 22px;\n\n// Form\n// ---\n@label-required-color: @highlight-color;\n@label-color: @heading-color;\n@form-warning-input-bg: @input-bg;\n@form-item-margin-bottom: 24px;\n@form-item-trailing-colon: true;\n@form-vertical-label-padding: 0 0 8px;\n@form-vertical-label-margin: 0;\n@form-item-label-font-size: @font-size-base;\n@form-item-label-height: @input-height-base;\n@form-item-label-colon-margin-right: 8px;\n@form-item-label-colon-margin-left: 2px;\n@form-error-input-bg: @input-bg;\n\n// Input\n// ---\n@input-height-base: @height-base;\n@input-height-lg: @height-lg;\n@input-height-sm: @height-sm;\n@input-padding-horizontal: @control-padding-horizontal - @line-width;\n@input-padding-horizontal-base: @input-padding-horizontal;\n@input-padding-horizontal-sm: @control-padding-horizontal-sm - @line-width;\n@input-padding-horizontal-lg: @input-padding-horizontal;\n@input-padding-vertical-base: max(\n  (round(((@input-height-base - @font-size-base * @line-height-base) / 2) * 10) / 10) -\n    @border-width-base,\n  3px\n);\n@input-padding-vertical-sm: max(\n  (round(((@input-height-sm - @font-size-base * @line-height-base) / 2) * 10) / 10) -\n    @border-width-base,\n  0\n);\n@input-padding-vertical-lg: (\n    ceil(((@input-height-lg - @font-size-lg * @line-height-base) / 2) * 10) / 10\n  ) - @border-width-base;\n@input-placeholder-color: hsv(0, 0, 75%);\n@input-color: @text-color;\n@input-icon-color: @input-color;\n@input-border-color: @border-color-base;\n@input-bg: @component-background;\n@input-number-hover-border-color: @input-hover-border-color;\n@input-number-handler-active-bg: #f4f4f4;\n@input-number-handler-hover-bg: @primary-5;\n@input-number-handler-bg: @component-background;\n@input-number-handler-border-color: @border-color-base;\n@input-addon-bg: @background-color-light;\n@input-hover-border-color: @primary-5;\n@input-disabled-bg: @disabled-bg;\n@input-outline-offset: 0 0;\n@input-icon-hover-color: fade(@black, 85%);\n@input-disabled-color: @disabled-color;\n@input-variant-filled-bg: @background-color-base;\n@input-variant-filled-hover-bg: @background-color-dark;\n\n// Mentions\n// ---\n@mentions-dropdown-bg: @component-background;\n@mentions-dropdown-menu-item-hover-bg: @mentions-dropdown-bg;\n\n// Select\n// ---\n@select-height: @input-height-base;\n@select-border-color: @border-color-base;\n@select-item-selected-color: @text-color;\n@select-item-selected-font-weight: 600;\n@select-dropdown-bg: @component-background;\n@select-item-selected-bg: @primary-1;\n@select-item-active-bg: @item-hover-bg;\n@select-dropdown-vertical-padding: @dropdown-vertical-padding;\n@select-dropdown-font-size: @dropdown-font-size;\n@select-dropdown-line-height: @dropdown-line-height;\n@select-dropdown-height: 32px;\n@select-background: @component-background;\n@select-clear-background: @select-background;\n@select-selection-item-bg: @background-color-base;\n@select-selection-item-border-color: @border-color-split;\n@select-single-item-height-lg: 40px;\n@select-multiple-item-height: @input-height-base - @input-padding-vertical-base * 2; // Normal 24px\n@select-multiple-item-height-sm: @input-height-sm - @input-padding-vertical-base * 2;\n@select-multiple-item-height-lg: 32px;\n@select-multiple-item-spacing-half: ceil((@input-padding-vertical-base / 2));\n@select-multiple-disabled-background: @input-disabled-bg;\n@select-multiple-item-disabled-color: #bfbfbf;\n@select-multiple-item-disabled-border-color: @select-border-color;\n@select-select-affix-padding: 4px;\n\n// Cascader\n// ---\n@cascader-bg: @component-background;\n@cascader-item-selected-bg: @primary-1;\n@cascader-menu-bg: @component-background;\n@cascader-menu-border-color-split: @border-color-split;\n\n// Cascader\n// ----\n@cascader-dropdown-vertical-padding: @dropdown-vertical-padding;\n@cascader-dropdown-edge-child-vertical-padding: @dropdown-edge-child-vertical-padding;\n@cascader-dropdown-font-size: @dropdown-font-size;\n@cascader-dropdown-line-height: @dropdown-line-height;\n\n// Anchor\n// ---\n@anchor-bg: transparent;\n@anchor-border-color: @border-color-split;\n@anchor-link-top: 4px;\n@anchor-link-left: 16px;\n@anchor-link-padding: @anchor-link-top 0 @anchor-link-top @anchor-link-left;\n\n// Tooltip\n// ---\n// Tooltip max width\n@tooltip-max-width: 250px;\n// Tooltip text color\n@tooltip-color: #fff;\n// Tooltip background color\n@tooltip-bg: rgba(0, 0, 0, 0.75);\n// Tooltip arrow width\n@tooltip-arrow-width: 16px;\n// Tooltip distance with trigger\n@tooltip-distance: @tooltip-arrow-width - 1px + 4px;\n// Tooltip arrow color\n@tooltip-arrow-color: @tooltip-bg;\n@tooltip-border-radius: @border-radius-base;\n\n// Popover\n// ---\n// Popover body background color\n@popover-bg: @component-background;\n// Popover text color\n@popover-color: @text-color;\n// Popover maximum width\n@popover-min-width: 177px;\n@popover-min-height: 32px;\n// Popover arrow width\n@popover-arrow-width: @tooltip-arrow-width;\n// Popover arrow color\n@popover-arrow-color: @popover-bg;\n// Popover arrow box shadow\n@popover-arrow-box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.05);\n// Popover outer arrow color\n@popover-arrow-outer-color: @popover-bg;\n// Popover distance with trigger\n@popover-distance: calc(@popover-arrow-width / 2 + @margin-xss);\n@popover-padding-horizontal: @padding-md;\n\n// Modal\n// --\n@modal-header-padding-vertical: @padding-md;\n@modal-header-padding-horizontal: @padding-lg;\n@modal-body-padding: @padding-lg;\n@modal-header-bg: @component-background;\n@modal-header-padding: @modal-header-padding-vertical @modal-header-padding-horizontal;\n@modal-header-border-width: @border-width-base;\n@modal-header-border-style: @border-style-base;\n@modal-header-title-line-height: 22px;\n@modal-header-title-font-size: @font-size-lg;\n@modal-header-border-color-split: @border-color-split;\n@modal-header-close-size: @modal-header-title-line-height + 2 * @modal-header-padding-vertical;\n@modal-content-bg: @component-background;\n@modal-heading-color: @heading-color;\n@modal-close-color: @text-color-secondary;\n@modal-footer-bg: transparent;\n@modal-footer-border-color-split: @border-color-split;\n@modal-footer-border-style: @border-style-base;\n@modal-footer-padding-vertical: 10px;\n@modal-footer-padding-horizontal: 16px;\n@modal-footer-border-width: @border-width-base;\n@modal-mask-bg: fade(@black, 45%);\n@modal-confirm-body-padding: 32px 32px 24px;\n@modal-confirm-title-font-size: @font-size-lg;\n@modal-border-radius: @border-radius-base;\n\n// Progress\n// --\n@progress-default-color: @processing-color;\n@progress-remaining-color: rgba(0, 0, 0, 0.04);\n@progress-info-text-color: @progress-text-color;\n@progress-radius: 100px;\n@progress-steps-item-bg: #f3f3f3;\n@progress-text-font-size: 1em;\n@progress-text-color: @text-color; // This is for circle text color, should be renamed better\n@progress-circle-text-font-size: 1em;\n// Menu\n// ---\n@menu-inline-toplevel-item-height: 40px;\n@menu-item-height: 40px;\n@menu-item-group-height: @line-height-base;\n@menu-collapsed-width: 80px;\n@menu-bg: @component-background;\n@menu-popup-bg: @component-background;\n@menu-item-color: @text-color;\n@menu-inline-submenu-bg: @background-color-light;\n@menu-highlight-color: @primary-color;\n@menu-highlight-danger-color: @error-color;\n@menu-item-active-bg: @primary-1;\n@menu-item-active-danger-bg: @red-1;\n@menu-item-active-border-width: 3px;\n@menu-item-group-title-color: @text-color-secondary;\n@menu-item-vertical-margin: 4px;\n@menu-item-font-size: @font-size-base;\n@menu-item-boundary-margin: 8px;\n@menu-item-padding-horizontal: 20px;\n@menu-item-padding: 0 @menu-item-padding-horizontal;\n@menu-horizontal-line-height: 46px;\n@menu-icon-margin-right: 10px;\n@menu-icon-size: @menu-item-font-size;\n@menu-icon-size-lg: @font-size-lg;\n@menu-item-group-title-font-size: @menu-item-font-size;\n\n// dark theme\n@menu-dark-color: @text-color-secondary-dark;\n@menu-dark-danger-color: @error-color;\n@menu-dark-bg: @layout-header-background;\n@menu-dark-arrow-color: #fff;\n@menu-dark-inline-submenu-bg: #000c17;\n@menu-dark-highlight-color: #fff;\n@menu-dark-item-active-bg: @primary-color;\n@menu-dark-item-active-danger-bg: @error-color;\n@menu-dark-selected-item-icon-color: @white;\n@menu-dark-selected-item-text-color: @white;\n@menu-dark-item-hover-bg: transparent;\n// Spin\n// ---\n@spin-dot-size-sm: 14px;\n@spin-dot-size: 20px;\n@spin-dot-size-lg: 32px;\n\n// Splitter\n// ---\n@splitter-split-bar-size: 2px;\n@splitter-split-trigger-size: 6px;\n@splitter-split-bar-draggable-size: 20px;\n@splitter-split-bar-collapsible-size: 24px;\n@splitter-resize-spinner-size: 20px;\n@splitter-bar-bg: rgba(0, 0, 0, 0.04);\n@splitter-bar-hover-bg: #e6f4ff;\n@splitter-bar-active-bg: #bae0ff;\n\n// Table\n// --\n@table-bg: @component-background;\n@table-header-bg: @background-color-light;\n@table-header-color: @heading-color;\n@table-header-sort-bg: @background-color-base;\n@table-body-sort-bg: #fafafa;\n@table-row-hover-bg: @background-color-light;\n@table-selected-row-color: inherit;\n@table-selected-row-bg: @primary-1;\n@table-body-selected-sort-bg: @table-selected-row-bg;\n@table-selected-row-hover-bg: ~'var(--@{ant-prefix}-primary-color-active-deprecated-d-02)';\n@table-expanded-row-bg: #fbfbfb;\n@table-padding-vertical: 16px;\n@table-padding-horizontal: 16px;\n@table-padding-vertical-md: (@table-padding-vertical * 3 / 4);\n@table-padding-horizontal-md: (@table-padding-horizontal / 2);\n@table-padding-vertical-sm: (@table-padding-vertical / 2);\n@table-padding-horizontal-sm: (@table-padding-horizontal / 2);\n@table-border-color: @border-color-split;\n@table-border-radius-base: @border-radius-base;\n@table-footer-bg: @background-color-light;\n@table-footer-color: @heading-color;\n@table-header-bg-sm: @table-header-bg;\n@table-font-size: @font-size-base;\n@table-font-size-md: @table-font-size;\n@table-font-size-sm: @table-font-size;\n@table-header-cell-split-color: rgba(0, 0, 0, 0.06);\n// Sorter\n// Legacy: `table-header-sort-active-bg` is used for hover not real active\n@table-header-sort-active-bg: rgba(0, 0, 0, 0.04);\n@table-fixed-header-sort-active-bg: hsv(0, 0, 96%);\n\n// Filter\n@table-header-filter-active-bg: rgba(0, 0, 0, 0.04);\n@table-filter-btns-bg: inherit;\n@table-filter-dropdown-bg: @component-background;\n@table-expand-icon-bg: @component-background;\n@table-selection-column-width: 32px;\n// Sticky\n@table-sticky-scroll-bar-bg: fade(#000, 35%);\n@table-sticky-scroll-bar-radius: 4px;\n\n// Tag\n// --\n@tag-border-radius: @border-radius-base;\n@tag-default-bg: @background-color-light;\n@tag-default-color: @text-color;\n@tag-font-size: @font-size-sm;\n@tag-line-height: 20px;\n\n// TimePicker\n// ---\n@picker-bg: @component-background;\n@picker-basic-cell-hover-color: @item-hover-bg;\n@picker-basic-cell-active-with-range-color: @primary-1;\n@picker-basic-cell-hover-with-range-color: ~'var(--@{ant-prefix}-primary-color-deprecated-l-35)';\n@picker-basic-cell-disabled-bg: rgba(0, 0, 0, 0.04);\n@picker-border-color: @border-color-split;\n@picker-date-hover-range-border-color: ~'var(--@{ant-prefix}-primary-color-deprecated-l-20)';\n@picker-date-hover-range-color: @picker-basic-cell-hover-with-range-color;\n@picker-time-panel-column-width: 56px;\n@picker-time-panel-column-height: 224px;\n@picker-time-panel-cell-height: 28px;\n@picker-panel-cell-height: 24px;\n@picker-panel-cell-width: 36px;\n@picker-text-height: 40px;\n@picker-panel-without-time-cell-height: 66px;\n\n// Calendar\n// ---\n@calendar-bg: @component-background;\n@calendar-input-bg: @input-bg;\n@calendar-border-color: @border-color-inverse;\n@calendar-item-active-bg: @item-active-bg;\n@calendar-column-active-bg: ~'var(--@{ant-prefix}-primary-color-active-deprecated-f-30)';\n@calendar-full-bg: @calendar-bg;\n@calendar-full-panel-bg: @calendar-full-bg;\n\n// Carousel\n// ---\n@carousel-dot-width: 16px;\n@carousel-dot-height: 3px;\n@carousel-dot-active-width: 24px;\n\n// Badge\n// ---\n@badge-height: 20px;\n@badge-height-sm: 14px;\n@badge-dot-size: 6px;\n@badge-font-size: @font-size-sm;\n@badge-font-size-sm: @font-size-sm;\n@badge-font-weight: normal;\n@badge-status-size: 6px;\n@badge-text-color: @component-background;\n@badge-color: @highlight-color;\n\n// Rate\n// ---\n@rate-star-color: @yellow-6;\n@rate-star-bg: @border-color-split;\n@rate-star-size: 20px;\n@rate-star-hover-scale: scale(1.1);\n\n// Card\n// ---\n@card-head-color: @heading-color;\n@card-head-background: transparent;\n@card-head-font-size: @font-size-lg;\n@card-head-font-size-sm: @font-size-base;\n@card-head-padding: 16px;\n@card-head-padding-sm: (@card-head-padding / 2);\n@card-head-height: 48px;\n@card-head-height-sm: 36px;\n@card-inner-head-padding: 12px;\n@card-padding-base: 24px;\n@card-padding-base-sm: (@card-padding-base / 2);\n@card-actions-background: @component-background;\n@card-actions-li-margin: 12px 0;\n@card-skeleton-bg: #cfd8dc;\n@card-background: @component-background;\n@card-shadow: 0 1px 2px -2px rgba(0, 0, 0, 0.16), 0 3px 6px 0 rgba(0, 0, 0, 0.12),\n  0 5px 12px 4px rgba(0, 0, 0, 0.09);\n@card-radius: @border-radius-base;\n@card-head-tabs-margin-bottom: -17px;\n@card-head-extra-color: @text-color;\n\n// Comment\n// ---\n@comment-bg: inherit;\n@comment-padding-base: @padding-md 0;\n@comment-nest-indent: 44px;\n@comment-font-size-base: @font-size-base;\n@comment-font-size-sm: @font-size-sm;\n@comment-author-name-color: @text-color-secondary;\n@comment-author-time-color: #ccc;\n@comment-action-color: @text-color-secondary;\n@comment-action-hover-color: #595959;\n@comment-actions-margin-bottom: inherit;\n@comment-actions-margin-top: @margin-sm;\n@comment-content-detail-p-margin-bottom: inherit;\n\n// Tabs\n// ---\n@tabs-card-head-background: @background-color-light;\n@tabs-card-height: 40px;\n@tabs-card-active-color: @primary-color;\n@tabs-card-horizontal-padding: (\n    (@tabs-card-height - floor(@font-size-base * @line-height-base)) / 2\n  ) - @border-width-base @padding-md;\n@tabs-card-horizontal-padding-sm: 6px @padding-md;\n@tabs-card-horizontal-padding-lg: 7px @padding-md 6px;\n@tabs-title-font-size: @font-size-base;\n@tabs-title-font-size-lg: @font-size-lg;\n@tabs-title-font-size-sm: @font-size-base;\n@tabs-ink-bar-color: @primary-color;\n@tabs-bar-margin: 0 0 @margin-md 0;\n@tabs-horizontal-gutter: 32px;\n@tabs-horizontal-margin: 0 0 0 @tabs-horizontal-gutter;\n@tabs-horizontal-margin-rtl: 0 0 0 32px;\n@tabs-horizontal-padding: @padding-sm 0;\n@tabs-horizontal-padding-lg: @padding-md 0;\n@tabs-horizontal-padding-sm: @padding-xs 0;\n@tabs-vertical-padding: @padding-xs @padding-lg;\n@tabs-vertical-margin: @margin-md 0 0 0;\n@tabs-scrolling-size: 32px;\n@tabs-highlight-color: @primary-color;\n@tabs-hover-color: @primary-5;\n@tabs-active-color: @primary-7;\n@tabs-card-gutter: 2px;\n@tabs-card-tab-active-border-top: 2px solid transparent;\n\n// Avatar\n// ---\n@avatar-size-base: 32px;\n@avatar-size-lg: 40px;\n@avatar-size-sm: 24px;\n@avatar-font-size-base: 18px;\n@avatar-font-size-lg: 24px;\n@avatar-font-size-sm: 14px;\n@avatar-bg: #ccc;\n@avatar-color: #fff;\n@avatar-border-radius: @border-radius-base;\n@avatar-group-overlapping: -8px;\n@avatar-group-space: 3px;\n@avatar-group-border-color: #fff;\n\n// Switch\n// ---\n@switch-height: 22px;\n@switch-sm-height: 16px;\n@switch-min-width: 44px;\n@switch-sm-min-width: 28px;\n@switch-disabled-opacity: 0.4;\n@switch-color: @primary-color;\n@switch-bg: @component-background;\n@switch-shadow-color: fade(#00230b, 20%);\n@switch-padding: 2px;\n@switch-inner-margin-min: ceil(@switch-height * 0.3);\n@switch-inner-margin-max: ceil(@switch-height * 1.1);\n@switch-sm-inner-margin-min: ceil(@switch-sm-height * 0.3);\n@switch-sm-inner-margin-max: ceil(@switch-sm-height * 1.1);\n\n// Pagination\n// ---\n@pagination-item-bg: @component-background;\n@pagination-item-size: @height-base;\n@pagination-item-size-sm: 24px;\n@pagination-font-family: @font-family;\n@pagination-font-weight-active: 500;\n@pagination-item-bg-active: @component-background;\n@pagination-item-link-bg: @component-background;\n@pagination-item-disabled-color-active: @disabled-color;\n@pagination-item-disabled-bg-active: @disabled-active-bg;\n@pagination-item-input-bg: @component-background;\n@pagination-mini-options-size-changer-top: 0px;\n\n// PageHeader\n// ---\n@page-header-padding: @padding-lg;\n@page-header-padding-vertical: @padding-md;\n@page-header-padding-breadcrumb: @padding-sm;\n@page-header-content-padding-vertical: @padding-sm;\n@page-header-back-color: #000;\n@page-header-ghost-bg: inherit;\n@page-header-heading-title: @heading-4-size;\n@page-header-heading-sub-title: 14px;\n@page-header-tabs-tab-font-size: 16px;\n\n// Breadcrumb\n// ---\n@breadcrumb-base-color: @text-color-secondary;\n@breadcrumb-last-item-color: @text-color;\n@breadcrumb-font-size: @font-size-base;\n@breadcrumb-icon-font-size: @font-size-base;\n@breadcrumb-link-color: @text-color-secondary;\n@breadcrumb-link-color-hover: @text-color;\n@breadcrumb-separator-color: @text-color-secondary;\n@breadcrumb-separator-margin: 0 @padding-xs;\n\n// Slider\n// ---\n@slider-margin: 10px 6px 10px;\n@slider-rail-background-color: @background-color-base;\n@slider-rail-background-color-hover: #e1e1e1;\n@slider-track-background-color: @primary-3;\n@slider-track-background-color-hover: @primary-4;\n@slider-handle-border-width: 2px;\n@slider-handle-background-color: @component-background;\n@slider-handle-color: @primary-3;\n@slider-handle-color-hover: @primary-4;\n@slider-handle-color-focus: ~'var(--@{ant-prefix}-primary-color-deprecated-t-20)';\n@slider-handle-color-focus-shadow: ~'var(--@{ant-prefix}-primary-color-deprecated-f-12)';\n@slider-handle-color-tooltip-open: @primary-color;\n@slider-handle-size: 14px;\n@slider-handle-margin-top: -5px;\n@slider-handle-margin-left: -5px;\n@slider-handle-shadow: 0;\n@slider-dot-border-color: @border-color-split;\n@slider-dot-border-color-active: ~'var(--@{ant-prefix}-primary-color-deprecated-t-50)';\n@slider-disabled-color: @disabled-color;\n@slider-disabled-background-color: @component-background;\n\n// Tree\n// ---\n@tree-bg: @component-background;\n@tree-title-height: 24px;\n@tree-child-padding: 18px;\n@tree-directory-selected-color: #fff;\n@tree-directory-selected-bg: @primary-color;\n@tree-node-hover-bg: @item-hover-bg;\n@tree-node-selected-bg: @primary-2;\n\n// Collapse\n// ---\n@collapse-header-padding: @padding-sm @padding-md;\n@collapse-header-padding-extra: 40px;\n@collapse-header-bg: @background-color-light;\n@collapse-content-padding: @padding-md;\n@collapse-content-bg: @component-background;\n@collapse-header-arrow-left: 16px;\n\n// Skeleton\n// ---\n@skeleton-color: rgba(190, 190, 190, 0.2);\n@skeleton-to-color: shade(@skeleton-color, 5%);\n@skeleton-paragraph-margin-top: 28px;\n@skeleton-paragraph-li-margin-top: @margin-md;\n@skeleton-paragraph-li-height: 16px;\n@skeleton-title-height: 16px;\n@skeleton-title-paragraph-margin-top: @margin-lg;\n\n// Transfer\n// ---\n@transfer-header-height: 40px;\n@transfer-item-height: @height-base;\n@transfer-disabled-bg: @disabled-bg;\n@transfer-list-height: 200px;\n@transfer-item-hover-bg: @item-hover-bg;\n@transfer-item-selected-hover-bg: ~'var(--@{ant-prefix}-primary-color-active-deprecated-d-02)';\n@transfer-item-padding-vertical: 6px;\n@transfer-list-search-icon-top: 12px;\n\n// Message\n// ---\n@message-notice-content-padding: 10px 16px;\n@message-notice-content-bg: @component-background;\n// Motion\n// ---\n@wave-animation-width: 6px;\n\n// Alert\n// ---\n@alert-success-border-color: @success-color-deprecated-border;\n@alert-success-bg-color: @success-color-deprecated-bg;\n@alert-success-icon-color: @success-color;\n@alert-info-border-color: @info-color-deprecated-border;\n@alert-info-bg-color: @info-color-deprecated-bg;\n@alert-info-icon-color: @info-color;\n@alert-warning-border-color: @warning-color-deprecated-border;\n@alert-warning-bg-color: @warning-color-deprecated-bg;\n@alert-warning-icon-color: @warning-color;\n@alert-error-border-color: @error-color-deprecated-border;\n@alert-error-bg-color: @error-color-deprecated-bg;\n@alert-error-icon-color: @error-color;\n@alert-message-color: @heading-color;\n@alert-text-color: @text-color;\n@alert-close-color: @text-color-secondary;\n@alert-close-hover-color: @icon-color-hover;\n@alert-padding-vertical: @padding-xs;\n@alert-padding-horizontal: @padding-md - 1px;\n@alert-no-icon-padding-vertical: @padding-xs;\n@alert-with-description-no-icon-padding-vertical: @padding-md - 1px;\n@alert-with-description-padding-vertical: @padding-md - 1px;\n@alert-with-description-padding: @alert-with-description-padding-vertical 15px\n  @alert-with-description-no-icon-padding-vertical @alert-with-description-icon-size;\n@alert-icon-top: 8px + @font-size-base * (@line-height-base / 2) - (@font-size-base / 2);\n@alert-with-description-icon-size: 24px;\n\n// List\n// ---\n@list-header-background: transparent;\n@list-footer-background: transparent;\n@list-empty-text-padding: @padding-md;\n@list-item-padding: @padding-sm 0;\n@list-item-padding-sm: @padding-xs @padding-md;\n@list-item-padding-lg: 16px 24px;\n@list-item-meta-margin-bottom: @padding-md;\n@list-item-meta-avatar-margin-right: @padding-md;\n@list-item-meta-title-margin-bottom: @padding-sm;\n@list-customize-card-bg: @component-background;\n@list-item-meta-description-font-size: @font-size-base;\n\n// Statistic\n// ---\n@statistic-title-font-size: @font-size-base;\n@statistic-content-font-size: 24px;\n@statistic-unit-font-size: 24px;\n@statistic-font-family: @font-family;\n\n// Drawer\n// ---\n@drawer-header-padding: @padding-md @padding-lg;\n@drawer-body-padding: @padding-lg;\n@drawer-bg: @component-background;\n@drawer-footer-padding-vertical: @modal-footer-padding-vertical;\n@drawer-footer-padding-horizontal: @modal-footer-padding-horizontal;\n@drawer-header-close-size: 56px;\n@drawer-title-font-size: @font-size-lg;\n@drawer-title-line-height: 22px;\n\n// Timeline\n// ---\n@timeline-width: 2px;\n@timeline-color: @border-color-split;\n@timeline-dot-border-width: 2px;\n@timeline-dot-color: @primary-color;\n@timeline-dot-bg: @component-background;\n@timeline-item-padding-bottom: 20px;\n\n// Typography\n// ---\n@typography-title-font-weight: 600;\n@typography-title-margin-top: 1.2em;\n@typography-title-margin-bottom: 0.5em;\n\n// Upload\n// ---\n@upload-actions-color: @text-color-secondary;\n\n// Steps\n// ---\n@process-tail-color: @border-color-split;\n@steps-nav-arrow-color: fade(@black, 25%);\n@steps-background: @component-background;\n@steps-icon-size: 32px;\n@steps-icon-custom-size: @steps-icon-size;\n@steps-icon-custom-top: 0px;\n@steps-icon-custom-font-size: 24px;\n@steps-icon-top: -0.5px;\n@steps-icon-font-size: @font-size-lg;\n@steps-icon-margin: 0 8px 0 0;\n@steps-title-line-height: @height-base;\n@steps-small-icon-size: 24px;\n@steps-small-icon-margin: 0 8px 0 0;\n@steps-dot-size: 8px;\n@steps-dot-top: 2px;\n@steps-current-dot-size: 10px;\n@steps-description-max-width: 140px;\n@steps-nav-content-max-width: auto;\n@steps-vertical-icon-width: 16px;\n@steps-vertical-tail-width: 16px;\n@steps-vertical-tail-width-sm: 12px;\n\n// Notification\n// ---\n@notification-bg: @component-background;\n@notification-padding-vertical: 16px;\n@notification-padding-horizontal: 24px;\n\n// Result\n// ---\n@result-title-font-size: 24px;\n@result-subtitle-font-size: @font-size-base;\n@result-icon-font-size: 72px;\n@result-extra-margin: 24px 0 0 0;\n\n// Image\n// ---\n@image-size-base: 48px;\n@image-font-size-base: 24px;\n@image-bg: #f5f5f5;\n@image-color: #fff;\n@image-mask-font-size: 16px;\n@image-preview-operation-size: 18px;\n@image-preview-operation-color: @text-color-dark;\n@image-preview-operation-disabled-color: fade(@image-preview-operation-color, 25%);\n\n// Segmented\n// ---\n@segmented-bg: fade(@black, 4%);\n@segmented-hover-bg: fade(@black, 6%);\n@segmented-selected-bg: @white;\n@segmented-label-color: fade(@black, 65%);\n@segmented-label-hover-color: #262626;\n"
  },
  {
    "path": "components/style/variable.less",
    "content": "@root-entry-name: variable;\n\n@import './themes/variable.less';\n@import './core/index';\n"
  },
  {
    "path": "components/switch/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n最简单的用法。\n\n## en-US\n\nThe most basic usage.\n"
  },
  {
    "path": "components/switch/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\n\n@Component({\n  selector: 'nz-demo-switch-basic',\n  imports: [FormsModule, NzSwitchModule],\n  template: `<nz-switch [(ngModel)]=\"switchValue\" />`\n})\nexport class NzDemoSwitchBasicComponent {\n  switchValue = false;\n}\n"
  },
  {
    "path": "components/switch/demo/control.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 完整控制\n  en-US: Control\n---\n\n## zh-CN\n\n`Switch` 的状态完全由用户接管，不再自动根据点击事件改变数据。\n\n## en-US\n\nThe status of `Switch` is completely up to the user and no longer automatically changes the data based on the click event.\n"
  },
  {
    "path": "components/switch/demo/control.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\n\n@Component({\n  selector: 'nz-demo-switch-control',\n  imports: [FormsModule, NzSwitchModule],\n  template: ` <nz-switch [(ngModel)]=\"switchValue\" [nzControl]=\"true\" (click)=\"clickSwitch()\" [nzLoading]=\"loading\" /> `\n})\nexport class NzDemoSwitchControlComponent {\n  switchValue = false;\n  loading = false;\n\n  clickSwitch(): void {\n    if (!this.loading) {\n      this.loading = true;\n      setTimeout(() => {\n        this.switchValue = !this.switchValue;\n        this.loading = false;\n      }, 3000);\n    }\n  }\n}\n"
  },
  {
    "path": "components/switch/demo/disabled.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 不可用\n  en-US: Disabled\n---\n\n## zh-CN\n\nSwitch 失效状态。\n\n## en-US\n\nDisabled state of `Switch`.\n"
  },
  {
    "path": "components/switch/demo/disabled.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\n\n@Component({\n  selector: 'nz-demo-switch-disabled',\n  imports: [FormsModule, NzButtonModule, NzSwitchModule],\n  template: `\n    <nz-switch [(ngModel)]=\"switchValue\" [nzDisabled]=\"isDisabled\" />\n    <br />\n    <br />\n    <button nz-button nzType=\"primary\" (click)=\"isDisabled = !isDisabled\">Toggle disabled</button>\n  `\n})\nexport class NzDemoSwitchDisabledComponent {\n  switchValue = false;\n  isDisabled = true;\n}\n"
  },
  {
    "path": "components/switch/demo/loading.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 加载中\n  en-US: Loading\n---\n\n## zh-CN\n\n标识开关操作仍在执行中。\n\n## en-US\n\nMark a pending state of switch.\n"
  },
  {
    "path": "components/switch/demo/loading.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\n\n@Component({\n  selector: 'nz-demo-switch-loading',\n  imports: [FormsModule, NzSwitchModule],\n  template: `\n    <nz-switch [ngModel]=\"true\" nzLoading />\n    <br />\n    <br />\n    <nz-switch nzSize=\"small\" [ngModel]=\"false\" nzLoading />\n  `\n})\nexport class NzDemoSwitchLoadingComponent {}\n"
  },
  {
    "path": "components/switch/demo/size.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 两种大小\n  en-US: Two sizes\n---\n\n## zh-CN\n\n`nzSize=\"small\"` 表示小号开关。\n\n## en-US\n\n`nzSize=\"small\"` represents a small sized switch.\n"
  },
  {
    "path": "components/switch/demo/size.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\n\n@Component({\n  selector: 'nz-demo-switch-size',\n  imports: [FormsModule, NzSwitchModule],\n  template: `\n    <nz-switch [ngModel]=\"true\" />\n    <br />\n    <br />\n    <nz-switch nzSize=\"small\" [ngModel]=\"true\" />\n  `\n})\nexport class NzDemoSwitchSizeComponent {}\n"
  },
  {
    "path": "components/switch/demo/text.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 文字和图标\n  en-US: Text & icon\n---\n\n## zh-CN\n\n带有文字和图标。\n\n## en-US\n\nWith text and icon.\n"
  },
  {
    "path": "components/switch/demo/text.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\n\n@Component({\n  selector: 'nz-demo-switch-text',\n  imports: [FormsModule, NzIconModule, NzSwitchModule],\n  template: `\n    <nz-switch [ngModel]=\"true\" nzCheckedChildren=\"开\" nzUnCheckedChildren=\"关\" />\n    <br />\n    <br />\n    <nz-switch [ngModel]=\"false\" nzCheckedChildren=\"1\" nzUnCheckedChildren=\"0\" />\n    <br />\n    <br />\n    <nz-switch [ngModel]=\"true\" [nzCheckedChildren]=\"checkedTemplate\" [nzUnCheckedChildren]=\"unCheckedTemplate\" />\n    <ng-template #checkedTemplate><nz-icon nzType=\"check\" /></ng-template>\n    <ng-template #unCheckedTemplate><nz-icon nzType=\"close\" /></ng-template>\n  `\n})\nexport class NzDemoSwitchTextComponent {}\n"
  },
  {
    "path": "components/switch/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Entry\ntitle: Switch\ncover: 'https://gw.alipayobjects.com/zos/alicdn/zNdJQMhfm/Switch.svg'\ndescription: Used to toggle between two states.\n---\n\n## When To Use\n\n- If you need to represent the switching between two states or on-off state.\n- The difference between `Switch` and `Checkbox` is that `Switch` will trigger a state change directly when you toggle it, while `Checkbox` is generally used for state marking, which should work in conjunction with submit operation.\n\n## API\n\n### nz-switch\n\n| Property                | Description                                                             | Type                          | Default     | Global Config |\n| ----------------------- | ----------------------------------------------------------------------- | ----------------------------- | ----------- | ------------- |\n| `[nzId]`                | button id attribute inside the component                                | `string`                      | -           |\n| `[ngModel]`             | determine whether the `nz-switch` is checked, double binding            | `boolean`                     | `false`     |\n| `[nzCheckedChildren]`   | content to be shown when the state is checked                           | `string \\| TemplateRef<void>` | -           |\n| `[nzUnCheckedChildren]` | content to be shown when the state is unchecked                         | `string \\| TemplateRef<void>` | -           |\n| `[nzDisabled]`          | Disable switch                                                          | `boolean`                     | `false`     |\n| `[nzSize]`              | the size of the `nz-switch`, options: `default` `small`                 | `'small' \\| 'default'`        | `'default'` | ✅            |\n| `[nzLoading]`           | loading state of switch                                                 | `boolean`                     | `false`     |\n| `[nzControl]`           | determine whether fully control state by user                           | `boolean`                     | `false`     |\n| `(ngModelChange)`       | a callback function, can be executed when the checked state is changing | `EventEmitter<boolean>`       | -           |\n\n#### Methods\n\n| Name    | Description  |\n| ------- | ------------ |\n| focus() | get focus    |\n| blur()  | remove focus |\n"
  },
  {
    "path": "components/switch/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 开关\ntype: 数据录入\ntitle: Switch\ncover: 'https://gw.alipayobjects.com/zos/alicdn/zNdJQMhfm/Switch.svg'\ndescription: 使用开关切换两种状态之间。\n---\n\n## 何时使用\n\n- 需要表示开关状态/两种状态之间的切换时；\n- 和 `checkbox`的区别是，切换 `switch` 会直接触发状态改变，而 `checkbox` 一般用于状态标记，需要和提交操作配合。\n\n## API\n\n### nz-switch\n\n| 参数                    | 说明                                | 类型                          | 默认值      | 全局配置 |\n| ----------------------- | ----------------------------------- | ----------------------------- | ----------- | -------- |\n| `[nzId]`                | 组件内部 button 的 id 值            | `string`                      | -           |\n| `[ngModel]`             | 指定当前是否选中，可双向绑定        | `boolean`                     | `false`     |\n| `[nzCheckedChildren]`   | 选中时的内容                        | `string \\| TemplateRef<void>` | -           |\n| `[nzUnCheckedChildren]` | 非选中时的内容                      | `string \\| TemplateRef<void>` | -           |\n| `[nzDisabled]`          | disable 状态                        | `boolean`                     | `false`     |\n| `[nzSize]`              | 开关大小，可选值：`default` `small` | `'small' \\| 'default'`        | `'default'` | ✅       |\n| `[nzLoading]`           | 加载中的开关                        | `boolean`                     | `false`     |\n| `[nzControl]`           | 是否完全由用户控制状态              | `boolean`                     | `false`     |\n| `(ngModelChange)`       | 当前是否选中的回调                  | `EventEmitter<boolean>`       | `false`     |\n\n#### 方法\n\n| 名称    | 描述     |\n| ------- | -------- |\n| focus() | 获取焦点 |\n| blur()  | 移除焦点 |\n"
  },
  {
    "path": "components/switch/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/switch/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/switch/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './switch.component';\nexport * from './switch.module';\n"
  },
  {
    "path": "components/switch/style/entry.less",
    "content": "@import './index.less';\n@import './patch.less';\n"
  },
  {
    "path": "components/switch/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@switch-prefix-cls: ~'@{ant-prefix}-switch';\n@switch-duration: 0.2s;\n\n@switch-pin-size: @switch-height - 4px;\n@switch-sm-pin-size: @switch-sm-height - 4px;\n\n.@{switch-prefix-cls} {\n  .reset-component();\n\n  position: relative;\n  display: inline-block;\n  box-sizing: border-box;\n  min-width: @switch-min-width;\n  height: @switch-height;\n  line-height: @switch-height;\n  vertical-align: middle;\n  background-color: @disabled-color;\n  border: 0;\n  border-radius: 100px;\n  cursor: pointer;\n  transition: all @switch-duration;\n  user-select: none;\n\n  &:focus {\n    outline: 0;\n    box-shadow: 0 0 0 2px fade(@disabled-color, 10%);\n  }\n\n  &-checked:focus {\n    box-shadow: 0 0 0 2px @primary-1;\n  }\n\n  &:focus:hover {\n    box-shadow: none;\n  }\n\n  &-checked {\n    background-color: @switch-color;\n  }\n\n  &-loading,\n  &-disabled {\n    cursor: not-allowed;\n    opacity: @switch-disabled-opacity;\n\n    * {\n      box-shadow: none;\n      cursor: not-allowed;\n    }\n  }\n\n  // ========================= Inner ==========================\n  &-inner {\n    display: block;\n    margin: 0 @switch-inner-margin-min 0 @switch-inner-margin-max;\n    color: @text-color-inverse;\n    font-size: @font-size-sm;\n    transition: margin @switch-duration;\n  }\n\n  &-checked &-inner {\n    margin: 0 @switch-inner-margin-max 0 @switch-inner-margin-min;\n  }\n\n  // ========================= Handle =========================\n  &-handle {\n    position: absolute;\n    top: @switch-padding;\n    left: @switch-padding;\n    width: @switch-pin-size;\n    height: @switch-pin-size;\n    transition: all @switch-duration ease-in-out;\n\n    &::before {\n      position: absolute;\n      top: 0;\n      right: 0;\n      bottom: 0;\n      left: 0;\n      background-color: @switch-bg;\n      border-radius: (@switch-pin-size / 2);\n      box-shadow: 0 2px 4px 0 @switch-shadow-color;\n      transition: all @switch-duration ease-in-out;\n      content: '';\n    }\n  }\n\n  &-checked &-handle {\n    left: calc(100% - @switch-pin-size - @switch-padding);\n  }\n\n  &:not(&-disabled):active {\n    .@{switch-prefix-cls}-handle::before {\n      right: -30%;\n      left: 0;\n    }\n\n    &.@{switch-prefix-cls}-checked {\n      .@{switch-prefix-cls}-handle::before {\n        right: 0;\n        left: -30%;\n      }\n    }\n  }\n\n  // ======================== Loading =========================\n  &-loading-icon.@{iconfont-css-prefix} {\n    position: relative;\n    top: ((@switch-pin-size - @font-size-base) / 2);\n    color: rgba(0, 0, 0, 0.65);\n    vertical-align: top;\n  }\n\n  &-checked &-loading-icon {\n    color: @switch-color;\n  }\n\n  // ========================== Size ==========================\n  &-small {\n    min-width: @switch-sm-min-width;\n    height: @switch-sm-height;\n    line-height: @switch-sm-height;\n\n    .@{switch-prefix-cls}-inner {\n      margin: 0 @switch-sm-inner-margin-min 0 @switch-sm-inner-margin-max;\n      font-size: @font-size-sm;\n    }\n\n    .@{switch-prefix-cls}-handle {\n      width: @switch-sm-pin-size;\n      height: @switch-sm-pin-size;\n    }\n\n    .@{switch-prefix-cls}-loading-icon {\n      top: ((@switch-sm-pin-size - 9px) / 2);\n      font-size: 9px;\n    }\n\n    &.@{switch-prefix-cls}-checked {\n      .@{switch-prefix-cls}-inner {\n        margin: 0 @switch-sm-inner-margin-max 0 @switch-sm-inner-margin-min;\n      }\n\n      .@{switch-prefix-cls}-handle {\n        left: calc(100% - @switch-sm-pin-size - @switch-padding);\n      }\n    }\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/switch/style/patch.less",
    "content": "nz-switch {\n  display: inline-block;\n}\n"
  },
  {
    "path": "components/switch/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@switch-prefix-cls: ~'@{ant-prefix}-switch';\n\n@switch-pin-size: @switch-height - 4px;\n@switch-sm-pin-size: @switch-sm-height - 4px;\n\n.@{switch-prefix-cls}-rtl {\n  direction: rtl;\n\n  .@{switch-prefix-cls}-inner {\n    margin: 0 @switch-inner-margin-max 0 @switch-inner-margin-min;\n  }\n\n  .@{switch-prefix-cls}-handle {\n    right: @switch-padding;\n    left: auto;\n  }\n\n  &:not(&-disabled):active {\n    .@{switch-prefix-cls}-handle::before {\n      right: 0;\n      left: -30%;\n    }\n\n    &.@{switch-prefix-cls}-checked {\n      .@{switch-prefix-cls}-handle::before {\n        right: -30%;\n        left: 0;\n      }\n    }\n  }\n\n  &.@{switch-prefix-cls}-checked {\n    .@{switch-prefix-cls}-inner {\n      margin: 0 @switch-inner-margin-min 0 @switch-inner-margin-max;\n    }\n\n    .@{switch-prefix-cls}-handle {\n      right: calc(100% - @switch-pin-size - @switch-padding);\n    }\n  }\n\n  &.@{switch-prefix-cls}-small {\n    &.@{switch-prefix-cls}-checked {\n      .@{switch-prefix-cls}-handle {\n        right: calc(100% - @switch-sm-pin-size - @switch-padding);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/switch/switch.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { FocusMonitor } from '@angular/cdk/a11y';\nimport { Directionality } from '@angular/cdk/bidi';\nimport { ENTER, LEFT_ARROW, RIGHT_ARROW, SPACE } from '@angular/cdk/keycodes';\nimport {\n  AfterViewInit,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DestroyRef,\n  ElementRef,\n  Input,\n  NgZone,\n  OnInit,\n  TemplateRef,\n  ViewChild,\n  ViewEncapsulation,\n  booleanAttribute,\n  computed,\n  forwardRef,\n  inject,\n  signal,\n  type OnChanges,\n  type SimpleChanges\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\n\nimport { NzConfigKey, NzConfigService, WithConfig } from 'ng-zorro-antd/core/config';\nimport { NZ_FORM_SIZE } from 'ng-zorro-antd/core/form';\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzSizeDSType, OnChangeType, OnTouchedType } from 'ng-zorro-antd/core/types';\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\nimport { NzWaveModule } from 'ng-zorro-antd/core/wave';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'switch';\n\n@Component({\n  selector: 'nz-switch',\n  exportAs: 'nzSwitch',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => NzSwitchComponent),\n      multi: true\n    }\n  ],\n  template: `\n    <button\n      nz-wave\n      type=\"button\"\n      class=\"ant-switch\"\n      #switchElement\n      [attr.id]=\"nzId\"\n      [disabled]=\"nzDisabled\"\n      [class.ant-switch-checked]=\"isChecked\"\n      [class.ant-switch-loading]=\"nzLoading\"\n      [class.ant-switch-disabled]=\"nzDisabled\"\n      [class.ant-switch-small]=\"finalSize() === 'small'\"\n      [class.ant-switch-rtl]=\"dir() === 'rtl'\"\n      [nzWaveExtraNode]=\"true\"\n    >\n      <span class=\"ant-switch-handle\">\n        @if (nzLoading) {\n          <nz-icon nzType=\"loading\" class=\"ant-switch-loading-icon\" />\n        }\n      </span>\n      <span class=\"ant-switch-inner\">\n        @if (isChecked) {\n          <ng-container *nzStringTemplateOutlet=\"nzCheckedChildren\">{{ nzCheckedChildren }}</ng-container>\n        } @else {\n          <ng-container *nzStringTemplateOutlet=\"nzUnCheckedChildren\">{{ nzUnCheckedChildren }}</ng-container>\n        }\n      </span>\n      <div class=\"ant-click-animating-node\"></div>\n    </button>\n  `,\n  imports: [NzWaveModule, NzIconModule, NzOutletModule]\n})\nexport class NzSwitchComponent implements ControlValueAccessor, AfterViewInit, OnInit, OnChanges {\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  nzConfigService = inject(NzConfigService);\n  private el: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement;\n  private ngZone = inject(NgZone);\n  private cdr = inject(ChangeDetectorRef);\n  private focusMonitor = inject(FocusMonitor);\n  private destroyRef = inject(DestroyRef);\n\n  isChecked = false;\n  onChange: OnChangeType = () => {};\n  onTouched: OnTouchedType = () => {};\n  @ViewChild('switchElement', { static: true }) switchElement!: ElementRef<HTMLElement>;\n  @Input({ transform: booleanAttribute }) nzLoading = false;\n  @Input({ transform: booleanAttribute }) nzDisabled = false;\n  @Input({ transform: booleanAttribute }) nzControl = false;\n  @Input() nzCheckedChildren: string | TemplateRef<void> | null = null;\n  @Input() nzUnCheckedChildren: string | TemplateRef<void> | null = null;\n  @Input() @WithConfig() nzSize: NzSizeDSType = 'default';\n  @Input() nzId: string | null = null;\n\n  protected readonly dir = inject(Directionality).valueSignal;\n\n  private isNzDisableFirstChange = true;\n\n  private readonly size = signal<NzSizeDSType>(this.nzSize);\n\n  private readonly formSize = inject(NZ_FORM_SIZE, { optional: true });\n\n  protected readonly finalSize = computed(() => this.formSize?.() || this.size());\n\n  updateValue(value: boolean): void {\n    if (this.isChecked !== value) {\n      this.isChecked = value;\n      this.onChange(this.isChecked);\n    }\n  }\n\n  focus(): void {\n    this.focusMonitor.focusVia(this.switchElement.nativeElement, 'keyboard');\n  }\n\n  blur(): void {\n    this.switchElement.nativeElement.blur();\n  }\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      this.focusMonitor.stopMonitoring(this.switchElement!.nativeElement);\n    });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzSize } = changes;\n    if (nzSize) {\n      this.size.set(nzSize.currentValue);\n    }\n  }\n\n  ngOnInit(): void {\n    fromEventOutsideAngular(this.el, 'click')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(event => {\n        event.preventDefault();\n\n        if (this.nzControl || this.nzDisabled || this.nzLoading) {\n          return;\n        }\n\n        this.ngZone.run(() => {\n          this.updateValue(!this.isChecked);\n          this.cdr.markForCheck();\n        });\n      });\n\n    fromEventOutsideAngular<KeyboardEvent>(this.switchElement.nativeElement, 'keydown')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(event => {\n        if (this.nzControl || this.nzDisabled || this.nzLoading) {\n          return;\n        }\n\n        const { keyCode } = event;\n        if (keyCode !== LEFT_ARROW && keyCode !== RIGHT_ARROW && keyCode !== SPACE && keyCode !== ENTER) {\n          return;\n        }\n\n        event.preventDefault();\n\n        this.ngZone.run(() => {\n          if (keyCode === LEFT_ARROW) {\n            this.updateValue(false);\n          } else if (keyCode === RIGHT_ARROW) {\n            this.updateValue(true);\n          } else if (keyCode === SPACE || keyCode === ENTER) {\n            this.updateValue(!this.isChecked);\n          }\n\n          this.cdr.markForCheck();\n        });\n      });\n  }\n\n  ngAfterViewInit(): void {\n    this.focusMonitor\n      .monitor(this.switchElement!.nativeElement, true)\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(focusOrigin => {\n        if (!focusOrigin) {\n          /** https://github.com/angular/angular/issues/17793 **/\n          Promise.resolve().then(() => this.onTouched());\n        }\n      });\n  }\n\n  writeValue(value: boolean): void {\n    this.isChecked = value;\n    this.cdr.markForCheck();\n  }\n\n  registerOnChange(fn: OnChangeType): void {\n    this.onChange = fn;\n  }\n\n  registerOnTouched(fn: OnTouchedType): void {\n    this.onTouched = fn;\n  }\n\n  setDisabledState(disabled: boolean): void {\n    this.nzDisabled = (this.isNzDisableFirstChange && this.nzDisabled) || disabled;\n    this.isNzDisableFirstChange = false;\n    this.cdr.markForCheck();\n  }\n}\n"
  },
  {
    "path": "components/switch/switch.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzSwitchComponent } from './switch.component';\n\n@NgModule({\n  imports: [NzSwitchComponent],\n  exports: [NzSwitchComponent]\n})\nexport class NzSwitchModule {}\n"
  },
  {
    "path": "components/switch/switch.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport { ENTER, LEFT_ARROW, RIGHT_ARROW, SPACE } from '@angular/cdk/keycodes';\nimport {\n  ApplicationRef,\n  Component,\n  DebugElement,\n  provideZoneChangeDetection,\n  signal,\n  TemplateRef,\n  ViewChild,\n  type WritableSignal\n} from '@angular/core';\nimport { ComponentFixture, fakeAsync, flush, TestBed } from '@angular/core/testing';\nimport { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\n\nimport { NZ_FORM_SIZE } from 'ng-zorro-antd/core/form';\nimport { dispatchKeyboardEvent } from 'ng-zorro-antd/core/testing';\nimport { NzSizeDSType, type NzSizeLDSType } from 'ng-zorro-antd/core/types';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzSwitchComponent } from './switch.component';\nimport { NzSwitchModule } from './switch.module';\n\ndescribe('switch', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideZoneChangeDetection()]\n    });\n  });\n\n  describe('basic switch', () => {\n    let fixture: ComponentFixture<NzTestSwitchBasicComponent>;\n    let testComponent: NzTestSwitchBasicComponent;\n    let switchElement: DebugElement;\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestSwitchBasicComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n      switchElement = fixture.debugElement.query(By.directive(NzSwitchComponent));\n    });\n    it('should className correct', () => {\n      fixture.detectChanges();\n      expect(switchElement.nativeElement.firstElementChild!.classList).toContain('ant-switch');\n    });\n    it('should ngModel work', fakeAsync(() => {\n      fixture.detectChanges();\n      expect(switchElement.nativeElement.firstElementChild!.classList).not.toContain('ant-switch-checked');\n      expect(testComponent.value).toBe(false);\n      testComponent.value = true;\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(switchElement.nativeElement.firstElementChild!.classList).toContain('ant-switch-checked');\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(0);\n    }));\n    it('should click work', fakeAsync(() => {\n      expect(testComponent.value).toBe(false);\n      switchElement.nativeElement.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(true);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(1);\n      switchElement.nativeElement.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(false);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(2);\n      testComponent.control = true;\n      fixture.detectChanges();\n      switchElement.nativeElement.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(false);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(2);\n    }));\n    it('should disable work', fakeAsync(() => {\n      testComponent.disabled = true;\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(false);\n      switchElement.nativeElement.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(false);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(0);\n    }));\n    it('should loading work', fakeAsync(() => {\n      testComponent.loading = true;\n      fixture.detectChanges();\n      expect(switchElement.nativeElement.firstElementChild!.classList).toContain('ant-switch-loading');\n      expect(testComponent.value).toBe(false);\n      switchElement.nativeElement.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(false);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(0);\n    }));\n    it('should size work', () => {\n      testComponent.size = 'small';\n      fixture.detectChanges();\n      expect(switchElement.nativeElement.firstElementChild!.classList).toContain('ant-switch-small');\n    });\n    it('should key down work', () => {\n      expect(testComponent.value).toBe(false);\n      switchElement.nativeElement.click();\n      fixture.detectChanges();\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(1);\n      expect(testComponent.value).toBe(true);\n      dispatchKeyboardEvent(switchElement.nativeElement.firstElementChild, 'keydown', RIGHT_ARROW);\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(true);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(1);\n      dispatchKeyboardEvent(switchElement.nativeElement.firstElementChild, 'keydown', LEFT_ARROW);\n\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(false);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(2);\n      dispatchKeyboardEvent(switchElement.nativeElement.firstElementChild, 'keydown', LEFT_ARROW);\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(false);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(2);\n      dispatchKeyboardEvent(switchElement.nativeElement.firstElementChild, 'keydown', SPACE);\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(true);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(3);\n      dispatchKeyboardEvent(switchElement.nativeElement.firstElementChild, 'keydown', ENTER);\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(false);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(4);\n      testComponent.control = true;\n      fixture.detectChanges();\n      dispatchKeyboardEvent(switchElement.nativeElement.firstElementChild, 'keydown', ENTER);\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(false);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(4);\n      testComponent.control = false;\n      testComponent.loading = true;\n      fixture.detectChanges();\n      dispatchKeyboardEvent(switchElement.nativeElement.firstElementChild, 'keydown', ENTER);\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(false);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(4);\n      testComponent.control = false;\n      testComponent.loading = false;\n      testComponent.disabled = true;\n      fixture.detectChanges();\n      dispatchKeyboardEvent(switchElement.nativeElement.firstElementChild, 'keydown', ENTER);\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(false);\n      expect(testComponent.modelChange).toHaveBeenCalledTimes(4);\n    });\n    it('should children work', fakeAsync(() => {\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(switchElement.nativeElement.querySelector('.ant-switch-inner').innerText).toBe('off');\n      switchElement.nativeElement.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(switchElement.nativeElement.querySelector('.ant-switch-inner').innerText).toBe('on');\n    }));\n    it('should focus and blur function work', () => {\n      fixture.detectChanges();\n      expect(switchElement.nativeElement.firstElementChild === document.activeElement).toBe(false);\n      testComponent.nzSwitchComponent.focus();\n      fixture.detectChanges();\n      expect(switchElement.nativeElement.firstElementChild === document.activeElement).toBe(true);\n      testComponent.nzSwitchComponent.blur();\n      fixture.detectChanges();\n      expect(switchElement.nativeElement.firstElementChild === document.activeElement).toBe(false);\n    });\n    describe('change detection behavior', () => {\n      it('should not run change detection on `click` events if the switch is disabled', () => {\n        testComponent.disabled = true;\n        fixture.detectChanges();\n\n        const appRef = TestBed.inject(ApplicationRef);\n        const event = new MouseEvent('click');\n\n        spyOn(appRef, 'tick');\n        spyOn(event, 'preventDefault').and.callThrough();\n\n        switchElement.nativeElement.dispatchEvent(event);\n\n        expect(appRef.tick).not.toHaveBeenCalled();\n        expect(event.preventDefault).toHaveBeenCalled();\n      });\n      it('should not run change detection on `keydown` events if the switch is disabled', () => {\n        testComponent.disabled = true;\n        fixture.detectChanges();\n\n        const switchButton = switchElement.nativeElement.querySelector('.ant-switch');\n        const appRef = TestBed.inject(ApplicationRef);\n        const event = new KeyboardEvent('keydown', {\n          keyCode: SPACE\n        });\n\n        spyOn(appRef, 'tick');\n        spyOn(event, 'preventDefault').and.callThrough();\n\n        switchButton.dispatchEvent(event);\n\n        expect(appRef.tick).not.toHaveBeenCalled();\n        expect(event.preventDefault).not.toHaveBeenCalled();\n\n        testComponent.disabled = false;\n        fixture.detectChanges();\n\n        switchButton.dispatchEvent(event);\n\n        expect(event.preventDefault).toHaveBeenCalled();\n      });\n    });\n  });\n  describe('template switch', () => {\n    let fixture: ComponentFixture<NzTestSwitchTemplateComponent>;\n    let switchElement: DebugElement;\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestSwitchTemplateComponent);\n      fixture.detectChanges();\n      switchElement = fixture.debugElement.query(By.directive(NzSwitchComponent));\n    });\n    it('should children template work', fakeAsync(() => {\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(switchElement.nativeElement.querySelector('.ant-switch-inner').firstElementChild!.classList).toContain(\n        'anticon-close'\n      );\n      switchElement.nativeElement.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(switchElement.nativeElement.querySelector('.ant-switch-inner').firstElementChild!.classList).toContain(\n        'anticon-check'\n      );\n    }));\n  });\n  describe('switch form', () => {\n    let fixture: ComponentFixture<NzTestSwitchFormComponent>;\n    let testComponent: NzTestSwitchFormComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestSwitchFormComponent);\n      testComponent = fixture.debugElement.componentInstance;\n    });\n    it('should be in pristine, untouched, and valid states and enable initially', fakeAsync(() => {\n      fixture.detectChanges();\n      flush();\n      const switchElement = fixture.debugElement.query(By.directive(NzSwitchComponent));\n      const buttonElement = switchElement.nativeElement.firstElementChild! as HTMLButtonElement;\n      expect(testComponent.formControl.valid).toBe(true);\n      expect(testComponent.formControl.pristine).toBe(true);\n      expect(testComponent.formControl.touched).toBe(false);\n      expect(buttonElement.disabled).toBeFalsy();\n      expect(buttonElement.classList).not.toContain('ant-switch-disabled');\n    }));\n    it('should be disable if form is disable and nzDisable set to false initially', fakeAsync(() => {\n      testComponent.disable();\n      fixture.detectChanges();\n      flush();\n      const switchElement = fixture.debugElement.query(By.directive(NzSwitchComponent));\n      const buttonElement = switchElement.nativeElement.firstElementChild! as HTMLButtonElement;\n      expect(buttonElement.disabled).toBeTruthy();\n      expect(buttonElement.classList).toContain('ant-switch-disabled');\n    }));\n    it('should set disabled work', fakeAsync(() => {\n      testComponent.disabled = true;\n      fixture.detectChanges();\n      flush();\n      const switchElement = fixture.debugElement.query(By.directive(NzSwitchComponent));\n      const buttonElement = switchElement.nativeElement.firstElementChild! as HTMLButtonElement;\n\n      expect(buttonElement.disabled).toBeTruthy();\n      expect(buttonElement.classList).toContain('ant-switch-disabled');\n      expect(testComponent.formControl.value).toBe(true);\n\n      switchElement.nativeElement.click();\n      fixture.detectChanges();\n      expect(testComponent.formControl.value).toBe(true);\n\n      testComponent.enable();\n      fixture.detectChanges();\n      flush();\n      expect(buttonElement.disabled).toBeFalsy();\n      expect(buttonElement.classList).not.toContain('ant-switch-disabled');\n      switchElement.nativeElement.click();\n      fixture.detectChanges();\n      expect(testComponent.formControl.value).toBe(false);\n\n      testComponent.disable();\n      fixture.detectChanges();\n      flush();\n      expect(buttonElement.disabled).toBeTruthy();\n      expect(buttonElement.classList).toContain('ant-switch-disabled');\n      switchElement.nativeElement.click();\n      fixture.detectChanges();\n      expect(testComponent.formControl.value).toBe(false);\n    }));\n  });\n  describe('RTL', () => {\n    it('should className correct on dir change', () => {\n      const fixture = TestBed.createComponent(NzTestSwitchRtlComponent);\n      const switchElement = fixture.debugElement.query(By.directive(NzSwitchComponent));\n      fixture.detectChanges();\n      expect(switchElement.nativeElement.firstElementChild!.classList).toContain('ant-switch-rtl');\n\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n      expect(switchElement.nativeElement.firstElementChild!.classList).not.toContain('ant-switch-rtl');\n    });\n  });\n});\n\ndescribe('finalSize', () => {\n  let fixture: ComponentFixture<NzTestSwitchBasicComponent>;\n  let switchElement: HTMLElement;\n  let formSizeSignal: WritableSignal<NzSizeLDSType>;\n\n  beforeEach(() => {\n    formSizeSignal = signal<NzSizeDSType>('default');\n  });\n  afterEach(() => {\n    TestBed.resetTestingModule();\n  });\n  it('should set correctly the size from the formSize signal', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_FORM_SIZE, useValue: formSizeSignal }]\n    });\n    fixture = TestBed.createComponent(NzTestSwitchBasicComponent);\n    switchElement = fixture.debugElement.query(By.directive(NzSwitchComponent)).nativeElement;\n    fixture.detectChanges();\n    formSizeSignal.set('small');\n    fixture.detectChanges();\n    expect(switchElement.firstElementChild!.classList).toContain('ant-switch-small');\n  });\n  it('should set correctly the size from the component input', () => {\n    fixture = TestBed.createComponent(NzTestSwitchBasicComponent);\n    switchElement = fixture.debugElement.query(By.directive(NzSwitchComponent)).nativeElement;\n    fixture.componentInstance.size = 'small';\n    fixture.detectChanges();\n    expect(switchElement.firstElementChild!.classList).toContain('ant-switch-small');\n  });\n});\n\n@Component({\n  imports: [FormsModule, NzIconModule, NzSwitchModule],\n  template: `\n    <ng-template #checkedChildrenTemplate><nz-icon nzType=\"check\" /></ng-template>\n    <ng-template #unCheckedChildrenTemplate><nz-icon nzType=\"closs\" /></ng-template>\n    <nz-switch\n      [(ngModel)]=\"value\"\n      (ngModelChange)=\"modelChange($event)\"\n      [nzDisabled]=\"disabled\"\n      [nzLoading]=\"loading\"\n      [nzSize]=\"size\"\n      [nzControl]=\"control\"\n      [nzCheckedChildren]=\"checkedChildren\"\n      [nzUnCheckedChildren]=\"unCheckedChildren\"\n    />\n  `\n})\nexport class NzTestSwitchBasicComponent {\n  @ViewChild(NzSwitchComponent, { static: false }) nzSwitchComponent!: NzSwitchComponent;\n  @ViewChild('checkedChildrenTemplate', { static: false }) checkedChildrenTemplate!: TemplateRef<void>;\n  @ViewChild('unCheckedChildrenTemplate', { static: false }) unCheckedChildrenTemplate!: TemplateRef<void>;\n  checkedChildren = 'on';\n  unCheckedChildren = 'off';\n  value = false;\n  control = false;\n  disabled = false;\n  size: NzSizeDSType = 'default';\n  loading = false;\n  modelChange = jasmine.createSpy('model change callback');\n}\n\n@Component({\n  imports: [NzIconModule, NzSwitchModule],\n  template: `\n    <ng-template #checkedChildrenTemplate><nz-icon nzType=\"check\" /></ng-template>\n    <ng-template #unCheckedChildrenTemplate><nz-icon nzType=\"close\" /></ng-template>\n    <nz-switch [nzCheckedChildren]=\"checkedChildrenTemplate\" [nzUnCheckedChildren]=\"unCheckedChildrenTemplate\" />\n  `\n})\nexport class NzTestSwitchTemplateComponent {}\n\n@Component({\n  imports: [ReactiveFormsModule, NzSwitchModule],\n  template: `\n    <form>\n      <nz-switch [formControl]=\"formControl\" [nzDisabled]=\"disabled\" />\n    </form>\n  `\n})\nexport class NzTestSwitchFormComponent {\n  formControl = new FormControl(true);\n\n  disabled = false;\n\n  disable(): void {\n    this.formControl.disable();\n  }\n\n  enable(): void {\n    this.formControl.enable();\n  }\n}\n\n@Component({\n  imports: [BidiModule, FormsModule, NzSwitchModule],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-switch [(ngModel)]=\"switchValue\" />\n    </div>\n  `\n})\nexport class NzTestSwitchRtlComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n  switchValue = false;\n}\n"
  },
  {
    "path": "components/table/demo/ajax.md",
    "content": "---\norder: 9\ntitle:\n  en-US: Ajax\n  zh-CN: 远程加载数据\n---\n\n## zh-CN\n\n这个例子通过简单的 ajax 读取方式，演示了如何从服务端读取并展现数据，具有筛选、排序等功能以及页面 loading 效果。开发者可以自行接入其他数据处理方式。\n\n- 分页：使用 `[nzFrontPagination]=\"false\"` 指定由服务端分页。\n- 排序：使用 `[nzSortFn]=\"true\"` 指定由服务端排序，如果需要多列排序可使用 `[nzSortPriority]=\"true\"`。\n- 筛选：使用 `[nzFilters]` 来指定筛选项，使用 `[nzFilterFn]=\"true\"` 指定由服务端筛选\n- 参数传输：通过 `(nzQueryParams)` 服务端需要的参数，数据结构为\n\n```typescript\n{\n  pageIndex: number;\n  pageSize: number;\n  sort: Array<{ key: string; value: 'ascend' | 'descend' | null }>;\n  filter: Array<{ key: string; value: any | any[] }>;\n}\n```\n\n**注意，此示例使用 [模拟接口](https://randomuser.me)，展示数据可能不准确，请打开网络面板查看请求。**\n\n## en-US\n\nThis example shows how to fetch and present data from remote server, and how to implement filtering and sorting in server side by sending related parameters to server.\n\n- Pagination：Set `[nzFrontPagination]=\"false\"` to disable frontend pagination.\n- Sort：Set `[nzSortFn]=\"true\"` to enable server sort, if you need multiple sort, set `[nzSortPriority]=\"true\"`.\n- Filter：Pass options to `[nzFilters]` and set `[nzFilterFn]=\"true\"` to enable server filter.\n- Params：Get all params from `(nzQueryParams)`, the data structure is\n\n```typescript\n{\n  pageIndex: number;\n  pageSize: number;\n  sort: Array<{ key: string; value: 'ascend' | 'descend' | null }>;\n  filter: Array<{ key: string; value: any | any[] }>;\n}\n```\n\n**Note, this example uses a [Mock API](https://randomuser.me) that you can look up in Network Console.**\n"
  },
  {
    "path": "components/table/demo/ajax.ts",
    "content": "import { HttpClient, HttpParams } from '@angular/common/http';\nimport { Component, OnInit } from '@angular/core';\nimport { Observable, of } from 'rxjs';\nimport { catchError } from 'rxjs/operators';\n\nimport { NzTableModule, NzTableQueryParams } from 'ng-zorro-antd/table';\n\ninterface RandomUser {\n  gender: string;\n  email: string;\n  name: {\n    title: string;\n    first: string;\n    last: string;\n  };\n}\n\n@Component({\n  selector: 'nz-demo-table-ajax',\n  imports: [NzTableModule],\n  template: `\n    <nz-table\n      nzShowSizeChanger\n      [nzData]=\"listOfRandomUser\"\n      [nzFrontPagination]=\"false\"\n      [nzLoading]=\"loading\"\n      [nzTotal]=\"total\"\n      [nzPageSize]=\"pageSize\"\n      [nzPageIndex]=\"pageIndex\"\n      (nzQueryParams)=\"onQueryParamsChange($event)\"\n    >\n      <thead>\n        <tr>\n          <th nzColumnKey=\"name\" [nzSortFn]=\"true\">Name</th>\n          <th nzColumnKey=\"gender\" [nzFilters]=\"filterGender\" [nzFilterFn]=\"true\">Gender</th>\n          <th nzColumnKey=\"email\" [nzSortFn]=\"true\">Email</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of listOfRandomUser; track data) {\n          <tr>\n            <td>{{ data.name.first }} {{ data.name.last }}</td>\n            <td>{{ data.gender }}</td>\n            <td>{{ data.email }}</td>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n  `\n})\nexport class NzDemoTableAjaxComponent implements OnInit {\n  total = 1;\n  listOfRandomUser: RandomUser[] = [];\n  loading = true;\n  pageSize = 10;\n  pageIndex = 1;\n  filterGender = [\n    { text: 'male', value: 'male' },\n    { text: 'female', value: 'female' }\n  ];\n\n  loadDataFromServer(\n    pageIndex: number,\n    pageSize: number,\n    sortField: string | null,\n    sortOrder: string | null,\n    filter: Array<{ key: string; value: string[] }>\n  ): void {\n    this.loading = true;\n    this.getUsers(pageIndex, pageSize, sortField, sortOrder, filter).subscribe(data => {\n      this.loading = false;\n      this.total = 200; // mock the total data here\n      this.listOfRandomUser = data.results;\n    });\n  }\n\n  onQueryParamsChange(params: NzTableQueryParams): void {\n    console.log(params);\n    const { pageSize, pageIndex, sort, filter } = params;\n    const currentSort = sort.find(item => item.value !== null);\n    const sortField = (currentSort && currentSort.key) || null;\n    const sortOrder = (currentSort && currentSort.value) || null;\n    this.loadDataFromServer(pageIndex, pageSize, sortField, sortOrder, filter);\n  }\n\n  constructor(private http: HttpClient) {}\n\n  ngOnInit(): void {\n    this.loadDataFromServer(this.pageIndex, this.pageSize, null, null, []);\n  }\n\n  getUsers(\n    pageIndex: number,\n    pageSize: number,\n    sortField: string | null,\n    sortOrder: string | null,\n    filters: Array<{ key: string; value: string[] }>\n  ): Observable<{ results: RandomUser[] }> {\n    let params = new HttpParams()\n      .append('page', `${pageIndex}`)\n      .append('results', `${pageSize}`)\n      .append('sortField', `${sortField}`)\n      .append('sortOrder', `${sortOrder}`);\n    filters.forEach(filter => {\n      filter.value.forEach(value => {\n        params = params.append(filter.key, value);\n      });\n    });\n    return this.http\n      .get<{ results: RandomUser[] }>('https://api.randomuser.me/', { params })\n      .pipe(catchError(() => of({ results: [] })));\n  }\n}\n"
  },
  {
    "path": "components/table/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  en-US: Basic Usage\n  zh-CN: 基本用法\n---\n\n## zh-CN\n\n简单的表格，最后一列是各种操作。\n\n## en-US\n\nSimple table with actions.\n"
  },
  {
    "path": "components/table/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\nimport { NzTableModule } from 'ng-zorro-antd/table';\n\ninterface Person {\n  key: string;\n  name: string;\n  age: number;\n  address: string;\n}\n\n@Component({\n  selector: 'nz-demo-table-basic',\n  imports: [NzDividerModule, NzTableModule],\n  template: `\n    <nz-table #basicTable [nzData]=\"listOfData\">\n      <thead>\n        <tr>\n          <th>Name</th>\n          <th>Age</th>\n          <th>Address</th>\n          <th>Action</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of basicTable.data; track data) {\n          <tr>\n            <td>{{ data.name }}</td>\n            <td>{{ data.age }}</td>\n            <td>{{ data.address }}</td>\n            <td>\n              <a>Action 一 {{ data.name }}</a>\n              <nz-divider nzType=\"vertical\" />\n              <a>Delete</a>\n            </td>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n  `\n})\nexport class NzDemoTableBasicComponent {\n  listOfData: Person[] = [\n    {\n      key: '1',\n      name: 'John Brown',\n      age: 32,\n      address: 'New York No. 1 Lake Park'\n    },\n    {\n      key: '2',\n      name: 'Jim Green',\n      age: 42,\n      address: 'London No. 1 Lake Park'\n    },\n    {\n      key: '3',\n      name: 'Joe Black',\n      age: 32,\n      address: 'Sidney No. 1 Lake Park'\n    }\n  ];\n}\n"
  },
  {
    "path": "components/table/demo/bordered.md",
    "content": "---\norder: 11\ntitle:\n  en-US: border, title and footer\n  zh-CN: 带边框\n---\n\n## zh-CN\n\n添加表格边框线，页头和页脚。\n\n## en-US\n\nAdd border, title and footer for table.\n"
  },
  {
    "path": "components/table/demo/bordered.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTableModule } from 'ng-zorro-antd/table';\n\n@Component({\n  selector: 'nz-demo-table-bordered',\n  imports: [NzTableModule],\n  template: `\n    <nz-table #borderedTable nzBordered nzFooter=\"Footer\" nzTitle=\"Header\" [nzData]=\"dataSet\">\n      <thead>\n        <tr>\n          <th>Name</th>\n          <th>Age</th>\n          <th>Address</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of borderedTable.data; track data) {\n          <tr>\n            <td>{{ data.name }}</td>\n            <td>{{ data.age }}</td>\n            <td>{{ data.address }}</td>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n\n    <nz-table #outBordered nzOuterBordered nzFooter=\"Footer\" nzTitle=\"Header\" [nzData]=\"dataSet\">\n      <thead>\n        <tr>\n          <th>Name</th>\n          <th>Age</th>\n          <th>Address</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of outBordered.data; track data) {\n          <tr>\n            <td>{{ data.name }}</td>\n            <td>{{ data.age }}</td>\n            <td>{{ data.address }}</td>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n  `\n})\nexport class NzDemoTableBorderedComponent {\n  dataSet = [\n    {\n      name: 'John Brown',\n      age: 32,\n      address: 'New York No. 1 Lake Park'\n    },\n    {\n      name: 'Jim Green',\n      age: 42,\n      address: 'London No. 1 Lake Park'\n    },\n    {\n      name: 'Joe Black',\n      age: 32,\n      address: 'Sidney No. 1 Lake Park'\n    }\n  ];\n}\n"
  },
  {
    "path": "components/table/demo/break-word.md",
    "content": "---\norder: 26\ntitle:\n  en-US: Break Word\n  zh-CN: 折行显示\n---\n\n## zh-CN\n\n当有连续超长字符串时，可以使用 `nzBreakWord` 来折行显示\n\n## en-US\n\nInsert line breaks within words with `nzBreakWord` to prevent text from overflowing its content box\n"
  },
  {
    "path": "components/table/demo/break-word.ts",
    "content": "import { Component, OnInit } from '@angular/core';\n\nimport { NzTableModule } from 'ng-zorro-antd/table';\n\n@Component({\n  selector: 'nz-demo-table-break-word',\n  imports: [NzTableModule],\n  template: `\n    <nz-table #fixedTable [nzData]=\"listOfData\" [nzScroll]=\"{ x: '1000px', y: '240px' }\">\n      <thead>\n        <tr>\n          <th nzLeft>Full Name</th>\n          <th nzLeft>Age</th>\n          <th>Column 1</th>\n          <th>Column 2</th>\n          <th>Column 3</th>\n          <th>Column 4</th>\n          <th>Column 5</th>\n          <th>Column 6</th>\n          <th>Column 7</th>\n          <th>Column 8</th>\n          <th nzRight>Action</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of fixedTable.data; track data) {\n          <tr>\n            <td nzLeft>{{ data.name }}</td>\n            <td nzLeft>{{ data.age }}</td>\n            <td nzBreakWord>{{ data.address }}</td>\n            <td nzBreakWord>{{ data.address }}</td>\n            <td nzBreakWord>{{ data.address }}</td>\n            <td nzBreakWord>{{ data.address }}</td>\n            <td nzBreakWord>{{ data.address }}</td>\n            <td nzBreakWord>{{ data.address }}</td>\n            <td nzBreakWord>{{ data.address }}</td>\n            <td nzBreakWord>{{ data.address }}</td>\n            <td nzRight>\n              <a>action</a>\n            </td>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n  `\n})\nexport class NzDemoTableBreakWordComponent implements OnInit {\n  listOfData: Array<{ name: string; age: number; address: string }> = [];\n\n  ngOnInit(): void {\n    for (let i = 0; i < 100; i++) {\n      this.listOfData.push({\n        name: `Edward King`,\n        age: 32,\n        address: `LondonLondonLondonLondonLondon`\n      });\n    }\n  }\n}\n"
  },
  {
    "path": "components/table/demo/colspan-rowspan.md",
    "content": "---\norder: 15\ntitle:\n  en-US: colSpan and rowSpan\n  zh-CN: 表格行/列合并\n---\n\n## zh-CN\n\n像 [`W3C标准 <table>`](https://www.w3.org/TR/html401/struct/tables.html) 一样，使用 `colspan` 和 `rowspan` 合并行/列。\n\n## en-US\n\nUse `colspan` and `rowspan` like [`W3C standards <table>`](https://www.w3.org/TR/html401/struct/tables.html)\n"
  },
  {
    "path": "components/table/demo/colspan-rowspan.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTableModule } from 'ng-zorro-antd/table';\n\n@Component({\n  selector: 'nz-demo-table-colspan-rowspan',\n  imports: [NzTableModule],\n  template: `\n    <nz-table #colSpanTable [nzData]=\"listOfData\" nzBordered>\n      <thead>\n        <tr>\n          <th>Name</th>\n          <th>Age</th>\n          <th colspan=\"2\">Home phone</th>\n          <th>Address</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of colSpanTable.data; track data) {\n          <tr>\n            <td>{{ data.name }}</td>\n            @switch ($index) {\n              @case (2) {\n                <td>{{ data.age }}</td>\n                <td rowspan=\"2\">{{ data.tel }}</td>\n                <td>{{ data.phone }}</td>\n                <td>{{ data.address }}</td>\n              }\n              @case (3) {\n                <td>{{ data.age }}</td>\n                <td>{{ data.phone }}</td>\n                <td>{{ data.address }}</td>\n              }\n              @case (4) {\n                <td colspan=\"5\">{{ data.age }}</td>\n              }\n              @default {\n                <td>{{ data.age }}</td>\n                <td>{{ data.tel }}</td>\n                <td>{{ data.phone }}</td>\n                <td>{{ data.address }}</td>\n              }\n            }\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n  `\n})\nexport class NzDemoTableColspanRowspanComponent {\n  listOfData = [\n    {\n      key: '1',\n      name: 'John Brown',\n      age: 32,\n      tel: '0571-22098909',\n      phone: 18889898989,\n      address: 'New York No. 1 Lake Park'\n    },\n    {\n      key: '2',\n      name: 'Jim Green',\n      tel: '0571-22098333',\n      phone: 18889898888,\n      age: 42,\n      address: 'London No. 1 Lake Park'\n    },\n    {\n      key: '3',\n      name: 'Joe Black',\n      age: 32,\n      tel: '0575-22098909',\n      phone: 18900010002,\n      address: 'Sidney No. 1 Lake Park'\n    },\n    {\n      key: '4',\n      name: 'Jim Red',\n      age: 18,\n      tel: '0575-22098909',\n      phone: 18900010002,\n      address: 'London No. 2 Lake Park'\n    },\n    {\n      key: '5',\n      name: 'Jake White',\n      age: 18,\n      tel: '0575-22098909',\n      phone: 18900010002,\n      address: 'Dublin No. 2 Lake Park'\n    }\n  ];\n}\n"
  },
  {
    "path": "components/table/demo/custom-column.md",
    "content": "---\norder: 31\ntitle:\n  en-US: Custom Column\n  zh-CN: 自定义列\n---\n\n## zh-CN\n\n控制表格中列的展示与排序\n\n## en-US\n\nControl the display and ordering of columns in a table.\n"
  },
  {
    "path": "components/table/demo/custom-column.ts",
    "content": "import { CdkDrag, CdkDragDrop, CdkDropList, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';\nimport { ChangeDetectorRef, Component, OnInit } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\nimport { NzGridModule } from 'ng-zorro-antd/grid';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzModalModule } from 'ng-zorro-antd/modal';\nimport { NzCustomColumn, NzTableModule } from 'ng-zorro-antd/table';\n\ninterface Person {\n  key: string;\n  name: string;\n  gender: 'male' | 'female';\n  age: number;\n  address: string;\n}\n\ninterface CustomColumn extends NzCustomColumn {\n  name: string;\n  required?: boolean;\n  position?: 'left' | 'right';\n}\n\n@Component({\n  selector: 'nz-demo-table-custom-column',\n  imports: [\n    NzButtonModule,\n    NzDividerModule,\n    NzGridModule,\n    NzIconModule,\n    NzModalModule,\n    NzTableModule,\n    CdkDrag,\n    CdkDropList\n  ],\n  template: `\n    <button nz-button nzType=\"primary\" nzSize=\"small\" (click)=\"showModal()\" style=\"margin-bottom: 8px;\">\n      <nz-icon nzType=\"setting\" nzTheme=\"outline\" />\n    </button>\n    <nz-table #basicTable [nzData]=\"listOfData\" [nzCustomColumn]=\"customColumn\">\n      <thead>\n        <tr>\n          <th nzCellControl=\"name\">Name</th>\n          <th nzCellControl=\"gender\">Gender</th>\n          <th nzCellControl=\"age\">Age</th>\n          <th nzCellControl=\"address\">Address</th>\n          <th nzCellControl=\"action\">Action</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of basicTable.data; track data) {\n          <tr>\n            <td nzCellControl=\"name\">{{ data.name }}</td>\n            <td nzCellControl=\"gender\">{{ data.gender }}</td>\n            <td nzCellControl=\"age\">{{ data.age }}</td>\n            <td nzCellControl=\"address\">{{ data.address }}</td>\n            <td nzCellControl=\"action\">\n              <a>Action</a>\n              <nz-divider nzType=\"vertical\" />\n              <a>Delete</a>\n            </td>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n\n    <nz-modal [(nzVisible)]=\"isVisible\" nzTitle=\"Custom Column\" (nzOnCancel)=\"handleCancel()\" (nzOnOk)=\"handleOk()\">\n      <ng-container *nzModalContent>\n        <div nz-row [nzGutter]=\"24\">\n          <div nz-col class=\"gutter-row\" [nzSpan]=\"12\">\n            <div class=\"example-container\">\n              <p>Displayed (drag and drop to sort)</p>\n              @for (item of title; track item) {\n                <div class=\"example-box\">\n                  {{ item.name }}\n                </div>\n              }\n              <div\n                cdkDropList\n                #todoList=\"cdkDropList\"\n                [cdkDropListData]=\"fix\"\n                [cdkDropListConnectedTo]=\"[doneList]\"\n                class=\"example-list\"\n                (cdkDropListDropped)=\"drop($event)\"\n              >\n                @for (item of fix; track item) {\n                  <div class=\"example-box\" cdkDrag>\n                    {{ item.name }}\n                    <nz-icon nzType=\"minus-circle\" nzTheme=\"outline\" (click)=\"deleteCustom(item, $index)\" />\n                  </div>\n                }\n              </div>\n              @for (item of footer; track item) {\n                <div class=\"example-box\">\n                  {{ item.name }}\n                </div>\n              }\n            </div>\n          </div>\n          <div nz-col class=\"gutter-row\" [nzSpan]=\"12\">\n            <div class=\"example-container\">\n              <p>Not Shown</p>\n              <div\n                cdkDropList\n                #doneList=\"cdkDropList\"\n                [cdkDropListData]=\"notFix\"\n                [cdkDropListConnectedTo]=\"[todoList]\"\n                class=\"example-list\"\n                (cdkDropListDropped)=\"drop($event)\"\n              >\n                @for (item of notFix; track item) {\n                  <div class=\"example-box\" cdkDrag>\n                    {{ item.name }}\n                    <nz-icon nzType=\"plus-circle\" nzTheme=\"outline\" (click)=\"addCustom(item, $index)\" />\n                  </div>\n                }\n              </div>\n            </div>\n          </div>\n        </div>\n      </ng-container>\n    </nz-modal>\n  `,\n  styles: `\n    .example-container {\n      height: 350px;\n      display: flex;\n      flex-direction: column;\n    }\n\n    .example-list {\n      min-height: 60px;\n      border-radius: 4px;\n      overflow-x: hidden;\n      overflow-y: auto;\n      display: block;\n      border: 1px dashed #ccc;\n      flex: 1 1 auto;\n    }\n\n    .example-list > .example-box {\n      cursor: move;\n    }\n\n    .cdk-drag-preview {\n      box-sizing: border-box;\n      border-radius: 4px;\n      box-shadow:\n        0 5px 5px -3px rgba(0, 0, 0, 0.2),\n        0 8px 10px 1px rgba(0, 0, 0, 0.14),\n        0 3px 14px 2px rgba(0, 0, 0, 0.12);\n    }\n\n    .cdk-drag-placeholder {\n      opacity: 0;\n    }\n\n    .cdk-drag-animating {\n      transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);\n    }\n\n    .example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) {\n      transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);\n    }\n\n    .example-box {\n      display: flex;\n      flex-direction: row;\n      justify-content: space-between;\n      align-items: center;\n      box-sizing: border-box;\n      margin: 4px;\n      padding: 4px 8px;\n      background-color: rgb(0 112 204 / 15%);\n    }\n\n    .example-box span {\n      cursor: pointer;\n    }\n  `\n})\nexport class NzDemoTableCustomColumnComponent implements OnInit {\n  listOfData: Person[] = [\n    {\n      key: '1',\n      name: 'John Brown',\n      gender: 'female',\n      age: 32,\n      address: 'New York No. 1 Lake Park'\n    },\n    {\n      key: '2',\n      name: 'Jim Green',\n      gender: 'female',\n      age: 42,\n      address: 'London No. 1 Lake Park'\n    },\n    {\n      key: '3',\n      name: 'Joe Black',\n      gender: 'male',\n      age: 32,\n      address: 'Sidney No. 1 Lake Park'\n    }\n  ];\n\n  customColumn: CustomColumn[] = [\n    {\n      name: 'Name',\n      value: 'name',\n      default: true,\n      required: true,\n      position: 'left',\n      width: 200,\n      fixWidth: true\n    },\n    {\n      name: 'Gender',\n      value: 'gender',\n      default: true,\n      width: 200\n    },\n    {\n      name: 'Address',\n      value: 'address',\n      default: true,\n      width: 200\n    },\n    {\n      name: 'Age',\n      value: 'age',\n      default: true,\n      width: 200\n    },\n    {\n      name: 'Action',\n      value: 'action',\n      default: true,\n      required: true,\n      position: 'right',\n      width: 200\n    }\n  ];\n\n  isVisible: boolean = false;\n  title: CustomColumn[] = [];\n  footer: CustomColumn[] = [];\n  fix: CustomColumn[] = [];\n  notFix: CustomColumn[] = [];\n\n  constructor(private cdr: ChangeDetectorRef) {}\n\n  ngOnInit(): void {\n    this.title = this.customColumn.filter(item => item.position === 'left' && item.required);\n    this.footer = this.customColumn.filter(item => item.position === 'right' && item.required);\n    this.fix = this.customColumn.filter(item => item.default && !item.required);\n    this.notFix = this.customColumn.filter(item => !item.default && !item.required);\n  }\n\n  drop(event: CdkDragDrop<CustomColumn[]>): void {\n    if (event.previousContainer === event.container) {\n      moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);\n    } else {\n      transferArrayItem(event.previousContainer.data, event.container.data, event.previousIndex, event.currentIndex);\n    }\n    this.fix = this.fix.map(item => {\n      item.default = true;\n      return item;\n    });\n    this.notFix = this.notFix.map(item => {\n      item.default = false;\n      return item;\n    });\n    this.cdr.markForCheck();\n  }\n\n  deleteCustom(value: CustomColumn, index: number): void {\n    value.default = false;\n    this.notFix = [...this.notFix, value];\n    this.fix.splice(index, 1);\n    this.cdr.markForCheck();\n  }\n\n  addCustom(value: CustomColumn, index: number): void {\n    value.default = true;\n    this.fix = [...this.fix, value];\n    this.notFix.splice(index, 1);\n    this.cdr.markForCheck();\n  }\n\n  showModal(): void {\n    this.isVisible = true;\n  }\n\n  handleOk(): void {\n    this.customColumn = [...this.title, ...this.fix, ...this.notFix, ...this.footer];\n    this.isVisible = false;\n    this.cdr.markForCheck();\n  }\n\n  handleCancel(): void {\n    this.isVisible = false;\n  }\n}\n"
  },
  {
    "path": "components/table/demo/custom-filter-panel.md",
    "content": "---\norder: 8\ntitle:\n  en-US: Customized filter panel\n  zh-CN: 自定义筛选菜单\n---\n\n## zh-CN\n\n通过 `<nz-filter-trigger>` 组件定义自定义的列筛选功能，并实现一个搜索列的示例。\n\n## en-US\n\nImplement a customized column search example via `<nz-filter-trigger>`.\n"
  },
  {
    "path": "components/table/demo/custom-filter-panel.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzDropdownModule } from 'ng-zorro-antd/dropdown';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzTableModule } from 'ng-zorro-antd/table';\n\ninterface DataItem {\n  name: string;\n  age: number;\n  address: string;\n}\n@Component({\n  selector: 'nz-demo-table-custom-filter-panel',\n  imports: [FormsModule, NzButtonModule, NzDropdownModule, NzIconModule, NzInputModule, NzTableModule],\n  template: `\n    <nz-table #nzTable [nzData]=\"listOfDisplayData\" nzTableLayout=\"fixed\">\n      <thead>\n        <tr>\n          <th nzCustomFilter>\n            Name\n            <nz-filter-trigger [(nzVisible)]=\"visible\" [nzActive]=\"searchValue.length > 0\" [nzDropdownMenu]=\"menu\">\n              <nz-icon nzType=\"search\" />\n            </nz-filter-trigger>\n          </th>\n          <th>Age</th>\n          <th>Address</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of nzTable.data; track data) {\n          <tr>\n            <td>{{ data.name }}</td>\n            <td>{{ data.age }}</td>\n            <td>{{ data.address }}</td>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n    <nz-dropdown-menu #menu=\"nzDropdownMenu\">\n      <div class=\"ant-table-filter-dropdown\">\n        <div class=\"search-box\">\n          <input type=\"text\" nz-input placeholder=\"Search name\" [(ngModel)]=\"searchValue\" />\n          <button nz-button nzSize=\"small\" nzType=\"primary\" (click)=\"search()\" class=\"search-button\">Search</button>\n          <button nz-button nzSize=\"small\" (click)=\"reset()\">Reset</button>\n        </div>\n      </div>\n    </nz-dropdown-menu>\n  `,\n  styles: `\n    .search-box {\n      padding: 8px;\n    }\n\n    .search-box input {\n      width: 188px;\n      margin-bottom: 8px;\n      display: block;\n    }\n\n    .search-box button {\n      width: 90px;\n    }\n\n    .search-button {\n      margin-right: 8px;\n    }\n  `\n})\nexport class NzDemoTableCustomFilterPanelComponent {\n  searchValue = '';\n  visible = false;\n  listOfData: DataItem[] = [\n    {\n      name: 'John Brown',\n      age: 32,\n      address: 'New York No. 1 Lake Park'\n    },\n    {\n      name: 'Jim Green',\n      age: 42,\n      address: 'London No. 1 Lake Park'\n    },\n    {\n      name: 'Joe Black',\n      age: 32,\n      address: 'Sidney No. 1 Lake Park'\n    },\n    {\n      name: 'Jim Red',\n      age: 32,\n      address: 'London No. 2 Lake Park'\n    }\n  ];\n  listOfDisplayData = [...this.listOfData];\n\n  reset(): void {\n    this.searchValue = '';\n    this.search();\n  }\n\n  search(): void {\n    this.visible = false;\n    this.listOfDisplayData = this.listOfData.filter((item: DataItem) => item.name.indexOf(this.searchValue) !== -1);\n  }\n}\n"
  },
  {
    "path": "components/table/demo/drag-sorting.md",
    "content": "---\norder: 25\ntitle:\n  en-US: Drag sorting\n  zh-CN: 拖拽排序\n---\n\n## zh-CN\n\n使用自定义元素，用户可以导入 [@angular/cdk/drag-drop](https://material.angular.io/cdk/drag-drop/overview) 来实现拖拽排序。\n\n> 注意：需要手动导入 `import { DragDropModule } from '@angular/cdk/drag-drop'`;\n\n## en-US\n\nBy using custom components, we can integrate table with [@angular/cdk/drag-drop](https://material.angular.io/cdk/drag-drop/overview) to implement drag sorting.\n\n> Note: Need to `import { DragDropModule } from '@angular/cdk/drag-drop'`;\n"
  },
  {
    "path": "components/table/demo/drag-sorting.ts",
    "content": "import { CdkDrag, CdkDragDrop, CdkDropList, moveItemInArray } from '@angular/cdk/drag-drop';\nimport { Component } from '@angular/core';\n\nimport { NzTableModule } from 'ng-zorro-antd/table';\n\n@Component({\n  selector: 'nz-demo-table-drag-sorting',\n  imports: [CdkDropList, CdkDrag, NzTableModule],\n  template: `\n    <nz-table [nzData]=\"listOfData\" [nzFrontPagination]=\"false\" [nzShowPagination]=\"false\">\n      <thead>\n        <tr>\n          <th>Name</th>\n          <th>Age</th>\n          <th>Address</th>\n        </tr>\n      </thead>\n      <tbody cdkDropList (cdkDropListDropped)=\"drop($event)\">\n        @for (data of listOfData; track data) {\n          <tr cdkDrag>\n            <td>{{ data.name }}</td>\n            <td>{{ data.age }}</td>\n            <td>{{ data.address }}</td>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n  `,\n  styles: `\n    ::ng-deep .cdk-drag-preview {\n      display: table;\n    }\n\n    ::ng-deep .cdk-drag-placeholder {\n      opacity: 0;\n    }\n  `\n})\nexport class NzDemoTableDragSortingComponent {\n  listOfData = [\n    {\n      key: '1',\n      name: 'John Brown',\n      age: 32,\n      address: 'New York No. 1 Lake Park'\n    },\n    {\n      key: '2',\n      name: 'Jim Green',\n      age: 42,\n      address: 'London No. 1 Lake Park'\n    },\n    {\n      key: '3',\n      name: 'Joe Black',\n      age: 32,\n      address: 'Sidney No. 1 Lake Park'\n    }\n  ];\n\n  drop(event: CdkDragDrop<string[]>): void {\n    moveItemInArray(this.listOfData, event.previousIndex, event.currentIndex);\n  }\n}\n"
  },
  {
    "path": "components/table/demo/dynamic-settings.md",
    "content": "---\norder: 30\ntitle:\n  en-US: Dynamic Settings\n  zh-CN: 动态控制表格属性\n---\n\n## zh-CN\n\n选择不同配置组合查看效果。\n\n## en-US\n\nSelect different settings to see the result.\n"
  },
  {
    "path": "components/table/demo/dynamic-settings.ts",
    "content": "import { Component, OnInit } from '@angular/core';\nimport { FormControl, FormGroup, NonNullableFormBuilder, ReactiveFormsModule } from '@angular/forms';\n\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\nimport {\n  NzTableLayout,\n  NzTableModule,\n  NzTablePaginationPosition,\n  NzTablePaginationType,\n  NzTableSize\n} from 'ng-zorro-antd/table';\n\ninterface ItemData {\n  name: string;\n  age: number | string;\n  address: string;\n  checked: boolean;\n  expand: boolean;\n  description: string;\n  disabled?: boolean;\n}\n\ntype TableScroll = 'unset' | 'scroll' | 'fixed';\n\ninterface Setting {\n  bordered: boolean;\n  loading: boolean;\n  pagination: boolean;\n  sizeChanger: boolean;\n  title: boolean;\n  header: boolean;\n  footer: boolean;\n  expandable: boolean;\n  checkbox: boolean;\n  fixHeader: boolean;\n  noResult: boolean;\n  ellipsis: boolean;\n  simple: boolean;\n  size: NzTableSize;\n  tableScroll: TableScroll;\n  tableLayout: NzTableLayout;\n  position: NzTablePaginationPosition;\n  paginationType: NzTablePaginationType;\n}\n\n@Component({\n  selector: 'nz-demo-table-dynamic-settings',\n  imports: [ReactiveFormsModule, NzDividerModule, NzFormModule, NzRadioModule, NzSwitchModule, NzTableModule],\n  template: `\n    <div class=\"components-table-demo-control-bar\">\n      <form nz-form nzLayout=\"inline\" [formGroup]=\"settingForm\">\n        @for (item of listOfSwitch; track item) {\n          <nz-form-item>\n            <nz-form-label>{{ item.name }}</nz-form-label>\n            <nz-form-control>\n              <nz-switch [formControlName]=\"item.formControlName\" />\n            </nz-form-control>\n          </nz-form-item>\n        }\n        @for (radio of listOfRadio; track radio) {\n          <nz-form-item>\n            <nz-form-label>{{ radio.name }}</nz-form-label>\n            <nz-form-control>\n              <nz-radio-group [formControlName]=\"radio.formControlName\">\n                @for (o of radio.listOfOption; track o) {\n                  <label nz-radio-button [nzValue]=\"o.value\">{{ o.label }}</label>\n                }\n              </nz-radio-group>\n            </nz-form-control>\n          </nz-form-item>\n        }\n      </form>\n    </div>\n    <nz-table\n      #dynamicTable\n      [nzScroll]=\"{ x: scrollX, y: scrollY }\"\n      [nzData]=\"listOfData\"\n      [nzTableLayout]=\"settingValue.tableLayout\"\n      [nzBordered]=\"settingValue.bordered\"\n      [nzSimple]=\"settingValue.simple\"\n      [nzLoading]=\"settingValue.loading\"\n      [nzPaginationType]=\"settingValue.paginationType\"\n      [nzPaginationPosition]=\"settingValue.position\"\n      [nzShowSizeChanger]=\"settingValue.sizeChanger\"\n      [nzFrontPagination]=\"settingValue.pagination\"\n      [nzShowPagination]=\"settingValue.pagination\"\n      [nzFooter]=\"settingValue.footer ? 'Here is Footer' : null\"\n      [nzTitle]=\"settingValue.title ? 'Here is Title' : null\"\n      [nzSize]=\"settingValue.size\"\n      (nzCurrentPageDataChange)=\"currentPageDataChange($event)\"\n    >\n      <thead>\n        @if (settingValue.header) {\n          <tr>\n            @if (settingValue.expandable) {\n              <th nzWidth=\"40px\" [nzLeft]=\"fixedColumn\"></th>\n            }\n            @if (settingValue.checkbox) {\n              <th\n                nzWidth=\"60px\"\n                [(nzChecked)]=\"allChecked\"\n                [nzLeft]=\"fixedColumn\"\n                [nzIndeterminate]=\"indeterminate\"\n                (nzCheckedChange)=\"checkAll($event)\"\n              ></th>\n            }\n            <th [nzLeft]=\"fixedColumn\">Name</th>\n            <th>Age</th>\n            <th>Address</th>\n            <th [nzRight]=\"fixedColumn\">Action</th>\n          </tr>\n        }\n      </thead>\n      <tbody>\n        @for (data of dynamicTable.data; track data) {\n          <tr>\n            @if (settingValue.expandable) {\n              <td [nzLeft]=\"fixedColumn\" [(nzExpand)]=\"data.expand\"></td>\n            }\n            @if (settingValue.checkbox) {\n              <td [nzLeft]=\"fixedColumn\" [(nzChecked)]=\"data.checked\" (nzCheckedChange)=\"refreshStatus()\"></td>\n            }\n            <td [nzLeft]=\"fixedColumn\">{{ data.name }}</td>\n            <td>{{ data.age }}</td>\n            <td [nzEllipsis]=\"settingValue.ellipsis\">{{ data.address }}</td>\n            <td [nzRight]=\"fixedColumn\" [nzEllipsis]=\"settingValue.ellipsis\">\n              <a href=\"#\">Delete</a>\n              <nz-divider nzType=\"vertical\" />\n              <a href=\"#\">More action</a>\n            </td>\n          </tr>\n          @if (settingValue.expandable) {\n            <tr [nzExpand]=\"data.expand\">\n              <span>{{ data.description }}</span>\n            </tr>\n          }\n        }\n      </tbody>\n    </nz-table>\n  `,\n  styles: `\n    form nz-form-item {\n      margin-right: 16px;\n      margin-bottom: 8px;\n    }\n  `\n})\nexport class NzDemoTableDynamicSettingsComponent implements OnInit {\n  settingForm: FormGroup<{ [K in keyof Setting]: FormControl<Setting[K]> }>;\n  listOfData: readonly ItemData[] = [];\n  displayData: readonly ItemData[] = [];\n  allChecked = false;\n  indeterminate = false;\n  fixedColumn = false;\n  scrollX: string | null = null;\n  scrollY: string | null = null;\n  settingValue: Setting;\n  listOfSwitch = [\n    { name: 'Bordered', formControlName: 'bordered' },\n    { name: 'Loading', formControlName: 'loading' },\n    { name: 'Pagination', formControlName: 'pagination' },\n    { name: 'PageSizeChanger', formControlName: 'sizeChanger' },\n    { name: 'Title', formControlName: 'title' },\n    { name: 'Column Header', formControlName: 'header' },\n    { name: 'Footer', formControlName: 'footer' },\n    { name: 'Expandable', formControlName: 'expandable' },\n    { name: 'Checkbox', formControlName: 'checkbox' },\n    { name: 'Fixed Header', formControlName: 'fixHeader' },\n    { name: 'No Result', formControlName: 'noResult' },\n    { name: 'Ellipsis', formControlName: 'ellipsis' },\n    { name: 'Simple Pagination', formControlName: 'simple' }\n  ];\n  listOfRadio = [\n    {\n      name: 'Size',\n      formControlName: 'size',\n      listOfOption: [\n        { value: 'default', label: 'Default' },\n        { value: 'middle', label: 'Middle' },\n        { value: 'small', label: 'Small' }\n      ]\n    },\n    {\n      name: 'Table Scroll',\n      formControlName: 'tableScroll',\n      listOfOption: [\n        { value: 'unset', label: 'Unset' },\n        { value: 'scroll', label: 'Scroll' },\n        { value: 'fixed', label: 'Fixed' }\n      ]\n    },\n    {\n      name: 'Table Layout',\n      formControlName: 'tableLayout',\n      listOfOption: [\n        { value: 'auto', label: 'Auto' },\n        { value: 'fixed', label: 'Fixed' }\n      ]\n    },\n    {\n      name: 'Pagination Position',\n      formControlName: 'position',\n      listOfOption: [\n        { value: 'top', label: 'Top' },\n        { value: 'bottom', label: 'Bottom' },\n        { value: 'both', label: 'Both' }\n      ]\n    },\n    {\n      name: 'Pagination Type',\n      formControlName: 'paginationType',\n      listOfOption: [\n        { value: 'default', label: 'Default' },\n        { value: 'small', label: 'Small' }\n      ]\n    }\n  ];\n\n  currentPageDataChange($event: readonly ItemData[]): void {\n    this.displayData = $event;\n    this.refreshStatus();\n  }\n\n  refreshStatus(): void {\n    const validData = this.displayData.filter(value => !value.disabled);\n    const allChecked = validData.length > 0 && validData.every(value => value.checked);\n    const allUnChecked = validData.every(value => !value.checked);\n    this.allChecked = allChecked;\n    this.indeterminate = !allChecked && !allUnChecked;\n  }\n\n  checkAll(value: boolean): void {\n    this.displayData.forEach(data => {\n      if (!data.disabled) {\n        data.checked = value;\n      }\n    });\n    this.refreshStatus();\n  }\n\n  generateData(): readonly ItemData[] {\n    const data: ItemData[] = [];\n    for (let i = 1; i <= 100; i++) {\n      data.push({\n        name: 'John Brown',\n        age: `${i}2`,\n        address: `New York No. ${i} Lake Park`,\n        description: `My name is John Brown, I am ${i}2 years old, living in New York No. ${i} Lake Park.`,\n        checked: false,\n        expand: false\n      });\n    }\n    return data;\n  }\n\n  constructor(private formBuilder: NonNullableFormBuilder) {\n    this.settingForm = this.formBuilder.group({\n      bordered: [false],\n      loading: [false],\n      pagination: [true],\n      sizeChanger: [false],\n      title: [true],\n      header: [true],\n      footer: [true],\n      expandable: [true],\n      checkbox: [true],\n      fixHeader: [false],\n      noResult: [false],\n      ellipsis: [false],\n      simple: [false],\n      size: 'small' as NzTableSize,\n      paginationType: 'default' as NzTablePaginationType,\n      tableScroll: 'unset' as TableScroll,\n      tableLayout: 'auto' as NzTableLayout,\n      position: 'bottom' as NzTablePaginationPosition\n    });\n\n    this.settingValue = this.settingForm.value as Setting;\n  }\n\n  ngOnInit(): void {\n    this.settingForm.valueChanges.subscribe(value => {\n      this.settingValue = value as Setting;\n    });\n    this.settingForm.controls.tableScroll.valueChanges.subscribe(scroll => {\n      this.fixedColumn = scroll === 'fixed';\n      this.scrollX = scroll === 'scroll' || scroll === 'fixed' ? '100vw' : null;\n    });\n    this.settingForm.controls.fixHeader.valueChanges.subscribe(fixed => {\n      this.scrollY = fixed ? '240px' : null;\n    });\n    this.settingForm.controls.noResult.valueChanges.subscribe(empty => {\n      if (empty) {\n        this.listOfData = [];\n      } else {\n        this.listOfData = this.generateData();\n      }\n    });\n    this.listOfData = this.generateData();\n  }\n}\n"
  },
  {
    "path": "components/table/demo/edit-cell.md",
    "content": "---\norder: 22\ntitle:\n  en-US: Editable Cells\n  zh-CN: 可编辑单元格\n---\n\n## zh-CN\n\n定制带单元格编辑功能的表格，自由操作单元格内容。\n\n> 为了获得更好的性能，NG-ZORRO 所有组件都运行在 [OnPush](https://angular.cn/guide/components/advanced-configuration#changedetectionstrategy) 模式下，这意味着对 `@Input()` 数据的 mutate 将不会生效，请使用 immutable 方式操作数组或者对象。\n\n> 开发者可以参照该例子根据自己需求自由定制表格的编辑功能。\n\n## en-US\n\nTable with editable cells.\n\n> In order to get better performance, all NG-ZORRO's components are running under [OnPush](https://angular.dev/guide/components/advanced-configuration#changedetectionstrategy) mode, this means any mutate to the `@Input()` data won't trigger change detection, please use immutable way to update array or object.\n\n> User can refer to this example to customize the way of editing forms.\n"
  },
  {
    "path": "components/table/demo/edit-cell.ts",
    "content": "import { Component, OnInit } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm';\nimport { NzTableModule } from 'ng-zorro-antd/table';\n\ninterface ItemData {\n  id: string;\n  name: string;\n  age: string;\n  address: string;\n}\n\n@Component({\n  selector: 'nz-demo-table-edit-cell',\n  imports: [FormsModule, NzButtonModule, NzInputModule, NzPopconfirmModule, NzTableModule],\n  template: `\n    <button nz-button (click)=\"addRow()\" nzType=\"primary\">Add</button>\n    <br />\n    <br />\n    <nz-table #editRowTable nzBordered [nzData]=\"listOfData\">\n      <thead>\n        <tr>\n          <th nzWidth=\"30%\">Name</th>\n          <th>Age</th>\n          <th>Address</th>\n          <th>Action</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of editRowTable.data; track data) {\n          <tr class=\"editable-row\">\n            <td>\n              <div class=\"editable-cell\" [hidden]=\"editId === data.id\" (click)=\"startEdit(data.id)\">\n                {{ data.name }}\n              </div>\n              <input [hidden]=\"editId !== data.id\" type=\"text\" nz-input [(ngModel)]=\"data.name\" (blur)=\"stopEdit()\" />\n            </td>\n            <td>{{ data.age }}</td>\n            <td>{{ data.address }}</td>\n            <td>\n              <a nz-popconfirm nzPopconfirmTitle=\"Sure to delete?\" (nzOnConfirm)=\"deleteRow(data.id)\">Delete</a>\n            </td>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n  `,\n  styles: `\n    .editable-cell {\n      position: relative;\n      padding: 5px 12px;\n      cursor: pointer;\n    }\n\n    .editable-row:hover .editable-cell {\n      border: 1px solid #d9d9d9;\n      border-radius: 4px;\n      padding: 4px 11px;\n    }\n  `\n})\nexport class NzDemoTableEditCellComponent implements OnInit {\n  i = 0;\n  editId: string | null = null;\n  listOfData: ItemData[] = [];\n\n  startEdit(id: string): void {\n    this.editId = id;\n  }\n\n  stopEdit(): void {\n    this.editId = null;\n  }\n\n  addRow(): void {\n    this.listOfData = [\n      ...this.listOfData,\n      {\n        id: `${this.i}`,\n        name: `Edward King ${this.i}`,\n        age: '32',\n        address: `London, Park Lane no. ${this.i}`\n      }\n    ];\n    this.i++;\n  }\n\n  deleteRow(id: string): void {\n    this.listOfData = this.listOfData.filter(d => d.id !== id);\n  }\n\n  ngOnInit(): void {\n    this.addRow();\n    this.addRow();\n  }\n}\n"
  },
  {
    "path": "components/table/demo/edit-row.md",
    "content": "---\norder: 23\ntitle:\n  en-US: Editable Rows\n  zh-CN: 可编辑行\n---\n\n## zh-CN\n\n定制带行编辑功能的表格，自由操作行内容。\n\n> 为了获得更好的性能，NG-ZORRO 所有组件都运行在 [OnPush](https://angular.cn/guide/components/advanced-configuration#changedetectionstrategy) 模式下，这意味着对 `@Input()` 数据的 mutate 将不会生效，请使用 immutable 方式操作数组或者对象。\n\n> 开发者可以参照该例子根据自己需求自由定制表格的编辑功能。\n\n## en-US\n\nTable with editable rows.\n\n> In order to get better performance, all NG-ZORRO's components are running under [OnPush](https://angular.dev/guide/components/advanced-configuration#changedetectionstrategy) mode, this means any mutate to the `@Input()` data won't trigger change detection, please use immutable way to update array or object.\n\n> User can refer to this example to customize the way of editing forms.\n"
  },
  {
    "path": "components/table/demo/edit-row.ts",
    "content": "import { Component, OnInit } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm';\nimport { NzTableModule } from 'ng-zorro-antd/table';\n\ninterface ItemData {\n  id: string;\n  name: string;\n  age: number;\n  address: string;\n}\n\n@Component({\n  selector: 'nz-demo-table-edit-row',\n  imports: [FormsModule, NzInputModule, NzPopconfirmModule, NzTableModule],\n  template: `\n    <nz-table #editRowTable nzBordered [nzData]=\"listOfData\" nzTableLayout=\"fixed\">\n      <thead>\n        <tr>\n          <th nzWidth=\"25%\">Name</th>\n          <th nzWidth=\"15%\">Age</th>\n          <th nzWidth=\"40%\">Address</th>\n          <th>Action</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of editRowTable.data; track data) {\n          <tr>\n            @if (!editCache[data.id].edit) {\n              <td>{{ data.name }}</td>\n              <td>{{ data.age }}</td>\n              <td>{{ data.address }}</td>\n              <td><a (click)=\"startEdit(data.id)\">Edit</a></td>\n            } @else {\n              <td><input type=\"text\" nz-input [(ngModel)]=\"editCache[data.id].data.name\" /></td>\n              <td><input type=\"text\" nz-input [(ngModel)]=\"editCache[data.id].data.age\" /></td>\n              <td><input type=\"text\" nz-input [(ngModel)]=\"editCache[data.id].data.address\" /></td>\n              <td>\n                <a (click)=\"saveEdit(data.id)\" class=\"save\">Save</a>\n                <a nz-popconfirm nzPopconfirmTitle=\"Sure to cancel?\" (nzOnConfirm)=\"cancelEdit(data.id)\">Cancel</a>\n              </td>\n            }\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n  `,\n  styles: `\n    .save {\n      margin-right: 8px;\n    }\n  `\n})\nexport class NzDemoTableEditRowComponent implements OnInit {\n  editCache: { [key: string]: { edit: boolean; data: ItemData } } = {};\n  listOfData: ItemData[] = [];\n\n  startEdit(id: string): void {\n    this.editCache[id].edit = true;\n  }\n\n  cancelEdit(id: string): void {\n    const index = this.listOfData.findIndex(item => item.id === id);\n    this.editCache[id] = {\n      data: { ...this.listOfData[index] },\n      edit: false\n    };\n  }\n\n  saveEdit(id: string): void {\n    const index = this.listOfData.findIndex(item => item.id === id);\n    Object.assign(this.listOfData[index], this.editCache[id].data);\n    this.editCache[id].edit = false;\n  }\n\n  updateEditCache(): void {\n    this.listOfData.forEach(item => {\n      this.editCache[item.id] = {\n        edit: false,\n        data: { ...item }\n      };\n    });\n  }\n\n  ngOnInit(): void {\n    const data: ItemData[] = [];\n    for (let i = 0; i < 100; i++) {\n      data.push({\n        id: `${i}`,\n        name: `Edward ${i}`,\n        age: 32,\n        address: `London Park no. ${i}`\n      });\n    }\n    this.listOfData = data;\n    this.updateEditCache();\n  }\n}\n"
  },
  {
    "path": "components/table/demo/ellipsis.md",
    "content": "---\norder: 27\ntitle:\n  en-US: ellipsis column\n  zh-CN: 单元格自动省略\n---\n\n## zh-CN\n\n设置 `nzTableLayout=\"fixed\"` 与 `nzEllipsis` 可以让单元格内容根据宽度自动省略。\n\n> 列头缩略暂不支持和排序筛选一起使用。\n\n## en-US\n\nEllipsis cell content via setting `nzEllipsis` and `nzTableLayout=\"fixed\"`.\n\n> can not working with sorter and filters for now\n"
  },
  {
    "path": "components/table/demo/ellipsis.ts",
    "content": "import { Component, OnInit } from '@angular/core';\n\nimport { NzTableModule } from 'ng-zorro-antd/table';\n\n@Component({\n  selector: 'nz-demo-table-ellipsis',\n  imports: [NzTableModule],\n  template: `\n    <nz-table #fixedTable [nzData]=\"listOfData\" nzTableLayout=\"fixed\">\n      <thead>\n        <tr>\n          <th>Full Name</th>\n          <th>Age</th>\n          <th>Column 1</th>\n          <th>Column 2</th>\n          <th nzEllipsis>Column ColumnColumn 3</th>\n          <th>Column 4</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of fixedTable.data; track data) {\n          <tr>\n            <td>{{ data.name }}</td>\n            <td>{{ data.age }}</td>\n            <td nzEllipsis>{{ data.address }}</td>\n            <td nzEllipsis>{{ data.address }}</td>\n            <td nzEllipsis>{{ data.address }}</td>\n            <td nzEllipsis>{{ data.address }}</td>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n  `\n})\nexport class NzDemoTableEllipsisComponent implements OnInit {\n  listOfData: Array<{ name: string; age: number; address: string }> = [];\n\n  ngOnInit(): void {\n    for (let i = 0; i < 3; i++) {\n      this.listOfData.push({\n        name: `Edward King`,\n        age: 32,\n        address: `LondonLondonLondonLondonLondon`\n      });\n    }\n  }\n}\n"
  },
  {
    "path": "components/table/demo/expand-children.md",
    "content": "---\norder: 16\ntitle:\n  en-US: Tree data\n  zh-CN: 树形数据展示\n---\n\n## zh-CN\n\n表格支持树形数据的展示，可以通过设置 `nzIndentSize` 以控制每一层的缩进宽度，本例子中提供了树与数组之间的转换函数，实际业务中请根据需求修改。\n\n## en-US\n\nDisplay tree structure data in Table, control the indent width by setting `nzIndentSize`.\n"
  },
  {
    "path": "components/table/demo/expand-children.ts",
    "content": "import { Component, OnInit } from '@angular/core';\n\nimport { NzTableModule } from 'ng-zorro-antd/table';\n\nexport interface TreeNodeInterface {\n  key: string;\n  name: string;\n  age?: number;\n  level?: number;\n  expand?: boolean;\n  address?: string;\n  children?: TreeNodeInterface[];\n  parent?: TreeNodeInterface;\n}\n\n@Component({\n  selector: 'nz-demo-table-expand-children',\n  imports: [NzTableModule],\n  template: `\n    <nz-table #expandTable [nzData]=\"listOfMapData\" nzTableLayout=\"fixed\">\n      <thead>\n        <tr>\n          <th>Name</th>\n          <th>Age</th>\n          <th>Address</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of expandTable.data; track data) {\n          @for (item of mapOfExpandedData[data.key]; track item) {\n            @if ((item.parent && item.parent.expand) || !item.parent) {\n              <tr>\n                <td\n                  [nzIndentSize]=\"item.level! * 20\"\n                  [nzShowExpand]=\"!!item.children\"\n                  [(nzExpand)]=\"item.expand\"\n                  (nzExpandChange)=\"collapse(mapOfExpandedData[data.key], item, $event)\"\n                >\n                  {{ item.name }}\n                </td>\n                <td>{{ item.age }}</td>\n                <td>{{ item.address }}</td>\n              </tr>\n            }\n          }\n        }\n      </tbody>\n    </nz-table>\n  `\n})\nexport class NzDemoTableExpandChildrenComponent implements OnInit {\n  listOfMapData: TreeNodeInterface[] = [\n    {\n      key: `1`,\n      name: 'John Brown sr.',\n      age: 60,\n      address: 'New York No. 1 Lake Park',\n      children: [\n        {\n          key: `1-1`,\n          name: 'John Brown',\n          age: 42,\n          address: 'New York No. 2 Lake Park'\n        },\n        {\n          key: `1-2`,\n          name: 'John Brown jr.',\n          age: 30,\n          address: 'New York No. 3 Lake Park',\n          children: [\n            {\n              key: `1-2-1`,\n              name: 'Jimmy Brown',\n              age: 16,\n              address: 'New York No. 3 Lake Park'\n            }\n          ]\n        },\n        {\n          key: `1-3`,\n          name: 'Jim Green sr.',\n          age: 72,\n          address: 'London No. 1 Lake Park',\n          children: [\n            {\n              key: `1-3-1`,\n              name: 'Jim Green',\n              age: 42,\n              address: 'London No. 2 Lake Park',\n              children: [\n                {\n                  key: `1-3-1-1`,\n                  name: 'Jim Green jr.',\n                  age: 25,\n                  address: 'London No. 3 Lake Park'\n                },\n                {\n                  key: `1-3-1-2`,\n                  name: 'Jimmy Green sr.',\n                  age: 18,\n                  address: 'London No. 4 Lake Park'\n                }\n              ]\n            }\n          ]\n        }\n      ]\n    },\n    {\n      key: `2`,\n      name: 'Joe Black',\n      age: 32,\n      address: 'Sidney No. 1 Lake Park'\n    }\n  ];\n  mapOfExpandedData: { [key: string]: TreeNodeInterface[] } = {};\n\n  collapse(array: TreeNodeInterface[], data: TreeNodeInterface, $event: boolean): void {\n    if (!$event) {\n      if (data.children) {\n        data.children.forEach(d => {\n          const target = array.find(a => a.key === d.key)!;\n          target.expand = false;\n          this.collapse(array, target, false);\n        });\n      } else {\n        return;\n      }\n    }\n  }\n\n  convertTreeToList(root: TreeNodeInterface): TreeNodeInterface[] {\n    const stack: TreeNodeInterface[] = [];\n    const array: TreeNodeInterface[] = [];\n    const hashMap = {};\n    stack.push({ ...root, level: 0, expand: false });\n\n    while (stack.length !== 0) {\n      const node = stack.pop()!;\n      this.visitNode(node, hashMap, array);\n      if (node.children) {\n        for (let i = node.children.length - 1; i >= 0; i--) {\n          stack.push({ ...node.children[i], level: node.level! + 1, expand: false, parent: node });\n        }\n      }\n    }\n\n    return array;\n  }\n\n  visitNode(node: TreeNodeInterface, hashMap: { [key: string]: boolean }, array: TreeNodeInterface[]): void {\n    if (!hashMap[node.key]) {\n      hashMap[node.key] = true;\n      array.push(node);\n    }\n  }\n\n  ngOnInit(): void {\n    this.listOfMapData.forEach(item => {\n      this.mapOfExpandedData[item.key] = this.convertTreeToList(item);\n    });\n  }\n}\n"
  },
  {
    "path": "components/table/demo/expand-icon.md",
    "content": "---\norder: 14\ntitle:\n  en-US: Customize the expansion icon\n  zh-CN: 自定义展开 icon\n---\n\n## zh-CN\n\n当使用 `nzExpand` 属性时，添加 `nzExpandIcon` 自定义展开图标。\n\n## en-US\n\nWhen using the `nzExpand` prop, add the `nzExpandIcon` custom expand icon.\n"
  },
  {
    "path": "components/table/demo/expand-icon.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzTableModule } from 'ng-zorro-antd/table';\n\n@Component({\n  selector: 'nz-demo-table-expand-icon',\n  imports: [NzIconModule, NzTableModule],\n  template: `\n    <nz-table #nzTable [nzData]=\"listOfData\" nzTableLayout=\"fixed\">\n      <thead>\n        <tr>\n          <th nzWidth=\"60px\"></th>\n          <th>Name</th>\n          <th>Age</th>\n          <th>Address</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of nzTable.data; track data) {\n          <tr>\n            <td [nzExpand]=\"expandSet.has(data.id)\" [nzExpandIcon]=\"expandIcon\"></td>\n            <td>{{ data.name }}</td>\n            <td>{{ data.age }}</td>\n            <td>{{ data.address }}</td>\n          </tr>\n          <tr [nzExpand]=\"expandSet.has(data.id)\">\n            <span>{{ data.description }}</span>\n          </tr>\n          <ng-template #expandIcon>\n            @if (!expandSet.has(data.id)) {\n              <nz-icon nzType=\"plus-circle\" nzTheme=\"outline\" (click)=\"onExpandChange(data.id, true)\" />\n            } @else {\n              <nz-icon nzType=\"minus-circle\" nzTheme=\"outline\" (click)=\"onExpandChange(data.id, false)\" />\n            }\n          </ng-template>\n        }\n      </tbody>\n    </nz-table>\n  `\n})\nexport class NzDemoTableExpandIconComponent {\n  expandSet = new Set<number>();\n  onExpandChange(id: number, checked: boolean): void {\n    if (checked) {\n      this.expandSet.add(id);\n    } else {\n      this.expandSet.delete(id);\n    }\n  }\n  listOfData = [\n    {\n      id: 1,\n      name: 'John Brown',\n      age: 32,\n      expand: false,\n      address: 'New York No. 1 Lake Park',\n      description: 'My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park.'\n    },\n    {\n      id: 2,\n      name: 'Jim Green',\n      age: 42,\n      expand: false,\n      address: 'London No. 1 Lake Park',\n      description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.'\n    },\n    {\n      id: 3,\n      name: 'Joe Black',\n      age: 32,\n      expand: false,\n      address: 'Sidney No. 1 Lake Park',\n      description: 'My name is Joe Black, I am 32 years old, living in Sidney No. 1 Lake Park.'\n    }\n  ];\n}\n"
  },
  {
    "path": "components/table/demo/expand.md",
    "content": "---\norder: 13\ntitle:\n  en-US: Expandable Row\n  zh-CN: 可展开\n---\n\n## zh-CN\n\n当表格内容较多不能一次性完全展示时，可以通过 `td` 上的 `nzExpand` 属性展开。\n\n## en-US\n\nWhen there's too much information to show and the table can't display all at once.\n"
  },
  {
    "path": "components/table/demo/expand.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTableModule } from 'ng-zorro-antd/table';\n\n@Component({\n  selector: 'nz-demo-table-expand',\n  imports: [NzTableModule],\n  template: `\n    <nz-table #nzTable [nzData]=\"listOfData\" nzTableLayout=\"fixed\">\n      <thead>\n        <tr>\n          <th nzWidth=\"60px\"></th>\n          <th>Name</th>\n          <th>Age</th>\n          <th>Address</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of nzTable.data; track data) {\n          <tr>\n            <td [nzExpand]=\"expandSet.has(data.id)\" (nzExpandChange)=\"onExpandChange(data.id, $event)\"></td>\n            <td>{{ data.name }}</td>\n            <td>{{ data.age }}</td>\n            <td>{{ data.address }}</td>\n          </tr>\n          <tr [nzExpand]=\"expandSet.has(data.id)\">\n            <span>{{ data.description }}</span>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n  `\n})\nexport class NzDemoTableExpandComponent {\n  expandSet = new Set<number>();\n  onExpandChange(id: number, checked: boolean): void {\n    if (checked) {\n      this.expandSet.add(id);\n    } else {\n      this.expandSet.delete(id);\n    }\n  }\n  listOfData = [\n    {\n      id: 1,\n      name: 'John Brown',\n      age: 32,\n      expand: false,\n      address: 'New York No. 1 Lake Park',\n      description: 'My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park.'\n    },\n    {\n      id: 2,\n      name: 'Jim Green',\n      age: 42,\n      expand: false,\n      address: 'London No. 1 Lake Park',\n      description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.'\n    },\n    {\n      id: 3,\n      name: 'Joe Black',\n      age: 32,\n      expand: false,\n      address: 'Sidney No. 1 Lake Park',\n      description: 'My name is Joe Black, I am 32 years old, living in Sidney No. 1 Lake Park.'\n    }\n  ];\n}\n"
  },
  {
    "path": "components/table/demo/fixed-columns-header.md",
    "content": "---\norder: 19\ntitle:\n  en-US: Fixed Columns and Header\n  zh-CN: 固定头和列\n---\n\n## zh-CN\n\n同时固定头和列，适合同时展示有大量数据和数据列。\n\n> 列头与内容不对齐或出现列重复，请指定固定列的宽度 `[nzWidth]`。如果指定 width 不生效或出现白色垂直空隙，请尝试建议留一列不设宽度以适应弹性布局，或者检查是否有超长连续字段破坏布局。\n> 建议指定 `nzScroll.x` 为大于表格宽度的固定值或百分比。注意，且非固定列宽度之和不要超过 `nzScroll.x`。\n> 注意：固定列通过 sticky 实现，IE 11 会降级成横向滚动。\n\n## en-US\n\nFixed header and column at the same time, a solution for displaying large amounts of data with long columns.\n\n> Specify the `[nzWidth]` of columns if header and cell do not align properly. If specified width is not working or have gutter between columns, please try to leave one column at least without width to fit fluid layout, or make sure no long word to break table layout.\n> A fixed value which is greater than table width for `nzScroll.x` is recommended. The sum of unfixed columns should not greater than `nzScroll.x`.\n> Note: We using sticky to implement fixed effect. IE 11 will downgrade to horizontal scroll.\n"
  },
  {
    "path": "components/table/demo/fixed-columns-header.ts",
    "content": "import { Component, OnInit } from '@angular/core';\n\nimport { NzTableModule } from 'ng-zorro-antd/table';\n\ninterface ItemData {\n  name: string;\n  age: number;\n  address: string;\n}\n\n@Component({\n  selector: 'nz-demo-table-fixed-columns-header',\n  imports: [NzTableModule],\n  template: `\n    <nz-table #fixedTable [nzData]=\"listOfData\" [nzScroll]=\"{ x: '1150px', y: '240px' }\">\n      <thead>\n        <tr>\n          <th nzLeft>Full Name</th>\n          <th nzLeft>Age</th>\n          <th>Column 1</th>\n          <th>Column 2</th>\n          <th>Column 3</th>\n          <th>Column 4</th>\n          <th>Column 5</th>\n          <th>Column 6</th>\n          <th>Column 7</th>\n          <th>Column 8</th>\n          <th nzRight>Action</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of fixedTable.data; track data) {\n          <tr>\n            <td nzLeft>{{ data.name }}</td>\n            <td nzLeft>{{ data.age }}</td>\n            <td>{{ data.address }}</td>\n            <td>{{ data.address }}</td>\n            <td>{{ data.address }}</td>\n            <td>{{ data.address }}</td>\n            <td>{{ data.address }}</td>\n            <td>{{ data.address }}</td>\n            <td>{{ data.address }}</td>\n            <td>{{ data.address }}</td>\n            <td nzRight>\n              <a>action</a>\n            </td>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n  `\n})\nexport class NzDemoTableFixedColumnsHeaderComponent implements OnInit {\n  listOfData: ItemData[] = [];\n\n  ngOnInit(): void {\n    for (let i = 0; i < 100; i++) {\n      this.listOfData.push({\n        name: `Edward King ${i}`,\n        age: 32,\n        address: `London`\n      });\n    }\n  }\n}\n"
  },
  {
    "path": "components/table/demo/fixed-columns.md",
    "content": "---\norder: 18\ntitle:\n  en-US: Fixed Columns\n  zh-CN: 固定列\n---\n\n## zh-CN\n\n对于列数很多的数据，可以使用 `[nzLeft]` 和 `[nzRight]` 固定前后的列，横向滚动查看其它数据，需要和 `[nzScroll].x` 配合使用。\n\n> 列头与内容不对齐或出现列重复，请指定固定列的宽度 `[nzWidth]`。如果指定 width 不生效或出现白色垂直空隙，请尝试建议留一列不设宽度以适应弹性布局，或者检查是否有超长连续字段破坏布局。\n> 建议指定 `nzScroll.x` 为大于表格宽度的固定值或百分比。注意，且非固定列宽度之和不要超过 `nzScroll.x`。\n> 注意：固定列通过 sticky 实现，IE 11 会降级成横向滚动。\n\n## en-US\n\nTo fix some columns and scroll inside other columns, and you must set `[nzScroll].x`, `[nzLeft]` and `[nzRight]` meanwhile.\n\n> Specify the `[nzWidth]` of columns if header and cell do not align properly. If specified width is not working or have gutter between columns, please try to leave one column at least without width to fit fluid layout, or make sure no long word to break table layout.\n> A fixed value which is greater than table width for `nzScroll.x` is recommended. The sum of unfixed columns should not greater than `nzScroll.x`.\n> Note: We using sticky to implement fixed effect. IE 11 will downgrade to horizontal scroll.\n"
  },
  {
    "path": "components/table/demo/fixed-columns.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTableModule } from 'ng-zorro-antd/table';\n\n@Component({\n  selector: 'nz-demo-table-fixed-columns',\n  imports: [NzTableModule],\n  template: `\n    <nz-table #columnTable [nzData]=\"listOfData\" [nzScroll]=\"{ x: '1100px' }\">\n      <thead>\n        <tr>\n          <th nzLeft>Full Name</th>\n          <th nzLeft>Age</th>\n          <th>Column 1</th>\n          <th>Column 2</th>\n          <th>Column 3</th>\n          <th>Column 4</th>\n          <th>Column 5</th>\n          <th>Column 6</th>\n          <th>Column 7</th>\n          <th nzRight>Column 8</th>\n          <th nzRight>Action</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of columnTable.data; track data) {\n          <tr>\n            <td nzLeft>{{ data.name }}</td>\n            <td nzLeft>{{ data.age }}</td>\n            <td>{{ data.address }}</td>\n            <td>{{ data.address }}</td>\n            <td>{{ data.address }}</td>\n            <td>{{ data.address }}</td>\n            <td>{{ data.address }}</td>\n            <td>{{ data.address }}</td>\n            <td>{{ data.address }}</td>\n            <td nzRight>{{ data.address }}</td>\n            <td nzRight>\n              <a>action</a>\n            </td>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n  `\n})\nexport class NzDemoTableFixedColumnsComponent {\n  listOfData = [\n    {\n      key: '1',\n      name: 'John Brown',\n      age: 32,\n      address: 'New York'\n    },\n    {\n      key: '2',\n      name: 'Jim Green',\n      age: 40,\n      address: 'London'\n    }\n  ];\n}\n"
  },
  {
    "path": "components/table/demo/fixed-header.md",
    "content": "---\norder: 17\ntitle:\n  en-US: Fixed Header\n  zh-CN: 固定表头\n---\n\n## zh-CN\n\n指定 `[nzScroll]` 的 `y` 数值 方便一页内展示大量数据，每一列的宽度可以由 `[nzWidth]` 指定。\n\n## en-US\n\nDisplay large amounts of data in scrollable view via set `y` of `[nzScroll]`, you can specify column width via `[nzWidth]`.\n"
  },
  {
    "path": "components/table/demo/fixed-header.ts",
    "content": "import { Component, OnInit } from '@angular/core';\n\nimport { NzTableModule } from 'ng-zorro-antd/table';\n\ninterface ItemData {\n  name: string;\n  age: number;\n  address: string;\n}\n\n@Component({\n  selector: 'nz-demo-table-fixed-header',\n  imports: [NzTableModule],\n  template: `\n    <nz-table #headerTable [nzData]=\"listOfData\" [nzPageSize]=\"50\" [nzScroll]=\"{ y: '240px' }\">\n      <thead>\n        <tr>\n          <th>Name</th>\n          <th nzWidth=\"100px\">Age</th>\n          <th>Address</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of headerTable.data; track data) {\n          <tr>\n            <td>{{ data.name }}</td>\n            <td>{{ data.age }}</td>\n            <td>{{ data.address }}</td>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n  `\n})\nexport class NzDemoTableFixedHeaderComponent implements OnInit {\n  listOfData: ItemData[] = [];\n\n  ngOnInit(): void {\n    const data: ItemData[] = [];\n    for (let i = 0; i < 100; i++) {\n      data.push({\n        name: `Edward King ${i}`,\n        age: 32,\n        address: `London, Park Lane no. ${i}`\n      });\n    }\n    this.listOfData = data;\n  }\n}\n"
  },
  {
    "path": "components/table/demo/grouping-columns.md",
    "content": "---\norder: 21\ntitle:\n  en-US: Grouping table head\n  zh-CN: 表头分组\n---\n\n## zh-CN\n\n固定列与分组表头联合使用。\n\n## en-US\n\nGroup table head with fixed columns.\n"
  },
  {
    "path": "components/table/demo/grouping-columns.ts",
    "content": "import { Component, OnInit } from '@angular/core';\n\nimport { NzTableModule } from 'ng-zorro-antd/table';\n\ninterface ItemData {\n  name: string;\n  age: number;\n  street: string;\n  building: string;\n  number: number;\n  companyAddress: string;\n  companyName: string;\n  gender: string;\n}\n\n@Component({\n  selector: 'nz-demo-table-grouping-columns',\n  imports: [NzTableModule],\n  template: `\n    <nz-table #groupingTable [nzData]=\"listOfData\" nzBordered nzSize=\"middle\" [nzScroll]=\"{ x: '1200px', y: '240px' }\">\n      <thead>\n        <tr>\n          <th rowspan=\"4\" nzLeft [nzFilters]=\"filterName\" [nzFilterFn]=\"nameFilterFn\">Name</th>\n          <th colspan=\"4\">Other</th>\n          <th colspan=\"2\">Company</th>\n          <th rowspan=\"4\" nzRight>Gender</th>\n        </tr>\n        <tr>\n          <th rowspan=\"3\" [nzSortFn]=\"sortAgeFn\">Age</th>\n          <th colspan=\"3\">Address</th>\n          <th rowspan=\"3\">Company Address</th>\n          <th rowspan=\"3\">Company Name</th>\n        </tr>\n        <tr>\n          <th rowspan=\"2\">Street</th>\n          <th colspan=\"2\">Block</th>\n        </tr>\n        <tr>\n          <th>Building</th>\n          <th>Door No.</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of groupingTable.data; track data) {\n          <tr>\n            <td nzLeft>{{ data.name }}</td>\n            <td>{{ data.age }}</td>\n            <td>{{ data.street }}</td>\n            <td>{{ data.building }}</td>\n            <td>{{ data.number }}</td>\n            <td>{{ data.companyAddress }}</td>\n            <td>{{ data.companyName }}</td>\n            <td nzRight>{{ data.gender }}</td>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n  `\n})\nexport class NzDemoTableGroupingColumnsComponent implements OnInit {\n  listOfData: ItemData[] = [];\n  sortAgeFn = (a: ItemData, b: ItemData): number => a.age - b.age;\n  nameFilterFn = (list: string[], item: ItemData): boolean => list.some(name => item.name.indexOf(name) !== -1);\n  filterName = [\n    { text: 'Joe', value: 'Joe' },\n    { text: 'John', value: 'John' }\n  ];\n\n  ngOnInit(): void {\n    const data: ItemData[] = [];\n    for (let i = 0; i < 100; i++) {\n      data.push({\n        name: 'John Brown',\n        age: i + 1,\n        street: 'Lake Park',\n        building: 'C',\n        number: 2035,\n        companyAddress: 'Lake Street 42',\n        companyName: 'SoftLake Co',\n        gender: 'M'\n      });\n    }\n    this.listOfData = data;\n  }\n}\n"
  },
  {
    "path": "components/table/demo/multiple-sorter.md",
    "content": "---\norder: 7\ntitle:\n  en-US: Multiple sorter\n  zh-CN: 多列排序\n---\n\n## zh-CN\n\n使用 `[nzSortPriority]` 字段以配置多列排序优先级。通过 `[nzSortFn]` 配置排序逻辑。\n\n## en-US\n\nUse `[nzSortPriority]` to config the priority of sort columns. Though `[nzSortFn]` to customize compare function.\n"
  },
  {
    "path": "components/table/demo/multiple-sorter.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTableModule } from 'ng-zorro-antd/table';\n\ninterface ItemData {\n  name: string;\n  chinese: number;\n  math: number;\n  english: number;\n}\n\n@Component({\n  selector: 'nz-demo-table-multiple-sorter',\n  imports: [NzTableModule],\n  template: `\n    <nz-table #sortTable [nzData]=\"listOfData\" nzTableLayout=\"fixed\">\n      <thead>\n        <tr>\n          @for (column of listOfColumn; track column) {\n            <th [nzSortFn]=\"column.compare\" [nzSortPriority]=\"column.priority\">\n              {{ column.title }}\n            </th>\n          }\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of sortTable.data; track data) {\n          <tr>\n            <td>{{ data.name }}</td>\n            <td>{{ data.chinese }}</td>\n            <td>{{ data.math }}</td>\n            <td>{{ data.english }}</td>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n  `\n})\nexport class NzDemoTableMultipleSorterComponent {\n  listOfColumn = [\n    {\n      title: 'Name',\n      compare: (a: ItemData, b: ItemData) => a.name.localeCompare(b.name),\n      priority: false\n    },\n    {\n      title: 'Chinese Score',\n      compare: (a: ItemData, b: ItemData) => a.chinese - b.chinese,\n      priority: 3\n    },\n    {\n      title: 'Math Score',\n      compare: (a: ItemData, b: ItemData) => a.math - b.math,\n      priority: 2\n    },\n    {\n      title: 'English Score',\n      compare: (a: ItemData, b: ItemData) => a.english - b.english,\n      priority: 1\n    }\n  ];\n  listOfData: ItemData[] = [\n    {\n      name: 'John Brown',\n      chinese: 98,\n      math: 60,\n      english: 70\n    },\n    {\n      name: 'Jim Green',\n      chinese: 98,\n      math: 66,\n      english: 89\n    },\n    {\n      name: 'Joe Black',\n      chinese: 98,\n      math: 90,\n      english: 70\n    },\n    {\n      name: 'Jim Red',\n      chinese: 88,\n      math: 99,\n      english: 89\n    }\n  ];\n}\n"
  },
  {
    "path": "components/table/demo/nested-table.md",
    "content": "---\norder: 24\ntitle:\n  en-US: Nested tables\n  zh-CN: 嵌套子表格\n---\n\n## zh-CN\n\n展示每行数据更详细的信息。\n\n## en-US\n\nShowing more detailed info of every row.\n"
  },
  {
    "path": "components/table/demo/nested-table.ts",
    "content": "import { Component, OnInit } from '@angular/core';\n\nimport { NzBadgeModule } from 'ng-zorro-antd/badge';\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\nimport { NzDropdownModule } from 'ng-zorro-antd/dropdown';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzTableModule } from 'ng-zorro-antd/table';\n\ninterface ParentItemData {\n  key: number;\n  name: string;\n  platform: string;\n  version: string;\n  upgradeNum: number | string;\n  creator: string;\n  createdAt: string;\n  expand: boolean;\n}\n\ninterface ChildrenItemData {\n  key: number;\n  name: string;\n  date: string;\n  upgradeNum: string;\n}\n\n@Component({\n  selector: 'nz-demo-table-nested-table',\n  imports: [NzBadgeModule, NzDividerModule, NzDropdownModule, NzIconModule, NzTableModule],\n  template: `\n    <nz-table #nestedTable [nzData]=\"listOfParentData\" [nzPageSize]=\"10\">\n      <thead>\n        <tr>\n          <th></th>\n          <th>Name</th>\n          <th>Platform</th>\n          <th>Version</th>\n          <th>Upgraded</th>\n          <th>Creator</th>\n          <th>Date</th>\n          <th>Action</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of nestedTable.data; track data) {\n          <tr>\n            <td [(nzExpand)]=\"data.expand\"></td>\n            <td>{{ data.name }}</td>\n            <td>{{ data.platform }}</td>\n            <td>{{ data.version }}</td>\n            <td>{{ data.upgradeNum }}</td>\n            <td>{{ data.creator }}</td>\n            <td>{{ data.createdAt }}</td>\n            <td>\n              <a>Publish</a>\n            </td>\n          </tr>\n          <tr [nzExpand]=\"data.expand\">\n            <nz-table #innerTable [nzData]=\"listOfChildrenData\" nzSize=\"middle\" [nzShowPagination]=\"false\">\n              <thead>\n                <tr>\n                  <th>Date</th>\n                  <th>Name</th>\n                  <th>Status</th>\n                  <th>Upgrade Status</th>\n                  <th>Action</th>\n                </tr>\n              </thead>\n              <tbody>\n                @for (data of innerTable.data; track data) {\n                  <tr>\n                    <td>{{ data.date }}</td>\n                    <td>{{ data.name }}</td>\n                    <td>\n                      <nz-badge nzStatus=\"success\" nzText=\"Finished\" />\n                    </td>\n                    <td>{{ data.upgradeNum }}</td>\n                    <td>\n                      <span class=\"table-operation\">\n                        <a nz-dropdown class=\"operation\" [nzDropdownMenu]=\"menu\">\n                          Pause\n                          <nz-icon nzType=\"down\" />\n                        </a>\n                        <nz-dropdown-menu #menu=\"nzDropdownMenu\">\n                          <ul nz-menu>\n                            <li nz-menu-item>\n                              <a>Action 1</a>\n                            </li>\n                            <li nz-menu-item>\n                              <a>Action 2</a>\n                            </li>\n                          </ul>\n                        </nz-dropdown-menu>\n                        <nz-divider nzType=\"vertical\" />\n                        <a class=\"operation\">Stop</a>\n                        <nz-divider nzType=\"vertical\" />\n                        <a>More</a>\n                      </span>\n                    </td>\n                  </tr>\n                }\n              </tbody>\n            </nz-table>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n  `\n})\nexport class NzDemoTableNestedTableComponent implements OnInit {\n  listOfParentData: ParentItemData[] = [];\n  listOfChildrenData: ChildrenItemData[] = [];\n\n  ngOnInit(): void {\n    for (let i = 0; i < 3; ++i) {\n      this.listOfParentData.push({\n        key: i,\n        name: 'Screen',\n        platform: 'iOS',\n        version: '10.3.4.5654',\n        upgradeNum: 500,\n        creator: 'Jack',\n        createdAt: '2014-12-24 23:12:00',\n        expand: false\n      });\n    }\n    for (let i = 0; i < 3; ++i) {\n      this.listOfChildrenData.push({\n        key: i,\n        date: '2014-12-24 23:12:00',\n        name: 'This is production name',\n        upgradeNum: 'Upgraded: 56'\n      });\n    }\n  }\n}\n"
  },
  {
    "path": "components/table/demo/reset-filter.md",
    "content": "---\norder: 7\ntitle:\n  en-US: Reset filters and sorters\n  zh-CN: 可控的筛选和排序\n---\n\n## zh-CN\n\n修改 `[nzSortOrder]` 和 `[nzFilters]` 来指定当前列的排序与筛选状态。\n\n## en-US\n\nControl sorters and filters by `[nzSortOrder]` and `[nzFilters]`.\n"
  },
  {
    "path": "components/table/demo/reset-filter.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport {\n  NzTableFilterFn,\n  NzTableFilterList,\n  NzTableModule,\n  NzTableSortFn,\n  NzTableSortOrder\n} from 'ng-zorro-antd/table';\n\ninterface ItemData {\n  name: string;\n  age: number;\n  address: string;\n}\n\ninterface ColumnItem {\n  name: string;\n  sortOrder: NzTableSortOrder | null;\n  sortFn: NzTableSortFn<ItemData> | null;\n  listOfFilter: NzTableFilterList;\n  filterFn: NzTableFilterFn<ItemData> | null;\n}\n\n@Component({\n  selector: 'nz-demo-table-reset-filter',\n  imports: [NzButtonModule, NzTableModule],\n  template: `\n    <div class=\"table-operations\">\n      <button nz-button (click)=\"sortByAge()\">Sort age</button>\n      <button nz-button (click)=\"resetFilters()\">Clear filters</button>\n      <button nz-button (click)=\"resetSortAndFilters()\">Clear filters and sorters</button>\n    </div>\n    <nz-table #filterTable [nzData]=\"listOfData\" nzTableLayout=\"fixed\">\n      <thead>\n        <tr>\n          @for (column of listOfColumns; track column.name) {\n            <th\n              [(nzSortOrder)]=\"column.sortOrder\"\n              [nzSortFn]=\"column.sortFn\"\n              [nzFilters]=\"column.listOfFilter\"\n              [nzFilterFn]=\"column.filterFn\"\n            >\n              {{ column.name }}\n            </th>\n          }\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of filterTable.data; track data) {\n          <tr>\n            <td>{{ data.name }}</td>\n            <td>{{ data.age }}</td>\n            <td>{{ data.address }}</td>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n  `,\n  styles: `\n    .table-operations {\n      margin-bottom: 16px;\n    }\n\n    .table-operations > button {\n      margin-right: 8px;\n    }\n  `\n})\nexport class NzDemoTableResetFilterComponent {\n  listOfColumns: ColumnItem[] = [\n    {\n      name: 'Name',\n      sortOrder: null,\n      sortFn: (a: ItemData, b: ItemData) => a.name.localeCompare(b.name),\n      listOfFilter: [\n        { text: 'Joe', value: 'Joe' },\n        { text: 'Jim', value: 'Jim' }\n      ],\n      filterFn: (list: string[], item: ItemData) => list.some(name => item.name.indexOf(name) !== -1)\n    },\n    {\n      name: 'Age',\n      sortOrder: null,\n      sortFn: (a: ItemData, b: ItemData) => a.age - b.age,\n      listOfFilter: [],\n      filterFn: null\n    },\n    {\n      name: 'Address',\n      sortFn: null,\n      sortOrder: null,\n      listOfFilter: [\n        { text: 'London', value: 'London' },\n        { text: 'Sidney', value: 'Sidney' }\n      ],\n      filterFn: (address: string, item: ItemData) => item.address.indexOf(address) !== -1\n    }\n  ];\n  listOfData: ItemData[] = [\n    {\n      name: 'John Brown',\n      age: 32,\n      address: 'New York No. 1 Lake Park'\n    },\n    {\n      name: 'Jim Green',\n      age: 42,\n      address: 'London No. 1 Lake Park'\n    },\n    {\n      name: 'Joe Black',\n      age: 32,\n      address: 'Sidney No. 1 Lake Park'\n    },\n    {\n      name: 'Jim Red',\n      age: 32,\n      address: 'London No. 2 Lake Park'\n    }\n  ];\n\n  sortByAge(): void {\n    this.listOfColumns.forEach(item => {\n      if (item.name === 'Age') {\n        item.sortOrder = 'descend';\n      } else {\n        item.sortOrder = null;\n      }\n    });\n  }\n\n  resetFilters(): void {\n    this.listOfColumns.forEach(item => {\n      if (item.name === 'Name') {\n        item.listOfFilter = [\n          { text: 'Joe', value: 'Joe' },\n          { text: 'Jim', value: 'Jim' }\n        ];\n      } else if (item.name === 'Address') {\n        item.listOfFilter = [\n          { text: 'London', value: 'London' },\n          { text: 'Sidney', value: 'Sidney' }\n        ];\n      }\n    });\n  }\n\n  resetSortAndFilters(): void {\n    this.listOfColumns.forEach(item => {\n      item.sortOrder = null;\n    });\n    this.resetFilters();\n  }\n}\n"
  },
  {
    "path": "components/table/demo/row-selection-and-operation.md",
    "content": "---\norder: 3\ntitle:\n  en-US: Selection and operation\n  zh-CN: 选择和操作\n---\n\n## zh-CN\n\n第一列是联动的选择框，增加 `[nzChecked]` 后，`th` 获得和 `nz-checkbox` 一样的功能，选择后进行操作，完成后清空选择，请注意：数据逻辑需要自行控制。\n\n## en-US\n\nRows can be selectable by making first column as a selectable column, to perform operations and clear selections after selecting some rows, all data strategy should be controlled by the developers.\n"
  },
  {
    "path": "components/table/demo/row-selection-and-operation.ts",
    "content": "import { Component, OnInit } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzTableModule } from 'ng-zorro-antd/table';\n\nexport interface Data {\n  id: number;\n  name: string;\n  age: number;\n  address: string;\n  disabled: boolean;\n}\n\n@Component({\n  selector: 'nz-demo-table-row-selection-and-operation',\n  imports: [NzButtonModule, NzTableModule],\n  template: `\n    <div class=\"send-request\">\n      <button\n        nz-button\n        nzType=\"primary\"\n        [disabled]=\"setOfCheckedId.size === 0\"\n        [nzLoading]=\"loading\"\n        (click)=\"sendRequest()\"\n      >\n        Send Request\n      </button>\n      <span>Selected {{ setOfCheckedId.size }} items</span>\n    </div>\n    <nz-table\n      #rowSelectionTable\n      nzShowPagination\n      nzShowSizeChanger\n      [nzData]=\"listOfData\"\n      (nzCurrentPageDataChange)=\"onCurrentPageDataChange($event)\"\n    >\n      <thead>\n        <tr>\n          <th\n            [nzChecked]=\"checked\"\n            [nzIndeterminate]=\"indeterminate\"\n            nzLabel=\"Select all\"\n            (nzCheckedChange)=\"onAllChecked($event)\"\n          ></th>\n          <th>Name</th>\n          <th>Age</th>\n          <th>Address</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of rowSelectionTable.data; track data) {\n          <tr>\n            <td\n              [nzChecked]=\"setOfCheckedId.has(data.id)\"\n              [nzDisabled]=\"data.disabled\"\n              [nzLabel]=\"data.name\"\n              (nzCheckedChange)=\"onItemChecked(data.id, $event)\"\n            ></td>\n            <td>{{ data.name }}</td>\n            <td>{{ data.age }}</td>\n            <td>{{ data.address }}</td>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n  `,\n  styles: `\n    .send-request {\n      margin-bottom: 16px;\n    }\n\n    .send-request span {\n      margin-left: 8px;\n    }\n  `\n})\nexport class NzDemoTableRowSelectionAndOperationComponent implements OnInit {\n  checked = false;\n  loading = false;\n  indeterminate = false;\n  listOfData: readonly Data[] = [];\n  listOfCurrentPageData: readonly Data[] = [];\n  setOfCheckedId = new Set<number>();\n\n  updateCheckedSet(id: number, checked: boolean): void {\n    if (checked) {\n      this.setOfCheckedId.add(id);\n    } else {\n      this.setOfCheckedId.delete(id);\n    }\n  }\n\n  onCurrentPageDataChange(listOfCurrentPageData: readonly Data[]): void {\n    this.listOfCurrentPageData = listOfCurrentPageData;\n    this.refreshCheckedStatus();\n  }\n\n  refreshCheckedStatus(): void {\n    const listOfEnabledData = this.listOfCurrentPageData.filter(({ disabled }) => !disabled);\n    this.checked = listOfEnabledData.every(({ id }) => this.setOfCheckedId.has(id));\n    this.indeterminate = listOfEnabledData.some(({ id }) => this.setOfCheckedId.has(id)) && !this.checked;\n  }\n\n  onItemChecked(id: number, checked: boolean): void {\n    this.updateCheckedSet(id, checked);\n    this.refreshCheckedStatus();\n  }\n\n  onAllChecked(checked: boolean): void {\n    this.listOfCurrentPageData\n      .filter(({ disabled }) => !disabled)\n      .forEach(({ id }) => this.updateCheckedSet(id, checked));\n    this.refreshCheckedStatus();\n  }\n\n  sendRequest(): void {\n    this.loading = true;\n    const requestData = this.listOfData.filter(data => this.setOfCheckedId.has(data.id));\n    console.log(requestData);\n    setTimeout(() => {\n      this.setOfCheckedId.clear();\n      this.refreshCheckedStatus();\n      this.loading = false;\n    }, 1000);\n  }\n\n  ngOnInit(): void {\n    this.listOfData = new Array(100).fill(0).map((_, index) => ({\n      id: index,\n      name: `Edward King ${index}`,\n      age: 32,\n      address: `London, Park Lane no. ${index}`,\n      disabled: index % 2 === 0\n    }));\n  }\n}\n"
  },
  {
    "path": "components/table/demo/row-selection-custom.md",
    "content": "---\norder: 4\ntitle:\n  en-US: Custom selection\n  zh-CN: 自定义选择项\n---\n\n## zh-CN\n\n通过 `nzSelections` 自定义选择项.\n\n## en-US\n\nUse `nzSelections` to custom selections.\n"
  },
  {
    "path": "components/table/demo/row-selection-custom.ts",
    "content": "import { Component, OnInit } from '@angular/core';\n\nimport { NzTableModule } from 'ng-zorro-antd/table';\n\ninterface ItemData {\n  id: number;\n  name: string;\n  age: number;\n  address: string;\n}\n\n@Component({\n  selector: 'nz-demo-table-row-selection-custom',\n  imports: [NzTableModule],\n  template: `\n    <nz-table\n      #rowSelectionTable\n      nzShowSizeChanger\n      [nzData]=\"listOfData\"\n      (nzCurrentPageDataChange)=\"onCurrentPageDataChange($event)\"\n    >\n      <thead>\n        <tr>\n          <th\n            [nzSelections]=\"listOfSelection\"\n            [(nzChecked)]=\"checked\"\n            [nzIndeterminate]=\"indeterminate\"\n            (nzCheckedChange)=\"onAllChecked($event)\"\n          ></th>\n          <th>Name</th>\n          <th>Age</th>\n          <th>Address</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of rowSelectionTable.data; track data) {\n          <tr>\n            <td [nzChecked]=\"setOfCheckedId.has(data.id)\" (nzCheckedChange)=\"onItemChecked(data.id, $event)\"></td>\n            <td>{{ data.name }}</td>\n            <td>{{ data.age }}</td>\n            <td>{{ data.address }}</td>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n  `\n})\nexport class NzDemoTableRowSelectionCustomComponent implements OnInit {\n  listOfSelection = [\n    {\n      text: 'Select All Row',\n      onSelect: () => {\n        this.onAllChecked(true);\n      }\n    },\n    {\n      text: 'Select Odd Row',\n      onSelect: () => {\n        this.listOfCurrentPageData.forEach((data, index) => this.updateCheckedSet(data.id, index % 2 !== 0));\n        this.refreshCheckedStatus();\n      }\n    },\n    {\n      text: 'Select Even Row',\n      onSelect: () => {\n        this.listOfCurrentPageData.forEach((data, index) => this.updateCheckedSet(data.id, index % 2 === 0));\n        this.refreshCheckedStatus();\n      }\n    }\n  ];\n  checked = false;\n  indeterminate = false;\n  listOfCurrentPageData: readonly ItemData[] = [];\n  listOfData: readonly ItemData[] = [];\n  setOfCheckedId = new Set<number>();\n\n  updateCheckedSet(id: number, checked: boolean): void {\n    if (checked) {\n      this.setOfCheckedId.add(id);\n    } else {\n      this.setOfCheckedId.delete(id);\n    }\n  }\n\n  onItemChecked(id: number, checked: boolean): void {\n    this.updateCheckedSet(id, checked);\n    this.refreshCheckedStatus();\n  }\n\n  onAllChecked(value: boolean): void {\n    this.listOfCurrentPageData.forEach(item => this.updateCheckedSet(item.id, value));\n    this.refreshCheckedStatus();\n  }\n\n  onCurrentPageDataChange($event: readonly ItemData[]): void {\n    this.listOfCurrentPageData = $event;\n    this.refreshCheckedStatus();\n  }\n\n  refreshCheckedStatus(): void {\n    this.checked = this.listOfCurrentPageData.every(item => this.setOfCheckedId.has(item.id));\n    this.indeterminate = this.listOfCurrentPageData.some(item => this.setOfCheckedId.has(item.id)) && !this.checked;\n  }\n\n  ngOnInit(): void {\n    this.listOfData = new Array(200).fill(0).map((_, index) => ({\n      id: index,\n      name: `Edward King ${index}`,\n      age: 32,\n      address: `London, Park Lane no. ${index}`\n    }));\n  }\n}\n"
  },
  {
    "path": "components/table/demo/size.md",
    "content": "---\norder: 10\ntitle:\n  en-US: size\n  zh-CN: 紧凑型\n---\n\n## zh-CN\n\n两种紧凑型的列表，小型列表只用于对话框内。\n\n## en-US\n\nTwo compacted table size: `middle` and `small`, `small` size is used in Modal only.\n"
  },
  {
    "path": "components/table/demo/size.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTableModule } from 'ng-zorro-antd/table';\n\n@Component({\n  selector: 'nz-demo-table-size',\n  imports: [NzTableModule],\n  template: `\n    <h4>Middle size table</h4>\n    <nz-table #middleTable nzSize=\"middle\" [nzData]=\"data\">\n      <thead>\n        <tr>\n          <th>Name</th>\n          <th>Age</th>\n          <th>Address</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of middleTable.data; track data) {\n          <tr>\n            <td>{{ data.name }}</td>\n            <td>{{ data.age }}</td>\n            <td>{{ data.address }}</td>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n    <h4>Small size table</h4>\n    <nz-table #smallTable nzSize=\"small\" [nzData]=\"data\">\n      <thead>\n        <tr>\n          <th>Name</th>\n          <th>Age</th>\n          <th>Address</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of smallTable.data; track data) {\n          <tr>\n            <td>{{ data.name }}</td>\n            <td>{{ data.age }}</td>\n            <td>{{ data.address }}</td>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n  `,\n  styles: `\n    h4 {\n      margin-bottom: 16px;\n    }\n  `\n})\nexport class NzDemoTableSizeComponent {\n  data = [\n    {\n      name: 'John Brown',\n      age: 32,\n      address: 'New York No. 1 Lake Park'\n    },\n    {\n      name: 'Jim Green',\n      age: 42,\n      address: 'London No. 1 Lake Park'\n    },\n    {\n      name: 'Joe Black',\n      age: 32,\n      address: 'Sidney No. 1 Lake Park'\n    }\n  ];\n}\n"
  },
  {
    "path": "components/table/demo/sort-filter.md",
    "content": "---\norder: 5\ntitle:\n  en-US: Filter and sorter\n  zh-CN: 筛选和排序\n---\n\n## zh-CN\n\n筛选：对某一列数据进行筛选，通过指定 `[nzFilters]` 属性来指定筛选菜单，`[nzFilterFn]` 指定筛选函数，`[nzFilterMultiple]` 用于指定多选和单选，通过设置 `[nzFilters]` 中的 `{ byDefault: true }` 属性来默认启用一个筛选器。\n\n排序：对某一列数据进行排序，通过指定 `[nzSortOrder]` 来指定默认排序顺序，`[nzSortFn]` 指定排序函数 `[nzSortDirections]` 改变每列可用的排序方式。\n\n## en-US\n\nFilter: Use `[nzFilters]` to define options of the filter menu, `[nzFilterFn]` to determine filtered result, and `[nzFilterMultiple]` to indicate whether it's multiple or single selection, you can enable a filter by default by setting a `[nzFilters]` object's property: `{ byDefault: true }`.\n\nSort: Use `[nzSortOrder]` to make a column sorted by default, use `[nzSortFn]` to determine sort result, and `[nzSortDirections]` to define available sort methods.\n"
  },
  {
    "path": "components/table/demo/sort-filter.ts",
    "content": "import { Component } from '@angular/core';\n\nimport {\n  NzTableFilterFn,\n  NzTableFilterList,\n  NzTableModule,\n  NzTableSortFn,\n  NzTableSortOrder\n} from 'ng-zorro-antd/table';\n\ninterface ItemData {\n  name: string;\n  age: number;\n  address: string;\n}\n\ninterface ColumnItem {\n  name: string;\n  sortOrder: NzTableSortOrder | null;\n  sortFn: NzTableSortFn<ItemData> | null;\n  listOfFilter: NzTableFilterList;\n  filterFn: NzTableFilterFn<ItemData> | null;\n  filterMultiple: boolean;\n  sortDirections: NzTableSortOrder[];\n}\n\n@Component({\n  selector: 'nz-demo-table-sort-filter',\n  imports: [NzTableModule],\n  template: `\n    <nz-table #filterTable [nzData]=\"listOfData\" nzTableLayout=\"fixed\">\n      <thead>\n        <tr>\n          @for (column of listOfColumns; track column) {\n            <th\n              [nzSortOrder]=\"column.sortOrder\"\n              [nzSortFn]=\"column.sortFn\"\n              [nzSortDirections]=\"column.sortDirections\"\n              [nzFilterMultiple]=\"column.filterMultiple\"\n              [nzFilters]=\"column.listOfFilter\"\n              [nzFilterFn]=\"column.filterFn\"\n            >\n              {{ column.name }}\n            </th>\n          }\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of filterTable.data; track data) {\n          <tr>\n            <td>{{ data.name }}</td>\n            <td>{{ data.age }}</td>\n            <td>{{ data.address }}</td>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n  `\n})\nexport class NzDemoTableSortFilterComponent {\n  listOfColumns: ColumnItem[] = [\n    {\n      name: 'Name',\n      sortOrder: null,\n      sortFn: (a: ItemData, b: ItemData) => a.name.localeCompare(b.name),\n      sortDirections: ['ascend', 'descend', null],\n      filterMultiple: true,\n      listOfFilter: [\n        { text: 'Joe', value: 'Joe' },\n        { text: 'Jim', value: 'Jim', byDefault: true }\n      ],\n      filterFn: (list: string[], item: ItemData) => list.some(name => item.name.indexOf(name) !== -1)\n    },\n    {\n      name: 'Age',\n      sortOrder: 'descend',\n      sortFn: (a: ItemData, b: ItemData) => a.age - b.age,\n      sortDirections: ['descend', null],\n      listOfFilter: [],\n      filterFn: null,\n      filterMultiple: true\n    },\n    {\n      name: 'Address',\n      sortOrder: null,\n      sortDirections: ['ascend', 'descend', null],\n      sortFn: (a: ItemData, b: ItemData) => a.address.length - b.address.length,\n      filterMultiple: false,\n      listOfFilter: [\n        { text: 'London', value: 'London' },\n        { text: 'Sidney', value: 'Sidney' }\n      ],\n      filterFn: (address: string, item: ItemData) => item.address.indexOf(address) !== -1\n    }\n  ];\n  listOfData: ItemData[] = [\n    {\n      name: 'John Brown',\n      age: 32,\n      address: 'New York No. 1 Lake Park'\n    },\n    {\n      name: 'Jim Green',\n      age: 42,\n      address: 'London No. 1 Lake Park'\n    },\n    {\n      name: 'Joe Black',\n      age: 32,\n      address: 'Sidney No. 1 Lake Park'\n    },\n    {\n      name: 'Jim Red',\n      age: 32,\n      address: 'London No. 2 Lake Park'\n    }\n  ];\n}\n"
  },
  {
    "path": "components/table/demo/summary.md",
    "content": "---\norder: 29\ntitle:\n  en-US: Summary\n  zh-CN: 总结栏\n---\n\n## zh-CN\n\n通过 `nzSummary` 设置总结栏。可以通过配置 `nzFixed` 属性使其固定。\n\n## en-US\n\nSet summary content by `nzSummary` prop. You can fixed it by set `nzFixed` prop.\n"
  },
  {
    "path": "components/table/demo/summary.ts",
    "content": "import { Component, OnInit } from '@angular/core';\n\nimport { NzTableModule } from 'ng-zorro-antd/table';\nimport { NzTypographyModule } from 'ng-zorro-antd/typography';\n\n@Component({\n  selector: 'nz-demo-table-summary',\n  imports: [NzTableModule, NzTypographyModule],\n  template: `\n    <nz-table #middleTable nzBordered [nzData]=\"data\" [nzShowPagination]=\"false\">\n      <thead>\n        <tr>\n          <th>Name</th>\n          <th>Borrow</th>\n          <th>Repayment</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of middleTable.data; track $index) {\n          <tr>\n            <td>{{ data.name }}</td>\n            <td>{{ data.borrow }}</td>\n            <td>{{ data.repayment }}</td>\n          </tr>\n        }\n      </tbody>\n      <tfoot nzSummary>\n        <tr>\n          <td>Total</td>\n          <td>\n            <span nz-typography nzType=\"danger\">{{ totalBorrow }}</span>\n          </td>\n          <td>\n            <span nz-typography>{{ totalRepayment }}</span>\n          </td>\n        </tr>\n        <tr>\n          <td>Balance</td>\n          <td colspan=\"2\">\n            <span nz-typography>{{ totalBorrow - totalRepayment }}</span>\n          </td>\n        </tr>\n      </tfoot>\n    </nz-table>\n\n    <br />\n\n    <nz-table\n      #fixedTable\n      nzBordered\n      [nzData]=\"fixedData\"\n      [nzShowPagination]=\"false\"\n      [nzScroll]=\"{ x: '1280px', y: '500px' }\"\n    >\n      <thead>\n        <tr>\n          <th>Name</th>\n          <th>Description</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of fixedTable.data; track data.key) {\n          <tr>\n            <td>{{ data.name }}</td>\n            <td>{{ data.description }}</td>\n          </tr>\n        }\n      </tbody>\n      <tfoot nzSummary nzFixed>\n        <tr>\n          <td>Summary</td>\n          <td>This is a summary content</td>\n        </tr>\n      </tfoot>\n    </nz-table>\n  `,\n  styles: `\n    :host ::ng-deep tfoot.ant-table-summary {\n      background-color: #fafafa !important;\n    }\n  `\n})\nexport class NzDemoTableSummaryComponent implements OnInit {\n  data = [\n    {\n      name: 'John Brown',\n      borrow: 10,\n      repayment: 33\n    },\n    {\n      name: 'Jim Green',\n      borrow: 100,\n      repayment: 0\n    },\n    {\n      name: 'Joe Black',\n      borrow: 10,\n      repayment: 10\n    },\n    {\n      name: 'Jim Red',\n      borrow: 75,\n      repayment: 45\n    }\n  ];\n\n  fixedData: Array<{ key: number; name: string; description: string }> = [];\n  totalBorrow = 0;\n  totalRepayment = 0;\n\n  ngOnInit(): void {\n    this.data.forEach(({ borrow, repayment }) => {\n      this.totalBorrow += borrow;\n      this.totalRepayment += repayment;\n    });\n\n    for (let i = 0; i < 20; i += 1) {\n      this.fixedData.push({\n        key: i,\n        name: ['Light', 'Bamboo', 'Little'][i % 3],\n        description: 'Everything that has a beginning, has an end.'\n      });\n    }\n  }\n}\n"
  },
  {
    "path": "components/table/demo/template.md",
    "content": "---\norder: 25\ntitle:\n  en-US: Template\n  zh-CN: 模板用法\n---\n\n## zh-CN\n\n模板模式，显示内容仅由模板内容控制，不再需要向 `nzData` 传入数据，完全像普通 `table` 一样使用，使用 ant-design 的样式。\n\n## en-US\n\nTemplate mode, same usage as `table`, there is no need to data to `nzData`.\n"
  },
  {
    "path": "components/table/demo/template.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTableModule } from 'ng-zorro-antd/table';\n\n@Component({\n  selector: 'nz-demo-table-template',\n  imports: [NzTableModule],\n  template: `\n    <nz-table nzTemplateMode>\n      <thead>\n        <tr>\n          <th>Company</th>\n          <th>Contact</th>\n          <th>Country</th>\n        </tr>\n      </thead>\n      <tbody>\n        <tr>\n          <td>Alfreds Futterkiste</td>\n          <td>Maria Anders</td>\n          <td>Germany</td>\n        </tr>\n        <tr>\n          <td>Centro comercial Moctezuma</td>\n          <td>Francisco Chang</td>\n          <td>Mexico</td>\n        </tr>\n        <tr>\n          <td>Ernst Handel</td>\n          <td>Roland Mendel</td>\n          <td>Austria</td>\n        </tr>\n        <tr>\n          <td>Island Trading</td>\n          <td>Helen Bennett</td>\n          <td>UK</td>\n        </tr>\n        <tr>\n          <td>Laughing Bacchus Winecellars</td>\n          <td>Yoshi Tannamuri</td>\n          <td>Canada</td>\n        </tr>\n        <tr>\n          <td>Magazzini Alimentari Riuniti</td>\n          <td>Giovanni Rovelli</td>\n          <td>Italy</td>\n        </tr>\n      </tbody>\n    </nz-table>\n  `\n})\nexport class NzDemoTableTemplateComponent {}\n"
  },
  {
    "path": "components/table/demo/virtual.md",
    "content": "---\norder: 24\ntitle:\n  en-US: Virtual Scroll\n  zh-CN: 虚拟滚动\n---\n\n## zh-CN\n\n虚拟滚动，结合 [cdk scrolling](https://material.angular.io/cdk/scrolling/overview) 的虚拟滚动，用于巨量数据加载。可以通过获得 `cdkVirtualScrollViewport` 进行进一步操作，见本示例及 [API](https://material.angular.io/cdk/scrolling/api#CdkVirtualScrollViewport)。\n\n## en-US\n\nVirtual scrolling combine with [cdk scrolling](https://material.angular.io/cdk/scrolling/overview) used to display large data, you can get `cdkVirtualScrollViewport` in `NzTableComponent` and find more API [here](https://material.angular.io/cdk/scrolling/api#CdkVirtualScrollViewport).\n"
  },
  {
    "path": "components/table/demo/virtual.ts",
    "content": "import { AfterViewInit, Component, OnDestroy, OnInit, ViewChild } from '@angular/core';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzTableComponent, NzTableModule } from 'ng-zorro-antd/table';\n\nexport interface VirtualDataInterface {\n  index: number;\n  name: string;\n  age: number;\n  address: string;\n}\n\n@Component({\n  selector: 'nz-demo-table-virtual',\n  imports: [NzButtonModule, NzTableModule],\n  template: `\n    <button nz-button (click)=\"scrollToIndex(200)\">Scroll To Index 200</button>\n    <br />\n    <br />\n    <nz-table\n      #virtualTable\n      [nzBordered]=\"true\"\n      [nzVirtualItemSize]=\"54\"\n      [nzData]=\"listOfData\"\n      [nzVirtualForTrackBy]=\"trackByIndex\"\n      [nzFrontPagination]=\"false\"\n      [nzShowPagination]=\"false\"\n      [nzScroll]=\"{ x: '1200px', y: '240px' }\"\n    >\n      <thead>\n        <tr>\n          <th nzLeft>Full Name</th>\n          <th nzLeft>Age</th>\n          <th>Index</th>\n          <th>Column 1</th>\n          <th>Column 2</th>\n          <th>Column 3</th>\n          <th>Column 4</th>\n          <th>Column 5</th>\n          <th>Column 6</th>\n          <th>Column 7</th>\n          <th>Column 8</th>\n          <th nzRight>Action</th>\n        </tr>\n      </thead>\n      <tbody>\n        <ng-template nz-virtual-scroll let-data let-index=\"index\">\n          <tr>\n            <td nzLeft>{{ data.name }}</td>\n            <td nzLeft>{{ data.age }}</td>\n            <td>{{ data.index }}</td>\n            <td>{{ data.address }}</td>\n            <td>{{ data.address }}</td>\n            <td>{{ data.address }}</td>\n            <td>{{ data.address }}</td>\n            <td>{{ data.address }}</td>\n            <td>{{ data.address }}</td>\n            <td>{{ data.address }}</td>\n            <td>{{ data.address }}</td>\n            <td nzRight>\n              <a>action</a>\n            </td>\n          </tr>\n        </ng-template>\n      </tbody>\n    </nz-table>\n  `\n})\nexport class NzDemoTableVirtualComponent implements OnInit, AfterViewInit, OnDestroy {\n  @ViewChild('virtualTable', { static: false }) nzTableComponent?: NzTableComponent<VirtualDataInterface>;\n  private destroy$ = new Subject<boolean>();\n  listOfData: VirtualDataInterface[] = [];\n\n  scrollToIndex(index: number): void {\n    this.nzTableComponent?.cdkVirtualScrollViewport?.scrollToIndex(index);\n  }\n\n  trackByIndex(_: number, data: VirtualDataInterface): number {\n    return data.index;\n  }\n\n  ngOnInit(): void {\n    const data = [];\n    for (let i = 0; i < 20000; i++) {\n      data.push({\n        index: i,\n        name: `Edward`,\n        age: i,\n        address: `London`\n      });\n    }\n    this.listOfData = data;\n  }\n\n  ngAfterViewInit(): void {\n    this.nzTableComponent?.cdkVirtualScrollViewport?.scrolledIndexChange\n      .pipe(takeUntil(this.destroy$))\n      .subscribe((data: number) => {\n        console.log('scroll index to', data);\n      });\n  }\n\n  ngOnDestroy(): void {\n    this.destroy$.next(true);\n    this.destroy$.complete();\n  }\n}\n"
  },
  {
    "path": "components/table/doc/index.en-US.md",
    "content": "---\ncategory: Components\ncols: 1\ntype: Data Display\ntitle: Table\ncover: 'https://gw.alipayobjects.com/zos/alicdn/f-SbcX2Lx/Table.svg'\ndescription: A table displays rows of data.\n---\n\n## When To Use\n\n- To display a collection of structured data.\n- To sort, search, paginate and filter data.\n\n## How To Use\n\nThe Table component is both easy to use and highly customizable.\n\n### Highly Customizable\n\nThe `nz-table` can be used like [` W3C Standard <table>`](https://www.w3.org/TR/html401/struct/tables.html). Developers can control every part of the table as they wish.\n\n### Component Enhancements\n\nThe component in `nz-table` such as `th`, `td`, `thead` etc. are enhanced. Developers can make the table sortable, filterable, with fixed header, perform server side rendering etc. easily with the provided api.\n\n### Data Processing\n\nThe data passed to `[nzData]` is exported with [Template Context](https://angular.dev/guide/templates/template-statements#statement-context) after processing (including paging, sorting and filtering). `*ngFor` can be used to render current page data in table.\n\n```html\n<nz-table #basicTable [nzData]=\"dataSet\">\n  <thead>\n    <tr>\n      <th>Name</th>\n      <th>Age</th>\n      <th>Address</th>\n      <th>Action</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr *ngFor=\"let data of basicTable.data\">\n      <td>{{data.name}}</td>\n      <td>{{data.age}}</td>\n      <td>{{data.address}}</td>\n      <td>\n        <a>Action 一 {{data.name}}</a>\n        <nz-divider nzType=\"vertical\"></nz-divider>\n        <a>Delete</a>\n      </td>\n    </tr>\n  </tbody>\n</nz-table>\n```\n\n## API\n\n### nz-table\n\n| Property                    | Description                                                                                                                                                                              | Type                                                                   | Default            | Global Config |\n| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | ------------------ | ------------- |\n| `[nzData]`                  | Data record array to be rendered                                                                                                                                                         | `T[]`                                                                  | -                  |\n| `[nzFrontPagination]`       | Whether to paginate data on client. Should be set to `false` if data is to be paginated on server side or if all the data is to be displayed at once in the table without any pagination | `boolean`                                                              | `true`             |\n| `[nzTotal]`                 | Total data count. Should set when `nzFrontPagination` is `false`                                                                                                                         | `number`                                                               | -                  |\n| `[nzCustomColumn]`          | Control the display and sorting of table columns, (after enabling `nzWidthConfig` and `[nzWidth]` of `th` will not take effect)                                                          | `NzCustomColumn[]`                                                     | -                  |\n| `[nzPageIndex]`             | pageIndex , double binding                                                                                                                                                               | `number`                                                               | -                  |\n| `[nzPageSize]`              | pageSize, double binding                                                                                                                                                                 | `number`                                                               | -                  |\n| `[nzShowPagination]`        | Whether to show pagination component at bottom of the table                                                                                                                              | `boolean`                                                              | `true`             |\n| `[nzPaginationPosition]`    | Specify the position of pagination                                                                                                                                                       | `'top' \\| 'bottom' \\| 'both'`                                          | `'bottom'`         |\n| `[nzPaginationType]`        | Specify the size of pagination                                                                                                                                                           | `'default' \\| 'small'`                                                 | `'default'`        |\n| `[nzBordered]`              | Whether to show all table borders                                                                                                                                                        | `boolean`                                                              | `false`            | ✅            |\n| `[nzOuterBordered]`         | Whether to show table outer borders                                                                                                                                                      | `boolean`                                                              | `false`            | -             |\n| `[nzWidthConfig]`           | Set col width can not used with `[nzWidth]` of `th`                                                                                                                                      | `string[]`                                                             | `[]`               |\n| `[nzSize]`                  | Size of table                                                                                                                                                                            | `'middle' \\| 'small' \\| 'default'`                                     | `'default'`        | ✅            |\n| `[nzLoading]`               | Loading status of table                                                                                                                                                                  | `boolean`                                                              | `false`            |\n| `[nzLoadingIndicator]`      | The loading indicator                                                                                                                                                                    | `TemplateRef<void>`                                                    | -                  | ✅            |\n| `[nzLoadingDelay]`          | Specifies a delay in milliseconds for loading state (prevents flush)                                                                                                                     | `number`                                                               | `0`                |\n| `[nzScroll]`                | Whether table can be scrolled in x/y direction. `x` or `y` can be a string that indicates the width and height of table body                                                             | `object`                                                               | -                  |\n| `[nzTitle]`                 | Table title renderer                                                                                                                                                                     | `string \\| TemplateRef<void>`                                          | -                  |\n| `[nzFooter]`                | Table footer renderer                                                                                                                                                                    | `string \\| TemplateRef<void>`                                          | -                  |\n| `[nzNoResult]`              | Custom no result content                                                                                                                                                                 | `string \\| TemplateRef<void>`                                          | -                  |\n| `[nzPageSizeOptions]`       | Specify the sizeChanger options                                                                                                                                                          | `number[]`                                                             | `[10, 20, 30, 40]` |\n| `[nzShowQuickJumper]`       | Determine whether you can jump to pages directly                                                                                                                                         | `boolean`                                                              | `false`            | ✅            |\n| `[nzShowSizeChanger]`       | Determine whether `nzPageSize` can be changed                                                                                                                                            | `boolean`                                                              | `false`            | ✅            |\n| `[nzShowTotal]`             | To display Pagination total number and range, same as Pagination                                                                                                                         | `TemplateRef<{ $implicit: number, range: [ number, number ] }>`        | -                  |\n| `[nzItemRender]`            | To customize Pagination item, same as Pagination                                                                                                                                         | `TemplateRef<{ $implicit: 'page' \\| 'prev' \\| 'next', page: number }>` | -                  |\n| `[nzHideOnSinglePage]`      | Whether to hide pagination on single page                                                                                                                                                | `boolean`                                                              | `false`            |\n| `[nzSimple]`                | Whether to use simple mode                                                                                                                                                               | `boolean`                                                              | -                  | ✅            |\n| `[nzTemplateMode]`          | Template mode，no need to pass data to `nzData`                                                                                                                                          | `boolean`                                                              | `false`            |\n| `[nzVirtualItemSize]`       | The size of the items in the list, same as [cdk itemSize](https://material.angular.io/cdk/scrolling/api)                                                                                 | `number`                                                               | `0`                |\n| `[nzVirtualMaxBufferPx]`    | The number of pixels worth of buffer to render for when rendering new items, same as [cdk maxBufferPx](https://material.angular.io/cdk/scrolling/api)                                    | `number`                                                               | `200`              |\n| `[nzVirtualMinBufferPx]`    | The minimum amount of buffer rendered beyond the viewport (in pixels),same as [cdk minBufferPx](https://material.angular.io/cdk/scrolling/api)                                           | `number`                                                               | `100`              |\n| `[nzVirtualForTrackBy]`     | The TrackByFunction to be used for tracking changes.                                                                                                                                     | `TrackByFunction<T>`                                                   | -                  |\n| `[noDataVirtualHeight]`     | Height of inner scroll when having no data, if nothing is passed the default value is used.                                                                                              | `string`                                                               | `'182px'`          |\n| `(nzPageIndexChange)`       | Callback when `pageIndex` changes                                                                                                                                                        | `EventEmitter<number>`                                                 | -                  |\n| `(nzPageSizeChange)`        | Callback when `pageSize` changes                                                                                                                                                         | `EventEmitter<number>`                                                 | -                  |\n| `(nzCurrentPageDataChange)` | Callback when current pageData changes                                                                                                                                                   | `EventEmitter<T[]>`                                                    | -                  |\n| `(nzCustomColumnChange)`    | Callback when the table is reordered                                                                                                                                                     | `EventEmitter<NzCustomColumn[]>`                                       | -                  |\n| `(nzQueryParams)`           | Callback with params when working with server side pagination, sorting and filtering                                                                                                     | `EventEmitter<NzTableQueryParams>`                                     | -                  |\n\n### th\n\nCheckbox property\n\n| Property            | Description                                         | Type                    | Default |\n| ------------------- | --------------------------------------------------- | ----------------------- | ------- |\n| `[nzShowCheckbox]`  | Whether `nz-checkbox` should be shown in the header | `boolean`               | -       |\n| `[nzDisabled]`      | Whether the `nz-checkbox` is disabled               | `boolean`               | -       |\n| `[nzIndeterminate]` | `nz-checkbox` indeterminate status                  | `boolean`               | -       |\n| `[nzLabel]`         | ARIA label for the `nz-checkbox`                    | `string`                | -       |\n| `[nzChecked]`       | Checked status, double binding                      | `boolean`               | -       |\n| `(nzCheckedChange)` | Callback when checked status changes                | `EventEmitter<boolean>` | -       |\n\nSelection property\n\n| Property               | Description                                                         | Type                                     | Default |\n| ---------------------- | ------------------------------------------------------------------- | ---------------------------------------- | ------- |\n| `[nzShowRowSelection]` | Whether to show row selection options                               | `boolean`                                | -       |\n| `[nzSelections]`       | Selection options including `text` and `onSelect` callback function | `Array<{ text: string, onSelect: any }>` | -       |\n\nSort property\n\n| Property              | Description                                                                                                                                      | Type                                          | Default                       |\n| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------- | ----------------------------- |\n| `[nzShowSort]`        | Whether to display sorting                                                                                                                       | `boolean`                                     | -                             |\n| `[nzSortFn]`          | Sort function used to sort the data on client side (ref to `Array.sort` compareFunction). Should be set to `true` when using server side sorting | `NzTableSortFn<T> \\| boolean`                 | -                             |\n| `[nzSortOrder]`       | Sort direction                                                                                                                                   | `'descend' \\| 'ascend' \\| null`               | -                             |\n| `[nzSortDirections]`  | Supported sort order, could be `'descend'`, `'ascend'`, `null`                                                                                   | `Array<'descend' \\| 'ascend' \\| null>`        | `['ascend', 'descend', null]` |\n| `(nzSortOrderChange)` | Callback when sort direction changes                                                                                                             | `EventEmitter<'descend' \\| 'ascend' \\| null>` | -                             |\n\nFilter property\n\n| Property             | Description                                                                                            | Type                                                       | Default |\n| -------------------- | ------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------- | ------- |\n| `[nzShowFilter]`     | Whether to show filter                                                                                 | `boolean`                                                  | -       |\n| `[nzFilterFn]`       | Filter function used to filter the data on client side. Set to `true` when using server side filtering | `NzTableFilterFn<T> \\| boolean`                            | -       |\n| `[nzFilters]`        | Filter options, `text`, and `value` for callback, `byDefault` to enable filter by default              | `Array<{ text: string; value: any; byDefault?: boolean }>` | -       |\n| `[nzFilterMultiple]` | Whether multiple mode filtering is enabled                                                             | `boolean`                                                  | `true`  |\n| `(nzFilterChange)`   | Callback when filter `value` changes                                                                   | `EventEmitter<any[] \\| any>`                               | -       |\n\nStyle property\n\n| Property          | Description                                                                                                  | Type                            | Default |\n| ----------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------- | ------- |\n| `[nzWidth]`       | Specify the column width (in pixels), can not used when grouping columns                                     | `string`                        | -       |\n| `[nzLeft]`        | Left pixels, used to fixed column to left, auto calc when set to `true` and disable fixed when `false`       | `string \\| boolean`             | -       |\n| `[nzRight]`       | Right pixels, used to fixed column to right, auto calc when set to `true` and disable fixed when `false`     | `string \\| boolean`             | -       |\n| `[nzAlign]`       | Specify how content is aligned                                                                               | `'left' \\| 'right' \\| 'center'` | -       |\n| `[nzCellControl]` | Set the position of the column, which is the value of the `value` field in the `NzCustomColumn` type         | `string`                        | -       |\n| `[nzBreakWord]`   | Whether insert line breaks within words                                                                      | `boolean`                       | `false` |\n| `[nzEllipsis]`    | ellipsis cell content, not working with sorter and filters for now. Only work when nzTableLayout was `fixed` | `boolean`                       | `false` |\n\nOther\n\n| Property        | Description                                  | Type     | Default |\n| --------------- | -------------------------------------------- | -------- | ------- |\n| `[nzColumnKey]` | column key, work with server sort and filter | `string` | -       |\n\n### td\n\nCheckbox property\n\n| Property            | Description                       | Type                    | Default |\n| ------------------- | --------------------------------- | ----------------------- | ------- |\n| `[nzShowCheckbox]`  | Whether add nz-checkbox           | `boolean`               | -       |\n| `[nzDisabled]`      | Whether disable checkbox          | `boolean`               | -       |\n| `[nzIndeterminate]` | Indeterminate status              | `boolean`               | -       |\n| `[nzLabel]`         | ARIA label for the `nz-checkbox`  | `string`                | -       |\n| `[nzChecked]`       | Checked status, double binding    | `boolean`               | -       |\n| `(nzCheckedChange)` | Checked status change callback    | `EventEmitter<boolean>` | -       |\n| `[colSpan]`         | how many columns the cell extends | `number`                | `null`  |\n| `[rowSpan]`         | how many rows the cell extends    | `number`                | `null`  |\n\nExpand property\n\n| Property           | Description                           | Type                    | Default |\n| ------------------ | ------------------------------------- | ----------------------- | ------- |\n| `[nzShowExpand]`   | Whether show expand icon              | `boolean`               | -       |\n| `[nzExpand]`       | Current expand status, double binding | `boolean`               | -       |\n| `[nzExpandIcon]`   | Custom expand icon                    | `TemplateRef<void>`     | -       |\n| `(nzExpandChange)` | Expand status change callback         | `EventEmitter<boolean>` | -       |\n\nStyle property\n\n| Property          | Description                                                                                                  | Type                            | Default |\n| ----------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------- | ------- |\n| `[nzLeft]`        | Left pixels, used to fixed column to left, auto calc when set to `true` and disable fixed when `false`       | `string \\| boolean`             | -       |\n| `[nzRight]`       | Right pixels, used to fixed column to right, auto calc when set to `true` and disable fixed when `false`     | `string \\| boolean`             | -       |\n| `[nzAlign]`       | Specify how content is aligned                                                                               | `'left' \\| 'right' \\| 'center'` | -       |\n| `[nzCellControl]` | Set the position of the column, which is the value of the `value` field in the `NzCustomColumn` type         | `string`                        | -       |\n| `[nzBreakWord]`   | Whether insert line breaks within words                                                                      | `boolean`                       | `false` |\n| `[nzEllipsis]`    | ellipsis cell content, not working with sorter and filters for now. Only work when nzTableLayout was `fixed` | `boolean`                       | `false` |\n\nOther property\n\n| Property         | Description                        | Type     | Default |\n| ---------------- | ---------------------------------- | -------- | ------- |\n| `[nzIndentSize]` | Indent size in pixels of tree data | `number` | -       |\n\n### thead\n\n| Property              | Description                                                  | Type                                                                  | Default |\n| --------------------- | ------------------------------------------------------------ | --------------------------------------------------------------------- | ------- |\n| `(nzSortOrderChange)` | sort change callback，should used with `nzColumnKey` of `th` | `EventEmitter<{ key: string, value: 'descend' \\| 'ascend' \\| null }>` | -       |\n\n### tr\n\n| Property     | Description                                              | Type      | Default |\n| ------------ | -------------------------------------------------------- | --------- | ------- |\n| `[nzExpand]` | Whether expand current row，used with `nzExpand` of `td` | `boolean` | -       |\n\n### tfoot\n\n| Property      | Description                         | Type                           | Default |\n| ------------- | ----------------------------------- | ------------------------------ | ------- |\n| `[nzSummary]` | Summary content                     | `boolean`                      | -       |\n| `[nzFixed]`   | Fixed summary, used with `nzScroll` | `boolean \\| 'top' \\| 'bottom'` | `false` |\n\n### nz-filter-trigger\n\nCustomized filter panel\n\n| Property            | Description                                                                                       | Type                      | Default |\n| ------------------- | ------------------------------------------------------------------------------------------------- | ------------------------- | ------- |\n| `[nzDropdownMenu]`  | Dropdown menu                                                                                     | `NzDropdownMenuComponent` | -       |\n| `[nzVisible]`       | whether the dropdown menu is visible, double binding                                              | `boolean`                 | -       |\n| `[nzActive]`        | whether the icon status is activated                                                              | `boolean`                 | `false` |\n| `[nzHasBackdrop]`   | Whether or not attach a backdrop.                                                                 | `boolean`                 | `false` |\n| `(nzVisibleChange)` | a callback function takes an argument: `nzVisible`, is executed when the visible state is changed | `EventEmitter<boolean>`   | -       |\n\n### [nz-virtual-scroll]\n\nvirtual scroll directive work with `ng-template`, type: `TemplateRef<{ $implicit: T, index: number }>`.\n\n## Note\n\nIn order to get better performance, all NG-ZORRO's components are running under [OnPush](https://angular.dev/guide/components/advanced-configuration#changedetectionstrategy) mode, this means any mutate to the `@Input()` data won't trigger change detection, please use immutable way to update array or object.\n\n```typescript\n// add data\nthis.dataSet = [\n  ...this.dataSet,\n  {\n    key: `${this.i}`,\n    name: `Edward King ${this.i}`,\n    age: '32',\n    address: `London, Park Lane no. ${this.i}`\n  }\n];\n// remove data\nthis.dataSet = this.dataSet.filter(d => d.key !== i);\n```\n\nRecommend using [immer](https://immerjs.github.io/immer/docs/introduction) for a better development experience.\n"
  },
  {
    "path": "components/table/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ncols: 1\ntype: 数据展示\ntitle: Table\nsubtitle: 表格\ncover: 'https://gw.alipayobjects.com/zos/alicdn/f-SbcX2Lx/Table.svg'\ndescription: 展示行列数据。\n---\n\n## 何时使用\n\n- 当有大量结构化的数据需要展现时；\n- 当需要对数据进行排序、搜索、分页、自定义操作等复杂行为时。\n\n## 如何使用\n\nTable 组件同时具备了易用性和高度可定制性\n\n### 高度定制\n\n在 `nz-table` 组件中完整的暴露了 [`W3C标准 <table>`](https://www.w3.org/TR/html401/struct/tables.html) 的所有组成部分，你可以像使用 `table` 元素一样使用 `nz-table` ，根据依据业务需求，使用者可以自由的控制任何一个部分的样式、内容、逻辑和事件绑定。\n\n### 组件增强\n\n在 `nz-table`, `thead`, `th`, `td` 等多个暴露的元素上，组件提供了增强语法，经过配置之后可以很方便的实现多选、过滤、排序、固定列、固定表头、服务端分页等功能。\n\n### 数据处理\n\n将数据传入`[nzData]`，经过组件处理之后（包括分页、排序、筛选等），通过 [模板变量](https://angular.cn/guide/templates/template-statements#statement-context) 获取当前展示表格部分的数据，使用 `*ngFor` 依据需求将数据渲染。\n\n```html\n<nz-table #basicTable [nzData]=\"dataSet\">\n  <thead>\n    <tr>\n      <th>Name</th>\n      <th>Age</th>\n      <th>Address</th>\n      <th>Action</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr *ngFor=\"let data of basicTable.data\">\n      <td>{{data.name}}</td>\n      <td>{{data.age}}</td>\n      <td>{{data.address}}</td>\n      <td>\n        <a>Action 一 {{data.name}}</a>\n        <nz-divider nzType=\"vertical\"></nz-divider>\n        <a>Delete</a>\n      </td>\n    </tr>\n  </tbody>\n</nz-table>\n```\n\n## API\n\n### nz-table\n\n| 参数                        | 说明                                                                                                                 | 类型                                                                   | 默认值                   | 全局配置 |\n| --------------------------- | -------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | ------------------------ | -------- |\n| `[nzData]`                  | 数据数组                                                                                                             | `T[]`                                                                  | -                        |\n| `[nzFrontPagination]`       | 是否在前端对数据进行分页，如果在服务器分页数据或者需要在前端显示全部数据时传入 false                                 | `boolean`                                                              | `true`                   |\n| `[nzTotal]`                 | 当前总数据，在服务器渲染时需要传入                                                                                   | `number`                                                               | -                        |\n| `[nzCustomColumn]`          | 控制表格列的展示与排序，(开启后 `nzWidthConfig` 和 `th` 的 `[nzWidth]` 将不生效)                                     | `NzCustomColumn[]`                                                     | -                        |\n| `[nzPageIndex]`             | 当前页码，可双向绑定                                                                                                 | `number`                                                               | -                        |\n| `[nzPageSize]`              | 每页展示多少数据，可双向绑定                                                                                         | `number`                                                               | -                        |\n| `[nzShowPagination]`        | 是否显示分页器                                                                                                       | `boolean`                                                              | `true`                   |\n| `[nzPaginationPosition]`    | 指定分页显示的位置                                                                                                   | `'top' \\| 'bottom' \\| 'both'`                                          | `'bottom'`               |\n| `[nzPaginationType]`        | 指定分页显示的尺寸                                                                                                   | `'default' \\| 'small'`                                                 | `'default'`              |\n| `[nzBordered]`              | 是否展示外边框和列边框                                                                                               | `boolean`                                                              | `false`                  | ✅       |\n| `[nzOuterBordered]`         | 是否显示外边框                                                                                                       | `boolean`                                                              | `false`                  | -        |\n| `[nzWidthConfig]`           | 表头分组时指定每列宽度，与 `th` 的 `[nzWidth]` 不可混用                                                              | `string[]`                                                             | `[]`                     |\n| `[nzSize]`                  | 正常或迷你类型                                                                                                       | `'middle' \\| 'small' \\| 'default'`                                     | `'default'`              | ✅       |\n| `[nzLoading]`               | 页面是否加载中                                                                                                       | `boolean`                                                              | `false`                  |\n| `[nzLoadingIndicator]`      | 加载指示符                                                                                                           | `TemplateRef<void>`                                                    | -                        | ✅       |\n| `[nzLoadingDelay]`          | 延迟显示加载效果的时间（防止闪烁）                                                                                   | `number`                                                               | `0`                      |\n| `[nzScroll]`                | 横向或纵向支持滚动，也可用于指定滚动区域的宽高度：`{ x: \"300px\", y: \"300px\" }`                                       | `object`                                                               | -                        |\n| `[nzTitle]`                 | 表格标题                                                                                                             | `string \\| TemplateRef<void>`                                          | -                        |\n| `[nzFooter]`                | 表格尾部                                                                                                             | `string \\| TemplateRef<void>`                                          | -                        |\n| `[nzNoResult]`              | 无数据时显示内容                                                                                                     | `string \\| TemplateRef<void>`                                          | -                        |\n| `[nzPageSizeOptions]`       | 页数选择器可选值                                                                                                     | `number[]`                                                             | `[ 10, 20, 30, 40, 50 ]` |\n| `[nzShowQuickJumper]`       | 是否可以快速跳转至某页                                                                                               | `boolean`                                                              | `false`                  | ✅       |\n| `[nzShowSizeChanger]`       | 是否可以改变 `nzPageSize`                                                                                            | `boolean`                                                              | `false`                  | ✅       |\n| `[nzShowTotal]`             | 用于显示数据总量和当前数据范围，用法参照 Pagination 组件                                                             | `TemplateRef<{ $implicit: number, range: [ number, number ] }>`        | -                        |\n| `[nzItemRender]`            | 用于自定义页码的结构，用法参照 Pagination 组件                                                                       | `TemplateRef<{ $implicit: 'page' \\| 'prev' \\| 'next', page: number }>` | -                        |\n| `[nzHideOnSinglePage]`      | 只有一页时是否隐藏分页器                                                                                             | `boolean`                                                              | `false`                  | ✅       |\n| `[nzSimple]`                | 当添加该属性时，显示为简单分页                                                                                       | `boolean`                                                              | -                        | ✅       |\n| `[nzTemplateMode]`          | 模板模式，无需将数据传递给 `nzData`                                                                                  | `boolean`                                                              | `false`                  |\n| `[nzVirtualItemSize]`       | 虚拟滚动时每一列的高度，与 [cdk itemSize](https://material.angular.io/cdk/scrolling/api) 相同                        | `number`                                                               | `0`                      |\n| `[nzVirtualMaxBufferPx]`    | 缓冲区最大像素高度，与 [cdk maxBufferPx](https://material.angular.io/cdk/scrolling/api) 相同                         | `number`                                                               | `200`                    |\n| `[nzVirtualMinBufferPx]`    | 缓冲区最小像素高度，低于该值时将加载新结构，与 [cdk minBufferPx](https://material.angular.io/cdk/scrolling/api) 相同 | `number`                                                               | `100`                    |\n| `[nzVirtualForTrackBy]`     | 虚拟滚动数据 `TrackByFunction` 函数                                                                                  | `TrackByFunction<T>`                                                   | -                        |\n| `(nzPageIndexChange)`       | 当前页码改变时的回调函数                                                                                             | `EventEmitter<number>`                                                 | -                        |\n| `(nzPageSizeChange)`        | 页数改变时的回调函数                                                                                                 | `EventEmitter<number>`                                                 | -                        |\n| `(nzCurrentPageDataChange)` | 当前页面展示数据改变的回调函数                                                                                       | `EventEmitter<T[]>`                                                    | -                        |\n| `(nzCustomColumnChange)`    | 当表格重新排序后的回调                                                                                               | `EventEmitter<NzCustomColumn[]>`                                       | -                        |\n| `(nzQueryParams)`           | 当服务端分页、筛选、排序时，用于获得参数，具体见示例                                                                 | `EventEmitter<NzTableQueryParams>`                                     | -                        |\n\n### th\n\n勾选属性\n\n| 参数                | 说明                            | 类型                    | 默认值 |\n| ------------------- | ------------------------------- | ----------------------- | ------ |\n| `[nzShowCheckbox]`  | 是否添加 checkbox               | `boolean`               | -      |\n| `[nzDisabled]`      | checkbox 是否禁用               | `boolean`               | -      |\n| `[nzIndeterminate]` | checkbox indeterminate 状态     | `boolean`               | -      |\n| `[nzLabel]`         | checkbox 的可访问性标签         | `string`                | -      |\n| `[nzChecked]`       | checkbox 是否被选中，可双向绑定 | `boolean`               | -      |\n| `(nzCheckedChange)` | 选中的回调                      | `EventEmitter<boolean>` | -      |\n\n下拉选择属性\n\n| 参数                   | 说明                                        | 类型                                     | 默认值 |\n| ---------------------- | ------------------------------------------- | ---------------------------------------- | ------ |\n| `[nzShowRowSelection]` | 是否显示下拉选择                            | `boolean`                                | -      |\n| `[nzSelections]`       | 下拉选择的内容 `text` 及回调函数 `onSelect` | `Array<{ text: string, onSelect: any }>` | -      |\n\n排序属性\n\n| 参数                  | 说明                                                                                      | 类型                                          | 默认值                        |\n| --------------------- | ----------------------------------------------------------------------------------------- | --------------------------------------------- | ----------------------------- |\n| `[nzShowSort]`        | 是否显示排序                                                                              | `boolean`                                     | -                             |\n| `[nzSortFn]`          | 排序函数，前端排序使用一个函数(参考 Array.sort 的 compareFunction)，服务端排序时传入 true | `NzTableSortFn<T> \\| boolean`                 | -                             |\n| `[nzSortDirections]`  | 支持的排序方式，取值为 `'ascend'`, `'descend'`, `null`                                    | `Array<'ascend' \\| 'descend' \\| null>`        | `['ascend', 'descend', null]` |\n| `[nzSortOrder]`       | 当前排序状态，可双向绑定                                                                  | `'ascend' \\| 'descend' \\| null`               | null                          |\n| `(nzSortOrderChange)` | 排序状态改变回调                                                                          | `EventEmitter<'ascend' \\| 'descend' \\| null>` | -                             |\n\n过滤属性\n\n| 参数                    | 说明                                                                                   | 类型                                                       | 默认值    |\n| ----------------------- | -------------------------------------------------------------------------------------- | ---------------------------------------------------------- | --------- |\n| `[nzShowFilter]`        | 是否显示过滤                                                                           | `boolean`                                                  | -         |\n| `[nzFilterFn]`          | 前端排序时，确定筛选的运行函数，服务端排序时，传入 true                                | `NzTableFilterFn<T> \\| boolean`                            | -         |\n| `[noDataVirtualHeight]` | 没有数据时内部滚动的高度，如果没有传递任何内容，则使用默认值。                         | `string`                                                   | `'182px'` |\n| `[nzFilters]`           | 过滤器内容, 显示数据 `text`，回调函数传出 `value`，设置 `byDefault` 以默认应用过滤规则 | `Array<{ text: string; value: any; byDefault?: boolean }>` | -         |\n| `[nzFilterMultiple]`    | 是否为多选过滤器                                                                       | `boolean`                                                  | `true`    |\n| `(nzFilterChange)`      | 过滤器内容选择的 value 数据回调                                                        | `EventEmitter<any[] \\| any>`                               | -         |\n\n样式属性\n\n| 参数              | 说明                                                                                           | 类型                            | 默认值  |\n| ----------------- | ---------------------------------------------------------------------------------------------- | ------------------------------- | ------- |\n| `[nzWidth]`       | 指定该列宽度，表头未分组时可用                                                                 | `string`                        | -       |\n| `[nzLeft]`        | 左侧距离，用于固定左侧列，当为 `true` 时自动计算，为 `false` 时停止固定                        | `string \\| boolean`             | `false` |\n| `[nzRight]`       | 右侧距离，用于固定右侧列，当为 `true` 时自动计算，为 `false` 时停止固定                        | `string \\| boolean`             | `false` |\n| `[nzAlign]`       | 设置列内容的对齐方式                                                                           | `'left' \\| 'right' \\| 'center'` | -       |\n| `[nzCellControl]` | 设置列的位置，该值为 `NzCustomColumn` 类型中 `value` 字段的值                                  | `string`                        | -       |\n| `[nzBreakWord]`   | 是否折行显示                                                                                   | `boolean`                       | `false` |\n| `[nzEllipsis]`    | 超过宽度将自动省略，暂不支持和排序筛选一起使用。仅当表格布局将为 `nzTableLayout=\"fixed\"`时可用 | `boolean`                       | `false` |\n| `[colSpan]`       | 每单元格中扩展列的数量                                                                         | `number`                        | `null`  |\n| `[rowSpan]`       | 每单元格中扩展行的数量                                                                         | `number`                        | `null`  |\n\n其他\n\n| 参数            | 说明                                   | 类型     | 默认值 |\n| --------------- | -------------------------------------- | -------- | ------ |\n| `[nzColumnKey]` | 当前列的 key，用于服务端筛选和排序使用 | `string` | -      |\n\n### td\n\n勾选属性\n\n| 参数                | 说明                            | 类型                    | 默认值 |\n| ------------------- | ------------------------------- | ----------------------- | ------ |\n| `[nzShowCheckbox]`  | 是否添加 checkbox               | `boolean`               | -      |\n| `[nzDisabled]`      | checkbox 是否禁用               | `boolean`               | -      |\n| `[nzIndeterminate]` | checkbox indeterminate 状态     | `boolean`               | -      |\n| `[nzLabel]`         | checkbox 的可访问性标签         | `string`                | -      |\n| `[nzChecked]`       | checkbox 是否被选中，可双向绑定 | `boolean`               | -      |\n| `(nzCheckedChange)` | 选中的回调                      | `EventEmitter<boolean>` | -      |\n| `[colSpan]`         | 单元格可横跨的列数              | `number`                | `null` |\n| `[rowSpan]`         | 单元格可横跨的行数              | `number`                | `null` |\n\n展开属性\n\n| 参数               | 说明                         | 类型                    | 默认值 |\n| ------------------ | ---------------------------- | ----------------------- | ------ |\n| `[nzShowExpand]`   | 是否显示展开按钮             | `boolean`               | -      |\n| `[nzExpand]`       | 当前展开按钮状态，可双向绑定 | `boolean`               | -      |\n| `[nzExpandIcon]`   | 自定义展开图标               | `TemplateRef<void>`     | -      |\n| `(nzExpandChange)` | 当前展开按钮状态改变回调函数 | `EventEmitter<boolean>` | -      |\n\n样式属性\n\n| 参数              | 说明                                                                                           | 类型                            | 默认值  |\n| ----------------- | ---------------------------------------------------------------------------------------------- | ------------------------------- | ------- |\n| `[nzLeft]`        | 左侧距离，用于固定左侧列，当为 `true` 时自动计算，为 `false` 时停止固定                        | `string \\| boolean`             | `false` |\n| `[nzRight]`       | 右侧距离，用于固定右侧列，当为 `true` 时自动计算，为 `false` 时停止固定                        | `string \\| boolean`             | `false` |\n| `[nzAlign]`       | 设置列内容的对齐方式                                                                           | `'left' \\| 'right' \\| 'center'` | -       |\n| `[nzCellControl]` | 设置列的位置，该值为 `NzCustomColumn` 类型中 `value` 字段的值                                  | `string`                        | -       |\n| `[nzBreakWord]`   | 是否折行显示                                                                                   | `boolean`                       | `false` |\n| `[nzEllipsis]`    | 超过宽度将自动省略，暂不支持和排序筛选一起使用。仅当表格布局将为 `nzTableLayout=\"fixed\"`时可用 | `boolean`                       | `false` |\n\n其他\n\n| 参数             | 说明                                         | 类型     | 默认值 |\n| ---------------- | -------------------------------------------- | -------- | ------ |\n| `[nzIndentSize]` | 展示树形数据时，每层缩进的宽度，以 px 为单位 | `number` | -      |\n\n### thead\n\n| 参数                  | 说明                                                      | 类型                                                                  | 默认值 |\n| --------------------- | --------------------------------------------------------- | --------------------------------------------------------------------- | ------ |\n| `(nzSortOrderChange)` | 排序状态改变回调，需要与 `th` 上的 `nzColumnKey` 同时使用 | `EventEmitter<{ key: string, value: 'descend' \\| 'ascend' \\| null }>` | -      |\n\n### tr\n\n| 参数         | 说明                                                 | 类型      | 默认值 |\n| ------------ | ---------------------------------------------------- | --------- | ------ |\n| `[nzExpand]` | 当前列是否展开，与 `td` 上的 `nzExpand` 属性配合使用 | `boolean` | -      |\n\n### tfoot\n\n| 参数          | 说明                                       | 类型                           | 默认值  |\n| ------------- | ------------------------------------------ | ------------------------------ | ------- |\n| `[nzSummary]` | 总结栏                                     | `boolean`                      | -       |\n| `[nzFixed]`   | 总结栏是否固定，与 `nzScroll` 属性配合使用 | `boolean \\| 'top' \\| 'bottom'` | `false` |\n\n### nz-filter-trigger\n\n用于自定义筛选功能\n\n| 参数                | 说明                                     | 类型                      | 默认值  |\n| ------------------- | ---------------------------------------- | ------------------------- | ------- |\n| `[nzDropdownMenu]`  | Dropdown 下拉菜单组件                    | `NzDropdownMenuComponent` | -       |\n| `[nzVisible]`       | 菜单是否显示，可双向绑定                 | `boolean`                 | -       |\n| `[nzActive]`        | 是否激活选中图标效果                     | `boolean`                 | `false` |\n| `[nzHasBackdrop]`   | 是否附带背景板                           | `boolean`                 | `false` |\n| `(nzVisibleChange)` | 菜单显示状态改变时调用，参数为 nzVisible | `EventEmitter<boolean>`   | -       |\n\n### [nz-virtual-scroll]\n\n虚拟滚动时配合 `ng-template` 使用, 格式为： `TemplateRef<{ $implicit: T, index: number }>`。\n\n## 注意\n\n为了获得更好的性能，NG-ZORRO 所有组件都运行在 [OnPush](https://angular.cn/guide/components/advanced-configuration#changedetectionstrategy) 模式下，这意味着对 `@Input()` 数据的 mutate 将不会生效，请使用 immutable 方式操作数组或者对象。\n\n```typescript\n// 增加数据\nthis.dataSet = [\n  ...this.dataSet,\n  {\n    key: `${this.i}`,\n    name: `Edward King ${this.i}`,\n    age: '32',\n    address: `London, Park Lane no. ${this.i}`\n  }\n];\n// 删除数据\nthis.dataSet = this.dataSet.filter(d => d.key !== i);\n```\n\n开发者也可以使用 [immer](https://immerjs.github.io/immer/docs/introduction) 获得更好的操作体验。\n"
  },
  {
    "path": "components/table/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/table/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/table/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './src/table.module';\nexport * from './src/table.types';\nexport * from './src/table-data.service';\nexport * from './src/table-style.service';\nexport * from './src/table/table.component';\nexport * from './src/table/table-content.component';\nexport * from './src/table/table-fixed-row.component';\nexport * from './src/table/table-inner-default.component';\nexport * from './src/table/table-inner-scroll.component';\nexport * from './src/table/table-virtual-scroll.directive';\nexport * from './src/table/table-fixed-row.component';\nexport * from './src/table/tbody.component';\nexport * from './src/table/thead.component';\nexport * from './src/table/tfoot-summary.component';\nexport * from './src/table/tr.directive';\nexport * from './src/table/tr-expand.directive';\nexport * from './src/table/title-footer.component';\nexport * from './src/table/tr-measure.component';\nexport * from './src/cell/cell-fixed.directive';\nexport * from './src/cell/cell.directive';\nexport * from './src/cell/custom-column.directive';\nexport * from './src/cell/th-measure.directive';\nexport * from './src/cell/td-addon.component';\nexport * from './src/cell/th-selection.component';\nexport * from './src/cell/th-addon.component';\nexport * from './src/addon/filter.component';\nexport * from './src/addon/row-expand-button.directive';\nexport * from './src/addon/row-indent.directive';\nexport * from './src/addon/selection.component';\nexport * from './src/addon/sorters.component';\nexport * from './src/addon/filter-trigger.component';\nexport * from './src/styled/align.directive';\nexport * from './src/styled/ellipsis.directive';\nexport * from './src/styled/word-break.directive';\n"
  },
  {
    "path": "components/table/src/addon/filter-trigger.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ElementRef,\n  EventEmitter,\n  Input,\n  OnInit,\n  Output,\n  ViewChild,\n  ViewEncapsulation,\n  booleanAttribute,\n  DestroyRef,\n  inject\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { NzConfigKey, NzConfigService, WithConfig } from 'ng-zorro-antd/core/config';\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\nimport { NzDropdownDirective, NzDropdownModule, NzDropdownMenuComponent } from 'ng-zorro-antd/dropdown';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'filterTrigger';\n\n@Component({\n  selector: 'nz-filter-trigger',\n  exportAs: `nzFilterTrigger`,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <span\n      nz-dropdown\n      class=\"ant-table-filter-trigger\"\n      nzTrigger=\"click\"\n      nzPlacement=\"bottomRight\"\n      [nzBackdrop]=\"nzBackdrop\"\n      [nzClickHide]=\"false\"\n      [nzDropdownMenu]=\"nzDropdownMenu\"\n      [class.active]=\"nzActive\"\n      [class.ant-table-filter-open]=\"nzVisible\"\n      [nzVisible]=\"nzVisible\"\n      (nzVisibleChange)=\"onVisibleChange($event)\"\n    >\n      <ng-content />\n    </span>\n  `,\n  imports: [NzDropdownModule]\n})\nexport class NzFilterTriggerComponent implements OnInit {\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  public readonly nzConfigService = inject(NzConfigService);\n  private readonly cdr = inject(ChangeDetectorRef);\n  private readonly destroyRef = inject(DestroyRef);\n\n  @Input() nzActive = false;\n  @Input() nzDropdownMenu!: NzDropdownMenuComponent;\n  @Input() nzVisible = false;\n\n  @Input({ transform: booleanAttribute }) @WithConfig() nzBackdrop = false;\n\n  @Output() readonly nzVisibleChange = new EventEmitter<boolean>();\n\n  @ViewChild(NzDropdownDirective, { static: true, read: ElementRef }) nzDropdown!: ElementRef<HTMLElement>;\n\n  onVisibleChange(visible: boolean): void {\n    this.nzVisible = visible;\n    this.nzVisibleChange.next(visible);\n  }\n\n  hide(): void {\n    this.nzVisible = false;\n    this.cdr.markForCheck();\n  }\n\n  show(): void {\n    this.nzVisible = true;\n    this.cdr.markForCheck();\n  }\n\n  ngOnInit(): void {\n    fromEventOutsideAngular(this.nzDropdown.nativeElement, 'click')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(event => event.stopPropagation());\n  }\n}\n"
  },
  {
    "path": "components/table/src/addon/filter.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DestroyRef,\n  EventEmitter,\n  inject,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  SimpleChanges,\n  TemplateRef,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzCheckboxModule } from 'ng-zorro-antd/checkbox';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { arraysEqual } from 'ng-zorro-antd/core/util';\nimport { NzDropdownModule } from 'ng-zorro-antd/dropdown';\nimport { NzI18nService, NzTableI18nInterface } from 'ng-zorro-antd/i18n';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzRadioComponent } from 'ng-zorro-antd/radio';\n\nimport { NzTableFilterList } from '../table.types';\nimport { NzFilterTriggerComponent } from './filter-trigger.component';\n\ninterface NzThItemInterface {\n  text: string;\n  value: NzSafeAny;\n  checked: boolean;\n}\n\n@Component({\n  selector: 'nz-table-filter',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <span class=\"ant-table-column-title\">\n      <ng-template [ngTemplateOutlet]=\"contentTemplate\" />\n    </span>\n    @if (!customFilter) {\n      <nz-filter-trigger\n        [nzVisible]=\"isVisible\"\n        [nzActive]=\"isChecked\"\n        [nzDropdownMenu]=\"filterMenu\"\n        (nzVisibleChange)=\"onVisibleChange($event)\"\n      >\n        <nz-icon nzType=\"filter\" nzTheme=\"fill\" />\n      </nz-filter-trigger>\n      <nz-dropdown-menu #filterMenu=\"nzDropdownMenu\">\n        <div class=\"ant-table-filter-dropdown\">\n          <ul nz-menu>\n            @for (f of listOfParsedFilter; track f.value) {\n              <li nz-menu-item [nzSelected]=\"f.checked\" (click)=\"check(f)\">\n                @if (!filterMultiple) {\n                  <label nz-radio [ngModel]=\"f.checked\" (ngModelChange)=\"check(f)\"></label>\n                } @else {\n                  <label nz-checkbox [ngModel]=\"f.checked\" (ngModelChange)=\"check(f)\"></label>\n                }\n                <span>{{ f.text }}</span>\n              </li>\n            }\n          </ul>\n          <div class=\"ant-table-filter-dropdown-btns\">\n            <button nz-button nzType=\"link\" nzSize=\"small\" (click)=\"reset()\" [disabled]=\"!isChecked\">\n              {{ locale.filterReset }}\n            </button>\n            <button nz-button nzType=\"primary\" nzSize=\"small\" (click)=\"confirm()\">{{ locale.filterConfirm }}</button>\n          </div>\n        </div>\n      </nz-dropdown-menu>\n    } @else {\n      <ng-container [ngTemplateOutlet]=\"extraTemplate\" />\n    }\n  `,\n  host: { class: 'ant-table-filter-column' },\n  imports: [\n    NgTemplateOutlet,\n    NzFilterTriggerComponent,\n    NzIconModule,\n    NzDropdownModule,\n    NzRadioComponent,\n    NzCheckboxModule,\n    FormsModule,\n    NzButtonModule\n  ]\n})\nexport class NzTableFilterComponent implements OnChanges, OnInit {\n  private readonly cdr = inject(ChangeDetectorRef);\n  private readonly i18n = inject(NzI18nService);\n  private readonly destroyRef = inject(DestroyRef);\n\n  @Input() contentTemplate: TemplateRef<NzSafeAny> | null = null;\n  @Input() customFilter = false;\n  @Input() extraTemplate: TemplateRef<NzSafeAny> | null = null;\n  @Input() filterMultiple = true;\n  @Input() listOfFilter: NzTableFilterList = [];\n  @Output() readonly filterChange = new EventEmitter<NzSafeAny[] | NzSafeAny>();\n  locale!: NzTableI18nInterface;\n  isChecked = false;\n  isVisible = false;\n  listOfParsedFilter: NzThItemInterface[] = [];\n  listOfChecked: NzSafeAny[] = [];\n\n  check(filter: NzThItemInterface): void {\n    if (this.filterMultiple) {\n      this.listOfParsedFilter = this.listOfParsedFilter.map(item => {\n        if (item === filter) {\n          return { ...item, checked: !filter.checked };\n        } else {\n          return item;\n        }\n      });\n      filter.checked = !filter.checked;\n    } else {\n      this.listOfParsedFilter = this.listOfParsedFilter.map(item => ({ ...item, checked: item === filter }));\n    }\n    this.isChecked = this.getCheckedStatus(this.listOfParsedFilter);\n  }\n\n  confirm(): void {\n    this.isVisible = false;\n    this.emitFilterData();\n  }\n\n  reset(): void {\n    this.isVisible = false;\n    this.listOfParsedFilter = this.parseListOfFilter(this.listOfFilter, true);\n    this.isChecked = this.getCheckedStatus(this.listOfParsedFilter);\n    this.emitFilterData();\n  }\n\n  onVisibleChange(value: boolean): void {\n    this.isVisible = value;\n    if (!value) {\n      this.emitFilterData();\n    } else {\n      this.listOfChecked = this.listOfParsedFilter.filter(item => item.checked).map(item => item.value);\n    }\n  }\n\n  emitFilterData(): void {\n    const listOfChecked = this.listOfParsedFilter.filter(item => item.checked).map(item => item.value);\n    if (!arraysEqual(this.listOfChecked, listOfChecked)) {\n      if (this.filterMultiple) {\n        this.filterChange.emit(listOfChecked);\n      } else {\n        this.filterChange.emit(listOfChecked.length > 0 ? listOfChecked[0] : null);\n      }\n    }\n  }\n\n  parseListOfFilter(listOfFilter: NzTableFilterList, reset?: boolean): NzThItemInterface[] {\n    return listOfFilter.map(item => {\n      const checked = reset ? false : !!item.byDefault;\n      return { text: item.text, value: item.value, checked };\n    });\n  }\n\n  getCheckedStatus(listOfParsedFilter: NzThItemInterface[]): boolean {\n    return listOfParsedFilter.some(item => item.checked);\n  }\n\n  ngOnInit(): void {\n    this.i18n.localeChange.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      this.locale = this.i18n.getLocaleData('Table');\n      this.cdr.markForCheck();\n    });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { listOfFilter } = changes;\n    if (listOfFilter && this.listOfFilter && this.listOfFilter.length) {\n      this.listOfParsedFilter = this.parseListOfFilter(this.listOfFilter);\n      this.isChecked = this.getCheckedStatus(this.listOfParsedFilter);\n    }\n  }\n}\n"
  },
  {
    "path": "components/table/src/addon/row-expand-button.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, EventEmitter, Input, Output } from '@angular/core';\n\n@Directive({\n  selector: 'button[nz-row-expand-button]',\n  host: {\n    class: 'ant-table-row-expand-icon',\n    '[type]': `'button'`,\n    '[class.ant-table-row-expand-icon-expanded]': `!spaceMode && expand === true`,\n    '[class.ant-table-row-expand-icon-collapsed]': `!spaceMode && expand === false`,\n    '[class.ant-table-row-expand-icon-spaced]': 'spaceMode',\n    '(click)': 'onHostClick()'\n  }\n})\nexport class NzRowExpandButtonDirective {\n  @Input() expand = false;\n  @Input() spaceMode = false;\n  @Output() readonly expandChange = new EventEmitter();\n\n  onHostClick(): void {\n    if (!this.spaceMode) {\n      this.expand = !this.expand;\n      this.expandChange.next(this.expand);\n    }\n  }\n}\n"
  },
  {
    "path": "components/table/src/addon/row-indent.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, Input } from '@angular/core';\n\n@Directive({\n  selector: 'nz-row-indent',\n  host: {\n    class: 'ant-table-row-indent',\n    '[style.padding-left.px]': 'indentSize'\n  }\n})\nexport class NzRowIndentDirective {\n  @Input() indentSize = 0;\n}\n"
  },
  {
    "path": "components/table/src/addon/selection.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, ViewEncapsulation } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCheckboxModule } from 'ng-zorro-antd/checkbox';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { NzDropdownModule } from 'ng-zorro-antd/dropdown';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-table-selection',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    @if (showCheckbox) {\n      <label\n        nz-checkbox\n        [class.ant-table-selection-select-all-custom]=\"showRowSelection\"\n        [ngModel]=\"checked\"\n        [nzDisabled]=\"disabled\"\n        [nzIndeterminate]=\"indeterminate\"\n        [attr.aria-label]=\"label\"\n        (ngModelChange)=\"onCheckedChange($event)\"\n      ></label>\n    }\n    @if (showRowSelection) {\n      <div class=\"ant-table-selection-extra\">\n        <span nz-dropdown class=\"ant-table-selection-down\" nzPlacement=\"bottomLeft\" [nzDropdownMenu]=\"selectionMenu\">\n          <nz-icon nzType=\"down\" />\n        </span>\n        <nz-dropdown-menu #selectionMenu=\"nzDropdownMenu\">\n          <ul nz-menu class=\"ant-table-selection-menu\">\n            @for (selection of listOfSelections; track selection) {\n              <li nz-menu-item (click)=\"selection.onSelect()\">\n                {{ selection.text }}\n              </li>\n            }\n          </ul>\n        </nz-dropdown-menu>\n      </div>\n    }\n  `,\n  host: { class: 'ant-table-selection' },\n  imports: [FormsModule, NzCheckboxModule, NzDropdownModule, NzIconModule]\n})\nexport class NzTableSelectionComponent {\n  @Input() listOfSelections: Array<{ text: string; onSelect(...args: NzSafeAny[]): NzSafeAny }> = [];\n  @Input() checked = false;\n  @Input() disabled = false;\n  @Input() indeterminate = false;\n  @Input() label: string | null = null;\n  @Input() showCheckbox = false;\n  @Input() showRowSelection = false;\n  @Output() readonly checkedChange = new EventEmitter<boolean>();\n\n  onCheckedChange(checked: boolean): void {\n    this.checked = checked;\n    this.checkedChange.emit(checked);\n  }\n}\n"
  },
  {
    "path": "components/table/src/addon/sorters.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  Input,\n  OnChanges,\n  SimpleChanges,\n  TemplateRef,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nimport { NzTableSortOrder } from '../table.types';\n\n@Component({\n  selector: 'nz-table-sorters',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <span class=\"ant-table-column-title\"><ng-template [ngTemplateOutlet]=\"contentTemplate\" /></span>\n    <span class=\"ant-table-column-sorter\" [class.ant-table-column-sorter-full]=\"isDown && isUp\">\n      <span class=\"ant-table-column-sorter-inner\">\n        @if (isUp) {\n          <nz-icon nzType=\"caret-up\" class=\"ant-table-column-sorter-up\" [class.active]=\"sortOrder === 'ascend'\" />\n        }\n        @if (isDown) {\n          <nz-icon nzType=\"caret-down\" class=\"ant-table-column-sorter-down\" [class.active]=\"sortOrder === 'descend'\" />\n        }\n      </span>\n    </span>\n  `,\n  host: {\n    class: 'ant-table-column-sorters'\n  },\n  imports: [NzIconModule, NgTemplateOutlet]\n})\nexport class NzTableSortersComponent implements OnChanges {\n  @Input() sortDirections: NzTableSortOrder[] = ['ascend', 'descend', null];\n  @Input() sortOrder: NzTableSortOrder = null;\n  @Input() contentTemplate: TemplateRef<NzSafeAny> | null = null;\n  isUp = false;\n  isDown = false;\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { sortDirections } = changes;\n    if (sortDirections) {\n      this.isUp = this.sortDirections.indexOf('ascend') !== -1;\n      this.isDown = this.sortDirections.indexOf('descend') !== -1;\n    }\n  }\n}\n"
  },
  {
    "path": "components/table/src/cell/cell-fixed.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, ElementRef, inject, Input, OnChanges, Renderer2 } from '@angular/core';\nimport { Subject } from 'rxjs';\n\n@Directive({\n  selector: 'td[nzRight],th[nzRight],td[nzLeft],th[nzLeft]',\n  host: {\n    '[class.ant-table-cell-fix-right]': `isFixedRight`,\n    '[class.ant-table-cell-fix-left]': `isFixedLeft`,\n    '[style.position]': `isFixed? 'sticky' : null`\n  }\n})\nexport class NzCellFixedDirective implements OnChanges {\n  private renderer = inject(Renderer2);\n  private el: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement;\n\n  @Input() nzRight: string | boolean = false;\n  @Input() nzLeft: string | boolean = false;\n  @Input() colspan: number | null = null;\n  @Input() colSpan: number | null = null;\n  changes$ = new Subject<void>();\n  isAutoLeft = false;\n  isAutoRight = false;\n  isFixedLeft = false;\n  isFixedRight = false;\n  isFixed = false;\n\n  setAutoLeftWidth(autoLeft: string | null): void {\n    this.renderer.setStyle(this.el, 'left', autoLeft);\n  }\n\n  setAutoRightWidth(autoRight: string | null): void {\n    this.renderer.setStyle(this.el, 'right', autoRight);\n  }\n\n  setIsFirstRight(isFirstRight: boolean): void {\n    this.setFixClass(isFirstRight, 'ant-table-cell-fix-right-first');\n  }\n\n  setIsLastLeft(isLastLeft: boolean): void {\n    this.setFixClass(isLastLeft, 'ant-table-cell-fix-left-last');\n  }\n\n  private setFixClass(flag: boolean, className: string): void {\n    // the setFixClass function may call many times, so remove it first.\n    this.renderer.removeClass(this.el, className);\n\n    if (flag) {\n      this.renderer.addClass(this.el, className);\n    }\n  }\n\n  ngOnChanges(): void {\n    this.setIsFirstRight(false);\n    this.setIsLastLeft(false);\n    this.isAutoLeft = this.nzLeft === '' || this.nzLeft === true;\n    this.isAutoRight = this.nzRight === '' || this.nzRight === true;\n    this.isFixedLeft = this.nzLeft !== false;\n    this.isFixedRight = this.nzRight !== false;\n    this.isFixed = this.isFixedLeft || this.isFixedRight;\n    const validatePx = (value: string | boolean): string | null => {\n      if (typeof value === 'string' && value !== '') {\n        return value;\n      } else {\n        return null;\n      }\n    };\n    this.setAutoLeftWidth(validatePx(this.nzLeft));\n    this.setAutoRightWidth(validatePx(this.nzRight));\n    this.changes$.next();\n  }\n}\n"
  },
  {
    "path": "components/table/src/cell/cell.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, inject } from '@angular/core';\n\nimport { NzTableStyleService } from '../table-style.service';\n\n@Directive({\n  selector: 'th:not(.nz-disable-th), td:not(.nz-disable-td)',\n  host: {\n    '[class.ant-table-cell]': 'isInsideTable'\n  }\n})\nexport class NzTableCellDirective {\n  isInsideTable = !!inject(NzTableStyleService, { optional: true });\n}\n"
  },
  {
    "path": "components/table/src/cell/custom-column.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { DestroyRef, Directive, ElementRef, inject, Input, OnInit, Renderer2 } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { NzTableDataService } from '../table-data.service';\n\n@Directive({\n  selector: 'td[nzCellControl],th[nzCellControl]'\n})\nexport class NzCustomColumnDirective<T> implements OnInit {\n  private el: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement;\n  private renderer = inject(Renderer2);\n  private nzTableDataService = inject(NzTableDataService<T>);\n  private destroyRef = inject(DestroyRef);\n\n  @Input() nzCellControl: string | null = null;\n\n  ngOnInit(): void {\n    this.nzTableDataService.listOfCustomColumn$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(item => {\n      item.forEach((v, i) => {\n        if (v.value === this.nzCellControl) {\n          this.renderer.setStyle(this.el, 'display', v.default ? 'block' : 'none');\n          this.renderer.setStyle(this.el, 'order', i);\n          this.renderer.setStyle(this.el, 'flex', v.fixWidth ? `1 0 ${v.width}px` : `1 1 ${v.width}px`);\n        }\n      });\n    });\n  }\n}\n"
  },
  {
    "path": "components/table/src/cell/td-addon.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\n/* eslint-disable @angular-eslint/component-selector */\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  EventEmitter,\n  Input,\n  OnChanges,\n  Output,\n  SimpleChange,\n  SimpleChanges,\n  TemplateRef,\n  ViewEncapsulation,\n  booleanAttribute\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzCheckboxModule } from 'ng-zorro-antd/checkbox';\n\nimport { NzRowExpandButtonDirective } from '../addon/row-expand-button.directive';\nimport { NzRowIndentDirective } from '../addon/row-indent.directive';\n\n@Component({\n  selector:\n    'td[nzChecked], td[nzDisabled], td[nzIndeterminate], td[nzIndentSize], td[nzExpand], td[nzShowExpand], td[nzShowCheckbox]',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    @if (nzShowExpand || nzIndentSize > 0) {\n      <nz-row-indent [indentSize]=\"nzIndentSize\" />\n      @if (nzExpandIcon) {\n        <ng-template [ngTemplateOutlet]=\"nzExpandIcon\" />\n      } @else {\n        <button\n          nz-row-expand-button\n          [expand]=\"nzExpand\"\n          (expandChange)=\"onExpandChange($event)\"\n          [spaceMode]=\"!nzShowExpand\"\n        ></button>\n      }\n    }\n    @if (nzShowCheckbox) {\n      <label\n        nz-checkbox\n        [nzDisabled]=\"nzDisabled\"\n        [ngModel]=\"nzChecked\"\n        [nzIndeterminate]=\"nzIndeterminate\"\n        [attr.aria-label]=\"nzLabel\"\n        (ngModelChange)=\"onCheckedChange($event)\"\n      ></label>\n    }\n    <ng-content />\n  `,\n  host: {\n    '[class.ant-table-cell-with-append]': `nzShowExpand || nzIndentSize > 0`,\n    '[class.ant-table-selection-column]': `nzShowCheckbox`\n  },\n  imports: [NzRowIndentDirective, NzRowExpandButtonDirective, NgTemplateOutlet, NzCheckboxModule, FormsModule]\n})\nexport class NzTdAddOnComponent implements OnChanges {\n  @Input() nzChecked = false;\n  @Input() nzDisabled = false;\n  @Input() nzIndeterminate = false;\n  @Input() nzLabel: string | null = null;\n  @Input() nzIndentSize = 0;\n  @Input({ transform: booleanAttribute }) nzShowExpand = false;\n  @Input({ transform: booleanAttribute }) nzShowCheckbox = false;\n  @Input({ transform: booleanAttribute }) nzExpand = false;\n  @Input() nzExpandIcon: TemplateRef<void> | null = null;\n  @Output() readonly nzCheckedChange = new EventEmitter<boolean>();\n  @Output() readonly nzExpandChange = new EventEmitter<boolean>();\n  private isNzShowExpandChanged = false;\n  private isNzShowCheckboxChanged = false;\n\n  onCheckedChange(checked: boolean): void {\n    this.nzChecked = checked;\n    this.nzCheckedChange.emit(checked);\n  }\n\n  onExpandChange(expand: boolean): void {\n    this.nzExpand = expand;\n    this.nzExpandChange.emit(expand);\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const isFirstChange = (value: SimpleChange): boolean =>\n      value && value.firstChange && value.currentValue !== undefined;\n    const { nzExpand, nzChecked, nzShowExpand, nzShowCheckbox } = changes;\n    if (nzShowExpand) {\n      this.isNzShowExpandChanged = true;\n    }\n    if (nzShowCheckbox) {\n      this.isNzShowCheckboxChanged = true;\n    }\n    if (isFirstChange(nzExpand) && !this.isNzShowExpandChanged) {\n      this.nzShowExpand = true;\n    }\n    if (isFirstChange(nzChecked) && !this.isNzShowCheckboxChanged) {\n      this.nzShowCheckbox = true;\n    }\n  }\n}\n"
  },
  {
    "path": "components/table/src/cell/th-addon.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\n/* eslint-disable @angular-eslint/component-selector */\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ElementRef,\n  EventEmitter,\n  Input,\n  NgZone,\n  OnChanges,\n  OnInit,\n  Output,\n  SimpleChange,\n  SimpleChanges,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject,\n  DestroyRef\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Subject } from 'rxjs';\nimport { filter } from 'rxjs/operators';\n\nimport { NzConfigKey, NzConfigService, WithConfig } from 'ng-zorro-antd/core/config';\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\n\nimport { NzTableFilterComponent } from '../addon/filter.component';\nimport { NzTableSortersComponent } from '../addon/sorters.component';\nimport {\n  NzTableFilterFn,\n  NzTableFilterList,\n  NzTableFilterValue,\n  NzTableSortFn,\n  NzTableSortOrder\n} from '../table.types';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'table';\n\n@Component({\n  selector:\n    'th[nzColumnKey], th[nzSortFn], th[nzSortOrder], th[nzFilters], th[nzShowSort], th[nzShowFilter], th[nzCustomFilter]',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    @if (nzShowFilter || nzCustomFilter) {\n      <nz-table-filter\n        [contentTemplate]=\"notFilterTemplate\"\n        [extraTemplate]=\"extraTemplate\"\n        [customFilter]=\"nzCustomFilter\"\n        [filterMultiple]=\"nzFilterMultiple\"\n        [listOfFilter]=\"nzFilters\"\n        (filterChange)=\"onFilterValueChange($event)\"\n      />\n    } @else {\n      <ng-container [ngTemplateOutlet]=\"notFilterTemplate\" />\n    }\n    <ng-template #notFilterTemplate>\n      <ng-template [ngTemplateOutlet]=\"nzShowSort ? sortTemplate : contentTemplate\" />\n    </ng-template>\n    <ng-template #extraTemplate>\n      <ng-content select=\"[nz-th-extra]\" />\n      <ng-content select=\"nz-filter-trigger\" />\n    </ng-template>\n    <ng-template #sortTemplate>\n      <nz-table-sorters [sortOrder]=\"sortOrder\" [sortDirections]=\"sortDirections\" [contentTemplate]=\"contentTemplate\" />\n    </ng-template>\n    <ng-template #contentTemplate>\n      <ng-content />\n    </ng-template>\n  `,\n  host: {\n    '[class.ant-table-column-has-sorters]': 'nzShowSort',\n    '[class.ant-table-column-sort]': `sortOrder === 'descend' || sortOrder === 'ascend'`\n  },\n  imports: [NzTableFilterComponent, NgTemplateOutlet, NzTableSortersComponent]\n})\nexport class NzThAddOnComponent<T> implements OnChanges, OnInit {\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  nzConfigService = inject(NzConfigService);\n  private el: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement;\n  private destroyRef = inject(DestroyRef);\n  private cdr = inject(ChangeDetectorRef);\n  private ngZone = inject(NgZone);\n\n  manualClickOrder$ = new Subject<NzThAddOnComponent<T>>();\n  calcOperatorChange$ = new Subject<void>();\n  nzFilterValue: NzTableFilterValue = null;\n  sortOrder: NzTableSortOrder = null;\n  sortDirections: NzTableSortOrder[] = ['ascend', 'descend', null];\n  private sortOrderChange$ = new Subject<NzTableSortOrder>();\n  private isNzShowSortChanged = false;\n  private isNzShowFilterChanged = false;\n  @Input() nzColumnKey?: string;\n  @Input() nzFilterMultiple = true;\n  @Input() nzSortOrder: NzTableSortOrder = null;\n  @Input() nzSortPriority: number | boolean = false;\n  @Input() @WithConfig() nzSortDirections: NzTableSortOrder[] = ['ascend', 'descend', null];\n  @Input() nzFilters: NzTableFilterList = [];\n  @Input() nzSortFn: NzTableSortFn<T> | boolean | null = null;\n  @Input() nzFilterFn: NzTableFilterFn<T> | boolean | null = null;\n  @Input({ transform: booleanAttribute }) nzShowSort = false;\n  @Input({ transform: booleanAttribute }) nzShowFilter = false;\n  @Input({ transform: booleanAttribute }) nzCustomFilter = false;\n  @Output() readonly nzCheckedChange = new EventEmitter<boolean>();\n  @Output() readonly nzSortOrderChange = new EventEmitter<string | null>();\n  @Output() readonly nzFilterChange = new EventEmitter<NzTableFilterValue>();\n\n  getNextSortDirection(sortDirections: NzTableSortOrder[], current: NzTableSortOrder): NzTableSortOrder {\n    const index = sortDirections.indexOf(current);\n    if (index === sortDirections.length - 1) {\n      return sortDirections[0];\n    } else {\n      return sortDirections[index + 1];\n    }\n  }\n\n  setSortOrder(order: NzTableSortOrder): void {\n    this.sortOrderChange$.next(order);\n  }\n\n  clearSortOrder(): void {\n    if (this.sortOrder !== null) {\n      this.setSortOrder(null);\n    }\n  }\n\n  onFilterValueChange(value: NzTableFilterValue): void {\n    this.nzFilterChange.emit(value);\n    this.nzFilterValue = value;\n    this.updateCalcOperator();\n  }\n\n  updateCalcOperator(): void {\n    this.calcOperatorChange$.next();\n  }\n\n  ngOnInit(): void {\n    fromEventOutsideAngular(this.el, 'click')\n      .pipe(\n        filter(() => this.nzShowSort),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(() => {\n        const nextOrder = this.getNextSortDirection(this.sortDirections, this.sortOrder!);\n        this.ngZone.run(() => {\n          this.setSortOrder(nextOrder);\n          this.manualClickOrder$.next(this);\n        });\n      });\n\n    this.sortOrderChange$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(order => {\n      if (this.sortOrder !== order) {\n        this.sortOrder = order;\n        this.nzSortOrderChange.emit(order);\n      }\n      this.updateCalcOperator();\n      this.cdr.markForCheck();\n    });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const {\n      nzSortDirections,\n      nzFilters,\n      nzSortOrder,\n      nzSortFn,\n      nzFilterFn,\n      nzSortPriority,\n      nzFilterMultiple,\n      nzShowSort,\n      nzShowFilter\n    } = changes;\n    if (nzSortDirections) {\n      if (this.nzSortDirections && this.nzSortDirections.length) {\n        this.sortDirections = this.nzSortDirections;\n      }\n    }\n    if (nzSortOrder) {\n      this.sortOrder = this.nzSortOrder;\n      this.setSortOrder(this.nzSortOrder);\n    }\n    if (nzShowSort) {\n      this.isNzShowSortChanged = true;\n    }\n    if (nzShowFilter) {\n      this.isNzShowFilterChanged = true;\n    }\n    const isFirstChange = (value: SimpleChange): boolean =>\n      value && value.firstChange && value.currentValue !== undefined;\n    if ((isFirstChange(nzSortOrder) || isFirstChange(nzSortFn)) && !this.isNzShowSortChanged) {\n      this.nzShowSort = true;\n    }\n    if (isFirstChange(nzFilters) && !this.isNzShowFilterChanged) {\n      this.nzShowFilter = true;\n    }\n    if ((nzFilters || nzFilterMultiple) && this.nzShowFilter) {\n      const listOfValue = this.nzFilters.filter(item => item.byDefault).map(item => item.value);\n      this.nzFilterValue = this.nzFilterMultiple ? listOfValue : listOfValue[0] || null;\n    }\n    if (nzSortFn || nzFilterFn || nzSortPriority || nzFilters) {\n      this.updateCalcOperator();\n    }\n  }\n}\n"
  },
  {
    "path": "components/table/src/cell/th-measure.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, ElementRef, inject, Input, OnChanges, Renderer2, SimpleChanges } from '@angular/core';\nimport { Subject } from 'rxjs';\n\nimport { isNil } from 'ng-zorro-antd/core/util';\n\n@Directive({\n  selector: 'th'\n})\nexport class NzThMeasureDirective implements OnChanges {\n  private renderer = inject(Renderer2);\n  private el: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement;\n\n  changes$ = new Subject<void>();\n  @Input() nzWidth: string | null = null;\n  @Input() colspan: string | number | null = null;\n  @Input() colSpan: string | number | null = null;\n  @Input() rowspan: string | number | null = null;\n  @Input() rowSpan: string | number | null = null;\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzWidth, colspan, rowspan, colSpan, rowSpan } = changes;\n    if (colspan || colSpan) {\n      const col = this.colspan || this.colSpan;\n      if (!isNil(col)) {\n        this.renderer.setAttribute(this.el, 'colspan', `${col}`);\n      } else {\n        this.renderer.removeAttribute(this.el, 'colspan');\n      }\n    }\n    if (rowspan || rowSpan) {\n      const row = this.rowspan || this.rowSpan;\n      if (!isNil(row)) {\n        this.renderer.setAttribute(this.el, 'rowspan', `${row}`);\n      } else {\n        this.renderer.removeAttribute(this.el, 'rowspan');\n      }\n    }\n    if (nzWidth || colspan) {\n      this.changes$.next();\n    }\n  }\n}\n"
  },
  {
    "path": "components/table/src/cell/th-selection.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\n/* eslint-disable @angular-eslint/component-selector */\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  EventEmitter,\n  Input,\n  OnChanges,\n  Output,\n  SimpleChange,\n  SimpleChanges,\n  ViewEncapsulation,\n  booleanAttribute\n} from '@angular/core';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzTableSelectionComponent } from '../addon/selection.component';\n\n@Component({\n  selector: 'th[nzSelections],th[nzChecked],th[nzShowCheckbox],th[nzShowRowSelection]',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    <nz-table-selection\n      [checked]=\"nzChecked\"\n      [disabled]=\"nzDisabled\"\n      [indeterminate]=\"nzIndeterminate\"\n      [label]=\"nzLabel\"\n      [listOfSelections]=\"nzSelections\"\n      [showCheckbox]=\"nzShowCheckbox\"\n      [showRowSelection]=\"nzShowRowSelection\"\n      (checkedChange)=\"onCheckedChange($event)\"\n    />\n    <ng-content />\n  `,\n  host: { class: 'ant-table-selection-column' },\n  imports: [NzTableSelectionComponent]\n})\nexport class NzThSelectionComponent implements OnChanges {\n  @Input() nzSelections: Array<{ text: string; onSelect(...args: NzSafeAny[]): NzSafeAny }> = [];\n  @Input({ transform: booleanAttribute }) nzChecked = false;\n  @Input({ transform: booleanAttribute }) nzDisabled = false;\n  @Input() nzIndeterminate = false;\n  @Input() nzLabel: string | null = null;\n  @Input({ transform: booleanAttribute }) nzShowCheckbox = false;\n  @Input({ transform: booleanAttribute }) nzShowRowSelection = false;\n  @Output() readonly nzCheckedChange = new EventEmitter<boolean>();\n\n  private isNzShowExpandChanged = false;\n  private isNzShowCheckboxChanged = false;\n\n  onCheckedChange(checked: boolean): void {\n    this.nzChecked = checked;\n    this.nzCheckedChange.emit(checked);\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const isFirstChange = (value: SimpleChange): boolean =>\n      value && value.firstChange && value.currentValue !== undefined;\n    const { nzChecked, nzSelections, nzShowExpand, nzShowCheckbox } = changes;\n    if (nzShowExpand) {\n      this.isNzShowExpandChanged = true;\n    }\n    if (nzShowCheckbox) {\n      this.isNzShowCheckboxChanged = true;\n    }\n    if (isFirstChange(nzSelections) && !this.isNzShowExpandChanged) {\n      this.nzShowRowSelection = true;\n    }\n    if (isFirstChange(nzChecked) && !this.isNzShowCheckboxChanged) {\n      this.nzShowCheckbox = true;\n    }\n  }\n}\n"
  },
  {
    "path": "components/table/src/styled/align.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, Input } from '@angular/core';\n\n@Directive({\n  selector: 'th[nzAlign],td[nzAlign]',\n  host: {\n    '[style.text-align]': 'nzAlign'\n  }\n})\nexport class NzCellAlignDirective {\n  @Input() nzAlign: 'left' | 'right' | 'center' | null = null;\n}\n"
  },
  {
    "path": "components/table/src/styled/ellipsis.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, Input, booleanAttribute } from '@angular/core';\n\n@Directive({\n  selector: 'th[nzEllipsis],td[nzEllipsis]',\n  host: {\n    '[class.ant-table-cell-ellipsis]': 'nzEllipsis'\n  }\n})\nexport class NzCellEllipsisDirective {\n  @Input({ transform: booleanAttribute }) nzEllipsis = true;\n}\n"
  },
  {
    "path": "components/table/src/styled/word-break.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, Input, booleanAttribute } from '@angular/core';\n\n@Directive({\n  selector: 'th[nzBreakWord],td[nzBreakWord]',\n  host: {\n    '[style.word-break]': `nzBreakWord ? 'break-all' : ''`\n  }\n})\nexport class NzCellBreakWordDirective {\n  @Input({ transform: booleanAttribute }) nzBreakWord = true;\n}\n"
  },
  {
    "path": "components/table/src/table/table-content.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, Input, TemplateRef, ViewEncapsulation } from '@angular/core';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzTableLayout } from '../table.types';\n\n@Component({\n  selector: 'table[nz-table-content]',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    @if (listOfColWidth.length > 0) {\n      <colgroup>\n        @for (width of listOfColWidth; track $index) {\n          <col [style.width]=\"width\" [style.minWidth]=\"width\" />\n        }\n      </colgroup>\n    }\n    @if (theadTemplate) {\n      <thead class=\"ant-table-thead\">\n        <ng-template [ngTemplateOutlet]=\"theadTemplate\" />\n      </thead>\n    }\n    <ng-template [ngTemplateOutlet]=\"contentTemplate\" />\n    <ng-content />\n    @if (tfootTemplate) {\n      <tfoot class=\"ant-table-summary\">\n        <ng-template [ngTemplateOutlet]=\"tfootTemplate\" />\n      </tfoot>\n    }\n  `,\n  host: {\n    '[style.table-layout]': 'tableLayout',\n    '[class.ant-table-fixed]': 'scrollX',\n    '[style.width]': 'scrollX',\n    '[style.min-width]': `scrollX ? '100%' : null`\n  },\n  imports: [NgTemplateOutlet]\n})\nexport class NzTableContentComponent {\n  @Input() tableLayout: NzTableLayout = 'auto';\n  @Input() theadTemplate: TemplateRef<NzSafeAny> | null = null;\n  @Input() contentTemplate: TemplateRef<NzSafeAny> | null = null;\n  @Input() tfootTemplate: TemplateRef<NzSafeAny> | null = null;\n  @Input() listOfColWidth: ReadonlyArray<string | null> = [];\n  @Input() scrollX: string | null = null;\n}\n"
  },
  {
    "path": "components/table/src/table/table-fixed-row.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { AsyncPipe, NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterViewInit,\n  ChangeDetectionStrategy,\n  Component,\n  DestroyRef,\n  ElementRef,\n  inject,\n  OnInit,\n  Renderer2,\n  ViewChild,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { BehaviorSubject } from 'rxjs';\n\nimport { NzTableStyleService } from '../table-style.service';\n\n@Component({\n  selector: 'tr[nz-table-fixed-row], tr[nzExpand]',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <td class=\"nz-disable-td ant-table-cell\" #tdElement>\n      @if (enableAutoMeasure$ | async) {\n        <div\n          class=\"ant-table-expanded-row-fixed\"\n          style=\"position: sticky; left: 0; overflow: hidden;\"\n          [style.width.px]=\"hostWidth$ | async\"\n        >\n          <ng-template [ngTemplateOutlet]=\"contentTemplate\" />\n        </div>\n      } @else {\n        <ng-template [ngTemplateOutlet]=\"contentTemplate\" />\n      }\n    </td>\n    <ng-template #contentTemplate>\n      <ng-content />\n    </ng-template>\n  `,\n  imports: [AsyncPipe, NgTemplateOutlet]\n})\nexport class NzTableFixedRowComponent implements OnInit, AfterViewInit {\n  private nzTableStyleService = inject(NzTableStyleService);\n  private renderer = inject(Renderer2);\n  private destroyRef = inject(DestroyRef);\n\n  @ViewChild('tdElement', { static: true }) tdElement!: ElementRef;\n  hostWidth$ = new BehaviorSubject<number | null>(null);\n  enableAutoMeasure$ = new BehaviorSubject<boolean>(false);\n\n  ngOnInit(): void {\n    if (this.nzTableStyleService) {\n      const { enableAutoMeasure$, hostWidth$ } = this.nzTableStyleService;\n      enableAutoMeasure$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(this.enableAutoMeasure$);\n      hostWidth$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(this.hostWidth$);\n    }\n  }\n\n  ngAfterViewInit(): void {\n    this.nzTableStyleService.columnCount$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(count => {\n      this.renderer.setAttribute(this.tdElement.nativeElement, 'colspan', `${count}`);\n    });\n  }\n}\n"
  },
  {
    "path": "components/table/src/table/table-inner-default.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, Input, TemplateRef, ViewEncapsulation } from '@angular/core';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzTableLayout } from '../table.types';\nimport { NzTableContentComponent } from './table-content.component';\n\n@Component({\n  selector: 'nz-table-inner-default',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <div class=\"ant-table-content\">\n      <table\n        nz-table-content\n        [contentTemplate]=\"contentTemplate\"\n        [tableLayout]=\"tableLayout\"\n        [listOfColWidth]=\"listOfColWidth\"\n        [theadTemplate]=\"theadTemplate\"\n        [tfootTemplate]=\"tfootTemplate\"\n      ></table>\n    </div>\n  `,\n  host: { class: 'ant-table-container' },\n  imports: [NzTableContentComponent]\n})\nexport class NzTableInnerDefaultComponent {\n  @Input() tableLayout: NzTableLayout = 'auto';\n  @Input() listOfColWidth: ReadonlyArray<string | null> = [];\n  @Input() theadTemplate: TemplateRef<NzSafeAny> | null = null;\n  @Input() contentTemplate: TemplateRef<NzSafeAny> | null = null;\n  @Input() tfootTemplate: TemplateRef<NzSafeAny> | null = null;\n}\n"
  },
  {
    "path": "components/table/src/table/table-inner-scroll.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Platform } from '@angular/cdk/platform';\nimport { CdkVirtualScrollViewport, ScrollingModule } from '@angular/cdk/scrolling';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterViewInit,\n  ChangeDetectionStrategy,\n  Component,\n  DestroyRef,\n  ElementRef,\n  inject,\n  Input,\n  NgZone,\n  OnChanges,\n  Renderer2,\n  SimpleChanges,\n  TemplateRef,\n  TrackByFunction,\n  ViewChild,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { merge, Subject } from 'rxjs';\nimport { delay, filter, startWith, switchMap } from 'rxjs/operators';\n\nimport { NzResizeService } from 'ng-zorro-antd/core/services';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\n\nimport { NzTableSummaryFixedType } from '../table.types';\nimport { NzTableContentComponent } from './table-content.component';\nimport { NzTbodyComponent } from './tbody.component';\n\n@Component({\n  selector: 'nz-table-inner-scroll',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    @if (scrollY) {\n      <div #tableHeaderElement [style]=\"headerStyleMap\" class=\"ant-table-header nz-table-hide-scrollbar\">\n        <table\n          nz-table-content\n          tableLayout=\"fixed\"\n          [scrollX]=\"scrollX\"\n          [listOfColWidth]=\"listOfColWidth\"\n          [theadTemplate]=\"theadTemplate\"\n          [tfootTemplate]=\"tfootFixed === 'top' ? tfootTemplate : null\"\n        ></table>\n      </div>\n      @if (!virtualTemplate) {\n        <div #tableBodyElement cdkScrollable class=\"ant-table-body\" [style]=\"bodyStyleMap\">\n          <table\n            nz-table-content\n            tableLayout=\"fixed\"\n            [scrollX]=\"scrollX\"\n            [listOfColWidth]=\"listOfColWidth\"\n            [contentTemplate]=\"contentTemplate\"\n          ></table>\n        </div>\n      } @else {\n        <cdk-virtual-scroll-viewport\n          #tableBodyElement\n          [itemSize]=\"virtualItemSize\"\n          [maxBufferPx]=\"virtualMaxBufferPx\"\n          [minBufferPx]=\"virtualMinBufferPx\"\n          [style.height]=\"data.length ? scrollY : noDataVirtualHeight\"\n        >\n          <table nz-table-content tableLayout=\"fixed\" [scrollX]=\"scrollX\" [listOfColWidth]=\"listOfColWidth\">\n            <tbody>\n              <ng-container *cdkVirtualFor=\"let item of data; let i = index; trackBy: virtualForTrackBy\">\n                <ng-template\n                  [ngTemplateOutlet]=\"virtualTemplate\"\n                  [ngTemplateOutletContext]=\"{ $implicit: item, index: i }\"\n                />\n              </ng-container>\n            </tbody>\n          </table>\n        </cdk-virtual-scroll-viewport>\n      }\n      @if (tfootFixed === 'bottom') {\n        <div #tableFootElement class=\"ant-table-summary\" [style]=\"headerStyleMap\">\n          <table\n            nz-table-content\n            tableLayout=\"fixed\"\n            [scrollX]=\"scrollX\"\n            [listOfColWidth]=\"listOfColWidth\"\n            [tfootTemplate]=\"tfootTemplate\"\n          ></table>\n        </div>\n      }\n    } @else {\n      <div class=\"ant-table-content\" #tableBodyElement [style]=\"bodyStyleMap\">\n        <table\n          nz-table-content\n          tableLayout=\"fixed\"\n          [scrollX]=\"scrollX\"\n          [listOfColWidth]=\"listOfColWidth\"\n          [theadTemplate]=\"theadTemplate\"\n          [contentTemplate]=\"contentTemplate\"\n          [tfootTemplate]=\"tfootTemplate\"\n        ></table>\n      </div>\n    }\n  `,\n  host: { class: 'ant-table-container' },\n  imports: [NzTableContentComponent, ScrollingModule, NgTemplateOutlet, NzTbodyComponent]\n})\nexport class NzTableInnerScrollComponent<T> implements OnChanges, AfterViewInit {\n  private renderer = inject(Renderer2);\n  private ngZone = inject(NgZone);\n  private platform = inject(Platform);\n  private resizeService = inject(NzResizeService);\n  private destroyRef = inject(DestroyRef);\n\n  @Input() data: readonly T[] = [];\n  @Input() scrollX: string | null = null;\n  @Input() scrollY: string | null = null;\n  @Input() contentTemplate: TemplateRef<NzSafeAny> | null = null;\n  @Input() widthConfig: string[] = [];\n  @Input() listOfColWidth: ReadonlyArray<string | null> = [];\n  @Input() theadTemplate: TemplateRef<NzSafeAny> | null = null;\n  @Input() tfootTemplate: TemplateRef<NzSafeAny> | null = null;\n  @Input() tfootFixed: NzTableSummaryFixedType | null = null;\n  @Input() virtualTemplate: TemplateRef<NzSafeAny> | null = null;\n  @Input() virtualItemSize = 0;\n  @Input() virtualMaxBufferPx = 200;\n  @Input() virtualMinBufferPx = 100;\n  @Input() tableMainElement?: HTMLDivElement;\n  @Input() virtualForTrackBy: TrackByFunction<T> = index => index;\n  @ViewChild('tableHeaderElement', { read: ElementRef }) tableHeaderElement!: ElementRef;\n  @ViewChild('tableBodyElement', { read: ElementRef }) tableBodyElement!: ElementRef;\n  @ViewChild('tableFootElement', { read: ElementRef }) tableFootElement?: ElementRef;\n  @ViewChild(CdkVirtualScrollViewport, { read: CdkVirtualScrollViewport })\n  cdkVirtualScrollViewport?: CdkVirtualScrollViewport;\n  headerStyleMap = {};\n  bodyStyleMap = {};\n  @Input() verticalScrollBarWidth = 0;\n  @Input() noDataVirtualHeight = '182px';\n  private data$ = new Subject<void>();\n  private scroll$ = new Subject<void>();\n\n  private setScrollPositionClassName(clear: boolean = false): void {\n    const { scrollWidth, scrollLeft, clientWidth } = this.tableBodyElement.nativeElement;\n    const leftClassName = 'ant-table-ping-left';\n    const rightClassName = 'ant-table-ping-right';\n    if ((scrollWidth === clientWidth && scrollWidth !== 0) || clear) {\n      this.renderer.removeClass(this.tableMainElement, leftClassName);\n      this.renderer.removeClass(this.tableMainElement, rightClassName);\n    } else if (scrollLeft === 0) {\n      this.renderer.removeClass(this.tableMainElement, leftClassName);\n      this.renderer.addClass(this.tableMainElement, rightClassName);\n    } else if (scrollWidth === scrollLeft + clientWidth) {\n      this.renderer.removeClass(this.tableMainElement, rightClassName);\n      this.renderer.addClass(this.tableMainElement, leftClassName);\n    } else {\n      this.renderer.addClass(this.tableMainElement, leftClassName);\n      this.renderer.addClass(this.tableMainElement, rightClassName);\n    }\n  }\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      this.setScrollPositionClassName(true);\n    });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { scrollX, scrollY, data } = changes;\n    if (scrollX || scrollY) {\n      const hasVerticalScrollBar = this.verticalScrollBarWidth !== 0;\n      this.headerStyleMap = {\n        overflowX: 'hidden',\n        overflowY: this.scrollY && hasVerticalScrollBar ? 'scroll' : 'hidden'\n      };\n      this.bodyStyleMap = {\n        overflowY: this.scrollY ? 'scroll' : 'hidden',\n        overflowX: this.scrollX ? 'auto' : null,\n        maxHeight: this.scrollY\n      };\n      // Caretaker note: we have to emit the value outside the Angular zone, thus DOM timer (`delay(0)`) and `scroll`\n      // event listener will be also added outside the Angular zone.\n      this.ngZone.runOutsideAngular(() => this.scroll$.next());\n    }\n    if (data) {\n      // See the comment above.\n      this.ngZone.runOutsideAngular(() => this.data$.next());\n    }\n  }\n\n  ngAfterViewInit(): void {\n    if (this.platform.isBrowser) {\n      const scrollEvent$ = this.scroll$.pipe(\n        startWith(null),\n        delay(0),\n        switchMap(() =>\n          fromEventOutsideAngular<MouseEvent>(this.tableBodyElement.nativeElement, 'scroll').pipe(startWith(true))\n        )\n      );\n      const resize$ = this.resizeService.connect();\n      merge(scrollEvent$, resize$, this.data$, this.scroll$)\n        .pipe(startWith(true), delay(0), takeUntilDestroyed(this.destroyRef))\n        .subscribe(() => this.setScrollPositionClassName());\n      scrollEvent$.pipe(filter(() => !!this.scrollY)).subscribe(() => {\n        this.tableHeaderElement.nativeElement.scrollLeft = this.tableBodyElement.nativeElement.scrollLeft;\n        if (this.tableFootElement) {\n          this.tableFootElement.nativeElement.scrollLeft = this.tableBodyElement.nativeElement.scrollLeft;\n        }\n      });\n    }\n  }\n}\n"
  },
  {
    "path": "components/table/src/table/table-virtual-scroll.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, inject, TemplateRef } from '@angular/core';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\n@Directive({\n  selector: '[nz-virtual-scroll]',\n  exportAs: 'nzVirtualScroll'\n})\nexport class NzTableVirtualScrollDirective<T> {\n  templateRef: TemplateRef<{ $implicit: T; index: number }> = inject(TemplateRef);\n\n  static ngTemplateContextGuard<T>(\n    _dir: NzTableVirtualScrollDirective<T>,\n    _ctx: NzSafeAny\n  ): _ctx is { $implicit: T; index: number } {\n    return true;\n  }\n}\n"
  },
  {
    "path": "components/table/src/table/table.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterViewInit,\n  ChangeDetectionStrategy,\n  Component,\n  ContentChild,\n  EventEmitter,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  SimpleChanges,\n  TemplateRef,\n  TrackByFunction,\n  ViewChild,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject,\n  DestroyRef,\n  ElementRef,\n  ChangeDetectorRef\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { BehaviorSubject, combineLatest } from 'rxjs';\nimport { filter, map } from 'rxjs/operators';\n\nimport { NzResizeObserver } from 'ng-zorro-antd/cdk/resize-observer';\nimport { NzConfigKey, onConfigChangeEventForComponent, WithConfig } from 'ng-zorro-antd/core/config';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { measureScrollbar } from 'ng-zorro-antd/core/util';\nimport { NzPaginationModule, PaginationItemRenderContext } from 'ng-zorro-antd/pagination';\nimport { NzSpinComponent } from 'ng-zorro-antd/spin';\n\nimport { NzTableDataService } from '../table-data.service';\nimport { NzTableStyleService } from '../table-style.service';\nimport {\n  NzCustomColumn,\n  NzTableLayout,\n  NzTablePaginationPosition,\n  NzTablePaginationType,\n  NzTableQueryParams,\n  NzTableSize,\n  NzTableSummaryFixedType\n} from '../table.types';\nimport { NzTableInnerDefaultComponent } from './table-inner-default.component';\nimport { NzTableInnerScrollComponent } from './table-inner-scroll.component';\nimport { NzTableVirtualScrollDirective } from './table-virtual-scroll.directive';\nimport { NzTableTitleFooterComponent } from './title-footer.component';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'table';\n\n@Component({\n  selector: 'nz-table',\n  exportAs: 'nzTable',\n  providers: [NzTableStyleService, NzTableDataService],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <nz-spin [nzDelay]=\"nzLoadingDelay\" [nzSpinning]=\"nzLoading\" [nzIndicator]=\"nzLoadingIndicator\">\n      @if (nzPaginationPosition === 'both' || nzPaginationPosition === 'top') {\n        <ng-template [ngTemplateOutlet]=\"paginationTemplate\" />\n      }\n      <div\n        #tableMainElement\n        class=\"ant-table\"\n        [class.ant-table-rtl]=\"dir === 'rtl'\"\n        [class.ant-table-fixed-header]=\"nzData.length && scrollY\"\n        [class.ant-table-fixed-column]=\"scrollX\"\n        [class.ant-table-has-fix-left]=\"hasFixLeft\"\n        [class.ant-table-has-fix-right]=\"hasFixRight\"\n        [class.ant-table-bordered]=\"nzBordered\"\n        [class.nz-table-out-bordered]=\"nzOuterBordered && !nzBordered\"\n        [class.ant-table-middle]=\"nzSize === 'middle'\"\n        [class.ant-table-small]=\"nzSize === 'small'\"\n      >\n        @if (nzTitle) {\n          <nz-table-title-footer [title]=\"nzTitle\" />\n        }\n        @if (scrollY || scrollX) {\n          <nz-table-inner-scroll\n            [data]=\"data\"\n            [scrollX]=\"scrollX\"\n            [scrollY]=\"scrollY\"\n            [contentTemplate]=\"contentTemplate\"\n            [listOfColWidth]=\"listOfAutoColWidth\"\n            [theadTemplate]=\"theadTemplate\"\n            [tfootTemplate]=\"tfootTemplate\"\n            [tfootFixed]=\"tfootFixed\"\n            [verticalScrollBarWidth]=\"verticalScrollBarWidth\"\n            [virtualTemplate]=\"nzVirtualScrollDirective ? nzVirtualScrollDirective.templateRef : null\"\n            [virtualItemSize]=\"nzVirtualItemSize\"\n            [virtualMaxBufferPx]=\"nzVirtualMaxBufferPx\"\n            [virtualMinBufferPx]=\"nzVirtualMinBufferPx\"\n            [tableMainElement]=\"tableMainElement\"\n            [virtualForTrackBy]=\"nzVirtualForTrackBy\"\n            [noDataVirtualHeight]=\"noDataVirtualHeight\"\n          />\n        } @else {\n          <nz-table-inner-default\n            [tableLayout]=\"nzTableLayout\"\n            [listOfColWidth]=\"listOfManualColWidth\"\n            [theadTemplate]=\"theadTemplate\"\n            [contentTemplate]=\"contentTemplate\"\n            [tfootTemplate]=\"tfootTemplate\"\n          />\n        }\n        @if (nzFooter) {\n          <nz-table-title-footer [footer]=\"nzFooter\" />\n        }\n      </div>\n      @if (nzPaginationPosition === 'both' || nzPaginationPosition === 'bottom') {\n        <ng-template [ngTemplateOutlet]=\"paginationTemplate\" />\n      }\n    </nz-spin>\n    <ng-template #paginationTemplate>\n      @if (nzShowPagination && data.length) {\n        <nz-pagination\n          [hidden]=\"!showPagination\"\n          class=\"ant-table-pagination ant-table-pagination-right\"\n          [nzShowSizeChanger]=\"nzShowSizeChanger\"\n          [nzPageSizeOptions]=\"nzPageSizeOptions\"\n          [nzItemRender]=\"nzItemRender!\"\n          [nzShowQuickJumper]=\"nzShowQuickJumper\"\n          [nzHideOnSinglePage]=\"nzHideOnSinglePage\"\n          [nzShowTotal]=\"nzShowTotal\"\n          [nzSize]=\"nzPaginationType === 'small' ? 'small' : nzSize === 'default' ? 'default' : 'small'\"\n          [nzPageSize]=\"nzPageSize\"\n          [nzTotal]=\"nzTotal\"\n          [nzSimple]=\"nzSimple\"\n          [nzPageIndex]=\"nzPageIndex\"\n          (nzPageSizeChange)=\"onPageSizeChange($event)\"\n          (nzPageIndexChange)=\"onPageIndexChange($event)\"\n        />\n      }\n    </ng-template>\n    <ng-template #contentTemplate>\n      <ng-content />\n    </ng-template>\n  `,\n  host: {\n    class: 'ant-table-wrapper',\n    '[class.ant-table-wrapper-rtl]': 'dir === \"rtl\"',\n    '[class.ant-table-custom-column]': `nzCustomColumn.length`\n  },\n  imports: [\n    NzSpinComponent,\n    NgTemplateOutlet,\n    NzTableTitleFooterComponent,\n    NzTableInnerScrollComponent,\n    NzTableInnerDefaultComponent,\n    NzPaginationModule\n  ]\n})\nexport class NzTableComponent<T> implements OnInit, OnChanges, AfterViewInit {\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  private elementRef = inject(ElementRef);\n  private nzResizeObserver = inject(NzResizeObserver);\n  private cdr = inject(ChangeDetectorRef);\n  private nzTableStyleService = inject(NzTableStyleService);\n  private nzTableDataService = inject(NzTableDataService<T>);\n  private directionality = inject(Directionality);\n  private destroyRef = inject(DestroyRef);\n\n  @Input() nzTableLayout: NzTableLayout = 'auto';\n  @Input() nzShowTotal: TemplateRef<{ $implicit: number; range: [number, number] }> | null = null;\n  @Input() nzItemRender: TemplateRef<PaginationItemRenderContext> | null = null;\n  @Input() nzTitle: string | TemplateRef<NzSafeAny> | null = null;\n  @Input() nzFooter: string | TemplateRef<NzSafeAny> | null = null;\n  @Input() nzNoResult: string | TemplateRef<NzSafeAny> | undefined = undefined;\n  @Input() nzPageSizeOptions = [10, 20, 30, 40, 50];\n  @Input() nzVirtualItemSize = 0;\n  @Input() nzVirtualMaxBufferPx = 200;\n  @Input() nzVirtualMinBufferPx = 100;\n  @Input() nzVirtualForTrackBy: TrackByFunction<T> = index => index;\n  @Input() nzLoadingDelay = 0;\n  @Input() nzPageIndex = 1;\n  @Input() nzPageSize = 10;\n  @Input() nzTotal = 0;\n  @Input() nzWidthConfig: ReadonlyArray<string | null> = [];\n  @Input() nzData: readonly T[] = [];\n  @Input() nzCustomColumn: NzCustomColumn[] = [];\n\n  @Input() nzPaginationPosition: NzTablePaginationPosition = 'bottom';\n  @Input() nzScroll: { x?: string | null; y?: string | null } = { x: null, y: null };\n  @Input() noDataVirtualHeight = '182px';\n  @Input() nzPaginationType: NzTablePaginationType = 'default';\n  @Input({ transform: booleanAttribute }) nzFrontPagination = true;\n  @Input({ transform: booleanAttribute }) nzTemplateMode = false;\n  @Input({ transform: booleanAttribute }) nzShowPagination = true;\n  @Input({ transform: booleanAttribute }) nzLoading = false;\n  @Input({ transform: booleanAttribute }) nzOuterBordered = false;\n  @Input() @WithConfig() nzLoadingIndicator: TemplateRef<NzSafeAny> | null = null;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzBordered: boolean = false;\n  @Input() @WithConfig() nzSize: NzTableSize = 'default';\n  @Input({ transform: booleanAttribute }) @WithConfig() nzShowSizeChanger: boolean = false;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzHideOnSinglePage: boolean = false;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzShowQuickJumper: boolean = false;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzSimple: boolean = false;\n  @Output() readonly nzPageSizeChange = new EventEmitter<number>();\n  @Output() readonly nzPageIndexChange = new EventEmitter<number>();\n  @Output() readonly nzQueryParams = new EventEmitter<NzTableQueryParams>();\n  @Output() readonly nzCurrentPageDataChange = new EventEmitter<readonly T[]>();\n  @Output() readonly nzCustomColumnChange = new EventEmitter<readonly NzCustomColumn[]>();\n\n  /** public data for ngFor tr */\n  public data: readonly T[] = [];\n  public cdkVirtualScrollViewport?: CdkVirtualScrollViewport;\n  scrollX: string | null = null;\n  scrollY: string | null = null;\n  theadTemplate: TemplateRef<NzSafeAny> | null = null;\n  tfootTemplate: TemplateRef<NzSafeAny> | null = null;\n  tfootFixed: NzTableSummaryFixedType | null = null;\n  listOfAutoColWidth: ReadonlyArray<string | null> = [];\n  listOfManualColWidth: ReadonlyArray<string | null> = [];\n  hasFixLeft = false;\n  hasFixRight = false;\n  showPagination = true;\n  private templateMode$ = new BehaviorSubject<boolean>(false);\n  dir: Direction = 'ltr';\n  @ContentChild(NzTableVirtualScrollDirective, { static: false })\n  nzVirtualScrollDirective!: NzTableVirtualScrollDirective<T>;\n  @ViewChild(NzTableInnerScrollComponent) nzTableInnerScrollComponent!: NzTableInnerScrollComponent<T>;\n  verticalScrollBarWidth = 0;\n  onPageSizeChange(size: number): void {\n    this.nzTableDataService.updatePageSize(size);\n  }\n\n  onPageIndexChange(index: number): void {\n    this.nzTableDataService.updatePageIndex(index);\n  }\n\n  constructor() {\n    onConfigChangeEventForComponent(NZ_CONFIG_MODULE_NAME, () => this.cdr.markForCheck());\n  }\n\n  ngOnInit(): void {\n    const { pageIndexDistinct$, pageSizeDistinct$, listOfCurrentPageData$, total$, queryParams$, listOfCustomColumn$ } =\n      this.nzTableDataService;\n    const { theadTemplate$, tfootTemplate$, tfootFixed$, hasFixLeft$, hasFixRight$ } = this.nzTableStyleService;\n\n    this.dir = this.directionality.value;\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n      this.dir = direction;\n      this.cdr.detectChanges();\n    });\n\n    queryParams$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(this.nzQueryParams);\n    pageIndexDistinct$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(pageIndex => {\n      if (pageIndex !== this.nzPageIndex) {\n        this.nzPageIndex = pageIndex;\n        this.nzPageIndexChange.next(pageIndex);\n      }\n    });\n    pageSizeDistinct$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(pageSize => {\n      if (pageSize !== this.nzPageSize) {\n        this.nzPageSize = pageSize;\n        this.nzPageSizeChange.next(pageSize);\n      }\n    });\n    total$\n      .pipe(\n        takeUntilDestroyed(this.destroyRef),\n        filter(total => this.nzFrontPagination && total !== this.nzTotal)\n      )\n      .subscribe(total => {\n        this.nzTotal = total;\n        this.cdr.markForCheck();\n      });\n    listOfCurrentPageData$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(data => {\n      this.data = data;\n      this.nzCurrentPageDataChange.next(data);\n      this.cdr.markForCheck();\n    });\n\n    listOfCustomColumn$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(data => {\n      this.nzCustomColumn = data;\n      this.nzCustomColumnChange.next(data);\n      this.cdr.markForCheck();\n    });\n\n    theadTemplate$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(theadTemplate => {\n      this.theadTemplate = theadTemplate;\n      this.cdr.markForCheck();\n    });\n\n    combineLatest([tfootTemplate$, tfootFixed$])\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(([tfootTemplate, tfootFixed]) => {\n        this.tfootTemplate = tfootTemplate;\n        this.tfootFixed = tfootFixed;\n        this.cdr.markForCheck();\n      });\n\n    hasFixLeft$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(hasFixLeft => {\n      this.hasFixLeft = hasFixLeft;\n      this.cdr.markForCheck();\n    });\n\n    hasFixRight$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(hasFixRight => {\n      this.hasFixRight = hasFixRight;\n      this.cdr.markForCheck();\n    });\n\n    combineLatest([total$, this.templateMode$])\n      .pipe(\n        map(([total, templateMode]) => total === 0 && !templateMode),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(empty => {\n        this.nzTableStyleService.setShowEmpty(empty);\n      });\n\n    this.verticalScrollBarWidth = measureScrollbar('vertical');\n    this.nzTableStyleService.listOfListOfThWidthPx$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(listOfWidth => {\n      this.listOfAutoColWidth = listOfWidth;\n      this.cdr.markForCheck();\n    });\n    this.nzTableStyleService.manualWidthConfigPx$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(listOfWidth => {\n      this.listOfManualColWidth = listOfWidth;\n      this.cdr.markForCheck();\n    });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const {\n      nzScroll,\n      nzPageIndex,\n      nzPageSize,\n      nzFrontPagination,\n      nzData,\n      nzCustomColumn,\n      nzWidthConfig,\n      nzNoResult,\n      nzTemplateMode\n    } = changes;\n    if (nzPageIndex) {\n      this.nzTableDataService.updatePageIndex(this.nzPageIndex);\n    }\n    if (nzPageSize) {\n      this.nzTableDataService.updatePageSize(this.nzPageSize);\n    }\n    if (nzData) {\n      this.nzData = this.nzData || [];\n      this.nzTableDataService.updateListOfData(this.nzData);\n    }\n    if (nzCustomColumn) {\n      this.nzCustomColumn = this.nzCustomColumn || [];\n      this.nzTableDataService.updateListOfCustomColumn(this.nzCustomColumn);\n    }\n    if (nzFrontPagination) {\n      this.nzTableDataService.updateFrontPagination(this.nzFrontPagination);\n    }\n    if (nzScroll) {\n      this.setScrollOnChanges();\n    }\n    if (nzWidthConfig) {\n      this.nzTableStyleService.setTableWidthConfig(this.nzWidthConfig);\n    }\n    if (nzTemplateMode) {\n      this.templateMode$.next(this.nzTemplateMode);\n    }\n    if (nzNoResult) {\n      this.nzTableStyleService.setNoResult(this.nzNoResult);\n    }\n\n    this.updateShowPagination();\n  }\n\n  ngAfterViewInit(): void {\n    this.nzResizeObserver\n      .observe(this.elementRef)\n      .pipe(\n        map(([entry]) => {\n          const { width } = entry.target.getBoundingClientRect();\n          const scrollBarWidth = this.scrollY ? this.verticalScrollBarWidth : 0;\n          return Math.floor(width - scrollBarWidth);\n        }),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(this.nzTableStyleService.hostWidth$);\n    if (this.nzTableInnerScrollComponent && this.nzTableInnerScrollComponent.cdkVirtualScrollViewport) {\n      this.cdkVirtualScrollViewport = this.nzTableInnerScrollComponent.cdkVirtualScrollViewport;\n    }\n  }\n\n  private setScrollOnChanges(): void {\n    this.scrollX = (this.nzScroll && this.nzScroll.x) || null;\n    this.scrollY = (this.nzScroll && this.nzScroll.y) || null;\n    this.nzTableStyleService.setScroll(this.scrollX, this.scrollY);\n  }\n\n  private updateShowPagination(): void {\n    this.showPagination =\n      (this.nzHideOnSinglePage && this.nzData.length > this.nzPageSize) ||\n      (this.nzData.length > 0 && !this.nzHideOnSinglePage) ||\n      (!this.nzFrontPagination && this.nzTotal > this.nzPageSize);\n  }\n}\n"
  },
  {
    "path": "components/table/src/table/tbody.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\n/* eslint-disable @angular-eslint/component-selector */\n\nimport { AsyncPipe } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, TemplateRef, ViewEncapsulation, inject } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { BehaviorSubject } from 'rxjs';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { NzEmptyModule } from 'ng-zorro-antd/empty';\n\nimport { NzTableStyleService } from '../table-style.service';\nimport { NzTableFixedRowComponent } from './table-fixed-row.component';\nimport { NzTrMeasureComponent } from './tr-measure.component';\n\n@Component({\n  selector: 'tbody',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    @if (listOfMeasureColumn$ | async; as listOfMeasureColumn) {\n      @if (isInsideTable && listOfMeasureColumn.length) {\n        <tr\n          nz-table-measure-row\n          [listOfMeasureColumn]=\"listOfMeasureColumn\"\n          (listOfAutoWidth)=\"onListOfAutoWidthChange($event)\"\n        ></tr>\n      }\n    }\n    <ng-content />\n    @if (showEmpty$ | async) {\n      <tr class=\"ant-table-placeholder\" nz-table-fixed-row>\n        <nz-embed-empty nzComponentName=\"table\" [specificContent]=\"(noResult$ | async)!\" />\n      </tr>\n    }\n  `,\n  host: {\n    '[class.ant-table-tbody]': 'isInsideTable'\n  },\n  imports: [AsyncPipe, NzTrMeasureComponent, NzTableFixedRowComponent, NzEmptyModule]\n})\nexport class NzTbodyComponent {\n  showEmpty$ = new BehaviorSubject<boolean>(false);\n  noResult$ = new BehaviorSubject<string | TemplateRef<NzSafeAny> | undefined>(undefined);\n  listOfMeasureColumn$ = new BehaviorSubject<readonly string[]>([]);\n  private nzTableStyleService = inject(NzTableStyleService, { optional: true });\n  isInsideTable = !!this.nzTableStyleService;\n\n  constructor() {\n    if (this.nzTableStyleService) {\n      const { showEmpty$, noResult$, listOfMeasureColumn$ } = this.nzTableStyleService;\n      noResult$.pipe(takeUntilDestroyed()).subscribe(this.noResult$);\n      listOfMeasureColumn$.pipe(takeUntilDestroyed()).subscribe(this.listOfMeasureColumn$);\n      showEmpty$.pipe(takeUntilDestroyed()).subscribe(this.showEmpty$);\n    }\n  }\n\n  onListOfAutoWidthChange(listOfAutoWidth: number[]): void {\n    this.nzTableStyleService?.setListOfAutoWidth(listOfAutoWidth);\n  }\n}\n"
  },
  {
    "path": "components/table/src/table/tfoot-summary.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  Component,\n  inject,\n  Input,\n  OnChanges,\n  OnInit,\n  SimpleChanges,\n  TemplateRef,\n  ViewChild,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzTableStyleService } from '../table-style.service';\nimport { NzTableSummaryFixedType } from '../table.types';\n\nfunction fixedAttribute(value: NzTableSummaryFixedType | boolean | unknown): NzTableSummaryFixedType | null {\n  return value === 'top' || value === 'bottom' ? value : booleanAttribute(value) ? 'bottom' : null;\n}\n\n/* eslint-disable @angular-eslint/component-selector */\n@Component({\n  selector: 'tfoot[nzSummary]',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <ng-template #contentTemplate>\n      <ng-content />\n    </ng-template>\n    @if (!isInsideTable || !nzFixed) {\n      <ng-template [ngTemplateOutlet]=\"contentTemplate\" />\n    }\n  `,\n  imports: [NgTemplateOutlet],\n  host: {\n    '[class.ant-table-summary]': '!isInsideTable || !nzFixed'\n  }\n})\nexport class NzTfootSummaryComponent implements OnInit, OnChanges {\n  @Input({ transform: fixedAttribute }) nzFixed: NzTableSummaryFixedType | null = null;\n  @ViewChild('contentTemplate', { static: true }) templateRef!: TemplateRef<NzSafeAny>;\n  private nzTableStyleService = inject(NzTableStyleService, { optional: true });\n  isInsideTable = !!this.nzTableStyleService;\n\n  ngOnInit(): void {\n    this.nzTableStyleService?.setTfootTemplate(this.templateRef);\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzFixed } = changes;\n    this.nzTableStyleService?.setTfootFixed(nzFixed.currentValue);\n  }\n}\n"
  },
  {
    "path": "components/table/src/table/thead.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\n/* eslint-disable @angular-eslint/component-selector */\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterContentInit,\n  AfterViewInit,\n  ChangeDetectionStrategy,\n  Component,\n  ContentChildren,\n  ElementRef,\n  EventEmitter,\n  OnInit,\n  Output,\n  QueryList,\n  Renderer2,\n  TemplateRef,\n  ViewChild,\n  ViewEncapsulation,\n  inject,\n  DestroyRef\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { EMPTY, Observable, merge, of } from 'rxjs';\nimport { delay, map, mergeMap, startWith, switchMap } from 'rxjs/operators';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzThAddOnComponent } from '../cell/th-addon.component';\nimport { NzTableDataService } from '../table-data.service';\nimport { NzTableStyleService } from '../table-style.service';\nimport { NzTrDirective } from './tr.directive';\n\n@Component({\n  selector: 'thead:not(.ant-table-thead)',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <ng-template #contentTemplate>\n      <ng-content />\n    </ng-template>\n    @if (!isInsideTable) {\n      <ng-template [ngTemplateOutlet]=\"contentTemplate\" />\n    }\n  `,\n  imports: [NgTemplateOutlet]\n})\nexport class NzTheadComponent<T> implements AfterContentInit, AfterViewInit, OnInit {\n  private nzTableStyleService = inject(NzTableStyleService, { optional: true });\n  private nzTableDataService: NzTableDataService<T> | null = inject(NzTableDataService, { optional: true });\n  private destroyRef = inject(DestroyRef);\n  private el: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement;\n  private renderer = inject(Renderer2);\n\n  isInsideTable = !!this.nzTableStyleService;\n  @ViewChild('contentTemplate', { static: true }) templateRef!: TemplateRef<NzSafeAny>;\n  @ContentChildren(NzTrDirective, { descendants: true }) listOfNzTrDirective!: QueryList<NzTrDirective>;\n  @ContentChildren(NzThAddOnComponent, { descendants: true }) listOfNzThAddOnComponent!: QueryList<\n    NzThAddOnComponent<T>\n  >;\n  @Output() readonly nzSortOrderChange = new EventEmitter<{ key: NzSafeAny; value: string | null }>();\n\n  ngOnInit(): void {\n    if (this.nzTableStyleService) {\n      this.nzTableStyleService.setTheadTemplate(this.templateRef);\n    }\n  }\n\n  ngAfterContentInit(): void {\n    if (this.nzTableStyleService) {\n      const firstTableRow$ = this.listOfNzTrDirective.changes.pipe(\n        startWith(this.listOfNzTrDirective),\n        map(item => item && item.first),\n        takeUntilDestroyed(this.destroyRef)\n      ) as Observable<NzTrDirective>;\n      const listOfColumnsChanges$ = firstTableRow$.pipe(\n        switchMap(firstTableRow => (firstTableRow ? firstTableRow.listOfColumnsChanges$ : EMPTY))\n      );\n      listOfColumnsChanges$.subscribe(data => this.nzTableStyleService!.setListOfTh(data));\n      /** TODO: need reset the measure row when scrollX change **/\n      this.nzTableStyleService.enableAutoMeasure$\n        .pipe(switchMap(enable => (enable ? listOfColumnsChanges$ : of([]))))\n        .pipe(takeUntilDestroyed(this.destroyRef))\n        .subscribe(data => this.nzTableStyleService!.setListOfMeasureColumn(data));\n      const listOfFixedLeftColumnChanges$ = firstTableRow$.pipe(\n        switchMap(firstTr => (firstTr ? firstTr.listOfFixedLeftColumnChanges$ : EMPTY))\n      );\n      const listOfFixedRightColumnChanges$ = firstTableRow$.pipe(\n        switchMap(firstTr => (firstTr ? firstTr.listOfFixedRightColumnChanges$ : EMPTY))\n      );\n      listOfFixedLeftColumnChanges$.subscribe(listOfFixedLeftColumn => {\n        this.nzTableStyleService!.setHasFixLeft(listOfFixedLeftColumn.length !== 0);\n      });\n      listOfFixedRightColumnChanges$.subscribe(listOfFixedRightColumn => {\n        this.nzTableStyleService!.setHasFixRight(listOfFixedRightColumn.length !== 0);\n      });\n    }\n\n    if (this.nzTableDataService) {\n      const listOfColumn$ = this.listOfNzThAddOnComponent.changes.pipe(\n        startWith(this.listOfNzThAddOnComponent)\n      ) as Observable<QueryList<NzThAddOnComponent<T>>>;\n      const manualSort$ = listOfColumn$.pipe(\n        switchMap(() => merge(...this.listOfNzThAddOnComponent.map(th => th.manualClickOrder$))),\n        takeUntilDestroyed(this.destroyRef)\n      );\n      manualSort$.subscribe(data => {\n        const emitValue = { key: data.nzColumnKey, value: data.sortOrder };\n        this.nzSortOrderChange.emit(emitValue);\n        if (data.nzSortFn && data.nzSortPriority === false) {\n          this.listOfNzThAddOnComponent.filter(th => th !== data).forEach(th => th.clearSortOrder());\n        }\n      });\n      const listOfCalcOperator$ = listOfColumn$.pipe(\n        switchMap(list =>\n          merge(listOfColumn$, ...list.map(c => c.calcOperatorChange$)).pipe(mergeMap(() => listOfColumn$))\n        ),\n        map(list =>\n          list\n            .filter(item => !!item.nzSortFn || !!item.nzFilterFn)\n            .map(item => {\n              const { nzSortFn, sortOrder, nzFilterFn, nzFilterValue, nzSortPriority, nzColumnKey } = item;\n              return {\n                key: nzColumnKey,\n                sortFn: nzSortFn,\n                sortPriority: nzSortPriority,\n                sortOrder: sortOrder!,\n                filterFn: nzFilterFn!,\n                filterValue: nzFilterValue\n              };\n            })\n        ),\n        // TODO: after checked error here\n        delay(0),\n        takeUntilDestroyed(this.destroyRef)\n      );\n      listOfCalcOperator$.subscribe(list => {\n        this.nzTableDataService?.listOfCalcOperator$.next(list);\n      });\n    }\n  }\n\n  ngAfterViewInit(): void {\n    if (this.nzTableStyleService) {\n      this.renderer.removeChild(this.renderer.parentNode(this.el), this.el);\n    }\n  }\n}\n"
  },
  {
    "path": "components/table/src/table/title-footer.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, Input, TemplateRef, ViewEncapsulation } from '@angular/core';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\n@Component({\n  selector: 'nz-table-title-footer',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <ng-container *nzStringTemplateOutlet=\"title\">{{ title }}</ng-container>\n    <ng-container *nzStringTemplateOutlet=\"footer\">{{ footer }}</ng-container>\n  `,\n  host: {\n    '[class.ant-table-title]': `title !== null`,\n    '[class.ant-table-footer]': `footer !== null`\n  },\n  imports: [NzOutletModule]\n})\nexport class NzTableTitleFooterComponent {\n  @Input() title: string | TemplateRef<NzSafeAny> | null = null;\n  @Input() footer: string | TemplateRef<NzSafeAny> | null = null;\n}\n"
  },
  {
    "path": "components/table/src/table/tr-expand.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { booleanAttribute, Directive, Input } from '@angular/core';\n\n@Directive({\n  selector: 'tr[nzExpand]',\n  host: {\n    class: 'ant-table-expanded-row',\n    '[hidden]': `!nzExpand`\n  }\n})\nexport class NzTrExpandDirective {\n  @Input({ transform: booleanAttribute }) nzExpand = true;\n}\n"
  },
  {
    "path": "components/table/src/table/tr-measure.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  AfterViewInit,\n  ChangeDetectionStrategy,\n  Component,\n  DestroyRef,\n  ElementRef,\n  EventEmitter,\n  inject,\n  Input,\n  NgZone,\n  Output,\n  QueryList,\n  ViewChildren,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Observable, combineLatest } from 'rxjs';\nimport { debounceTime, map, startWith, switchMap } from 'rxjs/operators';\n\nimport { NzResizeObserver } from 'ng-zorro-antd/cdk/resize-observer';\n\n@Component({\n  selector: 'tr[nz-table-measure-row]',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    @for (th of listOfMeasureColumn; track $index) {\n      <td #tdElement class=\"nz-disable-td\" style=\"padding: 0; border: 0; height: 0;\"></td>\n    }\n  `,\n  host: {\n    class: 'ant-table-measure-now'\n  }\n})\nexport class NzTrMeasureComponent implements AfterViewInit {\n  private nzResizeObserver = inject(NzResizeObserver);\n  private ngZone = inject(NgZone);\n  private destroyRef = inject(DestroyRef);\n\n  @Input() listOfMeasureColumn: readonly string[] = [];\n  @Output() readonly listOfAutoWidth = new EventEmitter<number[]>();\n  @ViewChildren('tdElement') listOfTdElement!: QueryList<ElementRef>;\n\n  ngAfterViewInit(): void {\n    this.listOfTdElement.changes\n      .pipe(startWith(this.listOfTdElement))\n      .pipe(\n        switchMap(\n          list =>\n            combineLatest(\n              list.toArray().map((item: ElementRef) =>\n                this.nzResizeObserver.observe(item).pipe(\n                  map(([entry]) => {\n                    const { width } = entry.target.getBoundingClientRect();\n                    return Math.floor(width);\n                  })\n                )\n              )\n            ) as Observable<number[]>\n        ),\n        debounceTime(16),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(data => {\n        // Caretaker note: we don't have to re-enter the Angular zone each time the stream emits.\n        // The below check is necessary to be sure that zone is not nooped through `BootstrapOptions`\n        // (`bootstrapModule(AppModule, { ngZone: 'noop' }))`. The `ngZone instanceof NgZone` may return\n        // `false` if zone is nooped, since `ngZone` will be an instance of the `NoopNgZone`.\n        // The `ResizeObserver` might be also patched through `zone.js/dist/zone-patch-resize-observer`,\n        // thus calling `ngZone.run` again will cause another change detection.\n        if (this.ngZone instanceof NgZone && NgZone.isInAngularZone()) {\n          this.listOfAutoWidth.next(data);\n        } else {\n          this.ngZone.run(() => this.listOfAutoWidth.next(data));\n        }\n      });\n  }\n}\n"
  },
  {
    "path": "components/table/src/table/tr.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { AfterContentInit, ContentChildren, DestroyRef, Directive, QueryList, inject } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Observable, ReplaySubject, combineLatest, merge } from 'rxjs';\nimport { map, mergeMap, startWith, switchMap } from 'rxjs/operators';\n\nimport { NzCellFixedDirective } from '../cell/cell-fixed.directive';\nimport { NzThMeasureDirective } from '../cell/th-measure.directive';\nimport { NzTableStyleService } from '../table-style.service';\n\n@Directive({\n  selector: 'tr:not([nz-table-measure-row]):not([nzExpand]):not([nz-table-fixed-row])',\n  host: {\n    '[class.ant-table-row]': 'isInsideTable'\n  }\n})\nexport class NzTrDirective implements AfterContentInit {\n  private destroyRef = inject(DestroyRef);\n\n  @ContentChildren(NzThMeasureDirective) listOfNzThDirective!: QueryList<NzThMeasureDirective>;\n  @ContentChildren(NzCellFixedDirective) listOfCellFixedDirective!: QueryList<NzCellFixedDirective>;\n\n  private listOfFixedColumns$ = new ReplaySubject<NzCellFixedDirective[]>(1);\n  private listOfColumns$ = new ReplaySubject<NzThMeasureDirective[]>(1);\n  listOfFixedColumnsChanges$: Observable<NzCellFixedDirective[]> = this.listOfFixedColumns$.pipe(\n    switchMap(list =>\n      merge(this.listOfFixedColumns$, ...list.map(c => c.changes$)).pipe(mergeMap(() => this.listOfFixedColumns$))\n    ),\n    takeUntilDestroyed(this.destroyRef)\n  );\n  listOfFixedLeftColumnChanges$ = this.listOfFixedColumnsChanges$.pipe(\n    map(list => list.filter(item => item.nzLeft !== false))\n  );\n  listOfFixedRightColumnChanges$ = this.listOfFixedColumnsChanges$.pipe(\n    map(list => list.filter(item => item.nzRight !== false))\n  );\n  listOfColumnsChanges$: Observable<NzThMeasureDirective[]> = this.listOfColumns$.pipe(\n    switchMap(list =>\n      merge(this.listOfColumns$, ...list.map(c => c.changes$)).pipe(mergeMap(() => this.listOfColumns$))\n    ),\n    takeUntilDestroyed(this.destroyRef)\n  );\n\n  private nzTableStyleService = inject(NzTableStyleService, { optional: true });\n  isInsideTable = !!this.nzTableStyleService;\n\n  ngAfterContentInit(): void {\n    if (this.nzTableStyleService) {\n      this.listOfCellFixedDirective.changes\n        .pipe(startWith(this.listOfCellFixedDirective), takeUntilDestroyed(this.destroyRef))\n        .subscribe(this.listOfFixedColumns$);\n      this.listOfNzThDirective.changes\n        .pipe(startWith(this.listOfNzThDirective), takeUntilDestroyed(this.destroyRef))\n        .subscribe(this.listOfColumns$);\n      /** set last left and first right **/\n      this.listOfFixedLeftColumnChanges$.subscribe(listOfFixedLeft => {\n        listOfFixedLeft.forEach(cell => cell.setIsLastLeft(cell === listOfFixedLeft[listOfFixedLeft.length - 1]));\n      });\n      this.listOfFixedRightColumnChanges$.subscribe(listOfFixedRight => {\n        listOfFixedRight.forEach(cell => cell.setIsFirstRight(cell === listOfFixedRight[0]));\n      });\n      /** calculate fixed nzLeft and nzRight **/\n      combineLatest([this.nzTableStyleService.listOfListOfThWidth$, this.listOfFixedLeftColumnChanges$])\n        .pipe(takeUntilDestroyed(this.destroyRef))\n        .subscribe(([listOfAutoWidth, listOfLeftCell]) => {\n          listOfLeftCell.forEach((cell, index) => {\n            if (cell.isAutoLeft) {\n              const currentArray = listOfLeftCell.slice(0, index);\n              const count = currentArray.reduce((pre, cur) => pre + (cur.colspan || cur.colSpan || 1), 0);\n              const width = listOfAutoWidth.slice(0, count).reduce((pre, cur) => pre + cur, 0);\n              cell.setAutoLeftWidth(`${width}px`);\n            }\n          });\n        });\n      combineLatest([this.nzTableStyleService.listOfListOfThWidth$, this.listOfFixedRightColumnChanges$])\n        .pipe(takeUntilDestroyed(this.destroyRef))\n        .subscribe(([listOfAutoWidth, listOfRightCell]) => {\n          listOfRightCell.forEach((_, index) => {\n            const cell = listOfRightCell[listOfRightCell.length - index - 1];\n            if (cell.isAutoRight) {\n              const currentArray = listOfRightCell.slice(listOfRightCell.length - index, listOfRightCell.length);\n              const count = currentArray.reduce((pre, cur) => pre + (cur.colspan || cur.colSpan || 1), 0);\n              const width = listOfAutoWidth\n                .slice(listOfAutoWidth.length - count, listOfAutoWidth.length)\n                .reduce((pre, cur) => pre + cur, 0);\n              cell.setAutoRightWidth(`${width}px`);\n            }\n          });\n        });\n    }\n  }\n}\n"
  },
  {
    "path": "components/table/src/table-data.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { DestroyRef, inject, Injectable } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { BehaviorSubject, Observable, combineLatest } from 'rxjs';\nimport { debounceTime, distinctUntilChanged, filter, map, skip, switchMap } from 'rxjs/operators';\n\nimport {\n  NzCustomColumn,\n  NzTableFilterFn,\n  NzTableFilterValue,\n  NzTableQueryParams,\n  NzTableSortFn,\n  NzTableSortOrder\n} from './table.types';\n\n@Injectable()\nexport class NzTableDataService<T> {\n  private destroyRef = inject(DestroyRef);\n  private pageIndex$ = new BehaviorSubject<number>(1);\n  private frontPagination$ = new BehaviorSubject<boolean>(true);\n  private pageSize$ = new BehaviorSubject<number>(10);\n  private listOfData$ = new BehaviorSubject<readonly T[]>([]);\n  listOfCustomColumn$ = new BehaviorSubject<NzCustomColumn[]>([]);\n  pageIndexDistinct$ = this.pageIndex$.pipe(distinctUntilChanged());\n  pageSizeDistinct$ = this.pageSize$.pipe(distinctUntilChanged());\n  listOfCalcOperator$ = new BehaviorSubject<\n    Array<{\n      key?: string;\n      sortFn: NzTableSortFn<T> | null | boolean;\n      sortOrder: NzTableSortOrder;\n      filterFn: NzTableFilterFn<T> | null | boolean;\n      filterValue: NzTableFilterValue;\n      sortPriority: number | boolean;\n    }>\n  >([]);\n  queryParams$: Observable<NzTableQueryParams> = combineLatest([\n    this.pageIndexDistinct$,\n    this.pageSizeDistinct$,\n    this.listOfCalcOperator$\n  ]).pipe(\n    debounceTime(0),\n    skip(1),\n    map(([pageIndex, pageSize, listOfCalc]) => ({\n      pageIndex,\n      pageSize,\n      sort: listOfCalc\n        .filter(item => item.sortFn)\n        .map(item => ({\n          key: item.key!,\n          value: item.sortOrder\n        })),\n      filter: listOfCalc\n        .filter(item => item.filterFn)\n        .map(item => ({\n          key: item.key!,\n          value: item.filterValue\n        }))\n    }))\n  );\n  private listOfDataAfterCalc$ = combineLatest([this.listOfData$, this.listOfCalcOperator$]).pipe(\n    map(([listOfData, listOfCalcOperator]) => {\n      let listOfDataAfterCalc = [...listOfData];\n      const listOfFilterOperator = listOfCalcOperator.filter(item => {\n        const { filterValue, filterFn } = item;\n        const isReset =\n          filterValue === null ||\n          filterValue === undefined ||\n          (Array.isArray(filterValue) && filterValue!.length === 0);\n        return !isReset && typeof filterFn === 'function';\n      });\n      for (const item of listOfFilterOperator) {\n        const { filterFn, filterValue } = item;\n        listOfDataAfterCalc = listOfDataAfterCalc.filter(data => (filterFn as NzTableFilterFn<T>)(filterValue, data));\n      }\n      const listOfSortOperator = listOfCalcOperator\n        .filter(item => item.sortOrder !== null && typeof item.sortFn === 'function')\n        .sort((a, b) => +b.sortPriority - +a.sortPriority);\n      if (listOfCalcOperator.length) {\n        listOfDataAfterCalc.sort((record1, record2) => {\n          for (const item of listOfSortOperator) {\n            const { sortFn, sortOrder } = item;\n            if (sortFn && sortOrder) {\n              const compareResult = (sortFn as NzTableSortFn<T>)(record1, record2, sortOrder);\n              if (compareResult !== 0) {\n                return sortOrder === 'ascend' ? compareResult : -compareResult;\n              }\n            }\n          }\n          return 0;\n        });\n      }\n      return listOfDataAfterCalc;\n    })\n  );\n  private listOfFrontEndCurrentPageData$ = combineLatest([\n    this.pageIndexDistinct$,\n    this.pageSizeDistinct$,\n    this.listOfDataAfterCalc$\n  ]).pipe(\n    takeUntilDestroyed(this.destroyRef),\n    filter(value => {\n      const [pageIndex, pageSize, listOfData] = value;\n      const maxPageIndex = Math.ceil(listOfData.length / pageSize) || 1;\n      return pageIndex <= maxPageIndex;\n    }),\n    map(([pageIndex, pageSize, listOfData]) => listOfData.slice((pageIndex - 1) * pageSize, pageIndex * pageSize))\n  );\n  listOfCurrentPageData$ = this.frontPagination$.pipe(\n    switchMap(pagination => (pagination ? this.listOfFrontEndCurrentPageData$ : this.listOfDataAfterCalc$))\n  );\n  total$ = this.frontPagination$.pipe(\n    switchMap(pagination => (pagination ? this.listOfDataAfterCalc$ : this.listOfData$)),\n    map(list => list.length),\n    distinctUntilChanged()\n  );\n\n  updatePageSize(size: number): void {\n    this.pageSize$.next(size);\n  }\n  updateFrontPagination(pagination: boolean): void {\n    this.frontPagination$.next(pagination);\n  }\n  updatePageIndex(index: number): void {\n    this.pageIndex$.next(index);\n  }\n  updateListOfData(list: readonly T[]): void {\n    this.listOfData$.next(list);\n  }\n  updateListOfCustomColumn(list: NzCustomColumn[]): void {\n    this.listOfCustomColumn$.next(list);\n  }\n}\n"
  },
  {
    "path": "components/table/src/table-style.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Injectable, TemplateRef } from '@angular/core';\nimport { BehaviorSubject, combineLatest, merge, ReplaySubject } from 'rxjs';\nimport { map } from 'rxjs/operators';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzThMeasureDirective } from './cell/th-measure.directive';\nimport { NzTableSummaryFixedType } from './table.types';\n\n@Injectable()\nexport class NzTableStyleService {\n  theadTemplate$ = new ReplaySubject<TemplateRef<NzSafeAny>>(1);\n  tfootTemplate$ = new ReplaySubject<TemplateRef<NzSafeAny>>(1);\n  tfootFixed$ = new ReplaySubject<NzTableSummaryFixedType | null>(1);\n  hasFixLeft$ = new ReplaySubject<boolean>(1);\n  hasFixRight$ = new ReplaySubject<boolean>(1);\n  hostWidth$ = new ReplaySubject<number>(1);\n  columnCount$ = new ReplaySubject<number>(1);\n  showEmpty$ = new ReplaySubject<boolean>(1);\n  noResult$ = new ReplaySubject<string | TemplateRef<NzSafeAny> | undefined>(1);\n  private listOfThWidthConfigPx$ = new BehaviorSubject<ReadonlyArray<string | null>>([]);\n  private tableWidthConfigPx$ = new BehaviorSubject<ReadonlyArray<string | null>>([]);\n  manualWidthConfigPx$ = combineLatest([this.tableWidthConfigPx$, this.listOfThWidthConfigPx$]).pipe(\n    map(([widthConfig, listOfWidth]) => (widthConfig.length ? widthConfig : listOfWidth))\n  );\n  private listOfAutoWidthPx$ = new ReplaySubject<readonly string[]>(1);\n  listOfListOfThWidthPx$ = merge(\n    /** init with manual width **/\n    this.manualWidthConfigPx$,\n    combineLatest([this.listOfAutoWidthPx$, this.manualWidthConfigPx$]).pipe(\n      map(([autoWidth, manualWidth]) => {\n        /** use autoWidth until column length match **/\n        if (autoWidth.length === manualWidth.length) {\n          return autoWidth.map((width, index) => {\n            if (width === '0px') {\n              return manualWidth[index] || null;\n            } else {\n              return manualWidth[index] || width;\n            }\n          });\n        } else {\n          return manualWidth;\n        }\n      })\n    )\n  );\n  listOfMeasureColumn$ = new ReplaySubject<readonly string[]>(1);\n  listOfListOfThWidth$ = this.listOfAutoWidthPx$.pipe(map(list => list.map(width => parseInt(width, 10))));\n  enableAutoMeasure$ = new ReplaySubject<boolean>(1);\n\n  setTheadTemplate(template: TemplateRef<NzSafeAny>): void {\n    this.theadTemplate$.next(template);\n  }\n\n  setTfootTemplate(template: TemplateRef<NzSafeAny>): void {\n    this.tfootTemplate$.next(template);\n  }\n\n  setTfootFixed(fixed: NzTableSummaryFixedType | null): void {\n    this.tfootFixed$.next(fixed);\n  }\n\n  setHasFixLeft(hasFixLeft: boolean): void {\n    this.hasFixLeft$.next(hasFixLeft);\n  }\n\n  setHasFixRight(hasFixRight: boolean): void {\n    this.hasFixRight$.next(hasFixRight);\n  }\n\n  setTableWidthConfig(widthConfig: ReadonlyArray<string | null>): void {\n    this.tableWidthConfigPx$.next(widthConfig);\n  }\n\n  setListOfTh(listOfTh: readonly NzThMeasureDirective[]): void {\n    let columnCount = 0;\n    listOfTh.forEach(th => {\n      columnCount += (th.colspan && +th.colspan) || (th.colSpan && +th.colSpan) || 1;\n    });\n    const listOfThPx = listOfTh.map(item => item.nzWidth);\n    this.columnCount$.next(columnCount);\n    this.listOfThWidthConfigPx$.next(listOfThPx);\n  }\n\n  setListOfMeasureColumn(listOfTh: readonly NzThMeasureDirective[]): void {\n    const listOfKeys: string[] = [];\n    listOfTh.forEach(th => {\n      const length = (th.colspan && +th.colspan) || (th.colSpan && +th.colSpan) || 1;\n      for (let i = 0; i < length; i++) {\n        listOfKeys.push(`measure_key_${i}`);\n      }\n    });\n    this.listOfMeasureColumn$.next(listOfKeys);\n  }\n\n  setListOfAutoWidth(listOfAutoWidth: number[]): void {\n    this.listOfAutoWidthPx$.next(listOfAutoWidth.map(width => `${width}px`));\n  }\n\n  setShowEmpty(showEmpty: boolean): void {\n    this.showEmpty$.next(showEmpty);\n  }\n\n  setNoResult(noResult: string | TemplateRef<NzSafeAny> | undefined): void {\n    this.noResult$.next(noResult);\n  }\n\n  setScroll(scrollX: string | null, scrollY: string | null): void {\n    const enableAutoMeasure = !!(scrollX || scrollY);\n    if (!enableAutoMeasure) {\n      this.setListOfAutoWidth([]);\n    }\n    this.enableAutoMeasure$.next(enableAutoMeasure);\n  }\n}\n"
  },
  {
    "path": "components/table/src/table.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzFilterTriggerComponent } from './addon/filter-trigger.component';\nimport { NzTableFilterComponent } from './addon/filter.component';\nimport { NzRowExpandButtonDirective } from './addon/row-expand-button.directive';\nimport { NzRowIndentDirective } from './addon/row-indent.directive';\nimport { NzTableSelectionComponent } from './addon/selection.component';\nimport { NzTableSortersComponent } from './addon/sorters.component';\nimport { NzCellFixedDirective } from './cell/cell-fixed.directive';\nimport { NzTableCellDirective } from './cell/cell.directive';\nimport { NzCustomColumnDirective } from './cell/custom-column.directive';\nimport { NzTdAddOnComponent } from './cell/td-addon.component';\nimport { NzThAddOnComponent } from './cell/th-addon.component';\nimport { NzThMeasureDirective } from './cell/th-measure.directive';\nimport { NzThSelectionComponent } from './cell/th-selection.component';\nimport { NzCellAlignDirective } from './styled/align.directive';\nimport { NzCellEllipsisDirective } from './styled/ellipsis.directive';\nimport { NzCellBreakWordDirective } from './styled/word-break.directive';\nimport { NzTableContentComponent } from './table/table-content.component';\nimport { NzTableFixedRowComponent } from './table/table-fixed-row.component';\nimport { NzTableInnerDefaultComponent } from './table/table-inner-default.component';\nimport { NzTableInnerScrollComponent } from './table/table-inner-scroll.component';\nimport { NzTableVirtualScrollDirective } from './table/table-virtual-scroll.directive';\nimport { NzTableComponent } from './table/table.component';\nimport { NzTbodyComponent } from './table/tbody.component';\nimport { NzTfootSummaryComponent } from './table/tfoot-summary.component';\nimport { NzTheadComponent } from './table/thead.component';\nimport { NzTableTitleFooterComponent } from './table/title-footer.component';\nimport { NzTrExpandDirective } from './table/tr-expand.directive';\nimport { NzTrMeasureComponent } from './table/tr-measure.component';\nimport { NzTrDirective } from './table/tr.directive';\n\n@NgModule({\n  imports: [\n    NzTableComponent,\n    NzThAddOnComponent,\n    NzTableCellDirective,\n    NzThMeasureDirective,\n    NzTdAddOnComponent,\n    NzTheadComponent,\n    NzTbodyComponent,\n    NzTrDirective,\n    NzTrExpandDirective,\n    NzTfootSummaryComponent,\n    NzTableVirtualScrollDirective,\n    NzCellFixedDirective,\n    NzCustomColumnDirective,\n    NzTableContentComponent,\n    NzTableTitleFooterComponent,\n    NzTableInnerDefaultComponent,\n    NzTableInnerScrollComponent,\n    NzTrMeasureComponent,\n    NzRowIndentDirective,\n    NzRowExpandButtonDirective,\n    NzCellBreakWordDirective,\n    NzCellAlignDirective,\n    NzTableSortersComponent,\n    NzTableFilterComponent,\n    NzTableSelectionComponent,\n    NzCellEllipsisDirective,\n    NzFilterTriggerComponent,\n    NzTableFixedRowComponent,\n    NzThSelectionComponent\n  ],\n  exports: [\n    NzTableComponent,\n    NzThAddOnComponent,\n    NzTableCellDirective,\n    NzThMeasureDirective,\n    NzTdAddOnComponent,\n    NzTheadComponent,\n    NzTbodyComponent,\n    NzTrDirective,\n    NzTableVirtualScrollDirective,\n    NzCellFixedDirective,\n    NzCustomColumnDirective,\n    NzFilterTriggerComponent,\n    NzTrExpandDirective,\n    NzTfootSummaryComponent,\n    NzCellBreakWordDirective,\n    NzCellAlignDirective,\n    NzCellEllipsisDirective,\n    NzTableFixedRowComponent,\n    NzThSelectionComponent\n  ]\n})\nexport class NzTableModule {}\n"
  },
  {
    "path": "components/table/src/table.types.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nexport type NzTableLayout = 'fixed' | 'auto';\nexport type NzTablePaginationPosition = 'top' | 'bottom' | 'both';\nexport type NzTablePaginationType = 'default' | 'small';\nexport type NzTableSize = 'middle' | 'default' | 'small';\nexport type NzTableFilterList = Array<{ text: string; value: NzSafeAny; byDefault?: boolean }>;\nexport type NzTableSortOrder = string | 'ascend' | 'descend' | null;\nexport type NzTableSortFn<T = unknown> = (a: T, b: T, sortOrder?: NzTableSortOrder) => number;\nexport type NzTableFilterValue = NzSafeAny[] | NzSafeAny;\nexport type NzTableFilterFn<T = unknown> = (value: NzTableFilterValue, data: T) => boolean;\n\nexport interface NzTableQueryParams {\n  pageIndex: number;\n  pageSize: number;\n  sort: Array<{ key: string; value: NzTableSortOrder }>;\n  filter: Array<{ key: string; value: NzTableFilterValue }>;\n}\n\nexport interface NzCustomColumn {\n  value: string;\n  default: boolean;\n  width: number;\n  fixWidth?: boolean;\n}\n\nexport type NzTableSummaryFixedType = 'top' | 'bottom';\n"
  },
  {
    "path": "components/table/src/testing/custom-column.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, DebugElement, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\nimport { NzCustomColumn, NzTableComponent, NzTableModule } from 'ng-zorro-antd/table';\n\ndescribe('nz-table-custom-column', () => {\n  let fixture: ComponentFixture<NzCustomColumnTestTableComponent>;\n  let testComponent: NzCustomColumnTestTableComponent;\n  let resultEl: DebugElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n    fixture = TestBed.createComponent(NzCustomColumnTestTableComponent);\n    fixture.detectChanges();\n    testComponent = fixture.componentInstance;\n    resultEl = fixture.debugElement.query(By.directive(NzTableComponent));\n  });\n\n  it('custom-column basic', () => {\n    fixture.detectChanges();\n    // age: order = 3\n    expect(resultEl.nativeElement.querySelectorAll('.ant-table-cell')[2].getAttribute('nzcellcontrol')).toBe('age');\n    expect(resultEl.nativeElement.querySelectorAll('.ant-table-cell')[2].style.order).toBe('3');\n    testComponent.customColumn = [\n      {\n        value: 'name',\n        default: true,\n        width: 200\n      },\n      {\n        value: 'age',\n        default: true,\n        width: 200\n      },\n      {\n        value: 'gender',\n        default: false,\n        width: 200\n      },\n      {\n        value: 'address',\n        default: true,\n        width: 200\n      },\n      {\n        value: 'action',\n        default: true,\n        width: 200\n      }\n    ];\n    fixture.detectChanges();\n    // age: order = 1\n    expect(resultEl.nativeElement.querySelectorAll('.ant-table-cell')[2].getAttribute('nzcellcontrol')).toBe('age');\n    expect(resultEl.nativeElement.querySelectorAll('.ant-table-cell')[2].style.order).toBe('1');\n\n    expect(resultEl.nativeElement.querySelectorAll('.ant-table-cell')[1].getAttribute('nzcellcontrol')).toBe('gender');\n    expect(resultEl.nativeElement.querySelectorAll('.ant-table-cell')[1].style.display).toBe('none');\n  });\n});\n\ninterface Person {\n  key: string;\n  name: string;\n  gender: 'male' | 'female';\n  age: number;\n  address: string;\n}\n\n@Component({\n  imports: [NzDividerModule, NzTableModule],\n  template: `\n    <nz-table #basicTable [nzData]=\"listOfData\" [nzCustomColumn]=\"customColumn\">\n      <thead>\n        <tr>\n          <th nzCellControl=\"name\">Name</th>\n          <th nzCellControl=\"gender\">Gender</th>\n          <th nzCellControl=\"age\">Age</th>\n          <th nzCellControl=\"address\">Address</th>\n          <th nzCellControl=\"action\">Action</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of basicTable.data; track data) {\n          <tr>\n            <td nzCellControl=\"name\">{{ data.name }}</td>\n            <td nzCellControl=\"gender\">{{ data.gender }}</td>\n            <td nzCellControl=\"age\">{{ data.age }}</td>\n            <td nzCellControl=\"address\">{{ data.address }}</td>\n            <td nzCellControl=\"action\">\n              <a>Action</a>\n              <nz-divider nzType=\"vertical\" />\n              <a>Delete</a>\n            </td>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n  `\n})\nexport class NzCustomColumnTestTableComponent {\n  listOfData: Person[] = [\n    {\n      key: '1',\n      name: 'John Brown',\n      gender: 'female',\n      age: 32,\n      address: 'New York No. 1 Lake Park'\n    },\n    {\n      key: '2',\n      name: 'Jim Green',\n      gender: 'female',\n      age: 42,\n      address: 'London No. 1 Lake Park'\n    },\n    {\n      key: '3',\n      name: 'Joe Black',\n      gender: 'male',\n      age: 32,\n      address: 'Sidney No. 1 Lake Park'\n    }\n  ];\n\n  customColumn: NzCustomColumn[] = [\n    {\n      value: 'name',\n      default: true,\n      width: 200\n    },\n    {\n      value: 'gender',\n      default: true,\n      width: 200\n    },\n    {\n      value: 'address',\n      default: true,\n      width: 200\n    },\n    {\n      value: 'age',\n      default: true,\n      width: 200\n    },\n    {\n      value: 'action',\n      default: true,\n      width: 200\n    }\n  ];\n}\n"
  },
  {
    "path": "components/table/src/testing/table.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport {\n  Component,\n  DebugElement,\n  OnInit,\n  provideZoneChangeDetection,\n  ViewChild,\n  ViewEncapsulation\n} from '@angular/core';\nimport { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { NzI18nService } from 'ng-zorro-antd/i18n';\nimport en_US from 'ng-zorro-antd/i18n/languages/en_US';\nimport { NzTableComponent, NzTableModule, NzTableSize } from 'ng-zorro-antd/table';\n\ndescribe('nz-table', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  describe('basic nz-table', () => {\n    let fixture: ComponentFixture<NzTestTableBasicComponent>;\n    let testComponent: NzTestTableBasicComponent;\n    let table: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTableBasicComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n      table = fixture.debugElement.query(By.directive(NzTableComponent));\n    });\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n      expect(table.nativeElement.classList).toContain('ant-table-wrapper');\n    });\n\n    it('should pageIndex set work', () => {\n      fixture.detectChanges();\n      expect(testComponent.pageIndex).toBe(1);\n      expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(0);\n      expect(table.nativeElement.querySelector('.ant-pagination-item-active').innerText).toBe('1');\n      testComponent.pageIndex = 2;\n      fixture.detectChanges();\n      expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(0);\n      expect(table.nativeElement.querySelector('.ant-pagination-item-active').innerText).toBe('2');\n    });\n\n    it('should pageIndex click work', () => {\n      fixture.detectChanges();\n      expect(testComponent.pageIndex).toBe(1);\n      expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(0);\n      table.nativeElement.querySelectorAll('.ant-pagination-item')[1].click();\n      fixture.detectChanges();\n      expect(testComponent.pageIndex).toBe(2);\n      expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(1);\n      expect(table.nativeElement.querySelector('.ant-pagination-item-active').innerText).toBe('2');\n    });\n\n    it('should pageSize change work', () => {\n      fixture.detectChanges();\n      expect(testComponent.pageSize).toBe(10);\n      expect(testComponent.pageSizeChange).toHaveBeenCalledTimes(0);\n      expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(0);\n      expect(table.nativeElement.querySelectorAll('.ant-pagination-item').length).toBe(2);\n      testComponent.pageSize = 20;\n      fixture.detectChanges();\n      expect(table.nativeElement.querySelectorAll('.ant-pagination-item').length).toBe(1);\n      expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(0);\n      expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(0);\n    });\n\n    it('should pageSize change check pageIndex bounding', fakeAsync(() => {\n      fixture.detectChanges();\n      expect(testComponent.pageSize).toBe(10);\n      expect(testComponent.pageIndex).toBe(1);\n      expect(testComponent.pageSizeChange).toHaveBeenCalledTimes(0);\n      expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(0);\n      testComponent.pageIndex = 2;\n      fixture.detectChanges();\n      expect(testComponent.pageSizeChange).toHaveBeenCalledTimes(0);\n      expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(0);\n      testComponent.pageSize = 5;\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(testComponent.pageIndex).toBe(2);\n      expect(testComponent.pageSizeChange).toHaveBeenCalledTimes(0);\n      expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(0);\n      testComponent.nzTableComponent.onPageIndexChange(1);\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(testComponent.pageIndex).toBe(1);\n      expect(testComponent.pageSizeChange).toHaveBeenCalledTimes(0);\n      expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(1);\n      fixture.destroy();\n    }));\n\n    it('should nzData change check pageIndex bounding', fakeAsync(() => {\n      fixture.detectChanges();\n      expect(testComponent.pageSize).toBe(10);\n      expect(testComponent.pageIndex).toBe(1);\n      expect(testComponent.pageSizeChange).toHaveBeenCalledTimes(0);\n      expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(0);\n      testComponent.pageIndex = 2;\n      fixture.detectChanges();\n      expect(testComponent.pageSizeChange).toHaveBeenCalledTimes(0);\n      expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(0);\n      testComponent.dataSet = [...testComponent.dataSet, ...testComponent.dataSet];\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(testComponent.pageIndex).toBe(2);\n      expect(testComponent.pageSizeChange).toHaveBeenCalledTimes(0);\n      expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(0);\n      testComponent.dataSet = testComponent.dataSet.slice(0, 10);\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(testComponent.pageIndex).toBe(1);\n      expect(testComponent.pageSizeChange).toHaveBeenCalledTimes(0);\n      expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(1);\n      fixture.destroy();\n    }));\n\n    it('should pagination simple work', () => {\n      fixture.detectChanges();\n      expect(table.nativeElement.querySelector('.ant-pagination-simple')).toBeNull();\n      testComponent.simple = true;\n      fixture.detectChanges();\n      expect(table.nativeElement.querySelector('.ant-pagination-simple')).toBeDefined();\n    });\n\n    it('should pagination work', () => {\n      fixture.detectChanges();\n      expect(table.nativeElement.querySelector('.ant-pagination')).toBeDefined();\n      expect(table.nativeElement.querySelectorAll('.ant-table-tbody tr').length).toBe(10);\n      testComponent.pagination = false;\n      testComponent.front = false;\n      fixture.detectChanges();\n      expect(table.nativeElement.querySelector('.ant-pagination')).toBeNull();\n      expect(table.nativeElement.querySelectorAll('.ant-table-tbody tr').length).toBe(20);\n    });\n\n    it('should bordered work', () => {\n      fixture.detectChanges();\n      expect(table.nativeElement.querySelector('.ant-table').classList).not.toContain('ant-table-bordered');\n      testComponent.bordered = true;\n      fixture.detectChanges();\n      expect(table.nativeElement.querySelector('.ant-table').classList).toContain('ant-table-bordered');\n    });\n\n    it('should size work', () => {\n      fixture.detectChanges();\n      expect(testComponent.size).toBe('small');\n      expect(table.nativeElement.querySelector('.ant-table').classList).toContain('ant-table-small');\n      testComponent.size = 'middle';\n      fixture.detectChanges();\n      expect(table.nativeElement.querySelector('.ant-table').classList).toContain('ant-table-middle');\n      testComponent.size = 'default';\n      fixture.detectChanges();\n      expect(table.nativeElement.querySelector('.ant-table').classList).toContain('ant-table');\n    });\n\n    it('should footer & title work', () => {\n      fixture.detectChanges();\n      expect(table.nativeElement.querySelector('.ant-table-title').innerText).toBe('Here is Title');\n      expect(table.nativeElement.querySelector('.ant-table-footer').innerText).toBe('Here is Footer');\n      testComponent.footer = false;\n      testComponent.title = false;\n      fixture.detectChanges();\n      expect(table.nativeElement.querySelector('.ant-table-title')).toBeNull();\n      expect(table.nativeElement.querySelector('.ant-table-footer')).toBeNull();\n    });\n\n    it('should noResult work', () => {\n      testComponent.dataSet = [];\n      fixture.detectChanges();\n      expect(table.nativeElement.querySelector('.ant-table-placeholder').innerText.trim()).toBe('暂无数据');\n      testComponent.noResult = 'test';\n      fixture.detectChanges();\n      expect(table.nativeElement.querySelector('.ant-table-placeholder').innerText).toBe('test');\n    });\n\n    it('should fixed header work', () => {\n      fixture.detectChanges();\n      expect(table.nativeElement.querySelector('.ant-table-scroll')).toBe(null);\n      testComponent.fixHeader = true;\n      expect(table.nativeElement.querySelector('.ant-table-scroll')).toBeDefined();\n    });\n\n    it('should width config', () => {\n      fixture.detectChanges();\n      expect(table.nativeElement.querySelectorAll('col').length).toBe(4);\n      testComponent.widthConfig = ['100px', '50px'];\n      fixture.detectChanges();\n      expect(table.nativeElement.querySelectorAll('col')[0].style.width).toBe('100px');\n      expect(table.nativeElement.querySelectorAll('col')[1].style.width).toBe('50px');\n    });\n\n    it('should showQuickJumper & showSizeChanger work', () => {\n      fixture.detectChanges();\n      expect(table.nativeElement.querySelector('.ant-pagination-options-quick-jumper')).toBe(null);\n      expect(table.nativeElement.querySelector('.ant-pagination-options-size-changer')).toBe(null);\n      testComponent.showQuickJumper = true;\n      testComponent.showSizeChanger = true;\n      expect(table.nativeElement.querySelector('.ant-pagination-options-quick-jumper')).toBeDefined();\n      expect(table.nativeElement.querySelector('.ant-pagination-options-size-changer')).toBeDefined();\n    });\n\n    it('should hideOnSinglePage work', () => {\n      fixture.detectChanges();\n      expect(table.nativeElement.querySelector('.ant-pagination').children.length).not.toBe(0);\n      testComponent.hideOnSinglePage = true;\n      testComponent.dataSet = [{}];\n      fixture.detectChanges();\n      expect(table.nativeElement.querySelector('.ant-pagination[hidden]')).not.toBeNull();\n    });\n\n    it('should showPagination work with nzFrontPagination and hideOnSinglePage', () => {\n      fixture.detectChanges();\n      expect(table.nativeElement.querySelector('.ant-pagination').children.length).not.toBe(0);\n      testComponent.front = false;\n      testComponent.hideOnSinglePage = true;\n      testComponent.dataSet = [{}];\n      fixture.detectChanges();\n      expect(table.nativeElement.querySelector('.ant-pagination').children.length).not.toBe(0);\n    });\n\n    it('i18n', () => {\n      testComponent.dataSet = [];\n      fixture.detectChanges();\n      expect(table.nativeElement.querySelector('.ant-table-placeholder').innerText.trim()).toBe('暂无数据');\n      TestBed.inject(NzI18nService).setLocale(en_US);\n      fixture.detectChanges();\n      expect(table.nativeElement.querySelector('.ant-table-placeholder').innerText.trim()).toBe('No Data');\n    });\n  });\n\n  describe('scroll nz-table', () => {\n    let fixture: ComponentFixture<NzTestTableScrollComponent>;\n    let testComponent: NzTestTableScrollComponent;\n    let table: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTableScrollComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n      table = fixture.debugElement.query(By.directive(NzTableComponent));\n    });\n\n    it('should change width affect scroll', () => {\n      fixture.detectChanges();\n      testComponent.width = 1000;\n      window.dispatchEvent(new Event('resize'));\n      fixture.detectChanges();\n      const tableBody = table.nativeElement.querySelector('.ant-table-body');\n      expect(tableBody.scrollWidth).toBe(tableBody.clientWidth);\n    });\n  });\n\n  describe('double binding nz-table', () => {\n    let fixture: ComponentFixture<NzTableSpecCrashComponent>;\n    let testComponent: NzTableSpecCrashComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTableSpecCrashComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n    });\n\n    it('should not crash when double binding pageSize and pageIndex', () => {\n      fixture.detectChanges();\n      expect(testComponent.pageIndexChange).toHaveBeenCalledTimes(0);\n    });\n  });\n\n  describe('RTL', () => {\n    let fixture: ComponentFixture<NzTestTableRtlComponent>;\n    let table: DebugElement;\n    let tableElement: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTableRtlComponent);\n      table = fixture.debugElement.query(By.directive(NzTableComponent));\n      fixture.detectChanges();\n      tableElement = table.nativeElement;\n    });\n\n    it('should table className correct on dir change', () => {\n      fixture.detectChanges();\n      expect(tableElement.classList).toContain('ant-table-wrapper-rtl');\n\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n      expect(tableElement.classList).not.toContain('ant-table-wrapper-rtl');\n    });\n  });\n});\n\ninterface BasicTestDataItem {\n  name?: string;\n  age?: string;\n  address?: string;\n  description?: string;\n  checked?: boolean;\n  expand?: boolean;\n}\n\ntype NzPageSizeChangeFn = (pageSize: number) => void;\n\n@Component({\n  imports: [NzTableModule],\n  template: `\n    <nz-table\n      #dynamicTable\n      [nzScroll]=\"fixHeader ? { y: '240px' } : {}\"\n      [(nzPageIndex)]=\"pageIndex\"\n      (nzPageIndexChange)=\"pageIndexChange($event)\"\n      [(nzPageSize)]=\"pageSize\"\n      (nzPageSizeChange)=\"pageSizeChange($event)\"\n      [nzData]=\"dataSet\"\n      [nzBordered]=\"bordered\"\n      [nzLoading]=\"loading\"\n      [nzShowSizeChanger]=\"showSizeChanger\"\n      [nzSimple]=\"simple\"\n      [nzShowQuickJumper]=\"showQuickJumper\"\n      [nzHideOnSinglePage]=\"hideOnSinglePage\"\n      [nzWidthConfig]=\"widthConfig\"\n      [nzShowPagination]=\"pagination\"\n      [nzFrontPagination]=\"front\"\n      [nzFooter]=\"footer ? 'Here is Footer' : null\"\n      [nzNoResult]=\"noResult\"\n      [nzTitle]=\"title ? 'Here is Title' : null\"\n      [nzSize]=\"size\"\n    >\n      @if (header) {\n        <thead>\n          <tr>\n            <th>Name</th>\n            <th>Age</th>\n            <th>Address</th>\n            <th>Action</th>\n          </tr>\n        </thead>\n      }\n      <tbody>\n        @for (data of dynamicTable.data; track data.age) {\n          <tr>\n            <td>{{ data.name }}</td>\n            <td>{{ data.age }}</td>\n            <td>{{ data.address }}</td>\n            <td>\n              <a href=\"#\">Action 一 {{ data.name }}</a>\n              <a href=\"#\">Delete</a>\n            </td>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n  `\n})\nexport class NzTestTableBasicComponent implements OnInit {\n  @ViewChild(NzTableComponent, { static: false }) nzTableComponent!: NzTableComponent<BasicTestDataItem>;\n  pageIndex = 1;\n  pageIndexChange = jasmine.createSpy<NzPageSizeChangeFn>('pageIndex callback');\n  pageSize = 10;\n  pageSizeChange = jasmine.createSpy<NzPageSizeChangeFn>('pageSize callback');\n  dataSet: BasicTestDataItem[] = [];\n  noResult = '';\n  showSizeChanger = false;\n  showQuickJumper = false;\n  hideOnSinglePage = false;\n  bordered = false;\n  loading = false;\n  pagination = true;\n  header = true;\n  title = true;\n  footer = true;\n  front = true;\n  fixHeader = false;\n  simple = false;\n  size: NzTableSize = 'small';\n  widthConfig: string[] = [];\n\n  ngOnInit(): void {\n    for (let i = 1; i <= 20; i++) {\n      this.dataSet.push({\n        name: 'John Brown',\n        age: `${i}2`,\n        address: `New York No. ${i} Lake Park`,\n        description: `My name is John Brown, I am ${i}2 years old, living in New York No. ${i} Lake Park.`,\n        checked: false,\n        expand: false\n      });\n    }\n  }\n}\n\ninterface ScrollTestDataItem {\n  name: string;\n  age: number;\n  address: string;\n}\n\n@Component({\n  imports: [NzTableModule],\n  template: `\n    <div style=\"display: block;\" [style.width.px]=\"width\">\n      <nz-table #nzTable [nzData]=\"dataSet\" [nzPageSize]=\"10\" [nzScroll]=\"{ x: '600px', y: '240px' }\">\n        <thead>\n          <tr>\n            <th>Full Name</th>\n            <th>Age</th>\n            <th>Column 1</th>\n            <th>Column 2</th>\n            <th>Column 3</th>\n            <th>Column 4</th>\n            <th>Column 5</th>\n            <th>Column 6</th>\n            <th>Column 7</th>\n            <th>Column 8</th>\n            <th>Action</th>\n          </tr>\n        </thead>\n        <tbody>\n          @for (data of nzTable.data; track data) {\n            <tr>\n              <td>{{ data.name }}</td>\n              <td>{{ data.age }}</td>\n              <td>{{ data.address }}</td>\n              <td>{{ data.address }}</td>\n              <td>{{ data.address }}</td>\n              <td>{{ data.address }}</td>\n              <td>{{ data.address }}</td>\n              <td>{{ data.address }}</td>\n              <td>{{ data.address }}</td>\n              <td>{{ data.address }}</td>\n              <td>\n                <a>action</a>\n              </td>\n            </tr>\n          }\n        </tbody>\n      </nz-table>\n    </div>\n  `,\n  encapsulation: ViewEncapsulation.None,\n  styles: `\n    @import '../../../style/testing.less';\n    @import '../../../style/entry.less';\n  `\n})\nexport class NzTestTableScrollComponent implements OnInit {\n  @ViewChild(NzTableComponent, { static: false }) nzTableComponent!: NzTableComponent<ScrollTestDataItem>;\n  dataSet: ScrollTestDataItem[] = [];\n  width = 300;\n\n  ngOnInit(): void {\n    for (let i = 0; i < 100; i++) {\n      this.dataSet.push({\n        name: `Edward King ${i}`,\n        age: 32,\n        address: `London, Park Lane no. ${i}`\n      });\n    }\n  }\n}\n\n/** https://github.com/NG-ZORRO/ng-zorro-antd/issues/3004 **/\n@Component({\n  imports: [NzTableModule],\n  template: `\n    <nz-table\n      #nzTable\n      [nzData]=\"data\"\n      [(nzPageIndex)]=\"pageIndex\"\n      [(nzPageSize)]=\"pageSize\"\n      (nzPageIndexChange)=\"pageIndexChange($event)\"\n    >\n      <thead>\n        <tr>\n          <th>ID</th>\n          <th>NAME</th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (item of nzTable.data; track item) {\n          <tr>\n            <td>{{ item.id }}</td>\n            <td>{{ item.name }}</td>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n  `\n})\nexport class NzTableSpecCrashComponent {\n  data: Array<{ id: number; name: string }> = [];\n  pageIndex = 1;\n  pageSize = 10;\n  pageIndexChange = jasmine.createSpy<NzPageSizeChangeFn>('pageSize callback');\n\n  constructor() {\n    setTimeout(() => {\n      this.data = new Array(100).fill(1).map((_, i) => ({\n        id: i + 1,\n        name: `name ${i + 1}`\n      }));\n    }, 1000);\n  }\n}\n\ninterface RtlTestDataItem {\n  name?: string;\n  age?: string;\n  address?: string;\n  description?: string;\n  checked?: boolean;\n  expand?: boolean;\n}\n\n@Component({\n  imports: [BidiModule, NzTableModule],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-table #dynamicTable [nzData]=\"dataSet\" [nzSimple]=\"simple\">\n        @if (header) {\n          <thead>\n            <tr>\n              <th>Name</th>\n              <th>Age</th>\n              <th>Address</th>\n              <th>Action</th>\n            </tr>\n          </thead>\n        }\n        <tbody>\n          @for (data of dynamicTable.data; track data) {\n            <tr>\n              <td>{{ data.name }}</td>\n              <td>{{ data.age }}</td>\n              <td>{{ data.address }}</td>\n              <td>\n                <a href=\"#\">Action 一 {{ data.name }}</a>\n                <a href=\"#\">Delete</a>\n              </td>\n            </tr>\n          }\n        </tbody>\n      </nz-table>\n    </div>\n  `\n})\nexport class NzTestTableRtlComponent implements OnInit {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n\n  @ViewChild(NzTableComponent, { static: false }) nzTableComponent!: NzTableComponent<RtlTestDataItem>;\n  pageIndex = 1;\n  pageSize = 10;\n  dataSet: RtlTestDataItem[] = [];\n  header = true;\n  simple = false;\n\n  ngOnInit(): void {\n    for (let i = 1; i <= 20; i++) {\n      this.dataSet.push({\n        name: 'John Brown',\n        age: `${i}2`,\n        address: `New York No. ${i} Lake Park`,\n        description: `My name is John Brown, I am ${i}2 years old, living in New York No. ${i} Lake Park.`,\n        checked: false,\n        expand: false\n      });\n    }\n  }\n}\n"
  },
  {
    "path": "components/table/src/testing/tbody.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, DebugElement } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { NzTableModule, NzTbodyComponent } from 'ng-zorro-antd/table';\n\ndescribe('nz-tbody', () => {\n  describe('nz-tbody in table', () => {\n    let fixture: ComponentFixture<NzTbodyTestTableComponent>;\n    let tbody: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTbodyTestTableComponent);\n      fixture.detectChanges();\n      tbody = fixture.debugElement.query(By.directive(NzTbodyComponent));\n    });\n\n    it('should not add class', () => {\n      fixture.detectChanges();\n      expect(tbody.nativeElement.classList).not.toContain('ant-table-tbody');\n    });\n  });\n\n  describe('nz-tbody in nz-table', () => {\n    let fixture: ComponentFixture<NzTbodyTestNzTableComponent>;\n    let tbody: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTbodyTestNzTableComponent);\n      fixture.detectChanges();\n      tbody = fixture.debugElement.query(By.directive(NzTbodyComponent));\n    });\n    it('should not add class', () => {\n      fixture.detectChanges();\n      expect(tbody.nativeElement.classList).toContain('ant-table-tbody');\n    });\n  });\n});\n\n@Component({\n  imports: [NzTableModule],\n  template: `\n    <table>\n      <tbody></tbody>\n    </table>\n  `\n})\nexport class NzTbodyTestTableComponent {}\n\n@Component({\n  imports: [NzTableModule],\n  template: `\n    <nz-table>\n      <tbody></tbody>\n    </nz-table>\n  `\n})\nexport class NzTbodyTestNzTableComponent {\n  expand = false;\n}\n"
  },
  {
    "path": "components/table/src/testing/td.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, DebugElement, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, fakeAsync, flush, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { NzTdAddOnComponent, NzTableModule } from 'ng-zorro-antd/table';\n\ndescribe('nz-td', () => {\n  let fixture: ComponentFixture<NzTestTdComponent>;\n  let testComponent: NzTestTdComponent;\n  let td: DebugElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n    fixture = TestBed.createComponent(NzTestTdComponent);\n    fixture.detectChanges();\n    testComponent = fixture.debugElement.componentInstance;\n    td = fixture.debugElement.query(By.directive(NzTdAddOnComponent));\n  });\n\n  it('should checkbox work', () => {\n    fixture.detectChanges();\n    expect(td.nativeElement.querySelector('.ant-checkbox-wrapper')).toBeDefined();\n    expect(td.nativeElement.classList).toContain('ant-table-selection-column');\n  });\n\n  it('should checked work', fakeAsync(() => {\n    fixture.detectChanges();\n    expect(td.nativeElement.querySelector('.ant-checkbox-wrapper').firstElementChild!.classList).not.toContain(\n      'ant-checkbox-checked'\n    );\n    testComponent.checked = true;\n    fixture.detectChanges();\n    flush();\n    fixture.detectChanges();\n    expect(testComponent.checked).toBe(true);\n    expect(td.nativeElement.querySelector('.ant-checkbox-wrapper').firstElementChild!.classList).toContain(\n      'ant-checkbox-checked'\n    );\n    expect(testComponent.checkedChange).toHaveBeenCalledTimes(0);\n  }));\n\n  it('should disabled work', () => {\n    fixture.detectChanges();\n    testComponent.disabled = true;\n    fixture.detectChanges();\n    expect(testComponent.checked).toBe(false);\n    expect(\n      td.nativeElement\n        .querySelector('.ant-checkbox-wrapper')\n        .firstElementChild!.classList.contains('ant-checkbox-checked')\n    ).toBe(false);\n    expect(testComponent.checkedChange).toHaveBeenCalledTimes(0);\n    td.nativeElement.querySelector('.ant-checkbox-wrapper').click();\n    fixture.detectChanges();\n    expect(testComponent.checked).toBe(false);\n    expect(\n      td.nativeElement\n        .querySelector('.ant-checkbox-wrapper')\n        .firstElementChild!.classList.contains('ant-checkbox-checked')\n    ).toBe(false);\n    expect(testComponent.checkedChange).toHaveBeenCalledTimes(0);\n  });\n\n  it('should indeterminate work', () => {\n    fixture.detectChanges();\n    fixture.detectChanges();\n    testComponent.indeterminate = true;\n    fixture.detectChanges();\n    expect(\n      td.nativeElement\n        .querySelector('.ant-checkbox-wrapper')\n        .firstElementChild!.classList.contains('ant-checkbox-indeterminate')\n    ).toBe(true);\n    testComponent.checked = true;\n    fixture.detectChanges();\n    expect(\n      td.nativeElement\n        .querySelector('.ant-checkbox-wrapper')\n        .firstElementChild!.classList.contains('ant-checkbox-indeterminate')\n    ).toBe(true);\n  });\n\n  it('should expand work', () => {\n    fixture.detectChanges();\n    expect(td.nativeElement.querySelector('.ant-table-row-expand-icon').classList).toContain(\n      'ant-table-row-expand-icon-collapsed'\n    );\n    testComponent.expand = true;\n    fixture.detectChanges();\n    expect(td.nativeElement.querySelector('.ant-table-row-expand-icon').classList).toContain(\n      'ant-table-row-expand-icon-expanded'\n    );\n    expect(testComponent.expandChange).toHaveBeenCalledTimes(0);\n  });\n\n  it('should click expand work', () => {\n    fixture.detectChanges();\n    expect(td.nativeElement.querySelector('.ant-table-row-expand-icon').classList).toContain(\n      'ant-table-row-expand-icon-collapsed'\n    );\n    td.nativeElement.querySelector('.ant-table-row-expand-icon').click();\n    fixture.detectChanges();\n    expect(testComponent.expand).toBe(true);\n    expect(td.nativeElement.querySelector('.ant-table-row-expand-icon').classList).toContain(\n      'ant-table-row-expand-icon-expanded'\n    );\n    expect(testComponent.expandChange).toHaveBeenCalledTimes(1);\n  });\n\n  it('should be row index when index-size is 0', () => {\n    testComponent.indentSize = 0;\n    fixture.detectChanges();\n    expect(td.nativeElement.querySelector('.ant-table-row-indent')).not.toBeNull();\n  });\n\n  it('should indentSize work', () => {\n    testComponent.indentSize = 20;\n    fixture.detectChanges();\n    expect(td.nativeElement.querySelector('.ant-table-row-indent').style.paddingLeft).toBe('20px');\n  });\n\n  it('should left work', () => {\n    testComponent.left = '20px';\n    fixture.detectChanges();\n    expect(td.nativeElement.classList).toContain('ant-table-cell-fix-left');\n    expect(td.nativeElement.style.left).toBe('20px');\n  });\n\n  it('should right work', () => {\n    testComponent.right = '20px';\n    fixture.detectChanges();\n    expect(td.nativeElement.classList).toContain('ant-table-cell-fix-right');\n    expect(td.nativeElement.style.right).toBe('20px');\n  });\n\n  it('should be throw error when use specific class name', () => {\n    expect(() => {\n      TestBed.configureTestingModule({\n        declarations: [NzTestDisableTdComponent]\n      }).createComponent(NzTestDisableTdComponent);\n    }).toThrow();\n  });\n\n  it('should add aria-label', () => {\n    testComponent.label = 'test-label';\n    fixture.detectChanges();\n    console.log(td.nativeElement.querySelector('label').attributes.getNamedItem('aria-label').value);\n    expect(td.nativeElement.querySelector('label').attributes.getNamedItem('aria-label').value).toBe('test-label'); //toContain('test-label');\n  });\n});\n\n@Component({\n  imports: [NzTableModule],\n  template: `\n    <td\n      [(nzChecked)]=\"checked\"\n      [nzIndeterminate]=\"indeterminate\"\n      [nzLabel]=\"label\"\n      (nzCheckedChange)=\"checkedChange($event)\"\n      [nzDisabled]=\"disabled\"\n      [(nzExpand)]=\"expand\"\n      (nzExpandChange)=\"expandChange($event)\"\n      [nzIndentSize]=\"indentSize\"\n      [nzLeft]=\"left\"\n      [nzRight]=\"right\"\n    ></td>\n  `\n})\nexport class NzTestTdComponent {\n  checked = false;\n  checkedChange = jasmine.createSpy('show change');\n  indeterminate = false;\n  disabled = false;\n  expand = false;\n  expandChange = jasmine.createSpy('expand change');\n  indentSize: number = 0;\n  left: string | boolean = false;\n  right: string | boolean = false;\n  label: string | null = null;\n}\n\n@Component({\n  imports: [NzTableModule],\n  template: `<td class=\"nz-disable-td\" [nzChecked]=\"true\"></td>`\n})\nexport class NzTestDisableTdComponent {}\n"
  },
  {
    "path": "components/table/src/testing/tfoot.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, ElementRef, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\n\nimport { NzTableModule } from '../table.module';\nimport { NzTableSummaryFixedType } from '../table.types';\n\ndescribe('tfoot', () => {\n  let fixture: ComponentFixture<TestComponent>;\n  let component: TestComponent;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n    fixture = TestBed.createComponent(TestComponent);\n    fixture.detectChanges();\n    component = fixture.componentInstance;\n  });\n\n  it('should nzSummary work ', () => {\n    fixture.detectChanges();\n    const tfoot = component.elementRef.nativeElement.querySelector('tfoot.ant-table-summary') as HTMLElement;\n    expect(tfoot.textContent).toContain('summary');\n  });\n\n  it('should fixed work', () => {\n    component.scrollY = '100px';\n    component.fixed = true;\n    fixture.detectChanges();\n\n    const tfoot = component.elementRef.nativeElement.querySelector('div.ant-table-summary tfoot.ant-table-summary');\n    expect(tfoot).toBeTruthy();\n  });\n\n  it('should fixed not work when scrollY is not set', () => {\n    component.scrollY = null;\n    component.fixed = true;\n    fixture.detectChanges();\n\n    const tfoot = component.elementRef.nativeElement.querySelector('div.ant-table-summary tfoot.ant-table-summary');\n    expect(tfoot).not.toBeTruthy();\n  });\n\n  it('should fixed at top work', () => {\n    component.scrollY = '100px';\n    component.fixed = 'top';\n    fixture.detectChanges();\n\n    const tfoot = component.elementRef.nativeElement.querySelector('div.ant-table-header tfoot.ant-table-summary');\n    expect(tfoot).toBeTruthy();\n  });\n});\n\n@Component({\n  imports: [NzTableModule],\n  template: `\n    <nz-table [nzScroll]=\"{ x: scrollX, y: scrollY }\">\n      <thead>\n        <th></th>\n        <th></th>\n      </thead>\n      <tbody>\n        <tr>\n          <td>1</td>\n          <td>2</td>\n        </tr>\n      </tbody>\n      <tfoot nzSummary [nzFixed]=\"fixed\">\n        <td colspan=\"2\">summary</td>\n      </tfoot>\n    </nz-table>\n  `\n})\nexport class TestComponent {\n  scrollX: string | null = null;\n  scrollY: string | null = null;\n  fixed: NzTableSummaryFixedType | boolean = false;\n\n  constructor(public elementRef: ElementRef) {}\n}\n"
  },
  {
    "path": "components/table/src/testing/th.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ApplicationRef, Component, DebugElement, provideZoneChangeDetection, ViewChild } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\nimport { NzThAddOnComponent, NzTableModule } from 'ng-zorro-antd/table';\n\ndescribe('nz-th', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideNoopAnimations(), provideZoneChangeDetection()]\n    });\n  });\n\n  describe('nz-th addon in nz-table', () => {\n    let fixture: ComponentFixture<NzThTestNzTableComponent>;\n    let testComponent: NzThTestNzTableComponent;\n    let th: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzThTestNzTableComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n      th = fixture.debugElement.query(By.directive(NzThAddOnComponent));\n    });\n\n    it('should showSort work', () => {\n      fixture.detectChanges();\n      expect(th.nativeElement.classList).toContain('ant-table-column-has-sorters');\n      expect(th.nativeElement.querySelector('.ant-table-column-sorter')).toBeDefined();\n    });\n\n    it('should sort change work', () => {\n      fixture.detectChanges();\n      expect(th.nativeElement.querySelector('.ant-table-column-sorter-up').classList).not.toContain('active');\n      expect(th.nativeElement.querySelector('.ant-table-column-sorter-down').classList).not.toContain('active');\n      expect(th.nativeElement.classList).not.toContain('ant-table-column-sort');\n      testComponent.sort = 'ascend';\n      fixture.detectChanges();\n      expect(th.nativeElement.querySelector('.ant-table-column-sorter-up').classList).toContain('active');\n      expect(th.nativeElement.querySelector('.ant-table-column-sorter-down').classList).not.toContain('active');\n      expect(th.nativeElement.classList).toContain('ant-table-column-sort');\n      testComponent.sort = 'descend';\n      fixture.detectChanges();\n      expect(th.nativeElement.querySelector('.ant-table-column-sorter-up').classList).not.toContain('active');\n      expect(th.nativeElement.querySelector('.ant-table-column-sorter-down').classList).toContain('active');\n      expect(th.nativeElement.classList).toContain('ant-table-column-sort');\n      testComponent.sort = null;\n      fixture.detectChanges();\n      expect(th.nativeElement.querySelector('.ant-table-column-sorter-up').classList).not.toContain('active');\n      expect(th.nativeElement.querySelector('.ant-table-column-sorter-down').classList).not.toContain('active');\n      expect(th.nativeElement.classList).not.toContain('ant-table-column-sort');\n      expect(testComponent.sortChange).toHaveBeenCalledTimes(0);\n    });\n\n    it('should sort click work', () => {\n      fixture.detectChanges();\n      expect(th.nativeElement.querySelector('.ant-table-column-sorter-up').classList).not.toContain('active');\n      expect(th.nativeElement.querySelector('.ant-table-column-sorter-down').classList).not.toContain('active');\n      th.nativeElement.querySelector('.ant-table-column-sorters').firstElementChild.click();\n      fixture.detectChanges();\n      expect(testComponent.sort).toBe('ascend');\n      expect(testComponent.sortChange).toHaveBeenCalledTimes(1);\n      expect(th.nativeElement.querySelector('.ant-table-column-sorter-up').classList).toContain('active');\n      expect(th.nativeElement.querySelector('.ant-table-column-sorter-down').classList).not.toContain('active');\n      th.nativeElement.querySelector('.ant-table-column-sorters').firstElementChild.click();\n      fixture.detectChanges();\n      expect(testComponent.sortChange).toHaveBeenCalledTimes(2);\n      expect(testComponent.sort).toBe('descend');\n      expect(th.nativeElement.querySelector('.ant-table-column-sorter-up').classList).not.toContain('active');\n      expect(th.nativeElement.querySelector('.ant-table-column-sorter-down').classList).toContain('active');\n      th.nativeElement.querySelector('.ant-table-column-sorters').firstElementChild.click();\n      fixture.detectChanges();\n      expect(testComponent.sortChange).toHaveBeenCalledTimes(3);\n      expect(testComponent.sort).toBe(null);\n    });\n\n    it('should left work', () => {\n      testComponent.left = '20px';\n      fixture.detectChanges();\n      expect(th.nativeElement.classList).toContain('ant-table-cell-fix-left');\n      expect(th.nativeElement.style.left).toBe('20px');\n    });\n\n    it('should right work', () => {\n      testComponent.right = '20px';\n      fixture.detectChanges();\n      expect(th.nativeElement.classList).toContain('ant-table-cell-fix-right');\n      expect(th.nativeElement.style.right).toBe('20px');\n    });\n\n    it('should be throw error when use specific class name', () => {\n      expect(() => {\n        TestBed.configureTestingModule({\n          declarations: [NzTestDisableThComponent]\n        }).createComponent(NzTestDisableThComponent);\n      }).toThrow();\n    });\n\n    it('should not run change detection on click events for the `nz-filter-trigger`', () => {\n      const appRef = TestBed.inject(ApplicationRef);\n      const event = new MouseEvent('click');\n\n      spyOn(appRef, 'tick');\n      spyOn(event, 'stopPropagation').and.callThrough();\n\n      fixture.debugElement.nativeElement\n        .querySelector('nz-filter-trigger .ant-table-filter-trigger')\n        .dispatchEvent(event);\n\n      expect(appRef.tick).not.toHaveBeenCalled();\n      expect(event.stopPropagation).toHaveBeenCalled();\n    });\n  });\n});\n\n@Component({\n  imports: [NzTableModule],\n  template: `\n    @if (!destroy) {\n      <nz-table>\n        <th\n          [nzLeft]=\"left\"\n          [nzRight]=\"right\"\n          [nzWidth]=\"width\"\n          [(nzSortOrder)]=\"sort\"\n          (nzSortOrderChange)=\"sortChange($event)\"\n          [nzFilters]=\"filters\"\n          (nzFilterChange)=\"filterChange($event)\"\n          [nzFilterMultiple]=\"filterMultiple\"\n        ></th>\n      </nz-table>\n    }\n  `\n})\nexport class NzThTestNzTableComponent {\n  @ViewChild(NzThAddOnComponent, { static: false }) nzThComponent!: NzThAddOnComponent<NzSafeAny>;\n  destroy = false;\n  left: string | boolean = false;\n  right: string | boolean = false;\n  width: string | null = null;\n  sort: string | null = null;\n  sortChange = jasmine.createSpy('sort change');\n  filters = [\n    { text: 'filter1', value: '1' },\n    { text: 'filter2', value: '2' }\n  ];\n  filterChange = jasmine.createSpy('filter change');\n  filterMultiple = true;\n}\n\ninterface ItemData {\n  name: string;\n  age: number;\n  address: string;\n}\n\n@Component({\n  imports: [NzTableModule],\n  template: `\n    <nz-table #filterTable [nzData]=\"displayData\">\n      <thead (nzSortOrderChange)=\"sort($any($event))\">\n        <tr>\n          <th nzColumnKey=\"name\" [nzFilters]=\"nameList\" (nzFilterChange)=\"filter($event, searchAddress)\">Name</th>\n          <th nzColumnKey=\"age\">Age</th>\n          <th\n            nzColumnKey=\"address\"\n            [nzFilterMultiple]=\"false\"\n            [nzFilters]=\"addressList\"\n            (nzFilterChange)=\"filter(listOfSearchName, $event)\"\n          >\n            Address\n          </th>\n        </tr>\n      </thead>\n      <tbody>\n        @for (data of filterTable.data; track data) {\n          <tr>\n            <td>{{ data.name }}</td>\n            <td>{{ data.age }}</td>\n            <td>{{ data.address }}</td>\n          </tr>\n        }\n      </tbody>\n    </nz-table>\n  `\n})\nexport class NzThTestTableDefaultFilterComponent {\n  nameList = [\n    { text: 'Joe', value: 'Joe', byDefault: true },\n    { text: 'Jim', value: 'Jim' }\n  ];\n  addressList = [\n    { text: 'London', value: 'London', byDefault: true },\n    { text: 'Sidney', value: 'Sidney' }\n  ];\n  sortName: keyof ItemData | null = null;\n  sortValue: string | null = null;\n  listOfSearchName = ['Joe', 'London'];\n  searchAddress!: string;\n  data: ItemData[] = [\n    {\n      name: 'John Brown',\n      age: 32,\n      address: 'New York No. 1 Lake Park'\n    },\n    {\n      name: 'Jim Green',\n      age: 42,\n      address: 'London No. 1 Lake Park'\n    },\n    {\n      name: 'Joe Black',\n      age: 32,\n      address: 'Sidney No. 1 Lake Park'\n    },\n    {\n      name: 'Jim Red',\n      age: 32,\n      address: 'London No. 2 Lake Park'\n    }\n  ];\n  displayData: ItemData[] = [];\n\n  @ViewChild(NzThAddOnComponent, { static: false }) nzThComponent!: NzThAddOnComponent<ItemData>;\n\n  sort(sort: { key: keyof ItemData; value: string }): void {\n    this.sortName = sort.key;\n    this.sortValue = sort.value;\n    this.search();\n  }\n\n  filter(listOfSearchName: string[], searchAddress: string): void {\n    this.listOfSearchName = listOfSearchName;\n    this.searchAddress = searchAddress;\n    this.search();\n  }\n\n  search(): void {\n    /** filter data **/\n    const filterFunc = (item: { name: string; address: string; age: number }): boolean =>\n      (this.searchAddress ? item.address.indexOf(this.searchAddress) !== -1 : true) &&\n      (this.listOfSearchName.length ? this.listOfSearchName.some(name => item.name.indexOf(name) !== -1) : true);\n    const data = this.data.filter(item => filterFunc(item));\n    /** sort data **/\n    if (this.sortName && this.sortValue) {\n      this.displayData = data.sort((a: ItemData, b: ItemData) =>\n        this.sortValue === 'ascend'\n          ? a[this.sortName!] > b[this.sortName!]\n            ? 1\n            : -1\n          : b[this.sortName!] > a[this.sortName!]\n            ? 1\n            : -1\n      );\n    } else {\n      this.displayData = data;\n    }\n  }\n}\n\n@Component({\n  imports: [NzTableModule],\n  template: `<th class=\"nz-disable-th\"></th>`\n})\nexport class NzTestDisableThComponent {}\n"
  },
  {
    "path": "components/table/src/testing/thead.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, DebugElement } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { NzTableComponent, NzTableModule } from 'ng-zorro-antd/table';\n\ndescribe('nz-thead', () => {\n  let fixture: ComponentFixture<NzTheadTestNzTableComponent>;\n  let testComponent: NzTheadTestNzTableComponent;\n  let table: DebugElement;\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzTheadTestNzTableComponent);\n    fixture.detectChanges();\n    testComponent = fixture.debugElement.componentInstance;\n    table = fixture.debugElement.query(By.directive(NzTableComponent));\n  });\n\n  it('should sort change', () => {\n    fixture.detectChanges();\n    expect(testComponent.sortChange).toHaveBeenCalledTimes(0);\n    const upButtons = table.nativeElement.querySelectorAll('.ant-table-column-sorters');\n    upButtons[0].click();\n    fixture.detectChanges();\n    expect(testComponent.sortChange).toHaveBeenCalledTimes(1);\n    expect(upButtons[0].querySelector('.ant-table-column-sorter-down').classList).toContain('anticon-caret-down');\n    upButtons[1].click();\n    fixture.detectChanges();\n    expect(upButtons[0].querySelector('.ant-table-column-sorter-down').classList).toContain('anticon-caret-down');\n    expect(upButtons[1].querySelector('.ant-table-column-sorter-down').classList).toContain('anticon-caret-down');\n    expect(testComponent.sortChange).toHaveBeenCalledTimes(2);\n  });\n\n  // Test for #3603\n  it('should support dynamic headers', () => {\n    fixture.detectChanges();\n    expect(testComponent.sortChange).toHaveBeenCalledTimes(0);\n    let upButtons = table.nativeElement.querySelectorAll('.ant-table-column-sorters');\n    upButtons[2].click();\n    fixture.detectChanges();\n    expect(testComponent.sortChange).toHaveBeenCalledTimes(1);\n    upButtons[3].click();\n    fixture.detectChanges();\n    expect(testComponent.sortChange).toHaveBeenCalledTimes(2);\n\n    testComponent.columns = testComponent.columns.slice(0, 1);\n    fixture.detectChanges();\n    upButtons = table.nativeElement.querySelectorAll('.ant-table-column-sorters');\n    expect(upButtons.length).toBe(3);\n    upButtons[2].click();\n    expect(testComponent.sortChange).toHaveBeenCalledTimes(3);\n  });\n});\n\n@Component({\n  imports: [NzTableModule],\n  template: `\n    <nz-table>\n      <thead (nzSortOrderChange)=\"sortChange($event)\">\n        <th nzColumnKey=\"first\" [nzSortFn]=\"filterFn\"></th>\n        <th nzColumnKey=\"second\" [nzSortFn]=\"filterFn\">></th>\n        @for (col of columns; track col) {\n          <th [nzColumnKey]=\"col\" [nzSortFn]=\"filterFn\">></th>\n        }\n      </thead>\n    </nz-table>\n  `\n})\nexport class NzTheadTestNzTableComponent {\n  sortChange = jasmine.createSpy('sort change');\n  columns = ['third', 'fourth'];\n  filterFn = (): number => -1;\n}\n"
  },
  {
    "path": "components/table/src/testing/tr.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, DebugElement } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { NzTableModule, NzTrDirective } from 'ng-zorro-antd/table';\n\ndescribe('nz-tr', () => {\n  let fixture: ComponentFixture<NzTrTestTableComponent>;\n  let tr: DebugElement;\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzTrTestTableComponent);\n    fixture.detectChanges();\n    tr = fixture.debugElement.query(By.directive(NzTrDirective));\n  });\n\n  it('should not add class', () => {\n    fixture.detectChanges();\n    expect(tr.nativeElement.classList).not.toContain('ant-table-row');\n  });\n});\n\n@Component({\n  imports: [NzTableModule],\n  template: `\n    <table>\n      <tr></tr>\n    </table>\n  `\n})\nexport class NzTrTestTableComponent {}\n"
  },
  {
    "path": "components/table/style/bordered.less",
    "content": "@import './size';\n@import (reference) '../../style/themes/index';\n@table-prefix-cls: ~'@{ant-prefix}-table';\n\n@table-border: @border-width-base @border-style-base @table-border-color;\n\n.@{table-prefix-cls}.@{table-prefix-cls}-bordered {\n  // ============================ Title =============================\n  > .@{table-prefix-cls}-title {\n    border: @table-border;\n    border-bottom: 0;\n  }\n\n  > .@{table-prefix-cls}-container {\n    // ============================ Content ============================\n    border-left: @table-border;\n\n    > .@{table-prefix-cls}-content,\n    > .@{table-prefix-cls}-header,\n    > .@{table-prefix-cls}-body,\n    > .@{table-prefix-cls}-summary {\n      > table {\n        // ============================= Cell =============================\n        > thead > tr > th,\n        > tbody > tr > td,\n        > tfoot > tr > th,\n        > tfoot > tr > td {\n          border-right: @table-border;\n        }\n        // ============================ Header ============================\n        > thead {\n          > tr:not(:last-child) > th {\n            border-bottom: @border-width-base @border-style-base @table-border-color;\n          }\n\n          > tr > th {\n            &::before {\n              background-color: transparent !important;\n            }\n          }\n        }\n\n        // Fixed right should provides additional border\n        > thead > tr,\n        > tbody > tr,\n        > tfoot > tr {\n          > .@{table-prefix-cls}-cell-fix-right-first::after {\n            border-right: @table-border;\n          }\n        }\n      }\n\n      // ========================== Expandable ==========================\n      > table > tbody > tr > td {\n        > .@{table-prefix-cls}-expanded-row-fixed {\n          margin: -@table-padding-vertical (-@table-padding-horizontal - @border-width-base);\n\n          &::after {\n            position: absolute;\n            top: 0;\n            right: @border-width-base;\n            bottom: 0;\n            border-right: @table-border;\n            content: '';\n          }\n        }\n      }\n    }\n\n    > .@{table-prefix-cls}-content,\n    > .@{table-prefix-cls}-header {\n      > table {\n        border-top: @table-border;\n      }\n    }\n  }\n\n  &.@{table-prefix-cls}-scroll-horizontal {\n    > .@{table-prefix-cls}-container > .@{table-prefix-cls}-body {\n      > table > tbody {\n        > tr.@{table-prefix-cls}-expanded-row,\n        > tr.@{table-prefix-cls}-placeholder {\n          > td {\n            border-right: 0;\n          }\n        }\n      }\n    }\n  }\n\n  // Size related\n  &.@{table-prefix-cls}-middle {\n    > .@{table-prefix-cls}-container {\n      > .@{table-prefix-cls}-content,\n      > .@{table-prefix-cls}-body {\n        > table > tbody > tr > td {\n          > .@{table-prefix-cls}-expanded-row-fixed {\n            margin: -@table-padding-vertical-md (-@table-padding-horizontal-md - @border-width-base);\n          }\n        }\n      }\n    }\n  }\n\n  &.@{table-prefix-cls}-small {\n    > .@{table-prefix-cls}-container {\n      > .@{table-prefix-cls}-content,\n      > .@{table-prefix-cls}-body {\n        > table > tbody > tr > td {\n          > .@{table-prefix-cls}-expanded-row-fixed {\n            margin: -@table-padding-vertical-sm (-@table-padding-horizontal-sm - @border-width-base);\n          }\n        }\n      }\n    }\n  }\n\n  // ============================ Footer ============================\n  > .@{table-prefix-cls}-footer {\n    border: @table-border;\n    border-top: 0;\n  }\n}\n\n.@{table-prefix-cls}-cell {\n  // ============================ Nested ============================\n  .@{table-prefix-cls}-container:first-child {\n    // :first-child to avoid the case when bordered and title is set\n    border-top: 0;\n  }\n\n  // https://github.com/ant-design/ant-design/issues/35577\n  &-scrollbar:not([rowspan]) {\n    box-shadow: 0 @border-width-base 0 @border-width-base @table-header-bg;\n  }\n}\n"
  },
  {
    "path": "components/table/style/entry.less",
    "content": "@import './index.less';\n@import './patch.less';\n// style dependencies\n// deps-lint-skip: menu\n@import '../../empty/style/entry.less';\n@import '../../radio/style/entry.less';\n@import '../../checkbox/style/entry.less';\n@import '../../dropdown/style/entry.less';\n@import '../../spin/style/entry.less';\n@import '../../pagination/style/entry.less';\n"
  },
  {
    "path": "components/table/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import './size';\n@import './bordered';\n\n@table-prefix-cls: ~'@{ant-prefix}-table';\n@tree-prefix-cls: ~'@{ant-prefix}-tree';\n@dropdown-prefix-cls: ~'@{ant-prefix}-dropdown';\n@descriptions-prefix-cls: ~'@{ant-prefix}-descriptions';\n@table-header-icon-color: #bfbfbf;\n@table-header-icon-color-hover: darken(@table-header-icon-color, 10%);\n@table-sticky-zindex: calc(@zindex-table-fixed + 1);\n@table-sticky-scroll-bar-active-bg: fade(@table-sticky-scroll-bar-bg, 80%);\n@table-filter-dropdown-max-height: 264px;\n@table-expand-column-width: 48px;\n\n.@{table-prefix-cls}-wrapper {\n  clear: both;\n  max-width: 100%;\n  .clearfix();\n}\n\n.@{table-prefix-cls} {\n  .reset-component();\n  position: relative;\n  font-size: @table-font-size;\n  background: @table-bg;\n  border-radius: @table-border-radius-base;\n\n  // https://github.com/ant-design/ant-design/issues/17611\n  table {\n    width: 100%;\n    text-align: left;\n    border-radius: @table-border-radius-base @table-border-radius-base 0 0;\n    border-collapse: separate;\n    border-spacing: 0;\n  }\n\n  // ============================= Cell =============================\n  &-thead > tr > th,\n  &-tbody > tr > td,\n  tfoot > tr > th,\n  tfoot > tr > td {\n    position: relative;\n    padding: @table-padding-vertical @table-padding-horizontal;\n    overflow-wrap: break-word;\n  }\n\n  &-cell-ellipsis {\n    overflow: hidden;\n    white-space: nowrap;\n    text-overflow: ellipsis;\n    word-break: keep-all;\n\n    // Fixed first or last should special process\n    &.@{table-prefix-cls}-cell-fix-left-last,\n    &.@{table-prefix-cls}-cell-fix-right-first {\n      overflow: visible;\n\n      .@{table-prefix-cls}-cell-content {\n        display: block;\n        overflow: hidden;\n        text-overflow: ellipsis;\n      }\n    }\n\n    .@{table-prefix-cls}-column-title {\n      overflow: hidden;\n      text-overflow: ellipsis;\n      word-break: keep-all;\n    }\n  }\n\n  // ============================ Title =============================\n  &-title {\n    padding: @table-padding-vertical @table-padding-horizontal;\n  }\n\n  // ============================ Footer ============================\n  &-footer {\n    padding: @table-padding-vertical @table-padding-horizontal;\n    color: @table-footer-color;\n    background: @table-footer-bg;\n  }\n\n  // ============================ Header ============================\n  &-thead {\n    > tr {\n      > th {\n        position: relative;\n        color: @table-header-color;\n        font-weight: 500;\n        text-align: left;\n        background: @table-header-bg;\n        border-bottom: @border-width-base @border-style-base @table-border-color;\n        transition: background 0.3s ease;\n\n        &[colspan]:not([colspan='1']) {\n          text-align: center;\n        }\n\n        &:not(:last-child):not(.@{table-prefix-cls}-selection-column):not(.@{table-prefix-cls}-row-expand-icon-cell):not([colspan])::before {\n          position: absolute;\n          top: 50%;\n          right: 0;\n          width: 1px;\n          height: 1.6em;\n          background-color: @table-header-cell-split-color;\n          transform: translateY(-50%);\n          transition: background-color 0.3s;\n          content: '';\n        }\n      }\n    }\n\n    > tr:not(:last-child) > th {\n      &[colspan] {\n        border-bottom: 0;\n      }\n    }\n  }\n\n  // ============================= Body =============================\n  &-tbody {\n    > tr {\n      > td {\n        border-bottom: @border-width-base @border-style-base @table-border-color;\n        transition: background 0.3s;\n\n        // ========================= Nest Table ===========================\n        > .@{table-prefix-cls}-wrapper:only-child,\n        > .@{table-prefix-cls}-expanded-row-fixed > .@{table-prefix-cls}-wrapper:only-child {\n          .@{table-prefix-cls} {\n            margin: -@table-padding-vertical -@table-padding-horizontal -@table-padding-vertical (@table-expand-column-width -\n                  @table-padding-horizontal);\n\n            &-tbody > tr:last-child > td {\n              border-bottom: 0;\n\n              &:first-child,\n              &:last-child {\n                border-radius: 0;\n              }\n            }\n          }\n        }\n      }\n\n      &.@{table-prefix-cls}-row:hover > td,\n      > td.@{table-prefix-cls}-cell-row-hover {\n        background: @table-row-hover-bg;\n      }\n\n      &.@{table-prefix-cls}-row-selected {\n        > td {\n          background: @table-selected-row-bg;\n          border-color: rgba(0, 0, 0, 0.03);\n        }\n\n        &:hover {\n          > td {\n            background: @table-selected-row-hover-bg;\n          }\n        }\n      }\n    }\n  }\n\n  // =========================== Summary ============================\n  &-summary {\n    position: relative;\n    z-index: @zindex-table-fixed;\n    background: @table-bg;\n\n    div& {\n      box-shadow: 0 -@border-width-base 0 @table-border-color;\n    }\n\n    > tr {\n      > th,\n      > td {\n        border-bottom: @border-width-base @border-style-base @table-border-color;\n      }\n    }\n  }\n\n  // ========================== Pagination ==========================\n  &-pagination.@{ant-prefix}-pagination {\n    margin: 16px 0;\n  }\n\n  &-pagination {\n    display: flex;\n    flex-wrap: wrap;\n    row-gap: @padding-xs;\n\n    > * {\n      flex: none;\n    }\n\n    &-left {\n      justify-content: flex-start;\n    }\n\n    &-center {\n      justify-content: center;\n    }\n\n    &-right {\n      justify-content: flex-end;\n    }\n  }\n\n  // ================================================================\n  // =                           Function                           =\n  // ================================================================\n\n  // ============================ Sorter ============================\n  &-thead th.@{table-prefix-cls}-column-has-sorters {\n    outline: none;\n    cursor: pointer;\n    transition: all 0.3s;\n\n    &:hover {\n      background: @table-header-sort-active-bg;\n\n      &::before {\n        background-color: transparent !important;\n      }\n    }\n\n    &:focus-visible {\n      color: @primary-color;\n    }\n\n    // https://github.com/ant-design/ant-design/issues/30969\n    &.@{table-prefix-cls}-cell-fix-left:hover,\n    &.@{table-prefix-cls}-cell-fix-right:hover {\n      background: @table-fixed-header-sort-active-bg;\n    }\n  }\n\n  &-thead th.@{table-prefix-cls}-column-sort {\n    background: @table-header-sort-bg;\n\n    &::before {\n      background-color: transparent !important;\n    }\n  }\n\n  td&-column-sort {\n    background: @table-body-sort-bg;\n  }\n\n  &-column-title {\n    position: relative;\n    z-index: 1;\n    flex: 1;\n  }\n\n  &-column-sorters {\n    display: flex;\n    flex: auto;\n    align-items: center;\n    justify-content: space-between;\n\n    &::after {\n      position: absolute;\n      top: 0;\n      right: 0;\n      bottom: 0;\n      left: 0;\n      width: 100%;\n      height: 100%;\n      content: '';\n    }\n  }\n\n  &-column-sorter {\n    margin-left: 4px;\n    color: @table-header-icon-color;\n    font-size: 0;\n    transition: color 0.3s;\n\n    &-inner {\n      display: inline-flex;\n      flex-direction: column;\n      align-items: center;\n    }\n\n    &-up,\n    &-down {\n      font-size: 11px;\n\n      &.active {\n        color: @primary-color;\n      }\n    }\n\n    &-up + &-down {\n      margin-top: -0.3em;\n    }\n  }\n\n  &-column-sorters:hover &-column-sorter {\n    color: darken(@table-header-icon-color, 10%);\n  }\n\n  // ============================ Filter ============================\n  &-filter-column {\n    display: flex;\n    justify-content: space-between;\n  }\n\n  &-filter-trigger {\n    position: relative;\n    display: flex;\n    align-items: center;\n    margin: -4px (-@table-padding-horizontal / 2) -4px 4px;\n    padding: 0 4px;\n    color: @table-header-icon-color;\n    font-size: @font-size-sm;\n    border-radius: @border-radius-base;\n    cursor: pointer;\n    transition: all 0.3s;\n\n    &:hover {\n      color: @text-color-secondary;\n      background: @table-header-filter-active-bg;\n    }\n\n    &.active {\n      color: @primary-color;\n    }\n  }\n\n  // Dropdown\n  &-filter-dropdown {\n    .reset-component();\n\n    min-width: 120px;\n    background-color: @table-filter-dropdown-bg;\n    border-radius: @border-radius-base;\n    box-shadow: @box-shadow-base;\n\n    // Reset menu\n    .@{dropdown-prefix-cls}-menu {\n      // https://github.com/ant-design/ant-design/issues/4916\n      // https://github.com/ant-design/ant-design/issues/19542\n      max-height: @table-filter-dropdown-max-height;\n      overflow-x: hidden;\n      border: 0;\n      box-shadow: none;\n\n      &:empty::after {\n        display: block;\n        padding: 8px 0;\n        color: @disabled-color;\n        font-size: @font-size-sm;\n        text-align: center;\n        content: 'Not Found';\n      }\n    }\n\n    &-tree {\n      padding: 8px 8px 0;\n\n      .@{tree-prefix-cls}-treenode .@{tree-prefix-cls}-node-content-wrapper:hover {\n        background-color: @tree-node-hover-bg;\n      }\n\n      .@{tree-prefix-cls}-treenode-checkbox-checked .@{tree-prefix-cls}-node-content-wrapper {\n        &,\n        &:hover {\n          background-color: @tree-node-selected-bg;\n        }\n      }\n    }\n\n    &-search {\n      padding: 8px;\n      border-bottom: @border-width-base @border-color-split @border-style-base;\n\n      &-input {\n        input {\n          min-width: 140px;\n        }\n        .@{iconfont-css-prefix} {\n          color: @disabled-color;\n        }\n      }\n    }\n\n    &-checkall {\n      width: 100%;\n      margin-bottom: 4px;\n      margin-left: 4px;\n    }\n\n    &-submenu > ul {\n      max-height: calc(100vh - 130px);\n      overflow-x: hidden;\n      overflow-y: auto;\n    }\n\n    // Checkbox\n    &,\n    &-submenu {\n      .@{ant-prefix}-checkbox-wrapper + span {\n        padding-left: 8px;\n      }\n    }\n\n    // Operation\n    &-btns {\n      display: flex;\n      justify-content: space-between;\n      padding: 7px 8px;\n      overflow: hidden;\n      background-color: @table-filter-btns-bg;\n      border-top: @border-width-base @border-style-base @table-border-color;\n    }\n  }\n\n  // ========================== Selections ==========================\n  &-selection-col {\n    width: @table-selection-column-width;\n  }\n\n  &-bordered &-selection-col {\n    width: @table-selection-column-width + 18px;\n  }\n\n  table tr th&-selection-column,\n  table tr td&-selection-column {\n    padding-right: @padding-xs;\n    padding-left: @padding-xs;\n    text-align: center;\n\n    .@{ant-prefix}-radio-wrapper {\n      margin-right: 0;\n    }\n  }\n\n  table tr th&-selection-column&-cell-fix-left {\n    z-index: 3;\n  }\n\n  table tr th&-selection-column::after {\n    background-color: transparent !important;\n  }\n\n  &-selection {\n    position: relative;\n    display: inline-flex;\n    flex-direction: column;\n\n    &-extra {\n      position: absolute;\n      top: 0;\n      z-index: 1;\n      cursor: pointer;\n      transition: all 0.3s;\n      margin-inline-start: 100%;\n      padding-inline-start: (@table-padding-horizontal / 4);\n\n      .@{iconfont-css-prefix} {\n        color: @table-header-icon-color;\n        font-size: 10px;\n\n        &:hover {\n          color: @table-header-icon-color-hover;\n        }\n      }\n    }\n  }\n\n  // ========================== Expandable ==========================\n  &-expand-icon-col {\n    width: @table-expand-column-width;\n  }\n\n  &-row-expand-icon-cell {\n    text-align: center;\n\n    .@{table-prefix-cls}-row-expand-icon {\n      display: inline-flex;\n      float: none;\n      vertical-align: sub;\n    }\n  }\n\n  &-row-indent {\n    float: left;\n    height: 1px;\n  }\n\n  &-row-expand-icon {\n    .operation-unit();\n    position: relative;\n    float: left;\n    box-sizing: border-box;\n    width: @expand-icon-size;\n    height: @expand-icon-size;\n    padding: 0;\n    color: inherit;\n    line-height: ceil(((@font-size-sm * 1.4 - @border-width-base * 3) / 2)) * 2 + @border-width-base *\n      3;\n    background: @table-expand-icon-bg;\n    border: @border-width-base @border-style-base @table-border-color;\n    border-radius: @border-radius-base;\n    transform: scale((unit(@checkbox-size) / unit(@expand-icon-size)));\n    transition: all 0.3s;\n    user-select: none;\n    @expand-icon-size: ceil(((@font-size-sm * 1.4 - @border-width-base * 3) / 2)) * 2 +\n      @border-width-base * 3;\n\n    &:focus,\n    &:hover,\n    &:active {\n      border-color: currentcolor;\n    }\n\n    &::before,\n    &::after {\n      position: absolute;\n      background: currentcolor;\n      transition: transform 0.3s ease-out;\n      content: '';\n    }\n\n    &::before {\n      top: ceil(((@font-size-sm * 1.4 - @border-width-base * 3) / 2));\n      right: 3px;\n      left: 3px;\n      height: @border-width-base;\n    }\n\n    &::after {\n      top: 3px;\n      bottom: 3px;\n      left: ceil(((@font-size-sm * 1.4 - @border-width-base * 3) / 2));\n      width: @border-width-base;\n      transform: rotate(90deg);\n    }\n\n    // Motion effect\n    &-collapsed::before {\n      transform: rotate(-180deg);\n    }\n\n    &-collapsed::after {\n      transform: rotate(0deg);\n    }\n\n    &-spaced {\n      &::before,\n      &::after {\n        display: none;\n        content: none;\n      }\n      background: transparent;\n      border: 0;\n      visibility: hidden;\n    }\n\n    .@{table-prefix-cls}-row-indent + & {\n      margin-top: ((@font-size-base * @line-height-base - @border-width-base * 3) / 2) -\n        ceil(((@font-size-sm * 1.4 - @border-width-base * 3) / 2));\n      margin-right: @padding-xs;\n    }\n  }\n\n  tr&-expanded-row {\n    &,\n    &:hover {\n      > td {\n        background: @table-expanded-row-bg;\n      }\n    }\n\n    // https://github.com/ant-design/ant-design/issues/25573\n    .@{descriptions-prefix-cls}-view {\n      display: flex;\n\n      table {\n        flex: auto;\n        width: auto;\n      }\n    }\n  }\n\n  // With fixed\n  .@{table-prefix-cls}-expanded-row-fixed {\n    position: relative;\n    margin: -@table-padding-vertical -@table-padding-horizontal;\n    padding: @table-padding-vertical @table-padding-horizontal;\n  }\n\n  // ========================= Placeholder ==========================\n  &-tbody > tr&-placeholder {\n    text-align: center;\n    .@{table-prefix-cls}-empty & {\n      color: @disabled-color;\n    }\n\n    &:hover {\n      > td {\n        background: @component-background;\n      }\n    }\n  }\n\n  // ============================ Fixed =============================\n  &-cell-fix-left,\n  &-cell-fix-right {\n    position: sticky !important;\n    z-index: @zindex-table-fixed;\n    background: @table-bg;\n  }\n\n  &-cell-fix-left-first::after,\n  &-cell-fix-left-last::after {\n    position: absolute;\n    top: 0;\n    right: 0;\n    bottom: -1px;\n    width: 30px;\n    transform: translateX(100%);\n    transition: box-shadow 0.3s;\n    content: '';\n    pointer-events: none;\n  }\n\n  &-cell-fix-left-all::after {\n    display: none;\n  }\n\n  &-cell-fix-right-first::after,\n  &-cell-fix-right-last::after {\n    position: absolute;\n    top: 0;\n    bottom: -1px;\n    left: 0;\n    width: 30px;\n    transform: translateX(-100%);\n    transition: box-shadow 0.3s;\n    content: '';\n    pointer-events: none;\n  }\n\n  .@{table-prefix-cls}-container {\n    &::before,\n    &::after {\n      position: absolute;\n      top: 0;\n      bottom: 0;\n      z-index: calc(@table-sticky-zindex + 1);\n      width: 30px;\n      transition: box-shadow 0.3s;\n      content: '';\n      pointer-events: none;\n    }\n\n    &::before {\n      left: 0;\n    }\n\n    &::after {\n      right: 0;\n    }\n  }\n\n  &-ping-left {\n    &:not(.@{table-prefix-cls}-has-fix-left) > .@{table-prefix-cls}-container {\n      position: relative;\n\n      &::before {\n        box-shadow: inset 10px 0 8px -8px darken(@shadow-color, 5%);\n      }\n    }\n\n    .@{table-prefix-cls}-cell-fix-left-first::after,\n    .@{table-prefix-cls}-cell-fix-left-last::after {\n      box-shadow: inset 10px 0 8px -8px darken(@shadow-color, 5%);\n    }\n\n    .@{table-prefix-cls}-cell-fix-left-last::before {\n      background-color: transparent !important;\n    }\n  }\n\n  &-ping-right {\n    &:not(.@{table-prefix-cls}-has-fix-right) > .@{table-prefix-cls}-container {\n      position: relative;\n\n      &::after {\n        box-shadow: inset -10px 0 8px -8px darken(@shadow-color, 5%);\n      }\n    }\n\n    .@{table-prefix-cls}-cell-fix-right-first::after,\n    .@{table-prefix-cls}-cell-fix-right-last::after {\n      box-shadow: inset -10px 0 8px -8px darken(@shadow-color, 5%);\n    }\n  }\n\n  &-sticky {\n    &-holder {\n      position: sticky;\n      z-index: @table-sticky-zindex;\n      background: @component-background;\n    }\n\n    &-scroll {\n      position: sticky;\n      bottom: 0;\n      z-index: @table-sticky-zindex;\n      display: flex;\n      align-items: center;\n      background: lighten(@table-border-color, 80%);\n      border-top: 1px solid @table-border-color;\n      opacity: 0.6;\n\n      &:hover {\n        transform-origin: center bottom;\n      }\n\n      &-bar {\n        height: 8px;\n        background-color: @table-sticky-scroll-bar-bg;\n        border-radius: @table-sticky-scroll-bar-radius;\n\n        &:hover {\n          background-color: @table-sticky-scroll-bar-active-bg;\n        }\n\n        &-active {\n          background-color: @table-sticky-scroll-bar-active-bg;\n        }\n      }\n    }\n  }\n}\n\n@media all and (-ms-high-contrast: none) {\n  .@{table-prefix-cls} {\n    &-ping-left {\n      .@{table-prefix-cls}-cell-fix-left-last::after {\n        box-shadow: none !important;\n      }\n    }\n\n    &-ping-right {\n      .@{table-prefix-cls}-cell-fix-right-first::after {\n        box-shadow: none !important;\n      }\n    }\n  }\n}\n\n@import './radius';\n@import './rtl';\n"
  },
  {
    "path": "components/table/style/patch.less",
    "content": "nz-table,\nnz-table-title-footer,\nnz-table-inner-scroll,\nnz-table-inner-default,\nnz-table-selection {\n  display: block;\n}\n\nnz-filter-trigger {\n  display: inline-flex;\n}\n\n.nz-table-out-bordered {\n  > .@{table-prefix-cls}-title {\n    border: @table-border;\n    border-bottom: 0;\n  }\n  > .@{table-prefix-cls}-container {\n    border: @table-border;\n    border-bottom: 0;\n  }\n  > .@{table-prefix-cls}-footer {\n    border: @table-border;\n    border-top: 0;\n  }\n}\n\ncdk-virtual-scroll-viewport.ant-table-body {\n  overflow-y: scroll;\n}\n\n.nz-table-hide-scrollbar {\n  scrollbar-color: @table-header-bg @table-header-bg;\n\n  &::-webkit-scrollbar {\n    background-color: @table-header-bg;\n  }\n}\n\n.@{table-prefix-cls}.@{table-prefix-cls}-small {\n  .nz-table-hide-scrollbar {\n    scrollbar-color: @table-header-bg-sm @table-header-bg-sm;\n\n    &::-webkit-scrollbar {\n      background-color: transparent;\n    }\n  }\n}\n\n.ant-table-wrapper-rtl .ant-table thead > tr > th.ant-table-selection-column {\n  text-align: center;\n}\n\n// virtual scroll border\n.@{table-prefix-cls}.@{table-prefix-cls}-bordered {\n\n  > .@{table-prefix-cls}-container {\n    > .cdk-virtual-scroll-viewport > .cdk-virtual-scroll-content-wrapper {\n      > table {\n        // ============================= Cell =============================\n        > thead > tr > th,\n        > tbody > tr > td,\n        > tfoot > tr > th,\n        > tfoot > tr > td {\n          border-right: @table-border;\n        }\n        // ============================ Header ============================\n        > thead {\n          > tr:not(:last-child) > th {\n            border-bottom: @border-width-base @border-style-base @table-border-color;\n          }\n        }\n\n        // Fixed right should provides additional border\n        > thead > tr,\n        > tbody > tr,\n        > tfoot > tr {\n          > .@{table-prefix-cls}-cell-fix-right-first::after {\n            border-right: @table-border;\n          }\n        }\n      }\n\n      // ========================== Expandable ==========================\n      > table > tbody > tr > td {\n        > .@{table-prefix-cls}-expanded-row-fixed {\n          margin: -@table-padding-vertical (-@table-padding-horizontal - @border-width-base);\n\n          &::after {\n            position: absolute;\n            top: 0;\n            right: @border-width-base;\n            bottom: 0;\n            border-right: @table-border;\n            content: '';\n          }\n        }\n      }\n    }\n  }\n\n  &.@{table-prefix-cls}-scroll-horizontal {\n    > .@{table-prefix-cls}-container > .cdk-virtual-scroll-viewport > .cdk-virtual-scroll-content-wrapper {\n      > table > tbody {\n        > tr.@{table-prefix-cls}-expanded-row,\n        > tr.@{table-prefix-cls}-placeholder {\n          > td {\n            border-right: 0;\n          }\n        }\n      }\n    }\n  }\n\n  // Size related\n  &.@{table-prefix-cls}-middle {\n    > .@{table-prefix-cls}-container {\n      > .cdk-virtual-scroll-viewport > .cdk-virtual-scroll-content-wrapper {\n        > table > tbody > tr > td {\n          > .@{table-prefix-cls}-expanded-row-fixed {\n            margin: -@table-padding-vertical-md (-@table-padding-horizontal-md - @border-width-base);\n          }\n        }\n      }\n    }\n  }\n\n  &.@{table-prefix-cls}-small {\n    > .@{table-prefix-cls}-container {\n      > .cdk-virtual-scroll-viewport > .cdk-virtual-scroll-content-wrapper {\n        > table > tbody > tr > td {\n          > .@{table-prefix-cls}-expanded-row-fixed {\n            margin: -@table-padding-vertical-sm (-@table-padding-horizontal-sm - @border-width-base);\n          }\n        }\n      }\n    }\n  }\n}\n\n.@{table-prefix-cls}-custom-column {\n  col {\n    display: none;\n    width: auto !important;\n    min-width: auto !important;\n  }\n\n  .@{table-prefix-cls}-thead {\n    .@{table-prefix-cls}-row, tr {\n      display: flex;\n      justify-content: space-between;\n      width: 100%;\n\n      th {\n        overflow: hidden;\n      }\n    }\n  }\n\n  .@{table-prefix-cls}-tbody {\n    .@{table-prefix-cls}-row, tr {\n      display: flex;\n      justify-content: space-between;\n      width: 100%;\n\n      td {\n        overflow: hidden;\n      }\n\n      .nz-disable-td {\n        width: 100%;\n      }\n    }\n  }\n\n  .ant-table-fixed {\n    tr {\n      .ant-table-cell-fix-left-last, .ant-table-cell-fix-right-first {\n        overflow: visible;\n      }\n    }\n\n    .@{table-prefix-cls}-row {\n      width: 100%;\n    }\n  }\n}"
  },
  {
    "path": "components/table/style/radius.less",
    "content": "// ================================================================\n// =                         Border Radius                         =\n// ================================================================\n.@{table-prefix-cls} {\n  /* title + table */\n  &-title {\n    border-radius: @table-border-radius-base @table-border-radius-base 0 0;\n  }\n\n  &-title + &-container {\n    border-top-left-radius: 0;\n    border-top-right-radius: 0;\n\n    table {\n      border-radius: 0;\n\n      > thead > tr:first-child {\n        th:first-child {\n          border-radius: 0;\n        }\n\n        th:last-child {\n          border-radius: 0;\n        }\n      }\n    }\n  }\n\n  /* table */\n  &-container {\n    border-top-left-radius: @table-border-radius-base;\n    border-top-right-radius: @table-border-radius-base;\n\n    table > thead > tr:first-child {\n      th:first-child {\n        border-top-left-radius: @table-border-radius-base;\n      }\n\n      th:last-child {\n        border-top-right-radius: @table-border-radius-base;\n      }\n    }\n  }\n\n  /* table + footer */\n  &-footer {\n    border-radius: 0 0 @table-border-radius-base @table-border-radius-base;\n  }\n}\n"
  },
  {
    "path": "components/table/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@table-prefix-cls: ~'@{ant-prefix}-table';\n@table-wrapepr-cls: ~'@{table-prefix-cls}-wrapper';\n@table-wrapepr-rtl-cls: ~'@{table-prefix-cls}-wrapper-rtl';\n\n.@{table-prefix-cls}-wrapper {\n  &-rtl {\n    direction: rtl;\n  }\n}\n\n.@{table-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  table {\n    .@{table-wrapepr-rtl-cls} & {\n      text-align: right;\n    }\n  }\n\n  // ============================ Header ============================\n  &-thead {\n    > tr {\n      > th {\n        &[colspan]:not([colspan='1']) {\n          .@{table-wrapepr-rtl-cls} & {\n            text-align: center;\n          }\n        }\n\n        &:not(:last-child):not(.@{table-prefix-cls}-selection-column):not(.@{table-prefix-cls}-row-expand-icon-cell):not([colspan])::before {\n          .@{table-wrapepr-rtl-cls} & {\n            right: auto;\n            left: 0;\n          }\n        }\n\n        .@{table-wrapepr-rtl-cls} & {\n          text-align: right;\n        }\n      }\n    }\n  }\n\n  // ============================= Body =============================\n  &-tbody {\n    > tr {\n      // ========================= Nest Table ===========================\n      .@{table-prefix-cls}-wrapper:only-child {\n        .@{table-prefix-cls}.@{table-prefix-cls}-rtl {\n          margin: -@table-padding-vertical (@table-padding-horizontal + ceil(@font-size-sm * 1.4)) -@table-padding-vertical -@table-padding-horizontal;\n        }\n      }\n    }\n  }\n\n  // ========================== Pagination ==========================\n  &-pagination {\n    &-left {\n      .@{table-wrapepr-cls}.@{table-wrapepr-rtl-cls} & {\n        justify-content: flex-end;\n      }\n    }\n\n    &-right {\n      .@{table-wrapepr-cls}.@{table-wrapepr-rtl-cls} & {\n        justify-content: flex-start;\n      }\n    }\n  }\n\n  // ================================================================\n  // =                           Function                           =\n  // ================================================================\n\n  // ============================ Sorter ============================\n  &-column-sorter {\n    .@{table-wrapepr-rtl-cls} & {\n      margin-right: 4px;\n      margin-left: 0;\n    }\n  }\n\n  // ============================ Filter ============================\n  &-filter-column-title {\n    .@{table-wrapepr-rtl-cls} & {\n      padding: @table-padding-vertical @table-padding-horizontal @table-padding-vertical 2.3em;\n    }\n  }\n\n  &-thead tr th.@{table-prefix-cls}-column-has-sorters {\n    .@{table-prefix-cls}-filter-column-title {\n      .@{table-prefix-cls}-rtl & {\n        padding: 0 0 0 2.3em;\n      }\n    }\n  }\n\n  &-filter-trigger {\n    .@{table-wrapepr-rtl-cls} & {\n      margin: -4px 4px -4px (-@table-padding-horizontal / 2);\n    }\n  }\n\n  // Dropdown\n  &-filter-dropdown {\n    // Checkbox\n    &,\n    &-submenu {\n      .@{ant-prefix}-checkbox-wrapper + span {\n        .@{ant-prefix}-dropdown-rtl &,\n        .@{ant-prefix}-dropdown-menu-submenu-rtl& {\n          padding-right: 8px;\n          padding-left: 0;\n        }\n      }\n    }\n  }\n\n  // ========================== Selections ==========================\n  &-selection {\n    .@{table-wrapepr-rtl-cls} & {\n      text-align: center;\n    }\n  }\n\n  // ========================== Expandable ==========================\n  &-row-indent {\n    .@{table-wrapepr-rtl-cls} & {\n      float: right;\n    }\n  }\n\n  &-row-expand-icon {\n    .@{table-wrapepr-rtl-cls} & {\n      float: right;\n    }\n\n    .@{table-prefix-cls}-row-indent + & {\n      .@{table-wrapepr-rtl-cls} & {\n        margin-right: 0;\n        margin-left: @padding-xs;\n      }\n    }\n\n    &::after {\n      .@{table-wrapepr-rtl-cls} & {\n        transform: rotate(-90deg);\n      }\n    }\n\n    &-collapsed::before {\n      .@{table-wrapepr-rtl-cls} & {\n        transform: rotate(180deg);\n      }\n    }\n\n    &-collapsed::after {\n      .@{table-wrapepr-rtl-cls} & {\n        transform: rotate(0deg);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/table/style/size.less",
    "content": "@import (reference) '../../style/themes/index';\n\n@table-prefix-cls: ~'@{ant-prefix}-table';\n\n.table-size(@size, @padding-vertical, @padding-horizontal, @font-size) {\n  .@{table-prefix-cls}.@{table-prefix-cls}-@{size} {\n    font-size: @font-size;\n\n    .@{table-prefix-cls}-title,\n    .@{table-prefix-cls}-footer,\n    .@{table-prefix-cls}-thead > tr > th,\n    .@{table-prefix-cls}-tbody > tr > td,\n    tfoot > tr > th,\n    tfoot > tr > td {\n      padding: @padding-vertical @padding-horizontal;\n    }\n\n    .@{table-prefix-cls}-filter-trigger {\n      margin-right: -(@padding-horizontal / 2);\n    }\n\n    .@{table-prefix-cls}-expanded-row-fixed {\n      margin: -@padding-vertical -@padding-horizontal;\n    }\n\n    .@{table-prefix-cls}-tbody {\n      // ========================= Nest Table ===========================\n      .@{table-prefix-cls}-wrapper:only-child {\n        .@{table-prefix-cls} {\n          margin: -@padding-vertical -@padding-horizontal -@padding-vertical (@table-expand-column-width -\n                @padding-horizontal);\n        }\n      }\n    }\n\n    // https://github.com/ant-design/ant-design/issues/35167\n    .@{table-prefix-cls}-selection-column {\n      padding-inline-start: (@padding-horizontal / 4);\n    }\n  }\n}\n\n// ================================================================\n// =                            Middle                            =\n// ================================================================\n.table-size(~'middle', @table-padding-vertical-md, @table-padding-horizontal-md, @table-font-size-md);\n\n// ================================================================\n// =                            Small                             =\n// ================================================================\n.table-size(~'small', @table-padding-vertical-sm, @table-padding-horizontal-sm, @table-font-size-sm);\n"
  },
  {
    "path": "components/tabs/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n默认选中第一项。\n\n## en-US\n\nDefault activate first tab.\n"
  },
  {
    "path": "components/tabs/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTabsModule } from 'ng-zorro-antd/tabs';\n\n@Component({\n  selector: 'nz-demo-tabs-basic',\n  imports: [NzTabsModule],\n  template: `\n    <nz-tabs>\n      <nz-tab nzTitle=\"Tab 1\">Content of Tab Pane 1</nz-tab>\n      <nz-tab nzTitle=\"Tab 2\">Content of Tab Pane 2</nz-tab>\n      <nz-tab nzTitle=\"Tab 3\">Content of Tab Pane 3</nz-tab>\n    </nz-tabs>\n  `\n})\nexport class NzDemoTabsBasicComponent {}\n"
  },
  {
    "path": "components/tabs/demo/card-top.md",
    "content": "---\norder: 11\ntitle:\n  zh-CN: 卡片式页签容器\n  en-US: Container of card type Tab\n---\n\n## zh-CN\n\n用于容器顶部，需要一点额外的样式覆盖。\n\n## en-US\n\nShould be used at the top of container, needs to override styles.\n"
  },
  {
    "path": "components/tabs/demo/card-top.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTabsModule } from 'ng-zorro-antd/tabs';\n\n@Component({\n  selector: 'nz-demo-tabs-card-top',\n  imports: [NzTabsModule],\n  template: `\n    <div class=\"card-container\">\n      <nz-tabs nzType=\"card\">\n        @for (tab of tabs; track tab) {\n          <nz-tab [nzTitle]=\"'Tab Title ' + tab\">\n            <p>Content of Tab Pane {{ tab }}</p>\n            <p>Content of Tab Pane {{ tab }}</p>\n            <p>Content of Tab Pane {{ tab }}</p>\n          </nz-tab>\n        }\n      </nz-tabs>\n    </div>\n  `,\n  styles: `\n    :host {\n      background: #f5f5f5;\n      overflow: hidden;\n      padding: 24px;\n      display: block;\n    }\n\n    .card-container ::ng-deep p {\n      margin: 0;\n    }\n    .card-container ::ng-deep > .ant-tabs-card .ant-tabs-content {\n      height: 120px;\n      margin-top: -16px;\n    }\n    .card-container ::ng-deep > .ant-tabs-card .ant-tabs-content > .ant-tabs-tabpane {\n      background: #fff;\n      padding: 16px;\n    }\n    .card-container ::ng-deep > .ant-tabs-card > .ant-tabs-nav::before {\n      display: none;\n    }\n    .card-container ::ng-deep > .ant-tabs-card .ant-tabs-tab {\n      border-color: transparent;\n      background: transparent;\n    }\n    .card-container ::ng-deep > .ant-tabs-card .ant-tabs-tab-active {\n      border-color: #fff;\n      background: #fff;\n    }\n  `\n})\nexport class NzDemoTabsCardTopComponent {\n  tabs = [1, 2, 3];\n}\n"
  },
  {
    "path": "components/tabs/demo/card.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 卡片式页签\n  en-US: Card type tab\n---\n\n## zh-CN\n\n另一种样式的页签，不提供对应的垂直样式。\n\n## en-US\n\nAnother type Tabs, which doesn't support vertical mode.\n"
  },
  {
    "path": "components/tabs/demo/card.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTabsModule } from 'ng-zorro-antd/tabs';\n\n@Component({\n  selector: 'nz-demo-tabs-card',\n  imports: [NzTabsModule],\n  template: `\n    <nz-tabs nzType=\"card\">\n      @for (tab of tabs; track tab) {\n        <nz-tab [nzTitle]=\"'Tab' + tab\">Content of Tab Pane {{ tab }}</nz-tab>\n      }\n    </nz-tabs>\n  `\n})\nexport class NzDemoTabsCardComponent {\n  tabs = [1, 2, 3];\n}\n"
  },
  {
    "path": "components/tabs/demo/centered.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 居中\n  en-US: Centered\n---\n\n## zh-CN\n\n标签居中展示。\n\n## en-US\n\nCentered tabs.\n"
  },
  {
    "path": "components/tabs/demo/centered.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTabsModule } from 'ng-zorro-antd/tabs';\n\n@Component({\n  selector: 'nz-demo-tabs-centered',\n  imports: [NzTabsModule],\n  template: `\n    <nz-tabs nzCentered>\n      <nz-tab nzTitle=\"Tab 1\">Content of Tab Pane 1</nz-tab>\n      <nz-tab nzTitle=\"Tab 2\">Content of Tab Pane 2</nz-tab>\n      <nz-tab nzTitle=\"Tab 3\">Content of Tab Pane 3</nz-tab>\n    </nz-tabs>\n  `\n})\nexport class NzDemoTabsCenteredComponent {}\n"
  },
  {
    "path": "components/tabs/demo/custom-add-trigger.md",
    "content": "---\norder: 12\ntitle:\n  zh-CN: 自定义新增页签触发器\n  en-US: Customized trigger of new tab\n---\n\n## zh-CN\n\n给自定义触发器绑定事件。\n\n## en-US\n\nBind event for customized trigger.\n"
  },
  {
    "path": "components/tabs/demo/custom-add-trigger.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzTabsModule } from 'ng-zorro-antd/tabs';\n\n@Component({\n  selector: 'nz-demo-tabs-custom-add-trigger',\n  imports: [NzButtonModule, NzTabsModule],\n  template: `\n    <div style=\"margin-bottom: 16px;\">\n      <button nz-button (click)=\"newTab()\">ADD</button>\n    </div>\n    <nz-tabs [(nzSelectedIndex)]=\"index\" nzType=\"editable-card\" nzHideAdd (nzClose)=\"closeTab($event)\">\n      @for (tab of tabs; track tab) {\n        <nz-tab [nzClosable]=\"$index > 1\" [nzTitle]=\"tab\">Content of {{ tab }}</nz-tab>\n      }\n    </nz-tabs>\n  `\n})\nexport class NzDemoTabsCustomAddTriggerComponent {\n  index = 0;\n  tabs = ['Tab 1', 'Tab 2'];\n\n  closeTab({ index }: { index: number }): void {\n    this.tabs.splice(index, 1);\n  }\n\n  newTab(): void {\n    this.tabs.push('New Tab');\n    this.index = this.tabs.length - 1;\n  }\n}\n"
  },
  {
    "path": "components/tabs/demo/disabled.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 禁用\n  en-US: Disabled\n---\n\n## zh-CN\n\n禁用某一项。\n\n## en-US\n\nDisabled a tab.\n"
  },
  {
    "path": "components/tabs/demo/disabled.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTabsModule } from 'ng-zorro-antd/tabs';\n\n@Component({\n  selector: 'nz-demo-tabs-disabled',\n  imports: [NzTabsModule],\n  template: `\n    <nz-tabs>\n      @for (tab of tabs; track tab) {\n        <nz-tab [nzTitle]=\"tab.name\" [nzDisabled]=\"tab.disabled\">\n          {{ tab.name }}\n        </nz-tab>\n      }\n    </nz-tabs>\n  `\n})\nexport class NzDemoTabsDisabledComponent {\n  tabs = [\n    {\n      name: 'Tab 1',\n      disabled: false\n    },\n    {\n      name: 'Tab 2',\n      disabled: true\n    },\n    {\n      name: 'Tab 3',\n      disabled: false\n    }\n  ];\n}\n"
  },
  {
    "path": "components/tabs/demo/draggable.md",
    "content": "---\norder: 16\ntitle:\n  zh-CN: 可拖拽标签\n  en-US: Draggable Tabs\n---\n\n## zh-CN\n\n通过 CDK `DragDropModule` 实现标签可拖拽。\n\n## en-US\n\nUse CDK `DragDropModule` to make tabs draggable.\n"
  },
  {
    "path": "components/tabs/demo/draggable.ts",
    "content": "import { CdkDrag, CdkDragDrop, CdkDropList, moveItemInArray } from '@angular/cdk/drag-drop';\nimport { ChangeDetectorRef, Component, inject } from '@angular/core';\n\nimport { NzTabsModule } from 'ng-zorro-antd/tabs';\n\n@Component({\n  selector: 'nz-demo-tabs-draggable',\n  imports: [NzTabsModule, CdkDrag, CdkDropList],\n  template: `\n    <nz-tabs\n      [(nzSelectedIndex)]=\"selectedTabIndex\"\n      class=\"example-drag-tabs\"\n      cdkDropList\n      (cdkDropListDropped)=\"drop($event)\"\n      cdkDropListOrientation=\"horizontal\"\n      cdkDropListElementContainer=\".ant-tabs-nav-list\"\n    >\n      @for (tab of tabs; track tab) {\n        <nz-tab [nzTitle]=\"title\">\n          {{ tab.content }}\n        </nz-tab>\n        <ng-template #title>\n          <span cdkDrag cdkDragRootElement=\".ant-tabs-tab\" cdkDragPreviewClass=\"preview\">\n            {{ tab.name }}\n          </span>\n        </ng-template>\n      }\n    </nz-tabs>\n  `,\n  styles: `\n    :host ::ng-deep .ant-tabs-tab-btn {\n      cursor: move;\n    }\n    nz-tabs.cdk-drop-list-dragging {\n      pointer-events: none;\n    }\n    .preview.cdk-drag-animating {\n      transition: all 250ms cubic-bezier(0, 0, 0.2, 1);\n    }\n    ::ng-deep .ant-tabs-tab.cdk-drag-placeholder .ant-tabs-tab-btn {\n      opacity: 0.5;\n    }\n  `\n})\nexport class NzDemoTabsDraggableComponent {\n  private cdr = inject(ChangeDetectorRef);\n  tabs = [\n    {\n      name: 'Tab 1',\n      content: 'Content of Tab Pane 1'\n    },\n    {\n      name: 'Tab 2',\n      content: 'Content of Tab Pane 2'\n    },\n    {\n      name: 'Tab 3',\n      content: 'Content of Tab Pane 3'\n    }\n  ];\n  selectedTabIndex = 0;\n\n  drop(event: CdkDragDrop<string[]>): void {\n    const prevActive = this.tabs[this.selectedTabIndex];\n    moveItemInArray(this.tabs, event.previousIndex, event.currentIndex);\n    this.selectedTabIndex = this.tabs.indexOf(prevActive);\n    this.cdr.markForCheck();\n  }\n}\n"
  },
  {
    "path": "components/tabs/demo/editable-card.md",
    "content": "---\norder: 10\ntitle:\n  zh-CN: 新增和关闭页签\n  en-US: Add & close tab\n---\n\n## zh-CN\n\n只有卡片样式的页签支持新增和关闭选项。\n\n## en-US\n\nOnly card type Tabs support adding & closable.\n"
  },
  {
    "path": "components/tabs/demo/editable-card.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTabsModule } from 'ng-zorro-antd/tabs';\n\n@Component({\n  selector: 'nz-demo-tabs-editable-card',\n  imports: [NzTabsModule],\n  template: `\n    <nz-tabs [(nzSelectedIndex)]=\"selectedIndex\" nzType=\"editable-card\" (nzAdd)=\"newTab()\" (nzClose)=\"closeTab($event)\">\n      @for (tab of tabs; track tab) {\n        <nz-tab nzClosable [nzTitle]=\"tab\">Content of {{ tab }}</nz-tab>\n      }\n    </nz-tabs>\n  `\n})\nexport class NzDemoTabsEditableCardComponent {\n  tabs = ['Tab 1', 'Tab 2'];\n  selectedIndex = 0;\n\n  closeTab({ index }: { index: number }): void {\n    this.tabs.splice(index, 1);\n  }\n\n  newTab(): void {\n    this.tabs.push('New Tab');\n    this.selectedIndex = this.tabs.length;\n  }\n}\n"
  },
  {
    "path": "components/tabs/demo/extra.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 附加内容\n  en-US: Extra content\n---\n\n## zh-CN\n\n可以在页签两边添加附加操作。\n\n## en-US\n\nYou can add extra actions to the start or end or even both sides of Tabs.\n"
  },
  {
    "path": "components/tabs/demo/extra.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzCheckboxModule } from 'ng-zorro-antd/checkbox';\nimport { NzTabsModule } from 'ng-zorro-antd/tabs';\n\n@Component({\n  selector: 'nz-demo-tabs-extra',\n  imports: [NzButtonModule, NzTabsModule, NzCheckboxModule, FormsModule],\n  template: `\n    <nz-tabs [nzTabBarExtraContent]=\"extraTemplate\">\n      @for (tab of tabs; track tab) {\n        <nz-tab [nzTitle]=\"'Tab ' + tab\">Content of tab {{ tab }}</nz-tab>\n      }\n    </nz-tabs>\n    <ng-template #extraTemplate>\n      <button nz-button>Extra Action</button>\n    </ng-template>\n\n    <br />\n    <br />\n    <p>You can also specify its direction or both side</p>\n    <br />\n    <nz-checkbox-group [nzOptions]=\"positionOptions\" [(ngModel)]=\"positions\" />\n    <br />\n    <br />\n\n    <nz-tabs>\n      @if (positions.includes('start')) {\n        <button *nzTabBarExtraContent=\"'start'\" nz-button [style.margin-right.px]=\"16\">Start Extra Action</button>\n      }\n      @if (positions.includes('end')) {\n        <button *nzTabBarExtraContent=\"'end'\" nz-button [style.margin-left.px]=\"16\">End Extra Action</button>\n      }\n\n      @for (tab of tabs; track tab) {\n        <nz-tab [nzTitle]=\"'Tab ' + tab\">Content of tab {{ tab }}</nz-tab>\n      }\n    </nz-tabs>\n  `\n})\nexport class NzDemoTabsExtraComponent {\n  tabs = [1, 2, 3];\n  positionOptions = [\n    { label: 'start', value: 'start' },\n    { label: 'end', value: 'end' }\n  ];\n  positions = ['start', 'end'];\n}\n"
  },
  {
    "path": "components/tabs/demo/guard.md",
    "content": "---\norder: 15\ntitle:\n  zh-CN: 标签守卫\n  en-US: Tab guard\n---\n\n## zh-CN\n\n通过 `nzCanDeactivate` 决定一个 tab 是否可以被切换。\n\n## en-US\n\nVia `nzCanDeactivate` to determine if a tab can be deactivated.\n"
  },
  {
    "path": "components/tabs/demo/guard.ts",
    "content": "import { ChangeDetectionStrategy, Component, inject } from '@angular/core';\nimport { Observable } from 'rxjs';\n\nimport { NzModalModule, NzModalService } from 'ng-zorro-antd/modal';\nimport { NzTabsCanDeactivateFn, NzTabsModule } from 'ng-zorro-antd/tabs';\n\n@Component({\n  selector: 'nz-demo-tabs-guard',\n  imports: [NzTabsModule, NzModalModule],\n  template: `\n    <nz-tabs [nzCanDeactivate]=\"canDeactivate\">\n      @for (tab of tabs; track tab) {\n        <nz-tab [nzTitle]=\"'Tab' + tab\">Content of tab {{ tab }}</nz-tab>\n      }\n    </nz-tabs>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class NzDemoTabsGuardComponent {\n  tabs = [1, 2, 3, 4];\n  private modalService = inject(NzModalService);\n\n  canDeactivate: NzTabsCanDeactivateFn = (fromIndex: number, toIndex: number) => {\n    switch (fromIndex) {\n      case 0:\n        return toIndex === 1;\n      case 1:\n        return Promise.resolve(toIndex === 2);\n      case 2:\n        return this.confirm();\n      default:\n        return true;\n    }\n  };\n\n  private confirm(): Observable<boolean> {\n    return new Observable(observer => {\n      this.modalService.confirm({\n        nzTitle: 'Are you sure you want to leave this tab?',\n        nzOnOk: () => {\n          observer.next(true);\n          observer.complete();\n        },\n        nzOnCancel: () => {\n          observer.next(false);\n          observer.complete();\n        }\n      });\n    });\n  }\n}\n"
  },
  {
    "path": "components/tabs/demo/icon.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 图标\n  en-US: Icon\n---\n\n## zh-CN\n\n有图标的标签。\n\n## en-US\n\nThe Tab with Icon.\n"
  },
  {
    "path": "components/tabs/demo/icon.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzTabsModule } from 'ng-zorro-antd/tabs';\n\n@Component({\n  selector: 'nz-demo-tabs-icon',\n  imports: [NzIconModule, NzTabsModule],\n  template: `\n    <nz-tabs>\n      @for (tab of tabs; track tab) {\n        <nz-tab [nzTitle]=\"titleTemplate\">\n          <ng-template #titleTemplate>\n            <nz-icon [nzType]=\"tab.icon\" />\n            {{ tab.name }}\n          </ng-template>\n          {{ tab.name }}\n        </nz-tab>\n      }\n    </nz-tabs>\n  `\n})\nexport class NzDemoTabsIconComponent {\n  tabs = [\n    {\n      name: 'Tab 1',\n      icon: 'apple'\n    },\n    {\n      name: 'Tab 2',\n      icon: 'android'\n    }\n  ];\n}\n"
  },
  {
    "path": "components/tabs/demo/indicator.md",
    "content": "---\norder: 17\ntitle:\n  zh-CN: 指示条\n  en-US: Indicator\n---\n\n## zh-CN\n\n设置 `nzIndicator` 属性，自定义指示条宽度和对齐方式。\n\n## en-US\n\nSet `nzIndicator` prop to custom indicator size and align.\n"
  },
  {
    "path": "components/tabs/demo/indicator.ts",
    "content": "import { Component, computed, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\nimport { NzTabsModule, type NzIndicator, type NzIndicatorAlign } from 'ng-zorro-antd/tabs';\n\n@Component({\n  selector: 'nz-demo-tabs-indicator',\n  imports: [NzTabsModule, NzRadioModule, FormsModule],\n  template: `\n    <nz-radio-group nzButtonStyle=\"solid\" [(ngModel)]=\"positionIndicator\">\n      <label nz-radio-button nzValue=\"start\">Start</label>\n      <label nz-radio-button nzValue=\"center\">Center</label>\n      <label nz-radio-button nzValue=\"end\">End</label>\n    </nz-radio-group>\n    <nz-tabs [nzIndicator]=\"indicator()\">\n      <nz-tab nzTitle=\"Tab 1\">Content of Tab Pane 1</nz-tab>\n      <nz-tab nzTitle=\"Tab 2\">Content of Tab Pane 2</nz-tab>\n      <nz-tab nzTitle=\"Tab 3\">Content of Tab Pane 3</nz-tab>\n    </nz-tabs>\n  `\n})\nexport class NzDemoTabsIndicatorComponent {\n  readonly positionIndicator = signal<NzIndicatorAlign>('start');\n\n  protected readonly indicator = computed<NzIndicator>(() => ({\n    size: origin => origin - 25,\n    align: this.positionIndicator()\n  }));\n}\n"
  },
  {
    "path": "components/tabs/demo/lazy.md",
    "content": "---\norder: 13\ntitle:\n  zh-CN: 延迟加载\n  en-US: LazyLoad\n---\n\n## zh-CN\n\n默认情况下，`nz-tab` 中的组件是立即加载的。可以通过在 `ng-template` 中使用 `[nz-tab]` 指令来实现延迟加载选项卡内容。\n\n> 配合 `nzDestroyInactiveTabPane` 使用，可以实现 tab 隐藏时销毁组件。\n\n## en-US\n\nBy default, the contents in `nz-tab` are eagerly loaded. Tab contents can be lazy loaded by declaring the body in a `ng-template` with the `[nz-tab]` directive.\n\n> Combine with `nzDestroyInactiveTabPane` to destroy the component when the tab is hidden.\n"
  },
  {
    "path": "components/tabs/demo/lazy.ts",
    "content": "import { Component, OnInit } from '@angular/core';\n\nimport { NzTabsModule } from 'ng-zorro-antd/tabs';\n\n@Component({\n  selector: 'nz-demo-tab-content-lazy',\n  template: `lazy`\n})\nexport class NzDemoTabContentLazyComponent implements OnInit {\n  ngOnInit(): void {\n    console.log(`I will init when tab active`);\n  }\n}\n\n@Component({\n  selector: 'nz-demo-tab-content-eagerly',\n  template: `eagerly`\n})\nexport class NzDemoTabContentEagerlyComponent implements OnInit {\n  ngOnInit(): void {\n    console.log(`I will init eagerly`);\n  }\n}\n\n@Component({\n  selector: 'nz-demo-tabs-lazy',\n  imports: [NzTabsModule, NzDemoTabContentEagerlyComponent, NzDemoTabContentLazyComponent],\n  template: `\n    <nz-tabs>\n      <nz-tab nzTitle=\"Tab Eagerly 1\">\n        <nz-demo-tab-content-eagerly />\n      </nz-tab>\n      <nz-tab nzTitle=\"Tab Eagerly 2\">\n        <nz-demo-tab-content-eagerly />\n      </nz-tab>\n      <nz-tab nzTitle=\"Tab Lazy 1\">\n        <ng-template nz-tab>\n          <nz-demo-tab-content-lazy />\n        </ng-template>\n      </nz-tab>\n      <nz-tab nzTitle=\"Tab Lazy 2\">\n        <ng-template nz-tab>\n          <nz-demo-tab-content-lazy />\n        </ng-template>\n      </nz-tab>\n    </nz-tabs>\n  `\n})\nexport class NzDemoTabsLazyComponent {}\n"
  },
  {
    "path": "components/tabs/demo/link-router.md",
    "content": "---\norder: 14\ntitle:\n  zh-CN: 路由联动\n  en-US: With Router\n---\n\n## zh-CN\n\n与路由联动，点击 tab 更改路由，并且在路由改变时自动切换 tab。\n\n## en-US\n\nLink with router.\n"
  },
  {
    "path": "components/tabs/demo/link-router.ts",
    "content": "import { Component } from '@angular/core';\nimport { Params, RouterLink } from '@angular/router';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzTabsModule } from 'ng-zorro-antd/tabs';\n\n@Component({\n  selector: 'nz-demo-tabs-link-router',\n  imports: [RouterLink, NzTabsModule, NzButtonModule],\n  template: `\n    <div style=\"margin-bottom: 16px;\">\n      <button nz-button (click)=\"newTab()\">ADD</button>\n    </div>\n    <nz-tabs nzLinkRouter>\n      <nz-tab>\n        <a *nzTabLink nz-tab-link [routerLink]=\"['.']\" [queryParams]=\"{ tab: 'one' }\" queryParamsHandling=\"merge\">\n          Default\n        </a>\n        Default.\n      </nz-tab>\n      <nz-tab>\n        <a *nzTabLink nz-tab-link [routerLink]=\"['.']\" [queryParams]=\"{ tab: 'two' }\" queryParamsHandling=\"merge\">\n          Two\n        </a>\n        Two.\n      </nz-tab>\n      <nz-tab>\n        <a *nzTabLink nz-tab-link [routerLink]=\"['.']\" [queryParams]=\"{ tab: 'three' }\" queryParamsHandling=\"merge\">\n          Three\n        </a>\n        Three.\n      </nz-tab>\n      <nz-tab>\n        <a *nzTabLink nz-tab-link [routerLink]=\"['.']\" [queryParams]=\"{ tab: 'four' }\" queryParamsHandling=\"merge\">\n          Four\n        </a>\n        Four.\n      </nz-tab>\n      @for (tab of dynamicTabs; track tab.title) {\n        <nz-tab>\n          <a\n            *nzTabLink\n            nz-tab-link\n            [routerLink]=\"tab.routerLink\"\n            [queryParams]=\"tab.queryParams ?? {}\"\n            queryParamsHandling=\"merge\"\n          >\n            {{ tab.title }}\n          </a>\n          {{ tab.content }}\n        </nz-tab>\n      }\n    </nz-tabs>\n  `\n})\nexport class NzDemoTabsLinkRouterComponent {\n  dynamicTabs: Array<{ title: string; content: string; queryParams?: Params; routerLink: string[] }> = [];\n\n  newTab(): void {\n    const { length } = this.dynamicTabs;\n    const newTabId = length + 1;\n    const title = `NewTab${newTabId}`;\n    this.dynamicTabs = [\n      ...this.dynamicTabs,\n      {\n        title,\n        content: title,\n        routerLink: ['.'],\n        queryParams: {\n          tab: newTabId\n        }\n      }\n    ];\n  }\n}\n"
  },
  {
    "path": "components/tabs/demo/position.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 位置\n  en-US: Position\n---\n\n## zh-CN\n\n有四个位置，`nzTabPosition=\"left|right|top|bottom\"`。\n\n## en-US\n\nTab's position: left, right, top or bottom.\n"
  },
  {
    "path": "components/tabs/demo/position.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSelectModule } from 'ng-zorro-antd/select';\nimport { NzTabPosition, NzTabsModule } from 'ng-zorro-antd/tabs';\n\n@Component({\n  selector: 'nz-demo-tabs-position',\n  imports: [FormsModule, NzSelectModule, NzTabsModule],\n  template: `\n    <div style=\"margin-bottom: 16px;\">\n      Tab position:\n      <nz-select [(ngModel)]=\"position\" style=\"width: 80px;\">\n        @for (option of options; track option.value) {\n          <nz-option [nzLabel]=\"option.label\" [nzValue]=\"option.value\" />\n        }\n      </nz-select>\n    </div>\n    <nz-tabs [nzTabPosition]=\"position\">\n      @for (tab of tabs; track tab) {\n        <nz-tab [nzTitle]=\"'Tab ' + tab\">Content of tab {{ tab }}</nz-tab>\n      }\n    </nz-tabs>\n  `\n})\nexport class NzDemoTabsPositionComponent {\n  position: NzTabPosition = 'top';\n  tabs = [1, 2, 3];\n  options = [\n    { value: 'top', label: 'top' },\n    { value: 'left', label: 'left' },\n    { value: 'right', label: 'right' },\n    { value: 'bottom', label: 'bottom' }\n  ];\n}\n"
  },
  {
    "path": "components/tabs/demo/size.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 大小\n  en-US: Size\n---\n\n## zh-CN\n\n大号页签用在页头区域，小号用在弹出框等较狭窄的容器内。\n\n## en-US\n\nLarge size tabs are usually used in page header, and small size could be used in Modal.\n"
  },
  {
    "path": "components/tabs/demo/size.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\nimport { NzTabsModule } from 'ng-zorro-antd/tabs';\n\n@Component({\n  selector: 'nz-demo-tabs-size',\n  imports: [FormsModule, NzRadioModule, NzTabsModule],\n  template: `\n    <nz-radio-group [(ngModel)]=\"size\">\n      <label nz-radio-button nzValue=\"small\"><span>Small</span></label>\n      <label nz-radio-button nzValue=\"default\"><span>Default</span></label>\n      <label nz-radio-button nzValue=\"large\"><span>Large</span></label>\n    </nz-radio-group>\n    <nz-tabs [nzSize]=\"size\">\n      @for (tab of tabs; track tab) {\n        <nz-tab [nzTitle]=\"'Tab ' + tab\">Content of tab {{ tab }}</nz-tab>\n      }\n    </nz-tabs>\n  `\n})\nexport class NzDemoTabsSizeComponent {\n  size: 'large' | 'default' | 'small' = 'small';\n  tabs = [1, 2, 3];\n}\n"
  },
  {
    "path": "components/tabs/demo/slide.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 滑动\n  en-US: Slide\n---\n\n## zh-CN\n\n可以左右、上下滑动，容纳更多标签。\n\n## en-US\n\nTab can be slide to left or right(up or down), which is used for a lot of tabs.\n"
  },
  {
    "path": "components/tabs/demo/slide.ts",
    "content": "import { Component, OnInit } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzInputNumberModule } from 'ng-zorro-antd/input-number';\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\nimport { NzTabPosition, NzTabsModule } from 'ng-zorro-antd/tabs';\n\n@Component({\n  selector: 'nz-demo-tabs-slide',\n  imports: [FormsModule, NzInputNumberModule, NzRadioModule, NzTabsModule],\n  template: `\n    <nz-radio-group [(ngModel)]=\"nzTabPosition\" style=\"margin-bottom: 8px;\">\n      <label nz-radio-button nzValue=\"top\">Horizontal</label>\n      <label nz-radio-button nzValue=\"left\">Vertical</label>\n    </nz-radio-group>\n    <nz-input-number style=\"float:right;\" [nzMin]=\"0\" [nzMax]=\"29\" [(ngModel)]=\"selectedIndex\" />\n\n    <nz-tabs\n      style=\"height:220px;\"\n      [nzTabPosition]=\"nzTabPosition\"\n      [(nzSelectedIndex)]=\"selectedIndex\"\n      (nzSelectChange)=\"log([$event])\"\n    >\n      @for (tab of tabs; track tab) {\n        <nz-tab\n          [nzTitle]=\"tab.name\"\n          [nzDisabled]=\"tab.disabled\"\n          (nzSelect)=\"log(['select', tab])\"\n          (nzClick)=\"log(['click', tab])\"\n          (nzContextmenu)=\"log(['contextmenu', tab])\"\n          (nzDeselect)=\"log(['deselect', tab])\"\n        >\n          {{ tab.content }}\n        </nz-tab>\n      }\n    </nz-tabs>\n  `\n})\nexport class NzDemoTabsSlideComponent implements OnInit {\n  tabs: Array<{ name: string; content: string; disabled: boolean }> = [];\n  nzTabPosition: NzTabPosition = 'top';\n  selectedIndex = 27;\n\n  /* eslint-disable-next-line @typescript-eslint/no-explicit-any */\n  log(args: any[]): void {\n    console.log(args);\n  }\n\n  ngOnInit(): void {\n    for (let i = 0; i < 30; i++) {\n      this.tabs.push({\n        name: `Tab ${i}`,\n        disabled: i === 28,\n        content: `Content of tab ${i}`\n      });\n    }\n  }\n}\n"
  },
  {
    "path": "components/tabs/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Navigation\ntitle: Tabs\ncols: 1\ncover: 'https://gw.alipayobjects.com/zos/antfincdn/lkI2hNEDr2V/Tabs.svg'\ndescription: Tabs make it easy to switch between different views.\n---\n\n## When To Use\n\nAnt Design has 3 types of Tabs for different situations.\n\n- Card Tabs: for managing too many closeable views.\n- Normal Tabs: for functional aspects of a page.\n- [RadioButton](/components/radio/en/#components-radio-demo-radiobutton): for secondary tabs.\n\n## API\n\n### nz-tabs\n\n| Property                     | Description                                                                               | Type                                                | Default                            | Global Config |\n| ---------------------------- | ----------------------------------------------------------------------------------------- | --------------------------------------------------- | ---------------------------------- | ------------- |\n| `[nzSelectedIndex]`          | Current tab's index                                                                       | `number`                                            | -                                  |\n| `[nzAnimated]`               | Whether to change tabs with animation. Only works while `nzTabPosition=\"top\" \\| \"bottom\"` | `boolean \\| {inkBar:boolean, tabPane:boolean}`      | `true`, `false` when `type=\"card\"` | ✅            |\n| `[nzSize]`                   | preset tab bar size                                                                       | `'large' \\| 'small' \\| 'default'`                   | `'default'`                        | ✅            |\n| `[nzTabBarExtraContent]`     | Extra content in tab bar                                                                  | `TemplateRef<void>`                                 | -                                  |\n| `[nzTabBarStyle]`            | Tab bar style object                                                                      | `object`                                            | -                                  |\n| `[nzTabPosition]`            | Position of tabs                                                                          | `'top' \\| 'right' \\| 'bottom' \\| 'left'`            | `'top'`                            |               |\n| `[nzType]`                   | Basic style of tabs                                                                       | `'line' \\| 'card' \\| 'editable-card'`               | `'line'`                           | ✅            |\n| `[nzTabBarGutter]`           | The gap between tabs                                                                      | `number`                                            | -                                  | ✅            |\n| `[nzHideAll]`                | Whether hide all tabs                                                                     | `boolean`                                           | `false`                            |\n| `[nzLinkRouter]`             | Link with Angular router. It supports child mode and query param mode                     | `boolean`                                           | `false`                            |               |\n| `[nzLinkExact]`              | Use exact routing matching                                                                | `boolean`                                           | `true`                             |\n| `[nzCanDeactivate]`          | Determine if a tab can be deactivated                                                     | `NzTabsCanDeactivateFn`                             | -                                  |\n| `[nzCentered]`               | Centers tabs                                                                              | `boolean`                                           | `false`                            |\n| `[nzDestroyInactiveTabPane]` | Whether destroy inactive TabPane when change tab                                          | `boolean`                                           | `false`                            |\n| `[nzIndicator]`              | Custom indicator size and align                                                           | `NzIndicator`                                       | -                                  |\n| `(nzSelectedIndexChange)`    | Current tab's index change callback                                                       | `EventEmitter<number>`                              | -                                  |\n| `(nzSelectChange)`           | Current tab's change callback                                                             | `EventEmitter<{index: number,tab: NzTabComponent}>` | -                                  |\n\n### nz-tabs[nzType=\"editable-card\"]\n\n| Property      | Description                    | Type                              | Default | Global Config |\n| ------------- | ------------------------------ | --------------------------------- | ------- | ------------- |\n| `[nzHideAdd]` | Hide plus icon or not          | `boolean`                         | `false` |\n| `[nzAddIcon]` | Add icon                       | `string \\| TemplateRef<void>`     | -       |\n| `(nzAdd)`     | When add button clicked emit   | `EventEmitter<>`                  | -       |\n| `(nzClose)`   | When close button clicked emit | `EventEmitter<{ index: number }>` | -       |\n\n### nz-tab\n\n| Property          | Description                                                              | Type                          | Default |\n| ----------------- | ------------------------------------------------------------------------ | ----------------------------- | ------- |\n| `[nzTitle]`       | Show text in tab's head                                                  | `string \\| TemplateRef<void>` | -       |\n| `[nzForceRender]` | Forced render of content in tabs, not lazy render after clicking on tabs | `boolean`                     | `false` |\n| `[nzDisabled]`    | tab disable                                                              | `boolean`                     | -       |\n| `(nzClick)`       | title click callback                                                     | `EventEmitter<void>`          | -       |\n| `(nzContextmenu)` | title contextmenu callback                                               | `EventEmitter<MouseEvent>`    | -       |\n| `(nzSelect)`      | title select callback                                                    | `EventEmitter<void>`          | -       |\n| `(nzDeselect)`    | title deselect callback                                                  | `EventEmitter<void>`          | -       |\n\n### nz-tabs[nzType=\"editable-card\"] > nz-tab\n\n| Property        | Description            | Type                          | Default | Global Config |\n| --------------- | ---------------------- | ----------------------------- | ------- | ------------- |\n| `[nzClosable]`  | Show close icon or not | `boolean`                     | `false` |\n| `[nzCloseIcon]` | Close icon             | `string \\| TemplateRef<void>` | -       |\n\n#### Template variable references of `nz-tab[nzTitle]`\n\n| Property  | Description                                                                         | Type      |\n| --------- | ----------------------------------------------------------------------------------- | --------- |\n| `visible` | Is the title in the visible area, will be rendered to the dropdown menu if `false`. | `boolean` |\n\nUse in `nz-tab[nzTitle]`\n\n```html\n<nz-tab [nzTitle]=\"titleTemplate\">\n  ...\n  <ng-template #titleTemplate let-visible=\"visible\">...</ng-template>\n</nz-tab>\n```\n\nUse in `*nzTabLink`\n\n```html\n<nz-tab>\n  <a *nzTabLink=\"let visible = visible\" nz-tab-link [routerLink]=\"['.']\">...</a>\n</nz-tab>\n```\n\n### [nz-tab]\n\nTab contents can be lazy loaded by declaring the body in a `ng-template` with the `[nz-tab]` attribute.\n\n### ng-template[nzTabLink] > a[nz-tab-link]\n\nShow a link in tab's head. Used in router link mode.\n\n```html\n<nz-tabs nzLinkRouter>\n  <nz-tab>\n    <a *nzTabLink nz-tab-link [routerLink]=\"['.']\">Link</a>\n    Default.\n  </nz-tab>\n</nz-tabs>\n```\n\n### [nzTabBarExtraContent]\n\n> Note: `*nzTabBarExtraContent` has a higher priority than `nz-tabs[nzTabBarExtraContent]`.\n\n| Property                 | Description               | Type               | Default | Global Config |\n| ------------------------ | ------------------------- | ------------------ | ------- | ------------- |\n| `[nzTabBarExtraContent]` | Position of extra content | `'start' \\| 'end'` | `'end'` |\n"
  },
  {
    "path": "components/tabs/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 标签页\ntype: 导航\ntitle: Tabs\ncols: 1\ncover: 'https://gw.alipayobjects.com/zos/antfincdn/lkI2hNEDr2V/Tabs.svg'\ndescription: 选项卡切换组件。\n---\n\n## 何时使用\n\n提供平级的区域将大块内容进行收纳和展现，保持界面整洁。\n\nAnt Design 依次提供了三级选项卡，分别用于不同的场景。\n\n- 卡片式的页签，提供可关闭的样式，常用于容器顶部。\n- 标准线条式页签，用于容器内部的主功能切换，这是最常用的 Tabs。\n- [RadioButton](/components/radio/zh/#components-radio-demo-radiobutton) 可作为更次级的页签来使用。\n\n## API\n\n### nz-tabs\n\n| 参数                         | 说明                                                               | 类型                                                | 默认值                                | 全局配置 |\n| ---------------------------- | ------------------------------------------------------------------ | --------------------------------------------------- | ------------------------------------- | -------- |\n| `[nzSelectedIndex]`          | 当前激活 tab 面板的 序列号，可双向绑定                             | `number`                                            | -                                     |\n| `[nzAnimated]`               | 是否使用动画切换 Tabs，在 `nzTabPosition=\"top\" \\| \"bottom\"` 时有效 | `boolean \\| {inkBar:boolean, tabPane:boolean}`      | `true`, 当 `type=\"card\"` 时为 `false` | ✅       |\n| `[nzSize]`                   | 大小，提供 `large` `default` 和 `small` 三种大小                   | `'large' \\| 'small' \\| 'default'`                   | `'default'`                           | ✅       |\n| `[nzTabBarExtraContent]`     | tab bar 上额外的元素                                               | `TemplateRef<void>`                                 | -                                     |\n| `[nzTabBarStyle]`            | tab bar 的样式对象                                                 | `object`                                            | -                                     |\n| `[nzTabPosition]`            | 页签位置，可选值有 `top` `right` `bottom` `left`                   | `'top' \\| 'right' \\| 'bottom' \\| 'left'`            | `'top'`                               |          |\n| `[nzType]`                   | 页签的基本样式                                                     | `'line' \\| 'card' \\| 'editable-card'`               | `'line'`                              | ✅       |\n| `[nzTabBarGutter]`           | tabs 之间的间隙                                                    | `number`                                            | -                                     | ✅       |\n| `[nzHideAll]`                | 是否隐藏所有 tab 内容                                              | `boolean`                                           | `false`                               |\n| `[nzLinkRouter]`             | 与 Angular 路由联动                                                | `boolean`                                           | `false`                               |          |\n| `[nzLinkExact]`              | 以严格匹配模式确定联动的路由                                       | `boolean`                                           | `true`                                |\n| `[nzCanDeactivate]`          | 决定一个 tab 是否可以被切换                                        | `NzTabsCanDeactivateFn`                             | -                                     |\n| `[nzCentered]`               | 标签居中展示                                                       | `boolean`                                           | `false`                               |\n| `[nzDestroyInactiveTabPane]` | 被隐藏时是否销毁 DOM 结构                                          | `boolean`                                           | `false`                               |\n| `[nzIndicator]`              | 自定义指示条宽度和对齐方式                                         | `NzIndicator`                                       | -                                     |\n| `(nzSelectedIndexChange)`    | 当前激活 tab 面板的 序列号变更回调函数                             | `EventEmitter<number>`                              | -                                     |\n| `(nzSelectChange)`           | 当前激活 tab 面板变更回调函数                                      | `EventEmitter<{index: number,tab: NzTabComponent}>` | -                                     |\n\n### nz-tabs[nzType=\"editable-card\"]\n\n| 参数          | 说明                 | 类型                              | 默认值  | 全局配置 |\n| ------------- | -------------------- | --------------------------------- | ------- | -------- |\n| `[nzHideAdd]` | 隐藏添加按钮         | `boolean`                         | `false` |\n| `[nzAddIcon]` | 添加按钮图标         | `string \\| TemplateRef<void>`     | -       |\n| `(nzAdd)`     | 点击添加按钮时的事件 | `EventEmitter<>`                  | -       |\n| `(nzClose)`   | 点击删除按钮时的事件 | `EventEmitter<{ index: number }>` | -       |\n\n### nz-tab\n\n| 参数              | 说明                      | 类型                                        | 默认值  |\n| ----------------- | ------------------------- | ------------------------------------------- | ------- |\n| `[nzTitle]`       | 选项卡头显示文字          | `string \\| TemplateRef<TabTemplateContext>` | -       |\n| `[nzForceRender]` | 被隐藏时是否渲染 DOM 结构 | `boolean`                                   | `false` |\n| `[nzDisabled]`    | 是否禁用                  | `boolean`                                   | -       |\n| `(nzClick)`       | 单击 title 的回调函数     | `EventEmitter<void>`                        | -       |\n| `(nzContextmenu)` | 右键 title 的回调函数     | `EventEmitter<MouseEvent>`                  | -       |\n| `(nzSelect)`      | tab 被选中的回调函数      | `EventEmitter<void>`                        | -       |\n| `(nzDeselect)`    | tab 被取消选中的回调函数  | `EventEmitter<void>`                        | -       |\n\n### nz-tabs[nzType=\"editable-card\"] > nz-tab\n\n| 参数            | 说明         | 类型                          | 默认值  | 全局配置 |\n| --------------- | ------------ | ----------------------------- | ------- | -------- |\n| `[nzClosable]`  | 显示删除按钮 | `boolean`                     | `false` |\n| `[nzCloseIcon]` | 关闭按钮图标 | `string \\| TemplateRef<void>` | -       |\n\n#### `nz-tab[nzTitle]` 的模版引用变量\n\n| 属性      | 说明                                                    | 类型      |\n| --------- | ------------------------------------------------------- | --------- |\n| `visible` | 表示是否在可见区域, 为 `false` 时将会被渲染到下拉菜单中 | `boolean` |\n\n在 `nz-tab[nzTitle]` 中使用\n\n```html\n<nz-tab [nzTitle]=\"titleTemplate\">\n  ...\n  <ng-template #titleTemplate let-visible=\"visible\">...</ng-template>\n</nz-tab>\n```\n\n在 `*nzTabLink` 中使用\n\n```html\n<nz-tab>\n  <a *nzTabLink=\"let visible = visible\" nz-tab-link [routerLink]=\"['.']\">...</a>\n</nz-tab>\n```\n\n### [nz-tab]\n\n与 `ng-template` 一同使用，用于标记需要懒加载的 `tab` 内容，具体用法见示例。\n\n### ng-template[nzTabLink] > a[nz-tab-link]\n\n路由联动可以让 tab 的切换和路由行为相一致。\n\n```html\n<nz-tabs nzLinkRouter>\n  <nz-tab>\n    <a *nzTabLink nz-tab-link [routerLink]=\"['.']\">Link</a>\n    Default.\n  </nz-tab>\n</nz-tabs>\n```\n\n### [nzTabBarExtraContent]\n\n> 注意：`*nzTabBarExtraContent` 比 `nz-tabs[nzTabBarExtraContent]` 具有更高的优先级。\n\n| 参数                     | 说明           | 类型               | 默认值  |\n| ------------------------ | -------------- | ------------------ | ------- |\n| `[nzTabBarExtraContent]` | 附加内容的位置 | `'start' \\| 'end'` | `'end'` |\n"
  },
  {
    "path": "components/tabs/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/tabs/interfaces.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Observable } from 'rxjs';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nexport type NzTabPosition = 'top' | 'bottom' | 'left' | 'right';\nexport type NzTabType = 'line' | 'card' | 'editable-card';\nexport type NzTabsCanDeactivateFn = (\n  fromIndex: number,\n  toIndex: number\n) => Observable<boolean> | Promise<boolean> | boolean;\nexport type NzTabPositionMode = 'horizontal' | 'vertical';\n\nexport interface NzAnimatedInterface {\n  inkBar: boolean;\n  tabPane: boolean;\n}\n\nexport class NzTabChangeEvent {\n  index?: number;\n  tab: NzSafeAny;\n}\n\nexport interface NzTabScrollListOffset {\n  x: number;\n  y: number;\n}\n\nexport type NzTabScrollListOffsetEvent = NzTabScrollListOffset & { event: Event };\n\ninterface NzTabWheelScrollEvent {\n  type: 'wheel';\n  event: WheelEvent;\n}\n\ninterface NzTabTouchScrollEvent {\n  type: 'touchstart' | 'touchmove' | 'touchend';\n  event: TouchEvent;\n}\n\nexport type NzTabScrollEvent = NzTabTouchScrollEvent | NzTabWheelScrollEvent;\nexport type NzTabScrollEventHandlerFun<T extends NzTabScrollEvent['event']> = (event: T) => void;\n\nexport interface TabTemplateContext {\n  visible: boolean;\n}\n\nexport type NzIndicatorAlign = 'start' | 'end' | 'center';\nexport interface NzIndicator {\n  size?: number | ((origin: number) => number);\n  align: NzIndicatorAlign;\n}\n"
  },
  {
    "path": "components/tabs/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/tabs/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './interfaces';\nexport { NzTabAddButtonComponent as ɵNzTabAddButtonComponent } from './tab-add-button.component';\nexport * from './tab-bar-extra-content.directive';\nexport { NzTabBodyComponent as ɵNzTabBodyComponent } from './tab-body.component';\nexport { NzTabCloseButtonComponent as ɵNzTabCloseButtonComponent } from './tab-close-button.component';\nexport * from './tab-link.directive';\nexport { NzTabNavBarComponent as ɵNzTabNavBarComponent } from './tab-nav-bar.component';\nexport { NzTabNavItemDirective as ɵNzTabNavItemDirective } from './tab-nav-item.directive';\nexport { NzTabNavOperationComponent as ɵNzTabNavOperationComponent } from './tab-nav-operation.component';\nexport { NzTabScrollListDirective as ɵNzTabScrollListDirective } from './tab-scroll-list.directive';\nexport * from './tab.component';\nexport * from './tab.directive';\nexport { NzTabsInkBarDirective as ɵNzTabsInkBarDirective } from './tabs-ink-bar.directive';\nexport * from './tabs.component';\nexport * from './tabs.module';\n"
  },
  {
    "path": "components/tabs/style/card-style.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@tab-prefix-cls: ~'@{ant-prefix}-tabs';\n\n// card style\n.@{tab-prefix-cls} {\n  &&-card &-card-bar &-ink-bar {\n    visibility: hidden;\n  }\n\n  &&-card &-card-bar &-tab {\n    margin: 0;\n    margin-right: @tabs-card-gutter;\n    padding: @tabs-card-horizontal-padding;\n    line-height: 22px;\n    background: @tabs-card-head-background;\n    border: @border-width-base @border-style-base @border-color-split;\n    border-radius: @border-radius-base @border-radius-base 0 0;\n    transition: all 0.3s @ease-in-out;\n  }\n\n  &&-card &-card-bar &-tab-active {\n    color: @tabs-card-active-color;\n    background: @component-background;\n    border-color: @border-color-split;\n    border-bottom: @border-width-base solid @component-background;\n\n    &::before {\n      border-top: @tabs-card-tab-active-border-top;\n    }\n  }\n\n  &&-small &-card-bar &-tab {\n    padding: @tabs-card-horizontal-padding-sm;\n  }\n\n  &&-card &-card-bar &-tab-disabled {\n    color: @disabled-color;\n  }\n\n  &&-card &-card-bar &-tab-inactive {\n    padding: 0;\n  }\n\n  &&-card &-card-bar &-nav-wrap {\n    margin-bottom: 0;\n  }\n\n  &&-card &-card-bar &-tab &-close-x {\n    width: 16px;\n    height: @font-size-base;\n    margin-right: -5px;\n    margin-left: 3px;\n    overflow: hidden;\n    color: @text-color-secondary;\n    font-size: @font-size-sm;\n    vertical-align: middle;\n    transition: all 0.3s;\n\n    &:hover {\n      color: @heading-color;\n    }\n  }\n\n  &&-card &-card-content > &-tabpane,\n  &&-editable-card &-card-content > &-tabpane {\n    transition: none !important;\n\n    &-inactive {\n      overflow: hidden;\n    }\n  }\n\n  &&-card &-card-bar &-tab:hover .@{iconfont-css-prefix}-close {\n    opacity: 1;\n  }\n\n  &-extra-content {\n    // stylelint-disable-next-line\n    line-height: @tabs-title-font-size * @line-height-base + extract(@tabs-horizontal-padding, 1) * 2;\n\n    .@{tab-prefix-cls}-new-tab {\n      position: relative;\n      width: 20px;\n      height: 20px;\n      color: @text-color;\n      font-size: 12px;\n      line-height: 20px;\n      text-align: center;\n      border: @border-width-base @border-style-base @border-color-split;\n      border-radius: @border-radius-base;\n      cursor: pointer;\n      transition: all 0.3s;\n\n      &:hover {\n        color: @tabs-card-active-color;\n        border-color: @tabs-card-active-color;\n      }\n\n      svg {\n        position: absolute;\n        top: 0;\n        right: 0;\n        bottom: 0;\n        left: 0;\n        margin: auto;\n      }\n    }\n  }\n\n  // https://github.com/ant-design/ant-design/issues/17865\n  &&-large &-extra-content {\n    // stylelint-disable-next-line\n    line-height: @tabs-title-font-size-lg * @line-height-base + extract(@tabs-horizontal-padding-lg, 1) * 2;\n  }\n\n  // https://github.com/ant-design/ant-design/issues/17865\n  &&-small &-extra-content {\n    // stylelint-disable-next-line\n    line-height: @tabs-title-font-size-sm * @line-height-base + extract(@tabs-horizontal-padding-sm, 1) * 2;\n  }\n\n  // https://github.com/ant-design/ant-design/issues/17865\n  &&-card &-extra-content {\n    line-height: @tabs-card-height;\n  }\n\n  // https://github.com/ant-design/ant-design/issues/4669\n  &-vertical&-card &-card-bar&-left-bar,\n  &-vertical&-card &-card-bar&-right-bar {\n    .@{tab-prefix-cls}-nav-container {\n      height: 100%;\n    }\n    .@{tab-prefix-cls}-tab {\n      margin-bottom: @margin-sm;\n      border-bottom: @border-width-base @border-style-base @border-color-split;\n\n      &-active {\n        padding-bottom: 4px;\n      }\n\n      &:last-child {\n        margin-bottom: @margin-sm;\n      }\n    }\n    .@{tab-prefix-cls}-new-tab {\n      width: 90%;\n    }\n  }\n\n  &-vertical&-card&-left &-card-bar&-left-bar {\n    .@{tab-prefix-cls}-nav-wrap {\n      margin-right: 0;\n    }\n    .@{tab-prefix-cls}-tab {\n      margin-right: 1px;\n      border-right: 0;\n      border-radius: @border-radius-base 0 0 @border-radius-base;\n\n      &-active {\n        margin-right: -1px;\n        padding-right: @padding-md + 2px;\n      }\n    }\n  }\n\n  &-vertical&-card&-right &-card-bar&-right-bar {\n    .@{tab-prefix-cls}-nav-wrap {\n      margin-left: 0;\n    }\n    .@{tab-prefix-cls}-tab {\n      margin-left: 1px;\n      border-left: 0;\n      border-radius: 0 @border-radius-base @border-radius-base 0;\n\n      &-active {\n        margin-left: -1px;\n        padding-left: @padding-md + 2px;\n      }\n    }\n  }\n\n  // https://github.com/ant-design/ant-design/issues/9104\n  & &-card-bar&-bottom-bar &-tab {\n    height: auto;\n    border-top-color: @border-color-split;\n    border-bottom: @border-width-base @border-style-base @border-color-split;\n    border-radius: 0 0 @border-radius-base @border-radius-base;\n  }\n\n  & &-card-bar&-bottom-bar &-tab-active {\n    color: @primary-color;\n    border-top-color: @component-background;\n  }\n}\n\n@import './card-style.rtl.less';\n"
  },
  {
    "path": "components/tabs/style/card-style.rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@tab-prefix-cls: ~'@{ant-prefix}-tabs';\n\n// card style\n.@{tab-prefix-cls} {\n  &&-card &-card-bar &-tab &-close-x {\n    .@{tab-prefix-cls}-rtl& {\n      margin-right: 3px;\n      margin-left: -5px;\n    }\n  }\n\n  &-extra-content {\n    .@{tab-prefix-cls}-rtl & {\n      float: left !important;\n    }\n  }\n}\n"
  },
  {
    "path": "components/tabs/style/card.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@tab-prefix-cls: ~'@{ant-prefix}-tabs';\n\n.@{tab-prefix-cls}-card {\n  > .@{tab-prefix-cls}-nav,\n  > div > .@{tab-prefix-cls}-nav {\n    .@{tab-prefix-cls}-tab {\n      margin: 0;\n      padding: @tabs-card-horizontal-padding;\n      background: @tabs-card-head-background;\n      border: @border-width-base @border-style-base @border-color-split;\n      transition: all @animation-duration-slow @ease-in-out;\n\n      &-active {\n        color: @tabs-card-active-color;\n        background: @component-background;\n      }\n    }\n\n    .@{tab-prefix-cls}-ink-bar {\n      visibility: hidden;\n    }\n  }\n\n  // ========================== Top & Bottom ==========================\n  &.@{tab-prefix-cls}-top,\n  &.@{tab-prefix-cls}-bottom {\n    > .@{tab-prefix-cls}-nav,\n    > div > .@{tab-prefix-cls}-nav {\n      .@{tab-prefix-cls}-tab + .@{tab-prefix-cls}-tab {\n        margin-left: @tabs-card-gutter;\n      }\n    }\n  }\n\n  &.@{tab-prefix-cls}-top {\n    > .@{tab-prefix-cls}-nav,\n    > div > .@{tab-prefix-cls}-nav {\n      .@{tab-prefix-cls}-tab {\n        border-radius: @border-radius-base @border-radius-base 0 0;\n\n        &-active {\n          border-bottom-color: @component-background;\n        }\n      }\n    }\n  }\n  &.@{tab-prefix-cls}-bottom {\n    > .@{tab-prefix-cls}-nav,\n    > div > .@{tab-prefix-cls}-nav {\n      .@{tab-prefix-cls}-tab {\n        border-radius: 0 0 @border-radius-base @border-radius-base;\n\n        &-active {\n          border-top-color: @component-background;\n        }\n      }\n    }\n  }\n\n  // ========================== Left & Right ==========================\n  &.@{tab-prefix-cls}-left,\n  &.@{tab-prefix-cls}-right {\n    > .@{tab-prefix-cls}-nav,\n    > div > .@{tab-prefix-cls}-nav {\n      .@{tab-prefix-cls}-tab + .@{tab-prefix-cls}-tab {\n        margin-top: @tabs-card-gutter;\n      }\n    }\n  }\n\n  &.@{tab-prefix-cls}-left {\n    > .@{tab-prefix-cls}-nav,\n    > div > .@{tab-prefix-cls}-nav {\n      .@{tab-prefix-cls}-tab {\n        border-radius: @border-radius-base 0 0 @border-radius-base;\n\n        &-active {\n          border-right-color: @component-background;\n        }\n      }\n    }\n  }\n  &.@{tab-prefix-cls}-right {\n    > .@{tab-prefix-cls}-nav,\n    > div > .@{tab-prefix-cls}-nav {\n      .@{tab-prefix-cls}-tab {\n        border-radius: 0 @border-radius-base @border-radius-base 0;\n\n        &-active {\n          border-left-color: @component-background;\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/tabs/style/dropdown.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@tab-prefix-cls: ~'@{ant-prefix}-tabs';\n\n.@{tab-prefix-cls}-dropdown {\n  .reset-component();\n\n  position: absolute;\n  top: -9999px;\n  left: -9999px;\n  z-index: @zindex-dropdown;\n  display: block;\n\n  &-hidden {\n    display: none;\n  }\n\n  &-menu {\n    max-height: 200px;\n    margin: 0;\n    padding: @dropdown-edge-child-vertical-padding 0;\n    overflow-x: hidden;\n    overflow-y: auto;\n    text-align: left;\n    list-style-type: none;\n    background-color: @dropdown-menu-bg;\n    background-clip: padding-box;\n    border-radius: @border-radius-base;\n    outline: none;\n    box-shadow: @box-shadow-base;\n\n    &-item {\n      display: flex;\n      align-items: center;\n      min-width: 120px;\n      margin: 0;\n      padding: @dropdown-vertical-padding @control-padding-horizontal;\n      overflow: hidden;\n      color: @text-color;\n      font-weight: normal;\n      font-size: @dropdown-font-size;\n      line-height: @dropdown-line-height;\n      white-space: nowrap;\n      text-overflow: ellipsis;\n      cursor: pointer;\n      transition: all 0.3s;\n\n      > span {\n        flex: 1;\n        white-space: nowrap;\n      }\n\n      &-remove {\n        flex: none;\n        margin-left: @margin-sm;\n        color: @text-color-secondary;\n        font-size: @font-size-sm;\n        background: transparent;\n        border: 0;\n        cursor: pointer;\n\n        &:hover {\n          color: @tabs-hover-color;\n        }\n      }\n\n      &:hover {\n        background: @item-hover-bg;\n      }\n\n      &-disabled {\n        &,\n        &:hover {\n          color: @disabled-color;\n          background: transparent;\n          cursor: not-allowed;\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/tabs/style/entry.less",
    "content": "@import './index.less';\n@import './patch.less';\n"
  },
  {
    "path": "components/tabs/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import './size';\n@import './rtl';\n@import './position';\n@import './dropdown';\n@import './card';\n\n@tab-prefix-cls: ~'@{ant-prefix}-tabs';\n\n.@{tab-prefix-cls} {\n  .reset-component();\n\n  display: flex;\n\n  // ========================== Navigation ==========================\n  > .@{tab-prefix-cls}-nav,\n  > div > .@{tab-prefix-cls}-nav {\n    position: relative;\n    display: flex;\n    flex: none;\n    align-items: center;\n\n    .@{tab-prefix-cls}-nav-wrap {\n      position: relative;\n      display: flex;\n      flex: auto;\n      align-self: stretch;\n      overflow: hidden;\n      white-space: nowrap;\n      transform: translate(0); // Fix chrome render bug\n\n      // >>>>> Ping shadow\n      &::before,\n      &::after {\n        position: absolute;\n        z-index: 1;\n        opacity: 0;\n        transition: opacity @animation-duration-slow;\n        content: '';\n        pointer-events: none;\n      }\n    }\n\n    .@{tab-prefix-cls}-nav-list {\n      position: relative;\n      display: flex;\n      transition: transform @animation-duration-slow;\n    }\n\n    // >>>>>>>> Operations\n    .@{tab-prefix-cls}-nav-operations {\n      display: flex;\n      align-self: stretch;\n\n      &-hidden {\n        position: absolute;\n        visibility: hidden;\n        pointer-events: none;\n      }\n    }\n\n    .@{tab-prefix-cls}-nav-more {\n      position: relative;\n      padding: @tabs-card-horizontal-padding;\n      background: transparent;\n      border: 0;\n\n      &::after {\n        position: absolute;\n        right: 0;\n        bottom: 0;\n        left: 0;\n        height: 5px;\n        transform: translateY(100%);\n        content: '';\n      }\n    }\n\n    .@{tab-prefix-cls}-nav-add {\n      min-width: @tabs-card-height;\n      margin-left: @tabs-card-gutter;\n      padding: 0 @padding-xs;\n      background: @tabs-card-head-background;\n      border: @border-width-base @border-style-base @border-color-split;\n      border-radius: @border-radius-base @border-radius-base 0 0;\n      outline: none;\n      cursor: pointer;\n      transition: all @animation-duration-slow @ease-in-out;\n\n      &:hover {\n        color: @tabs-hover-color;\n      }\n\n      &:active,\n      &:focus {\n        color: @tabs-active-color;\n      }\n    }\n  }\n\n  &-extra-content {\n    flex: none;\n  }\n\n  &-centered {\n    > .@{tab-prefix-cls}-nav,\n    > div > .@{tab-prefix-cls}-nav {\n      .@{tab-prefix-cls}-nav-wrap {\n        &:not([class*='@{tab-prefix-cls}-nav-wrap-ping']) {\n          justify-content: center;\n        }\n      }\n    }\n  }\n\n  // ============================ InkBar ============================\n  &-ink-bar {\n    position: absolute;\n    background: @tabs-ink-bar-color;\n    pointer-events: none;\n  }\n\n  // ============================= Tabs =============================\n  &-tab {\n    position: relative;\n    display: inline-flex;\n    align-items: center;\n    padding: @tabs-horizontal-padding;\n    font-size: @tabs-title-font-size;\n    background: transparent;\n    border: 0;\n    outline: none;\n    cursor: pointer;\n\n    &-btn,\n    &-remove {\n      &:focus,\n      &:active {\n        color: @tabs-active-color;\n      }\n    }\n\n    &-btn {\n      outline: none;\n      transition: all 0.3s;\n    }\n\n    &-remove {\n      flex: none;\n      margin-right: -@margin-xss;\n      margin-left: @margin-xs;\n      color: @text-color-secondary;\n      font-size: @font-size-sm;\n      background: transparent;\n      border: none;\n      outline: none;\n      cursor: pointer;\n      transition: all @animation-duration-slow;\n\n      &:hover {\n        color: @heading-color;\n      }\n    }\n\n    &:hover {\n      color: @tabs-hover-color;\n    }\n\n    &&-active &-btn {\n      color: @tabs-highlight-color;\n      text-shadow: 0 0 0.25px currentcolor;\n    }\n\n    &&-disabled {\n      color: @disabled-color;\n      cursor: not-allowed;\n    }\n\n    &&-disabled &-btn,\n    &&-disabled &-remove {\n      &:focus,\n      &:active {\n        color: @disabled-color;\n      }\n    }\n\n    & &-remove .@{iconfont-css-prefix} {\n      margin: 0;\n    }\n\n    .@{iconfont-css-prefix} {\n      margin-right: @margin-sm;\n    }\n  }\n\n  &-tab + &-tab {\n    margin: @tabs-horizontal-margin;\n  }\n\n  // =========================== TabPanes ===========================\n  &-content {\n    &-holder {\n      flex: auto;\n      min-width: 0;\n      min-height: 0;\n    }\n\n    position: relative;\n    width: 100%;\n  }\n\n  &-tabpane {\n    outline: none;\n\n    &-hidden {\n      display: none;\n    }\n  }\n\n  // Motion\n  &-switch {\n    &-appear,\n    &-enter {\n      transition: none;\n\n      &-start {\n        opacity: 0;\n      }\n\n      &-active {\n        opacity: 1;\n        transition: opacity @animation-duration-slow;\n      }\n    }\n\n    &-leave {\n      position: absolute;\n      transition: none;\n      inset: 0;\n\n      &-start {\n        opacity: 1;\n      }\n\n      &-active {\n        opacity: 0;\n        transition: opacity @animation-duration-slow;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/tabs/style/patch.less",
    "content": "@import './index';\n\n.ant-tabs-dropdown-menu-item a[nz-tab-link] {\n  position: relative;\n}\n\n.ant-tabs-tab-btn {\n  background-color: unset;\n  border: none;\n  cursor: pointer;\n}\n\n.ant-tabs-tab a[nz-tab-link] {\n  &::before {\n    position: absolute;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    background-color: transparent;\n    content: '';\n  }\n\n  ~ * {\n    position: relative;\n  }\n}\n\n.nz-tabs-dropdown.ant-dropdown {\n  .ant-dropdown-menu {\n    max-height: 200px;\n    margin: 0;\n    padding: @dropdown-edge-child-vertical-padding 0;\n    overflow-x: hidden;\n    overflow-y: auto;\n    text-align: left;\n    list-style-type: none;\n    background-color: @dropdown-menu-bg;\n    background-clip: padding-box;\n    border-radius: @border-radius-base;\n    outline: none;\n    box-shadow: @box-shadow-base;\n\n    &-item {\n      min-width: 120px;\n      margin: 0;\n      padding: @dropdown-vertical-padding @control-padding-horizontal;\n      overflow: hidden;\n      color: @text-color;\n      font-weight: normal;\n      font-size: @dropdown-font-size;\n      line-height: @dropdown-line-height;\n      white-space: nowrap;\n      text-overflow: ellipsis;\n      cursor: pointer;\n      transition: all 0.3s;\n\n      &:hover {\n        background: @item-hover-bg;\n      }\n\n      &-disabled {\n        &,\n        &:hover {\n          color: @disabled-color;\n          background: transparent;\n          cursor: not-allowed;\n\n          a {\n            color: @disabled-color;\n            pointer-events: none;\n          }\n        }\n      }\n    }\n  }\n}\n\n.@{tab-prefix-cls} {\n  &-rtl {\n    &-tab-next {\n      .@{tab-prefix-cls}-rtl & {\n        right: auto;\n        left: 2px;\n      }\n    }\n  }\n\n  &-tab-disabled a {\n    color: @disabled-color;\n    pointer-events: none;\n  }\n\n  > .@{tab-prefix-cls}-nav,\n  > div > .@{tab-prefix-cls}-nav {\n    .@{tab-prefix-cls}-nav-add {\n      min-height: @tabs-card-height;\n    }\n  }\n}\n"
  },
  {
    "path": "components/tabs/style/position.less",
    "content": "@import '../../style/themes/index';\n@tab-prefix-cls: ~'@{ant-prefix}-tabs';\n\n.@{tab-prefix-cls} {\n  // ========================== Top & Bottom ==========================\n  &-top,\n  &-bottom {\n    flex-direction: column;\n\n    > .@{tab-prefix-cls}-nav,\n    > div > .@{tab-prefix-cls}-nav {\n      margin: @tabs-bar-margin;\n\n      &::before {\n        position: absolute;\n        right: 0;\n        left: 0;\n        border-bottom: @border-width-base @border-style-base @border-color-split;\n        content: '';\n      }\n\n      .@{tab-prefix-cls}-ink-bar {\n        height: 2px;\n\n        &-animated {\n          transition: width @animation-duration-slow, left @animation-duration-slow,\n            right @animation-duration-slow;\n        }\n      }\n\n      .@{tab-prefix-cls}-nav-wrap {\n        &::before,\n        &::after {\n          top: 0;\n          bottom: 0;\n          width: 30px;\n        }\n\n        &::before {\n          left: 0;\n          box-shadow: inset 10px 0 8px -8px fade(@shadow-color, 8%);\n        }\n\n        &::after {\n          right: 0;\n          box-shadow: inset -10px 0 8px -8px fade(@shadow-color, 8%);\n        }\n\n        &.@{tab-prefix-cls}-nav-wrap-ping-left::before {\n          opacity: 1;\n        }\n        &.@{tab-prefix-cls}-nav-wrap-ping-right::after {\n          opacity: 1;\n        }\n      }\n    }\n  }\n\n  &-top {\n    > .@{tab-prefix-cls}-nav,\n    > div > .@{tab-prefix-cls}-nav {\n      &::before {\n        bottom: 0;\n      }\n\n      .@{tab-prefix-cls}-ink-bar {\n        bottom: 0;\n      }\n    }\n  }\n\n  &-bottom {\n    > .@{tab-prefix-cls}-nav,\n    > div > .@{tab-prefix-cls}-nav {\n      order: 1;\n      margin-top: @margin-md;\n      margin-bottom: 0;\n\n      &::before {\n        top: 0;\n      }\n\n      .@{tab-prefix-cls}-ink-bar {\n        top: 0;\n      }\n    }\n\n    > .@{tab-prefix-cls}-content-holder,\n    > div > .@{tab-prefix-cls}-content-holder {\n      order: 0;\n    }\n  }\n\n  // ========================== Left & Right ==========================\n  &-left,\n  &-right {\n    > .@{tab-prefix-cls}-nav,\n    > div > .@{tab-prefix-cls}-nav {\n      flex-direction: column;\n      min-width: 50px;\n\n      // >>>>>>>>>>> Tab\n      .@{tab-prefix-cls}-tab {\n        padding: @tabs-vertical-padding;\n        text-align: center;\n      }\n\n      .@{tab-prefix-cls}-tab + .@{tab-prefix-cls}-tab {\n        margin: @tabs-vertical-margin;\n      }\n\n      // >>>>>>>>>>> Nav\n      .@{tab-prefix-cls}-nav-wrap {\n        flex-direction: column;\n\n        &::before,\n        &::after {\n          right: 0;\n          left: 0;\n          height: 30px;\n        }\n\n        &::before {\n          top: 0;\n          box-shadow: inset 0 10px 8px -8px fade(@shadow-color, 8%);\n        }\n\n        &::after {\n          bottom: 0;\n          box-shadow: inset 0 -10px 8px -8px fade(@shadow-color, 8%);\n        }\n\n        &.@{tab-prefix-cls}-nav-wrap-ping-top::before {\n          opacity: 1;\n        }\n        &.@{tab-prefix-cls}-nav-wrap-ping-bottom::after {\n          opacity: 1;\n        }\n      }\n\n      // >>>>>>>>>>> Ink Bar\n      .@{tab-prefix-cls}-ink-bar {\n        width: 2px;\n\n        &-animated {\n          transition: height @animation-duration-slow, top @animation-duration-slow;\n        }\n      }\n\n      .@{tab-prefix-cls}-nav-list,\n      .@{tab-prefix-cls}-nav-operations {\n        flex: 1 0 auto; // fix safari scroll problem\n        flex-direction: column;\n      }\n    }\n  }\n\n  &-left {\n    > .@{tab-prefix-cls}-nav,\n    > div > .@{tab-prefix-cls}-nav {\n      .@{tab-prefix-cls}-ink-bar {\n        right: 0;\n      }\n    }\n\n    > .@{tab-prefix-cls}-content-holder,\n    > div > .@{tab-prefix-cls}-content-holder {\n      margin-left: -@border-width-base;\n      border-left: @border-width-base @border-style-base @border-color-split;\n\n      > .@{tab-prefix-cls}-content > .@{tab-prefix-cls}-tabpane {\n        padding-left: @padding-lg;\n      }\n    }\n  }\n\n  &-right {\n    > .@{tab-prefix-cls}-nav,\n    > div > .@{tab-prefix-cls}-nav {\n      order: 1;\n\n      .@{tab-prefix-cls}-ink-bar {\n        left: 0;\n      }\n    }\n\n    > .@{tab-prefix-cls}-content-holder,\n    > div > .@{tab-prefix-cls}-content-holder {\n      order: 0;\n      margin-right: -@border-width-base;\n      border-right: @border-width-base @border-style-base @border-color-split;\n\n      > .@{tab-prefix-cls}-content > .@{tab-prefix-cls}-tabpane {\n        padding-right: @padding-lg;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/tabs/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@tab-prefix-cls: ~'@{ant-prefix}-tabs';\n\n.@{tab-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n\n    .@{tab-prefix-cls}-nav {\n      .@{tab-prefix-cls}-tab {\n        margin: @tabs-horizontal-margin-rtl;\n\n        &:last-of-type {\n          margin-left: 0;\n        }\n\n        .@{iconfont-css-prefix} {\n          margin-right: 0;\n          margin-left: @margin-sm;\n        }\n\n        .@{tab-prefix-cls}-tab-remove {\n          margin-right: @margin-xs;\n          margin-left: -@margin-xss;\n\n          .@{iconfont-css-prefix} {\n            margin: 0;\n          }\n        }\n      }\n    }\n\n    &.@{tab-prefix-cls}-left {\n      > .@{tab-prefix-cls}-nav {\n        order: 1;\n      }\n      > .@{tab-prefix-cls}-content-holder {\n        order: 0;\n      }\n    }\n\n    &.@{tab-prefix-cls}-right {\n      > .@{tab-prefix-cls}-nav {\n        order: 0;\n      }\n      > .@{tab-prefix-cls}-content-holder {\n        order: 1;\n      }\n    }\n  }\n\n  // ====================== Card ======================\n  &-card {\n    &.@{tab-prefix-cls}-top,\n    &.@{tab-prefix-cls}-bottom {\n      > .@{tab-prefix-cls}-nav,\n      > div > .@{tab-prefix-cls}-nav {\n        .@{tab-prefix-cls}-tab + .@{tab-prefix-cls}-tab {\n          .@{tab-prefix-cls}-rtl& {\n            margin-right: @tabs-card-gutter;\n            margin-left: 0;\n          }\n        }\n        .@{tab-prefix-cls}-nav-add {\n          .@{tab-prefix-cls}-rtl& {\n            margin-right: @tabs-card-gutter;\n            margin-left: 0;\n          }\n        }\n      }\n    }\n  }\n}\n\n.@{tab-prefix-cls}-dropdown {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &-menu-item {\n    .@{tab-prefix-cls}-dropdown-rtl & {\n      text-align: right;\n    }\n  }\n}\n"
  },
  {
    "path": "components/tabs/style/size.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@tab-prefix-cls: ~'@{ant-prefix}-tabs';\n\n.@{tab-prefix-cls} {\n  &-small {\n    > .@{tab-prefix-cls}-nav {\n      .@{tab-prefix-cls}-tab {\n        padding: @tabs-horizontal-padding-sm;\n        font-size: @tabs-title-font-size-sm;\n      }\n    }\n  }\n\n  &-large {\n    > .@{tab-prefix-cls}-nav {\n      .@{tab-prefix-cls}-tab {\n        padding: @tabs-horizontal-padding-lg;\n        font-size: @tabs-title-font-size-lg;\n      }\n    }\n  }\n\n  &-card {\n    &.@{tab-prefix-cls}-small {\n      > .@{tab-prefix-cls}-nav {\n        .@{tab-prefix-cls}-tab {\n          padding: @tabs-card-horizontal-padding-sm;\n        }\n      }\n    }\n\n    &.@{tab-prefix-cls}-large {\n      > .@{tab-prefix-cls}-nav {\n        .@{tab-prefix-cls}-tab {\n          padding: @tabs-card-horizontal-padding-lg;\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/tabs/tab-add-button.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, ElementRef, inject, Input, TemplateRef } from '@angular/core';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-tab-add-button, button[nz-tab-add-button]',\n  template: `\n    <ng-container *nzStringTemplateOutlet=\"addIcon; let icon\">\n      <nz-icon [nzType]=\"icon\" nzTheme=\"outline\" />\n    </ng-container>\n  `,\n  host: {\n    class: 'ant-tabs-nav-add',\n    'aria-label': 'Add tab',\n    type: 'button'\n  },\n  imports: [NzOutletModule, NzIconModule]\n})\nexport class NzTabAddButtonComponent {\n  @Input() addIcon: string | TemplateRef<NzSafeAny> = 'plus';\n\n  private readonly element: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement;\n\n  getElementWidth(): number {\n    return this.element?.offsetWidth || 0;\n  }\n\n  getElementHeight(): number {\n    return this.element?.offsetHeight || 0;\n  }\n}\n"
  },
  {
    "path": "components/tabs/tab-bar-extra-content.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, inject, input, TemplateRef } from '@angular/core';\n\n@Directive({\n  selector: '[nzTabBarExtraContent]:not(nz-tabs)'\n})\nexport class NzTabBarExtraContentDirective {\n  readonly position = input<'start' | 'end'>('end', { alias: 'nzTabBarExtraContent' });\n  readonly templateRef = inject(TemplateRef);\n}\n"
  },
  {
    "path": "components/tabs/tab-body.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  computed,\n  effect,\n  ElementRef,\n  inject,\n  input,\n  signal,\n  TemplateRef,\n  untracked,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { isAnimationEnabled } from 'ng-zorro-antd/core/animation';\nimport { requestAnimationFrame } from 'ng-zorro-antd/core/polyfill';\nimport { generateClassName } from 'ng-zorro-antd/core/util';\n\ntype AnimationState = 'enter-start' | 'enter-active' | 'leave-start' | 'leave-active' | 'void' | 'hidden';\n\nconst CLASS_NAME = 'ant-tabs-tabpane';\nconst ANIMATION_PREFIX = 'ant-tabs-switch';\nconst ANIMATION_CLASS_MAP: Record<AnimationState, string[]> = {\n  'enter-start': [generateClassName(ANIMATION_PREFIX, 'enter'), generateClassName(ANIMATION_PREFIX, 'enter-start')],\n  'enter-active': [generateClassName(ANIMATION_PREFIX, 'enter'), generateClassName(ANIMATION_PREFIX, 'enter-active')],\n  'leave-start': [generateClassName(ANIMATION_PREFIX, 'leave'), generateClassName(ANIMATION_PREFIX, 'leave-start')],\n  'leave-active': [generateClassName(ANIMATION_PREFIX, 'leave'), generateClassName(ANIMATION_PREFIX, 'leave-active')],\n  // If animation is enabled, we should hide the tabpane after the leave animation is done\n  hidden: [generateClassName(CLASS_NAME, 'hidden')],\n  void: []\n};\n\n@Component({\n  selector: '[nz-tab-body]',\n  exportAs: 'nzTabBody',\n  imports: [NgTemplateOutlet],\n  template: `<ng-template [ngTemplateOutlet]=\"content()\" />`,\n  host: {\n    '[class]': 'class()',\n    '[class.ant-tabs-tabpane-active]': 'active()',\n    '[attr.tabindex]': 'active() ? 0 : -1',\n    '[attr.aria-hidden]': '!active()',\n    '(transitionend)': '_onTransitionEnd($event)'\n  },\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class NzTabBodyComponent {\n  private readonly elementRef = inject(ElementRef);\n\n  readonly content = input<TemplateRef<void> | null>(null);\n  readonly active = input(false);\n  readonly animated = input(true);\n\n  protected readonly _animationState = signal<AnimationState>('void');\n  protected readonly _animationEnabled = isAnimationEnabled(() => this.animated());\n\n  protected readonly class = computed(() => {\n    const cls: string[] = [CLASS_NAME];\n    if (this._animationEnabled()) {\n      cls.push(...ANIMATION_CLASS_MAP[this._animationState()]);\n    } else if (!this.active()) {\n      cls.push(generateClassName(CLASS_NAME, 'hidden'));\n    }\n    return cls;\n  });\n\n  constructor() {\n    effect(() => {\n      if (!this._animationEnabled()) {\n        return;\n      }\n\n      if (!this.active()) {\n        untracked(() => this._animationState.set('leave-start'));\n        requestAnimationFrame(() => {\n          this._animationState.set('leave-active');\n        });\n      } else {\n        untracked(() => this._animationState.set('enter-start'));\n        requestAnimationFrame(() => {\n          this._animationState.set('enter-active');\n        });\n      }\n    });\n  }\n\n  protected _onTransitionEnd(event: TransitionEvent): void {\n    // avoid event bubbling from child elements\n    if (event.target !== this.elementRef.nativeElement) {\n      return;\n    }\n\n    const currentState = this._animationState();\n    if (currentState === 'enter-active') {\n      this._animationState.set('void');\n    } else if (currentState === 'leave-active') {\n      this._animationState.set('hidden');\n    }\n  }\n}\n"
  },
  {
    "path": "components/tabs/tab-close-button.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, Input, TemplateRef } from '@angular/core';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-tab-close-button, button[nz-tab-close-button]',\n  template: `\n    <ng-container *nzStringTemplateOutlet=\"closeIcon; let icon\">\n      <nz-icon [nzType]=\"icon\" nzTheme=\"outline\" />\n    </ng-container>\n  `,\n  host: {\n    class: 'ant-tabs-tab-remove',\n    'aria-label': 'Close tab',\n    type: 'button'\n  },\n  imports: [NzOutletModule, NzIconModule]\n})\nexport class NzTabCloseButtonComponent {\n  @Input() closeIcon: string | TemplateRef<NzSafeAny> = 'close';\n}\n"
  },
  {
    "path": "components/tabs/tab-link.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive, ElementRef, TemplateRef, inject } from '@angular/core';\nimport { RouterLink } from '@angular/router';\n\nimport { TabTemplateContext } from './interfaces';\n\n/**\n * Fix https://github.com/angular/angular/issues/8563\n */\n@Directive({\n  selector: 'ng-template[nzTabLink]',\n  exportAs: 'nzTabLinkTemplate'\n})\nexport class NzTabLinkTemplateDirective {\n  templateRef: TemplateRef<TabTemplateContext> = inject(TemplateRef, { host: true });\n}\n\n/**\n * This component is for catching `routerLink` directive.\n */\n@Directive({\n  selector: 'a[nz-tab-link]',\n  exportAs: 'nzTabLink'\n})\nexport class NzTabLinkDirective {\n  elementRef = inject(ElementRef<HTMLAnchorElement>);\n  routerLink = inject(RouterLink, { self: true, optional: true });\n}\n"
  },
  {
    "path": "components/tabs/tab-nav-bar.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { FocusKeyManager } from '@angular/cdk/a11y';\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport { coerceNumberProperty } from '@angular/cdk/coercion';\nimport { DOWN_ARROW, ENTER, LEFT_ARROW, RIGHT_ARROW, SPACE, UP_ARROW, hasModifierKey } from '@angular/cdk/keycodes';\nimport { ViewportRuler } from '@angular/cdk/overlay';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterContentChecked,\n  AfterViewInit,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ContentChildren,\n  DestroyRef,\n  ElementRef,\n  EventEmitter,\n  Input,\n  NgZone,\n  OnChanges,\n  Output,\n  QueryList,\n  SimpleChanges,\n  TemplateRef,\n  ViewChild,\n  ViewEncapsulation,\n  booleanAttribute,\n  computed,\n  inject,\n  input\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { animationFrameScheduler, asapScheduler, merge, of } from 'rxjs';\nimport { auditTime } from 'rxjs/operators';\n\nimport { NzResizeObserver } from 'ng-zorro-antd/cdk/resize-observer';\nimport { requestAnimationFrame } from 'ng-zorro-antd/core/polyfill';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzTabPositionMode, NzTabScrollEvent, NzTabScrollListOffsetEvent, type NzIndicator } from './interfaces';\nimport { NzTabAddButtonComponent } from './tab-add-button.component';\nimport { NzTabBarExtraContentDirective } from './tab-bar-extra-content.directive';\nimport { NzTabNavItemDirective } from './tab-nav-item.directive';\nimport { NzTabNavOperationComponent } from './tab-nav-operation.component';\nimport { NzTabScrollListDirective } from './tab-scroll-list.directive';\nimport { NzTabsInkBarDirective } from './tabs-ink-bar.directive';\n\nconst RESIZE_SCHEDULER = typeof requestAnimationFrame !== 'undefined' ? animationFrameScheduler : asapScheduler;\nconst CSS_TRANSFORM_TIME = 150;\n\n@Component({\n  selector: 'nz-tabs-nav',\n  exportAs: 'nzTabsNav',\n  imports: [\n    NzTabScrollListDirective,\n    NzTabAddButtonComponent,\n    NzTabsInkBarDirective,\n    NzTabNavOperationComponent,\n    NgTemplateOutlet\n  ],\n  template: `\n    @if (startExtraContent()) {\n      <div class=\"ant-tabs-extra-content\">\n        <ng-template [ngTemplateOutlet]=\"startExtraContent()!.templateRef\" />\n      </div>\n    }\n    <div\n      class=\"ant-tabs-nav-wrap\"\n      [class.ant-tabs-nav-wrap-ping-left]=\"pingLeft\"\n      [class.ant-tabs-nav-wrap-ping-right]=\"pingRight\"\n      [class.ant-tabs-nav-wrap-ping-top]=\"pingTop\"\n      [class.ant-tabs-nav-wrap-ping-bottom]=\"pingBottom\"\n      #navWrap\n    >\n      <div\n        class=\"ant-tabs-nav-list\"\n        #navList\n        nzTabScrollList\n        (offsetChange)=\"onOffsetChange($event)\"\n        (tabScroll)=\"tabScroll.emit($event)\"\n        role=\"tablist\"\n      >\n        <ng-content />\n        @if (showAddButton) {\n          <button\n            role=\"tab\"\n            [attr.tabindex]=\"-1\"\n            nz-tab-add-button\n            [addIcon]=\"addIcon\"\n            (click)=\"addClicked.emit()\"\n          ></button>\n        }\n        <div\n          nz-tabs-ink-bar\n          [hidden]=\"hideBar\"\n          [position]=\"position\"\n          [animated]=\"inkBarAnimated\"\n          [indicator]=\"indicator()\"\n        ></div>\n      </div>\n    </div>\n    <nz-tab-nav-operation\n      (addClicked)=\"addClicked.emit()\"\n      (selected)=\"onSelectedFromMenu($event)\"\n      [addIcon]=\"addIcon\"\n      [addable]=\"addable\"\n      [items]=\"hiddenItems\"\n    />\n    @if (endExtraContent()) {\n      <div class=\"ant-tabs-extra-content\">\n        <ng-template [ngTemplateOutlet]=\"endExtraContent()!.templateRef\" />\n      </div>\n    } @else if (extraTemplate) {\n      <div class=\"ant-tabs-extra-content\">\n        <ng-template [ngTemplateOutlet]=\"extraTemplate\" />\n      </div>\n    }\n  `,\n  host: {\n    class: 'ant-tabs-nav',\n    '(keydown)': 'handleKeydown($event)'\n  },\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None\n})\nexport class NzTabNavBarComponent implements AfterViewInit, AfterContentChecked, OnChanges {\n  private cdr = inject(ChangeDetectorRef);\n  private ngZone = inject(NgZone);\n  private viewportRuler = inject(ViewportRuler);\n  private nzResizeObserver = inject(NzResizeObserver);\n  private dir = inject(Directionality);\n  private destroyRef = inject(DestroyRef);\n\n  @Output() readonly indexFocused: EventEmitter<number> = new EventEmitter<number>();\n  @Output() readonly selectFocusedIndex: EventEmitter<number> = new EventEmitter<number>();\n  @Output() readonly addClicked = new EventEmitter<void>();\n  @Output() readonly tabScroll = new EventEmitter<NzTabScrollEvent>();\n\n  @Input() position: NzTabPositionMode = 'horizontal';\n  @Input({ transform: booleanAttribute }) addable: boolean = false;\n  @Input({ transform: booleanAttribute }) hideBar: boolean = false;\n  @Input() addIcon: string | TemplateRef<NzSafeAny> = 'plus';\n  @Input() inkBarAnimated = true;\n  @Input() extraTemplate?: TemplateRef<void>;\n\n  readonly extraContents = input.required<readonly NzTabBarExtraContentDirective[]>();\n  readonly indicator = input<NzIndicator>();\n\n  readonly startExtraContent = computed(() => this.extraContents().find(item => item.position() === 'start'));\n  readonly endExtraContent = computed(() => this.extraContents().find(item => item.position() === 'end'));\n\n  @Input()\n  get selectedIndex(): number {\n    return this._selectedIndex;\n  }\n  set selectedIndex(value: number) {\n    const newValue = coerceNumberProperty(value);\n    if (this._selectedIndex !== newValue) {\n      this._selectedIndex = value;\n      this.selectedIndexChanged = true;\n      if (this.keyManager) {\n        this.keyManager.updateActiveItem(value);\n      }\n    }\n  }\n\n  @ViewChild('navWrap', { static: true }) navWrapRef!: ElementRef<HTMLElement>;\n  @ViewChild('navList', { static: true }) navListRef!: ElementRef<HTMLElement>;\n  @ViewChild(NzTabNavOperationComponent, { static: true }) operationRef!: NzTabNavOperationComponent;\n  @ViewChild(NzTabAddButtonComponent, { static: false }) addBtnRef!: NzTabAddButtonComponent;\n  @ViewChild(NzTabsInkBarDirective, { static: true }) inkBar!: NzTabsInkBarDirective;\n  @ContentChildren(NzTabNavItemDirective, { descendants: true }) items!: QueryList<NzTabNavItemDirective>;\n\n  /** Tracks which element has focus; used for keyboard navigation */\n  get focusIndex(): number {\n    return this.keyManager ? this.keyManager.activeItemIndex! : 0;\n  }\n\n  /** When the focus index is set, we must manually send focus to the correct label */\n  set focusIndex(value: number) {\n    if (!this.isValidIndex(value) || this.focusIndex === value || !this.keyManager) {\n      return;\n    }\n\n    this.keyManager.setActiveItem(value);\n  }\n\n  get showAddButton(): boolean {\n    return this.hiddenItems.length === 0 && this.addable;\n  }\n\n  translate: null | string = null;\n  transformX = 0;\n  transformY = 0;\n  pingLeft = false;\n  pingRight = false;\n  pingTop = false;\n  pingBottom = false;\n  hiddenItems: NzTabNavItemDirective[] = [];\n\n  private keyManager!: FocusKeyManager<NzTabNavItemDirective>;\n  private _selectedIndex = 0;\n  private wrapperWidth = 0;\n  private wrapperHeight = 0;\n  private scrollListWidth = 0;\n  private scrollListHeight = 0;\n  private operationWidth = 0;\n  private operationHeight = 0;\n  private addButtonWidth = 0;\n  private addButtonHeight = 0;\n  private selectedIndexChanged = false;\n  private lockAnimationTimeoutId?: ReturnType<typeof setTimeout>;\n  private cssTransformTimeWaitingId?: ReturnType<typeof setTimeout>;\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      clearTimeout(this.lockAnimationTimeoutId);\n      clearTimeout(this.cssTransformTimeWaitingId);\n    });\n  }\n\n  ngAfterViewInit(): void {\n    const dirChange = this.dir ? this.dir.change.asObservable() : of(null);\n    const resize = this.viewportRuler.change(150);\n\n    const realign = (): void => {\n      this.updateScrollListPosition();\n      this.alignInkBarToSelectedTab();\n    };\n    this.keyManager = new FocusKeyManager<NzTabNavItemDirective>(this.items)\n      .withHorizontalOrientation(this.getLayoutDirection())\n      .withWrap();\n    this.keyManager.updateActiveItem(this.selectedIndex);\n\n    requestAnimationFrame(realign);\n\n    merge(this.nzResizeObserver.observe(this.navWrapRef), this.nzResizeObserver.observe(this.navListRef))\n      .pipe(takeUntilDestroyed(this.destroyRef), auditTime(16, RESIZE_SCHEDULER))\n      .subscribe(() => {\n        realign();\n      });\n    merge(dirChange, resize, this.items.changes)\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(() => {\n        Promise.resolve().then(realign);\n        this.keyManager.withHorizontalOrientation(this.getLayoutDirection());\n      });\n\n    this.keyManager.change.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(newFocusIndex => {\n      this.indexFocused.emit(newFocusIndex);\n      this.scrollToTab(this.keyManager.activeItem!);\n    });\n  }\n\n  ngAfterContentChecked(): void {\n    if (this.selectedIndexChanged) {\n      this.updateScrollListPosition();\n      this.alignInkBarToSelectedTab();\n      this.selectedIndexChanged = false;\n      this.cdr.markForCheck();\n    }\n  }\n\n  onSelectedFromMenu(tab: NzTabNavItemDirective): void {\n    const tabIndex = this.items.toArray().findIndex(e => e === tab);\n    if (tabIndex !== -1) {\n      this.keyManager.updateActiveItem(tabIndex);\n      if (this.focusIndex !== this.selectedIndex) {\n        this.selectFocusedIndex.emit(this.focusIndex);\n        this.scrollToTab(tab);\n      }\n    }\n  }\n\n  onOffsetChange(e: NzTabScrollListOffsetEvent): void {\n    if (this.position === 'horizontal') {\n      if (!this.lockAnimationTimeoutId) {\n        if (this.transformX >= 0 && e.x > 0) {\n          return;\n        }\n        if (this.transformX <= this.wrapperWidth - this.scrollListWidth && e.x < 0) {\n          return;\n        }\n      }\n      e.event.preventDefault();\n      this.transformX = this.clampTransformX(this.transformX + e.x);\n      this.setTransform(this.transformX, 0);\n    } else {\n      if (!this.lockAnimationTimeoutId) {\n        if (this.transformY >= 0 && e.y > 0) {\n          return;\n        }\n        if (this.transformY <= this.wrapperHeight - this.scrollListHeight && e.y < 0) {\n          return;\n        }\n      }\n      e.event.preventDefault();\n      this.transformY = this.clampTransformY(this.transformY + e.y);\n      this.setTransform(0, this.transformY);\n    }\n\n    this.lockAnimation();\n    this.setVisibleRange();\n    this.setPingStatus();\n  }\n\n  handleKeydown(event: KeyboardEvent): void {\n    const inNavigationList = this.navWrapRef.nativeElement.contains(event.target as HTMLElement);\n    if (hasModifierKey(event) || !inNavigationList) {\n      return;\n    }\n\n    switch (event.keyCode) {\n      case LEFT_ARROW:\n      case UP_ARROW:\n      case RIGHT_ARROW:\n      case DOWN_ARROW:\n        this.lockAnimation();\n        this.keyManager.onKeydown(event);\n        break;\n      case ENTER:\n      case SPACE:\n        if (this.focusIndex !== this.selectedIndex) {\n          this.selectFocusedIndex.emit(this.focusIndex);\n        }\n        break;\n      default:\n        this.keyManager.onKeydown(event);\n    }\n  }\n\n  private isValidIndex(index: number): boolean {\n    if (!this.items) {\n      return true;\n    }\n\n    const tab = this.items ? this.items.toArray()[index] : null;\n    return !!tab && !tab.disabled;\n  }\n\n  private scrollToTab(tab: NzTabNavItemDirective): void {\n    if (!this.items.find(e => e === tab)) {\n      return;\n    }\n    const tabs = this.items.toArray();\n\n    if (this.position === 'horizontal') {\n      let newTransform = this.transformX;\n      if (this.getLayoutDirection() === 'rtl') {\n        const right = tabs[0].left + tabs[0].width - tab.left - tab.width;\n\n        if (right < this.transformX) {\n          newTransform = right;\n        } else if (right + tab.width > this.transformX + this.wrapperWidth) {\n          newTransform = right + tab.width - this.wrapperWidth;\n        }\n      } else if (tab.left < -this.transformX) {\n        newTransform = -tab.left;\n      } else if (tab.left + tab.width > -this.transformX + this.wrapperWidth) {\n        newTransform = -(tab.left + tab.width - this.wrapperWidth);\n      }\n      this.transformX = newTransform;\n      this.transformY = 0;\n      this.setTransform(newTransform, 0);\n    } else {\n      let newTransform = this.transformY;\n\n      if (tab.top < -this.transformY) {\n        newTransform = -tab.top;\n      } else if (tab.top + tab.height > -this.transformY + this.wrapperHeight) {\n        newTransform = -(tab.top + tab.height - this.wrapperHeight);\n      }\n      this.transformY = newTransform;\n      this.transformX = 0;\n      this.setTransform(0, newTransform);\n    }\n\n    clearTimeout(this.cssTransformTimeWaitingId);\n    this.cssTransformTimeWaitingId = setTimeout(() => {\n      this.setVisibleRange();\n    }, CSS_TRANSFORM_TIME);\n  }\n\n  private lockAnimation(): void {\n    if (!this.lockAnimationTimeoutId) {\n      this.ngZone.runOutsideAngular(() => {\n        this.navListRef.nativeElement.style.transition = 'none';\n        this.lockAnimationTimeoutId = setTimeout(() => {\n          this.navListRef.nativeElement.style.transition = '';\n          this.lockAnimationTimeoutId = undefined;\n        }, CSS_TRANSFORM_TIME);\n      });\n    }\n  }\n\n  private setTransform(x: number, y: number): void {\n    this.navListRef.nativeElement.style.transform = `translate(${x}px, ${y}px)`;\n  }\n\n  private clampTransformX(transform: number): number {\n    const scrollWidth = this.wrapperWidth - this.scrollListWidth;\n    if (this.getLayoutDirection() === 'rtl') {\n      return Math.max(Math.min(scrollWidth, transform), 0);\n    } else {\n      return Math.min(Math.max(scrollWidth, transform), 0);\n    }\n  }\n\n  private clampTransformY(transform: number): number {\n    return Math.min(Math.max(this.wrapperHeight - this.scrollListHeight, transform), 0);\n  }\n\n  private updateScrollListPosition(): void {\n    this.resetSizes();\n    this.transformX = this.clampTransformX(this.transformX);\n    this.transformY = this.clampTransformY(this.transformY);\n    this.setVisibleRange();\n    this.setPingStatus();\n    if (this.keyManager) {\n      this.keyManager.updateActiveItem(this.keyManager.activeItemIndex!);\n      if (this.keyManager.activeItem) {\n        this.scrollToTab(this.keyManager.activeItem);\n      }\n    }\n  }\n\n  private resetSizes(): void {\n    this.addButtonWidth = this.addBtnRef ? this.addBtnRef.getElementWidth() : 0;\n    this.addButtonHeight = this.addBtnRef ? this.addBtnRef.getElementHeight() : 0;\n    this.operationWidth = this.operationRef.getElementWidth();\n    this.operationHeight = this.operationRef.getElementHeight();\n    this.wrapperWidth = this.navWrapRef.nativeElement.offsetWidth || 0;\n    this.wrapperHeight = this.navWrapRef.nativeElement.offsetHeight || 0;\n    this.scrollListHeight = this.navListRef.nativeElement.offsetHeight || 0;\n    this.scrollListWidth = this.navListRef.nativeElement.offsetWidth || 0;\n  }\n\n  private alignInkBarToSelectedTab(): void {\n    const selectedItem = this.items && this.items.length ? this.items.toArray()[this.selectedIndex] : null;\n    const selectedItemElement = selectedItem ? selectedItem.elementRef.nativeElement : null;\n\n    if (selectedItemElement) {\n      /**\n       * .ant-tabs-nav-list - Target offset parent element\n       *   └──.ant-tabs-tab\n       *        └──.ant-tabs-tab-btn - Currently focused element\n       */\n      this.inkBar.alignToElement(selectedItemElement.parentElement!);\n    }\n  }\n\n  private setPingStatus(): void {\n    const ping = {\n      top: false,\n      right: false,\n      bottom: false,\n      left: false\n    };\n    const navWrap = this.navWrapRef.nativeElement;\n    if (this.position === 'horizontal') {\n      if (this.getLayoutDirection() === 'rtl') {\n        ping.right = this.transformX > 0;\n        ping.left = this.transformX + this.wrapperWidth < this.scrollListWidth;\n      } else {\n        ping.left = this.transformX < 0;\n        ping.right = -this.transformX + this.wrapperWidth < this.scrollListWidth;\n      }\n    } else {\n      ping.top = this.transformY < 0;\n      ping.bottom = -this.transformY + this.wrapperHeight < this.scrollListHeight;\n    }\n\n    (Object.keys(ping) as Array<'top' | 'right' | 'bottom' | 'left'>).forEach(pos => {\n      const className = `ant-tabs-nav-wrap-ping-${pos}`;\n      if (ping[pos]) {\n        navWrap.classList.add(className);\n      } else {\n        navWrap.classList.remove(className);\n      }\n    });\n  }\n\n  private setVisibleRange(): void {\n    let unit: 'width' | 'height';\n    let position: 'left' | 'top' | 'right';\n    let transformSize: number;\n    let basicSize: number;\n    let tabContentSize: number;\n    let addSize: number;\n    const tabs = this.items.toArray();\n    const DEFAULT_SIZE = { width: 0, height: 0, left: 0, top: 0, right: 0 };\n\n    const getOffset = (index: number): number => {\n      let offset: number;\n      const size = tabs[index] || DEFAULT_SIZE;\n      if (position === 'right') {\n        offset = tabs[0].left + tabs[0].width - tabs[index].left - tabs[index].width;\n      } else {\n        offset = size[position];\n      }\n      return offset;\n    };\n\n    if (this.position === 'horizontal') {\n      unit = 'width';\n      basicSize = this.wrapperWidth;\n      tabContentSize = this.scrollListWidth - (this.hiddenItems.length ? this.operationWidth : 0);\n      addSize = this.addButtonWidth;\n      transformSize = Math.abs(this.transformX);\n      if (this.getLayoutDirection() === 'rtl') {\n        position = 'right';\n        this.pingRight = this.transformX > 0;\n        this.pingLeft = this.transformX + this.wrapperWidth < this.scrollListWidth;\n      } else {\n        this.pingLeft = this.transformX < 0;\n        this.pingRight = -this.transformX + this.wrapperWidth < this.scrollListWidth;\n        position = 'left';\n      }\n    } else {\n      unit = 'height';\n      basicSize = this.wrapperHeight;\n      tabContentSize = this.scrollListHeight - (this.hiddenItems.length ? this.operationHeight : 0);\n      addSize = this.addButtonHeight;\n      position = 'top';\n      transformSize = -this.transformY;\n      this.pingTop = this.transformY < 0;\n      this.pingBottom = -this.transformY + this.wrapperHeight < this.scrollListHeight;\n    }\n\n    let mergedBasicSize = basicSize;\n    if (tabContentSize + addSize > basicSize) {\n      mergedBasicSize = basicSize - addSize;\n    }\n\n    if (!tabs.length) {\n      this.hiddenItems = [];\n      this.cdr.markForCheck();\n      return;\n    }\n\n    const len = tabs.length;\n    let endIndex = len;\n    for (let i = 0; i < len; i += 1) {\n      const offset = getOffset(i);\n      const size = tabs[i] || DEFAULT_SIZE;\n      if (offset + size[unit] > transformSize + mergedBasicSize) {\n        endIndex = i - 1;\n        break;\n      }\n    }\n\n    let startIndex = 0;\n    for (let i = len - 1; i >= 0; i -= 1) {\n      const offset = getOffset(i);\n      if (offset < transformSize) {\n        startIndex = i + 1;\n        break;\n      }\n    }\n\n    const startHiddenTabs = tabs.slice(0, startIndex);\n    const endHiddenTabs = tabs.slice(endIndex + 1);\n    this.hiddenItems = [...startHiddenTabs, ...endHiddenTabs];\n    this.cdr.markForCheck();\n  }\n\n  private getLayoutDirection(): Direction {\n    return this.dir && this.dir.value === 'rtl' ? 'rtl' : 'ltr';\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    // The first will be aligning in ngAfterViewInit\n    const { position, indicator } = changes;\n    if (position && !position.isFirstChange()) {\n      this.updateScrollListPosition();\n    }\n    if ((position && !position.isFirstChange()) || (indicator && !indicator.isFirstChange())) {\n      this.alignInkBarToSelectedTab();\n      this.lockAnimation();\n    }\n  }\n}\n"
  },
  {
    "path": "components/tabs/tab-nav-item.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { FocusableOption } from '@angular/cdk/a11y';\nimport { Directive, ElementRef, Input, booleanAttribute, inject } from '@angular/core';\n\nimport { NzTabComponent } from './tab.component';\n\n@Directive({\n  selector: '[nzTabNavItem]'\n})\nexport class NzTabNavItemDirective implements FocusableOption {\n  @Input({ transform: booleanAttribute }) disabled: boolean = false;\n  @Input() tab!: NzTabComponent;\n  @Input({ transform: booleanAttribute }) active: boolean = false;\n\n  public elementRef: ElementRef<HTMLElement> = inject(ElementRef<HTMLElement>);\n  private el: HTMLElement = this.elementRef.nativeElement;\n  private parentElement: HTMLElement = this.el.parentElement!;\n\n  focus(): void {\n    this.el.focus({ preventScroll: true });\n  }\n\n  get width(): number {\n    return this.parentElement.offsetWidth;\n  }\n\n  get height(): number {\n    return this.parentElement.offsetHeight;\n  }\n\n  get left(): number {\n    return this.parentElement.offsetLeft;\n  }\n\n  get top(): number {\n    return this.parentElement.offsetTop;\n  }\n}\n"
  },
  {
    "path": "components/tabs/tab-nav-operation.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ElementRef,\n  EventEmitter,\n  Input,\n  OnDestroy,\n  Output,\n  TemplateRef,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject\n} from '@angular/core';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { NzDropdownModule } from 'ng-zorro-antd/dropdown';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\n\nimport { NzTabAddButtonComponent } from './tab-add-button.component';\nimport { NzTabNavItemDirective } from './tab-nav-item.directive';\n\n@Component({\n  selector: 'nz-tab-nav-operation',\n  exportAs: 'nzTabNavOperation',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <button\n      nz-dropdown\n      class=\"ant-tabs-nav-more\"\n      type=\"button\"\n      tabindex=\"-1\"\n      aria-hidden=\"true\"\n      nzOverlayClassName=\"nz-tabs-dropdown\"\n      #dropdownTrigger=\"nzDropdown\"\n      [nzDropdownMenu]=\"menu\"\n      [nzOverlayStyle]=\"{ minWidth: '46px' }\"\n      [nzMatchWidthElement]=\"null\"\n      (nzVisibleChange)=\"menuVisChange($event)\"\n      (mouseenter)=\"showItems()\"\n    >\n      <nz-icon nzType=\"ellipsis\" />\n    </button>\n    <nz-dropdown-menu #menu=\"nzDropdownMenu\">\n      @if (menuOpened) {\n        <ul nz-menu>\n          @for (item of items; track item) {\n            <li\n              nz-menu-item\n              class=\"ant-tabs-dropdown-menu-item\"\n              [class.ant-tabs-dropdown-menu-item-disabled]=\"item.disabled\"\n              [nzSelected]=\"item.active\"\n              [nzDisabled]=\"item.disabled\"\n              (click)=\"onSelect(item)\"\n              (contextmenu)=\"onContextmenu(item, $event)\"\n            >\n              <ng-container *nzStringTemplateOutlet=\"item.tab.label; context: { visible: false }\">\n                {{ item.tab.label }}\n              </ng-container>\n            </li>\n          }\n        </ul>\n      }\n    </nz-dropdown-menu>\n    @if (addable) {\n      <button nz-tab-add-button [addIcon]=\"addIcon\" (click)=\"addClicked.emit()\"></button>\n    }\n  `,\n  host: {\n    class: 'ant-tabs-nav-operations',\n    '[class.ant-tabs-nav-operations-hidden]': 'items.length === 0'\n  },\n  imports: [NzDropdownModule, NzIconModule, NzOutletModule, NzTabAddButtonComponent, NzMenuModule]\n})\nexport class NzTabNavOperationComponent implements OnDestroy {\n  @Input() items: NzTabNavItemDirective[] = [];\n  @Input({ transform: booleanAttribute }) addable: boolean = false;\n  @Input() addIcon: string | TemplateRef<NzSafeAny> = 'plus';\n\n  @Output() readonly addClicked = new EventEmitter<void>();\n  @Output() readonly selected = new EventEmitter<NzTabNavItemDirective>();\n  closeAnimationWaitTimeoutId?: ReturnType<typeof setTimeout>;\n  menuOpened = false;\n\n  private cdr = inject(ChangeDetectorRef);\n  private readonly element: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement;\n\n  onSelect(item: NzTabNavItemDirective): void {\n    if (!item.disabled) {\n      // ignore nzCanDeactivate\n      item.tab.nzClick.emit();\n      this.selected.emit(item);\n    }\n  }\n\n  onContextmenu(item: NzTabNavItemDirective, e: MouseEvent): void {\n    if (!item.disabled) {\n      item.tab.nzContextmenu.emit(e);\n    }\n  }\n  showItems(): void {\n    clearTimeout(this.closeAnimationWaitTimeoutId);\n    this.menuOpened = true;\n    this.cdr.markForCheck();\n  }\n\n  menuVisChange(visible: boolean): void {\n    if (!visible) {\n      this.closeAnimationWaitTimeoutId = setTimeout(() => {\n        this.menuOpened = false;\n        this.cdr.markForCheck();\n      }, 150);\n    }\n  }\n\n  getElementWidth(): number {\n    return this.element?.offsetWidth || 0;\n  }\n\n  getElementHeight(): number {\n    return this.element?.offsetHeight || 0;\n  }\n\n  ngOnDestroy(): void {\n    clearTimeout(this.closeAnimationWaitTimeoutId);\n  }\n}\n"
  },
  {
    "path": "components/tabs/tab-scroll-list.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { DestroyRef, Directive, ElementRef, EventEmitter, inject, NgZone, OnInit, Output } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Observable, Subscription } from 'rxjs';\n\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\n\nimport {\n  NzTabScrollEvent,\n  NzTabScrollEventHandlerFun,\n  NzTabScrollListOffset,\n  NzTabScrollListOffsetEvent\n} from './interfaces';\n\nconst MIN_SWIPE_DISTANCE = 0.1;\nconst STOP_SWIPE_DISTANCE = 0.01;\nconst REFRESH_INTERVAL = 20;\nconst SPEED_OFF_MULTIPLE = 0.995 ** REFRESH_INTERVAL;\n\n@Directive({\n  selector: '[nzTabScrollList]'\n})\nexport class NzTabScrollListDirective implements OnInit {\n  private ngZone = inject(NgZone);\n  private destroyRef = inject(DestroyRef);\n  private el: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement;\n\n  lastWheelDirection: 'x' | 'y' | null = null;\n  lastWheelTimestamp = 0;\n  lastTimestamp = 0;\n  lastTimeDiff = 0;\n  lastMixedWheel = 0;\n  lastWheelPrevent = false;\n  touchPosition: NzTabScrollListOffset | null = null;\n  lastOffset: NzTabScrollListOffset | null = null;\n  motion = -1;\n\n  @Output() readonly offsetChange = new EventEmitter<NzTabScrollListOffsetEvent>();\n  @Output() readonly tabScroll = new EventEmitter<NzTabScrollEvent>();\n\n  ngOnInit(): void {\n    const wheel$ = fromEventOutsideAngular<WheelEvent>(this.el, 'wheel');\n    const touchstart$ = fromEventOutsideAngular<TouchEvent>(this.el, 'touchstart');\n    const touchmove$ = fromEventOutsideAngular<TouchEvent>(this.el, 'touchmove');\n    const touchend$ = fromEventOutsideAngular<TouchEvent>(this.el, 'touchend');\n\n    this.subscribeWrap('wheel', wheel$, this.onWheel);\n    this.subscribeWrap('touchstart', touchstart$, this.onTouchStart);\n    this.subscribeWrap('touchmove', touchmove$, this.onTouchMove);\n    this.subscribeWrap('touchend', touchend$, this.onTouchEnd);\n  }\n\n  private subscribeWrap<T extends NzTabScrollEvent['event']>(\n    type: NzTabScrollEvent['type'],\n    observable: Observable<T>,\n    handler: NzTabScrollEventHandlerFun<T>\n  ): Subscription {\n    return observable.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(event => {\n      this.tabScroll.emit({\n        type,\n        event\n      } as NzTabScrollEvent);\n      if (!event.defaultPrevented) {\n        handler(event);\n      }\n    });\n  }\n\n  onTouchEnd = (e: TouchEvent): void => {\n    if (!this.touchPosition) {\n      return;\n    }\n    const lastOffset = this.lastOffset;\n    const lastTimeDiff = this.lastTimeDiff;\n\n    this.lastOffset = this.touchPosition = null;\n\n    if (lastOffset) {\n      const distanceX = lastOffset.x / lastTimeDiff;\n      const distanceY = lastOffset.y / lastTimeDiff;\n      const absX = Math.abs(distanceX);\n      const absY = Math.abs(distanceY);\n\n      // Skip swipe if low distance\n      if (Math.max(absX, absY) < MIN_SWIPE_DISTANCE) {\n        return;\n      }\n\n      let currentX = distanceX;\n      let currentY = distanceY;\n\n      this.motion = window.setInterval(() => {\n        if (Math.abs(currentX) < STOP_SWIPE_DISTANCE && Math.abs(currentY) < STOP_SWIPE_DISTANCE) {\n          window.clearInterval(this.motion);\n          return;\n        }\n\n        currentX *= SPEED_OFF_MULTIPLE;\n        currentY *= SPEED_OFF_MULTIPLE;\n        this.onOffset(currentX * REFRESH_INTERVAL, currentY * REFRESH_INTERVAL, e);\n      }, REFRESH_INTERVAL);\n    }\n  };\n\n  onTouchMove = (e: TouchEvent): void => {\n    if (!this.touchPosition) {\n      return;\n    }\n\n    e.preventDefault();\n    const { screenX, screenY } = e.touches[0];\n\n    const offsetX = screenX - this.touchPosition.x;\n    const offsetY = screenY - this.touchPosition.y;\n    this.onOffset(offsetX, offsetY, e);\n    const now = Date.now();\n\n    this.lastTimeDiff = now - this.lastTimestamp;\n    this.lastTimestamp = now;\n    this.lastOffset = { x: offsetX, y: offsetY };\n    this.touchPosition = { x: screenX, y: screenY };\n  };\n\n  onTouchStart = (e: TouchEvent): void => {\n    const { screenX, screenY } = e.touches[0];\n    this.touchPosition = { x: screenX, y: screenY };\n    window.clearInterval(this.motion);\n  };\n\n  onWheel = (e: WheelEvent): void => {\n    const { deltaX, deltaY } = e;\n    let mixed: number;\n    const absX = Math.abs(deltaX);\n    const absY = Math.abs(deltaY);\n\n    if (absX === absY) {\n      mixed = this.lastWheelDirection === 'x' ? deltaX : deltaY;\n    } else if (absX > absY) {\n      mixed = deltaX;\n      this.lastWheelDirection = 'x';\n    } else {\n      mixed = deltaY;\n      this.lastWheelDirection = 'y';\n    }\n\n    // Optimize mac touch scroll\n    const now = Date.now();\n    const absMixed = Math.abs(mixed);\n\n    if (now - this.lastWheelTimestamp > 100 || absMixed - this.lastMixedWheel > 10) {\n      this.lastWheelPrevent = false;\n    }\n    this.onOffset(-mixed, -mixed, e);\n    if (e.defaultPrevented || this.lastWheelPrevent) {\n      this.lastWheelPrevent = true;\n    }\n\n    this.lastWheelTimestamp = now;\n    this.lastMixedWheel = absMixed;\n  };\n\n  onOffset(x: number, y: number, event: Event): void {\n    if (this.offsetChange.observers.length) {\n      this.ngZone.run(() => {\n        this.offsetChange.emit({\n          x,\n          y,\n          event\n        });\n      });\n    }\n  }\n}\n"
  },
  {
    "path": "components/tabs/tab.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  ContentChild,\n  EventEmitter,\n  InjectionToken,\n  Input,\n  OnChanges,\n  OnDestroy,\n  Output,\n  SimpleChanges,\n  TemplateRef,\n  ViewChild,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject\n} from '@angular/core';\nimport { Subject } from 'rxjs';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { TabTemplateContext } from './interfaces';\nimport { NzTabLinkDirective, NzTabLinkTemplateDirective } from './tab-link.directive';\nimport { NzTabDirective } from './tab.directive';\n\n/**\n * Used to provide a tab set to a tab without causing a circular dependency.\n */\nexport const NZ_TAB_SET = new InjectionToken<NzSafeAny>(typeof ngDevMode !== 'undefined' && ngDevMode ? 'nz-tabs' : '');\n\n@Component({\n  selector: 'nz-tab',\n  exportAs: 'nzTab',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    <ng-template #tabLinkTemplate>\n      <ng-content select=\"[nz-tab-link]\" />\n    </ng-template>\n    <ng-template #contentTemplate>\n      <ng-content />\n    </ng-template>\n  `\n})\nexport class NzTabComponent implements OnChanges, OnDestroy {\n  @Input() nzTitle: string | TemplateRef<TabTemplateContext> = '';\n  @Input({ transform: booleanAttribute }) nzClosable = false;\n  @Input() nzCloseIcon: string | TemplateRef<NzSafeAny> = 'close';\n  @Input({ transform: booleanAttribute }) nzDisabled = false;\n  @Input({ transform: booleanAttribute }) nzForceRender = false;\n  @Output() readonly nzSelect = new EventEmitter<void>();\n  @Output() readonly nzDeselect = new EventEmitter<void>();\n  @Output() readonly nzClick = new EventEmitter<void>();\n  @Output() readonly nzContextmenu = new EventEmitter<MouseEvent>();\n\n  @ContentChild(NzTabLinkTemplateDirective, { static: false }) nzTabLinkTemplateDirective!: NzTabLinkTemplateDirective;\n  @ContentChild(NzTabDirective, { static: false, read: TemplateRef }) template: TemplateRef<void> | null = null;\n  @ContentChild(NzTabLinkDirective, { static: false }) linkDirective!: NzTabLinkDirective;\n  @ViewChild('contentTemplate', { static: true }) contentTemplate!: TemplateRef<NzSafeAny>;\n\n  isActive: boolean = false;\n  hasBeenActive = false;\n  position: number | null = null;\n  origin: number | null = null;\n  closestTabSet = inject(NZ_TAB_SET);\n\n  readonly stateChanges = new Subject<void>();\n\n  get content(): TemplateRef<NzSafeAny> {\n    return this.template || this.contentTemplate;\n  }\n\n  get label(): string | TemplateRef<NzSafeAny> {\n    return this.nzTitle || this.nzTabLinkTemplateDirective?.templateRef;\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzTitle, nzDisabled, nzForceRender } = changes;\n    if (nzTitle || nzDisabled || nzForceRender) {\n      this.stateChanges.next();\n    }\n  }\n\n  ngOnDestroy(): void {\n    this.stateChanges.complete();\n  }\n\n  setActive(active: boolean): void {\n    this.isActive = active;\n    if (active) {\n      this.hasBeenActive = true;\n    }\n  }\n}\n"
  },
  {
    "path": "components/tabs/tab.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directive } from '@angular/core';\n\n/** Decorates the `ng-template` tags and reads out the template from it. */\n@Directive({\n  selector: '[nz-tab]',\n  exportAs: 'nzTab'\n})\nexport class NzTabDirective {}\n"
  },
  {
    "path": "components/tabs/tabs-ink-bar.directive.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { coerceCssPixelValue } from '@angular/cdk/coercion';\nimport { Directive, ElementRef, NgZone, inject, input } from '@angular/core';\n\nimport { isAnimationEnabled } from 'ng-zorro-antd/core/animation';\nimport { requestAnimationFrame } from 'ng-zorro-antd/core/polyfill';\nimport { isNil } from 'ng-zorro-antd/core/util';\n\nimport { NzTabPositionMode, type NzIndicator, type NzIndicatorAlign } from './interfaces';\n\n@Directive({\n  selector: 'nz-tabs-ink-bar, [nz-tabs-ink-bar]',\n  host: {\n    class: 'ant-tabs-ink-bar',\n    '[class.ant-tabs-ink-bar-animated]': 'animationEnabled()'\n  }\n})\nexport class NzTabsInkBarDirective {\n  private readonly ngZone = inject(NgZone);\n  private readonly el = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n  private readonly directionality = inject(Directionality).valueSignal;\n\n  readonly position = input<NzTabPositionMode>('horizontal');\n  readonly animated = input(true);\n  readonly indicator = input<NzIndicator>();\n  protected readonly animationEnabled = isAnimationEnabled(() => this.animated());\n\n  alignToElement(element: HTMLElement): void {\n    this.ngZone.runOutsideAngular(() => {\n      requestAnimationFrame(() => this.setStyles(element));\n    });\n  }\n\n  private setStyles(element: HTMLElement): void {\n    const { size, align } = this.indicator() || {};\n    if (this.position() === 'horizontal') {\n      this.el.style.top = '';\n      this.el.style.height = '';\n      this.el.style.width = coerceCssPixelValue(\n        size ? (typeof size === 'number' ? size : size(element?.offsetWidth ?? 0)) : (element?.offsetWidth ?? 0)\n      );\n      this.el.style.left = this.setIndicatorPosition(element, align);\n    } else {\n      this.el.style.left = '';\n      this.el.style.width = '';\n      this.el.style.height = coerceCssPixelValue(\n        !isNil(size)\n          ? typeof size === 'number'\n            ? size\n            : size(element?.offsetHeight ?? 0)\n          : (element?.offsetHeight ?? 0)\n      );\n      this.el.style.top = this.setIndicatorPosition(element, align);\n    }\n  }\n\n  private setIndicatorPosition(element: HTMLElement, align: NzIndicatorAlign = 'start'): string {\n    const isHorizontal = this.position() === 'horizontal';\n    const itemOffset = isHorizontal ? (element?.offsetLeft ?? 0) : (element?.offsetTop ?? 0);\n    const itemSize = isHorizontal ? (element?.offsetWidth ?? 0) : (element?.offsetHeight ?? 0);\n    const indicatorSize = isHorizontal ? this.el.offsetWidth : this.el.offsetHeight;\n    const isRtl = isHorizontal && this.directionality() === 'rtl';\n    const resolvedAlign: NzIndicatorAlign = isRtl && align !== 'center' ? (align === 'start' ? 'end' : 'start') : align;\n\n    switch (resolvedAlign) {\n      case 'start':\n        return coerceCssPixelValue(itemOffset);\n      case 'end':\n        return coerceCssPixelValue(itemOffset + itemSize - (indicatorSize || 0));\n      case 'center':\n        return coerceCssPixelValue(itemOffset + (itemSize - (indicatorSize || 0)) / 2);\n    }\n  }\n}\n"
  },
  {
    "path": "components/tabs/tabs.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ENTER, LEFT_ARROW, RIGHT_ARROW, SPACE } from '@angular/cdk/keycodes';\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport { AsyncPipe } from '@angular/common';\nimport {\n  Component,\n  DebugElement,\n  OnInit,\n  provideZoneChangeDetection,\n  QueryList,\n  signal,\n  ViewChild,\n  ViewChildren,\n  ViewEncapsulation\n} from '@angular/core';\nimport { ComponentFixture, fakeAsync, flush, inject, TestBed, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { provideRouter, Router, RouterLink, RouterOutlet, Routes } from '@angular/router';\nimport { Observable } from 'rxjs';\n\nimport { provideNzNoAnimation } from 'ng-zorro-antd/core/animation';\nimport { dispatchFakeEvent, dispatchKeyboardEvent } from 'ng-zorro-antd/core/testing';\nimport { NzSafeAny, NzSizeLDSType } from 'ng-zorro-antd/core/types';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzIndicator, NzTabPosition, NzTabType } from './interfaces';\nimport { NzTabNavBarComponent } from './tab-nav-bar.component';\nimport { NzTabNavOperationComponent } from './tab-nav-operation.component';\nimport { NzTabComponent } from './tab.component';\nimport { NzTabsComponent } from './tabs.component';\nimport { NzTabsModule } from './tabs.module';\n\ndescribe('tabs', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzNoAnimation(), provideNzIconsTesting(), provideZoneChangeDetection()]\n    });\n  });\n\n  describe('basic', () => {\n    let fixture: ComponentFixture<SimpleTabsTestComponent>;\n    let element: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(SimpleTabsTestComponent);\n      element = fixture.nativeElement;\n    });\n\n    it('should default to the first tab', () => {\n      checkSelectedIndex(1, fixture);\n    });\n\n    it('should load content on first change detection pass', () => {\n      fixture.detectChanges();\n      expect(element.querySelectorAll('.ant-tabs-tabpane')[0]!.textContent).toContain(`Content of Tab Pane 1`);\n    });\n\n    it('should change selected index on click', () => {\n      const component = fixture.debugElement.componentInstance;\n      component.selectedIndex = 0;\n      checkSelectedIndex(0, fixture);\n\n      // select the second tab\n      let tabLabel = fixture.debugElement.queryAll(By.css('.ant-tabs-tab'))[1];\n      tabLabel.nativeElement.click();\n      checkSelectedIndex(1, fixture);\n\n      // select the third tab\n      tabLabel = fixture.debugElement.queryAll(By.css('.ant-tabs-tab'))[2];\n      tabLabel.nativeElement.click();\n      checkSelectedIndex(2, fixture);\n    });\n\n    it('should support two-way binding for selectedIndex', fakeAsync(() => {\n      const component = fixture.componentInstance;\n      component.selectedIndex = 0;\n\n      fixture.detectChanges();\n\n      const tabLabel = fixture.debugElement.queryAll(By.css('.ant-tabs-tab'))[1];\n      tabLabel.nativeElement.click();\n      fixture.detectChanges();\n      flush();\n\n      expect(component.selectedIndex).toBe(1);\n    }));\n\n    it('should update tab positions when selected index is changed', () => {\n      fixture.detectChanges();\n      const component: NzTabsComponent = fixture.debugElement.query(By.css('nz-tabs'))!.componentInstance;\n      const tabs: NzTabComponent[] = component.tabs.toArray();\n\n      expect(tabs[0].position).toBeLessThan(0);\n      expect(tabs[1].position).toBe(0);\n      expect(tabs[2].position).toBeGreaterThan(0);\n\n      // Move to third tab\n      component.nzSelectedIndex = 2;\n      fixture.detectChanges();\n      expect(tabs[0].position).toBeLessThan(0);\n      expect(tabs[1].position).toBeLessThan(0);\n      expect(tabs[2].position).toBe(0);\n\n      // Move to the first tab\n      component.nzSelectedIndex = 0;\n      fixture.detectChanges();\n      expect(tabs[0].position).toBe(0);\n      expect(tabs[1].position).toBeGreaterThan(0);\n      expect(tabs[2].position).toBeGreaterThan(0);\n    });\n\n    it('should clamp the selected index to the size of the number of tabs', () => {\n      fixture.detectChanges();\n      const component: NzTabsComponent = fixture.debugElement.query(By.css('nz-tabs'))!.componentInstance;\n\n      // Set the index to be negative, expect the first tab selected\n      fixture.componentInstance.selectedIndex = -1;\n      fixture.detectChanges();\n      expect(component.nzSelectedIndex).toBe(0);\n\n      // Set the index beyond the size of the tabs, expect the last tab selected\n      fixture.componentInstance.selectedIndex = 3;\n      fixture.detectChanges();\n      expect(component.nzSelectedIndex).toBe(2);\n    });\n\n    it('should not crash when setting the selected index to NaN', () => {\n      const component = fixture.debugElement.componentInstance;\n\n      expect(() => {\n        component.selectedIndex = NaN;\n        fixture.detectChanges();\n      }).not.toThrow();\n    });\n\n    it('should emit nzSelectedIndexChange event on click', fakeAsync(() => {\n      const component = fixture.componentInstance;\n      component.selectedIndex = 0;\n      spyOn(component, 'handleSelection');\n\n      fixture.detectChanges();\n\n      const tabLabel = fixture.debugElement.queryAll(By.css('.ant-tabs-tab'))[1];\n\n      expect(component.handleSelection).toHaveBeenCalledTimes(0);\n\n      tabLabel.nativeElement.click();\n      fixture.detectChanges();\n      flush();\n\n      expect(component.handleSelection).toHaveBeenCalledTimes(1);\n      expect(component.selectedIndex).toBe(1);\n    }));\n\n    it('should emit nzSelectedIndexChange on arrow key navigation', fakeAsync(() => {\n      const component = fixture.componentInstance;\n      component.selectedIndex = 0;\n      spyOn(component, 'handleSelection');\n      fixture.detectChanges();\n\n      const tab = fixture.debugElement.queryAll(By.css('.ant-tabs-tab'))[1]!;\n      const tabsContainer = fixture.debugElement.query(By.css('.ant-tabs-nav-wrap'))!.nativeElement as HTMLElement;\n      const trigger = tab!.nativeElement as HTMLElement;\n\n      expect(component.handleSelection).toHaveBeenCalledTimes(0);\n\n      tab.nativeElement.click();\n      fixture.detectChanges();\n      flush();\n\n      expect(component.handleSelection).toHaveBeenCalledTimes(1);\n\n      dispatchKeyboardEvent(tabsContainer, 'keydown', LEFT_ARROW, trigger);\n      fixture.detectChanges();\n      dispatchKeyboardEvent(tabsContainer, 'keydown', ENTER, trigger);\n      fixture.detectChanges();\n      flush();\n\n      expect(component.handleSelection).toHaveBeenCalledTimes(2);\n      expect(component.handleSelection).toHaveBeenCalledWith(0);\n\n      dispatchKeyboardEvent(tabsContainer, 'keydown', RIGHT_ARROW, trigger);\n      fixture.detectChanges();\n      dispatchKeyboardEvent(tabsContainer, 'keydown', SPACE, trigger);\n      fixture.detectChanges();\n      flush();\n\n      expect(component.handleSelection).toHaveBeenCalledTimes(3);\n      expect(component.handleSelection).toHaveBeenCalledWith(1);\n    }));\n\n    it('should not emit nzSelectedIndexChange when key-event on navigation list outside', fakeAsync(() => {\n      const component = fixture.componentInstance;\n      component.selectedIndex = 0;\n      spyOn(component, 'handleSelection');\n      fixture.detectChanges();\n      fixture.detectChanges();\n      flush();\n\n      const tabsContainer = fixture.debugElement.query(By.css('.ant-tabs-nav-wrap'))!.nativeElement as HTMLElement;\n      const trigger = fixture.debugElement.query(By.css('.extra-input'))!.nativeElement as HTMLElement;\n\n      expect(component.handleSelection).toHaveBeenCalledTimes(0);\n\n      dispatchKeyboardEvent(tabsContainer, 'keydown', LEFT_ARROW, trigger);\n      fixture.detectChanges();\n      dispatchKeyboardEvent(tabsContainer, 'keydown', ENTER, trigger);\n      fixture.detectChanges();\n      flush();\n\n      expect(component.handleSelection).toHaveBeenCalledTimes(0);\n      tick(300);\n      fixture.detectChanges();\n    }));\n\n    it('should clean up the tabs QueryList on destroy', () => {\n      const component: NzTabsComponent = fixture.debugElement.query(By.css('nz-tabs'))!.componentInstance;\n      const spy = jasmine.createSpy('complete spy');\n      const subscription = component.tabs.changes.subscribe({ complete: spy });\n\n      fixture.destroy();\n\n      expect(spy).toHaveBeenCalled();\n      subscription.unsubscribe();\n    });\n\n    it('should set the correct position', () => {\n      const component = fixture.debugElement.componentInstance;\n      const tabSetElement = fixture.debugElement.query(By.css('.ant-tabs'))!.nativeElement!;\n      const tabSetContentElement = fixture.debugElement.query(By.css('.ant-tabs .ant-tabs-content'))!.nativeElement!;\n      component.position = 'left';\n      fixture.detectChanges();\n\n      expect(tabSetElement.classList).toContain('ant-tabs-left');\n      expect(tabSetContentElement.classList).toContain('ant-tabs-content-left');\n    });\n\n    it('should set the correct size', () => {\n      const component = fixture.debugElement.componentInstance;\n      const tabSetElement = fixture.debugElement.query(By.css('.ant-tabs'))!.nativeElement!;\n      component.size = 'small';\n      fixture.detectChanges();\n\n      expect(tabSetElement.classList).toContain('ant-tabs-small');\n    });\n\n    it('should set the correct type', () => {\n      const component = fixture.debugElement.componentInstance;\n      const tabSetElement = fixture.debugElement.query(By.css('.ant-tabs'))!.nativeElement!;\n      component.type = 'card';\n      fixture.detectChanges();\n\n      expect(tabSetElement.classList).toContain('ant-tabs-card');\n      expect(tabSetElement.classList).not.toContain('ant-tabs-editable');\n      expect(tabSetElement.classList).not.toContain('ant-tabs-editable-card');\n\n      component.type = 'editable-card';\n      fixture.detectChanges();\n\n      expect(tabSetElement.classList).toContain('ant-tabs-card');\n      expect(tabSetElement.classList).toContain('ant-tabs-editable');\n      expect(tabSetElement.classList).toContain('ant-tabs-editable-card');\n    });\n\n    it('should set the correct tabBarGutter', () => {\n      fixture.detectChanges();\n\n      const component = fixture.debugElement.componentInstance;\n      const tabsButtons = fixture.nativeElement.querySelectorAll('.ant-tabs-tab')! as HTMLElement[];\n      component.tabBarGutter = 10;\n      fixture.detectChanges();\n\n      expect(tabsButtons.length).toBe(3);\n\n      tabsButtons.forEach(tab => {\n        expect(tab.style.marginRight).toBe('10px');\n        expect(tab.style.marginBottom).toBe('');\n      });\n\n      component.position = 'left';\n      fixture.detectChanges();\n\n      tabsButtons.forEach(tab => {\n        expect(tab.style.marginRight).toBe('');\n        expect(tab.style.marginBottom).toBe('10px');\n      });\n    });\n\n    it('should set the correct tabBarStyle', fakeAsync(() => {\n      fixture.detectChanges();\n      tick(200);\n\n      const component = fixture.debugElement.componentInstance;\n      const tabsNav = fixture.debugElement.query(By.css('nz-tabs-nav'))!.nativeElement;\n      component.tabBarStyle = { color: 'rgb(255, 0, 0)' };\n\n      fixture.detectChanges();\n      tick(200);\n\n      expect(tabsNav.style.color).toBe('rgb(255, 0, 0)');\n    }));\n\n    it('should set the correct centered', () => {\n      const component = fixture.debugElement.componentInstance;\n      const tabSet = fixture.debugElement.query(By.css('nz-tabs'))!.nativeElement;\n      fixture.detectChanges();\n\n      expect(tabSet.classList).not.toContain('ant-tabs-centered');\n\n      component.centered = true;\n      fixture.detectChanges();\n\n      expect(tabSet.classList).toContain('ant-tabs-centered');\n    });\n\n    it('should canDeactivate work', () => {\n      const component = fixture.debugElement.componentInstance;\n      component.selectedIndex = 0;\n      component.canDeactivate = (_: number, next: number) => next !== 2;\n\n      fixture.detectChanges();\n\n      let tabLabel = fixture.debugElement.queryAll(By.css('.ant-tabs-tab'))[1];\n      tabLabel.nativeElement.click();\n      fixture.detectChanges();\n      checkSelectedIndex(1, fixture);\n\n      tabLabel = fixture.debugElement.queryAll(By.css('.ant-tabs-tab'))[2];\n      tabLabel.nativeElement.click();\n      fixture.detectChanges();\n      checkSelectedIndex(1, fixture);\n    });\n\n    it('should emit add event', () => {\n      const component = fixture.debugElement.componentInstance;\n      component.type = 'editable-card';\n      spyOn(fixture.componentInstance, 'handleAdd');\n      fixture.detectChanges();\n\n      const addButton = fixture.debugElement.query(By.css('.ant-tabs-nav-add'))!.nativeElement;\n      addButton.click();\n      fixture.detectChanges();\n\n      expect(fixture.componentInstance.handleAdd).toHaveBeenCalledTimes(1);\n    });\n\n    it('should emit close event', () => {\n      const component = fixture.debugElement.componentInstance;\n      component.type = 'editable-card';\n      component.closable = true;\n      spyOn(fixture.componentInstance, 'handleClose');\n      fixture.detectChanges();\n\n      const addButton = fixture.debugElement.queryAll(By.css('.ant-tabs-tab-remove'))[1]!.nativeElement;\n      addButton.click();\n      fixture.detectChanges();\n\n      expect(fixture.componentInstance.handleClose).toHaveBeenCalledTimes(1);\n      expect(fixture.componentInstance.handleClose).toHaveBeenCalledWith(jasmine.objectContaining({ index: 1 }));\n    });\n  });\n\n  describe('template inputs support', () => {\n    let fixture: ComponentFixture<TemplateTabsTestComponent>;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(TemplateTabsTestComponent);\n      fixture.detectChanges();\n    });\n\n    it('should set the correct title with template', () => {\n      const tabElement = fixture.debugElement.query(By.css(`.ant-tabs-tab:nth-of-type(2)`))!.nativeElement;\n      expect(tabElement.querySelector('.title')).not.toBeNull();\n    });\n\n    it('should set the correct content with template', () => {\n      const tabElement: HTMLDivElement = fixture.debugElement.query(By.css(`.ant-tabs-tabpane-active`))!.nativeElement;\n      expect(tabElement.textContent).toContain('Template Content of Tab Pane 1');\n    });\n\n    it('should set the correct close icons with template', () => {\n      const tabCloseButtons = fixture.debugElement.queryAll(By.css(`.ant-tabs-tab .ant-tabs-tab-remove`));\n      tabCloseButtons.forEach(e => {\n        const tabCloseBtnElement = e.nativeElement!;\n        expect(tabCloseBtnElement.querySelector('.close-icon')).not.toBeNull();\n        expect(tabCloseBtnElement.querySelector('.close-icon')!.textContent).toBe('x');\n      });\n    });\n\n    it('should set the correct add icons with template', () => {\n      const tabAddButton = fixture.debugElement.query(By.css(`nz-tabs-nav .ant-tabs-nav-add`))!.nativeElement;\n      expect(tabAddButton.querySelector('.add-icon')).not.toBeNull();\n      expect(tabAddButton.querySelector('.add-icon')!.textContent).toBe('+');\n    });\n  });\n\n  describe('disable', () => {\n    let fixture: ComponentFixture<DisableTabsTestComponent>;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(DisableTabsTestComponent);\n      fixture.detectChanges();\n    });\n\n    it('should have one disabled tab', () => {\n      const tabs = fixture.debugElement.queryAll(By.css('.ant-tabs-tab-disabled'));\n      expect(tabs.length).toBe(1);\n    });\n\n    it('should set the disabled flag on tab', () => {\n      const tabs = fixture.componentInstance.tabs.toArray();\n      let labels = fixture.debugElement.queryAll(By.css('.ant-tabs-tab-disabled'));\n      expect(tabs[0].nzDisabled).toBe(false);\n      expect(tabs[1].nzDisabled).toBe(false);\n      expect(labels.length).toBe(1);\n\n      fixture.componentInstance.disabled = true;\n      fixture.detectChanges();\n\n      expect(tabs[1].nzDisabled).toBe(true);\n      labels = fixture.debugElement.queryAll(By.css('.ant-tabs-tab-disabled'));\n      expect(labels.length).toBe(2);\n    });\n\n    it('should not have a close button when disabled', () => {\n      let closeButton = fixture.debugElement.query(By.css('.ant-tabs-tab-remove'));\n      expect(closeButton).not.toBeNull();\n\n      fixture.componentInstance.disabled = true;\n      fixture.detectChanges();\n\n      closeButton = fixture.debugElement.query(By.css('.ant-tabs-tab-remove'));\n      expect(closeButton).toBeNull();\n    });\n\n    it('should not change selected index on click when disabled', fakeAsync(() => {\n      const component = fixture.debugElement.componentInstance;\n      component.selectedIndex = 0;\n      fixture.detectChanges();\n\n      checkSelectedIndex(0, fixture);\n\n      let tabLabel = fixture.debugElement.queryAll(By.css('.ant-tabs-tab'))[2];\n      tabLabel.nativeElement.click();\n      fixture.detectChanges();\n      flush();\n\n      checkSelectedIndex(0, fixture);\n\n      tabLabel = fixture.debugElement.queryAll(By.css('.ant-tabs-tab'))[1];\n      tabLabel.nativeElement.click();\n      fixture.detectChanges();\n      flush();\n\n      checkSelectedIndex(1, fixture);\n\n      component.disabled = true;\n      component.selectedIndex = 0;\n      fixture.detectChanges();\n      flush();\n\n      tabLabel = fixture.debugElement.queryAll(By.css('.ant-tabs-tab'))[1];\n      tabLabel.nativeElement.click();\n      fixture.detectChanges();\n      flush();\n\n      checkSelectedIndex(0, fixture);\n    }));\n  });\n\n  describe('dynamic tabs', () => {\n    let fixture: ComponentFixture<DynamicTabsTestComponent>;\n\n    beforeEach(fakeAsync(() => {\n      fixture = TestBed.createComponent(DynamicTabsTestComponent);\n      fixture.detectChanges();\n      tick(300);\n      fixture.detectChanges();\n    }));\n\n    it('should be able to add a new tab, select it, and have correct origin position', fakeAsync(() => {\n      const component: NzTabsComponent = fixture.debugElement.query(By.css('nz-tabs'))!.componentInstance;\n\n      let tabs: NzTabComponent[] = component.tabs.toArray();\n      expect(tabs[0].origin).toBe(null);\n      expect(tabs[1].origin).toBe(0);\n      expect(tabs[2].origin).toBe(null);\n\n      // Add a new tab on the right and select it, expect an origin >= than 0 (animate right)\n      fixture.componentInstance.tabs.push({ title: 'New tab', content: 'to right of index' });\n      fixture.componentInstance.selectedIndex = 4;\n      fixture.detectChanges();\n      flush();\n\n      tabs = component.tabs.toArray();\n      expect(tabs[3].origin).toBeGreaterThanOrEqual(0);\n\n      // Add a new tab in the beginning and select it, expect an origin < than 0 (animate left)\n      fixture.componentInstance.selectedIndex = 0;\n      fixture.detectChanges();\n      flush();\n\n      fixture.componentInstance.tabs.push({ title: 'New tab', content: 'to left of index' });\n      fixture.detectChanges();\n      flush();\n\n      tabs = component.tabs.toArray();\n      expect(tabs[0].origin).toBeLessThan(0);\n    }));\n\n    it('should update selected index if the last tab removed while selected', fakeAsync(() => {\n      const component: NzTabsComponent = fixture.debugElement.query(By.css('nz-tabs'))!.componentInstance;\n\n      const numberOfTabs = component.tabs.length;\n      fixture.componentInstance.selectedIndex = numberOfTabs - 1;\n      fixture.detectChanges();\n      flush();\n\n      // Remove last tab while last tab is selected, expect the next tab over to be selected\n      fixture.componentInstance.tabs.pop();\n      fixture.detectChanges();\n      flush();\n\n      expect(component.nzSelectedIndex).toBe(numberOfTabs - 2);\n      expect(fixture.componentInstance.selectedIndex).toBe(numberOfTabs - 2);\n    }));\n\n    it('should maintain the selected tab if a new tab is added', () => {\n      fixture.detectChanges();\n      const component: NzTabsComponent = fixture.debugElement.query(By.css('nz-tabs'))!.componentInstance;\n\n      fixture.componentInstance.selectedIndex = 1;\n      fixture.detectChanges();\n\n      // Add a new tab at the beginning.\n      fixture.componentInstance.tabs.unshift({ title: 'New tab', content: 'at the start' });\n      fixture.detectChanges();\n\n      expect(component.nzSelectedIndex).toBe(2);\n      expect(component.tabs.toArray()[2].isActive).toBe(true);\n    });\n\n    it('should maintain the selected tab if a tab is removed', () => {\n      // Select the second tab.\n      fixture.componentInstance.selectedIndex = 1;\n      fixture.detectChanges();\n\n      const component: NzTabsComponent = fixture.debugElement.query(By.css('nz-tabs'))!.componentInstance;\n\n      // Remove the first tab that is right before the selected one.\n      fixture.componentInstance.tabs.splice(0, 1);\n      fixture.detectChanges();\n\n      // Since the first tab has been removed and the second one was selected before, the selected\n      // tab moved one position to the right. Meaning that the tab is now the first tab.\n      expect(component.nzSelectedIndex).toBe(0);\n      expect(component.tabs.toArray()[0].isActive).toBe(true);\n    });\n\n    it('should be able to select a new tab after creation', fakeAsync(() => {\n      fixture.detectChanges();\n      const component: NzTabsComponent = fixture.debugElement.query(By.css('nz-tabs'))!.componentInstance;\n\n      fixture.componentInstance.tabs.push({ title: 'Last tab', content: 'at the end' });\n      fixture.componentInstance.selectedIndex = 3;\n\n      fixture.detectChanges();\n      flush();\n\n      expect(component.nzSelectedIndex).toBe(3);\n      expect(component.tabs.toArray()[3].isActive).toBe(true);\n    }));\n\n    it('should not fire `selectedTabChange` when the amount of tabs changes', fakeAsync(() => {\n      fixture.detectChanges();\n      fixture.componentInstance.selectedIndex = 1;\n      fixture.detectChanges();\n\n      // Add a new tab at the beginning.\n      spyOn(fixture.componentInstance, 'handleSelection');\n      fixture.componentInstance.tabs.unshift({ title: 'New tab', content: 'at the start' });\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n\n      expect(fixture.componentInstance.handleSelection).not.toHaveBeenCalled();\n    }));\n\n    it('should show add btn after all tabs are removed', () => {\n      const component = fixture.debugElement.componentInstance;\n      component.closable = true;\n      component.type = 'editable-card';\n      fixture.detectChanges();\n      fixture.componentInstance.tabs.splice(0, component.tabs.length);\n      fixture.detectChanges();\n      const btnCount = fixture.debugElement.queryAll(By.css('.ant-tabs-nav-add')).length;\n      expect(btnCount).toBeGreaterThan(0);\n    });\n  });\n\n  describe('async tabs', () => {\n    it('should show tabs when they are available', fakeAsync(() => {\n      const fixture = TestBed.createComponent(AsyncTabsTestComponent);\n\n      expect(fixture.debugElement.queryAll(By.css('.ant-tabs-tab')).length).toBe(0);\n\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      tick(200);\n\n      expect(fixture.debugElement.queryAll(By.css('.ant-tabs-tab')).length).toBe(3);\n    }));\n  });\n\n  describe('nested tabs', () => {\n    it('should not pick up the tabs from descendant tab groups', () => {\n      const fixture = TestBed.createComponent(NestedTabsTestComponent);\n      fixture.detectChanges();\n\n      const groups = fixture.componentInstance.tabSets.toArray();\n\n      expect(groups.length).toBe(2);\n      expect(groups[0].tabs.map((tab: NzTabComponent) => tab.nzTitle)).toEqual(['Tab 0', 'Tab 1']);\n      expect(groups[1].tabs.map((tab: NzTabComponent) => tab.nzTitle)).toEqual(['Inner Tab 0', 'Inner Tab 1']);\n    });\n\n    it('should pick up indirect descendant tabs', () => {\n      const fixture = TestBed.createComponent(TabSetWithIndirectDescendantTabsTestComponent);\n      fixture.detectChanges();\n\n      const tabs = fixture.componentInstance.tabSet.tabs;\n      expect(tabs.map((tab: NzTabComponent) => tab.nzTitle)).toEqual(['Tab 0', 'Tab 1']);\n    });\n  });\n\n  describe('scrollable', () => {\n    let fixture: ComponentFixture<ScrollableTabsTestComponent>;\n    let element: HTMLElement;\n    let overlayContainerElement: HTMLElement;\n    beforeEach(fakeAsync(() => {\n      fixture = TestBed.createComponent(ScrollableTabsTestComponent);\n      element = fixture.nativeElement;\n\n      inject([OverlayContainer], (oc: OverlayContainer) => {\n        overlayContainerElement = oc.getContainerElement();\n      })();\n\n      fixture.detectChanges();\n      tick(300);\n      fixture.detectChanges();\n    }));\n\n    it('should hide the overflow tabs', () => {\n      const tabSetComponent = fixture.componentInstance.tabSet;\n      expect(tabSetComponent.tabNavBarRef.hiddenItems.length).toBeGreaterThan(0);\n      expect(element.querySelector('nz-tab-nav-operation')).not.toBeNull();\n    });\n\n    it('should get the correct outlet', fakeAsync(() => {\n      fixture.detectChanges();\n      flush(300);\n      fixture.detectChanges();\n      const inTabs = fixture.debugElement.queryAll(By.css('.ant-tabs-tab'));\n      inTabs.forEach(tab => {\n        expect(tab.nativeElement.textContent.trim()).toBe('Title in tabs');\n      });\n\n      dispatchFakeEvent(element.querySelector('nz-tab-nav-operation')!, 'mouseenter');\n      fixture.detectChanges();\n      flush(300);\n      fixture.detectChanges();\n\n      const inMenu = overlayContainerElement.querySelectorAll<HTMLLIElement>('.ant-tabs-dropdown-menu-item');\n      inMenu.forEach((tab: HTMLLIElement) => {\n        expect(tab.textContent!.trim()).toBe('Title in menu');\n      });\n    }));\n\n    it('should set transform to visible when selected invisible tab', fakeAsync(() => {\n      const tabsList = element.querySelector('.ant-tabs-nav-list')! as HTMLElement;\n      const translateX = getTranslate(tabsList.style.transform).x;\n      fixture.componentInstance.selectedIndex = 10;\n      fixture.detectChanges();\n      flush(300);\n      fixture.detectChanges();\n\n      const newTranslateX = getTranslate(tabsList.style.transform).x;\n      expect(translateX).toBeGreaterThan(newTranslateX);\n    }));\n\n    it('should handle the positions correctly', fakeAsync(() => {\n      fixture.componentInstance.position = 'left';\n      fixture.detectChanges();\n\n      const tabsList = element.querySelector('.ant-tabs-nav-list')! as HTMLElement;\n      const translateY = getTranslate(tabsList.style.transform).y;\n      const translateX = getTranslate(tabsList.style.transform).x;\n\n      expect(translateX).toBe(0);\n      expect(translateY).toBe(0);\n\n      fixture.componentInstance.selectedIndex = 15;\n      fixture.detectChanges();\n      flush(300);\n      fixture.detectChanges();\n\n      const newTranslateX = getTranslate(tabsList.style.transform).x;\n      const newTranslateY = getTranslate(tabsList.style.transform).y;\n      expect(translateX).toBe(newTranslateX);\n      expect(translateY).toBeGreaterThan(newTranslateY);\n    }));\n\n    it('should set transform to visible and select when selected on nav-operation', fakeAsync(() => {\n      spyOn(fixture.componentInstance, 'handleSelection');\n      fixture.detectChanges();\n      expect(fixture.componentInstance.handleSelection).toHaveBeenCalledTimes(0);\n\n      const tabsList = element.querySelector('.ant-tabs-nav-list')! as HTMLElement;\n      const translateX = getTranslate(tabsList.style.transform).x;\n      const navOperation = fixture.debugElement.query(By.css('nz-tab-nav-operation'))!\n        .componentInstance as NzTabNavOperationComponent;\n\n      navOperation.onSelect(navOperation.items[5]);\n\n      fixture.detectChanges();\n      flush(300);\n      fixture.detectChanges();\n\n      const newTranslateX = getTranslate(tabsList.style.transform).x;\n      expect(translateX).toBeGreaterThan(newTranslateX);\n      expect(fixture.componentInstance.handleSelection).toHaveBeenCalledTimes(1);\n    }));\n\n    it('should set transformX when scroll(mock)', fakeAsync(() => {\n      const tabNavBarComponent = fixture.debugElement.query(By.directive(NzTabNavBarComponent))!\n        .componentInstance as NzTabNavBarComponent;\n      const tabsList = element.querySelector('.ant-tabs-nav-list')! as HTMLElement;\n      let translateX = getTranslate(tabsList.style.transform).x;\n\n      expect(translateX).toBe(0);\n      expect(tabNavBarComponent).toBeDefined();\n\n      const event = {\n        x: -200,\n        y: -200,\n        event: new Event('wheel')\n      };\n\n      tabNavBarComponent.onOffsetChange(event);\n\n      fixture.detectChanges();\n      flush(300);\n      fixture.detectChanges();\n\n      translateX = getTranslate(tabsList.style.transform).x;\n      expect(translateX).toBe(-200);\n    }));\n\n    it('should set transformY when scroll(mock)', fakeAsync(() => {\n      fixture.componentInstance.position = 'left';\n      fixture.detectChanges();\n\n      const tabNavBarComponent = fixture.debugElement.query(By.directive(NzTabNavBarComponent))!\n        .componentInstance as NzTabNavBarComponent;\n      const tabsList = element.querySelector('.ant-tabs-nav-list')! as HTMLElement;\n      let translateY = getTranslate(tabsList.style.transform).y;\n\n      expect(translateY).toBe(0);\n\n      const event = {\n        x: -100,\n        y: -200,\n        event: new Event('wheel')\n      };\n\n      tabNavBarComponent.onOffsetChange(event);\n\n      fixture.detectChanges();\n      flush(300);\n      fixture.detectChanges();\n\n      translateY = getTranslate(tabsList.style.transform).y;\n      expect(translateY).toBe(-200);\n    }));\n  });\n\n  function checkSelectedIndex(expectedIndex: number, fixture: ComponentFixture<NzSafeAny>): void {\n    fixture.detectChanges();\n    const tabComponent: NzTabsComponent = fixture.debugElement.query(By.css('nz-tabs'))!.componentInstance;\n\n    expect(tabComponent.nzSelectedIndex).toBe(expectedIndex);\n\n    const tabElement = fixture.debugElement.query(\n      By.css(`.ant-tabs-tab:nth-of-type(${expectedIndex + 1})`)\n    )!.nativeElement;\n    expect(tabElement.classList.contains('ant-tabs-tab-active')).toBe(true);\n\n    const tabpaneElement: HTMLDivElement = fixture.debugElement.query(\n      By.css(`.ant-tabs-tabpane-active`)\n    )!.nativeElement;\n    expect(tabpaneElement.id.endsWith(`tab-${expectedIndex}`)).toBeTrue();\n  }\n\n  describe('router', () => {\n    let fixture: ComponentFixture<RouterTabsTestComponent>;\n    let tabs: DebugElement;\n    let router: Router;\n\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        providers: [provideNzNoAnimation(), provideNzIconsTesting(), provideRouter(routes)]\n      });\n\n      fixture = TestBed.createComponent(RouterTabsTestComponent);\n      fixture.detectChanges();\n\n      tabs = fixture.debugElement.query(By.directive(NzTabsComponent));\n    });\n\n    it('should change router and emit handleSelection once when click', fakeAsync(() => {\n      fixture.ngZone!.run(() => {\n        router = TestBed.inject(Router);\n        router.initialNavigation();\n        const component = fixture.componentInstance;\n        spyOn(component, 'handleSelection');\n        fixture.detectChanges();\n\n        expect((tabs.componentInstance as NzTabsComponent).nzSelectedIndex).toBe(0);\n        expect(component.handleSelection).toHaveBeenCalledTimes(0);\n\n        // select the second tab\n        const tabLabel = fixture.debugElement.queryAll(By.css('.ant-tabs-tab'))[1];\n        tabLabel.nativeElement.click();\n        fixture.detectChanges();\n        flush();\n\n        expect((tabs.componentInstance as NzTabsComponent).nzSelectedIndex).toBe(1);\n        expect(component.handleSelection).toHaveBeenCalledTimes(1);\n      });\n    }));\n  });\n\n  describe('rendering', () => {\n    let fixture: ComponentFixture<SimpleTabsRenderingComponent>;\n    let element: HTMLElement;\n\n    beforeEach(fakeAsync(() => {\n      fixture = TestBed.createComponent(SimpleTabsRenderingComponent);\n      element = fixture.nativeElement;\n      fixture.detectChanges();\n      tick();\n    }));\n\n    it('should delay rendering and preserve DOM of tabpane', fakeAsync(() => {\n      expect(element.querySelectorAll('.ant-tabs-tabpane').length).toBe(1);\n      fixture.componentInstance.selectedIndex = 1;\n      fixture.detectChanges();\n      tick(300);\n      expect(element.querySelectorAll('.ant-tabs-tabpane').length).toBe(2);\n      fixture.componentInstance.selectedIndex = 2;\n      fixture.detectChanges();\n      tick(300);\n      expect(element.querySelectorAll('.ant-tabs-tabpane').length).toBe(3);\n    }));\n\n    it('should render inactive tab when forceRender is true', fakeAsync(() => {\n      fixture.componentInstance.forceRender = true;\n      fixture.detectChanges();\n      tick(300);\n      expect(element.querySelectorAll('.ant-tabs-tabpane').length).toBe(3);\n    }));\n\n    it('should destroy inactive tab when destroyInactiveTabPane is true', fakeAsync(() => {\n      fixture.componentInstance.destroyInactiveTabPane = true;\n      fixture.detectChanges();\n      tick(300);\n      expect(element.querySelectorAll('.ant-tabs-tabpane').length).toBe(1);\n\n      fixture.componentInstance.selectedIndex = 1;\n      fixture.detectChanges();\n      tick(300);\n      expect(element.querySelectorAll('.ant-tabs-tabpane').length).toBe(1);\n\n      fixture.componentInstance.selectedIndex = 2;\n      fixture.detectChanges();\n      tick(300);\n      expect(element.querySelectorAll('.ant-tabs-tabpane').length).toBe(1);\n    }));\n  });\n\n  describe('dynamic router tabs', () => {\n    let fixture: ComponentFixture<DynamicRouterTabsTestComponent>;\n    let router: Router;\n\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        providers: [\n          provideRouter([\n            {\n              path: '',\n              pathMatch: 'full',\n              redirectTo: 'one'\n            },\n            {\n              path: 'one',\n              component: DynamicRouterTabsTestComponent\n            },\n            {\n              path: 'two',\n              component: DynamicRouterTabsTestComponent\n            },\n            {\n              path: 'three',\n              component: DynamicRouterTabsTestComponent\n            }\n          ])\n        ]\n      });\n\n      router = TestBed.inject(Router);\n      fixture = TestBed.createComponent(DynamicRouterTabsTestComponent);\n    });\n\n    it('should update active tab when tabs changed', fakeAsync(() => {\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n\n      router.initialNavigation();\n      tick();\n      fixture.detectChanges();\n\n      const comp = fixture.componentInstance;\n\n      router.navigate(['three']);\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n\n      comp.tabs = comp.lazyTabs;\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      tick();\n\n      expect(comp.selectedIdx).toBe(2);\n      flush();\n    }));\n  });\n\n  describe('extra content', () => {\n    it('should be possible to render additional content on both sides', () => {\n      const fixture = TestBed.createComponent(SimpleTabsWithExtraContentComponent);\n      fixture.detectChanges();\n      const tabsNav: HTMLDivElement = fixture.nativeElement.querySelector('.ant-tabs-nav');\n      expect(tabsNav.firstElementChild?.classList).toContain('ant-tabs-extra-content');\n      expect(tabsNav.firstElementChild?.textContent?.trim()).toEqual('Start Extra Action');\n      expect(tabsNav.lastElementChild?.classList).toContain('ant-tabs-extra-content');\n      expect(tabsNav.lastElementChild?.textContent?.trim()).toEqual('End Extra Action');\n    });\n  });\n\n  describe('indicator', () => {\n    let fixture: ComponentFixture<IndicatorTabsTestComponent>;\n    let element: HTMLElement;\n\n    beforeEach(fakeAsync(() => {\n      fixture = TestBed.createComponent(IndicatorTabsTestComponent);\n      element = fixture.nativeElement;\n      fixture.detectChanges();\n      tick(300);\n      fixture.detectChanges();\n    }));\n\n    it('should set indicator width and horizontal alignment', fakeAsync(() => {\n      fixture.componentInstance.indicator.set({\n        size: 20,\n        align: 'end'\n      });\n\n      fixture.detectChanges();\n      tick(300);\n      fixture.detectChanges();\n\n      const activeTab = element.querySelector('.ant-tabs-tab-active') as HTMLElement;\n      const inkBar = element.querySelector('.ant-tabs-ink-bar') as HTMLElement;\n      const expectedLeft = activeTab.offsetLeft + activeTab.offsetWidth - 20;\n\n      expect(inkBar.style.width).toBe('20px');\n      expect(parseFloat(inkBar.style.left)).toBe(expectedLeft);\n    }));\n\n    it('should update indicator style when nzIndicator changes', fakeAsync(() => {\n      fixture.componentInstance.indicator.set({\n        size: 10,\n        align: 'start'\n      });\n      fixture.detectChanges();\n      tick(300);\n      fixture.detectChanges();\n\n      const inkBar = element.querySelector('.ant-tabs-ink-bar') as HTMLElement;\n      const previousWidth = inkBar.style.width;\n      const previousLeft = inkBar.style.left;\n\n      fixture.componentInstance.indicator.set({\n        size: 30,\n        align: 'end'\n      });\n      fixture.detectChanges();\n      tick(300);\n      fixture.detectChanges();\n\n      expect(inkBar.style.width).toBe('30px');\n      expect(inkBar.style.width).not.toBe(previousWidth);\n      expect(inkBar.style.left).not.toBe(previousLeft);\n    }));\n\n    it('should set indicator height and vertical alignment', fakeAsync(() => {\n      fixture.componentInstance.position.set('left');\n      fixture.componentInstance.indicator.set({\n        size: origin => origin / 2,\n        align: 'center'\n      });\n\n      fixture.detectChanges();\n      tick(300);\n      fixture.detectChanges();\n\n      const activeTab = element.querySelector('.ant-tabs-tab-active') as HTMLElement;\n      const inkBar = element.querySelector('.ant-tabs-ink-bar') as HTMLElement;\n      const expectedHeight = activeTab.offsetHeight / 2;\n      const expectedTop = activeTab.offsetTop + (activeTab.offsetHeight - inkBar.offsetHeight) / 2;\n\n      expect(parseFloat(inkBar.style.height)).toBe(expectedHeight);\n      expect(parseFloat(inkBar.style.top)).toBe(expectedTop);\n    }));\n  });\n});\n\n@Component({\n  imports: [NzTabsModule],\n  template: `\n    <nz-tabs\n      [(nzSelectedIndex)]=\"selectedIndex\"\n      (nzSelectedIndexChange)=\"handleSelection($event)\"\n      (nzClose)=\"handleClose($event)\"\n      (nzAdd)=\"handleAdd()\"\n      [nzTabPosition]=\"position\"\n      [nzType]=\"type\"\n      [nzSize]=\"size\"\n      [nzTabBarGutter]=\"tabBarGutter\"\n      [nzTabBarStyle]=\"tabBarStyle\"\n      [nzCentered]=\"centered\"\n      [nzCanDeactivate]=\"canDeactivate\"\n      [nzTabBarExtraContent]=\"extraTemplate\"\n    >\n      <nz-tab nzTitle=\"Tab 0\" nzClosable>Content of Tab Pane 0</nz-tab>\n      <nz-tab nzTitle=\"Tab 1\" nzClosable>Content of Tab Pane 1</nz-tab>\n      <nz-tab nzTitle=\"Tab 2\">Content of Tab Pane 2</nz-tab>\n    </nz-tabs>\n    <ng-template #extraTemplate>\n      <input type=\"text\" class=\"extra-input\" />\n    </ng-template>\n  `\n})\nclass SimpleTabsTestComponent {\n  selectedIndex = 1;\n  position: NzTabPosition = 'top';\n  size: NzSizeLDSType = 'default';\n  type: NzTabType = 'line';\n  tabBarGutter?: number;\n  tabBarStyle: Record<string, string> | null = {};\n  centered = false;\n  canDeactivate = null;\n\n  handleSelection(_event: number): void {}\n\n  handleClose(_event: { index: number }): void {}\n\n  handleAdd(): void {}\n}\n\n@Component({\n  imports: [NzTabsModule],\n  template: `\n    <nz-tabs [(nzSelectedIndex)]=\"selectedIndex\" [nzDestroyInactiveTabPane]=\"destroyInactiveTabPane\">\n      <nz-tab nzTitle=\"Tab 0\" [nzForceRender]=\"forceRender\">Content of Tab Pane 0</nz-tab>\n      <nz-tab nzTitle=\"Tab 1\" [nzForceRender]=\"forceRender\">Content of Tab Pane 1</nz-tab>\n      <nz-tab nzTitle=\"Tab 2\" [nzForceRender]=\"forceRender\">Content of Tab Pane 2</nz-tab>\n    </nz-tabs>\n  `\n})\nclass SimpleTabsRenderingComponent {\n  selectedIndex = 0;\n  forceRender = false;\n  destroyInactiveTabPane = false;\n}\n\n@Component({\n  imports: [NzTabsModule],\n  template: `\n    <nz-tabs nzType=\"editable-card\" [(nzSelectedIndex)]=\"selectedIndex\" [nzAddIcon]=\"addTemplate\">\n      <nz-tab nzTitle=\"Tab 0\">Content of Tab Pane 0</nz-tab>\n      <nz-tab nzClosable [nzTitle]=\"titleTemplate\" [nzCloseIcon]=\"closeIconTemplate\">\n        <ng-template nz-tab>\n          <span class=\"content\">Template Content of Tab Pane 1</span>\n        </ng-template>\n      </nz-tab>\n    </nz-tabs>\n\n    <ng-template #titleTemplate>\n      <span class=\"title\">Template Title</span>\n    </ng-template>\n    <ng-template #closeIconTemplate>\n      <span class=\"close-icon\">x</span>\n    </ng-template>\n    <ng-template #addTemplate>\n      <span class=\"add-icon\">+</span>\n    </ng-template>\n  `\n})\nclass TemplateTabsTestComponent {\n  selectedIndex = 1;\n}\n\n@Component({\n  imports: [NzTabsModule],\n  template: `\n    <nz-tabs\n      nzType=\"editable-card\"\n      [(nzSelectedIndex)]=\"selectedIndex\"\n      (nzSelectedIndexChange)=\"handleSelection($event)\"\n    >\n      <nz-tab nzTitle=\"Tab 0\">Content of Tab Pane 0</nz-tab>\n      <nz-tab nzTitle=\"Tab 1\" nzClosable [nzDisabled]=\"disabled\">Content of Tab Pane 1</nz-tab>\n      <nz-tab nzTitle=\"Tab 2\" nzDisabled>Content of Tab Pane 2</nz-tab>\n    </nz-tabs>\n  `\n})\nclass DisableTabsTestComponent {\n  selectedIndex = 1;\n  disabled = false;\n  @ViewChildren(NzTabComponent) tabs!: QueryList<NzTabComponent>;\n\n  handleSelection(_event: number): void {}\n}\n\n@Component({\n  imports: [NzTabsModule],\n  template: `\n    <nz-tabs\n      [(nzSelectedIndex)]=\"selectedIndex\"\n      nzType=\"editable-card\"\n      (nzSelectedIndexChange)=\"handleSelection($event)\"\n    >\n      @for (tab of tabs; track tab) {\n        <nz-tab [nzTitle]=\"tab.title\">\n          {{ tab.content }}\n        </nz-tab>\n      }\n    </nz-tabs>\n  `\n})\nclass DynamicTabsTestComponent {\n  selectedIndex = 1;\n  tabs = [\n    { title: 'Tab 0', content: 'Content of Tab Pane 0' },\n    { title: 'Tab 1', content: 'Content of Tab Pane 1' },\n    { title: 'Tab 2', content: 'Content of Tab Pane 2' }\n  ];\n\n  handleSelection(_event: number): void {}\n}\n\n@Component({\n  imports: [NzTabsModule],\n  template: `\n    <div style=\"width: 200px; height: 200px\">\n      <nz-tabs\n        style=\"width: 200px; height: 200px\"\n        [(nzSelectedIndex)]=\"selectedIndex\"\n        (nzSelectedIndexChange)=\"handleSelection($event)\"\n        [nzTabPosition]=\"position\"\n      >\n        @for (_tab of tabs; track $index) {\n          <nz-tab [nzTitle]=\"titleTemplate\">\n            <ng-template #titleTemplate let-visible=\"visible\">Title in {{ visible ? 'tabs' : 'menu' }}</ng-template>\n            Content of Tab Pane {{ $index }}\n          </nz-tab>\n        }\n      </nz-tabs>\n    </div>\n  `,\n  encapsulation: ViewEncapsulation.None,\n  styles: `\n    @import '../style/testing.less';\n    @import '../style/entry.less';\n    @import './style/entry.less';\n  `\n})\nclass ScrollableTabsTestComponent {\n  selectedIndex = 0;\n  position: NzTabPosition = 'top';\n  tabs: NzSafeAny[] = Array(30).fill(null);\n  @ViewChild(NzTabsComponent, { static: true }) tabSet!: NzTabsComponent;\n\n  handleSelection(_event: number): void {}\n}\n\n@Component({\n  imports: [AsyncPipe, NzTabsModule],\n  template: `\n    <nz-tabs>\n      @for (tab of tabs | async; track tab) {\n        <nz-tab [nzTitle]=\"tab.title\">\n          {{ tab.content }}\n        </nz-tab>\n      }\n    </nz-tabs>\n  `\n})\nclass AsyncTabsTestComponent implements OnInit {\n  tabs!: Observable<Array<{ title: string; content: string }>>;\n\n  ngOnInit(): void {\n    this.tabs = new Observable(observer => {\n      setTimeout(() =>\n        observer.next([\n          { title: 'Tab 0', content: 'Content of Tab Pane 0' },\n          { title: 'Tab 1', content: 'Content of Tab Pane 1' },\n          { title: 'Tab 2', content: 'Content of Tab Pane 2' }\n        ])\n      );\n    });\n  }\n}\n\n@Component({\n  imports: [NzTabsModule],\n  template: `\n    <nz-tabs>\n      <nz-tab nzTitle=\"Tab 0\">Content of Tab Pane 0</nz-tab>\n      <nz-tab nzTitle=\"Tab 1\">\n        Content of Tab Pane 1\n        <nz-tabs>\n          <nz-tab nzTitle=\"Inner Tab 0\">Inner Content of Tab Pane 0</nz-tab>\n          <nz-tab nzTitle=\"Inner Tab 1\">Inner Content of Tab Pane 1</nz-tab>\n        </nz-tabs>\n      </nz-tab>\n    </nz-tabs>\n  `\n})\nclass NestedTabsTestComponent {\n  @ViewChildren(NzTabsComponent) tabSets!: QueryList<NzTabsComponent>;\n}\n\n@Component({\n  imports: [NzTabsModule],\n  template: `\n    <nz-tabs>\n      @if (true) {\n        <ng-container>\n          <nz-tab nzTitle=\"Tab 0\">Tab one content</nz-tab>\n          @if (true) {\n            <ng-container>\n              <nz-tab nzTitle=\"Tab 1\">Tab two content</nz-tab>\n            </ng-container>\n          }\n        </ng-container>\n      }\n    </nz-tabs>\n  `\n})\nclass TabSetWithIndirectDescendantTabsTestComponent {\n  @ViewChild(NzTabsComponent, { static: true }) tabSet!: NzTabsComponent;\n}\n\n@Component({\n  imports: [RouterLink, RouterOutlet, NzTabsModule],\n  template: `\n    <nz-tabs nzLinkRouter (nzSelectedIndexChange)=\"handleSelection($event)\">\n      <nz-tab nzTitle=\"default\">\n        <a *nzTabLink nz-tab-link [routerLink]=\"['.']\">One</a>\n        One\n      </nz-tab>\n      <nz-tab nzTitle=\"two\">\n        <a *nzTabLink nz-tab-link [routerLink]=\"['.', 'two']\">Two</a>\n        Two\n      </nz-tab>\n    </nz-tabs>\n    <router-outlet />\n  `\n})\nexport class RouterTabsTestComponent {\n  handleSelection(_event: number): void {}\n}\n\n@Component({\n  template: `\n    <nz-tabs nzLinkRouter [(nzSelectedIndex)]=\"selectedIdx\" [nzLinkExact]=\"false\">\n      @for (tab of tabs; track tab.title) {\n        <nz-tab>\n          <a *nzTabLink nz-tab-link [routerLink]=\"tab.route\">{{ tab.title }}</a>\n          {{ tab.title }}\n        </nz-tab>\n      }\n    </nz-tabs>\n    <router-outlet />\n  `,\n  imports: [RouterLink, RouterOutlet, NzTabsModule]\n})\nexport class DynamicRouterTabsTestComponent {\n  selectedIdx = 0;\n  tabs = [\n    {\n      title: 'one',\n      route: ['one']\n    },\n    {\n      title: 'two',\n      route: ['two']\n    }\n  ];\n  readonly lazyTabs = [\n    ...this.tabs,\n    {\n      title: 'three',\n      route: ['three']\n    }\n  ];\n}\n\nconst routes: Routes = [\n  {\n    path: '',\n    component: RouterTabsTestComponent,\n    data: {\n      path: ''\n    }\n  },\n  {\n    path: 'two',\n    component: RouterTabsTestComponent,\n    data: {\n      path: 'two'\n    }\n  }\n];\n\nfunction getTranslate(transformValue: string): { x: number; y: number } {\n  const match = transformValue.match(/translate\\((-*[0-9]+px), (-*[0-9]+px)\\)/);\n  return {\n    x: match && match[1] ? Number.parseFloat(match[1]) : 0,\n    y: match && match[2] ? Number.parseFloat(match[2]) : 0\n  };\n}\n\n@Component({\n  imports: [NzTabsModule],\n  template: `\n    <nz-tabs [(nzSelectedIndex)]=\"selectedIndex\">\n      <button *nzTabBarExtraContent=\"'start'\">Start Extra Action</button>\n      <button *nzTabBarExtraContent=\"'end'\">End Extra Action</button>\n\n      <nz-tab nzTitle=\"Tab 0\">Content of Tab Pane 0</nz-tab>\n      <nz-tab nzTitle=\"Tab 1\">Content of Tab Pane 1</nz-tab>\n      <nz-tab nzTitle=\"Tab 2\">Content of Tab Pane 2</nz-tab>\n    </nz-tabs>\n  `\n})\nclass SimpleTabsWithExtraContentComponent {\n  selectedIndex = 0;\n}\n\n@Component({\n  imports: [NzTabsModule],\n  template: `\n    <nz-tabs [nzTabPosition]=\"position()\" [nzIndicator]=\"indicator()\" [(nzSelectedIndex)]=\"selectedIndex\">\n      <nz-tab nzTitle=\"Tab 0\">Content of Tab Pane 0</nz-tab>\n      <nz-tab nzTitle=\"Tab 1\">Content of Tab Pane 1</nz-tab>\n      <nz-tab nzTitle=\"Tab 2\">Content of Tab Pane 2</nz-tab>\n    </nz-tabs>\n  `\n})\nclass IndicatorTabsTestComponent {\n  readonly selectedIndex = signal(1);\n  readonly position = signal<NzTabPosition>('top');\n  readonly indicator = signal<NzIndicator | undefined>(undefined);\n}\n"
  },
  {
    "path": "components/tabs/tabs.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { A11yModule } from '@angular/cdk/a11y';\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport { coerceNumberProperty } from '@angular/cdk/coercion';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterContentChecked,\n  AfterContentInit,\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  contentChildren,\n  ContentChildren,\n  DestroyRef,\n  EventEmitter,\n  forwardRef,\n  inject,\n  input,\n  Input,\n  NgZone,\n  OnInit,\n  Output,\n  QueryList,\n  TemplateRef,\n  ViewChild,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { NavigationEnd, Router, RouterLink } from '@angular/router';\nimport { merge, Observable, of, Subscription } from 'rxjs';\nimport { delay, filter, first, startWith } from 'rxjs/operators';\n\nimport { NzConfigKey, NzConfigService, WithConfig } from 'ng-zorro-antd/core/config';\nimport { PREFIX } from 'ng-zorro-antd/core/logger';\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzSafeAny, NzSizeLDSType } from 'ng-zorro-antd/core/types';\nimport { wrapIntoObservable } from 'ng-zorro-antd/core/util';\n\nimport {\n  NzAnimatedInterface,\n  NzTabChangeEvent,\n  NzTabPosition,\n  NzTabPositionMode,\n  NzTabsCanDeactivateFn,\n  NzTabScrollEvent,\n  NzTabType,\n  type NzIndicator\n} from './interfaces';\nimport { NzTabBarExtraContentDirective } from './tab-bar-extra-content.directive';\nimport { NzTabBodyComponent } from './tab-body.component';\nimport { NzTabCloseButtonComponent } from './tab-close-button.component';\nimport { NzTabLinkDirective } from './tab-link.directive';\nimport { NzTabNavBarComponent } from './tab-nav-bar.component';\nimport { NzTabNavItemDirective } from './tab-nav-item.directive';\nimport { NZ_TAB_SET, NzTabComponent } from './tab.component';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'tabs';\n\nlet nextId = 0;\n\n@Component({\n  selector: 'nz-tabs',\n  exportAs: 'nzTabs',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.Default,\n  providers: [\n    {\n      provide: NZ_TAB_SET,\n      useExisting: forwardRef(() => NzTabsComponent)\n    }\n  ],\n  template: `\n    @if (tabs.length || addable) {\n      <nz-tabs-nav\n        [style]=\"nzTabBarStyle\"\n        [selectedIndex]=\"nzSelectedIndex || 0\"\n        [inkBarAnimated]=\"inkBarAnimated\"\n        [addable]=\"addable\"\n        [addIcon]=\"nzAddIcon\"\n        [hideBar]=\"nzHideAll\"\n        [position]=\"position\"\n        [extraTemplate]=\"nzTabBarExtraContent\"\n        [extraContents]=\"extraContents()\"\n        [indicator]=\"nzIndicator()\"\n        (tabScroll)=\"nzTabListScroll.emit($event)\"\n        (selectFocusedIndex)=\"setSelectedIndex($event)\"\n        (addClicked)=\"onAdd()\"\n      >\n        @for (tab of tabs; track tab) {\n          <div\n            class=\"ant-tabs-tab\"\n            [style.margin-right.px]=\"position === 'horizontal' ? nzTabBarGutter : null\"\n            [style.margin-bottom.px]=\"position === 'vertical' ? nzTabBarGutter : null\"\n            [class.ant-tabs-tab-active]=\"nzSelectedIndex === $index\"\n            [class.ant-tabs-tab-disabled]=\"tab.nzDisabled\"\n            (click)=\"clickNavItem(tab, $index, $event)\"\n            (contextmenu)=\"contextmenuNavItem(tab, $event)\"\n          >\n            <button\n              type=\"button\"\n              role=\"tab\"\n              [id]=\"getTabContentId($index)\"\n              [attr.tabIndex]=\"getTabIndex(tab, $index)\"\n              [attr.aria-disabled]=\"tab.nzDisabled\"\n              [attr.aria-selected]=\"nzSelectedIndex === $index && !nzHideAll\"\n              [attr.aria-controls]=\"getTabContentId($index)\"\n              [disabled]=\"tab.nzDisabled\"\n              [tab]=\"tab\"\n              [active]=\"nzSelectedIndex === $index\"\n              class=\"ant-tabs-tab-btn\"\n              nzTabNavItem\n              cdkMonitorElementFocus\n            >\n              <ng-container *nzStringTemplateOutlet=\"tab.label; context: { visible: true }\">\n                {{ tab.label }}\n              </ng-container>\n              @if (tab.nzClosable && closable && !tab.nzDisabled) {\n                <button\n                  type=\"button\"\n                  nz-tab-close-button\n                  [closeIcon]=\"tab.nzCloseIcon\"\n                  (click)=\"onClose($index, $event)\"\n                ></button>\n              }\n            </button>\n          </div>\n        }\n      </nz-tabs-nav>\n    }\n    <div class=\"ant-tabs-content-holder\">\n      <div\n        class=\"ant-tabs-content\"\n        [class.ant-tabs-content-top]=\"nzTabPosition === 'top'\"\n        [class.ant-tabs-content-bottom]=\"nzTabPosition === 'bottom'\"\n        [class.ant-tabs-content-left]=\"nzTabPosition === 'left'\"\n        [class.ant-tabs-content-right]=\"nzTabPosition === 'right'\"\n        [class.ant-tabs-content-animated]=\"tabPaneAnimated\"\n      >\n        @if (!nzHideAll) {\n          @for (tab of tabs; track tab) {\n            @if (tab.nzForceRender) {\n              <ng-template [ngTemplateOutlet]=\"tabpaneTmpl\" />\n            } @else if (nzDestroyInactiveTabPane) {\n              @if (nzSelectedIndex === $index) {\n                <ng-template [ngTemplateOutlet]=\"tabpaneTmpl\" />\n              }\n            } @else {\n              @if (nzSelectedIndex === $index || tab.hasBeenActive) {\n                <ng-template [ngTemplateOutlet]=\"tabpaneTmpl\" />\n              }\n            }\n\n            <ng-template #tabpaneTmpl>\n              <div\n                role=\"tabpanel\"\n                [id]=\"getTabContentId($index)\"\n                [attr.aria-labelledby]=\"getTabContentId($index)\"\n                nz-tab-body\n                [active]=\"nzSelectedIndex === $index\"\n                [content]=\"tab.content\"\n                [animated]=\"tabPaneAnimated\"\n              ></div>\n            </ng-template>\n          }\n        }\n      </div>\n    </div>\n  `,\n  host: {\n    class: 'ant-tabs',\n    '[class.ant-tabs-card]': `nzType === 'card' || nzType === 'editable-card'`,\n    '[class.ant-tabs-editable]': `nzType === 'editable-card'`,\n    '[class.ant-tabs-editable-card]': `nzType === 'editable-card'`,\n    '[class.ant-tabs-centered]': `nzCentered`,\n    '[class.ant-tabs-rtl]': `dir === 'rtl'`,\n    '[class.ant-tabs-top]': `nzTabPosition === 'top'`,\n    '[class.ant-tabs-bottom]': `nzTabPosition === 'bottom'`,\n    '[class.ant-tabs-left]': `nzTabPosition === 'left'`,\n    '[class.ant-tabs-right]': `nzTabPosition === 'right'`,\n    '[class.ant-tabs-default]': `nzSize === 'default'`,\n    '[class.ant-tabs-small]': `nzSize === 'small'`,\n    '[class.ant-tabs-large]': `nzSize === 'large'`\n  },\n  imports: [\n    NzTabNavBarComponent,\n    NgTemplateOutlet,\n    NzTabNavItemDirective,\n    A11yModule,\n    NzOutletModule,\n    NzTabCloseButtonComponent,\n    NzTabBodyComponent\n  ]\n})\nexport class NzTabsComponent implements OnInit, AfterContentChecked, AfterContentInit {\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  public nzConfigService = inject(NzConfigService);\n  private ngZone = inject(NgZone);\n  private cdr = inject(ChangeDetectorRef);\n  private directionality = inject(Directionality);\n  private destroyRef = inject(DestroyRef);\n\n  @Input()\n  get nzSelectedIndex(): number | null {\n    return this.selectedIndex;\n  }\n  set nzSelectedIndex(value: null | number) {\n    this.indexToSelect = coerceNumberProperty(value, null);\n  }\n  @Input() nzTabPosition: NzTabPosition = 'top';\n  @Input() nzTabBarExtraContent?: TemplateRef<void>;\n  @Input() nzCanDeactivate: NzTabsCanDeactivateFn | null = null;\n  @Input() nzAddIcon: string | TemplateRef<NzSafeAny> = 'plus';\n  @Input() nzTabBarStyle: Record<string, string> | null = null;\n  @Input() @WithConfig() nzType: NzTabType = 'line';\n  @Input() @WithConfig() nzSize: NzSizeLDSType = 'default';\n  @Input() @WithConfig() nzAnimated: NzAnimatedInterface | boolean = true;\n  @Input() @WithConfig() nzTabBarGutter?: number = undefined;\n  @Input({ transform: booleanAttribute }) nzHideAdd: boolean = false;\n  @Input({ transform: booleanAttribute }) nzCentered: boolean = false;\n  @Input({ transform: booleanAttribute }) nzHideAll = false;\n  @Input({ transform: booleanAttribute }) nzLinkRouter = false;\n  @Input({ transform: booleanAttribute }) nzLinkExact = true;\n  @Input({ transform: booleanAttribute }) nzDestroyInactiveTabPane = false;\n\n  readonly nzIndicator = input<NzIndicator>();\n\n  @Output() readonly nzSelectChange: EventEmitter<NzTabChangeEvent> = new EventEmitter<NzTabChangeEvent>(true);\n  @Output() readonly nzSelectedIndexChange: EventEmitter<number> = new EventEmitter<number>();\n  @Output() readonly nzTabListScroll = new EventEmitter<NzTabScrollEvent>();\n  @Output() readonly nzClose = new EventEmitter<{ index: number }>();\n  @Output() readonly nzAdd = new EventEmitter<void>();\n\n  get position(): NzTabPositionMode {\n    return ['top', 'bottom'].indexOf(this.nzTabPosition) === -1 ? 'vertical' : 'horizontal';\n  }\n\n  get addable(): boolean {\n    return this.nzType === 'editable-card' && !this.nzHideAdd;\n  }\n\n  get closable(): boolean {\n    return this.nzType === 'editable-card';\n  }\n\n  get line(): boolean {\n    return this.nzType === 'line';\n  }\n\n  get inkBarAnimated(): boolean {\n    return this.line && (typeof this.nzAnimated === 'boolean' ? this.nzAnimated : this.nzAnimated.inkBar);\n  }\n\n  get tabPaneAnimated(): boolean {\n    return typeof this.nzAnimated === 'boolean' ? this.nzAnimated : this.nzAnimated.tabPane;\n  }\n\n  // Pick up only direct descendants under ivy rendering engine\n  // We filter out only the tabs that belong to this tab set in `tabs`.\n  @ContentChildren(NzTabComponent, { descendants: true })\n  allTabs: QueryList<NzTabComponent> = new QueryList<NzTabComponent>();\n\n  @ContentChildren(NzTabLinkDirective, { descendants: true })\n  tabLinks: QueryList<NzTabLinkDirective> = new QueryList<NzTabLinkDirective>();\n  @ViewChild(NzTabNavBarComponent, { static: false }) tabNavBarRef!: NzTabNavBarComponent;\n  // All the direct tabs for this tab set\n  tabs: QueryList<NzTabComponent> = new QueryList<NzTabComponent>();\n\n  readonly extraContents = contentChildren(NzTabBarExtraContentDirective);\n\n  dir: Direction = 'ltr';\n  private readonly tabSetId!: number;\n  private indexToSelect: number | null = 0;\n  private selectedIndex: number | null = null;\n  private tabLabelSubscription = Subscription.EMPTY;\n  private canDeactivateSubscription = Subscription.EMPTY;\n  private router = inject(Router, { optional: true });\n\n  constructor() {\n    this.tabSetId = nextId++;\n\n    this.destroyRef.onDestroy(() => {\n      this.tabs.destroy();\n      this.tabLabelSubscription.unsubscribe();\n      this.canDeactivateSubscription.unsubscribe();\n    });\n  }\n\n  ngOnInit(): void {\n    this.dir = this.directionality.value;\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n      this.dir = direction;\n      this.cdr.detectChanges();\n    });\n  }\n\n  ngAfterContentInit(): void {\n    this.ngZone.runOutsideAngular(() => {\n      Promise.resolve().then(() => this.setUpRouter());\n    });\n\n    this.subscribeToTabLabels();\n    this.subscribeToAllTabChanges();\n\n    // Subscribe to changes of the number of tabs, to be\n    // able to re-render the content as new tabs are added or removed.\n    this.tabs.changes.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      const indexToSelect = this.clampTabIndex(this.indexToSelect);\n\n      // Maintain the previously selected tab if a new tab is added or removed, and there is no\n      // explicit change that selects a different tab.\n      if (indexToSelect === this.selectedIndex) {\n        const tabs = this.tabs.toArray();\n\n        for (let i = 0; i < tabs.length; i++) {\n          if (tabs[i].isActive) {\n            // Assign both to the `indexToSelect` and `selectedIndex` so we don't fire a changed\n            // event, otherwise the consumer may end up in an infinite loop in some edge cases like\n            // adding a tab within the `nzSelectedIndexChange` event.\n            this.indexToSelect = this.selectedIndex = i;\n            break;\n          }\n        }\n      }\n      this.subscribeToTabLabels();\n      this.cdr.markForCheck();\n    });\n  }\n\n  ngAfterContentChecked(): void {\n    // Don't clamp the `indexToSelect` immediately in the setter because it can happen that\n    // the amount of tabs changes before the actual change detection runs.\n    const indexToSelect = (this.indexToSelect = this.clampTabIndex(this.indexToSelect));\n\n    // If there is a change in the selected index, emit a change event. Should not trigger if\n    // the selected index has not yet been initialized.\n    if (this.selectedIndex !== indexToSelect) {\n      const isFirstRun = this.selectedIndex == null;\n\n      if (!isFirstRun) {\n        this.nzSelectChange.emit(this.createChangeEvent(indexToSelect));\n      }\n\n      // Changing these values after change detection has run\n      // since the checked content may contain references to them.\n      Promise.resolve().then(() => {\n        this.tabs.forEach((tab, index) => tab.setActive(index === indexToSelect));\n\n        if (!isFirstRun) {\n          this.nzSelectedIndexChange.emit(indexToSelect);\n        }\n      });\n    }\n\n    // Set up the position for each tab and optionally set up an origin on the next selected tab.\n    this.tabs.forEach((tab, index) => {\n      tab.position = index - indexToSelect;\n\n      // If there is already a selected tab, then set up an origin for the next selected tab\n      // if it doesn't have one already.\n      if (this.selectedIndex != null && tab.position === 0 && !tab.origin) {\n        tab.origin = indexToSelect - this.selectedIndex;\n      }\n    });\n\n    if (this.selectedIndex !== indexToSelect) {\n      this.selectedIndex = indexToSelect;\n      this.cdr.markForCheck();\n    }\n  }\n\n  onClose(index: number, e: MouseEvent): void {\n    e.preventDefault();\n    e.stopPropagation();\n    this.nzClose.emit({ index });\n  }\n\n  onAdd(): void {\n    this.nzAdd.emit();\n  }\n\n  private clampTabIndex(index: number | null): number {\n    return Math.min(this.tabs.length - 1, Math.max(index || 0, 0));\n  }\n\n  private createChangeEvent(index: number): NzTabChangeEvent {\n    const event = new NzTabChangeEvent();\n    event.index = index;\n    if (this.tabs && this.tabs.length) {\n      event.tab = this.tabs.toArray()[index];\n      this.tabs.forEach((tab, i) => {\n        if (i !== index) {\n          tab.nzDeselect.emit();\n        }\n      });\n      event.tab.nzSelect.emit();\n    }\n    return event;\n  }\n\n  private subscribeToTabLabels(): void {\n    if (this.tabLabelSubscription) {\n      this.tabLabelSubscription.unsubscribe();\n    }\n\n    this.tabLabelSubscription = merge(...this.tabs.map(tab => tab.stateChanges)).subscribe(() =>\n      this.cdr.markForCheck()\n    );\n  }\n\n  private subscribeToAllTabChanges(): void {\n    this.allTabs.changes.pipe(startWith(this.allTabs)).subscribe((tabs: QueryList<NzTabComponent>) => {\n      this.tabs.reset(tabs.filter(tab => tab.closestTabSet === this));\n      this.tabs.notifyOnChanges();\n    });\n  }\n\n  canDeactivateFun(pre: number, next: number): Observable<boolean> {\n    if (typeof this.nzCanDeactivate === 'function') {\n      const observable = wrapIntoObservable(this.nzCanDeactivate(pre, next));\n      return observable.pipe(first(), takeUntilDestroyed(this.destroyRef));\n    } else {\n      return of(true);\n    }\n  }\n\n  clickNavItem(tab: NzTabComponent, index: number, e: MouseEvent): void {\n    if (!tab.nzDisabled) {\n      // ignore nzCanDeactivate\n      tab.nzClick.emit();\n      if (!this.isRouterLinkClickEvent(index, e)) {\n        this.setSelectedIndex(index);\n      }\n    }\n  }\n\n  private isRouterLinkClickEvent(index: number, event: MouseEvent): boolean {\n    const target = event.target as HTMLElement;\n    if (this.nzLinkRouter) {\n      return !!this.tabs.toArray()[index]?.linkDirective?.elementRef.nativeElement.contains(target);\n    } else {\n      return false;\n    }\n  }\n\n  contextmenuNavItem(tab: NzTabComponent, e: MouseEvent): void {\n    if (!tab.nzDisabled) {\n      // ignore nzCanDeactivate\n      tab.nzContextmenu.emit(e);\n    }\n  }\n\n  setSelectedIndex(index: number): void {\n    this.canDeactivateSubscription.unsubscribe();\n    this.canDeactivateSubscription = this.canDeactivateFun(this.selectedIndex!, index).subscribe(can => {\n      if (can) {\n        this.nzSelectedIndex = index;\n        this.tabNavBarRef.focusIndex = index;\n        this.cdr.markForCheck();\n      }\n    });\n  }\n\n  getTabIndex(tab: NzTabComponent, index: number): number | null {\n    if (tab.nzDisabled) {\n      return null;\n    }\n    return this.selectedIndex === index ? 0 : -1;\n  }\n\n  getTabContentId(i: number): string {\n    return `nz-tabs-${this.tabSetId}-tab-${i}`;\n  }\n\n  private setUpRouter(): void {\n    if (this.nzLinkRouter) {\n      if (!this.router) {\n        throw new Error(`${PREFIX} you should import 'RouterModule' if you want to use 'nzLinkRouter'!`);\n      }\n      merge(this.router.events.pipe(filter(e => e instanceof NavigationEnd)), this.tabLinks.changes)\n        .pipe(startWith(true), delay(0), takeUntilDestroyed(this.destroyRef))\n        .subscribe(() => {\n          this.updateRouterActive();\n          this.cdr.markForCheck();\n        });\n    }\n  }\n\n  private updateRouterActive(): void {\n    if (this.router?.navigated) {\n      const index = this.findShouldActiveTabIndex();\n      if (index !== this.selectedIndex) {\n        this.setSelectedIndex(index);\n      }\n      Promise.resolve().then(() => (this.nzHideAll = index === -1));\n    }\n  }\n\n  private findShouldActiveTabIndex(): number {\n    const tabs = this.tabs.toArray();\n    const isActive = this.isLinkActive(this.router);\n\n    return tabs.findIndex(tab => {\n      const c = tab.linkDirective;\n      return c ? isActive(c.routerLink) : false;\n    });\n  }\n\n  private isLinkActive(router: Router | null): (link?: RouterLink | null) => boolean {\n    return (link?: RouterLink | null) =>\n      link\n        ? !!router?.isActive(link.urlTree || '', {\n            paths: this.nzLinkExact ? 'exact' : 'subset',\n            queryParams: this.nzLinkExact ? 'exact' : 'subset',\n            fragment: 'ignored',\n            matrixParams: 'ignored'\n          })\n        : false;\n  }\n}\n"
  },
  {
    "path": "components/tabs/tabs.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzTabAddButtonComponent } from './tab-add-button.component';\nimport { NzTabBarExtraContentDirective } from './tab-bar-extra-content.directive';\nimport { NzTabBodyComponent } from './tab-body.component';\nimport { NzTabCloseButtonComponent } from './tab-close-button.component';\nimport { NzTabLinkDirective, NzTabLinkTemplateDirective } from './tab-link.directive';\nimport { NzTabNavBarComponent } from './tab-nav-bar.component';\nimport { NzTabNavItemDirective } from './tab-nav-item.directive';\nimport { NzTabNavOperationComponent } from './tab-nav-operation.component';\nimport { NzTabScrollListDirective } from './tab-scroll-list.directive';\nimport { NzTabComponent } from './tab.component';\nimport { NzTabDirective } from './tab.directive';\nimport { NzTabsInkBarDirective } from './tabs-ink-bar.directive';\nimport { NzTabsComponent } from './tabs.component';\n\nconst DIRECTIVES = [\n  NzTabsComponent,\n  NzTabComponent,\n  NzTabNavBarComponent,\n  NzTabNavItemDirective,\n  NzTabsInkBarDirective,\n  NzTabScrollListDirective,\n  NzTabNavOperationComponent,\n  NzTabAddButtonComponent,\n  NzTabCloseButtonComponent,\n  NzTabDirective,\n  NzTabBodyComponent,\n  NzTabLinkDirective,\n  NzTabLinkTemplateDirective,\n  NzTabBarExtraContentDirective\n];\n\n@NgModule({\n  imports: [DIRECTIVES],\n  exports: [DIRECTIVES]\n})\nexport class NzTabsModule {}\n"
  },
  {
    "path": "components/tag/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n基本标签的用法，可以通过添加 `nzMode=\"closeable\"` 变为可关闭标签。可关闭标签具有 `nzOnClose` 事件。\n\n## en-US\n\nUsage of basic Tag, and it could be closeable by set `nzMode=\"closeable\"` property. Closeable Tag supports `nzOnClose` events.\n"
  },
  {
    "path": "components/tag/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTagModule } from 'ng-zorro-antd/tag';\n\n@Component({\n  selector: 'nz-demo-tag-basic',\n  imports: [NzTagModule],\n  template: `\n    <nz-tag>Tag 1</nz-tag>\n    <nz-tag>\n      <a href=\"https://github.com/NG-ZORRO/ng-zorro-antd\">Link</a>\n    </nz-tag>\n    <nz-tag nzMode=\"closeable\" (nzOnClose)=\"onClose()\">Tag 2</nz-tag>\n    <nz-tag nzMode=\"closeable\" (nzOnClose)=\"preventDefault($event)\">Prevent Default</nz-tag>\n  `\n})\nexport class NzDemoTagBasicComponent {\n  onClose(): void {\n    console.log('tag was closed.');\n  }\n\n  preventDefault(e: Event): void {\n    e.preventDefault();\n    e.stopPropagation();\n    console.log('tag can not be closed.');\n  }\n}\n"
  },
  {
    "path": "components/tag/demo/borderless.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 无边框\n  en-US: Borderless\n---\n\n## zh-CN\n\n无边框模式。\n\n## en-US\n\nborderless.\n"
  },
  {
    "path": "components/tag/demo/borderless.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { presetColors } from 'ng-zorro-antd/core/color';\nimport { NzTagModule } from 'ng-zorro-antd/tag';\n\n@Component({\n  selector: 'nz-demo-tag-borderless',\n  imports: [NzTagModule],\n  template: `\n    @for (color of tagColors; track color) {\n      <nz-tag [nzColor]=\"color\" [nzBordered]=\"false\">{{ color }}</nz-tag>\n    }\n  `\n})\nexport class NzDemoTagBorderlessComponent {\n  readonly tagColors = presetColors;\n}\n"
  },
  {
    "path": "components/tag/demo/checkable.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 可选择\n  en-US: Checkable\n---\n\n## zh-CN\n\n可通过 `nzMode=\"checkable\"` 实现类似 Checkbox 的效果，点击切换选中效果。\n\n## en-US\n\n`nzMode=\"checkable\"` works like Checkbox, click it to toggle checked state.\n"
  },
  {
    "path": "components/tag/demo/checkable.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTagModule } from 'ng-zorro-antd/tag';\n\n@Component({\n  selector: 'nz-demo-tag-checkable',\n  imports: [NzTagModule],\n  template: `\n    <nz-tag nzMode=\"checkable\" [nzChecked]=\"true\" (nzCheckedChange)=\"checkChange($event)\">Tag1</nz-tag>\n    <nz-tag nzMode=\"checkable\" [nzChecked]=\"true\" (nzCheckedChange)=\"checkChange($event)\">Tag2</nz-tag>\n    <nz-tag nzMode=\"checkable\" [nzChecked]=\"true\" (nzCheckedChange)=\"checkChange($event)\">Tag3</nz-tag>\n  `\n})\nexport class NzDemoTagCheckableComponent {\n  checkChange(e: boolean): void {\n    console.log(e);\n  }\n}\n"
  },
  {
    "path": "components/tag/demo/colorful.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 多彩标签\n  en-US: Colorful Tag\n---\n\n## zh-CN\n\n我们添加了多种预设色彩的标签样式，用作不同场景使用。如果预设值不能满足你的需求，可以设置为具体的色值。\n\n## en-US\n\nWe preset a series of colorful tag style for different situation usage.\nAnd you can always set it to a hex color string for custom color.\n"
  },
  {
    "path": "components/tag/demo/colorful.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { presetColors } from 'ng-zorro-antd/core/color';\nimport { NzTagModule } from 'ng-zorro-antd/tag';\n\n@Component({\n  selector: 'nz-demo-tag-colorful',\n  imports: [NzTagModule],\n  template: `\n    <h4 style=\"margin-bottom: 16px\">Presets:</h4>\n    <div>\n      @for (color of presetColors; track color) {\n        <nz-tag [nzColor]=\"color\">{{ color }}</nz-tag>\n      }\n    </div>\n    <h4 style=\"margin: 16px 0\">Custom:</h4>\n    <div>\n      @for (color of customColors; track color) {\n        <nz-tag [nzColor]=\"color\">{{ color }}</nz-tag>\n      }\n    </div>\n  `,\n  styles: `\n    .ant-tag {\n      margin-bottom: 8px;\n    }\n  `\n})\nexport class NzDemoTagColorfulComponent {\n  readonly presetColors = presetColors;\n  readonly customColors = ['#f50', '#2db7f5', '#87d068', '#108ee9'];\n}\n"
  },
  {
    "path": "components/tag/demo/control.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 动态添加和删除\n  en-US: Add & Remove Dynamically\n---\n\n## zh-CN\n\n用数组生成一组标签，可以动态添加和删除。\n\n## en-US\n\nGenerating a set of Tags by array, you can add and remove dynamically.\n"
  },
  {
    "path": "components/tag/demo/control.ts",
    "content": "import { Component, ElementRef, ViewChild } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzNoAnimationDirective } from 'ng-zorro-antd/core/animation';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzTagModule } from 'ng-zorro-antd/tag';\n\n@Component({\n  selector: 'nz-demo-tag-control',\n  imports: [FormsModule, NzIconModule, NzInputModule, NzTagModule, NzNoAnimationDirective],\n  template: `\n    @for (tag of tags; track tag) {\n      <nz-tag [nzMode]=\"$first ? 'default' : 'closeable'\" (nzOnClose)=\"handleClose(tag)\">\n        {{ sliceTagName(tag) }}\n      </nz-tag>\n    }\n\n    @if (!inputVisible) {\n      <nz-tag class=\"editable-tag\" nzNoAnimation (click)=\"showInput()\">\n        <nz-icon nzType=\"plus\" />\n        New Tag\n      </nz-tag>\n    } @else {\n      <input\n        #inputElement\n        nz-input\n        nzSize=\"small\"\n        type=\"text\"\n        [(ngModel)]=\"inputValue\"\n        style=\"width: 78px;\"\n        (blur)=\"handleInputConfirm()\"\n        (keydown.enter)=\"handleInputConfirm()\"\n      />\n    }\n  `,\n  styles: `\n    .editable-tag {\n      background: rgb(255, 255, 255);\n      border-style: dashed;\n    }\n  `\n})\nexport class NzDemoTagControlComponent {\n  tags = ['Unremovable', 'Tag 2', 'Tag 3'];\n  inputVisible = false;\n  inputValue = '';\n  @ViewChild('inputElement', { static: false }) inputElement?: ElementRef;\n\n  handleClose(removedTag: {}): void {\n    this.tags = this.tags.filter(tag => tag !== removedTag);\n  }\n\n  sliceTagName(tag: string): string {\n    const isLongTag = tag.length > 20;\n    return isLongTag ? `${tag.slice(0, 20)}...` : tag;\n  }\n\n  showInput(): void {\n    this.inputVisible = true;\n    setTimeout(() => {\n      this.inputElement?.nativeElement.focus();\n    }, 10);\n  }\n\n  handleInputConfirm(): void {\n    if (this.inputValue && this.tags.indexOf(this.inputValue) === -1) {\n      this.tags = [...this.tags, this.inputValue];\n    }\n    this.inputValue = '';\n    this.inputVisible = false;\n  }\n}\n"
  },
  {
    "path": "components/tag/demo/hot-tags.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 热门标签\n  en-US: Hot Tags\n---\n\n## zh-CN\n\n选择你感兴趣的话题。\n\n## en-US\n\nSelect your favourite topics.\n"
  },
  {
    "path": "components/tag/demo/hot-tags.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTagModule } from 'ng-zorro-antd/tag';\n\nconst tagsFromServer = ['Movie', 'Books', 'Music', 'Sports'];\n\n@Component({\n  selector: 'nz-demo-tag-hot-tags',\n  imports: [NzTagModule],\n  template: `\n    <strong>Categories:</strong>\n    @for (tag of hotTags; track $index) {\n      <nz-tag\n        nzMode=\"checkable\"\n        [nzChecked]=\"selectedTags.indexOf(tag) > -1\"\n        (nzCheckedChange)=\"handleChange($event, tag)\"\n      >\n        {{ tag }}\n      </nz-tag>\n    }\n  `\n})\nexport class NzDemoTagHotTagsComponent {\n  hotTags = tagsFromServer;\n  selectedTags: string[] = [];\n\n  handleChange(checked: boolean, tag: string): void {\n    if (checked) {\n      this.selectedTags.push(tag);\n    } else {\n      this.selectedTags = this.selectedTags.filter(t => t !== tag);\n    }\n    console.log('You are interested in: ', this.selectedTags);\n  }\n}\n"
  },
  {
    "path": "components/tag/demo/icon.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 图标按钮\n  en-US: Icon\n---\n\n## zh-CN\n\n在 tag 组件内嵌入 icon。\n\n## en-US\n\nTag components can contain an icon.\n"
  },
  {
    "path": "components/tag/demo/icon.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzTagModule } from 'ng-zorro-antd/tag';\n\n@Component({\n  selector: 'nz-demo-tag-icon',\n  imports: [NzIconModule, NzTagModule],\n  template: `\n    <nz-tag nzColor=\"#55acee\">\n      <nz-icon nzType=\"twitter\" />\n      <span>Twitter</span>\n    </nz-tag>\n    <nz-tag nzColor=\"#cd201f\">\n      <nz-icon nzType=\"youtube\" />\n      <span>Youtube</span>\n    </nz-tag>\n    <nz-tag nzColor=\"#3b5999\">\n      <nz-icon nzType=\"facebook\" />\n      <span>Facebook</span>\n    </nz-tag>\n    <nz-tag nzColor=\"#55acee\">\n      <nz-icon nzType=\"linkedin\" />\n      <span>LinkedIn</span>\n    </nz-tag>\n  `\n})\nexport class NzDemoTagIconComponent {}\n"
  },
  {
    "path": "components/tag/demo/status.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 预设状态的标签\n  en-US: Status Tag\n---\n\n## zh-CN\n\n预设五种状态颜色，可以通过设置 `nzColor` 为 `success`、 `processing`、`error`、`default`、`warning` 来代表不同的状态。\n\n## en-US\n\nWe preset five different colors, you can set `nzColor` property such as `success`,`processing`,`error`,`default` and `warning` to indicate specific status.\n"
  },
  {
    "path": "components/tag/demo/status.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzTagModule } from 'ng-zorro-antd/tag';\n\n@Component({\n  selector: 'nz-demo-tag-status',\n  imports: [NzIconModule, NzTagModule],\n  template: `\n    <div>\n      <h4>Without icon</h4>\n      <nz-tag nzColor=\"success\">success</nz-tag>\n      <nz-tag nzColor=\"processing\">processing</nz-tag>\n      <nz-tag nzColor=\"error\">error</nz-tag>\n      <nz-tag nzColor=\"warning\">warning</nz-tag>\n      <nz-tag nzColor=\"default\">default</nz-tag>\n    </div>\n    <div>\n      <h4>With icon</h4>\n      <nz-tag nzColor=\"success\">\n        <nz-icon nzType=\"check-circle\" />\n        <span>success</span>\n      </nz-tag>\n      <nz-tag nzColor=\"processing\">\n        <nz-icon nzType=\"sync\" nzSpin />\n        <span>processing</span>\n      </nz-tag>\n      <nz-tag nzColor=\"error\">\n        <nz-icon nzType=\"close-circle\" />\n        <span>error</span>\n      </nz-tag>\n      <nz-tag nzColor=\"warning\">\n        <nz-icon nzType=\"exclamation-circle\" />\n        <span>warning</span>\n      </nz-tag>\n      <nz-tag nzColor=\"default\">\n        <nz-icon nzType=\"clock-circle\" />\n        <span>default</span>\n      </nz-tag>\n    </div>\n  `\n})\nexport class NzDemoTagStatusComponent {}\n"
  },
  {
    "path": "components/tag/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Display\ntitle: Tag\ncover: 'https://gw.alipayobjects.com/zos/alicdn/cH1BOLfxC/Tag.svg'\ndescription: Used for marking and categorization.\n---\n\n## When To Use\n\n- It can be used to tag by dimension or property.\n\n- When categorizing.\n\n## API\n\n### nz-tag\n\n| Property            | Description                                                                 | Type                                      | Default     |\n| ------------------- | --------------------------------------------------------------------------- | ----------------------------------------- | ----------- |\n| `[nzMode]`          | Mode of tag                                                                 | `'closeable' \\| 'default' \\| 'checkable'` | `'default'` |\n| `[nzChecked]`       | Checked status of Tag, double binding, only works when `nzMode=\"checkable\"` | `boolean`                                 | `false`     |\n| `[nzColor]`         | Color of the Tag                                                            | `string`                                  | -           |\n| `[nzBordered]`      | Whether has border style                                                    | `boolean`                                 | `true`      |\n| `(nzOnClose)`       | Callback executed when tag is closed, only works when `nzMode=\"closable\"`   | `EventEmitter<MouseEvent>`                | -           |\n| `(nzCheckedChange)` | Checked status change call back, only works when `nzMode=\"checkable\"`       | `EventEmitter<boolean>`                   | -           |\n"
  },
  {
    "path": "components/tag/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 标签\ntype: 数据展示\ntitle: Tag\ncover: 'https://gw.alipayobjects.com/zos/alicdn/cH1BOLfxC/Tag.svg'\ndescription: 进行标记和分类的小标签。\n---\n\n## 何时使用\n\n- 用于标记事物的属性和维度。\n- 进行分类。\n\n## API\n\n### nz-tag\n\n| 参数                | 说明                                                           | 类型                                      | 默认值      |\n| ------------------- | -------------------------------------------------------------- | ----------------------------------------- | ----------- |\n| `[nzMode]`          | 设定标签工作的模式                                             | `'closeable' \\| 'default' \\| 'checkable'` | `'default'` |\n| `[nzChecked]`       | 设置标签的选中状态，可双向绑定，在 `nzMode=\"checkable\"` 时可用 | `boolean`                                 | `false`     |\n| `[nzColor]`         | 标签色                                                         | `string`                                  | -           |\n| `[nzBordered]`      | 是否有边框                                                     | `boolean`                                 | `true`      |\n| `(nzOnClose)`       | 关闭时的回调，在 `nzMode=\"closable\"` 时可用                    | `EventEmitter<MouseEvent>`                | -           |\n| `(nzCheckedChange)` | 设置标签的选中状态的回调，在 `nzMode=\"checkable\"` 时可用       | `EventEmitter<void>`                      | -           |\n"
  },
  {
    "path": "components/tag/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/tag/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/tag/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './tag.component';\nexport * from './tag.module';\nexport * from './typings';\n"
  },
  {
    "path": "components/tag/style/entry.less",
    "content": "@import './index.less';\n@import './patch.less';\n"
  },
  {
    "path": "components/tag/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@tag-prefix-cls: ~'@{ant-prefix}-tag';\n\n.@{tag-prefix-cls} {\n  .reset-component();\n\n  display: inline-block;\n  height: auto;\n  margin-right: 8px;\n  padding: 0 7px;\n  font-size: @tag-font-size;\n  line-height: @tag-line-height;\n  white-space: nowrap;\n  background: @tag-default-bg;\n  border: @border-width-base @border-style-base @border-color-base;\n  border-radius: @tag-border-radius;\n  opacity: 1;\n  transition: all 0.3s;\n\n  &,\n  a,\n  a:hover {\n    color: @tag-default-color;\n  }\n\n  > a:first-child:last-child {\n    display: inline-block;\n    margin: 0 -8px;\n    padding: 0 8px;\n  }\n\n  &-close-icon {\n    margin-left: 3px;\n    color: @text-color-secondary;\n    font-size: 10px;\n    cursor: pointer;\n    transition: all 0.3s;\n\n    &:hover {\n      color: @heading-color;\n    }\n  }\n\n  &-has-color {\n    border-color: transparent;\n    &,\n    a,\n    a:hover,\n    .@{iconfont-css-prefix}-close,\n    .@{iconfont-css-prefix}-close:hover {\n      color: @text-color-inverse;\n    }\n  }\n\n  &-checkable {\n    background-color: transparent;\n    border-color: transparent;\n    cursor: pointer;\n\n    &:not(&-checked):hover {\n      color: @primary-color;\n    }\n\n    &:active,\n    &-checked {\n      color: @text-color-inverse;\n    }\n\n    &-checked {\n      background-color: @primary-6;\n    }\n\n    &:active {\n      background-color: @primary-7;\n    }\n  }\n\n  &-hidden {\n    display: none;\n  }\n\n  // mixin to iterate over colors and create CSS class for each one\n  .make-color-classes(@i: length(@preset-colors)) when (@i > 0) {\n    .make-color-classes(@i - 1);\n    @color: extract(@preset-colors, @i);\n    @lightColor: '@{color}-1';\n    @lightBorderColor: '@{color}-3';\n    @darkColor: '@{color}-6';\n    @textColor: '@{color}-7';\n    &-@{color} {\n      color: @@textColor;\n      background: @@lightColor;\n      border-color: @@lightBorderColor;\n    }\n    &-@{color}-inverse {\n      color: @text-color-inverse;\n      background: @@darkColor;\n      border-color: @@darkColor;\n    }\n  }\n\n  .make-status-color-classes(@status, @cssVariableType) {\n    @bgColor: '@{cssVariableType}-color-deprecated-bg';\n    @borderColor: '@{cssVariableType}-color-deprecated-border';\n    @textColor: '@{cssVariableType}-color';\n    &-@{status} {\n      color: @@textColor;\n      background: @@bgColor;\n      border-color: @@borderColor;\n    }\n  }\n\n  .make-color-classes();\n\n  .make-status-color-classes(success, success);\n  .make-status-color-classes(processing, info);\n  .make-status-color-classes(error, error);\n  .make-status-color-classes(warning, warning);\n\n  // To ensure that a space will be placed between character and `Icon`.\n  > .@{iconfont-css-prefix} + span,\n  > span + .@{iconfont-css-prefix} {\n    margin-left: 7px;\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/tag/style/patch.less",
    "content": ".@{tag-prefix-cls} {\n  // This is a feature of Antd 5, so we need add in the patch file.\n  &&-borderless {\n    border-color: transparent;\n  }\n}\n"
  },
  {
    "path": "components/tag/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@tag-prefix-cls: ~'@{ant-prefix}-tag';\n\n.@{tag-prefix-cls} {\n  &&-rtl {\n    margin-right: 0;\n    margin-left: 8px;\n    direction: rtl;\n    text-align: right;\n  }\n\n  &-close-icon {\n    .@{tag-prefix-cls}-rtl & {\n      margin-right: 3px;\n      margin-left: 0;\n    }\n  }\n\n  > .@{iconfont-css-prefix} + span,\n  > span + .@{iconfont-css-prefix} {\n    .@{tag-prefix-cls}-rtl& {\n      margin-right: 7px;\n      margin-left: 0;\n    }\n  }\n}\n"
  },
  {
    "path": "components/tag/tag.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport {\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DestroyRef,\n  ElementRef,\n  EventEmitter,\n  inject,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  Renderer2,\n  SimpleChanges,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { isPresetColor, isStatusColor, presetColors, statusColors } from 'ng-zorro-antd/core/color';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nimport { NzTagColor } from './typings';\n\n@Component({\n  selector: 'nz-tag',\n  exportAs: 'nzTag',\n  template: `\n    <ng-content />\n    @if (nzMode === 'closeable') {\n      <nz-icon nzType=\"close\" class=\"ant-tag-close-icon\" tabindex=\"-1\" (click)=\"closeTag($event)\" />\n    }\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  host: {\n    class: 'ant-tag',\n    '[style.background-color]': `isPresetColor ? '' : nzColor`,\n    '[class.ant-tag-has-color]': `nzColor && !isPresetColor`,\n    '[class.ant-tag-checkable]': `nzMode === 'checkable'`,\n    '[class.ant-tag-checkable-checked]': `nzChecked`,\n    '[class.ant-tag-rtl]': `dir === 'rtl'`,\n    '[class.ant-tag-borderless]': `!nzBordered`,\n    '(click)': 'updateCheckedStatus()'\n  },\n  imports: [NzIconModule]\n})\nexport class NzTagComponent implements OnChanges, OnInit {\n  private cdr = inject(ChangeDetectorRef);\n  private renderer = inject(Renderer2);\n  private el: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement;\n  private directionality = inject(Directionality);\n  private destroyRef = inject(DestroyRef);\n\n  @Input() nzMode: 'default' | 'closeable' | 'checkable' = 'default';\n  @Input() nzColor?: NzTagColor;\n  @Input({ transform: booleanAttribute }) nzChecked = false;\n  @Input({ transform: booleanAttribute }) nzBordered = true;\n  @Output() readonly nzOnClose = new EventEmitter<MouseEvent>();\n  @Output() readonly nzCheckedChange = new EventEmitter<boolean>();\n  dir: Direction = 'ltr';\n  isPresetColor = false;\n\n  updateCheckedStatus(): void {\n    if (this.nzMode === 'checkable') {\n      this.nzChecked = !this.nzChecked;\n      this.nzCheckedChange.emit(this.nzChecked);\n    }\n  }\n\n  closeTag(e: MouseEvent): void {\n    this.nzOnClose.emit(e);\n    if (!e.defaultPrevented) {\n      this.renderer.removeChild(this.renderer.parentNode(this.el), this.el);\n    }\n  }\n\n  private clearPresetColor(): void {\n    // /(ant-tag-(?:pink|red|...))/g\n    const regexp = new RegExp(`(ant-tag-(?:${[...presetColors, ...statusColors].join('|')}))`, 'g');\n    const classname = this.el.classList.toString();\n    const matches: string[] = [];\n    let match: RegExpExecArray | null = regexp.exec(classname);\n    while (match !== null) {\n      matches.push(match[1]);\n      match = regexp.exec(classname);\n    }\n    this.el.classList.remove(...matches);\n  }\n\n  private setPresetColor(): void {\n    this.clearPresetColor();\n    if (!this.nzColor) {\n      this.isPresetColor = false;\n    } else {\n      this.isPresetColor = isPresetColor(this.nzColor) || isStatusColor(this.nzColor);\n    }\n    if (this.isPresetColor) {\n      this.el.classList.add(`ant-tag-${this.nzColor}`);\n    }\n  }\n\n  ngOnInit(): void {\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n      this.dir = direction;\n      this.cdr.detectChanges();\n    });\n\n    this.dir = this.directionality.value;\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzColor } = changes;\n    if (nzColor) {\n      this.setPresetColor();\n    }\n  }\n}\n"
  },
  {
    "path": "components/tag/tag.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzTagComponent } from './tag.component';\n\n@NgModule({\n  imports: [NzTagComponent],\n  exports: [NzTagComponent]\n})\nexport class NzTagModule {}\n"
  },
  {
    "path": "components/tag/tag.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Direction } from '@angular/cdk/bidi';\nimport { Component, DebugElement, provideZoneChangeDetection } from '@angular/core';\nimport { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { NzTagComponent } from './tag.component';\nimport { NzTagModule } from './tag.module';\n\ndescribe('tag', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), provideZoneChangeDetection()]\n    });\n  });\n\n  describe('basic tag', () => {\n    let fixture: ComponentFixture<NzTestTagBasicComponent>;\n    let testComponent: NzTestTagBasicComponent;\n    let tag: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTagBasicComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n      tag = fixture.debugElement.query(By.directive(NzTagComponent));\n    });\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n      expect(tag.nativeElement.classList).toContain('ant-tag');\n    });\n\n    it('should checkable work', () => {\n      fixture.detectChanges();\n      expect(tag.nativeElement.classList).not.toContain('ant-tag-checkable');\n      testComponent.mode = 'checkable';\n      fixture.detectChanges();\n      expect(testComponent.checked).toBe(false);\n      expect(testComponent.checkedChange).toHaveBeenCalledTimes(0);\n      expect(tag.nativeElement.classList).toContain('ant-tag-checkable');\n      expect(tag.nativeElement.classList).not.toContain('ant-tag-checkable-checked');\n      tag.nativeElement.click();\n      fixture.detectChanges();\n      expect(testComponent.checked).toBe(true);\n      expect(testComponent.checkedChange).toHaveBeenCalledTimes(1);\n      expect(tag.nativeElement.classList).toContain('ant-tag-checkable');\n      expect(tag.nativeElement.classList).toContain('ant-tag-checkable-checked');\n    });\n\n    it('should closeable work', fakeAsync(() => {\n      fixture.detectChanges();\n      expect(tag.nativeElement.querySelector('.anticon-close')).toBeNull();\n      testComponent.mode = 'closeable';\n      fixture.detectChanges();\n      expect(tag.nativeElement.querySelector('.anticon-close')).toBeDefined();\n      tag.nativeElement.querySelector('.anticon-close').click();\n      fixture.detectChanges();\n      expect(testComponent.onClose).toHaveBeenCalledTimes(1);\n      tick(1000);\n      fixture.detectChanges();\n      expect(fixture.nativeElement.querySelector('nz-tag')).toBeFalsy();\n    }));\n\n    it('should color work', () => {\n      fixture.detectChanges();\n      expect(tag.nativeElement.classList).not.toContain('ant-tag-has-color');\n      testComponent.color = 'green';\n      fixture.detectChanges();\n      expect(tag.nativeElement.classList).toContain('ant-tag-green');\n      testComponent.color = '#f50';\n      fixture.detectChanges();\n      expect(tag.nativeElement.classList).not.toContain('ant-tag-green');\n      expect(tag.nativeElement.style.backgroundColor).toBe('rgb(255, 85, 0)');\n      testComponent.color = 'green';\n      fixture.detectChanges();\n      expect(tag.nativeElement.classList).toContain('ant-tag-green');\n      expect(tag.nativeElement.style.backgroundColor).toBe('');\n    });\n\n    it('should status color work', () => {\n      fixture.detectChanges();\n      testComponent.color = 'success';\n      fixture.detectChanges();\n      expect(tag.nativeElement.classList).toContain('ant-tag-success');\n      testComponent.color = 'processing';\n      fixture.detectChanges();\n      expect(tag.nativeElement.classList).toContain('ant-tag-processing');\n      testComponent.color = 'invalid';\n      fixture.detectChanges();\n      expect(tag.nativeElement.classList).not.toContain('ant-tag-invalid');\n    });\n\n    // https://github.com/NG-ZORRO/ng-zorro-antd/issues/1176\n    it('should nzColor accept empty string', () => {\n      testComponent.color = 'green';\n      fixture.detectChanges();\n      expect(tag.nativeElement.classList).toContain('ant-tag-green');\n      testComponent.color = '';\n      fixture.detectChanges();\n      expect(tag.nativeElement.classList).not.toContain('ant-tag-has-color');\n      testComponent.color = undefined;\n      fixture.detectChanges();\n      expect(tag.nativeElement.classList).not.toContain('ant-tag-has-color');\n    });\n\n    it('should have bordered by default', () => {\n      expect(tag.nativeElement.classList).not.toContain('ant-tag-borderless');\n      testComponent.bordered = false;\n      fixture.detectChanges();\n      expect(tag.nativeElement.classList).toContain('ant-tag-borderless');\n    });\n  });\n\n  describe('prevent tag', () => {\n    let fixture: ComponentFixture<NzTestTagPreventComponent>;\n    let tag: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTagPreventComponent);\n      fixture.detectChanges();\n      tag = fixture.debugElement.query(By.directive(NzTagComponent));\n    });\n\n    it('should close prevent default', fakeAsync(() => {\n      fixture.detectChanges();\n      expect(tag.nativeElement.querySelector('.anticon-close')).toBeDefined();\n      tag.nativeElement.querySelector('.anticon-close').click();\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n      expect(tag.nativeElement.querySelector('.anticon-close')).toBeDefined();\n    }));\n  });\n\n  describe('RTL', () => {\n    it('should className correct on dir change', () => {\n      const fixture = TestBed.createComponent(NzTestTagRtlComponent);\n      const tag = fixture.debugElement.query(By.directive(NzTagComponent));\n      fixture.detectChanges();\n      expect(tag.nativeElement.className).toContain('ant-tag-rtl');\n\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n      expect(tag.nativeElement.className).not.toContain('ant-tag-rtl');\n    });\n  });\n});\n\n@Component({\n  imports: [NzTagModule],\n  selector: 'nz-test-basic-tag',\n  template: `\n    <nz-tag\n      [nzMode]=\"mode\"\n      [(nzChecked)]=\"checked\"\n      [nzColor]=\"color\"\n      [nzBordered]=\"bordered\"\n      (nzCheckedChange)=\"checkedChange($event)\"\n      (nzOnClose)=\"onClose()\"\n    >\n      Tag 1\n    </nz-tag>\n  `\n})\nexport class NzTestTagBasicComponent {\n  mode: 'default' | 'closeable' | 'checkable' = 'default';\n  color: string | undefined;\n  checked = false;\n  bordered = true;\n  onClose = jasmine.createSpy('on close');\n  afterClose = jasmine.createSpy('after close');\n  checkedChange = jasmine.createSpy('after close');\n}\n\n@Component({\n  imports: [NzTagModule],\n  template: `<nz-tag nzMode=\"closeable\" (nzOnClose)=\"onClose($event)\">Tag 1</nz-tag>`\n})\nexport class NzTestTagPreventComponent {\n  onClose(e: MouseEvent): void {\n    e.preventDefault();\n  }\n}\n\n@Component({\n  imports: [BidiModule, NzTestTagBasicComponent],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-test-basic-tag />\n    </div>\n  `\n})\nexport class NzTestTagRtlComponent {\n  direction: Direction = 'rtl';\n}\n"
  },
  {
    "path": "components/tag/typings.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzPresetColor, NzStatusColor } from 'ng-zorro-antd/core/color';\n\nexport type NzTagColor = NzPresetColor | NzStatusColor | (string & {});\n"
  },
  {
    "path": "components/test.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\n// eslint-disable-next-line import/no-unassigned-import\nimport 'zone.js/testing';\nimport { getTestBed } from '@angular/core/testing';\nimport { BrowserTestingModule, platformBrowserTesting } from '@angular/platform-browser/testing';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ndeclare const __karma__: any;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any, unused-imports/no-unused-vars\ndeclare const require: any;\n\n\n// First, initialize the Angular testing environment.\ngetTestBed().initTestEnvironment(BrowserTestingModule, platformBrowserTesting(), {\n  teardown: { destroyAfterEach: false }\n});\njasmine.getEnv().allowRespy(true);\n\n\n"
  },
  {
    "path": "components/time-picker/demo/addon.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 附加内容\n  en-US: Addon\n---\n\n## zh-CN\n\n在 `nz-time-picker` 选择框底部显示自定义的内容。\n\n## en-US\n\nRender addon contents to `nz-time-picker` panel's bottom.\n"
  },
  {
    "path": "components/time-picker/demo/addon.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzTimePickerModule } from 'ng-zorro-antd/time-picker';\n\n@Component({\n  selector: 'nz-demo-time-picker-addon',\n  imports: [FormsModule, NzButtonModule, NzTimePickerModule],\n  template: `\n    <nz-time-picker [(ngModel)]=\"time\" [nzAddOn]=\"addOnTemplate\" #timePicker />\n    <ng-template #addOnTemplate>\n      <button nz-button nzSize=\"small\" nzType=\"primary\" (click)=\"timePicker.close()\">Ok</button>\n    </ng-template>\n  `\n})\nexport class NzDemoTimePickerAddonComponent {\n  time: Date | null = null;\n}\n"
  },
  {
    "path": "components/time-picker/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n点击 `nz-time-picker`，然后可以在浮层中选择或者输入某一时间。\n\n## en-US\n\nClick `nz-time-picker`, and then we could select or input a time in panel.\n"
  },
  {
    "path": "components/time-picker/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzTimePickerModule } from 'ng-zorro-antd/time-picker';\n\n@Component({\n  selector: 'nz-demo-time-picker-basic',\n  imports: [FormsModule, NzTimePickerModule],\n  template: `<nz-time-picker [(ngModel)]=\"time\" [nzDefaultOpenValue]=\"defaultOpenValue\" />`\n})\nexport class NzDemoTimePickerBasicComponent {\n  time: Date | null = null;\n  defaultOpenValue = new Date(0, 0, 0, 0, 0, 0);\n}\n"
  },
  {
    "path": "components/time-picker/demo/confirmation.md",
    "content": "---\norder: 11\nversion: 21.1.0\ntitle:\n  zh-CN: 选择确认\n  en-US: Need Confirm\n---\n\n## zh-CN\n\nTimePicker 默认会根据 picker 的交互行为，自动选择是否需要确认按钮。你也可以通过 `nzNeedConfirm` 属性来手动设置是否需要确认按钮。当有 `nzNeedConfirm` 时，用户始终需要点击确认按钮才能完成选择。反之，则会在选择或者失去焦点时提交。\n\n## en-US\n\nTimePicker will automatically determine whether to show a confirm button according to the `picker` property. You can also set the `nzNeedConfirm` property to determine whether to show a confirm button. When `nzNeedConfirm` is set, the user must click the confirm button to complete the selection. Otherwise, the selection will be submitted when the picker loses focus or select a time.\n"
  },
  {
    "path": "components/time-picker/demo/confirmation.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTimePickerModule } from 'ng-zorro-antd/time-picker';\n\n@Component({\n  selector: 'nz-demo-time-picker-confirmation',\n  imports: [NzTimePickerModule],\n  template: ` <nz-time-picker nzNeedConfirm />`\n})\nexport class NzDemoTimePickerConfirmationComponent {}\n"
  },
  {
    "path": "components/time-picker/demo/disabled-part.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 禁用部分\n  en-US: disabled part\n---\n\n## zh-CN\n\n禁用部分时间选择。\n\n## en-US\n\nTo specify the hours|minutes|seconds that cannot be selected\n"
  },
  {
    "path": "components/time-picker/demo/disabled-part.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTimePickerModule } from 'ng-zorro-antd/time-picker';\n\n@Component({\n  selector: 'nz-demo-time-picker-disabled-part',\n  imports: [NzTimePickerModule],\n  template: `\n    <nz-time-picker\n      [nzDisabledHours]=\"disabledHours\"\n      [nzDisabledMinutes]=\"disabledMinutes\"\n      [nzDisabledSeconds]=\"disabledSeconds\"\n    />\n  `\n})\nexport class NzDemoTimePickerDisabledPartComponent {\n  disabledHours(): number[] {\n    return [1, 2, 3];\n  }\n\n  disabledMinutes(hour: number): number[] {\n    if (hour === 4) {\n      return [20, 21, 22, 23, 24, 25];\n    } else {\n      return [];\n    }\n  }\n\n  disabledSeconds(hour: number, minute: number): number[] {\n    if (hour === 5 && minute === 1) {\n      return [20, 21, 22, 23, 24, 25];\n    } else {\n      return [];\n    }\n  }\n}\n"
  },
  {
    "path": "components/time-picker/demo/disabled.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 禁用\n  en-US: disabled\n---\n\n## zh-CN\n\n禁用时间选择。\n\n## en-US\n\nA disabled state of the `nz-time-picker`.\n"
  },
  {
    "path": "components/time-picker/demo/disabled.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTimePickerModule } from 'ng-zorro-antd/time-picker';\n\n@Component({\n  selector: 'nz-demo-time-picker-disabled',\n  imports: [NzTimePickerModule],\n  template: `<nz-time-picker nzDisabled />`\n})\nexport class NzDemoTimePickerDisabledComponent {}\n"
  },
  {
    "path": "components/time-picker/demo/hide-column.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 选择时分\n  en-US: Hour and minute\n---\n\n## zh-CN\n\n`nz-time-picker` 浮层中的列会随着 `nzFormat` 变化，当略去 `nzFormat` 中的某部分时，浮层中对应的列也会消失。\n\n## en-US\n\nWhile part of `nzFormat` is omitted, the corresponding column in panel will disappear, too.\n"
  },
  {
    "path": "components/time-picker/demo/hide-column.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzTimePickerModule } from 'ng-zorro-antd/time-picker';\n\n@Component({\n  selector: 'nz-demo-time-picker-hide-column',\n  imports: [FormsModule, NzTimePickerModule],\n  template: `<nz-time-picker [(ngModel)]=\"time\" nzFormat=\"HH:mm\" />`\n})\nexport class NzDemoTimePickerHideColumnComponent {\n  time = new Date();\n}\n"
  },
  {
    "path": "components/time-picker/demo/interval-options.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 步长选项\n  en-US: interval option\n---\n\n## zh-CN\n\n可以使用 `nzHourStep` `nzMinuteStep` `nzSecondStep` 按步长展示可选的时分秒。\n\n## en-US\n\nShow stepped options by `nzHourStep` `nzMinuteStep` `nzSecondStep`.\n"
  },
  {
    "path": "components/time-picker/demo/interval-options.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTimePickerModule } from 'ng-zorro-antd/time-picker';\n\n@Component({\n  selector: 'nz-demo-time-picker-interval-options',\n  imports: [NzTimePickerModule],\n  template: `<nz-time-picker [nzMinuteStep]=\"15\" [nzSecondStep]=\"10\" />`\n})\nexport class NzDemoTimePickerIntervalOptionsComponent {}\n"
  },
  {
    "path": "components/time-picker/demo/placement.md",
    "content": "---\norder: 12\nversion: 21.1.0\ntitle:\n  zh-CN: 自定义位置\n  en-US: Placement\n---\n\n## zh-CN\n\n可以通过 `nzPlacement` 手动指定弹出的位置。\n\n## en-US\n\nYou can manually specify the position of the popup via `nzPlacement`.\n"
  },
  {
    "path": "components/time-picker/demo/placement.ts",
    "content": "import { Component, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport type { NzPlacement } from 'ng-zorro-antd/core/types';\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\nimport { NzTimePickerModule } from 'ng-zorro-antd/time-picker';\n\n@Component({\n  selector: 'nz-demo-time-picker-placement',\n  imports: [FormsModule, NzTimePickerModule, NzRadioModule],\n  template: `\n    <nz-radio-group [(ngModel)]=\"placement\">\n      <label nz-radio-button nzValue=\"bottomLeft\">bottomLeft</label>\n      <label nz-radio-button nzValue=\"bottomRight\">bottomRight</label>\n      <label nz-radio-button nzValue=\"topLeft\">topLeft</label>\n      <label nz-radio-button nzValue=\"topRight\">topRight</label>\n    </nz-radio-group>\n    <br />\n    <br />\n    <nz-time-picker [nzPlacement]=\"placement()\" />\n    <br />\n  `,\n  styles: `\n    nz-time-picker {\n      margin: 0 8px 12px 0;\n    }\n  `\n})\nexport class NzDemoTimePickerPlacementComponent {\n  readonly placement = signal<NzPlacement>('bottomLeft');\n}\n"
  },
  {
    "path": "components/time-picker/demo/prefix-suffix.md",
    "content": "---\norder: 0\nversion: 21.1.0\ntitle:\n  zh-CN: 前后缀\n  en-US: Prefix and Suffix\n---\n\n## zh-CN\n\n自定义前缀 `nzPrefix` 和后缀图标 `nzSuffixIcon`。\n\n## en-US\n\nCustom `nzPrefix` and `nzSuffixIcon`.\n"
  },
  {
    "path": "components/time-picker/demo/prefix-suffix.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzFlexModule } from 'ng-zorro-antd/flex';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzTimePickerModule } from 'ng-zorro-antd/time-picker';\n\n@Component({\n  selector: 'nz-demo-time-picker-prefix-suffix',\n  imports: [NzTimePickerModule, NzIconModule, NzFlexModule],\n  template: `\n    <nz-flex nzVertical nzGap=\"small\">\n      <nz-time-picker nzPrefix=\"smile\" />\n      <nz-time-picker [nzPrefix]=\"smile\" />\n      <nz-time-picker nzSuffixIcon=\"smile\" />\n      <nz-time-picker [nzSuffixIcon]=\"smile\" />\n      <ng-template #smile><nz-icon nzType=\"smile\" /></ng-template>\n    </nz-flex>\n  `\n})\nexport class NzDemoTimePickerPrefixSuffixComponent {}\n"
  },
  {
    "path": "components/time-picker/demo/size.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 三种大小\n  en-US: Three Sizes\n---\n\n## zh-CN\n\n三种大小的输入框，大的用在表单中，中的为默认。\n\n## en-US\n\nThe input box comes in three sizes. large is used in the form, while the medium size is the default.\n"
  },
  {
    "path": "components/time-picker/demo/size.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzTimePickerModule } from 'ng-zorro-antd/time-picker';\n\n@Component({\n  selector: 'nz-demo-time-picker-size',\n  imports: [FormsModule, NzTimePickerModule],\n  template: `\n    <nz-time-picker [(ngModel)]=\"time\" nzSize=\"large\" />\n    <nz-time-picker [(ngModel)]=\"time\" />\n    <nz-time-picker [(ngModel)]=\"time\" nzSize=\"small\" />\n  `,\n  styles: `\n    nz-time-picker {\n      margin: 0 8px 12px 0;\n    }\n  `\n})\nexport class NzDemoTimePickerSizeComponent {\n  time = new Date();\n}\n"
  },
  {
    "path": "components/time-picker/demo/status.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 自定义状态\n  en-US: Status\n---\n\n## zh-CN\n\n使用 `nzStatus` 为 TimePicker 添加状态，可选 `error` 或者 `warning`。\n\n## en-US\n\nAdd status to TimePicker with `nzStatus`, which could be `error` or `warning`.\n"
  },
  {
    "path": "components/time-picker/demo/status.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTimePickerModule } from 'ng-zorro-antd/time-picker';\n\n@Component({\n  selector: 'nz-demo-time-picker-status',\n  imports: [NzTimePickerModule],\n  template: `\n    <nz-time-picker nzStatus=\"error\" />\n    <br />\n    <br />\n    <nz-time-picker nzStatus=\"warning\">></nz-time-picker>\n  `\n})\nexport class NzDemoTimePickerStatusComponent {}\n"
  },
  {
    "path": "components/time-picker/demo/use12-hours.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 12小时制\n  en-US: 12 hours\n---\n\n## zh-CN\n\n12小时制的时间选择器，默认format为 `h:mm:ss a`\n\n## en-US\n\nTimePicker of 12 hours with default format `h:mm:ss a`\n"
  },
  {
    "path": "components/time-picker/demo/use12-hours.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzTimePickerModule } from 'ng-zorro-antd/time-picker';\n\n@Component({\n  selector: 'nz-demo-time-picker-use12-hours',\n  imports: [FormsModule, NzTimePickerModule],\n  template: `\n    <nz-time-picker [(ngModel)]=\"time\" nzUse12Hours />\n    <br />\n    <br />\n    <nz-time-picker [(ngModel)]=\"time\" nzUse12Hours nzFormat=\"h:mm a\" />\n  `\n})\nexport class NzDemoTimePickerUse12HoursComponent {\n  time: Date | null = null;\n}\n"
  },
  {
    "path": "components/time-picker/demo/value.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 数据绑定\n  en-US: Data binding\n---\n\n## zh-CN\n\n可以进行双向绑定。\n\n## en-US\n\nWork with two-way binding.\n"
  },
  {
    "path": "components/time-picker/demo/value.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzTimePickerModule } from 'ng-zorro-antd/time-picker';\n\n@Component({\n  selector: 'nz-demo-time-picker-value',\n  imports: [FormsModule, NzTimePickerModule],\n  template: `<nz-time-picker [(ngModel)]=\"time\" />`\n})\nexport class NzDemoTimePickerValueComponent {\n  time: Date | null = null;\n}\n"
  },
  {
    "path": "components/time-picker/demo/variant.md",
    "content": "---\norder: 10\nversion: 20.0.0\ntitle:\n  zh-CN: 形态变体\n  en-US: Variants\n---\n\n## zh-CN\n\nTimePicker 形态变体，可选 `outlined`、`filled`、`borderless`、`underlined` 四种形态。\n\n## en-US\n\nVariants of TimePicker, there are four variants: `outlined`, `filled`, `borderless` and `underlined`.\n"
  },
  {
    "path": "components/time-picker/demo/variant.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\nimport { NzTimePickerModule } from 'ng-zorro-antd/time-picker';\n\n@Component({\n  selector: 'nz-demo-time-picker-variant',\n  imports: [NzTimePickerModule, NzSpaceModule],\n  template: ` <nz-space nzDirection=\"vertical\" style=\"width: 100%\">\n    <nz-time-picker *nzSpaceItem nzVariant=\"outlined\" />\n    <nz-time-picker *nzSpaceItem nzVariant=\"filled\" />\n    <nz-time-picker *nzSpaceItem nzVariant=\"borderless\" />\n    <nz-time-picker *nzSpaceItem nzVariant=\"underlined\" />\n  </nz-space>`\n})\nexport class NzDemoTimePickerVariantComponent {}\n"
  },
  {
    "path": "components/time-picker/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Entry\ntitle: TimePicker\ncover: 'https://gw.alipayobjects.com/zos/alicdn/h04Zsl98I/TimePicker.svg'\ndescription: To select/input a time.\n---\n\n## When To Use\n\nBy clicking the input box, you can select a time from a popup panel.\n\n## API\n\n### nz-time-picker\n\n| Property                  | Description                                                                            | Type                                                       | Default           | Global Config | Version |\n| ------------------------- | -------------------------------------------------------------------------------------- | ---------------------------------------------------------- | ----------------- | ------------- | ------- |\n| `[nzId]`                  | input id attribute inside the component                                                | `string`                                                   | -                 |\n| `[ngModel]`               | to set time                                                                            | `Date`                                                     | -                 |\n| `[nzAddOn]`               | called from timepicker panel to render some addon to its bottom                        | `TemplateRef<void>`                                        | -                 |\n| `[nzAllowEmpty]`          | allow clearing text                                                                    | `boolean`                                                  | `true`            | ✅            |\n| `[nzAutoFocus]`           | get focus when component mounted                                                       | `boolean`                                                  | `false`           |\n| `[nzBackdrop]`            | whether or not the overlay should attach a backdrop                                    | `boolean`                                                  | `false`           |\n| `[nzClearText]`           | clear tooltip of icon                                                                  | `string`                                                   | `'clear'`         | ✅            |\n| `[nzNowText]`             | text of the Now button                                                                 | `string`                                                   | `'Now'`           | ✅            |\n| `[nzOkText]`              | text of the Ok button                                                                  | `string`                                                   | `'Ok'`            | ✅            |\n| `[nzDefaultOpenValue]`    | default open panel value if `[ngModel]` is null                                        | `Date`                                                     | `new Date()`      |\n| `[nzDisabled]`            | determine whether the TimePicker is disabled                                           | `boolean`                                                  | `false`           |\n| `[nzDisabledHours]`       | to specify the hours that cannot be selected                                           | `() => number[]`                                           | -                 |\n| `[nzDisabledMinutes]`     | to specify the minutes that cannot be selected                                         | `(hour: number) => number[]`                               | -                 |\n| `[nzDisabledSeconds]`     | to specify the seconds that cannot be selected                                         | `(hour: number, minute: number) => number[]`               | -                 |\n| `[nzFormat]`              | to set the time format                                                                 | [DatePipe](https://angular.dev/api/common/DatePipe)        | `'HH:mm:ss'`      | ✅            |\n| `[nzHideDisabledOptions]` | hide the options that can not be selected                                              | `boolean`                                                  | `false`           |\n| `[nzHourStep]`            | interval between hours in picker                                                       | `number`                                                   | `1`               | ✅            |\n| `[nzMinuteStep]`          | interval between minutes in picker                                                     | `number`                                                   | `1`               | ✅            |\n| `[nzSecondStep]`          | interval between seconds in picker                                                     | `number`                                                   | `1`               | ✅            |\n| `[nzSize]`                | width of time picker box                                                               | `'large' \\| 'small' \\| 'default'`                          | `'default'`       |\n| `[nzStatus]`              | Set validation status                                                                  | `'error' \\| 'warning'`                                     | -                 |\n| `[nzVariant]`             | Variants of TimePicker                                                                 | `'outlined' \\| 'borderless' \\| 'filled' \\| 'underlined'`   | `'outlined'`      | ✅            | 20.0.0  |\n| `[nzInputReadOnly]`       | set the readonly attribute of the input tag (avoids virtual keyboard on touch devices) | `boolean`                                                  | `false`           | -             |\n| `[nzOpen]`                | whether to popup panel, double binding                                                 | `boolean`                                                  | `false`           |\n| `[nzPlaceHolder]`         | display when there's no value                                                          | `string`                                                   | `'Select a time'` |\n| `[nzPopupClassName]`      | className of panel                                                                     | `string`                                                   | `''`              | ✅            |\n| `[nzUse12Hours]`          | display as 12 hours format, with default format `h:mm:ss a`                            | `boolean`                                                  | `false`           | ✅            |\n| `[nzSuffixIcon]`          | the custom suffix icon                                                                 | `string \\| TemplateRef`                                    | -                 | ✅            |\n| `[nzPrefix]`              | the custom prefix                                                                      | `string \\| TemplateRef`                                    | -                 |               | 21.1.0  |\n| `[nzNeedConfirm]`         | Need click confirm button to trigger value change                                      | `boolean`                                                  | -                 |               | 21.1.0  |\n| `[nzPlacement]`           | The position where the selection box pops up                                           | `'bottomLeft' \\| 'bottomRight' \\| 'topLeft' \\| 'topRight'` | -                 |               | 21.1.0  |\n| `(ngModelChange)`         | a callback function, can be executed when the selected time is changing                | `EventEmitter<Date>`                                       | -                 |\n| `(nzOpenChange)`          | a callback function which will be called while panel opening/closing                   | `EventEmitter<boolean>`                                    | -                 |\n\n#### Methods\n\n| Name      | Description  |\n| --------- | ------------ |\n| `blur()`  | remove focus |\n| `focus()` | get focus    |\n\n## FAQ\n\n### Q: The overlay layer element does not follow the scroll position when scrolling\n\nBy default, the overlay layer element uses body as the scroll container. If using another scroll container, add the [CdkScrollable](https://material.angular.dev/cdk/scrolling/api#CdkScrollable) directive to the custom scroll container element.\nNote: You need to import the `CdkScrollable` directive or `ScrollingModule` module from `@angular/cdk/scrolling`.\n"
  },
  {
    "path": "components/time-picker/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 时间选择框\ntype: 数据录入\ntitle: TimePicker\ncover: 'https://gw.alipayobjects.com/zos/alicdn/h04Zsl98I/TimePicker.svg'\ndescription: 输入或选择时间的控件。\n---\n\n## 何时使用\n\n当用户需要输入一个时间，可以点击标准输入框，弹出时间面板进行选择。\n\n## API\n\n### nz-time-picker\n\n| 参数                      | 说明                                                    | 类型                                                       | 默认值         | 全局配置 | 版本   |\n| ------------------------- | ------------------------------------------------------- | ---------------------------------------------------------- | -------------- | -------- | ------ |\n| `[nzId]`                  | 组件内部 input 的 id 值                                 | `string`                                                   | -              |\n| `[ngModel]`               | 当前时间                                                | `Date`                                                     | -              |\n| `[nzAddOn]`               | 选择框底部显示自定义的内容                              | `TemplateRef<void>`                                        | -              |\n| `[nzAllowEmpty]`          | 是否展示清除按钮                                        | `boolean`                                                  | `true`         | ✅       |\n| `[nzAutoFocus]`           | 自动获取焦点                                            | `boolean`                                                  | `false`        |\n| `[nzBackdrop]`            | 浮层是否应带有背景板                                    | `boolean`                                                  | `false`        |\n| `[nzClearText]`           | 清除按钮的提示文案                                      | `string`                                                   | `'clear'`      | ✅       |\n| `[nzNowText]`             | 此刻按钮文本                                            | `string`                                                   | `'此刻'`       | ✅       |\n| `[nzOkText]`              | 确认按钮文本                                            | `string`                                                   | `'确定'`       | ✅       |\n| `[nzDefaultOpenValue]`    | 当 `[ngModel]` 不存在时，可以设置面板打开时默认选中的值 | `Date`                                                     | `new Date()`   |\n| `[nzDisabled]`            | 禁用全部操作                                            | `boolean`                                                  | `false`        |\n| `[nzDisabledHours]`       | 禁止选择部分小时选项                                    | `() => number[]`                                           | -              |\n| `[nzDisabledMinutes]`     | 禁止选择部分分钟选项                                    | `(hour: number) => number[]`                               | -              |\n| `[nzDisabledSeconds]`     | 禁止选择部分秒选项                                      | `(hour: number, minute: number) => number[]`               | -              |\n| `[nzFormat]`              | 展示的时间格式                                          | [DatePipe](https://angular.cn/api/common/DatePipe)         | `'HH:mm:ss'`   | ✅       |\n| `[nzHideDisabledOptions]` | 隐藏禁止选择的选项                                      | `boolean`                                                  | `false`        |\n| `[nzHourStep]`            | 小时选项间隔                                            | `number`                                                   | `1`            | ✅       |\n| `[nzMinuteStep]`          | 分钟选项间隔                                            | `number`                                                   | `1`            | ✅       |\n| `[nzSecondStep]`          | 秒选项间隔                                              | `number`                                                   | `1`            | ✅       |\n| `[nzSize]`                | 时间选择框大小                                          | `'large' \\| 'small' \\| 'default'`                          | `'default'`    |\n| `[nzStatus]`              | 设置校验状态                                            | `'error' \\| 'warning'`                                     | -              |\n| `[nzVariant]`             | 形态变体                                                | `'outlined' \\| 'borderless' \\| 'filled' \\| 'underlined'`   | `'outlined'`   | ✅       | 20.0.0 |\n| `[nzInputReadOnly]`       | 为 input 标签设置只读属性（避免在移动设备上触发小键盘） | `boolean`                                                  | `false`        | -        |\n| `[nzOpen]`                | 面板是否打开，可双向绑定                                | `boolean`                                                  | `false`        |\n| `[nzPlaceHolder]`         | 没有值的时候显示的内容                                  | `string`                                                   | `'请选择时间'` |\n| `[nzPopupClassName]`      | 弹出层类名                                              | `string`                                                   | `''`           | ✅       |\n| `[nzUse12Hours]`          | 使用 12 小时制，为 true 时 format 默认为`h:mm:ss a`     | `boolean`                                                  | `false`        | ✅       |\n| `[nzSuffixIcon]`          | 自定义的后缀图标                                        | `string \\| TemplateRef`                                    | -              | ✅       |\n| `[nzPrefix]`              | 自定义前缀                                              | `string \\| TemplateRef`                                    | -              |          | 21.1.0 |\n| `[nzNeedConfirm]`         | 是否需要确认按钮，为 false 时失去焦点即代表选择         | `boolean`                                                  | -              |          | 21.1.0 |\n| `[nzPlacement]`           | 选择框弹出的位置                                        | `'bottomLeft' \\| 'bottomRight' \\| 'topLeft' \\| 'topRight'` | -              |          | 21.1.0 |\n| `(ngModelChange)`         | 时间发生变化的回调                                      | `EventEmitter<Date>`                                       | -              |\n| `(nzOpenChange)`          | 面板打开/关闭时的回调                                   | `EventEmitter<boolean>`                                    | -              |\n\n#### 方法\n\n| 名称      | 描述     |\n| --------- | -------- |\n| `blur()`  | 移除焦点 |\n| `focus()` | 获取焦点 |\n\n## FAQ\n\n### Q：滚动时浮层元素没有跟随滚动位置\n\n默认情况下，浮层元素使用 `body` 作为滚动容器，如果使用了其他滚动容器，在自定义滚动容器元素上添加 [CdkScrollable](https://material.angular.dev/cdk/scrolling/api#CdkScrollable) 指令。\n注意：您需要从 `@angular/cdk/scrolling` 导入 `CdkScrollable` 指令或 `ScrollingModule` 模块。\n"
  },
  {
    "path": "components/time-picker/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/time-picker/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/time-picker/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './time-picker.component';\nexport * from './time-picker.module';\nexport * from './time-picker-panel.component';\n"
  },
  {
    "path": "components/time-picker/style/entry.less",
    "content": "@import './index.less';\n"
  },
  {
    "path": "components/time-picker/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import '../../input/style/mixin';\n"
  },
  {
    "path": "components/time-picker/time-holder.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { TimeHolder } from './time-holder';\n\nfunction mathSecondRound(value: Date): number {\n  return Math.floor(value.getTime() / 1000);\n}\n\ndescribe('time holder', () => {\n  it('should get hours/minutes/seconds', () => {\n    const holder = new TimeHolder().setValue(new Date(0, 0, 0, 23, 10, 20));\n    expect(holder.hours).toEqual(23);\n    expect(holder.minutes).toEqual(10);\n    expect(holder.seconds).toEqual(20);\n  });\n\n  it('should set hours', () => {\n    const holder = new TimeHolder().setHours(23, false).setMinutes(10, false).setSeconds(20, false);\n    const date = new Date();\n    date.setHours(23);\n    date.setMinutes(10);\n    date.setSeconds(20);\n    expect(mathSecondRound(holder.value!)).toEqual(mathSecondRound(date));\n  });\n\n  it('should ignore disabled', () => {\n    const holder = new TimeHolder().setHours(23, false).setMinutes(10, false).setSeconds(20, false);\n    holder.setHours(0, true).setMinutes(0, true).setSeconds(0, true);\n    const date = new Date();\n    date.setHours(23);\n    date.setMinutes(10);\n    date.setSeconds(20);\n    expect(mathSecondRound(holder.value!)).toEqual(mathSecondRound(date));\n  });\n\n  it('should ignore date part', () => {\n    const holder = new TimeHolder().setValue(new Date(2001, 10, 1, 23, 10, 20));\n    expect(holder.hours).toEqual(23);\n    expect(holder.minutes).toEqual(10);\n    expect(holder.seconds).toEqual(20);\n  });\n\n  it('value should be undefined when cleared', () => {\n    const holder = new TimeHolder().setValue(new Date(2001, 10, 1, 23, 10, 20));\n    holder.setValue(undefined);\n    expect(holder.value).toBeUndefined();\n    expect(holder.isEmpty).toBeTruthy();\n  });\n\n  it('hours/minutes/seconds should be undefined when cleared', () => {\n    const holder = new TimeHolder().setValue(new Date(2001, 10, 1, 23, 10, 20));\n    holder.clear();\n    expect(holder.hours).toBeUndefined();\n    expect(holder.minutes).toBeUndefined();\n    expect(holder.seconds).toBeUndefined();\n  });\n\n  it('should 12-hour worked', () => {\n    const holder = new TimeHolder().setValue(new Date(0, 0, 0, 0, 0, 0));\n    holder.setUse12Hours(true);\n    holder.setSelected12Hours('pm');\n    holder.setHours(3, false);\n    expect(holder.viewHours).toBe(3);\n    expect(holder.hours).toBe(15);\n    const date = new Date(0, 0, 0, 15, 0, 0, 0);\n    expect(mathSecondRound(holder.value!)).toEqual(mathSecondRound(date));\n  });\n\n  it('should set default selected 12-hours with value', () => {\n    const holderPM = new TimeHolder().setValue(new Date(0, 0, 0, 15, 2, 3), true);\n    expect(holderPM.selected12Hours).toBe('PM');\n    const holderAM = new TimeHolder().setValue(new Date(0, 0, 0, 0, 2, 3), true);\n    expect(holderAM.selected12Hours).toBe('AM');\n  });\n\n  it('should transform special value in 12-hour', () => {\n    const holder = new TimeHolder().setValue(new Date(), true);\n    holder.setSelected12Hours('am');\n    holder.setHours(12, false);\n    expect(holder.hours).toBe(0);\n    holder.setSelected12Hours('pm');\n    expect(holder.hours).toBe(12);\n  });\n});\n"
  },
  {
    "path": "components/time-picker/time-holder.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Observable, Subject } from 'rxjs';\n\nimport { isNil, isNotNil } from 'ng-zorro-antd/core/util';\n\nexport class TimeHolder {\n  selected12Hours: string | undefined = undefined;\n  private _value: Date | undefined;\n  private _use12Hours: boolean = false;\n  private _defaultOpenValue!: Date;\n  private _changes = new Subject<Date>();\n\n  setMinutes(value: number, disabled: boolean): this {\n    if (!disabled) {\n      this.initValue();\n      this.value.setMinutes(value);\n      this.update();\n    }\n    return this;\n  }\n\n  setHours(value: number, disabled: boolean): this {\n    if (!disabled) {\n      this.initValue();\n      if (this._use12Hours) {\n        if (this.selected12Hours === 'PM' && value !== 12) {\n          this.value.setHours((value as number) + 12);\n        } else if (this.selected12Hours === 'AM' && value === 12) {\n          this.value.setHours(0);\n        } else {\n          this.value.setHours(value);\n        }\n      } else {\n        this.value.setHours(value);\n      }\n      this.update();\n    }\n    return this;\n  }\n\n  setSeconds(value: number, disabled: boolean): this {\n    if (!disabled) {\n      this.initValue();\n      this.value.setSeconds(value);\n      this.update();\n    }\n    return this;\n  }\n\n  setUse12Hours(value: boolean): this {\n    this._use12Hours = value;\n    return this;\n  }\n\n  get changes(): Observable<Date> {\n    return this._changes.asObservable();\n  }\n\n  setValue(value: Date | undefined, use12Hours?: boolean): this {\n    if (isNotNil(use12Hours)) {\n      this._use12Hours = use12Hours as boolean;\n    }\n    if (value !== this.value) {\n      this._value = value;\n      if (isNotNil(this.value)) {\n        if (this._use12Hours && isNotNil(this.hours)) {\n          this.selected12Hours = this.hours >= 12 ? 'PM' : 'AM';\n        }\n      } else {\n        this._clear();\n      }\n    }\n\n    return this;\n  }\n\n  initValue(): void {\n    if (isNil(this.value)) {\n      this.setValue(new Date(), this._use12Hours);\n    }\n  }\n\n  clear(): void {\n    this._clear();\n    this.update();\n  }\n\n  get isEmpty(): boolean {\n    return !(isNotNil(this.hours) || isNotNil(this.minutes) || isNotNil(this.seconds));\n  }\n\n  private _clear(): void {\n    this._value = undefined;\n    this.selected12Hours = undefined;\n  }\n\n  private update(): void {\n    if (this.isEmpty) {\n      this._value = undefined;\n    } else {\n      if (isNotNil(this.hours)) {\n        this.value!.setHours(this.hours!);\n      }\n\n      if (isNotNil(this.minutes)) {\n        this.value!.setMinutes(this.minutes!);\n      }\n\n      if (isNotNil(this.seconds)) {\n        this.value!.setSeconds(this.seconds!);\n      }\n\n      if (this._use12Hours) {\n        if (this.selected12Hours === 'PM' && this.hours! < 12) {\n          this.value!.setHours(this.hours! + 12);\n        }\n        if (this.selected12Hours === 'AM' && this.hours! >= 12) {\n          this.value!.setHours(this.hours! - 12);\n        }\n      }\n    }\n    this.changed();\n  }\n\n  changed(): void {\n    this._changes.next(this.value);\n  }\n\n  /**\n   * @description\n   * UI view hours\n   * Get viewHours which is selected in `time-picker-panel` and its range is [12, 1, 2, ..., 11]\n   */\n  get viewHours(): number | undefined {\n    return this._use12Hours && isNotNil(this.hours) ? this.calculateViewHour(this.hours!) : this.hours;\n  }\n\n  setSelected12Hours(value: string | undefined): void {\n    if (value!.toUpperCase() !== this.selected12Hours) {\n      this.selected12Hours = value!.toUpperCase();\n      this.update();\n    }\n  }\n\n  get value(): Date {\n    return this._value || this._defaultOpenValue;\n  }\n\n  get hours(): number | undefined {\n    return this.value?.getHours();\n  }\n\n  get minutes(): number | undefined {\n    return this.value?.getMinutes();\n  }\n\n  get seconds(): number | undefined {\n    return this.value?.getSeconds();\n  }\n\n  setDefaultOpenValue(value: Date): this {\n    this._defaultOpenValue = value;\n    return this;\n  }\n\n  private calculateViewHour(value: number): number {\n    const selected12Hours = this.selected12Hours;\n    if (selected12Hours === 'PM' && value > 12) {\n      return value - 12;\n    }\n    if (selected12Hours === 'AM' && value === 0) {\n      return 12;\n    }\n    return value;\n  }\n}\n"
  },
  {
    "path": "components/time-picker/time-picker-panel.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ApplicationRef, Component, DebugElement, provideZoneChangeDetection, ViewChild } from '@angular/core';\nimport { ComponentFixture, TestBed, fakeAsync, flush, tick } from '@angular/core/testing';\nimport { FormsModule } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\n\nimport { dispatchFakeEvent } from 'ng-zorro-antd/core/testing';\n\nimport { NzTimePickerPanelComponent } from './time-picker-panel.component';\n\ndescribe('time-picker-panel', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  describe('basic', () => {\n    let fixture: ComponentFixture<NzTestTimePanelComponent>;\n    let testComponent: NzTestTimePanelComponent;\n    let panelElement: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTimePanelComponent);\n      testComponent = fixture.debugElement.componentInstance;\n      fixture.detectChanges();\n      panelElement = fixture.debugElement.query(By.directive(NzTimePickerPanelComponent));\n    });\n\n    it('should init correct', () => {\n      fixture.detectChanges();\n      expect(panelElement.nativeElement.classList).toContain('ant-picker-time-panel');\n    });\n\n    it('should format work', () => {\n      fixture.detectChanges();\n      expect(testComponent.nzTimePickerPanelComponent.hourEnabled).toBe(true);\n      expect(testComponent.nzTimePickerPanelComponent.minuteEnabled).toBe(true);\n      expect(testComponent.nzTimePickerPanelComponent.secondEnabled).toBe(true);\n      expect(testComponent.nzTimePickerPanelComponent.enabledColumns).toBe(3);\n      testComponent.format = 'HH:mm';\n      fixture.detectChanges();\n      expect(testComponent.nzTimePickerPanelComponent.hourEnabled).toBe(true);\n      expect(testComponent.nzTimePickerPanelComponent.minuteEnabled).toBe(true);\n      expect(testComponent.nzTimePickerPanelComponent.secondEnabled).toBe(false);\n      expect(testComponent.nzTimePickerPanelComponent.enabledColumns).toBe(2);\n      testComponent.format = null!;\n      fixture.detectChanges();\n      expect(testComponent.nzTimePickerPanelComponent.hourEnabled).toBe(true);\n      expect(testComponent.nzTimePickerPanelComponent.minuteEnabled).toBe(true);\n      expect(testComponent.nzTimePickerPanelComponent.secondEnabled).toBe(false);\n      expect(testComponent.nzTimePickerPanelComponent.enabledColumns).toBe(2);\n    });\n\n    // it('should default open value work', fakeAsync(() => {\n    //   testComponent.opened = true;\n    //   fixture.detectChanges();\n    //   tick(1000);\n    //   fixture.detectChanges();\n    //   let listOfSelectedLi = panelElement.nativeElement.querySelectorAll('.ant-picker-time-panel-cell-selected');\n    //   expect(listOfSelectedLi[0].innerText).toBe('10');\n    //   expect(listOfSelectedLi[1].innerText).toBe('11');\n    //   expect(listOfSelectedLi[2].innerText).toBe('12');\n    //   listOfSelectedLi.forEach((li: HTMLElement) => {\n    //     expect(li.parentElement!.parentElement!.scrollTop).toBe(li.offsetTop);\n    //   });\n    //   testComponent.value = new Date(0, 0, 0, 8, 9, 10);\n    //   fixture.detectChanges();\n    //   flush();\n    //   fixture.detectChanges();\n    //   flush();\n    //   listOfSelectedLi = panelElement.nativeElement.querySelectorAll('.ant-picker-time-panel-cell-selected');\n    //   expect(listOfSelectedLi[0].innerText).toBe('08');\n    //   expect(listOfSelectedLi[1].innerText).toBe('09');\n    //   expect(listOfSelectedLi[2].innerText).toBe('10');\n    // }));\n\n    it('should select default open value on list click', fakeAsync(() => {\n      const listOfSelectedLi = panelElement.nativeElement.querySelectorAll('.ant-picker-time-panel-cell-selected');\n      expect(listOfSelectedLi[0].innerText).toBe('10');\n      expect(listOfSelectedLi[1].innerText).toBe('11');\n      expect(listOfSelectedLi[2].innerText).toBe('12');\n      expect(testComponent.value).toBeUndefined();\n      dispatchFakeEvent(listOfSelectedLi[0], 'click');\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.value).not.toBeUndefined();\n    }));\n\n    it('should select scroll work', fakeAsync(() => {\n      testComponent.value = new Date(0, 0, 0, 8, 9, 10);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      flush();\n      let listOfSelectedLi = panelElement.nativeElement.querySelectorAll('.ant-picker-time-panel-cell-selected');\n      expect(listOfSelectedLi[0].innerText).toBe('08');\n      expect(listOfSelectedLi[1].innerText).toBe('09');\n      expect(listOfSelectedLi[2].innerText).toBe('10');\n      testComponent.nzTimePickerPanelComponent.selectHour({ index: 0, disabled: false });\n      testComponent.nzTimePickerPanelComponent.selectMinute({ index: 1, disabled: false });\n      testComponent.nzTimePickerPanelComponent.selectSecond({ index: 2, disabled: false });\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      flush();\n      listOfSelectedLi = panelElement.nativeElement.querySelectorAll('.ant-picker-time-panel-cell-selected');\n      expect(listOfSelectedLi[0].innerText).toBe('00');\n      expect(listOfSelectedLi[1].innerText).toBe('01');\n      expect(listOfSelectedLi[2].innerText).toBe('02');\n    }));\n\n    it('should step work', () => {\n      fixture.detectChanges();\n      let listOfSelectContainer = panelElement.nativeElement.querySelectorAll('.ant-picker-time-panel-column');\n      expect(listOfSelectContainer[0].children.length).toEqual(24);\n      expect(listOfSelectContainer[1].children.length).toEqual(60);\n      expect(listOfSelectContainer[2].children.length).toEqual(60);\n      testComponent.hourStep = 2;\n      testComponent.minuteStep = 15;\n      testComponent.secondStep = 10;\n      fixture.detectChanges();\n      listOfSelectContainer = panelElement.nativeElement.querySelectorAll('.ant-picker-time-panel-column');\n      expect(listOfSelectContainer[0].children.length).toEqual(12);\n      expect(listOfSelectContainer[1].children.length).toEqual(4);\n      expect(listOfSelectContainer[2].children.length).toEqual(6);\n    });\n\n    it('should click now work', () => {\n      const now = new Date();\n      fixture.detectChanges();\n      dispatchFakeEvent(panelElement.nativeElement.querySelector('.ant-picker-now > a'), 'click');\n      fixture.detectChanges();\n      const listOfSelectContainer = panelElement.nativeElement.querySelectorAll('.ant-picker-time-panel-column');\n      expect(\n        listOfSelectContainer[0].querySelector('.ant-picker-time-panel-cell-selected .ant-picker-time-panel-cell-inner')\n          .textContent\n      ).toContain(now.getHours().toString());\n      expect(\n        listOfSelectContainer[1].querySelector('.ant-picker-time-panel-cell-selected .ant-picker-time-panel-cell-inner')\n          .textContent\n      ).toContain(now.getMinutes().toString());\n    });\n\n    it('should offsetTop is right', fakeAsync(() => {\n      testComponent.value = new Date(0, 0, 0, 0, 0, 0);\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      const listOfSelectedLi = panelElement.nativeElement.querySelector('.ant-picker-time-panel-cell-selected');\n      expect(listOfSelectedLi.offsetTop).toBe(0);\n    }));\n\n    describe('change detection behavior', () => {\n      it('should not run change detection when the timer picker panel is clicked', () => {\n        const appRef = TestBed.inject(ApplicationRef);\n        const event = new MouseEvent('mousedown');\n\n        spyOn(appRef, 'tick');\n        spyOn(event, 'preventDefault').and.callThrough();\n\n        fixture.nativeElement.querySelector('nz-time-picker-panel').dispatchEvent(event);\n\n        expect(appRef.tick).not.toHaveBeenCalled();\n        expect(event.preventDefault).toHaveBeenCalled();\n      });\n    });\n  });\n\n  describe('disabled', () => {\n    let fixture: ComponentFixture<NzTestTimePanelDisabledComponent>;\n    let testComponent: NzTestTimePanelDisabledComponent;\n    let panelElement: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTimePanelDisabledComponent);\n      testComponent = fixture.debugElement.componentInstance;\n      fixture.detectChanges();\n      panelElement = fixture.debugElement.query(By.directive(NzTimePickerPanelComponent));\n    });\n\n    it('should disabled work', fakeAsync(() => {\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      flush();\n      const listOfSelectContainer = panelElement.nativeElement.querySelectorAll('.ant-picker-time-panel-column');\n      expect(listOfSelectContainer[0].querySelectorAll('.ant-picker-time-panel-cell-disabled').length).toBe(3);\n      expect(listOfSelectContainer[1].querySelectorAll('.ant-picker-time-panel-cell-disabled').length).toBe(0);\n      expect(listOfSelectContainer[2].querySelectorAll('.ant-picker-time-panel-cell-disabled').length).toBe(0);\n      testComponent.nzTimePickerPanelComponent.selectHour({ index: 4, disabled: false });\n      fixture.detectChanges();\n      expect(listOfSelectContainer[1].querySelectorAll('.ant-picker-time-panel-cell-disabled').length).toBe(6);\n      testComponent.nzTimePickerPanelComponent.selectHour({ index: 5, disabled: false });\n      testComponent.nzTimePickerPanelComponent.selectMinute({ index: 1, disabled: false });\n      fixture.detectChanges();\n      expect(listOfSelectContainer[2].querySelectorAll('.ant-picker-time-panel-cell-disabled').length).toBe(6);\n      testComponent.hideDisabledOptions = true;\n      fixture.detectChanges();\n      expect(listOfSelectContainer[0].children.length).toBe(21);\n      expect(listOfSelectContainer[2].children.length).toBe(54);\n    }));\n\n    it('should now disabled work', fakeAsync(() => {\n      // disable every hour\n      testComponent.disabledHours = () => [...Array(24).keys()];\n      fixture.detectChanges();\n      flush();\n      dispatchFakeEvent(panelElement.nativeElement.querySelector('.ant-picker-now > a'), 'click');\n      fixture.detectChanges();\n      const listOfSelectContainer = panelElement.nativeElement.querySelectorAll('.ant-picker-time-panel-column');\n      expect(\n        listOfSelectContainer[0].querySelector('.ant-picker-time-panel-cell-selected .ant-picker-time-panel-cell-inner')\n          .textContent\n      ).toBe('10');\n      expect(\n        listOfSelectContainer[1].querySelector('.ant-picker-time-panel-cell-selected .ant-picker-time-panel-cell-inner')\n          .textContent\n      ).toBe('11');\n      expect(\n        listOfSelectContainer[2].querySelector('.ant-picker-time-panel-cell-selected .ant-picker-time-panel-cell-inner')\n          .textContent\n      ).toBe('12');\n    }));\n  });\n\n  describe('12-hour', () => {\n    let panelElement: DebugElement;\n    let fixture12Hour: ComponentFixture<NzTest12HourTimePanelComponent>;\n    let testComponent: NzTest12HourTimePanelComponent;\n\n    beforeEach(() => {\n      fixture12Hour = TestBed.createComponent(NzTest12HourTimePanelComponent);\n      testComponent = fixture12Hour.debugElement.componentInstance;\n      fixture12Hour.detectChanges();\n      panelElement = fixture12Hour.debugElement.query(By.directive(NzTimePickerPanelComponent));\n    });\n\n    it('basic 12-hour time-picker-panel', fakeAsync(() => {\n      fixture12Hour.detectChanges();\n      expect(testComponent.nzTimePickerPanelComponent.enabledColumns).toBe(4);\n      const listColumns: HTMLElement[] = panelElement.nativeElement.querySelectorAll('.ant-picker-time-panel-column');\n      expect(listColumns[0].querySelectorAll('li')[0].innerText).toBe('12');\n      const hour12labels = listColumns[3].querySelectorAll('li');\n      expect(hour12labels[0].innerText).toBe('am');\n      expect(hour12labels[1].innerText).toBe('pm');\n    }));\n\n    it('default value 12-hour time-picker-panel', fakeAsync(() => {\n      fixture12Hour.detectChanges();\n      tick(1000);\n      fixture12Hour.detectChanges();\n      const listOfSelectedLi = panelElement.nativeElement.querySelectorAll('.ant-picker-time-panel-cell-selected');\n      expect(listOfSelectedLi[0].innerText).toBe('12');\n      expect(listOfSelectedLi[1].innerText).toBe('00');\n      expect(listOfSelectedLi[2].innerText).toBe('00');\n      expect(listOfSelectedLi[3].innerText).toBe('am');\n    }));\n\n    it('should scroll work in 12-hour', fakeAsync(() => {\n      fixture12Hour.componentInstance.openValue = new Date(0, 0, 0, 5, 6, 7);\n      fixture12Hour.componentInstance.nzTimePickerPanelComponent.select12Hours({ index: 1, value: 'pm' });\n      fixture12Hour.detectChanges();\n      tick(1000);\n      fixture12Hour.detectChanges();\n      let listOfSelectedLi = panelElement.nativeElement.querySelectorAll('.ant-picker-time-panel-cell-selected');\n      expect(listOfSelectedLi[0].innerText).toBe('05');\n      expect(listOfSelectedLi[1].innerText).toBe('06');\n      expect(listOfSelectedLi[2].innerText).toBe('07');\n      expect(listOfSelectedLi[3].innerText).toBe('pm');\n      fixture12Hour.componentInstance.value = new Date(0, 0, 0, 6, 7, 8);\n      fixture12Hour.detectChanges();\n      tick(1000);\n      fixture12Hour.detectChanges();\n      listOfSelectedLi = panelElement.nativeElement.querySelectorAll('.ant-picker-time-panel-cell-selected');\n      expect(listOfSelectedLi[0].innerText).toBe('06');\n      expect(listOfSelectedLi[1].innerText).toBe('07');\n      expect(listOfSelectedLi[2].innerText).toBe('08');\n    }));\n\n    it('select hour and 12-hour in 12-hour-time-picker-panel', fakeAsync(() => {\n      fixture12Hour.detectChanges();\n      testComponent.nzTimePickerPanelComponent.selectHour({ index: 3, disabled: false });\n      testComponent.nzTimePickerPanelComponent.select12Hours({ index: 1, value: 'pm' });\n      fixture12Hour.detectChanges();\n      flush();\n      fixture12Hour.detectChanges();\n      expect(testComponent.value!.getHours()).toBe(15);\n      testComponent.nzTimePickerPanelComponent.select12Hours({ index: 0, value: 'am' });\n      fixture12Hour.detectChanges();\n      flush();\n      fixture12Hour.detectChanges();\n      expect(testComponent.value!.getHours()).toBe(3);\n    }));\n\n    it('hour step in 12-hour-time-picker-panel', fakeAsync(() => {\n      testComponent.hourStep = 2;\n      fixture12Hour.detectChanges();\n      const listOfHourContainer = panelElement.nativeElement.querySelectorAll('.ant-picker-time-panel-column');\n      expect(listOfHourContainer[0].children.length).toEqual(6);\n    }));\n  });\n\n  describe('disabled and format 12-hour', () => {\n    let panelElement: DebugElement;\n    let fixture12Hour: ComponentFixture<NzTest12HourTimePanelDisabledComponent>;\n    let testComponent: NzTest12HourTimePanelDisabledComponent;\n\n    beforeEach(() => {\n      fixture12Hour = TestBed.createComponent(NzTest12HourTimePanelDisabledComponent);\n      testComponent = fixture12Hour.debugElement.componentInstance;\n      fixture12Hour.detectChanges();\n      panelElement = fixture12Hour.debugElement.query(By.directive(NzTimePickerPanelComponent));\n    });\n\n    it('format in 12-hour-time-pick-panel', fakeAsync(() => {\n      testComponent.format = 'hh:mm:ss A';\n      fixture12Hour.detectChanges();\n      const list12HourLi = panelElement.nativeElement\n        .querySelectorAll('.ant-picker-time-panel-column')[3]\n        .querySelectorAll('li');\n      expect(list12HourLi[0].innerText).toBe('AM');\n      expect(list12HourLi[1].innerText).toBe('PM');\n    }));\n\n    it('disabled hour in 12-hour-time-picker-panel', fakeAsync(() => {\n      fixture12Hour.detectChanges();\n      flush();\n      testComponent.disabledHours = (): number[] => [0, 3, 4, 5, 12, 18, 19, 20, 24];\n      fixture12Hour.detectChanges();\n      let listHourLi = panelElement.nativeElement\n        .querySelectorAll('.ant-picker-time-panel-column')[0]\n        .querySelectorAll('li');\n      expect(listHourLi[0].classList).toContain('ant-picker-time-panel-cell-disabled');\n      expect(listHourLi[3].classList).toContain('ant-picker-time-panel-cell-disabled');\n      expect(listHourLi[4].classList).toContain('ant-picker-time-panel-cell-disabled');\n      expect(listHourLi[5].classList).toContain('ant-picker-time-panel-cell-disabled');\n      testComponent.nzTimePickerPanelComponent.select12Hours({ index: 1, value: 'pm' });\n      fixture12Hour.detectChanges();\n      listHourLi = panelElement.nativeElement\n        .querySelectorAll('.ant-picker-time-panel-column')[0]\n        .querySelectorAll('li');\n      expect(listHourLi[0].classList).toContain('ant-picker-time-panel-cell-disabled');\n      expect(listHourLi[6].classList).toContain('ant-picker-time-panel-cell-disabled');\n      expect(listHourLi[7].classList).toContain('ant-picker-time-panel-cell-disabled');\n      expect(listHourLi[8].classList).toContain('ant-picker-time-panel-cell-disabled');\n\n      fixture12Hour.detectChanges();\n      tick(500);\n      flush();\n      listHourLi = panelElement.nativeElement\n        .querySelectorAll('.ant-picker-time-panel-column')[3]\n        .querySelectorAll('li');\n\n      expect(listHourLi.length).not.toBe(0);\n    }));\n  });\n});\n\n@Component({\n  imports: [NzTimePickerPanelComponent, FormsModule],\n  template: `\n    <nz-time-picker-panel\n      [(ngModel)]=\"value\"\n      [format]=\"format\"\n      [nzDefaultOpenValue]=\"openValue\"\n      [nzSecondStep]=\"secondStep\"\n      [nzMinuteStep]=\"minuteStep\"\n      [nzHourStep]=\"hourStep\"\n    />\n  `\n})\nexport class NzTestTimePanelComponent {\n  @ViewChild(NzTimePickerPanelComponent, { static: false }) nzTimePickerPanelComponent!: NzTimePickerPanelComponent;\n  secondStep = 1;\n  minuteStep = 1;\n  hourStep = 1;\n  value?: Date;\n  openValue = new Date(0, 0, 0, 10, 11, 12);\n  format: string = 'HH:mm:ss';\n}\n\n@Component({\n  imports: [NzTimePickerPanelComponent, FormsModule],\n  template: `\n    <nz-time-picker-panel\n      [(ngModel)]=\"value\"\n      [format]=\"format\"\n      [nzDisabledHours]=\"disabledHours\"\n      [nzDisabledMinutes]=\"disabledMinutes\"\n      [nzDisabledSeconds]=\"disabledSeconds\"\n      [nzDefaultOpenValue]=\"openValue\"\n      [nzSecondStep]=\"secondStep\"\n      [nzMinuteStep]=\"minuteStep\"\n      [nzInDatePicker]=\"inDatePicker\"\n      [nzHideDisabledOptions]=\"hideDisabledOptions\"\n      [nzHourStep]=\"hourStep\"\n    />\n  `\n})\nexport class NzTestTimePanelDisabledComponent {\n  @ViewChild(NzTimePickerPanelComponent, { static: false }) nzTimePickerPanelComponent!: NzTimePickerPanelComponent;\n  inDatePicker = false;\n  secondStep = 1;\n  minuteStep = 1;\n  hourStep = 1;\n  hideDisabledOptions = false;\n  value = new Date(0, 0, 0, 0, 0, 0);\n  openValue = new Date(0, 0, 0, 10, 11, 12);\n  format = 'HH:mm:ss';\n\n  disabledHours(): number[] {\n    return [1, 2, 3];\n  }\n\n  disabledMinutes(hour: number): number[] {\n    if (hour === 4) {\n      return [20, 21, 22, 23, 24, 25];\n    } else {\n      return [];\n    }\n  }\n\n  disabledSeconds(hour: number, minute: number): number[] {\n    if (hour === 5 && minute === 1) {\n      return [20, 21, 22, 23, 24, 25];\n    } else {\n      return [];\n    }\n  }\n}\n\n@Component({\n  imports: [NzTimePickerPanelComponent, FormsModule],\n  template: `\n    <nz-time-picker-panel\n      [(ngModel)]=\"value\"\n      [nzUse12Hours]=\"true\"\n      [nzDefaultOpenValue]=\"openValue\"\n      [nzHourStep]=\"hourStep\"\n      [format]=\"format\"\n    />\n  `\n})\nexport class NzTest12HourTimePanelComponent {\n  @ViewChild(NzTimePickerPanelComponent, { static: false }) nzTimePickerPanelComponent!: NzTimePickerPanelComponent;\n  format = 'hh:mm:ss a';\n  hourStep = 1;\n  value?: Date;\n  openValue = new Date(0, 0, 0, 0, 0, 0);\n}\n\n@Component({\n  imports: [NzTimePickerPanelComponent, FormsModule],\n  template: `\n    <nz-time-picker-panel\n      [format]=\"format\"\n      [(ngModel)]=\"value\"\n      [nzUse12Hours]=\"true\"\n      [nzDisabledHours]=\"disabledHours\"\n      [nzDisabledMinutes]=\"disabledMinutes\"\n      [nzDisabledSeconds]=\"disabledSeconds\"\n      [nzHideDisabledOptions]=\"false\"\n    />\n  `\n})\nexport class NzTest12HourTimePanelDisabledComponent {\n  @ViewChild(NzTimePickerPanelComponent, { static: false }) nzTimePickerPanelComponent!: NzTimePickerPanelComponent;\n  format = 'hh:mm:ss a';\n  value = new Date(0, 0, 0, 1, 1, 1);\n\n  disabledHours = (): number[] => [];\n\n  disabledMinutes(hour: number): number[] {\n    if (hour === 4) {\n      return [20, 21, 22, 23, 24, 25];\n    } else {\n      return [];\n    }\n  }\n\n  disabledSeconds(hour: number, minute: number): number[] {\n    if (hour === 5 && minute === 1) {\n      return [20, 21, 22, 23, 24, 25];\n    } else {\n      return [];\n    }\n  }\n}\n"
  },
  {
    "path": "components/time-picker/time-picker-panel.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { DecimalPipe, NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DebugElement,\n  ElementRef,\n  EventEmitter,\n  Input,\n  NgZone,\n  OnChanges,\n  OnInit,\n  Output,\n  SimpleChanges,\n  TemplateRef,\n  ViewChild,\n  ViewEncapsulation,\n  booleanAttribute,\n  forwardRef,\n  numberAttribute,\n  inject,\n  DestroyRef\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { requestAnimationFrame } from 'ng-zorro-antd/core/polyfill';\nimport { fromEventOutsideAngular, isNotNil } from 'ng-zorro-antd/core/util';\nimport { DateHelperService, NzI18nModule } from 'ng-zorro-antd/i18n';\n\nimport { TimeHolder } from './time-holder';\n\nfunction makeRange(length: number, step: number = 1, start: number = 0): number[] {\n  return new Array(Math.ceil(length / step)).fill(0).map((_, i) => (i + start) * step);\n}\n\nexport type NzTimePickerUnit = 'hour' | 'minute' | 'second' | '12-hour';\n\n@Component({\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  selector: 'nz-time-picker-panel',\n  exportAs: 'nzTimePickerPanel',\n  template: `\n    @if (nzInDatePicker) {\n      <div class=\"ant-picker-header\">\n        <div class=\"ant-picker-header-view\">{{ dateHelper.format($any(time?.value), format) || '&nbsp;' }}</div>\n      </div>\n    }\n    <div class=\"ant-picker-content\">\n      @if (hourEnabled) {\n        <ul #hourListElement class=\"ant-picker-time-panel-column\" style=\"position: relative;\">\n          @for (hour of hourRange; track $index) {\n            @if (!(nzHideDisabledOptions && hour.disabled)) {\n              <li\n                class=\"ant-picker-time-panel-cell\"\n                (click)=\"selectHour(hour)\"\n                [class.ant-picker-time-panel-cell-selected]=\"isSelectedHour(hour)\"\n                [class.ant-picker-time-panel-cell-disabled]=\"hour.disabled\"\n              >\n                <div class=\"ant-picker-time-panel-cell-inner\">{{ hour.index | number: '2.0-0' }}</div>\n              </li>\n            }\n          }\n        </ul>\n      }\n      @if (minuteEnabled) {\n        <ul #minuteListElement class=\"ant-picker-time-panel-column\" style=\"position: relative;\">\n          @for (minute of minuteRange; track $index) {\n            @if (!(nzHideDisabledOptions && minute.disabled)) {\n              <li\n                class=\"ant-picker-time-panel-cell\"\n                (click)=\"selectMinute(minute)\"\n                [class.ant-picker-time-panel-cell-selected]=\"isSelectedMinute(minute)\"\n                [class.ant-picker-time-panel-cell-disabled]=\"minute.disabled\"\n              >\n                <div class=\"ant-picker-time-panel-cell-inner\">{{ minute.index | number: '2.0-0' }}</div>\n              </li>\n            }\n          }\n        </ul>\n      }\n      @if (secondEnabled) {\n        <ul #secondListElement class=\"ant-picker-time-panel-column\" style=\"position: relative;\">\n          @for (second of secondRange; track $index) {\n            @if (!(nzHideDisabledOptions && second.disabled)) {\n              <li\n                class=\"ant-picker-time-panel-cell\"\n                (click)=\"selectSecond(second)\"\n                [class.ant-picker-time-panel-cell-selected]=\"isSelectedSecond(second)\"\n                [class.ant-picker-time-panel-cell-disabled]=\"second.disabled\"\n              >\n                <div class=\"ant-picker-time-panel-cell-inner\">{{ second.index | number: '2.0-0' }}</div>\n              </li>\n            }\n          }\n        </ul>\n      }\n      @if (nzUse12Hours) {\n        <ul #use12HoursListElement class=\"ant-picker-time-panel-column\" style=\"position: relative;\">\n          @for (range of use12HoursRange; track range) {\n            <li\n              (click)=\"select12Hours(range)\"\n              class=\"ant-picker-time-panel-cell\"\n              [class.ant-picker-time-panel-cell-selected]=\"isSelected12Hours(range)\"\n            >\n              <div class=\"ant-picker-time-panel-cell-inner\">{{ range.value }}</div>\n            </li>\n          }\n        </ul>\n      }\n    </div>\n    @if (!nzInDatePicker) {\n      <div class=\"ant-picker-footer\">\n        @if (nzAddOn) {\n          <div class=\"ant-picker-footer-extra\">\n            <ng-template [ngTemplateOutlet]=\"nzAddOn\" />\n          </div>\n        }\n        <ul class=\"ant-picker-ranges\">\n          <li class=\"ant-picker-now\">\n            <a (click)=\"onClickNow()\">\n              {{ nzNowText || ('Calendar.lang.now' | nzI18n) }}\n            </a>\n          </li>\n          <li class=\"ant-picker-ok\">\n            <button nz-button type=\"button\" nzSize=\"small\" nzType=\"primary\" (click)=\"onClickOk()\">\n              {{ nzOkText || ('Calendar.lang.ok' | nzI18n) }}\n            </button>\n          </li>\n        </ul>\n      </div>\n    }\n  `,\n  host: {\n    class: 'ant-picker-time-panel',\n    '[class.ant-picker-time-panel-column-0]': `enabledColumns === 0 && !nzInDatePicker`,\n    '[class.ant-picker-time-panel-column-1]': `enabledColumns === 1 && !nzInDatePicker`,\n    '[class.ant-picker-time-panel-column-2]': `enabledColumns === 2 && !nzInDatePicker`,\n    '[class.ant-picker-time-panel-column-3]': `enabledColumns === 3 && !nzInDatePicker`,\n    '[class.ant-picker-time-panel-narrow]': `enabledColumns < 3`,\n    '[class.ant-picker-time-panel-placement-bottomLeft]': `!nzInDatePicker`\n  },\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => NzTimePickerPanelComponent),\n      multi: true\n    }\n  ],\n  imports: [DecimalPipe, NgTemplateOutlet, NzI18nModule, NzButtonModule]\n})\nexport class NzTimePickerPanelComponent implements ControlValueAccessor, OnInit, OnChanges {\n  dateHelper = inject(DateHelperService);\n  private ngZone = inject(NgZone);\n  private cdr = inject(ChangeDetectorRef);\n  private elementRef = inject(ElementRef);\n  private destroyRef = inject(DestroyRef);\n\n  private _nzHourStep = 1;\n  private _nzMinuteStep = 1;\n  private _nzSecondStep = 1;\n  private onChange?: (value: Date) => void;\n  private onTouch?: () => void;\n  private _format = 'HH:mm:ss';\n  private _disabledHours?: () => number[] = () => [];\n  private _disabledMinutes?: (hour: number) => number[] = () => [];\n  private _disabledSeconds?: (hour: number, minute: number) => number[] = () => [];\n  private _allowEmpty = true;\n  time = new TimeHolder();\n  hourEnabled = true;\n  minuteEnabled = true;\n  secondEnabled = true;\n  firstScrolled = false;\n  enabledColumns = 3;\n  hourRange!: ReadonlyArray<{ index: number; disabled: boolean }>;\n  minuteRange!: ReadonlyArray<{ index: number; disabled: boolean }>;\n  secondRange!: ReadonlyArray<{ index: number; disabled: boolean }>;\n  use12HoursRange!: ReadonlyArray<{ index: number; value: string }>;\n\n  @ViewChild('hourListElement', { static: false })\n  hourListElement?: DebugElement;\n  @ViewChild('minuteListElement', { static: false }) minuteListElement?: DebugElement;\n  @ViewChild('secondListElement', { static: false }) secondListElement?: DebugElement;\n  @ViewChild('use12HoursListElement', { static: false }) use12HoursListElement?: DebugElement;\n\n  @Input({ transform: booleanAttribute }) nzInDatePicker: boolean = false; // If inside a date-picker, more diff works need to be done\n  @Input() nzAddOn?: TemplateRef<void>;\n  @Input() nzHideDisabledOptions = false;\n  @Input() nzClearText?: string;\n  @Input() nzNowText?: string;\n  @Input() nzOkText?: string;\n  @Input() nzPlaceHolder?: string | null;\n  @Input({ transform: booleanAttribute }) nzUse12Hours = false;\n  @Input() nzDefaultOpenValue?: Date;\n\n  @Output() readonly closePanel = new EventEmitter<void>();\n\n  @Input({ transform: booleanAttribute })\n  set nzAllowEmpty(value: boolean) {\n    this._allowEmpty = value;\n  }\n\n  get nzAllowEmpty(): boolean {\n    return this._allowEmpty;\n  }\n\n  @Input()\n  set nzDisabledHours(value: undefined | (() => number[])) {\n    this._disabledHours = value;\n    if (this._disabledHours) {\n      this.buildHours();\n    }\n  }\n\n  get nzDisabledHours(): undefined | (() => number[]) {\n    return this._disabledHours;\n  }\n\n  @Input()\n  set nzDisabledMinutes(value: undefined | ((hour: number) => number[])) {\n    if (isNotNil(value)) {\n      this._disabledMinutes = value;\n      this.buildMinutes();\n    }\n  }\n\n  get nzDisabledMinutes(): undefined | ((hour: number) => number[]) {\n    return this._disabledMinutes;\n  }\n\n  @Input()\n  set nzDisabledSeconds(value: undefined | ((hour: number, minute: number) => number[])) {\n    if (isNotNil(value)) {\n      this._disabledSeconds = value;\n      this.buildSeconds();\n    }\n  }\n\n  get nzDisabledSeconds(): undefined | ((hour: number, minute: number) => number[]) {\n    return this._disabledSeconds;\n  }\n\n  @Input()\n  set format(value: string) {\n    if (isNotNil(value)) {\n      this._format = value;\n      this.enabledColumns = 0;\n      const charSet = new Set(value);\n      this.hourEnabled = charSet.has('H') || charSet.has('h');\n      this.minuteEnabled = charSet.has('m');\n      this.secondEnabled = charSet.has('s');\n      if (this.hourEnabled) {\n        this.enabledColumns++;\n      }\n      if (this.minuteEnabled) {\n        this.enabledColumns++;\n      }\n      if (this.secondEnabled) {\n        this.enabledColumns++;\n      }\n      if (this.nzUse12Hours) {\n        this.build12Hours();\n      }\n    }\n  }\n\n  get format(): string {\n    return this._format;\n  }\n\n  @Input({ transform: numberAttribute })\n  set nzHourStep(value: number) {\n    this._nzHourStep = value || 1;\n    this.buildHours();\n  }\n\n  get nzHourStep(): number {\n    return this._nzHourStep;\n  }\n\n  @Input({ transform: numberAttribute })\n  set nzMinuteStep(value: number) {\n    this._nzMinuteStep = value || 1;\n    this.buildMinutes();\n  }\n\n  get nzMinuteStep(): number {\n    return this._nzMinuteStep;\n  }\n\n  @Input({ transform: numberAttribute })\n  set nzSecondStep(value: number) {\n    this._nzSecondStep = value || 1;\n    this.buildSeconds();\n  }\n\n  get nzSecondStep(): number {\n    return this._nzSecondStep;\n  }\n\n  buildHours(): void {\n    let hourRanges = 24;\n    let disabledHours = this.nzDisabledHours?.();\n    let startIndex = 0;\n    if (this.nzUse12Hours) {\n      hourRanges = 12;\n      if (disabledHours) {\n        if (this.time.selected12Hours === 'PM') {\n          /**\n           * Filter and transform hours which greater or equal to 12\n           * [0, 1, 2, ..., 12, 13, 14, 15, ..., 23] => [12, 1, 2, 3, ..., 11]\n           */\n          disabledHours = disabledHours.filter(i => i >= 12).map(i => (i > 12 ? i - 12 : i));\n        } else {\n          /**\n           * Filter and transform hours which less than 12\n           * [0, 1, 2, ..., 12, 13, 14, 15, ...23] => [12, 1, 2, 3, ..., 11]\n           */\n          disabledHours = disabledHours.filter(i => i < 12 || i === 24).map(i => (i === 24 || i === 0 ? 12 : i));\n        }\n      }\n      startIndex = 1;\n    }\n    this.hourRange = makeRange(hourRanges, this.nzHourStep, startIndex).map(r => ({\n      index: r,\n      disabled: !!disabledHours && disabledHours.indexOf(r) !== -1\n    }));\n    if (this.nzUse12Hours && this.hourRange[this.hourRange.length - 1].index === 12) {\n      const temp = [...this.hourRange];\n      temp.unshift(temp[temp.length - 1]);\n      temp.splice(temp.length - 1, 1);\n      this.hourRange = temp;\n    }\n  }\n\n  buildMinutes(): void {\n    this.minuteRange = makeRange(60, this.nzMinuteStep).map(r => ({\n      index: r,\n      disabled: !!this.nzDisabledMinutes && this.nzDisabledMinutes(this.time.hours!).indexOf(r) !== -1\n    }));\n  }\n\n  buildSeconds(): void {\n    this.secondRange = makeRange(60, this.nzSecondStep).map(r => ({\n      index: r,\n      disabled:\n        !!this.nzDisabledSeconds && this.nzDisabledSeconds(this.time.hours!, this.time.minutes!).indexOf(r) !== -1\n    }));\n  }\n\n  build12Hours(): void {\n    const isUpperFormat = this._format.includes('A');\n    this.use12HoursRange = [\n      {\n        index: 0,\n        value: isUpperFormat ? 'AM' : 'am'\n      },\n      {\n        index: 1,\n        value: isUpperFormat ? 'PM' : 'pm'\n      }\n    ];\n  }\n\n  buildTimes(): void {\n    this.buildHours();\n    this.buildMinutes();\n    this.buildSeconds();\n    this.build12Hours();\n  }\n\n  scrollToTime(delay: number = 0): void {\n    if (this.hourEnabled && this.hourListElement) {\n      this.scrollToSelected(this.hourListElement.nativeElement, this.time.viewHours!, delay, 'hour');\n    }\n    if (this.minuteEnabled && this.minuteListElement) {\n      this.scrollToSelected(this.minuteListElement.nativeElement, this.time.minutes!, delay, 'minute');\n    }\n    if (this.secondEnabled && this.secondListElement) {\n      this.scrollToSelected(this.secondListElement.nativeElement, this.time.seconds!, delay, 'second');\n    }\n    if (this.nzUse12Hours && this.use12HoursListElement) {\n      const selectedHours = this.time.selected12Hours;\n      const index = selectedHours === 'AM' ? 0 : 1;\n      this.scrollToSelected(this.use12HoursListElement.nativeElement, index, delay, '12-hour');\n    }\n  }\n\n  selectHour(hour: { index: number; disabled: boolean }): void {\n    this.time.setHours(hour.index, hour.disabled);\n    if (this._disabledMinutes) {\n      this.buildMinutes();\n    }\n    if (this._disabledSeconds || this._disabledMinutes) {\n      this.buildSeconds();\n    }\n  }\n\n  selectMinute(minute: { index: number; disabled: boolean }): void {\n    this.time.setMinutes(minute.index, minute.disabled);\n    if (this._disabledSeconds) {\n      this.buildSeconds();\n    }\n  }\n\n  selectSecond(second: { index: number; disabled: boolean }): void {\n    this.time.setSeconds(second.index, second.disabled);\n  }\n\n  select12Hours(value: { index: number; value: string }): void {\n    this.time.setSelected12Hours(value.value);\n    if (this._disabledHours) {\n      this.buildHours();\n    }\n    if (this._disabledMinutes) {\n      this.buildMinutes();\n    }\n    if (this._disabledSeconds) {\n      this.buildSeconds();\n    }\n  }\n\n  scrollToSelected(instance: HTMLElement, index: number, duration: number = 0, unit: NzTimePickerUnit): void {\n    if (!instance) {\n      return;\n    }\n    const transIndex = this.translateIndex(index, unit);\n    const currentOption = (instance.children[transIndex] || instance.children[0]) as HTMLElement;\n    this.scrollTo(instance, currentOption.offsetTop, duration);\n  }\n\n  translateIndex(index: number, unit: NzTimePickerUnit): number {\n    if (unit === 'hour') {\n      return this.calcIndex(this.nzDisabledHours?.(), this.hourRange.map(item => item.index).indexOf(index));\n    } else if (unit === 'minute') {\n      return this.calcIndex(\n        this.nzDisabledMinutes?.(this.time.hours!),\n        this.minuteRange.map(item => item.index).indexOf(index)\n      );\n    } else if (unit === 'second') {\n      // second\n      return this.calcIndex(\n        this.nzDisabledSeconds?.(this.time.hours!, this.time.minutes!),\n        this.secondRange.map(item => item.index).indexOf(index)\n      );\n    } else {\n      // 12-hour\n      return this.calcIndex([], this.use12HoursRange.map(item => item.index).indexOf(index));\n    }\n  }\n\n  scrollTo(element: HTMLElement, to: number, duration: number): void {\n    if (duration <= 0) {\n      element.scrollTop = to;\n      return;\n    }\n    const difference = to - element.scrollTop;\n    const perTick = (difference / duration) * 10;\n\n    this.ngZone.runOutsideAngular(() => {\n      requestAnimationFrame(() => {\n        element.scrollTop = element.scrollTop + perTick;\n        if (element.scrollTop === to) {\n          return;\n        }\n        this.scrollTo(element, to, duration - 10);\n      });\n    });\n  }\n\n  calcIndex(array: number[] | undefined, index: number): number {\n    if (array?.length && this.nzHideDisabledOptions) {\n      return index - array.reduce((pre, value) => pre + (value < index ? 1 : 0), 0);\n    } else {\n      return index;\n    }\n  }\n\n  protected changed(): void {\n    if (this.onChange) {\n      this.onChange(this.time.value!);\n    }\n  }\n\n  protected touched(): void {\n    if (this.onTouch) {\n      this.onTouch();\n    }\n  }\n\n  timeDisabled(value: Date): boolean {\n    const hour = value.getHours();\n    const minute = value.getMinutes();\n    const second = value.getSeconds();\n    return (\n      (this.nzDisabledHours?.().indexOf(hour) ?? -1) > -1 ||\n      (this.nzDisabledMinutes?.(hour).indexOf(minute) ?? -1) > -1 ||\n      (this.nzDisabledSeconds?.(hour, minute).indexOf(second) ?? -1) > -1\n    );\n  }\n\n  onClickNow(): void {\n    const now = new Date();\n    if (this.timeDisabled(now)) {\n      return;\n    }\n    this.time.setValue(now);\n    this.changed();\n    this.closePanel.emit();\n  }\n\n  onClickOk(): void {\n    this.time.setValue(this.time.value, this.nzUse12Hours);\n    this.changed();\n    this.closePanel.emit();\n  }\n\n  isSelectedHour(hour: { index: number; disabled: boolean }): boolean {\n    return hour.index === this.time.viewHours;\n  }\n\n  isSelectedMinute(minute: { index: number; disabled: boolean }): boolean {\n    return minute.index === this.time.minutes;\n  }\n\n  isSelectedSecond(second: { index: number; disabled: boolean }): boolean {\n    return second.index === this.time.seconds;\n  }\n\n  isSelected12Hours(value: { index: number; value: string }): boolean {\n    return value.value.toUpperCase() === this.time.selected12Hours;\n  }\n\n  ngOnInit(): void {\n    this.time.changes.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      this.changed();\n      this.touched();\n      this.scrollToTime(120);\n    });\n    this.buildTimes();\n\n    this.ngZone.runOutsideAngular(() => {\n      setTimeout(() => {\n        this.scrollToTime();\n        this.firstScrolled = true;\n      });\n    });\n\n    fromEventOutsideAngular(this.elementRef.nativeElement, 'mousedown')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(event => {\n        event.preventDefault();\n      });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzUse12Hours, nzDefaultOpenValue } = changes;\n    if (!nzUse12Hours?.previousValue && nzUse12Hours?.currentValue) {\n      this.build12Hours();\n      this.enabledColumns++;\n    }\n    if (nzDefaultOpenValue?.currentValue) {\n      this.time.setDefaultOpenValue(this.nzDefaultOpenValue || new Date());\n    }\n  }\n\n  writeValue(value: Date): void {\n    this.time.setValue(value, this.nzUse12Hours);\n    this.buildTimes();\n\n    if (value && this.firstScrolled) {\n      this.scrollToTime(120);\n    }\n    // Mark this component to be checked manually with internal properties changing (see: https://github.com/angular/angular/issues/10816)\n    this.cdr.markForCheck();\n  }\n\n  registerOnChange(fn: (value: Date) => void): void {\n    this.onChange = fn;\n  }\n\n  registerOnTouched(fn: () => void): void {\n    this.onTouch = fn;\n  }\n}\n"
  },
  {
    "path": "components/time-picker/time-picker.component.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Direction } from '@angular/cdk/bidi';\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport { registerLocaleData } from '@angular/common';\nimport zh from '@angular/common/locales/zh';\nimport {\n  Component,\n  DebugElement,\n  provideZoneChangeDetection,\n  signal,\n  viewChild,\n  ViewChild,\n  type WritableSignal\n} from '@angular/core';\nimport { ComponentFixture, fakeAsync, flush, inject, TestBed, tick } from '@angular/core/testing';\nimport { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { NZ_FORM_SIZE, NZ_FORM_VARIANT } from 'ng-zorro-antd/core/form';\nimport { dispatchFakeEvent, dispatchMouseEvent, typeInElement } from 'ng-zorro-antd/core/testing';\nimport { NzPlacement, NzStatus, NzVariant, type NzSizeLDSType } from 'ng-zorro-antd/core/types';\nimport { PREFIX_CLASS } from 'ng-zorro-antd/date-picker';\nimport { getPickerInput, getPickerOkButton } from 'ng-zorro-antd/date-picker/testing/util';\nimport { NzFormControlStatusType, NzFormModule } from 'ng-zorro-antd/form';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NZ_SPACE_COMPACT_SIZE } from 'ng-zorro-antd/space';\n\nimport { en_GB, NzI18nService } from '../i18n';\nimport { NzTimePickerComponent } from './time-picker.component';\n\nregisterLocaleData(zh);\n\ndescribe('time-picker', () => {\n  let overlayContainer: OverlayContainer;\n  let overlayContainerElement: HTMLElement;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations(), provideZoneChangeDetection()]\n    });\n  });\n\n  beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n    overlayContainer = oc;\n    overlayContainerElement = oc.getContainerElement();\n  }));\n\n  afterEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n    oc.ngOnDestroy();\n    overlayContainer.ngOnDestroy();\n  }));\n\n  describe('basic', () => {\n    let testComponent: NzTestTimePickerComponent;\n    let fixture: ComponentFixture<NzTestTimePickerComponent>;\n    let timeElement: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTimePickerComponent);\n      testComponent = fixture.debugElement.componentInstance;\n      fixture.detectChanges();\n      timeElement = fixture.debugElement.query(By.directive(NzTimePickerComponent));\n    });\n\n    it('should init work', () => {\n      fixture.detectChanges();\n      expect(timeElement.nativeElement.classList).toContain('ant-picker');\n      expect(timeElement.nativeElement.classList).not.toContain('ant-picker-disabled');\n    });\n\n    it('should autofocus work', () => {\n      fixture.detectChanges();\n      testComponent.autoFocus = true;\n      fixture.detectChanges();\n      expect(timeElement.nativeElement.querySelector('input').attributes.getNamedItem('autofocus').name).toBe(\n        'autofocus'\n      );\n      testComponent.autoFocus = false;\n      fixture.detectChanges();\n      expect(timeElement.nativeElement.querySelector('input').attributes.getNamedItem('autofocus')).toBe(null);\n    });\n\n    it('should focus and blur function work', () => {\n      fixture.detectChanges();\n      expect(timeElement.nativeElement.querySelector('input') === document.activeElement).toBe(false);\n      testComponent.nzTimePickerComponent.focus();\n      fixture.detectChanges();\n      expect(timeElement.nativeElement.querySelector('input') === document.activeElement).toBe(true);\n      testComponent.nzTimePickerComponent.blur();\n      fixture.detectChanges();\n      expect(timeElement.nativeElement.querySelector('input') === document.activeElement).toBe(false);\n    });\n\n    it('should disabled work', fakeAsync(() => {\n      testComponent.disabled = true;\n      fixture.detectChanges();\n\n      const inputElement = fixture.debugElement.query(By.css('input')).nativeElement as HTMLInputElement;\n      expect(inputElement.disabled).toBe(true);\n      expect(timeElement.nativeElement.classList).toContain('ant-picker-disabled');\n      expect(timeElement.componentInstance.nzDisabled).toBeTruthy();\n      testComponent.nzTimePickerComponent.focus();\n      fixture.detectChanges();\n      expect(timeElement.nativeElement.querySelector('input') === document.activeElement).toBe(false);\n\n      testComponent.nzTimePickerComponent.setDisabledState(false);\n      fixture.detectChanges();\n      flush();\n      expect(inputElement.disabled).toBe(false);\n      expect(timeElement.nativeElement.classList).not.toContain('ant-picker-disabled');\n      expect(timeElement.componentInstance.nzDisabled).toBeFalsy();\n      testComponent.nzTimePickerComponent.focus();\n      fixture.detectChanges();\n      expect(timeElement.nativeElement.querySelector('input') === document.activeElement).toBe(true);\n\n      testComponent.nzTimePickerComponent.setDisabledState(true);\n      fixture.detectChanges();\n      flush();\n      expect(inputElement.disabled).toBe(true);\n      expect(timeElement.nativeElement.classList).toContain('ant-picker-disabled');\n      expect(timeElement.componentInstance.nzDisabled).toBeTruthy();\n      testComponent.nzTimePickerComponent.focus();\n      fixture.detectChanges();\n      expect(timeElement.nativeElement.querySelector('input') === document.activeElement).toBe(false);\n    }));\n\n    it('should readOnly work', () => {\n      testComponent.nzInputReadOnly = true;\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement).readOnly).toBeTruthy();\n\n      testComponent.nzInputReadOnly = false;\n      fixture.detectChanges();\n      expect(getPickerInput(fixture.debugElement).readOnly).not.toBeTruthy();\n    });\n\n    it('should open and close work', () => {\n      testComponent.open = true;\n      fixture.detectChanges();\n      expect(testComponent.openChange).toHaveBeenCalledTimes(0);\n      testComponent.nzTimePickerComponent.close();\n      fixture.detectChanges();\n      expect(testComponent.openChange).toHaveBeenCalledTimes(2);\n      expect(testComponent.open).toBe(false);\n      testComponent.nzTimePickerComponent.open();\n      fixture.detectChanges();\n      expect(testComponent.openChange).toHaveBeenCalledTimes(3);\n      expect(testComponent.open).toBe(true);\n    });\n\n    it('should clear work', fakeAsync(() => {\n      fixture.detectChanges();\n      testComponent.date = new Date('2018-11-11 11:11:11');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      timeElement.nativeElement.querySelector('.ant-picker-clear').click();\n      fixture.detectChanges();\n      expect(testComponent.date).toBeNull();\n    }));\n\n    it('should support default nzfomat in 12-hours', () => {\n      testComponent.use12Hours = true;\n      fixture.detectChanges();\n      expect(testComponent.nzTimePickerComponent.nzFormat).toBe('h:mm:ss a');\n    });\n\n    it('should support ngModelChange', fakeAsync(() => {\n      testComponent.date = new Date('2020-03-26 11:33:00');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      const nzOnChange = spyOn(testComponent, 'onChange');\n      testComponent.open = true;\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-picker-time-panel-cell-selected > div')!.textContent).toBe(\n        '11'\n      );\n\n      dispatchMouseEvent(overlayContainerElement.querySelector('.ant-picker-time-panel-cell')!, 'click');\n      fixture.detectChanges();\n      getPickerInput(fixture.debugElement).dispatchEvent(new KeyboardEvent('keyup', { key: 'enter' }));\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(nzOnChange).toHaveBeenCalled();\n      const result = (nzOnChange.calls.allArgs()[0] as Date[])[0];\n      expect(result.getHours()).toBe(0);\n      expect(testComponent.nzTimePickerComponent.inputRef.nativeElement.value).toBe('00:33:00');\n    }));\n\n    it('should support ISO string', fakeAsync(() => {\n      testComponent.date = new Date('2020-03-27T13:49:54.917Z');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      testComponent.open = true;\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      const date = new Date(testComponent.date);\n      expect(\n        queryFromOverlay('.ant-picker-time-panel-column:nth-child(1) .ant-picker-time-panel-cell-selected > div')!\n          .textContent\n      ).toBe(date.getHours().toString());\n      expect(\n        queryFromOverlay('.ant-picker-time-panel-column:nth-child(2) .ant-picker-time-panel-cell-selected > div')!\n          .textContent\n      ).toBe(date.getMinutes().toString());\n    }));\n\n    it('should support custom suffixIcon', fakeAsync(() => {\n      testComponent.nzSuffixIcon = 'calendar';\n      fixture.detectChanges();\n      expect(fixture.debugElement.query(By.css(`.anticon-calendar`))).toBeDefined();\n    }));\n\n    it('should display string prefix as text content', () => {\n      testComponent.nzPrefix = 'Time';\n      fixture.detectChanges();\n      const prefixElement = fixture.debugElement.query(By.css('.ant-picker-prefix'));\n      expect(prefixElement).not.toBeNull();\n      expect(prefixElement.nativeElement.textContent.trim()).toBe('Time');\n    });\n\n    it('should not display prefix element when nzPrefix is not set', () => {\n      testComponent.nzPrefix = undefined;\n      fixture.detectChanges();\n      const prefixElement = fixture.debugElement.query(By.css('.ant-picker-prefix'));\n      expect(prefixElement).toBeNull();\n    });\n\n    it('should update prefix when nzPrefix changes', () => {\n      testComponent.nzPrefix = 'Start';\n      fixture.detectChanges();\n      let prefixElement = fixture.debugElement.query(By.css('.ant-picker-prefix'));\n      expect(prefixElement.nativeElement.textContent.trim()).toBe('Start');\n\n      testComponent.nzPrefix = 'End';\n      fixture.detectChanges();\n      prefixElement = fixture.debugElement.query(By.css('.ant-picker-prefix'));\n      expect(prefixElement.nativeElement.textContent.trim()).toBe('End');\n    });\n\n    it('should backdrop work', fakeAsync(() => {\n      testComponent.nzBackdrop = true;\n      testComponent.open = true;\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      const boundingBox = overlayContainerElement.children[0];\n      expect(boundingBox.children[0].classList).toContain('cdk-overlay-backdrop');\n    }));\n\n    it('should open with click and close with tab', fakeAsync(() => {\n      dispatchMouseEvent(getPickerInput(fixture.debugElement), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).not.toBeNull();\n\n      triggerInputBlur(fixture.debugElement);\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      expect(getPickerContainer()).toBeNull();\n    }));\n\n    it('should set default opening time when clicking ok', fakeAsync(() => {\n      const onChange = spyOn(testComponent, 'onChange');\n      dispatchMouseEvent(getPickerInput(fixture.debugElement), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).not.toBeNull();\n\n      const okButton = getPickerOkButton(fixture.debugElement);\n      expect(okButton).not.toBeNull();\n      dispatchFakeEvent(okButton, 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      const result = (onChange.calls.allArgs()[0] as Date[])[0];\n      expect(result.getHours()).toEqual(0);\n      expect(result.getMinutes()).toEqual(0);\n      expect(result.getSeconds()).toEqual(0);\n    }));\n\n    it('should not set time when clicking ok without default opening time', fakeAsync(() => {\n      const onChange = spyOn(testComponent, 'onChange');\n      testComponent.defaultOpenValue = null!;\n      dispatchMouseEvent(getPickerInput(fixture.debugElement), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).not.toBeNull();\n\n      const okButton = getPickerOkButton(fixture.debugElement);\n      expect(okButton).not.toBeNull();\n      dispatchFakeEvent(okButton, 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      const result = (onChange.calls.allArgs()[0] as Date[])[0];\n      expect(result).toBeNull();\n    }));\n\n    it('should set previous value when tabbing out with invalid input', fakeAsync(() => {\n      testComponent.date = new Date('2020-03-27T13:49:54.917');\n\n      fixture.detectChanges();\n      dispatchMouseEvent(getPickerInput(fixture.debugElement), 'click');\n      fixture.detectChanges();\n      tick(500);\n\n      fixture.detectChanges();\n      const input = getPickerInput(fixture.debugElement);\n      typeInElement('invalid', input);\n      fixture.detectChanges();\n\n      triggerInputBlur(fixture.debugElement);\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      expect(input.value).not.toEqual('invalid');\n    }));\n\n    it('should set new value when tabbing out with valid input', fakeAsync(() => {\n      const onChange = spyOn(testComponent, 'onChange');\n      testComponent.date = new Date('2020-03-27T13:49:54.917');\n\n      fixture.detectChanges();\n      dispatchMouseEvent(getPickerInput(fixture.debugElement), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      const input = getPickerInput(fixture.debugElement);\n      typeInElement('20:10:30', input);\n      fixture.detectChanges();\n\n      triggerInputBlur(fixture.debugElement);\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      const result = (onChange.calls.allArgs()[0] as Date[])[0];\n      expect(result.getHours()).toEqual(20);\n      expect(result.getMinutes()).toEqual(10);\n      expect(result.getSeconds()).toEqual(30);\n    }));\n\n    describe('should nzVariant works', () => {\n      it('filled', () => {\n        fixture.detectChanges();\n        expect(fixture.debugElement.query(By.css(`.ant-picker-filled`))).toBeNull();\n        fixture.componentInstance.nzVariant = 'filled';\n        fixture.detectChanges();\n        expect(fixture.debugElement.query(By.css(`.ant-picker-filled`))).toBeDefined();\n      });\n      it('borderless', () => {\n        fixture.detectChanges();\n        expect(fixture.debugElement.query(By.css(`.ant-picker-borderless`))).toBeNull();\n        fixture.componentInstance.nzVariant = 'borderless';\n        fixture.detectChanges();\n        expect(fixture.debugElement.query(By.css(`.ant-picker-borderless`))).toBeDefined();\n      });\n      it('underlined', () => {\n        fixture.detectChanges();\n        expect(fixture.debugElement.query(By.css(`.ant-picker-underlined`))).toBeNull();\n        fixture.componentInstance.nzVariant = 'underlined';\n        fixture.detectChanges();\n        expect(fixture.debugElement.query(By.css(`.ant-picker-underlined`))).toBeDefined();\n      });\n    });\n\n    it('should not trigger blur after close panel', fakeAsync(() => {\n      dispatchMouseEvent(getPickerInput(fixture.debugElement), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n      expect(getPickerContainer()).not.toBeNull();\n\n      const okButton = getPickerOkButton(fixture.debugElement);\n      expect(okButton).not.toBeNull();\n      dispatchFakeEvent(okButton, 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      expect(timeElement.nativeElement.querySelector('input') === document.activeElement).toBe(false);\n    }));\n\n    describe('setup I18n service', () => {\n      let srv: NzI18nService;\n\n      beforeEach(inject([NzI18nService], (s: NzI18nService) => {\n        srv = s;\n      }));\n\n      it('should detect the language changes', fakeAsync(() => {\n        let placeHolderValue: string | undefined;\n        placeHolderValue = timeElement.nativeElement.querySelector('input').placeholder;\n\n        expect(placeHolderValue).toBe('请选择时间');\n\n        srv.setLocale(en_GB);\n        tick(400);\n        fixture.detectChanges();\n\n        placeHolderValue = timeElement.nativeElement.querySelector('input').placeholder;\n        expect(placeHolderValue).toBe('Select time');\n      }));\n    });\n  });\n\n  describe('placement', () => {\n    let fixture: ComponentFixture<NzTestTimePickerPlacementComponent>;\n    let fixtureInstance: NzTestTimePickerPlacementComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTimePickerPlacementComponent);\n      fixtureInstance = fixture.componentInstance;\n      fixture.detectChanges();\n    });\n\n    function openTimePicker(): void {\n      dispatchMouseEvent(getPickerInput(fixture.debugElement), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n    }\n\n    function closeTimePicker(): void {\n      triggerInputBlur(fixture.debugElement);\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n    }\n\n    it('should default to bottomLeft placement', fakeAsync(() => {\n      expect(fixtureInstance.nzTimePickerComponent().nzPlacement()).toBe('bottomLeft');\n    }));\n\n    it('should support bottomLeft placement', fakeAsync(() => {\n      fixtureInstance.nzPlacement = 'bottomLeft';\n      fixture.detectChanges();\n      openTimePicker();\n\n      const dropdown = queryFromOverlay('.ant-picker-dropdown');\n      expect(dropdown).toBeTruthy();\n      expect(dropdown.classList.contains('ant-picker-dropdown-placement-bottomLeft')).toBe(true);\n      expect(dropdown.classList.contains('ant-picker-dropdown-placement-topLeft')).toBe(false);\n      expect(dropdown.classList.contains('ant-picker-dropdown-placement-bottomRight')).toBe(false);\n      expect(dropdown.classList.contains('ant-picker-dropdown-placement-topRight')).toBe(false);\n\n      closeTimePicker();\n    }));\n\n    it('should support bottomRight placement', fakeAsync(() => {\n      fixtureInstance.nzPlacement = 'bottomRight';\n      fixture.detectChanges();\n      openTimePicker();\n\n      const dropdown = queryFromOverlay('.ant-picker-dropdown');\n      expect(dropdown).toBeTruthy();\n      expect(dropdown.classList.contains('ant-picker-dropdown-placement-bottomLeft')).toBe(false);\n      expect(dropdown.classList.contains('ant-picker-dropdown-placement-topLeft')).toBe(false);\n      expect(dropdown.classList.contains('ant-picker-dropdown-placement-bottomRight')).toBe(true);\n      expect(dropdown.classList.contains('ant-picker-dropdown-placement-topRight')).toBe(false);\n\n      closeTimePicker();\n    }));\n\n    it('should support topLeft placement', fakeAsync(() => {\n      fixtureInstance.nzPlacement = 'topLeft';\n      fixture.detectChanges();\n      openTimePicker();\n\n      const dropdown = queryFromOverlay('.ant-picker-dropdown');\n      expect(dropdown).toBeTruthy();\n      expect(dropdown.classList.contains('ant-picker-dropdown-placement-bottomLeft')).toBe(false);\n      expect(dropdown.classList.contains('ant-picker-dropdown-placement-topLeft')).toBe(true);\n      expect(dropdown.classList.contains('ant-picker-dropdown-placement-bottomRight')).toBe(false);\n      expect(dropdown.classList.contains('ant-picker-dropdown-placement-topRight')).toBe(false);\n\n      closeTimePicker();\n    }));\n\n    it('should support topRight placement', fakeAsync(() => {\n      fixtureInstance.nzPlacement = 'topRight';\n      fixture.detectChanges();\n      openTimePicker();\n\n      const dropdown = queryFromOverlay('.ant-picker-dropdown');\n      expect(dropdown).toBeTruthy();\n      expect(dropdown.classList.contains('ant-picker-dropdown-placement-bottomLeft')).toBe(false);\n      expect(dropdown.classList.contains('ant-picker-dropdown-placement-topLeft')).toBe(false);\n      expect(dropdown.classList.contains('ant-picker-dropdown-placement-bottomRight')).toBe(false);\n      expect(dropdown.classList.contains('ant-picker-dropdown-placement-topRight')).toBe(true);\n\n      closeTimePicker();\n    }));\n\n    it('should dynamically change placement', fakeAsync(() => {\n      // Start with bottomLeft\n      fixtureInstance.nzPlacement = 'bottomLeft';\n      fixture.detectChanges();\n      openTimePicker();\n\n      let dropdown = queryFromOverlay('.ant-picker-dropdown');\n      expect(dropdown.classList.contains('ant-picker-dropdown-placement-bottomLeft')).toBe(true);\n\n      closeTimePicker();\n\n      // Change to topRight\n      fixtureInstance.nzPlacement = 'topRight';\n      fixture.detectChanges();\n      openTimePicker();\n\n      dropdown = queryFromOverlay('.ant-picker-dropdown');\n      expect(dropdown.classList.contains('ant-picker-dropdown-placement-bottomLeft')).toBe(false);\n      expect(dropdown.classList.contains('ant-picker-dropdown-placement-topRight')).toBe(true);\n\n      closeTimePicker();\n    }));\n\n    it('should update placement when input changes without reopening', fakeAsync(() => {\n      // Start with bottomLeft\n      fixtureInstance.nzPlacement = 'bottomLeft';\n      fixture.detectChanges();\n      expect(fixtureInstance.nzTimePickerComponent()?.nzPlacement()).toBe('bottomLeft');\n\n      // Change to topRight\n      fixtureInstance.nzPlacement = 'topRight';\n      fixture.detectChanges();\n      expect(fixtureInstance.nzTimePickerComponent().nzPlacement()).toBe('topRight');\n\n      // Open and verify the correct class is applied\n      openTimePicker();\n      const dropdown = queryFromOverlay('.ant-picker-dropdown');\n      expect(dropdown.classList.contains('ant-picker-dropdown-placement-topRight')).toBe(true);\n\n      closeTimePicker();\n    }));\n\n    it('should change placement while picker is open', fakeAsync(() => {\n      fixtureInstance.nzPlacement = 'bottomLeft';\n      fixture.detectChanges();\n      openTimePicker();\n\n      let dropdown = queryFromOverlay('.ant-picker-dropdown');\n      expect(dropdown.classList.contains('ant-picker-dropdown-placement-bottomLeft')).toBe(true);\n\n      // Change placement while open\n      fixtureInstance.nzPlacement = 'topLeft';\n      fixture.detectChanges();\n      tick(100);\n      fixture.detectChanges();\n\n      dropdown = queryFromOverlay('.ant-picker-dropdown');\n      expect(dropdown.classList.contains('ant-picker-dropdown-placement-topLeft')).toBe(true);\n      expect(dropdown.classList.contains('ant-picker-dropdown-placement-bottomLeft')).toBe(false);\n\n      closeTimePicker();\n    }));\n\n    it('should maintain placement when selecting a time', fakeAsync(() => {\n      fixtureInstance.nzPlacement = 'topLeft';\n      fixture.detectChanges();\n      openTimePicker();\n\n      const dropdown = queryFromOverlay('.ant-picker-dropdown');\n      expect(dropdown.classList.contains('ant-picker-dropdown-placement-topLeft')).toBe(true);\n\n      // Select a time\n      dispatchMouseEvent(overlayContainerElement.querySelector('.ant-picker-time-panel-cell')!, 'click');\n      fixture.detectChanges();\n\n      // Dropdown should still have the correct placement class\n      const dropdownAfterSelect = queryFromOverlay('.ant-picker-dropdown');\n      expect(dropdownAfterSelect.classList.contains('ant-picker-dropdown-placement-topLeft')).toBe(true);\n\n      closeTimePicker();\n    }));\n\n    it('should work with disabled state', fakeAsync(() => {\n      fixtureInstance.nzPlacement = 'topRight';\n      fixture.detectChanges();\n\n      // Open and verify placement\n      openTimePicker();\n      const dropdown = queryFromOverlay('.ant-picker-dropdown');\n      expect(dropdown.classList.contains('ant-picker-dropdown-placement-topRight')).toBe(true);\n\n      closeTimePicker();\n    }));\n  });\n\n  describe('status', () => {\n    let testComponent: NzTestTimePickerStatusComponent;\n    let fixture: ComponentFixture<NzTestTimePickerStatusComponent>;\n    let timeElement: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTimePickerStatusComponent);\n      testComponent = fixture.debugElement.componentInstance;\n      fixture.detectChanges();\n      timeElement = fixture.debugElement.query(By.directive(NzTimePickerComponent));\n    });\n\n    it('should className correct with nzStatus', () => {\n      fixture.detectChanges();\n      expect(timeElement.nativeElement.classList).toContain('ant-picker-status-error');\n\n      testComponent.status = 'warning';\n      fixture.detectChanges();\n      expect(timeElement.nativeElement.className).toContain('ant-picker-status-warning');\n\n      testComponent.status = '';\n      fixture.detectChanges();\n      expect(timeElement.nativeElement.className).not.toContain('ant-picker-status-warning');\n    });\n  });\n\n  describe('RTL', () => {\n    let testComponent: NzTestTimePickerDirComponent;\n    let fixture: ComponentFixture<NzTestTimePickerDirComponent>;\n    let timeElement: DebugElement;\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTimePickerDirComponent);\n      testComponent = fixture.debugElement.componentInstance;\n      fixture.detectChanges();\n      timeElement = fixture.debugElement.query(By.directive(NzTimePickerComponent));\n    });\n\n    it('should className correct on dir change', () => {\n      expect(timeElement.nativeElement.classList).not.toContain('ant-picker-rtl');\n      testComponent.dir = 'rtl';\n      fixture.detectChanges();\n      expect(timeElement.nativeElement.classList).toContain('ant-picker-rtl');\n    });\n\n    it('should work correctly with placement in RTL mode', fakeAsync(() => {\n      testComponent.dir = 'rtl';\n      testComponent.nzPlacement = 'bottomLeft';\n      fixture.detectChanges();\n\n      dispatchMouseEvent(getPickerInput(fixture.debugElement), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      const dropdown = queryFromOverlay('.ant-picker-dropdown');\n      expect(dropdown.classList.contains('ant-picker-dropdown-rtl')).toBe(true);\n      expect(dropdown.classList.contains('ant-picker-dropdown-placement-bottomLeft')).toBe(true);\n\n      triggerInputBlur(fixture.debugElement);\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n    }));\n  });\n\n  describe('prefix with template', () => {\n    let fixture: ComponentFixture<NzTestTimePickerPrefixTemplateComponent>;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTimePickerPrefixTemplateComponent);\n      fixture.detectChanges();\n    });\n\n    it('should render prefix template with icon', () => {\n      const prefixElement = fixture.debugElement.query(By.css('.ant-picker-prefix'));\n      expect(prefixElement).not.toBeNull();\n      expect(prefixElement.query(By.css('.anticon-clock-circle'))).not.toBeNull();\n    });\n  });\n\n  describe('in form', () => {\n    let testComponent: NzTestTimePickerInFormComponent;\n    let fixture: ComponentFixture<NzTestTimePickerInFormComponent>;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTimePickerInFormComponent);\n      testComponent = fixture.debugElement.componentInstance;\n    });\n\n    it('should disable if the form is disabled initially and nzDisabled set to false', fakeAsync(() => {\n      testComponent.disable();\n      fixture.detectChanges();\n      flush();\n      const timeElement = fixture.debugElement.query(By.directive(NzTimePickerComponent));\n      const inputElement = fixture.debugElement.query(By.css('input')).nativeElement as HTMLInputElement;\n\n      expect(timeElement.componentInstance.nzDisabled).toBe(true);\n      expect(timeElement.nativeElement.classList).toContain('ant-picker-disabled');\n      expect(inputElement.disabled).toBe(true);\n    }));\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n      const timeElement = fixture.debugElement.query(By.directive(NzTimePickerComponent)).nativeElement;\n      expect(timeElement.classList).toContain('ant-picker-status-error');\n      expect(timeElement.querySelector('nz-form-item-feedback-icon')).toBeTruthy();\n\n      testComponent.status = 'warning';\n      fixture.detectChanges();\n      expect(timeElement.classList).toContain('ant-picker-status-warning');\n\n      testComponent.status = 'success';\n      fixture.detectChanges();\n      expect(timeElement.classList).toContain('ant-picker-status-success');\n\n      testComponent.feedback = false;\n      fixture.detectChanges();\n      expect(timeElement.querySelector('nz-form-item-feedback-icon')).toBeNull();\n    });\n  });\n\n  describe('confirmation', () => {\n    let testComponent: NzTestTimePickerConfirmationComponent;\n    let fixture: ComponentFixture<NzTestTimePickerConfirmationComponent>;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTimePickerConfirmationComponent);\n      testComponent = fixture.debugElement.componentInstance;\n      fixture.detectChanges();\n    });\n\n    it('should emit value when OK button is clicked with nzNeedConfirm enabled', fakeAsync(() => {\n      const onChange = spyOn(testComponent, 'onChange');\n      testComponent.needConfirm = true;\n      testComponent.date = new Date('2020-03-27T10:30:00');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      dispatchMouseEvent(getPickerInput(fixture.debugElement), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      expect(getPickerContainer()).not.toBeNull();\n\n      // Select a different time\n      const timeCell = overlayContainerElement.querySelector('.ant-picker-time-panel-cell:nth-child(3)');\n      dispatchMouseEvent(timeCell!, 'click');\n      fixture.detectChanges();\n\n      // Click OK button\n      const okButton = getPickerOkButton(fixture.debugElement);\n      expect(okButton).not.toBeNull();\n      dispatchFakeEvent(okButton, 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      expect(onChange).toHaveBeenCalled();\n      expect(getPickerContainer()).toBeNull();\n    }));\n\n    it('should revert to previous value when tabbing out without OK click with nzNeedConfirm enabled', fakeAsync(() => {\n      const onChange = spyOn(testComponent, 'onChange');\n      testComponent.needConfirm = true;\n      testComponent.date = new Date('2020-03-27T10:30:00');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      const originalValue = testComponent.date;\n\n      dispatchMouseEvent(getPickerInput(fixture.debugElement), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      expect(getPickerContainer()).not.toBeNull();\n\n      // Select a different time\n      const timeCell = overlayContainerElement.querySelector('.ant-picker-time-panel-cell:nth-child(5)');\n      dispatchMouseEvent(timeCell!, 'click');\n      fixture.detectChanges();\n\n      // Tab out without clicking OK\n      triggerInputBlur(fixture.debugElement);\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      expect(onChange).not.toHaveBeenCalled();\n      expect(getPickerContainer()).toBeNull();\n      // Value should revert to original\n      expect(testComponent.nzTimePickerComponent.value?.getTime()).toBe((originalValue as Date).getTime());\n    }));\n\n    it('should revert to previous value when pressing Enter without OK click with nzNeedConfirm enabled', fakeAsync(() => {\n      const onChange = spyOn(testComponent, 'onChange');\n      testComponent.needConfirm = true;\n      testComponent.date = new Date('2020-03-27T10:30:00');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      const originalValue = testComponent.date;\n\n      dispatchMouseEvent(getPickerInput(fixture.debugElement), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      expect(getPickerContainer()).not.toBeNull();\n\n      // Select a different time\n      const timeCell = overlayContainerElement.querySelector('.ant-picker-time-panel-cell:nth-child(8)');\n      dispatchMouseEvent(timeCell!, 'click');\n      fixture.detectChanges();\n\n      // Press Enter without clicking OK\n      getPickerInput(fixture.debugElement).dispatchEvent(new KeyboardEvent('keyup', { key: 'enter' }));\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      expect(onChange).not.toHaveBeenCalled();\n      expect(getPickerContainer()).toBeNull();\n      // Value should revert to original\n      expect(testComponent.nzTimePickerComponent.value?.getTime()).toBe((originalValue as Date).getTime());\n    }));\n\n    it('should emit value when tabbing out without nzNeedConfirm (default behavior)', fakeAsync(() => {\n      const onChange = spyOn(testComponent, 'onChange');\n      testComponent.needConfirm = false;\n      testComponent.date = new Date('2020-03-27T10:30:00');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      dispatchMouseEvent(getPickerInput(fixture.debugElement), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      expect(getPickerContainer()).not.toBeNull();\n\n      // Select a different time\n      const timeCell = overlayContainerElement.querySelector('.ant-picker-time-panel-cell:nth-child(10)');\n      dispatchMouseEvent(timeCell!, 'click');\n      fixture.detectChanges();\n\n      // Tab out\n      triggerInputBlur(fixture.debugElement);\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      expect(onChange).toHaveBeenCalled();\n      expect(getPickerContainer()).toBeNull();\n    }));\n\n    it('should emit value when OK button is clicked without nzNeedConfirm', fakeAsync(() => {\n      const onChange = spyOn(testComponent, 'onChange');\n      testComponent.needConfirm = false;\n      fixture.detectChanges();\n\n      dispatchMouseEvent(getPickerInput(fixture.debugElement), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      expect(getPickerContainer()).not.toBeNull();\n\n      const okButton = getPickerOkButton(fixture.debugElement);\n      expect(okButton).not.toBeNull();\n      dispatchFakeEvent(okButton, 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      expect(onChange).toHaveBeenCalled();\n      expect(getPickerContainer()).toBeNull();\n    }));\n\n    it('should handle multiple open/close cycles correctly with nzNeedConfirm', fakeAsync(() => {\n      const onChange = spyOn(testComponent, 'onChange');\n      testComponent.needConfirm = true;\n      testComponent.date = new Date('2020-03-27T10:30:00');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      // First cycle: select and confirm\n      dispatchMouseEvent(getPickerInput(fixture.debugElement), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      const timeCell1 = overlayContainerElement.querySelector('.ant-picker-time-panel-cell:nth-child(5)');\n      dispatchMouseEvent(timeCell1!, 'click');\n      fixture.detectChanges();\n\n      const okButton1 = getPickerOkButton(fixture.debugElement);\n      dispatchFakeEvent(okButton1, 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      expect(onChange).toHaveBeenCalledTimes(1);\n      onChange.calls.reset();\n\n      // Second cycle: select but don't confirm\n      dispatchMouseEvent(getPickerInput(fixture.debugElement), 'click');\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      const timeCell2 = overlayContainerElement.querySelector('.ant-picker-time-panel-cell:nth-child(10)');\n      dispatchMouseEvent(timeCell2!, 'click');\n      fixture.detectChanges();\n\n      triggerInputBlur(fixture.debugElement);\n      fixture.detectChanges();\n      tick(500);\n      fixture.detectChanges();\n\n      expect(onChange).not.toHaveBeenCalled();\n    }));\n  });\n\n  function queryFromOverlay(selector: string): HTMLElement {\n    return overlayContainerElement.querySelector(selector) as HTMLElement;\n  }\n\n  function getPickerContainer(): HTMLElement {\n    return queryFromOverlay(`.${PREFIX_CLASS}-panel-container`) as HTMLElement;\n  }\n\n  function triggerInputBlur(debugElement: DebugElement): void {\n    dispatchFakeEvent(getPickerInput(debugElement), 'blur');\n  }\n});\n\ndescribe('time-picker size', () => {\n  let fixture: ComponentFixture<NzTestTimePickerSizeComponent>;\n  let timePickerElement: HTMLElement;\n  let compactSizeSignal: WritableSignal<NzSizeLDSType>;\n  let formSizeSignal: WritableSignal<NzSizeLDSType>;\n\n  beforeEach(() => {\n    compactSizeSignal = signal<NzSizeLDSType>('large');\n    formSizeSignal = signal<NzSizeLDSType>('default');\n  });\n  afterEach(() => {\n    TestBed.resetTestingModule();\n  });\n  it('should set correctly the size from the formSize signal', () => {\n    TestBed.configureTestingModule({\n      providers: [\n        { provide: NZ_FORM_SIZE, useValue: formSizeSignal },\n        { provide: NZ_SPACE_COMPACT_SIZE, useValue: compactSizeSignal }\n      ]\n    });\n    fixture = TestBed.createComponent(NzTestTimePickerSizeComponent);\n    timePickerElement = fixture.debugElement.query(By.directive(NzTimePickerComponent)).nativeElement;\n    fixture.detectChanges();\n    formSizeSignal.set('large');\n    fixture.detectChanges();\n    expect(timePickerElement.classList).toContain('ant-picker-large');\n  });\n  it('should set correctly the size from the compactSize signal', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_SPACE_COMPACT_SIZE, useValue: compactSizeSignal }]\n    });\n    fixture = TestBed.createComponent(NzTestTimePickerSizeComponent);\n    timePickerElement = fixture.debugElement.query(By.directive(NzTimePickerComponent)).nativeElement;\n    fixture.detectChanges();\n    expect(timePickerElement.classList).toContain('ant-picker-large');\n  });\n  it('should set correctly the size from the component input', () => {\n    fixture = TestBed.createComponent(NzTestTimePickerSizeComponent);\n    timePickerElement = fixture.debugElement.query(By.directive(NzTimePickerComponent)).nativeElement;\n    fixture.componentInstance.size = 'large';\n    fixture.detectChanges();\n    expect(timePickerElement.classList).toContain('ant-picker-large');\n  });\n});\n\ndescribe('finalVariant', () => {\n  let fixture: ComponentFixture<NzTestTimePickerVariantComponent>;\n  let timePickerElement: HTMLElement;\n  let formVariantSignal: WritableSignal<NzVariant>;\n  beforeEach(() => {\n    formVariantSignal = signal<NzVariant>('outlined');\n  });\n  afterEach(() => {\n    TestBed.resetTestingModule();\n  });\n  it('should use the formVariant when nzVariant is not explicitly set', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_FORM_VARIANT, useValue: formVariantSignal }]\n    });\n    fixture = TestBed.createComponent(NzTestTimePickerVariantComponent);\n    timePickerElement = fixture.debugElement.query(By.directive(NzTimePickerComponent)).nativeElement;\n    fixture.detectChanges();\n    formVariantSignal.set('filled');\n    fixture.detectChanges();\n    expect(timePickerElement.classList).toContain('ant-picker-filled');\n  });\n  it('should use nzVariant over formVariant when nzVariant is explicitly set', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_FORM_VARIANT, useValue: formVariantSignal }]\n    });\n    fixture = TestBed.createComponent(NzTestTimePickerVariantComponent);\n    timePickerElement = fixture.debugElement.query(By.directive(NzTimePickerComponent)).nativeElement;\n    fixture.detectChanges();\n    formVariantSignal.set('filled');\n    fixture.componentInstance.variant.set('borderless');\n    fixture.detectChanges();\n    expect(timePickerElement.classList).toContain('ant-picker-borderless');\n    expect(timePickerElement.classList).not.toContain('ant-picker-filled');\n  });\n  it('should not apply formVariant when nzVariant is explicitly set', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_FORM_VARIANT, useValue: formVariantSignal }]\n    });\n    fixture = TestBed.createComponent(NzTestTimePickerVariantComponent);\n    timePickerElement = fixture.debugElement.query(By.directive(NzTimePickerComponent)).nativeElement;\n    fixture.detectChanges();\n    fixture.componentInstance.variant.set('outlined');\n    fixture.detectChanges();\n    formVariantSignal.set('filled');\n    fixture.detectChanges();\n    expect(timePickerElement.classList).not.toContain('ant-picker-filled');\n  });\n  it('should use nzVariant when no formVariant is provided', () => {\n    fixture = TestBed.createComponent(NzTestTimePickerVariantComponent);\n    timePickerElement = fixture.debugElement.query(By.directive(NzTimePickerComponent)).nativeElement;\n    fixture.detectChanges();\n    fixture.componentInstance.variant.set('filled');\n    fixture.detectChanges();\n    expect(timePickerElement.classList).toContain('ant-picker-filled');\n  });\n  it('should default to outlined when neither nzVariant nor formVariant is set', () => {\n    fixture = TestBed.createComponent(NzTestTimePickerVariantComponent);\n    timePickerElement = fixture.debugElement.query(By.directive(NzTimePickerComponent)).nativeElement;\n    fixture.detectChanges();\n    expect(timePickerElement.classList).not.toContain('ant-picker-filled');\n    expect(timePickerElement.classList).not.toContain('ant-picker-borderless');\n    expect(timePickerElement.classList).not.toContain('ant-picker-underlined');\n  });\n});\n\n@Component({\n  imports: [NzTimePickerComponent, FormsModule],\n  template: `\n    <nz-time-picker\n      [nzAutoFocus]=\"autoFocus\"\n      [(ngModel)]=\"date\"\n      (ngModelChange)=\"onChange($event)\"\n      [(nzOpen)]=\"open\"\n      (nzOpenChange)=\"openChange($event)\"\n      [nzDisabled]=\"disabled\"\n      [nzInputReadOnly]=\"nzInputReadOnly\"\n      [nzUse12Hours]=\"use12Hours\"\n      [nzSuffixIcon]=\"nzSuffixIcon\"\n      [nzPrefix]=\"nzPrefix\"\n      [nzBackdrop]=\"nzBackdrop\"\n      [nzDefaultOpenValue]=\"defaultOpenValue\"\n      [nzVariant]=\"nzVariant\"\n    />\n  `\n})\nexport class NzTestTimePickerComponent {\n  open = false;\n  openChange = jasmine.createSpy('open change');\n  autoFocus = false;\n  date: Date | string = new Date();\n  disabled = false;\n  nzInputReadOnly = false;\n  use12Hours = false;\n  nzSuffixIcon: string = 'close-circle';\n  nzPrefix?: string;\n  nzBackdrop = false;\n  nzVariant: NzVariant = 'outlined';\n  defaultOpenValue: Date = new Date('2020-03-27T00:00:00');\n  onChange(_: Date | null): void {}\n  @ViewChild(NzTimePickerComponent, { static: false }) nzTimePickerComponent!: NzTimePickerComponent;\n}\n\n@Component({\n  imports: [NzTimePickerComponent],\n  template: `<nz-time-picker [nzStatus]=\"status\" />`\n})\nexport class NzTestTimePickerStatusComponent {\n  status: NzStatus = 'error';\n}\n\n@Component({\n  imports: [NzTimePickerComponent, BidiModule],\n  template: `\n    <div [dir]=\"dir\">\n      <nz-time-picker [nzPlacement]=\"nzPlacement\" />\n    </div>\n  `\n})\nexport class NzTestTimePickerDirComponent {\n  dir: Direction = 'ltr';\n  nzPlacement: NzPlacement = 'bottomLeft';\n}\n\n@Component({\n  imports: [NzFormModule, ReactiveFormsModule, NzTimePickerComponent],\n  template: `\n    <form nz-form [formGroup]=\"timePickerForm\">\n      <nz-form-item>\n        <nz-form-control [nzHasFeedback]=\"feedback\" [nzValidateStatus]=\"status\">\n          <nz-time-picker formControlName=\"time\" [nzDisabled]=\"disabled\" />\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `\n})\nexport class NzTestTimePickerInFormComponent {\n  timePickerForm = new FormGroup({\n    time: new FormControl(new Date())\n  });\n  status: NzFormControlStatusType = 'error';\n  feedback = true;\n  disabled = false;\n\n  disable(): void {\n    this.timePickerForm.disable();\n  }\n}\n\n@Component({\n  imports: [NzTimePickerComponent, NzIconModule],\n  template: `\n    <nz-time-picker [nzPrefix]=\"prefixTemplate\" />\n    <ng-template #prefixTemplate>\n      <nz-icon nzType=\"clock-circle\" />\n    </ng-template>\n  `\n})\nexport class NzTestTimePickerPrefixTemplateComponent {}\n\n@Component({\n  imports: [NzTimePickerComponent, FormsModule],\n  template: `\n    <nz-time-picker\n      [(ngModel)]=\"date\"\n      (ngModelChange)=\"onChange($event)\"\n      [nzNeedConfirm]=\"needConfirm\"\n      [nzDefaultOpenValue]=\"defaultOpenValue\"\n    />\n  `\n})\nexport class NzTestTimePickerConfirmationComponent {\n  date: Date | null = null;\n  needConfirm = false;\n  defaultOpenValue: Date = new Date('2020-03-27T00:00:00');\n  onChange(_: Date | null): void {}\n  @ViewChild(NzTimePickerComponent, { static: false }) nzTimePickerComponent!: NzTimePickerComponent;\n}\n\n@Component({\n  imports: [NzTimePickerComponent, FormsModule],\n  template: ` <nz-time-picker [nzPlacement]=\"nzPlacement\" [(ngModel)]=\"date\" /> `\n})\nexport class NzTestTimePickerPlacementComponent {\n  nzPlacement: NzPlacement = 'bottomLeft';\n  date: Date | null = null;\n  nzTimePickerComponent = viewChild.required<NzTimePickerComponent>(NzTimePickerComponent);\n}\n\n@Component({\n  imports: [NzTimePickerComponent],\n  template: ` <nz-time-picker [nzSize]=\"size\" /> `\n})\nclass NzTestTimePickerSizeComponent {\n  size: NzSizeLDSType = 'default';\n}\n\n@Component({\n  imports: [NzTimePickerComponent],\n  template: `<nz-time-picker [nzVariant]=\"variant()\" />`\n})\nexport class NzTestTimePickerVariantComponent {\n  readonly variant = signal<NzVariant | undefined>(undefined);\n}\n"
  },
  {
    "path": "components/time-picker/time-picker.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { ConnectedOverlayPositionChange, OverlayModule } from '@angular/cdk/overlay';\nimport { Platform, _getEventTarget } from '@angular/cdk/platform';\nimport { AsyncPipe } from '@angular/common';\nimport {\n  AfterViewInit,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DestroyRef,\n  ElementRef,\n  EventEmitter,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  Renderer2,\n  SimpleChanges,\n  TemplateRef,\n  ViewChild,\n  ViewEncapsulation,\n  booleanAttribute,\n  computed,\n  forwardRef,\n  inject,\n  input,\n  linkedSignal,\n  signal\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { Observable, of } from 'rxjs';\nimport { distinctUntilChanged, map, withLatestFrom } from 'rxjs/operators';\n\nimport { isValid } from 'date-fns';\n\nimport { slideAnimationEnter, slideAnimationLeave } from 'ng-zorro-antd/core/animation';\nimport { NzConfigKey, NzConfigService, WithConfig } from 'ng-zorro-antd/core/config';\nimport {\n  NZ_FORM_SIZE,\n  NZ_FORM_VARIANT,\n  NzFormItemFeedbackIconComponent,\n  NzFormNoStatusService,\n  NzFormStatusService\n} from 'ng-zorro-antd/core/form';\nimport { warn } from 'ng-zorro-antd/core/logger';\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { DATE_PICKER_POSITION_MAP, DEFAULT_DATE_PICKER_POSITIONS, NzOverlayModule } from 'ng-zorro-antd/core/overlay';\nimport {\n  NgClassInterface,\n  NzPlacement,\n  NzSafeAny,\n  NzSizeLDSType,\n  NzStatus,\n  NzValidateStatus,\n  NzVariant\n} from 'ng-zorro-antd/core/types';\nimport { generateClassName, getStatusClassNames, isNil } from 'ng-zorro-antd/core/util';\nimport { DateHelperService, NzI18nService } from 'ng-zorro-antd/i18n';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NZ_SPACE_COMPACT_ITEM_TYPE, NZ_SPACE_COMPACT_SIZE, NzSpaceCompactItemDirective } from 'ng-zorro-antd/space';\n\nimport { NzTimePickerPanelComponent } from './time-picker-panel.component';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'timePicker';\n\n@Component({\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  selector: 'nz-time-picker',\n  exportAs: 'nzTimePicker',\n  template: `\n    @if (nzPrefix(); as prefix) {\n      <span class=\"ant-picker-prefix\">\n        <ng-container *nzStringTemplateOutlet=\"prefix\">{{ prefix }}</ng-container>\n      </span>\n    }\n    <div class=\"ant-picker-input\">\n      <input\n        #inputElement\n        [attr.id]=\"nzId\"\n        type=\"text\"\n        [size]=\"inputSize\"\n        autocomplete=\"off\"\n        [placeholder]=\"nzPlaceHolder || (i18nPlaceHolder$ | async)\"\n        [(ngModel)]=\"inputValue\"\n        [disabled]=\"nzDisabled\"\n        [readOnly]=\"nzInputReadOnly\"\n        (focus)=\"onFocus(true)\"\n        (blur)=\"onFocus(false)\"\n        (keyup.enter)=\"onKeyupEnter()\"\n        (keyup.escape)=\"onKeyupEsc()\"\n        (ngModelChange)=\"onInputChange($event)\"\n      />\n      <span class=\"ant-picker-suffix\">\n        <ng-container *nzStringTemplateOutlet=\"nzSuffixIcon; let suffixIcon\">\n          <nz-icon [nzType]=\"suffixIcon\" />\n        </ng-container>\n        @if (hasFeedback && !!status) {\n          <nz-form-item-feedback-icon [status]=\"status\" />\n        }\n      </span>\n      @if (nzAllowEmpty && !nzDisabled && value) {\n        <span class=\"ant-picker-clear\" (click)=\"onClickClearBtn($event)\">\n          <nz-icon nzType=\"close-circle\" nzTheme=\"fill\" [attr.aria-label]=\"nzClearText\" [attr.title]=\"nzClearText\" />\n        </span>\n      }\n    </div>\n\n    <ng-template\n      cdkConnectedOverlay\n      nzConnectedOverlay\n      cdkConnectedOverlayTransformOriginOn=\".ant-picker-dropdown\"\n      [cdkConnectedOverlayHasBackdrop]=\"nzBackdrop\"\n      [cdkConnectedOverlayPositions]=\"overlayPositions()\"\n      [cdkConnectedOverlayOrigin]=\"origin\"\n      [cdkConnectedOverlayOpen]=\"nzOpen\"\n      (detach)=\"close()\"\n      (overlayOutsideClick)=\"onClickOutside($event)\"\n      (positionChange)=\"onPositionChange($event)\"\n    >\n      <div\n        [animate.enter]=\"timepickerAnimationEnter()\"\n        [animate.leave]=\"timepickerAnimationLeave()\"\n        [class]=\"dropdownTimePickerClass()\"\n        style=\"position: relative\"\n      >\n        <div class=\"ant-picker-panel-container\">\n          <div tabindex=\"-1\" class=\"ant-picker-panel\">\n            <nz-time-picker-panel\n              [class]=\"nzPopupClassName\"\n              [format]=\"nzFormat\"\n              [nzHourStep]=\"nzHourStep\"\n              [nzMinuteStep]=\"nzMinuteStep\"\n              [nzSecondStep]=\"nzSecondStep\"\n              [nzDisabledHours]=\"nzDisabledHours\"\n              [nzDisabledMinutes]=\"nzDisabledMinutes\"\n              [nzDisabledSeconds]=\"nzDisabledSeconds\"\n              [nzPlaceHolder]=\"nzPlaceHolder || (i18nPlaceHolder$ | async)\"\n              [nzHideDisabledOptions]=\"nzHideDisabledOptions\"\n              [nzUse12Hours]=\"nzUse12Hours\"\n              [nzDefaultOpenValue]=\"nzDefaultOpenValue\"\n              [nzAddOn]=\"nzAddOn\"\n              [nzClearText]=\"nzClearText\"\n              [nzNowText]=\"nzNowText\"\n              [nzOkText]=\"nzOkText\"\n              [nzAllowEmpty]=\"nzAllowEmpty\"\n              [(ngModel)]=\"value\"\n              (ngModelChange)=\"onPanelValueChange($event)\"\n              (closePanel)=\"closePanel()\"\n            />\n          </div>\n        </div>\n      </div>\n    </ng-template>\n  `,\n  host: {\n    class: 'ant-picker',\n    '[class.ant-picker-large]': `finalSize() === 'large'`,\n    '[class.ant-picker-small]': `finalSize() === 'small'`,\n    '[class.ant-picker-disabled]': `nzDisabled`,\n    '[class.ant-picker-focused]': `focused`,\n    '[class.ant-picker-rtl]': `dir() === 'rtl'`,\n    '[class.ant-picker-borderless]': `finalVariant() === 'borderless'`,\n    '[class.ant-picker-filled]': `finalVariant() === 'filled'`,\n    '[class.ant-picker-underlined]': `finalVariant() === 'underlined'`,\n    '(click)': 'open()'\n  },\n  hostDirectives: [NzSpaceCompactItemDirective],\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => NzTimePickerComponent),\n      multi: true\n    },\n    {\n      provide: NZ_SPACE_COMPACT_ITEM_TYPE,\n      useValue: 'picker'\n    }\n  ],\n  imports: [\n    AsyncPipe,\n    FormsModule,\n    NzOutletModule,\n    NzIconModule,\n    NzFormItemFeedbackIconComponent,\n    NzTimePickerPanelComponent,\n    NzOverlayModule,\n    OverlayModule\n  ]\n})\nexport class NzTimePickerComponent implements ControlValueAccessor, OnInit, AfterViewInit, OnChanges {\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  public nzConfigService = inject(NzConfigService);\n  protected i18n = inject(NzI18nService);\n  private elementRef = inject(ElementRef);\n  private renderer = inject(Renderer2);\n  private cdr = inject(ChangeDetectorRef);\n  private dateHelper = inject(DateHelperService);\n  private platform = inject(Platform);\n  private destroyRef = inject(DestroyRef);\n\n  protected readonly dir = inject(Directionality).valueSignal;\n\n  private _onChange?: (value: Date | null) => void;\n  private _onTouched?: () => void;\n  private isNzDisableFirstChange: boolean = true;\n\n  isInit = false;\n  focused = false;\n  inputValue: string = '';\n  value: Date | null = null;\n  preValue: Date | null = null;\n  inputSize?: number;\n  i18nPlaceHolder$: Observable<string | undefined> = of(undefined);\n\n  // status\n  prefixCls: string = 'ant-picker';\n  statusCls: NgClassInterface = {};\n  status: NzValidateStatus = '';\n  hasFeedback: boolean = false;\n\n  get origin(): ElementRef {\n    return this.elementRef;\n  }\n\n  @ViewChild('inputElement', { static: true }) inputRef!: ElementRef<HTMLInputElement>;\n  @Input() nzId: string | null = null;\n  @Input() nzSize: NzSizeLDSType = 'default';\n  @Input() nzStatus: NzStatus = '';\n  @Input() @WithConfig() nzVariant: NzVariant | undefined = undefined;\n  @Input() @WithConfig() nzHourStep: number = 1;\n  @Input() @WithConfig() nzMinuteStep: number = 1;\n  @Input() @WithConfig() nzSecondStep: number = 1;\n  @Input() @WithConfig() nzClearText: string = 'clear';\n  @Input() @WithConfig() nzNowText: string = '';\n  @Input() @WithConfig() nzOkText: string = '';\n  @Input() @WithConfig() nzPopupClassName: string = '';\n  @Input() nzPlaceHolder = '';\n  @Input() nzAddOn?: TemplateRef<void>;\n  @Input() nzDefaultOpenValue?: Date;\n  @Input() nzDisabledHours?: () => number[];\n  @Input() nzDisabledMinutes?: (hour: number) => number[];\n  @Input() nzDisabledSeconds?: (hour: number, minute: number) => number[];\n  @Input() @WithConfig() nzFormat: string = 'HH:mm:ss';\n  @Input() nzOpen = false;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzUse12Hours: boolean = false;\n  @Input() @WithConfig() nzSuffixIcon: string | TemplateRef<NzSafeAny> = 'clock-circle';\n\n  @Output() readonly nzOpenChange = new EventEmitter<boolean>();\n\n  @Input({ transform: booleanAttribute }) nzHideDisabledOptions = false;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzAllowEmpty: boolean = true;\n  @Input({ transform: booleanAttribute }) nzDisabled = false;\n  @Input({ transform: booleanAttribute }) nzAutoFocus = false;\n  @Input() @WithConfig() nzBackdrop = false;\n  @Input({ transform: booleanAttribute }) nzInputReadOnly: boolean = false;\n\n  private readonly formSize = inject(NZ_FORM_SIZE, { optional: true });\n  private readonly formVariant = inject(NZ_FORM_VARIANT, { optional: true });\n  private hasConfirmed = false;\n\n  readonly nzPrefix = input<string | TemplateRef<void>>();\n  readonly nzNeedConfirm = input(false, { transform: booleanAttribute });\n  readonly nzPlacement = input<NzPlacement>('bottomLeft');\n\n  protected readonly currentPosition = linkedSignal(() => DATE_PICKER_POSITION_MAP[this.nzPlacement()]);\n  protected readonly overlayPositions = computed(() => [this.currentPosition(), ...DEFAULT_DATE_PICKER_POSITIONS]);\n\n  protected readonly timepickerAnimationEnter = slideAnimationEnter();\n  protected readonly timepickerAnimationLeave = slideAnimationLeave();\n\n  emitValue(value: Date | null): void {\n    this.setValue(value, true);\n\n    if (this._onChange) {\n      this._onChange(this.value);\n    }\n\n    if (this._onTouched) {\n      this._onTouched();\n    }\n  }\n\n  setValue(value: Date | null, syncPreValue: boolean = false): void {\n    if (syncPreValue) {\n      this.preValue = isValid(value) ? new Date(value!) : null;\n    }\n    this.value = isValid(value) ? new Date(value!) : null;\n    this.inputValue = this.dateHelper.format(value, this.nzFormat);\n    this.cdr.markForCheck();\n  }\n\n  open(): void {\n    if (this.nzDisabled || this.nzOpen) {\n      return;\n    }\n    this.focus();\n    this.nzOpen = true;\n    this.nzOpenChange.emit(this.nzOpen);\n  }\n\n  close(): void {\n    this.nzOpen = false;\n    this.cdr.markForCheck();\n    this.nzOpenChange.emit(this.nzOpen);\n  }\n\n  updateAutoFocus(): void {\n    if (this.isInit && !this.nzDisabled) {\n      if (this.nzAutoFocus) {\n        this.renderer.setAttribute(this.inputRef.nativeElement, 'autofocus', 'autofocus');\n      } else {\n        this.renderer.removeAttribute(this.inputRef.nativeElement, 'autofocus');\n      }\n    }\n  }\n\n  onClickClearBtn(event: MouseEvent): void {\n    event.stopPropagation();\n    this.emitValue(null);\n  }\n\n  onClickOutside(event: MouseEvent): void {\n    const target = _getEventTarget(event);\n    if (!this.elementRef.nativeElement.contains(target)) {\n      this.setCurrentValueAndClose();\n    }\n  }\n\n  onFocus(value: boolean): void {\n    this.focused = value;\n    if (!value) {\n      if (this.checkTimeValid(this.value)) {\n        this.setCurrentValueAndClose();\n      } else {\n        this.setValue(this.preValue);\n        this.close();\n      }\n    }\n  }\n\n  focus(): void {\n    if (this.inputRef.nativeElement) {\n      this.inputRef.nativeElement.focus();\n    }\n  }\n\n  blur(): void {\n    if (this.inputRef.nativeElement) {\n      this.inputRef.nativeElement.blur();\n    }\n  }\n\n  onKeyupEsc(): void {\n    this.setValue(this.preValue);\n  }\n\n  onKeyupEnter(): void {\n    if (this.nzOpen && isValid(this.value)) {\n      this.setCurrentValueAndClose();\n    } else if (!this.nzOpen) {\n      this.open();\n    }\n  }\n\n  onInputChange(str: string): void {\n    if (!this.platform.TRIDENT && document.activeElement === this.inputRef.nativeElement) {\n      this.open();\n      this.parseTimeString(str);\n    }\n  }\n\n  onPanelValueChange(value: Date): void {\n    this.setValue(value);\n    this.focus();\n  }\n\n  closePanel(): void {\n    this.hasConfirmed = true;\n    this.inputRef.nativeElement.blur();\n  }\n\n  setCurrentValueAndClose(): void {\n    if (this.hasConfirmed || !this.nzNeedConfirm()) {\n      this.emitValue(this.value);\n      this.hasConfirmed = false;\n    } else {\n      this.setValue(this.preValue);\n    }\n    this.close();\n  }\n\n  onPositionChange(position: ConnectedOverlayPositionChange): void {\n    this.currentPosition.set(position.connectionPair);\n  }\n\n  protected finalSize = computed(() => {\n    if (this.formSize?.()) {\n      return this.formSize();\n    }\n    if (this.compactSize) {\n      return this.compactSize();\n    }\n    return this.size();\n  });\n\n  protected readonly finalVariant = computed(() => this.variant() || this.formVariant?.() || 'outlined');\n\n  protected dropdownTimePickerClass = computed(() => {\n    const classList = [this.generateClass('dropdown')];\n    const { originX, originY } = this.currentPosition();\n    const dir = this.dir();\n\n    if (originX === 'start' && originY === 'bottom') {\n      classList.push(this.generateClass('dropdown-placement-bottomLeft'));\n    } else if (originX === 'start' && originY === 'top') {\n      classList.push(this.generateClass('dropdown-placement-topLeft'));\n    } else if (originX === 'end' && originY === 'bottom') {\n      classList.push(this.generateClass('dropdown-placement-bottomRight'));\n    } else if (originX === 'end' && originY === 'top') {\n      classList.push(this.generateClass('dropdown-placement-topRight'));\n    }\n\n    if (dir === 'rtl') {\n      classList.push(this.generateClass('dropdown-rtl'));\n    }\n\n    return classList;\n  });\n\n  private size = signal<NzSizeLDSType>(this.nzSize);\n  private readonly variant = signal<NzVariant | undefined>(this.nzVariant);\n  private compactSize = inject(NZ_SPACE_COMPACT_SIZE, { optional: true });\n  private nzFormStatusService = inject(NzFormStatusService, { optional: true });\n  private nzFormNoStatusService = inject(NzFormNoStatusService, { optional: true });\n\n  ngOnInit(): void {\n    this.nzFormStatusService?.formStatusChanges\n      .pipe(\n        distinctUntilChanged((pre, cur) => pre.status === cur.status && pre.hasFeedback === cur.hasFeedback),\n        withLatestFrom(this.nzFormNoStatusService ? this.nzFormNoStatusService.noFormStatus : of(false)),\n        map(([{ status, hasFeedback }, noStatus]) => ({ status: noStatus ? '' : status, hasFeedback })),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(({ status, hasFeedback }) => {\n        this.setStatusStyles(status, hasFeedback);\n      });\n\n    this.inputSize = Math.max(8, this.nzFormat.length) + 2;\n    this.i18nPlaceHolder$ = this.i18n.localeChange.pipe(map(nzLocale => nzLocale.TimePicker.placeholder));\n  }\n\n  ngOnChanges({ nzUse12Hours, nzFormat, nzDisabled, nzAutoFocus, nzStatus, nzSize, nzVariant }: SimpleChanges): void {\n    if (nzUse12Hours && !nzUse12Hours.previousValue && nzUse12Hours.currentValue && !nzFormat) {\n      this.nzFormat = 'h:mm:ss a';\n    }\n    if (nzDisabled) {\n      const value = nzDisabled.currentValue;\n      const input = this.inputRef.nativeElement as HTMLInputElement;\n      if (value) {\n        this.renderer.setAttribute(input, 'disabled', '');\n      } else {\n        this.renderer.removeAttribute(input, 'disabled');\n      }\n    }\n    if (nzAutoFocus) {\n      this.updateAutoFocus();\n    }\n    if (nzStatus) {\n      this.setStatusStyles(this.nzStatus, this.hasFeedback);\n    }\n    if (nzSize) {\n      this.size.set(nzSize.currentValue);\n    }\n    if (nzVariant) {\n      this.variant.set(nzVariant.currentValue);\n    }\n  }\n\n  parseTimeString(str: string): void {\n    const value = this.dateHelper.parseTime(str, this.nzFormat) || null;\n    if (isValid(value)) {\n      this.value = value;\n      this.cdr.markForCheck();\n    }\n  }\n\n  ngAfterViewInit(): void {\n    this.isInit = true;\n    this.updateAutoFocus();\n  }\n\n  writeValue(time: Date | null | undefined): void {\n    let result: Date | null;\n\n    if (time instanceof Date) {\n      result = time;\n    } else if (isNil(time)) {\n      result = null;\n    } else {\n      warn('Non-Date type is not recommended for time-picker, use \"Date\" type.');\n      result = new Date(time);\n    }\n\n    this.setValue(result, true);\n  }\n\n  registerOnChange(fn: (time: Date | null) => void): void {\n    this._onChange = fn;\n  }\n\n  registerOnTouched(fn: () => void): void {\n    this._onTouched = fn;\n  }\n\n  setDisabledState(isDisabled: boolean): void {\n    this.nzDisabled = (this.isNzDisableFirstChange && this.nzDisabled) || isDisabled;\n    this.isNzDisableFirstChange = false;\n    this.cdr.markForCheck();\n  }\n\n  private checkTimeValid(value: Date | null): boolean {\n    if (!value) {\n      return true;\n    }\n\n    const disabledHours = this.nzDisabledHours?.();\n    const disabledMinutes = this.nzDisabledMinutes?.(value.getHours());\n    const disabledSeconds = this.nzDisabledSeconds?.(value.getHours(), value.getMinutes());\n\n    return !(\n      disabledHours?.includes(value.getHours()) ||\n      disabledMinutes?.includes(value.getMinutes()) ||\n      disabledSeconds?.includes(value.getSeconds())\n    );\n  }\n\n  private setStatusStyles(status: NzValidateStatus, hasFeedback: boolean): void {\n    // set inner status\n    this.status = status;\n    this.hasFeedback = hasFeedback;\n    this.cdr.markForCheck();\n    // render status if nzStatus is set\n    this.statusCls = getStatusClassNames(this.prefixCls, status, hasFeedback);\n    Object.keys(this.statusCls).forEach(status => {\n      if (this.statusCls[status]) {\n        this.renderer.addClass(this.elementRef.nativeElement, status);\n      } else {\n        this.renderer.removeClass(this.elementRef.nativeElement, status);\n      }\n    });\n  }\n\n  private generateClass(suffix: string): string {\n    return generateClassName(this.prefixCls, suffix);\n  }\n}\n"
  },
  {
    "path": "components/time-picker/time-picker.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzTimePickerPanelComponent } from './time-picker-panel.component';\nimport { NzTimePickerComponent } from './time-picker.component';\n\n@NgModule({\n  imports: [NzTimePickerComponent, NzTimePickerPanelComponent],\n  exports: [NzTimePickerPanelComponent, NzTimePickerComponent]\n})\nexport class NzTimePickerModule {}\n"
  },
  {
    "path": "components/timeline/demo/alternate.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 交替展现\n  en-US: Alternate\n---\n\n## zh-CN\n\n内容在时间轴两侧交替出现。\n\n## en-US\n\nAlternate timeline.\n"
  },
  {
    "path": "components/timeline/demo/alternate.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzTimelineModule } from 'ng-zorro-antd/timeline';\n\n@Component({\n  selector: 'nz-demo-timeline-alternate',\n  imports: [NzIconModule, NzTimelineModule],\n  template: `\n    <nz-timeline nzMode=\"alternate\">\n      <nz-timeline-item>Create a services site 2015-09-01</nz-timeline-item>\n      <nz-timeline-item nzColor=\"green\">Solve initial network problems 2015-09-01</nz-timeline-item>\n      <nz-timeline-item [nzDot]=\"dotTemplate\">\n        Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem\n        aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.\n      </nz-timeline-item>\n      <nz-timeline-item nzColor=\"red\">Network problems being solved 2015-09-01</nz-timeline-item>\n      <nz-timeline-item>Create a services site 2015-09-01</nz-timeline-item>\n      <nz-timeline-item [nzDot]=\"dotTemplate\">Technical testing 2015-09-01</nz-timeline-item>\n    </nz-timeline>\n    <ng-template #dotTemplate>\n      <nz-icon nzType=\"clock-circle-o\" style=\"font-size: 16px;\" />\n    </ng-template>\n  `\n})\nexport class NzDemoTimelineAlternateComponent {}\n"
  },
  {
    "path": "components/timeline/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本用法\n  en-US: Basic\n---\n\n## zh-CN\n\n基本的时间轴。\n\n## en-US\n\nBasic timeline.\n"
  },
  {
    "path": "components/timeline/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTimelineModule } from 'ng-zorro-antd/timeline';\n\n@Component({\n  selector: 'nz-demo-timeline-basic',\n  imports: [NzTimelineModule],\n  template: `\n    <nz-timeline>\n      <nz-timeline-item>Create a services site 2015-09-01</nz-timeline-item>\n      <nz-timeline-item>Solve initial network problems 2015-09-01</nz-timeline-item>\n      <nz-timeline-item>Technical testing 2015-09-01</nz-timeline-item>\n      <nz-timeline-item>Network problems being solved 2015-09-01</nz-timeline-item>\n    </nz-timeline>\n  `\n})\nexport class NzDemoTimelineBasicComponent {}\n"
  },
  {
    "path": "components/timeline/demo/color.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 圆圈颜色\n  en-US: Color\n---\n\n## zh-CN\n\n圆圈颜色，绿色用于已完成、成功状态，红色表示告警或错误状态，蓝色可表示正在进行或其他默认状态，灰色表示未完成或失效状态。\n\n## en-US\n\nSet the color of circles. `green` means completed or success status, `red` means warning or error, and `blue` means ongoing or other default status, `gray` for unfinished or disabled status.\n"
  },
  {
    "path": "components/timeline/demo/color.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTimelineModule } from 'ng-zorro-antd/timeline';\n\n@Component({\n  selector: 'nz-demo-timeline-color',\n  imports: [NzTimelineModule],\n  template: `\n    <nz-timeline>\n      <nz-timeline-item nzColor=\"green\">Create a services site 2015-09-01</nz-timeline-item>\n      <nz-timeline-item nzColor=\"green\">Solve initial network problems 2015-09-01</nz-timeline-item>\n      <nz-timeline-item nzColor=\"red\">\n        <p>Solve initial network problems 1</p>\n        <p>Solve initial network problems 2</p>\n        <p>Solve initial network problems 3 2015-09-01</p>\n      </nz-timeline-item>\n      <nz-timeline-item>\n        <p>Technical testing 1</p>\n        <p>Technical testing 2</p>\n        <p>Technical testing 3 2015-09-01</p>\n      </nz-timeline-item>\n      <nz-timeline-item nzColor=\"gray\">\n        <p>Technical testing 1</p>\n        <p>Technical testing 2</p>\n        <p>Technical testing 3 2015-09-01</p>\n      </nz-timeline-item>\n      <nz-timeline-item nzColor=\"gray\">\n        <p>Technical testing 1</p>\n        <p>Technical testing 2</p>\n        <p>Technical testing 3 2015-09-01</p>\n      </nz-timeline-item>\n    </nz-timeline>\n  `\n})\nexport class NzDemoTimelineColorComponent {}\n"
  },
  {
    "path": "components/timeline/demo/custom.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 自定义时间轴点\n  en-US: Custom\n---\n\n## zh-CN\n\n可以设置为图标或其他自定义元素。\n\n## en-US\n\nSet a node as an icon or other custom element.\n"
  },
  {
    "path": "components/timeline/demo/custom.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzTimelineModule } from 'ng-zorro-antd/timeline';\n\n@Component({\n  selector: 'nz-demo-timeline-custom',\n  imports: [NzIconModule, NzTimelineModule],\n  template: `\n    <nz-timeline>\n      <nz-timeline-item>Create a services site 2015-09-01</nz-timeline-item>\n      <nz-timeline-item>Solve initial network problems 2015-09-01</nz-timeline-item>\n      <nz-timeline-item nzColor=\"red\" [nzDot]=\"dotTemplate\">Technical testing 2015-09-01</nz-timeline-item>\n      <nz-timeline-item>Network problems being solved 2015-09-01</nz-timeline-item>\n    </nz-timeline>\n    <ng-template #dotTemplate>\n      <nz-icon nzType=\"clock-circle-o\" style=\"font-size: 16px;\" />\n    </ng-template>\n  `\n})\nexport class NzDemoTimelineCustomComponent {}\n"
  },
  {
    "path": "components/timeline/demo/label.md",
    "content": "---\norder: 10\ntitle:\n  zh-CN: 标签\n  en-US: Label\n---\n\n## zh-CN\n\n使用 `nzLabel` 标签单独展示时间。\n\n## en-US\n\nUse `nzLabel` show time alone.\n"
  },
  {
    "path": "components/timeline/demo/label.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\nimport { NzTimelineMode, NzTimelineModule } from 'ng-zorro-antd/timeline';\n\n@Component({\n  selector: 'nz-demo-timeline-label',\n  imports: [FormsModule, NzRadioModule, NzTimelineModule],\n  template: `\n    <nz-radio-group [(ngModel)]=\"mode\">\n      <label nz-radio nzValue=\"left\">Left</label>\n      <label nz-radio nzValue=\"right\">Right</label>\n      <label nz-radio nzValue=\"alternate\">Alternative</label>\n    </nz-radio-group>\n    <br />\n    <br />\n    <nz-timeline [nzMode]=\"mode\">\n      <nz-timeline-item nzLabel=\"2015-09-01\">Create a services</nz-timeline-item>\n      <nz-timeline-item nzLabel=\"2015-09-01 09:12:11\">Solve initial network problems</nz-timeline-item>\n      <nz-timeline-item>Technical testing</nz-timeline-item>\n      <nz-timeline-item nzLabel=\"2015-09-01 09:12:11\">Network problems being solved</nz-timeline-item>\n    </nz-timeline>\n  `\n})\nexport class NzDemoTimelineLabelComponent {\n  mode: NzTimelineMode = 'left';\n}\n"
  },
  {
    "path": "components/timeline/demo/pending.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 最后一个及排序\n  en-US: Last node\n---\n\n## zh-CN\n\n当任务状态正在发生，还在记录过程中，可用幽灵节点来表示当前的时间节点，当 `nzPending` 为真值时展示幽灵节点，如果 `nzPending` 是 Template 可用于定制该节点内容，同时 `nzPendingDot` 将可以用于定制其轴点。`nzReverse` 属性用于控制节点排序，为 `false` 时按正序排列，为 `true` 时按倒序排列。\n\n## en-US\n\nWhen the timeline is incomplete and ongoing, put a ghost node at last. set `[nzPending]=\"true\"` or `[nzPending]=\"a TemplateRef\"`. Used in ascend chronological order.\n"
  },
  {
    "path": "components/timeline/demo/pending.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzTimelineModule } from 'ng-zorro-antd/timeline';\n\n@Component({\n  selector: 'nz-demo-timeline-pending',\n  imports: [NzButtonModule, NzTimelineModule],\n  template: `\n    <nz-timeline nzPending=\"Recording...\" [nzReverse]=\"reverse\">\n      <nz-timeline-item>Create a services site 2015-09-01</nz-timeline-item>\n      <nz-timeline-item>Solve initial network problems 2015-09-01</nz-timeline-item>\n      <nz-timeline-item>Technical testing 2015-09-01</nz-timeline-item>\n    </nz-timeline>\n    <br />\n    <br />\n    <button nz-button nzType=\"primary\" (click)=\"toggleReverse()\">Toggle Reverse</button>\n  `\n})\nexport class NzDemoTimelinePendingComponent {\n  reverse = false;\n\n  toggleReverse(): void {\n    this.reverse = !this.reverse;\n  }\n}\n"
  },
  {
    "path": "components/timeline/demo/position.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 自定义位置\n  en-US: Custom Position\n---\n\n## zh-CN\n\n可以为每一项指定位置。\n\n## en-US\n\nYou can assign different positions to timeline items.\n"
  },
  {
    "path": "components/timeline/demo/position.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTimelineModule } from 'ng-zorro-antd/timeline';\n\n@Component({\n  selector: 'nz-demo-timeline-position',\n  imports: [NzTimelineModule],\n  template: `\n    <nz-timeline nzMode=\"custom\">\n      <nz-timeline-item nzPosition=\"left\" [nzDot]=\"soccerTemplate\">Alice 20'</nz-timeline-item>\n      <nz-timeline-item nzPosition=\"left\" [nzDot]=\"soccerTemplate\">Susan 28'</nz-timeline-item>\n      <nz-timeline-item nzPosition=\"right\" nzColor=\"red\" [nzDot]=\"soccerTemplate\">Tim 45'</nz-timeline-item>\n      <nz-timeline-item nzPosition=\"left\" [nzDot]=\"soccerTemplate\">Bob 79'</nz-timeline-item>\n    </nz-timeline>\n    <ng-template #soccerTemplate>⚽</ng-template>\n  `\n})\nexport class NzDemoTimelinePositionComponent {}\n"
  },
  {
    "path": "components/timeline/demo/right.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 右侧时间轴点\n  en-US: Right alternate\n---\n\n## zh-CN\n\n时间轴可以在内容的右边。\n\n## en-US\n\nRight alternate timeline.\n"
  },
  {
    "path": "components/timeline/demo/right.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzTimelineModule } from 'ng-zorro-antd/timeline';\n\n@Component({\n  selector: 'nz-demo-timeline-right',\n  imports: [NzIconModule, NzTimelineModule],\n  template: `\n    <nz-timeline nzMode=\"right\">\n      <nz-timeline-item>Create a services site 2015-09-01</nz-timeline-item>\n      <nz-timeline-item>Solve initial network problems 2015-09-01</nz-timeline-item>\n      <nz-timeline-item [nzDot]=\"dotTemplate\" nzColor=\"red\">Technical testing 2015-09-01</nz-timeline-item>\n      <nz-timeline-item>Network problems being solved 2015-09-01</nz-timeline-item>\n    </nz-timeline>\n    <ng-template #dotTemplate>\n      <nz-icon nzType=\"clock-circle-o\" style=\"font-size: 16px;\" />\n    </ng-template>\n  `\n})\nexport class NzDemoTimelineRightComponent {}\n"
  },
  {
    "path": "components/timeline/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Display\ntitle: Timeline\ncover: 'https://gw.alipayobjects.com/zos/antfincdn/vJmo00mmgR/Timeline.svg'\ndescription: Vertical display timeline.\n---\n\n## When To Use\n\n- When a series of information needs to be ordered by time (ascend or descend).\n- When you need a timeline to make a visual connection.\n\n## API\n\n```html\n<nz-timeline>\n  <nz-timeline-item>step1 2015-09-01</nz-timeline-item>\n  <nz-timeline-item>step2 2015-09-01</nz-timeline-item>\n  <nz-timeline-item>step3 2015-09-01</nz-timeline-item>\n  <nz-timeline-item>step4 2015-09-01</nz-timeline-item>\n</nz-timeline>\n```\n\n### nz-timeline\n\nTimeline\n\n| Property         | Description                                                                         | Type                                           | Default                        |\n| ---------------- | ----------------------------------------------------------------------------------- | ---------------------------------------------- | ------------------------------ |\n| `[nzPending]`    | Set the last ghost node's existence or its content                                  | `string \\| boolean \\| TemplateRef<void>`       | `false`                        |\n| `[nzPendingDot]` | Set the dot of the last ghost node when pending is true                             | `string \\| TemplateRef<void>`                  | `<nz-icon nzType=\"loading\" />` |\n| `[nzReverse]`    | Reverse nodes or not                                                                | `boolean`                                      | `false`                        |\n| `[nzMode]`       | By sending `alternate` the timeline will distribute the nodes to the left and right | `'left' \\| 'alternate' \\| 'right' \\| 'custom'` | -                              |\n\n### nz-timeline-item\n\nNode of timeline\n\n| Property       | Description                                                                             | Type                          | Default |\n| -------------- | --------------------------------------------------------------------------------------- | ----------------------------- | ------- |\n| `[nzColor]`    | Set the circle's color to `'blue' \\| 'red' \\| 'green' \\| 'gray'` or other custom colors | `string`                      | `blue`  |\n| `[nzDot]`      | Customize timeline dot                                                                  | `string \\| TemplateRef<void>` | -       |\n| `[nzPosition]` | Customize position, only works when `nzMode` is `custom`                                | `'left' \\| 'right'`           | -       |\n| `[nzLabel]`    | Set the label                                                                           | `string \\| TemplateRef<void>` | -       |\n"
  },
  {
    "path": "components/timeline/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 时间轴\ntype: 数据展示\ntitle: Timeline\ncover: 'https://gw.alipayobjects.com/zos/antfincdn/vJmo00mmgR/Timeline.svg'\ndescription: 垂直展示的时间流信息。\n---\n\n## 何时使用\n\n- 当有一系列信息需按时间排列时，可正序和倒序。\n- 需要有一条时间轴进行视觉上的串联时。\n\n## API\n\n```html\n<nz-timeline>\n  <nz-timeline-item>创建服务现场 2015-09-01</nz-timeline-item>\n  <nz-timeline-item>初步排除网络异常 2015-09-01</nz-timeline-item>\n  <nz-timeline-item>技术测试异常 2015-09-01</nz-timeline-item>\n  <nz-timeline-item>网络异常正在修复 2015-09-01</nz-timeline-item>\n</nz-timeline>\n```\n\n### nz-timeline\n\n时间轴。\n\n| 参数             | 说明                                     | 类型                                           | 默认值                         |\n| ---------------- | ---------------------------------------- | ---------------------------------------------- | ------------------------------ |\n| `[nzPending]`    | 指定最后一个幽灵节点是否存在或内容       | `string \\| boolean \\| TemplateRef<void>`       | `false`                        |\n| `[nzPendingDot]` | 当最后一个幽灵节点存在時，指定其时间图点 | `string \\| TemplateRef<void>`                  | `<nz-icon nzType=\"loading\" />` |\n| `[nzReverse]`    | 节点排序                                 | `boolean`                                      | `false`                        |\n| `[nzMode]`       | 可以改变时间轴和内容的相对位置           | `'left' \\| 'alternate' \\| 'right' \\| 'custom'` | -                              |\n\n### nz-timeline-item\n\n时间轴的每一个节点。\n\n| 参数           | 说明                                                               | 类型                          | 默认值   |\n| -------------- | ------------------------------------------------------------------ | ----------------------------- | -------- |\n| `[nzColor]`    | 指定圆圈颜色 `'blue' \\| 'red' \\| 'green' \\| 'gray'` 或自定义的色值 | `string`                      | `'blue'` |\n| `[nzDot]`      | 自定义时间轴点                                                     | `string \\| TemplateRef<void>` | -        |\n| `[nzPosition]` | 自定义节点位置，仅当 `nzMode` 为 `custom` 时有效                   | `'left' \\| 'right'`           | -        |\n| `[nzLabel]`    | 设置标签                                                           | `string \\| TemplateRef<void>` | -        |\n"
  },
  {
    "path": "components/timeline/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/timeline/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/timeline/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './timeline-item.component';\nexport * from './timeline.component';\nexport * from './timeline.module';\nexport * from './timeline.service';\nexport type { NzTimelineMode, NzTimelinePosition, NzTimelineItemColor } from './typings';\n"
  },
  {
    "path": "components/timeline/style/entry.less",
    "content": "@import './index.less';\n"
  },
  {
    "path": "components/timeline/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@timeline-prefix-cls: ~'@{ant-prefix}-timeline';\n\n.@{timeline-prefix-cls} {\n  .reset-component();\n\n  margin: 0;\n  padding: 0;\n  list-style: none;\n\n  &-item {\n    position: relative;\n    margin: 0;\n    padding-bottom: @timeline-item-padding-bottom;\n    font-size: @font-size-base;\n    list-style: none;\n\n    &-tail {\n      position: absolute;\n      top: 10px;\n      left: 4px;\n      height: calc(100% - 10px);\n      border-left: @timeline-width solid @timeline-color;\n    }\n\n    &-pending &-head {\n      font-size: @font-size-sm;\n      background-color: transparent;\n    }\n\n    &-pending &-tail {\n      display: none;\n    }\n\n    &-head {\n      position: absolute;\n      width: 10px;\n      height: 10px;\n      background-color: @timeline-dot-bg;\n      border: @timeline-dot-border-width solid transparent;\n      border-radius: 100px;\n\n      &-blue {\n        color: @primary-color;\n        border-color: @primary-color;\n      }\n\n      &-red {\n        color: @error-color;\n        border-color: @error-color;\n      }\n\n      &-green {\n        color: @success-color;\n        border-color: @success-color;\n      }\n\n      &-gray {\n        color: @disabled-color;\n        border-color: @disabled-color;\n      }\n    }\n\n    &-head-custom {\n      position: absolute;\n      top: 5.5px;\n      left: 5px;\n      width: auto;\n      height: auto;\n      margin-top: 0;\n      padding: 3px 1px;\n      line-height: 1;\n      text-align: center;\n      border: 0;\n      border-radius: 0;\n      transform: translate(-50%, -50%);\n    }\n\n    &-content {\n      position: relative;\n      top: -(@font-size-base * @line-height-base - @font-size-base) + 1px;\n      margin: 0 0 0 @margin-lg + 2px;\n      word-break: break-word;\n    }\n\n    &-last {\n      > .@{timeline-prefix-cls}-item-tail {\n        display: none;\n      }\n      > .@{timeline-prefix-cls}-item-content {\n        min-height: 48px;\n      }\n    }\n  }\n\n  &.@{timeline-prefix-cls}-alternate,\n  &.@{timeline-prefix-cls}-right,\n  &.@{timeline-prefix-cls}-label {\n    .@{timeline-prefix-cls}-item {\n      &-tail,\n      &-head,\n      &-head-custom {\n        left: 50%;\n      }\n\n      &-head {\n        margin-left: -4px;\n\n        &-custom {\n          margin-left: 1px;\n        }\n      }\n\n      &-left {\n        .@{timeline-prefix-cls}-item-content {\n          left: calc(50% - 4px);\n          width: calc(50% - 14px);\n          text-align: left;\n        }\n      }\n\n      &-right {\n        .@{timeline-prefix-cls}-item-content {\n          width: calc(50% - 12px);\n          margin: 0;\n          text-align: right;\n        }\n      }\n    }\n  }\n\n  &.@{timeline-prefix-cls}-right {\n    .@{timeline-prefix-cls}-item-right {\n      .@{timeline-prefix-cls}-item-tail,\n      .@{timeline-prefix-cls}-item-head,\n      .@{timeline-prefix-cls}-item-head-custom {\n        left: calc(100% - 4px - @timeline-width);\n      }\n      .@{timeline-prefix-cls}-item-content {\n        width: calc(100% - 18px);\n      }\n    }\n  }\n\n  &&-pending &-item-last &-item-tail {\n    display: block;\n    height: calc(100% - 14px);\n    border-left: 2px dotted @timeline-color;\n  }\n\n  &&-reverse &-item-last &-item-tail {\n    display: none;\n  }\n\n  &&-reverse &-item-pending {\n    .@{timeline-prefix-cls}-item-tail {\n      top: 15px;\n      display: block;\n      height: calc(100% - 15px);\n      border-left: 2px dotted @timeline-color;\n    }\n    .@{timeline-prefix-cls}-item-content {\n      min-height: 48px;\n    }\n  }\n  &.@{timeline-prefix-cls}-label {\n    .@{timeline-prefix-cls}-item-label {\n      position: absolute;\n      top: -(@font-size-base * @line-height-base - @font-size-base) + 1px;\n      width: calc(50% - 12px);\n      text-align: right;\n    }\n    .@{timeline-prefix-cls}-item-right {\n      .@{timeline-prefix-cls}-item-label {\n        left: calc(50% + 14px);\n        width: calc(50% - 14px);\n        text-align: left;\n      }\n    }\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/timeline/style/index.tsx",
    "content": "import '../../style/index.less';\nimport './index.less';\n"
  },
  {
    "path": "components/timeline/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@timeline-prefix-cls: ~'@{ant-prefix}-timeline';\n\n.@{timeline-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &-item {\n    &-tail {\n      .@{timeline-prefix-cls}-rtl & {\n        right: 4px;\n        left: auto;\n        border-right: @timeline-width solid @timeline-color;\n        border-left: none;\n      }\n    }\n\n    &-head-custom {\n      .@{timeline-prefix-cls}-rtl & {\n        right: 5px;\n        left: auto;\n        transform: translate(50%, -50%);\n      }\n    }\n\n    &-content {\n      .@{timeline-prefix-cls}-rtl & {\n        margin: 0 18px 0 0;\n      }\n    }\n  }\n\n  &.@{timeline-prefix-cls}-alternate,\n  &.@{timeline-prefix-cls}-right,\n  &.@{timeline-prefix-cls}-label {\n    .@{timeline-prefix-cls}-item {\n      &-tail,\n      &-head,\n      &-head-custom {\n        .@{timeline-prefix-cls}-rtl& {\n          right: 50%;\n          left: auto;\n        }\n      }\n\n      &-head {\n        .@{timeline-prefix-cls}-rtl& {\n          margin-right: -4px;\n          margin-left: 0;\n        }\n\n        &-custom {\n          .@{timeline-prefix-cls}-rtl& {\n            margin-right: 1px;\n            margin-left: 0;\n          }\n        }\n      }\n\n      &-left {\n        .@{timeline-prefix-cls}-item-content {\n          .@{timeline-prefix-cls}-rtl& {\n            right: calc(50% - 4px);\n            left: auto;\n            text-align: right;\n          }\n        }\n      }\n\n      &-right {\n        .@{timeline-prefix-cls}-item-content {\n          .@{timeline-prefix-cls}-rtl& {\n            text-align: left;\n          }\n        }\n      }\n    }\n  }\n\n  &.@{timeline-prefix-cls}-right {\n    .@{timeline-prefix-cls}-item-right {\n      .@{timeline-prefix-cls}-item-tail,\n      .@{timeline-prefix-cls}-item-head,\n      .@{timeline-prefix-cls}-item-head-custom {\n        .@{timeline-prefix-cls}-rtl& {\n          right: 0;\n          left: auto;\n        }\n      }\n\n      .@{timeline-prefix-cls}-item-content {\n        .@{timeline-prefix-cls}-rtl& {\n          width: 100%;\n          margin-right: 18px;\n          text-align: right;\n        }\n      }\n    }\n  }\n\n  &&-pending &-item-last &-item-tail {\n    .@{timeline-prefix-cls}-rtl& {\n      border-right: 2px dotted @timeline-color;\n      border-left: none;\n    }\n  }\n\n  &&-reverse &-item-pending {\n    .@{timeline-prefix-cls}-item-tail {\n      .@{timeline-prefix-cls}-rtl& {\n        border-right: 2px dotted @timeline-color;\n        border-left: none;\n      }\n    }\n  }\n\n  &.@{timeline-prefix-cls}-label {\n    .@{timeline-prefix-cls}-item-label {\n      .@{timeline-prefix-cls}-rtl& {\n        text-align: left;\n      }\n    }\n    .@{timeline-prefix-cls}-item-right {\n      .@{timeline-prefix-cls}-item-label {\n        .@{timeline-prefix-cls}-rtl& {\n          right: calc(50% + 14px);\n          text-align: right;\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/timeline/timeline-item.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  inject,\n  Input,\n  OnChanges,\n  SimpleChanges,\n  TemplateRef,\n  ViewChild,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\n\nimport { TimelineService } from './timeline.service';\nimport { NzTimelineItemColor, NzTimelinePosition, TimelineTimeDefaultColors } from './typings';\n\nfunction isDefaultColor(color?: string): boolean {\n  return TimelineTimeDefaultColors.findIndex(i => i === color) !== -1;\n}\n\n@Component({\n  selector: 'nz-timeline-item, [nz-timeline-item]',\n  exportAs: 'nzTimelineItem',\n  template: `\n    <ng-template #template>\n      <li\n        class=\"ant-timeline-item\"\n        [class.ant-timeline-item-right]=\"(nzPosition || position) === 'right'\"\n        [class.ant-timeline-item-left]=\"(nzPosition || position) === 'left'\"\n        [class.ant-timeline-item-last]=\"isLast\"\n      >\n        @if (nzLabel) {\n          <div class=\"ant-timeline-item-label\">\n            <ng-container *nzStringTemplateOutlet=\"nzLabel\">{{ nzLabel }}</ng-container>\n          </div>\n        }\n        <div class=\"ant-timeline-item-tail\"></div>\n        <div\n          class=\"ant-timeline-item-head\"\n          [class.ant-timeline-item-head-red]=\"nzColor === 'red'\"\n          [class.ant-timeline-item-head-blue]=\"nzColor === 'blue'\"\n          [class.ant-timeline-item-head-green]=\"nzColor === 'green'\"\n          [class.ant-timeline-item-head-gray]=\"nzColor === 'gray'\"\n          [class.ant-timeline-item-head-custom]=\"!!nzDot\"\n          [style.border-color]=\"borderColor\"\n        >\n          <ng-container *nzStringTemplateOutlet=\"nzDot\">{{ nzDot }}</ng-container>\n        </div>\n        <div class=\"ant-timeline-item-content\">\n          <ng-content />\n        </div>\n      </li>\n    </ng-template>\n  `,\n  imports: [NzOutletModule],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None\n})\nexport class NzTimelineItemComponent implements OnChanges {\n  private cdr = inject(ChangeDetectorRef);\n  private timelineService = inject(TimelineService);\n\n  @ViewChild('template', { static: false }) template!: TemplateRef<void>;\n\n  @Input() nzPosition?: NzTimelinePosition;\n  @Input() nzColor: NzTimelineItemColor = 'blue';\n  @Input() nzDot?: string | TemplateRef<void>;\n  @Input() nzLabel?: string | TemplateRef<void>;\n\n  isLast = false;\n  borderColor: string | null = null;\n  position?: NzTimelinePosition;\n\n  ngOnChanges(changes: SimpleChanges): void {\n    this.timelineService.markForCheck();\n    const { nzColor } = changes;\n    if (nzColor) {\n      this.updateCustomColor();\n    }\n  }\n\n  detectChanges(): void {\n    this.cdr.detectChanges();\n  }\n\n  private updateCustomColor(): void {\n    this.borderColor = isDefaultColor(this.nzColor) ? null : this.nzColor;\n  }\n}\n"
  },
  {
    "path": "components/timeline/timeline.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterContentInit,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ContentChildren,\n  Input,\n  OnChanges,\n  OnInit,\n  QueryList,\n  SimpleChange,\n  SimpleChanges,\n  TemplateRef,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject,\n  DestroyRef\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nimport { NzTimelineItemComponent } from './timeline-item.component';\nimport { TimelineService } from './timeline.service';\nimport { NzTimelineMode, NzTimelinePosition } from './typings';\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  selector: 'nz-timeline',\n  providers: [TimelineService],\n  exportAs: 'nzTimeline',\n  template: `\n    <ul\n      class=\"ant-timeline\"\n      [class.ant-timeline-label]=\"hasLabelItem\"\n      [class.ant-timeline-right]=\"!hasLabelItem && nzMode === 'right'\"\n      [class.ant-timeline-alternate]=\"nzMode === 'alternate' || nzMode === 'custom'\"\n      [class.ant-timeline-pending]=\"!!nzPending\"\n      [class.ant-timeline-reverse]=\"nzReverse\"\n      [class.ant-timeline-rtl]=\"dir === 'rtl'\"\n    >\n      <!-- pending dot (reversed) -->\n      @if (nzReverse) {\n        <ng-container [ngTemplateOutlet]=\"pendingTemplate\" />\n      }\n      <!-- timeline items -->\n      @for (item of timelineItems; track item) {\n        <ng-template [ngTemplateOutlet]=\"item.template\" />\n      }\n      @if (!nzReverse) {\n        <ng-container [ngTemplateOutlet]=\"pendingTemplate\" />\n      }\n      <!-- pending dot -->\n    </ul>\n    <ng-template #pendingTemplate>\n      @if (nzPending) {\n        <li class=\"ant-timeline-item ant-timeline-item-pending\">\n          <div class=\"ant-timeline-item-tail\"></div>\n          <div class=\"ant-timeline-item-head ant-timeline-item-head-custom ant-timeline-item-head-blue\">\n            <ng-container *nzStringTemplateOutlet=\"nzPendingDot\">\n              {{ nzPendingDot }}\n              @if (!nzPendingDot) {\n                <nz-icon nzType=\"loading\" />\n              }\n            </ng-container>\n          </div>\n          <div class=\"ant-timeline-item-content\">\n            <ng-container *nzStringTemplateOutlet=\"nzPending\">\n              {{ isPendingBoolean ? '' : nzPending }}\n            </ng-container>\n          </div>\n        </li>\n      }\n    </ng-template>\n    <!-- Grasp items -->\n    <ng-content />\n  `,\n  imports: [NgTemplateOutlet, NzOutletModule, NzIconModule]\n})\nexport class NzTimelineComponent implements AfterContentInit, OnChanges, OnInit {\n  private cdr = inject(ChangeDetectorRef);\n  private timelineService = inject(TimelineService);\n  private directionality = inject(Directionality);\n  private destroyRef = inject(DestroyRef);\n\n  @ContentChildren(NzTimelineItemComponent) listOfItems!: QueryList<NzTimelineItemComponent>;\n\n  @Input() nzMode: NzTimelineMode = 'left';\n  @Input() nzPending?: string | boolean | TemplateRef<void>;\n  @Input() nzPendingDot?: string | TemplateRef<void>;\n  @Input({ transform: booleanAttribute }) nzReverse: boolean = false;\n\n  isPendingBoolean: boolean = false;\n  timelineItems: NzTimelineItemComponent[] = [];\n  dir: Direction = 'ltr';\n  hasLabelItem = false;\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzMode, nzReverse, nzPending } = changes;\n\n    if (simpleChangeActivated(nzMode) || simpleChangeActivated(nzReverse)) {\n      this.updateChildren();\n    }\n\n    if (nzPending) {\n      this.isPendingBoolean = nzPending.currentValue === true;\n    }\n  }\n\n  ngOnInit(): void {\n    this.timelineService.check$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      this.cdr.markForCheck();\n    });\n\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n      this.dir = direction;\n      this.cdr.detectChanges();\n    });\n\n    this.dir = this.directionality.value;\n  }\n\n  ngAfterContentInit(): void {\n    this.updateChildren();\n\n    this.listOfItems.changes.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      this.updateChildren();\n    });\n  }\n\n  private updateChildren(): void {\n    if (this.listOfItems && this.listOfItems.length) {\n      const length = this.listOfItems.length;\n      let hasLabelItem = false;\n\n      this.listOfItems.forEach((item: NzTimelineItemComponent, index: number) => {\n        item.isLast = !this.nzReverse ? index === length - 1 : index === 0;\n        item.position = getInferredTimelineItemPosition(index, this.nzMode);\n\n        if (!hasLabelItem && item.nzLabel) {\n          hasLabelItem = true;\n        }\n\n        item.detectChanges();\n      });\n\n      this.timelineItems = this.nzReverse ? this.listOfItems.toArray().reverse() : this.listOfItems.toArray();\n      this.hasLabelItem = hasLabelItem;\n    } else {\n      this.timelineItems = [];\n      this.hasLabelItem = false;\n    }\n\n    this.cdr.markForCheck();\n  }\n}\n\nfunction simpleChangeActivated(simpleChange?: SimpleChange): boolean {\n  return !!(simpleChange && (simpleChange.previousValue !== simpleChange.currentValue || simpleChange.isFirstChange()));\n}\n\nfunction getInferredTimelineItemPosition(index: number, mode: NzTimelineMode): NzTimelinePosition | undefined {\n  if (mode === 'custom') {\n    return undefined;\n  } else if (mode === 'left' || mode === 'right') {\n    return mode;\n  } else {\n    return mode === 'alternate' && index % 2 === 0 ? 'left' : 'right';\n  }\n}\n"
  },
  {
    "path": "components/timeline/timeline.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzTimelineItemComponent } from './timeline-item.component';\nimport { NzTimelineComponent } from './timeline.component';\n\n@NgModule({\n  imports: [NzTimelineItemComponent, NzTimelineComponent],\n  exports: [NzTimelineItemComponent, NzTimelineComponent]\n})\nexport class NzTimelineModule {}\n"
  },
  {
    "path": "components/timeline/timeline.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Injectable } from '@angular/core';\nimport { ReplaySubject } from 'rxjs';\n\n@Injectable()\nexport class TimelineService {\n  check$ = new ReplaySubject<void>(1);\n\n  markForCheck(): void {\n    this.check$.next();\n  }\n}\n"
  },
  {
    "path": "components/timeline/timeline.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport { Component, DebugElement, provideZoneChangeDetection, ViewChild } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\n\nimport { NzDemoTimelineLabelComponent } from './demo/label';\nimport { NzTimelineComponent } from './timeline.component';\nimport { NzTimelineModule } from './timeline.module';\nimport { NzTimelineMode } from './typings';\n\ndescribe('nz-timeline', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection()]\n    });\n  });\n\n  describe('basic', () => {\n    let fixture: ComponentFixture<NzTestTimelineBasicComponent>;\n    let testComponent: NzTestTimelineBasicComponent;\n    let timeline: DebugElement;\n    let items: HTMLDivElement[] = [];\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTimelineBasicComponent);\n      testComponent = fixture.componentInstance;\n      fixture.detectChanges();\n\n      timeline = fixture.debugElement.query(By.directive(NzTimelineComponent));\n      items = Array.from((fixture.debugElement.nativeElement as HTMLElement).querySelectorAll('.ant-timeline-item'));\n    });\n\n    it('should init className correct', () => {\n      expect(timeline.nativeElement.firstElementChild!.classList).toContain('ant-timeline');\n      expect(items.length).toBeGreaterThan(0);\n      expect(items[0].classList).not.toContain('ant-timeline-item-last');\n      expect(items[3].classList).toContain('ant-timeline-item-last');\n    });\n\n    it('should color work', () => {\n      fixture.detectChanges();\n      expect(items[0].querySelector('.ant-timeline-item-head')!.classList).toContain('ant-timeline-item-head-blue');\n      testComponent.color = 'red';\n      fixture.detectChanges();\n      expect(items[0].querySelector('.ant-timeline-item-head')!.classList).toContain('ant-timeline-item-head-red');\n      testComponent.color = 'green';\n      fixture.detectChanges();\n      expect(items[0].querySelector('.ant-timeline-item-head')!.classList).toContain('ant-timeline-item-head-green');\n    });\n\n    it('should dot work', () => {\n      fixture.detectChanges();\n      expect((items[0].querySelector('.ant-timeline-item-head') as HTMLDivElement).innerText).toBe('dot');\n      expect((items[1].querySelector('.ant-timeline-item-head') as HTMLDivElement).innerText).toBe('template');\n    });\n\n    it('should last work', () => {\n      fixture.detectChanges();\n      expect(items.length).toBe(4);\n      testComponent.last = true;\n      fixture.detectChanges();\n      items = Array.from((fixture.debugElement.nativeElement as HTMLElement).querySelectorAll('.ant-timeline-item'));\n      expect(items.length).toBe(5);\n      expect(items[4]!.classList).toContain('ant-timeline-item-last');\n    });\n\n    it('should pending work', () => {\n      fixture.detectChanges();\n      expect(timeline.nativeElement.querySelector('.ant-timeline-item-pending')).toBeNull();\n      testComponent.pending = true;\n      fixture.detectChanges();\n      expect(timeline.nativeElement.querySelector('.ant-timeline-item-pending').innerText).toBe('');\n      testComponent.pending = 'pending';\n      fixture.detectChanges();\n      expect(timeline.nativeElement.querySelector('.ant-timeline-item-pending').innerText).toBe('pending');\n    });\n\n    it('should reverse work', () => {\n      fixture.detectChanges();\n      testComponent.pending = true;\n      testComponent.reverse = true;\n      fixture.detectChanges();\n      expect(timeline.nativeElement.firstElementChild.firstElementChild!.classList).toContain(\n        'ant-timeline-item-pending'\n      );\n      expect(items[0].classList).toContain('ant-timeline-item-last');\n      expect(items[3].classList).not.toContain('ant-timeline-item-last');\n    });\n\n    it('should alternate position work', () => {\n      fixture.detectChanges();\n      testComponent.mode = 'alternate';\n      fixture.detectChanges();\n      expect(timeline.nativeElement.firstElementChild!.classList).toContain('ant-timeline-alternate');\n      expect(items[0].classList).toContain('ant-timeline-item-left');\n      expect(items[1].classList).toContain('ant-timeline-item-right');\n      expect(items[2].classList).toContain('ant-timeline-item-left');\n    });\n\n    it('should alternate right position work', () => {\n      fixture.detectChanges();\n      testComponent.mode = 'right';\n      fixture.detectChanges();\n      expect(timeline.nativeElement.firstElementChild!.classList).toContain('ant-timeline-right');\n      expect(items[0].classList).toContain('ant-timeline-item-right');\n      expect(items[1].classList).toContain('ant-timeline-item-right');\n      expect(items[2].classList).toContain('ant-timeline-item-right');\n    });\n  });\n\n  // add another test component for simplicity\n  describe('custom position', () => {\n    let fixture: ComponentFixture<NzTestTimelineCustomPositionComponent>;\n    let timeline: DebugElement;\n    let items: HTMLDivElement[] = [];\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTimelineCustomPositionComponent);\n      fixture.detectChanges();\n\n      timeline = fixture.debugElement.query(By.directive(NzTimelineComponent));\n      items = Array.from((fixture.debugElement.nativeElement as HTMLElement).querySelectorAll('.ant-timeline-item'));\n    });\n\n    it('should custom position work', () => {\n      expect(timeline.nativeElement.firstElementChild!.classList).toContain('ant-timeline-alternate');\n      expect(items[0].classList).toContain('ant-timeline-item-right');\n    });\n  });\n\n  describe('custom color', () => {\n    let fixture: ComponentFixture<NzTestTimelineCustomColorComponent>;\n    let items: HTMLLIElement[];\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTimelineCustomColorComponent);\n      fixture.detectChanges();\n\n      items = Array.from((fixture.debugElement.nativeElement as HTMLElement).querySelectorAll('.ant-timeline-item'));\n    });\n\n    it('should support custom color', () => {\n      fixture.detectChanges();\n      expect((items[0].querySelector('.ant-timeline-item-head') as HTMLDivElement)!.style.borderColor).toBe('cyan');\n      expect((items[1].querySelector('.ant-timeline-item-head') as HTMLDivElement)!.style.borderColor).toBe(\n        'rgb(200, 0, 0)'\n      );\n      expect((items[2].querySelector('.ant-timeline-item-head') as HTMLDivElement)!.style.borderColor).toBe(\n        'rgb(120, 18, 65)'\n      ); // hex would be converted to rgb()\n      expect((items[3].querySelector('.ant-timeline-item-head') as HTMLDivElement)!.style.borderColor).toBe('');\n    });\n  });\n\n  describe('pending', () => {\n    let fixture: ComponentFixture<NzTestTimelinePendingComponent>;\n    let timeline: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTimelinePendingComponent);\n      fixture.detectChanges();\n      timeline = fixture.debugElement.query(By.directive(NzTimelineComponent));\n    });\n\n    it('should pending work', () => {\n      fixture.detectChanges();\n      expect(timeline.nativeElement.querySelector('.ant-timeline-item-pending').innerText).toBe('template');\n    });\n  });\n\n  describe('label', () => {\n    let fixture: ComponentFixture<NzDemoTimelineLabelComponent>;\n    let timeline: DebugElement;\n    let items: HTMLLIElement[];\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzDemoTimelineLabelComponent);\n      fixture.detectChanges();\n\n      timeline = fixture.debugElement.query(By.directive(NzTimelineComponent));\n      items = Array.from((fixture.debugElement.nativeElement as HTMLElement).querySelectorAll('.ant-timeline-item'));\n    });\n\n    it('should label work', () => {\n      expect(timeline.nativeElement.firstElementChild!.classList).toContain('ant-timeline-label');\n      expect(items[0].firstElementChild!.classList).toContain('ant-timeline-item-label');\n      expect(items[2].firstElementChild!.classList).not.toContain('ant-timeline-item-label');\n    });\n\n    it('should mode right not affecting classnames', () => {\n      fixture.componentInstance.mode = 'right';\n      fixture.detectChanges();\n\n      expect(timeline.nativeElement.firstElementChild!.classList).not.toContain('ant-timeline-right');\n    });\n  });\n\n  describe('RTL', () => {\n    let fixture: ComponentFixture<NzTestTimelineRtlComponent>;\n    let timeline: DebugElement;\n    let items: HTMLDivElement[] = [];\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTimelineRtlComponent);\n      fixture.detectChanges();\n\n      timeline = fixture.debugElement.query(By.directive(NzTimelineComponent));\n      items = Array.from((fixture.debugElement.nativeElement as HTMLElement).querySelectorAll('.ant-timeline-item'));\n    });\n\n    it('should init className correct', () => {\n      expect(timeline.nativeElement.firstElementChild!.classList).toContain('ant-timeline-rtl');\n      expect(items.length).toBeGreaterThan(0);\n\n      fixture.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n      expect(timeline.nativeElement.firstElementChild!.classList).not.toContain('ant-timeline-rtl');\n    });\n  });\n\n  describe('clear', () => {\n    let fixture: ComponentFixture<NzTestTimelineClearItemsComponent>;\n    let timeline: NzTimelineComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTimelineClearItemsComponent);\n      fixture.detectChanges();\n      timeline = fixture.componentInstance.nzTimeLine;\n    });\n\n    it('test clear items', () => {\n      fixture.componentInstance.reset();\n      fixture.detectChanges();\n      expect(timeline.timelineItems.length).toBe(0);\n    });\n  });\n});\n\n@Component({\n  imports: [NzTimelineModule],\n  selector: 'nz-test-basic-timeline',\n  template: `\n    <ng-template #dotTemplate>template</ng-template>\n    <nz-timeline [nzPending]=\"pending\" [nzReverse]=\"reverse\" [nzMode]=\"mode\">\n      <nz-timeline-item [nzColor]=\"color\" [nzDot]=\"dot\">Create a services site 2015-09-01</nz-timeline-item>\n      <nz-timeline-item [nzDot]=\"dotTemplate\">Solve initial network problems 2015-09-01</nz-timeline-item>\n      <nz-timeline-item>Technical testing 2015-09-01</nz-timeline-item>\n      <nz-timeline-item>Network problems being solved 2015-09-01</nz-timeline-item>\n      @if (last) {\n        <nz-timeline-item>Network problems being solved 2015-09-01</nz-timeline-item>\n      }\n    </nz-timeline>\n  `\n})\nexport class NzTestTimelineBasicComponent {\n  color = 'blue';\n  dot = 'dot';\n  pending: boolean | string = false;\n  last = false;\n  reverse = false;\n  mode: NzTimelineMode = 'left';\n}\n\n@Component({\n  imports: [NzTimelineModule],\n  template: `\n    <nz-timeline>\n      <nz-timeline-item nzColor=\"cyan\">Create a services site 2015-09-01</nz-timeline-item>\n      <nz-timeline-item nzColor=\"rgb(200, 0, 0)\">Solve initial network problems 2015-09-01</nz-timeline-item>\n      <nz-timeline-item nzColor=\"#781241\">Technical testing 2015-09-01</nz-timeline-item>\n      <nz-timeline-item nzColor=\"red\">Network problems being solved 2015-09-01</nz-timeline-item>\n    </nz-timeline>\n  `\n})\nexport class NzTestTimelineCustomColorComponent {}\n\n@Component({\n  imports: [NzTimelineModule],\n  template: `\n    <ng-template #pendingTemplate>template</ng-template>\n    <nz-timeline [nzPending]=\"pendingTemplate\">\n      <nz-timeline-item>Technical testing 2015-09-01</nz-timeline-item>\n      <nz-timeline-item>Network problems being solved 2015-09-01</nz-timeline-item>\n    </nz-timeline>\n  `\n})\nexport class NzTestTimelinePendingComponent {}\n\n@Component({\n  imports: [NzTimelineModule],\n  template: `\n    <nz-timeline nzMode=\"custom\">\n      <nz-timeline-item nzPosition=\"right\">Right</nz-timeline-item>\n      <nz-timeline-item nzPosition=\"left\">Left</nz-timeline-item>\n    </nz-timeline>\n  `\n})\nexport class NzTestTimelineCustomPositionComponent {}\n\n@Component({\n  imports: [BidiModule, NzTestTimelineBasicComponent],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-test-basic-timeline />\n    </div>\n  `\n})\nexport class NzTestTimelineRtlComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n}\n\n@Component({\n  imports: [NzTimelineModule],\n  template: `\n    <nz-timeline nzMode=\"custom\">\n      @for (item of data; track item) {\n        <nz-timeline-item>{{ item }}</nz-timeline-item>\n      }\n    </nz-timeline>\n    <span (click)=\"reset()\">reset</span>\n  `\n})\nexport class NzTestTimelineClearItemsComponent {\n  @ViewChild(NzTimelineComponent)\n  nzTimeLine!: NzTimelineComponent;\n  data = [1, 2, 3];\n  reset(): void {\n    this.data = [];\n  }\n}\n"
  },
  {
    "path": "components/timeline/typings.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport type NzTimelineMode = 'left' | 'alternate' | 'right' | 'custom';\n\nexport type NzTimelinePosition = 'left' | 'right';\n\nexport const TimelineTimeDefaultColors = ['red', 'blue', 'green', 'grey', 'gray'] as const;\nexport type NzTimelineItemColor = (typeof TimelineTimeDefaultColors)[number] | string;\n"
  },
  {
    "path": "components/tooltip/base.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { CdkConnectedOverlay, ConnectedOverlayPositionChange, ConnectionPositionPair } from '@angular/cdk/overlay';\nimport { _getEventTarget } from '@angular/cdk/platform';\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n  AfterViewInit,\n  ChangeDetectorRef,\n  DestroyRef,\n  Directive,\n  ElementRef,\n  EventEmitter,\n  OnChanges,\n  PLATFORM_ID,\n  Renderer2,\n  SimpleChanges,\n  TemplateRef,\n  Type,\n  ViewChild,\n  ViewContainerRef,\n  inject\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Subject, asapScheduler } from 'rxjs';\nimport { delay, distinctUntilChanged, filter } from 'rxjs/operators';\n\nimport { NzNoAnimationDirective } from 'ng-zorro-antd/core/animation';\nimport { NzConfigService, PopConfirmConfig, PopoverConfig } from 'ng-zorro-antd/core/config';\nimport {\n  DEFAULT_TOOLTIP_POSITIONS,\n  POSITION_MAP,\n  POSITION_TYPE,\n  TOOLTIP_OFFSET_MAP,\n  getPlacementName,\n  setConnectedPositionOffset\n} from 'ng-zorro-antd/core/overlay';\nimport { NgClassInterface, NgStyleInterface, NzSafeAny, NzTSType } from 'ng-zorro-antd/core/types';\nimport { isNotNil, toBoolean } from 'ng-zorro-antd/core/util';\n\nexport interface PropertyMapping {\n  [key: string]: [string, () => unknown];\n}\n\nexport type NzTooltipTrigger = 'click' | 'focus' | 'hover' | null;\n\n@Directive()\nexport abstract class NzTooltipBaseDirective implements AfterViewInit, OnChanges {\n  config?: Required<PopoverConfig | PopConfirmConfig>;\n  abstract arrowPointAtCenter?: boolean;\n  abstract directiveTitle?: NzTSType | null;\n  abstract directiveContent?: NzTSType | null;\n  abstract title?: NzTSType | null;\n  abstract content?: NzTSType | null;\n  abstract trigger?: NzTooltipTrigger;\n  abstract placement?: string | string[];\n  abstract origin?: ElementRef<HTMLElement>;\n  abstract visible?: boolean;\n  abstract mouseEnterDelay?: number;\n  abstract mouseLeaveDelay?: number;\n  abstract overlayClassName?: string;\n  abstract overlayStyle?: NgStyleInterface;\n  abstract overlayClickable?: boolean;\n  /** @deprecated Default is false, and customization is no longer supported. This will be removed in v22.0.0. */\n  cdkConnectedOverlayPush?: boolean = false;\n  visibleChange = new EventEmitter<boolean>();\n\n  /**\n   * This true title that would be used in other parts on this component.\n   */\n  protected get _title(): NzTSType | null {\n    return this.title || this.directiveTitle || null;\n  }\n\n  protected get _content(): NzTSType | null {\n    return this.content || this.directiveContent || null;\n  }\n\n  protected get _trigger(): NzTooltipTrigger {\n    return typeof this.trigger !== 'undefined' ? this.trigger : 'hover';\n  }\n\n  protected get _placement(): string[] {\n    const p = this.placement;\n    return Array.isArray(p) && p.length > 0 ? p : typeof p === 'string' && p ? [p] : ['top'];\n  }\n\n  protected get _visible(): boolean {\n    return (typeof this.visible !== 'undefined' ? this.visible : this.internalVisible) || false;\n  }\n\n  protected get _mouseEnterDelay(): number {\n    return this.mouseEnterDelay || 0.15;\n  }\n\n  protected get _mouseLeaveDelay(): number {\n    return this.mouseLeaveDelay || 0.1;\n  }\n\n  protected get _overlayClassName(): string | null {\n    return this.overlayClassName || null;\n  }\n\n  protected get _overlayStyle(): NgStyleInterface | null {\n    return this.overlayStyle || null;\n  }\n\n  protected get _overlayClickable(): boolean {\n    return this.overlayClickable ?? true;\n  }\n\n  private internalVisible = false;\n\n  protected getProxyPropertyMap(): PropertyMapping {\n    return {\n      noAnimation: ['noAnimation', () => !!this.noAnimation]\n    };\n  }\n\n  component?: NzTooltipBaseComponent;\n\n  protected readonly destroy$ = new Subject<void>();\n  protected readonly triggerDisposables: VoidFunction[] = [];\n\n  private delayTimer?: ReturnType<typeof setTimeout>;\n\n  elementRef = inject(ElementRef);\n  protected hostView = inject(ViewContainerRef);\n  protected renderer = inject(Renderer2);\n  protected noAnimation = inject(NzNoAnimationDirective, { host: true, optional: true });\n  protected nzConfigService = inject(NzConfigService);\n  protected destroyRef = inject(DestroyRef);\n  protected platformId = inject(PLATFORM_ID);\n\n  constructor(protected componentType: Type<NzTooltipBaseComponent>) {\n    this.destroyRef.onDestroy(() => {\n      // Clear toggling timer. Issue #3875 #4317 #4386\n      this.clearTogglingTimer();\n      this.removeTriggerListeners();\n    });\n  }\n\n  ngAfterViewInit(): void {\n    if (isPlatformBrowser(this.platformId)) {\n      this.createComponent();\n      this.registerTriggers();\n    }\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { trigger } = changes;\n\n    if (trigger && !trigger.isFirstChange()) {\n      this.registerTriggers();\n    }\n\n    if (this.component) {\n      this.updatePropertiesByChanges(changes);\n    }\n  }\n\n  show(): void {\n    this.component?.show();\n  }\n\n  hide(): void {\n    this.component?.hide();\n  }\n\n  /**\n   * Force the component to update its position.\n   */\n  updatePosition(): void {\n    if (this.component) {\n      this.component.updatePosition();\n    }\n  }\n\n  /**\n   * Create a dynamic tooltip component. This method can be overridden.\n   */\n  protected createComponent(): void {\n    const componentRef = this.hostView.createComponent(this.componentType);\n\n    this.component = componentRef.instance as NzTooltipBaseComponent;\n\n    // Remove the component's DOM because it should be in the overlay container.\n    this.renderer.removeChild(\n      this.renderer.parentNode(this.elementRef.nativeElement),\n      componentRef.location.nativeElement\n    );\n    this.component.setOverlayOrigin(this.origin || this.elementRef);\n\n    this.initProperties();\n\n    const visibleChange$ = this.component.nzVisibleChange.pipe(distinctUntilChanged());\n\n    visibleChange$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(visible => {\n      this.internalVisible = visible;\n      this.visibleChange.emit(visible);\n    });\n\n    // In some cases, the rendering takes into account the height at which the `arrow` is in the wrong place,\n    // so `cdk` sets the container position incorrectly.\n    // To avoid this, after placing the `arrow` in the correct position, we should `re-calculate` the position of the `overlay`.\n    visibleChange$\n      .pipe(\n        filter(Boolean),\n        delay(0, asapScheduler),\n        filter(() => Boolean(this.component?.overlay?.overlayRef)),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(() => {\n        this.component?.updatePosition();\n      });\n  }\n\n  protected registerTriggers(): void {\n    // When the method gets invoked, all properties have been synced to the dynamic component.\n    // After removing the old API, we can just check the directive's own `nzTrigger`.\n    const el = this.elementRef.nativeElement;\n    const trigger = this.trigger;\n\n    this.removeTriggerListeners();\n\n    if (trigger === 'hover') {\n      let overlayElement: HTMLElement;\n      this.triggerDisposables.push(\n        this.renderer.listen(el, 'mouseenter', () => {\n          this.delayEnterLeave(true, true, this._mouseEnterDelay);\n        })\n      );\n      this.triggerDisposables.push(\n        this.renderer.listen(el, 'mouseleave', () => {\n          this.delayEnterLeave(true, false, this._mouseLeaveDelay);\n          if (this.component?.overlay.overlayRef && !overlayElement) {\n            overlayElement = this.component.overlay.overlayRef.overlayElement;\n            this.triggerDisposables.push(\n              this.renderer.listen(overlayElement, 'mouseenter', () => {\n                this.delayEnterLeave(false, true, this._mouseEnterDelay);\n              })\n            );\n            this.triggerDisposables.push(\n              this.renderer.listen(overlayElement, 'mouseleave', () => {\n                this.delayEnterLeave(false, false, this._mouseLeaveDelay);\n              })\n            );\n          }\n        })\n      );\n    } else if (trigger === 'focus') {\n      this.triggerDisposables.push(this.renderer.listen(el, 'focusin', () => this.show()));\n      this.triggerDisposables.push(this.renderer.listen(el, 'focusout', () => this.hide()));\n    } else if (trigger === 'click') {\n      this.triggerDisposables.push(\n        this.renderer.listen(el, 'click', (e: MouseEvent) => {\n          e.preventDefault();\n          this.show();\n        })\n      );\n    }\n    // Else do nothing because user wants to control the visibility programmatically.\n  }\n\n  private updatePropertiesByChanges(changes: SimpleChanges): void {\n    this.updatePropertiesByKeys(Object.keys(changes));\n  }\n\n  private updatePropertiesByKeys(keys?: string[]): void {\n    const mappingProperties: PropertyMapping = {\n      // common mappings\n      title: ['nzTitle', () => this._title],\n      directiveTitle: ['nzTitle', () => this._title],\n      content: ['nzContent', () => this._content],\n      directiveContent: ['nzContent', () => this._content],\n      trigger: ['nzTrigger', () => this._trigger],\n      placement: ['nzPlacement', () => this._placement],\n      visible: ['nzVisible', () => this._visible],\n      mouseEnterDelay: ['nzMouseEnterDelay', () => this._mouseEnterDelay],\n      mouseLeaveDelay: ['nzMouseLeaveDelay', () => this._mouseLeaveDelay],\n      overlayClassName: ['nzOverlayClassName', () => this._overlayClassName],\n      overlayStyle: ['nzOverlayStyle', () => this._overlayStyle],\n      overlayClickable: ['nzOverlayClickable', () => this._overlayClickable],\n      arrowPointAtCenter: ['nzArrowPointAtCenter', () => this.arrowPointAtCenter],\n      cdkConnectedOverlayPush: ['cdkConnectedOverlayPush', () => this.cdkConnectedOverlayPush],\n      ...this.getProxyPropertyMap()\n    };\n\n    (keys || Object.keys(mappingProperties).filter(key => !key.startsWith('directive'))).forEach(\n      (property: NzSafeAny) => {\n        if (mappingProperties[property]) {\n          const [name, valueFn] = mappingProperties[property];\n          this.updateComponentValue(name, valueFn());\n        }\n      }\n    );\n\n    this.component?.updateByDirective();\n  }\n\n  private initProperties(): void {\n    this.updatePropertiesByKeys();\n  }\n\n  private updateComponentValue(key: string, value: NzSafeAny): void {\n    if (typeof value !== 'undefined') {\n      // @ts-ignore\n      this.component[key] = value;\n    }\n  }\n\n  private delayEnterLeave(isOrigin: boolean, isEnter: boolean, delay: number = -1): void {\n    if (this.delayTimer) {\n      this.clearTogglingTimer();\n    } else if (delay > 0) {\n      this.delayTimer = setTimeout(() => {\n        this.delayTimer = undefined;\n        isEnter ? this.show() : this.hide();\n      }, delay * 1000);\n    } else {\n      // `isOrigin` is used due to the tooltip will not hide immediately\n      // (maybe caused by the fade-out animation).\n      isEnter && isOrigin ? this.show() : this.hide();\n    }\n  }\n\n  private removeTriggerListeners(): void {\n    this.triggerDisposables.forEach(dispose => dispose());\n    this.triggerDisposables.length = 0;\n  }\n\n  private clearTogglingTimer(): void {\n    if (this.delayTimer) {\n      clearTimeout(this.delayTimer);\n      this.delayTimer = undefined;\n    }\n  }\n}\n\n@Directive()\nexport abstract class NzTooltipBaseComponent {\n  @ViewChild('overlay', { static: false }) overlay!: CdkConnectedOverlay;\n\n  protected readonly noAnimation = inject(NzNoAnimationDirective, { host: true, optional: true });\n  protected readonly dir = inject(Directionality).valueSignal;\n  protected readonly cdr = inject(ChangeDetectorRef);\n  protected readonly elementRef = inject(ElementRef);\n  protected readonly destroyRef = inject(DestroyRef);\n\n  nzTitle: NzTSType | null = null;\n  nzContent: NzTSType | null = null;\n  nzArrowPointAtCenter: boolean = false;\n  nzOverlayClassName!: string;\n  nzOverlayStyle: NgStyleInterface = {};\n  nzOverlayClickable: boolean = true;\n  nzBackdrop = false;\n  nzMouseEnterDelay?: number;\n  nzMouseLeaveDelay?: number;\n  /** @deprecated Default is false, and customization is no longer supported. This will be removed in v22.0.0. */\n  cdkConnectedOverlayPush?: boolean = false;\n\n  nzVisibleChange = new Subject<boolean>();\n\n  set nzVisible(value: boolean) {\n    const visible = toBoolean(value);\n    if (this._visible !== visible) {\n      this._visible = visible;\n      this.nzVisibleChange.next(visible);\n    }\n  }\n\n  get nzVisible(): boolean {\n    return this._visible;\n  }\n\n  _visible = false;\n\n  set nzTrigger(value: NzTooltipTrigger) {\n    this._trigger = value;\n  }\n\n  get nzTrigger(): NzTooltipTrigger {\n    return this._trigger;\n  }\n\n  protected _trigger: NzTooltipTrigger = 'hover';\n\n  set nzPlacement(value: POSITION_TYPE[]) {\n    const preferredPosition = value.map(placement =>\n      setConnectedPositionOffset(POSITION_MAP[placement], TOOLTIP_OFFSET_MAP[placement])\n    );\n    this._positions = [...preferredPosition, ...DEFAULT_TOOLTIP_POSITIONS];\n  }\n\n  preferredPlacement: string = 'top';\n\n  origin!: ElementRef<NzSafeAny>;\n\n  _classMap: NgClassInterface = {};\n\n  _prefix = 'ant-tooltip';\n\n  _positions: ConnectionPositionPair[] = [...DEFAULT_TOOLTIP_POSITIONS];\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      this.nzVisibleChange.complete();\n    });\n  }\n\n  show(): void {\n    if (this.nzVisible) {\n      return;\n    }\n\n    if (!this.isEmpty()) {\n      this.nzVisible = true;\n      this.nzVisibleChange.next(true);\n      this.cdr.detectChanges();\n    }\n\n    // for ltr for overlay to display tooltip in correct placement in rtl direction.\n    if (this.origin && this.overlay && this.overlay.overlayRef && this.overlay.overlayRef.getDirection() === 'rtl') {\n      this.overlay.overlayRef.setDirection('ltr');\n    }\n  }\n\n  hide(): void {\n    if (!this.nzVisible) {\n      return;\n    }\n\n    this.nzVisible = false;\n    this.nzVisibleChange.next(false);\n    this.cdr.detectChanges();\n  }\n\n  updateByDirective(): void {\n    this.updateStyles();\n    this.cdr.detectChanges();\n\n    Promise.resolve().then(() => {\n      this.updatePosition();\n      this.updateVisibilityByTitle();\n    });\n  }\n\n  /**\n   * Force the component to update its position.\n   */\n  updatePosition(): void {\n    if (this.origin && this.overlay && this.overlay.overlayRef) {\n      this.overlay.overlayRef.updatePosition();\n    }\n  }\n\n  onPositionChange(position: ConnectedOverlayPositionChange): void {\n    this.preferredPlacement = getPlacementName(position)!;\n    this.updateStyles();\n\n    // We have to trigger immediate change detection or the element would blink.\n    this.cdr.detectChanges();\n  }\n\n  setOverlayOrigin(origin: ElementRef<HTMLElement>): void {\n    this.origin = origin;\n    this.cdr.markForCheck();\n  }\n\n  onClickOutside(event: MouseEvent): void {\n    if (!this.nzOverlayClickable) {\n      return;\n    }\n    const target = _getEventTarget(event);\n    if (!this.origin.nativeElement.contains(target) && this.nzTrigger !== null) {\n      this.hide();\n    }\n  }\n\n  /**\n   * Hide the component while the content is empty.\n   */\n  private updateVisibilityByTitle(): void {\n    if (this.isEmpty()) {\n      this.hide();\n    }\n  }\n\n  protected updateStyles(): void {\n    this._classMap = {\n      ...this.transformClassListToMap(this.nzOverlayClassName),\n      [`${this._prefix}-placement-${this.preferredPlacement}`]: true\n    };\n  }\n\n  protected transformClassListToMap(klass: string): Record<string, boolean> {\n    const result: Record<string, boolean> = {};\n    /**\n     * @see https://github.com/angular/angular/blob/f6e97763cfab9fa2bea6e6b1303b64f1b499c3ef/packages/common/src/directives/ng_class.ts#L92\n     */\n    const classes = klass !== null ? klass.split(/\\s+/) : [];\n    classes.forEach(className => (result[className] = true));\n    return result;\n  }\n\n  /**\n   * Empty component cannot be opened.\n   */\n  protected abstract isEmpty(): boolean;\n}\n\nexport function isTooltipEmpty(value: string | TemplateRef<void> | null): boolean {\n  return value instanceof TemplateRef ? false : value === '' || !isNotNil(value);\n}\n"
  },
  {
    "path": "components/tooltip/demo/arrow-point-at-center.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 箭头指向\n  en-US: Arrow pointing at the center\n---\n\n## zh-CN\n\n通过设置 `nzTooltipArrowPointAtCenter` ，可以箭头将指向目标元素的中心。\n\n## en-US\n\nBy specifying `nzTooltipArrowPointAtCenter` prop, the arrow can be point to the center of the target element.\n"
  },
  {
    "path": "components/tooltip/demo/arrow-point-at-center.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzTooltipModule } from 'ng-zorro-antd/tooltip';\n\n@Component({\n  selector: 'nz-demo-tooltip-arrow-point-at-center',\n  imports: [NzButtonModule, NzTooltipModule],\n  template: `\n    <button nz-button nzTooltipTitle=\"prompt text\" nzTooltipPlacement=\"topLeft\" nz-tooltip>\n      Align edge / 边缘对齐\n    </button>\n    <button\n      nz-button\n      nz-tooltip\n      nzTooltipTitle=\"prompt text\"\n      nzTooltipPlacement=\"bottomLeft\"\n      [nzTooltipArrowPointAtCenter]=\"true\"\n    >\n      Arrow points to center / 箭头指向中心\n    </button>\n  `,\n  styles: `\n    button {\n      margin-right: 8px;\n      margin-bottom: 8px;\n    }\n  `\n})\nexport class NzDemoTooltipArrowPointAtCenterComponent {}\n"
  },
  {
    "path": "components/tooltip/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n最简单的用法。\n\n## en-US\n\nThe simplest usage.\n"
  },
  {
    "path": "components/tooltip/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTooltipModule } from 'ng-zorro-antd/tooltip';\n\n@Component({\n  selector: 'nz-demo-tooltip-basic',\n  imports: [NzTooltipModule],\n  template: `<span nz-tooltip nzTooltipTitle=\"prompt text\">Tooltip will show when mouse enter.</span>`\n})\nexport class NzDemoTooltipBasicComponent {}\n"
  },
  {
    "path": "components/tooltip/demo/color.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 多彩文字提示\n  en-US: Colorful tooltip\n---\n\n## zh-CN\n\n我们添加了多种预设色彩的文字提示样式，供不同场景使用。\n\n## en-US\n\nWe preset a series of colorful Tooltip styles for use in different situations.\n"
  },
  {
    "path": "components/tooltip/demo/color.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { presetColors } from 'ng-zorro-antd/core/color';\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\nimport { NzTooltipModule } from 'ng-zorro-antd/tooltip';\n\n@Component({\n  selector: 'nz-demo-tooltip-color',\n  imports: [NzButtonModule, NzDividerModule, NzTooltipModule],\n  template: `\n    <nz-divider nzText=\"Preset\" nzOrientation=\"left\" />\n    @for (color of presetColors; track color) {\n      <button nz-button nz-tooltip [nzTooltipTitle]=\"color\" [nzTooltipColor]=\"color\">\n        {{ color }}\n      </button>\n    }\n    <nz-divider nzText=\"Custom\" nzOrientation=\"left\" />\n    @for (color of customColors; track color) {\n      <button nz-button nz-tooltip [nzTooltipTitle]=\"color\" [nzTooltipColor]=\"color\">\n        {{ color }}\n      </button>\n    }\n  `,\n  styles: `\n    .ant-btn {\n      margin-right: 8px;\n      margin-bottom: 8px;\n    }\n  `\n})\nexport class NzDemoTooltipColorComponent {\n  customColors: string[] = ['#f50', '#2db7f5', '#87d068', '#108ee9'];\n  presetColors = presetColors;\n}\n"
  },
  {
    "path": "components/tooltip/demo/origin.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 指定目标\n  en-US: Target\n---\n\n## zh-CN\n\n通过 `nzTooltipOrigin` 指定 tooltip 的锚定元素（可以使用指令 `NzElementPatchDirective` 获取元素）\n\n## en-US\n\nUse `nzTooltipOrigin` to set the origin of the tooltip (You can use the utility directive `NzElementPatchDirective` to get the element).\n"
  },
  {
    "path": "components/tooltip/demo/origin.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzElementPatchDirective } from 'ng-zorro-antd/core/element-patch';\nimport { NzTooltipModule } from 'ng-zorro-antd/tooltip';\n\n@Component({\n  selector: 'nz-demo-tooltip-origin',\n  imports: [NzButtonModule, NzTooltipModule, NzElementPatchDirective],\n  template: `\n    <button nz-button nz-element #button=\"nzElement\">Action</button>\n    <a nz-tooltip nzTooltipTitle=\"This action could not be revoked!\" [nzTooltipOrigin]=\"button.elementRef\">Notice</a>\n  `,\n  styles: `\n    button {\n      margin-right: 8px;\n    }\n  `\n})\nexport class NzDemoTooltipOriginComponent {}\n"
  },
  {
    "path": "components/tooltip/demo/placement.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 位置\n  en-US: Placement\n---\n\n## zh-CN\n\n位置有 12 个方向。\n\n## en-US\n\nThe Tooltip has 12 placements choice.\n"
  },
  {
    "path": "components/tooltip/demo/placement.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzTooltipModule } from 'ng-zorro-antd/tooltip';\n\n@Component({\n  selector: 'nz-demo-tooltip-placement',\n  imports: [NzButtonModule, NzTooltipModule],\n  template: `\n    <div style=\"margin-left:60px;\">\n      <button nzTooltipTitle=\"prompt text\" [nzTooltipPlacement]=\"['topLeft', 'leftTop']\" nz-button nz-tooltip>\n        TL\n      </button>\n      <button nzTooltipTitle=\"prompt text\" nzTooltipPlacement=\"top\" nz-button nz-tooltip>Top</button>\n      <button nzTooltipTitle=\"prompt text\" nzTooltipPlacement=\"topRight\" nz-button nz-tooltip>TR</button>\n    </div>\n    <div style=\"float:left;width: 60px;\">\n      <button nzTooltipTitle=\"prompt text\" nzTooltipPlacement=\"leftTop\" nz-button nz-tooltip>LT</button>\n      <button nzTooltipTitle=\"prompt text\" nzTooltipPlacement=\"left\" nz-button nz-tooltip>Left</button>\n      <button nzTooltipTitle=\"prompt text\" nzTooltipPlacement=\"leftBottom\" nz-button nz-tooltip>LB</button>\n    </div>\n    <div style=\"margin-left:270px;width: 60px;\">\n      <button nzTooltipTitle=\"prompt text\" nzTooltipPlacement=\"rightTop\" nz-button nz-tooltip>RT</button>\n      <button nzTooltipTitle=\"prompt text\" nzTooltipPlacement=\"right\" nz-button nz-tooltip>Right</button>\n      <button nzTooltipTitle=\"prompt text\" nzTooltipPlacement=\"rightBottom\" nz-button nz-tooltip>RB</button>\n    </div>\n    <div style=\"margin-left:60px;clear: both;\">\n      <button nzTooltipTitle=\"prompt text\" nzTooltipPlacement=\"bottomLeft\" nz-button nz-tooltip>BL</button>\n      <button nzTooltipTitle=\"prompt text\" nzTooltipPlacement=\"bottom\" nz-button nz-tooltip>Bottom</button>\n      <button nzTooltipTitle=\"prompt text\" nzTooltipPlacement=\"bottomRight\" nz-button nz-tooltip>BR</button>\n    </div>\n  `,\n  styles: `\n    button {\n      width: 70px;\n      text-align: center;\n      padding: 0;\n      margin-right: 8px;\n      margin-bottom: 8px;\n    }\n  `\n})\nexport class NzDemoTooltipPlacementComponent {}\n"
  },
  {
    "path": "components/tooltip/demo/template.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 模板渲染\n  en-US: Template\n---\n\n## zh-CN\n\n`nzTooltipTitle` 可以传入 `TemplateRef<any>` 模板渲染。\n\n## en-US\n\n`nzTooltipTitle` accept the type of `TemplateRef<any>`\n"
  },
  {
    "path": "components/tooltip/demo/template.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzTooltipModule } from 'ng-zorro-antd/tooltip';\n\n@Component({\n  selector: 'nz-demo-tooltip-template',\n  imports: [NzIconModule, NzTooltipModule],\n  template: `\n    <a nz-tooltip [nzTooltipTitle]=\"titleTemplate\" [nzTooltipTitleContext]=\"{ $implicit: 'Icon' }\"\n      >This Tooltip has an Icon</a\n    >\n    <ng-template #titleTemplate let-thing>\n      <nz-icon nzType=\"file\" />\n      <span>Tooltip With {{ thing }}</span>\n    </ng-template>\n  `,\n  styles: `\n    .anticon {\n      margin-right: 8px;\n      margin-left: 8px;\n    }\n  `\n})\nexport class NzDemoTooltipTemplateComponent {}\n"
  },
  {
    "path": "components/tooltip/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Display\ntitle: Tooltip\ncover: 'https://gw.alipayobjects.com/zos/alicdn/Vyyeu8jq2/Tooltp.svg'\ndescription: Simple text popup box.\n---\n\n## When To Use\n\n- The Tooltip doesn't support complex text or operations. The tip is shown on mouse enter and is hidden on mouse leave.\n- To provide an explanation fo a `button/text/operation`. It's often used instead of the HTML `title` attribute to explain `button/text/operation`.\n\n## API\n\n### [nz-tooltip]\n\n| Property                        | Description                                                      | Type                                                                                                                                                                              | Default   |\n| ------------------------------- | ---------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- |\n| `[nzTooltipArrowPointAtCenter]` | Arrow point at center of the origin                              | `boolean`                                                                                                                                                                         | `false`   |\n| `[nzTooltipTitle]`              | The text shown in the tooltip                                    | `string \\| TemplateRef<void>`                                                                                                                                                     | -         |\n| `[nzTooltipTitleContext]`       | The context of tooltip title                                     | `object`                                                                                                                                                                          | -         |\n| `[nzTooltipTrigger]`            | Tooltip trigger mode. If set to `null` it would not be triggered | `'click' \\| 'focus' \\| 'hover' \\| null`                                                                                                                                           | `'hover'` |\n| `[nzTooltipPlacement]`          | The position of the tooltip relative to the target               | `'top' \\| 'left' \\| 'right' \\| 'bottom' \\| 'topLeft' \\| 'topRight' \\| 'bottomLeft' \\| 'bottomRight' \\| 'leftTop' \\| 'leftBottom' \\| 'rightTop' \\| 'rightBottom' \\| Array<string>` | `'top'`   |\n| `[nzTooltipColor]`              | The background color                                             | `string`                                                                                                                                                                          | -         |\n| `[nzTooltipOrigin]`             | Origin of the tooltip                                            | `ElementRef`                                                                                                                                                                      | -         |\n| `[nzTooltipVisible]`            | Show or hide tooltip                                             | `boolean`                                                                                                                                                                         | `false`   |\n| `(nzTooltipVisibleChange)`      | Callback of hide or show                                         | `EventEmitter<boolean>`                                                                                                                                                           | -         |\n| `[nzTooltipMouseEnterDelay]`    | Delay in seconds, before tooltip is shown on mouse enter         | `number`                                                                                                                                                                          | `0.15`    |\n| `[nzTooltipMouseLeaveDelay]`    | Delay in seconds, before tooltip is hidden on mouse leave        | `number`                                                                                                                                                                          | `0.1`     |\n| `[nzTooltipOverlayClassName]`   | Class name of the tooltip card                                   | `string`                                                                                                                                                                          | -         |\n| `[nzTooltipOverlayStyle]`       | Style of the tooltip card                                        | `object`                                                                                                                                                                          | -         |\n\n### Common API\n\nThe following APIs are shared by `nz-tooltip`, `nz-popconfirm`, `nz-popover`.\n\n| Method             | Description     |\n| ------------------ | --------------- |\n| `show()`           | Show            |\n| `hide()`           | Hide            |\n| `updatePosition()` | Update position |\n\n## Exclude body element's scroll event need to refresh the position of CDK\n\nIn using the tooltip (including popconfirm、popover), the body element's scroll event will update the position of the tooltip. It will never update the tooltip's position if the scroll event happens in a custom element. You can add the `cdkScrollable` directive to achieve the goal. Take notice that you need to import relative package `import { ScrollingModule } from '@angular/cdk/scrolling';`, for more information you can visit [scrolling/api](https://material.angular.io/cdk/scrolling/api).\n\n## Note\n\nPlease ensure that the node of `[nz-tooltip]` accepts `onMouseEnter`, `onMouseLeave`, `onFocus`, `onClick` events.\n\n## FAQ\n\n### Q: The overlay layer element does not follow the scroll position when scrolling\n\nBy default, the overlay layer element uses body as the scroll container. If using another scroll container, add the [CdkScrollable](https://material.angular.dev/cdk/scrolling/api#CdkScrollable) directive to the custom scroll container element.\nNote: You need to import the `CdkScrollable` directive or `ScrollingModule` module from `@angular/cdk/scrolling`.\n"
  },
  {
    "path": "components/tooltip/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 文字提示\ntype: 数据展示\ntitle: Tooltip\ncover: 'https://gw.alipayobjects.com/zos/alicdn/Vyyeu8jq2/Tooltp.svg'\ndescription: 简单的文字提示气泡框。\n---\n\n## 何时使用\n\n鼠标移入则显示提示，移出消失，气泡浮层不承载复杂文本和操作。\n\n可用来代替系统默认的 `title` 提示，提供一个`按钮/文字/操作`的文案解释。\n\n## API\n\n### [nz-tooltip]\n\n| 参数                            | 说明                                                                       | 类型                                                                                                                                                                              | 默认值    |\n| ------------------------------- | -------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- |\n| `[nzTooltipArrowPointAtCenter]` | 箭头指向锚点的中心                                                         | `boolean`                                                                                                                                                                         | `false`   |\n| `[nzTooltipTitle]`              | 提示文字                                                                   | `string \\| TemplateRef<void>`                                                                                                                                                     | -         |\n| `[nzTooltipTitleContext]`       | 提示文字模板上下文                                                         | `object`                                                                                                                                                                          | -         |\n| `[nzTooltipTrigger]`            | 触发行为，可选 `'click' \\| 'focus' \\| 'hover'`，为 `null` 时不响应光标事件 | `'click' \\| 'focus' \\| 'hover' \\| null`                                                                                                                                           | `'hover'` |\n| `[nzTooltipPlacement]`          | 气泡框位置                                                                 | `'top' \\| 'left' \\| 'right' \\| 'bottom' \\| 'topLeft' \\| 'topRight' \\| 'bottomLeft' \\| 'bottomRight' \\| 'leftTop' \\| 'leftBottom' \\| 'rightTop' \\| 'rightBottom' \\| Array<string>` | `'top'`   |\n| `[nzTooltipColor]`              | 背景颜色                                                                   | `string`                                                                                                                                                                          | -         |\n| `[nzTooltipOrigin]`             | 气泡框定位元素                                                             | `ElementRef`                                                                                                                                                                      | -         |\n| `[nzTooltipVisible]`            | 显示隐藏气泡框                                                             | `boolean`                                                                                                                                                                         | `false`   |\n| `(nzTooltipVisibleChange)`      | 显示隐藏的事件                                                             | `EventEmitter<boolean>`                                                                                                                                                           | -         |\n| `[nzTooltipMouseEnterDelay]`    | 鼠标移入后延时多少才显示 Tooltip，单位：秒                                 | `number`                                                                                                                                                                          | `0.15`    |\n| `[nzTooltipMouseLeaveDelay]`    | 鼠标移出后延时多少才隐藏 Tooltip，单位：秒                                 | `number`                                                                                                                                                                          | `0.1`     |\n| `[nzTooltipOverlayClassName]`   | 卡片类名                                                                   | `string`                                                                                                                                                                          | -         |\n| `[nzTooltipOverlayStyle]`       | 卡片样式                                                                   | `object`                                                                                                                                                                          | -         |\n\n### 共同的 API\n\n以下 API 为 `nz-tooltip`、`nz-popconfirm`、`nz-popover` 共享的 API。\n\n| 方法               | 说明     |\n| ------------------ | -------- |\n| `show()`           | 打开     |\n| `hide()`           | 隐藏     |\n| `updatePosition()` | 调整位置 |\n\n## 注意\n\n请确保 `[nz-tooltip]` 元素能接受 `onMouseEnter`、`onMouseLeave`、`onFocus`、`onClick` 事件。\n\n## FAQ\n\n### Q：滚动时浮层元素没有跟随滚动位置\n\n默认情况下，浮层元素使用 `body` 作为滚动容器，如果使用了其他滚动容器，在自定义滚动容器元素上添加 [CdkScrollable](https://material.angular.dev/cdk/scrolling/api#CdkScrollable) 指令。\n注意：您需要从 `@angular/cdk/scrolling` 导入 `CdkScrollable` 指令或 `ScrollingModule` 模块。\n"
  },
  {
    "path": "components/tooltip/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/tooltip/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/tooltip/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './tooltip';\nexport * from './tooltip.module';\nexport * from './base';\n"
  },
  {
    "path": "components/tooltip/style/entry.less",
    "content": "@import './index.less';\n@import './patch';\n"
  },
  {
    "path": "components/tooltip/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import '../../style/core/motion/zoom';\n\n@tooltip-prefix-cls: ~'@{ant-prefix}-tooltip';\n\n// Base class\n.@{tooltip-prefix-cls} {\n  .reset-component();\n\n  --antd-arrow-background-color: @tooltip-bg;\n\n  position: absolute;\n  z-index: @zindex-tooltip;\n  display: block;\n  width: max-content;\n  max-width: @tooltip-max-width;\n  visibility: visible;\n\n  &-content {\n    position: relative;\n  }\n\n  &-hidden {\n    display: none;\n  }\n\n  // Wrapper for the tooltip content\n  &-inner {\n    min-width: 30px;\n    min-height: 32px;\n    padding: calc(@padding-sm / 2) @padding-xs;\n    color: @tooltip-color;\n    text-align: start;\n    text-decoration: none;\n    word-wrap: break-word;\n    background-color: @tooltip-bg;\n    border-radius: @border-radius-base;\n    box-shadow: @box-shadow-base;\n  }\n\n  // Arrow Style\n  .placementArrow(@tooltip-arrow-width, 4px, @arrow-border-radius, var(--antd-arrow-background-color), @popover-arrow-box-shadow);\n}\n\n.generator-tooltip-preset-color(@i: length(@preset-colors)) when (@i > 0) {\n  .generator-tooltip-preset-color(@i - 1);\n  @color: extract(@preset-colors, @i);\n  @lightColor: '@{color}-6';\n\n  .@{tooltip-prefix-cls}-@{color} {\n    .@{tooltip-prefix-cls}-inner {\n      background-color: @@lightColor;\n    }\n\n    .@{tooltip-prefix-cls}-arrow {\n      --antd-arrow-background-color: @@lightColor;\n    }\n  }\n}\n\n.generator-tooltip-preset-color();\n\n// Animations\n.zoom-motion('zoom-big-fast', antZoomBig, @animation-duration-fast);\n\n@import './rtl';\n"
  },
  {
    "path": "components/tooltip/style/patch.less",
    "content": ".ant-tooltip {\n  position: relative;\n}\n"
  },
  {
    "path": "components/tooltip/style/rtl.less",
    "content": "@tooltip-prefix-cls: ~'@{ant-prefix}-tooltip';\n\n// Base class\n.@{tooltip-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n}\n"
  },
  {
    "path": "components/tooltip/tooltip.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzTooltipComponent, NzTooltipDirective } from './tooltip';\n\n@NgModule({\n  imports: [NzTooltipComponent, NzTooltipDirective],\n  exports: [NzTooltipComponent, NzTooltipDirective]\n})\nexport class NzTooltipModule {}\n"
  },
  {
    "path": "components/tooltip/tooltip.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport { Component, ElementRef, provideZoneChangeDetection, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, inject, TestBed, tick } from '@angular/core/testing';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { NzElementPatchDirective } from 'ng-zorro-antd/core/element-patch';\nimport { dispatchMouseEvent } from 'ng-zorro-antd/core/testing';\n\nimport { NzTooltipBaseDirective, NzTooltipTrigger } from './base';\nimport { NzTooltipDirective } from './tooltip';\nimport { NzTooltipModule } from './tooltip.module';\n\ndescribe('tooltip', () => {\n  let fixture: ComponentFixture<NzTooltipTestComponent>;\n  let component: NzTooltipTestComponent;\n  let overlayContainer: OverlayContainer;\n  let overlayContainerElement: HTMLElement;\n\n  beforeEach(fakeAsync(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection(), provideNoopAnimations()]\n    });\n    fixture = TestBed.createComponent(NzTooltipTestComponent);\n    component = fixture.componentInstance;\n    fixture.detectChanges();\n  }));\n\n  beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n    overlayContainer = oc;\n    overlayContainerElement = oc.getContainerElement();\n  }));\n\n  afterEach(() => {\n    overlayContainer.ngOnDestroy();\n  });\n\n  function getTextContentOf(selector: string): string | null {\n    const el = overlayContainerElement.querySelector(selector);\n    return el && el.textContent ? el.textContent : null;\n  }\n\n  function getTitleTextContent(): string | null {\n    return getTextContentOf('.ant-tooltip-title');\n  }\n\n  function waitingForTooltipToggling(): void {\n    fixture.detectChanges();\n    tick(1000);\n    fixture.detectChanges();\n  }\n\n  describe('visibility', () => {\n    it('should hover mode work', fakeAsync(() => {\n      const title = 'title-string';\n      const triggerElement = component.titleString.nativeElement;\n\n      expect(overlayContainerElement.textContent).not.toContain(title);\n\n      dispatchMouseEvent(triggerElement, 'mouseenter');\n      waitingForTooltipToggling();\n      dispatchMouseEvent(triggerElement, 'mouseenter');\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent).toContain(title);\n      expect(component.visibilityTogglingCount).toBe(1);\n\n      const overlayElement = getOverlayElementForTooltip(component.titleStringDirective);\n\n      dispatchMouseEvent(triggerElement, 'mouseleave');\n      fixture.detectChanges();\n      dispatchMouseEvent(overlayElement, 'mouseenter');\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent).toContain(title);\n\n      dispatchMouseEvent(overlayElement, 'mouseleave');\n      waitingForTooltipToggling();\n      // FIXME: the following line errors\n      // expect(overlayContainerElement.textContent).not.toContain(title);\n      // Don't know why this breaks. The website works fine.\n\n      dispatchMouseEvent(triggerElement, 'mouseenter');\n      waitingForTooltipToggling();\n      expect(overlayContainerElement.textContent).toContain(title);\n\n      dispatchMouseEvent(triggerElement, 'mouseleave');\n      waitingForTooltipToggling();\n      expect(overlayContainerElement.textContent).not.toContain(title);\n\n      component.mouseEnterDelay = 0.2;\n      fixture.detectChanges();\n      dispatchMouseEvent(triggerElement, 'mouseenter');\n      tick(150);\n      expect(overlayContainerElement.textContent).not.toContain(title);\n      tick(50);\n      expect(overlayContainerElement.textContent).toContain(title);\n\n      dispatchMouseEvent(triggerElement, 'mouseleave');\n      tick(150);\n      expect(overlayContainerElement.textContent).not.toContain(title);\n\n      component.mouseEnterDelay = 0.15;\n      component.mouseLeaveDelay = 0.2;\n      fixture.detectChanges();\n      dispatchMouseEvent(triggerElement, 'mouseenter');\n      tick(150);\n      expect(overlayContainerElement.textContent).toContain(title);\n\n      dispatchMouseEvent(triggerElement, 'mouseleave');\n      tick(150);\n      expect(overlayContainerElement.textContent).toContain(title);\n      tick(50);\n      expect(overlayContainerElement.textContent).not.toContain(title);\n    }));\n\n    it('should click mode work', fakeAsync(() => {\n      const title = 'title-template';\n      const triggerElement = component.titleTemplate.nativeElement;\n\n      dispatchMouseEvent(triggerElement, 'click');\n      waitingForTooltipToggling();\n      expect(overlayContainerElement.textContent).toContain(title);\n\n      dispatchMouseEvent(document.body, 'click');\n      waitingForTooltipToggling();\n      expect(overlayContainerElement.textContent).not.toContain(title);\n    }));\n\n    it('should focus and blur mode work', fakeAsync(() => {\n      const title = 'focus';\n      const triggerElement = component.focusTemplate.nativeElement;\n\n      dispatchMouseEvent(triggerElement, 'focusin');\n      waitingForTooltipToggling();\n      expect(overlayContainerElement.textContent).toContain(title);\n\n      dispatchMouseEvent(triggerElement, 'focusout');\n      waitingForTooltipToggling();\n      expect(overlayContainerElement.textContent).not.toContain(title);\n    }));\n\n    it('should support changing visibility programmatically', fakeAsync(() => {\n      const title = 'program';\n\n      component.visible = true;\n      waitingForTooltipToggling();\n      expect(overlayContainerElement.textContent).toContain(title);\n      expect(component.visibilityTogglingCount).toBe(1);\n\n      component.visible = false;\n      waitingForTooltipToggling();\n      expect(overlayContainerElement.textContent).not.toContain(title);\n      expect(component.visibilityTogglingCount).toBe(2);\n    }));\n\n    it('should not hide tooltip when `nzTooltipTrigger` is null', fakeAsync(() => {\n      const title = 'always show';\n\n      component.trigger = null;\n      component.visible = true;\n      waitingForTooltipToggling();\n      dispatchMouseEvent(document.body, 'click');\n      waitingForTooltipToggling();\n      expect(overlayContainerElement.textContent).toContain(title);\n\n      component.trigger = 'click';\n      waitingForTooltipToggling();\n      dispatchMouseEvent(document.body, 'click');\n      waitingForTooltipToggling();\n      expect(overlayContainerElement.textContent).not.toContain(title);\n    }));\n  });\n\n  describe('content', () => {\n    it('cannot be visible when the title is empty', fakeAsync(() => {\n      const triggerElement = component.titleString.nativeElement;\n\n      component.title = null;\n      fixture.detectChanges();\n\n      dispatchMouseEvent(triggerElement, 'mouseenter');\n      waitingForTooltipToggling();\n      expect(getTitleTextContent()).not.toContain('title-string');\n      expect(component.visibilityTogglingCount).toBe(0);\n    }));\n\n    it('should change overlayStyle when the overlayStyle is changed', fakeAsync(() => {\n      const triggerElement = component.titleString.nativeElement;\n\n      dispatchMouseEvent(triggerElement, 'mouseenter');\n      waitingForTooltipToggling();\n\n      component.style = { color: '#fff' };\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector<HTMLElement>('.ant-tooltip')!.style.color).toBe(\n        'rgb(255, 255, 255)'\n      );\n\n      component.style = { color: '#000' };\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector<HTMLElement>('.ant-tooltip')!.style.color).toBe('rgb(0, 0, 0)');\n    }));\n\n    it('should change overlayClass when the nzTooltipOverlayClassName is changed', fakeAsync(() => {\n      const triggerElement = component.titleString.nativeElement;\n\n      dispatchMouseEvent(triggerElement, 'mouseenter');\n      waitingForTooltipToggling();\n\n      component.class = 'testClass2';\n      fixture.detectChanges();\n\n      expect(overlayContainerElement.querySelector<HTMLElement>('.testClass')).toBeNull();\n      expect(overlayContainerElement.querySelector<HTMLElement>('.testClass2')).not.toBeNull();\n    }));\n\n    it('should nzTooltipOverlayClassName support classes listed in the string (space delimited)', fakeAsync(() => {\n      const triggerElement = component.titleString.nativeElement;\n      component.class = 'testClass1 testClass2';\n      fixture.detectChanges();\n\n      dispatchMouseEvent(triggerElement, 'mouseenter');\n      waitingForTooltipToggling();\n\n      expect(overlayContainerElement.querySelector<HTMLElement>('.testClass1.testClass2')).not.toBeNull();\n    }));\n\n    it('should hide when the title is changed to null', fakeAsync(() => {\n      const title = 'title-string';\n      const triggerElement = component.titleString.nativeElement;\n\n      expect(overlayContainerElement.textContent).not.toContain(title);\n\n      dispatchMouseEvent(triggerElement, 'mouseenter');\n      waitingForTooltipToggling();\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent).toContain(title);\n      expect(component.visibilityTogglingCount).toBe(1);\n\n      // Should close when the title is changed to null.\n      component.title = null;\n      fixture.detectChanges();\n      waitingForTooltipToggling();\n      fixture.detectChanges();\n      expect(overlayContainerElement.textContent).not.toContain(title);\n      expect(component.visibilityTogglingCount).toBe(2);\n    }));\n\n    // changing the title on the directive should be synced to the component\n    it('should set `setTitle` proxy to `nzTitle`', fakeAsync(() => {\n      const triggerElement = component.titleString.nativeElement;\n      const tooltipComponent = component.titleStringDirective.component!;\n\n      dispatchMouseEvent(triggerElement, 'mouseenter');\n      waitingForTooltipToggling();\n      expect(tooltipComponent.nzTitle).toBe('title-string');\n      expect(overlayContainerElement.textContent).toContain('title-string');\n\n      component.title = 'changed!';\n      fixture.detectChanges();\n      expect(tooltipComponent.nzTitle).toBe('changed!');\n      expect(overlayContainerElement.textContent).toContain('changed!');\n    }));\n\n    it('should support changing trigger', fakeAsync(() => {\n      const featureKey = 'title-template';\n      const triggerElement = component.titleTemplate.nativeElement;\n\n      dispatchMouseEvent(triggerElement, 'click');\n      waitingForTooltipToggling();\n      expect(overlayContainerElement.textContent).toContain(featureKey);\n\n      dispatchMouseEvent(document.body, 'click');\n      waitingForTooltipToggling();\n      expect(overlayContainerElement.textContent).not.toContain(featureKey);\n\n      component.trigger = null;\n      fixture.detectChanges();\n\n      dispatchMouseEvent(triggerElement, 'mouseenter');\n      waitingForTooltipToggling();\n      expect(overlayContainerElement.textContent).not.toContain(featureKey);\n    }));\n\n    it('should support changing position', fakeAsync(() => {\n      const tooltipComponent = component.titleStringDirective.component!;\n\n      // here we just make sure the preferred position is the first in the position array\n      expect(tooltipComponent._positions.length).toBe(5);\n    }));\n\n    it('should background work', fakeAsync(() => {\n      const triggerElement = component.titleTemplate.nativeElement;\n      component.color = 'pink';\n      fixture.detectChanges();\n\n      dispatchMouseEvent(triggerElement, 'click');\n      waitingForTooltipToggling();\n      const tooltip = overlayContainerElement.querySelector<HTMLElement>('.ant-tooltip')!;\n      expect(tooltip.classList).toContain('ant-tooltip-pink');\n\n      component.color = '#f50';\n      fixture.detectChanges();\n\n      expect(tooltip.querySelector<HTMLElement>('.ant-tooltip-inner')!.style.backgroundColor).toBe('rgb(255, 85, 0)');\n      const arrow = tooltip.querySelector<HTMLElement>('.ant-tooltip-arrow')!;\n      // Check that the CSS variable is correctly set on the arrow element\n      const arrowStyles = getComputedStyle(arrow);\n      const cssVarValue = arrowStyles.getPropertyValue('--antd-arrow-background-color').trim();\n      expect(cssVarValue).toBe('#f50');\n    }));\n  });\n\n  describe('dom', () => {\n    it('should not insert element as the sibling of the directive element', fakeAsync(() => {\n      fixture.detectChanges();\n      const triggerElement = component.inBtnGroup.nativeElement;\n      // There's a <!--container--> element created by Ivy.\n      expect(triggerElement.nextSibling.nextSibling.tagName).toBe('BUTTON');\n    }));\n  });\n});\n\ndescribe('origin', () => {\n  let component: NzTestTooltipTargetComponent;\n\n  beforeEach(fakeAsync(() => {\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations()]\n    });\n    const fixture = TestBed.createComponent(NzTestTooltipTargetComponent);\n    component = fixture.componentInstance;\n    fixture.detectChanges();\n  }));\n\n  it('should target work', () => {\n    expect((component.tooltip!.component!.origin!.nativeElement as HTMLElement).tagName).toBe('BUTTON');\n  });\n});\n\ndescribe('arrow', () => {\n  let component: NzTestTooltipArrowComponent;\n\n  beforeEach(fakeAsync(() => {\n    TestBed.configureTestingModule({\n      providers: [provideNoopAnimations()]\n    });\n    const fixture = TestBed.createComponent(NzTestTooltipArrowComponent);\n    component = fixture.componentInstance;\n    fixture.detectChanges();\n  }));\n\n  it('should support arrow pointing at center', () => {\n    const overlayElement = getOverlayElementForTooltip(component.tooltipDirective);\n\n    expect(overlayElement.querySelector('.ant-tooltip-arrow')).toBeTruthy();\n    // just read style.transform wouldn't get us the correct result\n    /** FIXME\n     * This test failed on CI but not on local ...\n     * expect(overlayElement.parentElement!.innerHTML).toContain('transform: translateX');\n     * **/\n  });\n});\n\nfunction getOverlayElementForTooltip(tooltip: NzTooltipBaseDirective): HTMLElement {\n  return tooltip!.component!.overlay.overlayRef.overlayElement;\n}\n\n@Component({\n  imports: [NzTooltipModule],\n  template: `\n    <a\n      #titleString\n      nz-tooltip\n      [nzTooltipTitle]=\"title\"\n      nzTooltipTrigger=\"hover\"\n      nzTooltipPlacement=\"topLeft\"\n      [nzTooltipOverlayClassName]=\"class\"\n      [nzTooltipOverlayStyle]=\"style\"\n      [nzTooltipMouseEnterDelay]=\"mouseEnterDelay\"\n      [nzTooltipMouseLeaveDelay]=\"mouseLeaveDelay\"\n      (nzTooltipVisibleChange)=\"onVisibleChange()\"\n    >\n      Hover\n    </a>\n\n    <a #titleTemplate nz-tooltip [nzTooltipTitle]=\"template\" [nzTooltipTrigger]=\"trigger\" [nzTooltipColor]=\"color\">\n      Click\n    </a>\n\n    <a #focusTooltip nz-tooltip nzTooltipTrigger=\"focus\" nzTooltipTitle=\"focus\">Focus</a>\n\n    <a\n      #program\n      nz-tooltip\n      [nzTooltipTrigger]=\"null\"\n      nzTooltipTitle=\"program\"\n      [nzTooltipVisible]=\"visible\"\n      (nzTooltipVisibleChange)=\"onVisibleChange()\"\n    >\n      Manually\n    </a>\n\n    <a #alwaysShow nz-tooltip [nzTooltipTrigger]=\"trigger\" nzTooltipTitle=\"always show\" [nzTooltipVisible]=\"visible\">\n      Always Show\n    </a>\n\n    <div>\n      <button>A</button>\n      <button #inBtnGroup nz-tooltip nzTooltipTitle=\"title-string\">B</button>\n      <button>C</button>\n    </div>\n\n    <ng-template #template>title-template</ng-template>\n  `\n})\nexport class NzTooltipTestComponent {\n  @ViewChild('titleString', { static: false }) titleString!: ElementRef;\n  @ViewChild('titleString', { static: false, read: NzTooltipDirective })\n  titleStringDirective!: NzTooltipDirective;\n\n  @ViewChild('titleTemplate', { static: false }) titleTemplate!: ElementRef;\n  @ViewChild('titleTemplate', { static: false, read: NzTooltipDirective })\n  titleTemplateDirective!: NzTooltipDirective;\n\n  @ViewChild('focusTooltip', { static: false }) focusTemplate!: ElementRef;\n  @ViewChild('alwaysShow', { static: false }) alwaysShow!: ElementRef;\n\n  trigger: NzTooltipTrigger = 'click';\n\n  @ViewChild('inBtnGroup', { static: false }) inBtnGroup!: ElementRef;\n\n  title: string | null = 'title-string';\n  visible = false;\n  visibilityTogglingCount = 0;\n  style = { color: '#000' };\n  class = 'testClass';\n  mouseEnterDelay = 0.15;\n  mouseLeaveDelay = 0.1;\n  color?: string;\n  onVisibleChange(): void {\n    this.visibilityTogglingCount += 1;\n  }\n}\n\n@Component({\n  imports: [NzElementPatchDirective, NzTooltipModule],\n  template: `\n    <button nz-element #button=\"nzElement\">Action</button>\n    <a nz-tooltip nzTooltipTitle=\"This action could not be revoked!\" [nzTooltipOrigin]=\"button.elementRef\">Notice</a>\n  `\n})\nexport class NzTestTooltipTargetComponent {\n  @ViewChild(NzTooltipDirective) tooltip?: NzTooltipDirective;\n}\n\n@Component({\n  imports: [NzTooltipModule],\n  template: `\n    <a\n      #titleString\n      nz-tooltip\n      [nzTooltipVisible]=\"true\"\n      nzTooltipTitle=\"Title\"\n      nzTooltipPlacement=\"bottomLeft\"\n      [nzTooltipArrowPointAtCenter]=\"true\"\n    >\n      Tooltip\n    </a>\n  `\n})\nexport class NzTestTooltipArrowComponent {\n  @ViewChild('titleString', { static: false, read: NzTooltipDirective }) tooltipDirective!: NzTooltipDirective;\n}\n"
  },
  {
    "path": "components/tooltip/tooltip.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { OverlayModule } from '@angular/cdk/overlay';\nimport {\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  Component,\n  Directive,\n  ElementRef,\n  EventEmitter,\n  Input,\n  Output,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { NzNoAnimationDirective, withAnimationCheck } from 'ng-zorro-antd/core/animation';\nimport { isPresetColor, NzPresetColor } from 'ng-zorro-antd/core/color';\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzOverlayModule } from 'ng-zorro-antd/core/overlay';\nimport { NgStyleInterface, NzTSType } from 'ng-zorro-antd/core/types';\n\nimport {\n  isTooltipEmpty,\n  NzTooltipBaseComponent,\n  NzTooltipBaseDirective,\n  NzTooltipTrigger,\n  PropertyMapping\n} from './base';\n\n@Directive({\n  selector: '[nz-tooltip]',\n  exportAs: 'nzTooltip',\n  host: {\n    '[class.ant-tooltip-open]': 'visible'\n  }\n})\nexport class NzTooltipDirective extends NzTooltipBaseDirective {\n  /* eslint-disable @angular-eslint/no-input-rename, @angular-eslint/no-output-rename */\n  @Input('nzTooltipTitle') override title?: NzTSType | null;\n  @Input('nzTooltipTitleContext') titleContext?: object | null = null;\n  @Input('nz-tooltip') override directiveTitle?: NzTSType | null;\n  @Input('nzTooltipTrigger') override trigger?: NzTooltipTrigger = 'hover';\n  @Input('nzTooltipPlacement') override placement?: string | string[] = 'top';\n  @Input('nzTooltipOrigin') override origin?: ElementRef<HTMLElement>;\n  @Input('nzTooltipVisible') override visible?: boolean;\n  @Input('nzTooltipMouseEnterDelay') override mouseEnterDelay?: number;\n  @Input('nzTooltipMouseLeaveDelay') override mouseLeaveDelay?: number;\n  @Input('nzTooltipOverlayClassName') override overlayClassName?: string;\n  @Input('nzTooltipOverlayStyle') override overlayStyle?: NgStyleInterface;\n  @Input({ alias: 'nzTooltipArrowPointAtCenter', transform: booleanAttribute }) override arrowPointAtCenter?: boolean;\n  /** @deprecated Default is false, and customization is no longer supported. This will be removed in v22.0.0. */\n  @Input({ transform: booleanAttribute }) override cdkConnectedOverlayPush?: boolean = false;\n  @Input() nzTooltipColor?: string;\n\n  override directiveContent?: NzTSType | null = null;\n  override content?: NzTSType | null = null;\n  override overlayClickable?: boolean;\n\n  @Output('nzTooltipVisibleChange') override readonly visibleChange = new EventEmitter<boolean>();\n\n  constructor() {\n    super(NzTooltipComponent);\n  }\n\n  protected override getProxyPropertyMap(): PropertyMapping {\n    return {\n      ...super.getProxyPropertyMap(),\n      nzTooltipColor: ['nzColor', () => this.nzTooltipColor],\n      titleContext: ['nzTitleContext', () => this.titleContext]\n    };\n  }\n}\n\n@Component({\n  selector: 'nz-tooltip',\n  exportAs: 'nzTooltipComponent',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  template: `\n    <ng-template\n      #overlay=\"cdkConnectedOverlay\"\n      cdkConnectedOverlay\n      nzConnectedOverlay\n      [cdkConnectedOverlayOrigin]=\"origin\"\n      [cdkConnectedOverlayOpen]=\"_visible\"\n      [cdkConnectedOverlayPositions]=\"_positions\"\n      [cdkConnectedOverlayPush]=\"cdkConnectedOverlayPush\"\n      [nzArrowPointAtCenter]=\"nzArrowPointAtCenter\"\n      (overlayOutsideClick)=\"onClickOutside($event)\"\n      (detach)=\"hide()\"\n      (positionChange)=\"onPositionChange($event)\"\n    >\n      <div\n        class=\"ant-tooltip\"\n        [class.ant-tooltip-rtl]=\"dir() === 'rtl'\"\n        [class]=\"_classMap\"\n        [style]=\"nzOverlayStyle\"\n        [nzNoAnimation]=\"!!noAnimation?.nzNoAnimation?.()\"\n        [animate.enter]=\"zoomAnimationEnter()\"\n        [animate.leave]=\"zoomAnimationLeave()\"\n      >\n        <div class=\"ant-tooltip-arrow\" [style]=\"_arrowStyleMap\"></div>\n        <div class=\"ant-tooltip-content\">\n          <div class=\"ant-tooltip-inner\" [style]=\"_contentStyleMap\">\n            <ng-container *nzStringTemplateOutlet=\"nzTitle; context: nzTitleContext\">{{ nzTitle }}</ng-container>\n          </div>\n        </div>\n      </div>\n    </ng-template>\n  `,\n  imports: [OverlayModule, NzNoAnimationDirective, NzOutletModule, NzOverlayModule]\n})\nexport class NzTooltipComponent extends NzTooltipBaseComponent {\n  protected _animationPrefix = 'ant-zoom-big-fast';\n  override nzTitle: NzTSType | null = null;\n  nzTitleContext: object | null = null;\n  nzColor?: string | NzPresetColor;\n\n  protected _arrowStyleMap: NgStyleInterface = {};\n  protected _contentStyleMap: NgStyleInterface = {};\n\n  protected readonly zoomAnimationEnter = withAnimationCheck(\n    () => `${this._animationPrefix}-enter ${this._animationPrefix}-enter-active`\n  );\n  protected readonly zoomAnimationLeave = withAnimationCheck(\n    () => `${this._animationPrefix}-leave ${this._animationPrefix}-leave-active`\n  );\n\n  protected isEmpty(): boolean {\n    return isTooltipEmpty(this.nzTitle);\n  }\n\n  protected override updateStyles(): void {\n    const isColorPreset = this.nzColor && isPresetColor(this.nzColor);\n\n    this._classMap = {\n      ...this.transformClassListToMap(this.nzOverlayClassName),\n      [`${this._prefix}-placement-${this.preferredPlacement}`]: true,\n      [`${this._prefix}-${this.nzColor}`]: isColorPreset\n    };\n\n    this._contentStyleMap = {\n      backgroundColor: !!this.nzColor && !isColorPreset ? this.nzColor : null\n    };\n\n    this._arrowStyleMap = {\n      '--antd-arrow-background-color': !!this.nzColor && !isColorPreset ? this.nzColor : null\n    };\n  }\n}\n"
  },
  {
    "path": "components/transfer/demo/advanced.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 高级用法\n  en-US: Advanced\n---\n\n## zh-CN\n\n穿梭框高级用法，可配置操作文案，可定制宽高，可对底部进行自定义渲染。\n\n## en-US\n\nAdvanced Usage of Transfer.\n\nYou can customize the labels of the transfer buttons, the width and height of the columns, and what should be displayed in the footer.\n"
  },
  {
    "path": "components/transfer/demo/advanced.ts",
    "content": "import { Component, OnInit } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzMessageService } from 'ng-zorro-antd/message';\nimport { NzTransferModule, TransferItem } from 'ng-zorro-antd/transfer';\n\n@Component({\n  selector: 'nz-demo-transfer-advanced',\n  imports: [NzButtonModule, NzTransferModule],\n  template: `\n    <nz-transfer\n      [nzDataSource]=\"list\"\n      nzShowSearch\n      [nzOperations]=\"['to right', 'to left']\"\n      [nzListStyle]=\"{ 'width.px': 250, 'height.px': 300 }\"\n      [nzRender]=\"render\"\n      [nzFooter]=\"footer\"\n      (nzSelectChange)=\"select($event)\"\n      (nzChange)=\"change($event)\"\n    >\n      <ng-template #render let-item>{{ item.title }}-{{ item.description }}</ng-template>\n      <ng-template #footer let-direction>\n        <button nz-button (click)=\"reload(direction)\" nzSize=\"small\" style=\"float: right; margin: 5px;\">\n          reload\n        </button>\n      </ng-template>\n    </nz-transfer>\n  `\n})\nexport class NzDemoTransferAdvancedComponent implements OnInit {\n  list: TransferItem[] = [];\n\n  constructor(private messageService: NzMessageService) {}\n\n  ngOnInit(): void {\n    this.getData();\n  }\n\n  getData(): void {\n    const ret: TransferItem[] = [];\n    for (let i = 0; i < 20; i++) {\n      ret.push({\n        key: i.toString(),\n        title: `content${i + 1}`,\n        description: `description of content${i + 1}`,\n        direction: Math.random() * 2 > 1 ? 'right' : undefined\n      });\n    }\n    this.list = ret;\n  }\n\n  reload(direction: string): void {\n    this.getData();\n    this.messageService.success(`your clicked ${direction}!`);\n  }\n\n  select(ret: {}): void {\n    console.log('nzSelectChange', ret);\n  }\n\n  change(ret: {}): void {\n    console.log('nzChange', ret);\n  }\n}\n"
  },
  {
    "path": "components/transfer/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本用法\n  en-US: Basic\n---\n\n## zh-CN\n\n最基本的用法，展示了 `nzDataSource` 每行的渲染函数 `nzRender` 以及回调函数 `nzChange`、`nzSelectChange` 的用法。\n\n## en-US\n\nThe most basic usage of `nz-transfer` involves providing the source data and target keys arrays, plus the rendering and some callback functions.\n"
  },
  {
    "path": "components/transfer/demo/basic.ts",
    "content": "import { Component, OnInit } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\nimport { NzTransferModule, TransferItem } from 'ng-zorro-antd/transfer';\n\n@Component({\n  selector: 'nz-demo-transfer-basic',\n  imports: [FormsModule, NzSwitchModule, NzTransferModule],\n  template: `\n    <nz-transfer\n      [nzDataSource]=\"list\"\n      [nzDisabled]=\"disabled\"\n      [nzTitles]=\"['Source', 'Target']\"\n      (nzSelectChange)=\"select($event)\"\n      [nzSelectedKeys]=\"['0', '2', '3']\"\n      (nzChange)=\"change($event)\"\n    />\n    <br />\n    <nz-switch [(ngModel)]=\"disabled\" nzCheckedChildren=\"disabled\" nzUnCheckedChildren=\"disabled\" />\n  `\n})\nexport class NzDemoTransferBasicComponent implements OnInit {\n  list: TransferItem[] = [];\n  disabled = false;\n\n  ngOnInit(): void {\n    for (let i = 0; i < 20; i++) {\n      this.list.push({\n        key: i.toString(),\n        title: `content${i + 1}`,\n        disabled: i % 3 < 1\n      });\n    }\n\n    [2, 3].forEach(idx => (this.list[idx].direction = 'right'));\n  }\n\n  select(ret: {}): void {\n    console.log('nzSelectChange', ret);\n  }\n\n  change(ret: {}): void {\n    console.log('nzChange', ret);\n  }\n}\n"
  },
  {
    "path": "components/transfer/demo/can-move.md",
    "content": "---\norder: 6\ndebug: true\ntitle:\n  zh-CN: 二次校验\n  en-US: Check Before Move\n---\n\n## zh-CN\n\n利用 `nzCanMove` 允许在穿梭过程中二次校验；示例默认向右移时强制选中的第一项不可穿梭。\n\n## en-US\n\nCan use `nzCanMove` to do two-verification.\n"
  },
  {
    "path": "components/transfer/demo/can-move.ts",
    "content": "import { Component, OnInit } from '@angular/core';\nimport { Observable, of } from 'rxjs';\nimport { delay } from 'rxjs/operators';\n\nimport { NzTransferModule, TransferCanMove, TransferItem } from 'ng-zorro-antd/transfer';\n\n@Component({\n  selector: 'nz-demo-transfer-can-move',\n  imports: [NzTransferModule],\n  template: `\n    <nz-transfer\n      [nzDataSource]=\"list\"\n      [nzCanMove]=\"canMove\"\n      (nzSelectChange)=\"select($event)\"\n      (nzChange)=\"change($event)\"\n    />\n  `\n})\nexport class NzDemoTransferCanMoveComponent implements OnInit {\n  list: TransferItem[] = [];\n\n  ngOnInit(): void {\n    for (let i = 0; i < 20; i++) {\n      this.list.push({\n        key: i.toString(),\n        title: `content${i + 1}`,\n        disabled: i % 3 < 1\n      });\n    }\n\n    [2, 3].forEach(idx => (this.list[idx].direction = 'right'));\n  }\n\n  canMove(arg: TransferCanMove): Observable<TransferItem[]> {\n    if (arg.direction === 'right' && arg.list.length > 0) {\n      arg.list.splice(0, 1);\n    }\n    // or\n    // if (arg.direction === 'right' && arg.list.length > 0) delete arg.list[0];\n    return of(arg.list).pipe(delay(1000));\n  }\n\n  select(ret: {}): void {\n    console.log('nzSelectChange', ret);\n  }\n\n  change(ret: {}): void {\n    console.log('nzChange', ret);\n  }\n}\n"
  },
  {
    "path": "components/transfer/demo/custom-item.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 自定义渲染行数据\n  en-US: Custom datasource\n---\n\n## zh-CN\n\n自定义渲染每一个 Transfer Item，可用于渲染复杂数据。\n\n## en-US\n\nCustom each Transfer Item, and in this way you can render a complex datasource.\n"
  },
  {
    "path": "components/transfer/demo/custom-item.ts",
    "content": "import { Component, OnInit } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzTransferModule, TransferItem } from 'ng-zorro-antd/transfer';\n\n@Component({\n  selector: 'nz-demo-transfer-custom-item',\n  imports: [NzIconModule, NzTransferModule],\n  template: `\n    <nz-transfer\n      [nzDataSource]=\"list\"\n      [nzListStyle]=\"{ 'width.px': 300, 'height.px': 300 }\"\n      [nzRender]=\"render\"\n      (nzSelectChange)=\"select($event)\"\n      (nzChange)=\"change($event)\"\n    >\n      <ng-template #render let-item>\n        <nz-icon nzType=\"{{ item.icon }}\" />\n        {{ item.title }}\n      </ng-template>\n    </nz-transfer>\n  `\n})\nexport class NzDemoTransferCustomItemComponent implements OnInit {\n  list: Array<TransferItem & { description: string; icon: string }> = [];\n\n  ngOnInit(): void {\n    this.getData();\n  }\n\n  getData(): void {\n    const ret: Array<TransferItem & { description: string; icon: string }> = [];\n    for (let i = 0; i < 20; i++) {\n      ret.push({\n        key: i.toString(),\n        title: `content${i + 1}`,\n        description: `description of content${i + 1}`,\n        direction: Math.random() * 2 > 1 ? 'right' : undefined,\n        icon: `frown-o`\n      });\n    }\n    this.list = ret;\n  }\n\n  select(ret: {}): void {\n    console.log('nzSelectChange', ret);\n  }\n\n  change(ret: {}): void {\n    console.log('nzChange', ret);\n  }\n}\n"
  },
  {
    "path": "components/transfer/demo/one-way.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 单向样式\n  en-US: One Way\n---\n\n## zh-CN\n\n通过 `nzOneWay` 将 Transfer 转为单向样式。\n\n## en-US\n\nUse `nzOneWay` to make Transfer the one way style.\n"
  },
  {
    "path": "components/transfer/demo/one-way.ts",
    "content": "import { Component, OnInit } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\nimport { NzTransferModule, TransferItem } from 'ng-zorro-antd/transfer';\n\n@Component({\n  selector: 'nz-demo-transfer-one-way',\n  imports: [NzTransferModule, NzSwitchModule, FormsModule],\n  template: `\n    <nz-transfer\n      [nzDataSource]=\"list\"\n      [nzDisabled]=\"disabled\"\n      [nzTitles]=\"['Source', 'Target']\"\n      (nzSelectChange)=\"select($event)\"\n      [nzSelectedKeys]=\"['0', '2', '3']\"\n      nzOneWay\n      (nzChange)=\"change($event)\"\n    />\n    <div style=\"margin-top: 8px;\">\n      <nz-switch [(ngModel)]=\"disabled\" nzCheckedChildren=\"disabled\" nzUnCheckedChildren=\"disabled\" />\n      <div></div>\n    </div>\n  `\n})\nexport class NzDemoTransferOneWayComponent implements OnInit {\n  list: TransferItem[] = [];\n  disabled = false;\n\n  ngOnInit(): void {\n    for (let i = 0; i < 20; i++) {\n      this.list.push({\n        key: i.toString(),\n        title: `content${i + 1}`,\n        disabled: i % 3 < 1\n      });\n    }\n\n    [2, 3].forEach(idx => (this.list[idx].direction = 'right'));\n  }\n\n  select(ret: {}): void {\n    console.log('nzSelectChange', ret);\n  }\n\n  change(ret: {}): void {\n    console.log('nzChange', ret);\n  }\n}\n"
  },
  {
    "path": "components/transfer/demo/search.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 带搜索框\n  en-US: Search\n---\n\n## zh-CN\n\n带搜索框的穿梭框，可以自定义搜索函数。\n\n## en-US\n\nTransfer with a search box.\n"
  },
  {
    "path": "components/transfer/demo/search.ts",
    "content": "import { Component, OnInit } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\nimport { NzTransferModule, TransferItem } from 'ng-zorro-antd/transfer';\n\n@Component({\n  selector: 'nz-demo-transfer-search',\n  imports: [FormsModule, NzSwitchModule, NzTransferModule],\n  template: `\n    <nz-transfer\n      [nzDataSource]=\"list\"\n      [nzDisabled]=\"disabled\"\n      nzShowSearch\n      [nzFilterOption]=\"filterOption\"\n      (nzSearchChange)=\"search($event)\"\n      (nzSelectChange)=\"select($event)\"\n      (nzChange)=\"change($event)\"\n    />\n    <br />\n    <nz-switch [(ngModel)]=\"disabled\" nzCheckedChildren=\"disabled\" nzUnCheckedChildren=\"disabled\" />\n  `\n})\nexport class NzDemoTransferSearchComponent implements OnInit {\n  list: TransferItem[] = [];\n  disabled = false;\n\n  ngOnInit(): void {\n    for (let i = 0; i < 20; i++) {\n      this.list.push({\n        key: i.toString(),\n        title: `content${i + 1}`,\n        description: `description of content${i + 1}`,\n        direction: Math.random() * 2 > 1 ? 'right' : undefined\n      });\n    }\n  }\n\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  filterOption(inputValue: string, item: any): boolean {\n    return item.description.indexOf(inputValue) > -1;\n  }\n\n  search(ret: {}): void {\n    console.log('nzSearchChange', ret);\n  }\n\n  select(ret: {}): void {\n    console.log('nzSelectChange', ret);\n  }\n\n  change(ret: {}): void {\n    console.log('nzChange', ret);\n  }\n}\n"
  },
  {
    "path": "components/transfer/demo/status.md",
    "content": "---\norder: 11\ntitle:\n  zh-CN: 自定义状态\n  en-US: Status\n---\n\n## zh-CN\n\n使用 `nzStatus` 为 Transfer 添加状态，可选 `error` 或者 `warning`。\n\n## en-US\n\nAdd status to Transfer with `nzStatus`, which could be `error` or `warning`.\n"
  },
  {
    "path": "components/transfer/demo/status.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTransferModule } from 'ng-zorro-antd/transfer';\n\n@Component({\n  selector: 'nz-demo-transfer-status',\n  imports: [NzTransferModule],\n  template: `\n    <nz-transfer [nzDataSource]=\"[]\" nzStatus=\"error\" />\n    <br />\n    <nz-transfer [nzDataSource]=\"[]\" nzStatus=\"warning\" nzShowSearch />\n  `\n})\nexport class NzDemoTransferStatusComponent {}\n"
  },
  {
    "path": "components/transfer/demo/table-transfer.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 表格穿梭框\n  en-US: Table Transfer\n---\n\n## zh-CN\n\n使用 Table 组件作为自定义渲染列表。\n\n## en-US\n\nCustomize render list with Table component.\n"
  },
  {
    "path": "components/transfer/demo/table-transfer.ts",
    "content": "import { Component, OnInit } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\nimport { NzTableModule } from 'ng-zorro-antd/table';\nimport { NzTagModule } from 'ng-zorro-antd/tag';\nimport { NzTransferModule, TransferChange, TransferItem, TransferSelectChange } from 'ng-zorro-antd/transfer';\n\n@Component({\n  selector: 'nz-demo-transfer-table-transfer',\n  imports: [FormsModule, NzSwitchModule, NzTableModule, NzTagModule, NzTransferModule],\n  template: `\n    <nz-transfer\n      [nzDataSource]=\"list\"\n      [nzDisabled]=\"disabled\"\n      [nzShowSearch]=\"showSearch\"\n      [nzShowSelectAll]=\"false\"\n      [nzRenderList]=\"[renderList, renderList]\"\n      (nzSelectChange)=\"select($event)\"\n      (nzChange)=\"change($event)\"\n    >\n      <ng-template\n        #renderList\n        let-items\n        let-direction=\"direction\"\n        let-stat=\"stat\"\n        let-disabled=\"disabled\"\n        let-onItemSelectAll=\"onItemSelectAll\"\n        let-onItemSelect=\"onItemSelect\"\n      >\n        <nz-table #t [nzData]=\"$asTransferItems(items)\" nzSize=\"small\">\n          <thead>\n            <tr>\n              <th\n                [nzDisabled]=\"disabled\"\n                [nzChecked]=\"stat.checkAll\"\n                [nzIndeterminate]=\"stat.checkHalf\"\n                (nzCheckedChange)=\"onItemSelectAll($event)\"\n              ></th>\n              <th>Name</th>\n              @if (direction === 'left') {\n                <th>Tag</th>\n              }\n              <th>Description</th>\n            </tr>\n          </thead>\n          <tbody>\n            @for (data of t.data; track data) {\n              <tr (click)=\"onItemSelect(data)\">\n                <td\n                  [nzChecked]=\"!!data.checked\"\n                  [nzDisabled]=\"disabled || data.disabled\"\n                  (nzCheckedChange)=\"onItemSelect(data)\"\n                ></td>\n                <td>{{ data.title }}</td>\n                @if (direction === 'left') {\n                  <td>\n                    <nz-tag>{{ data.tag }}</nz-tag>\n                  </td>\n                }\n                <td>{{ data.description }}</td>\n              </tr>\n            }\n          </tbody>\n        </nz-table>\n      </ng-template>\n    </nz-transfer>\n    <div style=\"margin-top: 8px;\">\n      <nz-switch [(ngModel)]=\"disabled\" nzCheckedChildren=\"disabled\" nzUnCheckedChildren=\"disabled\" />\n      <nz-switch [(ngModel)]=\"showSearch\" nzCheckedChildren=\"showSearch\" nzUnCheckedChildren=\"showSearch\" />\n    </div>\n  `\n})\nexport class NzDemoTransferTableTransferComponent implements OnInit {\n  list: TransferItem[] = [];\n  $asTransferItems = (data: unknown): TransferItem[] => data as TransferItem[];\n  disabled = false;\n  showSearch = false;\n\n  ngOnInit(): void {\n    for (let i = 0; i < 20; i++) {\n      this.list.push({\n        key: i.toString(),\n        title: `content${i + 1}`,\n        description: `description of content${i + 1}`,\n        disabled: i % 4 === 0,\n        tag: ['cat', 'dog', 'bird'][i % 3],\n        checked: false\n      });\n    }\n\n    [2, 3].forEach(idx => (this.list[idx].direction = 'right'));\n  }\n\n  select(ret: TransferSelectChange): void {\n    console.log('nzSelectChange', ret);\n  }\n\n  change(ret: TransferChange): void {\n    console.log('nzChange', ret);\n    const listKeys = ret.list.map(l => l.key);\n    const hasOwnKey = (e: TransferItem): boolean => e.hasOwnProperty('key');\n    this.list = this.list.map(e => {\n      if (listKeys.includes(e.key) && hasOwnKey(e)) {\n        if (ret.to === 'left') {\n          delete e.hide;\n        } else if (ret.to === 'right') {\n          e.hide = false;\n        }\n      }\n      return e;\n    });\n  }\n}\n"
  },
  {
    "path": "components/transfer/demo/tree-transfer.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 树穿梭框\n  en-US: Tree Transfer\n---\n\n## zh-CN\n\n使用 Tree 组件作为自定义渲染列表。\n\n## en-US\n\nCustomize render list with Tree component.\n"
  },
  {
    "path": "components/transfer/demo/tree-transfer.ts",
    "content": "import { Component, ViewChild } from '@angular/core';\n\nimport { NzFormatEmitEvent, NzTreeNode, NzTreeNodeOptions } from 'ng-zorro-antd/core/tree';\nimport { NzTransferModule, TransferChange } from 'ng-zorro-antd/transfer';\nimport { NzTreeComponent, NzTreeModule } from 'ng-zorro-antd/tree';\n\n@Component({\n  selector: 'nz-demo-transfer-tree-transfer',\n  imports: [NzTransferModule, NzTreeModule],\n  template: `\n    <nz-transfer\n      [nzDataSource]=\"list\"\n      [nzShowSelectAll]=\"false\"\n      [nzRenderList]=\"[leftRenderList, null]\"\n      (nzChange)=\"change($event)\"\n    >\n      <ng-template #leftRenderList let-items let-onItemSelectAll=\"onItemSelectAll\" let-onItemSelect=\"onItemSelect\">\n        <nz-tree\n          #tree\n          [nzData]=\"treeData\"\n          nzExpandAll\n          nzBlockNode\n          nzCheckable\n          nzCheckStrictly\n          (nzCheckboxChange)=\"treeCheckboxChange($event, onItemSelect)\"\n        >\n          <ng-template #nzTreeTemplate let-node>\n            <span\n              (click)=\"checkboxChange(node, onItemSelect)\"\n              class=\"ant-tree-node-content-wrapper ant-tree-node-content-wrapper-open\"\n            >\n              {{ node.title }}\n            </span>\n          </ng-template>\n        </nz-tree>\n      </ng-template>\n    </nz-transfer>\n  `\n})\nexport class NzDemoTransferTreeTransferComponent {\n  @ViewChild('tree', { static: true }) tree!: NzTreeComponent;\n  list: NzTreeNodeOptions[] = [\n    { key: '0', id: 0, title: '0-0', isLeaf: true },\n    { key: '1', id: 1, parentid: 0, title: '0-1' },\n    { key: '2', id: 2, parentid: 1, title: '0-1-0', isLeaf: true },\n    { key: '3', id: 3, parentid: 1, title: '0-1-1', isLeaf: true },\n    { key: '4', id: 4, title: '0-3', isLeaf: true }\n  ];\n  treeData = this.generateTree(this.list);\n  checkedNodeList: NzTreeNode[] = [];\n\n  private generateTree(arr: NzTreeNodeOptions[]): NzTreeNodeOptions[] {\n    const tree: NzTreeNodeOptions[] = [];\n    const mappedArr: Record<string, NzTreeNodeOptions> = {};\n    let arrElem: NzTreeNodeOptions;\n    let mappedElem: NzTreeNodeOptions;\n\n    for (let i = 0, len = arr.length; i < len; i++) {\n      arrElem = arr[i];\n      mappedArr[arrElem.id] = { ...arrElem };\n      mappedArr[arrElem.id].children = [];\n    }\n\n    for (const id in mappedArr) {\n      if (mappedArr.hasOwnProperty(id)) {\n        mappedElem = mappedArr[id];\n        if (mappedElem.parentid) {\n          mappedArr[mappedElem.parentid].children!.push(mappedElem);\n        } else {\n          tree.push(mappedElem);\n        }\n      }\n    }\n    return tree;\n  }\n\n  treeCheckboxChange(event: NzFormatEmitEvent, onItemSelect: (item: NzTreeNodeOptions) => void): void {\n    this.checkboxChange(event.node!, onItemSelect);\n  }\n\n  checkboxChange(node: NzTreeNode, onItemSelect: (item: NzTreeNodeOptions) => void): void {\n    if (node.isDisabled) {\n      return;\n    }\n\n    if (node.isChecked) {\n      this.checkedNodeList.push(node);\n    } else {\n      const idx = this.checkedNodeList.indexOf(node);\n      if (idx !== -1) {\n        this.checkedNodeList.splice(idx, 1);\n      }\n    }\n    const item = this.list.find(w => w.id === node.origin.id);\n    onItemSelect(item!);\n  }\n\n  change(ret: TransferChange): void {\n    const isDisabled = ret.to === 'right';\n    this.checkedNodeList.forEach(node => {\n      if (ret.list.find(w => w.key === node.key)) {\n        node.isDisabled = isDisabled;\n        node.isChecked = isDisabled;\n      }\n    });\n    this.checkedNodeList = this.checkedNodeList.filter(item => item.isChecked);\n  }\n}\n"
  },
  {
    "path": "components/transfer/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Entry\ncols: 1\ntitle: Transfer\ncover: 'https://gw.alipayobjects.com/zos/alicdn/QAXskNI4G/Transfer.svg'\ndescription: Double column transfer choice box.\n---\n\n## When To Use\n\n- It is a select control essentially which can be use for selecting multiple items.\n- Transfer can display more information for items and take up more space.\n\nTransfer the elements between two columns intuitively and efficiently.\n\nOne or more elements can be selected from either column, one click on the proper `direction` button, and the transfer is done. The left column is considered the `source` and the right column is considered the `target`. As you can see in the API description, these names are reflected in.\n\n## API\n\n### nz-transfer\n\n| Property                | Description                                                                                                                       | Type                                                   | Default               |\n| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ | --------------------- |\n| `[nzDataSource]`        | Used for setting the data source. Except for the elements whose keys are `direction: 'right'` prop, or using `nzTargetKeys` prop. | `TransferItem[]`                                       | `[]`                  |\n| `[nzDisabled]`          | Whether the transfer is disabled                                                                                                  | `boolean`                                              | `false`               |\n| `[nzTitles]`            | A set of titles that are sorted from left to right.                                                                               | `string[]`                                             | `['', '']`            |\n| `[nzOperations]`        | A set of operations that are sorted from bottom to top.                                                                           | `string[]`                                             | `['', '']`            |\n| `[nzListStyle]`         | A custom CSS style used for rendering the transfer columns. equals to `ngStyle`                                                   | `object`                                               | -                     |\n| `[nzItemUnit]`          | single unit                                                                                                                       | `string`                                               | `'item'`              |\n| `[nzItemsUnit]`         | multiple unit                                                                                                                     | `string`                                               | `'items'`             |\n| `[nzRenderList]`        | Customize render list, please refer to the case.                                                                                  | `Array<TemplateRef<void> \\| null>`                     | `[null, null]`        |\n| `[nzRender]`            | The function to generate the item shown on a column. please refer to the case.                                                    | `TemplateRef<void>`                                    | -                     |\n| `[nzFooter]`            | A function used for rendering the footer. please refer to the case.                                                               | `TemplateRef<void>`                                    | -                     |\n| `[nzShowSelectAll]`     | Whether to display the select all box                                                                                             | `boolean`                                              | `true`                |\n| `[nzShowSearch]`        | Whether a search box is shown on each column.                                                                                     | `boolean`                                              | `false`               |\n| `[nzFilterOption]`      | A function to determine whether an item should be shown in a search result list                                                   | `(inputValue: string, item: TransferItem) => boolean`  | -                     |\n| `[nzSearchPlaceholder]` | The hint text of the search box.                                                                                                  | `string`                                               | `'Search here'`       |\n| `[nzNotFoundContent]`   | Text to display when a column is empty.                                                                                           | `string`                                               | `'The list is empty'` |\n| `[nzCanMove]`           | A function to determine what items should be moved (by default all checked items are moved). please refer to the case.            | `(arg: TransferCanMove) => Observable<TransferItem[]>` | -                     |\n| `[nzSelectedKeys]`      | A set of keys of selected items.                                                                                                  | `string[]`                                             | -                     |\n| `[nzTargetKeys]`        | A set of keys of elements that are listed on the right column.                                                                    | `string[]`                                             | -                     |\n| `[nzOneWay]`            | Display as single direction style                                                                                                 | `boolean`                                              | `false`               |\n| `[nzStatus]`            | Set validation status                                                                                                             | `'error' \\| 'warning'`                                 | -                     |\n| `(nzChange)`            | A callback function that is executed when the transfer between columns is complete.                                               | `EventEmitter<TransferChange>`                         | -                     |\n| `(nzSearchChange)`      | A callback function which is executed when search field are changed                                                               | `EventEmitter<TransferSearchChange>`                   | -                     |\n| `(nzSelectChange)`      | A callback function which is executed when selected items are changed.                                                            | `EventEmitter<TransferSearchChange>`                   | -                     |\n\n#### TransferItem\n\n| Property  | Description                                                                                     | Type                | Default |\n| --------- | ----------------------------------------------------------------------------------------------- | ------------------- | ------- |\n| title     | Used to display and search keyword                                                              | `string`            | -       |\n| direction | Used for setting the data source. Except the elements whose keys are `direction: 'right'` prop. | `'left' \\| 'right'` | -       |\n| disabled  | specifies whether the checkbox is disabled                                                      | `boolean`           | `false` |\n| checked   | specifies whether the checkbox is selected                                                      | `boolean`           | `false` |\n\n#### TransferCanMove\n\n| Property  | Description                       | Type                | Default |\n| --------- | --------------------------------- | ------------------- | ------- |\n| direction | data direction                    | `'left' \\| 'right'` | -       |\n| list      | Used for setting the source data. | `TransferItem[]`    | `[]`    |\n\n#### TransferChange\n\n| Property | Description                       | Type                | Default |\n| -------- | --------------------------------- | ------------------- | ------- |\n| from     | data direction                    | `'left' \\| 'right'` | -       |\n| to       | data direction                    | `'left' \\| 'right'` | -       |\n| list     | Used for setting the source data. | `TransferItem[]`    | `[]`    |\n\n#### TransferSearchChange\n\n| Property  | Description    | Type                | Default |\n| --------- | -------------- | ------------------- | ------- |\n| direction | data direction | `'left' \\| 'right'` | -       |\n| value     | Search keyword | `string`            | -       |\n\n#### nzRenderList\n\n| Property          | Description             | Type                           | Default |\n| ----------------- | ----------------------- | ------------------------------ | ------- |\n| `direction`       | List render direction   | `'left' \\| 'right'`            | -       |\n| `disabled`        | Disable list or not     | `boolean`                      | -       |\n| `items`           | Filtered items          | `TransferItem[]`               | -       |\n| `onItemSelect`    | Select item             | `(item: TransferItem) => void` | -       |\n| `onItemSelectAll` | Select a group of items | `(selected: boolean) => void`  | -       |\n"
  },
  {
    "path": "components/transfer/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 穿梭框\ntype: 数据录入\ncols: 1\ntitle: Transfer\ncover: 'https://gw.alipayobjects.com/zos/alicdn/QAXskNI4G/Transfer.svg'\ndescription: 双栏穿梭选择框。\n---\n\n## 何时使用\n\n- 需要在多个可选项中进行多选时。\n- 比起 Select 和 TreeSelect，穿梭框占据更大的空间，可以展示可选项的更多信息。\n\n穿梭选择框用直观的方式在两栏中移动元素，完成选择行为。\n\n选择一个或以上的选项后，点击对应的方向键，可以把选中的选项移动到另一栏。\n其中，左边一栏为 `source`，右边一栏为 `target`，API 的设计也反映了这两个概念。\n\n## API\n\n### nz-transfer\n\n| 参数                    | 说明                                                                                                                  | 类型                                                   | 默认值             |\n| ----------------------- | --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ | ------------------ |\n| `[nzDataSource]`        | 数据源，其中若数据属性 `direction: 'right'` 将会被渲染到右边一栏中或使用 `nzTargetKeys`                               | `TransferItem[]`                                       | `[]`               |\n| `[nzDisabled]`          | 是否禁用                                                                                                              | `boolean`                                              | `false`            |\n| `[nzTitles]`            | 标题集合，顺序从左至右                                                                                                | `string[]`                                             | `['', '']`         |\n| `[nzOperations]`        | 操作文案集合，顺序从下至上                                                                                            | `string[]`                                             | `['', '']`         |\n| `[nzListStyle]`         | 两个穿梭框的自定义样式，等同 `ngStyle`                                                                                | `object`                                               | -                  |\n| `[nzItemUnit]`          | 单数单位                                                                                                              | `string`                                               | `'项目'`           |\n| `[nzItemsUnit]`         | 复数单位                                                                                                              | `string`                                               | `'项目'`           |\n| `[nzRenderList]`        | 自定义渲染列表，见示例                                                                                                | `Array<TemplateRef<void> \\| null>`                     | `[null, null]`     |\n| `[nzRender]`            | 每行数据渲染模板，见示例                                                                                              | `TemplateRef<void>`                                    | -                  |\n| `[nzFooter]`            | 底部渲染模板，见示例                                                                                                  | `TemplateRef<void>`                                    | -                  |\n| `[nzShowSelectAll]`     | 是否显示全选框                                                                                                        | `boolean`                                              | `true`             |\n| `[nzShowSearch]`        | 是否显示搜索框                                                                                                        | `boolean`                                              | `false`            |\n| `[nzFilterOption]`      | 接收 `inputValue` `option` 两个参数，当 `option` 符合筛选条件时，应返回 `true`，反之则返回 `false`。                  | `(inputValue: string, item: TransferItem) => boolean`  | -                  |\n| `[nzSearchPlaceholder]` | 搜索框的默认值                                                                                                        | `string`                                               | `'请输入搜索内容'` |\n| `[nzNotFoundContent]`   | 当列表为空时显示的内容                                                                                                | `string`                                               | `'列表为空'`       |\n| `[nzCanMove]`           | 穿梭时二次校验。**注意：** 穿梭组件内部始终只保留一份数据，二次校验过程中需取消穿梭项则直接删除该项；具体用法见示例。 | `(arg: TransferCanMove) => Observable<TransferItem[]>` | -                  |\n| `[nzSelectedKeys]`      | 设置被选中的 key 集合                                                                                                 | `string[]`                                             | -                  |\n| `[nzTargetKeys]`        | 显示在右侧框数据的 key 集合                                                                                           | `string[]`                                             | -                  |\n| `[nzOneWay]`            | 展示为单向样式                                                                                                        | `boolean`                                              | `false`            |\n| `[nzStatus]`            | 设置校验状态                                                                                                          | `'error' \\| 'warning'`                                 | -                  |\n| `(nzChange)`            | 选项在两栏之间转移时的回调函数                                                                                        | `EventEmitter<TransferChange>`                         | -                  |\n| `(nzSearchChange)`      | 搜索框内容时改变时的回调函数                                                                                          | `EventEmitter<TransferSearchChange>`                   | -                  |\n| `(nzSelectChange)`      | 选中项发生改变时的回调函数                                                                                            | `EventEmitter<TransferSearchChange>`                   | -                  |\n\n#### TransferItem\n\n| 参数      | 说明                                                | 类型                | 默认值  |\n| --------- | --------------------------------------------------- | ------------------- | ------- |\n| title     | 标题，用于显示及搜索关键字判断                      | `string`            | -       |\n| direction | 指定数据方向，若指定 `right` 为右栏，其他情况为左栏 | `'left' \\| 'right'` | -       |\n| disabled  | 指定 checkbox 为不可用状态                          | `boolean`           | `false` |\n| checked   | 指定 checkbox 为选中状态                            | `boolean`           | `false` |\n\n#### TransferCanMove\n\n| 参数      | 说明     | 类型                | 默认值 |\n| --------- | -------- | ------------------- | ------ |\n| direction | 数据方向 | `'left' \\| 'right'` | -      |\n| list      | 数据源   | `TransferItem[]`    | `[]`   |\n\n#### TransferChange\n\n| 参数 | 说明     | 类型                | 默认值 |\n| ---- | -------- | ------------------- | ------ |\n| from | 数据方向 | `'left' \\| 'right'` | -      |\n| to   | 数据方向 | `'left' \\| 'right'` | -      |\n| list | 数据源   | `TransferItem[]`    | `[]`   |\n\n#### TransferSearchChange\n\n| 参数      | 说明       | 类型                | 默认值 |\n| --------- | ---------- | ------------------- | ------ |\n| direction | 数据方向   | `'left' \\| 'right'` | -      |\n| value     | 搜索关键词 | `string`            | -      |\n\n#### nzRenderList\n\n| 参数              | 说明           | 类型                           | 默认值 |\n| ----------------- | -------------- | ------------------------------ | ------ |\n| `direction`       | 渲染列表的方向 | `'left' \\| 'right'`            | -      |\n| `disabled`        | 是否禁用列表   | `boolean`                      | -      |\n| `items`           | 过滤后的数据   | `TransferItem[]`               | -      |\n| `onItemSelect`    | 勾选条目       | `(item: TransferItem) => void` | -      |\n| `onItemSelectAll` | 勾选一组条目   | `(selected: boolean) => void`  | -      |\n"
  },
  {
    "path": "components/transfer/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/transfer/interface.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nexport type TransferDirection = 'left' | 'right';\n\nexport interface TransferItem {\n  title: string;\n  direction?: TransferDirection;\n  disabled?: boolean;\n  checked?: boolean;\n  hide?: boolean;\n  [key: string]: NzSafeAny;\n}\n\nexport interface TransferCanMove {\n  direction: TransferDirection;\n  list: TransferItem[];\n}\n\nexport interface TransferChange {\n  from: TransferDirection;\n  to: TransferDirection;\n  list: TransferItem[];\n}\n\nexport interface TransferSearchChange {\n  direction: TransferDirection;\n  value: string;\n}\n\nexport interface TransferSelectChange {\n  direction: TransferDirection;\n  checked: boolean;\n  list: TransferItem[];\n  item?: TransferItem;\n}\n\nexport interface TransferStat {\n  checkAll: boolean;\n  checkHalf: boolean;\n  checkCount: number;\n  shownCount: number;\n  availableCount: number;\n}\n\nexport interface RenderListContext {\n  $implicit: TransferItem[];\n  direction: TransferDirection;\n  disabled: boolean;\n  onItemSelectAll: (x: boolean) => void;\n  onItemSelect: (x: TransferItem) => void;\n  stat: TransferStat;\n}\n"
  },
  {
    "path": "components/transfer/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/transfer/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './interface';\nexport { NzTransferListComponent } from './transfer-list.component';\nexport { NzTransferSearchComponent } from './transfer-search.component';\nexport { NzTransferComponent } from './transfer.component';\nexport { NzTransferModule } from './transfer.module';\n"
  },
  {
    "path": "components/transfer/style/customize.less",
    "content": "@import '../../style/themes/index';\n\n@transfer-prefix-cls: ~'@{ant-prefix}-transfer';\n\n@table-prefix-cls: ~'@{ant-prefix}-table';\n@input-prefix-cls: ~'@{ant-prefix}-input';\n\n.@{transfer-prefix-cls}-customize-list {\n  .@{transfer-prefix-cls}-list {\n    flex: 1 1 50%;\n    width: auto;\n    height: auto;\n    min-height: @transfer-list-height;\n  }\n\n  // =================== Hook Components ===================\n  .@{table-prefix-cls}-wrapper {\n    .@{table-prefix-cls}-small {\n      border: 0;\n      border-radius: 0;\n\n      .@{table-prefix-cls}-selection-column {\n        width: 40px;\n        min-width: 40px;\n      }\n\n      > .@{table-prefix-cls}-content {\n        // Header background color\n        > .@{table-prefix-cls}-body > table > .@{table-prefix-cls}-thead > tr > th {\n          background: @table-header-bg;\n        }\n\n        .@{table-prefix-cls}-row:last-child td {\n          border-bottom: @border-width-base @border-style-base @border-color-split;\n        }\n      }\n\n      .@{table-prefix-cls}-body {\n        margin: 0;\n      }\n    }\n\n    .@{table-prefix-cls}-pagination.@{ant-prefix}-pagination {\n      margin: 16px 0 4px;\n    }\n  }\n  .@{input-prefix-cls} {\n    &[disabled] {\n      background-color: transparent;\n    }\n  }\n}\n"
  },
  {
    "path": "components/transfer/style/entry.less",
    "content": "@import './index.less';\n// style dependencies\n@import '../../empty/style/entry.less';\n@import '../../checkbox/style/entry.less';\n@import '../../button/style/entry.less';\n@import '../../input/style/entry.less';\n"
  },
  {
    "path": "components/transfer/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import '../../checkbox/style/mixin';\n@import './customize';\n@import './status';\n\n@transfer-prefix-cls: ~'@{ant-prefix}-transfer';\n\n@transfer-header-vertical-padding: ceil(\n  ((@transfer-header-height - 1px - @font-size-base * @line-height-base) / 2)\n);\n\n.@{transfer-prefix-cls} {\n  .reset-component();\n\n  position: relative;\n  display: flex;\n  align-items: stretch;\n\n  &-disabled {\n    .@{transfer-prefix-cls}-list {\n      background: @transfer-disabled-bg;\n    }\n  }\n\n  &-list {\n    display: flex;\n    flex-direction: column;\n    width: 180px;\n    height: @transfer-list-height;\n    border: @border-width-base @border-style-base @border-color-base;\n    border-radius: @border-radius-base;\n\n    &-with-pagination {\n      width: 250px;\n      height: auto;\n    }\n\n    &-search {\n      .anticon-search {\n        color: @disabled-color;\n      }\n    }\n\n    &-header {\n      display: flex;\n      flex: none;\n      align-items: center;\n      height: @transfer-header-height;\n      // border-top is on the transfer dom. We should minus 1px for this\n      padding: (@transfer-header-vertical-padding - 1px) @control-padding-horizontal\n        @transfer-header-vertical-padding;\n      color: @text-color;\n      background: @component-background;\n      border-bottom: @border-width-base @border-style-base @border-color-split;\n      border-radius: @border-radius-base @border-radius-base 0 0;\n\n      > *:not(:last-child) {\n        margin-right: 4px;\n      }\n\n      > * {\n        flex: none;\n      }\n\n      &-title {\n        flex: auto;\n        overflow: hidden;\n        white-space: nowrap;\n        text-align: right;\n        text-overflow: ellipsis;\n      }\n\n      &-dropdown {\n        font-size: 10px;\n        transform: translateY(10%);\n        cursor: pointer;\n\n        &[disabled] {\n          cursor: not-allowed;\n        }\n      }\n    }\n\n    &-body {\n      display: flex;\n      flex: auto;\n      flex-direction: column;\n      overflow: hidden;\n      font-size: @font-size-base;\n\n      &-search-wrapper {\n        position: relative;\n        flex: none;\n        padding: @padding-sm;\n      }\n    }\n\n    &-content {\n      flex: auto;\n      margin: 0;\n      padding: 0;\n      overflow: auto;\n      list-style: none;\n\n      &-item {\n        display: flex;\n        align-items: center;\n        min-height: @transfer-item-height;\n        padding: @transfer-item-padding-vertical @control-padding-horizontal;\n        line-height: @transfer-item-height - 2 * @transfer-item-padding-vertical;\n        transition: all 0.3s;\n\n        > *:not(:last-child) {\n          margin-right: 8px;\n        }\n\n        > * {\n          flex: none;\n        }\n\n        &-text {\n          flex: auto;\n          overflow: hidden;\n          white-space: nowrap;\n          text-overflow: ellipsis;\n        }\n\n        &-remove {\n          position: relative;\n          color: @border-color-base;\n          cursor: pointer;\n          transition: all 0.3s;\n\n          &:hover {\n            color: @link-hover-color;\n          }\n\n          &::after {\n            position: absolute;\n            top: -@transfer-item-padding-vertical;\n            right: -50%;\n            bottom: -@transfer-item-padding-vertical;\n            left: -50%;\n            content: '';\n          }\n        }\n      }\n\n      &-item:not(&-item-disabled) {\n        &:hover {\n          background-color: @transfer-item-hover-bg;\n          cursor: pointer;\n        }\n\n        &.@{transfer-prefix-cls}-list-content-item-checked:hover {\n          background-color: @transfer-item-selected-hover-bg;\n        }\n      }\n\n      // Do not change hover style when `oneWay` mode\n      &-show-remove &-item:not(&-item-disabled):hover {\n        background: transparent;\n        cursor: default;\n      }\n\n      &-item-checked {\n        background-color: @item-active-bg;\n      }\n\n      &-item-disabled {\n        color: @btn-disable-color;\n        cursor: not-allowed;\n      }\n    }\n\n    &-pagination {\n      padding: @padding-xs 0;\n      text-align: right;\n      border-top: @border-width-base @border-style-base @border-color-split;\n    }\n\n    &-body-not-found {\n      flex: none;\n      width: 100%;\n      margin: auto 0;\n      color: @disabled-color;\n      text-align: center;\n    }\n\n    &-footer {\n      border-top: @border-width-base @border-style-base @border-color-split;\n    }\n  }\n\n  &-operation {\n    display: flex;\n    flex: none;\n    flex-direction: column;\n    align-self: center;\n    margin: 0 8px;\n    vertical-align: middle;\n\n    .@{ant-prefix}-btn {\n      display: block;\n\n      &:first-child {\n        margin-bottom: 4px;\n      }\n\n      .@{iconfont-css-prefix} {\n        font-size: 12px;\n      }\n    }\n  }\n\n  .@{ant-prefix}-empty-image {\n    max-height: (@transfer-header-height / 2) - 22;\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/transfer/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import '../../checkbox/style/mixin';\n\n@transfer-prefix-cls: ~'@{ant-prefix}-transfer';\n\n.@{transfer-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &-list {\n    &-search {\n      .@{transfer-prefix-cls}-rtl & {\n        padding-right: @control-padding-horizontal-sm;\n        padding-left: 24px;\n      }\n\n      &-action {\n        .@{transfer-prefix-cls}-rtl & {\n          right: auto;\n          left: 12px;\n        }\n      }\n    }\n\n    &-header {\n      > *:not(:last-child) {\n        .@{transfer-prefix-cls}-rtl & {\n          margin-right: 0;\n          margin-left: 4px;\n        }\n      }\n\n      .@{transfer-prefix-cls}-rtl & {\n        right: 0;\n        left: auto;\n      }\n\n      &-title {\n        .@{transfer-prefix-cls}-rtl & {\n          text-align: left;\n        }\n      }\n    }\n\n    &-content {\n      &-item {\n        > *:not(:last-child) {\n          .@{transfer-prefix-cls}-rtl & {\n            margin-right: 0;\n            margin-left: 8px;\n          }\n        }\n      }\n    }\n\n    &-pagination {\n      .@{transfer-prefix-cls}-rtl & {\n        text-align: left;\n      }\n    }\n\n    &-footer {\n      .@{transfer-prefix-cls}-rtl & {\n        right: 0;\n        left: auto;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/transfer/style/status.less",
    "content": "@import '../../input/style/mixin';\n\n@transfer-prefix-cls: ~'@{ant-prefix}-transfer';\n\n.transfer-status-color(@color) {\n  .@{transfer-prefix-cls}-list {\n    border-color: @color;\n\n    &-search:not([disabled]) {\n      border-color: @input-border-color;\n\n      &:hover {\n        .hover();\n      }\n\n      &:focus {\n        .active();\n      }\n    }\n  }\n}\n\n.@{transfer-prefix-cls} {\n  &-status-error {\n    .transfer-status-color(@error-color);\n  }\n\n  &-status-warning {\n    .transfer-status-color(@warning-color);\n  }\n}\n"
  },
  {
    "path": "components/transfer/transfer-list.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterViewInit,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ElementRef,\n  EventEmitter,\n  Input,\n  Output,\n  QueryList,\n  TemplateRef,\n  ViewChild,\n  ViewChildren,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { merge } from 'rxjs';\nimport { startWith, switchMap } from 'rxjs/operators';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzCheckboxComponent, NzCheckboxModule } from 'ng-zorro-antd/checkbox';\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\nimport { NzEmptyModule } from 'ng-zorro-antd/empty';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\nimport { RenderListContext, TransferDirection, TransferItem, TransferStat } from './interface';\n\n@Component({\n  selector: 'nz-transfer-list',\n  exportAs: 'nzTransferList',\n  imports: [\n    NzInputModule,\n    FormsModule,\n    NzCheckboxModule,\n    NgTemplateOutlet,\n    NzEmptyModule,\n    NzIconModule,\n    NzButtonModule\n  ],\n  template: `\n    <div class=\"ant-transfer-list-header\">\n      @if (showSelectAll && !oneWay) {\n        <label\n          class=\"ant-transfer-list-checkbox\"\n          nz-checkbox\n          #headerCheckbox\n          [nzChecked]=\"stat.checkAll\"\n          (nzCheckedChange)=\"onItemSelectAll($event)\"\n          [nzIndeterminate]=\"stat.checkHalf\"\n          [nzDisabled]=\"stat.availableCount === 0 || disabled\"\n        ></label>\n      }\n      <span class=\"ant-transfer-list-header-selected\">\n        <span>\n          @if (!oneWay) {\n            {{ (stat.checkCount > 0 ? stat.checkCount + '/' : '') + stat.shownCount }}\n          } @else {\n            {{ stat.shownCount }}\n          }\n          {{ validData.length > 1 ? itemsUnit : itemUnit }}\n        </span>\n      </span>\n      @if (titleText) {\n        <span class=\"ant-transfer-list-header-title\">{{ titleText }}</span>\n      }\n    </div>\n    <div class=\"ant-transfer-list-body\" [class.ant-transfer-list-body-with-search]=\"showSearch\">\n      @if (showSearch) {\n        <div class=\"ant-transfer-list-body-search-wrapper\">\n          <nz-input-wrapper class=\"ant-transfer-list-search\" nzAllowClear>\n            <nz-icon nzInputPrefix nzType=\"search\" />\n            <input\n              nz-input\n              [placeholder]=\"searchPlaceholder\"\n              [disabled]=\"disabled\"\n              [(ngModel)]=\"filter\"\n              (ngModelChange)=\"handleFilter($event)\"\n            />\n          </nz-input-wrapper>\n        </div>\n      }\n      @if (renderList) {\n        <div class=\"ant-transfer-list-body-customize-wrapper\">\n          <ng-container\n            *ngTemplateOutlet=\"\n              renderList;\n              context: {\n                $implicit: validData,\n                direction: direction,\n                disabled: disabled,\n                onItemSelectAll: onItemSelectAll,\n                onItemSelect: onItemSelect,\n                stat: stat\n              }\n            \"\n          />\n        </div>\n      } @else {\n        @if (stat.shownCount > 0) {\n          <ul class=\"ant-transfer-list-content\">\n            @for (item of validData; track item.key) {\n              <li\n                (click)=\"!oneWay ? onItemSelect(item) : null\"\n                class=\"ant-transfer-list-content-item\"\n                [class]=\"{ 'ant-transfer-list-content-item-disabled': disabled || item.disabled }\"\n              >\n                @if (!oneWay) {\n                  <label\n                    #checkboxes\n                    nz-checkbox\n                    [nzChecked]=\"item.checked\"\n                    (nzCheckedChange)=\"onItemSelect(item)\"\n                    [nzDisabled]=\"disabled || item.disabled\"\n                  >\n                    @if (!render) {\n                      {{ item.title }}\n                    } @else {\n                      <ng-template [ngTemplateOutlet]=\"render\" [ngTemplateOutletContext]=\"{ $implicit: item }\" />\n                    }\n                  </label>\n                } @else {\n                  @if (!render) {\n                    <span class=\"ant-transfer-list-content-item-text\">\n                      {{ item.title }}\n                    </span>\n                    <div\n                      class=\"ant-transfer-list-content-item-remove\"\n                      [class]=\"{ 'ant-transfer-list-content-item-disabled': disabled || item.disabled }\"\n                      (click)=\"!(disabled || item.disabled) ? deleteItem(item) : null\"\n                    >\n                      <nz-icon nzType=\"delete\" nzTheme=\"outline\" />\n                    </div>\n                  } @else {\n                    <ng-template [ngTemplateOutlet]=\"render\" [ngTemplateOutletContext]=\"{ $implicit: item }\" />\n                  }\n                }\n              </li>\n            }\n          </ul>\n        } @else {\n          <div class=\"ant-transfer-list-body-not-found\">\n            <nz-embed-empty nzComponentName=\"transfer\" [specificContent]=\"notFoundContent\" />\n          </div>\n        }\n      }\n    </div>\n    @if (footer) {\n      <div class=\"ant-transfer-list-footer\">\n        <ng-template [ngTemplateOutlet]=\"footer\" [ngTemplateOutletContext]=\"{ $implicit: direction }\" />\n      </div>\n    }\n  `,\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    class: 'ant-transfer-list',\n    '[class.ant-transfer-list-with-footer]': '!!footer'\n  }\n})\nexport class NzTransferListComponent implements AfterViewInit {\n  // #region fields\n  private cdr = inject(ChangeDetectorRef);\n\n  @Input() direction: TransferDirection = 'left';\n  @Input() titleText = '';\n  @Input() showSelectAll = true;\n\n  @Input() dataSource: TransferItem[] = [];\n\n  @Input() itemUnit: string | undefined = '';\n  @Input() itemsUnit: string | undefined = '';\n  @Input() filter = '';\n  @Input() oneWay: boolean = false;\n  @Input({ transform: booleanAttribute }) disabled: boolean = false;\n  @Input({ transform: booleanAttribute }) showSearch?: boolean;\n  @Input() searchPlaceholder?: string;\n  @Input() notFoundContent?: string;\n  @Input() filterOption?: (inputValue: string, item: TransferItem) => boolean;\n\n  @Input() renderList: TemplateRef<RenderListContext> | null = null;\n  @Input() render: TemplateRef<{ $implicit: TransferItem }> | null = null;\n  @Input() footer: TemplateRef<{ $implicit: TransferDirection }> | null = null;\n\n  // events\n  @Output() readonly handleSelectAll: EventEmitter<boolean> = new EventEmitter<boolean>();\n  @Output() readonly handleSelect = new EventEmitter<TransferItem>();\n  @Output() readonly filterChange = new EventEmitter<{ direction: TransferDirection; value: string }>();\n  @Output() readonly moveToLeft = new EventEmitter<void>();\n\n  @ViewChild('headerCheckbox', { read: NzCheckboxComponent }) headerCheckbox?: NzCheckboxComponent;\n\n  @ViewChildren('checkboxes', { read: ElementRef }) checkboxes!: QueryList<ElementRef<HTMLLabelElement>>;\n\n  stat: TransferStat = {\n    checkAll: false,\n    checkHalf: false,\n    checkCount: 0,\n    shownCount: 0,\n    availableCount: 0\n  };\n\n  get validData(): TransferItem[] {\n    return this.dataSource.filter(w => !w.hide);\n  }\n\n  get availableData(): TransferItem[] {\n    // filter disabled data\n    return this.validData.filter(w => !w.disabled);\n  }\n\n  onItemSelect = (item: TransferItem): void => {\n    if (this.disabled || item.disabled) {\n      return;\n    }\n    item.checked = !item.checked;\n    this.updateCheckStatus();\n    this.handleSelect.emit(item);\n  };\n\n  onItemSelectAll = (status: boolean): void => {\n    this.dataSource.forEach(item => {\n      if (!item.disabled && !item.hide) {\n        item.checked = status;\n      }\n    });\n\n    this.updateCheckStatus();\n    this.handleSelectAll.emit(status);\n  };\n\n  private updateCheckStatus(): void {\n    const validCount = this.dataSource.filter(w => !w.disabled).length;\n    this.stat.checkCount = this.dataSource.filter(w => w.checked && !w.disabled).length;\n    this.stat.shownCount = this.validData.length;\n    this.stat.availableCount = this.availableData.length;\n    this.stat.checkAll = validCount > 0 && validCount === this.stat.checkCount;\n    this.stat.checkHalf = this.stat.checkCount > 0 && !this.stat.checkAll;\n    // Note: this is done explicitly since the internal `nzChecked` value may not be updated in edge cases.\n    // Consider the following flow:\n    // 1) the initial value of `stat.checkAll` is `false`\n    // 2) the user filters items\n    // 3) the user clicks \"Select All\" checkbox\n    // 4) the `NzCheckboxComponent` sets `nzChecked` to `true` internally\n    // 5) the user clicks \"Move to right\"\n    // 6) items are moved and the `updateCheckStatus` is invoked\n    // 7) the `stat.checkAll` value has never been updated in this flow, it's always been `false`\n    // 8) the `nzChecked` is still `true` and the checkbox is not unchecked\n    // This is because Angular checks bindings and it checked that `[nzChecked]=\"stat.checkAll\"` has\n    // never been updated, so Angular did not set new `nzChecked` value on the checkbox.\n    this.headerCheckbox && (this.headerCheckbox.nzChecked = this.stat.checkAll);\n  }\n\n  // #endregion\n\n  // #region search\n\n  handleFilter(value: string): void {\n    this.dataSource.forEach(item => {\n      item.hide = value.length > 0 && !this.matchFilter(value, item);\n    });\n    this.stat.shownCount = this.validData.length;\n    this.stat.availableCount = this.availableData.length;\n    this.filterChange.emit({ direction: this.direction, value });\n  }\n\n  deleteItem(item: TransferItem): void {\n    item.checked = true;\n    this.handleSelect.emit(item);\n    this.moveToLeft.emit();\n  }\n\n  private matchFilter(text: string, item: TransferItem): boolean {\n    if (this.filterOption) {\n      return this.filterOption(text, item);\n    }\n    return item.title.includes(text);\n  }\n\n  // #endregion\n\n  markForCheck(): void {\n    this.updateCheckStatus();\n    this.cdr.markForCheck();\n  }\n\n  ngAfterViewInit(): void {\n    this.checkboxes.changes\n      .pipe(\n        startWith(this.checkboxes),\n        switchMap(() => {\n          const checkboxes = this.checkboxes.toArray();\n          return merge(\n            ...checkboxes.map(checkbox => fromEventOutsideAngular<MouseEvent>(checkbox.nativeElement, 'click'))\n          );\n        })\n      )\n      .subscribe(event => {\n        event.stopPropagation();\n      });\n  }\n}\n"
  },
  {
    "path": "components/transfer/transfer-search.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  EventEmitter,\n  Input,\n  OnChanges,\n  Output,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n/**\n * @deprecated Will be removed in v22.0.0. Please use `nz-input-wrapper` instead.\n */\n@Component({\n  selector: '[nz-transfer-search]',\n  exportAs: 'nzTransferSearch',\n  template: `\n    <span class=\"ant-input-prefix\">\n      <nz-icon nzType=\"search\" />\n    </span>\n    <input\n      [(ngModel)]=\"value\"\n      (ngModelChange)=\"_handle()\"\n      [disabled]=\"disabled\"\n      [placeholder]=\"placeholder\"\n      class=\"ant-input\"\n      [class.ant-input-disabled]=\"disabled\"\n    />\n    @if (value && value.length > 0) {\n      <span class=\"ant-input-suffix\" (click)=\"_clear()\">\n        <nz-icon nzType=\"close-circle\" nzTheme=\"fill\" class=\"ant-input-clear-icon\" />\n      </span>\n    }\n  `,\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  imports: [FormsModule, NzIconModule]\n})\nexport class NzTransferSearchComponent implements OnChanges {\n  // region: fields\n  private cdr = inject(ChangeDetectorRef);\n\n  @Input() placeholder?: string;\n  @Input() value?: string;\n  @Input({ transform: booleanAttribute }) disabled: boolean = false;\n\n  @Output() readonly valueChanged = new EventEmitter<string>();\n  @Output() readonly valueClear = new EventEmitter<void>();\n\n  // endregion\n\n  protected _handle(): void {\n    this.valueChanged.emit(this.value);\n  }\n\n  protected _clear(): void {\n    if (this.disabled) {\n      return;\n    }\n    this.value = '';\n    this.valueClear.emit();\n  }\n\n  ngOnChanges(): void {\n    this.cdr.detectChanges();\n  }\n}\n"
  },
  {
    "path": "components/transfer/transfer.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ElementRef,\n  EventEmitter,\n  HostListener,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  QueryList,\n  Renderer2,\n  SimpleChanges,\n  TemplateRef,\n  ViewChildren,\n  ViewEncapsulation,\n  booleanAttribute,\n  inject,\n  DestroyRef\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Observable, of as observableOf, of } from 'rxjs';\nimport { distinctUntilChanged, map, withLatestFrom } from 'rxjs/operators';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzFormNoStatusService, NzFormStatusService } from 'ng-zorro-antd/core/form';\nimport { NgClassInterface, NgStyleInterface, NzSafeAny, NzStatus, NzValidateStatus } from 'ng-zorro-antd/core/types';\nimport { getStatusClassNames, toArray } from 'ng-zorro-antd/core/util';\nimport { NzI18nService, NzTransferI18nInterface } from 'ng-zorro-antd/i18n';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nimport {\n  TransferCanMove,\n  TransferChange,\n  TransferDirection,\n  TransferItem,\n  TransferSearchChange,\n  TransferSelectChange\n} from './interface';\nimport { NzTransferListComponent } from './transfer-list.component';\n\n@Component({\n  selector: 'nz-transfer',\n  exportAs: 'nzTransfer',\n  template: `\n    <nz-transfer-list\n      class=\"ant-transfer-list\"\n      [style]=\"nzListStyle\"\n      data-direction=\"left\"\n      direction=\"left\"\n      [titleText]=\"nzTitles[0]\"\n      [showSelectAll]=\"nzShowSelectAll\"\n      [dataSource]=\"leftDataSource\"\n      [filter]=\"leftFilter\"\n      [filterOption]=\"nzFilterOption\"\n      (filterChange)=\"handleFilterChange($event)\"\n      [renderList]=\"nzRenderList && nzRenderList[0]\"\n      [render]=\"nzRender\"\n      [disabled]=\"nzDisabled\"\n      [showSearch]=\"nzShowSearch\"\n      [searchPlaceholder]=\"nzSearchPlaceholder || locale?.searchPlaceholder\"\n      [notFoundContent]=\"nzNotFoundContent\"\n      [itemUnit]=\"nzItemUnit || locale?.itemUnit\"\n      [itemsUnit]=\"nzItemsUnit || locale?.itemsUnit\"\n      [footer]=\"nzFooter\"\n      (handleSelect)=\"handleLeftSelect($event)\"\n      (handleSelectAll)=\"handleLeftSelectAll($event)\"\n    />\n    @if (dir !== 'rtl') {\n      <div class=\"ant-transfer-operation\">\n        @if (!nzOneWay) {\n          <button\n            nz-button\n            type=\"button\"\n            (click)=\"moveToLeft()\"\n            [disabled]=\"nzDisabled || !leftActive\"\n            nzType=\"primary\"\n            nzSize=\"small\"\n          >\n            <nz-icon nzType=\"left\" />\n            @if (nzOperations[1]) {\n              <span>{{ nzOperations[1] }}</span>\n            }\n          </button>\n        }\n        <button\n          nz-button\n          type=\"button\"\n          (click)=\"moveToRight()\"\n          [disabled]=\"nzDisabled || !rightActive\"\n          nzType=\"primary\"\n          nzSize=\"small\"\n        >\n          <nz-icon nzType=\"right\" />\n          @if (nzOperations[0]) {\n            <span>{{ nzOperations[0] }}</span>\n          }\n        </button>\n      </div>\n    } @else {\n      <div class=\"ant-transfer-operation\">\n        <button\n          nz-button\n          type=\"button\"\n          (click)=\"moveToRight()\"\n          [disabled]=\"nzDisabled || !rightActive\"\n          nzType=\"primary\"\n          nzSize=\"small\"\n        >\n          <nz-icon nzType=\"left\" />\n          @if (nzOperations[0]) {\n            <span>{{ nzOperations[0] }}</span>\n          }\n        </button>\n        @if (!nzOneWay) {\n          <button\n            nz-button\n            type=\"button\"\n            (click)=\"moveToLeft()\"\n            [disabled]=\"nzDisabled || !leftActive\"\n            nzType=\"primary\"\n            nzSize=\"small\"\n          >\n            <nz-icon nzType=\"right\" />\n            @if (nzOperations[1]) {\n              <span>{{ nzOperations[1] }}</span>\n            }\n          </button>\n        }\n      </div>\n    }\n    <nz-transfer-list\n      class=\"ant-transfer-list\"\n      [style]=\"nzListStyle\"\n      data-direction=\"right\"\n      direction=\"right\"\n      [titleText]=\"nzTitles[1]\"\n      [showSelectAll]=\"nzShowSelectAll\"\n      [dataSource]=\"rightDataSource\"\n      [filter]=\"rightFilter\"\n      [filterOption]=\"nzFilterOption\"\n      (filterChange)=\"handleFilterChange($event)\"\n      [renderList]=\"nzRenderList && nzRenderList[1]\"\n      [render]=\"nzRender\"\n      [disabled]=\"nzDisabled\"\n      [showSearch]=\"nzShowSearch\"\n      [searchPlaceholder]=\"nzSearchPlaceholder || locale?.searchPlaceholder\"\n      [notFoundContent]=\"nzNotFoundContent\"\n      [itemUnit]=\"nzItemUnit || locale?.itemUnit\"\n      [itemsUnit]=\"nzItemsUnit || locale?.itemsUnit\"\n      [footer]=\"nzFooter\"\n      [oneWay]=\"nzOneWay\"\n      (moveToLeft)=\"moveToLeft()\"\n      (handleSelect)=\"handleRightSelect($event)\"\n      (handleSelectAll)=\"handleRightSelectAll($event)\"\n    />\n  `,\n  host: {\n    class: 'ant-transfer',\n    '[class.ant-transfer-rtl]': `dir === 'rtl'`,\n    '[class.ant-transfer-disabled]': `nzDisabled`,\n    '[class.ant-transfer-customize-list]': `nzRenderList`\n  },\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  imports: [NzTransferListComponent, NzIconModule, NzButtonModule]\n})\nexport class NzTransferComponent implements OnInit, OnChanges {\n  private destroyRef = inject(DestroyRef);\n  private cdr = inject(ChangeDetectorRef);\n  private i18n = inject(NzI18nService);\n  private elementRef = inject(ElementRef<HTMLElement>);\n  private renderer = inject(Renderer2);\n  private directionality = inject(Directionality);\n  private nzFormStatusService = inject(NzFormStatusService, { optional: true });\n  private nzFormNoStatusService = inject(NzFormNoStatusService, { optional: true });\n\n  @ViewChildren(NzTransferListComponent) lists!: QueryList<NzTransferListComponent>;\n  locale!: NzTransferI18nInterface;\n\n  leftFilter = '';\n  rightFilter = '';\n  dir: Direction = 'ltr';\n\n  // status\n  prefixCls: string = 'ant-transfer';\n  statusCls: NgClassInterface = {};\n  hasFeedback: boolean = false;\n\n  // #region fields\n\n  @Input({ transform: booleanAttribute }) nzDisabled = false;\n  @Input() nzDataSource: TransferItem[] = [];\n  @Input() nzTitles: string[] = ['', ''];\n  @Input() nzOperations: string[] = [];\n  @Input() nzListStyle: NgStyleInterface = {};\n  @Input({ transform: booleanAttribute }) nzShowSelectAll = true;\n  @Input() nzItemUnit?: string;\n  @Input() nzItemsUnit?: string;\n  @Input() nzCanMove: (arg: TransferCanMove) => Observable<TransferItem[]> = (arg: TransferCanMove) => of(arg.list);\n  @Input() nzRenderList: Array<TemplateRef<NzSafeAny> | null> | null = null;\n  @Input() nzRender: TemplateRef<NzSafeAny> | null = null;\n  @Input() nzFooter: TemplateRef<NzSafeAny> | null = null;\n  @Input({ transform: booleanAttribute }) nzShowSearch = false;\n  @Input() nzFilterOption?: (inputValue: string, item: TransferItem) => boolean;\n  @Input() nzSearchPlaceholder?: string;\n  @Input() nzNotFoundContent?: string;\n  @Input() nzTargetKeys: string[] = [];\n  @Input() nzSelectedKeys: string[] = [];\n  @Input() nzStatus: NzStatus = '';\n  @Input({ transform: booleanAttribute }) nzOneWay: boolean = false;\n\n  // events\n  @Output() readonly nzChange = new EventEmitter<TransferChange>();\n  @Output() readonly nzSearchChange = new EventEmitter<TransferSearchChange>();\n  @Output() readonly nzSelectChange = new EventEmitter<TransferSelectChange>();\n\n  // #endregion\n\n  // #region process data\n\n  // left\n  leftDataSource: TransferItem[] = [];\n  lastLeftCheckedIndex?: number;\n\n  // right\n  rightDataSource: TransferItem[] = [];\n  lastRightCheckedIndex?: number;\n\n  isShiftPressed = false;\n\n  @HostListener('window:keydown.shift')\n  onTriggerShiftDown(): void {\n    this.isShiftPressed = true;\n  }\n\n  @HostListener('window:keyup.shift')\n  onTriggerShiftUp(): void {\n    this.isShiftPressed = false;\n  }\n\n  @HostListener('mousedown', ['$event'])\n  onTriggerMouseDown(event: MouseEvent): void {\n    const isInsideTransfer = (event.target as HTMLElement).closest('.ant-transfer-list');\n    if (event.shiftKey && isInsideTransfer) {\n      event.preventDefault();\n    }\n  }\n\n  private splitDataSource(): void {\n    this.leftDataSource = [];\n    this.rightDataSource = [];\n    this.nzDataSource.forEach(record => {\n      if (record.direction === 'right') {\n        record.direction = 'right';\n        this.rightDataSource.push(record);\n      } else {\n        record.direction = 'left';\n        this.leftDataSource.push(record);\n      }\n    });\n  }\n\n  private getCheckedData(direction: TransferDirection): TransferItem[] {\n    return this[direction === 'left' ? 'leftDataSource' : 'rightDataSource'].filter(w => w.checked);\n  }\n\n  handleLeftSelectAll = (checked: boolean): void => this.handleSelect('left', checked);\n  handleRightSelectAll = (checked: boolean): void => this.handleSelect('right', checked);\n\n  handleLeftSelect = (item: TransferItem): void => this.handleSelect('left', !!item.checked, item);\n  handleRightSelect = (item: TransferItem): void => this.handleSelect('right', !!item.checked, item);\n\n  handleSelect(direction: TransferDirection, checked: boolean, item?: TransferItem): void {\n    if (item) {\n      const datasource = direction === 'left' ? this.leftDataSource : this.rightDataSource;\n      const currentIndex = datasource.findIndex(i => i.key === item.key);\n      const lastCheckedIndex = this[direction === 'left' ? 'lastLeftCheckedIndex' : 'lastRightCheckedIndex'] ?? -1;\n      if (this.isShiftPressed && lastCheckedIndex > -1) {\n        const start = Math.min(lastCheckedIndex, currentIndex);\n        const end = Math.max(lastCheckedIndex, currentIndex);\n        for (let i = start; i <= end; i++) {\n          const item = datasource[i];\n          if (!item.disabled) {\n            item.checked = checked;\n          }\n        }\n        this.markForCheckAllList();\n      }\n      this[direction === 'left' ? 'lastLeftCheckedIndex' : 'lastRightCheckedIndex'] = currentIndex;\n    }\n    const list = this.getCheckedData(direction);\n    const count = list.filter(i => !i.disabled).length;\n    this.updateOperationStatus(direction, count);\n    this.nzSelectChange.emit({ direction, checked, list, item });\n  }\n\n  handleFilterChange(ret: { direction: TransferDirection; value: string }): void {\n    this.nzSearchChange.emit(ret);\n  }\n\n  // #endregion\n\n  // #region operation\n\n  leftActive = false;\n  rightActive = false;\n\n  private updateOperationStatus(direction: TransferDirection, count?: number): void {\n    this[direction === 'right' ? 'leftActive' : 'rightActive'] =\n      (typeof count === 'undefined' ? this.getCheckedData(direction).filter(w => !w.disabled).length : count) > 0;\n  }\n\n  moveToLeft = (): void => this.moveTo('left');\n  moveToRight = (): void => this.moveTo('right');\n\n  moveTo(direction: TransferDirection): void {\n    const oppositeDirection = direction === 'left' ? 'right' : 'left';\n    this.updateOperationStatus(oppositeDirection, 0);\n    const datasource = direction === 'left' ? this.rightDataSource : this.leftDataSource;\n    const moveList = datasource.filter(item => item.checked === true && !item.disabled);\n    this.nzCanMove({ direction, list: moveList }).subscribe({\n      next: newMoveList =>\n        this.truthMoveTo(\n          direction,\n          newMoveList.filter(i => !!i)\n        ),\n      error: () => moveList.forEach(i => (i.checked = false))\n    });\n  }\n\n  private truthMoveTo(direction: TransferDirection, list: TransferItem[]): void {\n    const oppositeDirection = direction === 'left' ? 'right' : 'left';\n    const datasource = direction === 'left' ? this.rightDataSource : this.leftDataSource;\n    const targetDatasource = direction === 'left' ? this.leftDataSource : this.rightDataSource;\n    for (const item of list) {\n      item.checked = false;\n      item.hide = false;\n      item.direction = direction;\n      datasource.splice(datasource.indexOf(item), 1);\n    }\n    targetDatasource.splice(0, 0, ...list);\n    this.updateOperationStatus(oppositeDirection);\n    this.nzChange.emit({ from: oppositeDirection, to: direction, list });\n    this.markForCheckAllList();\n  }\n\n  // #endregion\n\n  private markForCheckAllList(): void {\n    if (!this.lists) {\n      return;\n    }\n    this.lists.forEach(i => i.markForCheck());\n  }\n\n  private handleNzTargetKeys(): void {\n    const keys = toArray(this.nzTargetKeys);\n    const hasOwnKey = (e: TransferItem): boolean => e.hasOwnProperty('key');\n    this.leftDataSource.forEach(e => {\n      if (hasOwnKey(e) && keys.indexOf(e.key) !== -1 && !e.disabled) {\n        e.checked = true;\n      }\n    });\n    this.moveToRight();\n  }\n\n  private handleNzSelectedKeys(): void {\n    const keys = toArray(this.nzSelectedKeys);\n    this.nzDataSource.forEach(e => {\n      if (keys.indexOf(e.key) !== -1) {\n        e.checked = true;\n      }\n    });\n\n    const term = (ld: TransferItem): boolean => ld.disabled === false && ld.checked === true;\n    this.rightActive = this.leftDataSource.some(term);\n    this.leftActive = this.rightDataSource.some(term);\n  }\n\n  ngOnInit(): void {\n    this.nzFormStatusService?.formStatusChanges\n      .pipe(\n        distinctUntilChanged((pre, cur) => pre.status === cur.status && pre.hasFeedback === cur.hasFeedback),\n        withLatestFrom(this.nzFormNoStatusService ? this.nzFormNoStatusService.noFormStatus : observableOf(false)),\n        map(([{ status, hasFeedback }, noStatus]) => ({ status: noStatus ? '' : status, hasFeedback })),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(({ status, hasFeedback }) => {\n        this.setStatusStyles(status, hasFeedback);\n      });\n\n    this.i18n.localeChange.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      this.locale = this.i18n.getLocaleData('Transfer');\n      this.markForCheckAllList();\n    });\n\n    this.dir = this.directionality.value;\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n      this.dir = direction;\n      this.cdr.detectChanges();\n    });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzStatus, nzDataSource, nzTargetKeys, nzSelectedKeys } = changes;\n    if (nzDataSource) {\n      this.splitDataSource();\n      this.updateOperationStatus('left');\n      this.updateOperationStatus('right');\n      this.cdr.detectChanges();\n      this.markForCheckAllList();\n    }\n    if (nzTargetKeys) {\n      this.handleNzTargetKeys();\n    }\n    if (nzSelectedKeys) {\n      this.handleNzSelectedKeys();\n    }\n    if (nzStatus) {\n      this.setStatusStyles(this.nzStatus, this.hasFeedback);\n    }\n  }\n\n  private setStatusStyles(status: NzValidateStatus, hasFeedback: boolean): void {\n    // set inner status\n    this.hasFeedback = hasFeedback;\n    this.cdr.markForCheck();\n    // render status if nzStatus is set\n    this.statusCls = getStatusClassNames(this.prefixCls, status, hasFeedback);\n    Object.keys(this.statusCls).forEach(status => {\n      if (this.statusCls[status]) {\n        this.renderer.addClass(this.elementRef.nativeElement, status);\n      } else {\n        this.renderer.removeClass(this.elementRef.nativeElement, status);\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "components/transfer/transfer.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzTransferListComponent } from './transfer-list.component';\nimport { NzTransferSearchComponent } from './transfer-search.component';\nimport { NzTransferComponent } from './transfer.component';\n\n@NgModule({\n  imports: [NzTransferComponent, NzTransferListComponent, NzTransferSearchComponent],\n  exports: [NzTransferComponent]\n})\nexport class NzTransferModule {}\n"
  },
  {
    "path": "components/transfer/transfer.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BidiModule, Dir, Direction } from '@angular/cdk/bidi';\nimport {\n  ApplicationRef,\n  Component,\n  DebugElement,\n  OnInit,\n  provideZoneChangeDetection,\n  TemplateRef,\n  ViewChild\n} from '@angular/core';\nimport { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\nimport { Observable, of } from 'rxjs';\nimport { map } from 'rxjs/operators';\n\nimport { NzSafeAny, NzStatus } from 'ng-zorro-antd/core/types';\nimport { NzFormControlStatusType, NzFormModule } from 'ng-zorro-antd/form';\nimport en_US from 'ng-zorro-antd/i18n/languages/en_US';\nimport { NzI18nService } from 'ng-zorro-antd/i18n/nz-i18n.service';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\nimport {\n  NzTransferComponent,\n  NzTransferModule,\n  TransferCanMove,\n  TransferChange,\n  TransferDirection,\n  TransferItem,\n  TransferSearchChange,\n  TransferSelectChange\n} from 'ng-zorro-antd/transfer';\n\nconst COUNT = 21;\nconst LEFT_COUNT = 2;\nconst DISABLED = 1;\n\ndescribe('transfer', () => {\n  let fixture: ComponentFixture<TestTransferComponent>;\n  let debugElement: DebugElement;\n  let instance: TestTransferComponent;\n  let pageObject: TransferPageObject<AbstractTestTransferComponent>;\n\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideZoneChangeDetection(), provideNzIconsTesting(), provideNoopAnimations()]\n    });\n    fixture = TestBed.createComponent(TestTransferComponent);\n    debugElement = fixture.debugElement;\n    instance = debugElement.componentInstance;\n    pageObject = new TransferPageObject(fixture);\n    fixture.detectChanges();\n  });\n\n  describe('[default]', () => {\n    it('should be from left to right when via nzTargetKeys property', () => {\n      instance.nzTargetKeys = ['0', '1'];\n      fixture.detectChanges();\n\n      const leftKeys = instance.comp.leftDataSource.map(e => e.key);\n      const rightKeys = instance.comp.rightDataSource.map(e => e.key);\n\n      expect(rightKeys).toContain('0');\n      expect(leftKeys).not.toContain('0');\n\n      expect(rightKeys).toContain('1');\n      expect(leftKeys).not.toContain('1');\n    });\n\n    it('should be from left to right when via nzSelectedKeys property', () => {\n      instance.nzSelectedKeys = ['0', '1', '2'];\n      fixture.detectChanges();\n\n      expect(\n        instance.comp.nzSelectedKeys.every(e => {\n          const data = instance.comp.nzDataSource.find(d => d.key === e);\n          return !!data?.checked;\n        })\n      ).toBe(true);\n    });\n\n    it('nzOneWay', () => {\n      instance.nzOneWay = true;\n      fixture.detectChanges();\n      expect(!pageObject.rightList.querySelector('.ant-transfer-list-header .ant-transfer-list-checkbox')).toBeTrue();\n      expect(debugElement.queryAll(By.css('.ant-transfer-operation .ant-btn')).length).toBe(1);\n      expect(\n        debugElement.query(By.css('.ant-transfer-operation .ant-btn .anticon')).nativeElement.getAttribute('nztype')\n      ).toBe('right');\n      expect(\n        pageObject.rightList.querySelector('.ant-transfer-list-content-item .ant-transfer-list-content-item-text')\n          ?.tagName\n      ).toBe('SPAN');\n      expect(\n        pageObject.rightList.querySelector('.ant-transfer-list-content-item .ant-transfer-list-content-item-remove')\n          ?.tagName\n      ).toBe('DIV');\n    });\n\n    it('should be from left to right', () => {\n      pageObject\n        .expectLeft(LEFT_COUNT)\n        .transfer('right', 0)\n        .expectLeft(LEFT_COUNT - 1)\n        .expectRight(COUNT - LEFT_COUNT + 1);\n    });\n\n    it('should be from right to left', () => {\n      pageObject\n        .expectRight(COUNT - LEFT_COUNT)\n        .transfer('left', [0, 1])\n        .expectRight(COUNT - LEFT_COUNT - 2)\n        .expectLeft(LEFT_COUNT + 2);\n    });\n\n    it('should be from left to right when via search found items', () => {\n      pageObject\n        .expectLeft(LEFT_COUNT)\n        .search('left', '1')\n        .transfer('right', 0)\n        .expectLeft(LEFT_COUNT - 1)\n        .expectRight(COUNT - LEFT_COUNT + 1);\n      expect(pageObject.leftList.querySelectorAll('.ant-transfer-list-content-item').length).toBe(0);\n    });\n\n    it('should be from right to left when via search found items', () => {\n      pageObject\n        .expectRight(COUNT - LEFT_COUNT)\n        .search('right', '2')\n        .transfer('left', [0, 1])\n        .expectLeft(LEFT_COUNT + 2)\n        .expectRight(COUNT - LEFT_COUNT - 2);\n      expect(pageObject.rightList.querySelectorAll('.ant-transfer-list-content-item').length).toBe(DISABLED);\n    });\n\n    it('should be forced to display when the original item is hidden', () => {\n      pageObject.checkItem('left', 0).search('left', '1');\n      pageObject.rightBtn.click();\n      fixture.detectChanges();\n      expect(instance.comp.rightDataSource.filter(w => !w.hide).length).toBe(COUNT - LEFT_COUNT + 1);\n    });\n\n    it('should have correct disable state on moving buttons', () => {\n      const transferOperationButtons: DebugElement[] = debugElement.queryAll(\n        By.css('.ant-transfer-operation > button')\n      );\n      const transferToRightButton: HTMLElement = transferOperationButtons[1].nativeNode;\n      expect((transferToRightButton as NzSafeAny)['disabled']).toEqual(true);\n      pageObject.checkItem('left', 0);\n      expect((transferToRightButton as NzSafeAny)['disabled']).toEqual(false);\n      pageObject.checkItem('left', 0);\n      expect((transferToRightButton as NzSafeAny)['disabled']).toEqual(true);\n    });\n\n    it('should be custom filter option', () => {\n      instance.nzFilterOption = (inputValue: string, item: NzSafeAny): boolean =>\n        item.description.indexOf(inputValue) > -1;\n      fixture.detectChanges();\n      pageObject.expectLeft(LEFT_COUNT).search('left', 'description of content1');\n      expect(pageObject.leftList.querySelectorAll('.ant-transfer-list-content-item').length).toBe(1);\n      (pageObject.leftList.querySelector('.ant-transfer-list-search .ant-input-clear-icon') as HTMLElement).click();\n      fixture.detectChanges();\n      expect(pageObject.leftList.querySelectorAll('.ant-transfer-list-content-item').length).toBe(LEFT_COUNT);\n    });\n\n    it('should be clear search keywords', () => {\n      pageObject.expectLeft(LEFT_COUNT).search('left', '1');\n      expect(pageObject.leftList.querySelectorAll('.ant-transfer-list-content-item').length).toBe(1);\n      (pageObject.leftList.querySelector('.ant-transfer-list-search .ant-input-clear-icon') as HTMLElement).click();\n      fixture.detectChanges();\n      expect(pageObject.leftList.querySelectorAll('.ant-transfer-list-content-item').length).toBe(LEFT_COUNT);\n    });\n\n    it('should be checkbox is toggle select', () => {\n      expect(instance.comp.leftDataSource.filter(w => w.checked).length).toBe(0);\n      pageObject.checkItem('left', 0);\n      expect(instance.comp.leftDataSource.filter(w => w.checked).length).toBe(1);\n      pageObject.checkItem('left', 0);\n      expect(instance.comp.leftDataSource.filter(w => w.checked).length).toBe(0);\n    });\n\n    it('should be checkbox is toggle select by blank area', () => {\n      expect(instance.comp.leftDataSource.filter(w => w.checked).length).toBe(0);\n      pageObject.checkItem('left', 0, '.ant-transfer-list-content-item');\n      expect(instance.comp.leftDataSource.filter(w => w.checked).length).toBe(1);\n    });\n\n    it('should be checkbox is disabled toggle select when setting disabled prop', () => {\n      instance.nzDataSource = [{ title: `content`, disabled: true }];\n      fixture.detectChanges();\n      expect(instance.comp.leftDataSource.filter(w => w.checked).length).toBe(0);\n      pageObject.checkItem('left', 0);\n      expect(instance.comp.leftDataSource.filter(w => w.checked).length).toBe(0);\n      pageObject.checkItem('left', 0);\n      expect(instance.comp.leftDataSource.filter(w => w.checked).length).toBe(0);\n    });\n\n    it('should be checkbox is toggle select via checkbox all in left', () => {\n      expect(instance.comp.leftDataSource.filter(w => w.checked).length).toBe(0);\n      const btn = pageObject.leftList.querySelector('.ant-transfer-list-header .ant-checkbox') as HTMLElement;\n      btn.click();\n      expect(instance.comp.leftDataSource.filter(w => w.checked).length).toBe(LEFT_COUNT);\n      btn.click();\n      expect(instance.comp.leftDataSource.filter(w => w.checked).length).toBe(0);\n    });\n\n    it('should be checkbox is toggle select via checkbox all in right', () => {\n      expect(instance.comp.rightDataSource.filter(w => w.checked).length).toBe(0);\n      const btn = pageObject.rightList.querySelector('.ant-transfer-list-header .ant-checkbox') as HTMLElement;\n      btn.click();\n      expect(instance.comp.rightDataSource.filter(w => w.checked).length).toBe(COUNT - LEFT_COUNT - DISABLED);\n      btn.click();\n      expect(instance.comp.rightDataSource.filter(w => w.checked).length).toBe(0);\n    });\n\n    it('should be checkboxes are toggle select via shift key', () => {\n      expect(instance.comp.rightDataSource.filter(w => w.checked).length).toBe(0);\n      pageObject.checkItem('right', 0);\n      expect(instance.comp.rightDataSource.filter(w => w.checked).length).toBe(1);\n      window.dispatchEvent(new KeyboardEvent('keydown', { key: 'Shift' }));\n      expect(instance.comp.isShiftPressed).toBeTrue();\n      fixture.detectChanges();\n      const multiSelectEndIndex = 9;\n      pageObject.checkItem('right', multiSelectEndIndex);\n      expect(instance.comp.rightDataSource.filter(w => w.checked).length).toBe(\n        COUNT - LEFT_COUNT - DISABLED - multiSelectEndIndex + 1\n      );\n      window.dispatchEvent(new KeyboardEvent('keyup', { key: 'Shift' }));\n      expect(instance.comp.isShiftPressed).toBeFalse();\n    });\n\n    describe('#notFoundContent', () => {\n      it('should be the left and right list have data', () => {\n        instance.nzDataSource = [{ title: `content0`, direction: 'right' }, { title: `content1` }];\n        fixture.detectChanges();\n        expect(pageObject.rightList.querySelector('nz-embed-empty')).toBeFalsy();\n        expect(pageObject.leftList.querySelector('nz-embed-empty')).toBeFalsy();\n      });\n\n      it('should be the right list is no data', () => {\n        instance.nzDataSource = [{ title: `content0` }, { title: `content1` }];\n        fixture.detectChanges();\n        expect(pageObject.rightList.querySelector('nz-embed-empty')).toBeTruthy();\n        expect(pageObject.leftList.querySelector('nz-embed-empty')).toBeFalsy();\n      });\n\n      it('should be the left list is no data', () => {\n        instance.nzDataSource = [{ title: `content0`, direction: 'right' }];\n        fixture.detectChanges();\n        expect(pageObject.rightList.querySelector('nz-embed-empty')).toBeFalsy();\n        expect(pageObject.leftList.querySelector('nz-embed-empty')).toBeTruthy();\n      });\n\n      it('should be the left and right list is no data', () => {\n        instance.nzDataSource = [];\n        fixture.detectChanges();\n        expect(pageObject.rightList.querySelector('nz-embed-empty')).toBeTruthy();\n        expect(pageObject.leftList.querySelector('nz-embed-empty')).toBeTruthy();\n      });\n    });\n\n    describe('#nzDisabled', () => {\n      it('should working', async () => {\n        instance.nzDisabled = true;\n        fixture.autoDetectChanges();\n        await fixture.whenStable();\n        expect(debugElement.queryAll(By.css('.ant-transfer-disabled')).length).toBe(1);\n        // All operation buttons muse be disabled\n        expect(debugElement.queryAll(By.css('.ant-transfer-operation .ant-btn[disabled]')).length).toBe(2);\n        // All search inputs must be disabled\n        expect(debugElement.queryAll(By.css('.ant-transfer-list-search.ant-input-disabled')).length).toBe(2);\n        // All items must be disabled\n        expect(debugElement.queryAll(By.css('.ant-transfer-list-content-item-disabled')).length).toBe(COUNT);\n        // All checkboxes (include 2 check-all) must be disabled\n        expect(debugElement.queryAll(By.css('.ant-checkbox-disabled')).length).toBe(COUNT + 2);\n      });\n\n      it('should be disabled clear', async () => {\n        pageObject.expectLeft(LEFT_COUNT).search('left', '1');\n        expect(pageObject.leftList.querySelectorAll('.ant-transfer-list-content-item').length).toBe(1);\n        instance.nzDisabled = true;\n        fixture.detectChanges();\n        await fixture.whenStable();\n        const clearBtn = pageObject.leftList.querySelector(\n          '.ant-transfer-list-search .ant-input-clear-icon:not(.ant-input-clear-icon-hidden)'\n        ) as HTMLElement | null;\n        clearBtn?.click();\n        fixture.detectChanges();\n        await fixture.whenStable();\n        expect(pageObject.leftList.querySelectorAll('.ant-transfer-list-content-item').length).toBe(1);\n      });\n\n      it('should be disabled check all when search result is empty', () => {\n        pageObject.expectLeft(LEFT_COUNT).search('left', '模拟');\n        const selectorPath = '[data-direction=\"left\"] .ant-transfer-list-header .ant-checkbox-disabled';\n        expect(pageObject.leftList.querySelectorAll(selectorPath).length).toBe(1);\n      });\n\n      it('should be disabled check all when all options are disabled', () => {\n        instance.nzDataSource = [{ title: `content`, disabled: true }];\n        fixture.detectChanges();\n        const cls = '[data-direction=\"left\"] .ant-transfer-list-header .ant-checkbox-disabled';\n        expect(debugElement.queryAll(By.css(cls)).length).toBe(1);\n      });\n    });\n\n    it('#nzShowSelectAll', () => {\n      const cls = `[data-direction=\"left\"] .ant-transfer-list-header .ant-checkbox`;\n      expect(debugElement.queryAll(By.css(cls)).length).toBe(1);\n      instance.nzShowSelectAll = false;\n      fixture.detectChanges();\n      expect(debugElement.queryAll(By.css(cls)).length).toBe(0);\n    });\n\n    it('#nzRenderList', () => {\n      instance.nzRenderList = [instance.renderListTpl, instance.renderListTpl];\n      fixture.detectChanges();\n      expect(debugElement.queryAll(By.css('.ant-transfer-customize-list')).length).toBe(1);\n      expect(debugElement.queryAll(By.css('.transfer-renderList')).length).toBe(2);\n    });\n\n    it('should be uncheck all when two verification error', () => {\n      instance.canMove = (arg: TransferCanMove): Observable<TransferItem[]> =>\n        of(arg.list).pipe(\n          map(() => {\n            throw new Error('error');\n          })\n        );\n      fixture.detectChanges();\n      pageObject\n        .expectLeft(LEFT_COUNT)\n        .transfer('right', [0, 1])\n        .expectLeft(LEFT_COUNT)\n        .expectRight(COUNT - LEFT_COUNT);\n    });\n\n    it('should be custom render item', () => {\n      const tempFixture = TestBed.createComponent(TestTransferCustomRenderComponent);\n      tempFixture.detectChanges();\n      const leftList = tempFixture.debugElement.query(By.css('[data-direction=\"left\"]')).nativeElement as HTMLElement;\n      expect(leftList.querySelectorAll('.anticon-frown-o').length).toBe(LEFT_COUNT);\n    });\n\n    it('should be custom footer', () => {\n      expect(pageObject.leftList.querySelector('#transfer-footer') != null).toBe(true);\n    });\n\n    it('#i18n', () => {\n      const tempFixture = TestBed.createComponent(TestTransferCustomRenderComponent);\n      tempFixture.detectChanges();\n      TestBed.inject(NzI18nService).setLocale(en_US);\n      tempFixture.detectChanges();\n      const searchPhText = (\n        tempFixture.debugElement.query(By.css('.ant-transfer-list-search input')).nativeElement as HTMLElement\n      ).attributes.getNamedItem('placeholder')!.textContent;\n      expect(searchPhText).toBe(en_US.Transfer.searchPlaceholder);\n    });\n\n    describe('change detection behavior', () => {\n      it('should not trigger change detection when the `ant-transfer-list-content-item label` is clicked', () => {\n        const appRef = TestBed.inject(ApplicationRef);\n        const event = new MouseEvent('click');\n\n        spyOn(appRef, 'tick');\n        spyOn(event, 'stopPropagation').and.callThrough();\n\n        const [label] = fixture.nativeElement.querySelectorAll('.ant-transfer-list-content-item label');\n\n        label.dispatchEvent(event);\n\n        expect(appRef.tick).not.toHaveBeenCalled();\n        expect(event.stopPropagation).toHaveBeenCalled();\n      });\n    });\n\n    // https://github.com/NG-ZORRO/ng-zorro-antd/issues/6667\n    it('should uncheck \"Select all\" checkbox after searched items are moved', () => {\n      const { leftList } = pageObject;\n      pageObject.search('left', 'content1');\n      expect(leftList.querySelectorAll('.ant-transfer-list-content-item').length).toBe(1);\n\n      const selectAll = leftList.querySelector<HTMLElement>('.ant-transfer-list-header .ant-checkbox')!;\n      selectAll.click();\n      fixture.detectChanges();\n\n      pageObject.rightBtn.click();\n      fixture.detectChanges();\n\n      expect(selectAll).not.toHaveClass('ant-checkbox-checked');\n      expect(selectAll).not.toHaveClass('ant-checkbox-indeterminate');\n    });\n  });\n\n  describe('#canMove', () => {\n    it('default', () => {\n      const fixture = TestBed.createComponent(TestTransferCustomRenderComponent);\n      pageObject = new TransferPageObject(fixture);\n      fixture.detectChanges();\n      pageObject\n        .expectLeft(LEFT_COUNT)\n        .transfer('right', 0)\n        .expectLeft(LEFT_COUNT - 1)\n        .expectRight(COUNT - LEFT_COUNT + 1);\n    });\n\n    it('should be from left to right when two verification', () => {\n      instance.canMove = (arg: TransferCanMove): Observable<TransferItem[]> => {\n        if (arg.direction === 'right' && arg.list.length > 0) {\n          arg.list.splice(0, 1);\n        }\n        return of(arg.list);\n      };\n      fixture.detectChanges();\n      pageObject\n        .expectLeft(LEFT_COUNT)\n        .transfer('right', [0, 1])\n        .expectLeft(LEFT_COUNT - 1)\n        .expectRight(COUNT - LEFT_COUNT + 1);\n    });\n  });\n\n  describe('#issues', () => {\n    let fixture: ComponentFixture<Test996Component>;\n\n    // https://github.com/NG-ZORRO/ng-zorro-antd/issues/996\n    it('#996', fakeAsync(() => {\n      fixture = TestBed.createComponent(Test996Component);\n      pageObject = new TransferPageObject(fixture);\n      fixture.detectChanges();\n      expect(\n        pageObject.getEl('[data-direction=\"right\"] .ant-transfer-list-header .ant-checkbox').classList\n      ).not.toContain('ant-checkbox-checked');\n      pageObject.checkItem('right', 1);\n      tick(50);\n      fixture.detectChanges();\n      expect(pageObject.getEl('[data-direction=\"right\"] .ant-transfer-list-header .ant-checkbox').classList).toContain(\n        'ant-checkbox-checked'\n      );\n    }));\n  });\n\n  describe('RTL', () => {\n    let componentElement: HTMLElement;\n    let fixture: ComponentFixture<NzTestTransferRtlComponent>;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTransferRtlComponent);\n      componentElement = fixture.debugElement.query(By.directive(NzTransferComponent)).nativeElement;\n      fixture.detectChanges();\n    });\n\n    it('should className correct on dir change', fakeAsync(() => {\n      expect(componentElement.classList).toContain('ant-transfer-rtl');\n      fixture.debugElement.componentInstance.direction = 'ltr';\n      fixture.detectChanges();\n      expect(componentElement.classList).not.toContain('ant-transfer-rtl');\n    }));\n  });\n\n  describe('transfer status', () => {\n    let fixture: ComponentFixture<NzTestTransferStatusComponent>;\n    let componentElement: HTMLElement;\n    let testComponent: NzTestTransferStatusComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTransferStatusComponent);\n      componentElement = fixture.debugElement.query(By.directive(NzTransferComponent)).nativeElement;\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n    });\n\n    it('should className correct with nzStatus', () => {\n      fixture.detectChanges();\n      expect(componentElement.className).toContain('ant-transfer-status-error');\n\n      testComponent.status = 'warning';\n      fixture.detectChanges();\n      expect(componentElement.className).toContain('ant-transfer-status-warning');\n\n      testComponent.status = '';\n      fixture.detectChanges();\n      expect(componentElement.className).not.toContain('ant-transfer-status-warning');\n    });\n  });\n\n  describe('transfer in form', () => {\n    let fixture: ComponentFixture<NzTestTransferInFormComponent>;\n    let componentElement: HTMLElement;\n    let testComponent: NzTestTransferInFormComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTransferInFormComponent);\n      componentElement = fixture.debugElement.query(By.directive(NzTransferComponent)).nativeElement;\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n    });\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n      expect(componentElement.classList).toContain('ant-transfer-status-error');\n\n      testComponent.status = 'warning';\n      fixture.detectChanges();\n      expect(componentElement.classList).toContain('ant-transfer-status-warning');\n\n      testComponent.status = 'success';\n      fixture.detectChanges();\n      expect(componentElement.classList).toContain('ant-transfer-status-success');\n\n      testComponent.feedback = false;\n      fixture.detectChanges();\n      expect(componentElement.classList).not.toContain('ant-transfer-has-feedback');\n    });\n  });\n\n  class TransferPageObject<T extends AbstractTestTransferComponent> {\n    [key: string]: NzSafeAny;\n\n    constructor(public fixture: ComponentFixture<T>) {}\n\n    get debugElement(): DebugElement {\n      return this.fixture.debugElement;\n    }\n\n    get transferElement(): NzTransferComponent {\n      return this.fixture.componentInstance.comp;\n    }\n\n    getEl(cls: string): HTMLElement {\n      return this.debugElement.query(By.css(cls)).nativeElement as HTMLElement;\n    }\n\n    get leftBtn(): HTMLButtonElement {\n      return this.debugElement.query(By.css('.ant-transfer-operation .anticon-left'))\n        .nativeElement as HTMLButtonElement;\n    }\n\n    get rightBtn(): HTMLButtonElement {\n      return this.debugElement.query(By.css('.ant-transfer-operation .anticon-right'))\n        .nativeElement as HTMLButtonElement;\n    }\n\n    get leftList(): HTMLElement {\n      return this.debugElement.query(By.css('[data-direction=\"left\"]')).nativeElement as HTMLElement;\n    }\n\n    get rightList(): HTMLElement {\n      return this.debugElement.query(By.css('[data-direction=\"right\"]')).nativeElement as HTMLElement;\n    }\n\n    transfer(direction: TransferDirection, index: number | number[]): this {\n      if (!Array.isArray(index)) {\n        index = [index];\n      }\n      this.checkItem(direction === 'left' ? 'right' : 'left', index);\n      (direction === 'left' ? this.leftBtn : this.rightBtn).click();\n      this.fixture.detectChanges();\n      return this;\n    }\n\n    checkItem(\n      direction: TransferDirection,\n      index: number | number[],\n      cls: string = '.ant-transfer-list-content-item label'\n    ): this {\n      if (!Array.isArray(index)) {\n        index = [index];\n      }\n      const items = (direction === 'left' ? this.leftList : this.rightList).querySelectorAll(cls);\n      for (const idx of index) {\n        (items[idx] as HTMLElement).click();\n        this.fixture.detectChanges();\n      }\n      this.fixture.detectChanges();\n      return this;\n    }\n\n    search(direction: TransferDirection, value: string): this {\n      // .ant-transfer-list-search has been moved to the host\n      const ipt = (direction === 'left' ? this.leftList : this.rightList).querySelector(\n        '.ant-transfer-list-search input'\n      ) as HTMLInputElement;\n      ipt.value = value;\n      ipt.dispatchEvent(new Event('input'));\n      this.fixture.detectChanges();\n      return this;\n    }\n\n    expectLeft(count: number): this {\n      expect(this.transferElement.leftDataSource.length).toBe(count);\n      return this;\n    }\n\n    expectRight(count: number): this {\n      expect(this.transferElement.rightDataSource.length).toBe(count);\n      return this;\n    }\n  }\n});\n\ninterface AbstractTestTransferComponent {\n  comp: NzTransferComponent;\n}\n\n@Component({\n  imports: [NzTransferModule],\n  selector: 'nz-test-transfer',\n  template: `\n    <nz-transfer\n      #comp\n      [nzDataSource]=\"nzDataSource\"\n      [nzRenderList]=\"nzRenderList\"\n      [nzShowSelectAll]=\"nzShowSelectAll\"\n      [nzDisabled]=\"nzDisabled\"\n      [nzTitles]=\"['Source', 'Target']\"\n      [nzOperations]=\"['to right', 'to left']\"\n      [nzItemUnit]=\"nzItemUnit\"\n      [nzItemsUnit]=\"nzItemsUnit\"\n      [nzListStyle]=\"nzListStyle\"\n      [nzShowSearch]=\"nzShowSearch\"\n      [nzFilterOption]=\"nzFilterOption\"\n      [nzSearchPlaceholder]=\"nzSearchPlaceholder\"\n      [nzNotFoundContent]=\"nzNotFoundContent\"\n      [nzCanMove]=\"canMove\"\n      [nzFooter]=\"footer\"\n      [nzTargetKeys]=\"nzTargetKeys\"\n      [nzOneWay]=\"nzOneWay\"\n      (nzSearchChange)=\"search($event)\"\n      (nzSelectChange)=\"select($event)\"\n      (nzChange)=\"change($event)\"\n    />\n    <ng-template #renderList>\n      <p class=\"transfer-renderList\">renderList</p>\n    </ng-template>\n    <ng-template #footer>\n      <p id=\"transfer-footer\">footer</p>\n    </ng-template>\n  `\n})\nclass TestTransferComponent implements OnInit, AbstractTestTransferComponent {\n  @ViewChild('comp', { static: false }) comp!: NzTransferComponent;\n  @ViewChild('renderList', { static: false }) renderListTpl!: TemplateRef<void>;\n  nzDataSource: NzSafeAny[] = [];\n  nzRenderList: Array<TemplateRef<void> | null> = [null, null];\n  nzDisabled = false;\n  nzShowSelectAll = true;\n  nzSelectedKeys = ['0', '1', '2'];\n  nzTargetKeys: string[] = [];\n  nzItemUnit = 'item';\n  nzItemsUnit = 'items';\n  nzListStyle = { 'width.px': 300, 'height.px': 300 };\n  nzShowSearch = true;\n  nzFilterOption?: (inputValue: string, item: NzSafeAny) => boolean;\n  nzSearchPlaceholder = '请输入搜索内容';\n  nzNotFoundContent = '列表为空';\n  nzOneWay = false;\n\n  canMove(arg: TransferCanMove): Observable<TransferItem[]> {\n    // if (arg.direction === 'right' && arg.list.length > 0) arg.list.splice(0, 1);\n    // or\n    // if (arg.direction === 'right' && arg.list.length > 0) delete arg.list[0];\n    return of(arg.list);\n  }\n\n  ngOnInit(): void {\n    const ret: Array<{\n      key: string;\n      title: string;\n      description: string;\n      direction: TransferDirection;\n      icon: string;\n      disabled: boolean;\n    }> = [];\n    for (let i = 0; i < COUNT; i++) {\n      ret.push({\n        key: i.toString(),\n        title: `content${i + 1}`,\n        description: `description of content${i + 1}`,\n        direction: i >= LEFT_COUNT ? 'right' : 'left',\n        icon: `frown-o`,\n        disabled: i === 20\n      });\n    }\n    this.nzDataSource = ret;\n  }\n\n  search(_: TransferSearchChange): void {}\n\n  select(_: TransferSelectChange): void {}\n\n  change(_: TransferChange): void {}\n}\n\n@Component({\n  imports: [NzIconModule, NzTransferModule],\n  template: `\n    <nz-transfer #comp nzShowSearch [nzRender]=\"render\" [nzDataSource]=\"nzDataSource\">\n      <ng-template #render let-item>\n        <nz-icon nzType=\"{{ item.icon }}\" />\n        {{ item.title }}\n      </ng-template>\n    </nz-transfer>\n  `\n})\nclass TestTransferCustomRenderComponent implements OnInit, AbstractTestTransferComponent {\n  @ViewChild('comp', { static: false }) comp!: NzTransferComponent;\n  nzDataSource: Array<{ key: string; title: string; description: string; direction: TransferDirection; icon: string }> =\n    [];\n\n  ngOnInit(): void {\n    const ret: Array<{ key: string; title: string; description: string; direction: TransferDirection; icon: string }> =\n      [];\n    for (let i = 0; i < COUNT; i++) {\n      ret.push({\n        key: i.toString(),\n        title: `content${i + 1}`,\n        description: `description of content${i + 1}`,\n        direction: i >= LEFT_COUNT ? 'right' : 'left',\n        icon: `frown-o`\n      });\n    }\n    this.nzDataSource = ret;\n  }\n}\n\n// https://github.com/NG-ZORRO/ng-zorro-antd/issues/996\n@Component({\n  imports: [NzTransferModule],\n  template: `<nz-transfer [nzDataSource]=\"list\" />`\n})\nclass Test996Component implements OnInit {\n  @ViewChild(NzTransferComponent, { static: true }) comp!: NzTransferComponent;\n  list: NzSafeAny[] = [];\n\n  ngOnInit(): void {\n    for (let i = 0; i < 2; i++) {\n      this.list.push({ key: i.toString(), title: `content${i + 1}`, disabled: i % 3 < 1 });\n    }\n\n    [0, 1].forEach(idx => (this.list[idx].direction = 'right'));\n  }\n}\n\n@Component({\n  imports: [BidiModule, TestTransferComponent],\n  template: `\n    <div [dir]=\"direction\">\n      <nz-test-transfer />\n    </div>\n  `\n})\nexport class NzTestTransferRtlComponent {\n  @ViewChild(Dir) dir!: Dir;\n  direction: Direction = 'rtl';\n}\n\n@Component({\n  imports: [NzTransferModule],\n  template: `<nz-transfer [nzDataSource]=\"[]\" [nzStatus]=\"status\" />`\n})\nexport class NzTestTransferStatusComponent {\n  status: NzStatus = 'error';\n}\n\n@Component({\n  imports: [NzFormModule, NzTransferModule],\n  template: `\n    <form nz-form>\n      <nz-form-item>\n        <nz-form-control [nzHasFeedback]=\"feedback\" [nzValidateStatus]=\"status\">\n          <nz-transfer [nzDataSource]=\"[]\" />\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `\n})\nexport class NzTestTransferInFormComponent {\n  status: NzFormControlStatusType = 'error';\n  feedback = true;\n}\n"
  },
  {
    "path": "components/tree/demo/basic-controlled.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 受控操作示例\n  en-US: basic controlled example\n---\n\n## zh-CN\n\n受控操作示例(默认)。\n\n## en-US\n\nbasic controlled example.\n"
  },
  {
    "path": "components/tree/demo/basic-controlled.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzFormatEmitEvent, NzTreeModule } from 'ng-zorro-antd/tree';\n\n@Component({\n  selector: 'nz-demo-tree-basic-controlled',\n  imports: [NzTreeModule],\n  template: `\n    <nz-tree\n      [nzData]=\"nodes\"\n      nzCheckable\n      nzMultiple\n      [nzCheckedKeys]=\"defaultCheckedKeys\"\n      [nzExpandedKeys]=\"defaultExpandedKeys\"\n      [nzSelectedKeys]=\"defaultSelectedKeys\"\n      (nzClick)=\"nzEvent($event)\"\n      (nzExpandChange)=\"nzEvent($event)\"\n      (nzCheckboxChange)=\"nzEvent($event)\"\n    />\n  `\n})\nexport class NzDemoTreeBasicControlledComponent {\n  defaultCheckedKeys = ['0-0-0'];\n  defaultSelectedKeys = ['0-0-0'];\n  defaultExpandedKeys = ['0-0', '0-0-0', '0-0-1'];\n\n  readonly nodes = [\n    {\n      title: '0-0',\n      key: '0-0',\n      expanded: true,\n      children: [\n        {\n          title: '0-0-0',\n          key: '0-0-0',\n          children: [\n            { title: '0-0-0-0', key: '0-0-0-0', isLeaf: true },\n            { title: '0-0-0-1', key: '0-0-0-1', isLeaf: true },\n            { title: '0-0-0-2', key: '0-0-0-2', isLeaf: true }\n          ]\n        },\n        {\n          title: '0-0-1',\n          key: '0-0-1',\n          children: [\n            { title: '0-0-1-0', key: '0-0-1-0', isLeaf: true },\n            { title: '0-0-1-1', key: '0-0-1-1', isLeaf: true },\n            { title: '0-0-1-2', key: '0-0-1-2', isLeaf: true }\n          ]\n        },\n        {\n          title: '0-0-2',\n          key: '0-0-2',\n          isLeaf: true\n        }\n      ]\n    },\n    {\n      title: '0-1',\n      key: '0-1',\n      children: [\n        { title: '0-1-0-0', key: '0-1-0-0', isLeaf: true },\n        { title: '0-1-0-1', key: '0-1-0-1', isLeaf: true },\n        { title: '0-1-0-2', key: '0-1-0-2', isLeaf: true }\n      ]\n    },\n    {\n      title: '0-2',\n      key: '0-2',\n      isLeaf: true\n    }\n  ];\n\n  nzEvent(event: NzFormatEmitEvent): void {\n    console.log(event);\n  }\n}\n"
  },
  {
    "path": "components/tree/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: basic\n---\n\n## zh-CN\n\n最简单的用法，展示可勾选，可选中，禁用，默认展开等功能。\n\n## en-US\n\nThe most basic usage, tell you how to use checkable, selectable, disabled, defaultExpandKeys, and etc.\n"
  },
  {
    "path": "components/tree/demo/basic.ts",
    "content": "import { Component, ViewChild } from '@angular/core';\n\nimport { NzFormatEmitEvent, NzTreeComponent, NzTreeModule, NzTreeNodeOptions } from 'ng-zorro-antd/tree';\n\n@Component({\n  selector: 'nz-demo-tree-basic',\n  imports: [NzTreeModule],\n  template: `\n    <nz-tree\n      #nzTreeComponent\n      [nzData]=\"nodes\"\n      nzCheckable\n      [nzCheckedKeys]=\"defaultCheckedKeys\"\n      [nzExpandedKeys]=\"defaultExpandedKeys\"\n      [nzSelectedKeys]=\"defaultSelectedKeys\"\n      (nzClick)=\"nzClick($event)\"\n      (nzDblClick)=\"nzClick($event)\"\n      (nzContextMenu)=\"nzClick($event)\"\n      (nzCheckboxChange)=\"nzCheck($event)\"\n      (nzExpandChange)=\"nzCheck($event)\"\n    />\n  `\n})\nexport class NzDemoTreeBasicComponent {\n  @ViewChild('nzTreeComponent', { static: false }) nzTreeComponent!: NzTreeComponent;\n  defaultCheckedKeys = ['10020'];\n  defaultSelectedKeys = ['10010'];\n  defaultExpandedKeys = ['100', '1001'];\n\n  readonly nodes: NzTreeNodeOptions[] = [\n    {\n      title: 'parent 1',\n      key: '100',\n      children: [\n        {\n          title: 'parent 1-0',\n          key: '1001',\n          disabled: true,\n          children: [\n            { title: 'leaf 1-0-0', key: '10010', disableCheckbox: true, isLeaf: true },\n            { title: 'leaf 1-0-1', key: '10011', isLeaf: true }\n          ]\n        },\n        {\n          title: 'parent 1-1',\n          key: '1002',\n          children: [\n            { title: 'leaf 1-1-0', key: '10020', isLeaf: true },\n            { title: 'leaf 1-1-1', key: '10021', isLeaf: true }\n          ]\n        }\n      ]\n    }\n  ];\n\n  nzClick(event: NzFormatEmitEvent): void {\n    console.log(event);\n  }\n\n  nzCheck(event: NzFormatEmitEvent): void {\n    console.log(event);\n  }\n\n  // nzSelectedKeys change\n  nzSelect(keys: string[]): void {\n    console.log(keys, this.nzTreeComponent.getSelectedNodeList());\n  }\n}\n"
  },
  {
    "path": "components/tree/demo/customized-icon.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 自定义图标\n  en-US: Customize Icon\n---\n\n## zh-CN\n\n可以针对不同的节点定制图标。\n\n## en-US\n\nYou can customize icons for different nodes.\n"
  },
  {
    "path": "components/tree/demo/customized-icon.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzTreeModule } from 'ng-zorro-antd/tree';\n\n@Component({\n  selector: 'nz-demo-tree-customized-icon',\n  imports: [NzIconModule, NzTreeModule],\n  template: `\n    <nz-tree [nzData]=\"nodes\" nzShowIcon />\n    <nz-tree [nzData]=\"nodes\" nzShowIcon [nzExpandedIcon]=\"multiExpandedIconTpl\">\n      <ng-template #multiExpandedIconTpl let-node let-origin=\"origin\">\n        @if (!origin.isLeaf) {\n          <nz-icon [nzType]=\"node.isExpanded ? 'folder-open' : 'folder'\" class=\"ant-tree-switcher-line-icon\" />\n        } @else {\n          <nz-icon nzType=\"file\" class=\"ant-tree-switcher-line-icon\" />\n        }\n      </ng-template>\n    </nz-tree>\n  `\n})\nexport class NzDemoTreeCustomizedIconComponent {\n  readonly nodes = [\n    {\n      title: 'parent 1',\n      key: '100',\n      expanded: true,\n      icon: 'smile',\n      children: [\n        { title: 'leaf', key: '1001', icon: 'meh', isLeaf: true },\n        { title: 'leaf', key: '1002', icon: 'frown', isLeaf: true }\n      ]\n    }\n  ];\n}\n"
  },
  {
    "path": "components/tree/demo/directory.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 目录\n  en-US: directory\n---\n\n## zh-CN\n\n使用 `nzTreeTemplate` 实现自定义目录结构，通过 `let-origin=\"origin\"` 获得原始数据，`let-node` 获取当前节点状态。\n\n## en-US\n\nCustomize directory tree with `nzTreeTemplate`, get data from `let-origin=\"origin\"`, get node status from `let-node`.\n"
  },
  {
    "path": "components/tree/demo/directory.ts",
    "content": "import { LowerCasePipe } from '@angular/common';\nimport { Component } from '@angular/core';\n\nimport { NzContextMenuService, NzDropdownMenuComponent, NzDropdownModule } from 'ng-zorro-antd/dropdown';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzFormatEmitEvent, NzTreeModule, NzTreeNode } from 'ng-zorro-antd/tree';\n\n@Component({\n  selector: 'nz-demo-tree-directory',\n  imports: [NzDropdownModule, NzIconModule, NzTreeModule, LowerCasePipe],\n  template: `\n    <nz-tree\n      nzBlockNode\n      [nzData]=\"nodes\"\n      (nzClick)=\"activeNode($event)\"\n      (nzDblClick)=\"openFolder($event)\"\n      [nzTreeTemplate]=\"nzTreeTemplate\"\n    />\n    <ng-template #nzTreeTemplate let-node let-origin=\"origin\">\n      <span class=\"custom-node\">\n        @if (!node.isLeaf) {\n          <span (contextmenu)=\"contextMenu($event, menu)\">\n            <nz-icon [nzType]=\"node.isExpanded ? 'folder-open' : 'folder'\" (click)=\"openFolder(node)\" />\n            <span class=\"folder-name\">{{ node.title }}</span>\n            <span class=\"folder-desc\">created by {{ origin.author | lowercase }}</span>\n          </span>\n        } @else {\n          <span (contextmenu)=\"contextMenu($event, menu)\">\n            <nz-icon nzType=\"file\" />\n            <span class=\"file-name\">{{ node.title }}</span>\n            <span class=\"file-desc\">modified by {{ origin.author | lowercase }}</span>\n          </span>\n        }\n      </span>\n    </ng-template>\n    <nz-dropdown-menu #menu=\"nzDropdownMenu\">\n      <ul nz-menu>\n        <li nz-menu-item (click)=\"selectDropdown()\">Action 1</li>\n        <li nz-menu-item (click)=\"selectDropdown()\">Action 2</li>\n      </ul>\n    </nz-dropdown-menu>\n  `,\n  styles: `\n    nz-tree {\n      overflow: hidden;\n      margin: 0 -24px;\n      padding: 0 24px;\n    }\n\n    .custom-node {\n      cursor: pointer;\n      line-height: 24px;\n      margin-left: 4px;\n      display: inline-block;\n    }\n\n    .file-name,\n    .folder-name {\n      margin-left: 4px;\n    }\n\n    .file-desc,\n    .folder-desc {\n      padding: 0 8px;\n      display: inline-block;\n      background: #87ceff;\n      color: #ffffff;\n      position: relative;\n      left: 12px;\n    }\n  `\n})\nexport class NzDemoTreeDirectoryComponent {\n  activatedNode?: NzTreeNode;\n  readonly nodes = [\n    {\n      title: 'parent 0',\n      key: '100',\n      author: 'NG ZORRO',\n      expanded: true,\n      children: [\n        { title: 'leaf 0-0', key: '1000', author: 'NG ZORRO', isLeaf: true },\n        { title: 'leaf 0-1', key: '1001', author: 'NG ZORRO', isLeaf: true }\n      ]\n    },\n    {\n      title: 'parent 1',\n      key: '101',\n      author: 'NG ZORRO',\n      children: [\n        { title: 'leaf 1-0', key: '1010', author: 'NG ZORRO', isLeaf: true },\n        { title: 'leaf 1-1', key: '1011', author: 'NG ZORRO', isLeaf: true }\n      ]\n    }\n  ];\n\n  constructor(private nzContextMenuService: NzContextMenuService) {}\n\n  openFolder(data: NzTreeNode | NzFormatEmitEvent): void {\n    // do something if u want\n    if (data instanceof NzTreeNode) {\n      data.isExpanded = !data.isExpanded;\n    } else {\n      const node = data.node;\n      if (node) {\n        node.isExpanded = !node.isExpanded;\n      }\n    }\n  }\n\n  activeNode(data: NzFormatEmitEvent): void {\n    this.activatedNode = data.node!;\n  }\n\n  contextMenu($event: MouseEvent, menu: NzDropdownMenuComponent): void {\n    this.nzContextMenuService.create($event, menu);\n  }\n\n  selectDropdown(): void {\n    // do something\n  }\n}\n"
  },
  {
    "path": "components/tree/demo/draggable-confirm.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 拖动示例-二次校验\n  en-US: draggable-with-two-confirmation\n---\n\n## zh-CN\n\nnzBeforeDrop: 在拖拽放置事件(drop事件)之前做校验, 例如仅允许拖拽到内部(延时一秒)、放置前结合modal验证等。\n\n## en-US\n\nnzBeforeDrop: Validate before drop event, for example: only allow to drag inside(delay 1s)、 validate using modal .etc.\n"
  },
  {
    "path": "components/tree/demo/draggable-confirm.ts",
    "content": "import { Component } from '@angular/core';\nimport { Observable, of } from 'rxjs';\nimport { delay } from 'rxjs/operators';\n\nimport { NzFormatBeforeDropEvent, NzTreeModule } from 'ng-zorro-antd/tree';\n\n@Component({\n  selector: 'nz-demo-tree-draggable-confirm',\n  imports: [NzTreeModule],\n  template: `<nz-tree [nzData]=\"nodes\" nzDraggable nzBlockNode [nzBeforeDrop]=\"beforeDrop\" />`\n})\nexport class NzDemoTreeDraggableConfirmComponent {\n  readonly nodes = [\n    {\n      title: '0-0',\n      key: '100',\n      expanded: true,\n      children: [\n        {\n          title: '0-0-0',\n          key: '1001',\n          children: [\n            { title: '0-0-0-0', key: '10010', isLeaf: true },\n            { title: '0-0-0-1', key: '10011', isLeaf: true }\n          ]\n        },\n        {\n          title: '0-0-1',\n          key: '1002',\n          children: [{ title: '0-0-1-0', key: '10020', isLeaf: true }]\n        }\n      ]\n    }\n  ];\n\n  beforeDrop(arg: NzFormatBeforeDropEvent): Observable<boolean> {\n    // if insert node into another node, wait 1s\n    if (arg.pos === 0) {\n      return of(true).pipe(delay(1000));\n    } else {\n      return of(false);\n    }\n  }\n}\n"
  },
  {
    "path": "components/tree/demo/draggable.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 拖动示例\n  en-US: draggable\n---\n\n## zh-CN\n\n将节点拖拽到其他节点内部或前后。\n\n## en-US\n\nDrag treeNode to insert after the other treeNode or insert into the other parent TreeNode.\n"
  },
  {
    "path": "components/tree/demo/draggable.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzFormatEmitEvent, NzTreeModule } from 'ng-zorro-antd/tree';\n\n@Component({\n  selector: 'nz-demo-tree-draggable',\n  imports: [NzTreeModule],\n  template: `<nz-tree [nzData]=\"nodes\" nzDraggable nzBlockNode (nzOnDrop)=\"nzEvent($event)\" />`\n})\nexport class NzDemoTreeDraggableComponent {\n  readonly nodes = [\n    {\n      title: '0-0',\n      key: '00',\n      expanded: true,\n      children: [\n        {\n          title: '0-0-0',\n          key: '000',\n          expanded: true,\n          children: [\n            { title: '0-0-0-0', key: '0000', isLeaf: true },\n            { title: '0-0-0-1', key: '0001', isLeaf: true },\n            { title: '0-0-0-2', key: '0002', isLeaf: true }\n          ]\n        },\n        {\n          title: '0-0-1',\n          key: '001',\n          children: [\n            { title: '0-0-1-0', key: '0010', isLeaf: true },\n            { title: '0-0-1-1', key: '0011', isLeaf: true },\n            { title: '0-0-1-2', key: '0012', isLeaf: true }\n          ]\n        },\n        {\n          title: '0-0-2',\n          key: '002'\n        }\n      ]\n    },\n    {\n      title: '0-1',\n      key: '01',\n      children: [\n        {\n          title: '0-1-0',\n          key: '010',\n          children: [\n            { title: '0-1-0-0', key: '0100', isLeaf: true },\n            { title: '0-1-0-1', key: '0101', isLeaf: true },\n            { title: '0-1-0-2', key: '0102', isLeaf: true }\n          ]\n        },\n        {\n          title: '0-1-1',\n          key: '011',\n          children: [\n            { title: '0-1-1-0', key: '0110', isLeaf: true },\n            { title: '0-1-1-1', key: '0111', isLeaf: true },\n            { title: '0-1-1-2', key: '0112', isLeaf: true }\n          ]\n        }\n      ]\n    },\n    {\n      title: '0-2',\n      key: '02',\n      isLeaf: true\n    }\n  ];\n\n  nzEvent(event: NzFormatEmitEvent): void {\n    console.log(event);\n  }\n}\n"
  },
  {
    "path": "components/tree/demo/dynamic.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 异步数据加载\n  en-US: load data asynchronously\n---\n\n## zh-CN\n\n点击展开节点，动态加载数据。\n\n## en-US\n\nTo load data asynchronously when click to expand a treeNode.\n"
  },
  {
    "path": "components/tree/demo/dynamic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzFormatEmitEvent, NzTreeModule, NzTreeNodeOptions } from 'ng-zorro-antd/tree';\n\n@Component({\n  selector: 'nz-demo-tree-dynamic',\n  imports: [NzTreeModule],\n  template: ` <nz-tree [nzData]=\"nodes\" nzAsyncData (nzClick)=\"nzEvent($event)\" (nzExpandChange)=\"nzEvent($event)\" /> `\n})\nexport class NzDemoTreeDynamicComponent {\n  readonly nodes = [\n    { title: 'Expand to load', key: '0' },\n    { title: 'Expand to load', key: '1' },\n    { title: 'Tree Node', key: '2', isLeaf: true }\n  ];\n\n  nzEvent(event: NzFormatEmitEvent): void {\n    // load child async\n    if (event.eventName === 'expand') {\n      const node = event.node;\n      if (node?.getChildren().length === 0 && node?.isExpanded) {\n        this.loadNode().then(data => {\n          node.addChildren(data);\n        });\n      }\n    }\n  }\n\n  loadNode(): Promise<NzTreeNodeOptions[]> {\n    return new Promise(resolve => {\n      setTimeout(\n        () =>\n          resolve([\n            { title: 'Child Node', key: `${new Date().getTime()}-0` },\n            { title: 'Child Node', key: `${new Date().getTime()}-1` }\n          ]),\n        1000\n      );\n    });\n  }\n}\n"
  },
  {
    "path": "components/tree/demo/line.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 连接线\n  en-US: Tree With Line\n---\n\n## zh-CN\n\n带连接线的树。\n\n## en-US\n\nTree With Line.\n"
  },
  {
    "path": "components/tree/demo/line.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzFormatEmitEvent, NzTreeModule } from 'ng-zorro-antd/tree';\n\n@Component({\n  selector: 'nz-demo-tree-line',\n  imports: [NzTreeModule],\n  template: `<nz-tree [nzData]=\"nodes\" nzShowLine (nzClick)=\"nzEvent($event)\" />`\n})\nexport class NzDemoTreeLineComponent {\n  readonly nodes = [\n    {\n      title: 'parent 1',\n      key: '100',\n      expanded: true,\n      children: [\n        {\n          title: 'parent 1-0',\n          key: '1001',\n          expanded: true,\n          children: [\n            { title: 'leaf', key: '10010', isLeaf: true },\n            { title: 'leaf', key: '10011', isLeaf: true },\n            { title: 'leaf', key: '10012', isLeaf: true }\n          ]\n        },\n        {\n          title: 'parent 1-1',\n          key: '1002',\n          children: [{ title: 'leaf', key: '10020', isLeaf: true }]\n        },\n        {\n          title: 'parent 1-2',\n          key: '1003',\n          children: [\n            { title: 'leaf', key: '10030', isLeaf: true },\n            { title: 'leaf', key: '10031', isLeaf: true }\n          ]\n        }\n      ]\n    }\n  ];\n\n  nzEvent(event: NzFormatEmitEvent): void {\n    console.log(event);\n  }\n}\n"
  },
  {
    "path": "components/tree/demo/search.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 可搜索\n  en-US: Searchable\n---\n\n## zh-CN\n\n可搜索的树。\n\n## en-US\n\nSearchable Tree.\n"
  },
  {
    "path": "components/tree/demo/search.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzFormatEmitEvent, NzTreeModule } from 'ng-zorro-antd/tree';\n\n@Component({\n  selector: 'nz-demo-tree-search',\n  imports: [FormsModule, NzIconModule, NzInputModule, NzTreeModule],\n  template: `\n    <nz-input-wrapper>\n      <input type=\"text\" nz-input placeholder=\"Search\" [(ngModel)]=\"searchValue\" />\n      <nz-icon nzInputSuffix nzType=\"search\" />\n    </nz-input-wrapper>\n    <br />\n    <nz-tree\n      [nzData]=\"nodes\"\n      [nzSearchValue]=\"searchValue\"\n      (nzClick)=\"nzEvent($event)\"\n      (nzExpandChange)=\"nzEvent($event)\"\n      (nzSearchValueChange)=\"nzEvent($event)\"\n    />\n  `\n})\nexport class NzDemoTreeSearchComponent {\n  searchValue = '';\n\n  readonly nodes = [\n    {\n      title: '0-0',\n      key: '0-0',\n      children: [\n        {\n          title: '0-0-0',\n          key: '0-0-0',\n          children: [\n            { title: '0-0-0-0', key: '0-0-0-0', isLeaf: true },\n            { title: '0-0-0-1', key: '0-0-0-1', isLeaf: true },\n            { title: '0-0-0-2', key: '0-0-0-2', isLeaf: true }\n          ]\n        },\n        {\n          title: '0-0-1',\n          key: '0-0-1',\n          children: [\n            { title: '0-0-1-0', key: '0-0-1-0', isLeaf: true },\n            { title: '0-0-1-1', key: '0-0-1-1', isLeaf: true },\n            { title: '0-0-1-2', key: '0-0-1-2', isLeaf: true }\n          ]\n        },\n        {\n          title: '0-0-2',\n          key: '0-0-2',\n          isLeaf: true\n        }\n      ]\n    },\n    {\n      title: '0-1',\n      key: '0-1',\n      children: [\n        { title: '0-1-0-0', key: '0-1-0-0', isLeaf: true },\n        { title: '0-1-0-1', key: '0-1-0-1', isLeaf: true },\n        { title: '0-1-0-2', key: '0-1-0-2', isLeaf: true }\n      ]\n    },\n    {\n      title: '0-2',\n      key: '0-2',\n      isLeaf: true\n    }\n  ];\n\n  nzEvent(event: NzFormatEmitEvent): void {\n    console.log(event);\n  }\n}\n"
  },
  {
    "path": "components/tree/demo/virtual-scroll.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 虚拟滚动\n  en-US: Virtual Scroll\n---\n\n## zh-CN\n\n设定 `nzVirtualHeight` 开启虚拟滚动。\n\n## en-US\n\nSet `nzVirtualHeight` to enable virtual scroll.\n"
  },
  {
    "path": "components/tree/demo/virtual-scroll.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTreeModule, NzTreeNodeOptions } from 'ng-zorro-antd/tree';\n\nfunction dig(path = '0', level = 3): NzTreeNodeOptions[] {\n  const list: NzTreeNodeOptions[] = [];\n  for (let i = 0; i < 10; i += 1) {\n    const key = `${path}-${i}`;\n    const treeNode: NzTreeNodeOptions = {\n      title: key,\n      key,\n      expanded: true,\n      children: [],\n      isLeaf: false\n    };\n\n    if (level > 0) {\n      treeNode.children = dig(key, level - 1);\n    } else {\n      treeNode.isLeaf = true;\n    }\n\n    list.push(treeNode);\n  }\n  return list;\n}\n\n@Component({\n  selector: 'nz-demo-tree-virtual-scroll',\n  imports: [NzTreeModule],\n  template: `<nz-tree [nzData]=\"nodes\" nzBlockNode nzVirtualHeight=\"300px\" />`\n})\nexport class NzDemoTreeVirtualScrollComponent {\n  nodes: NzTreeNodeOptions[] = dig();\n}\n"
  },
  {
    "path": "components/tree/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Display\ntitle: Tree\ncover: 'https://gw.alipayobjects.com/zos/alicdn/Xh-oWqg9k/Tree.svg'\ndescription: Multiple-level structure list.\n---\n\n## When To Use\n\nAlmost anything can be represented in a tree structure. Examples include directories, organization hierarchies, biological classifications, countries, etc. The `Tree` component is a way of representing the hierarchical relationship between these things. You can also expand, collapse, and select a treeNode within a `Tree`.\n\n## API\n\n### nz-tree\n\n> Tips: According to the current data structure design, you need to ensure that `nzData` is set first, otherwise other attributes will not take effect. After the asynchronous operation returns data, re-assign other attributes to trigger rendering(including `nzExpandAll` `nzExpandedKeys` `nzCheckedKeys` `nzSelectedKeys` `nzSearchValue`). Please refer to [#5152](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5152) to track the optimization progress.\n\n| Property                 | Description                                                                                                                                           | Type                                                        | Default | Global Config |\n| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- | ------- | ------------- |\n| `[nzData]`               | Tree data (Reference NzTreeNode)                                                                                                                      | `NzTreeNodeOptions[] \\| NzTreeNode[]`                       | `[]`    |\n| `[nzBlockNode]`          | Whether treeNode fill remaining horizontal space                                                                                                      | `boolean`                                                   | `false` | ✅            |\n| `[nzCheckable]`          | Add a checkbox before the treeNodes                                                                                                                   | `boolean`                                                   | `false` |\n| `[nzShowExpand]`         | Show a Expand Icon before the treeNodes                                                                                                               | `boolean`                                                   | `true`  |               |\n| `[nzShowLine]`           | Shows a connecting line                                                                                                                               | `boolean`                                                   | `false` |               |\n| `[nzExpandedIcon]`       | Customize an expand icon                                                                                                                              | `TemplateRef<{ $implicit: NzTreeNode }>`                    | -       |\n| `[nzShowIcon]`           | Shows the icon before a TreeNode's title. There is no default style                                                                                   | `boolean`                                                   | `false` | ✅            |\n| `[nzAsyncData]`          | Load data asynchronously (should be used with NzTreeNode.addChildren(...))                                                                            | `boolean`                                                   | `false` |\n| `[nzDraggable]`          | Specifies whether this Tree is draggable                                                                                                              | `boolean`                                                   | `false` |\n| `[nzMultiple]`           | Allows selecting multiple treeNodes                                                                                                                   | `boolean`                                                   | `false` |\n| `[nzHideUnMatched]`      | Hide unmatched nodes while searching                                                                                                                  | `boolean`                                                   | `false` | ✅            |\n| `[nzCheckStrictly]`      | Check treeNode precisely; parent treeNode and children treeNodes are not associated                                                                   | `boolean`                                                   | `false` |\n| `[nzTreeTemplate]`       | Custom Nodes                                                                                                                                          | `TemplateRef<{ $implicit: NzTreeNode }>`                    | -       |\n| `[nzExpandAll]`          | Whether to expand all treeNodes                                                                                                                       | `boolean`                                                   | `false` |\n| `[nzExpandedKeys]`       | Specify the keys of the default expanded treeNodes                                                                                                    | `string[]`                                                  | `[]`    |\n| `[nzCheckedKeys]`        | Specifies the keys of the default checked treeNodes                                                                                                   | `string[]`                                                  | `[]`    |\n| `[nzSelectedKeys]`       | Specifies the keys of the default selected treeNodes                                                                                                  | `string[]`                                                  | `[]`    |\n| `[nzSearchValue]`        | Filter (highlight) treeNodes (see demo `Searchable`), two-way binding                                                                                 | `string`                                                    | `null`  |\n| `[nzSearchFunc]`         | Custom matching method, used with `nzSearchValue`                                                                                                     | `(node: NzTreeNodeOptions) => boolean`                      | `null`  |\n| `[nzBeforeDrop]`         | Drop before the second check, allowing the user to decide whether to allow placement                                                                  | `(confirm: NzFormatBeforeDropEvent) => Observable<boolean>` | -       |\n| `[nzVirtualHeight]`      | The height of virtual scroll                                                                                                                          | `string`                                                    | `-`     |\n| `[nzVirtualItemSize]`    | The size of the items in the list, same as [cdk itemSize](https://material.angular.io/cdk/scrolling/api)                                              | `number`                                                    | `28`    |\n| `[nzVirtualMaxBufferPx]` | The number of pixels worth of buffer to render for when rendering new items, same as [cdk maxBufferPx](https://material.angular.io/cdk/scrolling/api) | `number`                                                    | `500`   |\n| `[nzVirtualMinBufferPx]` | The minimum amount of buffer rendered beyond the viewport (in pixels),same as [cdk minBufferPx](https://material.angular.io/cdk/scrolling/api)        | `number`                                                    | `28`    |\n| `(nzClick)`              | Callback function for when the user clicks a treeNode                                                                                                 | `EventEmitter<NzFormatEmitEvent>`                           | -       |\n| `(nzDblClick)`           | Callback function for when the user double clicks a treeNode                                                                                          | `EventEmitter<NzFormatEmitEvent>`                           | -       |\n| `(nzContextMenu)`        | Callback function for when the user right clicks a treeNode                                                                                           | `EventEmitter<NzFormatEmitEvent>`                           | -       |\n| `(nzCheckboxChange)`     | Callback function for when user clicks the checkbox                                                                                                   | `EventEmitter<NzFormatEmitEvent>`                           | -       |\n| `(nzExpandChange)`       | Callback function for when a treeNode is expanded or collapsed                                                                                        | `EventEmitter<NzFormatEmitEvent>`                           | -       |\n| `(nzSearchValueChange)`  | Callback function for when filter treeNodes(used with `nzSearchValue`)                                                                                | `EventEmitter<NzFormatEmitEvent>`                           | -       |\n| `(nzOnDragStart)`        | Callback function for when the onDragStart event occurs                                                                                               | `EventEmitter<NzFormatEmitEvent>`                           | -       |\n| `(nzOnDragEnter)`        | Callback function for when the onDragEnter event occurs                                                                                               | `EventEmitter<NzFormatEmitEvent>`                           | -       |\n| `(nzOnDragOver)`         | Callback function for when the onDragOver event occurs                                                                                                | `EventEmitter<NzFormatEmitEvent>`                           | -       |\n| `(nzOnDragLeave)`        | Callback function for when the onDragLeave event occurs                                                                                               | `EventEmitter<NzFormatEmitEvent>`                           | -       |\n| `(nzOnDrop)`             | Callback function for when the onDrop event occurs                                                                                                    | `EventEmitter<NzFormatEmitEvent>`                           | -       |\n| `(nzOnDragEnd)`          | Callback function for when the onDragEnd event occurs                                                                                                 | `EventEmitter<NzFormatEmitEvent>`                           | -       |\n\n#### Methods\n\n| Property                 | Description                                     | Type           |\n| ------------------------ | ----------------------------------------------- | -------------- |\n| `getTreeNodes`           | get all nodes(NzTreeNode)                       | `NzTreeNode[]` |\n| `getTreeNodeByKey`       | get NzTreeNode with key                         | `NzTreeNode`   |\n| `getCheckedNodeList`     | get checked nodes(merged)                       | `NzTreeNode[]` |\n| `getSelectedNodeList`    | get selected nodes                              | `NzTreeNode[]` |\n| `getHalfCheckedNodeList` | get half checked nodes                          | `NzTreeNode[]` |\n| `getExpandedNodeList`    | get expanded nodes                              | `NzTreeNode[]` |\n| `getMatchedNodeList`     | get matched nodes(if nzSearchValue is not null) | `NzTreeNode[]` |\n\n#### NzTreeNodeOptions props\n\n| Property          | Description                                              | Type                  | Default |\n| ----------------- | -------------------------------------------------------- | --------------------- | ------- |\n| `title`           | Title                                                    | `string`              | `'---'` |\n| `key`             | Must be unique！                                         | `string`              | `null`  |\n| `icon`            | icon before the treeNode，used with `nzShowIcon`         | `string`              | `null`  |\n| `children`        | TreeNode's children                                      | `NzTreeNodeOptions[]` | `[]`    |\n| `isLeaf`          | Determines if this is a leaf node(can not be dropped to) | `boolean`             | `false` |\n| `checked`         | Set the treeNode be checked                              | `boolean`             | `false` |\n| `selected`        | Set the treeNode be selected                             | `boolean`             | `false` |\n| `expanded`        | Set the treeNode be expanded ()                          | `boolean`             | `false` |\n| `selectable`      | Set whether the treeNode can be selected                 | `boolean`             | `true`  |\n| `disabled`        | Disables the treeNode                                    | `boolean`             | `false` |\n| `disableCheckbox` | Disables the checkbox of the treeNode                    | `boolean`             | `false` |\n| `[key: string]`   | Indexable Types, can be used with NzTreeNode.origin      | `any `                | -       |\n\n#### NzFormatEmitEvent props\n\n| Property        | Description                                                                 | Type                                                                                                                                                                | Default |\n| --------------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |\n| `eventName`     | Event Name                                                                  | enum: `'click' \\| 'dblclick' \\| 'contextmenu' \\| 'check' \\| 'expand' \\| 'search' \\| 'dragstart' \\| 'dragenter' \\| 'dragover' \\| 'dragleave' \\| 'drop' \\| 'dragend'` | -       |\n| `node `         | The current operation node (such as the target node to drop while dragging) | `NzTreeNode`                                                                                                                                                        | `null`  |\n| `event`         | MouseEvent or DragEvent                                                     | `'MouseEvent' \\| 'DragEvent'`                                                                                                                                       | `null`  |\n| `dragNode?`     | Current drag node (existing if dragged)                                     | `NzTreeNode`                                                                                                                                                        | `null`  |\n| `selectedKeys?` | Selected nodes list                                                         | `NzTreeNode[]`                                                                                                                                                      | `[]`    |\n| `checkedKeys?`  | Checked nodes list                                                          | `NzTreeNode[]`                                                                                                                                                      | `[]`    |\n| `matchedKeys?`  | Matched keys list while searching                                           | `NzTreeNode[]`                                                                                                                                                      | `[]`    |\n| `keys?`         | All nodes' keys list related event(except drag events)                      | `string[]`                                                                                                                                                          | `[]`    |\n| `nodes?`        | All nodes related event(except drag events)                                 | `NzTreeNode[]`                                                                                                                                                      | `[]`    |\n\n#### NzFormatBeforeDropEvent props\n\n| Property | Description                                                                                        | Type         | Default |\n| -------- | -------------------------------------------------------------------------------------------------- | ------------ | ------- |\n| dragNode | Current drag node (existing when dragged)                                                          | `NzTreeNode` | -       |\n| node     | The current operation node (such as the target node to drop while dragging)                        | `NzTreeNode` | -       |\n| pos      | position to drop(-1: before the target node, 0: inside the target node, 1: behind the target node) | `number`     | -       |\n\n#### NzTreeNode props\n\n| Property            | Description                                                                                                         | Type                                     | Default                   |\n| ------------------- | ------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- | ------------------------- |\n| `title`             | Title                                                                                                               | `string`                                 | `NzTreeNodeOptions.title` |\n| `key`               | Key                                                                                                                 | `string`                                 | `NzTreeNodeOptions.key`   |\n| `level`             | TreeNode's level relative to the root node                                                                          | `number`                                 | `number`                  |\n| `children`          | Children                                                                                                            | `NzTreeNode[]`                           | `[]`                      |\n| `origin`            | treeNode's raw data of NzTreeNodeOptions(user provided to show more data)                                           | `NzTreeNodeOptions`                      | -                         |\n| `getParentNode`     | Get parentNode                                                                                                      | `function`                               | `null`                    |\n| `isLeaf`            | Whether treeNode is a Leaf Node                                                                                     | `boolean`                                | `false`                   |\n| `isExpanded`        | Whether treeNode is expanded                                                                                        | `boolean`                                | `false`                   |\n| `isDisabled`        | Whether treeNode is disabled                                                                                        | `boolean`                                | `false`                   |\n| `isDisableCheckbox` | Whether treeNode's checkbox can not be clicked                                                                      | `boolean`                                | `false`                   |\n| `isSelectable`      | Set whether the treeNode can be selected                                                                            | `boolean`                                | `true`                    |\n| `isChecked`         | Whether treeNode is checked                                                                                         | `boolean`                                | `false`                   |\n| `isHalfChecked`     | Part of treeNode's children are checked                                                                             | `boolean`                                | `false`                   |\n| `isSelected`        | Whether treeNode is selected                                                                                        | `boolean`                                | `false`                   |\n| `isLoading`         | Whether treeNode is loading(when nzAsyncData is true)                                                               | `boolean`                                | `false`                   |\n| `isMatched`         | Whether treeNode's title contains nzSearchValue                                                                     | `boolean`                                | `false`                   |\n| `setSyncChecked`    | set isChecked value and sync other nodes' state of checkbox                                                         | `function`                               | -                         |\n| `getChildren`       | Get all children                                                                                                    | `function`                               | -                         |\n| `addChildren`       | Add child nodes, receive NzTreeNode or NzTreeNodeOptions array, the second parameter is the inserted index position | `(children: array, index?: number )=>{}` | -                         |\n| `clearChildren`     | Clear the treeNode's children                                                                                       | `function`                               | -                         |\n| `remove`            | Clear current node(not root node)                                                                                   | `function`                               | -                         |\n\n## Note\n\n- Please make sure `nzData` is set before the mentioned properties above:\n\n```typescript\n// Demo\nthis.nzExpandAll = false;\nconst nodes = []; // source data\nthis.nzData = [...nodes];\n// Reset the above mentioned properties if you have used after setting of nzData\nthis.nzExpandedKeys = [...this.nzExpandedKeys];\n// this.nzExpandAll = true;\nthis.nzCheckedKeys = [...this.nzCheckedKeys];\nthis.nzSelectedKeys = [...this.nzSelectedKeys];\n```\n\n- `NzTreeNodeOptions` accepts your custom properties，use `NzTreeNode.origin` to get them.\n- If Tree Methods are used with ViewChild, should be used in ngAfterViewInit.\n- Setting `nzData` with NzTreeNodeOptions[] is better，if you set nzData with NzTreeNode[], it will be deprecated in next major version(8.x).\n"
  },
  {
    "path": "components/tree/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ntype: 数据展示\ntitle: Tree\nsubtitle: 树形控件\ncover: 'https://gw.alipayobjects.com/zos/alicdn/Xh-oWqg9k/Tree.svg'\ndescription: 多层次的结构列表。\n---\n\n## 何时使用\n\n文件夹、组织架构、生物分类、国家地区等等，世间万物的大多数结构都是树形结构。使用`树控件`可以完整展现其中的层级关系，并具有展开收起选择等交互功能。\n\n## API\n\n### nz-tree\n\n> 说明: 根据目前的数据结构设计，需要保证优先设置 `nzData`，否则各属性不会生效。异步操作待数据返回后，重新赋值其他各属性触发渲染(`nzExpandAll` `nzExpandedKeys` `nzCheckedKeys` `nzSelectedKeys` `nzSearchValue`)。重构优化工作请追踪 [#5152](https://github.com/NG-ZORRO/ng-zorro-antd/issues/5152)。\n\n| 参数                     | 说明                                                                                                                 | 类型                                                        | 默认值  | 全局配置 |\n| ------------------------ | -------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- | ------- | -------- |\n| `[nzData]`               | 元数据                                                                                                               | `NzTreeNodeOptions[] \\| NzTreeNode[]`                       | `[]`    |\n| `[nzBlockNode]`          | 是否节点占据一行                                                                                                     | `boolean`                                                   | `false` | ✅       |\n| `[nzCheckable]`          | 节点前添加 checkbox 复选框                                                                                           | `boolean`                                                   | `false` |\n| `[nzShowExpand]`         | 节点前添加展开图标                                                                                                   | `boolean`                                                   | `true`  |          |\n| `[nzShowLine]`           | 是否展示连接线                                                                                                       | `boolean`                                                   | `false` |          |\n| `[nzExpandedIcon]`       | 自定义展开图标                                                                                                       | `TemplateRef<{ $implicit: NzTreeNode }>`                    | -       |\n| `[nzShowIcon]`           | 是否展示 TreeNode title 前的图标，没有默认样式                                                                       | `boolean`                                                   | `false` | ✅       |\n| `[nzAsyncData]`          | 是否异步加载(显示加载状态)                                                                                           | `boolean`                                                   | `false` |\n| `[nzDraggable]`          | 设置节点可拖拽                                                                                                       | `boolean`                                                   | `false` |\n| `[nzMultiple]`           | 支持点选多个节点（节点本身）                                                                                         | `boolean`                                                   | `false` |\n| `[nzHideUnMatched]`      | 搜索隐藏未匹配的节点                                                                                                 | `boolean`                                                   | `false` | ✅       |\n| `[nzCheckStrictly]`      | checkable 状态下节点选择完全受控（父子节点选中状态不再关联）                                                         | `boolean`                                                   | `false` |\n| `[nzTreeTemplate]`       | 自定义节点                                                                                                           | `TemplateRef<{ $implicit: NzTreeNode }>`                    | -       |\n| `[nzExpandAll]`          | 默认展开所有树节点                                                                                                   | `boolean`                                                   | `false` |\n| `[nzExpandedKeys]`       | 展开指定的树节点                                                                                                     | `string[]`                                                  | `[]`    |\n| `[nzCheckedKeys]`        | 指定选中复选框的树节点                                                                                               | `string[]`                                                  | `[]`    |\n| `[nzSelectedKeys]`       | 指定选中的树节点                                                                                                     | `string[]`                                                  | `[]`    |\n| `[nzSearchValue]`        | 按需筛选树高亮节点(参考可搜索的树),双向绑定                                                                          | `string`                                                    | `null`  |\n| `[nzSearchFunc]`         | 自定义匹配方法，配合 `nzSearchValue` 使用                                                                            | `(node: NzTreeNodeOptions) => boolean`                      | `null`  |\n| `[nzBeforeDrop]`         | drop 前二次校验,允许用户自行决定是否允许放置                                                                         | `(confirm: NzFormatBeforeDropEvent) => Observable<boolean>` | -       |\n| `[nzVirtualHeight]`      | 虚拟滚动的总高度                                                                                                     | `string`                                                    | `-`     |\n| `[nzVirtualItemSize]`    | 虚拟滚动时每一列的高度，与 [cdk itemSize](https://material.angular.io/cdk/scrolling/api) 相同                        | `number`                                                    | `28`    |\n| `[nzVirtualMaxBufferPx]` | 缓冲区最大像素高度，与 [cdk maxBufferPx](https://material.angular.io/cdk/scrolling/api) 相同                         | `number`                                                    | `500`   |\n| `[nzVirtualMinBufferPx]` | 缓冲区最小像素高度，低于该值时将加载新结构，与 [cdk minBufferPx](https://material.angular.io/cdk/scrolling/api) 相同 | `number`                                                    | `28`    |\n| `(nzClick)`              | 点击树节点触发                                                                                                       | `EventEmitter<NzFormatEmitEvent>`                           | -       |\n| `(nzDblClick)`           | 双击树节点触发                                                                                                       | `EventEmitter<NzFormatEmitEvent>`                           | -       |\n| `(nzContextMenu)`        | 右键树节点触发                                                                                                       | `EventEmitter<NzFormatEmitEvent>`                           | -       |\n| `(nzCheckboxChange)`     | 点击树节点 checkbox 触发                                                                                             | `EventEmitter<NzFormatEmitEvent>`                           | -       |\n| `(nzExpandChange)`       | 点击展开树节点图标触发                                                                                               | `EventEmitter<NzFormatEmitEvent>`                           | -       |\n| `(nzSearchValueChange)`  | 搜索节点时调用(`nzSearchValue` 配合使用)                                                                             | `EventEmitter<NzFormatEmitEvent>`                           | -       |\n| `(nzOnDragStart)`        | 开始拖拽时调用                                                                                                       | `EventEmitter<NzFormatEmitEvent>`                           | -       |\n| `(nzOnDragEnter)`        | dragenter 触发时调用                                                                                                 | `EventEmitter<NzFormatEmitEvent>`                           | -       |\n| `(nzOnDragOver)`         | dragover 触发时调用                                                                                                  | `EventEmitter<NzFormatEmitEvent>`                           | -       |\n| `(nzOnDragLeave)`        | dragleave 触发时调用                                                                                                 | `EventEmitter<NzFormatEmitEvent>`                           | -       |\n| `(nzOnDrop)`             | drop 触发时调用                                                                                                      | `EventEmitter<NzFormatEmitEvent>`                           | -       |\n| `(nzOnDragEnd)`          | dragend 触发时调用                                                                                                   | `EventEmitter<NzFormatEmitEvent>`                           | -       |\n\n#### 方法\n\n| 方法名                   | 说明                               | 返回值         |\n| ------------------------ | ---------------------------------- | -------------- |\n| `getTreeNodes`           | 获取组件 NzTreeNode 节点           | `NzTreeNode[]` |\n| `getTreeNodeByKey`       | 按 key 获取 NzTreeNode 节点        | `NzTreeNode`   |\n| `getCheckedNodeList`     | 获取组件 checkbox 被点击选中的节点 | `NzTreeNode[]` |\n| `getSelectedNodeList`    | 获取组件被选中的节点               | `NzTreeNode[]` |\n| `getHalfCheckedNodeList` | 获取组件半选状态节点               | `NzTreeNode[]` |\n| `getExpandedNodeList`    | 获取组件展开状态节点               | `NzTreeNode[]` |\n| `getMatchedNodeList`     | 获取组搜索匹配到的节点             | `NzTreeNode[]` |\n\n#### NzTreeNodeOptions props\n\n| 参数              | 说明                                              | 类型                  | 默认值  |\n| ----------------- | ------------------------------------------------- | --------------------- | ------- |\n| `title`           | 标题                                              | `string`              | -       |\n| `key`             | 整个树范围内的所有节点的 key 值不能重复且不为空！ | `string`              | -       |\n| `icon`            | 节点前的图标，与 `nzShowIcon` 组合使用            | `string`              | -       |\n| `children`        | 子节点                                            | `NzTreeNodeOptions[]` | -       |\n| `isLeaf`          | 设置为叶子节点(叶子节点不可被拖拽模式放置)        | `boolean`             | `false` |\n| `checked`         | 设置节点 checkbox 是否选中                        | `boolean`             | `false` |\n| `selected`        | 设置节点本身是否选中                              | `boolean`             | `false` |\n| `expanded`        | 设置节点是否展开(叶子节点无效)                    | `boolean`             | `false` |\n| `selectable`      | 设置节点是否可被选中                              | `boolean`             | `true`  |\n| `disabled`        | 设置是否禁用节点(不可进行任何操作)                | `boolean`             | `false` |\n| `disableCheckbox` | 设置节点禁用 checkbox                             | `boolean`             | `false` |\n| `[key: string]`   | 自定义数据,可通过 NzTreeNode 的 origin 字段获取   | `any `                | -       |\n\n#### NzFormatEmitEvent props\n\n| 属性            | 说明                                          | 类型                                                                                                                                                                | 默认值 |\n| --------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |\n| `eventName`     | 事件名                                        | enum: `'click' \\| 'dblclick' \\| 'contextmenu' \\| 'check' \\| 'expand' \\| 'search' \\| 'dragstart' \\| 'dragenter' \\| 'dragover' \\| 'dragleave' \\| 'drop' \\| 'dragend'` | -      |\n| `node`          | 当前操作节点(拖拽时表示目标节点)              | `NzTreeNode`                                                                                                                                                        | `null` |\n| `event`         | 原生事件                                      | `'MouseEvent' \\| 'DragEvent'`                                                                                                                                       | `null` |\n| `dragNode?`     | 当前拖拽节点(拖拽时存在)                      | `NzTreeNode`                                                                                                                                                        | `null` |\n| `selectedKeys?` | 已选中的节点 key(单击时存在)                  | `NzTreeNode[]`                                                                                                                                                      | `[]`   |\n| `checkedKeys?`  | checkbox 已选中的节点 key(点击 checkbox 存在) | `NzTreeNode[]`                                                                                                                                                      | `[]`   |\n| `matchedKeys?`  | 搜索时匹配到的节点 key                        | `NzTreeNode[]`                                                                                                                                                      | `[]`   |\n| `keys?`         | 非拖拽事件相关的全部节点的 key 数组           | `string[]`                                                                                                                                                          | `[]`   |\n| `nodes?`        | 非拖拽事件相关的全部节点                      | `NzTreeNode[]`                                                                                                                                                      | `[]`   |\n\n#### NzFormatBeforeDropEvent props\n\n| 属性     | 说明                                                        | 类型         | 默认值 |\n| -------- | ----------------------------------------------------------- | ------------ | ------ |\n| dragNode | 当前拖拽节点(拖拽时存在)                                    | `NzTreeNode` | -      |\n| node     | 当前操作节点(拖拽时表示目标节点)                            | `NzTreeNode` | -      |\n| pos      | 放置位置(-1:目标节点前面, 0: 目标节点内部, 1: 目标节点后面) | `number`     | -      |\n\n#### NzTreeNode props\n\n| 属性                | 说明                                                                                          | 类型                                     | 默认值                    |\n| ------------------- | --------------------------------------------------------------------------------------------- | ---------------------------------------- | ------------------------- |\n| `title`             | 标题                                                                                          | `string`                                 | `NzTreeNodeOptions.title` |\n| `key`               | key 值                                                                                        | `string`                                 | `NzTreeNodeOptions.key`   |\n| `level`             | 层级(最顶层为 0，子节点逐层加 1)                                                              | `number`                                 | `number`                  |\n| `children`          | 子节点                                                                                        | `NzTreeNode[]`                           | `[]`                      |\n| `origin`            | 原始节点树结构(用户提供,用于展示额外信息)                                                     | `NzTreeNodeOptions`                      | -                         |\n| `getParentNode`     | 获取父节点                                                                                    | `function`                               | `null`                    |\n| `isLeaf`            | 是否为叶子节点                                                                                | `boolean`                                | `false`                   |\n| `isExpanded`        | 是否已展开                                                                                    | `boolean`                                | `false`                   |\n| `isDisabled`        | 是否禁用                                                                                      | `boolean`                                | `false`                   |\n| `isDisableCheckbox` | 是否禁用 checkbox                                                                             | `boolean`                                | `false`                   |\n| `isSelectable`      | 是否可选中                                                                                    | `boolean`                                | `true`                    |\n| `isChecked`         | 是否选中 checkbox                                                                             | `boolean`                                | `false`                   |\n| `isHalfChecked`     | 子节点有选中但未全选                                                                          | `boolean`                                | `false`                   |\n| `isSelected`        | 是否已选中                                                                                    | `boolean`                                | `false`                   |\n| `isLoading`         | 是否异步加载状态(影响展开图标展示)                                                            | `boolean`                                | `false`                   |\n| `isMatched`         | title 是否包含 nzSearchValue(搜索使用)                                                        | `boolean`                                | `false`                   |\n| `setSyncChecked`    | 设置 checked 状态并同步其他节点状态                                                           | `function`                               | -                         |\n| `getChildren`       | 获取子节点,返回 NzTreeNode 数组                                                               | `function`                               | -                         |\n| `addChildren`       | 添加子节点,接收 NzTreeNode 或 NzTreeNodeOptions 数组,第二个参数为插入的索引位置，默认插入末尾 | `(children: array, index?: number )=>{}` | -                         |\n| `clearChildren`     | 清除子节点                                                                                    | `function`                               | -                         |\n| `remove`            | 清除当前节点(非根节点)                                                                        | `function`                               | -                         |\n\n## 注意\n\n- 当前请确保 `nzData` 在其他数据相关的属性之前被初始化:\n\n```typescript\n// 示例\nthis.nzExpandAll = false;\nconst nodes = []; // 源数据\nthis.nzData = [...nodes];\n// nzData 值异步获取变化后重新渲染一下属性\nthis.nzExpandedKeys = [...this.nzExpandedKeys];\n// this.nzExpandAll = true;\nthis.nzCheckedKeys = [...this.nzCheckedKeys];\nthis.nzSelectedKeys = [...this.nzSelectedKeys];\n```\n\n- `NzTreeNodeOptions` 可以接受用户自定义属性，可通过 `NzTreeNode.origin` 属性取得。\n- 使用 ViewChild 时，Tree 方法需要在 ngAfterViewInit 中调用。\n- `nzData` 属性请传递 NzTreeNodeOptions 数组。\n"
  },
  {
    "path": "components/tree/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/tree/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/tree/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './tree.module';\nexport * from './tree.component';\nexport * from './tree-node.component';\nexport * from './tree-indent.component';\nexport * from './tree.service';\nexport * from './tree-node-switcher.component';\nexport * from './tree-node-checkbox.component';\nexport * from './tree-node-title.component';\nexport type { NzTreeNodeOptions, NzFormatEmitEvent, NzFormatBeforeDropEvent } from 'ng-zorro-antd/core/tree';\nexport { NzTreeNode } from 'ng-zorro-antd/core/tree';\n"
  },
  {
    "path": "components/tree/style/directory.less",
    "content": "@import '../../style/themes/index';\n\n@tree-prefix-cls: ~'@{ant-prefix}-tree';\n\n.@{tree-prefix-cls}.@{tree-prefix-cls}-directory {\n  // ================== TreeNode ==================\n  .@{tree-prefix-cls}-treenode {\n    position: relative;\n\n    // Hover color\n    &::before {\n      position: absolute;\n      top: 0;\n      right: 0;\n      bottom: 4px;\n      left: 0;\n      transition: background-color 0.3s;\n      content: '';\n      pointer-events: none;\n    }\n\n    &:hover {\n      &::before {\n        background: @item-hover-bg;\n      }\n    }\n\n    // Elements\n    > * {\n      z-index: 1;\n    }\n\n    // >>> Switcher\n    .@{tree-prefix-cls}-switcher {\n      transition: color 0.3s;\n    }\n\n    // >>> Title\n    .@{tree-prefix-cls}-node-content-wrapper {\n      border-radius: 0;\n      user-select: none;\n\n      &:hover {\n        background: transparent;\n      }\n\n      &.@{tree-prefix-cls}-node-selected {\n        color: @tree-directory-selected-color;\n        background: transparent;\n      }\n    }\n\n    // ============= Selected =============\n    &-selected {\n      &:hover::before,\n      &::before {\n        background: @tree-directory-selected-bg;\n      }\n\n      // >>> Switcher\n      .@{tree-prefix-cls}-switcher {\n        color: @tree-directory-selected-color;\n      }\n\n      // >>> Title\n      .@{tree-prefix-cls}-node-content-wrapper {\n        color: @tree-directory-selected-color;\n        background: transparent;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/tree/style/entry.less",
    "content": "@import './index.less';\n@import './patch.less';\n"
  },
  {
    "path": "components/tree/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import '../../checkbox/style/mixin';\n@import './mixin';\n@import './directory';\n\n@tree-prefix-cls: ~'@{ant-prefix}-tree';\n@tree-node-prefix-cls: ~'@{tree-prefix-cls}-treenode';\n\n.antCheckboxFn(@checkbox-prefix-cls: ~'@{ant-prefix}-tree-checkbox');\n\n.@{tree-prefix-cls} {\n  .antTreeFn(@tree-prefix-cls);\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/tree/style/mixin.less",
    "content": "@import '../../style/mixins/index';\n\n@tree-prefix-cls: ~'@{ant-prefix}-tree';\n@select-tree-prefix-cls: ~'@{ant-prefix}-select-tree';\n@tree-motion: ~'@{ant-prefix}-motion-collapse';\n@tree-node-padding: (@padding-xs / 2);\n// @deprecated: kept for customization usages, recommend using @tree-node-highlight-color instead.\n@tree-node-hightlight-color: inherit;\n@tree-node-highlight-color: @tree-node-hightlight-color;\n\n.antTreeSwitcherIcon(@type: 'tree-default-open-icon') {\n  .@{tree-prefix-cls}-switcher-icon,\n  .@{select-tree-prefix-cls}-switcher-icon {\n    display: inline-block;\n    font-size: 10px;\n    vertical-align: baseline;\n\n    svg {\n      transition: transform 0.3s;\n    }\n  }\n}\n\n.drop-indicator() {\n  .@{tree-prefix-cls}-drop-indicator {\n    position: absolute;\n    // it should displayed over the following node\n    z-index: 1;\n    height: 2px;\n    background-color: @primary-color;\n    border-radius: 1px;\n    pointer-events: none;\n\n    &::after {\n      position: absolute;\n      top: -3px;\n      left: -6px;\n      width: 8px;\n      height: 8px;\n      background-color: transparent;\n      border: 2px solid @primary-color;\n      border-radius: 50%;\n      content: '';\n    }\n  }\n}\n\n.antTreeFn(@custom-tree-prefix-cls) {\n  @custom-tree-node-prefix-cls: ~'@{custom-tree-prefix-cls}-treenode';\n  .reset-component();\n  background: @tree-bg;\n  border-radius: @border-radius-base;\n  transition: background-color 0.3s;\n\n  &-focused:not(:hover):not(&-active-focused) {\n    background: @primary-1;\n  }\n\n  // =================== Virtual List ===================\n  &-list-holder-inner {\n    align-items: flex-start;\n  }\n\n  &.@{custom-tree-prefix-cls}-block-node {\n    .@{custom-tree-prefix-cls}-list-holder-inner {\n      align-items: stretch;\n\n      // >>> Title\n      .@{custom-tree-prefix-cls}-node-content-wrapper {\n        flex: auto;\n      }\n\n      // >>> Drag\n      .@{custom-tree-node-prefix-cls}.dragging {\n        position: relative;\n\n        &::after {\n          position: absolute;\n          top: 0;\n          right: 0;\n          bottom: @tree-node-padding;\n          left: 0;\n          border: 1px solid @primary-color;\n          opacity: 0;\n          animation: ant-tree-node-fx-do-not-use 0.3s;\n          animation-play-state: running;\n          animation-fill-mode: forwards;\n          content: '';\n          pointer-events: none;\n        }\n      }\n    }\n  }\n\n  // ===================== TreeNode =====================\n  .@{custom-tree-node-prefix-cls} {\n    display: flex;\n    align-items: flex-start;\n    margin-bottom: @tree-node-padding;\n    outline: none;\n\n    // Disabled\n    &-disabled {\n      // >>> Title\n      .@{custom-tree-prefix-cls}-node-content-wrapper {\n        color: @disabled-color;\n        cursor: not-allowed;\n\n        &:hover {\n          background: transparent;\n        }\n      }\n    }\n\n    &-active .@{custom-tree-prefix-cls}-node-content-wrapper {\n      background: @tree-node-hover-bg;\n    }\n\n    &:not(&-disabled).filter-node .@{custom-tree-prefix-cls}-title {\n      color: @tree-node-highlight-color;\n      font-weight: 500;\n    }\n\n    &-draggable {\n      .@{custom-tree-prefix-cls}-draggable-icon {\n        width: @tree-title-height;\n        line-height: @tree-title-height;\n        text-align: center;\n        visibility: visible;\n        opacity: 0.2;\n        transition: opacity @animation-duration-slow;\n\n        .@{custom-tree-node-prefix-cls}:hover & {\n          opacity: 0.45;\n        }\n      }\n\n      &.@{custom-tree-node-prefix-cls}-disabled {\n        .@{custom-tree-prefix-cls}-draggable-icon {\n          visibility: hidden;\n        }\n      }\n    }\n  }\n\n  // >>> Indent\n  &-indent {\n    align-self: stretch;\n    white-space: nowrap;\n    user-select: none;\n\n    &-unit {\n      display: inline-block;\n      width: @tree-title-height;\n    }\n  }\n\n  // >>> Drag Handler\n  &-draggable-icon {\n    visibility: hidden;\n  }\n\n  // >>> Switcher\n  &-switcher {\n    .antTreeSwitcherIcon();\n    position: relative;\n    flex: none;\n    align-self: stretch;\n    width: @tree-title-height;\n    margin: 0;\n    line-height: @tree-title-height;\n    text-align: center;\n    cursor: pointer;\n    user-select: none;\n\n    &-noop {\n      cursor: default;\n    }\n\n    &_close {\n      .@{custom-tree-prefix-cls}-switcher-icon {\n        svg {\n          transform: rotate(-90deg);\n        }\n      }\n    }\n\n    &-loading-icon {\n      color: @primary-color;\n    }\n\n    &-leaf-line {\n      position: relative;\n      z-index: 1;\n      display: inline-block;\n      width: 100%;\n      height: 100%;\n      // https://github.com/ant-design/ant-design/issues/31884\n      &::before {\n        position: absolute;\n        top: 0;\n        right: 12px;\n        bottom: -@tree-node-padding;\n        margin-left: -1px;\n        border-right: 1px solid @normal-color;\n        content: ' ';\n      }\n\n      &::after {\n        position: absolute;\n        width: @tree-title-height - 14px;\n        height: @tree-title-height - 10px;\n        border-bottom: 1px solid @normal-color;\n        content: ' ';\n      }\n    }\n  }\n\n  // >>> Checkbox\n  &-checkbox {\n    top: initial;\n    margin: ((@tree-title-height - @checkbox-size) / 2) 8px 0 0;\n  }\n\n  // >>> Title\n  & &-node-content-wrapper {\n    position: relative;\n    z-index: auto;\n    min-height: @tree-title-height;\n    margin: 0;\n    padding: 0 4px;\n    color: inherit;\n    line-height: @tree-title-height;\n    background: transparent;\n    border-radius: @border-radius-base;\n    cursor: pointer;\n    transition: all 0.3s, border 0s, line-height 0s, box-shadow 0s;\n\n    &:hover {\n      background-color: @tree-node-hover-bg;\n    }\n\n    &.@{custom-tree-prefix-cls}-node-selected {\n      background-color: @tree-node-selected-bg;\n    }\n\n    // Icon\n    .@{custom-tree-prefix-cls}-iconEle {\n      display: inline-block;\n      width: @tree-title-height;\n      height: @tree-title-height;\n      line-height: @tree-title-height;\n      text-align: center;\n      vertical-align: top;\n\n      &:empty {\n        display: none;\n      }\n    }\n  }\n\n  // https://github.com/ant-design/ant-design/issues/28217\n  &-unselectable &-node-content-wrapper:hover {\n    background-color: transparent;\n  }\n\n  // ==================== Draggable =====================\n  &-node-content-wrapper {\n    line-height: @tree-title-height;\n    user-select: none;\n\n    .drop-indicator();\n  }\n\n  .@{custom-tree-node-prefix-cls}.drop-container {\n    > [draggable] {\n      box-shadow: 0 0 0 2px @primary-color;\n    }\n  }\n\n  // ==================== Show Line =====================\n  &-show-line {\n    // ================ Indent lines ================\n    .@{custom-tree-prefix-cls}-indent {\n      &-unit {\n        position: relative;\n        height: 100%;\n\n        &::before {\n          position: absolute;\n          top: 0;\n          right: (@tree-title-height / 2);\n          bottom: -@tree-node-padding;\n          border-right: 1px solid @border-color-base;\n          content: '';\n        }\n\n        &-end {\n          &::before {\n            display: none;\n          }\n        }\n      }\n    }\n\n    // ============== Cover Background ==============\n    .@{custom-tree-prefix-cls}-switcher {\n      background: @component-background;\n\n      &-line-icon {\n        // https://github.com/ant-design/ant-design/issues/32813\n        vertical-align: -0.15em;\n      }\n    }\n  }\n\n  .@{custom-tree-node-prefix-cls}-leaf-last {\n    .@{custom-tree-prefix-cls}-switcher {\n      &-leaf-line {\n        &::before {\n          top: auto !important;\n          bottom: auto !important;\n          height: @tree-title-height - 10px !important;\n        }\n      }\n    }\n  }\n}\n\n@keyframes ant-tree-node-fx-do-not-use {\n  0% {\n    opacity: 0;\n  }\n\n  100% {\n    opacity: 1;\n  }\n}\n"
  },
  {
    "path": "components/tree/style/patch.less",
    "content": "/*\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\n.font-highlight {\n  color: @highlight-color;\n}\n\nnz-tree {\n  display: block;\n}\n"
  },
  {
    "path": "components/tree/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import '../../checkbox/style/mixin';\n\n@tree-prefix-cls: ~'@{ant-prefix}-tree';\n@select-tree-prefix-cls: ~'@{ant-prefix}-select-tree';\n@tree-node-prefix-cls: ~'@{tree-prefix-cls}-treenode';\n\n.@{tree-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n    .@{tree-prefix-cls}-node-content-wrapper[draggable='true'] {\n      .@{tree-prefix-cls}-drop-indicator {\n        &::after {\n          right: -6px;\n          left: unset;\n        }\n      }\n    }\n  }\n\n  // ===================== TreeNode =====================\n  .@{tree-node-prefix-cls} {\n    &-rtl {\n      direction: rtl;\n    }\n  }\n\n  // >>> Switcher\n  &-switcher {\n    &_close {\n      .@{tree-prefix-cls}-switcher-icon {\n        svg {\n          .@{tree-prefix-cls}-rtl & {\n            transform: rotate(90deg);\n          }\n        }\n      }\n    }\n  }\n  // ==================== Show Line =====================\n  &-show-line {\n    // ================ Indent lines ================\n    .@{tree-prefix-cls}-indent {\n      &-unit {\n        &::before {\n          .@{tree-prefix-cls}-rtl& {\n            right: auto;\n            left: -(@tree-title-height / 2) - 1px;\n            border-right: none;\n            border-left: 1px solid @border-color-base;\n          }\n        }\n      }\n    }\n  }\n  // >>> Checkbox\n  &-checkbox {\n    .@{tree-prefix-cls}-rtl & {\n      margin: ((@tree-title-height - @checkbox-size) / 2) 0 0 8px;\n    }\n  }\n}\n\n.@{select-tree-prefix-cls} {\n  // >>> Checkbox\n  &-checkbox {\n    .@{tree-prefix-cls}-select-dropdown-rtl & {\n      margin: ((@tree-title-height - @checkbox-size) / 2) 0 0 8px;\n    }\n  }\n}\n"
  },
  {
    "path": "components/tree/tree-drop-indicator.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction } from '@angular/cdk/bidi';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  Input,\n  OnChanges,\n  numberAttribute,\n  inject\n} from '@angular/core';\n\nimport { NgStyleInterface } from 'ng-zorro-antd/core/types';\n\n@Component({\n  selector: 'nz-tree-drop-indicator',\n  exportAs: 'nzTreeDropIndicator',\n  template: ``,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    class: 'ant-tree-drop-indicator',\n    '[style]': 'style'\n  }\n})\nexport class NzTreeDropIndicatorComponent implements OnChanges {\n  @Input() dropPosition?: number;\n  @Input({ transform: numberAttribute }) level: number = 1;\n  @Input() direction: Direction = 'ltr';\n  style: NgStyleInterface = {};\n\n  private cdr = inject(ChangeDetectorRef);\n\n  ngOnChanges(): void {\n    this.renderIndicator(this.dropPosition!, this.direction);\n  }\n\n  renderIndicator(dropPosition: number, direction: Direction = 'ltr'): void {\n    const offset = 4;\n    const startPosition = direction === 'ltr' ? 'left' : 'right';\n    const endPosition = direction === 'ltr' ? 'right' : 'left';\n    const style: NgStyleInterface = {\n      [startPosition]: `${offset}px`,\n      [endPosition]: '0px'\n    };\n    switch (dropPosition) {\n      case -1:\n        style.top = `${-3}px`;\n        break;\n      case 1:\n        style.bottom = `${-3}px`;\n        break;\n      case 0:\n        // dropPosition === 0\n        style.bottom = `${-3}px`;\n        style[startPosition] = `${offset + 24}px`;\n        break;\n      default:\n        style.display = 'none';\n        break;\n    }\n    this.style = style;\n    this.cdr.markForCheck();\n  }\n}\n"
  },
  {
    "path": "components/tree/tree-indent.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from '@angular/core';\n\n@Component({\n  selector: 'nz-tree-indent',\n  exportAs: 'nzTreeIndent',\n  template: `\n    @for (_ of listOfUnit; track $index) {\n      <span\n        [class.ant-tree-indent-unit]=\"!nzSelectMode\"\n        [class.ant-select-tree-indent-unit]=\"nzSelectMode\"\n        [class.ant-select-tree-indent-unit-start]=\"nzSelectMode && nzIsStart[$index]\"\n        [class.ant-tree-indent-unit-start]=\"!nzSelectMode && nzIsStart[$index]\"\n        [class.ant-select-tree-indent-unit-end]=\"nzSelectMode && nzIsEnd[$index]\"\n        [class.ant-tree-indent-unit-end]=\"!nzSelectMode && nzIsEnd[$index]\"\n      ></span>\n    }\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    '[attr.aria-hidden]': 'true',\n    '[class.ant-tree-indent]': '!nzSelectMode',\n    '[class.ant-select-tree-indent]': 'nzSelectMode'\n  }\n})\nexport class NzTreeIndentComponent implements OnChanges {\n  @Input() nzTreeLevel = 0;\n  @Input() nzIsStart: boolean[] = [];\n  @Input() nzIsEnd: boolean[] = [];\n  @Input() nzSelectMode = false;\n\n  listOfUnit: number[] = [];\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzTreeLevel } = changes;\n    if (nzTreeLevel) {\n      this.listOfUnit = [...new Array(nzTreeLevel.currentValue || 0)];\n    }\n  }\n}\n"
  },
  {
    "path": "components/tree/tree-node-checkbox.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, Input, booleanAttribute } from '@angular/core';\n\n@Component({\n  // eslint-disable-next-line @angular-eslint/component-selector\n  selector: 'nz-tree-node-checkbox[builtin]',\n  template: `\n    <span [class.ant-tree-checkbox-inner]=\"!nzSelectMode\" [class.ant-select-tree-checkbox-inner]=\"nzSelectMode\"></span>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    '[class.ant-select-tree-checkbox]': `nzSelectMode`,\n    '[class.ant-select-tree-checkbox-checked]': `nzSelectMode && isChecked`,\n    '[class.ant-select-tree-checkbox-indeterminate]': `nzSelectMode && isHalfChecked`,\n    '[class.ant-select-tree-checkbox-disabled]': `nzSelectMode && (isDisabled || isDisableCheckbox)`,\n    '[class.ant-tree-checkbox]': `!nzSelectMode`,\n    '[class.ant-tree-checkbox-checked]': `!nzSelectMode && isChecked`,\n    '[class.ant-tree-checkbox-indeterminate]': `!nzSelectMode && isHalfChecked`,\n    '[class.ant-tree-checkbox-disabled]': `!nzSelectMode && (isDisabled || isDisableCheckbox)`\n  }\n})\nexport class NzTreeNodeBuiltinCheckboxComponent {\n  @Input() nzSelectMode = false;\n  @Input({ transform: booleanAttribute }) isChecked?: boolean;\n  @Input({ transform: booleanAttribute }) isHalfChecked?: boolean;\n  @Input({ transform: booleanAttribute }) isDisabled?: boolean;\n  @Input({ transform: booleanAttribute }) isDisableCheckbox?: boolean;\n}\n"
  },
  {
    "path": "components/tree/tree-node-switcher.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ChangeDetectionStrategy, Component, Input, TemplateRef, booleanAttribute } from '@angular/core';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzTreeNode, NzTreeNodeOptions } from 'ng-zorro-antd/core/tree';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'nz-tree-node-switcher',\n  template: `\n    @if (isShowSwitchIcon) {\n      @if (!isLoading) {\n        <ng-container *nzStringTemplateOutlet=\"nzExpandedIcon; context: { $implicit: context, origin: context.origin }\">\n          <nz-icon\n            nzType=\"caret-down\"\n            [class.ant-select-tree-switcher-icon]=\"nzSelectMode\"\n            [class.ant-tree-switcher-icon]=\"!nzSelectMode\"\n          />\n        </ng-container>\n      } @else {\n        <nz-icon nzType=\"loading\" [nzSpin]=\"true\" class=\"ant-tree-switcher-loading-icon\" />\n      }\n    }\n    @if (nzShowLine) {\n      @if (!isLoading) {\n        <ng-container *nzStringTemplateOutlet=\"nzExpandedIcon; context: { $implicit: context, origin: context.origin }\">\n          @if (isShowLineIcon) {\n            <nz-icon [nzType]=\"isSwitcherOpen ? 'minus-square' : 'plus-square'\" class=\"ant-tree-switcher-line-icon\" />\n          } @else {\n            <nz-icon nzType=\"file\" class=\"ant-tree-switcher-line-icon\" />\n          }\n        </ng-container>\n      } @else {\n        <nz-icon nzType=\"loading\" [nzSpin]=\"true\" class=\"ant-tree-switcher-loading-icon\" />\n      }\n    }\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    '[class.ant-select-tree-switcher]': 'nzSelectMode',\n    '[class.ant-select-tree-switcher-noop]': 'nzSelectMode && isLeaf',\n    '[class.ant-select-tree-switcher_open]': 'nzSelectMode && isSwitcherOpen',\n    '[class.ant-select-tree-switcher_close]': 'nzSelectMode && isSwitcherClose',\n    '[class.ant-tree-switcher]': '!nzSelectMode',\n    '[class.ant-tree-switcher-noop]': '!nzSelectMode && isLeaf',\n    '[class.ant-tree-switcher_open]': '!nzSelectMode && isSwitcherOpen',\n    '[class.ant-tree-switcher_close]': '!nzSelectMode && isSwitcherClose'\n  },\n  imports: [NzIconModule, NzOutletModule]\n})\nexport class NzTreeNodeSwitcherComponent {\n  @Input({ transform: booleanAttribute }) nzShowExpand?: boolean;\n  @Input({ transform: booleanAttribute }) nzShowLine?: boolean;\n  @Input() nzExpandedIcon?: TemplateRef<{ $implicit: NzTreeNode; origin: NzTreeNodeOptions }>;\n  @Input() nzSelectMode = false;\n  @Input() context!: NzTreeNode;\n  @Input({ transform: booleanAttribute }) isLeaf?: boolean;\n  @Input({ transform: booleanAttribute }) isLoading?: boolean;\n  @Input({ transform: booleanAttribute }) isExpanded?: boolean;\n\n  get isShowLineIcon(): boolean {\n    return !this.isLeaf && !!this.nzShowLine;\n  }\n\n  get isShowSwitchIcon(): boolean {\n    return !this.isLeaf && !this.nzShowLine;\n  }\n\n  get isSwitcherOpen(): boolean {\n    return !!this.isExpanded && !this.isLeaf;\n  }\n\n  get isSwitcherClose(): boolean {\n    return !this.isExpanded && !this.isLeaf;\n  }\n}\n"
  },
  {
    "path": "components/tree/tree-node-title.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  Input,\n  OnChanges,\n  SimpleChanges,\n  TemplateRef,\n  booleanAttribute,\n  inject\n} from '@angular/core';\n\nimport { NzHighlightPipe } from 'ng-zorro-antd/core/highlight';\nimport { NzTreeNode, NzTreeNodeOptions } from 'ng-zorro-antd/core/tree';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nimport { NzTreeDropIndicatorComponent } from './tree-drop-indicator.component';\n\n@Component({\n  selector: 'nz-tree-node-title',\n  template: `\n    <ng-template\n      [ngTemplateOutlet]=\"treeTemplate\"\n      [ngTemplateOutletContext]=\"{ $implicit: context, origin: context.origin }\"\n    />\n    @if (!treeTemplate) {\n      @if (icon && showIcon) {\n        <span\n          [class.ant-tree-icon__open]=\"isSwitcherOpen\"\n          [class.ant-tree-icon__close]=\"isSwitcherClose\"\n          [class.ant-tree-icon_loading]=\"isLoading\"\n          [class.ant-select-tree-iconEle]=\"selectMode\"\n          [class.ant-tree-iconEle]=\"!selectMode\"\n        >\n          <span\n            [class.ant-select-tree-iconEle]=\"selectMode\"\n            [class.ant-select-tree-icon__customize]=\"selectMode\"\n            [class.ant-tree-iconEle]=\"!selectMode\"\n            [class.ant-tree-icon__customize]=\"!selectMode\"\n          >\n            <nz-icon [nzType]=\"icon\" />\n          </span>\n        </span>\n      }\n      <span class=\"ant-tree-title\" [innerHTML]=\"title | nzHighlight: matchedValue : 'i' : 'font-highlight'\"></span>\n    }\n    @if (showIndicator) {\n      <nz-tree-drop-indicator [dropPosition]=\"dragPosition\" [level]=\"context.level\" />\n    }\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    '[attr.title]': 'title',\n    '[attr.draggable]': 'canDraggable',\n    '[attr.aria-grabbed]': 'canDraggable',\n    '[class.draggable]': 'canDraggable',\n    '[class.ant-select-tree-node-content-wrapper]': `selectMode`,\n    '[class.ant-select-tree-node-content-wrapper-open]': `selectMode && isSwitcherOpen`,\n    '[class.ant-select-tree-node-content-wrapper-close]': `selectMode && isSwitcherClose`,\n    '[class.ant-select-tree-node-selected]': `selectMode && isSelected`,\n    '[class.ant-tree-node-content-wrapper]': `!selectMode`,\n    '[class.ant-tree-node-content-wrapper-open]': `!selectMode && isSwitcherOpen`,\n    '[class.ant-tree-node-content-wrapper-close]': `!selectMode && isSwitcherClose`,\n    '[class.ant-tree-node-selected]': `!selectMode && isSelected`\n  },\n  imports: [NgTemplateOutlet, NzIconModule, NzHighlightPipe, NzTreeDropIndicatorComponent]\n})\nexport class NzTreeNodeTitleComponent implements OnChanges {\n  private cdr = inject(ChangeDetectorRef);\n\n  @Input() searchValue!: string;\n  @Input() treeTemplate: TemplateRef<{ $implicit: NzTreeNode; origin: NzTreeNodeOptions }> | null = null;\n  @Input({ transform: booleanAttribute }) draggable!: boolean;\n  @Input({ transform: booleanAttribute }) showIcon!: boolean;\n  @Input() selectMode = false;\n  @Input() context!: NzTreeNode;\n  @Input() icon!: string;\n  @Input() title!: string;\n  @Input({ transform: booleanAttribute }) isLoading!: boolean;\n  @Input({ transform: booleanAttribute }) isSelected!: boolean;\n  @Input({ transform: booleanAttribute }) isDisabled!: boolean;\n  @Input({ transform: booleanAttribute }) isMatched!: boolean;\n  @Input({ transform: booleanAttribute }) isExpanded!: boolean;\n  @Input({ transform: booleanAttribute }) isLeaf!: boolean;\n  // Drag indicator\n  @Input() showIndicator = true;\n  @Input() dragPosition?: number;\n\n  get canDraggable(): boolean | null {\n    return this.draggable && !this.isDisabled ? true : null;\n  }\n\n  get matchedValue(): string {\n    return this.isMatched ? this.searchValue : '';\n  }\n\n  get isSwitcherOpen(): boolean {\n    return this.isExpanded && !this.isLeaf;\n  }\n\n  get isSwitcherClose(): boolean {\n    return !this.isExpanded && !this.isLeaf;\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { showIndicator, dragPosition } = changes;\n    if (showIndicator || dragPosition) {\n      this.cdr.markForCheck();\n    }\n  }\n}\n"
  },
  {
    "path": "components/tree/tree-node.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ElementRef,\n  EventEmitter,\n  Input,\n  NgZone,\n  OnChanges,\n  OnInit,\n  Output,\n  Renderer2,\n  SimpleChanges,\n  TemplateRef,\n  booleanAttribute,\n  inject,\n  DestroyRef\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Observable, Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\n\nimport {\n  NzFormatBeforeDropEvent,\n  NzFormatEmitEvent,\n  NzTreeBaseService,\n  NzTreeNode,\n  NzTreeNodeOptions\n} from 'ng-zorro-antd/core/tree';\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\n\nimport { NzTreeIndentComponent } from './tree-indent.component';\nimport { NzTreeNodeBuiltinCheckboxComponent } from './tree-node-checkbox.component';\nimport { NzTreeNodeSwitcherComponent } from './tree-node-switcher.component';\nimport { NzTreeNodeTitleComponent } from './tree-node-title.component';\n\n@Component({\n  // eslint-disable-next-line @angular-eslint/component-selector\n  selector: 'nz-tree-node[builtin]',\n  exportAs: 'nzTreeBuiltinNode',\n  template: `\n    <nz-tree-indent\n      [nzTreeLevel]=\"nzTreeNode.level\"\n      [nzSelectMode]=\"nzSelectMode\"\n      [nzIsStart]=\"isStart\"\n      [nzIsEnd]=\"isEnd\"\n    />\n    @if (nzShowExpand) {\n      <nz-tree-node-switcher\n        [nzShowExpand]=\"nzShowExpand\"\n        [nzShowLine]=\"nzShowLine\"\n        [nzExpandedIcon]=\"nzExpandedIcon\"\n        [nzSelectMode]=\"nzSelectMode\"\n        [context]=\"nzTreeNode\"\n        [isLeaf]=\"isLeaf\"\n        [isExpanded]=\"isExpanded\"\n        [isLoading]=\"isLoading\"\n        (click)=\"clickExpand($event)\"\n      />\n    }\n    @if (nzCheckable) {\n      <nz-tree-node-checkbox\n        builtin\n        (click)=\"clickCheckbox($event)\"\n        [nzSelectMode]=\"nzSelectMode\"\n        [isChecked]=\"isChecked\"\n        [isHalfChecked]=\"isHalfChecked\"\n        [isDisabled]=\"isDisabled\"\n        [isDisableCheckbox]=\"isDisableCheckbox\"\n      />\n    }\n    <nz-tree-node-title\n      [icon]=\"icon\"\n      [title]=\"title\"\n      [isLoading]=\"isLoading\"\n      [isSelected]=\"isSelected\"\n      [isDisabled]=\"isDisabled\"\n      [isMatched]=\"isMatched\"\n      [isExpanded]=\"isExpanded\"\n      [isLeaf]=\"isLeaf\"\n      [searchValue]=\"nzSearchValue\"\n      [treeTemplate]=\"nzTreeTemplate\"\n      [draggable]=\"nzDraggable\"\n      [showIcon]=\"nzShowIcon\"\n      [selectMode]=\"nzSelectMode\"\n      [context]=\"nzTreeNode\"\n      [showIndicator]=\"showIndicator\"\n      [dragPosition]=\"dragPos\"\n      (dblclick)=\"dblClick($event)\"\n      (click)=\"clickSelect($event)\"\n      (contextmenu)=\"contextMenu($event)\"\n    />\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    '[class.ant-select-tree-treenode]': `nzSelectMode`,\n    '[class.ant-select-tree-treenode-disabled]': `nzSelectMode && isDisabled`,\n    '[class.ant-select-tree-treenode-switcher-open]': `nzSelectMode && isSwitcherOpen`,\n    '[class.ant-select-tree-treenode-switcher-close]': `nzSelectMode && isSwitcherClose`,\n    '[class.ant-select-tree-treenode-checkbox-checked]': `nzSelectMode && isChecked`,\n    '[class.ant-select-tree-treenode-checkbox-indeterminate]': `nzSelectMode && isHalfChecked`,\n    '[class.ant-select-tree-treenode-selected]': `nzSelectMode && isSelected`,\n    '[class.ant-select-tree-treenode-loading]': `nzSelectMode && isLoading`,\n    '[class.ant-tree-treenode]': `!nzSelectMode`,\n    '[class.ant-tree-treenode-disabled]': `!nzSelectMode && isDisabled`,\n    '[class.ant-tree-treenode-switcher-open]': `!nzSelectMode && isSwitcherOpen`,\n    '[class.ant-tree-treenode-switcher-close]': `!nzSelectMode && isSwitcherClose`,\n    '[class.ant-tree-treenode-checkbox-checked]': `!nzSelectMode && isChecked`,\n    '[class.ant-tree-treenode-checkbox-indeterminate]': `!nzSelectMode && isHalfChecked`,\n    '[class.ant-tree-treenode-selected]': `!nzSelectMode && isSelected`,\n    '[class.ant-tree-treenode-loading]': `!nzSelectMode && isLoading`,\n    '[class.dragging]': `draggingKey === nzTreeNode.key`,\n    '[style.display]': 'displayStyle'\n  },\n  imports: [\n    NzTreeIndentComponent,\n    NzTreeNodeSwitcherComponent,\n    NzTreeNodeBuiltinCheckboxComponent,\n    NzTreeNodeTitleComponent\n  ]\n})\nexport class NzTreeNodeBuiltinComponent implements OnInit, OnChanges {\n  private nzTreeService = inject(NzTreeBaseService);\n  private ngZone = inject(NgZone);\n  private renderer = inject(Renderer2);\n  private el: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement;\n  private cdr = inject(ChangeDetectorRef);\n  private destroyRef = inject(DestroyRef);\n\n  @Input() icon: string = '';\n  @Input() title: string = '';\n  @Input({ transform: booleanAttribute }) isLoading: boolean = false;\n  @Input({ transform: booleanAttribute }) isSelected: boolean = false;\n  @Input({ transform: booleanAttribute }) isDisabled: boolean = false;\n  @Input({ transform: booleanAttribute }) isMatched: boolean = false;\n  @Input({ transform: booleanAttribute }) isExpanded!: boolean;\n  @Input({ transform: booleanAttribute }) isLeaf!: boolean;\n  @Input({ transform: booleanAttribute }) isChecked?: boolean;\n  @Input({ transform: booleanAttribute }) isHalfChecked?: boolean;\n  @Input({ transform: booleanAttribute }) isDisableCheckbox?: boolean;\n  @Input({ transform: booleanAttribute }) isSelectable?: boolean;\n  @Input({ transform: booleanAttribute }) canHide?: boolean;\n  @Input() isStart: boolean[] = [];\n  @Input() isEnd: boolean[] = [];\n  @Input() nzTreeNode!: NzTreeNode;\n  @Input({ transform: booleanAttribute }) nzShowLine?: boolean;\n  @Input({ transform: booleanAttribute }) nzShowExpand?: boolean;\n  @Input({ transform: booleanAttribute }) nzCheckable?: boolean;\n  @Input({ transform: booleanAttribute }) nzAsyncData?: boolean;\n  @Input({ transform: booleanAttribute }) nzHideUnMatched = false;\n  @Input({ transform: booleanAttribute }) nzNoAnimation = false;\n  @Input({ transform: booleanAttribute }) nzSelectMode = false;\n  @Input({ transform: booleanAttribute }) nzShowIcon = false;\n  @Input() nzExpandedIcon?: TemplateRef<{ $implicit: NzTreeNode; origin: NzTreeNodeOptions }>;\n  @Input() nzTreeTemplate: TemplateRef<{ $implicit: NzTreeNode; origin: NzTreeNodeOptions }> | null = null;\n  @Input() nzBeforeDrop?: (confirm: NzFormatBeforeDropEvent) => Observable<boolean>;\n  @Input() nzSearchValue = '';\n  @Input({ transform: booleanAttribute }) nzDraggable: boolean = false;\n  @Output() readonly nzClick = new EventEmitter<NzFormatEmitEvent>();\n  @Output() readonly nzDblClick = new EventEmitter<NzFormatEmitEvent>();\n  @Output() readonly nzContextMenu = new EventEmitter<NzFormatEmitEvent>();\n  @Output() readonly nzCheckboxChange = new EventEmitter<NzFormatEmitEvent>();\n  @Output() readonly nzExpandChange = new EventEmitter<NzFormatEmitEvent>();\n  @Output() readonly nzOnDragStart = new EventEmitter<NzFormatEmitEvent>();\n  @Output() readonly nzOnDragEnter = new EventEmitter<NzFormatEmitEvent>();\n  @Output() readonly nzOnDragOver = new EventEmitter<NzFormatEmitEvent>();\n  @Output() readonly nzOnDragLeave = new EventEmitter<NzFormatEmitEvent>();\n  @Output() readonly nzOnDrop = new EventEmitter<NzFormatEmitEvent>();\n  @Output() readonly nzOnDragEnd = new EventEmitter<NzFormatEmitEvent>();\n\n  /**\n   * drag var\n   */\n  destroy$ = new Subject<void>();\n  dragPos = 2;\n  dragPosClass: Record<string, string> = {\n    0: 'drag-over',\n    1: 'drag-over-gap-bottom',\n    '-1': 'drag-over-gap-top'\n  };\n  draggingKey: string | null = null;\n  showIndicator = false;\n  /**\n   * default set\n   */\n  get displayStyle(): string {\n    // to hide unmatched nodes\n    return this.nzSearchValue && this.nzHideUnMatched && !this.isMatched && !this.isExpanded && this.canHide\n      ? 'none'\n      : '';\n  }\n\n  get isSwitcherOpen(): boolean {\n    return this.isExpanded && !this.isLeaf;\n  }\n\n  get isSwitcherClose(): boolean {\n    return !this.isExpanded && !this.isLeaf;\n  }\n\n  clickExpand(event: MouseEvent): void {\n    event.preventDefault();\n    if (!this.isLoading && !this.isLeaf) {\n      // set async state\n      if (this.nzAsyncData && this.nzTreeNode.children.length === 0 && !this.isExpanded) {\n        this.nzTreeNode.isLoading = true;\n      }\n      this.nzTreeNode.setExpanded(!this.isExpanded);\n    }\n    this.nzTreeService.setExpandedNodeList(this.nzTreeNode);\n    const eventNext = this.nzTreeService.formatEvent('expand', this.nzTreeNode, event);\n    this.nzExpandChange.emit(eventNext);\n  }\n\n  clickSelect(event: MouseEvent): void {\n    event.preventDefault();\n    if (this.isSelectable && !this.isDisabled) {\n      this.nzTreeNode.isSelected = !this.nzTreeNode.isSelected;\n    }\n    this.nzTreeService.setSelectedNodeList(this.nzTreeNode);\n    const eventNext = this.nzTreeService.formatEvent('click', this.nzTreeNode, event);\n    this.nzClick.emit(eventNext);\n  }\n\n  dblClick(event: MouseEvent): void {\n    event.preventDefault();\n    const eventNext = this.nzTreeService.formatEvent('dblclick', this.nzTreeNode, event);\n    this.nzDblClick.emit(eventNext);\n  }\n\n  contextMenu(event: MouseEvent): void {\n    const eventNext = this.nzTreeService.formatEvent('contextmenu', this.nzTreeNode, event);\n    this.nzContextMenu.emit(eventNext);\n  }\n\n  clickCheckbox(event: MouseEvent): void {\n    event.preventDefault();\n    // return if the node is disabled\n    if (this.isDisabled || this.isDisableCheckbox) {\n      return;\n    }\n    this.nzTreeNode.isChecked = !this.nzTreeNode.isChecked;\n    this.nzTreeNode.isHalfChecked = false;\n    this.nzTreeService.setCheckedNodeList(this.nzTreeNode);\n    const eventNext = this.nzTreeService.formatEvent('check', this.nzTreeNode, event);\n    this.nzCheckboxChange.emit(eventNext);\n  }\n\n  clearDragClass(): void {\n    const dragClass = ['drag-over-gap-top', 'drag-over-gap-bottom', 'drag-over', 'drop-target'];\n    dragClass.forEach(e => this.renderer.removeClass(this.el, e));\n  }\n\n  handleDragStart(e: DragEvent): void {\n    try {\n      // i.e., throw error\n      // firefox-need-it\n      e.dataTransfer!.setData('text/plain', this.nzTreeNode.key!);\n    } catch {\n      // noop\n    }\n    this.nzTreeService.setSelectedNode(this.nzTreeNode);\n    this.draggingKey = this.nzTreeNode.key;\n    const eventNext = this.nzTreeService.formatEvent('dragstart', this.nzTreeNode, e);\n    this.nzOnDragStart.emit(eventNext);\n  }\n\n  handleDragEnter(e: DragEvent): void {\n    e.preventDefault();\n    // reset position\n    this.showIndicator = this.nzTreeNode.key !== this.nzTreeService.getSelectedNode()?.key;\n    this.renderIndicator(2);\n    this.ngZone.run(() => {\n      const eventNext = this.nzTreeService.formatEvent('dragenter', this.nzTreeNode, e);\n      this.nzOnDragEnter.emit(eventNext);\n    });\n  }\n\n  handleDragOver(e: DragEvent): void {\n    e.preventDefault();\n    const dropPosition = this.nzTreeService.calcDropPosition(e);\n    if (this.dragPos !== dropPosition) {\n      this.clearDragClass();\n      this.renderIndicator(dropPosition);\n      // leaf node will pass\n      if (!(this.dragPos === 0 && this.isLeaf)) {\n        this.renderer.addClass(this.el, this.dragPosClass[this.dragPos]);\n        this.renderer.addClass(this.el, 'drop-target');\n      }\n    }\n    const eventNext = this.nzTreeService.formatEvent('dragover', this.nzTreeNode, e);\n    this.nzOnDragOver.emit(eventNext);\n  }\n\n  handleDragLeave(e: DragEvent): void {\n    e.preventDefault();\n    this.renderIndicator(2);\n    this.clearDragClass();\n    const eventNext = this.nzTreeService.formatEvent('dragleave', this.nzTreeNode, e);\n    this.nzOnDragLeave.emit(eventNext);\n  }\n\n  handleDragDrop(e: DragEvent): void {\n    e.preventDefault();\n    e.stopPropagation();\n    this.ngZone.run(() => {\n      this.showIndicator = false;\n      this.clearDragClass();\n      const node = this.nzTreeService.getSelectedNode();\n      if (!node || (node && node.key === this.nzTreeNode.key) || (this.dragPos === 0 && this.isLeaf)) {\n        return;\n      }\n      // pass if node is leafNo\n      const dropEvent = this.nzTreeService.formatEvent('drop', this.nzTreeNode, e);\n      const dragEndEvent = this.nzTreeService.formatEvent('dragend', this.nzTreeNode, e);\n      if (this.nzBeforeDrop) {\n        this.nzBeforeDrop({\n          dragNode: this.nzTreeService.getSelectedNode()!,\n          node: this.nzTreeNode,\n          pos: this.dragPos\n        }).subscribe((canDrop: boolean) => {\n          if (canDrop) {\n            this.nzTreeService.dropAndApply(this.nzTreeNode, this.dragPos);\n          }\n          this.nzOnDrop.emit(dropEvent);\n          this.nzOnDragEnd.emit(dragEndEvent);\n        });\n      } else if (this.nzTreeNode) {\n        this.nzTreeService.dropAndApply(this.nzTreeNode, this.dragPos);\n        this.nzOnDrop.emit(dropEvent);\n      }\n    });\n  }\n\n  handleDragEnd(e: DragEvent): void {\n    e.preventDefault();\n    this.ngZone.run(() => {\n      if (!this.nzBeforeDrop) {\n        // clear dragging state\n        this.draggingKey = null;\n        const eventNext = this.nzTreeService.formatEvent('dragend', this.nzTreeNode, e);\n        this.nzOnDragEnd.emit(eventNext);\n      } else {\n        // clear dragging state\n        this.draggingKey = null;\n        this.markForCheck();\n      }\n    });\n  }\n\n  /**\n   * Listening to dragging events.\n   */\n  handDragEvent(): void {\n    if (this.nzDraggable) {\n      this.destroy$ = new Subject();\n      fromEventOutsideAngular<DragEvent>(this.el, 'dragstart')\n        .pipe(takeUntil(this.destroy$))\n        .subscribe(e => this.handleDragStart(e));\n      fromEventOutsideAngular<DragEvent>(this.el, 'dragenter')\n        .pipe(takeUntil(this.destroy$))\n        .subscribe(e => this.handleDragEnter(e));\n      fromEventOutsideAngular<DragEvent>(this.el, 'dragover')\n        .pipe(takeUntil(this.destroy$))\n        .subscribe(e => this.handleDragOver(e));\n      fromEventOutsideAngular<DragEvent>(this.el, 'dragleave')\n        .pipe(takeUntil(this.destroy$))\n        .subscribe(e => this.handleDragLeave(e));\n      fromEventOutsideAngular<DragEvent>(this.el, 'drop')\n        .pipe(takeUntil(this.destroy$))\n        .subscribe(e => this.handleDragDrop(e));\n      fromEventOutsideAngular<DragEvent>(this.el, 'dragend')\n        .pipe(takeUntil(this.destroy$))\n        .subscribe(e => this.handleDragEnd(e));\n    } else {\n      this.destroy$.next();\n      this.destroy$.complete();\n    }\n  }\n\n  markForCheck(): void {\n    this.cdr.markForCheck();\n  }\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      this.destroy$.next();\n      this.destroy$.complete();\n    });\n  }\n\n  ngOnInit(): void {\n    this.nzTreeNode.component = this;\n\n    fromEventOutsideAngular(this.el, 'mousedown')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(event => {\n        if (this.nzSelectMode) {\n          event.preventDefault();\n        }\n      });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzDraggable } = changes;\n    if (nzDraggable) {\n      this.handDragEvent();\n    }\n  }\n\n  private renderIndicator(dropPosition: number): void {\n    this.ngZone.run(() => {\n      this.showIndicator = dropPosition !== 2;\n      if (this.nzTreeNode.key === this.nzTreeService.getSelectedNode()?.key || (dropPosition === 0 && this.isLeaf)) {\n        return;\n      }\n      this.dragPos = dropPosition;\n      this.cdr.markForCheck();\n    });\n  }\n}\n"
  },
  {
    "path": "components/tree/tree.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { CdkFixedSizeVirtualScroll, CdkVirtualForOf, CdkVirtualScrollViewport } from '@angular/cdk/scrolling';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ContentChild,\n  EventEmitter,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  SimpleChanges,\n  TemplateRef,\n  ViewChild,\n  booleanAttribute,\n  forwardRef,\n  inject,\n  DestroyRef\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { Observable } from 'rxjs';\n\nimport { NzAnimationTreeCollapseDirective, NzAnimationTreeCollapseService } from 'ng-zorro-antd/core/animation';\nimport { NzConfigKey, WithConfig } from 'ng-zorro-antd/core/config';\nimport {\n  NzFormatBeforeDropEvent,\n  NzFormatEmitEvent,\n  NzTreeBase,\n  NzTreeBaseService,\n  NzTreeHigherOrderServiceToken,\n  NzTreeNode,\n  NzTreeNodeKey,\n  NzTreeNodeOptions,\n  flattenTreeData\n} from 'ng-zorro-antd/core/tree';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzTreeNodeBuiltinComponent } from './tree-node.component';\nimport { NzTreeService } from './tree.service';\n\nexport function NzTreeServiceFactory(): NzTreeBaseService {\n  const higherOrderService = inject(NzTreeHigherOrderServiceToken, { skipSelf: true, optional: true });\n  const treeService = inject(NzTreeService);\n  return higherOrderService ?? treeService;\n}\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'tree';\n\n@Component({\n  selector: 'nz-tree',\n  exportAs: 'nzTree',\n  template: `\n    <div>\n      <input [style]=\"HIDDEN_STYLE\" />\n    </div>\n    <div class=\"ant-tree-treenode\" [style]=\"HIDDEN_NODE_STYLE\">\n      <div class=\"ant-tree-indent\">\n        <div class=\"ant-tree-indent-unit\"></div>\n      </div>\n    </div>\n    <div class=\"ant-tree-list\" [class.ant-select-tree-list]=\"nzSelectMode\" style=\"position: relative\">\n      @if (nzVirtualHeight) {\n        <cdk-virtual-scroll-viewport\n          [class.ant-select-tree-list-holder-inner]=\"nzSelectMode\"\n          [class.ant-tree-list-holder-inner]=\"!nzSelectMode\"\n          [itemSize]=\"nzVirtualItemSize\"\n          [minBufferPx]=\"nzVirtualMinBufferPx\"\n          [maxBufferPx]=\"nzVirtualMaxBufferPx\"\n          [style.height]=\"nzVirtualHeight\"\n        >\n          <ng-container *cdkVirtualFor=\"let node of nzFlattenNodes; trackBy: trackByFlattenNode\">\n            <nz-tree-node\n              builtin\n              [icon]=\"node.icon\"\n              [title]=\"node.title\"\n              [isLoading]=\"node.isLoading\"\n              [isSelected]=\"node.isSelected\"\n              [isDisabled]=\"node.isDisabled\"\n              [isMatched]=\"node.isMatched\"\n              [isExpanded]=\"node.isExpanded\"\n              [isLeaf]=\"node.isLeaf\"\n              [isStart]=\"node.isStart ?? []\"\n              [isEnd]=\"node.isEnd ?? []\"\n              [isChecked]=\"node.isChecked\"\n              [isHalfChecked]=\"node.isHalfChecked\"\n              [isDisableCheckbox]=\"node.isDisableCheckbox\"\n              [isSelectable]=\"node.isSelectable\"\n              [canHide]=\"node.canHide\"\n              [nzTreeNode]=\"node\"\n              [nzSelectMode]=\"nzSelectMode\"\n              [nzShowLine]=\"nzShowLine\"\n              [nzExpandedIcon]=\"nzExpandedIcon\"\n              [nzDraggable]=\"nzDraggable\"\n              [nzCheckable]=\"nzCheckable\"\n              [nzShowExpand]=\"nzShowExpand\"\n              [nzAsyncData]=\"nzAsyncData\"\n              [nzSearchValue]=\"nzSearchValue\"\n              [nzHideUnMatched]=\"nzHideUnMatched\"\n              [nzBeforeDrop]=\"nzBeforeDrop\"\n              [nzShowIcon]=\"nzShowIcon\"\n              [nzTreeTemplate]=\"nzTreeTemplate || nzTreeTemplateChild\"\n              (nzExpandChange)=\"eventTriggerChanged($event)\"\n              (nzClick)=\"eventTriggerChanged($event)\"\n              (nzDblClick)=\"eventTriggerChanged($event)\"\n              (nzContextMenu)=\"eventTriggerChanged($event)\"\n              (nzCheckboxChange)=\"eventTriggerChanged($event)\"\n              (nzOnDragStart)=\"eventTriggerChanged($event)\"\n              (nzOnDragEnter)=\"eventTriggerChanged($event)\"\n              (nzOnDragOver)=\"eventTriggerChanged($event)\"\n              (nzOnDragLeave)=\"eventTriggerChanged($event)\"\n              (nzOnDragEnd)=\"eventTriggerChanged($event)\"\n              (nzOnDrop)=\"eventTriggerChanged($event)\"\n            />\n          </ng-container>\n        </cdk-virtual-scroll-viewport>\n      } @else {\n        <div\n          [class.ant-select-tree-list-holder-inner]=\"nzSelectMode\"\n          [class.ant-tree-list-holder-inner]=\"!nzSelectMode\"\n        >\n          @for (node of nzFlattenNodes; track trackByFlattenNode($index, node)) {\n            <nz-tree-node\n              builtin\n              animation-tree-collapse\n              [icon]=\"node.icon\"\n              [title]=\"node.title\"\n              [isLoading]=\"node.isLoading\"\n              [isSelected]=\"node.isSelected\"\n              [isDisabled]=\"node.isDisabled\"\n              [isMatched]=\"node.isMatched\"\n              [isExpanded]=\"node.isExpanded\"\n              [isLeaf]=\"node.isLeaf\"\n              [isStart]=\"node.isStart ?? []\"\n              [isEnd]=\"node.isEnd ?? []\"\n              [isChecked]=\"node.isChecked\"\n              [isHalfChecked]=\"node.isHalfChecked\"\n              [isDisableCheckbox]=\"node.isDisableCheckbox\"\n              [isSelectable]=\"node.isSelectable\"\n              [canHide]=\"node.canHide\"\n              [nzTreeNode]=\"node\"\n              [nzSelectMode]=\"nzSelectMode\"\n              [nzShowLine]=\"nzShowLine\"\n              [nzExpandedIcon]=\"nzExpandedIcon\"\n              [nzDraggable]=\"nzDraggable\"\n              [nzCheckable]=\"nzCheckable\"\n              [nzShowExpand]=\"nzShowExpand\"\n              [nzAsyncData]=\"nzAsyncData\"\n              [nzSearchValue]=\"nzSearchValue\"\n              [nzHideUnMatched]=\"nzHideUnMatched\"\n              [nzBeforeDrop]=\"nzBeforeDrop\"\n              [nzShowIcon]=\"nzShowIcon\"\n              [nzTreeTemplate]=\"nzTreeTemplate || nzTreeTemplateChild\"\n              (nzExpandChange)=\"eventTriggerChanged($event)\"\n              (nzClick)=\"eventTriggerChanged($event)\"\n              (nzDblClick)=\"eventTriggerChanged($event)\"\n              (nzContextMenu)=\"eventTriggerChanged($event)\"\n              (nzCheckboxChange)=\"eventTriggerChanged($event)\"\n              (nzOnDragStart)=\"eventTriggerChanged($event)\"\n              (nzOnDragEnter)=\"eventTriggerChanged($event)\"\n              (nzOnDragOver)=\"eventTriggerChanged($event)\"\n              (nzOnDragLeave)=\"eventTriggerChanged($event)\"\n              (nzOnDragEnd)=\"eventTriggerChanged($event)\"\n              (nzOnDrop)=\"eventTriggerChanged($event)\"\n            />\n          }\n        </div>\n      }\n    </div>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  providers: [\n    NzTreeService,\n    NzAnimationTreeCollapseService,\n    {\n      provide: NzTreeBaseService,\n      useFactory: NzTreeServiceFactory\n    },\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => NzTreeComponent),\n      multi: true\n    }\n  ],\n  host: {\n    '[class.ant-select-tree]': `nzSelectMode`,\n    '[class.ant-select-tree-show-line]': `nzSelectMode && nzShowLine`,\n    '[class.ant-select-tree-icon-hide]': `nzSelectMode && !nzShowIcon`,\n    '[class.ant-select-tree-block-node]': `nzSelectMode && nzBlockNode`,\n    '[class.ant-tree]': `!nzSelectMode`,\n    '[class.ant-tree-rtl]': `dir() === 'rtl'`,\n    '[class.ant-tree-show-line]': `!nzSelectMode && nzShowLine`,\n    '[class.ant-tree-icon-hide]': `!nzSelectMode && !nzShowIcon`,\n    '[class.ant-tree-block-node]': `!nzSelectMode && nzBlockNode`,\n    '[class.draggable-tree]': `nzDraggable`\n  },\n  imports: [\n    CdkVirtualScrollViewport,\n    CdkFixedSizeVirtualScroll,\n    CdkVirtualForOf,\n    NzAnimationTreeCollapseDirective,\n    NzTreeNodeBuiltinComponent\n  ]\n})\nexport class NzTreeComponent extends NzTreeBase implements OnInit, OnChanges, ControlValueAccessor {\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  protected readonly dir = inject(Directionality).valueSignal;\n  private readonly cdr = inject(ChangeDetectorRef);\n  private readonly destroyRef = inject(DestroyRef);\n\n  @Input({ transform: booleanAttribute }) @WithConfig() nzShowIcon: boolean = false;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzHideUnMatched: boolean = false;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzBlockNode: boolean = false;\n  @Input({ transform: booleanAttribute }) nzExpandAll = false;\n  @Input({ transform: booleanAttribute }) nzSelectMode = false;\n  @Input({ transform: booleanAttribute }) nzCheckStrictly = false;\n  @Input({ transform: booleanAttribute }) nzShowExpand: boolean = true;\n  @Input({ transform: booleanAttribute }) nzShowLine = false;\n  @Input({ transform: booleanAttribute }) nzCheckable = false;\n  @Input({ transform: booleanAttribute }) nzAsyncData = false;\n  @Input({ transform: booleanAttribute }) nzDraggable: boolean = false;\n  @Input({ transform: booleanAttribute }) nzMultiple = false;\n  @Input() nzExpandedIcon?: TemplateRef<{ $implicit: NzTreeNode; origin: NzTreeNodeOptions }>;\n  @Input() nzVirtualItemSize = 28;\n  @Input() nzVirtualMaxBufferPx = 500;\n  @Input() nzVirtualMinBufferPx = 28;\n  @Input() nzVirtualHeight: string | null = null;\n  @Input() nzTreeTemplate?: TemplateRef<{ $implicit: NzTreeNode; origin: NzTreeNodeOptions }>;\n  @Input() nzBeforeDrop?: (confirm: NzFormatBeforeDropEvent) => Observable<boolean>;\n  @Input() nzData: NzTreeNodeOptions[] | NzTreeNode[] = [];\n  @Input() nzExpandedKeys: NzTreeNodeKey[] = [];\n  @Input() nzSelectedKeys: NzTreeNodeKey[] = [];\n  @Input() nzCheckedKeys: NzTreeNodeKey[] = [];\n  @Input() nzSearchValue: string = '';\n  @Input() nzSearchFunc?: (node: NzTreeNodeOptions) => boolean;\n  @ContentChild('nzTreeTemplate', { static: true }) nzTreeTemplateChild!: TemplateRef<{\n    $implicit: NzTreeNode;\n    origin: NzTreeNodeOptions;\n  }>;\n  @ViewChild(CdkVirtualScrollViewport, { read: CdkVirtualScrollViewport })\n  cdkVirtualScrollViewport!: CdkVirtualScrollViewport;\n  nzFlattenNodes: NzTreeNode[] = [];\n\n  @Output() readonly nzExpandedKeysChange: EventEmitter<string[]> = new EventEmitter<string[]>();\n  @Output() readonly nzSelectedKeysChange: EventEmitter<string[]> = new EventEmitter<string[]>();\n  @Output() readonly nzCheckedKeysChange: EventEmitter<NzTreeNodeKey[]> = new EventEmitter<NzTreeNodeKey[]>();\n  @Output() readonly nzSearchValueChange = new EventEmitter<NzFormatEmitEvent>();\n  @Output() readonly nzClick = new EventEmitter<NzFormatEmitEvent>();\n  @Output() readonly nzDblClick = new EventEmitter<NzFormatEmitEvent>();\n  @Output() readonly nzContextMenu = new EventEmitter<NzFormatEmitEvent>();\n  @Output() readonly nzCheckboxChange = new EventEmitter<NzFormatEmitEvent>();\n  @Output() readonly nzExpandChange = new EventEmitter<NzFormatEmitEvent>();\n  @Output() readonly nzOnDragStart = new EventEmitter<NzFormatEmitEvent>();\n  @Output() readonly nzOnDragEnter = new EventEmitter<NzFormatEmitEvent>();\n  @Output() readonly nzOnDragOver = new EventEmitter<NzFormatEmitEvent>();\n  @Output() readonly nzOnDragLeave = new EventEmitter<NzFormatEmitEvent>();\n  @Output() readonly nzOnDrop = new EventEmitter<NzFormatEmitEvent>();\n  @Output() readonly nzOnDragEnd = new EventEmitter<NzFormatEmitEvent>();\n\n  HIDDEN_STYLE = {\n    width: 0,\n    height: 0,\n    display: 'flex',\n    overflow: 'hidden',\n    opacity: 0,\n    border: 0,\n    padding: 0,\n    margin: 0\n  };\n\n  HIDDEN_NODE_STYLE = {\n    position: 'absolute',\n    pointerEvents: 'none',\n    visibility: 'hidden',\n    height: 0,\n    overflow: 'hidden'\n  };\n\n  onChange: (value: NzTreeNode[]) => void = () => null;\n  onTouched: () => void = () => null;\n\n  writeValue(value: NzTreeNode[]): void {\n    this.handleNzData(value);\n  }\n\n  registerOnChange(fn: (_: NzTreeNode[]) => void): void {\n    this.onChange = fn;\n  }\n\n  registerOnTouched(fn: () => void): void {\n    this.onTouched = fn;\n  }\n\n  /**\n   * Render all properties of nzTree\n   *\n   * @param changes all changes from @Input\n   */\n  renderTreeProperties(changes: SimpleChanges): void {\n    let useDefaultExpandedKeys = false;\n    let expandAll = false;\n    const {\n      nzData,\n      nzExpandedKeys,\n      nzSelectedKeys,\n      nzCheckedKeys,\n      nzCheckStrictly,\n      nzExpandAll,\n      nzMultiple,\n      nzSearchValue\n    } = changes;\n\n    if (nzExpandAll) {\n      useDefaultExpandedKeys = true;\n      expandAll = this.nzExpandAll;\n    }\n\n    if (nzMultiple) {\n      this.nzTreeService.isMultiple = this.nzMultiple;\n    }\n\n    if (nzCheckStrictly) {\n      this.nzTreeService.isCheckStrictly = this.nzCheckStrictly;\n    }\n\n    if (nzData) {\n      this.handleNzData(this.nzData);\n    }\n\n    if (nzCheckedKeys) {\n      this.handleCheckedKeys(this.nzCheckedKeys);\n    }\n\n    if (nzCheckStrictly) {\n      this.handleCheckedKeys(null);\n    }\n\n    if (nzExpandedKeys || nzExpandAll) {\n      useDefaultExpandedKeys = true;\n      this.handleExpandedKeys(expandAll || this.nzExpandedKeys);\n    }\n\n    if (nzSelectedKeys) {\n      this.handleSelectedKeys(this.nzSelectedKeys, this.nzMultiple);\n    }\n\n    if (nzSearchValue) {\n      if (!(nzSearchValue.firstChange && !this.nzSearchValue)) {\n        useDefaultExpandedKeys = false;\n        this.handleSearchValue(nzSearchValue.currentValue, this.nzSearchFunc);\n        this.nzSearchValueChange.emit(this.nzTreeService.formatEvent('search', null, null));\n      }\n    }\n\n    // flatten data\n    const currentExpandedKeys = this.getExpandedNodeList().map(v => v.key);\n    const newExpandedKeys = useDefaultExpandedKeys ? expandAll || this.nzExpandedKeys : currentExpandedKeys;\n    this.handleFlattenNodes(this.nzTreeService.rootNodes, newExpandedKeys);\n  }\n\n  trackByFlattenNode(_: number, node: NzTreeNode): string {\n    return node.key;\n  }\n  // Deal with properties\n  /**\n   * nzData\n   *\n   * @param value\n   */\n  handleNzData(value: NzSafeAny[]): void {\n    if (Array.isArray(value)) {\n      const data = this.coerceTreeNodes(value);\n      this.nzTreeService.initTree(data);\n    }\n  }\n\n  handleFlattenNodes(data: NzTreeNode[], expandKeys: NzTreeNodeKey[] | true = []): void {\n    this.nzTreeService.flattenTreeData(data, expandKeys);\n  }\n\n  handleCheckedKeys(keys: NzTreeNodeKey[] | null): void {\n    this.nzTreeService.conductCheck(keys, this.nzCheckStrictly);\n  }\n\n  handleExpandedKeys(keys: NzTreeNodeKey[] | true = []): void {\n    this.nzTreeService.conductExpandedKeys(keys);\n  }\n\n  handleSelectedKeys(keys: NzTreeNodeKey[], isMulti: boolean): void {\n    this.nzTreeService.conductSelectedKeys(keys, isMulti);\n  }\n\n  handleSearchValue(value: string, searchFunc?: (node: NzTreeNodeOptions) => boolean): void {\n    const dataList = flattenTreeData(this.nzTreeService.rootNodes, true).map(v => v.data);\n    const checkIfMatched = (node: NzTreeNode): boolean => {\n      if (searchFunc) {\n        return searchFunc(node.origin);\n      }\n      return !!value && node.title.toLowerCase().includes(value.toLowerCase());\n    };\n    dataList.forEach(v => {\n      v.isMatched = checkIfMatched(v);\n      v.canHide = !v.isMatched;\n      if (!v.isMatched) {\n        v.setExpanded(false);\n        this.nzTreeService.setExpandedNodeList(v);\n      } else {\n        // expand\n        this.nzTreeService.expandNodeAllParentBySearch(v);\n      }\n      this.nzTreeService.setMatchedNodeList(v);\n    });\n  }\n\n  /**\n   * Handle emit event\n   *\n   * @param event\n   * handle each event\n   */\n  eventTriggerChanged(event: NzFormatEmitEvent): void {\n    const node = event.node!;\n    switch (event.eventName) {\n      case 'expand':\n        this.renderTree();\n        this.nzExpandChange.emit(event);\n        break;\n      case 'click':\n        this.nzClick.emit(event);\n        break;\n      case 'dblclick':\n        this.nzDblClick.emit(event);\n        break;\n      case 'contextmenu':\n        this.nzContextMenu.emit(event);\n        break;\n      case 'check': {\n        // Render checked state with nodes' property `isChecked`\n        this.nzTreeService.setCheckedNodeList(node);\n        if (!this.nzCheckStrictly) {\n          this.nzTreeService.conduct(node);\n        }\n        // Cause check method will rerender list, so we need recover it and next the new event to user\n        const eventNext = this.nzTreeService.formatEvent('check', node, event.event!);\n        this.nzCheckboxChange.emit(eventNext);\n        const checkedKeys = this.nzTreeService.getCheckedNodeKeys();\n        this.nzCheckedKeysChange.emit(checkedKeys);\n        break;\n      }\n      case 'dragstart':\n        // if node is expanded\n        if (node.isExpanded) {\n          node.setExpanded(!node.isExpanded);\n          this.renderTree();\n        }\n        this.nzOnDragStart.emit(event);\n        break;\n      case 'dragenter': {\n        const selectedNode = this.nzTreeService.getSelectedNode();\n        if (selectedNode && selectedNode.key !== node.key && !node.isExpanded && !node.isLeaf) {\n          node.setExpanded(true);\n          this.renderTree();\n        }\n        this.nzOnDragEnter.emit(event);\n        break;\n      }\n      case 'dragover':\n        this.nzOnDragOver.emit(event);\n        break;\n      case 'dragleave':\n        this.nzOnDragLeave.emit(event);\n        break;\n      case 'dragend':\n        this.nzOnDragEnd.emit(event);\n        break;\n      case 'drop':\n        this.renderTree();\n        this.nzOnDrop.emit(event);\n        break;\n    }\n  }\n\n  /**\n   * Click expand icon\n   */\n  renderTree(): void {\n    this.handleFlattenNodes(\n      this.nzTreeService.rootNodes,\n      this.getExpandedNodeList().map(v => v.key)\n    );\n    this.cdr.markForCheck();\n  }\n\n  constructor() {\n    super(inject(NzTreeBaseService));\n  }\n\n  ngOnInit(): void {\n    this.nzTreeService.flattenNodes$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(data => {\n      this.nzFlattenNodes =\n        !!this.nzVirtualHeight && this.nzHideUnMatched && this.nzSearchValue?.length > 0\n          ? data.filter(d => !d.canHide)\n          : data;\n      this.cdr.markForCheck();\n    });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    this.renderTreeProperties(changes);\n  }\n}\n"
  },
  {
    "path": "components/tree/tree.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzTreeDropIndicatorComponent } from './tree-drop-indicator.component';\nimport { NzTreeIndentComponent } from './tree-indent.component';\nimport { NzTreeNodeBuiltinCheckboxComponent } from './tree-node-checkbox.component';\nimport { NzTreeNodeSwitcherComponent } from './tree-node-switcher.component';\nimport { NzTreeNodeTitleComponent } from './tree-node-title.component';\nimport { NzTreeNodeBuiltinComponent } from './tree-node.component';\nimport { NzTreeComponent } from './tree.component';\n\n@NgModule({\n  imports: [\n    NzTreeComponent,\n    NzTreeNodeBuiltinComponent,\n    NzTreeIndentComponent,\n    NzTreeNodeSwitcherComponent,\n    NzTreeNodeBuiltinCheckboxComponent,\n    NzTreeNodeTitleComponent,\n    NzTreeDropIndicatorComponent\n  ],\n\n  exports: [NzTreeComponent, NzTreeNodeBuiltinComponent, NzTreeIndentComponent]\n})\nexport class NzTreeModule {}\n"
  },
  {
    "path": "components/tree/tree.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Injectable } from '@angular/core';\n\nimport { NzTreeBaseService } from 'ng-zorro-antd/core/tree';\n\n@Injectable()\nexport class NzTreeService extends NzTreeBaseService {}\n"
  },
  {
    "path": "components/tree/tree.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ApplicationRef, Component, provideZoneChangeDetection, TemplateRef, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\nimport { Observable, of } from 'rxjs';\n\nimport { dispatchMouseEvent, dispatchTouchEvent } from 'ng-zorro-antd/core/testing';\nimport { NzFormatEmitEvent, NzTreeNode, NzTreeNodeOptions } from 'ng-zorro-antd/core/tree';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzTreeComponent } from './tree.component';\nimport { NzTreeModule } from './tree.module';\n\ndescribe('tree', () => {\n  beforeEach(() => {\n    // todo: use zoneless\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideNoopAnimations(), provideZoneChangeDetection()]\n    });\n  });\n\n  describe('controlled', () => {\n    let fixture: ComponentFixture<NzTestTreeBasicControlledComponent>;\n    let component: NzTestTreeBasicControlledComponent;\n    let nativeElement: Element;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTreeBasicControlledComponent);\n      component = fixture.componentInstance;\n      nativeElement = fixture.debugElement.nativeElement;\n      fixture.detectChanges();\n    });\n\n    describe('basic tree under default value', () => {\n      it('basic initial data', () => {\n        const shownNodes = nativeElement.querySelectorAll('nz-tree-node[builtin]');\n        const enableCheckbox = nativeElement.querySelectorAll('.ant-tree-checkbox');\n        expect(shownNodes.length).toEqual(3);\n        expect(enableCheckbox.length).toEqual(3);\n      });\n\n      it('should initialize properly', () => {\n        const shownNodes = nativeElement.querySelectorAll('nz-tree-node[builtin]');\n        const enableCheckbox = nativeElement.querySelectorAll('.ant-tree-checkbox');\n        expect(shownNodes.length).toEqual(3);\n        expect(enableCheckbox.length).toEqual(3);\n      });\n\n      it('should expand the specified node based on nzExpandedKeys', fakeAsync(() => {\n        component.defaultExpandedKeys = ['0-1'];\n        fixture.detectChanges();\n        const shownNodes = nativeElement.querySelectorAll('nz-tree-node[builtin]');\n        expect(shownNodes.length).toEqual(4);\n        tick(300);\n        fixture.detectChanges();\n        // leaf node should not be included\n        expect(component.treeComponent.getExpandedNodeList().length).toEqual(1);\n      }));\n\n      it('should expand all nodes while setting nzExpandAll', fakeAsync(() => {\n        component.expandAll = true;\n        fixture.detectChanges();\n        const shownNodes = nativeElement.querySelectorAll('nz-tree-node[builtin]');\n        expect(shownNodes.length).toEqual(7);\n        tick(300);\n        fixture.detectChanges();\n        // leaf node should not be included\n        expect(component.treeComponent.getExpandedNodeList().length).toEqual(4);\n      }));\n\n      it('should render checkbox state of nodes based on nzCheckedKeys', fakeAsync(() => {\n        component.expandAll = true; // Just for testing the selected state\n        component.defaultCheckedKeys = ['0-0-0', '0-0-1'];\n        fixture.detectChanges();\n        const checkedNodes = nativeElement.querySelectorAll('.ant-tree-checkbox-checked');\n        const halfCheckedNodes = nativeElement.querySelectorAll('.ant-tree-checkbox-indeterminate');\n        expect(checkedNodes.length).toEqual(2);\n        expect(halfCheckedNodes.length).toEqual(1);\n        tick(300);\n        fixture.detectChanges();\n        expect(component.treeComponent.getCheckedNodeList().length).toEqual(2);\n        expect(component.treeComponent.getHalfCheckedNodeList().length).toEqual(1);\n      }));\n\n      it('node check should not affect other nodes based on nzCheckStrictly', fakeAsync(() => {\n        component.expandAll = true;\n        component.checkStrictly = true;\n        component.defaultCheckedKeys = ['0-0-0', '0-0-1'];\n        fixture.detectChanges();\n        const checkedNodes = nativeElement.querySelectorAll('.ant-tree-checkbox-checked');\n        const halfCheckedNodes = nativeElement.querySelectorAll('.ant-tree-checkbox-indeterminate');\n        expect(checkedNodes.length).toEqual(2);\n        expect(halfCheckedNodes.length).toEqual(0);\n        tick(300);\n        fixture.detectChanges();\n        expect(component.treeComponent.getCheckedNodeList().length).toEqual(2);\n        expect(component.treeComponent.getHalfCheckedNodeList().length).toEqual(0);\n      }));\n\n      it('should select nodes based on nzSelectedKeys', fakeAsync(() => {\n        component.defaultSelectedKeys = ['0-0', '0-1'];\n        fixture.detectChanges();\n        // nzMultiple is true\n        const selectedNodes = nativeElement.querySelectorAll('.ant-tree-node-selected');\n        expect(selectedNodes.length).toEqual(2);\n        tick(300);\n        fixture.detectChanges();\n        expect(component.treeComponent.getSelectedNodeList().length).toEqual(2);\n      }));\n\n      it('should select only one nodes based on nzMultiple:false', fakeAsync(() => {\n        component.multiple = false;\n        component.defaultSelectedKeys = ['0-0', '0-1'];\n        fixture.detectChanges();\n        // nzMultiple is false\n        const selectedNodes = nativeElement.querySelectorAll('.ant-tree-node-selected');\n        expect(selectedNodes.length).toEqual(1);\n        tick(300);\n        fixture.detectChanges();\n        expect(component.treeComponent.getSelectedNodeList().length).toEqual(1);\n      }));\n\n      it('should match nodes based on nzSearchValue', fakeAsync(() => {\n        component.searchValue = '0-0-1';\n        fixture.detectChanges();\n        // will expand 0-0 only\n        const expandedNodes = nativeElement.querySelectorAll('.ant-tree-switcher_open');\n        const matchedNodes = nativeElement.querySelectorAll('.font-highlight');\n        expect(expandedNodes.length).toEqual(1);\n        expect(matchedNodes.length).toEqual(1);\n        tick(300);\n        fixture.detectChanges();\n        expect(component.treeComponent.getMatchedNodeList().length).toEqual(1);\n      }));\n\n      [\n        {\n          title:\n            \"should display 7 nodes when hideUnMatched=false and virtualHeight = undefined and nzSearchValue = '0-1'\",\n          when: { hideUnMatched: false, searchValue: '0-1' },\n          then: { matchedNodeList: 3, nzFlattenNodes: 7 }\n        },\n        {\n          title:\n            \"should display 7 nodes when hideUnMatched=false and virtualHeight = '300px' and nzSearchValue = '0-1'\",\n          when: { hideUnMatched: false, virtualHeight: '300px', searchValue: '0-1' },\n          then: { matchedNodeList: 3, nzFlattenNodes: 7 }\n        },\n        {\n          title:\n            \"'should display 7 nodes when hideUnMatched=true and virtualHeight = undefined and nzSearchValue = '0-1'\",\n          when: { hideUnMatched: true, searchValue: '0-1' },\n          then: { matchedNodeList: 3, nzFlattenNodes: 7 }\n        },\n        {\n          title:\n            \"should display 4 matched nodes based on nzSearchValue when hideUnMatched=true and virtualHeight = '300px' and nzSearchValue = undefined\",\n          when: { hideUnMatched: true, virtualHeight: '300px' },\n          then: { matchedNodeList: 0, nzFlattenNodes: 3 }\n        },\n        {\n          title:\n            \"should display 4 matched nodes based on nzSearchValue when hideUnMatched=true and virtualHeight = '300px' and nzSearchValue = ''\",\n          when: { hideUnMatched: true, virtualHeight: '300px', searchValue: '' },\n          then: { matchedNodeList: 0, nzFlattenNodes: 3 }\n        },\n        {\n          title:\n            \"should display 4 matched nodes based on nzSearchValue when hideUnMatched=true and virtualHeight = '300px' and nzSearchValue = '0-1'\",\n          when: { hideUnMatched: true, virtualHeight: '300px', searchValue: '0-1' },\n          then: { matchedNodeList: 3, nzFlattenNodes: 4 }\n        }\n      ].forEach(({ title, when, then }) => {\n        it(\n          title,\n          fakeAsync(() => {\n            // Given\n            component.searchValue = when.searchValue ?? '';\n            component.virtualHeight = when.virtualHeight ?? null;\n            component.hideUnMatched = when.hideUnMatched;\n            // When\n            fixture.detectChanges();\n            tick(300);\n            fixture.detectChanges();\n            // Then\n            expect(component.treeComponent.getMatchedNodeList().length)\n              .withContext('treeComponent.getMatchedNodeList().length')\n              .toBe(then.matchedNodeList);\n            expect(component.treeComponent.nzFlattenNodes.length)\n              .withContext('treeComponent.nzFlattenNodes.length')\n              .toBe(then.nzFlattenNodes);\n            expect(nativeElement.querySelectorAll('nz-tree-node').length)\n              .withContext('number of displayed nz-tree-node elements')\n              .toBe(then.nzFlattenNodes);\n          })\n        );\n      });\n\n      it('should match nodes based on nzSearchFunc', fakeAsync(() => {\n        component.searchFunc = (data: NzTreeNodeOptions): boolean => data.title === component.searchValue;\n        component.searchValue = '0-0';\n        fixture.detectChanges();\n        let expandedNodes = nativeElement.querySelectorAll('.ant-tree-switcher_open');\n        let matchedNodes = nativeElement.querySelectorAll('.font-highlight');\n        expect(expandedNodes.length).toEqual(0);\n        expect(matchedNodes.length).toEqual(1);\n        tick(300);\n        fixture.detectChanges();\n        expect(component.treeComponent.getMatchedNodeList().length).toEqual(1);\n\n        component.searchValue = '0-0-';\n        fixture.detectChanges();\n        expandedNodes = nativeElement.querySelectorAll('.ant-tree-switcher_open');\n        matchedNodes = nativeElement.querySelectorAll('.font-highlight');\n        expect(expandedNodes.length).toEqual(0);\n        expect(matchedNodes.length).toEqual(0);\n      }));\n\n      it('should keep parent expanded state of matched nodes based on nzHideUnMatched', fakeAsync(() => {\n        component.hideUnMatched = true;\n        fixture.detectChanges();\n        component.searchValue = '0-0-1';\n        fixture.detectChanges();\n        // will expand 0-0 but not matched\n        const node = nativeElement.querySelector('.ant-tree-switcher')!;\n        dispatchMouseEvent(node, 'click');\n        fixture.detectChanges();\n        tick();\n        fixture.detectChanges();\n        // 0-1 0-2 hidden, others are not shown because not expanded\n        const hiddenNodes = nativeElement.querySelectorAll('nz-tree-node[builtin][style*=\"display: none;\"]');\n        expect(hiddenNodes.length).toEqual(2);\n      }));\n\n      describe('change detection behavior', () => {\n        it('should not run change detection when the `nz-tree-node` is clicked', () => {\n          component.selectMode = true;\n          fixture.detectChanges();\n\n          const appRef = TestBed.inject(ApplicationRef);\n          const event = new MouseEvent('mousedown');\n\n          spyOn(appRef, 'tick');\n          spyOn(event, 'preventDefault').and.callThrough();\n\n          const treeNode = nativeElement.querySelector('nz-tree-node')!;\n          treeNode.dispatchEvent(event);\n\n          expect(appRef.tick).not.toHaveBeenCalled();\n          expect(event.preventDefault).toHaveBeenCalled();\n        });\n      });\n    });\n\n    describe('basic style of tree', () => {\n      it('should render tree with line based on nzShowLine', () => {\n        component.showLine = true;\n        fixture.detectChanges();\n        const lineTreeIcon = nativeElement.querySelectorAll('.anticon-plus-square');\n        expect(lineTreeIcon.length).toEqual(2); // one is leaf node\n      });\n\n      it('should show custom icon based on nzExpandedIcon', () => {\n        const button = nativeElement.querySelector('button')!;\n        button.click();\n        fixture.detectChanges();\n\n        const customIconElement = nativeElement.querySelectorAll('.ant-tree-switcher .anticon-smile');\n        // shown nodes are same with `basic initial data`\n        expect(customIconElement.length).toEqual(2);\n      });\n\n      it('should not trigger checkbox if node is disabled ', () => {\n        const spy = spyOn(component, 'nzEvent');\n        component.nodes = [\n          {\n            title: '0-0',\n            key: '0-0',\n            disableCheckbox: true,\n            disabled: true\n          }\n        ];\n        fixture.detectChanges();\n        const node = nativeElement.querySelector('.ant-tree-checkbox') as HTMLElement;\n        dispatchMouseEvent(node, 'click');\n        expect(spy).not.toHaveBeenCalled();\n      });\n\n      it('should should custom icon', () => {\n        component.nodes = [\n          {\n            title: '0-0',\n            key: '0-0',\n            icon: 'smile'\n          }\n        ];\n        fixture.detectChanges();\n        const node = nativeElement.querySelector('.ant-tree-icon__customize .anticon-smile') as HTMLElement;\n        expect(node).toBeDefined();\n      });\n\n      it('should should show loading icon', () => {\n        component.nodes = [\n          {\n            title: '0-0',\n            key: '0-0'\n          }\n        ];\n        component.asyncData = true;\n        fixture.detectChanges();\n        const targetNode = nativeElement.querySelector('.ant-tree-switcher') as HTMLElement;\n        dispatchMouseEvent(targetNode, 'click');\n        fixture.detectChanges();\n        expect(nativeElement.querySelectorAll('.ant-tree-treenode-loading').length).toEqual(1);\n        expect(component.treeComponent.getExpandedNodeList().length).toEqual(1);\n\n        component.treeComponent.getExpandedNodeList()[0].addChildren([\n          {\n            title: 'Child Node',\n            key: `0-0`\n          }\n        ]);\n        fixture.detectChanges();\n        expect(nativeElement.querySelectorAll('.ant-tree-treenode-loading').length).toEqual(0);\n        expect(fixture.componentInstance.treeComponent.getExpandedNodeList().length).toEqual(1);\n      });\n    });\n\n    describe('mouse event trigger', () => {\n      it('should select node when clicking', fakeAsync(() => {\n        const spy = spyOn(component, 'nzEvent');\n        expect(spy).not.toHaveBeenCalled();\n\n        // get first node 0-0\n        const node = nativeElement.querySelector('.ant-tree-node-content-wrapper')!;\n        dispatchMouseEvent(node, 'click');\n        fixture.detectChanges();\n        expect(spy).toHaveBeenCalledTimes(1);\n        expect(nativeElement.querySelector('.ant-tree-node-content-wrapper.ant-tree-node-selected')).toBeDefined();\n        tick(300);\n        fixture.detectChanges();\n        expect(component.treeComponent.getSelectedNodeList().length).toEqual(1);\n      }));\n\n      it('should expand node when clicking switcher', fakeAsync(() => {\n        const spy = spyOn(component, 'nzEvent');\n        // get first node 0-0\n        const node = nativeElement.querySelector('.ant-tree-switcher')!;\n        dispatchMouseEvent(node, 'click');\n        fixture.detectChanges();\n        expect(spy).toHaveBeenCalledTimes(1);\n        expect(nativeElement.querySelector('.ant-tree-switcher.ant-tree-switcher_open')).toBeDefined();\n        tick(300);\n        fixture.detectChanges();\n        expect(component.treeComponent.getExpandedNodeList().length).toEqual(1);\n      }));\n\n      it('should check node when clicking checkbox', fakeAsync(() => {\n        const spy = spyOn(component, 'nzEvent');\n        // get first node 0-0\n        const node = nativeElement.querySelector('.ant-tree-checkbox')!;\n        dispatchMouseEvent(node, 'click');\n        fixture.detectChanges();\n        expect(spy).toHaveBeenCalledTimes(1);\n        expect(nativeElement.querySelector('.ant-tree-checkbox.ant-tree-checkbox-checked')).toBeDefined();\n        tick(300);\n        fixture.detectChanges();\n        expect(component.treeComponent.getCheckedNodeList().length).toEqual(1);\n      }));\n\n      it('should trigger contextmenu event', fakeAsync(() => {\n        const spy = spyOn(component, 'nzEvent');\n        // get first node 0-0\n        const node = nativeElement.querySelector('.ant-tree-node-content-wrapper')!;\n        dispatchMouseEvent(node, 'contextmenu');\n        fixture.detectChanges();\n        expect(spy).toHaveBeenCalledTimes(1);\n      }));\n\n      it('should trigger dblclick event', fakeAsync(() => {\n        const spy = spyOn(component, 'nzEvent');\n        // get first node 0-0\n        const node = nativeElement.querySelector('.ant-tree-node-content-wrapper')!;\n        dispatchMouseEvent(node, 'dblclick');\n        fixture.detectChanges();\n        // Maybe needs to change\n        // In actual user behavior, click event may be triggered twice\n        expect(spy).toHaveBeenCalledTimes(1);\n      }));\n    });\n  });\n\n  describe('dnd', () => {\n    let fixture: ComponentFixture<NzTestTreeDraggableComponent>;\n    let component: NzTestTreeDraggableComponent;\n    let nativeElement: Element;\n\n    let dragStartSpy: jasmine.Spy;\n    let dragEnterSpy: jasmine.Spy;\n    let dragOverSpy: jasmine.Spy;\n    let dragLeaveSpy: jasmine.Spy;\n    let dropSpy: jasmine.Spy;\n    let dragEndSpy: jasmine.Spy;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTreeDraggableComponent);\n      component = fixture.componentInstance;\n      nativeElement = fixture.debugElement.nativeElement;\n\n      dragStartSpy = spyOn(component, 'onDragStart').and.callThrough();\n      dragEnterSpy = spyOn(component, 'onDragEnter').and.callThrough();\n      dragOverSpy = spyOn(component, 'onDragOver').and.callThrough();\n      dragLeaveSpy = spyOn(component, 'onDragLeave').and.callThrough();\n      dropSpy = spyOn(component, 'onDrop').and.callThrough();\n      dragEndSpy = spyOn(component, 'onDragEnd').and.callThrough();\n      fixture.detectChanges();\n    });\n\n    describe('drag event trigger', () => {\n      it('should trigger dragstart event', fakeAsync(() => {\n        // dragstart needs to collapse expanded node\n        component.defaultExpandedKeys = ['0-1'];\n        fixture.detectChanges();\n        let expandedNodes = nativeElement.querySelectorAll('.ant-tree-switcher_open');\n        expect(expandedNodes.length).toEqual(1);\n        const dragNode = nativeElement.querySelector(\"[title='0-1']\") as HTMLElement;\n        dispatchMouseEvent(dragNode, 'dragstart');\n        fixture.detectChanges();\n        expandedNodes = nativeElement.querySelectorAll('.ant-tree-switcher_open');\n        expect(expandedNodes.length).toEqual(0);\n      }));\n\n      // fixture.detectChanges() will stop event\n      it('should trigger drag event', fakeAsync(() => {\n        const dragNode = nativeElement.querySelector(\"[title='0-2']\") as HTMLElement;\n        const dropNode = nativeElement.querySelector(\"[title='0-0']\") as HTMLElement;\n        const passedNode = nativeElement.querySelector(\"[title='0-1']\") as HTMLElement;\n        //  ============ dragstart ==============\n        dispatchMouseEvent(dragNode, 'dragstart');\n        fixture.detectChanges();\n        expect(dragStartSpy).toHaveBeenCalledTimes(1);\n        let shownNodes = nativeElement.querySelectorAll('nz-tree-node[builtin]');\n        expect(shownNodes.length).toEqual(3);\n\n        //  ============ dragenter ==============\n        // DragNode enters one node, if it is not expanded, should expand it(0-1) and render tree again\n        // Do not do `fixture.detectChanges()` after dragenter, because it will stop dragover\n        dispatchMouseEvent(passedNode, 'dragenter');\n        dispatchMouseEvent(passedNode, 'dragover');\n\n        // ======= enter check, expand passing nodes ========\n        expect(dragEnterSpy).toHaveBeenCalledTimes(1);\n        expect(dragOverSpy).toHaveBeenCalledTimes(1);\n\n        //  ============ dragleave ==============\n        dispatchMouseEvent(passedNode, 'dragleave');\n        expect(dragLeaveSpy).toHaveBeenCalledTimes(1);\n\n        //  ============ drop ==============\n        // drop 0-2 to 0-0\n        dispatchMouseEvent(dropNode, 'dragenter');\n        dispatchMouseEvent(dropNode, 'drop');\n        dispatchMouseEvent(dropNode, 'dragend');\n\n        expect(dropSpy).toHaveBeenCalledTimes(1);\n        expect(dragEndSpy).toHaveBeenCalledTimes(1);\n        fixture.detectChanges();\n\n        // dragenter expands 0-1/0-1\n        shownNodes = nativeElement.querySelectorAll('nz-tree-node[builtin]');\n        expect(shownNodes.length).toEqual(7);\n      }));\n\n      xit('should trigger drag over event', fakeAsync(() => {\n        //  ============ over with different position in next test ==============\n        /**\n         * nzTreeService#calcDropPosition\n         * if (clientY <= top + des) {\n         *   return -1;\n         * } else if (clientY >= bottom - des) {\n         *   return 1;\n         * }\n         * return 0;\n         */\n\n        let elementNode;\n        const dragNode = nativeElement.querySelector(\"[title='0-2']\") as HTMLElement; // sixth node\n        const passedNode = nativeElement.querySelector(\"[title='0-1']\") as HTMLElement; // fifth node\n        //  ============ dragstart ==============\n        dispatchMouseEvent(dragNode, 'dragstart');\n        fixture.detectChanges();\n        let shownNodes = nativeElement.querySelectorAll('nz-tree-node[builtin]');\n        expect(shownNodes.length).toEqual(3);\n\n        //  ============ dragenter ==============\n        // DragNode enters one node, if it is not expanded, should expand it(0-1) and render tree again\n        // Do not do `fixture.detectChanges()` after dragenter, because it will stop dragover\n        dispatchMouseEvent(passedNode, 'dragenter');\n\n        // =========== dragover with different position ===========\n        // Each node's height with 24px + 4px padding, use getBoundingClientRect to get target node position\n        // drag-over-gap-top\n        const { x, y } = passedNode.getBoundingClientRect();\n        dispatchMouseEvent(passedNode, 'dragover', x + 50, y - 6);\n        elementNode = nativeElement.querySelector('nz-tree-node[builtin]:nth-child(2)') as HTMLElement;\n        expect(elementNode.classList).toContain('drag-over-gap-top');\n        tick(150);\n        // drag-over\n        dispatchMouseEvent(passedNode, 'dragover', x + 50, y + 12);\n        elementNode = nativeElement.querySelector('nz-tree-node[builtin]:nth-child(2)') as HTMLElement;\n        expect(elementNode.classList).toContain('drag-over');\n        tick(150);\n        // drag-over-gap-bottom\n        dispatchMouseEvent(passedNode, 'dragover', x + 50, y + 18);\n        elementNode = nativeElement.querySelector('nz-tree-node[builtin]:nth-child(2)') as HTMLElement;\n        expect(elementNode.classList).toContain('drag-over-gap-bottom');\n        tick(150);\n        // ======= enter check, expand passing nodes ========\n        expect(dragEnterSpy).toHaveBeenCalledTimes(1);\n        expect(dragOverSpy).toHaveBeenCalledTimes(3);\n        fixture.detectChanges();\n        shownNodes = nativeElement.querySelectorAll('nz-tree-node[builtin]');\n        expect(shownNodes.length).toEqual(4);\n      }));\n\n      it('should drop as nzBeforeDrop', fakeAsync(() => {\n        const dragNode = nativeElement.querySelector(\"[title='0-2']\") as HTMLElement;\n        const dropNode = nativeElement.querySelector(\"[title='0-0']\") as HTMLElement;\n        component.beforeDrop = (): Observable<boolean> => of(true);\n        fixture.detectChanges();\n        expect(\n          (nativeElement.querySelector(\"[title='0-2']\") as HTMLElement).querySelector('.ant-tree-indent')\n        ).toBeNull();\n        dispatchTouchEvent(dragNode, 'dragstart');\n        dispatchTouchEvent(dropNode, 'dragenter');\n        dispatchTouchEvent(dropNode, 'dragover');\n        // drop 0-2 to 0-0\n        dispatchTouchEvent(dropNode, 'drop');\n        tick(300);\n        fixture.detectChanges();\n        expect(\n          (nativeElement.querySelector(\"[title='0-2']\") as HTMLElement).querySelector('.ant-tree-indent')\n        ).toBeDefined();\n      }));\n\n      it('should nzBlockNode work', fakeAsync(() => {\n        const treeElement = nativeElement.querySelector('.ant-tree') as HTMLElement;\n        expect(treeElement.classList).toContain('ant-tree-block-node');\n      }));\n    });\n  });\n\n  describe('search', () => {\n    let fixture: ComponentFixture<NzTestTreeBasicSearchComponent>;\n    let component: NzTestTreeBasicSearchComponent;\n    let nativeElement: Element;\n\n    const getVisibleNodes = (title?: string): Element[] => {\n      const isNodeVisible = (el: Element): boolean => el.getClientRects().length !== 0;\n      const selector = title ? `[title='${title}']` : '[title]';\n      const nodes = nativeElement.querySelectorAll(selector);\n      return Array.from(nodes).filter(isNodeVisible);\n    };\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTreeBasicSearchComponent);\n      component = fixture.componentInstance;\n      nativeElement = fixture.debugElement.nativeElement;\n    });\n\n    describe('search case-insensitive', () => {\n      it('should list matches independent on casing', fakeAsync(() => {\n        fixture.detectChanges();\n        expect(getVisibleNodes().length).toEqual(3);\n\n        component.searchValue = 'foo';\n        fixture.detectChanges();\n        expect(getVisibleNodes().length).toEqual(2);\n        expect(getVisibleNodes('Foo').length).toEqual(1);\n        expect(getVisibleNodes('foo').length).toEqual(1);\n\n        component.searchValue = 'Foo';\n        fixture.detectChanges();\n        expect(getVisibleNodes().length).toEqual(2);\n        expect(getVisibleNodes('Foo').length).toEqual(1);\n        expect(getVisibleNodes('foo').length).toEqual(1);\n\n        component.searchValue = 'baz';\n        fixture.detectChanges();\n        expect(getVisibleNodes().length).toEqual(2);\n        expect(getVisibleNodes('Foo').length).toEqual(1);\n        expect(getVisibleNodes('Baz Bar').length).toEqual(1);\n      }));\n    });\n\n    describe('highlight case-insensitive', () => {\n      it('should highlight matched node', fakeAsync(() => {\n        fixture.detectChanges();\n        expect(getVisibleNodes().length).toEqual(3);\n\n        component.searchValue = 'baz';\n        fixture.detectChanges();\n        expect(getVisibleNodes().length).toEqual(2);\n        expect(getVisibleNodes('Foo').length).toEqual(1);\n        expect(getVisibleNodes('Baz Bar').length).toEqual(1);\n        const highlightedNode = getVisibleNodes('Baz Bar')[0].querySelector('.font-highlight');\n        expect(highlightedNode?.textContent).toEqual('Baz');\n      }));\n    });\n  });\n});\n\n@Component({\n  imports: [NzIconModule, NzTreeModule],\n  template: `\n    <button (click)=\"changeIcon(expandedIconTpl)\">Custom expand icon</button>\n    <nz-tree\n      #treeComponent\n      [nzData]=\"nodes\"\n      nzShowIcon\n      [nzCheckable]=\"true\"\n      [nzShowLine]=\"showLine\"\n      [nzCheckStrictly]=\"checkStrictly\"\n      [nzCheckedKeys]=\"defaultCheckedKeys\"\n      [nzExpandedKeys]=\"defaultExpandedKeys\"\n      [nzSelectedKeys]=\"defaultSelectedKeys\"\n      [nzMultiple]=\"multiple\"\n      [nzSearchValue]=\"searchValue\"\n      [nzSearchFunc]=\"searchFunc\"\n      [nzVirtualHeight]=\"virtualHeight\"\n      [nzHideUnMatched]=\"hideUnMatched\"\n      [nzExpandAll]=\"expandAll\"\n      [nzExpandedIcon]=\"expandedIcon\"\n      [nzAsyncData]=\"asyncData\"\n      [nzSelectMode]=\"selectMode\"\n      (nzSearchValueChange)=\"nzEvent($event)\"\n      (nzClick)=\"nzEvent($event)\"\n      (nzDblClick)=\"nzEvent($event)\"\n      (nzContextMenu)=\"nzEvent($event)\"\n      (nzExpandChange)=\"nzEvent($event)\"\n      (nzCheckboxChange)=\"nzEvent($event)\"\n    />\n    <ng-template #expandedIconTpl let-node>\n      <nz-icon nzType=\"smile\" class=\"ant-tree-switcher-icon\" />\n    </ng-template>\n  `\n})\nexport class NzTestTreeBasicControlledComponent {\n  @ViewChild('treeComponent', { static: true }) treeComponent!: NzTreeComponent;\n  searchValue: string = '';\n  multiple = true;\n  expandAll = false;\n  asyncData = false;\n  selectMode = false;\n  checkStrictly = false;\n  showLine = false;\n  defaultCheckedKeys: string[] = [];\n  defaultSelectedKeys: string[] = [];\n  defaultExpandedKeys: string[] = [];\n  expandedIcon?: TemplateRef<{ $implicit: NzTreeNode; origin: NzTreeNodeOptions }>;\n  searchFunc?: (node: NzTreeNodeOptions) => boolean;\n  virtualHeight: string | null = null;\n  hideUnMatched = false;\n  nodes: NzTreeNodeOptions[] | NzTreeNode[] = [\n    {\n      title: '0-0',\n      key: '0-0',\n      children: [\n        {\n          title: '0-0-0',\n          key: '0-0-0'\n        },\n        {\n          title: '0-0-1',\n          key: '0-0-1'\n        },\n        {\n          title: '0-0-2',\n          key: '0-0-2',\n          isLeaf: true\n        }\n      ]\n    },\n    {\n      title: '0-1',\n      key: '0-1',\n      children: [{ title: '0-1-0-0', key: '0-1-0-0', isLeaf: true }]\n    },\n    {\n      title: '0-2',\n      key: '0-2',\n      disabled: true,\n      isLeaf: true\n    }\n  ];\n\n  nzEvent(_data: NzFormatEmitEvent): void {}\n\n  // Just for testing\n  changeIcon(template: TemplateRef<{ $implicit: NzTreeNode; origin: NzTreeNodeOptions }>): void {\n    this.expandedIcon = template;\n  }\n}\n\n@Component({\n  imports: [NzTreeModule],\n  template: `\n    <nz-tree\n      nzBlockNode\n      [nzData]=\"nodes\"\n      nzDraggable\n      [nzExpandedKeys]=\"defaultExpandedKeys\"\n      [nzBeforeDrop]=\"beforeDrop\"\n      (nzOnDragStart)=\"onDragStart()\"\n      (nzOnDragEnter)=\"onDragEnter()\"\n      (nzOnDragLeave)=\"onDragLeave()\"\n      (nzOnDragOver)=\"onDragOver()\"\n      (nzOnDrop)=\"onDrop()\"\n      (nzOnDragEnd)=\"onDragEnd()\"\n    />\n  `\n})\nexport class NzTestTreeDraggableComponent {\n  @ViewChild(NzTreeComponent, { static: true }) treeComponent!: NzTreeComponent;\n  defaultExpandedKeys: string[] = [];\n  nodes: NzTreeNodeOptions[] | NzTreeNode[] = [\n    {\n      title: '0-0',\n      key: '0-0',\n      children: [\n        {\n          title: '0-0-0',\n          key: '0-0-0'\n        },\n        {\n          title: '0-0-1',\n          key: '0-0-1'\n        },\n        {\n          title: '0-0-2',\n          key: '0-0-2',\n          isLeaf: true\n        }\n      ]\n    },\n    {\n      title: '0-1',\n      key: '0-1',\n      children: [{ title: '0-1-0-0', key: '0-1-0-0', isLeaf: true }]\n    },\n    {\n      title: '0-2',\n      key: '0-2',\n      disabled: true,\n      isLeaf: true\n    }\n  ];\n  beforeDrop?: () => Observable<boolean>;\n\n  onDragStart(): void {}\n\n  onDragEnter(): void {}\n\n  onDragOver(): void {}\n\n  onDragLeave(): void {}\n\n  onDrop(): void {}\n\n  onDragEnd(): void {}\n}\n\n@Component({\n  imports: [NzTreeModule],\n  template: `\n    <nz-tree\n      [nzData]=\"nodes\"\n      [nzSearchValue]=\"searchValue\"\n      [nzExpandAll]=\"expandAll\"\n      [nzAsyncData]=\"asyncData\"\n      [nzHideUnMatched]=\"hideUnMatched\"\n    />\n  `\n})\nexport class NzTestTreeBasicSearchComponent {\n  @ViewChild(NzTreeComponent, { static: true }) treeComponent!: NzTreeComponent;\n  searchValue!: string;\n  expandAll = true;\n  asyncData = false;\n  hideUnMatched = true;\n  nodes: NzTreeNodeOptions[] | NzTreeNode[] = [\n    {\n      title: 'Foo',\n      key: '0-1',\n      children: [{ title: 'Baz Bar', key: '0-1-0', isLeaf: true }]\n    },\n    {\n      title: 'foo',\n      key: '0-2',\n      isLeaf: true\n    }\n  ];\n}\n"
  },
  {
    "path": "components/tree-select/demo/async.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 异步数据加载\n  en-US: Load data asynchronously\n---\n\n## zh-CN\n\n点击展开节点，动态加载数据，直到执行 addChildren() 方法取消加载状态。\n\n## en-US\n\nTo load data asynchronously when click to expand a treeNode, loading state keeps until excute addChildren().\n"
  },
  {
    "path": "components/tree-select/demo/async.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzFormatEmitEvent, NzTreeNodeOptions } from 'ng-zorro-antd/tree';\nimport { NzTreeSelectModule } from 'ng-zorro-antd/tree-select';\n\n@Component({\n  selector: 'nz-demo-tree-select-async',\n  imports: [FormsModule, NzTreeSelectModule],\n  template: `\n    <nz-tree-select\n      style=\"width: 250px\"\n      nzPlaceHolder=\"Please select\"\n      [nzExpandedKeys]=\"expandKeys\"\n      [(ngModel)]=\"value\"\n      [nzDropdownMatchSelectWidth]=\"true\"\n      [nzDropdownStyle]=\"{ 'max-height': '300px' }\"\n      [nzNodes]=\"nodes\"\n      [nzAsyncData]=\"true\"\n      (nzExpandChange)=\"onExpandChange($event)\"\n    />\n  `\n})\nexport class NzDemoTreeSelectAsyncComponent {\n  expandKeys = ['0-0'];\n  value?: string;\n  readonly nodes = [\n    {\n      title: 'Node1',\n      value: '0-0',\n      key: '0-0',\n      children: [\n        {\n          title: 'Child Node1',\n          value: '0-0-1',\n          key: '0-0-1'\n        },\n        {\n          title: 'Child Node2',\n          value: '0-0-2',\n          key: '0-0-2'\n        }\n      ]\n    },\n    {\n      title: 'Node2',\n      value: '0-1',\n      key: '0-1'\n    }\n  ];\n\n  onExpandChange(e: NzFormatEmitEvent): void {\n    const node = e.node;\n    if (node && node.getChildren().length === 0 && node.isExpanded) {\n      this.loadNode().then(data => {\n        node.addChildren(data);\n      });\n    }\n  }\n\n  loadNode(): Promise<NzTreeNodeOptions[]> {\n    return new Promise(resolve => {\n      setTimeout(\n        () =>\n          resolve([\n            { title: 'Child Node', key: `${new Date().getTime()}-0` },\n            { title: 'Child Node', key: `${new Date().getTime()}-1` }\n          ]),\n        1000\n      );\n    });\n  }\n}\n"
  },
  {
    "path": "components/tree-select/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n最简单的用法。\n\n## en-US\n\nThe most basic usage.\n"
  },
  {
    "path": "components/tree-select/demo/basic.ts",
    "content": "import { Component, OnInit } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzTreeSelectModule } from 'ng-zorro-antd/tree-select';\n\n@Component({\n  selector: 'nz-demo-tree-select-basic',\n  imports: [FormsModule, NzTreeSelectModule],\n  template: `\n    <nz-tree-select\n      style=\"width: 250px\"\n      [nzExpandedKeys]=\"expandKeys\"\n      [nzNodes]=\"nodes\"\n      nzShowSearch\n      nzPlaceHolder=\"Please select\"\n      [(ngModel)]=\"value\"\n      (ngModelChange)=\"onChange($event)\"\n    />\n  `\n})\nexport class NzDemoTreeSelectBasicComponent implements OnInit {\n  expandKeys = ['100', '1001'];\n  value?: string;\n  readonly nodes = [\n    {\n      title: 'parent 1',\n      key: '100',\n      children: [\n        {\n          title: 'parent 1-0',\n          key: '1001',\n          children: [\n            { title: 'leaf 1-0-0', key: '10010', isLeaf: true },\n            { title: 'leaf 1-0-1', key: '10011', isLeaf: true }\n          ]\n        },\n        {\n          title: 'parent 1-1',\n          key: '1002',\n          children: [{ title: 'leaf 1-1-0', key: '10020', isLeaf: true }]\n        }\n      ]\n    }\n  ];\n\n  onChange($event: string): void {\n    console.log($event);\n  }\n\n  ngOnInit(): void {\n    // mock async\n    setTimeout(() => {\n      this.value = '1001';\n    }, 1000);\n  }\n}\n"
  },
  {
    "path": "components/tree-select/demo/checkable.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 可勾选\n  en-US: Checkable\n---\n\n## zh-CN\n\n使用勾选框实现多选功能。\n\n## en-US\n\nMultiple and checkable.\n"
  },
  {
    "path": "components/tree-select/demo/checkable.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzTreeSelectModule } from 'ng-zorro-antd/tree-select';\n\n@Component({\n  selector: 'nz-demo-tree-select-checkable',\n  imports: [FormsModule, NzTreeSelectModule],\n  template: `\n    <nz-tree-select\n      style=\"width: 250px\"\n      [(ngModel)]=\"value\"\n      [nzNodes]=\"nodes\"\n      (ngModelChange)=\"onChange($event)\"\n      nzShowSearch\n      nzCheckable\n      nzPlaceHolder=\"Please select\"\n    />\n  `\n})\nexport class NzDemoTreeSelectCheckableComponent {\n  value: string[] = ['0-0-0'];\n  readonly nodes = [\n    {\n      title: 'Node1',\n      value: '0-0',\n      key: '0-0',\n      children: [\n        {\n          title: 'Child Node1',\n          value: '0-0-0',\n          key: '0-0-0',\n          isLeaf: true\n        }\n      ]\n    },\n    {\n      title: 'Node2',\n      value: '0-1',\n      key: '0-1',\n      children: [\n        {\n          title: 'Child Node3',\n          value: '0-1-0',\n          key: '0-1-0',\n          isLeaf: true\n        },\n        {\n          title: 'Child Node4',\n          value: '0-1-1',\n          key: '0-1-1',\n          isLeaf: true\n        },\n        {\n          title: 'Child Node5',\n          value: '0-1-2',\n          key: '0-1-2',\n          isLeaf: true\n        }\n      ]\n    }\n  ];\n\n  onChange($event: string[]): void {\n    console.log($event);\n  }\n}\n"
  },
  {
    "path": "components/tree-select/demo/customized-icon.md",
    "content": "---\norder: 4\ndebug: true\ntitle:\n  zh-CN: 自定义图标\n  en-US: Customize Icon\n---\n\n## zh-CN\n\n可以针对不同节点采用样式覆盖的方式定制图标。\n\n## en-US\n\nYou can customize icons for different nodes.\n"
  },
  {
    "path": "components/tree-select/demo/customized-icon.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzTreeSelectModule } from 'ng-zorro-antd/tree-select';\n\n@Component({\n  selector: 'nz-demo-tree-select-customized-icon',\n  imports: [FormsModule, NzIconModule, NzTreeSelectModule],\n  template: `\n    <nz-tree-select\n      style=\"width: 250px\"\n      [(ngModel)]=\"value\"\n      [nzNodes]=\"nodes\"\n      nzPlaceHolder=\"Please select\"\n      nzShowIcon\n    />\n    <br />\n    <nz-tree-select\n      style=\"width: 250px; margin-top: 20px;\"\n      [(ngModel)]=\"value\"\n      [nzNodes]=\"nodes\"\n      nzPlaceHolder=\"Please select\"\n    >\n      <ng-template #nzTreeTemplate let-node>\n        <span class=\"ant-tree-node-content-wrapper\" [class.ant-tree-node-selected]=\"node.isSelected\">\n          <span>\n            <nz-icon [nzType]=\"node.isExpanded ? 'folder-open' : 'folder'\" />\n            {{ node.title }}\n          </span>\n        </span>\n      </ng-template>\n    </nz-tree-select>\n  `\n})\nexport class NzDemoTreeSelectCustomizedIconComponent {\n  value?: string;\n  readonly nodes = [\n    {\n      title: 'parent 1',\n      key: '100',\n      expanded: true,\n      icon: 'smile',\n      children: [\n        { title: 'leaf 1-0-0', key: '10010', icon: 'meh', isLeaf: true },\n        { title: 'leaf 1-0-1', key: '10011', icon: 'frown', isLeaf: true }\n      ]\n    }\n  ];\n}\n"
  },
  {
    "path": "components/tree-select/demo/multiple.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 多选\n  en-US: Multiple Selection\n---\n\n## zh-CN\n\n多选的树选择，例子中通过 `nzMaxTagCount` 限制最多显示3个选项。\n\n## en-US\n\nMultiple selection usage, max 3 option will display at the same time by `nzMaxTagCount`.\n"
  },
  {
    "path": "components/tree-select/demo/multiple.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzTreeSelectModule } from 'ng-zorro-antd/tree-select';\n\n@Component({\n  selector: 'nz-demo-tree-select-multiple',\n  imports: [FormsModule, NzTreeSelectModule],\n  template: `\n    <nz-tree-select\n      style=\"width: 250px\"\n      nzPlaceHolder=\"Please select\"\n      [(ngModel)]=\"value\"\n      [nzMaxTagCount]=\"3\"\n      [nzMaxTagPlaceholder]=\"omittedPlaceHolder\"\n      [nzNodes]=\"nodes\"\n      nzDefaultExpandAll\n      nzMultiple\n      (ngModelChange)=\"onChange($event)\"\n    />\n    <ng-template #omittedPlaceHolder let-omittedValues>and {{ omittedValues.length }} more...</ng-template>\n  `\n})\nexport class NzDemoTreeSelectMultipleComponent {\n  value: string[] = [];\n  readonly nodes = [\n    {\n      title: 'parent 1',\n      key: '100',\n      children: [\n        {\n          title: 'parent 1-0',\n          key: '1001',\n          children: [\n            { title: 'leaf 1-0-0', key: '10010', isLeaf: true },\n            { title: 'leaf 1-0-1', key: '10011', isLeaf: true }\n          ]\n        },\n        {\n          title: 'parent 1-1',\n          key: '1002',\n          children: [{ title: 'leaf 1-1-0', key: '10020', isLeaf: true }]\n        }\n      ]\n    }\n  ];\n\n  onChange($event: string[]): void {\n    console.log($event);\n  }\n}\n"
  },
  {
    "path": "components/tree-select/demo/no-data.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 自定义空状态\n  en-US: Custom empty state\n---\n\n## zh-CN\n\n使用 `nzNotFoundContent` 自定义空数据状态\n\n## en-US\n\nUse `nzNotFoundContent` to customize empty data style\n"
  },
  {
    "path": "components/tree-select/demo/no-data.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzSpinModule } from 'ng-zorro-antd/spin';\nimport { NzTreeSelectModule } from 'ng-zorro-antd/tree-select';\n\n@Component({\n  selector: 'nz-demo-tree-select-no-data',\n  imports: [NzSpinModule, NzTreeSelectModule],\n  template: `\n    <nz-tree-select style=\"width: 250px\" [nzNodes]=\"[]\" nzPlaceHolder=\"Please select\" [nzNotFoundContent]=\"noData\" />\n    <ng-template #noData>\n      <div style=\"height: 200px; display: flex; justify-content: center; align-items: center\">\n        <nz-spin nzSimple />\n      </div>\n    </ng-template>\n  `\n})\nexport class NzDemoTreeSelectNoDataComponent {}\n"
  },
  {
    "path": "components/tree-select/demo/placement.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 位置\n  en-US: Placement\n---\n\n## zh-CN\n\n可以通过 `nzPlacement` 手动指定弹出的位置。\n\n## en-US\n\nYou can manually specify the position of the popup via `nzPlacement`.\n"
  },
  {
    "path": "components/tree-select/demo/placement.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzRadioModule } from 'ng-zorro-antd/radio';\nimport { NzTreeSelectModule, NzPlacementType } from 'ng-zorro-antd/tree-select';\n\n@Component({\n  selector: 'nz-demo-tree-select-placement',\n  imports: [FormsModule, NzRadioModule, NzTreeSelectModule],\n  template: `\n    <nz-radio-group [(ngModel)]=\"placement\">\n      @for (item of list; track item) {\n        <label nz-radio-button [nzValue]=\"item\">{{ item }}</label>\n      }\n    </nz-radio-group>\n    <br />\n    <br />\n    <nz-tree-select\n      nzPlaceHolder=\"Please select\"\n      [nzPlacement]=\"placement\"\n      [(ngModel)]=\"value\"\n      [nzNodes]=\"nodes\"\n      [nzDropdownStyle]=\"{ width: '300px' }\"\n      nzDefaultExpandAll\n      (ngModelChange)=\"onChange($event)\"\n    />\n  `\n})\nexport class NzDemoTreeSelectPlacementComponent {\n  list: NzPlacementType[] = ['topLeft', 'topRight', 'bottomLeft', 'bottomRight'];\n  placement: NzPlacementType = 'topLeft';\n  value: string[] = [];\n  readonly nodes = [\n    {\n      title: 'parent 1',\n      key: '100',\n      children: [\n        {\n          title: 'parent 1-0',\n          key: '1001',\n          children: [\n            { title: 'leaf 1-0-0', key: '10010', isLeaf: true },\n            { title: 'leaf 1-0-1', key: '10011', isLeaf: true }\n          ]\n        },\n        {\n          title: 'parent 1-1',\n          key: '1002',\n          children: [{ title: 'leaf 1-1-0', key: '10020', isLeaf: true }]\n        }\n      ]\n    }\n  ];\n\n  onChange($event: string[]): void {\n    console.log($event);\n  }\n}\n"
  },
  {
    "path": "components/tree-select/demo/prefix-and-suffix.md",
    "content": "---\norder: 12\ntitle:\n  zh-CN: 前后缀\n  en-US: Prefix and Suffix\n---\n\n## zh-CN\n\n自定义前缀 `nzPrefix` 和后缀图标 `nzSuffixIcon`。\n\n## en-US\n\nCustom `nzPrefix` and `nzSuffixIcon`.\n"
  },
  {
    "path": "components/tree-select/demo/prefix-and-suffix.ts",
    "content": "import { Component, model } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzTreeSelectModule } from 'ng-zorro-antd/tree-select';\n\n@Component({\n  selector: 'nz-demo-tree-select-prefix-and-suffix',\n  imports: [FormsModule, NzTreeSelectModule],\n  template: `\n    <nz-tree-select [nzNodes]=\"nodes\" nzSuffixIcon=\"smile\" [(ngModel)]=\"value\" nzDefaultExpandAll />\n    <br />\n    <br />\n    <nz-tree-select [nzNodes]=\"nodes\" nzPrefix=\"Prefix\" [(ngModel)]=\"value\" nzDefaultExpandAll />\n  `,\n  styles: `\n    nz-tree-select {\n      width: 100%;\n    }\n  `\n})\nexport class NzDemoTreeSelectPrefixAndSuffixComponent {\n  readonly value = model();\n  readonly nodes = [\n    {\n      title: 'parent 1',\n      key: '100',\n      children: [\n        {\n          title: 'parent 1-0',\n          key: '1001',\n          children: [\n            { title: 'leaf 1-0-0', key: '10010', isLeaf: true },\n            { title: 'leaf 1-0-1', key: '10011', isLeaf: true }\n          ]\n        },\n        {\n          title: 'parent 1-1',\n          key: '1002',\n          children: [{ title: 'leaf 1-1-0', key: '10020', isLeaf: true }]\n        }\n      ]\n    }\n  ];\n}\n"
  },
  {
    "path": "components/tree-select/demo/status.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 自定义状态\n  en-US: Status\n---\n\n## zh-CN\n\n使用 `nzStatus` 为 `TreeSelect` 添加状态，可选 `error` 或者 `warning`。\n\n## en-US\n\nAdd status to TreeSelect with `nzStatus`, which could be `error` or `warning`.\n"
  },
  {
    "path": "components/tree-select/demo/status.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTreeSelectModule } from 'ng-zorro-antd/tree-select';\n\n@Component({\n  selector: 'nz-demo-tree-select-status',\n  imports: [NzTreeSelectModule],\n  template: `\n    <nz-tree-select [nzNodes]=\"[]\" nzStatus=\"error\" nzPlaceHolder=\"Error\" style=\"width:100%;\" />\n    <br />\n    <br />\n    <nz-tree-select\n      nzMultiple\n      [nzNodes]=\"[]\"\n      nzShowSearch\n      nzStatus=\"warning\"\n      nzPlaceHolder=\"Warning multiple\"\n      style=\"width:100%;\"\n    />\n  `\n})\nexport class NzDemoTreeSelectStatusComponent {}\n"
  },
  {
    "path": "components/tree-select/demo/variant.md",
    "content": "---\norder: 10\nversion: 20.0.0\ntitle:\n  zh-CN: 形态变体\n  en-US: Variants\n---\n\n## zh-CN\n\nTreeSelect 形态变体，可选 `outlined`、`filled`、`borderless`、`underlined` 四种形态。\n\n## en-US\n\nVariants of TreeSelect, there are four variants: `outlined`, `filled`, `borderless` and `underlined`.\n"
  },
  {
    "path": "components/tree-select/demo/variant.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzFlexDirective } from 'ng-zorro-antd/flex';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\nimport { NzTreeSelectModule } from 'ng-zorro-antd/tree-select';\n\n@Component({\n  selector: 'nz-demo-tree-select-variant',\n  imports: [FormsModule, NzTreeSelectModule, NzFlexDirective, NzSpaceModule],\n  template: `\n    <div nz-flex nzGap=\"large\">\n      <nz-space nzDirection=\"vertical\" style=\"flex: 1\">\n        <nz-tree-select\n          *nzSpaceItem\n          style=\"width: 100%\"\n          [nzNodes]=\"nodes\"\n          nzVariant=\"outlined\"\n          [ngModel]=\"defaultValue\"\n          nzDefaultExpandAll\n        />\n        <nz-tree-select\n          *nzSpaceItem\n          style=\"width: 100%\"\n          [nzNodes]=\"nodes\"\n          nzVariant=\"filled\"\n          [ngModel]=\"defaultValue\"\n          nzDefaultExpandAll\n        />\n        <nz-tree-select\n          *nzSpaceItem\n          style=\"width: 100%\"\n          [nzNodes]=\"nodes\"\n          nzVariant=\"borderless\"\n          [ngModel]=\"defaultValue\"\n          nzDefaultExpandAll\n        />\n        <nz-tree-select\n          *nzSpaceItem\n          style=\"width: 100%\"\n          [nzNodes]=\"nodes\"\n          nzVariant=\"underlined\"\n          [ngModel]=\"defaultValue\"\n          nzDefaultExpandAll\n        />\n      </nz-space>\n      <nz-space nzDirection=\"vertical\" style=\"flex: 1\">\n        <nz-tree-select\n          *nzSpaceItem\n          style=\"width: 100%\"\n          nzVariant=\"outlined\"\n          [nzNodes]=\"nodes\"\n          [nzMaxTagCount]=\"3\"\n          nzMultiple\n          [ngModel]=\"defaultValue\"\n          nzDefaultExpandAll\n        />\n        <nz-tree-select\n          *nzSpaceItem\n          style=\"width: 100%\"\n          nzVariant=\"filled\"\n          [nzNodes]=\"nodes\"\n          [nzMaxTagCount]=\"3\"\n          nzMultiple\n          [ngModel]=\"defaultValue\"\n          nzDefaultExpandAll\n        />\n        <nz-tree-select\n          *nzSpaceItem\n          style=\"width: 100%\"\n          nzVariant=\"borderless\"\n          [nzNodes]=\"nodes\"\n          [nzMaxTagCount]=\"3\"\n          nzMultiple\n          [ngModel]=\"defaultValue\"\n          nzDefaultExpandAll\n        />\n        <nz-tree-select\n          *nzSpaceItem\n          style=\"width: 100%\"\n          nzVariant=\"underlined\"\n          [nzNodes]=\"nodes\"\n          [nzMaxTagCount]=\"3\"\n          nzMultiple\n          [ngModel]=\"defaultValue\"\n          nzDefaultExpandAll\n        />\n      </nz-space>\n    </div>\n  `\n})\nexport class NzDemoTreeSelectVariantComponent {\n  readonly defaultValue = '100';\n  readonly nodes = [\n    {\n      title: 'parent 1',\n      key: '100',\n      children: [\n        {\n          title: 'parent 1-0',\n          key: '1001',\n          children: [\n            { title: 'leaf 1-0-0', key: '10010', isLeaf: true },\n            { title: 'leaf 1-0-1', key: '10011', isLeaf: true }\n          ]\n        },\n        {\n          title: 'parent 1-1',\n          key: '1002',\n          children: [{ title: 'leaf 1-1-0', key: '10020', isLeaf: true }]\n        }\n      ]\n    }\n  ];\n}\n"
  },
  {
    "path": "components/tree-select/demo/virtual-scroll.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 虚拟滚动\n  en-US: Virtual Scroll\n---\n\n## zh-CN\n\n设定 `nzVirtualHeight` 开启虚拟滚动。\n\n## en-US\n\nSet `nzVirtualHeight` to enable virtual scroll.\n"
  },
  {
    "path": "components/tree-select/demo/virtual-scroll.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTreeNodeOptions } from 'ng-zorro-antd/tree';\nimport { NzTreeSelectModule } from 'ng-zorro-antd/tree-select';\n\nfunction dig(path = '0', level = 3): NzTreeNodeOptions[] {\n  const list: NzTreeNodeOptions[] = [];\n  for (let i = 0; i < 10; i += 1) {\n    const key = `${path}-${i}`;\n    const treeNode: NzTreeNodeOptions = {\n      title: key,\n      key,\n      expanded: true,\n      children: [],\n      isLeaf: false\n    };\n\n    if (level > 0) {\n      treeNode.children = dig(key, level - 1);\n    } else {\n      treeNode.isLeaf = true;\n    }\n\n    list.push(treeNode);\n  }\n  return list;\n}\n\n@Component({\n  selector: 'nz-demo-tree-select-virtual-scroll',\n  imports: [NzTreeSelectModule],\n  template: `\n    <nz-tree-select\n      style=\"width: 250px\"\n      [nzNodes]=\"nodes\"\n      nzShowSearch\n      nzPlaceHolder=\"Please select\"\n      nzVirtualHeight=\"300px\"\n      nzHideUnMatched=\"true\"\n    />\n  `\n})\nexport class NzDemoTreeSelectVirtualScrollComponent {\n  nodes: NzTreeNodeOptions[] = dig();\n}\n"
  },
  {
    "path": "components/tree-select/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Entry\ntitle: TreeSelect\ncover: 'https://gw.alipayobjects.com/zos/alicdn/Ax4DA0njr/TreeSelect.svg'\ndescription: Tree selection control.\n---\n\n## When To Use\n\n`TreeSelect` is similar to `Select`, but the values are provided in a tree like structure.\nAny data whose entries are defined in a hierarchical manner is fit to use this control. Examples of such case may include a corporate hierarchy, a directory structure, and so on.\n\n## API\n\n### nz-tree-select\n\n| Property                       | Description                                                                                                                                           | Type                                                       | Default                            | Global Config | Version |\n| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | ---------------------------------- | ------------- | ------- |\n| `[nzId]`                       | input id attribute inside the component                                                                                                               | `string`                                                   | -                                  |\n| `[nzAllowClear]`               | Whether allow clear                                                                                                                                   | `boolean`                                                  | `false`                            |\n| `[nzPlaceHolder]`              | Placeholder of the select input                                                                                                                       | `string`                                                   | -                                  |\n| `[nzPlacement]`                | The position where the selection box pops up                                                                                                          | `'bottomLeft' \\| 'bottomRight' \\| 'topLeft' \\| 'topRight'` | `'bottomLeft'`                     |\n| `[nzDisabled]`                 | Disabled or not                                                                                                                                       | `boolean`                                                  | `false`                            |\n| `[nzShowIcon]`                 | Shows the icon before a TreeNode's title. There is no default style                                                                                   | `boolean`                                                  | `false`                            |\n| `[nzShowSearch]`               | Whether to display a search input in the dropdown menu(valid only in the single mode)                                                                 | `boolean`                                                  | `false`                            | ✅            |\n| `[nzNotFoundContent]`          | Specify content to show when no result matches.                                                                                                       | `'string' \\| 'TemplateRef<void>'`                          | -                                  |\n| `[nzDropdownMatchSelectWidth]` | Determine whether the dropdown menu and the select input are the same width                                                                           | `boolean`                                                  | `true`                             | ✅            |\n| `[nzDropdownStyle]`            | To set the style of the dropdown menu                                                                                                                 | `object`                                                   | -                                  |\n| `[nzDropdownClassName]`        | classname of dropdown menu                                                                                                                            | `string`                                                   | -                                  |\n| `[nzMultiple]`                 | Support multiple or not, will be `true` when enable `nzCheckable`.                                                                                    | `boolean`                                                  | `false`                            |\n| `[nzHideUnMatched]`            | Hide unmatched nodes while searching                                                                                                                  | `boolean`                                                  | `false`                            | ✅            |\n| `[nzSize]`                     | To set the size of the select input                                                                                                                   | `'large' \\| 'small' \\| 'default'`                          | `'default'`                        | ✅            |\n| `[nzStatus]`                   | Set validation status                                                                                                                                 | `'error' \\| 'warning'`                                     | -                                  |               |\n| `[nzCheckable]`                | Whether to show checkbox on the treeNodes                                                                                                             | `boolean`                                                  | `false`                            |\n| `[nzCheckStrictly]`            | Check treeNode precisely; parent treeNode and children treeNodes are not associated                                                                   | `boolean`                                                  | `false`                            |\n| `[nzShowExpand]`               | Show a Expand Icon before the treeNodes                                                                                                               | `boolean`                                                  | `true`                             |               |\n| `[nzShowLine]`                 | Shows a connecting line                                                                                                                               | `boolean`                                                  | `false`                            |               |\n| `[nzPrefix]`                   | The custom prefix                                                                                                                                     | `TemplateRef<any> \\| string`                               | -                                  |               |\n| `[nzSuffixIcon]`               | The custom suffix icon                                                                                                                                | `TemplateRef<any> \\| string`                               | -                                  |               |\n| `[nzAsyncData]`                | Load data asynchronously (should be used with NzTreeNode.addChildren(...))                                                                            | `boolean`                                                  | `false`                            |\n| `[nzNodes]`                    | Data of the treeNodes                                                                                                                                 | `NzTreeNodeOptions[]`                                      | `[]`                               |\n| `[nzDefaultExpandAll]`         | Whether to expand all treeNodes by default                                                                                                            | `boolean`                                                  | `false`                            |\n| `[nzExpandedKeys]`             | Default expanded treeNodes                                                                                                                            | `string[]`                                                 | -                                  |\n| `[nzDisplayWith]`              | How to display the selected node value in the trigger                                                                                                 | `(node: NzTreeNode) => string`                             | `(node: NzTreeNode) => node.title` |\n| `[nzMaxTagCount]`              | Max tag count to show                                                                                                                                 | number                                                     | -                                  |\n| `[nzMaxTagPlaceholder]`        | Placeholder for not showing tags                                                                                                                      | TemplateRef<{ $implicit: NzTreeNode[] }>                   | -                                  |\n| `[nzTreeTemplate]`             | Custom Nodes                                                                                                                                          | `TemplateRef<{ $implicit: NzTreeNode }>`                   | -                                  |\n| `[nzVariant]`                  | Variants of TreeSelect                                                                                                                                | `'outlined' \\| 'borderless' \\| 'filled' \\| 'underlined'`   | `'outlined'`                       | ✅            | 20.0.0  |\n| `[nzVirtualHeight]`            | The height of virtual scroll                                                                                                                          | `string`                                                   | `-`                                |\n| `[nzVirtualItemSize]`          | The size of the items in the list, same as [cdk itemSize](https://material.angular.io/cdk/scrolling/api)                                              | `number`                                                   | `28`                               |\n| `[nzVirtualMaxBufferPx]`       | The number of pixels worth of buffer to render for when rendering new items, same as [cdk maxBufferPx](https://material.angular.io/cdk/scrolling/api) | `number`                                                   | `500`                              |\n| `[nzVirtualMinBufferPx]`       | The minimum amount of buffer rendered beyond the viewport (in pixels),same as [cdk minBufferPx](https://material.angular.io/cdk/scrolling/api)        | `number`                                                   | `28`                               |\n| `[nzBackdrop]`                 | whether or not the overlay should attach a backdrop                                                                                                   | `boolean`                                                  | `false`                            |\n| `(nzExpandChange)`             | Callback function for when a treeNode is expanded or collapsed                                                                                        | `EventEmitter<NzFormatEmitEvent>`                          | -                                  |\n\n#### Methods\n\n| Property                 | Description                                       | Type           |\n| ------------------------ | ------------------------------------------------- | -------------- |\n| `getTreeNodes`           | get all nodes(NzTreeNode)                         | `NzTreeNode[]` |\n| `getTreeNodeByKey`       | get NzTreeNode with key                           | `NzTreeNode`   |\n| `getCheckedNodeList`     | get checked nodes(merged)                         | `NzTreeNode[]` |\n| `getSelectedNodeList`    | get selected nodes                                | `NzTreeNode[]` |\n| `getHalfCheckedNodeList` | get half checked nodes                            | `NzTreeNode[]` |\n| `getExpandedNodeList`    | get expanded nodes                                | `NzTreeNode[]` |\n| `getMatchedNodeList`     | get matched nodes(if `nzSearchValue` is not null) | `NzTreeNode[]` |\n\n## FAQ\n\n### Q: The overlay layer element does not follow the scroll position when scrolling\n\nBy default, the overlay layer element uses body as the scroll container. If using another scroll container, add the [CdkScrollable](https://material.angular.dev/cdk/scrolling/api#CdkScrollable) directive to the custom scroll container element.\nNote: You need to import the `CdkScrollable` directive or `ScrollingModule` module from `@angular/cdk/scrolling`.\n"
  },
  {
    "path": "components/tree-select/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 树选择\ntype: 数据录入\ntitle: TreeSelect\ncover: 'https://gw.alipayobjects.com/zos/alicdn/Ax4DA0njr/TreeSelect.svg'\ndescription: 树型选择控件。\n---\n\n## 何时使用\n\n类似 Select 的选择控件，可选择的数据结构是一个树形结构时，可以使用 TreeSelect，例如公司层级、学科系统、分类目录等等。\n\n## API\n\n### nz-tree-select\n\n| 参数                           | 说明                                                                                                                 | 类型                                                       | 默认值                             | 全局配置 | 版本   |\n| ------------------------------ | -------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | ---------------------------------- | -------- | ------ |\n| `[nzId]`                       | 组件内部 input 的 id 值                                                                                              | `string`                                                   | -                                  |\n| `[nzAllowClear]`               | 显示清除按钮                                                                                                         | `boolean`                                                  | `false`                            |\n| `[nzPlaceHolder]`              | 选择框默认文字                                                                                                       | `string`                                                   | -                                  |\n| `[nzPlacement]`                | 选择框弹出的位置                                                                                                     | `'bottomLeft' \\| 'bottomRight' \\| 'topLeft' \\| 'topRight'` | `'bottomLeft'`                     |\n| `[nzDisabled]`                 | 禁用选择器                                                                                                           | `boolean`                                                  | `false`                            |\n| `[nzShowIcon]`                 | 是否展示 TreeNode title 前的图标，没有默认样式                                                                       | `boolean`                                                  | `false`                            | ✅       |\n| `[nzShowSearch]`               | 显示搜索框                                                                                                           | `boolean`                                                  | `false`                            |\n| `[nzNotFoundContent]`          | 当下拉列表为空时显示的内容                                                                                           | `'string' \\| 'TemplateRef<void>'`                          | -                                  |\n| `[nzDropdownMatchSelectWidth]` | 下拉菜单和选择器同宽                                                                                                 | `boolean`                                                  | `true`                             | ✅       |\n| `[nzDropdownStyle]`            | 下拉菜单的样式                                                                                                       | `{ [key: string]: string; }`                               | -                                  |\n| `[nzDropdownClassName]`        | 下拉菜单的 className 属性                                                                                            | `string`                                                   | -                                  |\n| `[nzMultiple]`                 | 支持多选（当设置 nzCheckable 时自动变为 true）                                                                       | `boolean`                                                  | `false`                            |\n| `[nzHideUnMatched]`            | 搜索隐藏未匹配的节点                                                                                                 | `boolean`                                                  | `false`                            | ✅       |\n| `[nzSize]`                     | 选择框大小                                                                                                           | `'large' \\| 'small' \\| 'default'`                          | `'default'`                        | ✅       |\n| `[nzStatus]`                   | 设置校验状态                                                                                                         | `'error' \\| 'warning'`                                     | -                                  |          |\n| `[nzCheckable]`                | 节点前添加 Checkbox 复选框                                                                                           | `boolean`                                                  | `false`                            |\n| `[nzCheckStrictly]`            | checkable 状态下节点选择完全受控（父子节点选中状态不再关联）                                                         | `boolean`                                                  | `false`                            |\n| `[nzShowExpand]`               | 节点前添加展开图标                                                                                                   | `boolean`                                                  | `true`                             |          |\n| `[nzShowLine]`                 | 是否展示连接线                                                                                                       | `boolean`                                                  | `false`                            |          |\n| `[nzPrefix]`                   | 自定义的选择框前缀                                                                                                   | `TemplateRef<any> \\| string`                               | -                                  |          |\n| `[nzSuffixIcon]`               | 自定义的选择框后缀图标                                                                                               | `TemplateRef<any> \\| string`                               | -                                  |          |\n| `[nzAsyncData]`                | 是否异步加载(显示加载状态)                                                                                           | `boolean`                                                  | `false`                            |\n| `[nzNodes]`                    | treeNodes 数据                                                                                                       | `NzTreeNodeOptions[]`                                      | `[]`                               |\n| `[nzDefaultExpandAll]`         | 默认展开所有树节点                                                                                                   | `boolean`                                                  | `false`                            |\n| `[nzExpandedKeys]`             | 默认展开指定的树节点                                                                                                 | `string[]`                                                 | -                                  |\n| `[nzDisplayWith]`              | 如何在输入框显示所选的节点值的方法                                                                                   | `(node: NzTreeNode) => string`                             | `(node: NzTreeNode) => node.title` |\n| `[nzMaxTagCount]`              | 最多显示多少个 tag                                                                                                   | `number`                                                   | -                                  |\n| `[nzMaxTagPlaceholder]`        | 隐藏 tag 时显示的内容                                                                                                | `TemplateRef<{ $implicit: NzTreeNode[] }>`                 | -                                  |\n| `[nzTreeTemplate]`             | 自定义节点                                                                                                           | `TemplateRef<{ $implicit: NzTreeNode }>`                   | -                                  |\n| `[nzVariant]`                  | 形态变体                                                                                                             | `'outlined' \\| 'borderless' \\| 'filled' \\| 'underlined'`   | `'outlined'`                       | ✅       | 20.0.0 |\n| `[nzVirtualHeight]`            | 虚拟滚动的总高度                                                                                                     | `string`                                                   | `-`                                |\n| `[nzVirtualItemSize]`          | 虚拟滚动时每一列的高度，与 [cdk itemSize](https://material.angular.io/cdk/scrolling/api) 相同                        | `number`                                                   | `28`                               |\n| `[nzVirtualMaxBufferPx]`       | 缓冲区最大像素高度，与 [cdk maxBufferPx](https://material.angular.io/cdk/scrolling/api) 相同                         | `number`                                                   | `500`                              |\n| `[nzVirtualMinBufferPx]`       | 缓冲区最小像素高度，低于该值时将加载新结构，与 [cdk minBufferPx](https://material.angular.io/cdk/scrolling/api) 相同 | `number`                                                   | `28`                               |\n| `[nzBackdrop]`                 | 浮层是否应带有背景板                                                                                                 | `boolean`                                                  | `false`                            |\n| `(nzExpandChange)`             | 点击展开树节点图标调用                                                                                               | `EventEmitter<NzFormatEmitEvent>`                          | -                                  |\n\n#### 方法\n\n| 方法名                   | 说明                               | 返回值         |\n| ------------------------ | ---------------------------------- | -------------- |\n| `getTreeNodes`           | 获取组件 NzTreeNode 节点           | `NzTreeNode[]` |\n| `getTreeNodeByKey`       | 按 key 获取 NzTreeNode 节点        | `NzTreeNode`   |\n| `getCheckedNodeList`     | 获取组件 checkbox 被点击选中的节点 | `NzTreeNode[]` |\n| `getSelectedNodeList`    | 获取组件被选中的节点               | `NzTreeNode[]` |\n| `getHalfCheckedNodeList` | 获取组件半选状态节点               | `NzTreeNode[]` |\n| `getExpandedNodeList`    | 获取组件展开状态节点               | `NzTreeNode[]` |\n| `getMatchedNodeList`     | 获取组搜索匹配到的节点             | `NzTreeNode[]` |\n\n## FAQ\n\n### Q：滚动时浮层元素没有跟随滚动位置\n\n默认情况下，浮层元素使用 `body` 作为滚动容器，如果使用了其他滚动容器，在自定义滚动容器元素上添加 [CdkScrollable](https://material.angular.dev/cdk/scrolling/api#CdkScrollable) 指令。\n注意：您需要从 `@angular/cdk/scrolling` 导入 `CdkScrollable` 指令或 `ScrollingModule` 模块。\n"
  },
  {
    "path": "components/tree-select/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/tree-select/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/tree-select/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './tree-select.component';\nexport * from './tree-select.module';\nexport * from './tree-select.service';\n"
  },
  {
    "path": "components/tree-select/style/entry.less",
    "content": "@import './index.less';\n// style dependencies\n// deps-lint-skip: select\n@import '../../tree/style/entry.less';\n@import '../../select/style/entry.less';\n@import '../../empty/style/entry.less';\n@import \"./patch.less\";\n"
  },
  {
    "path": "components/tree-select/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n@import '../../tree/style/mixin';\n@import '../../checkbox/style/mixin';\n\n@tree-select-prefix-cls: ~'@{ant-prefix}-tree-select';\n@select-tree-prefix-cls: ~'@{ant-prefix}-select-tree';\n\n.antCheckboxFn(@checkbox-prefix-cls: ~'@{select-tree-prefix-cls}-checkbox');\n\n.@{tree-select-prefix-cls} {\n  // ======================= Dropdown =======================\n  &-dropdown {\n    padding: @padding-xs (@padding-xs / 2);\n\n    &-rtl {\n      direction: rtl;\n    }\n    // ======================== Tree ========================\n    .@{select-tree-prefix-cls} {\n      border-radius: 0;\n\n      &-list-holder-inner {\n        align-items: stretch;\n\n        .@{select-tree-prefix-cls}-treenode {\n          .@{select-tree-prefix-cls}-node-content-wrapper {\n            flex: auto;\n          }\n        }\n      }\n    }\n  }\n}\n\n.@{select-tree-prefix-cls} {\n  .antTreeFn(@select-tree-prefix-cls);\n\n  // change switcher icon rotation in rtl direction\n  & &-switcher {\n    &_close {\n      .@{select-tree-prefix-cls}-switcher-icon {\n        svg {\n          .@{tree-select-prefix-cls}-dropdown-rtl & {\n            transform: rotate(90deg);\n          }\n        }\n      }\n    }\n\n    &-loading-icon {\n      .@{tree-select-prefix-cls}-dropdown-rtl & {\n        transform: scaleY(-1);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/tree-select/style/patch.less",
    "content": ".ant-tree.ant-select-tree.ant-tree-show-line nz-tree-node[builtin]:not(:last-child) > li::before {\n  position: absolute;\n  left: 12px;\n  width: 1px;\n  height: calc(100% - 16px);\n  margin: 26px 0;\n  border-left: 1px solid #d9d9d9;\n  content: ' ';\n}\n\n.ant-select-dropdown.ant-select-tree-dropdown {\n  position: relative;\n  top: 100%;\n  left: 0;\n  width: 100%;\n  margin-top: 4px;\n  margin-bottom: 4px;\n  overflow: auto;\n\n  .cdk-virtual-scroll-content-wrapper {\n    overflow: auto;\n  }\n}"
  },
  {
    "path": "components/tree-select/tree-select.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { FocusMonitor } from '@angular/cdk/a11y';\nimport { Directionality } from '@angular/cdk/bidi';\nimport { BACKSPACE, ESCAPE, TAB } from '@angular/cdk/keycodes';\nimport {\n  CdkConnectedOverlay,\n  CdkOverlayOrigin,\n  ConnectedOverlayPositionChange,\n  ConnectionPositionPair\n} from '@angular/cdk/overlay';\nimport { _getEventTarget } from '@angular/cdk/platform';\nimport { SlicePipe } from '@angular/common';\nimport {\n  ChangeDetectorRef,\n  Component,\n  ContentChild,\n  DestroyRef,\n  ElementRef,\n  EventEmitter,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  Renderer2,\n  SimpleChanges,\n  TemplateRef,\n  ViewChild,\n  booleanAttribute,\n  computed,\n  forwardRef,\n  inject,\n  numberAttribute,\n  signal\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { Subject, combineLatest, merge, of as observableOf } from 'rxjs';\nimport { distinctUntilChanged, filter, map, startWith, tap, withLatestFrom } from 'rxjs/operators';\n\nimport { NzNoAnimationDirective, slideAnimationEnter, slideAnimationLeave } from 'ng-zorro-antd/core/animation';\nimport { NzConfigKey, WithConfig, onConfigChangeEventForComponent } from 'ng-zorro-antd/core/config';\nimport {\n  NZ_FORM_SIZE,\n  NZ_FORM_VARIANT,\n  NzFormItemFeedbackIconComponent,\n  NzFormNoStatusService,\n  NzFormStatusService\n} from 'ng-zorro-antd/core/form';\nimport { NzStringTemplateOutletDirective } from 'ng-zorro-antd/core/outlet';\nimport { NzOverlayModule, POSITION_MAP } from 'ng-zorro-antd/core/overlay';\nimport { requestAnimationFrame } from 'ng-zorro-antd/core/polyfill';\nimport {\n  NzFormatEmitEvent,\n  NzTreeBase,\n  NzTreeHigherOrderServiceToken,\n  NzTreeNode,\n  NzTreeNodeOptions\n} from 'ng-zorro-antd/core/tree';\nimport {\n  NgClassInterface,\n  NgStyleInterface,\n  NzSafeAny,\n  NzSizeLDSType,\n  NzStatus,\n  NzValidateStatus,\n  NzVariant,\n  OnChangeType,\n  OnTouchedType\n} from 'ng-zorro-antd/core/types';\nimport { getStatusClassNames, isNotNil } from 'ng-zorro-antd/core/util';\nimport { NzEmptyModule } from 'ng-zorro-antd/empty';\nimport { NzSelectModule, NzSelectSearchComponent } from 'ng-zorro-antd/select';\nimport { NZ_SPACE_COMPACT_ITEM_TYPE, NZ_SPACE_COMPACT_SIZE, NzSpaceCompactItemDirective } from 'ng-zorro-antd/space';\nimport { NzTreeComponent, NzTreeModule } from 'ng-zorro-antd/tree';\n\nimport { NzTreeSelectService } from './tree-select.service';\n\nexport type NzPlacementType = 'bottomLeft' | 'bottomRight' | 'topLeft' | 'topRight' | '';\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'treeSelect';\nconst TREE_SELECT_DEFAULT_CLASS = 'ant-select-dropdown ant-select-tree-dropdown';\nconst listOfPositions = [\n  POSITION_MAP.bottomLeft,\n  POSITION_MAP.bottomRight,\n  POSITION_MAP.topRight,\n  POSITION_MAP.topLeft\n];\n\n@Component({\n  selector: 'nz-tree-select',\n  exportAs: 'nzTreeSelect',\n  imports: [\n    NzOverlayModule,\n    CdkConnectedOverlay,\n    NzNoAnimationDirective,\n    NzTreeModule,\n    NzEmptyModule,\n    CdkOverlayOrigin,\n    SlicePipe,\n    NzSelectModule,\n    NzFormItemFeedbackIconComponent,\n    NzStringTemplateOutletDirective\n  ],\n  template: `\n    <ng-template\n      cdkConnectedOverlay\n      nzConnectedOverlay\n      [cdkConnectedOverlayHasBackdrop]=\"nzBackdrop\"\n      [cdkConnectedOverlayOrigin]=\"cdkOverlayOrigin\"\n      [cdkConnectedOverlayPositions]=\"nzPlacement ? positions : []\"\n      [cdkConnectedOverlayOpen]=\"nzOpen\"\n      cdkConnectedOverlayTransformOriginOn=\".ant-select-tree-dropdown\"\n      [cdkConnectedOverlayMinWidth]=\"$any(nzDropdownMatchSelectWidth ? null : triggerWidth)\"\n      [cdkConnectedOverlayWidth]=\"$any(nzDropdownMatchSelectWidth ? triggerWidth : null)\"\n      (overlayOutsideClick)=\"onClickOutside($event)\"\n      (detach)=\"closeDropdown()\"\n      (positionChange)=\"onPositionChange($event)\"\n    >\n      <div\n        [class]=\"dropdownClassName\"\n        [nzNoAnimation]=\"!!noAnimation?.nzNoAnimation?.()\"\n        [animate.enter]=\"slideAnimationEnter()\"\n        [animate.leave]=\"slideAnimationLeave()\"\n        [class.ant-select-dropdown-placement-bottomLeft]=\"dropdownPosition === 'bottom'\"\n        [class.ant-select-dropdown-placement-topLeft]=\"dropdownPosition === 'top'\"\n        [class.ant-tree-select-dropdown-rtl]=\"dir() === 'rtl'\"\n        [dir]=\"dir()\"\n        [style]=\"nzDropdownStyle\"\n      >\n        <nz-tree\n          #treeRef\n          [hidden]=\"isNotFound\"\n          nzNoAnimation\n          nzSelectMode\n          nzBlockNode\n          [nzData]=\"nzNodes\"\n          [nzMultiple]=\"nzMultiple\"\n          [nzSearchValue]=\"inputValue\"\n          [nzHideUnMatched]=\"nzHideUnMatched\"\n          [nzShowIcon]=\"nzShowIcon\"\n          [nzCheckable]=\"nzCheckable\"\n          [nzAsyncData]=\"nzAsyncData\"\n          [nzShowExpand]=\"nzShowExpand\"\n          [nzShowLine]=\"nzShowLine\"\n          [nzExpandedIcon]=\"nzExpandedIcon\"\n          [nzExpandAll]=\"nzDefaultExpandAll\"\n          [nzExpandedKeys]=\"expandedKeys\"\n          [nzCheckedKeys]=\"nzCheckable ? value : []\"\n          [nzSelectedKeys]=\"!nzCheckable ? value : []\"\n          [nzTreeTemplate]=\"treeTemplate\"\n          [nzCheckStrictly]=\"nzCheckStrictly\"\n          [nzVirtualItemSize]=\"nzVirtualItemSize\"\n          [nzVirtualMaxBufferPx]=\"nzVirtualMaxBufferPx\"\n          [nzVirtualMinBufferPx]=\"nzVirtualMinBufferPx\"\n          [nzVirtualHeight]=\"nzVirtualHeight\"\n          (nzExpandChange)=\"onExpandedKeysChange($event)\"\n          (nzClick)=\"nzTreeClick.emit($event)\"\n          (nzCheckedKeysChange)=\"updateSelectedNodes()\"\n          (nzSelectedKeysChange)=\"updateSelectedNodes()\"\n          (nzCheckboxChange)=\"nzTreeCheckboxChange.emit($event)\"\n          (nzSearchValueChange)=\"setSearchValues($event)\"\n        />\n        @if (nzNodes.length === 0 || isNotFound) {\n          <span class=\"ant-select-not-found\">\n            <nz-embed-empty nzComponentName=\"tree-select\" [specificContent]=\"nzNotFoundContent\" />\n          </span>\n        }\n      </div>\n    </ng-template>\n\n    <div cdkOverlayOrigin class=\"ant-select-selector\">\n      @if (nzPrefix; as prefix) {\n        <div class=\"ant-select-prefix\">\n          <ng-container *nzStringTemplateOutlet=\"prefix\">{{ prefix }}</ng-container>\n        </div>\n      }\n\n      <span class=\"ant-select-selection-wrap\">\n        @if (isMultiple) {\n          <div class=\"ant-select-selection-overflow\">\n            @for (node of selectedNodes | slice: 0 : nzMaxTagCount; track node.key) {\n              <div class=\"ant-select-selection-overflow-item\">\n                <nz-select-item\n                  deletable\n                  [disabled]=\"node.isDisabled || nzDisabled\"\n                  [label]=\"nzDisplayWith(node)\"\n                  displayLabelInHtml\n                  (delete)=\"removeSelected(node, true)\"\n                />\n              </div>\n            }\n            @if (selectedNodes.length > nzMaxTagCount) {\n              <div class=\"ant-select-selection-overflow-item\">\n                <nz-select-item\n                  [contentTemplateOutlet]=\"nzMaxTagPlaceholder\"\n                  [contentTemplateOutletContext]=\"selectedNodes | slice: nzMaxTagCount\"\n                  [label]=\"'+ ' + (selectedNodes.length - nzMaxTagCount) + ' ...'\"\n                />\n              </div>\n            }\n            <div class=\"ant-select-selection-overflow-item ant-select-selection-overflow-item-suffix\">\n              <nz-select-search\n                [nzId]=\"nzId\"\n                [showInput]=\"nzShowSearch\"\n                (keydown)=\"onKeyDownInput($event)\"\n                (isComposingChange)=\"isComposingChange($event)\"\n                (valueChange)=\"setInputValue($event)\"\n                [value]=\"inputValue\"\n                [mirrorSync]=\"true\"\n                [disabled]=\"nzDisabled\"\n                [focusTrigger]=\"nzOpen\"\n              />\n            </div>\n          </div>\n        } @else {\n          <nz-select-search\n            [nzId]=\"nzId\"\n            [showInput]=\"nzShowSearch\"\n            (keydown)=\"onKeyDownInput($event)\"\n            (isComposingChange)=\"isComposingChange($event)\"\n            (valueChange)=\"setInputValue($event)\"\n            [value]=\"inputValue\"\n            [mirrorSync]=\"false\"\n            [disabled]=\"nzDisabled\"\n            [focusTrigger]=\"nzOpen\"\n          />\n          @if (selectedNodes.length === 1 && !isComposing && inputValue === '') {\n            <nz-select-item [label]=\"nzDisplayWith(selectedNodes[0])\" displayLabelInHtml />\n          }\n        }\n\n        @if (nzPlaceHolder && selectedNodes.length === 0) {\n          <nz-select-placeholder [placeholder]=\"nzPlaceHolder\" [style.display]=\"placeHolderDisplay\" />\n        }\n      </span>\n\n      <nz-select-arrow\n        [showArrow]=\"true\"\n        [search]=\"nzOpen && nzShowSearch\"\n        [suffixIcon]=\"nzSuffixIcon\"\n        [feedbackIcon]=\"feedbackIconTpl\"\n      >\n        <ng-template #feedbackIconTpl>\n          @if (hasFeedback && !!status) {\n            <nz-form-item-feedback-icon [status]=\"status\" />\n          }\n        </ng-template>\n      </nz-select-arrow>\n\n      @if (nzAllowClear && !nzDisabled && selectedNodes.length) {\n        <nz-select-clear (clear)=\"onClearSelection()\" />\n      }\n    </div>\n  `,\n  providers: [\n    NzTreeSelectService,\n    { provide: NZ_SPACE_COMPACT_ITEM_TYPE, useValue: 'select' },\n    {\n      provide: NzTreeHigherOrderServiceToken,\n      useExisting: NzTreeSelectService\n    },\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => NzTreeSelectComponent),\n      multi: true\n    }\n  ],\n  host: {\n    class: 'ant-select ant-tree-select',\n    '[class.ant-select-in-form-item]': '!!nzFormStatusService',\n    '[class.ant-select-rtl]': 'dir()===\"rtl\"',\n    '[class.ant-select-lg]': 'finalSize() === \"large\"',\n    '[class.ant-select-sm]': 'finalSize() === \"small\"',\n    '[class.ant-select-disabled]': 'nzDisabled',\n    '[class.ant-select-single]': '!isMultiple',\n    '[class.ant-select-show-arrow]': '!isMultiple',\n    '[class.ant-select-show-search]': '!isMultiple',\n    '[class.ant-select-borderless]': 'finalVariant() === \"borderless\"',\n    '[class.ant-select-filled]': 'finalVariant() === \"filled\"',\n    '[class.ant-select-underlined]': 'finalVariant() === \"underlined\"',\n    '[class.ant-select-multiple]': 'isMultiple',\n    '[class.ant-select-allow-clear]': 'nzAllowClear',\n    '[class.ant-select-open]': 'nzOpen',\n    '[class.ant-select-focused]': 'nzOpen || focused',\n    '(click)': 'trigger()',\n    '(keydown)': 'onKeydown($event)'\n  },\n  hostDirectives: [NzSpaceCompactItemDirective]\n})\nexport class NzTreeSelectComponent extends NzTreeBase implements ControlValueAccessor, OnInit, OnChanges {\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  private renderer = inject(Renderer2);\n  private cdr = inject(ChangeDetectorRef);\n  private elementRef = inject(ElementRef);\n  private focusMonitor = inject(FocusMonitor);\n  private destroyRef = inject(DestroyRef);\n\n  protected readonly slideAnimationEnter = slideAnimationEnter();\n  protected readonly slideAnimationLeave = slideAnimationLeave();\n\n  @Input() nzId: string | null = null;\n  @Input({ transform: booleanAttribute }) nzAllowClear: boolean = true;\n  @Input({ transform: booleanAttribute }) nzShowExpand: boolean = true;\n  @Input({ transform: booleanAttribute }) nzShowLine: boolean = false;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzDropdownMatchSelectWidth: boolean = true;\n  @Input({ transform: booleanAttribute }) nzCheckable: boolean = false;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzHideUnMatched: boolean = false;\n  @Input({ transform: booleanAttribute }) @WithConfig() nzShowIcon: boolean = false;\n  @Input({ transform: booleanAttribute }) nzShowSearch: boolean = false;\n  @Input({ transform: booleanAttribute }) nzDisabled = false;\n  @Input({ transform: booleanAttribute }) nzAsyncData = false;\n  @Input({ transform: booleanAttribute }) nzMultiple = false;\n  @Input({ transform: booleanAttribute }) nzDefaultExpandAll = false;\n  @Input({ transform: booleanAttribute }) nzCheckStrictly = false;\n  @Input() nzVirtualItemSize = 28;\n  @Input() nzVirtualMaxBufferPx = 500;\n  @Input() nzVirtualMinBufferPx = 28;\n  @Input() nzVirtualHeight: string | null = null;\n  @Input() nzExpandedIcon?: TemplateRef<{ $implicit: NzTreeNode; origin: NzTreeNodeOptions }>;\n  @Input() nzNotFoundContent?: string | TemplateRef<void>;\n  @Input() nzNodes: NzTreeNodeOptions[] | NzTreeNode[] = [];\n  @Input() nzOpen = false;\n  @Input() @WithConfig() nzSize: NzSizeLDSType = 'default';\n  @Input() @WithConfig() nzVariant: NzVariant | undefined = undefined;\n  @Input() nzPlaceHolder = '';\n  @Input() nzDropdownStyle: NgStyleInterface | null = null;\n  @Input() nzDropdownClassName?: string;\n  @Input() @WithConfig() nzBackdrop = false;\n  @Input() nzStatus: NzStatus = '';\n  @Input() nzPlacement: NzPlacementType = '';\n  @Input()\n  set nzExpandedKeys(value: string[]) {\n    this.expandedKeys = value;\n  }\n  get nzExpandedKeys(): string[] {\n    return this.expandedKeys;\n  }\n\n  @Input() nzPrefix: TemplateRef<NzSafeAny> | string | null = null;\n  @Input() nzSuffixIcon: TemplateRef<NzSafeAny> | string | null = null;\n  @Input() nzDisplayWith: (node: NzTreeNode) => string | undefined = (node: NzTreeNode) => node.title;\n  @Input({ transform: numberAttribute }) nzMaxTagCount!: number;\n  @Input() nzMaxTagPlaceholder: TemplateRef<{ $implicit: NzTreeNode[] }> | null = null;\n  @Output() readonly nzOpenChange = new EventEmitter<boolean>();\n  @Output() readonly nzCleared = new EventEmitter<void>();\n  @Output() readonly nzRemoved = new EventEmitter<NzTreeNode>();\n  @Output() readonly nzExpandChange = new EventEmitter<NzFormatEmitEvent>();\n  @Output() readonly nzTreeClick = new EventEmitter<NzFormatEmitEvent>();\n  @Output() readonly nzTreeCheckboxChange = new EventEmitter<NzFormatEmitEvent>();\n\n  @ViewChild(NzSelectSearchComponent, { static: false }) nzSelectSearchComponent!: NzSelectSearchComponent;\n  @ViewChild('treeRef', { static: false }) treeRef!: NzTreeComponent;\n  @ViewChild(CdkOverlayOrigin, { static: true }) cdkOverlayOrigin!: CdkOverlayOrigin;\n  @ViewChild(CdkConnectedOverlay, { static: false }) cdkConnectedOverlay!: CdkConnectedOverlay;\n\n  @Input() nzTreeTemplate!: TemplateRef<{ $implicit: NzTreeNode; origin: NzTreeNodeOptions }>;\n  @ContentChild('nzTreeTemplate', { static: true }) nzTreeTemplateChild!: TemplateRef<{\n    $implicit: NzTreeNode;\n    origin: NzTreeNodeOptions;\n  }>;\n  get treeTemplate(): TemplateRef<{ $implicit: NzTreeNode; origin: NzTreeNodeOptions }> {\n    return this.nzTreeTemplate || this.nzTreeTemplateChild;\n  }\n\n  prefixCls: string = 'ant-select';\n  statusCls: NgClassInterface = {};\n  status: NzValidateStatus = '';\n  hasFeedback: boolean = false;\n\n  dropdownClassName = TREE_SELECT_DEFAULT_CLASS;\n  triggerWidth?: number;\n  isComposing = false;\n  isNotFound = false;\n  focused = false;\n  inputValue = '';\n  dropdownPosition: 'top' | 'center' | 'bottom' = 'bottom';\n  selectedNodes: NzTreeNode[] = [];\n  expandedKeys: string[] = [];\n  value: string[] = [];\n  protected readonly dir = inject(Directionality).valueSignal;\n  positions: ConnectionPositionPair[] = [];\n\n  protected finalSize = computed(() => {\n    if (this.formSize?.()) {\n      return this.formSize();\n    }\n    if (this.compactSize) {\n      return this.compactSize();\n    }\n    return this.size();\n  });\n\n  protected readonly finalVariant = computed(() => this.variant() || this.formVariant?.() || 'outlined');\n\n  private size = signal<NzSizeLDSType>(this.nzSize);\n  private readonly variant = signal<NzVariant | undefined>(this.nzVariant);\n\n  private readonly formSize = inject(NZ_FORM_SIZE, { optional: true });\n  private readonly formVariant = inject(NZ_FORM_VARIANT, { optional: true });\n\n  private compactSize = inject(NZ_SPACE_COMPACT_SIZE, { optional: true });\n  private isNzDisableFirstChange: boolean = true;\n  private isComposingChange$ = new Subject<boolean>();\n  private searchValueChange$ = new Subject<string>();\n\n  onChange: OnChangeType = _value => {};\n  onTouched: OnTouchedType = () => {};\n\n  get placeHolderDisplay(): string {\n    return this.inputValue || this.isComposing || this.selectedNodes.length ? 'none' : 'block';\n  }\n\n  get isMultiple(): boolean {\n    return this.nzMultiple || this.nzCheckable;\n  }\n\n  noAnimation = inject(NzNoAnimationDirective, { host: true, optional: true });\n  nzFormStatusService = inject(NzFormStatusService, { optional: true });\n  private nzFormNoStatusService = inject(NzFormNoStatusService, { optional: true });\n\n  constructor() {\n    super(inject(NzTreeSelectService));\n\n    this.destroyRef.onDestroy(() => {\n      this.closeDropdown();\n    });\n\n    onConfigChangeEventForComponent(NZ_CONFIG_MODULE_NAME, () => {\n      this.size.set(this.nzSize);\n      this.cdr.markForCheck();\n    });\n  }\n\n  ngOnInit(): void {\n    this.size.set(this.nzSize);\n\n    this.nzFormStatusService?.formStatusChanges\n      .pipe(\n        distinctUntilChanged((pre, cur) => {\n          return pre.status === cur.status && pre.hasFeedback === cur.hasFeedback;\n        }),\n        withLatestFrom(this.nzFormNoStatusService ? this.nzFormNoStatusService.noFormStatus : observableOf(false)),\n        map(([{ status, hasFeedback }, noStatus]) => ({ status: noStatus ? '' : status, hasFeedback })),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(({ status, hasFeedback }) => {\n        this.setStatusStyles(status, hasFeedback);\n      });\n\n    this.subscribeSelectionChange();\n\n    this.focusMonitor\n      .monitor(this.elementRef, true)\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(focusOrigin => {\n        if (!focusOrigin) {\n          this.focused = false;\n          this.cdr.markForCheck();\n          Promise.resolve().then(() => {\n            this.onTouched();\n          });\n        } else {\n          this.focused = true;\n          this.cdr.markForCheck();\n        }\n      });\n\n    // setInputValue method executed earlier than isComposingChange\n    combineLatest([this.searchValueChange$, this.isComposingChange$.pipe(startWith(false))])\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(([searchValue, isComposing]) => {\n        this.isComposing = isComposing;\n        if (!isComposing) {\n          this.inputValue = searchValue;\n          this.updatePosition();\n        }\n      });\n  }\n\n  isComposingChange(isComposing: boolean): void {\n    this.isComposingChange$.next(isComposing);\n  }\n\n  setDisabledState(isDisabled: boolean): void {\n    this.nzDisabled = (this.isNzDisableFirstChange && this.nzDisabled) || isDisabled;\n    this.closeDropdown();\n    this.isNzDisableFirstChange = false;\n  }\n\n  private setStatusStyles(status: NzValidateStatus, hasFeedback: boolean): void {\n    // set inner status\n    this.status = status;\n    this.hasFeedback = hasFeedback;\n    this.cdr.markForCheck();\n    // render status if nzStatus is set\n    this.statusCls = getStatusClassNames(this.prefixCls, status, hasFeedback);\n    Object.keys(this.statusCls).forEach(status => {\n      if (this.statusCls[status]) {\n        this.renderer.addClass(this.elementRef.nativeElement, status);\n      } else {\n        this.renderer.removeClass(this.elementRef.nativeElement, status);\n      }\n    });\n  }\n\n  ngOnChanges({ nzNodes, nzDropdownClassName, nzStatus, nzPlacement, nzSize, nzVariant }: SimpleChanges): void {\n    if (nzNodes) {\n      this.updateSelectedNodes(true);\n    }\n    if (nzDropdownClassName) {\n      const className = this.nzDropdownClassName && this.nzDropdownClassName.trim();\n      this.dropdownClassName = className ? `${TREE_SELECT_DEFAULT_CLASS} ${className}` : TREE_SELECT_DEFAULT_CLASS;\n    }\n    if (nzStatus) {\n      this.setStatusStyles(this.nzStatus, this.hasFeedback);\n    }\n\n    if (nzPlacement && this.nzPlacement) {\n      if (POSITION_MAP[this.nzPlacement]) {\n        this.positions = [POSITION_MAP[this.nzPlacement]];\n      }\n    }\n    if (nzSize) {\n      this.size.set(nzSize.currentValue);\n    }\n    if (nzVariant) {\n      this.variant.set(nzVariant.currentValue);\n    }\n  }\n\n  writeValue(value: string[] | string): void {\n    if (isNotNil(value)) {\n      if (this.isMultiple && Array.isArray(value)) {\n        this.value = value;\n      } else {\n        this.value = [value as string];\n      }\n      // need clear selected nodes when user set value before updating\n      this.clearSelectedNodes();\n      this.updateSelectedNodes(true);\n    } else {\n      this.value = [];\n      this.clearSelectedNodes();\n      this.selectedNodes = [];\n    }\n    this.cdr.markForCheck();\n  }\n\n  registerOnChange(fn: (_: string[] | string | null) => void): void {\n    this.onChange = fn;\n  }\n\n  registerOnTouched(fn: () => void): void {\n    this.onTouched = fn;\n  }\n\n  onKeydown(event: KeyboardEvent): void {\n    if (this.nzDisabled) {\n      return;\n    }\n    switch (event.keyCode) {\n      case ESCAPE:\n        /**\n         * Skip the ESCAPE processing, it will be handled in {@link onOverlayKeyDown}.\n         */\n        break;\n      case TAB:\n        this.closeDropdown();\n        break;\n      default:\n        if (!this.nzOpen) {\n          this.openDropdown();\n        }\n    }\n  }\n\n  trigger(): void {\n    if (this.nzDisabled || (!this.nzDisabled && this.nzOpen)) {\n      this.closeDropdown();\n    } else {\n      this.openDropdown();\n    }\n  }\n\n  openDropdown(): void {\n    if (!this.nzDisabled) {\n      this.nzOpen = true;\n      this.nzOpenChange.emit(this.nzOpen);\n      this.updateCdkConnectedOverlayStatus();\n      if (this.nzShowSearch || this.isMultiple) {\n        this.focusOnInput();\n      }\n    }\n  }\n\n  closeDropdown(): void {\n    Promise.resolve().then(() => this.onTouched());\n    this.nzOpen = false;\n    this.inputValue = '';\n    this.isNotFound = false;\n    this.nzOpenChange.emit(this.nzOpen);\n    this.cdr.markForCheck();\n  }\n\n  onKeyDownInput(e: KeyboardEvent): void {\n    const keyCode = e.keyCode;\n    const eventTarget = e.target as HTMLInputElement;\n    if (this.isMultiple && !eventTarget.value && keyCode === BACKSPACE) {\n      e.preventDefault();\n      if (this.selectedNodes.length) {\n        const removeNode = this.selectedNodes[this.selectedNodes.length - 1];\n        if (removeNode && !removeNode.isDisabled) {\n          this.removeSelected(removeNode);\n        }\n      }\n    }\n  }\n\n  onExpandedKeysChange(value: NzFormatEmitEvent): void {\n    this.nzExpandChange.emit(value);\n    this.expandedKeys = [...value.keys!];\n  }\n\n  setInputValue(value: string): void {\n    this.searchValueChange$.next(value);\n  }\n\n  removeSelected(node: NzTreeNode, emit: boolean = true): void {\n    node.isSelected = false;\n    node.isChecked = false;\n    if (this.nzCheckable) {\n      this.nzTreeService.conduct(node, this.nzCheckStrictly);\n    } else {\n      this.nzTreeService.setSelectedNodeList(node, this.nzMultiple);\n    }\n\n    if (emit) {\n      this.nzRemoved.emit(node);\n    }\n  }\n\n  focusOnInput(): void {\n    if (this.nzSelectSearchComponent) {\n      this.nzSelectSearchComponent.focus();\n    }\n  }\n\n  subscribeSelectionChange(): void {\n    merge(\n      this.nzTreeClick.pipe(\n        tap((event: NzFormatEmitEvent) => {\n          const node = event.node!;\n          if (this.nzCheckable && !node.isDisabled && !node.isDisableCheckbox) {\n            node.isChecked = !node.isChecked;\n            node.isHalfChecked = false;\n            if (!this.nzCheckStrictly) {\n              this.nzTreeService.conduct(node);\n            }\n          }\n          if (this.nzCheckable) {\n            node.isSelected = false;\n          }\n        }),\n        filter((event: NzFormatEmitEvent) => {\n          const node = event.node!;\n          return this.nzCheckable ? !node.isDisabled && !node.isDisableCheckbox : !node.isDisabled && node.isSelectable;\n        })\n      ),\n      this.nzCheckable ? this.nzTreeCheckboxChange.asObservable() : observableOf(),\n      this.nzCleared,\n      this.nzRemoved\n    )\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(() => {\n        this.updateSelectedNodes();\n        const value = this.selectedNodes.map(node => node.key!);\n        this.value = [...value];\n        if (this.nzShowSearch || this.isMultiple) {\n          this.inputValue = '';\n          this.isNotFound = false;\n        }\n        if (this.isMultiple) {\n          this.onChange(value);\n          this.focusOnInput();\n          this.updatePosition();\n        } else {\n          this.closeDropdown();\n          this.onChange(value.length ? value[0] : null);\n        }\n      });\n  }\n\n  updateSelectedNodes(init: boolean = false): void {\n    if (init) {\n      const nodes = this.coerceTreeNodes(this.nzNodes);\n      this.nzTreeService.isMultiple = this.isMultiple;\n      this.nzTreeService.isCheckStrictly = this.nzCheckStrictly;\n      this.nzTreeService.initTree(nodes);\n      if (this.nzCheckable) {\n        this.nzTreeService.conductCheck(this.value, this.nzCheckStrictly);\n      } else {\n        this.nzTreeService.conductSelectedKeys(this.value, this.isMultiple);\n      }\n    }\n\n    this.selectedNodes = [...(this.nzCheckable ? this.getCheckedNodeList() : this.getSelectedNodeList())].sort(\n      (a, b) => {\n        const indexA = this.value.indexOf(a.key);\n        const indexB = this.value.indexOf(b.key);\n        if (indexA !== -1 && indexB !== -1) {\n          return indexA - indexB;\n        }\n        if (indexA !== -1) {\n          return -1;\n        }\n        if (indexB !== -1) {\n          return 1;\n        }\n        return 0;\n      }\n    );\n  }\n\n  updatePosition(): void {\n    requestAnimationFrame(() => {\n      this.cdkConnectedOverlay?.overlayRef?.updatePosition();\n    });\n  }\n\n  onPositionChange(position: ConnectedOverlayPositionChange): void {\n    this.dropdownPosition = position.connectionPair.originY;\n  }\n\n  onClearSelection(): void {\n    this.selectedNodes.forEach(node => {\n      this.removeSelected(node, false);\n    });\n    this.nzCleared.emit();\n  }\n\n  onClickOutside(event: MouseEvent): void {\n    const target = _getEventTarget(event);\n    if (!this.elementRef.nativeElement.contains(target)) {\n      this.closeDropdown();\n    }\n  }\n\n  setSearchValues($event: NzFormatEmitEvent): void {\n    Promise.resolve().then(() => {\n      this.isNotFound = (this.nzShowSearch || this.isMultiple) && !!this.inputValue && $event.matchedKeys!.length === 0;\n    });\n  }\n\n  updateCdkConnectedOverlayStatus(): void {\n    if (!this.nzPlacement || !listOfPositions.includes(POSITION_MAP[this.nzPlacement])) {\n      this.triggerWidth = this.cdkOverlayOrigin.elementRef.nativeElement.getBoundingClientRect().width;\n    }\n  }\n\n  clearSelectedNodes(): void {\n    this.selectedNodes.forEach(node => {\n      this.removeSelected(node, false);\n    });\n  }\n}\n"
  },
  {
    "path": "components/tree-select/tree-select.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzTreeSelectComponent } from './tree-select.component';\n\n@NgModule({\n  imports: [NzTreeSelectComponent],\n  exports: [NzTreeSelectComponent]\n})\nexport class NzTreeSelectModule {}\n"
  },
  {
    "path": "components/tree-select/tree-select.service.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Injectable } from '@angular/core';\n\nimport { NzTreeBaseService } from 'ng-zorro-antd/core/tree';\n\n@Injectable()\nexport class NzTreeSelectService extends NzTreeBaseService {}\n"
  },
  {
    "path": "components/tree-select/tree-select.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { BACKSPACE } from '@angular/cdk/keycodes';\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport { TestKey } from '@angular/cdk/testing';\nimport { UnitTestElement } from '@angular/cdk/testing/testbed';\nimport {\n  Component,\n  DebugElement,\n  NgZone,\n  provideZoneChangeDetection,\n  signal,\n  TemplateRef,\n  ViewChild,\n  WritableSignal\n} from '@angular/core';\nimport { ComponentFixture, fakeAsync, flush, inject, TestBed, tick } from '@angular/core/testing';\nimport { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { NZ_FORM_SIZE, NZ_FORM_VARIANT } from 'ng-zorro-antd/core/form';\nimport {\n  createKeyboardEvent,\n  dispatchFakeEvent,\n  dispatchMouseEvent,\n  MockNgZone,\n  typeInElement\n} from 'ng-zorro-antd/core/testing';\nimport { NzTreeNode, NzTreeNodeOptions } from 'ng-zorro-antd/core/tree';\nimport { NzSizeLDSType, NzStatus, NzVariant } from 'ng-zorro-antd/core/types';\nimport { NzFormControlStatusType, NzFormModule } from 'ng-zorro-antd/form';\nimport { NZ_SPACE_COMPACT_SIZE } from 'ng-zorro-antd/space';\n\nimport { NzTreeSelectComponent } from './tree-select.component';\nimport { NzTreeSelectModule } from './tree-select.module';\n\ndescribe('tree-select', () => {\n  let overlayContainer: OverlayContainer;\n  let overlayContainerElement: HTMLElement;\n  let zone: MockNgZone;\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [\n        // todo: use zoneless\n        provideZoneChangeDetection(),\n        provideNoopAnimations(),\n        {\n          provide: NgZone,\n          useFactory: () => {\n            zone = new MockNgZone();\n            return zone;\n          }\n        }\n      ]\n    });\n  });\n\n  beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n    overlayContainer = oc;\n    overlayContainerElement = oc.getContainerElement();\n  }));\n\n  afterEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n    oc.ngOnDestroy();\n    overlayContainer.ngOnDestroy();\n  }));\n\n  describe('basic', () => {\n    let fixture: ComponentFixture<NzTestTreeSelectBasicComponent>;\n    let testComponent: NzTestTreeSelectBasicComponent;\n    let treeSelectComponent: NzTreeSelectComponent;\n    let treeSelect: DebugElement;\n\n    beforeEach(fakeAsync(() => {\n      fixture = TestBed.createComponent(NzTestTreeSelectBasicComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n      treeSelect = fixture.debugElement.query(By.directive(NzTreeSelectComponent));\n      treeSelectComponent = treeSelect.componentInstance;\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n    }));\n\n    it('should size work', fakeAsync(() => {\n      testComponent.size = 'small';\n      fixture.detectChanges();\n      expect(treeSelect.nativeElement.classList).toContain('ant-select-sm');\n      testComponent.size = 'large';\n      fixture.detectChanges();\n      expect(treeSelect.nativeElement.classList).toContain('ant-select-lg');\n    }));\n\n    describe('should variant works', () => {\n      it('filled', () => {\n        fixture.detectChanges();\n        expect(treeSelect.nativeElement.classList).not.toContain('ant-select-filled');\n        testComponent.variant = 'filled';\n        fixture.detectChanges();\n        expect(treeSelect.nativeElement.classList).toContain('ant-select-filled');\n      });\n\n      it('borderless', () => {\n        fixture.detectChanges();\n        expect(treeSelect.nativeElement.classList).not.toContain('ant-select-borderless');\n        testComponent.variant = 'borderless';\n        fixture.detectChanges();\n        expect(treeSelect.nativeElement.classList).toContain('ant-select-borderless');\n      });\n\n      it('underlined', () => {\n        fixture.detectChanges();\n        expect(treeSelect.nativeElement.classList).not.toContain('ant-select-underlined');\n        testComponent.variant = 'underlined';\n        fixture.detectChanges();\n        expect(treeSelect.nativeElement.classList).toContain('ant-select-underlined');\n      });\n    });\n\n    it('should allowClear work', () => {\n      const nativeElement = treeSelect.nativeElement as HTMLElement;\n      expect(nativeElement.classList).not.toContain('ant-select-allow-clear');\n      expect(nativeElement.querySelector('nz-select-clear')).toBeNull();\n      testComponent.allowClear = true;\n      fixture.detectChanges();\n      expect(nativeElement.classList).toContain('ant-select-allow-clear');\n      expect(nativeElement.querySelector('nz-select-clear')).not.toBeNull();\n\n      (nativeElement.querySelector('nz-select-clear') as HTMLElement)!.click();\n      fixture.detectChanges();\n\n      expect(nativeElement.querySelector('nz-select-clear')).toBeNull();\n    });\n\n    it('should click toggle open', () => {\n      treeSelect.nativeElement.click();\n      fixture.detectChanges();\n      expect(treeSelectComponent.nzOpen).toBe(true);\n      treeSelect.nativeElement.click();\n      fixture.detectChanges();\n      expect(treeSelectComponent.nzOpen).toBe(false);\n    });\n\n    it('should close when the outside clicks', () => {\n      treeSelect.nativeElement.click();\n      fixture.detectChanges();\n      expect(treeSelectComponent.nzOpen).toBe(true);\n      dispatchFakeEvent(document.body, 'click');\n      fixture.detectChanges();\n      expect(treeSelectComponent.nzOpen).toBe(false);\n      fixture.detectChanges();\n    });\n\n    it('should disabled work', fakeAsync(() => {\n      testComponent.disabled = true;\n      fixture.detectChanges();\n      expect(treeSelect.nativeElement.classList).toContain('ant-select-disabled');\n      expect(treeSelectComponent.nzOpen).toBe(false);\n      treeSelect.nativeElement.click();\n      fixture.detectChanges();\n      tick();\n      expect(treeSelectComponent.nzOpen).toBe(false);\n      treeSelectComponent.openDropdown();\n      treeSelect.nativeElement.click();\n      fixture.detectChanges();\n      tick();\n    }));\n\n    it('should dropdownMatchSelectWidth work', () => {\n      testComponent.dropdownMatchSelectWidth = true;\n      fixture.detectChanges();\n      treeSelect.nativeElement.click();\n      fixture.detectChanges();\n      expect(treeSelectComponent.nzOpen).toBe(true);\n      const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement;\n      expect(overlayPane.style.width).toBe('250px');\n      treeSelectComponent.closeDropdown();\n      fixture.detectChanges();\n      testComponent.dropdownMatchSelectWidth = false;\n      fixture.detectChanges();\n      treeSelect.nativeElement.click();\n      fixture.detectChanges();\n      expect(treeSelectComponent.nzOpen).toBe(true);\n      expect(overlayPane.style.minWidth).toBe('250px');\n    });\n\n    it('should clear value work', fakeAsync(() => {\n      testComponent.allowClear = true;\n      fixture.detectChanges();\n      expect(testComponent.value).toBe('10001');\n      treeSelectComponent.updateSelectedNodes();\n      fixture.detectChanges();\n      treeSelect.nativeElement.querySelector('nz-select-clear').click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(null);\n    }));\n\n    it('should set null value work', fakeAsync(() => {\n      fixture.detectChanges();\n      expect(testComponent.value).toBe('10001');\n      testComponent.nzSelectTreeComponent.updateSelectedNodes();\n      fixture.detectChanges();\n      testComponent.setNull();\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(null);\n      expect(testComponent.nzSelectTreeComponent.selectedNodes.length).toEqual(0);\n      expect(testComponent.nzSelectTreeComponent.value.length).toBe(0);\n    }));\n\n    it('should dropdown style work', fakeAsync(() => {\n      treeSelect.nativeElement.click();\n      fixture.detectChanges();\n      expect(treeSelectComponent.nzOpen).toBe(true);\n      flush();\n      const targetElement = overlayContainerElement.querySelector('.ant-select-dropdown') as HTMLElement;\n      expect(targetElement.style.height).toBe('120px');\n    }));\n\n    it('should dropdown classname work', fakeAsync(() => {\n      treeSelect.nativeElement.click();\n      fixture.detectChanges();\n      expect(treeSelectComponent.nzOpen).toBe(true);\n      flush();\n      const targetElement = overlayContainerElement.querySelector('.ant-select-dropdown') as HTMLElement;\n      expect(targetElement.classList).toContain('class1');\n      expect(targetElement.classList).toContain('class2');\n    }));\n\n    it('should click option close dropdown', fakeAsync(() => {\n      treeSelect.nativeElement.click();\n      fixture.detectChanges();\n      expect(treeSelectComponent.nzOpen).toBe(true);\n      fixture.detectChanges();\n      const targetNode = overlayContainerElement.querySelectorAll('.ant-select-tree-node-content-wrapper')[2];\n      dispatchMouseEvent(targetNode, 'click');\n      fixture.detectChanges();\n      flush();\n      expect(treeSelectComponent.nzOpen).toBe(false);\n    }));\n\n    it('should be focusable', fakeAsync(() => {\n      const focusTrigger = treeSelect.query(By.css('.ant-select-selection-search-input')).nativeElement;\n      expect(treeSelect.nativeElement.classList).not.toContain('ant-select-focused');\n      dispatchFakeEvent(focusTrigger, 'focus');\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(treeSelect.nativeElement.classList).toContain('ant-select-focused');\n    }));\n\n    it('should open dropdown when keydown', fakeAsync(async () => {\n      const testElement = new UnitTestElement(treeSelect.nativeElement, async () => {\n        fixture.detectChanges();\n        flush();\n        fixture.detectChanges();\n      });\n      expect(treeSelectComponent.nzOpen).toBe(false);\n      await testElement.sendKeys(TestKey.ESCAPE);\n      expect(treeSelectComponent.nzOpen).toBe(false);\n\n      await testElement.sendKeys(TestKey.ENTER);\n      expect(treeSelectComponent.nzOpen).toBe(true);\n    }));\n\n    it('should close dropdown when TAB keydown', fakeAsync(async () => {\n      const testElement = new UnitTestElement(treeSelect.nativeElement, async () => {\n        fixture.detectChanges();\n        flush();\n        fixture.detectChanges();\n      });\n\n      treeSelectComponent.nzOpen = true;\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n\n      await testElement.sendKeys(TestKey.TAB);\n      expect(treeSelectComponent.nzOpen).toBe(false);\n    }));\n\n    it('should showSearch work', fakeAsync(() => {\n      treeSelectComponent.updateSelectedNodes();\n      fixture.detectChanges();\n      testComponent.showSearch = true;\n      fixture.detectChanges();\n      treeSelect.nativeElement.click();\n      fixture.detectChanges();\n      const searchInput = treeSelect.nativeElement.querySelector('nz-select-search .ant-select-selection-search-input');\n      expect(searchInput).toBeTruthy();\n      expect(searchInput.style.opacity).toBe('');\n      testComponent.showSearch = false;\n      fixture.detectChanges();\n      tick();\n      expect(searchInput.style.opacity).toBe('0');\n      flush();\n      fixture.detectChanges();\n    }));\n\n    it('should display no data', fakeAsync(() => {\n      treeSelectComponent.updateSelectedNodes();\n      fixture.detectChanges();\n      testComponent.showSearch = true;\n      fixture.detectChanges();\n      treeSelect.nativeElement.click();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('nz-tree')!.getAttribute('hidden')).toBeNull();\n      expect(overlayContainerElement.querySelector('.ant-select-not-found')).toBeFalsy();\n      fixture.detectChanges();\n      treeSelectComponent.inputValue = 'invalid_value';\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('nz-tree')!.getAttribute('hidden')).toBe('');\n      expect(overlayContainerElement.querySelector('.ant-select-not-found')).toBeTruthy();\n    }));\n\n    it('should clean search value when reopen', fakeAsync(() => {\n      testComponent.showSearch = true;\n      fixture.detectChanges();\n      treeSelect.nativeElement.click();\n      fixture.detectChanges();\n      treeSelectComponent.inputValue = 'invalid_value';\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.ant-select-not-found')).toBeTruthy();\n\n      treeSelect.nativeElement.click();\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      treeSelect.nativeElement.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n\n      expect(overlayContainerElement.querySelector('.ant-select-not-found')).toBeFalsy();\n    }));\n\n    it('should max tag count work', fakeAsync(() => {\n      fixture.detectChanges();\n      testComponent.multiple = true;\n      fixture.detectChanges();\n      testComponent.value = ['1001', '10001', '100011', '100012'];\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(treeSelect.nativeElement.querySelectorAll('nz-select-item').length).toBe(4);\n      testComponent.maxTagCount = 2;\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(treeSelect.nativeElement.querySelectorAll('nz-select-item').length).toBe(3);\n      const maxTagPlaceholderElement = treeSelect.nativeElement.querySelectorAll('nz-select-item')[2];\n      expect(maxTagPlaceholderElement).toBeTruthy();\n      expect(maxTagPlaceholderElement.innerText.trim()).toBe(\n        `+ ${testComponent.value.length - testComponent.maxTagCount} ...`\n      );\n    }));\n\n    it('should set selectable', fakeAsync(() => {\n      treeSelect.nativeElement.click();\n      fixture.detectChanges();\n      expect(treeSelectComponent.nzOpen).toBe(true);\n      let node = overlayContainerElement.querySelector('.ant-select-tree-node-content-wrapper')!;\n      dispatchMouseEvent(node, 'click');\n      fixture.detectChanges();\n      flush();\n      expect(treeSelectComponent.nzOpen).toBe(false);\n      testComponent.nodes[0].selectable = false;\n      treeSelect.nativeElement.click();\n      fixture.detectChanges();\n      expect(treeSelectComponent.nzOpen).toBe(true);\n      node = overlayContainerElement.querySelector('nz-tree-node[builtin]')!;\n      dispatchMouseEvent(node, 'click');\n      fixture.detectChanges();\n      flush();\n      expect(treeSelectComponent.nzOpen).toBe(true);\n    }));\n\n    it('should nzBackdrop work', fakeAsync(() => {\n      testComponent.hasBackdrop = true;\n      fixture.detectChanges();\n      treeSelect.nativeElement.click();\n      fixture.detectChanges();\n      const boundingBox = overlayContainerElement.children[0];\n      expect(boundingBox.children[0].classList).toContain('cdk-overlay-backdrop');\n    }));\n\n    it('should isComposing/inputValue is correct', fakeAsync(() => {\n      treeSelectComponent.inputValue = '';\n      treeSelectComponent.isComposingChange(true);\n      treeSelectComponent.setInputValue('1011');\n      flush();\n      expect(treeSelectComponent.isComposing).toBe(true);\n      expect(treeSelectComponent.inputValue).toBe('');\n    }));\n\n    it('should nzPrefix work', () => {\n      const host = fixture.debugElement.nativeElement;\n      testComponent.prefix = 'prefix';\n      fixture.detectChanges();\n      expect(host.querySelector('.ant-select-prefix')!.textContent?.trim()).toBe('prefix');\n\n      testComponent.prefix = testComponent.affixTemplate;\n      fixture.detectChanges();\n      expect(host.querySelector('.ant-select-prefix')!.textContent?.trim()).toBe('icon');\n    });\n\n    it('should nzSuffixIcon work', () => {\n      const host = fixture.debugElement.nativeElement;\n      expect(host.querySelector('.anticon-down')).toBeTruthy();\n      testComponent.suffixIcon = testComponent.affixTemplate;\n      fixture.detectChanges();\n      expect(host.querySelector('nz-select-arrow')!.textContent?.trim()).toBe('icon');\n    });\n  });\n\n  describe('checkable', () => {\n    let fixture: ComponentFixture<NzTestTreeSelectCheckableComponent>;\n    let testComponent: NzTestTreeSelectCheckableComponent;\n    let treeSelectComponent: NzTreeSelectComponent;\n    let treeSelect: DebugElement;\n\n    beforeEach(fakeAsync(() => {\n      fixture = TestBed.createComponent(NzTestTreeSelectCheckableComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n      treeSelect = fixture.debugElement.query(By.directive(NzTreeSelectComponent));\n      treeSelectComponent = treeSelect.componentInstance;\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n    }));\n\n    it('should is multiple', fakeAsync(() => {\n      treeSelect.nativeElement.click();\n      fixture.detectChanges();\n      expect(treeSelectComponent.nzOpen).toBe(true);\n      expect(treeSelectComponent.isMultiple).toBe(true);\n      flush();\n    }));\n\n    it('should update input width', fakeAsync(() => {\n      treeSelect.nativeElement.click();\n      fixture.detectChanges();\n      testComponent.showSearch = true;\n      fixture.detectChanges();\n      flush();\n      const input = treeSelect.nativeElement.querySelector('input') as HTMLInputElement;\n      typeInElement('test', input);\n      fixture.detectChanges();\n      flush();\n      typeInElement('test test test', input);\n      fixture.detectChanges();\n      flush();\n      treeSelectComponent.inputValue = '';\n      fixture.detectChanges();\n      flush();\n      typeInElement('', input);\n      fixture.detectChanges();\n      flush();\n      zone.simulateZoneExit();\n      fixture.detectChanges();\n      expect(input.style.width === '').toBe(true);\n    }));\n\n    it('should set null value work', fakeAsync(() => {\n      fixture.detectChanges();\n      expect(testComponent.value![0]).toBe('1000122');\n      testComponent.setNull();\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(testComponent.value).toBe(null);\n      expect(testComponent.nzSelectTreeComponent.selectedNodes.length).toBe(0);\n      expect(testComponent.nzSelectTreeComponent.value.length).toBe(0);\n    }));\n\n    it('should not check strictly work', fakeAsync(() => {\n      fixture.detectChanges();\n      testComponent.value = ['1001', '10001', '100012'];\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(testComponent.nzSelectTreeComponent.selectedNodes.length).toBe(1);\n      flush();\n    }));\n\n    it('should check strictly work', fakeAsync(() => {\n      fixture.detectChanges();\n      testComponent.checkStrictly = true;\n      testComponent.value = ['1001', '10001', '100012'];\n      fixture.detectChanges();\n      tick();\n      fixture.detectChanges();\n      expect(testComponent.nzSelectTreeComponent.selectedNodes.length).toBe(3);\n      testComponent.checkStrictly = false;\n      flush();\n      fixture.detectChanges();\n    }));\n\n    it('should remove checked when press backs', fakeAsync(() => {\n      treeSelect.nativeElement.click();\n      fixture.detectChanges();\n      testComponent.showSearch = true;\n      fixture.detectChanges();\n      flush();\n      const input = treeSelect.nativeElement.querySelector('input') as HTMLInputElement;\n      const BACKSPACE_EVENT = createKeyboardEvent('keydown', BACKSPACE, input);\n      treeSelectComponent.updateSelectedNodes();\n      fixture.detectChanges();\n      expect(treeSelectComponent.selectedNodes.length === 1).toBe(true);\n      treeSelectComponent.onKeyDownInput(BACKSPACE_EVENT);\n      fixture.detectChanges();\n      tick(200);\n      expect(treeSelectComponent.selectedNodes.length === 0).toBe(true);\n      treeSelectComponent.onKeyDownInput(BACKSPACE_EVENT);\n      fixture.detectChanges();\n      tick(200);\n      expect(treeSelectComponent.selectedNodes.length === 0).toBe(true);\n    }));\n\n    it('should click option not close dropdown', fakeAsync(() => {\n      treeSelect.nativeElement.click();\n      fixture.detectChanges();\n      expect(treeSelectComponent.nzOpen).toBe(true);\n      fixture.detectChanges();\n      const targetNode = overlayContainerElement.querySelectorAll('nz-tree-node[builtin]')[2];\n      dispatchMouseEvent(targetNode, 'click');\n      fixture.detectChanges();\n      flush();\n      expect(treeSelectComponent.nzOpen).toBe(true);\n    }));\n\n    it('should prevent open the dropdown when click remove', fakeAsync(() => {\n      testComponent.value = ['1000122'];\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(treeSelectComponent.selectedNodes.length).toBe(1);\n      treeSelect.nativeElement.querySelector('.ant-select-selection-item-remove').click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(treeSelectComponent.selectedNodes.length).toBe(0);\n      expect(treeSelectComponent.nzOpen).toBe(false);\n    }));\n\n    it('should display no data', fakeAsync(() => {\n      treeSelectComponent.updateSelectedNodes();\n      fixture.detectChanges();\n      testComponent.showSearch = true;\n      fixture.detectChanges();\n      treeSelect.nativeElement.click();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('nz-tree')!.getAttribute('hidden')).toBeNull();\n      expect(overlayContainerElement.querySelector('.ant-select-not-found')).toBeFalsy();\n      fixture.detectChanges();\n      treeSelectComponent.inputValue = 'invalid_value';\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('nz-tree')!.getAttribute('hidden')).toBe('');\n      expect(overlayContainerElement.querySelector('.ant-select-not-found')).toBeTruthy();\n    }));\n  });\n\n  describe('form', () => {\n    let fixture: ComponentFixture<NzTestTreeSelectFormComponent>;\n    let testComponent: NzTestTreeSelectFormComponent;\n    let treeSelect: DebugElement;\n    let treeSelectComponent: NzTreeSelectComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTreeSelectFormComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n      treeSelect = fixture.debugElement.query(By.directive(NzTreeSelectComponent));\n      treeSelectComponent = treeSelect.componentInstance;\n    });\n\n    it('should set disabled work', fakeAsync(() => {\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      const nativeElement = treeSelect.nativeElement as HTMLElement;\n      expect(nativeElement.classList).not.toContain('ant-select-disabled');\n      expect(nativeElement.querySelector('nz-select-clear')).not.toBeNull();\n      testComponent.disable();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(nativeElement.classList).toContain('ant-select-disabled');\n      expect(nativeElement.querySelector('nz-select-clear')).toBeNull();\n    }));\n\n    it('should set null value work', fakeAsync(() => {\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      expect(testComponent.formControl.value).toBe('10021');\n      testComponent.setNull();\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n      expect(testComponent.formControl.value).toBe(null);\n      expect(treeSelectComponent.selectedNodes.length).toBe(0);\n      expect(treeSelectComponent.value.length).toBe(0);\n    }));\n  });\n\n  describe('tree component', () => {\n    let fixture: ComponentFixture<NzTestTreeSelectCheckableComponent>;\n    let testComponent: NzTestTreeSelectCheckableComponent;\n    let treeSelectComponent: NzTreeSelectComponent;\n    let treeSelect: DebugElement;\n\n    beforeEach(fakeAsync(() => {\n      fixture = TestBed.createComponent(NzTestTreeSelectCheckableComponent);\n      fixture.detectChanges();\n      testComponent = fixture.debugElement.componentInstance;\n      treeSelect = fixture.debugElement.query(By.directive(NzTreeSelectComponent));\n      treeSelectComponent = treeSelect.componentInstance;\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      tick(200);\n      fixture.detectChanges();\n    }));\n\n    it('should keep expand state', () => {\n      testComponent.expandKeys = [];\n      treeSelect.nativeElement.click();\n      fixture.detectChanges();\n      expect(treeSelectComponent.nzExpandedKeys.length === 0).toBe(true);\n      expect(treeSelectComponent.nzOpen).toBe(true);\n      let targetSwitcher = overlayContainerElement.querySelector('.ant-select-tree-switcher')!;\n      expect(targetSwitcher.classList.contains('ant-select-tree-switcher_close')).toBe(true);\n      fixture.detectChanges();\n      dispatchMouseEvent(targetSwitcher, 'click');\n      fixture.detectChanges();\n      targetSwitcher = overlayContainerElement.querySelector('.ant-select-tree-switcher')!;\n      expect(targetSwitcher.classList.contains('ant-select-tree-switcher_open')).toBe(true);\n      expect(treeSelectComponent.nzExpandedKeys[0] === '1001').toBe(true);\n      treeSelect.nativeElement.click();\n      fixture.detectChanges();\n      expect(treeSelectComponent.nzOpen).toBe(false);\n      treeSelect.nativeElement.click();\n      fixture.detectChanges();\n      targetSwitcher = overlayContainerElement.querySelector('.ant-select-tree-switcher')!;\n      expect(treeSelectComponent.nzOpen).toBe(true);\n      expect(targetSwitcher.classList.contains('ant-select-tree-switcher_open')).toBe(true);\n      expect(treeSelectComponent.nzExpandedKeys[0] === '1001').toBe(true);\n    });\n  });\n\n  describe('customized icon', () => {\n    let fixture: ComponentFixture<NzTestTreeSelectCustomizedIconComponent>;\n    let treeSelect: DebugElement;\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTreeSelectCustomizedIconComponent);\n      treeSelect = fixture.debugElement.query(By.directive(NzTreeSelectComponent));\n    });\n\n    it('should display', fakeAsync(() => {\n      fixture.detectChanges();\n      treeSelect.nativeElement.click();\n      flush();\n      fixture.detectChanges();\n      expect(overlayContainerElement.querySelector('.anticon.anticon-frown-o')).toBeTruthy();\n    }));\n  });\n\n  describe('Status', () => {\n    let fixture: ComponentFixture<NzTestTreeSelectStatusComponent>;\n    let treeSelect: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTreeSelectStatusComponent);\n      treeSelect = fixture.debugElement.query(By.directive(NzTreeSelectComponent));\n    });\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n      expect(treeSelect.nativeElement.className).toContain('ant-select-status-error');\n\n      fixture.componentInstance.status = 'warning';\n      fixture.detectChanges();\n      expect(treeSelect.nativeElement.className).toContain('ant-select-status-warning');\n\n      fixture.componentInstance.status = '';\n      fixture.detectChanges();\n      expect(treeSelect.nativeElement.className).not.toContain('ant-select-status-warning');\n    });\n  });\n\n  describe('in form', () => {\n    let fixture: ComponentFixture<NzTestTreeSelectInFormComponent>;\n    let treeSelect!: HTMLElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTreeSelectInFormComponent);\n      treeSelect = fixture.debugElement.query(By.directive(NzTreeSelectComponent)).nativeElement;\n    });\n\n    it('should className correct', () => {\n      fixture.detectChanges();\n      expect(treeSelect.classList).toContain('ant-select-status-error');\n\n      fixture.componentInstance.status = 'warning';\n      fixture.detectChanges();\n      expect(treeSelect.classList).toContain('ant-select-status-warning');\n\n      fixture.componentInstance.status = 'success';\n      fixture.detectChanges();\n      expect(treeSelect.classList).toContain('ant-select-status-success');\n\n      fixture.componentInstance.feedback = false;\n      fixture.detectChanges();\n      expect(treeSelect.querySelector('nz-form-item-feedback-icon')).toBeNull();\n    });\n  });\n\n  describe('virtual scroll', () => {\n    let fixture: ComponentFixture<NzTestTreeSelectVirtualScrollComponent>;\n    let treeSelect: DebugElement;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTreeSelectVirtualScrollComponent);\n      treeSelect = fixture.debugElement.query(By.directive(NzTreeSelectComponent));\n    });\n\n    it('should set nzVirtualHeight work', fakeAsync(() => {\n      fixture.detectChanges();\n      treeSelect.nativeElement.click();\n      flush();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      const virtualScrollViewport = overlayContainerElement.querySelector('.cdk-virtual-scroll-viewport')!;\n      expect(window.getComputedStyle(virtualScrollViewport).height).toBe('300px');\n    }));\n\n    it('should support x-scroll when the length of node label is greater than the length of select dropdown', fakeAsync(() => {\n      fixture.detectChanges();\n      treeSelect.nativeElement.click();\n      flush();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n      overlayContainerElement\n        .querySelector('.cdk-virtual-scroll-content-wrapper')!\n        .setAttribute('style', 'width: 250px');\n      const virtualScrollViewport = overlayContainerElement.querySelector('.cdk-virtual-scroll-content-wrapper')!;\n      expect(virtualScrollViewport.clientWidth).toBe(250);\n      expect(virtualScrollViewport.scrollWidth).toBeGreaterThan(250);\n    }));\n  });\n});\n\ndescribe('tree-select finalSize', () => {\n  let fixture: ComponentFixture<TestTreeSelectFinalSizeComponent>;\n  let treeSelectElement: HTMLElement;\n  let compactSizeSignal: WritableSignal<NzSizeLDSType>;\n  let formSizeSignal: WritableSignal<NzSizeLDSType>;\n\n  beforeEach(() => {\n    compactSizeSignal = signal<NzSizeLDSType>('large');\n    formSizeSignal = signal<NzSizeLDSType>('default');\n  });\n  afterEach(() => {\n    TestBed.resetTestingModule();\n  });\n\n  it('should set correctly the size from the formSize signal', () => {\n    TestBed.configureTestingModule({\n      providers: [\n        { provide: NZ_FORM_SIZE, useValue: formSizeSignal },\n        { provide: NZ_SPACE_COMPACT_SIZE, useValue: compactSizeSignal }\n      ]\n    });\n    fixture = TestBed.createComponent(TestTreeSelectFinalSizeComponent);\n    treeSelectElement = fixture.debugElement.query(By.directive(NzTreeSelectComponent)).nativeElement;\n    fixture.detectChanges();\n    formSizeSignal.set('large');\n    fixture.detectChanges();\n    expect(treeSelectElement.classList).toContain('ant-select-lg');\n  });\n  it('should set correctly the size from the compactSize signal', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_SPACE_COMPACT_SIZE, useValue: compactSizeSignal }]\n    });\n    fixture = TestBed.createComponent(TestTreeSelectFinalSizeComponent);\n    treeSelectElement = fixture.debugElement.query(By.directive(NzTreeSelectComponent)).nativeElement;\n    fixture.detectChanges();\n    expect(treeSelectElement.classList).toContain('ant-select-lg');\n  });\n  it('should set correctly the size from the component input', () => {\n    fixture = TestBed.createComponent(TestTreeSelectFinalSizeComponent);\n    treeSelectElement = fixture.debugElement.query(By.directive(NzTreeSelectComponent)).nativeElement;\n    fixture.componentInstance.size = 'large';\n    fixture.detectChanges();\n    expect(treeSelectElement.classList).toContain('ant-select-lg');\n  });\n});\n\ndescribe('finalVariant', () => {\n  let fixture: ComponentFixture<TestTreeSelectFinalVariantComponent>;\n  let treeSelectElement: HTMLElement;\n  let formVariantSignal: WritableSignal<NzVariant>;\n\n  beforeEach(() => {\n    formVariantSignal = signal<NzVariant>('outlined');\n  });\n  afterEach(() => {\n    TestBed.resetTestingModule();\n  });\n  it('should use formVariant when nzVariant is not set (undefined by default)', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_FORM_VARIANT, useValue: formVariantSignal }]\n    });\n    fixture = TestBed.createComponent(TestTreeSelectFinalVariantComponent);\n    treeSelectElement = fixture.debugElement.query(By.directive(NzTreeSelectComponent)).nativeElement;\n    fixture.detectChanges();\n    formVariantSignal.set('filled');\n    fixture.detectChanges();\n    expect(treeSelectElement.classList).toContain('ant-select-filled');\n  });\n\n  it('should use nzVariant over formVariant when nzVariant is explicitly set', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_FORM_VARIANT, useValue: formVariantSignal }]\n    });\n    fixture = TestBed.createComponent(TestTreeSelectFinalVariantComponent);\n    treeSelectElement = fixture.debugElement.query(By.directive(NzTreeSelectComponent)).nativeElement;\n    fixture.componentInstance.variant.set('borderless');\n    fixture.detectChanges();\n    formVariantSignal.set('filled');\n    fixture.detectChanges();\n    expect(treeSelectElement.classList).toContain('ant-select-borderless');\n    expect(treeSelectElement.classList).not.toContain('ant-select-filled');\n  });\n\n  it('should use nzVariant outlined over formVariant when explicitly set', () => {\n    TestBed.configureTestingModule({\n      providers: [{ provide: NZ_FORM_VARIANT, useValue: formVariantSignal }]\n    });\n    fixture = TestBed.createComponent(TestTreeSelectFinalVariantComponent);\n    treeSelectElement = fixture.debugElement.query(By.directive(NzTreeSelectComponent)).nativeElement;\n    fixture.componentInstance.variant.set('outlined');\n    fixture.detectChanges();\n    formVariantSignal.set('filled');\n    fixture.detectChanges();\n    expect(treeSelectElement.classList).not.toContain('ant-select-filled');\n  });\n\n  it('should use nzVariant when no formVariant is provided', () => {\n    fixture = TestBed.createComponent(TestTreeSelectFinalVariantComponent);\n    treeSelectElement = fixture.debugElement.query(By.directive(NzTreeSelectComponent)).nativeElement;\n    fixture.componentInstance.variant.set('filled');\n    fixture.detectChanges();\n    expect(treeSelectElement.classList).toContain('ant-select-filled');\n  });\n\n  it('should default to outlined when neither nzVariant nor formVariant is set', () => {\n    fixture = TestBed.createComponent(TestTreeSelectFinalVariantComponent);\n    treeSelectElement = fixture.debugElement.query(By.directive(NzTreeSelectComponent)).nativeElement;\n    fixture.detectChanges();\n    expect(treeSelectElement.classList).not.toContain('ant-select-filled');\n    expect(treeSelectElement.classList).not.toContain('ant-select-borderless');\n    expect(treeSelectElement.classList).not.toContain('ant-select-underlined');\n  });\n});\n\n@Component({\n  imports: [NzTreeSelectModule, FormsModule],\n  template: `\n    <nz-tree-select\n      style=\"width:250px;position: relative;display: block;\"\n      nzPlaceHolder=\"Please select\"\n      [nzExpandedKeys]=\"expandKeys\"\n      [nzNodes]=\"nodes\"\n      [(ngModel)]=\"value\"\n      [nzSize]=\"size\"\n      [nzVariant]=\"variant\"\n      [nzAllowClear]=\"allowClear\"\n      [nzDropdownMatchSelectWidth]=\"dropdownMatchSelectWidth\"\n      [nzDisabled]=\"disabled\"\n      [nzShowSearch]=\"showSearch\"\n      [nzMultiple]=\"multiple\"\n      [nzMaxTagCount]=\"maxTagCount\"\n      [nzDropdownStyle]=\"{ height: '120px' }\"\n      [nzBackdrop]=\"hasBackdrop\"\n      [nzPrefix]=\"prefix\"\n      [nzSuffixIcon]=\"suffixIcon\"\n      nzDropdownClassName=\"class1 class2\"\n    />\n    <ng-template #affixTemplate>icon</ng-template>\n  `\n})\nexport class NzTestTreeSelectBasicComponent {\n  @ViewChild(NzTreeSelectComponent, { static: false }) nzSelectTreeComponent!: NzTreeSelectComponent;\n  @ViewChild('affixTemplate', { static: false }) affixTemplate!: TemplateRef<void>;\n  expandKeys = ['1001', '10001'];\n  value: string | string[] | null = '10001';\n  size: NzSizeLDSType = 'default';\n  variant: NzVariant = 'outlined';\n  allowClear = false;\n  disabled = false;\n  showSearch = false;\n  dropdownMatchSelectWidth = true;\n  multiple = false;\n  maxTagCount = Infinity;\n  prefix: string | TemplateRef<void> | null = null;\n  suffixIcon: string | TemplateRef<void> | null = null;\n  nodes: NzTreeNodeOptions[] = [\n    {\n      title: 'root1',\n      key: '1001',\n      children: [\n        {\n          title: 'child1',\n          key: '10001',\n          children: [\n            {\n              title: 'child1.1',\n              key: '100011',\n              children: []\n            },\n            {\n              title: 'child1.2',\n              key: '100012',\n              children: [\n                {\n                  title: 'grandchild1.2.1',\n                  key: '1000121',\n                  isLeaf: true,\n                  disabled: true\n                },\n                {\n                  title: 'grandchild1.2.2',\n                  key: '1000122',\n                  isLeaf: true\n                }\n              ]\n            }\n          ]\n        }\n      ]\n    },\n    {\n      title: 'root2',\n      key: '1002',\n      children: [\n        {\n          title: 'child2.1',\n          key: '10021',\n          children: [],\n          disableCheckbox: true\n        },\n        {\n          title: 'child2.2',\n          key: '10022',\n          children: [\n            {\n              title: 'grandchild2.2.1',\n              key: '100221',\n              isLeaf: true\n            }\n          ]\n        }\n      ]\n    }\n  ];\n  hasBackdrop = false;\n\n  setNull(): void {\n    this.value = null;\n  }\n}\n\n@Component({\n  imports: [FormsModule, NzTreeSelectModule],\n  template: `\n    <nz-tree-select\n      nzPlaceHolder=\"Please select\"\n      [nzExpandedKeys]=\"expandKeys\"\n      [nzNodes]=\"nodes\"\n      [nzShowSearch]=\"showSearch\"\n      [nzCheckable]=\"true\"\n      [nzCheckStrictly]=\"checkStrictly\"\n      [(ngModel)]=\"value\"\n    />\n  `\n})\nexport class NzTestTreeSelectCheckableComponent {\n  @ViewChild(NzTreeSelectComponent, { static: false }) nzSelectTreeComponent!: NzTreeSelectComponent;\n  expandKeys = ['1001', '10001'];\n  value: string[] | null = ['1000122'];\n  showSearch = false;\n  checkStrictly = false;\n  nodes = [\n    {\n      title: 'root1',\n      key: '1001',\n      children: [\n        {\n          title: 'child1',\n          key: '10001',\n          children: [\n            {\n              title: 'child1.1',\n              key: '100011',\n              children: []\n            },\n            {\n              title: 'child1.2',\n              key: '100012',\n              children: [\n                {\n                  title: 'grandchild1.2.1',\n                  key: '1000121',\n                  isLeaf: true,\n                  disabled: true\n                },\n                {\n                  title: 'grandchild1.2.2',\n                  key: '1000122',\n                  isLeaf: true\n                }\n              ]\n            }\n          ]\n        }\n      ]\n    },\n    {\n      title: 'root2',\n      key: '1002',\n      children: [\n        {\n          title: 'child2.1',\n          key: '10021',\n          children: [],\n          disableCheckbox: true\n        },\n        {\n          title: 'child2.2',\n          key: '10022',\n          children: [\n            {\n              title: 'grandchild2.2.1',\n              key: '100221',\n              isLeaf: true\n            }\n          ]\n        }\n      ]\n    }\n  ];\n\n  setNull(): void {\n    this.value = null;\n  }\n}\n\n@Component({\n  imports: [ReactiveFormsModule, NzTreeSelectModule],\n  template: `\n    <form>\n      <nz-tree-select [formControl]=\"formControl\" [nzNodes]=\"nodes\" />\n    </form>\n  `\n})\nexport class NzTestTreeSelectFormComponent {\n  formControl = new FormControl('10021');\n  nodes = [\n    {\n      title: 'root2',\n      key: '1002',\n      children: [\n        {\n          title: 'child2.1',\n          key: '10021'\n        },\n        {\n          title: 'child2.2',\n          key: '10022'\n        }\n      ]\n    }\n  ].map(item => new NzTreeNode(item));\n\n  disable(): void {\n    this.formControl.disable();\n  }\n\n  setNull(): void {\n    this.formControl.reset(null);\n  }\n}\n\n@Component({\n  imports: [FormsModule, NzTreeSelectModule],\n  template: `\n    <nz-tree-select [nzNodes]=\"nodes\" [(ngModel)]=\"value\">\n      <ng-template #nzTreeTemplate let-node>\n        <span>\n          <span class=\"anticon anticon-frown-o\"></span>\n          {{ node.title }}\n        </span>\n      </ng-template>\n    </nz-tree-select>\n  `\n})\nexport class NzTestTreeSelectCustomizedIconComponent {\n  value?: string;\n  nodes = [\n    new NzTreeNode({\n      title: 'root3',\n      key: '1003',\n      children: [\n        {\n          title: 'child3.1',\n          key: '10031'\n        },\n        {\n          title: 'child3.2',\n          key: '10032'\n        }\n      ]\n    })\n  ];\n}\n\n@Component({\n  imports: [FormsModule, NzTreeSelectModule],\n  template: `\n    <nz-tree-select\n      [nzNodes]=\"nodes\"\n      nzShowSearch\n      [nzStatus]=\"status\"\n      nzPlaceHolder=\"Please select\"\n      [(ngModel)]=\"value\"\n    />\n  `\n})\nexport class NzTestTreeSelectStatusComponent {\n  status: NzStatus = 'error';\n  value?: string = '1001';\n  nodes = [\n    {\n      title: 'parent 1',\n      key: '100',\n      children: [\n        {\n          title: 'parent 1-0',\n          key: '1001',\n          children: [\n            { title: 'leaf 1-0-0', key: '10010', isLeaf: true },\n            { title: 'leaf 1-0-1', key: '10011', isLeaf: true }\n          ]\n        },\n        {\n          title: 'parent 1-1',\n          key: '1002',\n          children: [{ title: 'leaf 1-1-0', key: '10020', isLeaf: true }]\n        }\n      ]\n    }\n  ];\n}\n\n@Component({\n  imports: [ReactiveFormsModule, NzFormModule, NzTreeSelectModule],\n  template: `\n    <form nz-form>\n      <nz-form-item>\n        <nz-form-control [nzHasFeedback]=\"feedback\" [nzValidateStatus]=\"status\">\n          <nz-tree-select [nzNodes]=\"[]\" />\n        </nz-form-control>\n      </nz-form-item>\n    </form>\n  `\n})\nexport class NzTestTreeSelectInFormComponent {\n  status: NzFormControlStatusType = 'error';\n  feedback = true;\n}\n\nfunction dig(path = '0', level = 3): NzTreeNodeOptions[] {\n  const list: NzTreeNodeOptions[] = [];\n  for (let i = 0; i < 10; i += 1) {\n    // long key for overflow\n    const key = `${path}-${i}-${Array(50).join('x')}`;\n    const treeNode: NzTreeNodeOptions = {\n      title: key,\n      key,\n      expanded: true,\n      children: [],\n      isLeaf: false\n    };\n\n    if (level > 0) {\n      treeNode.children = dig(key, level - 1);\n    } else {\n      treeNode.isLeaf = true;\n    }\n\n    list.push(treeNode);\n  }\n  return list;\n}\n\n@Component({\n  imports: [NzTreeSelectModule],\n  template: `\n    <nz-tree-select\n      [nzNodes]=\"nodes\"\n      nzShowSearch\n      nzPlaceHolder=\"Please select\"\n      nzVirtualHeight=\"300px\"\n      nzHideUnMatched=\"true\"\n      [nzDropdownMatchSelectWidth]=\"true\"\n    />\n  `\n})\nexport class NzTestTreeSelectVirtualScrollComponent {\n  nodes: NzTreeNodeOptions[] = dig();\n}\n\n@Component({\n  imports: [NzTreeSelectModule],\n  template: `<nz-tree-select [nzNodes]=\"[]\" [nzSize]=\"size\" />`\n})\nexport class TestTreeSelectFinalSizeComponent {\n  size: NzSizeLDSType = 'default';\n}\n\n@Component({\n  imports: [NzTreeSelectComponent],\n  template: `<nz-tree-select [nzVariant]=\"variant()\" />`\n})\nexport class TestTreeSelectFinalVariantComponent {\n  readonly variant = signal<NzVariant | undefined>(undefined);\n}\n"
  },
  {
    "path": "components/tree-view/checkbox.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { SelectionModel } from '@angular/cdk/collections';\nimport { Component, OnInit, ViewChild } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzTreeViewFlatDataSource } from './flat-data-source';\nimport { NzTreeFlattener } from './flattener';\nimport { NzTreeViewComponent } from './tree-view';\nimport { NzTreeViewModule } from './tree-view.module';\nimport { getParent, getDescendants } from './utils';\n\ndescribe('checkbox component for tree view', () => {\n  let fixture: ComponentFixture<NzTestTreeViewCheckBoxComponent>;\n  let testComponent: NzTestTreeViewCheckBoxComponent;\n\n  beforeEach(async () => {\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideNoopAnimations()]\n    });\n    fixture = TestBed.createComponent(NzTestTreeViewCheckBoxComponent);\n    testComponent = fixture.componentInstance;\n    await fixture.whenStable();\n    // expand all node\n    const { tree } = testComponent;\n    tree.expandAll();\n    await fixture.whenStable();\n  });\n\n  it('should check all children nodes when the parent is checked, vice versa', async () => {\n    const nodes = fixture.debugElement.queryAll(By.css('nz-tree-node-checkbox'));\n    const parent_1 = nodes[0];\n    // checked parent\n    parent_1.nativeElement.click();\n    await fixture.whenStable();\n    nodes.slice(0, 6).forEach(node => {\n      expect(node.nativeElement.classList).toContain('ant-tree-checkbox-checked');\n    });\n    nodes.slice(6, nodes.length).forEach(node => {\n      expect(node.nativeElement.classList).not.toContain('ant-tree-checkbox-checked');\n    });\n    // unchecked parent\n    parent_1.nativeElement.click();\n    await fixture.whenStable();\n    nodes.forEach(node => {\n      expect(node.nativeElement.classList).not.toContain('ant-tree-checkbox-checked');\n    });\n  });\n\n  it('should indeterminate parent when its child is checked', async () => {\n    const nodes = fixture.debugElement.queryAll(By.css('nz-tree-node-checkbox'));\n    const leaf_1_1_1 = nodes[2];\n    leaf_1_1_1.nativeElement.click();\n    await fixture.whenStable();\n    expect(leaf_1_1_1.nativeElement.classList).toContain('ant-tree-checkbox-checked');\n    const parent_1_1 = nodes[1];\n    const parent_1 = nodes[0];\n    expect(parent_1_1.nativeElement.classList).toContain('ant-tree-checkbox-indeterminate');\n    expect(parent_1.nativeElement.classList).toContain('ant-tree-checkbox-indeterminate');\n    nodes.slice(3, 8).forEach(node => {\n      expect(node.nativeElement.classList).not.toContain('ant-tree-checkbox-checked');\n    });\n  });\n\n  it('should not be checked when the node is disabled', async () => {\n    const checkboxList = fixture.debugElement.queryAll(By.css('nz-tree-node-checkbox'));\n    const parent_1_1 = fixture.debugElement.queryAll(By.css('nz-tree-node:not([builtin])'))[1];\n    const parent_1_1_checkbox = parent_1_1.query(By.css('nz-tree-node-checkbox'));\n    // disable status\n    expect(parent_1_1.nativeElement.classList).toContain('ant-tree-treenode-disabled');\n    expect(parent_1_1_checkbox.nativeElement.classList).toContain('ant-tree-checkbox-disabled');\n\n    // click\n    parent_1_1.nativeElement.click();\n    await fixture.whenStable();\n    checkboxList.forEach(checkbox => {\n      expect(checkbox.nativeElement.classList).not.toContain('ant-tree-checkbox-checked');\n    });\n    parent_1_1_checkbox.nativeElement.click();\n    await fixture.whenStable();\n    checkboxList.forEach(checkbox => {\n      expect(checkbox.nativeElement.classList).not.toContain('ant-tree-checkbox-checked');\n    });\n  });\n});\n\ninterface FlatNode {\n  expandable: boolean;\n  name: string;\n  level: number;\n  disabled: boolean;\n}\n\ninterface TreeNode {\n  name: string;\n  children?: TreeNode[];\n  disabled?: boolean;\n}\n\nconst TREE_DATA: TreeNode[] = [\n  {\n    name: 'parent 1',\n    children: [\n      {\n        name: 'parent 1-1',\n        disabled: true,\n        children: [{ name: 'leaf 1-1-1' }, { name: 'leaf 1-1-2' }]\n      },\n      {\n        name: 'parent 1-2',\n        children: [{ name: 'leaf 1-2-1' }]\n      }\n    ]\n  },\n  {\n    name: 'parent 2',\n    children: [{ name: 'leaf 2-1' }]\n  }\n];\n\n@Component({\n  imports: [NzIconModule, NzTreeViewModule],\n  template: `\n    <nz-tree-view [nzDataSource]=\"dataSource\" [nzLevelAccessor]=\"levelAccessor\">\n      <nz-tree-node *nzTreeNodeDef=\"let node\" nzTreeNodeIndentLine [nzExpandable]=\"false\">\n        <nz-tree-node-checkbox\n          [nzDisabled]=\"node.disabled\"\n          [nzChecked]=\"checklistSelection.isSelected(node)\"\n          (nzClick)=\"leafItemSelectionToggle(node)\"\n        />\n        <nz-tree-node-option [nzDisabled]=\"node.disabled\" (nzClick)=\"leafItemSelectionToggle(node)\">\n          {{ node.name }}\n        </nz-tree-node-option>\n      </nz-tree-node>\n\n      <nz-tree-node *nzTreeNodeDef=\"let node; when: hasChild\" nzTreeNodeIndentLine [nzExpandable]=\"true\">\n        <nz-tree-node-toggle>\n          <nz-icon nzType=\"caret-down\" nzTreeNodeToggleRotateIcon />\n        </nz-tree-node-toggle>\n        <nz-tree-node-checkbox\n          [nzDisabled]=\"node.disabled\"\n          [nzChecked]=\"descendantsAllSelected(node)\"\n          [nzIndeterminate]=\"descendantsPartiallySelected(node)\"\n          (nzClick)=\"itemSelectionToggle(node)\"\n        />\n        <nz-tree-node-option [nzDisabled]=\"node.disabled\" (nzClick)=\"itemSelectionToggle(node)\">\n          {{ node.name }}\n        </nz-tree-node-option>\n      </nz-tree-node>\n    </nz-tree-view>\n  `\n})\nexport class NzTestTreeViewCheckBoxComponent implements OnInit {\n  @ViewChild(NzTreeViewComponent, { static: true }) tree!: NzTreeViewComponent<FlatNode>;\n  levelAccessor = (dataNode: FlatNode): number => dataNode.level;\n  hasChild = (_: number, node: FlatNode): boolean => node.expandable;\n  transformer = (node: TreeNode, level: number): FlatNode => ({\n    expandable: !!node.children && node.children.length > 0,\n    name: node.name,\n    level,\n    disabled: !!node.disabled\n  });\n  checklistSelection = new SelectionModel<FlatNode>(true);\n  treeFlattener = new NzTreeFlattener(\n    this.transformer,\n    node => node.level,\n    node => node.expandable,\n    node => node.children\n  );\n  dataSource!: NzTreeViewFlatDataSource<TreeNode, FlatNode>;\n\n  ngOnInit(): void {\n    this.dataSource = new NzTreeViewFlatDataSource(this.tree, this.treeFlattener, TREE_DATA);\n  }\n\n  private getDescendants(node: FlatNode): FlatNode[] {\n    return getDescendants(this.tree.dataNodes, node, this.levelAccessor);\n  }\n\n  private getParentNode(node: FlatNode): FlatNode | null {\n    return getParent(this.tree.dataNodes, node, this.levelAccessor);\n  }\n\n  descendantsAllSelected(node: FlatNode): boolean {\n    const descendants = this.getDescendants(node);\n    return descendants.length > 0 && descendants.every(child => this.checklistSelection.isSelected(child));\n  }\n\n  descendantsPartiallySelected(node: FlatNode): boolean {\n    const descendants = this.getDescendants(node);\n    const result = descendants.some(child => this.checklistSelection.isSelected(child));\n    return result && !this.descendantsAllSelected(node);\n  }\n\n  leafItemSelectionToggle(node: FlatNode): void {\n    this.checklistSelection.toggle(node);\n    this.checkAllParentsSelection(node);\n  }\n\n  itemSelectionToggle(node: FlatNode): void {\n    this.checklistSelection.toggle(node);\n    const descendants = this.getDescendants(node);\n    this.checklistSelection.isSelected(node)\n      ? this.checklistSelection.select(...descendants)\n      : this.checklistSelection.deselect(...descendants);\n\n    descendants.forEach(child => this.checklistSelection.isSelected(child));\n    this.checkAllParentsSelection(node);\n  }\n\n  checkAllParentsSelection(node: FlatNode): void {\n    let parent: FlatNode | null = this.getParentNode(node);\n    while (parent) {\n      this.checkRootNodeSelection(parent);\n      parent = this.getParentNode(parent);\n    }\n  }\n\n  checkRootNodeSelection(node: FlatNode): void {\n    const nodeSelected = this.checklistSelection.isSelected(node);\n    const descendants = this.getDescendants(node);\n    const descAllSelected =\n      descendants.length > 0 && descendants.every(child => this.checklistSelection.isSelected(child));\n    if (nodeSelected && !descAllSelected) {\n      this.checklistSelection.deselect(node);\n    } else if (!nodeSelected && descAllSelected) {\n      this.checklistSelection.select(node);\n    }\n  }\n}\n"
  },
  {
    "path": "components/tree-view/checkbox.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  ElementRef,\n  NgZone,\n  OnInit,\n  booleanAttribute,\n  inject,\n  DestroyRef,\n  input,\n  output\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { filter } from 'rxjs/operators';\n\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\n\n@Component({\n  selector: 'nz-tree-node-checkbox:not([builtin])',\n  template: `<span class=\"ant-tree-checkbox-inner\"></span>`,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    class: 'ant-tree-checkbox',\n    '[class.ant-tree-checkbox-checked]': `nzChecked()`,\n    '[class.ant-tree-checkbox-indeterminate]': `nzIndeterminate()`,\n    '[class.ant-tree-checkbox-disabled]': `nzDisabled()`\n  }\n})\nexport class NzTreeNodeCheckboxComponent implements OnInit {\n  readonly nzChecked = input(false, { transform: booleanAttribute });\n  readonly nzIndeterminate = input(false, { transform: booleanAttribute });\n  readonly nzDisabled = input(false, { transform: booleanAttribute });\n  readonly nzClick = output<MouseEvent>();\n\n  protected readonly cdr = inject(ChangeDetectorRef);\n  protected readonly destroyRef = inject(DestroyRef);\n  protected readonly elementRef = inject(ElementRef);\n  protected readonly ngZone = inject(NgZone);\n\n  ngOnInit(): void {\n    fromEventOutsideAngular<MouseEvent>(this.elementRef.nativeElement, 'click')\n      .pipe(\n        filter(() => !this.nzDisabled()),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe((event: MouseEvent) => {\n        this.ngZone.run(() => {\n          this.nzClick.emit(event);\n        });\n      });\n  }\n}\n"
  },
  {
    "path": "components/tree-view/demo/basic-children-accessor.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: nzChildrenAccessor 基本用法\n  en-US: nzChildrenAccessor basic usage\n---\n\n## zh-CN\n\n使用 `nzChildrenAccessor` 实现树视图的基本功能，包括选中，禁用，展开等功能。\n\n## en-US\n\nUse `nzChildrenAccessor` for tree view basic usage, including select, disable and expand features.\n"
  },
  {
    "path": "components/tree-view/demo/basic-children-accessor.ts",
    "content": "import { SelectionModel } from '@angular/cdk/collections';\nimport { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzTreeViewComponent, NzTreeViewModule, NzTreeViewNestedDataSource } from 'ng-zorro-antd/tree-view';\n\ninterface TreeNode {\n  name: string;\n  disabled?: boolean;\n  children?: TreeNode[];\n}\n\nconst TREE_DATA: TreeNode[] = [\n  {\n    name: 'parent 1',\n    children: [\n      {\n        name: 'parent 1-0',\n        disabled: true,\n        children: [{ name: 'leaf' }, { name: 'leaf' }]\n      },\n      {\n        name: 'parent 1-1',\n        children: [{ name: 'leaf' }]\n      }\n    ]\n  }\n];\n\n@Component({\n  imports: [NzIconModule, NzTreeViewModule],\n  selector: 'nz-demo-tree-view-basic-children-accessor',\n  template: `\n    <nz-tree-view [nzDataSource]=\"dataSource\" [nzChildrenAccessor]=\"childrenAccessor\">\n      <nz-tree-node *nzTreeNodeDef=\"let node\" nzTreeNodePadding [nzExpandable]=\"false\">\n        <nz-tree-node-toggle nzTreeNodeNoopToggle />\n        <nz-tree-node-option\n          [nzDisabled]=\"node.disabled\"\n          [nzSelected]=\"selectListSelection.isSelected(node)\"\n          (nzClick)=\"selectListSelection.toggle(node)\"\n        >\n          {{ node.name }}\n        </nz-tree-node-option>\n      </nz-tree-node>\n\n      <nz-tree-node *nzTreeNodeDef=\"let node; when: hasChild\" nzTreeNodePadding [nzExpandable]=\"true\">\n        <nz-tree-node-toggle>\n          <nz-icon nzType=\"caret-down\" nzTreeNodeToggleRotateIcon />\n        </nz-tree-node-toggle>\n        <nz-tree-node-option\n          [nzDisabled]=\"node.disabled\"\n          [nzSelected]=\"selectListSelection.isSelected(node)\"\n          (nzClick)=\"selectListSelection.toggle(node)\"\n        >\n          {{ node.name }}\n        </nz-tree-node-option>\n      </nz-tree-node>\n    </nz-tree-view>\n  `\n})\nexport class NzDemoTreeViewBasicChildrenAccessorComponent implements OnInit, AfterViewInit {\n  @ViewChild(NzTreeViewComponent, { static: true }) tree!: NzTreeViewComponent<TreeNode>;\n\n  readonly childrenAccessor = (dataNode: TreeNode): TreeNode[] => dataNode.children ?? [];\n\n  readonly hasChild = (_: number, node: TreeNode): boolean => !!node.children?.length;\n\n  selectListSelection = new SelectionModel<TreeNode>(true);\n\n  dataSource!: NzTreeViewNestedDataSource<TreeNode>;\n\n  ngOnInit(): void {\n    this.dataSource = new NzTreeViewNestedDataSource<TreeNode>(this.tree, TREE_DATA);\n  }\n\n  ngAfterViewInit(): void {\n    this.tree.expandAll();\n  }\n}\n"
  },
  {
    "path": "components/tree-view/demo/basic-level-accessor.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: nzLevelAccessor 基本用法\n  en-US: nzLevelAccessor basic usage\n---\n\n## zh-CN\n\n使用 `nzLevelAccessor` 实现树视图的基本功能，包括选中，禁用，展开等功能。\n\n## en-US\n\nUse `nzLevelAccessor` for tree view basic usage, including select, disable and expand features.\n"
  },
  {
    "path": "components/tree-view/demo/basic-level-accessor.ts",
    "content": "import { SelectionModel } from '@angular/cdk/collections';\nimport { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport {\n  NzTreeFlattener,\n  NzTreeViewComponent,\n  NzTreeViewFlatDataSource,\n  NzTreeViewModule\n} from 'ng-zorro-antd/tree-view';\n\ninterface TreeNode {\n  name: string;\n  disabled?: boolean;\n  children?: TreeNode[];\n}\n\ninterface FlatNode {\n  expandable: boolean;\n  name: string;\n  level: number;\n  disabled: boolean;\n}\n\nconst TREE_DATA: TreeNode[] = [\n  {\n    name: 'parent 1',\n    children: [\n      {\n        name: 'parent 1-0',\n        disabled: true,\n        children: [{ name: 'leaf' }, { name: 'leaf' }]\n      },\n      {\n        name: 'parent 1-1',\n        children: [{ name: 'leaf' }]\n      }\n    ]\n  }\n];\n\n@Component({\n  imports: [NzIconModule, NzTreeViewModule],\n  selector: 'nz-demo-tree-view-basic-level-accessor',\n  template: `\n    <nz-tree-view [nzDataSource]=\"dataSource\" [nzLevelAccessor]=\"levelAccessor\">\n      <nz-tree-node *nzTreeNodeDef=\"let node\" nzTreeNodePadding [nzExpandable]=\"false\">\n        <nz-tree-node-toggle nzTreeNodeNoopToggle />\n        <nz-tree-node-option\n          [nzDisabled]=\"node.disabled\"\n          [nzSelected]=\"selectListSelection.isSelected(node)\"\n          (nzClick)=\"selectListSelection.toggle(node)\"\n        >\n          {{ node.name }}\n        </nz-tree-node-option>\n      </nz-tree-node>\n\n      <nz-tree-node *nzTreeNodeDef=\"let node; when: hasChild\" nzTreeNodePadding [nzExpandable]=\"true\">\n        <nz-tree-node-toggle>\n          <nz-icon nzType=\"caret-down\" nzTreeNodeToggleRotateIcon />\n        </nz-tree-node-toggle>\n        <nz-tree-node-option\n          [nzDisabled]=\"node.disabled\"\n          [nzSelected]=\"selectListSelection.isSelected(node)\"\n          (nzClick)=\"selectListSelection.toggle(node)\"\n        >\n          {{ node.name }}\n        </nz-tree-node-option>\n      </nz-tree-node>\n    </nz-tree-view>\n  `\n})\nexport class NzDemoTreeViewBasicLevelAccessorComponent implements OnInit, AfterViewInit {\n  @ViewChild(NzTreeViewComponent, { static: true }) tree!: NzTreeViewComponent<FlatNode>;\n\n  readonly levelAccessor = (dataNode: FlatNode): number => dataNode.level;\n\n  readonly hasChild = (_: number, node: FlatNode): boolean => node.expandable;\n\n  private transformer = (node: TreeNode, level: number): FlatNode => ({\n    expandable: !!node.children && node.children.length > 0,\n    name: node.name,\n    level,\n    disabled: !!node.disabled\n  });\n\n  private treeFlattener = new NzTreeFlattener<TreeNode, FlatNode>(\n    this.transformer,\n    node => node.level,\n    node => node.expandable,\n    node => node.children\n  );\n\n  selectListSelection = new SelectionModel<FlatNode>(true);\n\n  dataSource!: NzTreeViewFlatDataSource<TreeNode, FlatNode>;\n\n  ngOnInit(): void {\n    this.dataSource = new NzTreeViewFlatDataSource(this.tree, this.treeFlattener, TREE_DATA);\n  }\n\n  ngAfterViewInit(): void {\n    this.tree.expandAll();\n  }\n}\n"
  },
  {
    "path": "components/tree-view/demo/checkbox.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 选择框\n  en-US: checkbox\n---\n\n## zh-CN\n\n带选择框的树。\n\n## en-US\n\nTree with checkboxes.\n"
  },
  {
    "path": "components/tree-view/demo/checkbox.ts",
    "content": "import { SelectionModel } from '@angular/cdk/collections';\nimport { Component, OnInit, ViewChild } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport {\n  getDescendantsForNestedData,\n  getParentForNestedData,\n  NzTreeViewComponent,\n  NzTreeViewModule,\n  NzTreeViewNestedDataSource\n} from 'ng-zorro-antd/tree-view';\n\ninterface TreeNode {\n  name: string;\n  disabled?: boolean;\n  children?: TreeNode[];\n}\n\nconst TREE_DATA: TreeNode[] = [\n  {\n    name: '0-0',\n    disabled: true,\n    children: [{ name: '0-0-0' }, { name: '0-0-1' }, { name: '0-0-2' }]\n  },\n  {\n    name: '0-1',\n    children: [\n      {\n        name: '0-1-0',\n        children: [{ name: '0-1-0-0' }, { name: '0-1-0-1' }]\n      },\n      {\n        name: '0-1-1',\n        children: [{ name: '0-1-1-0' }, { name: '0-1-1-1' }]\n      }\n    ]\n  }\n];\n\n@Component({\n  selector: 'nz-demo-tree-view-checkbox',\n  imports: [NzIconModule, NzTreeViewModule],\n  template: `\n    <nz-tree-view [nzDataSource]=\"dataSource\" [nzChildrenAccessor]=\"childrenAccessor\">\n      <nz-tree-node *nzTreeNodeDef=\"let node\" nzTreeNodePadding [nzExpandable]=\"false\">\n        <nz-tree-node-toggle nzTreeNodeNoopToggle />\n        <nz-tree-node-checkbox\n          [nzDisabled]=\"node.disabled\"\n          [nzChecked]=\"checklistSelection.isSelected(node)\"\n          (nzClick)=\"leafItemSelectionToggle(node)\"\n        />\n        <nz-tree-node-option [nzDisabled]=\"node.disabled\" (nzClick)=\"leafItemSelectionToggle(node)\">\n          {{ node.name }}\n        </nz-tree-node-option>\n      </nz-tree-node>\n\n      <nz-tree-node *nzTreeNodeDef=\"let node; when: hasChild\" nzTreeNodePadding [nzExpandable]=\"true\">\n        <nz-tree-node-toggle>\n          <nz-icon nzType=\"caret-down\" nzTreeNodeToggleRotateIcon />\n        </nz-tree-node-toggle>\n        <nz-tree-node-checkbox\n          [nzDisabled]=\"node.disabled\"\n          [nzChecked]=\"descendantsAllSelected(node)\"\n          [nzIndeterminate]=\"descendantsPartiallySelected(node)\"\n          (nzClick)=\"itemSelectionToggle(node)\"\n        />\n        <nz-tree-node-option [nzDisabled]=\"node.disabled\" (nzClick)=\"itemSelectionToggle(node)\">\n          {{ node.name }}\n        </nz-tree-node-option>\n      </nz-tree-node>\n    </nz-tree-view>\n  `\n})\nexport class NzDemoTreeViewCheckboxComponent implements OnInit {\n  @ViewChild(NzTreeViewComponent, { static: true }) tree!: NzTreeViewComponent<TreeNode>;\n\n  readonly childrenAccessor = (dataNode: TreeNode): TreeNode[] => dataNode.children ?? [];\n\n  readonly hasChild = (_: number, node: TreeNode): boolean => !!node.children?.length;\n\n  checklistSelection = new SelectionModel<TreeNode>(true);\n\n  dataSource!: NzTreeViewNestedDataSource<TreeNode>;\n\n  ngOnInit(): void {\n    this.dataSource = new NzTreeViewNestedDataSource<TreeNode>(this.tree, TREE_DATA);\n  }\n\n  private getDescendants(node: TreeNode): TreeNode[] {\n    return getDescendantsForNestedData(node, this.childrenAccessor);\n  }\n\n  private getParentNode(node: TreeNode): TreeNode | null {\n    return getParentForNestedData(this.tree.dataNodes, node, this.childrenAccessor);\n  }\n\n  descendantsAllSelected(node: TreeNode): boolean {\n    const descendants = this.getDescendants(node);\n    return descendants.length > 0 && descendants.every(child => this.checklistSelection.isSelected(child));\n  }\n\n  descendantsPartiallySelected(node: TreeNode): boolean {\n    const descendants = this.getDescendants(node);\n    const result = descendants.some(child => this.checklistSelection.isSelected(child));\n    return result && !this.descendantsAllSelected(node);\n  }\n\n  leafItemSelectionToggle(node: TreeNode): void {\n    this.checklistSelection.toggle(node);\n    this.checkAllParentsSelection(node);\n  }\n\n  itemSelectionToggle(node: TreeNode): void {\n    this.checklistSelection.toggle(node);\n    const descendants = this.getDescendants(node);\n    this.checklistSelection.isSelected(node)\n      ? this.checklistSelection.select(...descendants)\n      : this.checklistSelection.deselect(...descendants);\n\n    descendants.forEach(child => this.checklistSelection.isSelected(child));\n    this.checkAllParentsSelection(node);\n  }\n\n  checkAllParentsSelection(node: TreeNode): void {\n    let parent: TreeNode | null = this.getParentNode(node);\n    while (parent) {\n      this.checkRootNodeSelection(parent);\n      parent = this.getParentNode(parent);\n    }\n  }\n\n  checkRootNodeSelection(node: TreeNode): void {\n    const nodeSelected = this.checklistSelection.isSelected(node);\n    const descendants = this.getDescendants(node);\n    const descAllSelected =\n      descendants.length > 0 && descendants.every(child => this.checklistSelection.isSelected(child));\n    if (nodeSelected && !descAllSelected) {\n      this.checklistSelection.deselect(node);\n    } else if (!nodeSelected && descAllSelected) {\n      this.checklistSelection.select(node);\n    }\n  }\n}\n"
  },
  {
    "path": "components/tree-view/demo/directory.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 目录\n  en-US: Directory\n---\n\n## zh-CN\n\n目录树\n\n## en-US\n\nDirectory tree.\n"
  },
  {
    "path": "components/tree-view/demo/directory.ts",
    "content": "import { SelectionModel } from '@angular/cdk/collections';\nimport { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport {\n  NzTreeFlattener,\n  NzTreeViewComponent,\n  NzTreeViewFlatDataSource,\n  NzTreeViewModule\n} from 'ng-zorro-antd/tree-view';\n\ninterface FoodNode {\n  name: string;\n  disabled?: boolean;\n  children?: FoodNode[];\n}\n\ninterface FlatFoodNode {\n  expandable: boolean;\n  name: string;\n  level: number;\n  disabled: boolean;\n}\n\nconst TREE_DATA: FoodNode[] = [\n  {\n    name: 'Fruit',\n    children: [{ name: 'Apple' }, { name: 'Banana', disabled: true }, { name: 'Fruit loops' }]\n  },\n  {\n    name: 'Vegetables',\n    children: [\n      {\n        name: 'Green',\n        children: [{ name: 'Broccoli' }, { name: 'Brussels sprouts' }]\n      },\n      {\n        name: 'Orange',\n        children: [{ name: 'Pumpkins' }, { name: 'Carrots' }]\n      }\n    ]\n  }\n];\n\n@Component({\n  selector: 'nz-demo-tree-view-directory',\n  imports: [NzIconModule, NzTreeViewModule],\n  template: `\n    <nz-tree-view [nzDataSource]=\"dataSource\" [nzLevelAccessor]=\"levelAccessor\" [nzDirectoryTree]=\"true\">\n      <nz-tree-node *nzTreeNodeDef=\"let node\" nzTreeNodePadding [nzExpandable]=\"false\">\n        <nz-tree-node-toggle nzTreeNodeNoopToggle />\n        <nz-tree-node-option\n          [nzDisabled]=\"node.disabled\"\n          [nzSelected]=\"selectListSelection.isSelected(node)\"\n          (nzClick)=\"selectListSelection.toggle(node)\"\n        >\n          <nz-icon nzType=\"file\" nzTheme=\"outline\" />\n          {{ node.name }}\n        </nz-tree-node-option>\n      </nz-tree-node>\n\n      <nz-tree-node *nzTreeNodeDef=\"let node; when: hasChild\" nzTreeNodePadding [nzExpandable]=\"true\">\n        <nz-tree-node-toggle>\n          <nz-icon nzType=\"caret-down\" nzTreeNodeToggleRotateIcon />\n        </nz-tree-node-toggle>\n        <nz-tree-node-option\n          [nzDisabled]=\"node.disabled\"\n          [nzSelected]=\"selectListSelection.isSelected(node)\"\n          (nzClick)=\"selectListSelection.toggle(node)\"\n        >\n          <nz-icon [nzType]=\"tree.isExpanded(node) ? 'folder-open' : 'folder'\" nzTheme=\"outline\" />\n          {{ node.name }}\n        </nz-tree-node-option>\n      </nz-tree-node>\n    </nz-tree-view>\n  `\n})\nexport class NzDemoTreeViewDirectoryComponent implements OnInit, AfterViewInit {\n  @ViewChild(NzTreeViewComponent, { static: true }) tree!: NzTreeViewComponent<FlatFoodNode>;\n\n  readonly levelAccessor = (dataNode: FlatFoodNode): number => dataNode.level;\n\n  readonly hasChild = (_: number, node: FlatFoodNode): boolean => node.expandable;\n\n  private transformer = (node: FoodNode, level: number): FlatFoodNode => ({\n    expandable: !!node.children && node.children.length > 0,\n    name: node.name,\n    level,\n    disabled: !!node.disabled\n  });\n\n  private treeFlattener = new NzTreeFlattener(\n    this.transformer,\n    node => node.level,\n    node => node.expandable,\n    node => node.children\n  );\n\n  selectListSelection = new SelectionModel<FlatFoodNode>(true);\n\n  dataSource!: NzTreeViewFlatDataSource<FoodNode, FlatFoodNode>;\n\n  ngOnInit(): void {\n    this.dataSource = new NzTreeViewFlatDataSource(this.tree, this.treeFlattener, TREE_DATA);\n  }\n\n  ngAfterViewInit(): void {\n    setTimeout(() => {\n      this.tree.expand(this.getNode('Vegetables')!);\n    }, 300);\n  }\n\n  getNode(name: string): FlatFoodNode | null {\n    return this.tree.dataNodes.find(n => n.name === name) || null;\n  }\n}\n"
  },
  {
    "path": "components/tree-view/demo/dynamic.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 异步加载数据\n  en-US: Load data asynchronously\n---\n\n## zh-CN\n\n点击展开节点，动态加载数据。\n\n## en-US\n\nTo load data asynchronously when click to expand a treeNode.\n"
  },
  {
    "path": "components/tree-view/demo/dynamic.ts",
    "content": "import { CollectionViewer, DataSource, SelectionChange } from '@angular/cdk/collections';\nimport { Component, OnInit, ViewChild } from '@angular/core';\nimport { BehaviorSubject, merge, Observable, of } from 'rxjs';\nimport { delay, map, tap } from 'rxjs/operators';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzTreeView, NzTreeViewComponent, NzTreeViewModule } from 'ng-zorro-antd/tree-view';\n\ninterface FlatNode {\n  expandable: boolean;\n  id: number;\n  label: string;\n  level: number;\n  loading?: boolean;\n}\n\nconst TREE_DATA: FlatNode[] = [\n  {\n    id: 0,\n    label: 'Expand to load',\n    level: 0,\n    expandable: true\n  },\n  {\n    id: 1,\n    label: 'Expand to load',\n    level: 0,\n    expandable: true\n  }\n];\n\nfunction getChildren(node: FlatNode): Observable<FlatNode[]> {\n  return of([\n    {\n      id: Date.now(),\n      label: `Child Node (level-${node.level + 1})`,\n      level: node.level + 1,\n      expandable: true\n    },\n    {\n      id: Date.now(),\n      label: `Child Node (level-${node.level + 1})`,\n      level: node.level + 1,\n      expandable: true\n    },\n    {\n      id: Date.now(),\n      label: `Leaf Node (level-${node.level + 1})`,\n      level: node.level + 1,\n      expandable: false\n    }\n  ]).pipe(delay(500));\n}\n\nclass DynamicDatasource implements DataSource<FlatNode> {\n  private flattenedData: BehaviorSubject<FlatNode[]>;\n  private childrenLoadedSet = new Set<FlatNode>();\n\n  constructor(\n    private tree: NzTreeView<FlatNode>,\n    initData: FlatNode[]\n  ) {\n    this.flattenedData = new BehaviorSubject<FlatNode[]>(initData);\n    tree.dataNodes = initData;\n  }\n\n  connect(collectionViewer: CollectionViewer): Observable<FlatNode[]> {\n    const changes = [\n      collectionViewer.viewChange,\n      this.tree._getExpansionModel().changed.pipe(tap(change => this.handleExpansionChange(change))),\n      this.flattenedData.asObservable()\n    ];\n    return merge(...changes).pipe(map(() => this.flattenedData.value));\n  }\n\n  handleExpansionChange(change: SelectionChange<FlatNode>): void {\n    if (change.added) {\n      change.added.forEach(node => this.loadChildren(node));\n    }\n  }\n\n  loadChildren(node: FlatNode): void {\n    if (this.childrenLoadedSet.has(node)) {\n      return;\n    }\n    node.loading = true;\n    getChildren(node).subscribe(children => {\n      node.loading = false;\n      const flattenedData = this.flattenedData.getValue();\n      const index = flattenedData.indexOf(node);\n      if (index !== -1) {\n        flattenedData.splice(index + 1, 0, ...children);\n        this.childrenLoadedSet.add(node);\n      }\n      this.flattenedData.next(flattenedData);\n      // save flattened data into tree instance\n      this.tree.dataNodes = flattenedData;\n    });\n  }\n\n  disconnect(): void {\n    this.flattenedData.complete();\n  }\n}\n\n@Component({\n  selector: 'nz-demo-tree-view-dynamic',\n  imports: [NzIconModule, NzTreeViewModule],\n  template: `\n    <nz-tree-view [nzDataSource]=\"dataSource\" [nzLevelAccessor]=\"levelAccessor\">\n      <nz-tree-node *nzTreeNodeDef=\"let node\" nzTreeNodePadding [nzExpandable]=\"false\">\n        {{ node.label }}\n      </nz-tree-node>\n\n      <nz-tree-node *nzTreeNodeDef=\"let node; when: hasChild\" nzTreeNodePadding [nzExpandable]=\"true\">\n        @if (!node.loading) {\n          <nz-tree-node-toggle>\n            <nz-icon nzType=\"caret-down\" nzTreeNodeToggleRotateIcon />\n          </nz-tree-node-toggle>\n        } @else {\n          <nz-tree-node-toggle nzTreeNodeNoopToggle>\n            <nz-icon nzType=\"loading\" nzTreeNodeToggleActiveIcon />\n          </nz-tree-node-toggle>\n        }\n        {{ node.label }}\n      </nz-tree-node>\n    </nz-tree-view>\n  `\n})\nexport class NzDemoTreeViewDynamicComponent implements OnInit {\n  @ViewChild(NzTreeViewComponent, { static: true }) tree!: NzTreeViewComponent<FlatNode>;\n\n  readonly levelAccessor = (dataNode: FlatNode): number => dataNode.level;\n\n  readonly hasChild = (_: number, node: FlatNode): boolean => node.expandable;\n\n  dataSource!: DynamicDatasource;\n\n  ngOnInit(): void {\n    this.dataSource = new DynamicDatasource(this.tree, TREE_DATA);\n  }\n}\n"
  },
  {
    "path": "components/tree-view/demo/editable.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 可编辑\n  en-US: editable\n---\n\n## zh-CN\n\n带添加和删除功能的树。\n\n## en-US\n\nTree with add and delete actions.\n"
  },
  {
    "path": "components/tree-view/demo/editable.ts",
    "content": "import { SelectionModel } from '@angular/cdk/collections';\nimport { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport {\n  getParentForNestedData,\n  NzTreeViewComponent,\n  NzTreeViewModule,\n  NzTreeViewNestedDataSource\n} from 'ng-zorro-antd/tree-view';\n\ninterface TreeNode {\n  name: string;\n  key: string;\n  children?: TreeNode[];\n}\n\nconst TREE_DATA: TreeNode[] = [\n  {\n    name: 'parent 1',\n    key: '1',\n    children: [\n      {\n        name: 'parent 1-0',\n        key: '1-0',\n        children: [\n          { name: 'leaf', key: '1-0-0' },\n          { name: 'leaf', key: '1-0-1' }\n        ]\n      },\n      {\n        name: 'parent 1-1',\n        key: '1-1',\n        children: [{ name: 'leaf', key: '1-1-0' }]\n      }\n    ]\n  },\n  {\n    key: '2',\n    name: 'parent 2',\n    children: [{ name: 'leaf', key: '2-0' }]\n  }\n];\n\n@Component({\n  selector: 'nz-demo-tree-view-editable',\n  imports: [NzButtonModule, NzInputModule, NzIconModule, NzTreeViewModule],\n  template: `\n    <nz-tree-view [nzDataSource]=\"dataSource\" [nzChildrenAccessor]=\"childrenAccessor\" [nzTrackBy]=\"trackBy\">\n      <nz-tree-node *nzTreeNodeDef=\"let node\" nzTreeNodeIndentLine [nzExpandable]=\"false\">\n        <nz-tree-node-option\n          [nzDisabled]=\"node.disabled\"\n          [nzSelected]=\"selectListSelection.isSelected(node)\"\n          (nzClick)=\"selectListSelection.toggle(node)\"\n        >\n          {{ node.name }}\n        </nz-tree-node-option>\n        <button nz-button nzType=\"text\" nzSize=\"small\" (click)=\"delete(node)\">\n          <nz-icon nzType=\"minus\" nzTheme=\"outline\" />\n        </button>\n      </nz-tree-node>\n\n      <nz-tree-node *nzTreeNodeDef=\"let node; when: hasNoContent\" nzTreeNodeIndentLine [nzExpandable]=\"false\">\n        <input nz-input placeholder=\"Input node name\" nzSize=\"small\" #inputElement />\n        &nbsp;\n        <button nz-button nzSize=\"small\" (click)=\"saveNode(node, inputElement.value)\">Add</button>\n      </nz-tree-node>\n\n      <nz-tree-node *nzTreeNodeDef=\"let node; when: hasChild\" nzTreeNodeIndentLine [nzExpandable]=\"true\">\n        <nz-tree-node-toggle>\n          <nz-icon nzType=\"caret-down\" nzTreeNodeToggleRotateIcon />\n        </nz-tree-node-toggle>\n        {{ node.name }}\n        <button nz-button nzType=\"text\" nzSize=\"small\" (click)=\"addNewNode(node)\">\n          <nz-icon nzType=\"plus\" nzTheme=\"outline\" />\n        </button>\n      </nz-tree-node>\n    </nz-tree-view>\n  `\n})\nexport class NzDemoTreeViewEditableComponent implements OnInit, AfterViewInit {\n  @ViewChild(NzTreeViewComponent, { static: true }) tree!: NzTreeViewComponent<TreeNode>;\n\n  readonly childrenAccessor = (dataNode: TreeNode): TreeNode[] => dataNode.children ?? [];\n\n  readonly hasChild = (_: number, node: TreeNode): boolean => !!node.children?.length;\n\n  readonly hasNoContent = (_: number, node: TreeNode): boolean => node.name === '';\n\n  readonly trackBy = (_: number, node: TreeNode): string => `${node.key}-${node.name}`;\n\n  selectListSelection = new SelectionModel<TreeNode>(true);\n\n  treeData = TREE_DATA;\n\n  dataSource!: NzTreeViewNestedDataSource<TreeNode>;\n\n  ngOnInit(): void {\n    this.dataSource = new NzTreeViewNestedDataSource<TreeNode>(this.tree, this.treeData);\n  }\n\n  ngAfterViewInit(): void {\n    this.tree.expandAll();\n  }\n\n  delete(node: TreeNode): void {\n    const parentNode = getParentForNestedData(this.treeData, node, this.childrenAccessor);\n    if (parentNode && parentNode.children) {\n      parentNode.children = parentNode.children.filter(e => e !== node);\n    }\n\n    this.dataSource.setData(this.treeData);\n  }\n  addNewNode(node: TreeNode): void {\n    node.children = node.children || [];\n    node.children.push({\n      name: '',\n      key: `${node.key}-${node.children.length}`\n    });\n    this.dataSource.setData(this.treeData);\n    this.tree.expand(node);\n  }\n\n  saveNode(node: TreeNode, value: string): void {\n    if (node) {\n      node.name = value;\n      this.dataSource.setData(this.treeData);\n    }\n  }\n}\n"
  },
  {
    "path": "components/tree-view/demo/line.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 带连接线的树\n  en-US: Tree with line\n---\n\n## zh-CN\n\n节点之间带连接线的树，常用于文件目录结构展示。\n\n## en-US\n\nTree with connected line between nodes.\n"
  },
  {
    "path": "components/tree-view/demo/line.ts",
    "content": "import { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzSwitchModule } from 'ng-zorro-antd/switch';\nimport { NzTreeViewComponent, NzTreeViewModule, NzTreeViewNestedDataSource } from 'ng-zorro-antd/tree-view';\n\ninterface TreeNode {\n  name: string;\n  children?: TreeNode[];\n}\n\nconst TREE_DATA: TreeNode[] = [\n  {\n    name: 'parent 1',\n    children: [\n      {\n        name: 'parent 1-0',\n        children: [{ name: 'leaf' }, { name: 'leaf' }]\n      },\n      {\n        name: 'parent 1-1',\n        children: [\n          { name: 'leaf' },\n          {\n            name: 'parent 1-1-0',\n            children: [{ name: 'leaf' }, { name: 'leaf' }]\n          },\n          { name: 'leaf' }\n        ]\n      }\n    ]\n  },\n  {\n    name: 'parent 2',\n    children: [{ name: 'leaf' }, { name: 'leaf' }]\n  }\n];\n\n@Component({\n  selector: 'nz-demo-tree-view-line',\n  imports: [FormsModule, NzIconModule, NzSwitchModule, NzTreeViewModule],\n  template: `\n    Show Leaf Icon:\n    <nz-switch [(ngModel)]=\"showLeafIcon\" />\n\n    <nz-tree-view [nzDataSource]=\"dataSource\" [nzChildrenAccessor]=\"childrenAccessor\">\n      <nz-tree-node *nzTreeNodeDef=\"let node\" nzTreeNodeIndentLine [nzExpandable]=\"false\">\n        @if (showLeafIcon) {\n          <nz-tree-node-toggle nzTreeNodeNoopToggle>\n            <nz-icon nzType=\"file\" nzTheme=\"outline\" />\n          </nz-tree-node-toggle>\n        }\n        <nz-tree-node-option>\n          {{ node.name }}\n        </nz-tree-node-option>\n      </nz-tree-node>\n\n      <nz-tree-node *nzTreeNodeDef=\"let node; when: hasChild\" nzTreeNodeIndentLine [nzExpandable]=\"true\">\n        <nz-tree-node-toggle>\n          <nz-icon [nzType]=\"tree.isExpanded(node) ? 'minus-square' : 'plus-square'\" nzTheme=\"outline\" />\n        </nz-tree-node-toggle>\n        <nz-tree-node-option>\n          {{ node.name }}\n        </nz-tree-node-option>\n      </nz-tree-node>\n    </nz-tree-view>\n  `\n})\nexport class NzDemoTreeViewLineComponent implements AfterViewInit, OnInit {\n  @ViewChild(NzTreeViewComponent, { static: true }) tree!: NzTreeViewComponent<TreeNode>;\n\n  readonly childrenAccessor = (dataNode: TreeNode): TreeNode[] => dataNode.children ?? [];\n\n  readonly hasChild = (_: number, node: TreeNode): boolean => !!node.children?.length;\n\n  showLeafIcon = false;\n\n  dataSource!: NzTreeViewNestedDataSource<TreeNode>;\n\n  ngOnInit(): void {\n    this.dataSource = new NzTreeViewNestedDataSource<TreeNode>(this.tree, TREE_DATA);\n  }\n\n  ngAfterViewInit(): void {\n    this.tree.expandAll();\n  }\n}\n"
  },
  {
    "path": "components/tree-view/demo/search.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 搜索\n  en-US: search\n---\n\n## zh-CN\n\n可搜索的树。\n\n## en-US\n\nSearchable Tree.\n"
  },
  {
    "path": "components/tree-view/demo/search.ts",
    "content": "import { Component, OnInit, ViewChild } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { BehaviorSubject, combineLatest } from 'rxjs';\nimport { auditTime, map } from 'rxjs/operators';\n\nimport { NzHighlightPipe } from 'ng-zorro-antd/core/highlight';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport {\n  NzTreeFlattener,\n  NzTreeViewComponent,\n  NzTreeViewFlatDataSource,\n  NzTreeViewModule\n} from 'ng-zorro-antd/tree-view';\n\ninterface TreeNode {\n  name: string;\n  children?: TreeNode[];\n}\n\nconst TREE_DATA: TreeNode[] = [\n  {\n    name: '0-0',\n    children: [{ name: '0-0-0' }, { name: '0-0-1' }, { name: '0-0-2' }]\n  },\n  {\n    name: '0-1',\n    children: [\n      {\n        name: '0-1-0',\n        children: [{ name: '0-1-0-0' }, { name: '0-1-0-1' }]\n      },\n      {\n        name: '0-1-1',\n        children: [{ name: '0-1-1-0' }, { name: '0-1-1-1' }]\n      }\n    ]\n  }\n];\n\ninterface FlatNode {\n  expandable: boolean;\n  name: string;\n  level: number;\n}\n\nclass FilteredTreeResult {\n  constructor(\n    public treeData: TreeNode[],\n    public needsToExpanded: TreeNode[] = []\n  ) {}\n}\n\n/**\n * From https://stackoverflow.com/a/45290208/6851836\n */\nfunction filterTreeData(data: TreeNode[], value: string): FilteredTreeResult {\n  const needsToExpanded = new Set<TreeNode>();\n  const _filter = (node: TreeNode, result: TreeNode[]): TreeNode[] => {\n    if (node.name.search(value) !== -1) {\n      result.push(node);\n      return result;\n    }\n    if (Array.isArray(node.children)) {\n      const nodes = node.children.reduce((a, b) => _filter(b, a), [] as TreeNode[]);\n      if (nodes.length) {\n        const parentNode = { ...node, children: nodes };\n        needsToExpanded.add(parentNode);\n        result.push(parentNode);\n      }\n    }\n    return result;\n  };\n  const treeData = data.reduce((a, b) => _filter(b, a), [] as TreeNode[]);\n  return new FilteredTreeResult(treeData, [...needsToExpanded]);\n}\n\n@Component({\n  selector: 'nz-demo-tree-view-search',\n  imports: [FormsModule, NzInputModule, NzIconModule, NzTreeViewModule, NzHighlightPipe],\n  template: `\n    <nz-input-wrapper>\n      <input type=\"text\" nz-input placeholder=\"Search\" ngModel (ngModelChange)=\"searchValue$.next($event)\" />\n      <nz-icon nzInputSuffix nzType=\"search\" />\n    </nz-input-wrapper>\n\n    <nz-tree-view [nzDataSource]=\"dataSource\" [nzLevelAccessor]=\"levelAccessor\">\n      <nz-tree-node *nzTreeNodeDef=\"let node\" nzTreeNodePadding [nzExpandable]=\"false\">\n        <nz-tree-node-toggle nzTreeNodeNoopToggle />\n        <span [innerHTML]=\"node.name | nzHighlight: searchValue : 'i' : 'highlight'\"></span>\n      </nz-tree-node>\n\n      <nz-tree-node *nzTreeNodeDef=\"let node; when: hasChild\" nzTreeNodePadding [nzExpandable]=\"true\">\n        <nz-tree-node-toggle>\n          <nz-icon nzType=\"caret-down\" nzTreeNodeToggleRotateIcon />\n        </nz-tree-node-toggle>\n        <span [innerHTML]=\"node.name | nzHighlight: searchValue : 'i' : 'highlight'\"></span>\n      </nz-tree-node>\n    </nz-tree-view>\n  `,\n  styles: `\n    nz-input-wrapper {\n      margin-bottom: 8px;\n    }\n\n    ::ng-deep .highlight {\n      color: #f50;\n    }\n  `\n})\nexport class NzDemoTreeViewSearchComponent implements OnInit {\n  @ViewChild(NzTreeViewComponent, { static: true }) tree!: NzTreeViewComponent<FlatNode>;\n\n  readonly levelAccessor = (dataNode: FlatNode): number => dataNode.level;\n\n  readonly hasChild = (_: number, node: FlatNode): boolean => node.expandable;\n\n  flatNodeMap = new Map<FlatNode, TreeNode>();\n  nestedNodeMap = new Map<TreeNode, FlatNode>();\n  expandedNodes: TreeNode[] = [];\n  searchValue = '';\n  originData$ = new BehaviorSubject(TREE_DATA);\n  searchValue$ = new BehaviorSubject<string>('');\n\n  transformer = (node: TreeNode, level: number): FlatNode => {\n    const existingNode = this.nestedNodeMap.get(node);\n    const flatNode =\n      existingNode && existingNode.name === node.name\n        ? existingNode\n        : {\n            expandable: !!node.children && node.children.length > 0,\n            name: node.name,\n            level\n          };\n    this.flatNodeMap.set(flatNode, node);\n    this.nestedNodeMap.set(node, flatNode);\n    return flatNode;\n  };\n\n  treeFlattener = new NzTreeFlattener<TreeNode, FlatNode>(\n    this.transformer,\n    node => node.level,\n    node => node.expandable,\n    node => node.children\n  );\n\n  filteredData$ = combineLatest([\n    this.originData$,\n    this.searchValue$.pipe(\n      auditTime(300),\n      map(value => (this.searchValue = value))\n    )\n  ]).pipe(map(([data, value]) => (value ? filterTreeData(data, value) : new FilteredTreeResult(data))));\n\n  dataSource!: NzTreeViewFlatDataSource<TreeNode, FlatNode>;\n\n  ngOnInit(): void {\n    this.dataSource = new NzTreeViewFlatDataSource(this.tree, this.treeFlattener);\n\n    this.filteredData$.subscribe(result => {\n      this.dataSource.setData(result.treeData);\n\n      const hasSearchValue = !!this.searchValue;\n      // trans nested nodes to flat nodes\n      const needsToExpanded = result.needsToExpanded.map(node => this.nestedNodeMap.get(node)!);\n      const expandedNodes = this.expandedNodes.map(node => this.nestedNodeMap.get(node)!);\n      // expand nodes\n      if (hasSearchValue) {\n        if (this.expandedNodes.length === 0) {\n          this.expandedNodes = this.tree._getExpansionModel().selected;\n          this.tree._getExpansionModel().clear();\n        }\n        this.tree._getExpansionModel().select(...needsToExpanded);\n      } else {\n        if (this.expandedNodes.length) {\n          this.tree._getExpansionModel().clear();\n          this.tree._getExpansionModel().select(...expandedNodes);\n          this.expandedNodes = [];\n        }\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "components/tree-view/demo/virtual-scroll.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 虚拟滚动\n  en-US: Virtual Scroll\n---\n\n## zh-CN\n\n使用虚拟滚动。\n\n## en-US\n\nUse virtual scroll.\n"
  },
  {
    "path": "components/tree-view/demo/virtual-scroll.ts",
    "content": "import { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport {\n  NzTreeFlattener,\n  NzTreeViewFlatDataSource,\n  NzTreeViewModule,\n  NzTreeVirtualScrollViewComponent\n} from 'ng-zorro-antd/tree-view';\n\ninterface TreeNode {\n  name: string;\n  children?: TreeNode[];\n}\n\nfunction dig(path: string = '0', level: number = 3): TreeNode[] {\n  const list: TreeNode[] = [];\n  for (let i = 0; i < 10; i += 1) {\n    const name = `${path}-${i}`;\n    const treeNode: TreeNode = {\n      name\n    };\n\n    if (level > 0) {\n      treeNode.children = dig(name, level - 1);\n    }\n\n    list.push(treeNode);\n  }\n  return list;\n}\n\nconst TREE_DATA: TreeNode[] = dig();\n\n/** Flat node with expandable and level information */\ninterface FlatNode {\n  expandable: boolean;\n  name: string;\n  level: number;\n}\n\n@Component({\n  selector: 'nz-demo-tree-view-virtual-scroll',\n  imports: [NzIconModule, NzTreeViewModule],\n  template: `\n    <nz-tree-virtual-scroll-view\n      class=\"virtual-scroll-tree\"\n      [nzDataSource]=\"dataSource\"\n      [nzLevelAccessor]=\"levelAccessor\"\n    >\n      <nz-tree-node *nzTreeNodeDef=\"let node\" nzTreeNodePadding [nzExpandable]=\"false\">\n        <nz-tree-node-toggle nzTreeNodeNoopToggle />\n        {{ node.name }}\n      </nz-tree-node>\n\n      <nz-tree-node *nzTreeNodeDef=\"let node; when: hasChild\" nzTreeNodePadding [nzExpandable]=\"true\">\n        <nz-tree-node-toggle>\n          <nz-icon nzType=\"caret-down\" nzTreeNodeToggleRotateIcon />\n        </nz-tree-node-toggle>\n        {{ node.name }}\n      </nz-tree-node>\n    </nz-tree-virtual-scroll-view>\n  `,\n  styles: `\n    .virtual-scroll-tree {\n      height: 200px;\n    }\n  `\n})\nexport class NzDemoTreeViewVirtualScrollComponent implements OnInit, AfterViewInit {\n  @ViewChild(NzTreeVirtualScrollViewComponent, { static: true }) tree!: NzTreeVirtualScrollViewComponent<FlatNode>;\n\n  readonly levelAccessor = (dataNode: FlatNode): number => dataNode.level;\n\n  readonly hasChild = (_: number, node: FlatNode): boolean => node.expandable;\n\n  private transformer = (node: TreeNode, level: number): FlatNode => ({\n    expandable: !!node.children && node.children.length > 0,\n    name: node.name,\n    level\n  });\n\n  treeFlattener = new NzTreeFlattener(\n    this.transformer,\n    node => node.level,\n    node => node.expandable,\n    node => node.children\n  );\n\n  dataSource!: NzTreeViewFlatDataSource<TreeNode, FlatNode>;\n\n  ngOnInit(): void {\n    this.dataSource = new NzTreeViewFlatDataSource(this.tree, this.treeFlattener, TREE_DATA);\n  }\n\n  ngAfterViewInit(): void {\n    setTimeout(() => {\n      this.tree.expandAll();\n    });\n  }\n}\n"
  },
  {
    "path": "components/tree-view/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Display\ntitle: TreeView\ntag: updated\ncover: 'https://gw.alipayobjects.com/zos/alicdn/Xh-oWqg9k/Tree.svg'\ndescription: Tree view component with better performance and customizability.\n---\n\n## When To Use\n\nMore basic Tree component, allowing each of its parts to be defined in the template, and state to be managed manually.\n\n> ⚠️ `nzTreeControl` has been removed in `v21.0.0`. Please use either `nzLevelAccessor` or `nzChildrenAccessor` instead, one of them must exist.\n\n## API\n\n### nz-tree-view\n\n| Property               | Description                                                                                                                       | Type                                                                                                               | Default                             |\n| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | ----------------------------------- |\n| `[nzDataSource]`       | The data array to render                                                                                                          | `DataSource<T> \\| Observable<T[]> \\| T[]`, [DataSource](https://material.angular.io/cdk/tree/overview#data-source) | -                                   |\n| `[nzLevelAccessor]`    | The level accessor of tree node ([levelAccessor](https://material.angular.io/cdk/tree/api#CdkTree)), used with flat data.         | `(dataNode: T) => number`                                                                                          | -                                   |\n| `[nzChildrenAccessor]` | The children accessor of tree node ([childrenAccessor](https://material.angular.io/cdk/tree/api#CdkTree)), used with nested data. | `(dataNode: T) => T[]`                                                                                             | -                                   |\n| `[nzTrackBy]`          | Tracking function that will be used to check the differences in data changes. Used similarly to ngFor trackBy function.           | `TrackByFunction`                                                                                                  | `(_index, dataNode: T) => dataNode` |\n| `[nzDirectoryTree]`    | Whether nodes are displayed as directory style                                                                                    | `boolean`                                                                                                          | `false`                             |\n| `[nzBlockNode]`        | Whether tree nodes fill remaining horizontal space                                                                                | `boolean`                                                                                                          | `false`                             |\n\n### nz-tree-virtual-scroll-view\n\nThe virtual scroll tree view, which can be accessed from\nthe [CdkVirtualScrollViewport](https://material.angular.io/cdk/scrolling/api#CdkVirtualScrollViewport) instance through\nthe `virtualScrollViewport` member of the component instance.\n\n| Property               | Description                                                                                                                       | Type                                                                                                               | Default                             |\n| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | ----------------------------------- |\n| `[nzDataSource]`       | The data array to render                                                                                                          | `DataSource<T> \\| Observable<T[]> \\| T[]`, [DataSource](https://material.angular.io/cdk/tree/overview#data-source) | -                                   |\n| `[nzLevelAccessor]`    | The level accessor of tree node ([levelAccessor](https://material.angular.io/cdk/tree/api#CdkTree)), used with flat data.         | `(dataNode: T) => number`                                                                                          | -                                   |\n| `[nzChildrenAccessor]` | The children accessor of tree node ([childrenAccessor](https://material.angular.io/cdk/tree/api#CdkTree)), used with nested data. | `(dataNode: T) => T[]`                                                                                             | -                                   |\n| `[nzTrackBy]`          | Tracking function that will be used to check the differences in data changes. Used similarly to ngFor trackBy function.           | `TrackByFunction`                                                                                                  | `(_index, dataNode: T) => dataNode` |\n| `[nzDirectoryTree]`    | Whether nodes are displayed as directory style                                                                                    | `boolean`                                                                                                          | `false`                             |\n| `[nzBlockNode]`        | Whether tree nodes fill remaining horizontal space                                                                                | `boolean`                                                                                                          | `false`                             |\n| `[nzItemSize]`         | The size of nodes in the tree (in pixels)                                                                                         | `number`                                                                                                           | `28`                                |\n| `[nzMinBufferPx]`      | The minimum amount of buffer rendered allowed outside the viewport (in pixels)                                                    | `number`                                                                                                           | `28 * 5`                            |\n| `[nzMaxBufferPx]`      | The amount of buffer required for rendering new nodes (in pixels)                                                                 | `number`                                                                                                           | `28 * 10`                           |\n\n### [nzTreeNodeDef]\n\nDirective to define `nz-tree-node`.\n\n| Property              | Description                                                                                                                                                                                                                                                                 | Type                                      | Default |\n| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- | ------- |\n| `[nzTreeNodeDefWhen]` | A matching function which indicates whether inputted node should be used. It matches the very first node that makes this function return `true`. If no nodes that makes this function return `true`, the node which does not define this function would be matched instead. | `(index: number, nodeData: T) => boolean` | -       |\n\n### nz-tree-node\n\nThe tree node container component, which needs to be defined by the `nzTreeNodeDef` directive.\n\n| Property         | Description                                                                                                                                                                                | Type      | Default |\n| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------- | ------- |\n| `[nzExpandable]` | [Whether or not this tree node is expandable](https://material.angular.io/cdk/tree/api#CdkTreeNode). Please set this parameter value when using `nzLevelAccessor` or `nzChildrenAccessor`. | `boolean` | `false` |\n\n### [nzTreeNodePadding]\n\nShow node indentation by adding `padding` **Best Performance**.\n\n```html\n<nz-tree-node nzTreeNodePadding></nz-tree-node>\n```\n\n### nzTreeNodeIndentLine\n\nShow node indentation by adding indent lines.\n\n```html\n<nz-tree-node nzTreeNodeIndentLine></nz-tree-node>\n```\n\n### nz-tree-node-toggle\n\nA toggle which is used to expand / collapse the node.\n\n| Property                      | Description                         | Type      | Default |\n| ----------------------------- | ----------------------------------- | --------- | ------- |\n| `[nzTreeNodeToggleRecursive]` | Is it recursively expand / collapse | `boolean` | `false` |\n\n### nz-tree-node-toggle[nzTreeNodeNoopToggle]\n\nA toggle that does no actions. This can be used for placeholders or displays icons.\n\n### [nzTreeNodeToggleRotateIcon]\n\nDefine an icon in the toggle, which it will automatically rotate depending on the collapse/expand state.\n\n### [nzTreeNodeToggleActiveIcon]\n\nDefine an icon in the toggle for an active style, which it can be used for the loading state.\n\n### nz-tree-node-option\n\nDefine the selectable feature of a node.\n\n| Property       | Description                     | Type                       | Default |\n| -------------- | ------------------------------- | -------------------------- | ------- |\n| `[nzSelected]` | Whether the option is selected. | `boolean`                  | `false` |\n| `[nzDisabled]` | Whether the option is disabled. | `boolean`                  | `false` |\n| `(nzClick)`    | Event on click.                 | `EventEmitter<MouseEvent>` | -       |\n\n### nz-tree-node-checkbox\n\nDefine the checkbox feature of a node.\n\n| Property            | Description                            | Type                       | Default |\n| ------------------- | -------------------------------------- | -------------------------- | ------- |\n| `[nzChecked]`       | Whether the checkbox is checked.       | `boolean`                  | `false` |\n| `[nzDisabled]`      | Whether the checkbox is disabled.      | `boolean`                  | `false` |\n| `[nzIndeterminate]` | Whether the checkbox is indeterminate. | `boolean`                  | `false` |\n| `(nzClick)`         | Event on click.                        | `EventEmitter<MouseEvent>` | -       |\n\n## Classes\n\n### NzTreeViewFlatDataSource extends DataSource\n\nThe `dataSource` for flat data that automatically responds to view and data changes, used with `nzLevelAccessor`.\n\n**Construction Parameters**\n\n| Name                                   | Description                                                          |\n| -------------------------------------- | -------------------------------------------------------------------- |\n| `tree: NzTreeView<T, F>`               | Tree View component instance.                                        |\n| `treeFlattener: NzTreeFlattener<T, F>` | Flattener for convert nested nodes `<T>` into flattened nodes `<F>`. |\n| `initialData: T[] = []`                | Initialized data `<T>`.                                              |\n\n**Methods**\n\n| Name                                                           | Description                                                        |\n| -------------------------------------------------------------- | ------------------------------------------------------------------ |\n| `connect(collectionViewer: CollectionViewer): Observable<F[]>` | Called in the TreeView component, emit flattenData to the TreeView |\n| `disconnect(): void`                                           | Call when TreeView component is destroyed.                         |\n| `setData(value: T[]): void`                                    | Set the origin data `<T>`.                                         |\n| `getData(): T[]`                                               | Get the origin data `<T>`.                                         |\n| `setFlattenedData(nodes: F[]): void`                           | Set the flattened data `<F>`.                                      |\n| `getFlattenData(): F[]`                                        | Get the flattened data `<F>`.                                      |\n\n### NzTreeViewNestedDataSource extends DataSource\n\nThe `dataSource` for nested data that automatically responds to view and data changes, used with `nzChildrenAccessor`.\n\n**Construction Parameters**\n\n| Name                    | Description                   |\n| ----------------------- | ----------------------------- |\n| `tree: NzTreeView<T>`   | Tree View component instance. |\n| `initialData: T[] = []` | Initialized data `<T>`.       |\n\n**Methods**\n\n| Name                                                           | Description                                                 |\n| -------------------------------------------------------------- | ----------------------------------------------------------- |\n| `connect(collectionViewer: CollectionViewer): Observable<T[]>` | Called in the TreeView component, emit data to the TreeView |\n| `disconnect(): void`                                           | Call when TreeView component is destroyed.                  |\n| `setData(value: T[]): void`                                    | Set the origin data `<T>`                                   |\n| `getData(): T[]`                                               | Get the origin data `<T>`                                   |\n\n### NzTreeFlattener\n\nConvert nested data with child nodes into node data with level information.\n\n**Construction Parameters**\n\n| Name                                                                    | Description                                                    |\n| ----------------------------------------------------------------------- | -------------------------------------------------------------- |\n| `transformFunction: (node: T, level: number) => F`                      | Receive a nested node `<T>` and return a flattened node `<F>`. |\n| `getLevel: (node: F) => number`                                         | Define the method to get the `level` property.                 |\n| `isExpandable: (node: F) => boolean`                                    | Methods for defining whether a node is expandable.             |\n| `getChildren: (node: T) => Observable<T[]> \\| T[] \\| undefined \\| null` | Define methods to get children nodes from nested node `<T>`.   |\n\n**Methods**\n\n| Name                                     | Description                                                |\n| ---------------------------------------- | ---------------------------------------------------------- |\n| `flattenNodes(structuredData: T[]): F[]` | Receive nested data `<T>` and return flattened data `<F>`. |\n\n## utils\n\nCommon utility classes in the Tree View component. Provides methods for getting the father, brother, and descendant nodes of the current tree node, including two sets of methods for **flat** and **nested** data structures respectively.\n\n**Flat Data**\n\n| Name                                                                                                   | Description                                                                                    |\n| ------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------- |\n| `getParent: (nodes: F[], node: F, getLevel: (dataNode: F) => number): F \\| null`                       | Return parent of the node.                                                                     |\n| `getDescendants: (nodes: F[], node: F, getLevel: (dataNode: F) => number): F[]`                        | Return descendants of the node.                                                                |\n| `getNextSibling: (nodes: F[], node: F, getLevel: (dataNode: F) => number, _index?: number): F \\| null` | Return the next sibling of the node, or the first sibling of the node after `_index` position. |\n\n**Nested Data**\n\n| Name                                                                                               | Description                                                                                  |\n| -------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |\n| `getParentForNestedData: (nodes: T[], node: T, getChildren: (dataNode: T) => T[]): T \\| null`      | Return parent of the node.                                                                   |\n| `getDescendantsForNestedData: (node: T, getChildren: (dataNode: T) => T[]): T[]`                   | Return descendants of the node.                                                              |\n| `getNextSiblingForNestedData: (nodes: T[], node: T, getChildren: (dataNode: T) => T[]): T \\| null` | Return the next sibling of the node.                                                         |\n| `flattenNestedNodes: (nodes: T[], getChildren: (dataNode: T) => T[]): T[]`                         | Flatten nested data and returns flat arrays, but does not change the nested node properties. |\n"
  },
  {
    "path": "components/tree-view/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ntype: 数据展示\ntitle: TreeView\nsubtitle: 树视图\ntag: updated\ncover: 'https://gw.alipayobjects.com/zos/alicdn/Xh-oWqg9k/Tree.svg'\ndescription: 树视图组件，相比封装好的 Tree 组件具有更高的定制度和更好的性能。\n---\n\n## 何时使用\n\n更基础的 Tree 组件，允许在模版中定义每个组成部分，并手动管理状态。\n\n> ⚠️ `nzTreeControl` 在 `v21.0.0` 中被移除，请使用 `nzLevelAccessor` 或 `nzChildrenAccessor` 替代。二者必须存在其一，否则无法正确构建视图。\n\n## API\n\n### nz-tree-view\n\n| 参数                   | 说明                                                                                                       | 类型                                                                                                               | 默认值                              |\n| ---------------------- | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | ----------------------------------- |\n| `[nzDataSource]`       | 用于渲染树的数组数据                                                                                       | `DataSource<T> \\| Observable<T[]> \\| T[]`, [DataSource](https://material.angular.io/cdk/tree/overview#data-source) | -                                   |\n| `[nzLevelAccessor]`    | 树层级访问方法（[levelAccessor](https://material.angular.io/cdk/tree/api#CdkTree)），结合扁平数据使用      | `(dataNode: T) => number`                                                                                          | -                                   |\n| `[nzChildrenAccessor]` | 树子节点访问方法（[childrenAccessor](https://material.angular.io/cdk/tree/api#CdkTree)），结合嵌套数据使用 | `(dataNode: T) => T[]`                                                                                             | -                                   |\n| `[nzTrackBy]`          | 用于检查数据变化的差异，使用方式类似于 ngFor 的 trackBy 函数                                               | `TrackByFunction`                                                                                                  | `(_index, dataNode: T) => dataNode` |\n| `[nzDirectoryTree]`    | 节点是否以文件夹样式显示                                                                                   | `boolean`                                                                                                          | `false`                             |\n| `[nzBlockNode]`        | 节点是否占据整行                                                                                           | `boolean`                                                                                                          | `false`                             |\n\n### nz-tree-virtual-scroll-view\n\n虚拟滚动的树视图，可以通过组件实例上的 `virtualScrollViewport` 成员访问 [CdkVirtualScrollViewport](https://material.angular.io/cdk/scrolling/api#CdkVirtualScrollViewport) 实例。\n\n| 参数                   | 说明                                                                                                       | 类型                                                                                                               | 默认值                              |\n| ---------------------- | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | ----------------------------------- |\n| `[nzDataSource]`       | 用于渲染树的数组数据                                                                                       | `DataSource<T> \\| Observable<T[]> \\| T[]`, [DataSource](https://material.angular.io/cdk/tree/overview#data-source) | -                                   |\n| `[nzLevelAccessor]`    | 树层级访问方法（[levelAccessor](https://material.angular.io/cdk/tree/api#CdkTree)），结合扁平数据使用      | `(dataNode: T) => number`                                                                                          | -                                   |\n| `[nzChildrenAccessor]` | 树子节点访问方法（[childrenAccessor](https://material.angular.io/cdk/tree/api#CdkTree)），结合嵌套数据使用 | `(dataNode: T) => T[]`                                                                                             | -                                   |\n| `[nzTrackBy]`          | 用于检查数据变化的差异，使用方式类似于 ngFor 的 trackBy 函数                                               | `TrackByFunction`                                                                                                  | `(_index, dataNode: T) => dataNode` |\n| `[nzDirectoryTree]`    | 节点是否以文件夹样式显示                                                                                   | `boolean`                                                                                                          | `false`                             |\n| `[nzBlockNode]`        | 节点是否占据整行                                                                                           | `boolean`                                                                                                          | `false`                             |\n| `[nzItemSize]`         | 节点的尺寸(px)                                                                                             | `number`                                                                                                           | `28`                                |\n| `[nzMinBufferPx]`      | 超出渲染区的最小缓存区大小(px)                                                                             | `number`                                                                                                           | `28 * 5`                            |\n| `[nzMaxBufferPx]`      | 需要渲染新节点时的缓冲区大小(px)                                                                           | `number`                                                                                                           | `28 * 10`                           |\n\n### [nzTreeNodeDef]\n\n用于定义 `nz-tree-node` 的指令。\n\n| 参数                  | 说明                                                                                                                   | 类型                                      | 默认值 |\n| --------------------- | ---------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- | ------ |\n| `[nzTreeNodeDefWhen]` | 用于定义是否使用此节点的方法，优先匹配第一个返回 `true` 的节点。如果没有返回 `true` 的节点，则匹配未定义此方法的节点。 | `(index: number, nodeData: T) => boolean` | -      |\n\n### nz-tree-node\n\n树节点容器组件，需要通过 `nzTreeNodeDef` 指令定义。\n\n| 参数             | 说明                                                                                                                                            | 类型      | 默认值  |\n| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ------- |\n| `[nzExpandable]` | [节点是否可展开](https://material.angular.io/cdk/tree/api#CdkTreeNode)，使用 `nzLevelAccessor` 或 `nzChildrenAccessor` 时需要明确指定该参数值。 | `boolean` | `false` |\n\n### [nzTreeNodePadding]\n\n以添加 `padding` 的方式显示节点缩进 **性能最好**。\n\n```html\n<nz-tree-node nzTreeNodePadding></nz-tree-node>\n```\n\n### nzTreeNodeIndentLine\n\n以添加缩进线的方式显示节点缩进。\n\n```html\n<nz-tree-node nzTreeNodeIndentLine></nz-tree-node>\n```\n\n### nz-tree-node-toggle\n\n切换部分，用于节点的展开/收起。\n\n| 参数                          | 说明                | 类型      | 默认值  |\n| ----------------------------- | ------------------- | --------- | ------- |\n| `[nzTreeNodeToggleRecursive]` | 是否为递归展开/收起 | `boolean` | `false` |\n\n### nz-tree-node-toggle[nzTreeNodeNoopToggle]\n\n不做任何操作的切换部分，可用于占位或者显示图标。\n\n### [nzTreeNodeToggleRotateIcon]\n\n定义切换部分中的图标，会随着展开收起状态自动旋转。\n\n### [nzTreeNodeToggleActiveIcon]\n\n定义切换部分中的图标，使其具有激活状态的样式，可用于 loading 图标。\n\n### nz-tree-node-option\n\n定义节点中的可选择部分。\n\n| 参数           | 说明         | 类型                       | 默认值  |\n| -------------- | ------------ | -------------------------- | ------- |\n| `[nzSelected]` | 是否选中     | `boolean`                  | `false` |\n| `[nzDisabled]` | 是否禁用     | `boolean`                  | `false` |\n| `(nzClick)`    | 点击时的事件 | `EventEmitter<MouseEvent>` | -       |\n\n### nz-tree-node-checkbox\n\n定义节点中的可勾选的部分。\n\n| 参数                | 说明         | 类型                       | 默认值  |\n| ------------------- | ------------ | -------------------------- | ------- |\n| `[nzChecked]`       | 是否勾选     | `boolean`                  | `false` |\n| `[nzIndeterminate]` | 是否为半选   | `boolean`                  | `false` |\n| `[nzDisabled] `     | 是否禁用     | `boolean`                  | `false` |\n| `(nzClick)`         | 点击时的事件 | `EventEmitter<MouseEvent>` | -       |\n\n## Classes\n\n### NzTreeViewFlatDataSource extends DataSource\n\n用于扁平数据的 `dataSource`，能够自动响应视图、数据变化，结合 `nzLevelAccessor` 使用。\n\n**构造参数**\n\n| 名称                                   | 说明                                               |\n| -------------------------------------- | -------------------------------------------------- |\n| `tree: NzTreeView<T, F>`               | Tree View 组件实例                                 |\n| `treeFlattener: NzTreeFlattener<T, F>` | 用于将嵌套节点 `<T>` 转化为扁平节点 `<F>` 的展平器 |\n| `initialData: T[] = []`                | 初始数据 `<T>`                                     |\n\n**方法**\n\n| 名称                                                           | 说明                                              |\n| -------------------------------------------------------------- | ------------------------------------------------- |\n| `connect(collectionViewer: CollectionViewer): Observable<F[]>` | TreeView 组件中调用，发射 flattenData 给 TreeView |\n| `disconnect(): void`                                           | TreeView 组件销毁时调用                           |\n| `setData(value: T[]): void`                                    | 设置初始数据 `<T>`                                |\n| `getData(): T[]`                                               | 获取初始数据 `<T>`                                |\n| `setFlattenedData(nodes: F[]): void`                           | 设置扁平数据 `<F>`                                |\n| `getFlattenData(): F[]`                                        | 获取扁平数据 `<F>`                                |\n\n### NzTreeViewNestedDataSource extends DataSource\n\n用于嵌套数据的 `dataSource`，能够自动响应视图、数据变化，结合 `nzChidrenAccessor` 使用。\n\n**构造参数**\n\n| 名称                    | 说明               |\n| ----------------------- | ------------------ |\n| `tree: NzTreeView<T>`   | Tree View 组件实例 |\n| `initialData: T[] = []` | 初始数据 `<T>`     |\n\n**方法**\n\n| 名称                                                           | 说明                                       |\n| -------------------------------------------------------------- | ------------------------------------------ |\n| `connect(collectionViewer: CollectionViewer): Observable<T[]>` | TreeView 组件中调用，发射 data 给 TreeView |\n| `disconnect(): void`                                           | TreeView 组件销毁时调用                    |\n| `setData(value: T[]): void`                                    | 设置初始数据 `<T>`                         |\n| `getData(): T[]`                                               | 获取初始数据 `<T>`                         |\n\n### NzTreeFlattener\n\n将具有子节点的嵌套数据转换为具有级别（level）信息的转换器类。\n\n**构造参数**\n\n| 名称                                                                    | 说明                                        |\n| ----------------------------------------------------------------------- | ------------------------------------------- |\n| `transformFunction: (node: T, level: number) => F`                      | 接收一个嵌套节点 `<T>`，返回扁平节点 `<F>`  |\n| `getLevel: (node: F) => number`                                         | 定义从扁平节点数据中获取 `level` 属性的方法 |\n| `isExpandable: (node: F) => boolean`                                    | 定义是否为可展开节点的方法                  |\n| `getChildren: (node: T) => Observable<T[]> \\| T[] \\| undefined \\| null` | 定义从嵌套数据 `<T>` 中获取子节点的方法     |\n\n**方法**\n\n| 名称                                     | 说明                                   |\n| ---------------------------------------- | -------------------------------------- |\n| `flattenNodes(structuredData: T[]): F[]` | 接收嵌套数据 `<T>`，返回扁平数据 `<F>` |\n\n## utils\n\nTree View 中常用的工具类。提供获取当前树节点的父亲、兄弟、子孙节点等方法，包含两套方法以分别用于**扁平**和**嵌套**数据结构。\n\n**扁平数据**\n\n| 名称                                                                                                   | 说明                                                           |\n| ------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------- |\n| `getParent: (nodes: F[], node: F, getLevel: (dataNode: F) => number): F \\| null`                       | 返回当前节点的父节点                                           |\n| `getDescendants: (nodes: F[], node: F, getLevel: (dataNode: F) => number): F[]`                        | 返回当前节点的所有子孙节点                                     |\n| `getNextSibling: (nodes: F[], node: F, getLevel: (dataNode: F) => number, _index?: number): F \\| null` | 返回当前节点的下一个兄弟节点（或 `_index` 后的第一个兄弟节点） |\n\n**嵌套数据**\n\n| 名称                                                                                               | 说明                                             |\n| -------------------------------------------------------------------------------------------------- | ------------------------------------------------ |\n| `getParentForNestedData: (nodes: T[], node: T, getChildren: (dataNode: T) => T[]): T \\| null`      | 返回当前节点的父节点                             |\n| `getDescendantsForNestedData: (node: T, getChildren: (dataNode: T) => T[]): T[]`                   | 返回当前节点的所有子孙节点                       |\n| `getNextSiblingForNestedData: (nodes: T[], node: T, getChildren: (dataNode: T) => T[]): T \\| null` | 返回当前节点的下一个兄弟节点                     |\n| `flattenNestedNodes: (nodes: T[], getChildren: (dataNode: T) => T[]): T[]`                         | 铺平嵌套数据，返回扁平数组，但不会改变节点属性。 |\n"
  },
  {
    "path": "components/tree-view/flat-data-source.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { CollectionViewer, DataSource } from '@angular/cdk/collections';\nimport { Observable, BehaviorSubject, merge } from 'rxjs';\nimport { map } from 'rxjs/operators';\n\nimport { NzTreeFlattener } from './flattener';\nimport { NzTreeView } from './tree';\n\nexport class NzTreeViewFlatDataSource<T, F> extends DataSource<F> {\n  private _flattenedData = new BehaviorSubject<F[]>([]);\n  private _data = new BehaviorSubject<T[]>([]);\n\n  constructor(\n    private readonly _tree: NzTreeView<F>,\n    private readonly _treeFlattener: NzTreeFlattener<T, F>,\n    readonly initialData: T[] = []\n  ) {\n    super();\n    this.setData(initialData);\n  }\n\n  setData(data: T[]): void {\n    this._data.next(data);\n    this.setFlattenedData(this.flatten(data));\n  }\n\n  getData(): T[] {\n    return this._data.getValue();\n  }\n\n  getFlattenData(): F[] {\n    return this._flattenedData.getValue();\n  }\n\n  setFlattenedData(nodes: F[]): void {\n    this._flattenedData.next(nodes);\n    this.setDataNodes(nodes);\n  }\n\n  connect(collectionViewer: CollectionViewer): Observable<F[]> {\n    return merge(collectionViewer.viewChange, this._flattenedData.asObservable()).pipe(\n      map(() => this.getFlattenData())\n    );\n  }\n\n  disconnect(): void {\n    // no op\n  }\n\n  private setDataNodes(nodes: F[]): void {\n    this._tree.dataNodes = nodes;\n  }\n\n  private flatten(data: T[]): F[] {\n    return this._treeFlattener.flattenNodes(data);\n  }\n}\n"
  },
  {
    "path": "components/tree-view/flattener.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Observable } from 'rxjs';\nimport { take } from 'rxjs/operators';\n\nexport class NzTreeFlattener<T, F> {\n  constructor(\n    public transformFunction: (node: T, level: number) => F,\n    public getLevel: (node: F) => number,\n    public isExpandable: (node: F) => boolean,\n    public getChildren: (node: T) => Observable<T[]> | T[] | undefined | null\n  ) {}\n\n  private flattenNode(node: T, level: number, resultNodes: F[], parentMap: boolean[]): F[] {\n    const flatNode = this.transformFunction(node, level);\n    resultNodes.push(flatNode);\n\n    if (this.isExpandable(flatNode)) {\n      const childrenNodes = this.getChildren(node);\n      if (childrenNodes) {\n        if (Array.isArray(childrenNodes)) {\n          this.flattenChildren(childrenNodes, level, resultNodes, parentMap);\n        } else {\n          childrenNodes.pipe(take(1)).subscribe(children => {\n            this.flattenChildren(children, level, resultNodes, parentMap);\n          });\n        }\n      }\n    }\n    return resultNodes;\n  }\n\n  private flattenChildren(children: T[], level: number, resultNodes: F[], parentMap: boolean[]): void {\n    children.forEach((child, index) => {\n      const childParentMap: boolean[] = parentMap.slice();\n      childParentMap.push(index !== children.length - 1);\n      this.flattenNode(child, level + 1, resultNodes, childParentMap);\n    });\n  }\n\n  /**\n   * Flatten a list of node type T to flattened version of node F.\n   * Please note that type T may be nested, and the length of `structuredData` may be different\n   * from that of returned list `F[]`.\n   */\n  flattenNodes(structuredData: T[]): F[] {\n    const resultNodes: F[] = [];\n    structuredData.forEach(node => this.flattenNode(node, 0, resultNodes, []));\n    return resultNodes;\n  }\n}\n"
  },
  {
    "path": "components/tree-view/indent.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DestroyRef,\n  Directive,\n  inject,\n  Input\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { animationFrameScheduler, asapScheduler, merge } from 'rxjs';\nimport { auditTime } from 'rxjs/operators';\n\nimport { NzNodeBase } from './node-base';\nimport { NzTreeView } from './tree';\nimport {\n  flattenNestedNodes,\n  getNextSibling,\n  getNextSiblingForNestedData,\n  getParent,\n  getParentForNestedData\n} from './utils';\n\n/**\n * [true, false, false, true] => 1001\n */\nfunction booleanArrayToString(arr: boolean[]): string {\n  return arr.map(i => (i ? 1 : 0)).join('');\n}\n\nconst BUILD_INDENTS_SCHEDULER = typeof requestAnimationFrame !== 'undefined' ? animationFrameScheduler : asapScheduler;\n\n@Component({\n  selector: 'nz-tree-node-indents',\n  template: `\n    @for (isEnd of indents; track isEnd) {\n      <span class=\"ant-tree-indent-unit\" [class.ant-tree-indent-unit-end]=\"!isEnd\"></span>\n    }\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    class: 'ant-tree-indent'\n  }\n})\nexport class NzTreeNodeIndentsComponent {\n  @Input() indents: boolean[] = [];\n}\n\n@Directive({\n  selector: 'nz-tree-node[nzTreeNodeIndentLine]',\n  host: {\n    class: 'ant-tree-show-line',\n    '[class.ant-tree-treenode-leaf-last]': 'isLast && isLeaf'\n  }\n})\nexport class NzTreeNodeIndentLineDirective<T> {\n  private readonly treeNode = inject(NzNodeBase<T>);\n  private readonly tree = inject(NzTreeView<T>);\n  private readonly cdr = inject(ChangeDetectorRef);\n  private readonly destroyRef = inject(DestroyRef);\n\n  private preNodeRef: T | null = null;\n  private nextNodeRef: T | null = null;\n  private currentIndents: string = '';\n\n  isLast: boolean | 'unset' = 'unset';\n\n  get isLeaf(): boolean {\n    return this.treeNode.isLeaf;\n  }\n\n  get dataNodes(): T[] {\n    return this.tree.dataNodes;\n  }\n\n  get currentDataNode(): T {\n    return this.treeNode.data;\n  }\n\n  constructor() {\n    this.buildIndents();\n    this.checkLast();\n\n    /**\n     * setting the indents can cause frame rate loss if it is set too often.\n     */\n    merge(this.treeNode._dataChanges, this.tree.dataSourceChanged$)\n      .pipe(auditTime(0, BUILD_INDENTS_SCHEDULER), takeUntilDestroyed(this.destroyRef))\n      .subscribe(() => {\n        this.buildIndents();\n        this.checkAdjacent();\n        this.cdr.markForCheck();\n      });\n  }\n\n  /**\n   * The true and false in indents indicate whether there should be a vertical line to the left of the current node.\n   * if there is no nextSibling, there is no vertical line.\n   */\n  private getIndents(): boolean[] {\n    if (this.tree.levelAccessor) {\n      return this.getIndentsForFlatData(this.dataNodes, this.currentDataNode, this.tree.levelAccessor);\n    } else if (this.tree.childrenAccessor) {\n      return this.getIndentsForNestedData(this.dataNodes, this.currentDataNode, this.tree.childrenAccessor);\n    } else {\n      return [];\n    }\n  }\n\n  private getIndentsForFlatData(nodes: T[], node: T, getLevel: (dataNode: T) => number): boolean[] {\n    const indents: boolean[] = [];\n    let parent = getParent(nodes, node, getLevel);\n    while (parent) {\n      const parentNextSibling = getNextSibling(nodes, parent, getLevel);\n      if (parentNextSibling) {\n        indents.unshift(true);\n      } else {\n        indents.unshift(false);\n      }\n      parent = getParent(nodes, parent, getLevel);\n    }\n    return indents;\n  }\n\n  private getIndentsForNestedData(nodes: T[], node: T, getChildren: (dataNode: T) => T[]): boolean[] {\n    const indents: boolean[] = [];\n    let parent = getParentForNestedData(nodes, node, getChildren);\n    while (parent) {\n      const parentNextSibling = getNextSiblingForNestedData(nodes, parent, getChildren);\n      if (parentNextSibling) {\n        indents.unshift(true);\n      } else {\n        indents.unshift(false);\n      }\n      parent = getParentForNestedData(nodes, parent, getChildren);\n    }\n    return indents;\n  }\n\n  private buildIndents(): void {\n    if (this.currentDataNode) {\n      const indents = this.getIndents();\n      const diffString = booleanArrayToString(indents);\n      if (diffString !== this.currentIndents) {\n        this.treeNode.setIndents(this.getIndents());\n        this.currentIndents = diffString;\n      }\n    }\n  }\n\n  /**\n   * We need to add a class name for the last child node,\n   * this result can also be affected when the adjacent nodes are changed.\n   */\n  private checkAdjacent(): void {\n    let nodes = [] as T[];\n    if (this.tree.levelAccessor) {\n      nodes = this.dataNodes;\n    } else if (this.tree.childrenAccessor) {\n      nodes = flattenNestedNodes(this.dataNodes, this.tree.childrenAccessor);\n    }\n    this.checkAdjacentNodeChanged(nodes);\n  }\n\n  private checkAdjacentNodeChanged(nodes: T[]): void {\n    const index = nodes.indexOf(this.currentDataNode);\n    const preNode = nodes[index - 1] || null;\n    const nextNode = nodes[index + 1] || null;\n    if (this.nextNodeRef !== nextNode || this.preNodeRef !== preNode) {\n      this.checkLast(index);\n    }\n    this.preNodeRef = preNode;\n    this.nextNodeRef = nextNode;\n  }\n\n  private checkLast(index?: number): void {\n    if (this.tree.levelAccessor) {\n      this.isLast = !getNextSibling(this.dataNodes, this.currentDataNode, this.tree.levelAccessor, index);\n    } else if (this.tree.childrenAccessor) {\n      this.isLast = !getNextSiblingForNestedData(this.dataNodes, this.currentDataNode, this.tree.childrenAccessor);\n    } else {\n      return;\n    }\n  }\n}\n"
  },
  {
    "path": "components/tree-view/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/tree-view/nested-data-source.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { CollectionViewer, DataSource } from '@angular/cdk/collections';\nimport { Observable, BehaviorSubject, merge } from 'rxjs';\nimport { map } from 'rxjs/operators';\n\nimport { NzTreeView } from './tree';\n\nexport class NzTreeViewNestedDataSource<T> extends DataSource<T> {\n  private _data = new BehaviorSubject<T[]>([]);\n\n  constructor(\n    private _tree: NzTreeView<T>,\n    readonly initialData: T[] = []\n  ) {\n    super();\n    this.setData(initialData);\n  }\n\n  setData(value: T[]): void {\n    this._data.next(value);\n    this.setTreeDataNodes(value);\n  }\n\n  getData(): T[] {\n    return this._data.getValue();\n  }\n\n  connect(collectionViewer: CollectionViewer): Observable<T[]> {\n    return merge(collectionViewer.viewChange, this._data.asObservable()).pipe(map(() => this.getData()));\n  }\n\n  disconnect(): void {\n    // no op\n  }\n\n  private setTreeDataNodes(nodes: T[]): void {\n    this._tree.dataNodes = nodes;\n  }\n}\n"
  },
  {
    "path": "components/tree-view/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/tree-view/node-base.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { CdkTreeNode } from '@angular/cdk/tree';\n\nexport abstract class NzNodeBase<T> extends CdkTreeNode<T> {\n  // Distinguish the isLeafNode of CdkTreeNode, isLeafNode is only used for Tree Control\n  abstract get isLeaf(): boolean;\n  abstract setIndents(indents: boolean[]): void;\n}\n"
  },
  {
    "path": "components/tree-view/node.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { CdkTreeNode, CdkTreeNodeDef, CdkTreeNodeOutletContext } from '@angular/cdk/tree';\nimport {\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  Component,\n  Directive,\n  effect,\n  EmbeddedViewRef,\n  forwardRef,\n  inject,\n  input,\n  Input,\n  OnDestroy,\n  OnInit,\n  signal,\n  ViewContainerRef\n} from '@angular/core';\n\nimport { NzAnimationTreeCollapseDirective } from 'ng-zorro-antd/core/animation';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzTreeNodeIndentsComponent } from './indent';\nimport { NzNodeBase } from './node-base';\nimport { NzTreeNodeNoopToggleDirective } from './toggle';\n\nexport interface NzTreeVirtualNodeData<T> {\n  data: T;\n  context: CdkTreeNodeOutletContext<T>;\n  nodeDef: CdkTreeNodeDef<T>;\n}\n\n@Component({\n  selector: 'nz-tree-node:not([builtin])',\n  exportAs: 'nzTreeNode',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  providers: [\n    {\n      provide: CdkTreeNode,\n      useExisting: forwardRef(() => NzTreeNodeComponent)\n    },\n    {\n      provide: NzNodeBase,\n      useExisting: forwardRef(() => NzTreeNodeComponent)\n    }\n  ],\n  template: `\n    @if (indents().length) {\n      <nz-tree-node-indents [indents]=\"indents()\" />\n    }\n    <ng-content select=\"nz-tree-node-toggle, [nz-tree-node-toggle]\" />\n    @if (indents().length && isLeaf) {\n      <nz-tree-node-toggle class=\"nz-tree-leaf-line-icon\" nzTreeNodeNoopToggle>\n        <span class=\"ant-tree-switcher-leaf-line\"></span>\n      </nz-tree-node-toggle>\n    }\n    <ng-content select=\"nz-tree-node-checkbox\" />\n    <ng-content select=\"nz-tree-node-option\" />\n    <ng-content />\n  `,\n  hostDirectives: [NzAnimationTreeCollapseDirective],\n  host: {\n    class: 'ant-tree-treenode',\n    '[class.ant-tree-treenode-switcher-open]': 'isExpanded',\n    '[class.ant-tree-treenode-switcher-close]': '!isExpanded',\n    '[class.ant-tree-treenode-selected]': 'selected()',\n    '[class.ant-tree-treenode-disabled]': 'disabled()'\n  },\n  imports: [NzTreeNodeIndentsComponent, NzTreeNodeNoopToggleDirective]\n})\nexport class NzTreeNodeComponent<T> extends NzNodeBase<T> implements OnDestroy, OnInit {\n  // Used to determine whether it is a leaf node\n  @Input({ alias: 'nzExpandable', transform: booleanAttribute })\n  override get isExpandable(): boolean {\n    return super.isExpandable;\n  }\n  override set isExpandable(value: boolean) {\n    super.isExpandable = value;\n  }\n\n  indents = signal<boolean[]>([]);\n  disabled = signal(false);\n  selected = signal(false);\n\n  get isLeaf(): boolean {\n    return !this.isExpandable;\n  }\n\n  disable(): void {\n    this.disabled.set(true);\n  }\n\n  enable(): void {\n    this.disabled.set(false);\n  }\n\n  select(): void {\n    this.selected.set(true);\n  }\n\n  deselect(): void {\n    this.selected.set(false);\n  }\n\n  setIndents(indents: boolean[]): void {\n    this.indents.set(indents);\n  }\n}\n\n@Directive({\n  selector: '[nzTreeNodeDef]',\n  providers: [\n    {\n      provide: CdkTreeNodeDef,\n      useExisting: forwardRef(() => NzTreeNodeDefDirective)\n    }\n  ]\n})\nexport class NzTreeNodeDefDirective<T> extends CdkTreeNodeDef<T> {\n  @Input({ alias: 'nzTreeNodeDefWhen' }) override when: (index: number, nodeData: T) => boolean = null!;\n}\n\n@Directive({\n  selector: '[nzTreeVirtualScrollNodeOutlet]'\n})\nexport class NzTreeVirtualScrollNodeOutletDirective<T> {\n  readonly data = input.required<NzTreeVirtualNodeData<T>>();\n  readonly compareBy = input.required<(value: T) => NzSafeAny>();\n\n  private readonly _viewContainerRef = inject(ViewContainerRef);\n  private _viewRef: EmbeddedViewRef<NzSafeAny> | null = null;\n  private _previousData: NzTreeVirtualNodeData<T> | null = null;\n\n  constructor() {\n    effect(() => {\n      const currentData = this.data();\n\n      const recreateView = this.shouldRecreateView(this._previousData, currentData, this.compareBy());\n      if (recreateView) {\n        const viewContainerRef = this._viewContainerRef;\n\n        if (this._viewRef) {\n          viewContainerRef.remove(viewContainerRef.indexOf(this._viewRef));\n        }\n\n        this._viewRef = currentData\n          ? viewContainerRef.createEmbeddedView(currentData.nodeDef.template, currentData.context)\n          : null;\n\n        if (CdkTreeNode.mostRecentTreeNode && this._viewRef) {\n          CdkTreeNode.mostRecentTreeNode.data = currentData.data;\n        }\n      } else if (this._viewRef && currentData.context) {\n        this.updateExistingContext(currentData.context);\n      }\n\n      // Save the current value as the previous value for the next iteration\n      this._previousData = currentData;\n    });\n  }\n\n  private shouldRecreateView(\n    previousData: NzTreeVirtualNodeData<T> | null,\n    currentData: NzTreeVirtualNodeData<T>,\n    compareByFn: (value: T) => NzSafeAny\n  ): boolean {\n    const prevCtxKeys = Object.keys(previousData || {});\n    const currCtxKeys = Object.keys(currentData || {});\n\n    if (prevCtxKeys.length === currCtxKeys.length) {\n      for (const propName of currCtxKeys) {\n        if (prevCtxKeys.indexOf(propName) === -1) {\n          return true;\n        }\n      }\n      return compareByFn((previousData?.data ?? null) as T) !== compareByFn((currentData?.data ?? null) as T);\n    }\n    return true;\n  }\n\n  private updateExistingContext(ctx: CdkTreeNodeOutletContext<T>): void {\n    for (const [key, value] of Object.entries(ctx)) {\n      this._viewRef!.context[key] = value;\n    }\n  }\n}\n"
  },
  {
    "path": "components/tree-view/option.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  ElementRef,\n  NgZone,\n  OnInit,\n  booleanAttribute,\n  inject,\n  DestroyRef,\n  input,\n  output,\n  effect\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { filter } from 'rxjs/operators';\n\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\n\nimport { NzTreeNodeComponent } from './node';\n\n@Component({\n  selector: 'nz-tree-node-option',\n  template: `<span class=\"ant-tree-title\"><ng-content /></span>`,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    class: 'ant-tree-node-content-wrapper',\n    '[class.ant-tree-node-content-wrapper-open]': 'isExpanded',\n    '[class.ant-tree-node-selected]': 'nzSelected()'\n  }\n})\nexport class NzTreeNodeOptionComponent<T> implements OnInit {\n  readonly nzSelected = input(false, { transform: booleanAttribute });\n  readonly nzDisabled = input(false, { transform: booleanAttribute });\n  readonly nzClick = output<MouseEvent>();\n\n  private readonly ngZone = inject(NgZone);\n  private readonly element: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement;\n  private readonly destroyRef = inject(DestroyRef);\n  private readonly treeNode = inject(NzTreeNodeComponent<T>);\n\n  get isExpanded(): boolean {\n    return this.treeNode.isExpanded;\n  }\n\n  constructor() {\n    effect(() => {\n      if (this.nzSelected()) {\n        this.treeNode.select();\n      } else {\n        this.treeNode.deselect();\n      }\n    });\n\n    effect(() => {\n      if (this.nzDisabled()) {\n        this.treeNode.disable();\n      } else {\n        this.treeNode.enable();\n      }\n    });\n  }\n\n  ngOnInit(): void {\n    fromEventOutsideAngular<MouseEvent>(this.element, 'click')\n      .pipe(\n        filter(() => !this.nzDisabled()),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(event => {\n        this.ngZone.run(() => this.nzClick.emit(event));\n      });\n  }\n}\n"
  },
  {
    "path": "components/tree-view/outlet.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { CdkTreeNodeOutlet } from '@angular/cdk/tree';\nimport { Directive, forwardRef } from '@angular/core';\n\n@Directive({\n  selector: '[nzTreeNodeOutlet]',\n  providers: [\n    {\n      provide: CdkTreeNodeOutlet,\n      useExisting: forwardRef(() => NzTreeNodeOutletDirective)\n    }\n  ]\n})\nexport class NzTreeNodeOutletDirective extends CdkTreeNodeOutlet {}\n"
  },
  {
    "path": "components/tree-view/padding.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { CdkTreeNodePadding } from '@angular/cdk/tree';\nimport { Directive, forwardRef, Input, numberAttribute } from '@angular/core';\n\n@Directive({\n  selector: '[nzTreeNodePadding]',\n  providers: [\n    {\n      provide: CdkTreeNodePadding,\n      useExisting: forwardRef(() => NzTreeNodePaddingDirective)\n    }\n  ]\n})\nexport class NzTreeNodePaddingDirective<T> extends CdkTreeNodePadding<T> {\n  override _indent = 24;\n\n  @Input({ alias: 'nzTreeNodePadding', transform: numberAttribute })\n  override get level(): number {\n    return this._level;\n  }\n  override set level(value: number) {\n    this._setLevelInput(value);\n  }\n\n  @Input('nzTreeNodePaddingIndent')\n  override get indent(): number | string {\n    return this._indent;\n  }\n  override set indent(indent: number | string) {\n    this._setIndentInput(indent);\n  }\n}\n"
  },
  {
    "path": "components/tree-view/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './tree-view.module';\nexport * from './checkbox';\nexport * from './utils';\nexport * from './indent';\nexport * from './node';\nexport * from './option';\nexport * from './outlet';\nexport * from './padding';\nexport * from './toggle';\nexport * from './tree-view';\nexport * from './tree';\nexport * from './tree-virtual-scroll-view';\nexport * from './flattener';\nexport * from './flat-data-source';\nexport * from './nested-data-source';\n"
  },
  {
    "path": "components/tree-view/style/entry.less",
    "content": "/*\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\n@import 'index.less';\n"
  },
  {
    "path": "components/tree-view/style/index.less",
    "content": "/*\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nnz-tree-virtual-scroll-view {\n  position: relative;\n  display: block;\n  overflow: auto;\n  transform: translateZ(0);\n  will-change: scroll-position;\n  contain: strict;\n  -webkit-overflow-scrolling: touch;\n\n  .ant-tree-list, .ant-tree-list-holder {\n    height: 100%;\n  }\n}\n\nnz-tree-virtual-scroll-view, nz-tree-view {\n  .ant-tree-switcher + .ant-tree-switcher.nz-tree-leaf-line-icon {\n    display: none;\n  }\n}\n\nnz-tree-view .ant-tree-list-holder-inner {\n  display: flex;\n  flex-direction: column;\n}\n"
  },
  {
    "path": "components/tree-view/toggle.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { CdkTreeNodeToggle } from '@angular/cdk/tree';\nimport { booleanAttribute, Directive, forwardRef, Input } from '@angular/core';\n\n@Directive({\n  selector: 'nz-tree-node-toggle[nzTreeNodeNoopToggle], [nzTreeNodeNoopToggle]',\n  host: {\n    class: 'ant-tree-switcher ant-tree-switcher-noop'\n  }\n})\nexport class NzTreeNodeNoopToggleDirective {}\n\n@Directive({\n  selector: 'nz-tree-node-toggle:not([nzTreeNodeNoopToggle]), [nzTreeNodeToggle]',\n  providers: [{ provide: CdkTreeNodeToggle, useExisting: forwardRef(() => NzTreeNodeToggleDirective) }],\n  host: {\n    class: 'ant-tree-switcher',\n    '[class.ant-tree-switcher_open]': 'isExpanded',\n    '[class.ant-tree-switcher_close]': '!isExpanded'\n  }\n})\nexport class NzTreeNodeToggleDirective<T> extends CdkTreeNodeToggle<T> {\n  @Input({ alias: 'nzTreeNodeToggleRecursive', transform: booleanAttribute }) override recursive = false;\n\n  get isExpanded(): boolean {\n    return this._treeNode.isExpanded;\n  }\n}\n\n@Directive({\n  selector: '[nzTreeNodeToggleRotateIcon]',\n  host: {\n    class: 'ant-tree-switcher-icon'\n  }\n})\nexport class NzTreeNodeToggleRotateIconDirective {}\n\n@Directive({\n  selector: '[nzTreeNodeToggleActiveIcon]',\n  host: {\n    class: 'ant-tree-switcher-loading-icon'\n  }\n})\nexport class NzTreeNodeToggleActiveIconDirective {}\n"
  },
  {
    "path": "components/tree-view/tree-view-based-children-accessor.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { SelectionModel } from '@angular/cdk/collections';\nimport { Component, OnInit, ViewChild } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { cloneDeep } from 'lodash';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzTreeNodeIndentLineDirective } from './indent';\nimport { NzTreeViewNestedDataSource } from './nested-data-source';\nimport { NzTreeNodeComponent } from './node';\nimport { NzTreeNodePaddingDirective } from './padding';\nimport { NzTreeViewComponent } from './tree-view';\nimport { NzTreeViewModule } from './tree-view.module';\n\n/**\n * Helper function to wait for the next animation frame in zoneless Angular environment\n */\nexport async function waitForNextAnimationFrame(): Promise<void> {\n  return new Promise(resolve => requestAnimationFrame(() => resolve()));\n}\n\ndescribe('tree-view based on nzChildrenAccessor', () => {\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideNoopAnimations()]\n    });\n  });\n\n  describe('tree view basic', () => {\n    let fixture: ComponentFixture<NzTestTreeViewBasicWithChildrenAccessorComponent>;\n    let testComponent: NzTestTreeViewBasicWithChildrenAccessorComponent;\n    let nativeElement: Element;\n\n    beforeEach(async () => {\n      fixture = TestBed.createComponent(NzTestTreeViewBasicWithChildrenAccessorComponent);\n      testComponent = fixture.componentInstance;\n      nativeElement = fixture.debugElement.nativeElement;\n      await fixture.whenStable();\n    });\n\n    it('should init nested tree data', () => {\n      const { dataNodes } = testComponent.tree;\n      const shownNodes = nativeElement.querySelectorAll('nz-tree-node:not([builtin])');\n      expect(dataNodes.length).toBe(2);\n      expect(dataNodes).toEqual(TREE_DATA);\n      expect(shownNodes.length).toBe(2);\n    });\n\n    it('should highlight when tree node option is selected', async () => {\n      const nodeOption = fixture.debugElement.query(By.css('nz-tree-node-option'));\n      nodeOption.nativeElement.click();\n      await fixture.whenStable();\n      expect(nodeOption.nativeElement.classList).toContain('ant-tree-node-selected');\n    });\n\n    it('should expand nodes when toggle the collapsed tree node', async () => {\n      const nodeToggle = fixture.debugElement.query(By.css('nz-tree-node-toggle'));\n      nodeToggle.nativeElement.click();\n      await fixture.whenStable();\n      expect(nodeToggle.nativeElement.classList).toContain('ant-tree-switcher_open');\n      expect(nativeElement.querySelectorAll('nz-tree-node:not([builtin])').length).toBe(4);\n    });\n\n    it('should collapse nodes when toggle the expanded tree node', async () => {\n      const firstNode = testComponent.tree.dataNodes[0];\n      testComponent.tree.expand(firstNode);\n      await fixture.whenStable();\n      const nodeToggle = fixture.debugElement.query(By.css('nz-tree-node-toggle'));\n      nodeToggle.nativeElement.click();\n      await fixture.whenStable();\n      expect(nodeToggle.nativeElement.classList).toContain('ant-tree-switcher_close');\n      expect(nativeElement.querySelectorAll('nz-tree-node:not([builtin])').length).toBe(2);\n    });\n\n    it('should disabled node can not be selected but can be expanded', async () => {\n      const firstNode = testComponent.tree.dataNodes[0];\n      testComponent.tree.expand(firstNode);\n      await fixture.whenStable();\n      expect(nativeElement.querySelectorAll('nz-tree-node:not([builtin])').length).toBe(4);\n      const disabledNode = fixture.debugElement.queryAll(By.css('nz-tree-node:not([builtin])'))[1];\n      expect((disabledNode.componentInstance as NzTreeNodeComponent<TreeNode>).data.name).toBe('parent 1-1');\n      const disabledNodeOption = disabledNode.query(By.css('nz-tree-node-option'));\n      const disabledNodeToggle = disabledNode.query(By.css('nz-tree-node-toggle'));\n      disabledNodeOption.nativeElement.click();\n      await fixture.whenStable();\n      expect(disabledNodeOption.nativeElement.classList).not.toContain('ant-tree-node-selected');\n      disabledNodeToggle.nativeElement.click();\n      await fixture.whenStable();\n      expect(disabledNodeToggle.nativeElement.classList).toContain('ant-tree-switcher_open');\n      expect(nativeElement.querySelectorAll('nz-tree-node:not([builtin])').length).toBe(6);\n    });\n\n    it('should nzDirectoryTree work', async () => {\n      const treeView = fixture.debugElement.query(By.css('nz-tree-view'));\n      expect(treeView.nativeElement.classList).not.toContain('ant-tree-directory');\n      testComponent.directoryTree = true;\n      fixture.changeDetectorRef.markForCheck();\n      await fixture.whenStable();\n      expect(treeView.nativeElement.classList).toContain('ant-tree-directory');\n      expect(treeView.nativeElement.classList).toContain('ant-tree-block-node');\n    });\n\n    it('should nzBlockNode work', async () => {\n      const treeView = fixture.debugElement.query(By.css('nz-tree-view'));\n      expect(treeView.nativeElement.classList).not.toContain('ant-tree-block-node');\n      testComponent.blockNode = true;\n      fixture.changeDetectorRef.markForCheck();\n      await fixture.whenStable();\n      expect(treeView.nativeElement.classList).toContain('ant-tree-block-node');\n    });\n  });\n\n  describe('nested data source', () => {\n    let fixture: ComponentFixture<NzTestTreeViewBasicWithChildrenAccessorComponent>;\n    let testComponent: NzTestTreeViewBasicWithChildrenAccessorComponent;\n\n    beforeEach(async () => {\n      fixture = TestBed.createComponent(NzTestTreeViewBasicWithChildrenAccessorComponent);\n      testComponent = fixture.componentInstance;\n      await fixture.whenStable();\n    });\n\n    it('should dataSource getData return origin nested data', () => {\n      const data = testComponent.dataSource.getData();\n      expect(data).toBe(TREE_DATA);\n    });\n\n    it('should dataSource connect emit origin nested data when tree expansion model changed or data changed', async () => {\n      let data: TreeNode[] = [];\n      const { dataSource } = testComponent;\n      const dataNodes = dataSource.getData();\n      dataSource\n        .connect(testComponent.tree)\n        .pipe()\n        .subscribe((value: TreeNode[]) => {\n          data = value;\n        });\n      // expand or collapse\n      testComponent.tree.expand(dataNodes[0]);\n      await fixture.whenStable();\n      expect(data).toEqual(TREE_DATA);\n      const firstNodeToggle = fixture.debugElement.query(By.css('nz-tree-node-toggle'));\n      firstNodeToggle.nativeElement.click();\n      await fixture.whenStable();\n      expect(data).toEqual(TREE_DATA);\n\n      // set new data\n      const newTreeData = cloneDeep(TREE_DATA).slice(0, 1);\n      testComponent.setData(newTreeData);\n      expect(testComponent.tree.dataNodes).toBe(newTreeData);\n      await fixture.whenStable();\n      expect(data).toEqual(newTreeData);\n    });\n  });\n\n  describe('padding', () => {\n    let fixture: ComponentFixture<NzTestTreeViewBasicWithChildrenAccessorComponent>;\n    let testComponent: NzTestTreeViewBasicWithChildrenAccessorComponent;\n    const defaultIndent = 24;\n\n    beforeEach(async () => {\n      fixture = TestBed.createComponent(NzTestTreeViewBasicWithChildrenAccessorComponent);\n      testComponent = fixture.componentInstance;\n      await fixture.whenStable();\n      // expand all node\n      const { tree } = testComponent;\n      tree.expandAll();\n      await fixture.whenStable();\n    });\n\n    it('should nzTreeNodePadding without value work', () => {\n      const nodes = fixture.debugElement.queryAll(By.css('nz-tree-node:not([builtin])'));\n      expect(nodes.length).toBe(8);\n      nodes.forEach(node => {\n        expect(window.getComputedStyle(node.nativeElement).paddingLeft).toBe(\n          `${(node.componentInstance as NzTreeNodeComponent<TreeNode>).level * defaultIndent}px`\n        );\n      });\n    });\n\n    it('should nzTreeNodePadding with value work', async () => {\n      const nodes = fixture.debugElement.queryAll(By.directive(NzTreeNodePaddingDirective));\n      expect(nodes.length).toBe(8);\n      const [parent_1, ...otherNodes] = nodes;\n      const parent_1_paddingDir = parent_1.injector.get(NzTreeNodePaddingDirective);\n      parent_1_paddingDir.level = 1;\n      await fixture.whenStable();\n      // 1 * defaultIndent = 24\n      expect(window.getComputedStyle(parent_1.nativeElement).paddingLeft).toBe('24px');\n      otherNodes.forEach(node => {\n        expect(window.getComputedStyle(node.nativeElement).paddingLeft).toBe(\n          `${(node.componentInstance as NzTreeNodeComponent<TreeNode>).level * defaultIndent}px`\n        );\n      });\n    });\n\n    it('should nzTreeNodePaddingIndent work', async () => {\n      const indent = 50;\n      const nodes = fixture.debugElement.queryAll(By.directive(NzTreeNodePaddingDirective));\n      expect(nodes.length).toBe(8);\n      nodes.forEach(node => {\n        const node_paddingDir = node.injector.get(NzTreeNodePaddingDirective);\n        node_paddingDir.indent = indent;\n      });\n      await fixture.whenStable();\n      nodes.forEach(node => {\n        expect(window.getComputedStyle(node.nativeElement).paddingLeft).toBe(\n          `${(node.componentInstance as NzTreeNodeComponent<TreeNode>).level * indent}px`\n        );\n      });\n    });\n  });\n\n  describe('line indents', () => {\n    let fixture: ComponentFixture<NzTestTreeViewLineComponent>;\n    let testComponent: NzTestTreeViewLineComponent;\n\n    beforeEach(async () => {\n      fixture = TestBed.createComponent(NzTestTreeViewLineComponent);\n      testComponent = fixture.componentInstance;\n      await fixture.whenStable();\n      // expand all node\n      const { tree } = testComponent;\n      tree.expandAll();\n      await waitForNextAnimationFrame();\n      await fixture.whenStable();\n    });\n\n    it('should nzTreeNodeIndentLine work', () => {\n      const nodes = fixture.debugElement.queryAll(By.directive(NzTreeNodeIndentLineDirective));\n      expect(nodes.length).toBe(8);\n      const [parent_1, parent_1_1, leaf_1_1_1, leaf_1_1_2, parent_1_2, leaf_1_2_1, parent_2, leaf_2_1] = nodes.map(\n        node => node.componentInstance as NzTreeNodeComponent<TreeNode>\n      );\n      expect(parent_1.indents()).toEqual([]);\n      expect(parent_1_1.indents()).toEqual([true]);\n      expect(leaf_1_1_1.indents()).toEqual([true, true]);\n      expect(leaf_1_1_2.indents()).toEqual([true, true]);\n      expect(parent_1_2.indents()).toEqual([true]);\n      expect(leaf_1_2_1.indents()).toEqual([true, false]);\n      expect(parent_2.indents()).toEqual([]);\n      expect(leaf_2_1.indents()).toEqual([false]);\n    });\n  });\n});\n\ninterface TreeNode {\n  name: string;\n  children?: TreeNode[];\n  disabled?: boolean;\n}\n\nconst TREE_DATA: TreeNode[] = [\n  {\n    name: 'parent 1',\n    children: [\n      {\n        name: 'parent 1-1',\n        disabled: true,\n        children: [{ name: 'leaf 1-1-1' }, { name: 'leaf 1-1-2' }]\n      },\n      {\n        name: 'parent 1-2',\n        children: [{ name: 'leaf 1-2-1' }]\n      }\n    ]\n  },\n  {\n    name: 'parent 2',\n    children: [{ name: 'leaf 2-1' }]\n  }\n];\n\n@Component({\n  imports: [NzIconModule, NzTreeViewModule],\n  template: `\n    <nz-tree-view\n      [nzDataSource]=\"dataSource\"\n      [nzChildrenAccessor]=\"childrenAccessor\"\n      [nzDirectoryTree]=\"directoryTree\"\n      [nzBlockNode]=\"blockNode\"\n    >\n      <nz-tree-node *nzTreeNodeDef=\"let node\" nzTreeNodePadding [nzExpandable]=\"false\">\n        <nz-tree-node-toggle nzTreeNodeNoopToggle />\n        <nz-tree-node-option\n          [nzDisabled]=\"node.disabled\"\n          [nzSelected]=\"selectListSelection.isSelected(node)\"\n          (nzClick)=\"selectListSelection.toggle(node)\"\n        >\n          {{ node.name }}\n        </nz-tree-node-option>\n      </nz-tree-node>\n\n      <nz-tree-node *nzTreeNodeDef=\"let node; when: hasChild\" nzTreeNodePadding [nzExpandable]=\"true\">\n        <nz-tree-node-toggle>\n          <nz-icon nzType=\"caret-down\" nzTreeNodeToggleRotateIcon />\n        </nz-tree-node-toggle>\n        <nz-tree-node-option\n          [nzDisabled]=\"node.disabled\"\n          [nzSelected]=\"selectListSelection.isSelected(node)\"\n          (nzClick)=\"selectListSelection.toggle(node)\"\n        >\n          {{ node.name }}\n        </nz-tree-node-option>\n      </nz-tree-node>\n    </nz-tree-view>\n  `\n})\nexport class NzTestTreeViewBasicWithChildrenAccessorComponent implements OnInit {\n  @ViewChild(NzTreeViewComponent, { static: true }) tree!: NzTreeViewComponent<TreeNode>;\n  childrenAccessor = (dataNode: TreeNode): TreeNode[] => dataNode.children ?? [];\n  hasChild = (_: number, node: TreeNode): boolean => !!node.children?.length;\n  selectListSelection = new SelectionModel<TreeNode>(true);\n  dataSource!: NzTreeViewNestedDataSource<TreeNode>;\n  directoryTree: boolean = false;\n  blockNode: boolean = false;\n\n  ngOnInit(): void {\n    this.dataSource = new NzTreeViewNestedDataSource<TreeNode>(this.tree, TREE_DATA);\n  }\n\n  setData(data: TreeNode[]): void {\n    this.dataSource.setData(data);\n  }\n}\n\n@Component({\n  imports: [NzIconModule, NzTreeViewModule],\n  template: `\n    <nz-tree-view [nzDataSource]=\"dataSource\" [nzChildrenAccessor]=\"childrenAccessor\">\n      <nz-tree-node *nzTreeNodeDef=\"let node\" nzTreeNodeIndentLine [nzExpandable]=\"false\">\n        <nz-tree-node-option>\n          {{ node.name }}\n        </nz-tree-node-option>\n      </nz-tree-node>\n\n      <nz-tree-node *nzTreeNodeDef=\"let node; when: hasChild\" nzTreeNodeIndentLine [nzExpandable]=\"true\">\n        <nz-tree-node-toggle>\n          <nz-icon nzType=\"caret-down\" nzTreeNodeToggleRotateIcon />\n        </nz-tree-node-toggle>\n        <nz-tree-node-option>\n          {{ node.name }}\n        </nz-tree-node-option>\n      </nz-tree-node>\n    </nz-tree-view>\n  `\n})\nexport class NzTestTreeViewLineComponent implements OnInit {\n  @ViewChild(NzTreeViewComponent, { static: true }) tree!: NzTreeViewComponent<TreeNode>;\n  childrenAccessor = (dataNode: TreeNode): TreeNode[] => dataNode.children ?? [];\n  hasChild = (_: number, node: TreeNode): boolean => !!node.children?.length;\n  dataSource!: NzTreeViewNestedDataSource<TreeNode>;\n\n  ngOnInit(): void {\n    this.dataSource = new NzTreeViewNestedDataSource<TreeNode>(this.tree, TREE_DATA);\n  }\n}\n"
  },
  {
    "path": "components/tree-view/tree-view-based-level-accessor.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { SelectionModel } from '@angular/cdk/collections';\nimport { Component, OnInit, ViewChild } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\nimport { of } from 'rxjs';\n\nimport { cloneDeep } from 'lodash';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzTreeViewFlatDataSource } from './flat-data-source';\nimport { NzTreeFlattener } from './flattener';\nimport { NzTreeNodeIndentLineDirective } from './indent';\nimport { NzTreeNodeComponent } from './node';\nimport { NzTreeNodePaddingDirective } from './padding';\nimport { NzTreeViewComponent } from './tree-view';\nimport { waitForNextAnimationFrame } from './tree-view-based-children-accessor.spec';\nimport { NzTreeViewModule } from './tree-view.module';\n\ndescribe('tree-view based on nzLevelAccessor', () => {\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideNoopAnimations()]\n    });\n  });\n\n  describe('tree view basic', () => {\n    let fixture: ComponentFixture<NzTestTreeViewBasicWithLevelAccessorComponent>;\n    let testComponent: NzTestTreeViewBasicWithLevelAccessorComponent;\n    let nativeElement: Element;\n\n    beforeEach(async () => {\n      fixture = TestBed.createComponent(NzTestTreeViewBasicWithLevelAccessorComponent);\n      testComponent = fixture.componentInstance;\n      nativeElement = fixture.debugElement.nativeElement;\n      await fixture.whenStable();\n    });\n\n    it('should init flat tree data', () => {\n      const { dataNodes } = testComponent.tree;\n      const shownNodes = nativeElement.querySelectorAll('nz-tree-node:not([builtin])');\n      expect(dataNodes.length).toBe(8);\n      expect(shownNodes.length).toBe(2);\n      const node = fixture.debugElement.query(By.css('nz-tree-node:not([builtin])'));\n      expect(node.componentInstance.data.name).toBe('parent 1');\n    });\n\n    it('should highlight when tree node option is selected', async () => {\n      const nodeOption = fixture.debugElement.query(By.css('nz-tree-node-option'));\n      nodeOption.nativeElement.click();\n      await fixture.whenStable();\n      expect(nodeOption.nativeElement.classList).toContain('ant-tree-node-selected');\n    });\n\n    it('should expand nodes when toggle the collapsed tree node', async () => {\n      const nodeToggle = fixture.debugElement.query(By.css('nz-tree-node-toggle'));\n      nodeToggle.nativeElement.click();\n      await fixture.whenStable();\n      expect(nodeToggle.nativeElement.classList).toContain('ant-tree-switcher_open');\n      expect(nativeElement.querySelectorAll('nz-tree-node:not([builtin])').length).toBe(4);\n    });\n\n    it('should collapse nodes when toggle the expanded tree node', async () => {\n      const firstNode = testComponent.tree.dataNodes[0];\n      testComponent.tree.expand(firstNode);\n      await fixture.whenStable();\n      const nodeToggle = fixture.debugElement.query(By.css('nz-tree-node-toggle'));\n      nodeToggle.nativeElement.click();\n      await fixture.whenStable();\n      expect(nodeToggle.nativeElement.classList).toContain('ant-tree-switcher_close');\n      expect(nativeElement.querySelectorAll('nz-tree-node:not([builtin])').length).toBe(2);\n    });\n\n    it('should disabled node can not be selected but can be expanded', async () => {\n      const firstNode = testComponent.tree.dataNodes[0];\n      testComponent.tree.expand(firstNode);\n      await fixture.whenStable();\n      expect(nativeElement.querySelectorAll('nz-tree-node:not([builtin])').length).toBe(4);\n      const disabledNode = fixture.debugElement.queryAll(By.css('nz-tree-node:not([builtin])'))[1];\n      expect((disabledNode.componentInstance as NzTreeNodeComponent<FlatNode>).data.name).toBe('parent 1-1');\n      const disabledNodeOption = disabledNode.query(By.css('nz-tree-node-option'));\n      const disabledNodeToggle = disabledNode.query(By.css('nz-tree-node-toggle'));\n      disabledNodeOption.nativeElement.click();\n      await fixture.whenStable();\n      expect(disabledNodeOption.nativeElement.classList).not.toContain('ant-tree-node-selected');\n      disabledNodeToggle.nativeElement.click();\n      await fixture.whenStable();\n      expect(disabledNodeToggle.nativeElement.classList).toContain('ant-tree-switcher_open');\n      expect(nativeElement.querySelectorAll('nz-tree-node:not([builtin])').length).toBe(6);\n    });\n\n    it('should nzDirectoryTree work', async () => {\n      const treeView = fixture.debugElement.query(By.css('nz-tree-view'));\n      expect(treeView.nativeElement.classList).not.toContain('ant-tree-directory');\n      testComponent.directoryTree = true;\n      fixture.changeDetectorRef.markForCheck();\n      await fixture.whenStable();\n      expect(treeView.nativeElement.classList).toContain('ant-tree-directory');\n      expect(treeView.nativeElement.classList).toContain('ant-tree-block-node');\n    });\n\n    it('should nzBlockNode work', async () => {\n      const treeView = fixture.debugElement.query(By.css('nz-tree-view'));\n      expect(treeView.nativeElement.classList).not.toContain('ant-tree-block-node');\n      testComponent.blockNode = true;\n      fixture.changeDetectorRef.markForCheck();\n      await fixture.whenStable();\n      expect(treeView.nativeElement.classList).toContain('ant-tree-block-node');\n    });\n  });\n\n  describe('flattener', () => {\n    let flattener: NzTreeFlattener<TreeNode, FlatNode>;\n    const transformer = (node: TreeNode, level: number): FlatNode => ({\n      expandable: !!node.children && node.children.length > 0,\n      name: node.name,\n      level,\n      disabled: !!node.disabled\n    });\n\n    it('should flattenNodes method transform nested nodes to flatten nodes', () => {\n      flattener = new NzTreeFlattener(\n        transformer,\n        node => node.level,\n        node => node.expandable,\n        node => node.children\n      );\n      expect(flattener.flattenNodes(TREE_DATA)).toEqual(flattenNodes);\n    });\n\n    it('should support getChildren by Observable', () => {\n      flattener = new NzTreeFlattener(\n        transformer,\n        node => node.level,\n        node => node.expandable,\n        node => of(node.children!)\n      );\n      expect(flattener.flattenNodes(TREE_DATA)).toEqual(flattenNodes);\n    });\n  });\n\n  describe('flat data source', () => {\n    let fixture: ComponentFixture<NzTestTreeViewBasicWithLevelAccessorComponent>;\n    let testComponent: NzTestTreeViewBasicWithLevelAccessorComponent;\n\n    beforeEach(async () => {\n      fixture = TestBed.createComponent(NzTestTreeViewBasicWithLevelAccessorComponent);\n      testComponent = fixture.componentInstance;\n      await fixture.whenStable();\n    });\n\n    it('should dataSource getData return origin nested data', () => {\n      const data = testComponent.dataSource.getData();\n      expect(data).toBe(TREE_DATA);\n    });\n\n    it('should dataSource connect emit the same data whatever tree expansion model changed or data changed', async () => {\n      let shownNodes: FlatNode[] = [];\n      const { dataSource } = testComponent;\n      const dataNodes = dataSource.getFlattenData();\n      dataSource\n        .connect(testComponent.tree)\n        .pipe()\n        .subscribe((value: FlatNode[]) => {\n          shownNodes = value;\n        });\n      // expand or collapse\n      testComponent.tree.expand(dataNodes[0]);\n      await fixture.whenStable();\n      expect(shownNodes).toEqual(dataNodes);\n      const firstNodeToggle = fixture.debugElement.query(By.css('nz-tree-node-toggle'));\n      firstNodeToggle.nativeElement.click();\n      await fixture.whenStable();\n      expect(shownNodes).toEqual(dataNodes);\n      // set new data\n      const newTreeData = cloneDeep(TREE_DATA).slice(0, 1);\n      testComponent.setData(newTreeData);\n      expect(testComponent.tree.dataNodes).toEqual(flattenNodes.slice(0, -2));\n      await fixture.whenStable();\n      expect(shownNodes.length).toBe(6);\n    });\n  });\n\n  describe('padding', () => {\n    let fixture: ComponentFixture<NzTestTreeViewBasicWithLevelAccessorComponent>;\n    let testComponent: NzTestTreeViewBasicWithLevelAccessorComponent;\n    const defaultIndent = 24;\n\n    beforeEach(async () => {\n      fixture = TestBed.createComponent(NzTestTreeViewBasicWithLevelAccessorComponent);\n      testComponent = fixture.componentInstance;\n      await fixture.whenStable();\n      // expand all node\n      const { tree } = testComponent;\n      tree.expandAll();\n      await fixture.whenStable();\n    });\n\n    it('should nzTreeNodePadding without value work', () => {\n      const nodes = fixture.debugElement.queryAll(By.css('nz-tree-node:not([builtin])'));\n      expect(nodes.length).toBe(8);\n      nodes.forEach(node => {\n        expect(window.getComputedStyle(node.nativeElement).paddingLeft).toBe(\n          `${(node.componentInstance as NzTreeNodeComponent<FlatNode>).data.level * defaultIndent}px`\n        );\n      });\n    });\n\n    it('should nzTreeNodePadding with value work', async () => {\n      const nodes = fixture.debugElement.queryAll(By.directive(NzTreeNodePaddingDirective));\n      expect(nodes.length).toBe(8);\n      const [parent_1, ...otherNodes] = nodes;\n      const parent_1_paddingDir = parent_1.injector.get(NzTreeNodePaddingDirective);\n      parent_1_paddingDir.level = 1;\n      await fixture.whenStable();\n      // 1 * defaultIndent = 24\n      expect(window.getComputedStyle(parent_1.nativeElement).paddingLeft).toBe('24px');\n      otherNodes.forEach(node => {\n        expect(window.getComputedStyle(node.nativeElement).paddingLeft).toBe(\n          `${(node.componentInstance as NzTreeNodeComponent<FlatNode>).data.level * defaultIndent}px`\n        );\n      });\n    });\n\n    it('should nzTreeNodePaddingIndent work', async () => {\n      const indent = 50;\n      const nodes = fixture.debugElement.queryAll(By.directive(NzTreeNodePaddingDirective));\n      expect(nodes.length).toBe(8);\n      nodes.forEach(node => {\n        const node_paddingDir = node.injector.get(NzTreeNodePaddingDirective);\n        node_paddingDir.indent = indent;\n      });\n      await fixture.whenStable();\n      nodes.forEach(node => {\n        expect(window.getComputedStyle(node.nativeElement).paddingLeft).toBe(\n          `${(node.componentInstance as NzTreeNodeComponent<FlatNode>).data.level * indent}px`\n        );\n      });\n    });\n  });\n\n  describe('line indents', () => {\n    let fixture: ComponentFixture<NzTestTreeViewLineComponent>;\n    let testComponent: NzTestTreeViewLineComponent;\n\n    beforeEach(async () => {\n      fixture = TestBed.createComponent(NzTestTreeViewLineComponent);\n      testComponent = fixture.componentInstance;\n      await fixture.whenStable();\n      // expand all node\n      const { tree } = testComponent;\n      tree.expandAll();\n      // wait for auditTime(0, animationFrameScheduler)\n      await waitForNextAnimationFrame();\n      await fixture.whenStable();\n    });\n\n    it('should nzTreeNodeIndentLine work', () => {\n      const nodes = fixture.debugElement.queryAll(By.directive(NzTreeNodeIndentLineDirective));\n      expect(nodes.length).toBe(8);\n      const [parent_1, parent_1_1, leaf_1_1_1, leaf_1_1_2, parent_1_2, leaf_1_2_1, parent_2, leaf_2_1] = nodes.map(\n        node => node.componentInstance as NzTreeNodeComponent<FlatNode>\n      );\n      expect(parent_1.indents()).toEqual([]);\n      expect(parent_1_1.indents()).toEqual([true]);\n      expect(leaf_1_1_1.indents()).toEqual([true, true]);\n      expect(leaf_1_1_2.indents()).toEqual([true, true]);\n      expect(parent_1_2.indents()).toEqual([true]);\n      expect(leaf_1_2_1.indents()).toEqual([true, false]);\n      expect(parent_2.indents()).toEqual([]);\n      expect(leaf_2_1.indents()).toEqual([false]);\n    });\n  });\n});\n\ninterface FlatNode {\n  expandable: boolean;\n  name: string;\n  level: number;\n  disabled: boolean;\n}\n\ninterface TreeNode {\n  name: string;\n  children?: TreeNode[];\n  disabled?: boolean;\n}\n\nconst TREE_DATA: TreeNode[] = [\n  {\n    name: 'parent 1',\n    children: [\n      {\n        name: 'parent 1-1',\n        disabled: true,\n        children: [{ name: 'leaf 1-1-1' }, { name: 'leaf 1-1-2' }]\n      },\n      {\n        name: 'parent 1-2',\n        children: [{ name: 'leaf 1-2-1' }]\n      }\n    ]\n  },\n  {\n    name: 'parent 2',\n    children: [{ name: 'leaf 2-1' }]\n  }\n];\n\nconst flattenNodes = [\n  { expandable: true, name: 'parent 1', level: 0, disabled: false },\n  { expandable: true, name: 'parent 1-1', level: 1, disabled: true },\n  { expandable: false, name: 'leaf 1-1-1', level: 2, disabled: false },\n  { expandable: false, name: 'leaf 1-1-2', level: 2, disabled: false },\n  { expandable: true, name: 'parent 1-2', level: 1, disabled: false },\n  { expandable: false, name: 'leaf 1-2-1', level: 2, disabled: false },\n  { expandable: true, name: 'parent 2', level: 0, disabled: false },\n  { expandable: false, name: 'leaf 2-1', level: 1, disabled: false }\n];\n\n@Component({\n  imports: [NzIconModule, NzTreeViewModule],\n  template: `\n    <nz-tree-view\n      [nzDataSource]=\"dataSource\"\n      [nzLevelAccessor]=\"levelAccessor\"\n      [nzDirectoryTree]=\"directoryTree\"\n      [nzBlockNode]=\"blockNode\"\n    >\n      <nz-tree-node *nzTreeNodeDef=\"let node\" nzTreeNodePadding [nzExpandable]=\"false\">\n        <nz-tree-node-option\n          [nzDisabled]=\"node.disabled\"\n          [nzSelected]=\"selectListSelection.isSelected(node)\"\n          (nzClick)=\"selectListSelection.toggle(node)\"\n        >\n          {{ node.name }}\n        </nz-tree-node-option>\n      </nz-tree-node>\n\n      <nz-tree-node *nzTreeNodeDef=\"let node; when: hasChild\" nzTreeNodePadding [nzExpandable]=\"true\">\n        <nz-tree-node-toggle>\n          <nz-icon nzType=\"caret-down\" nzTreeNodeToggleRotateIcon />\n        </nz-tree-node-toggle>\n        <nz-tree-node-option\n          [nzDisabled]=\"node.disabled\"\n          [nzSelected]=\"selectListSelection.isSelected(node)\"\n          (nzClick)=\"selectListSelection.toggle(node)\"\n        >\n          {{ node.name }}\n        </nz-tree-node-option>\n      </nz-tree-node>\n    </nz-tree-view>\n  `\n})\nexport class NzTestTreeViewBasicWithLevelAccessorComponent implements OnInit {\n  @ViewChild(NzTreeViewComponent, { static: true }) tree!: NzTreeViewComponent<FlatNode>;\n  readonly levelAccessor = (dataNode: FlatNode): number => dataNode.level;\n  readonly hasChild = (_: number, node: FlatNode): boolean => node.expandable;\n  private transformer = (node: TreeNode, level: number): FlatNode => ({\n    expandable: !!node.children && node.children.length > 0,\n    name: node.name,\n    level,\n    disabled: !!node.disabled\n  });\n  private treeFlattener = new NzTreeFlattener(\n    this.transformer,\n    node => node.level,\n    node => node.expandable,\n    node => node.children\n  );\n  selectListSelection = new SelectionModel<FlatNode>(true);\n  dataSource!: NzTreeViewFlatDataSource<TreeNode, FlatNode>;\n  directoryTree: boolean = false;\n  blockNode: boolean = false;\n\n  ngOnInit(): void {\n    this.dataSource = new NzTreeViewFlatDataSource(this.tree, this.treeFlattener, TREE_DATA);\n  }\n\n  setData(data: TreeNode[]): void {\n    this.dataSource.setData(data);\n  }\n}\n\n@Component({\n  imports: [NzIconModule, NzTreeViewModule],\n  template: `\n    <nz-tree-view [nzDataSource]=\"dataSource\" [nzLevelAccessor]=\"levelAccessor\">\n      <nz-tree-node *nzTreeNodeDef=\"let node\" nzTreeNodeIndentLine [nzExpandable]=\"false\">\n        <nz-tree-node-option>\n          {{ node.name }}\n        </nz-tree-node-option>\n      </nz-tree-node>\n\n      <nz-tree-node *nzTreeNodeDef=\"let node; when: hasChild\" nzTreeNodeIndentLine [nzExpandable]=\"true\">\n        <nz-tree-node-toggle>\n          <nz-icon nzType=\"caret-down\" nzTreeNodeToggleRotateIcon />\n        </nz-tree-node-toggle>\n        <nz-tree-node-option>\n          {{ node.name }}\n        </nz-tree-node-option>\n      </nz-tree-node>\n    </nz-tree-view>\n  `\n})\nexport class NzTestTreeViewLineComponent implements OnInit {\n  @ViewChild(NzTreeViewComponent, { static: true }) tree!: NzTreeViewComponent<FlatNode>;\n  levelAccessor = (dataNode: FlatNode): number => dataNode.level;\n  hasChild = (_: number, node: FlatNode): boolean => node.expandable;\n  transformer = (node: TreeNode, level: number): FlatNode => ({\n    expandable: !!node.children && node.children.length > 0,\n    name: node.name,\n    level,\n    disabled: !!node.disabled\n  });\n  treeFlattener = new NzTreeFlattener(\n    this.transformer,\n    node => node.level,\n    node => node.expandable,\n    node => node.children\n  );\n  dataSource!: NzTreeViewFlatDataSource<TreeNode, FlatNode>;\n\n  ngOnInit(): void {\n    this.dataSource = new NzTreeViewFlatDataSource(this.tree, this.treeFlattener, TREE_DATA);\n  }\n}\n"
  },
  {
    "path": "components/tree-view/tree-view.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzTreeNodeCheckboxComponent } from './checkbox';\nimport { NzTreeNodeIndentLineDirective, NzTreeNodeIndentsComponent } from './indent';\nimport { NzTreeNodeComponent, NzTreeNodeDefDirective, NzTreeVirtualScrollNodeOutletDirective } from './node';\nimport { NzTreeNodeOptionComponent } from './option';\nimport { NzTreeNodeOutletDirective } from './outlet';\nimport { NzTreeNodePaddingDirective } from './padding';\nimport {\n  NzTreeNodeNoopToggleDirective,\n  NzTreeNodeToggleActiveIconDirective,\n  NzTreeNodeToggleDirective,\n  NzTreeNodeToggleRotateIconDirective\n} from './toggle';\nimport { NzTreeView } from './tree';\nimport { NzTreeViewComponent } from './tree-view';\nimport { NzTreeVirtualScrollViewComponent } from './tree-virtual-scroll-view';\n\nconst treeWithControlComponents = [\n  NzTreeView,\n  NzTreeNodeOutletDirective,\n  NzTreeViewComponent,\n  NzTreeNodeDefDirective,\n  NzTreeNodeComponent,\n  NzTreeNodeToggleDirective,\n  NzTreeNodePaddingDirective,\n  NzTreeNodeToggleRotateIconDirective,\n  NzTreeNodeToggleActiveIconDirective,\n  NzTreeNodeOptionComponent,\n  NzTreeNodeNoopToggleDirective,\n  NzTreeNodeCheckboxComponent,\n  NzTreeNodeIndentsComponent,\n  NzTreeVirtualScrollViewComponent,\n  NzTreeVirtualScrollNodeOutletDirective,\n  NzTreeNodeIndentLineDirective\n];\n\n@NgModule({\n  imports: [treeWithControlComponents],\n  exports: [treeWithControlComponents]\n})\nexport class NzTreeViewModule {}\n"
  },
  {
    "path": "components/tree-view/tree-view.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { CdkTree } from '@angular/cdk/tree';\nimport { ChangeDetectionStrategy, Component, forwardRef, ViewChild, ViewEncapsulation } from '@angular/core';\n\nimport { NzAnimationTreeCollapseService } from 'ng-zorro-antd/core/animation';\n\nimport { NzTreeNodeOutletDirective } from './outlet';\nimport { NzTreeView } from './tree';\n\n@Component({\n  selector: 'nz-tree-view',\n  exportAs: 'nzTreeView',\n  imports: [NzTreeNodeOutletDirective],\n  template: `\n    <div class=\"ant-tree-list-holder\">\n      <div class=\"ant-tree-list-holder-inner\">\n        <ng-container nzTreeNodeOutlet />\n      </div>\n    </div>\n  `,\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  providers: [\n    NzAnimationTreeCollapseService,\n    { provide: CdkTree, useExisting: forwardRef(() => NzTreeViewComponent) },\n    { provide: NzTreeView, useExisting: forwardRef(() => NzTreeViewComponent) }\n  ],\n  host: {\n    class: 'ant-tree',\n    '[class.ant-tree-block-node]': 'nzDirectoryTree || nzBlockNode',\n    '[class.ant-tree-directory]': 'nzDirectoryTree',\n    '[class.ant-tree-rtl]': `dir() === 'rtl'`\n  }\n})\nexport class NzTreeViewComponent<T> extends NzTreeView<T> {\n  @ViewChild(NzTreeNodeOutletDirective, { static: true }) nodeOutlet!: NzTreeNodeOutletDirective;\n}\n"
  },
  {
    "path": "components/tree-view/tree-virtual-scroll-view-based-children-accessor.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';\nimport { CdkTreeNodeOutletContext } from '@angular/cdk/tree';\nimport { Component, OnInit, TrackByFunction, ViewChild } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { dispatchFakeEvent } from 'ng-zorro-antd/core/testing';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzTreeViewNestedDataSource } from './nested-data-source';\nimport { NzTreeNodeComponent } from './node';\nimport { NzTreeNodePaddingDirective } from './padding';\nimport { waitForNextAnimationFrame } from './tree-view-based-children-accessor.spec';\nimport { NzTreeViewModule } from './tree-view.module';\nimport { NzTreeVirtualScrollViewComponent } from './tree-virtual-scroll-view';\n\n/**\n * Finish initializing the virtual scroll component at the beginning of a test.\n * @param fixture Test Component include NzTreeVirtualScrollViewComponent\n */\nexport async function finishInit(fixture: ComponentFixture<NzSafeAny>): Promise<void> {\n  // set the height of the viewport to 180px, the height of node to 30px.\n  fixture.debugElement.nativeElement\n    .querySelector('.cdk-virtual-scroll-viewport')!\n    .setAttribute('style', 'height: 180px; width: 200px;');\n  fixture.debugElement.queryAll(By.directive(NzTreeNodeComponent))!.map(node => {\n    node.nativeElement.setAttribute('style', 'width: 100%; height: 30px;');\n  });\n  // render the viewport.\n  await fixture.whenStable();\n\n  // Flush the initial fake scroll event.\n  await waitForNextAnimationFrame(); // flush animation frame\n  await fixture.whenStable();\n}\n\n/**\n * Trigger a scroll event on the viewport (optionally setting a new scroll offset).\n * @param viewport virtual scroll viewport\n * @param offset scroll distance\n */\nexport async function triggerScroll(viewport: CdkVirtualScrollViewport, offset?: number): Promise<void> {\n  if (offset !== undefined) {\n    viewport.scrollToOffset(offset);\n  }\n  dispatchFakeEvent(viewport.scrollable!.getElementRef().nativeElement, 'scroll');\n  await waitForNextAnimationFrame();\n}\n\ndescribe('virtual scroll based nzChildrenAccessor', () => {\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideNoopAnimations()]\n    });\n  });\n\n  describe('basic', () => {\n    let fixture: ComponentFixture<NzTestTreeViewVirtualScrollWithChildrenAccessorComponent>;\n    let testComponent: NzTestTreeViewVirtualScrollWithChildrenAccessorComponent;\n    let tree: NzTreeVirtualScrollViewComponent<TreeNode>;\n    let viewport: CdkVirtualScrollViewport;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTreeViewVirtualScrollWithChildrenAccessorComponent);\n      testComponent = fixture.componentInstance;\n      tree = testComponent.tree;\n      viewport = tree.virtualScrollViewport;\n    });\n\n    it('should the virtual viewport initialize correctly', async () => {\n      await finishInit(fixture);\n      expect(viewport.getDataLength()).toBe(100);\n      expect(viewport.getDataLength()).toBe(tree.nodes.length);\n      // viewport size = 180\n      expect(viewport.getViewportSize()).toBe(180);\n      // itemSize = 30, nums of initial nodes = 100\n      expect(viewport._totalContentHeight()).toBe(`${testComponent.itemSize * 100}px`);\n      // maxBufferPx / 30 + 180 / itemSize = 4 + 6 = 10\n      expect(fixture.debugElement.queryAll(By.css('nz-tree-node')).length).toBe(10);\n      expect(viewport.getRenderedRange()).toEqual({\n        start: 0,\n        end: 10\n      });\n      expect(viewport.getOffsetToRenderedContentStart()).toBe(0);\n      expect(fixture.debugElement.query(By.css('nz-tree-node')).componentInstance.data.name).toBe('0-0');\n    });\n\n    it('should tree view inits data correctly', async () => {\n      await finishInit(fixture);\n      expect(tree.dataNodes.length).toBe(100);\n      expect(tree.nodes.length).toBe(100);\n      tree.nodes.forEach((node, index) => {\n        const nodeData = {\n          name: `0-${index}`,\n          desc: 'parent',\n          children: tree.dataNodes[index].children\n        };\n        expect(node).toEqual({\n          data: nodeData,\n          context: new CdkTreeNodeOutletContext<TreeNode>(nodeData),\n          nodeDef: tree._getNodeDef(nodeData, 0)\n        });\n      });\n    });\n\n    it('should render correct nodes when scroll', async () => {\n      await finishInit(fixture);\n      await triggerScroll(viewport, testComponent.itemSize * 10);\n      await fixture.whenStable();\n      // start: 10 - minBufferPx / 30 = 8, end: 10 + 180 / 30 + maxBufferPx / 30 = 20\n      expect(viewport.getRenderedRange()).toEqual({\n        start: 8,\n        end: 20\n      });\n      expect(viewport.getOffsetToRenderedContentStart()).toBe(testComponent.itemSize * 10 - testComponent.minBufferPx);\n      expect(fixture.debugElement.query(By.css('nz-tree-node')).componentInstance.data.name).toBe('0-8');\n      await triggerScroll(viewport, testComponent.itemSize * 25);\n      await fixture.whenStable();\n      expect(viewport.getRenderedRange()).toEqual({\n        start: 23,\n        end: 35\n      });\n      expect(viewport.getOffsetToRenderedContentStart()).toBe(testComponent.itemSize * 25 - testComponent.minBufferPx);\n      expect(fixture.debugElement.query(By.css('nz-tree-node')).componentInstance.data.name).toBe('0-23');\n    });\n\n    it('should expand nodes when toggle the collapsed tree node', async () => {\n      await finishInit(fixture);\n      expect(tree.nodes.length).toBe(100);\n      expect(viewport.getDataLength()).toBe(100);\n      const nodeToggle = fixture.debugElement.query(By.css('nz-tree-node-toggle'));\n      nodeToggle.nativeElement.click();\n      await fixture.whenStable();\n      expect(tree.nodes.length).toBe(200);\n      expect(viewport.getDataLength()).toBe(200);\n    });\n\n    it('should collapse nodes when toggle the expanded tree node', async () => {\n      await finishInit(fixture);\n      const firstNode = testComponent.tree.dataNodes[0];\n      testComponent.tree.expand(firstNode);\n      await fixture.whenStable();\n      expect(tree.nodes.length).toBe(200);\n      expect(viewport.getDataLength()).toBe(200);\n      let nodeToggle = fixture.debugElement.query(By.css('nz-tree-node-toggle'));\n      nodeToggle.nativeElement.click();\n      await fixture.whenStable();\n      nodeToggle = fixture.debugElement.query(By.css('nz-tree-node-toggle'));\n      expect(nodeToggle.nativeElement.classList).toContain('ant-tree-switcher_close');\n      expect(tree.nodes.length).toBe(100);\n      expect(viewport.getDataLength()).toBe(100);\n    });\n\n    it('should nzItemSize work', async () => {\n      testComponent.itemSize *= 2; // 60\n      await finishInit(fixture);\n      expect(viewport.getRenderedRange()).toEqual({\n        start: 0,\n        // 180 / 60 + maxBufferPx / 60 = 3 + 2 = 5\n        end: 5\n      });\n      await triggerScroll(viewport, testComponent.itemSize * 5);\n      await fixture.whenStable();\n      expect(viewport.getRenderedRange()).toEqual({\n        // 5 - minBufferPx / 60 = 5 - 1 = 4\n        start: 4,\n        // 5 + 180 / 60 + maxBufferPx / 60 = 5 + 3 + 2 = 10\n        end: 10\n      });\n    });\n\n    it('should nzMinBufferPx and nzMaxBufferPx work', async () => {\n      testComponent.minBufferPx = testComponent.itemSize; // 30\n      testComponent.maxBufferPx = testComponent.itemSize; // 30\n      await finishInit(fixture);\n      expect(viewport.getRenderedRange()).toEqual({\n        start: 0,\n        // 180 / 30 + maxBufferPx / 30 = 6 + 1 = 7\n        end: 7\n      });\n      await triggerScroll(viewport, testComponent.itemSize * 5);\n      await fixture.whenStable();\n      expect(viewport.getRenderedRange()).toEqual({\n        // 5 - minBufferPx / itemSize = 5 - 1 = 4\n        start: 4,\n        // 5 + 180 / 30 + maxBufferPx / 30 = 5 + 6 + 1 = 12\n        end: 12\n      });\n    });\n\n    it('should nzDirectoryTree work', async () => {\n      await finishInit(fixture);\n      const treeView = fixture.debugElement.query(By.css('nz-tree-virtual-scroll-view'));\n      expect(treeView.nativeElement.classList).not.toContain('ant-tree-directory');\n      testComponent.directoryTree = true;\n      fixture.changeDetectorRef.markForCheck();\n      await fixture.whenStable();\n      expect(treeView.nativeElement.classList).toContain('ant-tree-directory');\n      expect(treeView.nativeElement.classList).toContain('ant-tree-block-node');\n    });\n\n    it('should nzBlockNode work', async () => {\n      await finishInit(fixture);\n      const treeView = fixture.debugElement.query(By.css('nz-tree-virtual-scroll-view'));\n      expect(treeView.nativeElement.classList).not.toContain('ant-tree-block-node');\n      testComponent.blockNode = true;\n      fixture.changeDetectorRef.markForCheck();\n      await fixture.whenStable();\n      expect(treeView.nativeElement.classList).toContain('ant-tree-block-node');\n    });\n\n    it('should trackBy work', async () => {\n      const data = dig('v1-0');\n      await finishInit(fixture);\n      expect(fixture.debugElement.query(By.css('nz-tree-node')).componentInstance.data.name).toBe('0-0');\n      // change name format from '0-x' to 'v1-0-x'\n      testComponent.dataSource.setData(data);\n      await finishInit(fixture);\n      // data and view both changed\n      expect(tree.dataNodes[0].name).toBe('v1-0-0');\n      expect(fixture.debugElement.query(By.css('nz-tree-node')).componentInstance.data.name).toBe('v1-0-0');\n\n      // set trackBy to null, default use node self instead\n      testComponent.trackBy = null!;\n      // change name format from 'v1-0-x' to 'v2-0-x'\n      testComponent.dataSource.setData(dig('v2-0'));\n      await finishInit(fixture);\n      // data and view both changed\n      expect(tree.dataNodes[0].name).toBe('v2-0-0');\n      expect(fixture.debugElement.query(By.css('nz-tree-node')).componentInstance.data.name).toBe('v2-0-0');\n\n      // rerender new data depends on whether the index is the same (always same)\n      testComponent.trackBy = (index: number, _node: TreeNode) => index;\n      // change name format from 'v2-0-x' to 'v3-0-x'\n      testComponent.dataSource.setData(dig('v3-0'));\n      await finishInit(fixture);\n      // data has changed but view has not changed\n      expect(tree.dataNodes[0].name).toBe('v3-0-0');\n      expect(fixture.debugElement.query(By.css('nz-tree-node')).componentInstance.data.name).toBe('v2-0-0');\n    });\n  });\n\n  describe('padding', () => {\n    let fixture: ComponentFixture<NzTestTreeViewVirtualScrollWithChildrenAccessorComponent>;\n    let testComponent: NzTestTreeViewVirtualScrollWithChildrenAccessorComponent;\n    const defaultIndent = 24;\n\n    beforeEach(async () => {\n      fixture = TestBed.createComponent(NzTestTreeViewVirtualScrollWithChildrenAccessorComponent);\n      testComponent = fixture.componentInstance;\n      await finishInit(fixture);\n      const { tree } = testComponent;\n      tree.expand(tree.dataNodes[0]);\n      await fixture.whenStable();\n    });\n\n    it('should nzTreeNodePadding without value work', () => {\n      const nodes = fixture.debugElement.queryAll(By.css('nz-tree-node:not([builtin])'));\n      expect(nodes.length).toBe(10);\n      const [firstNode, ...otherNodes] = nodes;\n      expect(window.getComputedStyle(firstNode.nativeElement).paddingLeft).toBe('0px');\n      otherNodes.forEach(node => {\n        expect(window.getComputedStyle(node.nativeElement).paddingLeft).toBe(`${defaultIndent}px`); // level = 1, 24 * 1\n      });\n    });\n\n    it('should nzTreeNodePadding with value work', async () => {\n      const nodes = fixture.debugElement.queryAll(By.directive(NzTreeNodePaddingDirective));\n      expect(nodes.length).toBe(10);\n      const firstNode = nodes[0];\n      expect(window.getComputedStyle(firstNode.nativeElement).paddingLeft).toBe('0px');\n      const firstNode_paddingDir = firstNode.injector.get(NzTreeNodePaddingDirective);\n      firstNode_paddingDir.level = 1;\n      await fixture.whenStable();\n      // 1 * defaultIndent = 24\n      nodes.forEach(node => {\n        expect(window.getComputedStyle(node.nativeElement).paddingLeft).toBe(`${defaultIndent}px`);\n      });\n    });\n\n    it('should nzTreeNodePaddingIndent work', async () => {\n      const newIndent = 50;\n      const nodes = fixture.debugElement.queryAll(By.directive(NzTreeNodePaddingDirective));\n      nodes.forEach(node => {\n        const node_paddingDir = node.injector.get(NzTreeNodePaddingDirective);\n        node_paddingDir.indent = newIndent;\n      });\n      await fixture.whenStable();\n      const [firstNode, ...otherNodes] = nodes;\n      expect(window.getComputedStyle(firstNode.nativeElement).paddingLeft).toBe('0px');\n      otherNodes.forEach(node => {\n        expect(window.getComputedStyle(node.nativeElement).paddingLeft).toBe(`${newIndent}px`);\n      });\n    });\n  });\n});\n\ninterface TreeNode {\n  name: string;\n  desc: string;\n  children?: TreeNode[];\n}\n\nfunction dig(path: string = '0', level: number = 1): TreeNode[] {\n  const list: TreeNode[] = [];\n  for (let i = 0; i < 100; i += 1) {\n    const name = `${path}-${i}`;\n    const treeNode: TreeNode = {\n      name,\n      desc: level === 0 ? `leaf` : 'parent'\n    };\n\n    if (level > 0) {\n      treeNode.children = dig(name, level - 1);\n    }\n\n    list.push(treeNode);\n  }\n  return list;\n}\n\nconst TREE_DATA: TreeNode[] = dig();\n\n@Component({\n  imports: [NzIconModule, NzTreeViewModule],\n  template: `\n    <nz-tree-virtual-scroll-view\n      [nzDataSource]=\"dataSource\"\n      [nzChildrenAccessor]=\"childrenAccessor\"\n      [nzItemSize]=\"itemSize\"\n      [nzMinBufferPx]=\"minBufferPx\"\n      [nzMaxBufferPx]=\"maxBufferPx\"\n      [nzDirectoryTree]=\"directoryTree\"\n      [nzBlockNode]=\"blockNode\"\n      [nzTrackBy]=\"trackBy\"\n    >\n      <nz-tree-node *nzTreeNodeDef=\"let node\" nzTreeNodePadding [nzExpandable]=\"false\">\n        <nz-tree-node-toggle nzTreeNodeNoopToggle />\n        {{ node.name }}\n      </nz-tree-node>\n\n      <nz-tree-node *nzTreeNodeDef=\"let node; when: hasChild\" nzTreeNodePadding [nzExpandable]=\"true\">\n        <nz-tree-node-toggle>\n          <nz-icon nzType=\"caret-down\" nzTreeNodeToggleRotateIcon />\n        </nz-tree-node-toggle>\n        {{ node.name }}\n      </nz-tree-node>\n    </nz-tree-virtual-scroll-view>\n  `\n})\nexport class NzTestTreeViewVirtualScrollWithChildrenAccessorComponent implements OnInit {\n  @ViewChild(NzTreeVirtualScrollViewComponent, { static: true }) tree!: NzTreeVirtualScrollViewComponent<TreeNode>;\n  readonly childrenAccessor = (dataNode: TreeNode): TreeNode[] => dataNode.children ?? [];\n  readonly hasChild = (_: number, node: TreeNode): boolean => !!node.children?.length;\n  dataSource!: NzTreeViewNestedDataSource<TreeNode>;\n  directoryTree: boolean = false;\n  blockNode: boolean = false;\n  itemSize = 30;\n  minBufferPx = 30 * 2;\n  maxBufferPx = 30 * 4;\n  trackBy: TrackByFunction<TreeNode> = (_index: number, value: TreeNode): NzSafeAny => value;\n\n  ngOnInit(): void {\n    this.dataSource = new NzTreeViewNestedDataSource(this.tree, TREE_DATA);\n  }\n}\n"
  },
  {
    "path": "components/tree-view/tree-virtual-scroll-view-based-level-accessor.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';\nimport { CdkTreeNodeOutletContext } from '@angular/cdk/tree';\nimport { Component, OnInit, TrackByFunction, ViewChild } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzTreeViewFlatDataSource } from './flat-data-source';\nimport { NzTreeFlattener } from './flattener';\nimport { NzTreeNodePaddingDirective } from './padding';\nimport { NzTreeViewModule } from './tree-view.module';\nimport { NzTreeVirtualScrollViewComponent } from './tree-virtual-scroll-view';\nimport { finishInit, triggerScroll } from './tree-virtual-scroll-view-based-children-accessor.spec';\n\ndescribe('virtual scroll based nzLevelAccessor', () => {\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideNoopAnimations()]\n    });\n  });\n\n  describe('basic', () => {\n    let fixture: ComponentFixture<NzTestTreeViewVirtualScrollWithLevelAccessorComponent>;\n    let testComponent: NzTestTreeViewVirtualScrollWithLevelAccessorComponent;\n    let tree: NzTreeVirtualScrollViewComponent<FlatNode>;\n    let viewport: CdkVirtualScrollViewport;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTreeViewVirtualScrollWithLevelAccessorComponent);\n      testComponent = fixture.componentInstance;\n      tree = testComponent.tree;\n      viewport = tree.virtualScrollViewport;\n    });\n\n    it('should the virtual viewport initialize correctly', async () => {\n      await finishInit(fixture);\n      expect(viewport.getDataLength()).toBe(100);\n      expect(viewport.getDataLength()).toBe(tree.nodes.length);\n      // viewport size = 180\n      expect(viewport.getViewportSize()).toBe(180);\n      // itemSize = 30, nums of initial nodes = 100\n      expect(viewport._totalContentHeight()).toBe(`${testComponent.itemSize * 100}px`);\n      // maxBufferPx / 30 + 180 / itemSize = 4 + 6 = 10\n      expect(fixture.debugElement.queryAll(By.css('nz-tree-node')).length).toBe(10);\n      expect(viewport.getRenderedRange()).toEqual({\n        start: 0,\n        end: 10\n      });\n      expect(viewport.getOffsetToRenderedContentStart()).toBe(0);\n      expect(fixture.debugElement.query(By.css('nz-tree-node')).componentInstance.data.name).toBe('0-0');\n    });\n\n    it('should tree view inits data correctly', async () => {\n      await finishInit(fixture);\n      expect(tree.dataNodes.length).toBe(100 ** 2 + 100 ** 1);\n      expect(tree.nodes.length).toBe(100);\n      tree.nodes.forEach((node, index) => {\n        const nodeData = {\n          expandable: true,\n          level: 0,\n          name: `0-${index}`\n        };\n        expect(node).toEqual({\n          data: nodeData,\n          context: new CdkTreeNodeOutletContext<FlatNode>(nodeData),\n          nodeDef: tree._getNodeDef(nodeData, 0)\n        });\n      });\n    });\n\n    it('should render correct nodes when scroll', async () => {\n      await finishInit(fixture);\n      await triggerScroll(viewport, testComponent.itemSize * 10);\n      await fixture.whenStable();\n      // start: 10 - minBufferPx / 30 = 8, end: 10 + 180 / 30 + maxBufferPx / 30 = 20\n      expect(viewport.getRenderedRange()).toEqual({\n        start: 8,\n        end: 20\n      });\n      expect(viewport.getOffsetToRenderedContentStart()).toBe(testComponent.itemSize * 10 - testComponent.minBufferPx);\n      expect(fixture.debugElement.query(By.css('nz-tree-node')).componentInstance.data.name).toBe('0-8');\n      await triggerScroll(viewport, testComponent.itemSize * 25);\n      await fixture.whenStable();\n      expect(viewport.getRenderedRange()).toEqual({\n        start: 23,\n        end: 35\n      });\n      expect(viewport.getOffsetToRenderedContentStart()).toBe(testComponent.itemSize * 25 - testComponent.minBufferPx);\n      expect(fixture.debugElement.query(By.css('nz-tree-node')).componentInstance.data.name).toBe('0-23');\n    });\n\n    it('should expand nodes when toggle the collapsed tree node', async () => {\n      await finishInit(fixture);\n      expect(tree.nodes.length).toBe(100);\n      expect(viewport.getDataLength()).toBe(100);\n      const nodeToggle = fixture.debugElement.query(By.css('nz-tree-node-toggle'));\n      nodeToggle.nativeElement.click();\n      await fixture.whenStable();\n      expect(tree.nodes.length).toBe(200);\n      expect(viewport.getDataLength()).toBe(200);\n    });\n\n    it('should collapse nodes when toggle the expanded tree node', async () => {\n      await finishInit(fixture);\n      const firstNode = testComponent.tree.dataNodes[0];\n      testComponent.tree.expand(firstNode);\n      await fixture.whenStable();\n      expect(tree.nodes.length).toBe(200);\n      expect(viewport.getDataLength()).toBe(200);\n      const nodeToggle = fixture.debugElement.query(By.css('nz-tree-node-toggle'));\n      nodeToggle.nativeElement.click();\n      await fixture.whenStable();\n      expect(nodeToggle.nativeElement.classList).toContain('ant-tree-switcher_close');\n      expect(tree.nodes.length).toBe(100);\n      expect(viewport.getDataLength()).toBe(100);\n    });\n\n    it('should nzItemSize work', async () => {\n      testComponent.itemSize *= 2; // 60\n      await finishInit(fixture);\n      expect(viewport.getRenderedRange()).toEqual({\n        start: 0,\n        // 180 / 60 + maxBufferPx / 60 = 3 + 2 = 5\n        end: 5\n      });\n      await triggerScroll(viewport, testComponent.itemSize * 5);\n      await fixture.whenStable();\n      expect(viewport.getRenderedRange()).toEqual({\n        // 5 - minBufferPx / 60 = 5 - 1 = 4\n        start: 4,\n        // 5 + 180 / 60 + maxBufferPx / 60 = 5 + 3 + 2 = 10\n        end: 10\n      });\n    });\n\n    it('should nzMinBufferPx and nzMaxBufferPx work', async () => {\n      testComponent.minBufferPx = testComponent.itemSize; // 30\n      testComponent.maxBufferPx = testComponent.itemSize; // 30\n      await finishInit(fixture);\n      expect(viewport.getRenderedRange()).toEqual({\n        start: 0,\n        // 180 / 30 + maxBufferPx / 30 = 6 + 1 = 7\n        end: 7\n      });\n      await triggerScroll(viewport, testComponent.itemSize * 5);\n      await fixture.whenStable();\n      expect(viewport.getRenderedRange()).toEqual({\n        // 5 - minBufferPx / itemSize = 5 - 1 = 4\n        start: 4,\n        // 5 + 180 / 30 + maxBufferPx / 30 = 5 + 6 + 1 = 12\n        end: 12\n      });\n    });\n\n    it('should nzDirectoryTree work', async () => {\n      await finishInit(fixture);\n      const treeView = fixture.debugElement.query(By.css('nz-tree-virtual-scroll-view'));\n      expect(treeView.nativeElement.classList).not.toContain('ant-tree-directory');\n      testComponent.directoryTree = true;\n      fixture.changeDetectorRef.markForCheck();\n      await fixture.whenStable();\n      expect(treeView.nativeElement.classList).toContain('ant-tree-directory');\n      expect(treeView.nativeElement.classList).toContain('ant-tree-block-node');\n    });\n\n    it('should nzBlockNode work', async () => {\n      await finishInit(fixture);\n      const treeView = fixture.debugElement.query(By.css('nz-tree-virtual-scroll-view'));\n      expect(treeView.nativeElement.classList).not.toContain('ant-tree-block-node');\n      testComponent.blockNode = true;\n      fixture.changeDetectorRef.markForCheck();\n      await fixture.whenStable();\n      expect(treeView.nativeElement.classList).toContain('ant-tree-block-node');\n    });\n\n    it('should trackBy work', async () => {\n      await finishInit(fixture);\n      expect(fixture.debugElement.query(By.css('nz-tree-node')).componentInstance.data.name).toBe('0-0');\n      // change name format from '0-x' to 'v1-0-x'\n      testComponent.dataSource.setData(dig('v1-0'));\n      await finishInit(fixture);\n      // data and view both changed\n      expect(tree.dataNodes[0].name).toBe('v1-0-0');\n      expect(fixture.debugElement.query(By.css('nz-tree-node')).componentInstance.data.name).toBe('v1-0-0');\n\n      // set trackBy to null, default use node self instead\n      testComponent.trackBy = null!;\n      // change name format from 'v1-0-x' to 'v2-0-x'\n      testComponent.dataSource.setData(dig('v2-0'));\n      await finishInit(fixture);\n      // data and view both changed\n      expect(tree.dataNodes[0].name).toBe('v2-0-0');\n      expect(fixture.debugElement.query(By.css('nz-tree-node')).componentInstance.data.name).toBe('v2-0-0');\n\n      // rerender new data depends on whether the index is the same (always same)\n      testComponent.trackBy = (index: number, _node: FlatNode) => index;\n      // change name format from 'v2-0-x' to 'v3-0-x'\n      testComponent.dataSource.setData(dig('v3-0'));\n      await finishInit(fixture);\n      // data has changed but view has not changed\n      expect(tree.dataNodes[0].name).toBe('v3-0-0');\n      expect(fixture.debugElement.query(By.css('nz-tree-node')).componentInstance.data.name).toBe('v2-0-0');\n    });\n  });\n\n  describe('padding', () => {\n    let fixture: ComponentFixture<NzTestTreeViewVirtualScrollWithLevelAccessorComponent>;\n    let testComponent: NzTestTreeViewVirtualScrollWithLevelAccessorComponent;\n    const defaultIndent = 24;\n\n    beforeEach(async () => {\n      fixture = TestBed.createComponent(NzTestTreeViewVirtualScrollWithLevelAccessorComponent);\n      testComponent = fixture.componentInstance;\n      await finishInit(fixture);\n      const { tree } = testComponent;\n      tree.expand(tree.dataNodes[0]);\n      await fixture.whenStable();\n    });\n\n    it('should nzTreeNodePadding without value work', () => {\n      const nodes = fixture.debugElement.queryAll(By.css('nz-tree-node:not([builtin])'));\n      expect(nodes.length).toBe(10);\n      const [firstNode, ...otherNodes] = nodes;\n      expect(window.getComputedStyle(firstNode.nativeElement).paddingLeft).toBe('0px');\n      otherNodes.forEach(node => {\n        expect(window.getComputedStyle(node.nativeElement).paddingLeft).toBe(`${defaultIndent}px`); // level = 1, 24 * 1\n      });\n    });\n\n    it('should nzTreeNodePadding with value work', async () => {\n      const nodes = fixture.debugElement.queryAll(By.directive(NzTreeNodePaddingDirective));\n      expect(nodes.length).toBe(10);\n      const firstNode = nodes[0];\n      expect(window.getComputedStyle(firstNode.nativeElement).paddingLeft).toBe('0px');\n      const firstNode_paddingDir = firstNode.injector.get(NzTreeNodePaddingDirective);\n      firstNode_paddingDir.level = 1;\n      await fixture.whenStable();\n      // 1 * defaultIndent = 24\n      nodes.forEach(node => {\n        expect(window.getComputedStyle(node.nativeElement).paddingLeft).toBe(`${defaultIndent}px`);\n      });\n    });\n\n    it('should nzTreeNodePaddingIndent work', async () => {\n      const newIndent = 50;\n      const nodes = fixture.debugElement.queryAll(By.directive(NzTreeNodePaddingDirective));\n      expect(nodes.length).toBe(10);\n      nodes.forEach(node => {\n        const node_paddingDir = node.injector.get(NzTreeNodePaddingDirective);\n        node_paddingDir.indent = newIndent;\n      });\n      await fixture.whenStable();\n      const [firstNode, ...otherNodes] = nodes;\n      expect(window.getComputedStyle(firstNode.nativeElement).paddingLeft).toBe('0px');\n      otherNodes.forEach(node => {\n        expect(window.getComputedStyle(node.nativeElement).paddingLeft).toBe(`${newIndent}px`);\n      });\n    });\n  });\n});\n\ninterface TreeNode {\n  name: string;\n  children?: TreeNode[];\n}\n\ninterface FlatNode {\n  expandable: boolean;\n  name: string;\n  level: number;\n}\n\nfunction dig(path: string = '0', level: number = 1): TreeNode[] {\n  const list: TreeNode[] = [];\n  for (let i = 0; i < 100; i += 1) {\n    const name = `${path}-${i}`;\n    const treeNode: TreeNode = {\n      name\n    };\n\n    if (level > 0) {\n      treeNode.children = dig(name, level - 1);\n    }\n\n    list.push(treeNode);\n  }\n  return list;\n}\n\nconst TREE_DATA: TreeNode[] = dig();\n\n@Component({\n  imports: [NzIconModule, NzTreeViewModule],\n  template: `\n    <nz-tree-virtual-scroll-view\n      [nzDataSource]=\"dataSource\"\n      [nzLevelAccessor]=\"levelAccessor\"\n      [nzItemSize]=\"itemSize\"\n      [nzMinBufferPx]=\"minBufferPx\"\n      [nzMaxBufferPx]=\"maxBufferPx\"\n      [nzDirectoryTree]=\"directoryTree\"\n      [nzBlockNode]=\"blockNode\"\n      [nzTrackBy]=\"trackBy\"\n    >\n      <nz-tree-node *nzTreeNodeDef=\"let node\" nzTreeNodePadding [nzExpandable]=\"false\">\n        <nz-tree-node-toggle nzTreeNodeNoopToggle />\n        {{ node.name }}\n      </nz-tree-node>\n\n      <nz-tree-node *nzTreeNodeDef=\"let node; when: hasChild\" nzTreeNodePadding [nzExpandable]=\"true\">\n        <nz-tree-node-toggle>\n          <nz-icon nzType=\"caret-down\" nzTreeNodeToggleRotateIcon />\n        </nz-tree-node-toggle>\n        {{ node.name }}\n      </nz-tree-node>\n    </nz-tree-virtual-scroll-view>\n  `\n})\nexport class NzTestTreeViewVirtualScrollWithLevelAccessorComponent implements OnInit {\n  @ViewChild(NzTreeVirtualScrollViewComponent, { static: true }) tree!: NzTreeVirtualScrollViewComponent<FlatNode>;\n  levelAccessor = (dataNode: FlatNode): number => dataNode.level;\n  hasChild = (_: number, node: FlatNode): boolean => node.expandable;\n  transformer = (node: TreeNode, level: number): FlatNode => ({\n    expandable: !!node.children && node.children.length > 0,\n    name: node.name,\n    level\n  });\n  directoryTree: boolean = false;\n  blockNode: boolean = false;\n  itemSize = 30;\n  minBufferPx = 30 * 2;\n  maxBufferPx = 30 * 4;\n  trackBy: TrackByFunction<FlatNode> = (_index: number, value: FlatNode): NzSafeAny => value;\n  treeFlattener = new NzTreeFlattener(\n    this.transformer,\n    node => node.level,\n    node => node.expandable,\n    node => node.children\n  );\n  dataSource!: NzTreeViewFlatDataSource<TreeNode, FlatNode>;\n\n  ngOnInit(): void {\n    this.dataSource = new NzTreeViewFlatDataSource(this.tree, this.treeFlattener, TREE_DATA);\n  }\n}\n"
  },
  {
    "path": "components/tree-view/tree-virtual-scroll-view.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { CdkFixedSizeVirtualScroll, CdkVirtualForOf, CdkVirtualScrollViewport } from '@angular/cdk/scrolling';\nimport { CdkTree, CdkTreeNodeOutletContext } from '@angular/cdk/tree';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  forwardRef,\n  inject,\n  Input,\n  OnChanges,\n  SimpleChanges,\n  TrackByFunction,\n  ViewChild,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { NzAnimationTreeCollapseService } from 'ng-zorro-antd/core/animation';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { NzTreeVirtualNodeData, NzTreeVirtualScrollNodeOutletDirective } from './node';\nimport { NzTreeNodeOutletDirective } from './outlet';\nimport { NzTreeView } from './tree';\n\nconst DEFAULT_SIZE = 28;\n\n@Component({\n  selector: 'nz-tree-virtual-scroll-view',\n  exportAs: 'nzTreeVirtualScrollView',\n  template: `\n    <div class=\"ant-tree-list\">\n      <cdk-virtual-scroll-viewport\n        class=\"ant-tree-list-holder\"\n        [itemSize]=\"nzItemSize\"\n        [minBufferPx]=\"nzMinBufferPx\"\n        [maxBufferPx]=\"nzMaxBufferPx\"\n      >\n        <ng-container *cdkVirtualFor=\"let item of nodes; let i = index; trackBy: innerTrackBy\">\n          <ng-template nzTreeVirtualScrollNodeOutlet [data]=\"item\" [compareBy]=\"compareBy(i)\" />\n        </ng-container>\n      </cdk-virtual-scroll-viewport>\n    </div>\n    <ng-container nzTreeNodeOutlet />\n  `,\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  providers: [\n    NzAnimationTreeCollapseService,\n    { provide: NzTreeView, useExisting: forwardRef(() => NzTreeVirtualScrollViewComponent) },\n    { provide: CdkTree, useExisting: forwardRef(() => NzTreeVirtualScrollViewComponent) }\n  ],\n  host: {\n    class: 'ant-tree',\n    '[class.ant-tree-block-node]': 'nzDirectoryTree || nzBlockNode',\n    '[class.ant-tree-directory]': 'nzDirectoryTree',\n    '[class.ant-tree-rtl]': `dir() === 'rtl'`\n  },\n  imports: [\n    CdkFixedSizeVirtualScroll,\n    CdkVirtualForOf,\n    CdkVirtualScrollViewport,\n    NzTreeNodeOutletDirective,\n    NzTreeVirtualScrollNodeOutletDirective\n  ]\n})\nexport class NzTreeVirtualScrollViewComponent<T> extends NzTreeView<T> implements OnChanges {\n  @ViewChild(NzTreeNodeOutletDirective, { static: true }) override readonly _nodeOutlet: NzTreeNodeOutletDirective =\n    undefined!;\n  @ViewChild(CdkVirtualScrollViewport, { static: true }) readonly virtualScrollViewport!: CdkVirtualScrollViewport;\n\n  @Input() nzItemSize = DEFAULT_SIZE;\n  @Input() nzMinBufferPx = DEFAULT_SIZE * 5;\n  @Input() nzMaxBufferPx = DEFAULT_SIZE * 10;\n\n  nodes: Array<NzTreeVirtualNodeData<T>> = [];\n\n  innerTrackBy: TrackByFunction<NzTreeVirtualNodeData<T>> = i => i;\n\n  constructor() {\n    super();\n    const treeCollapseService = inject(NzAnimationTreeCollapseService);\n    treeCollapseService.virtualScroll = true;\n  }\n\n  ngOnChanges({ trackBy }: SimpleChanges): void {\n    if (trackBy) {\n      if (typeof trackBy.currentValue === 'function') {\n        this.innerTrackBy = (index: number, n) => this.trackBy(index, n.data);\n      } else {\n        this.innerTrackBy = i => i;\n      }\n    }\n  }\n\n  compareBy(index: number): (value: T) => NzSafeAny {\n    return (value: T) => (this.trackBy ? this.trackBy(index, value) : value);\n  }\n\n  override renderNodeChanges(data: T[]): void {\n    /* https://github.com/angular/components/blob/21cc21ea3b280c3f82a19f5ec1b679eb1eee1358/src/cdk/tree/tree.ts#L1103\n     * If levelAccessor is used, renderNodes needs to be recalculated, because flattenData (i.e., dataNodes) is used as renderNodes by default in the @angular/components library\n     * If childrenAccessor is used, @angular/components library inner will calculate renderNodes.\n     */\n    const renderNodes = this.levelAccessor ? this.getRenderNodes(data) : [...data];\n    this.nodes = renderNodes.map((n, i) => this.createNode(n, i));\n    this.dataSourceChanged$.next();\n    this.cdr.markForCheck();\n  }\n\n  private createNode(nodeData: T, index: number): NzTreeVirtualNodeData<T> {\n    const node = this._getNodeDef(nodeData, index);\n    const context = new CdkTreeNodeOutletContext<T>(nodeData);\n    return {\n      data: nodeData,\n      context,\n      nodeDef: node\n    };\n  }\n}\n"
  },
  {
    "path": "components/tree-view/tree.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { DataSource } from '@angular/cdk/collections';\nimport { CdkTree } from '@angular/cdk/tree';\nimport {\n  ChangeDetectorRef,\n  Component,\n  Input,\n  IterableDiffer,\n  ViewContainerRef,\n  booleanAttribute,\n  inject,\n  DestroyRef,\n  TrackByFunction\n} from '@angular/core';\nimport { Observable, Subject } from 'rxjs';\n\nimport { NzNoAnimationDirective } from 'ng-zorro-antd/core/animation';\n\nimport { getDescendants } from './utils';\n\n@Component({\n  template: ''\n})\nexport class NzTreeView<T> extends CdkTree<T> {\n  /* eslint-disable @angular-eslint/no-input-rename */\n  @Input({ alias: 'nzLevelAccessor' }) override levelAccessor?: (dataNode: T) => number = undefined;\n  @Input({ alias: 'nzChildrenAccessor' }) override childrenAccessor?: (dataNode: T) => T[] = undefined;\n  @Input({ alias: 'nzDataSource' })\n  override get dataSource(): DataSource<T> | Observable<T[]> | T[] {\n    return super.dataSource;\n  }\n  override set dataSource(dataSource: DataSource<T> | Observable<T[]> | T[]) {\n    super.dataSource = dataSource;\n  }\n  @Input({ alias: 'nzTrackBy' }) override trackBy: TrackByFunction<T> = (_index, item: T) => item;\n  @Input({ transform: booleanAttribute }) nzDirectoryTree = false;\n  @Input({ transform: booleanAttribute }) nzBlockNode = false;\n\n  protected readonly noAnimation = inject(NzNoAnimationDirective, { host: true, optional: true });\n  protected readonly destroyRef = inject(DestroyRef);\n  protected readonly directionality = inject(Directionality);\n  protected readonly cdr = inject(ChangeDetectorRef);\n\n  protected readonly dir = inject(Directionality).valueSignal;\n  readonly dataSourceChanged$ = new Subject<void>();\n\n  dataNodes: T[] = [];\n\n  override renderNodeChanges(\n    data: T[],\n    dataDiffer?: IterableDiffer<T>,\n    viewContainer?: ViewContainerRef,\n    parentData?: T\n  ): void {\n    /* https://github.com/angular/components/blob/21cc21ea3b280c3f82a19f5ec1b679eb1eee1358/src/cdk/tree/tree.ts#L1103\n     * If levelAccessor is used, renderNodes needs to be recalculated, because flattenData (i.e., dataNodes) is used as renderNodes by default in the @angular/components library\n     * If childrenAccessor is used, @angular/cdk library inner will calculate renderNodes.\n     */\n    const renderNodes = this.levelAccessor ? this.getRenderNodes(data) : [...data];\n    super.renderNodeChanges(renderNodes, dataDiffer, viewContainer, parentData);\n    this.dataSourceChanged$.next();\n    this.cdr.markForCheck();\n  }\n\n  /**\n   * get render nodes (length <= flattenData.length)>\n   * @param nodes all flatten nodes\n   */\n  protected getRenderNodes(nodes: T[]): T[] {\n    const getLevel = this.levelAccessor!;\n    const results: T[] = [];\n    const currentExpand: boolean[] = [];\n    currentExpand[0] = true;\n\n    nodes.forEach(node => {\n      let expand = true;\n      for (let i = 0; i <= getLevel(node); i++) {\n        expand = expand && currentExpand[i];\n      }\n      if (expand) {\n        results.push(node);\n      }\n      if (getDescendants(nodes, node, getLevel)) {\n        currentExpand[getLevel(node) + 1] = this.isExpanded(node);\n      }\n    });\n    return results;\n  }\n}\n"
  },
  {
    "path": "components/tree-view/utils.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { cloneDeep } from 'lodash';\n\nimport {\n  getParent,\n  getDescendants,\n  getNextSibling,\n  getParentForNestedData,\n  getNextSiblingForNestedData,\n  getDescendantsForNestedData,\n  flattenNestedNodes\n} from './utils';\n\ninterface FlatNode {\n  name: string;\n  level: number;\n}\n\ninterface NestedNode {\n  name: string;\n  children?: NestedNode[];\n}\n\ndescribe('TreeView Utils', () => {\n  const flatNodes: FlatNode[] = [\n    { name: '1', level: 0 },\n    { name: '1-1', level: 1 },\n    { name: '1-2', level: 1 },\n    { name: '1-3', level: 1 },\n    { name: '1-3-1', level: 2 },\n    { name: '1-3-2', level: 2 },\n    { name: '2', level: 0 },\n    { name: '2-1', level: 1 }\n  ];\n\n  const nestedNodes: NestedNode[] = [\n    {\n      name: '1',\n      children: [{ name: '1-1' }, { name: '1-2' }, { name: '1-3', children: [{ name: '1-3-1' }, { name: '1-3-2' }] }]\n    },\n    { name: '2', children: [{ name: '2-1' }] }\n  ];\n\n  const getLevel = (node: FlatNode): number => node.level;\n  const getChildren = (node: NestedNode): NestedNode[] => node.children ?? [];\n\n  describe('getParent', () => {\n    it('should return the parent node', () => {\n      expect(getParent(flatNodes, flatNodes[1], getLevel)).toBe(flatNodes[0]);\n      expect(getParent(flatNodes, flatNodes[2], getLevel)).toBe(flatNodes[0]);\n      expect(getParent(flatNodes, flatNodes[3], getLevel)).toBe(flatNodes[0]);\n      expect(getParent(flatNodes, flatNodes[4], getLevel)).toBe(flatNodes[3]);\n      expect(getParent(flatNodes, flatNodes[5], getLevel)).toBe(flatNodes[3]);\n      expect(getParent(flatNodes, flatNodes[7], getLevel)).toBe(flatNodes[6]);\n    });\n\n    it('should return null if the node not in nodes', () => {\n      const equalNode = cloneDeep(flatNodes[1]);\n      expect(getParent(flatNodes, equalNode, getLevel)).toBeNull();\n    });\n\n    it('should return null if no parent found', () => {\n      expect(getParent(flatNodes, flatNodes[0], getLevel)).toBeNull();\n      expect(getParent(flatNodes, flatNodes[6], getLevel)).toBeNull();\n    });\n  });\n\n  describe('getDescendants', () => {\n    it('should return all descendants', () => {\n      expect(getDescendants(flatNodes, flatNodes[0], getLevel)).toEqual([\n        flatNodes[1],\n        flatNodes[2],\n        flatNodes[3],\n        flatNodes[4],\n        flatNodes[5]\n      ]);\n      expect(getDescendants(flatNodes, flatNodes[3], getLevel)).toEqual([flatNodes[4], flatNodes[5]]);\n    });\n\n    it('should return an empty array if the node not in nodes', () => {\n      const equalNode = cloneDeep(flatNodes[1]);\n      expect(getDescendants(flatNodes, equalNode, getLevel)).toEqual([]);\n    });\n\n    it('should return an empty array if no descendants found', () => {\n      expect(getDescendants(flatNodes, flatNodes[1], getLevel)).toEqual([]);\n      expect(getDescendants(flatNodes, flatNodes[2], getLevel)).toEqual([]);\n      expect(getDescendants(flatNodes, flatNodes[4], getLevel)).toEqual([]);\n      expect(getDescendants(flatNodes, flatNodes[5], getLevel)).toEqual([]);\n    });\n  });\n\n  describe('getNextSibling', () => {\n    it('should return the next sibling', () => {\n      expect(getNextSibling(flatNodes, flatNodes[1], getLevel)).toBe(flatNodes[2]);\n      expect(getNextSibling(flatNodes, flatNodes[2], getLevel)).toBe(flatNodes[3]);\n      expect(getNextSibling(flatNodes, flatNodes[4], getLevel)).toBe(flatNodes[5]);\n    });\n\n    it('should return null if no next sibling found', () => {\n      expect(getNextSibling(flatNodes, flatNodes[3], getLevel)).toBeNull();\n      expect(getNextSibling(flatNodes, flatNodes[7], getLevel)).toBeNull();\n    });\n\n    it('should return the first sibling after _index loc if enter _index', () => {\n      const nextSibling = getNextSibling(flatNodes, flatNodes[1], getLevel, 2);\n      expect(nextSibling).toBe(flatNodes[3]);\n    });\n\n    it('should return the null if _index less than 0', () => {\n      const nextSibling = getNextSibling(flatNodes, flatNodes[1], getLevel, -1);\n      expect(nextSibling).toBeNull();\n    });\n  });\n\n  describe('getParentForNestedData', () => {\n    it('should return the parent node in nested data', () => {\n      expect(getParentForNestedData(nestedNodes, nestedNodes[0].children![0], getChildren)).toBe(nestedNodes[0]);\n      expect(getParentForNestedData(nestedNodes, nestedNodes[0].children![1], getChildren)).toBe(nestedNodes[0]);\n      expect(getParentForNestedData(nestedNodes, nestedNodes[0].children![2], getChildren)).toBe(nestedNodes[0]);\n      expect(getParentForNestedData(nestedNodes, nestedNodes[0].children![2].children![0], getChildren)).toBe(\n        nestedNodes[0].children![2]\n      );\n      expect(getParentForNestedData(nestedNodes, nestedNodes[0].children![2].children![1], getChildren)).toBe(\n        nestedNodes[0].children![2]\n      );\n      expect(getParentForNestedData(nestedNodes, nestedNodes[1].children![0], getChildren)).toBe(nestedNodes[1]);\n    });\n\n    it('should return null if the node not in nodes', () => {\n      const equalNode = cloneDeep(nestedNodes[0].children![0]);\n      const parent = getParentForNestedData(nestedNodes, equalNode, getChildren);\n      expect(parent).toBeNull();\n    });\n\n    it('should return null if no parent found in nested data', () => {\n      const parent = getParentForNestedData(nestedNodes, nestedNodes[0], getChildren);\n      expect(parent).toBeNull();\n    });\n  });\n\n  describe('getNextSiblingForNestedData', () => {\n    it('should return the next sibling in nested data', () => {\n      const nextSibling = getNextSiblingForNestedData(nestedNodes, nestedNodes[0].children![0], getChildren);\n      expect(nextSibling).toBe(nestedNodes[0].children![1]);\n    });\n\n    it('should return null if the node not in nodes', () => {\n      const equalNode = cloneDeep(nestedNodes[0].children![0]);\n      expect(getNextSiblingForNestedData(nestedNodes, equalNode, getChildren)).toBeNull();\n    });\n\n    it('should return null if no next sibling found in nested data', () => {\n      expect(getNextSiblingForNestedData(nestedNodes, nestedNodes[0].children![2], getChildren)).toBeNull();\n      expect(\n        getNextSiblingForNestedData(nestedNodes, nestedNodes[0].children![2].children![1], getChildren)\n      ).toBeNull();\n      expect(getNextSiblingForNestedData(nestedNodes, nestedNodes[1], getChildren)).toBeNull();\n      expect(getNextSiblingForNestedData(nestedNodes, nestedNodes[1].children![0], getChildren)).toBeNull();\n    });\n  });\n\n  describe('getDescendantsForNestedData', () => {\n    it('should return all descendants in nested data', () => {\n      expect(getDescendantsForNestedData(nestedNodes[0], getChildren)).toEqual([\n        nestedNodes[0].children![0],\n        nestedNodes[0].children![1],\n        nestedNodes[0].children![2],\n        nestedNodes[0].children![2].children![0],\n        nestedNodes[0].children![2].children![1]\n      ]);\n      expect(getDescendantsForNestedData(nestedNodes[0].children![2], getChildren)).toEqual([\n        nestedNodes[0].children![2].children![0],\n        nestedNodes[0].children![2].children![1]\n      ]);\n    });\n\n    it('should return an empty array if no descendants found in nested data', () => {\n      expect(getDescendantsForNestedData(nestedNodes[0].children![0], getChildren)).toEqual([]);\n      expect(getDescendantsForNestedData(nestedNodes[0].children![1], getChildren)).toEqual([]);\n      expect(getDescendantsForNestedData(nestedNodes[0].children![2].children![0], getChildren)).toEqual([]);\n      expect(getDescendantsForNestedData(nestedNodes[0].children![2].children![1], getChildren)).toEqual([]);\n      expect(getDescendantsForNestedData(nestedNodes[1].children![0], getChildren)).toEqual([]);\n    });\n  });\n\n  describe('flattenNestedNodes', () => {\n    it('should flatten nested nodes', () => {\n      const flattenedNodes = flattenNestedNodes(nestedNodes, getChildren);\n      expect(flattenedNodes).toEqual([\n        nestedNodes[0],\n        nestedNodes[0].children![0],\n        nestedNodes[0].children![1],\n        nestedNodes[0].children![2],\n        nestedNodes[0].children![2].children![0],\n        nestedNodes[0].children![2].children![1],\n        nestedNodes[1],\n        nestedNodes[1].children![0]\n      ]);\n    });\n  });\n});\n"
  },
  {
    "path": "components/tree-view/utils.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport const getParent = <T>(nodes: T[], node: T, getLevel: (dataNode: T) => number): T | null => {\n  let index = nodes.indexOf(node);\n  if (index < 0) {\n    return null;\n  }\n  const level = getLevel(node);\n  for (index--; index >= 0; index--) {\n    const preLevel = getLevel(nodes[index]);\n    if (preLevel + 1 === level) {\n      return nodes[index];\n    }\n    if (preLevel + 1 < level) {\n      return null;\n    }\n  }\n  return null;\n};\n\nexport const getDescendants = <T>(nodes: T[], node: T, getLevel: (dataNode: T) => number): T[] => {\n  let index = nodes.indexOf(node);\n  if (index < 0) {\n    return [];\n  }\n  const result = [];\n  const level = getLevel(nodes[index]);\n  for (index++; index < nodes.length; index++) {\n    if (getLevel(nodes[index]) > level) {\n      result.push(nodes[index]);\n    } else {\n      break;\n    }\n  }\n  return result;\n};\n\nexport const getNextSibling = <T>(\n  nodes: T[],\n  node: T,\n  getLevel: (dataNode: T) => number,\n  _index?: number\n): T | null => {\n  let index = typeof _index !== 'undefined' ? _index : nodes.indexOf(node);\n  if (index < 0) {\n    return null;\n  }\n  const level = getLevel(node);\n\n  for (index++; index < nodes.length; index++) {\n    const nextLevel = getLevel(nodes[index]);\n    if (nextLevel < level) {\n      return null;\n    }\n    if (nextLevel === level) {\n      return nodes[index];\n    }\n  }\n  return null;\n};\n\nexport const getParentForNestedData = <T>(nodes: T[], node: T, getChildren: (dataNode: T) => T[]): T | null => {\n  for (const parent of flattenNestedNodes(nodes, getChildren)) {\n    if (getChildren(parent)?.includes(node)) {\n      return parent;\n    }\n  }\n\n  return null;\n};\n\nexport const getNextSiblingForNestedData = <T>(nodes: T[], node: T, getChildren: (dataNode: T) => T[]): T | null => {\n  const len = nodes.length;\n  for (let i = 0; i < len; i++) {\n    if (nodes[i] === node) {\n      return i + 1 < len ? nodes[i + 1] : null;\n    }\n\n    const children = getChildren(nodes[i]);\n    if (children && children.length > 0) {\n      const sibling = getNextSiblingForNestedData(children, node, getChildren);\n      if (sibling) {\n        return sibling;\n      }\n    }\n  }\n  return null;\n};\n\nexport const getDescendantsForNestedData = <T>(node: T, getChildren: (dataNode: T) => T[]): T[] => {\n  let result: T[] = [];\n  const children = getChildren(node);\n  if (children && children.length > 0) {\n    children.forEach(child => {\n      result.push(child);\n      result = result.concat(getDescendantsForNestedData(child, getChildren));\n    });\n  }\n\n  return result;\n};\n\nexport const flattenNestedNodes = <T>(nodes: T[], getChildren: (dataNode: T) => T[]): T[] => {\n  const flattenedNodes = [];\n  for (const node of nodes) {\n    flattenedNodes.push(node);\n    if (getChildren(node)) {\n      flattenedNodes.push(...flattenNestedNodes(getChildren(node), getChildren));\n    }\n  }\n  return flattenedNodes;\n};\n"
  },
  {
    "path": "components/tsconfig.json",
    "content": "{\n  \"extends\": \"../tsconfig.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"rootDir\": \".\",\n    \"paths\": {\n      \"ng-zorro-antd/*\": [\n        \"./*\"\n      ]\n    },\n    \"alwaysStrict\": true,\n    \"strictFunctionTypes\": true\n  },\n  \"angularCompilerOptions\": {\n    \"strictInputAccessModifiers\": true,\n    \"skipTemplateCodegen\": true,\n    \"strictMetadataEmit\": true,\n    \"enableResourceInlining\": true,\n    \"fullTemplateTypeCheck\": true,\n    \"strictTemplates\": true,\n    \"strictInjectionParameters\": true\n  },\n  \"include\": [\n    \"./**/*.ts\"\n  ]\n}"
  },
  {
    "path": "components/tsconfig.lib.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \"./\",\n    \"outDir\": \"../release\",\n    \"alwaysStrict\": true,\n    \"declaration\": true,\n    \"inlineSources\": true,\n    \"declarationMap\": true,\n    \"sourceMap\": true,\n    \"strictFunctionTypes\": true,\n    \"stripInternal\": true\n  },\n  \"angularCompilerOptions\": {\n    \"strictInputAccessModifiers\": true,\n    \"skipTemplateCodegen\": true,\n    \"strictMetadataEmit\": true,\n    \"enableResourceInlining\": true,\n    \"fullTemplateTypeCheck\": true,\n    \"strictTemplates\": true,\n    \"strictInjectionParameters\": true\n  },\n  \"include\": [\n    \"**/*.ts\"\n  ]\n}\n"
  },
  {
    "path": "components/tsconfig.lib.prod.json",
    "content": "{\n  \"extends\": \"./tsconfig.lib.json\",\n  \"compilerOptions\": {\n    \"declarationMap\": false\n  },\n  \"angularCompilerOptions\": {\n    \"enableIvy\": true,\n    \"compilationMode\": \"partial\"\n  }\n}\n"
  },
  {
    "path": "components/tsconfig.spec.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../out-tsc/spec\",\n    \"types\": [\n      \"jasmine\"\n    ]\n  },\n  \"files\": [\n    \"test.ts\"\n  ],\n  \"include\": [\n    \"**/*.spec.ts\",\n    \"**/*.d.ts\",\n    \"../node_modules/@types/jasmine/index.d.ts\",\n    \"../node_modules/karma-viewport/dist/index.d.ts\"\n  ]\n}\n"
  },
  {
    "path": "components/typography/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n展示文档样例。\n\n## en-US\n\nDisplay the document sample.\n"
  },
  {
    "path": "components/typography/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\nimport { NzTypographyModule } from 'ng-zorro-antd/typography';\n\n@Component({\n  selector: 'nz-demo-typography-basic',\n  imports: [NzDividerModule, NzTypographyModule],\n  template: `\n    <article nz-typography>\n      <h1 nz-typography>Introduction</h1>\n      <p nz-typography>\n        In the process of internal desktop applications development, many different design specs and implementations\n        would be involved, which might cause designers and developers difficulties and duplication and reduce the\n        efficiency of development.\n      </p>\n      <p nz-typography>\n        After massive project practice and summaries, Ant Design, a design language for backgroundapplications, is\n        refined by Ant UED Team, which aims to\n        <span nz-typography>\n          <strong>\n            uniform the user interface specs for internal background projects, lower the unnecessary cost of design\n            differences and implementation and liberate the resources ofdesign and front-end development\n          </strong>\n        </span>\n        .\n      </p>\n      <h2 nz-typography>Guidelines and Resources</h2>\n      <p nz-typography>\n        We supply a series of design principles, practical patterns and high quality design resources (\n        <span nz-typography><code>Sketch</code></span>\n        and\n        <span nz-typography><code>Axure</code></span>\n        ), to help people create their product prototypes beautifully and efficiently.\n      </p>\n      <div nz-typography>\n        <ul>\n          <li>\n            <a href=\"/docs/spec/proximity\">Principles</a>\n          </li>\n          <li>\n            <a href=\"/docs/pattern/navigation\">Patterns</a>\n          </li>\n          <li>\n            <a href=\"/docs/resource/download\">Resource Download</a>\n          </li>\n        </ul>\n      </div>\n      <p nz-typography>\n        Press\n        <span nz-typography><kbd>Esc</kbd></span>\n        to exist...\n      </p>\n    </article>\n    <nz-divider />\n    <article nz-typography>\n      <h1 nz-typography>介绍</h1>\n      <p nz-typography>\n        蚂蚁的企业级产品是一个庞大且复杂的体系。这类产品不仅量级巨大且功能复杂，而且变动和并发频繁，常常需要设计与开发能够快速的做出响应。\n        同时这类产品中有存在很多类似的页面以及组件，可以通过抽象得到一些稳定且高复用性的内容。\n      </p>\n      <p nz-typography>\n        随着商业化的趋势，越来越多的企业级产品对更好的用户体验有了进一步的要求。带着这样的一个终极目标，我们（蚂蚁金服体验技术部）\n        经过大量的项目实践和总结，逐步打磨出一个服务于企业级产品的设计体系 Ant Design。 基于\n        <span nz-typography><mark>『确定』和『自然』</mark></span>\n        的设计价值观，通过模块化的解决方案，降低冗余的生产成本， 让设计者专注于\n        <span nz-typography><strong>更好的用户体验</strong></span>\n        。\n      </p>\n      <h2 nz-typography>设计资源</h2>\n      <p nz-typography>\n        我们提供完善的设计原则、最佳实践和设计资源文件 （\n        <span nz-typography><code>Sketch</code></span>\n        和\n        <span nz-typography><code>Axure</code></span>\n        ），来帮助业务快速设计出高质 量的产品原型。\n      </p>\n      <div nz-typography>\n        <ul>\n          <li>\n            <a href=\"/docs/spec/proximity\">设计原则</a>\n          </li>\n          <li>\n            <a href=\"/docs/pattern/navigation\">设计模式</a>\n          </li>\n          <li>\n            <a href=\"/docs/resource/download\">设计资源</a>\n          </li>\n        </ul>\n      </div>\n      <p nz-typography>\n        按\n        <span nz-typography><kbd>Esc</kbd></span>\n        键退出阅读……\n      </p>\n    </article>\n  `\n})\nexport class NzDemoTypographyBasicComponent {}\n"
  },
  {
    "path": "components/typography/demo/ellipsis.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 省略号\n  en-US: ellipsis\n---\n\n## zh-CN\n\n多行文本省略。\n\n## en-US\n\nMultiple line ellipsis support.\n"
  },
  {
    "path": "components/typography/demo/ellipsis.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTypographyModule } from 'ng-zorro-antd/typography';\n\n@Component({\n  selector: 'nz-demo-typography-ellipsis',\n  imports: [NzTypographyModule],\n  template: `\n    <p\n      nz-typography\n      nzEllipsis\n      nzCopyable\n      nzContent=\"Ant Design, a design language for background applications, is refined by Ant UED Team. Ant Design, a design language for background\n      applications, is refined by Ant UED Team. Ant Design, a design language for background applications, is refined by Ant UED Team. Ant\n      Design, a design language for background applications, is refined by Ant UED Team. Ant Design, a design language for background\n      applications, is refined by Ant UED Team. Ant Design\"\n    ></p>\n    <br />\n    <p nz-typography nzEllipsis>\n      Ant Design, a design language for background applications, is refined by Ant UED Team. Ant Design, a design\n      language for background applications, is refined by Ant UED Team. Ant Design, a design language for background\n      applications, is refined by Ant UED Team. Ant Design, a design language for background applications, is refined by\n      Ant UED Team. Ant Design, a design language for background applications, is refined by Ant UED Team. Ant Design\n    </p>\n    <br />\n    <p nz-typography nzEllipsis nzExpandable [nzEllipsisRows]=\"3\">\n      Ant Design, a design language for background applications, is refined by Ant UED Team. Ant Design, a design\n      language for background applications, is refined by Ant UED Team. Ant Design, a design language for background\n      applications, is refined by Ant UED Team. Ant Design, a design language for background applications, is refined by\n      Ant UED Team. Ant Design, a design language for background applications, is refined by Ant UED Team. Ant Design, a\n      design language for background applications, is refined by Ant UED Team.\n    </p>\n    <br />\n    <p\n      nz-typography\n      nzEllipsis\n      nzEditable\n      [nzEllipsisRows]=\"2\"\n      [nzContent]=\"dynamicContent\"\n      (nzContentChange)=\"onChange($event)\"\n    ></p>\n  `\n})\nexport class NzDemoTypographyEllipsisComponent {\n  dynamicContent =\n    'Ant Design, a design language for background applications, is refined by Ant UED Team. ' +\n    'Ant Design, a design language for background applications, is refined by Ant UED Team. ' +\n    'Ant Design, a design language for background applications, is refined by Ant UED Team. ' +\n    'Ant Design, a design language for background applications, is refined by Ant UED Team.';\n\n  onChange(event: string): void {\n    this.dynamicContent = event;\n  }\n}\n"
  },
  {
    "path": "components/typography/demo/interactive.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 可交互\n  en-US: Interactive\n---\n\n## zh-CN\n\n提供可编辑和可复制等额外的交互能力。\n\n## en-US\n\nProvide additional interactive capacity of editable and copyable.\n"
  },
  {
    "path": "components/typography/demo/interactive.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzTypographyModule } from 'ng-zorro-antd/typography';\n\n@Component({\n  selector: 'nz-demo-typography-interactive',\n  imports: [NzIconModule, NzTypographyModule],\n  template: `\n    <p nz-typography nzEditable [(nzContent)]=\"editStr\"></p>\n    <p\n      nz-typography\n      nzEditable\n      nzEditIcon=\"highlight\"\n      nzEditTooltip=\"click to edit text\"\n      [(nzContent)]=\"customEditIconStr\"\n    ></p>\n    <p nz-typography nzEditable [nzEditTooltip]=\"null\" [(nzContent)]=\"hideEditTooltipStr\"></p>\n    <p nz-typography nzCopyable nzEditable [(nzContent)]=\"copyStr\"></p>\n    <p nz-typography nzCopyable nzCopyText=\"Hello, Ant Design!\">Replace copy text.</p>\n    <p\n      nz-typography\n      nzCopyable\n      nzContent=\"Custom copy icons and tooltips text.\"\n      [nzCopyTooltips]=\"['click here', copedIcon]\"\n      [nzCopyIcons]=\"['meh', 'smile']\"\n    ></p>\n    <ng-template #copedIcon>\n      <nz-icon nzType=\"smile\" nzTheme=\"fill\" />\n      you clicked!!\n    </ng-template>\n    <p nz-typography nzCopyable [nzCopyTooltips]=\"null\" nzContent=\"Hide copy tooltips.\"></p>\n  `,\n  styles: `\n    p[nz-typography] {\n      margin-bottom: 1em;\n    }\n  `\n})\nexport class NzDemoTypographyInteractiveComponent {\n  editStr = 'This is an editable text.';\n  customEditIconStr = 'Custom edit icon and tooltip text.';\n  hideEditTooltipStr = 'Hide edit tooltip.';\n  copyStr = 'This is a copyable text.';\n}\n"
  },
  {
    "path": "components/typography/demo/suffix.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 后缀\n  en-US: suffix\n---\n\n## zh-CN\n\n添加后缀的省略。\n\n## en-US\n\nadd suffix ellipsis support.\n"
  },
  {
    "path": "components/typography/demo/suffix.ts",
    "content": "import { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzSliderModule } from 'ng-zorro-antd/slider';\nimport { NzTypographyModule } from 'ng-zorro-antd/typography';\n\n@Component({\n  selector: 'nz-demo-typography-suffix',\n  imports: [FormsModule, NzSliderModule, NzTypographyModule],\n  template: `\n    <nz-slider [(ngModel)]=\"rows\" [nzMax]=\"10\" [nzMin]=\"1\" />\n    <p\n      nz-typography\n      nzEllipsis\n      nzExpandable\n      [attr.title]=\"content + suffix\"\n      [nzEllipsisRows]=\"rows\"\n      [nzSuffix]=\"suffix\"\n      (nzOnEllipsis)=\"onEllipsisChange($event)\"\n    >\n      {{ content }}\n    </p>\n  `\n})\nexport class NzDemoTypographySuffixComponent {\n  content =\n    'To be, or not to be, that is a question: Whether it is nobler in the mind to suffer. The slings and arrows of ' +\n    'outrageous fortune Or to take arms against a sea of troubles, And by opposing end them? To die: to sleep; ' +\n    'No more; and by a sleep to say we end The heart-ache and the thousand natural shocks That flesh is heir to, ' +\n    'tis a consummation Devoutly to be wish d. To die, to sleep To sleep- perchance to dream: ay, there s the rub! ' +\n    'For in that sleep of death what dreams may come When we have shuffled off this mortal coil, Must give us pause. ' +\n    'There s the respect That makes calamity of so long life';\n\n  suffix = '--William Shakespeare';\n  rows = 1;\n\n  onEllipsisChange(ellipsis: boolean): void {\n    console.log(ellipsis);\n  }\n}\n"
  },
  {
    "path": "components/typography/demo/text.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 文本组件\n  en-US: Text Component\n---\n\n## zh-CN\n\n内置不同样式的文本。\n\n## en-US\n\nProvides multiple types of text.\n"
  },
  {
    "path": "components/typography/demo/text.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTypographyModule } from 'ng-zorro-antd/typography';\n\n@Component({\n  selector: 'nz-demo-typography-text',\n  imports: [NzTypographyModule],\n  template: `\n    <span nz-typography>Ant Design (default)</span>\n    <span nz-typography nzType=\"secondary\">Ant Design (secondary)</span>\n    <span nz-typography nzType=\"success\">Ant Design (success)</span>\n    <span nz-typography nzType=\"warning\">Ant Design (warning)</span>\n    <span nz-typography nzType=\"danger\">Ant Design (danger)</span>\n    <span nz-typography nzDisabled>Ant Design (disabled)</span>\n    <span nz-typography><mark>Ant Design (mark)</mark></span>\n    <span nz-typography><code>Ant Design (code)</code></span>\n    <span nz-typography><kbd>Ant Design (keyboard)</kbd></span>\n    <span nz-typography><u>Ant Design (underline)</u></span>\n    <span nz-typography><del>Ant Design (delete)</del></span>\n    <span nz-typography><strong>Ant Design (strong)</strong></span>\n    <span nz-typography>\n      <a href=\"https://ng.ant.design/\" target=\"_blank\">Ant Design</a>\n    </span>\n  `,\n  styles: `\n    span[nz-typography] {\n      display: block;\n    }\n    span[nz-typography] + span[nz-typography] {\n      margin-top: 8px;\n    }\n  `\n})\nexport class NzDemoTypographyTextComponent {}\n"
  },
  {
    "path": "components/typography/demo/title.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 标题组件\n  en-US: Title Component\n---\n\n## zh-CN\n\n展示不同级别的标题。\n\n## en-US\n\nDisplay title in different level.\n"
  },
  {
    "path": "components/typography/demo/title.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzTypographyModule } from 'ng-zorro-antd/typography';\n\n@Component({\n  selector: 'nz-demo-typography-title',\n  imports: [NzTypographyModule],\n  template: `\n    <h1 nz-typography>h1. Ant Design</h1>\n    <h2 nz-typography>h2. Ant Design</h2>\n    <h3 nz-typography>h3. Ant Design</h3>\n    <h4 nz-typography>h4. Ant Design</h4>\n    <h5 nz-typography>h5. Ant Design</h5>\n  `\n})\nexport class NzDemoTypographyTitleComponent {}\n"
  },
  {
    "path": "components/typography/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: General\ntitle: Typography\ncols: 1\ncover: 'https://gw.alipayobjects.com/zos/alicdn/GOM1KQ24O/Typography.svg'\ndescription: Basic text writing, including headings, body text, lists, and more.\n---\n\n## When To Use\n\n- When need to display title or paragraph contents in Articles/Blogs/Notes.\n- When you need copyable/editable/ellipsis texts.\n\n## API\n\n### [nz-typography]\n\n| Property            | Description                                                                    | Type                                                                 | Default             | Global Config |\n| ------------------- | ------------------------------------------------------------------------------ | -------------------------------------------------------------------- | ------------------- | ------------- |\n| `[nzContent]`       | Component content                                                              | `string`                                                             | -                   |               |\n| `[nzCopyable]`      | Can copy, require use `[nzContent]`                                            | `boolean`                                                            | `false`             |               |\n| `[nzEditable]`      | Editable, require use `[nzContent]`                                            | `boolean`                                                            | `false`             |               |\n| `[nzCopyIcons]`     | Custom copy icons                                                              | `[string \\| TemplateRef<void>, string \\| TemplateRef<void>]`         | `['copy', 'check']` | ✅            |\n| `[nzCopyTooltips]`  | Custom tooltips text, hide when it is `null`                                   | `null \\| [string \\| TemplateRef<void>, string \\| TemplateRef<void>]` | -                   | ✅            |\n| `[nzEditIcon]`      | Custom edit icon                                                               | `string \\| TemplateRef<void>`                                        | `'edit'`            | ✅            |\n| `[nzEditTooltip]`   | Custom tooltip text, hide when it is `null`                                    | `null \\| string \\| TemplateRef<void>`                                | -                   | ✅            |\n| `[nzEllipsis]`      | Display ellipsis when overflow, require use `[nzContent]` when dynamic content | `boolean`                                                            | `false`             |               |\n| `[nzSuffix]`        | The text suffix when used `nzEllipsis`                                         | `string`                                                             | -                   |               |\n| `[nzCopyText]`      | Customize the copy text                                                        | `string`                                                             | -                   |               |\n| `[nzDisabled]`      | Disable content                                                                | `boolean`                                                            | `false`             |               |\n| `[nzExpandable]`    | Expandable when ellipsis                                                       | `boolean`                                                            | `false`             |               |\n| `[nzEllipsisRows]`  | Line number                                                                    | `number`                                                             | `1`                 | ✅            |\n| `[nzType]`          | Content type                                                                   | `'secondary' \\| 'warning' \\| 'danger' \\| 'success'`                  | -                   |               |\n| `(nzContentChange)` | Trigger when user edit the content                                             | `EventEmitter<string>`                                               | -                   |               |\n| `(nzExpandChange)`  | Trigger when user expanded the content                                         | `EventEmitter<void>`                                                 | -                   |               |\n| `(nzOnEllipsis)`    | Trigger when ellipsis status changed                                           | `EventEmitter<boolean>`                                              | -                   |               |\n"
  },
  {
    "path": "components/typography/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 排版\ntype: 通用\ntitle: Typography\ncols: 1\ncover: 'https://gw.alipayobjects.com/zos/alicdn/GOM1KQ24O/Typography.svg'\ndescription: 文本的基本格式。\n---\n\n## 何时使用\n\n- 当需要展示标题、段落、列表内容时使用，如文章/博客/日志的文本样式。\n- 当需要一列基于文本的基础操作时，如拷贝/省略/可编辑。\n\n## API\n\n### [nz-typography]\n\n| 参数                | 说明                                                | 类型                                                                 | 默认值              | 全局配置 |\n| ------------------- | --------------------------------------------------- | -------------------------------------------------------------------- | ------------------- | -------- |\n| `[nzContent]`       | 组件内容                                            | `string`                                                             | -                   |\n| `[nzCopyable]`      | 是否可拷贝，需要配合 `[nzContent]` 使用             | `boolean`                                                            | `false`             |\n| `[nzEditable]`      | 是否可编辑，需要配合 `[nzContent]` 使用             | `boolean`                                                            | `false`             |\n| `[nzCopyIcons]`     | 自定义拷贝图标                                      | `[string \\| TemplateRef<void>, string \\| TemplateRef<void>]`         | `['copy', 'check']` | ✅       |\n| `[nzCopyTooltips]`  | 自定义提示文案，为 `null` 时隐藏文案                | `null \\| [string \\| TemplateRef<void>, string \\| TemplateRef<void>]` | -                   | ✅       |\n| `[nzEditIcon]`      | 自定义编辑图标                                      | `string \\| TemplateRef<void>`                                        | `'edit'`            | ✅       |\n| `[nzEditTooltip]`   | 自定义提示文案，为 `null` 时隐藏文案                | `null \\| string \\| TemplateRef<void>`                                | -                   | ✅       |\n| `[nzEllipsis]`      | 自动溢出省略，动态内容时需要配合 `[nzContent]` 使用 | `boolean`                                                            | `false`             |\n| `[nzExpandable]`    | 自动溢出省略时是否可展开                            | `boolean`                                                            | `false`             |          |\n| `[nzSuffix]`        | 自动溢出省略时的文本后缀                            | `string`                                                             | -                   |          |\n| `[nzCopyText]`      | 自定义被拷贝的文本                                  | `string`                                                             | -                   |          |\n| `[nzDisabled]`      | 禁用文本                                            | `boolean`                                                            | `false`             |          |\n| `[nzEllipsisRows]`  | 自动溢出省略时省略行数                              | `number`                                                             | `1`                 | ✅       |\n| `[nzType]`          | 文本类型                                            | `'secondary' \\| 'warning' \\| 'danger' \\| 'success'`                  | -                   |          |\n| `(nzContentChange)` | 当用户提交编辑内容时触发                            | `EventEmitter<string>`                                               | -                   |          |\n| `(nzExpandChange)`  | 展开省略文本时触发                                  | `EventEmitter<void>`                                                 | -                   |          |\n| `(nzOnEllipsis)`    | 当省略状态变化时触发                                | `EventEmitter<boolean>`                                              | -                   |          |\n"
  },
  {
    "path": "components/typography/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/typography/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/typography/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport { NzTypographyModule } from './typography.module';\nexport { NzTypographyComponent } from './typography.component';\nexport { NzTextCopyComponent } from './text-copy.component';\nexport { NzTextEditComponent } from './text-edit.component';\n"
  },
  {
    "path": "components/typography/style/entry.less",
    "content": "@import './index.less';\n\n// style dependencies\n@import '../../tooltip/style/entry.less';\n@import '../../input/style/entry.less';"
  },
  {
    "path": "components/typography/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@typography-prefix-cls: ~'@{ant-prefix}-typography';\n\n// =============== Basic ===============\n.@{typography-prefix-cls} {\n  color: @text-color;\n  word-break: break-word;\n\n  &&-secondary {\n    color: @text-color-secondary;\n  }\n\n  &&-success {\n    color: @success-color;\n  }\n\n  &&-warning {\n    color: @warning-color;\n  }\n\n  &&-danger {\n    color: @error-color;\n\n    a&:active,\n    a&:focus {\n      color: @error-color-active;\n    }\n\n    a&:hover {\n      color: @error-color-hover;\n    }\n  }\n\n  &&-disabled {\n    color: @disabled-color;\n    cursor: not-allowed;\n    user-select: none;\n  }\n\n  // Tag\n  div&,\n  p {\n    .typography-paragraph();\n  }\n\n  h1&,\n  div&-h1,\n  div&-h1 > textarea,\n  h1 {\n    .typography-title-1();\n  }\n\n  h2&,\n  div&-h2,\n  div&-h2 > textarea,\n  h2 {\n    .typography-title-2();\n  }\n\n  h3&,\n  div&-h3,\n  div&-h3 > textarea,\n  h3 {\n    .typography-title-3();\n  }\n\n  h4&,\n  div&-h4,\n  div&-h4 > textarea,\n  h4 {\n    .typography-title-4();\n  }\n\n  h5&,\n  div&-h5,\n  div&-h5 > textarea,\n  h5 {\n    .typography-title-5();\n  }\n\n  h1&,\n  h2&,\n  h3&,\n  h4&,\n  h5& {\n    .@{typography-prefix-cls} + & {\n      margin-top: @typography-title-margin-top;\n    }\n  }\n\n  div,\n  ul,\n  li,\n  p,\n  h1,\n  h2,\n  h3,\n  h4,\n  h5 {\n    + h1,\n    + h2,\n    + h3,\n    + h4,\n    + h5 {\n      margin-top: @typography-title-margin-top;\n    }\n  }\n\n  a&-ellipsis,\n  span&-ellipsis {\n    display: inline-block;\n    max-width: 100%;\n  }\n\n  a&,\n  a {\n    .operation-unit();\n    text-decoration: @link-decoration;\n\n    &:active,\n    &:hover {\n      text-decoration: @link-hover-decoration;\n    }\n\n    &[disabled],\n    &.@{typography-prefix-cls}-disabled {\n      color: @disabled-color;\n      cursor: not-allowed;\n\n      &:active,\n      &:hover {\n        color: @disabled-color;\n      }\n\n      &:active {\n        pointer-events: none;\n      }\n    }\n  }\n\n  code {\n    margin: 0 0.2em;\n    padding: 0.2em 0.4em 0.1em;\n    font-size: 85%;\n    background: rgba(150, 150, 150, 0.1);\n    border: 1px solid rgba(100, 100, 100, 0.2);\n    border-radius: 3px;\n  }\n\n  kbd {\n    margin: 0 0.2em;\n    padding: 0.15em 0.4em 0.1em;\n    font-size: 90%;\n    background: rgba(150, 150, 150, 0.06);\n    border: 1px solid rgba(100, 100, 100, 0.2);\n    border-bottom-width: 2px;\n    border-radius: 3px;\n  }\n\n  mark {\n    padding: 0;\n    background-color: @gold-3;\n  }\n\n  u,\n  ins {\n    text-decoration: underline;\n    text-decoration-skip-ink: auto;\n  }\n\n  s,\n  del {\n    text-decoration: line-through;\n  }\n\n  strong {\n    font-weight: 600;\n  }\n\n  // Operation\n  &-expand,\n  &-edit,\n  &-copy {\n    .operation-unit();\n\n    margin-left: 4px;\n  }\n\n  &-copy-success {\n    &,\n    &:hover,\n    &:focus {\n      color: @success-color;\n    }\n  }\n\n  // Text input area\n  &-edit-content {\n    position: relative;\n\n    div& {\n      left: -@input-padding-horizontal - 1px;\n      margin-top: -@input-padding-vertical-base - 1px;\n      margin-bottom: calc(1em - @input-padding-vertical-base - 1px);\n    }\n\n    &-confirm {\n      position: absolute;\n      right: 10px;\n      bottom: 8px;\n      color: @text-color-secondary;\n      // default style\n      font-weight: normal;\n      font-size: @font-size-base;\n      font-style: normal;\n      pointer-events: none;\n    }\n\n    // Fix Editable Textarea flash in Firefox\n    textarea {\n      // https://stackoverflow.com/a/7695964/3040605\n      height: 1em;\n      margin: 0 !important;\n      /* stylelint-disable-next-line property-no-vendor-prefix */\n      -moz-transition: none;\n    }\n  }\n\n  // list\n  ul,\n  ol {\n    margin: 0 0 1em;\n    padding: 0;\n\n    li {\n      margin: 0 0 0 20px;\n      padding: 0 0 0 4px;\n    }\n  }\n\n  ul {\n    list-style-type: circle;\n\n    ul {\n      list-style-type: disc;\n    }\n  }\n\n  ol {\n    list-style-type: decimal;\n  }\n\n  // pre & block\n  pre,\n  blockquote {\n    margin: 1em 0;\n  }\n\n  pre {\n    padding: 0.4em 0.6em;\n    white-space: pre-wrap;\n    word-wrap: break-word;\n    background: rgba(150, 150, 150, 0.1);\n    border: 1px solid rgba(100, 100, 100, 0.2);\n    border-radius: 3px;\n\n    // Compatible for marked\n    code {\n      display: inline;\n      margin: 0;\n      padding: 0;\n      font-size: inherit;\n      font-family: inherit;\n      background: transparent;\n      border: 0;\n    }\n  }\n\n  blockquote {\n    padding: 0 0 0 0.6em;\n    border-left: 4px solid rgba(100, 100, 100, 0.2);\n    opacity: 0.85;\n  }\n\n  // ============ Ellipsis ============\n  &-single-line {\n    white-space: nowrap;\n  }\n\n  &-ellipsis-single-line {\n    overflow: hidden;\n    text-overflow: ellipsis;\n\n    // https://blog.csdn.net/iefreer/article/details/50421025\n    a&,\n    span& {\n      vertical-align: bottom;\n    }\n  }\n\n  &-ellipsis-multiple-line {\n    /* stylelint-disable-next-line value-no-vendor-prefix */\n    display: -webkit-box;\n    overflow: hidden;\n    -webkit-line-clamp: 3;\n\n    /*! autoprefixer: ignore next */\n    -webkit-box-orient: vertical;\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/typography/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@typography-prefix-cls: ~'@{ant-prefix}-typography';\n\n.@{typography-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  // Operation\n  &-expand,\n  &-edit,\n  &-copy {\n    .@{typography-prefix-cls}-rtl & {\n      margin-right: 4px;\n      margin-left: 0;\n    }\n  }\n\n  &-expand {\n    .@{typography-prefix-cls}-rtl & {\n      float: left;\n    }\n  }\n\n  // Text input area\n  &-edit-content {\n    div& {\n      &.@{typography-prefix-cls}-rtl {\n        right: -@input-padding-horizontal - 1px;\n        left: auto;\n      }\n    }\n\n    &-confirm {\n      .@{typography-prefix-cls}-rtl & {\n        right: auto;\n        left: 10px;\n      }\n    }\n  }\n\n  // list\n  ul,\n  ol {\n    li {\n      .@{typography-prefix-cls}-rtl& {\n        margin: 0 20px 0 0;\n        padding: 0 4px 0 0;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/typography/text-copy.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Clipboard } from '@angular/cdk/clipboard';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DestroyRef,\n  ElementRef,\n  EventEmitter,\n  inject,\n  Input,\n  OnChanges,\n  OnInit,\n  Output,\n  SimpleChanges,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzTransButtonModule } from 'ng-zorro-antd/core/trans-button';\nimport { NzTSType } from 'ng-zorro-antd/core/types';\nimport { NzI18nService, NzTextI18nInterface } from 'ng-zorro-antd/i18n';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzTooltipModule } from 'ng-zorro-antd/tooltip';\n\n@Component({\n  selector: 'nz-text-copy',\n  exportAs: 'nzTextCopy',\n  template: `\n    <button\n      type=\"button\"\n      nz-tooltip\n      nz-trans-button\n      [nzTooltipTitle]=\"copied ? copedTooltip : copyTooltip\"\n      class=\"ant-typography-copy\"\n      [class.ant-typography-copy-success]=\"copied\"\n      (click)=\"onClick()\"\n    >\n      <ng-container *nzStringTemplateOutlet=\"copied ? copedIcon : copyIcon; let icon\">\n        <nz-icon [nzType]=\"icon\" />\n      </ng-container>\n    </button>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  imports: [NzTooltipModule, NzTransButtonModule, NzIconModule, NzOutletModule]\n})\nexport class NzTextCopyComponent implements OnInit, OnChanges {\n  private cdr = inject(ChangeDetectorRef);\n  private clipboard = inject(Clipboard);\n  private i18n = inject(NzI18nService);\n  private destroyRef = inject(DestroyRef);\n\n  copied = false;\n  copyId?: ReturnType<typeof setTimeout>;\n  locale!: NzTextI18nInterface;\n  nativeElement = inject(ElementRef).nativeElement;\n  copyTooltip: NzTSType | null = null;\n  copedTooltip: NzTSType | null = null;\n  copyIcon: NzTSType = 'copy';\n  copedIcon: NzTSType = 'check';\n\n  @Input() text!: string;\n  @Input() tooltips?: [NzTSType, NzTSType] | null;\n  @Input() icons: [NzTSType, NzTSType] = ['copy', 'check'];\n\n  @Output() readonly textCopy = new EventEmitter<string>();\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      clearTimeout(this.copyId);\n    });\n  }\n\n  ngOnInit(): void {\n    this.i18n.localeChange.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      this.locale = this.i18n.getLocaleData('Text');\n      this.updateTooltips();\n      this.cdr.markForCheck();\n    });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { tooltips, icons } = changes;\n    if (tooltips) {\n      this.updateTooltips();\n    }\n    if (icons) {\n      this.updateIcons();\n    }\n  }\n\n  onClick(): void {\n    if (this.copied) {\n      return;\n    }\n    this.copied = true;\n    this.cdr.detectChanges();\n    const text = this.text;\n    this.textCopy.emit(text);\n    this.clipboard.copy(text);\n    this.onCopied();\n  }\n\n  onCopied(): void {\n    clearTimeout(this.copyId);\n    this.copyId = setTimeout(() => {\n      this.copied = false;\n      this.cdr.detectChanges();\n    }, 3000);\n  }\n\n  private updateTooltips(): void {\n    if (this.tooltips === null) {\n      this.copedTooltip = null;\n      this.copyTooltip = null;\n    } else if (Array.isArray(this.tooltips)) {\n      const [copyTooltip, copedTooltip] = this.tooltips;\n      this.copyTooltip = copyTooltip || this.locale?.copy;\n      this.copedTooltip = copedTooltip || this.locale?.copied;\n    } else {\n      this.copyTooltip = this.locale?.copy;\n      this.copedTooltip = this.locale?.copied;\n    }\n    this.cdr.markForCheck();\n  }\n\n  private updateIcons(): void {\n    const [copyIcon, copedIcon] = this.icons;\n    this.copyIcon = copyIcon;\n    this.copedIcon = copedIcon;\n    this.cdr.markForCheck();\n  }\n}\n"
  },
  {
    "path": "components/typography/text-edit.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ENTER, ESCAPE } from '@angular/cdk/keycodes';\nimport {\n  afterNextRender,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DestroyRef,\n  ElementRef,\n  EventEmitter,\n  inject,\n  Injector,\n  Input,\n  NgZone,\n  OnInit,\n  Output,\n  ViewChild,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { BehaviorSubject } from 'rxjs';\nimport { first, switchMap } from 'rxjs/operators';\n\nimport { NzOutletModule } from 'ng-zorro-antd/core/outlet';\nimport { NzTransButtonModule } from 'ng-zorro-antd/core/trans-button';\nimport { NzTSType } from 'ng-zorro-antd/core/types';\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\nimport { NzI18nService, NzTextI18nInterface } from 'ng-zorro-antd/i18n';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzAutosizeDirective, NzInputModule } from 'ng-zorro-antd/input';\nimport { NzTooltipModule } from 'ng-zorro-antd/tooltip';\n\n@Component({\n  selector: 'nz-text-edit',\n  exportAs: 'nzTextEdit',\n  template: `\n    @if (editing) {\n      <textarea #textarea nz-input nzAutosize (blur)=\"confirm()\"></textarea>\n      <button nz-trans-button class=\"ant-typography-edit-content-confirm\" (click)=\"confirm()\">\n        <nz-icon nzType=\"enter\" />\n      </button>\n    } @else {\n      <button\n        nz-tooltip\n        nz-trans-button\n        class=\"ant-typography-edit\"\n        [nzTooltipTitle]=\"tooltip === null ? null : tooltip || locale?.edit\"\n        (click)=\"onClick()\"\n      >\n        <ng-container *nzStringTemplateOutlet=\"icon; let icon\">\n          <nz-icon [nzType]=\"icon\" />\n        </ng-container>\n      </button>\n    }\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  imports: [NzInputModule, NzTransButtonModule, NzIconModule, NzTooltipModule, NzOutletModule]\n})\nexport class NzTextEditComponent implements OnInit {\n  private ngZone = inject(NgZone);\n  private cdr = inject(ChangeDetectorRef);\n  private i18n = inject(NzI18nService);\n  private destroyRef = inject(DestroyRef);\n\n  editing = false;\n  locale!: NzTextI18nInterface;\n\n  @Input() text?: string;\n  @Input() icon: NzTSType = 'edit';\n  @Input() tooltip?: null | NzTSType;\n  @Output() readonly startEditing = new EventEmitter<void>();\n  @Output() readonly endEditing = new EventEmitter<string>(true);\n  @ViewChild('textarea', { static: false })\n  set textarea(textarea: ElementRef<HTMLTextAreaElement> | undefined) {\n    this.textarea$.next(textarea);\n  }\n  @ViewChild(NzAutosizeDirective, { static: false }) autosizeDirective!: NzAutosizeDirective;\n\n  beforeText?: string;\n  currentText?: string;\n  nativeElement: HTMLElement = inject(ElementRef).nativeElement;\n\n  // We could've saved the textarea within some private property (e.g. `_textarea`) and have a getter,\n  // but having subject makes the code more reactive and cancellable (e.g., event listeners will be\n  // automatically removed and re-added through the `switchMap` below).\n  private textarea$ = new BehaviorSubject<ElementRef<HTMLTextAreaElement> | null | undefined>(null);\n\n  private injector = inject(Injector);\n\n  ngOnInit(): void {\n    this.i18n.localeChange.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      this.locale = this.i18n.getLocaleData('Text');\n      this.cdr.markForCheck();\n    });\n\n    this.textarea$\n      .pipe(\n        switchMap(textarea => fromEventOutsideAngular<KeyboardEvent>(textarea?.nativeElement, 'keydown')),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(event => {\n        // Caretaker note: adding modifier at the end (for instance `(keydown.esc)`) will tell Angular to add\n        // an event listener through the `KeyEventsPlugin`, which always runs `ngZone.runGuarded()` internally.\n        // We're interested only in escape and enter keyboard buttons, otherwise Angular will run change detection\n        // on any `keydown` event.\n        if (event.keyCode !== ESCAPE && event.keyCode !== ENTER) {\n          return;\n        }\n\n        this.ngZone.run(() => {\n          if (event.keyCode === ESCAPE) {\n            this.onCancel();\n          } else {\n            this.onEnter(event);\n          }\n          this.cdr.markForCheck();\n        });\n      });\n\n    this.textarea$\n      .pipe(\n        switchMap(textarea => fromEventOutsideAngular<KeyboardEvent>(textarea?.nativeElement, 'input')),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe(event => {\n        this.currentText = (event.target as HTMLTextAreaElement).value;\n      });\n  }\n\n  onClick(): void {\n    this.beforeText = this.text;\n    this.currentText = this.beforeText;\n    this.editing = true;\n    this.startEditing.emit();\n    this.focusAndSetValue();\n  }\n\n  confirm(): void {\n    this.editing = false;\n    this.endEditing.emit(this.currentText);\n  }\n\n  onEnter(event: Event): void {\n    event.stopPropagation();\n    event.preventDefault();\n    this.confirm();\n  }\n\n  onCancel(): void {\n    this.currentText = this.beforeText;\n    this.confirm();\n  }\n\n  focusAndSetValue(): void {\n    const { injector } = this;\n\n    afterNextRender(\n      () => {\n        this.textarea$\n          .pipe(\n            // It may still not be available, so we need to wait until view queries\n            // are executed during the change detection. It's safer to wait until\n            // the query runs, and the textarea is set on the behavior subject.\n            first((textarea): textarea is ElementRef<HTMLTextAreaElement> => textarea != null),\n            takeUntilDestroyed(this.destroyRef)\n          )\n          .subscribe(textarea => {\n            textarea.nativeElement.focus();\n            textarea.nativeElement.value = this.currentText || '';\n            this.autosizeDirective.resizeToFitContent();\n            this.cdr.markForCheck();\n          });\n      },\n      { injector }\n    );\n  }\n}\n"
  },
  {
    "path": "components/typography/typography.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Direction, Directionality } from '@angular/cdk/bidi';\nimport { Platform } from '@angular/cdk/platform';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterViewInit,\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DestroyRef,\n  DOCUMENT,\n  ElementRef,\n  EmbeddedViewRef,\n  EventEmitter,\n  inject,\n  Input,\n  numberAttribute,\n  OnChanges,\n  OnInit,\n  Output,\n  Renderer2,\n  SimpleChanges,\n  TemplateRef,\n  ViewChild,\n  ViewContainerRef,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Subscription } from 'rxjs';\n\nimport { NzConfigKey, NzConfigService, WithConfig } from 'ng-zorro-antd/core/config';\nimport { cancelAnimationFrame, requestAnimationFrame } from 'ng-zorro-antd/core/polyfill';\nimport { NzResizeService } from 'ng-zorro-antd/core/services';\nimport { NzTSType } from 'ng-zorro-antd/core/types';\nimport { isStyleSupport, measure } from 'ng-zorro-antd/core/util';\nimport { NzI18nService, NzTextI18nInterface } from 'ng-zorro-antd/i18n';\n\nimport { NzTextCopyComponent } from './text-copy.component';\nimport { NzTextEditComponent } from './text-edit.component';\n\nconst NZ_CONFIG_MODULE_NAME: NzConfigKey = 'typography';\nconst EXPAND_ELEMENT_CLASSNAME = 'ant-typography-expand';\n\n@Component({\n  selector: `\n  nz-typography,\n  [nz-typography],\n  p[nz-paragraph],\n  span[nz-text],\n  h1[nz-title], h2[nz-title], h3[nz-title], h4[nz-title]\n  `,\n  exportAs: 'nzTypography',\n  template: `\n    <ng-template #contentTemplate let-content=\"content\">\n      @if (!content) {\n        <ng-content />\n      }\n      {{ content }}\n    </ng-template>\n    @if (!editing) {\n      @if (\n        expanded ||\n        (!hasOperationsWithEllipsis && nzEllipsisRows === 1 && !hasEllipsisObservers) ||\n        canCssEllipsis ||\n        (nzSuffix && expanded)\n      ) {\n        <ng-template [ngTemplateOutlet]=\"contentTemplate\" [ngTemplateOutletContext]=\"{ content: nzContent }\" />\n        @if (nzSuffix) {\n          {{ nzSuffix }}\n        }\n      } @else {\n        <span #ellipsisContainer></span>\n        @if (isEllipsis) {\n          {{ ellipsisStr }}\n        }\n        @if (nzSuffix) {\n          {{ nzSuffix }}\n        }\n        @if (nzExpandable && isEllipsis) {\n          <a #expandable class=\"ant-typography-expand\" (click)=\"onExpand()\">\n            {{ locale?.expand }}\n          </a>\n        }\n      }\n    }\n\n    @if (nzEditable) {\n      <nz-text-edit\n        [text]=\"nzContent\"\n        [icon]=\"nzEditIcon\"\n        [tooltip]=\"nzEditTooltip\"\n        (endEditing)=\"onEndEditing($event)\"\n        (startEditing)=\"onStartEditing()\"\n      />\n    }\n\n    @if (nzCopyable && !editing) {\n      <nz-text-copy\n        [text]=\"copyText\"\n        [tooltips]=\"nzCopyTooltips\"\n        [icons]=\"nzCopyIcons\"\n        (textCopy)=\"onTextCopy($event)\"\n      />\n    }\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  host: {\n    '[class.ant-typography]': '!editing',\n    '[class.ant-typography-rtl]': 'dir === \"rtl\"',\n    '[class.ant-typography-edit-content]': 'editing',\n    '[class.ant-typography-secondary]': 'nzType === \"secondary\"',\n    '[class.ant-typography-warning]': 'nzType === \"warning\"',\n    '[class.ant-typography-danger]': 'nzType === \"danger\"',\n    '[class.ant-typography-success]': 'nzType === \"success\"',\n    '[class.ant-typography-disabled]': 'nzDisabled',\n    '[class.ant-typography-ellipsis]': 'nzEllipsis && !expanded',\n    '[class.ant-typography-single-line]': 'nzEllipsis && nzEllipsisRows === 1',\n    '[class.ant-typography-ellipsis-single-line]': 'canCssEllipsis && nzEllipsisRows === 1',\n    '[class.ant-typography-ellipsis-multiple-line]': 'canCssEllipsis && nzEllipsisRows > 1',\n    '[style.-webkit-line-clamp]': '(canCssEllipsis && nzEllipsisRows > 1) ? nzEllipsisRows : null'\n  },\n  imports: [NgTemplateOutlet, NzTextEditComponent, NzTextCopyComponent]\n})\nexport class NzTypographyComponent implements OnInit, AfterViewInit, OnChanges {\n  readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;\n\n  nzConfigService = inject(NzConfigService);\n  private el: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement;\n  private cdr = inject(ChangeDetectorRef);\n  private viewContainerRef = inject(ViewContainerRef);\n  private renderer = inject(Renderer2);\n  private platform = inject(Platform);\n  private i18n = inject(NzI18nService);\n  private resizeService = inject(NzResizeService);\n  private directionality = inject(Directionality);\n  private document: Document = inject(DOCUMENT);\n  private destroyRef = inject(DestroyRef);\n\n  @Input({ transform: booleanAttribute }) nzCopyable = false;\n  @Input({ transform: booleanAttribute }) nzEditable = false;\n  @Input({ transform: booleanAttribute }) nzDisabled = false;\n  @Input({ transform: booleanAttribute }) nzExpandable = false;\n  @Input({ transform: booleanAttribute }) nzEllipsis = false;\n  @Input() @WithConfig() nzCopyTooltips?: [NzTSType, NzTSType] | null = undefined;\n  @Input() @WithConfig() nzCopyIcons: [NzTSType, NzTSType] = ['copy', 'check'];\n  @Input() @WithConfig() nzEditTooltip?: null | NzTSType = undefined;\n  @Input() @WithConfig() nzEditIcon: NzTSType = 'edit';\n  @Input() nzContent?: string;\n  @Input({ transform: numberAttribute }) @WithConfig() nzEllipsisRows: number = 1;\n  @Input() nzType: 'secondary' | 'warning' | 'danger' | 'success' | undefined;\n  @Input() nzCopyText: string | undefined;\n  @Input() nzSuffix: string | undefined;\n  @Output() readonly nzContentChange = new EventEmitter<string>();\n  @Output() readonly nzCopy = new EventEmitter<string>();\n  @Output() readonly nzExpandChange = new EventEmitter<void>();\n  // This is not a two-way binding output with {@link nzEllipsis}\n  @Output() readonly nzOnEllipsis = new EventEmitter<boolean>();\n\n  @ViewChild(NzTextEditComponent, { static: false }) textEditRef?: NzTextEditComponent;\n  @ViewChild(NzTextCopyComponent, { static: false }) textCopyRef?: NzTextCopyComponent;\n  @ViewChild('ellipsisContainer', { static: false }) ellipsisContainer?: ElementRef<HTMLSpanElement>;\n  @ViewChild('expandable', { static: false }) expandableBtn?: ElementRef<HTMLSpanElement>;\n  @ViewChild('contentTemplate', { static: false }) contentTemplate?: TemplateRef<{ content: string }>;\n\n  locale!: NzTextI18nInterface;\n  expandableBtnElementCache: HTMLElement | null = null;\n  editing = false;\n  ellipsisText: string | undefined;\n  cssEllipsis: boolean = false;\n  isEllipsis: boolean = true;\n  expanded: boolean = false;\n  ellipsisStr = '...';\n  dir: Direction = 'ltr';\n\n  get hasEllipsisObservers(): boolean {\n    return this.nzOnEllipsis.observers.length > 0;\n  }\n\n  get canCssEllipsis(): boolean {\n    return this.nzEllipsis && this.cssEllipsis && !this.expanded && !this.hasEllipsisObservers;\n  }\n\n  get hasOperationsWithEllipsis(): boolean {\n    return (this.nzCopyable || this.nzEditable || this.nzExpandable) && this.nzEllipsis;\n  }\n\n  private viewInit = false;\n  private requestId: number = -1;\n  private windowResizeSubscription = Subscription.EMPTY;\n\n  get copyText(): string {\n    return (typeof this.nzCopyText === 'string' ? this.nzCopyText : this.nzContent)!;\n  }\n\n  constructor() {\n    this.destroyRef.onDestroy(() => {\n      this.expandableBtnElementCache = null;\n      this.windowResizeSubscription.unsubscribe();\n    });\n  }\n\n  onTextCopy(text: string): void {\n    this.nzCopy.emit(text);\n  }\n\n  onStartEditing(): void {\n    this.editing = true;\n  }\n\n  onEndEditing(text: string): void {\n    this.editing = false;\n    this.nzContentChange.emit(text);\n    if (this.nzContent === text) {\n      this.renderOnNextFrame();\n    }\n    this.cdr.markForCheck();\n  }\n\n  onExpand(): void {\n    this.isEllipsis = false;\n    this.expanded = true;\n    this.nzExpandChange.emit();\n    this.nzOnEllipsis.emit(false);\n  }\n\n  canUseCSSEllipsis(): boolean {\n    if (this.nzEditable || this.nzCopyable || this.nzExpandable || this.nzSuffix) {\n      return false;\n    }\n    // make sure {@link nzOnEllipsis} works, will force use JS to calculations\n    if (this.hasEllipsisObservers) {\n      return false;\n    }\n    if (this.nzEllipsisRows === 1) {\n      return isStyleSupport('textOverflow');\n    } else {\n      return isStyleSupport('webkitLineClamp');\n    }\n  }\n\n  renderOnNextFrame(): void {\n    cancelAnimationFrame(this.requestId);\n    if (!this.viewInit || !this.nzEllipsis || this.nzEllipsisRows < 0 || this.expanded || !this.platform.isBrowser) {\n      return;\n    }\n    this.requestId = requestAnimationFrame(() => this.syncEllipsis());\n  }\n\n  getOriginContentViewRef(): { viewRef: EmbeddedViewRef<{ content: string }>; removeView(): void } {\n    const viewRef = this.viewContainerRef.createEmbeddedView<{ content: string }>(this.contentTemplate!, {\n      content: this.nzContent!\n    });\n    viewRef.detectChanges();\n    return {\n      viewRef,\n      removeView: () => this.viewContainerRef.remove(this.viewContainerRef.indexOf(viewRef))\n    };\n  }\n\n  syncEllipsis(): void {\n    if (this.cssEllipsis) {\n      return;\n    }\n    const { viewRef, removeView } = this.getOriginContentViewRef();\n    const fixedNodes = [this.textCopyRef, this.textEditRef]\n      .filter(e => e && e.nativeElement)\n      .map(e => e!.nativeElement);\n    const expandableBtnElement = this.getExpandableBtnElement();\n    if (expandableBtnElement) {\n      fixedNodes.push(expandableBtnElement);\n    }\n    const { contentNodes, text, ellipsis } = measure(\n      this.el,\n      this.nzEllipsisRows,\n      viewRef.rootNodes,\n      fixedNodes,\n      this.ellipsisStr,\n      this.nzSuffix\n    );\n\n    removeView();\n\n    this.ellipsisText = text;\n    if (ellipsis !== this.isEllipsis) {\n      this.isEllipsis = ellipsis;\n      this.nzOnEllipsis.emit(ellipsis);\n    }\n    const ellipsisContainerNativeElement = this.ellipsisContainer!.nativeElement;\n    while (ellipsisContainerNativeElement.firstChild) {\n      this.renderer.removeChild(ellipsisContainerNativeElement, ellipsisContainerNativeElement.firstChild);\n    }\n    contentNodes.forEach(n => {\n      this.renderer.appendChild(ellipsisContainerNativeElement, n.cloneNode(true));\n    });\n    this.cdr.markForCheck();\n  }\n\n  // Need to create the element for calculation size before view init\n  private getExpandableBtnElement(): HTMLElement | null {\n    if (this.nzExpandable) {\n      const expandText = this.locale ? this.locale.expand : '';\n      const cache = this.expandableBtnElementCache;\n      if (!cache || cache.innerText === expandText) {\n        const el = this.document.createElement('a');\n        el.className = EXPAND_ELEMENT_CLASSNAME;\n        el.innerText = expandText;\n        this.expandableBtnElementCache = el;\n      }\n      return this.expandableBtnElementCache;\n    } else {\n      this.expandableBtnElementCache = null;\n      return null;\n    }\n  }\n\n  private renderAndSubscribeWindowResize(): void {\n    if (this.platform.isBrowser) {\n      this.windowResizeSubscription.unsubscribe();\n      this.cssEllipsis = this.canUseCSSEllipsis();\n      this.renderOnNextFrame();\n      this.windowResizeSubscription = this.resizeService\n        .connect()\n        .pipe(takeUntilDestroyed(this.destroyRef))\n        .subscribe(() => this.renderOnNextFrame());\n    }\n  }\n\n  ngOnInit(): void {\n    this.i18n.localeChange.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      this.locale = this.i18n.getLocaleData('Text');\n      this.cdr.markForCheck();\n    });\n\n    this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {\n      this.dir = direction;\n      this.cdr.detectChanges();\n    });\n\n    this.dir = this.directionality.value;\n  }\n\n  ngAfterViewInit(): void {\n    this.viewInit = true;\n    this.renderAndSubscribeWindowResize();\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzCopyable, nzEditable, nzExpandable, nzEllipsis, nzContent, nzEllipsisRows, nzSuffix } = changes;\n    if (nzCopyable || nzEditable || nzExpandable || nzEllipsis || nzContent || nzEllipsisRows || nzSuffix) {\n      if (this.nzEllipsis) {\n        if (this.expanded) {\n          this.windowResizeSubscription.unsubscribe();\n        } else {\n          this.renderAndSubscribeWindowResize();\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/typography/typography.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzTextCopyComponent } from './text-copy.component';\nimport { NzTextEditComponent } from './text-edit.component';\nimport { NzTypographyComponent } from './typography.component';\n\n@NgModule({\n  imports: [NzTypographyComponent, NzTextCopyComponent, NzTextEditComponent],\n  exports: [NzTypographyComponent, NzTextCopyComponent, NzTextEditComponent]\n})\nexport class NzTypographyModule {}\n"
  },
  {
    "path": "components/typography/typography.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { CAPS_LOCK, ENTER, ESCAPE, TAB } from '@angular/cdk/keycodes';\nimport { OverlayContainer } from '@angular/cdk/overlay';\nimport { ApplicationRef, Component, NgZone, provideZoneChangeDetection, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, flush, inject, TestBed, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { provideNoopAnimations } from '@angular/platform-browser/animations';\n\nimport {\n  createKeyboardEvent,\n  dispatchFakeEvent,\n  dispatchKeyboardEvent,\n  dispatchMouseEvent,\n  MockNgZone,\n  typeInElement\n} from 'ng-zorro-antd/core/testing';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzTextEditComponent } from '.';\nimport { NzTypographyComponent } from './typography.component';\nimport { NzTypographyModule } from './typography.module';\n\ndeclare const viewport: NzSafeAny;\n\ndescribe('typography', () => {\n  let componentElement: HTMLElement;\n  let overlayContainer: OverlayContainer;\n  let overlayContainerElement: HTMLElement;\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [\n        // todo: use zoneless\n        provideZoneChangeDetection(),\n        provideNzIconsTesting(),\n        provideNoopAnimations(),\n        { provide: NgZone, useFactory: () => new MockNgZone() }\n      ]\n    });\n  });\n\n  beforeEach(inject([OverlayContainer], (oc: OverlayContainer) => {\n    overlayContainer = oc;\n    overlayContainerElement = oc.getContainerElement();\n  }));\n\n  afterEach(() => {\n    overlayContainer.ngOnDestroy();\n  });\n\n  function testCopyButton(\n    fixture: ComponentFixture<NzSafeAny>,\n    copyButton: HTMLButtonElement,\n    onHover: () => void,\n    onClick: () => void\n  ): void {\n    fixture.detectChanges();\n\n    dispatchMouseEvent(copyButton, 'mouseenter');\n    fixture.detectChanges();\n    tick(1000);\n    fixture.detectChanges();\n\n    onHover();\n\n    copyButton.click();\n    fixture.detectChanges();\n\n    onClick();\n\n    dispatchMouseEvent(copyButton, 'mouseleave');\n    fixture.detectChanges();\n    tick(3000);\n    fixture.detectChanges();\n  }\n\n  describe('base', () => {\n    let fixture: ComponentFixture<NzTestTypographyComponent>;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTypographyComponent);\n      componentElement = fixture.debugElement.nativeElement;\n      fixture.detectChanges();\n    });\n\n    it('should selector work', () => {\n      const elements = componentElement.querySelectorAll('[nz-typography]');\n      elements.forEach(el => {\n        expect(el.classList).toContain('ant-typography');\n      });\n    });\n\n    it('should [nzType] work', () => {\n      expect(componentElement.querySelector('.test-secondary')!.classList).toContain('ant-typography-secondary');\n      expect(componentElement.querySelector('.test-warning')!.classList).toContain('ant-typography-warning');\n      expect(componentElement.querySelector('.test-danger')!.classList).toContain('ant-typography-danger');\n      expect(componentElement.querySelector('.test-success')!.classList).toContain('ant-typography-success');\n    });\n\n    it('should [nzDisabled] work', () => {\n      expect(componentElement.querySelector('.test-disabled')!.classList).toContain('ant-typography-disabled');\n    });\n  });\n\n  describe('copyable', () => {\n    let fixture: ComponentFixture<NzTestTypographyCopyComponent>;\n    let testComponent: NzTestTypographyCopyComponent;\n\n    beforeEach(() => {\n      fixture = TestBed.createComponent(NzTestTypographyCopyComponent);\n      testComponent = fixture.componentInstance;\n      componentElement = fixture.debugElement.nativeElement;\n      fixture.detectChanges();\n    });\n\n    it('should copyable', () => {\n      spyOn(testComponent, 'onCopy');\n      const copyButtons = componentElement.querySelectorAll<HTMLButtonElement>('.ant-typography-copy');\n      expect(copyButtons.length).toBe(5);\n      copyButtons.forEach((btn, i) => {\n        btn.click();\n        fixture.detectChanges();\n        expect(testComponent.onCopy).toHaveBeenCalledWith(`Ant Design-${i}`);\n      });\n    });\n\n    it('should be set tooltips', fakeAsync(() => {\n      const copyButton = componentElement.querySelector<HTMLButtonElement>('.custom-tooltips .ant-typography-copy')!;\n      testCopyButton(\n        fixture,\n        copyButton,\n        () => {\n          expect(overlayContainerElement.textContent).toContain(testComponent.tooltips![0]);\n        },\n        () => {\n          expect(overlayContainerElement.textContent).toContain(testComponent.tooltips![1]);\n        }\n      );\n    }));\n\n    it('should be hied all tooltips', fakeAsync(() => {\n      const copyButton = componentElement.querySelector<HTMLButtonElement>('.custom-tooltips .ant-typography-copy')!;\n      testComponent.tooltips = null;\n      fixture.detectChanges();\n\n      testCopyButton(\n        fixture,\n        copyButton,\n        () => {\n          expect(overlayContainerElement.textContent).toBeFalsy();\n        },\n        () => {\n          expect(overlayContainerElement.textContent).toBeFalsy();\n        }\n      );\n    }));\n\n    it('should be set icons', fakeAsync(() => {\n      const copyButton = componentElement.querySelector<HTMLButtonElement>('.custom-icons .ant-typography-copy')!;\n      const icon = copyButton.querySelector('.anticon')!;\n\n      // init\n      expect(icon.className).toContain('meh');\n\n      testCopyButton(\n        fixture,\n        copyButton,\n        () => {\n          // hover\n          expect(icon.className).toContain('meh');\n        },\n        () => {\n          // clicked\n          expect(icon.className).toContain('smile');\n        }\n      );\n\n      // done\n      expect(icon.className).toContain('meh');\n    }));\n\n    it('should only trigger once within 3000ms', fakeAsync(() => {\n      spyOn(testComponent, 'onCopy');\n      const copyButton = componentElement.querySelector<HTMLButtonElement>('.ant-typography-copy');\n      expect(testComponent.onCopy).toHaveBeenCalledTimes(0);\n      copyButton!.click();\n      fixture.detectChanges();\n      copyButton!.click();\n      fixture.detectChanges();\n      expect(testComponent.onCopy).toHaveBeenCalledTimes(1);\n      tick(3000);\n      fixture.detectChanges();\n      copyButton!.click();\n      fixture.detectChanges();\n      expect(testComponent.onCopy).toHaveBeenCalledTimes(2);\n      flush();\n      fixture.detectChanges();\n    }));\n  });\n\n  describe('editable', () => {\n    let fixture: ComponentFixture<NzTestTypographyEditComponent>;\n    let testComponent: NzTestTypographyEditComponent;\n\n    beforeEach(fakeAsync(() => {\n      fixture = TestBed.createComponent(NzTestTypographyEditComponent);\n      testComponent = fixture.componentInstance;\n      componentElement = fixture.debugElement.nativeElement;\n      fixture.detectChanges();\n    }));\n\n    afterEach(fakeAsync(() => {\n      flush();\n      fixture.detectChanges();\n    }));\n\n    it('should discard changes when Esc keydown', () => {\n      const editButton = componentElement.querySelector<HTMLButtonElement>('.ant-typography-edit');\n      editButton!.click();\n      fixture.detectChanges();\n      expect(testComponent.str).toBe('This is an editable text.');\n      const textarea = componentElement.querySelector<HTMLTextAreaElement>('textarea')!;\n      typeInElement('test', textarea);\n      fixture.detectChanges();\n      testComponent.nzTypographyComponent.textEditRef!.onCancel();\n      fixture.detectChanges();\n      expect(testComponent.str).toBe('This is an editable text.');\n    });\n\n    it('should be set icon', fakeAsync(() => {\n      const icon = componentElement.querySelector<HTMLElement>('.anticon')!;\n      expect(icon.className).toContain('edit');\n\n      testComponent.icon = 'smile';\n      fixture.detectChanges();\n\n      expect(icon.className).toContain('smile');\n    }));\n\n    it('should be set tooltip', fakeAsync(() => {\n      testComponent.tooltip = 'click to copy.';\n      const editButton = componentElement.querySelector<HTMLButtonElement>('.ant-typography-edit')!;\n\n      fixture.detectChanges();\n\n      dispatchMouseEvent(editButton, 'mouseenter');\n      fixture.detectChanges();\n      tick(1000);\n      fixture.detectChanges();\n\n      expect(overlayContainerElement.textContent).toContain(testComponent.tooltip);\n\n      dispatchMouseEvent(editButton, 'mouseleave');\n      fixture.detectChanges();\n      tick(3000);\n      fixture.detectChanges();\n    }));\n\n    it('should edit work', fakeAsync(() => {\n      const editButton = componentElement.querySelector<HTMLButtonElement>('.ant-typography-edit');\n      editButton!.click();\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n\n      expect(testComponent.str).toBe('This is an editable text.');\n      const textarea = componentElement.querySelector<HTMLTextAreaElement>('textarea')!;\n      typeInElement('test', textarea);\n      fixture.detectChanges();\n      dispatchFakeEvent(textarea, 'blur');\n\n      fixture.detectChanges();\n      flush();\n      fixture.detectChanges();\n\n      expect(testComponent.str).toBe('test');\n    }));\n\n    it('should edit focus', () => {\n      const editButton = componentElement.querySelector<HTMLButtonElement>('.ant-typography-edit');\n      editButton!.click();\n      fixture.detectChanges();\n\n      // `tick()` will handle over after next render hooks.\n      TestBed.inject(ApplicationRef).tick();\n\n      const textarea = componentElement.querySelector<HTMLTextAreaElement>('textarea')! as HTMLTextAreaElement;\n\n      expect(document.activeElement === textarea).toBe(true);\n    });\n\n    it('should apply changes when Enter keydown', fakeAsync(() => {\n      const editButton = componentElement.querySelector<HTMLButtonElement>('.ant-typography-edit');\n      editButton!.click();\n      fixture.detectChanges();\n      const textarea = componentElement.querySelector<HTMLTextAreaElement>('textarea')!;\n      typeInElement('test', textarea);\n      fixture.detectChanges();\n      const event = createKeyboardEvent('keydown', ENTER, textarea);\n      testComponent.nzTypographyComponent.textEditRef!.onEnter(event);\n\n      flush();\n      fixture.detectChanges();\n\n      expect(testComponent.str).toBe('test');\n    }));\n  });\n\n  describe('ellipsis', () => {\n    let fixture: ComponentFixture<NzTestTypographyEllipsisComponent>;\n    let testComponent: NzTestTypographyEllipsisComponent;\n\n    beforeEach(fakeAsync(() => {\n      viewport.set(1200, 1000);\n      fixture = TestBed.createComponent(NzTestTypographyEllipsisComponent);\n      testComponent = fixture.componentInstance;\n      componentElement = fixture.debugElement.nativeElement;\n      fixture.detectChanges();\n      tick(16);\n      fixture.detectChanges();\n    }));\n\n    it('should ellipsis work', fakeAsync(() => {\n      componentElement.querySelectorAll('p').forEach(e => {\n        expect(e.classList).toContain('ant-typography-ellipsis');\n      });\n    }));\n\n    it('should css ellipsis', fakeAsync(() => {\n      const singleLine = componentElement.querySelector('.single')!;\n      const multipleLine = componentElement.querySelector('.multiple')!;\n      const dynamicContent = componentElement.querySelector('.dynamic')!;\n      expect(singleLine.classList).toContain('ant-typography-ellipsis-single-line');\n      expect(multipleLine.classList).toContain('ant-typography-ellipsis-multiple-line');\n      testComponent.expandable = true;\n      fixture.detectChanges();\n      expect(singleLine.classList).not.toContain('ant-typography-ellipsis-single-line');\n      expect(multipleLine.classList).not.toContain('ant-typography-ellipsis-multiple-line');\n      expect(dynamicContent.classList).not.toContain('ant-typography-ellipsis-multiple-line');\n    }));\n\n    it('should resize when content changed', fakeAsync(() => {\n      testComponent.expandable = true;\n      fixture.detectChanges();\n      tick(16);\n      fixture.detectChanges();\n      const dynamicContent = componentElement.querySelector('.dynamic')! as HTMLParagraphElement;\n      expect(dynamicContent.innerText.includes('...')).toBe(true);\n      testComponent.str = 'short content.';\n      fixture.detectChanges();\n      tick(16);\n      fixture.detectChanges();\n      expect(dynamicContent.innerText.includes('...')).toBe(false);\n    }));\n\n    it('should expandable', fakeAsync(() => {\n      testComponent.expandable = true;\n      viewport.set(400, 1000);\n      dispatchFakeEvent(window, 'resize');\n      fixture.detectChanges();\n      tick(16);\n      fixture.detectChanges();\n      tick(16);\n      componentElement.querySelectorAll('p').forEach((e, i) => {\n        expect(e.classList).toContain('ant-typography-ellipsis');\n        const expandBtn = e.querySelector('.ant-typography-expand') as HTMLAnchorElement;\n        expect(expandBtn).toBeTruthy();\n        expandBtn!.click();\n        fixture.detectChanges();\n        expect(e.classList).not.toContain('ant-typography-ellipsis');\n        expect(testComponent.onExpand).toHaveBeenCalledTimes(i + 1);\n      });\n    }));\n\n    it('should not resize when is expanded', fakeAsync(() => {\n      testComponent.expandable = true;\n      viewport.set(400, 1000);\n      dispatchFakeEvent(window, 'resize');\n      fixture.detectChanges();\n      tick(16);\n      fixture.detectChanges();\n      tick(16);\n      componentElement.querySelectorAll('p').forEach(e => {\n        const expandBtn = e.querySelector('.ant-typography-expand') as HTMLAnchorElement;\n        expandBtn!.click();\n        fixture.detectChanges();\n      });\n      testComponent.expandable = false;\n      fixture.detectChanges();\n      tick(16);\n      viewport.set(800, 1000);\n      dispatchFakeEvent(window, 'resize');\n      fixture.detectChanges();\n      tick(32);\n      fixture.detectChanges();\n      componentElement.querySelectorAll('p').forEach(e => {\n        expect(e.innerText.includes('...')).toBe(false);\n      });\n      viewport.reset();\n    }));\n\n    it('should resize work', fakeAsync(() => {\n      testComponent.expandable = true;\n      viewport.set(400, 1000);\n      dispatchFakeEvent(window, 'resize');\n      fixture.detectChanges();\n      tick(16);\n      fixture.detectChanges();\n      tick(16);\n      componentElement.querySelectorAll('p').forEach(e => {\n        expect(e.innerText.includes('...')).toBe(true);\n      });\n      viewport.set(8000, 1000);\n      dispatchFakeEvent(window, 'resize');\n      fixture.detectChanges();\n      tick(32);\n      fixture.detectChanges();\n      componentElement.querySelectorAll('p').forEach(e => {\n        expect(e.innerText.includes('...')).toBe(false);\n      });\n      expect(testComponent.onEllipsis).toHaveBeenCalledWith(false);\n      viewport.set(400, 1000);\n      dispatchFakeEvent(window, 'resize');\n      fixture.detectChanges();\n      tick(32);\n      fixture.detectChanges();\n      viewport.set(800, 1000);\n      dispatchFakeEvent(window, 'resize');\n      fixture.detectChanges();\n      tick(32);\n      fixture.detectChanges();\n      componentElement.querySelectorAll('p').forEach(e => {\n        expect(e.innerText.includes('...')).toBe(true);\n      });\n      expect(testComponent.onEllipsis).toHaveBeenCalledWith(true);\n      viewport.reset();\n    }));\n\n    it('should suffix work', fakeAsync(() => {\n      testComponent.expandable = true;\n      testComponent.suffix = 'The suffix.';\n\n      {\n        viewport.set(8000, 1000);\n        dispatchFakeEvent(window, 'resize');\n        fixture.detectChanges();\n        tick(32);\n        fixture.detectChanges();\n        const el = componentElement.querySelector('.dynamic') as HTMLParagraphElement;\n        expect(el.innerText.endsWith('The suffix.')).toBe(true);\n        expect(el.innerText.includes('...')).toBe(false);\n      }\n\n      {\n        viewport.set(800, 1000);\n        dispatchFakeEvent(window, 'resize');\n        fixture.detectChanges();\n        tick(32);\n        fixture.detectChanges();\n        const el = componentElement.querySelector('.dynamic') as HTMLParagraphElement;\n        expect(el.innerText.includes('The suffix.')).toBe(true);\n        expect(el.innerText.includes('...')).toBe(true);\n        testComponent.expandable = false;\n        fixture.detectChanges();\n        tick(32);\n        fixture.detectChanges();\n        expect(el.innerText.endsWith('The suffix.')).toBe(true);\n        expect(el.innerText.includes('...')).toBe(true);\n      }\n\n      viewport.reset();\n      dispatchFakeEvent(window, 'resize');\n      fixture.detectChanges();\n      tick(32);\n      fixture.detectChanges();\n    }));\n  });\n});\n\n// Caretaker note: this is moved to a separate `describe` block because the first `describe` block\n// mocks the `NgZone` with `MockNgZone`.\ndescribe('change detection behavior', () => {\n  let componentElement: HTMLElement;\n  let fixture: ComponentFixture<NzTestTypographyEditComponent>;\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      providers: [provideNzIconsTesting(), provideNoopAnimations()]\n    });\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzTestTypographyEditComponent);\n    componentElement = fixture.debugElement.nativeElement;\n    fixture.detectChanges();\n  });\n\n  it('should not run change detection on `input` event', () => {\n    componentElement.querySelector<HTMLButtonElement>('.ant-typography-edit')!.click();\n    fixture.detectChanges();\n\n    const appRef = TestBed.inject(ApplicationRef);\n    spyOn(appRef, 'tick');\n\n    const nzTextEdit = fixture.debugElement.query(By.directive(NzTextEditComponent));\n    const textarea: HTMLTextAreaElement = nzTextEdit.nativeElement.querySelector('textarea');\n\n    textarea.value = 'some-value';\n    dispatchFakeEvent(textarea, 'input');\n\n    expect(appRef.tick).not.toHaveBeenCalled();\n    expect(nzTextEdit.componentInstance.currentText).toEqual('some-value');\n  });\n\n  it('should not run change detection on non-handled keydown events', () => {\n    componentElement.querySelector<HTMLButtonElement>('.ant-typography-edit')!.click();\n    fixture.detectChanges();\n    const nzTextEdit = fixture.debugElement.query(By.directive(NzTextEditComponent));\n    const textarea: HTMLTextAreaElement = nzTextEdit.nativeElement.querySelector('textarea');\n    const spyCancel = spyOn(nzTextEdit.componentInstance, 'onCancel');\n    const spyEnter = spyOn(nzTextEdit.componentInstance, 'onEnter');\n\n    dispatchKeyboardEvent(textarea, 'keydown', TAB);\n    dispatchKeyboardEvent(textarea, 'keydown', CAPS_LOCK);\n\n    expect(spyCancel).not.toHaveBeenCalled();\n    expect(spyEnter).not.toHaveBeenCalled();\n\n    dispatchKeyboardEvent(textarea, 'keydown', ESCAPE);\n    expect(spyCancel).toHaveBeenCalled();\n    expect(spyEnter).not.toHaveBeenCalled();\n\n    spyCancel.calls.reset();\n\n    dispatchKeyboardEvent(textarea, 'keydown', ENTER);\n    expect(spyCancel).not.toHaveBeenCalled();\n    expect(spyEnter).toHaveBeenCalled();\n  });\n});\n\n@Component({\n  imports: [NzTypographyModule],\n  template: `\n    <h1 nz-typography>h1. Ant Design</h1>\n    <h2 nz-typography>h2. Ant Design</h2>\n    <h3 nz-typography>h3. Ant Design</h3>\n    <h4 nz-typography>h4. Ant Design</h4>\n    <h5 nz-typography>h5. Ant Design</h5>\n    <p nz-typography>Ant Design, a design language for background applications, is refined by Ant UED Team</p>\n    <span nz-typography>Ant Design</span>\n    <span class=\"test-secondary\" nz-typography nzType=\"secondary\">Ant Design</span>\n    <span class=\"test-success\" nz-typography nzType=\"success\">Ant Design</span>\n    <span class=\"test-warning\" nz-typography nzType=\"warning\">Ant Design</span>\n    <span class=\"test-danger\" nz-typography nzType=\"danger\">Ant Design</span>\n    <span class=\"test-disabled\" nz-typography nzDisabled>Ant Design</span>\n    <span nz-typography><mark>Ant Design</mark></span>\n    <span nz-typography><code>Ant Design</code></span>\n    <span nz-typography><u>Ant Design</u></span>\n    <span nz-typography><del>Ant Design</del></span>\n    <span nz-typography><strong>Ant Design</strong></span>\n  `\n})\nexport class NzTestTypographyComponent {}\n\n@Component({\n  imports: [NzTypographyModule],\n  template: `\n    <h4 nz-title nzCopyable class=\"test-copy-h4\" nzContent=\"Ant Design-0\" (nzCopy)=\"onCopy($event)\"></h4>\n    <p nz-paragraph nzCopyable class=\"test-copy-p\" nzContent=\"Ant Design-1\" (nzCopy)=\"onCopy($event)\"></p>\n    <span nz-text nzCopyable class=\"test-copy-text\" nzContent=\"Ant Design-2\" (nzCopy)=\"onCopy($event)\"></span>\n    <span nz-text nzCopyable nzCopyText=\"Ant Design-3\" class=\"test-copy-replace\" (nzCopy)=\"onCopy($event)\">Test</span>\n    <p\n      nz-typography\n      class=\"custom-icons custom-tooltips\"\n      nzCopyable\n      nzContent=\"Ant Design-4\"\n      (nzCopy)=\"onCopy($event)\"\n      [nzCopyTooltips]=\"tooltips\"\n      [nzCopyIcons]=\"icons\"\n    ></p>\n  `\n})\nexport class NzTestTypographyCopyComponent {\n  tooltips: [string, string] | null = ['click here', 'coped'];\n  icons: [string, string] = ['meh', 'smile'];\n  onCopy(_text: string): void {}\n}\n\n@Component({\n  imports: [NzTypographyModule],\n  template: `\n    <p\n      nz-paragraph\n      nzEditable\n      [nzEditIcon]=\"icon\"\n      [nzEditTooltip]=\"tooltip\"\n      (nzContentChange)=\"onChange($event)\"\n      [nzContent]=\"str\"\n    ></p>\n  `\n})\nexport class NzTestTypographyEditComponent {\n  @ViewChild(NzTypographyComponent, { static: false }) nzTypographyComponent!: NzTypographyComponent;\n  str = 'This is an editable text.';\n  icon = 'edit';\n  tooltip?: string | null;\n\n  onChange = (text: string): void => {\n    this.str = text;\n  };\n}\n\n@Component({\n  imports: [NzTypographyModule],\n  template: `\n    <p nz-paragraph nzEllipsis [nzExpandable]=\"expandable\" (nzExpandChange)=\"onExpand()\" class=\"single\">\n      Ant Design, a design language for background applications, is refined by Ant UED Team. Ant Design, a design\n      language for background applications, is refined by Ant UED Team. Ant Design, a design language for background\n      applications, is refined by Ant UED Team. Ant Design, a design language for background applications, is refined by\n      Ant UED Team. Ant Design, a design language for background applications, is refined by Ant UED Team. Ant Design, a\n      design language for background applications, is refined by Ant UED Team.\n    </p>\n    <br />\n    <p\n      nz-paragraph\n      nzEllipsis\n      [nzExpandable]=\"expandable\"\n      [nzEllipsisRows]=\"3\"\n      (nzExpandChange)=\"onExpand()\"\n      class=\"multiple\"\n    >\n      Ant Design, a design language for background applications, is refined by Ant UED Team. Ant Design, a design\n      language for background applications, is refined by Ant UED Team. Ant Design, a design language for background\n      applications, is refined by Ant UED Team. Ant Design, a design language for background applications, is refined by\n      Ant UED Team. Ant Design, a design language for background applications, is refined by Ant UED Team. Ant Design, a\n      design language for background applications, is refined by Ant UED Team.\n    </p>\n    <p\n      nz-paragraph\n      nzEllipsis\n      [nzExpandable]=\"expandable\"\n      [nzEllipsisRows]=\"2\"\n      (nzExpandChange)=\"onExpand()\"\n      (nzOnEllipsis)=\"onEllipsis($event)\"\n      [nzContent]=\"str\"\n      [nzSuffix]=\"suffix\"\n      class=\"dynamic\"\n    ></p>\n  `\n})\nexport class NzTestTypographyEllipsisComponent {\n  expandable = false;\n  onExpand = jasmine.createSpy('expand callback');\n  suffix?: string;\n  onEllipsis = jasmine.createSpy('ellipsis callback');\n  @ViewChild(NzTypographyComponent, { static: false }) nzTypographyComponent!: NzTypographyComponent;\n  str = new Array(5)\n    .fill('Ant Design, a design language for background applications, is refined by Ant UED Team.')\n    .join('');\n}\n"
  },
  {
    "path": "components/upload/demo/avatar.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 用户头像\n  en-US: Avatar\n---\n\n## zh-CN\n\n点击上传用户头像，并使用 `nzBeforeUpload` 限制用户上传的图片格式和大小。\n\n> `nzBeforeUpload` 的返回值可以是一个 Observable 以支持也支持异步检查。\n\n## en-US\n\nClick to upload user's avatar, and validate size and format of picture with `nzBeforeUpload`.\n\n> The return value of function `nzBeforeUpload` can be a Observable to check asynchronously.\n"
  },
  {
    "path": "components/upload/demo/avatar.ts",
    "content": "import { Component } from '@angular/core';\nimport { Observable, Observer } from 'rxjs';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzMessageService } from 'ng-zorro-antd/message';\nimport { NzUploadFile, NzUploadModule } from 'ng-zorro-antd/upload';\n\n@Component({\n  selector: 'nz-demo-upload-avatar',\n  imports: [NzIconModule, NzUploadModule],\n  template: `\n    <nz-upload\n      class=\"avatar-uploader\"\n      nzAction=\"https://www.mocky.io/v2/5cc8019d300000980a055e76\"\n      nzName=\"avatar\"\n      nzListType=\"picture-card\"\n      [nzShowUploadList]=\"false\"\n      [nzBeforeUpload]=\"beforeUpload\"\n      (nzChange)=\"handleChange($event)\"\n    >\n      @if (!avatarUrl) {\n        <nz-icon class=\"upload-icon\" [nzType]=\"loading ? 'loading' : 'plus'\" />\n        <div class=\"ant-upload-text\">Upload</div>\n      } @else {\n        <img [src]=\"avatarUrl\" style=\"width: 100%\" />\n      }\n    </nz-upload>\n  `,\n  styles: `\n    :host ::ng-deep .avatar-uploader > .ant-upload {\n      width: 128px;\n      height: 128px;\n    }\n  `\n})\nexport class NzDemoUploadAvatarComponent {\n  loading = false;\n  avatarUrl?: string;\n\n  constructor(private messageService: NzMessageService) {}\n\n  beforeUpload = (file: NzUploadFile, _fileList: NzUploadFile[]): Observable<boolean> =>\n    new Observable((observer: Observer<boolean>) => {\n      const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';\n      if (!isJpgOrPng) {\n        this.messageService.error('You can only upload JPG file!');\n        observer.complete();\n        return;\n      }\n      const isLt2M = file.size! / 1024 / 1024 < 2;\n      if (!isLt2M) {\n        this.messageService.error('Image must smaller than 2MB!');\n        observer.complete();\n        return;\n      }\n      observer.next(isJpgOrPng && isLt2M);\n      observer.complete();\n    });\n\n  private getBase64(img: File, callback: (img: string) => void): void {\n    const reader = new FileReader();\n    reader.addEventListener('load', () => callback(reader.result!.toString()));\n    reader.readAsDataURL(img);\n  }\n\n  handleChange(info: { file: NzUploadFile }): void {\n    switch (info.file.status) {\n      case 'uploading':\n        this.loading = true;\n        break;\n      case 'done':\n        // Get this url from response in real world.\n        this.getBase64(info.file!.originFileObj!, (img: string) => {\n          this.loading = false;\n          this.avatarUrl = img;\n        });\n        break;\n      case 'error':\n        this.messageService.error('Network error');\n        this.loading = false;\n        break;\n    }\n  }\n}\n"
  },
  {
    "path": "components/upload/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 点击上传\n  en-US: Upload by clicking\n---\n\n## zh-CN\n\n经典款式，用户点击按钮弹出文件选择框。\n\n## en-US\n\nClassic mode. File selection dialog pops up when upload button is clicked.\n"
  },
  {
    "path": "components/upload/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzMessageService } from 'ng-zorro-antd/message';\nimport { NzUploadChangeParam, NzUploadModule } from 'ng-zorro-antd/upload';\n\n@Component({\n  selector: 'nz-demo-upload-basic',\n  imports: [NzButtonModule, NzIconModule, NzUploadModule],\n  template: `\n    <nz-upload\n      nzAction=\"https://www.mocky.io/v2/5cc8019d300000980a055e76\"\n      [nzHeaders]=\"{ authorization: 'authorization-text' }\"\n      (nzChange)=\"handleChange($event)\"\n    >\n      <button nz-button>\n        <nz-icon nzType=\"upload\" />\n        Click to Upload\n      </button>\n    </nz-upload>\n  `\n})\nexport class NzDemoUploadBasicComponent {\n  constructor(private messageService: NzMessageService) {}\n\n  handleChange(info: NzUploadChangeParam): void {\n    if (info.file.status !== 'uploading') {\n      console.log(info.file, info.fileList);\n    }\n    if (info.file.status === 'done') {\n      this.messageService.success(`${info.file.name} file uploaded successfully`);\n    } else if (info.file.status === 'error') {\n      this.messageService.error(`${info.file.name} file upload failed.`);\n    }\n  }\n}\n"
  },
  {
    "path": "components/upload/demo/default-file-list.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 已上传的文件列表\n  en-US: Default Files\n---\n\n## zh-CN\n\n使用 `nzFileList` 设置已上传的内容。\n\n## en-US\n\nUse `nzFileList` for uploaded files when page init.\n"
  },
  {
    "path": "components/upload/demo/default-file-list.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzUploadFile, NzUploadModule } from 'ng-zorro-antd/upload';\n\n@Component({\n  selector: 'nz-demo-upload-default-file-list',\n  imports: [NzButtonModule, NzIconModule, NzUploadModule],\n  template: `\n    <nz-upload nzAction=\"https://www.mocky.io/v2/5cc8019d300000980a055e76\" [nzFileList]=\"fileList\">\n      <button nz-button>\n        <nz-icon nzType=\"upload\" />\n        Upload\n      </button>\n    </nz-upload>\n  `\n})\nexport class NzDemoUploadDefaultFileListComponent {\n  fileList: NzUploadFile[] = [\n    {\n      uid: '1',\n      name: 'xxx.png',\n      status: 'done',\n      response: 'Server Error 500', // custom error message to show\n      url: 'http://www.baidu.com/xxx.png'\n    },\n    {\n      uid: '2',\n      name: 'yyy.png',\n      status: 'done',\n      url: 'http://www.baidu.com/yyy.png'\n    },\n    {\n      uid: '3',\n      name: 'zzz.png',\n      status: 'error',\n      response: 'Server Error 500', // custom error message to show\n      url: 'http://www.baidu.com/zzz.png'\n    }\n  ];\n}\n"
  },
  {
    "path": "components/upload/demo/directory.md",
    "content": "---\norder: 6\ntitle:\n  zh-CN: 文件夹上传\n  en-US: Upload directory\n---\n\n## zh-CN\n\n支持上传一个文件夹里的所有文件。\n\n## en-US\n\nYou can select and upload a whole directory.\n"
  },
  {
    "path": "components/upload/demo/directory.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzUploadModule } from 'ng-zorro-antd/upload';\n\n@Component({\n  selector: 'nz-demo-upload-directory',\n  imports: [NzButtonModule, NzIconModule, NzUploadModule],\n  template: `\n    <nz-upload nzAction=\"https://www.mocky.io/v2/5cc8019d300000980a055e76\" nzDirectory>\n      <button nz-button>\n        <nz-icon nzType=\"upload\" />\n        Upload Directory\n      </button>\n    </nz-upload>\n  `\n})\nexport class NzDemoUploadDirectoryComponent {}\n"
  },
  {
    "path": "components/upload/demo/drag.md",
    "content": "---\norder: 5\ntitle:\n  zh-CN: 拖拽上传\n  en-US: Drag and Drop\n---\n\n## zh-CN\n\n把文件拖入指定区域，完成上传，同样支持点击上传。\n\n设置 `nzMultiple` 后，在 `IE10+` 可以一次上传多个文件。\n\n## en-US\n\nYou can drag files to a specific area, to upload. Alternatively, you can also upload by selecting.\n\nWe can upload serveral files at once in modern browsers by giving the input the `nzMultiple` attribute.\n"
  },
  {
    "path": "components/upload/demo/drag.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzMessageService } from 'ng-zorro-antd/message';\nimport { NzUploadChangeParam, NzUploadModule } from 'ng-zorro-antd/upload';\n\n@Component({\n  selector: 'nz-demo-upload-drag',\n  imports: [NzButtonModule, NzIconModule, NzUploadModule],\n  template: `\n    <nz-upload\n      nzType=\"drag\"\n      [nzMultiple]=\"true\"\n      nzAction=\"https://www.mocky.io/v2/5cc8019d300000980a055e76\"\n      (nzChange)=\"handleChange($event)\"\n    >\n      <p class=\"ant-upload-drag-icon\">\n        <nz-icon nzType=\"inbox\" />\n      </p>\n      <p class=\"ant-upload-text\">Click or drag file to this area to upload</p>\n      <p class=\"ant-upload-hint\">\n        Support for a single or bulk upload. Strictly prohibit from uploading company data or other band files\n      </p>\n    </nz-upload>\n  `\n})\nexport class NzDemoUploadDragComponent {\n  constructor(private messageService: NzMessageService) {}\n\n  handleChange({ file, fileList }: NzUploadChangeParam): void {\n    const status = file.status;\n    if (status !== 'uploading') {\n      console.log(file, fileList);\n    }\n    if (status === 'done') {\n      this.messageService.success(`${file.name} file uploaded successfully.`);\n    } else if (status === 'error') {\n      this.messageService.error(`${file.name} file upload failed.`);\n    }\n  }\n}\n"
  },
  {
    "path": "components/upload/demo/file-list.md",
    "content": "---\norder: 4\ntitle:\n  zh-CN: 完全控制的上传列表\n  en-US: Complete control over file list\n---\n\n## zh-CN\n\n使用 `nzFileList` 对列表进行完全控制，可以实现各种自定义功能，以下演示二种情况：\n\n1. 上传列表数量的限制。\n\n2. 读取远程路径并显示链接。\n\n## en-US\n\nYou can gain full control over filelist by configuring `nzFileList`. You can accomplish all kinds of customed functions. The following shows two circumstances:\n\n1. limit the number of uploaded files.\n\n2. read from response and show file link.\n"
  },
  {
    "path": "components/upload/demo/file-list.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzUploadChangeParam, NzUploadFile, NzUploadModule } from 'ng-zorro-antd/upload';\n\n@Component({\n  selector: 'nz-demo-upload-file-list',\n  imports: [NzButtonModule, NzIconModule, NzUploadModule],\n  template: `\n    <nz-upload\n      nzAction=\"https://www.mocky.io/v2/5cc8019d300000980a055e76\"\n      [nzFileList]=\"fileList\"\n      (nzChange)=\"handleChange($event)\"\n    >\n      <button nz-button>\n        <nz-icon nzType=\"upload\" />\n        Upload\n      </button>\n    </nz-upload>\n  `\n})\nexport class NzDemoUploadFileListComponent {\n  fileList: NzUploadFile[] = [\n    {\n      uid: '-1',\n      name: 'xxx.png',\n      status: 'done',\n      url: 'http://www.baidu.com/xxx.png'\n    }\n  ];\n\n  handleChange(info: NzUploadChangeParam): void {\n    let fileList = [...info.fileList];\n\n    // 1. Limit the number of uploaded files\n    // Only to show two recent uploaded files, and old ones will be replaced by the new\n    fileList = fileList.slice(-2);\n\n    // 2. Read from response and show file link\n    fileList = fileList.map(file => {\n      if (file.response) {\n        // Component will show file.url as link\n        file.url = file.response.url;\n      }\n      return file;\n    });\n\n    this.fileList = fileList;\n  }\n}\n"
  },
  {
    "path": "components/upload/demo/max-count.md",
    "content": "---\norder: 13\ntitle:\n  zh-CN: 限制数量\n  en-US: Max Count\n---\n\n## zh-CN\n\n通过 `nzMaxCount` 限制上传数量。当为 1 时，始终用最新上传的代替当前。\n\n## en-US\n\nLimit files with `nzMaxCount`. Will replace current one when `nzMaxCount` is 1\n"
  },
  {
    "path": "components/upload/demo/max-count.ts",
    "content": "import { Component, inject } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzFlexModule } from 'ng-zorro-antd/flex';\nimport { NzMessageService } from 'ng-zorro-antd/message';\nimport { NzUploadModule, type NzUploadChangeParam } from 'ng-zorro-antd/upload';\n\n@Component({\n  selector: 'nz-demo-upload-max-count',\n  imports: [NzUploadModule, NzButtonModule, NzFlexModule],\n  template: `\n    <div nz-flex nzVertical nzGap=\"2rem\">\n      <nz-upload\n        nzAction=\"https://www.mocky.io/v2/5cc8019d300000980a055e76\"\n        [nzHeaders]=\"{ authorization: 'authorization-text' }\"\n        [nzMaxCount]=\"1\"\n        (nzChange)=\"handleChange($event)\"\n      >\n        <button nz-button>Upload (Max: 1)</button>\n      </nz-upload>\n      <nz-upload\n        nzAction=\"https://www.mocky.io/v2/5cc8019d300000980a055e76\"\n        [nzHeaders]=\"{ authorization: 'authorization-text' }\"\n        [nzMaxCount]=\"3\"\n        (nzChange)=\"handleChange($event)\"\n      >\n        <button nz-button>Upload (Max: 3)</button>\n      </nz-upload>\n    </div>\n  `\n})\nexport class NzDemoUploadMaxCountComponent {\n  readonly #messageService = inject(NzMessageService);\n  handleChange(info: NzUploadChangeParam): void {\n    if (info.file.status !== 'uploading') {\n      console.log(info.file, info.fileList);\n    }\n    if (info.file.status === 'done') {\n      this.#messageService.success(`${info.file.name} file uploaded successfully`);\n    } else if (info.file.status === 'error') {\n      this.#messageService.error(`${info.file.name} file upload failed.`);\n    }\n  }\n}\n"
  },
  {
    "path": "components/upload/demo/picture-card.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 照片墙\n  en-US: Pictures Wall\n---\n\n## zh-CN\n\n用户可以上传图片并在列表中显示缩略图。当上传照片数到达限制后，上传按钮消失。\n\n## en-US\n\nAfter users upload picture, the thumbnail will be shown in list. The upload button will disappear when count meets limitation.\n"
  },
  {
    "path": "components/upload/demo/picture-card.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzModalModule } from 'ng-zorro-antd/modal';\nimport { NzUploadFile, NzUploadModule } from 'ng-zorro-antd/upload';\n\nconst getBase64 = (file: File): Promise<string | ArrayBuffer | null> =>\n  new Promise((resolve, reject) => {\n    const reader = new FileReader();\n    reader.readAsDataURL(file);\n    reader.onload = () => resolve(reader.result);\n    reader.onerror = error => reject(error);\n  });\n\n@Component({\n  selector: 'nz-demo-upload-picture-card',\n  imports: [NzIconModule, NzModalModule, NzUploadModule],\n  template: `\n    <nz-upload\n      nzAction=\"https://www.mocky.io/v2/5cc8019d300000980a055e76\"\n      nzListType=\"picture-card\"\n      [(nzFileList)]=\"fileList\"\n      [nzShowButton]=\"fileList.length < 8\"\n      [nzPreview]=\"handlePreview\"\n    >\n      <div>\n        <nz-icon nzType=\"plus\" />\n        <div style=\"margin-top: 8px\">Upload</div>\n      </div>\n    </nz-upload>\n    <nz-modal\n      [nzVisible]=\"previewVisible\"\n      [nzContent]=\"modalContent\"\n      [nzFooter]=\"null\"\n      (nzOnCancel)=\"previewVisible = false\"\n    >\n      <ng-template #modalContent>\n        <img [src]=\"previewImage\" style=\"width: 100%\" />\n      </ng-template>\n    </nz-modal>\n  `\n})\nexport class NzDemoUploadPictureCardComponent {\n  fileList: NzUploadFile[] = [\n    {\n      uid: '-1',\n      name: 'image.png',\n      status: 'done',\n      url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png'\n    },\n    {\n      uid: '-2',\n      name: 'image.png',\n      status: 'done',\n      url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png'\n    },\n    {\n      uid: '-3',\n      name: 'image.png',\n      status: 'done',\n      url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png'\n    },\n    {\n      uid: '-4',\n      name: 'image.png',\n      status: 'done',\n      url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png'\n    },\n    {\n      uid: '-xxx',\n      percent: 50,\n      name: 'image.png',\n      status: 'uploading',\n      url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png'\n    },\n    {\n      uid: '-5',\n      name: 'image.png',\n      status: 'error'\n    }\n  ];\n  previewImage: string | undefined = '';\n  previewVisible = false;\n\n  handlePreview = async (file: NzUploadFile): Promise<void> => {\n    if (!file.url && !file.preview) {\n      file.preview = await getBase64(file.originFileObj!);\n    }\n    this.previewImage = file.url || file.preview;\n    this.previewVisible = true;\n  };\n}\n"
  },
  {
    "path": "components/upload/demo/picture-style.md",
    "content": "---\norder: 8\ntitle:\n  zh-CN: 图片列表样式\n  en-US: Pictures with list style\n---\n\n## zh-CN\n\n上传文件为图片，可展示本地缩略图。`IE8/9` 不支持浏览器本地缩略图展示（[Ref](https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL)），可以写 `thumbUrl` 属性来代替。\n\n## en-US\n\nIf uploaded file is a picture, the thumbnail can be shown. `IE8/9` do not support local thumbnail show. Please use `thumbUrl` instead.\n"
  },
  {
    "path": "components/upload/demo/picture-style.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzUploadFile, NzUploadModule } from 'ng-zorro-antd/upload';\n\n@Component({\n  selector: 'nz-demo-upload-picture-style',\n  imports: [NzButtonModule, NzIconModule, NzUploadModule],\n  template: `\n    <nz-upload\n      nzAction=\"https://660d2bd96ddfa2943b33731c.mockapi.io/api/upload\"\n      nzListType=\"picture\"\n      [(nzFileList)]=\"fileList\"\n    >\n      <button nz-button>\n        <nz-icon nzType=\"upload\" />\n        Upload\n      </button>\n    </nz-upload>\n  `\n})\nexport class NzDemoUploadPictureStyleComponent {\n  fileList: NzUploadFile[] = [\n    {\n      uid: '0',\n      name: 'xxx.png',\n      status: 'uploading',\n      percent: 33\n    },\n    {\n      uid: '-1',\n      name: 'yyy.png',\n      status: 'done',\n      url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',\n      thumbUrl: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png'\n    },\n    {\n      uid: '-2',\n      name: 'zzz.png',\n      status: 'error'\n    }\n  ];\n}\n"
  },
  {
    "path": "components/upload/demo/png-only.md",
    "content": "---\norder: 12\ntitle:\n  zh-CN: 只上传 png 图片\n  en-US: Upload png file only\n---\n\n## zh-CN\n\n`nzBeforeUpload` 仅在返回 `false` 或 `Promise.reject()` 或 `Observable` 抛出错误时阻止上传行为。\n\n## en-US\n\n`nzBeforeUpload` only prevent upload behavior when return `false` or `Promise.reject()` or an `Observable` throw an error.\n"
  },
  {
    "path": "components/upload/demo/png-only.ts",
    "content": "import { Component, inject } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzMessageService } from 'ng-zorro-antd/message';\nimport { NzUploadModule, type NzUploadFile } from 'ng-zorro-antd/upload';\n\n@Component({\n  selector: 'nz-demo-upload-png-only',\n  imports: [NzButtonModule, NzIconModule, NzUploadModule],\n  template: `\n    <nz-upload [nzBeforeUpload]=\"beforeUpload\">\n      <button nz-button>\n        <nz-icon nzType=\"upload\" />\n        Upload only png\n      </button>\n    </nz-upload>\n  `\n})\nexport class NzDemoUploadPngOnlyComponent {\n  readonly #messageService = inject(NzMessageService);\n  beforeUpload = (file: NzUploadFile): boolean => {\n    const isPng = file.type === 'image/png';\n    if (!isPng) {\n      this.#messageService.error('You can only upload png file!');\n    }\n    return isPng;\n  };\n}\n"
  },
  {
    "path": "components/upload/demo/preview-file.md",
    "content": "---\norder: 9\ntitle:\n  zh-CN: 自定义预览\n  en-US: Customize preview file\n---\n\n## zh-CN\n\n自定义本地预览，用于处理非图片格式文件（例如视频文件）。\n\n## en-US\n\nCustomize local preview. Can handle with non-image format files such as video.\n"
  },
  {
    "path": "components/upload/demo/preview-file.ts",
    "content": "import { HttpClient } from '@angular/common/http';\nimport { Component } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport { map } from 'rxjs/operators';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzUploadFile, NzUploadModule } from 'ng-zorro-antd/upload';\n\n@Component({\n  selector: 'nz-demo-upload-preview-file',\n  imports: [NzButtonModule, NzIconModule, NzUploadModule],\n  template: `\n    <nz-upload\n      nzAction=\"https://www.mocky.io/v2/5cc8019d300000980a055e76\"\n      nzListType=\"picture\"\n      [nzPreviewFile]=\"previewFile\"\n    >\n      <button nz-button>\n        <nz-icon nzType=\"upload\" />\n        Upload\n      </button>\n    </nz-upload>\n  `\n})\nexport class NzDemoUploadPreviewFileComponent {\n  constructor(private http: HttpClient) {}\n\n  previewFile = (file: NzUploadFile): Observable<string> => {\n    console.log('Your upload file:', file);\n    return this.http\n      .post<{ thumbnail: string }>(`https://next.json-generator.com/api/json/get/4ytyBoLK8`, {\n        body: file\n      })\n      .pipe(map(res => res.thumbnail));\n  };\n}\n"
  },
  {
    "path": "components/upload/demo/transform-file.md",
    "content": "---\norder: 10\ntitle:\n  zh-CN: 上传前转换文件\n  en-US: Transform file before request\n---\n\n## zh-CN\n\n> 旧的 `nzTransformFile` 属性已被弃用.\n\n使用 `nzBeforeUpload` 在请求之前转换文件，例如添加水印。\n\n## en-US\n\n> The old `nzTransformFile` input has been deprecated.\n\nUse `nzBeforeUpload` to transform file before requesting it, for example to add a watermark.\n"
  },
  {
    "path": "components/upload/demo/transform-file.ts",
    "content": "import { Component } from '@angular/core';\nimport { Observable, Observer } from 'rxjs';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzUploadFile, NzUploadModule } from 'ng-zorro-antd/upload';\n\n@Component({\n  selector: 'nz-demo-upload-transform-file',\n  imports: [NzButtonModule, NzIconModule, NzUploadModule],\n  template: `\n    <nz-upload nzAction=\"https://www.mocky.io/v2/5cc8019d300000980a055e76\" [nzBeforeUpload]=\"transformFile\">\n      <button nz-button>\n        <nz-icon nzType=\"upload\" />\n        Upload\n      </button>\n    </nz-upload>\n  `\n})\nexport class NzDemoUploadTransformFileComponent {\n  transformFile = (file: NzUploadFile): Observable<Blob> =>\n    new Observable((observer: Observer<Blob>) => {\n      const reader = new FileReader();\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      reader.readAsDataURL(file as any);\n      reader.onload = () => {\n        const canvas = document.createElement('canvas');\n        const img = document.createElement('img');\n        img.src = reader.result as string;\n        img.onload = () => {\n          const ctx = canvas.getContext('2d')!;\n          ctx.drawImage(img, 0, 0);\n          ctx.fillStyle = 'red';\n          ctx.textBaseline = 'middle';\n          ctx.fillText('Ant Design', 20, 20);\n          canvas.toBlob(blob => {\n            observer.next(blob!);\n            observer.complete();\n          });\n        };\n      };\n    });\n}\n"
  },
  {
    "path": "components/upload/demo/upload-manually.md",
    "content": "---\norder: 7\ntitle:\n  zh-CN: 手动上传\n  en-US: Upload manually\n---\n\n## zh-CN\n\n`nzBeforeUpload` 返回 `false` 后，手动上传文件。\n\n## en-US\n\nUpload files manually after `nzBeforeUpload` returns `false`.\n"
  },
  {
    "path": "components/upload/demo/upload-manually.ts",
    "content": "import { HttpClient, HttpRequest, HttpResponse } from '@angular/common/http';\nimport { Component } from '@angular/core';\nimport { filter } from 'rxjs/operators';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzMessageService } from 'ng-zorro-antd/message';\nimport { NzUploadFile, NzUploadModule } from 'ng-zorro-antd/upload';\n\n@Component({\n  selector: 'nz-demo-upload-upload-manually',\n  imports: [NzButtonModule, NzIconModule, NzUploadModule],\n  template: `\n    <nz-upload [(nzFileList)]=\"fileList\" [nzBeforeUpload]=\"beforeUpload\">\n      <button nz-button>\n        <nz-icon nzType=\"upload\" />\n        Select File\n      </button>\n    </nz-upload>\n    <br />\n    <br />\n    <button\n      nz-button\n      nzType=\"primary\"\n      [nzLoading]=\"uploading\"\n      (click)=\"handleUpload()\"\n      [disabled]=\"fileList.length === 0\"\n    >\n      {{ uploading ? 'Uploading' : 'Start Upload' }}\n    </button>\n  `\n})\nexport class NzDemoUploadUploadManuallyComponent {\n  uploading = false;\n  fileList: NzUploadFile[] = [];\n\n  constructor(\n    private http: HttpClient,\n    private messageService: NzMessageService\n  ) {}\n\n  beforeUpload = (file: NzUploadFile): boolean => {\n    this.fileList = this.fileList.concat(file);\n    return false;\n  };\n\n  handleUpload(): void {\n    const formData = new FormData();\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    this.fileList.forEach((file: any) => {\n      formData.append('files[]', file);\n    });\n    this.uploading = true;\n    // You can use any AJAX library you like\n    const req = new HttpRequest('POST', 'https://www.mocky.io/v2/5cc8019d300000980a055e76', formData, {\n      // reportProgress: true\n    });\n    this.http\n      .request(req)\n      .pipe(filter(e => e instanceof HttpResponse))\n      .subscribe({\n        next: () => {\n          this.uploading = false;\n          this.fileList = [];\n          this.messageService.success('upload successfully.');\n        },\n        error: () => {\n          this.uploading = false;\n          this.messageService.error('upload failed.');\n        }\n      });\n  }\n}\n"
  },
  {
    "path": "components/upload/demo/upload-with-aliyun-oss.md",
    "content": "---\norder: 11\ntitle:\n  zh-CN: 阿里云 OSS\n  en-US: Aliyun OSS\n---\n\n## zh-CN\n\n使用阿里云 OSS 上传示例.\n\n## en-US\n\nUse Aliyun OSS upload example.\n"
  },
  {
    "path": "components/upload/demo/upload-with-aliyun-oss.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzUploadChangeParam, NzUploadFile, NzUploadModule } from 'ng-zorro-antd/upload';\n\n@Component({\n  selector: 'nz-demo-upload-upload-with-aliyun-oss',\n  imports: [NzButtonModule, NzIconModule, NzUploadModule],\n  template: `\n    <nz-upload\n      nzName=\"file\"\n      [(nzFileList)]=\"files\"\n      [nzTransformFile]=\"transformFile\"\n      [nzData]=\"getExtraData\"\n      [nzAction]=\"mockOSSData.host\"\n      (nzChange)=\"onChange($event)\"\n    >\n      Photos:\n      <button nz-button>\n        <nz-icon nzType=\"upload\" />\n        Click to Upload\n      </button>\n    </nz-upload>\n  `\n})\nexport class NzDemoUploadUploadWithAliyunOssComponent {\n  files: NzUploadFile[] = [];\n  mockOSSData = {\n    dir: 'user-dir/',\n    expire: '1577811661',\n    host: '//www.mocky.io/v2/5cc8019d300000980a055e76',\n    accessId: 'c2hhb2RhaG9uZw==',\n    policy: 'eGl4aWhhaGFrdWt1ZGFkYQ==',\n    signature: 'ZGFob25nc2hhbw=='\n  };\n\n  transformFile = (file: NzUploadFile): NzUploadFile => {\n    const suffix = file.name.slice(file.name.lastIndexOf('.'));\n    const filename = Date.now() + suffix;\n    file.url = this.mockOSSData.dir + filename;\n    return file;\n  };\n\n  getExtraData = (file: NzUploadFile): {} => {\n    const { accessId, policy, signature } = this.mockOSSData;\n\n    return {\n      key: file.url,\n      OSSAccessKeyId: accessId,\n      policy,\n      Signature: signature\n    };\n  };\n\n  onChange(e: NzUploadChangeParam): void {\n    console.log('Aliyun OSS:', e.fileList);\n  }\n}\n"
  },
  {
    "path": "components/upload/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Data Entry\ntitle: Upload\ncover: 'https://gw.alipayobjects.com/zos/alicdn/QaeBt_ZMg/Upload.svg'\ndescription: Used to select and upload files or drag and drop files.\n---\n\n## When To Use\n\nUploading is publishing information (web pages, text, pictures, video, etc.) to a remote server via a web page or upload tool.\n\n- When you need to upload one or more files.\n- When you need to show the process of uploading.\n- When you need to upload files by dragging and dropping.\n\n## API\n\n> You can consult [jQuery-File-Upload](https://github.com/blueimp/jQuery-File-Upload/wiki) about how to implement server-side upload interface.\n\n### nz-upload\n\n| Property                    | Description                                                                                                                                                                                                       | Type                                                                                             | Default         |\n| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | --------------- |\n| `[nzAccept]`                | File types that can be accepted. See [input accept Attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-accept)                                                                        | `string`                                                                                         | -               |\n| `[nzAction]`                | Required. Uploading URL                                                                                                                                                                                           | `string \\| ((file: NzUploadFile) => string \\| Observable<string>)`                               | -               |\n| `[nzDirectory]`             | support uploading the whole directory ([caniuse](https://caniuse.com/#feat=input-file-directory))                                                                                                                 | `boolean`                                                                                        | `false`         |\n| `[nzBeforeUpload]`          | Hook function, which will be executed before uploading. Uploading will be stopped with `false` or an Observable. **Warning： this function is not supported in IE9**. NOTICE: Must use `=>` to define the method. | `(file: NzUploadFile, fileList: NzUploadFile[]) => boolean \\| Observable<boolean>`               | -               |\n| `[nzCustomRequest]`         | Override for the default XHR behavior allowing for additional customization and the ability to implement your own XMLHttpRequest. NOTICE: Must use `=>` to define the method.                                     | `(item) => Subscription`                                                                         | -               |\n| `[nzData]`                  | Uploading params or function which can return uploading params. NOTICE: Must use `=>` to define the method.                                                                                                       | `Object \\| ((file: NzUploadFile) => Object \\| Observable<{}>)`                                   | -               |\n| `[nzDisabled]`              | disable upload button                                                                                                                                                                                             | `boolean`                                                                                        | `false`         |\n| `[nzFileList]`              | List of files, two-way data-binding                                                                                                                                                                               | `NzUploadFile[]`                                                                                 | -               |\n| `[nzLimit]`                 | limit single upload count when `nzMultiple` has opened. `0` unlimited                                                                                                                                             | `number`                                                                                         | `0`             |\n| `[nzMaxCount]`              | Limit the file displayed in uploaded files list. Will replace current one when maxCount is 1 unlimited                                                                                                            | `number\\|undefined`                                                                              | `undefined`     |\n| `[nzSize]`                  | limit file size (KB). `0` unlimited                                                                                                                                                                               | `number`                                                                                         | `0`             |\n| `[nzFileType]`              | limit file type, e.g: `image/png,image/jpeg,image/gif,image/bmp`                                                                                                                                                  | `string`                                                                                         | -               |\n| `[nzFilter]`                | Custom filter when choose file                                                                                                                                                                                    | `UploadFilter[]`                                                                                 | -               |\n| `[nzHeaders]`               | Set request headers, valid above IE10. NOTICE: Must use `=>` to define the method.                                                                                                                                | `Object \\| ((file: NzUploadFile) => Object \\| Observable<{}>)`                                   | -               |\n| `[nzListType]`              | Built-in stylesheets, support for three types: `text`, `picture` or `picture-card`                                                                                                                                | `'text' \\| 'picture' \\| 'picture-card'`                                                          | `'text'`        |\n| `[nzMultiple]`              | Whether to support selected multiple files. `IE10+` supported. You can select multiple files with CTRL holding down while multiple is set to be true                                                              | `boolean`                                                                                        | `false`         |\n| `[nzName]`                  | The name of the uploading file                                                                                                                                                                                    | `string`                                                                                         | `'file'`        |\n| `[nzShowUploadList]`        | Whether to show the default upload list, could be an object to specify `showPreviewIcon`, `showRemoveIcon` and `showDownloadIcon` individually                                                                    | `boolean \\| { showPreviewIcon?: boolean, showRemoveIcon?: boolean, showDownloadIcon?: boolean }` | `true`          |\n| `[nzShowButton]`            | Show upload button                                                                                                                                                                                                | `boolean`                                                                                        | `true`          |\n| `[nzWithCredentials]`       | ajax upload with cookie sent                                                                                                                                                                                      | `boolean`                                                                                        | `false`         |\n| `[nzOpenFileDialogOnClick]` | click open file dialog                                                                                                                                                                                            | `boolean`                                                                                        | `true`          |\n| `[nzPreview]`               | A callback function will be executed when the file link or preview icon is clicked. NOTICE: Must use `=>` to define the method.                                                                                   | `(file: NzUploadFile) => void`                                                                   | -               |\n| `[nzPreviewFile]`           | Customize preview file logic. NOTICE: Must use `=>` to define the method.                                                                                                                                         | `(file: NzUploadFile) => Observable<dataURL: string>`                                            | -               |\n| `[nzPreviewIsImage]`        | Customize the preview file is an image, generally used when the image URL is in a non-standard format. NOTICE: Must use `=>` to define the method.                                                                | `(file: NzUploadFile) => boolean`                                                                | -               |\n| `[nzRemove]`                | A callback function will be executed when the removing file button is clicked, remove event will be prevented when the return value is `false` or an Observable. NOTICE: Must use `=>` to define the method.      | `(file: NzUploadFile) => boolean \\| Observable<boolean>`                                         | -               |\n| `(nzChange)`                | A callback function, can be executed when uploading state is changing                                                                                                                                             | `EventEmitter<NzUploadChangeParam>`                                                              | -               |\n| `[nzDownload]`              | Click the method to download the file, pass the method to perform the method logic, do not pass the default jump to the new TAB.                                                                                  | `(file: NzUploadFile) => void`                                                                   | Jump to new TAB |\n| ~~`[nzTransformFile]`~~     | ~~Customize transform file before request~~                                                                                                                                                                       | ~~`(file: NzUploadFile) => NzUploadTransformFileType`~~                                          | -               |\n| `[nzIconRender]`            | Custom show icon                                                                                                                                                                                                  | `TemplateRef<{ $implicit: NzUploadFile }>`                                                       | -               |\n| `[nzFileListRender]`        | Custom file list                                                                                                                                                                                                  | `TemplateRef<{ $implicit: NzUploadFile[] }>`                                                     | -               |\n\n#### nzChange\n\n> The function will be called when uploading is in progress, completed or failed\n\nWhen uploading state changes, it returns:\n\n```js\n{\n  file: { /* ... */ },\n  fileList: [ /* ... */ ],\n  event: { /* ... */ },\n}\n```\n\n1. `file` File object for the current operation.\n\n   ```js\n   {\n      uid: 'uid',      // unique identifier\n      name: 'xx.png'   // file name\n      status: 'done', // options：uploading, done, error, removed\n      response: '{\"status\": \"success\"}', // response from server\n      linkProps: '{\"download\": \"image\"}', // additional html props of file link\n   }\n   ```\n\n2. `fileList` current list of files\n3. `event` response from server, including uploading progress, supported by advanced browsers.\n\n#### nzCustomRequest\n\nAllows for advanced customization by overriding default behavior in `HttpClient`. Provide your own XMLHttpRequest calls to interface with custom backend processes or interact with AWS S3 service through the `aws-sdk` package.\n\n`nzCustomRequest` callback is passed an object with:\n\n- `onProgress: (event: { percent: number }): void`\n- `onError: (event: Error): void`\n- `onSuccess: (body: Object, xhr?: Object): void`\n- `data: Object`\n- `filename: String`\n- `file: File`\n- `withCredentials: Boolean`\n- `action: String`\n- `headers: Object`\n"
  },
  {
    "path": "components/upload/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\nsubtitle: 上传\ntype: 数据录入\ntitle: Upload\ncover: 'https://gw.alipayobjects.com/zos/alicdn/QaeBt_ZMg/Upload.svg'\ndescription: 文件选择上传和拖拽上传控件。\n---\n\n## 何时使用\n\n上传是将信息（网页、文字、图片、视频等）通过网页或者上传工具发布到远程服务器上的过程。\n\n- 当需要上传一个或一些文件时。\n- 当需要展现上传的进度时。\n- 当需要使用拖拽交互时。\n\n## API\n\n> 服务端上传接口实现可以参考 [jQuery-File-Upload](https://github.com/blueimp/jQuery-File-Upload/wiki)。\n\n### nz-upload\n\n| 参数                        | 说明                                                                                                                            | 类型                                                                                             | 默认值       |\n| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | ------------ |\n| `[nzAccept]`                | 接受上传的文件类型, 详见 [input accept Attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-accept)  | `string`                                                                                         | -            |\n| `[nzAction]`                | 必选参数, 上传的地址                                                                                                            | `string \\| ((file: NzUploadFile) => string \\| Observable<string>)`                               | -            |\n| `[nzDirectory]`             | 支持上传文件夹（[caniuse](https://caniuse.com/#feat=input-file-directory)）                                                     | `boolean`                                                                                        | `false`      |\n| `[nzBeforeUpload]`          | 上传文件之前的钩子，参数为上传的文件，若返回 `false` 则停止上传。注意：**IE9** 不支持该方法；注意：务必使用 `=>` 定义处理方法。 | `(file: NzUploadFile, fileList: NzUploadFile[]) => boolean \\| Observable<boolean>`               | -            |\n| `[nzCustomRequest]`         | 通过覆盖默认的上传行为，可以自定义自己的上传实现；注意：务必使用 `=>` 定义处理方法。                                            | `(item) => Subscription`                                                                         | -            |\n| `[nzData]`                  | 上传所需参数或返回上传参数的方法；注意：务必使用 `=>` 定义处理方法。                                                            | `Object \\| ((file: NzUploadFile) => Object \\| Observable<{}>)`                                   | -            |\n| `[nzDisabled]`              | 是否禁用                                                                                                                        | `boolean`                                                                                        | `false`      |\n| `[nzFileList]`              | 文件列表，双向绑定                                                                                                              | `NzUploadFile[]`                                                                                 | -            |\n| `[nzLimit]`                 | 限制单次最多上传数量，`nzMultiple` 打开时有效；`0` 表示不限                                                                     | `number`                                                                                         | `0`          |\n| `[nzMaxCount]`              | 限制上传数量。当为 1 时，始终用最新上传的文件代替当前文件                                                                       | `number\\|undefined`                                                                              | `undefined`  |\n| `[nzSize]`                  | 限制文件大小，单位：KB；`0` 表示不限                                                                                            | `number`                                                                                         | `0`          |\n| `[nzFileType]`              | 限制文件类型，例如：`image/png,image/jpeg,image/gif,image/bmp`                                                                  | `string`                                                                                         | -            |\n| `[nzFilter]`                | 自定义过滤器                                                                                                                    | `UploadFilter[]`                                                                                 | -            |\n| `[nzHeaders]`               | 设置上传的请求头部，IE10 以上有效；注意：务必使用 `=>` 定义处理方法。                                                           | `Object \\| ((file: NzUploadFile) => Object \\| Observable<{}>)`                                   | -            |\n| `[nzListType]`              | 上传列表的内建样式，支持三种基本样式 `text`, `picture` 和 `picture-card`                                                        | `'text' \\| 'picture' \\| 'picture-card'`                                                          | `'text'`     |\n| `[nzMultiple]`              | 是否支持多选文件，`ie10+` 支持。开启后按住 ctrl 可选择多个文件。                                                                | `boolean`                                                                                        | `false`      |\n| `[nzName]`                  | 发到后台的文件参数名                                                                                                            | `string`                                                                                         | `'file'`     |\n| `[nzShowUploadList]`        | 是否展示 uploadList, 可设为一个对象，用于单独设定 `showPreviewIcon`，`showRemoveIcon` 和 `showDownloadIcon`                     | `boolean \\| { showPreviewIcon?: boolean, showRemoveIcon?: boolean, showDownloadIcon?: boolean }` | `true`       |\n| `[nzShowButton]`            | 是否展示上传按钮                                                                                                                | `boolean`                                                                                        | `true`       |\n| `[nzWithCredentials]`       | 上传请求时是否携带 cookie                                                                                                       | `boolean`                                                                                        | `false`      |\n| `[nzOpenFileDialogOnClick]` | 点击打开文件对话框                                                                                                              | `boolean`                                                                                        | `true`       |\n| `[nzPreview]`               | 点击文件链接或预览图标时的回调；注意：务必使用 `=>` 定义处理方法。                                                              | `(file: NzUploadFile) => void`                                                                   | -            |\n| `[nzPreviewFile]`           | 自定义文件预览逻辑；注意：务必使用 `=>` 定义处理方法。                                                                          | `(file: NzUploadFile) => Observable<dataURL: string>`                                            | -            |\n| `[nzPreviewIsImage]`        | 自定义预览文件是否有效图像，一般用于图像 URL 为非标准格式；注意：务必使用 `=>` 定义处理方法。                                   | `(file: NzUploadFile) => boolean`                                                                | -            |\n| `[nzRemove]`                | 点击移除文件时的回调，返回值为 false 时不移除。支持返回 `Observable` 对象；注意：务必使用 `=>` 定义处理方法。                   | `(file: NzUploadFile) => boolean \\| Observable<boolean>`                                         | -            |\n| `(nzChange)`                | 上传文件改变时的状态                                                                                                            | `EventEmitter<NzUploadChangeParam>`                                                              | -            |\n| `[nzDownload]`              | 点击下载文件时的回调，如果没有指定，则默认跳转到文件 url 对应的标签页                                                           | `(file: NzUploadFile) => void`                                                                   | 跳转新标签页 |\n| ~~`[nzTransformFile]`~~     | ~~在上传之前转换文件。支持返回一个 Observable 对象~~                                                                            | ~~`(file: NzUploadFile) => NzUploadTransformFileType`~~                                          | -            |\n| `[nzIconRender]`            | 自定义显示 icon                                                                                                                 | `TemplateRef<{ $implicit: NzUploadFile }>`                                                       | -            |\n| `[nzFileListRender]`        | 自定义显示整个列表                                                                                                              | `TemplateRef<{ $implicit: NzUploadFile[] }>`                                                     | -            |\n\n#### nzChange\n\n> 开始、上传进度、完成、失败都会调用这个函数。\n\n文件状态改变的回调，返回为：\n\n```js\n{\n  file: { /* ... */ },\n  fileList: [ /* ... */ ],\n  event: { /* ... */ },\n}\n```\n\n1. `file` 当前操作的文件对象。\n\n   ```js\n   {\n      uid: 'uid',      // 文件唯一标识\n      name: 'xx.png'   // 文件名\n      status: 'done', // 状态有：uploading done error removed\n      response: '{\"status\": \"success\"}', // 服务端响应内容\n      linkProps: '{\"download\": \"image\"}', // 下载链接额外的 HTML 属性\n   }\n   ```\n\n2. `fileList` 当前的文件列表。\n3. `event` 上传中的服务端响应内容，包含了上传进度等信息，高级浏览器支持。\n\n#### nzCustomRequest\n\n默认使用 HTML5 方式上传（即：使用 `HttpClient`），允许覆盖默认行为实现定制需求，例如直接与阿里云交互等。\n\n`nzCustomRequest` 回调传递以下参数：\n\n- `onProgress: (event: { percent: number }): void`\n- `onError: (event: Error): void`\n- `onSuccess: (body: Object, xhr?: Object): void`\n- `data: Object`\n- `filename: String`\n- `file: File`\n- `withCredentials: Boolean`\n- `action: String`\n- `headers: Object`\n"
  },
  {
    "path": "components/upload/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/upload/interface.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { TemplateRef } from '@angular/core';\nimport { Observable, Subscription } from 'rxjs';\n\nimport { IndexableObject, NzSafeAny } from 'ng-zorro-antd/core/types';\n\n/** Status */\nexport type UploadFileStatus = 'error' | 'success' | 'done' | 'uploading' | 'removed';\n\nexport type NzUploadType = 'select' | 'drag';\n\n/** Built-in styles of the uploading list. */\nexport type NzUploadListType = 'text' | 'picture' | 'picture-card';\n\nexport interface NzUploadFile {\n  uid: string;\n  size?: number;\n  name: string;\n  filename?: string;\n  lastModified?: string;\n  lastModifiedDate?: Date;\n  url?: string;\n  status?: UploadFileStatus;\n  originFileObj?: File;\n  percent?: number;\n  thumbUrl?: string;\n  response?: NzSafeAny;\n  error?: NzSafeAny;\n  linkProps?: { download: string };\n  type?: string;\n\n  [key: string]: NzSafeAny;\n}\n\nexport interface NzUploadChangeParam {\n  file: NzUploadFile;\n  fileList: NzUploadFile[];\n  event?: { percent: number };\n  /** Callback type. */\n  type?: string;\n}\n\nexport interface NzShowUploadList {\n  showRemoveIcon?: boolean;\n  showPreviewIcon?: boolean;\n  showDownloadIcon?: boolean;\n}\n\n/**\n * @deprecated will be removed in v22.0.0\n * Use `NzBeforeUploadFileType` instead.\n */\nexport type NzUploadTransformFileType = string | Blob | NzUploadFile | Observable<string | Blob | File>;\n\nexport type NzBeforeUploadFileType =\n  | boolean\n  | Observable<boolean | NzUploadFile | Blob | File | boolean>\n  | Promise<boolean | NzUploadFile | Blob | File | boolean>;\n\nexport interface ZipButtonOptions {\n  disabled?: boolean;\n  accept?: string | string[];\n  action?: string | ((file: NzUploadFile) => string | Observable<string>);\n  directory?: boolean;\n  openFileDialogOnClick?: boolean;\n  beforeUpload?(file: NzUploadFile, fileList: NzUploadFile[]): NzBeforeUploadFileType;\n  customRequest?(item: NzSafeAny): Subscription;\n  data?: {} | ((file: NzUploadFile) => {} | Observable<{}>);\n  headers?: {} | ((file: NzUploadFile) => {} | Observable<{}>);\n  name?: string;\n  multiple?: boolean;\n  withCredentials?: boolean;\n  filters?: UploadFilter[];\n  transformFile?(file: NzUploadFile): NzUploadTransformFileType;\n  onStart?(file: NzUploadFile): void;\n  onProgress?(e: NzSafeAny, file: NzUploadFile): void;\n  onSuccess?(ret: NzSafeAny, file: NzUploadFile, xhr: NzSafeAny): void;\n  onError?(err: NzSafeAny, file: NzUploadFile): void;\n}\n\nexport interface UploadFilter {\n  name: string;\n  fn(fileList: NzUploadFile[]): NzUploadFile[] | Observable<NzUploadFile[]>;\n}\n\nexport interface NzUploadXHRArgs {\n  action?: string;\n  name?: string;\n  headers?: IndexableObject;\n  file: NzUploadFile;\n  postFile: string | Blob | File | NzUploadFile;\n  data?: IndexableObject;\n  withCredentials?: boolean;\n  onProgress?(e: NzSafeAny, file: NzUploadFile): void;\n  onSuccess?(ret: NzSafeAny, file: NzUploadFile, xhr: NzSafeAny): void;\n  onError?(err: NzSafeAny, file: NzUploadFile): void;\n}\n\nexport type NzIconRenderTemplate = TemplateRef<{ $implicit: NzUploadFile }>;\n"
  },
  {
    "path": "components/upload/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/upload/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './interface';\nexport * from './upload-btn.component';\nexport * from './upload-list.component';\nexport * from './upload.component';\nexport * from './upload.module';\n"
  },
  {
    "path": "components/upload/style/entry.less",
    "content": "@import './index.less';\n// style dependencies\n@import '../../progress/style/entry.less';\n@import '../../tooltip/style/entry.less';\n@import './patch.less';\n"
  },
  {
    "path": "components/upload/style/index.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@upload-prefix-cls: ~'@{ant-prefix}-upload';\n@upload-item: ~'@{ant-prefix}-upload-list-item';\n@upload-picture-card-size: 104px;\n@upload-picture-card-border-style: @border-style-base;\n\n.@{upload-prefix-cls} {\n  .reset-component();\n\n  outline: 0;\n\n  p {\n    margin: 0;\n  }\n\n  &-btn {\n    display: block;\n    width: 100%;\n    outline: none;\n  }\n\n  input[type='file'] {\n    cursor: pointer;\n  }\n\n  &&-select {\n    display: inline-block;\n  }\n\n  &&-disabled {\n    color: @disabled-color;\n    cursor: not-allowed;\n  }\n\n  &&-select-picture-card {\n    width: @upload-picture-card-size;\n    height: @upload-picture-card-size;\n    margin-right: 8px;\n    margin-bottom: 8px;\n    text-align: center;\n    vertical-align: top;\n    background-color: @background-color-light;\n    border: @border-width-base dashed @border-color-base;\n    border-radius: @border-radius-base;\n    cursor: pointer;\n    transition: border-color 0.3s;\n\n    > .@{upload-prefix-cls} {\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      height: 100%;\n      text-align: center;\n    }\n\n    &:hover {\n      border-color: @primary-color;\n      .@{upload-prefix-cls}-disabled& {\n        border-color: @border-color-base;\n      }\n    }\n  }\n\n  &&-drag {\n    position: relative;\n    width: 100%;\n    height: 100%;\n    text-align: center;\n    background: @background-color-light;\n    border: @border-width-base dashed @border-color-base;\n    border-radius: @border-radius-base;\n    cursor: pointer;\n    transition: border-color 0.3s;\n\n    .@{upload-prefix-cls} {\n      padding: @padding-md 0;\n    }\n\n    &.@{upload-prefix-cls}-drag-hover:not(.@{upload-prefix-cls}-disabled) {\n      border-color: @primary-7;\n    }\n\n    &.@{upload-prefix-cls}-disabled {\n      cursor: not-allowed;\n    }\n\n    .@{upload-prefix-cls}-btn {\n      display: table;\n      height: 100%;\n    }\n\n    .@{upload-prefix-cls}-drag-container {\n      display: table-cell;\n      vertical-align: middle;\n    }\n\n    &:not(.@{upload-prefix-cls}-disabled):hover {\n      border-color: @primary-5;\n    }\n\n    p.@{upload-prefix-cls}-drag-icon {\n      .@{iconfont-css-prefix} {\n        color: @primary-5;\n        font-size: 48px;\n      }\n\n      margin-bottom: 20px;\n    }\n    p.@{upload-prefix-cls}-text {\n      margin: 0 0 4px;\n      color: @heading-color;\n      font-size: @font-size-lg;\n    }\n    p.@{upload-prefix-cls}-hint {\n      color: @text-color-secondary;\n      font-size: @font-size-base;\n    }\n\n    .@{iconfont-css-prefix}-plus {\n      color: @disabled-color;\n      font-size: 30px;\n      transition: all 0.3s;\n\n      &:hover {\n        color: @text-color-secondary;\n      }\n    }\n    &:hover .@{iconfont-css-prefix}-plus {\n      color: @text-color-secondary;\n    }\n  }\n\n  &-picture-card-wrapper {\n    .clearfix();\n\n    display: inline-block;\n    width: 100%;\n  }\n}\n\n.@{upload-prefix-cls}-list {\n  .reset-component();\n  .clearfix();\n  line-height: @line-height-base;\n\n  // ============================ Item ============================\n  &-item {\n    position: relative;\n    height: @line-height-base * @font-size-base;\n    margin-top: @margin-xs;\n    font-size: @font-size-base;\n\n    &-name {\n      display: inline-block;\n      width: 100%;\n      padding-left: @font-size-base + 8px;\n      overflow: hidden;\n      line-height: @line-height-base;\n      white-space: nowrap;\n      text-overflow: ellipsis;\n    }\n\n    &-card-actions {\n      position: absolute;\n      right: 0;\n\n      &-btn {\n        opacity: 0;\n      }\n\n      &-btn.@{ant-prefix}-btn-sm {\n        height: @line-height-base * @font-size-base;\n        line-height: 1;\n        vertical-align: top;\n      }\n\n      &.picture {\n        top: 22px;\n        line-height: 0;\n      }\n\n      &-btn:focus,\n      &.picture &-btn {\n        opacity: 1;\n      }\n\n      .@{iconfont-css-prefix} {\n        color: @upload-actions-color;\n        transition: all 0.3s;\n      }\n\n      &:hover .@{iconfont-css-prefix} {\n        color: @text-color;\n      }\n    }\n\n    &-info {\n      height: 100%;\n      transition: background-color 0.3s;\n\n      > span {\n        display: block;\n        width: 100%;\n        height: 100%;\n      }\n\n      .@{iconfont-css-prefix}-loading,\n      .@{upload-prefix-cls}-text-icon {\n        .@{iconfont-css-prefix} {\n          position: absolute;\n          top: (@font-size-base / 2) - 2px;\n          color: @text-color-secondary;\n          font-size: @font-size-base;\n        }\n      }\n    }\n\n    &:hover &-info {\n      background-color: @item-hover-bg;\n    }\n\n    &:hover &-card-actions-btn {\n      opacity: 1;\n    }\n\n    &-error,\n    &-error .@{upload-prefix-cls}-text-icon > .@{iconfont-css-prefix},\n    &-error &-name {\n      color: @error-color;\n    }\n\n    &-error &-card-actions {\n      .@{iconfont-css-prefix} {\n        color: @error-color;\n      }\n\n      &-btn {\n        opacity: 1;\n      }\n    }\n\n    &-progress {\n      position: absolute;\n      bottom: -12px;\n      width: 100%;\n      padding-left: @font-size-base + 12px;\n      font-size: @font-size-base;\n      line-height: 0;\n    }\n  }\n\n  // =================== Picture & Picture Card ===================\n  &-picture,\n  &-picture-card {\n    .@{upload-item} {\n      position: relative;\n      height: 66px;\n      padding: @padding-xs;\n      border: @border-width-base @upload-picture-card-border-style @border-color-base;\n      border-radius: @border-radius-base;\n\n      &:hover {\n        background: transparent;\n      }\n\n      &-error {\n        border-color: @error-color;\n      }\n    }\n\n    .@{upload-item}-info {\n      padding: 0;\n    }\n\n    .@{upload-item}:hover .@{upload-item}-info {\n      background: transparent;\n    }\n\n    .@{upload-item}-uploading {\n      border-style: dashed;\n    }\n\n    .@{upload-item}-thumbnail {\n      width: 48px;\n      height: 48px;\n      line-height: 60px;\n      text-align: center;\n      opacity: 0.8;\n\n      .@{iconfont-css-prefix} {\n        font-size: 26px;\n      }\n    }\n\n    // Adjust the color of the error icon : https://github.com/ant-design/ant-design/pull/24160\n    .@{upload-item}-error .@{upload-item}-thumbnail {\n      .@{iconfont-css-prefix} {\n        svg path {\n          &[fill='#e6f7ff'] {\n            fill: @error-color-deprecated-bg;\n          }\n\n          &[fill='#1890ff'] {\n            fill: @error-color;\n          }\n        }\n      }\n    }\n\n    .@{upload-item}-icon {\n      position: absolute;\n      top: 50%;\n      left: 50%;\n      font-size: 26px;\n      transform: translate(-50%, -50%);\n\n      .@{iconfont-css-prefix} {\n        font-size: 26px;\n      }\n    }\n\n    .@{upload-item}-image {\n      max-width: 100%;\n    }\n\n    .@{upload-item}-thumbnail img {\n      display: block;\n      width: 48px;\n      height: 48px;\n      overflow: hidden;\n    }\n\n    .@{upload-item}-name {\n      display: inline-block;\n      box-sizing: border-box;\n      max-width: 100%;\n      margin: 0 0 0 8px;\n      padding-right: 8px;\n      padding-left: 48px;\n      overflow: hidden;\n      line-height: 44px;\n      white-space: nowrap;\n      text-overflow: ellipsis;\n      transition: all 0.3s;\n    }\n\n    .@{upload-item}-uploading .@{upload-item}-name {\n      margin-bottom: 12px;\n    }\n\n    .@{upload-item}-progress {\n      bottom: 14px;\n      width: ~'calc(100% - 24px)';\n      margin-top: 0;\n      padding-left: 56px;\n    }\n  }\n\n  // ======================== Picture Card ========================\n  &-picture-card {\n    &-container {\n      display: inline-block;\n      width: @upload-picture-card-size;\n      height: @upload-picture-card-size;\n      margin: 0 @margin-xs @margin-xs 0;\n      vertical-align: top;\n    }\n\n    .@{upload-item} {\n      height: 100%;\n      margin: 0;\n    }\n\n    .@{upload-item}-info {\n      position: relative;\n      height: 100%;\n      overflow: hidden;\n\n      &::before {\n        position: absolute;\n        z-index: 1;\n        width: 100%;\n        height: 100%;\n        background-color: fade(@black, 50%);\n        opacity: 0;\n        transition: all 0.3s;\n        content: ' ';\n      }\n    }\n\n    .@{upload-item}:hover .@{upload-item}-info::before {\n      opacity: 1;\n    }\n\n    .@{upload-item}-actions {\n      position: absolute;\n      top: 50%;\n      left: 50%;\n      z-index: 10;\n      white-space: nowrap;\n      transform: translate(-50%, -50%);\n      opacity: 0;\n      transition: all 0.3s;\n\n      .@{iconfont-css-prefix}-eye,\n      .@{iconfont-css-prefix}-download,\n      .@{iconfont-css-prefix}-delete {\n        z-index: 10;\n        width: 16px;\n        margin: 0 4px;\n        color: @text-color-dark;\n        font-size: 16px;\n        cursor: pointer;\n        transition: all 0.3s;\n\n        &:hover {\n          color: @text-color-inverse;\n        }\n      }\n    }\n\n    .@{upload-item}-info:hover + .@{upload-item}-actions,\n    .@{upload-item}-actions:hover {\n      opacity: 1;\n    }\n\n    .@{upload-item}-thumbnail,\n    .@{upload-item}-thumbnail img {\n      position: static;\n      display: block;\n      width: 100%;\n      height: 100%;\n      object-fit: contain;\n    }\n\n    .@{upload-item}-name {\n      display: none;\n      margin: 8px 0 0;\n      padding: 0;\n      line-height: @line-height-base;\n      text-align: center;\n    }\n\n    .@{upload-item}-file + .@{upload-item}-name {\n      position: absolute;\n      bottom: 10px;\n      display: block;\n    }\n\n    .@{upload-item}-uploading {\n      &.@{upload-item} {\n        background-color: @background-color-light;\n      }\n\n      .@{upload-item}-info {\n        height: auto;\n\n        &::before,\n        .@{iconfont-css-prefix}-eye,\n        .@{iconfont-css-prefix}-delete {\n          display: none;\n        }\n      }\n    }\n\n    .@{upload-item}-progress {\n      bottom: 32px;\n      width: calc(100% - 14px);\n      padding-left: 0;\n    }\n  }\n\n  // ======================= Picture & Text =======================\n  &-text,\n  &-picture {\n    &-container {\n      transition: opacity @animation-duration-slow, height @animation-duration-slow;\n\n      &::before {\n        display: table;\n        width: 0;\n        height: 0;\n        content: '';\n      }\n\n      // Don't know why span here, just stretch it\n      .@{upload-prefix-cls}-span {\n        display: block;\n        flex: auto;\n      }\n    }\n\n    // text & picture no need this additional element.\n    // But it used for picture-card, let's keep it.\n    .@{upload-prefix-cls}-span {\n      display: flex;\n      align-items: center;\n\n      > * {\n        flex: none;\n      }\n    }\n\n    .@{upload-item}-name {\n      flex: auto;\n      margin: 0;\n      padding: 0 @padding-xs;\n    }\n\n    .@{upload-item}-card-actions {\n      position: static;\n    }\n  }\n\n  // ============================ Text ============================\n  &-text {\n    .@{upload-prefix-cls}-text-icon {\n      .@{iconfont-css-prefix} {\n        position: static;\n      }\n    }\n  }\n\n  // =========================== Motion ===========================\n  .@{upload-prefix-cls}-animate-inline-appear,\n  .@{upload-prefix-cls}-animate-inline-enter,\n  .@{upload-prefix-cls}-animate-inline-leave {\n    animation-duration: @animation-duration-slow;\n    animation-timing-function: @ease-in-out-circ;\n    animation-fill-mode: forwards;\n  }\n\n  .@{upload-prefix-cls}-animate-inline-appear,\n  .@{upload-prefix-cls}-animate-inline-enter {\n    animation-name: uploadAnimateInlineIn;\n  }\n\n  .@{upload-prefix-cls}-animate-inline-leave {\n    animation-name: uploadAnimateInlineOut;\n  }\n}\n\n@keyframes uploadAnimateInlineIn {\n  from {\n    width: 0;\n    height: 0;\n    margin: 0;\n    padding: 0;\n    opacity: 0;\n  }\n}\n\n@keyframes uploadAnimateInlineOut {\n  to {\n    width: 0;\n    height: 0;\n    margin: 0;\n    padding: 0;\n    opacity: 0;\n  }\n}\n\n@import './rtl';\n"
  },
  {
    "path": "components/upload/style/patch.less",
    "content": ".ant-upload-list-rtl.ant-upload-list-picture-card .ant-upload-list-item {\n  float: unset;\n}\n"
  },
  {
    "path": "components/upload/style/rtl.less",
    "content": "@import '../../style/themes/index';\n@import '../../style/mixins/index';\n\n@upload-prefix-cls: ~'@{ant-prefix}-upload';\n@upload-item: ~'@{ant-prefix}-upload-list-item';\n\n.@{upload-prefix-cls} {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &&-select-picture-card {\n    .@{upload-prefix-cls}-rtl& {\n      margin-right: auto;\n      margin-left: 8px;\n    }\n  }\n}\n\n.@{upload-prefix-cls}-list {\n  &-rtl {\n    direction: rtl;\n  }\n\n  &-item-list-type-text {\n    &:hover {\n      .@{upload-prefix-cls}-list-item-name-icon-count-1 {\n        .@{upload-prefix-cls}-list-rtl & {\n          padding-right: 22px;\n          padding-left: 14px;\n        }\n      }\n      .@{upload-prefix-cls}-list-item-name-icon-count-2 {\n        .@{upload-prefix-cls}-list-rtl & {\n          padding-right: 22px;\n          padding-left: 28px;\n        }\n      }\n    }\n  }\n\n  &-item {\n    &-name {\n      .@{upload-prefix-cls}-list-rtl & {\n        padding-right: @font-size-base + 8px;\n        padding-left: 0;\n      }\n    }\n\n    &-name-icon-count-1 {\n      .@{upload-prefix-cls}-list-rtl & {\n        padding-left: 14px;\n      }\n    }\n\n    &-card-actions {\n      .@{upload-prefix-cls}-list-rtl & {\n        right: auto;\n        left: 0;\n      }\n      .@{iconfont-css-prefix} {\n        .@{upload-prefix-cls}-list-rtl & {\n          padding-right: 0;\n          padding-left: 5px;\n        }\n      }\n    }\n\n    &-info {\n      .@{upload-prefix-cls}-list-rtl & {\n        padding: 0 4px 0 12px;\n      }\n    }\n\n    &-error &-card-actions {\n      .@{iconfont-css-prefix} {\n        .@{upload-prefix-cls}-list-rtl & {\n          padding-right: 0;\n          padding-left: 5px;\n        }\n      }\n    }\n\n    &-progress {\n      .@{upload-prefix-cls}-list-rtl & {\n        padding-right: @font-size-base + 12px;\n        padding-left: 0;\n      }\n    }\n  }\n\n  &-picture,\n  &-picture-card {\n    .@{upload-item}-info {\n      padding: 0;\n    }\n\n    .@{upload-item}-thumbnail {\n      .@{upload-prefix-cls}-list-rtl& {\n        right: 8px;\n        left: auto;\n      }\n    }\n\n    .@{upload-item}-icon {\n      .@{upload-prefix-cls}-list-rtl& {\n        right: 50%;\n        left: auto;\n        transform: translate(50%, -50%);\n      }\n    }\n\n    .@{upload-item}-name {\n      .@{upload-prefix-cls}-list-rtl& {\n        margin: 0 8px 0 0;\n        padding-right: 48px;\n        padding-left: 8px;\n      }\n    }\n\n    .@{upload-item}-name-icon-count-1 {\n      .@{upload-prefix-cls}-list-rtl& {\n        padding-right: 48px;\n        padding-left: 18px;\n      }\n    }\n\n    .@{upload-item}-name-icon-count-2 {\n      .@{upload-prefix-cls}-list-rtl& {\n        padding-right: 48px;\n        padding-left: 36px;\n      }\n    }\n\n    .@{upload-item}-progress {\n      .@{upload-prefix-cls}-list-rtl& {\n        padding-right: 0;\n        padding-left: 0;\n      }\n    }\n  }\n\n  &-picture-card {\n    &-container {\n      .@{upload-prefix-cls}-list-rtl & {\n        margin: 0 0 @margin-xs @margin-xs;\n      }\n    }\n\n    .@{upload-item}-actions {\n      .@{upload-prefix-cls}-list-rtl& {\n        right: 50%;\n        left: auto;\n        transform: translate(50%, -50%);\n      }\n    }\n\n    .@{upload-item}-file + .@{upload-item}-name {\n      .@{upload-prefix-cls}-list-rtl& {\n        margin: 8px 0 0;\n        padding: 0;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/upload/upload-btn.component.html",
    "content": "<!--\n  We explicitly bind `style.display` to avoid using an inline style\n  attribute property (which is not allowed when CSP `unsafe-inline`\n  is not specified).\n-->\n<input\n  type=\"file\"\n  #file\n  (change)=\"onChange($event)\"\n  [attr.accept]=\"options.accept\"\n  [attr.directory]=\"options.directory ? 'directory' : null\"\n  [attr.webkitdirectory]=\"options.directory ? 'webkitdirectory' : null\"\n  [multiple]=\"options.multiple\"\n  [style.display]=\"'none'\"\n/>\n<ng-content />\n"
  },
  {
    "path": "components/upload/upload-btn.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ENTER } from '@angular/cdk/keycodes';\nimport { HttpClient, HttpEvent, HttpEventType, HttpHeaders, HttpRequest, HttpResponse } from '@angular/common/http';\nimport { Component, DestroyRef, ElementRef, inject, Input, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Observable, of, Subscription } from 'rxjs';\nimport { filter, map, switchMap, tap } from 'rxjs/operators';\n\nimport { warn } from 'ng-zorro-antd/core/logger';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\n\nimport { NzUploadFile, NzUploadXHRArgs, ZipButtonOptions } from './interface';\n\n@Component({\n  selector: '[nz-upload-btn]',\n  exportAs: 'nzUploadBtn',\n  templateUrl: './upload-btn.component.html',\n  host: {\n    class: 'ant-upload',\n    '[attr.tabindex]': '\"0\"',\n    '[attr.role]': '\"button\"',\n    '[class.ant-upload-disabled]': 'options.disabled',\n    '(drop)': 'onFileDrop($event)',\n    '(dragover)': 'onFileDrop($event)'\n  },\n  encapsulation: ViewEncapsulation.None\n})\nexport class NzUploadBtnComponent implements OnInit {\n  reqs: Record<string, Subscription> = {};\n  private destroyed = false;\n  @ViewChild('file', { static: true }) file!: ElementRef<HTMLInputElement>;\n  @Input() options!: ZipButtonOptions;\n\n  onClick(): void {\n    if (this.options.disabled || !this.options.openFileDialogOnClick) {\n      return;\n    }\n    this.file.nativeElement.click();\n  }\n\n  // skip safari bug\n  onFileDrop(e: DragEvent): void {\n    if (this.options.disabled || e.type === 'dragover') {\n      e.preventDefault();\n      return;\n    }\n    if (this.options.directory) {\n      this.traverseFileTree(e.dataTransfer!.items);\n    } else {\n      const files: File[] = Array.prototype.slice\n        .call(e.dataTransfer!.files)\n        .filter((file: File) => this.attrAccept(file, this.options.accept));\n      if (files.length) {\n        this.uploadFiles(files);\n      }\n    }\n\n    e.preventDefault();\n  }\n\n  onChange(e: Event): void {\n    if (this.options.disabled) {\n      return;\n    }\n    const hie = e.target as HTMLInputElement;\n    this.uploadFiles(hie.files!);\n    hie.value = '';\n  }\n\n  private traverseFileTree(files: DataTransferItemList): void {\n    const _traverseFileTree = (item: NzSafeAny, path: string): void => {\n      if (item.isFile) {\n        item.file((file: File) => {\n          if (this.attrAccept(file, this.options.accept)) {\n            this.uploadFiles([file]);\n          }\n        });\n      } else if (item.isDirectory) {\n        const dirReader = item.createReader();\n\n        dirReader.readEntries((entries: NzSafeAny) => {\n          for (const entrieItem of entries) {\n            _traverseFileTree(entrieItem, `${path}${item.name}/`);\n          }\n        });\n      }\n    };\n\n    for (const file of files as NzSafeAny) {\n      _traverseFileTree(file.webkitGetAsEntry(), '');\n    }\n  }\n\n  private attrAccept(file: File, acceptedFiles?: string | string[]): boolean {\n    if (file && acceptedFiles) {\n      const acceptedFilesArray = Array.isArray(acceptedFiles) ? acceptedFiles : acceptedFiles.split(',');\n      const fileName = `${file.name}`;\n      const mimeType = `${file.type}`;\n      const baseMimeType = mimeType.replace(/\\/.*$/, '');\n\n      return acceptedFilesArray.some(type => {\n        const validType = type.trim();\n        if (validType.charAt(0) === '.') {\n          return (\n            fileName\n              .toLowerCase()\n              .indexOf(validType.toLowerCase(), fileName.toLowerCase().length - validType.toLowerCase().length) !== -1\n          );\n        } else if (/\\/\\*$/.test(validType)) {\n          // This is something like an image/* mime type\n          return baseMimeType === validType.replace(/\\/.*$/, '');\n        }\n        return mimeType === validType;\n      });\n    }\n    return true;\n  }\n\n  private attachUid(file: NzUploadFile): NzUploadFile {\n    if (!file.uid) {\n      file.uid = Math.random().toString(36).substring(2);\n    }\n    return file;\n  }\n\n  uploadFiles(fileList: FileList | File[]): void {\n    let filters$: Observable<NzUploadFile[]> = of(Array.prototype.slice.call(fileList));\n    if (this.options.filters) {\n      this.options.filters.forEach(f => {\n        filters$ = filters$.pipe(\n          switchMap(list => {\n            const fnRes = f.fn(list);\n            return fnRes instanceof Observable ? fnRes : of(fnRes);\n          })\n        );\n      });\n    }\n    filters$.subscribe({\n      next: list => {\n        list.forEach((file: NzUploadFile) => {\n          this.attachUid(file);\n          this.upload(file, list);\n        });\n      },\n      error: e => {\n        warn(`Unhandled upload filter error`, e);\n      }\n    });\n  }\n\n  private upload(file: NzUploadFile, fileList: NzUploadFile[]): void {\n    if (!this.options.beforeUpload) {\n      return this.post(file);\n    }\n    const before = this.options.beforeUpload(file, fileList);\n    const successBeforeLoadHook = (processedFile: NzUploadFile | boolean | Blob | File): void => {\n      const processedFileType = Object.prototype.toString.call(processedFile);\n      if (\n        typeof processedFile !== 'boolean' &&\n        (processedFileType === '[object File]' || processedFileType === '[object Blob]')\n      ) {\n        (processedFile as NzUploadFile).uid = file.uid; // we are sure that the file has already an uid, now nzBeforeUpload is used to transform the file, the transform file needs to have the same uid as the original file\n        this.post(file, processedFile as NzUploadFile);\n      } else if (processedFile) {\n        this.post(file);\n      }\n    };\n    const errorBeforeLoadHook = (error: NzSafeAny): void => {\n      warn(`Unhandled upload beforeUpload error`, error);\n    };\n\n    if (before instanceof Observable) {\n      before.subscribe({\n        next: successBeforeLoadHook,\n        error: errorBeforeLoadHook\n      });\n    } else if (before instanceof Promise) {\n      before.then(successBeforeLoadHook).catch(errorBeforeLoadHook);\n    } else if (before) {\n      return this.post(file);\n    }\n  }\n\n  private post(file: NzUploadFile, processedFile?: string | Blob | File | NzUploadFile): void {\n    if (this.destroyed) {\n      return;\n    }\n    let process$: Observable<string | Blob | File | NzUploadFile> = of(processedFile || file);\n    let transformedFile: string | Blob | File | NzUploadFile | undefined;\n    const opt = this.options;\n    const { uid } = file;\n    const { action, data, headers, transformFile } = opt;\n\n    const args: NzUploadXHRArgs = {\n      action: typeof action === 'string' ? action : '',\n      name: opt.name,\n      headers,\n      file,\n      postFile: file,\n      data,\n      withCredentials: opt.withCredentials,\n      onProgress: opt.onProgress\n        ? e => {\n            opt.onProgress!(e, file);\n          }\n        : undefined,\n      onSuccess: (ret, xhr) => {\n        this.clean(uid);\n        opt.onSuccess!(ret, file, xhr);\n      },\n      onError: xhr => {\n        this.clean(uid);\n        opt.onError!(xhr, file);\n      }\n    };\n\n    if (typeof action === 'function') {\n      const actionResult = (action as (file: NzUploadFile) => string | Observable<string>)(file);\n      if (actionResult instanceof Observable) {\n        process$ = process$.pipe(\n          switchMap(() => actionResult),\n          map(res => {\n            args.action = res;\n            return file;\n          })\n        );\n      } else {\n        args.action = actionResult;\n      }\n    }\n\n    if (typeof transformFile === 'function') {\n      const transformResult = transformFile(file);\n      process$ = process$.pipe(\n        switchMap(() => (transformResult instanceof Observable ? transformResult : of(transformResult))),\n        tap(newFile => (transformedFile = newFile))\n      );\n    }\n\n    /**\n     * TODO\n     * All this part of code needs to be removed in v22.0.0 when we will remove the `nzTransformFile` hook\n     */\n    if (typeof data === 'function') {\n      const dataResult = (data as (file: NzUploadFile) => {} | Observable<{}>)(file);\n      if (dataResult instanceof Observable) {\n        process$ = process$.pipe(\n          /**\n           * this is a little bit tricky but here is the explanation:\n           * Potentially, people can use the `beforeUpload` hook to transform the file, and also `nzTransformFile` hook to transform the file,\n           * if beforeUpload hook transform the file, so nzTransformFile hook must not be called, otherwise the file will be transformed twice\n           * Normally this can not happen, but it is possible until we remove the `nzTransformFile` hook\n           */\n          filter(() => !processedFile),\n          switchMap(() => dataResult),\n          map(res => {\n            args.data = res;\n            return transformedFile ?? file;\n          })\n        );\n      } else {\n        args.data = dataResult;\n      }\n    }\n\n    if (typeof headers === 'function') {\n      const headersResult = (headers as (file: NzUploadFile) => {} | Observable<{}>)(file);\n      if (headersResult instanceof Observable) {\n        process$ = process$.pipe(\n          switchMap(() => headersResult),\n          map(res => {\n            args.headers = res;\n            return transformedFile ?? file;\n          })\n        );\n      } else {\n        args.headers = headersResult;\n      }\n    }\n\n    process$.subscribe(newFile => {\n      args.postFile = newFile;\n      const req$ = (opt.customRequest || this.xhr).call(this, args);\n      if (!(req$ instanceof Subscription)) {\n        warn(`Must return Subscription type in '[nzCustomRequest]' property`);\n      }\n      this.reqs[uid] = req$;\n      opt.onStart!(file);\n    });\n  }\n\n  private xhr(args: NzUploadXHRArgs): Subscription {\n    const formData = new FormData();\n\n    if (args.data) {\n      Object.keys(args.data).map(key => {\n        formData.append(key, args.data![key]);\n      });\n    }\n\n    formData.append(args.name!, args.postFile as NzSafeAny);\n\n    if (!args.headers) {\n      args.headers = {};\n    }\n    if (args.headers['X-Requested-With'] !== null) {\n      args.headers['X-Requested-With'] = `XMLHttpRequest`;\n    } else {\n      delete args.headers['X-Requested-With'];\n    }\n    const req = new HttpRequest('POST', args.action!, formData, {\n      reportProgress: true,\n      withCredentials: args.withCredentials,\n      headers: new HttpHeaders(args.headers)\n    });\n    return this.http!.request(req).subscribe({\n      next: (event: HttpEvent<NzSafeAny>) => {\n        if (event.type === HttpEventType.UploadProgress) {\n          if (event.total! > 0) {\n            (event as NzSafeAny).percent = (event.loaded / event.total!) * 100;\n          }\n          args.onProgress!(event, args.file);\n        } else if (event instanceof HttpResponse) {\n          args.onSuccess!(event.body, args.file, event);\n        }\n      },\n      error: err => {\n        this.abort(args.file);\n        args.onError!(err, args.file);\n      }\n    });\n  }\n\n  private clean(uid: string): void {\n    const req$ = this.reqs[uid];\n    if (req$ instanceof Subscription) {\n      req$.unsubscribe();\n    }\n    delete this.reqs[uid];\n  }\n\n  abort(file?: NzUploadFile): void {\n    if (file) {\n      this.clean(file && file.uid);\n    } else {\n      Object.keys(this.reqs).forEach(uid => this.clean(uid));\n    }\n  }\n\n  private http = inject(HttpClient, { optional: true });\n  private elementRef = inject(ElementRef);\n  private destroyRef = inject(DestroyRef);\n\n  constructor() {\n    if (!this.http) {\n      throw new Error(\n        `Not found 'HttpClient', You can configure 'HttpClient' with 'provideHttpClient()' in your root module.`\n      );\n    }\n    this.destroyRef.onDestroy(() => {\n      this.destroyed = true;\n      this.abort();\n    });\n  }\n\n  ngOnInit(): void {\n    // Caretaker note: `input[type=file].click()` will open a native OS file picker,\n    // it doesn't require Angular to run `ApplicationRef.tick()`.\n    fromEventOutsideAngular(this.elementRef.nativeElement, 'click')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(() => this.onClick());\n\n    fromEventOutsideAngular<KeyboardEvent>(this.elementRef.nativeElement, 'keydown')\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe(event => {\n        if (this.options.disabled) {\n          return;\n        }\n        if (event.key === 'Enter' || event.keyCode === ENTER) {\n          this.onClick();\n        }\n      });\n  }\n}\n"
  },
  {
    "path": "components/upload/upload-list.component.html",
    "content": "@let _listType = listType();\n@for (file of list; track file) {\n  <div class=\"ant-upload-list-{{ _listType }}-container\">\n    <div\n      class=\"ant-upload-list-item ant-upload-list-item-{{ file.status }} ant-upload-list-item-list-type-{{ _listType }}\"\n      [attr.data-key]=\"file.key\"\n      [animate.enter]=\"itemAnimationEnter()\"\n      [animate.leave]=\"itemAnimationLeave()\"\n      nz-tooltip\n      [nzTooltipTitle]=\"file.status === 'error' ? file.message : null\"\n    >\n      <ng-template #icon>\n        @switch (file.iconType) {\n          @case ('uploading') {\n            <div class=\"ant-upload-list-item-thumbnail\" [class.ant-upload-list-item-file]=\"!file.isUploading\">\n              <ng-template [ngTemplateOutlet]=\"iconNode\" [ngTemplateOutletContext]=\"{ $implicit: file }\" />\n            </div>\n          }\n          @case ('thumbnail') {\n            <a\n              class=\"ant-upload-list-item-thumbnail\"\n              [class.ant-upload-list-item-file]=\"!file.isImageUrl\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n              [href]=\"file.url || file.thumbUrl\"\n              (click)=\"handlePreview(file, $event)\"\n            >\n              @if (file.isImageUrl) {\n                <img class=\"ant-upload-list-item-image\" [src]=\"file.thumbUrl || file.url\" [attr.alt]=\"file.name\" />\n              } @else {\n                <ng-template [ngTemplateOutlet]=\"iconNode\" [ngTemplateOutletContext]=\"{ $implicit: file }\" />\n              }\n            </a>\n          }\n          @default {\n            <div class=\"ant-upload-text-icon\">\n              <ng-template [ngTemplateOutlet]=\"iconNode\" [ngTemplateOutletContext]=\"{ $implicit: file }\" />\n            </div>\n          }\n        }\n      </ng-template>\n\n      <ng-template #iconNode let-file>\n        @if (!iconRender) {\n          @switch (_listType) {\n            @case ('picture') {\n              @if (file.isUploading) {\n                <nz-icon nzType=\"loading\" />\n              } @else {\n                <nz-icon [nzType]=\"file.isImageUrl ? 'picture' : 'file'\" nzTheme=\"twotone\" />\n              }\n            }\n            @case ('picture-card') {\n              @if (file.isUploading) {\n                {{ locale.uploading }}\n              } @else {\n                <nz-icon [nzType]=\"file.isImageUrl ? 'picture' : 'file'\" nzTheme=\"twotone\" />\n              }\n            }\n            @default {\n              <nz-icon [nzType]=\"file.isUploading ? 'loading' : 'paper-clip'\" />\n            }\n          }\n        } @else {\n          <ng-template [ngTemplateOutlet]=\"iconRender\" [ngTemplateOutletContext]=\"{ $implicit: file }\" />\n        }\n      </ng-template>\n\n      <ng-template #removeIcon>\n        @if (icons.showRemoveIcon) {\n          <button\n            type=\"button\"\n            nz-button\n            nzType=\"text\"\n            nzSize=\"small\"\n            (click)=\"handleRemove(file, $event)\"\n            [attr.title]=\"locale.removeFile\"\n            class=\"ant-upload-list-item-card-actions-btn\"\n          >\n            <nz-icon nzType=\"delete\" />\n          </button>\n        }\n      </ng-template>\n\n      <ng-template #downloadIcon>\n        @if (file.showDownload) {\n          <button\n            type=\"button\"\n            nz-button\n            nzType=\"text\"\n            nzSize=\"small\"\n            (click)=\"handleDownload(file)\"\n            [attr.title]=\"locale.downloadFile\"\n            class=\"ant-upload-list-item-card-actions-btn\"\n          >\n            <nz-icon nzType=\"download\" />\n          </button>\n        }\n      </ng-template>\n\n      <ng-template #downloadOrDelete>\n        @if (_listType !== 'picture-card') {\n          <span class=\"ant-upload-list-item-card-actions\" [class.picture]=\"_listType === 'picture'\">\n            <ng-template [ngTemplateOutlet]=\"downloadIcon\" />\n            <ng-template [ngTemplateOutlet]=\"removeIcon\" />\n          </span>\n        }\n      </ng-template>\n\n      <ng-template #preview>\n        @if (file.url) {\n          <a\n            target=\"_blank\"\n            rel=\"noopener noreferrer\"\n            class=\"ant-upload-list-item-name\"\n            [attr.title]=\"file.name\"\n            [href]=\"file.url\"\n            [attr.download]=\"file.linkProps && file.linkProps.download\"\n            (click)=\"handlePreview(file, $event)\"\n          >\n            {{ file.name }}\n          </a>\n        } @else {\n          <span class=\"ant-upload-list-item-name\" [attr.title]=\"file.name\" (click)=\"handlePreview(file, $event)\">\n            {{ file.name }}\n          </span>\n        }\n        <ng-template [ngTemplateOutlet]=\"downloadOrDelete\" />\n      </ng-template>\n\n      <div class=\"ant-upload-list-item-info\">\n        <span class=\"ant-upload-span\">\n          <ng-template [ngTemplateOutlet]=\"icon\" />\n          <ng-template [ngTemplateOutlet]=\"preview\" />\n        </span>\n      </div>\n      @if (!file.isUploading) {\n        @if (_listType === 'picture-card') {\n          <span class=\"ant-upload-list-item-actions\">\n            @if (icons.showPreviewIcon) {\n              <a\n                [href]=\"file.url || file.thumbUrl\"\n                target=\"_blank\"\n                rel=\"noopener noreferrer\"\n                [attr.title]=\"locale.previewFile\"\n                [style]=\"!(file.url || file.thumbUrl) ? { opacity: 0.5, 'pointer-events': 'none' } : null\"\n                (click)=\"handlePreview(file, $event)\"\n              >\n                <nz-icon nzType=\"eye\" />\n              </a>\n            }\n            @if (file.status === 'done') {\n              <ng-template [ngTemplateOutlet]=\"downloadIcon\" />\n            }\n            <ng-template [ngTemplateOutlet]=\"removeIcon\" />\n          </span>\n        }\n      } @else {\n        <div class=\"ant-upload-list-item-progress\">\n          <nz-progress [nzPercent]=\"file.percent!\" nzType=\"line\" [nzShowInfo]=\"false\" [nzStrokeWidth]=\"2\" />\n        </div>\n      }\n    </div>\n  </div>\n}\n"
  },
  {
    "path": "components/upload/upload-list.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { Platform } from '@angular/cdk/platform';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  computed,\n  DestroyRef,\n  DOCUMENT,\n  inject,\n  input,\n  Input,\n  NgZone,\n  OnChanges,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Observable, of } from 'rxjs';\nimport { map } from 'rxjs/operators';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { withAnimationCheck } from 'ng-zorro-antd/core/animation';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { fromEventOutsideAngular, generateClassName } from 'ng-zorro-antd/core/util';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzProgressModule } from 'ng-zorro-antd/progress';\nimport { NzTooltipModule } from 'ng-zorro-antd/tooltip';\n\nimport { NzIconRenderTemplate, NzShowUploadList, NzUploadFile, NzUploadListType } from './interface';\n\nconst isImageFileType = (type: string): boolean => !!type && type.indexOf('image/') === 0;\n\nconst CLASS_NAME = 'ant-upload-list';\nconst MEASURE_SIZE = 200;\n\ntype UploadListIconType = '' | 'uploading' | 'thumbnail';\n\ninterface UploadListFile extends NzUploadFile {\n  isImageUrl?: boolean;\n  isUploading?: boolean;\n  iconType?: UploadListIconType;\n  showDownload?: boolean;\n}\n\n@Component({\n  selector: 'nz-upload-list',\n  exportAs: 'nzUploadList',\n  templateUrl: './upload-list.component.html',\n  host: {\n    '[class]': 'class()'\n  },\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  imports: [NzTooltipModule, NgTemplateOutlet, NzIconModule, NzButtonModule, NzProgressModule]\n})\nexport class NzUploadListComponent implements OnChanges {\n  list: UploadListFile[] = [];\n\n  readonly listType = input<NzUploadListType>('text');\n  @Input() locale: NzSafeAny = {};\n  @Input()\n  set items(list: NzUploadFile[]) {\n    this.list = list;\n  }\n  @Input() icons!: NzShowUploadList;\n  @Input() onPreview?: (file: NzUploadFile) => void;\n  @Input() onRemove!: (file: NzUploadFile) => void;\n  @Input() onDownload?: (file: NzUploadFile) => void;\n  @Input() previewFile?: (file: NzUploadFile) => Observable<string>;\n  @Input() previewIsImage?: (file: NzUploadFile) => boolean;\n  @Input() iconRender: NzIconRenderTemplate | null = null;\n\n  private readonly document = inject(DOCUMENT);\n  private readonly destroyRef = inject(DestroyRef);\n  private readonly ngZone = inject(NgZone);\n  private readonly cdr = inject(ChangeDetectorRef);\n  private readonly platform = inject(Platform);\n  private readonly dir = inject(Directionality).valueSignal;\n\n  protected readonly class = computed(() => {\n    const cls = [CLASS_NAME, this.generateClass(this.listType())];\n    if (this.dir() === 'rtl') {\n      cls.push(this.generateClass('rtl'));\n    }\n    return cls;\n  });\n  private readonly showPic = computed(() => {\n    return this.listType() === 'picture' || this.listType() === 'picture-card';\n  });\n\n  protected readonly itemAnimationEnter = withAnimationCheck(\n    () => `ant-upload-${this.showPic() ? 'animate-inline' : 'animate'}-enter`\n  );\n  protected readonly itemAnimationLeave = withAnimationCheck(\n    () => `ant-upload-${this.showPic() ? 'animate-inline' : 'animate'}-leave`\n  );\n\n  private genErr(file: NzUploadFile): string {\n    if (file.response && typeof file.response === 'string') {\n      return file.response;\n    }\n    return (file.error && file.error.statusText) || this.locale.uploadError;\n  }\n\n  private extname(url: string): string {\n    const temp = url.split('/');\n    const filename = temp[temp.length - 1];\n    const filenameWithoutSuffix = filename.split(/#|\\?/)[0];\n    return (/\\.[^./\\\\]*$/.exec(filenameWithoutSuffix) || [''])[0];\n  }\n\n  isImageUrl(file: NzUploadFile): boolean {\n    if (isImageFileType(file.type!)) {\n      return true;\n    }\n    const url: string = (file.thumbUrl || file.url || '') as string;\n    if (!url) {\n      return false;\n    }\n    const extension = this.extname(url);\n    if (/^data:image\\//.test(url) || /(webp|svg|png|gif|jpg|jpeg|jfif|bmp|dpg)$/i.test(extension)) {\n      return true;\n    } else if (/^data:/.test(url)) {\n      // other file types of base64\n      return false;\n    } else if (extension) {\n      // other file types which have extension\n      return false;\n    }\n    return true;\n  }\n\n  private getIconType(file: UploadListFile): UploadListIconType {\n    if (!this.showPic()) {\n      return '';\n    }\n    if (file.isUploading || (!file.thumbUrl && !file.url)) {\n      return 'uploading';\n    } else {\n      return 'thumbnail';\n    }\n  }\n\n  private previewImage(file: File | Blob): Observable<string> {\n    if (!isImageFileType(file.type) || !this.platform.isBrowser) {\n      return of('');\n    }\n\n    const canvas = this.document.createElement('canvas');\n    canvas.width = MEASURE_SIZE;\n    canvas.height = MEASURE_SIZE;\n    canvas.style.cssText = `position: fixed; left: 0; top: 0; width: ${MEASURE_SIZE}px; height: ${MEASURE_SIZE}px; z-index: 9999; display: none;`;\n    this.document.body.appendChild(canvas);\n    const ctx = canvas.getContext('2d');\n    const img = new Image();\n    const objectUrl = URL.createObjectURL(file);\n    img.src = objectUrl;\n    return fromEventOutsideAngular(img, 'load').pipe(\n      map(() => {\n        const { width, height } = img;\n\n        let drawWidth = MEASURE_SIZE;\n        let drawHeight = MEASURE_SIZE;\n        let offsetX = 0;\n        let offsetY = 0;\n\n        if (width < height) {\n          drawHeight = height * (MEASURE_SIZE / width);\n          offsetY = -(drawHeight - drawWidth) / 2;\n        } else {\n          drawWidth = width * (MEASURE_SIZE / height);\n          offsetX = -(drawWidth - drawHeight) / 2;\n        }\n\n        try {\n          ctx!.drawImage(img, offsetX, offsetY, drawWidth, drawHeight);\n        } catch {\n          // noop\n        }\n        const dataURL = canvas.toDataURL();\n        this.document.body.removeChild(canvas);\n\n        URL.revokeObjectURL(objectUrl);\n        return dataURL;\n      })\n    );\n  }\n\n  private genThumb(): void {\n    if (!this.platform.isBrowser) {\n      return;\n    }\n\n    const win = window as NzSafeAny;\n    if (\n      !this.showPic() ||\n      typeof document === 'undefined' ||\n      typeof win === 'undefined' ||\n      !win.FileReader ||\n      !win.File\n    ) {\n      return;\n    }\n    this.list\n      .filter(file => file.originFileObj instanceof File && file.thumbUrl === undefined)\n      .forEach(file => {\n        file.thumbUrl = '';\n        // Caretaker note: we shouldn't use promises here since they're not cancellable.\n        // A promise microtask can be resolved after the view is destroyed. Thus, running `detectChanges()`\n        // will cause a runtime exception (`detectChanges()` cannot be run on destroyed views).\n        const dataUrl$ = (this.previewFile ? this.previewFile(file) : this.previewImage(file.originFileObj!)).pipe(\n          takeUntilDestroyed(this.destroyRef)\n        );\n        this.ngZone.runOutsideAngular(() => {\n          dataUrl$.subscribe(dataUrl => {\n            this.ngZone.run(() => {\n              file.thumbUrl = dataUrl;\n              this.detectChanges();\n            });\n          });\n        });\n      });\n  }\n\n  private showDownload(file: NzUploadFile): boolean {\n    return !!(this.icons.showDownloadIcon && file.status === 'done');\n  }\n\n  private fixData(): void {\n    this.list.forEach(file => {\n      file.isUploading = file.status === 'uploading';\n      file.message = this.genErr(file);\n      file.linkProps = typeof file.linkProps === 'string' ? JSON.parse(file.linkProps) : file.linkProps;\n      file.isImageUrl = this.previewIsImage ? this.previewIsImage(file) : this.isImageUrl(file);\n      file.iconType = this.getIconType(file);\n      file.showDownload = this.showDownload(file);\n    });\n  }\n\n  handlePreview(file: NzUploadFile, e: Event): void {\n    if (!this.onPreview) {\n      return;\n    }\n\n    e.preventDefault();\n    return this.onPreview(file);\n  }\n\n  handleRemove(file: NzUploadFile, e: Event): void {\n    e.preventDefault();\n    if (this.onRemove) {\n      this.onRemove(file);\n    }\n  }\n\n  handleDownload(file: NzUploadFile): void {\n    if (typeof this.onDownload === 'function') {\n      this.onDownload(file);\n    } else if (file.url) {\n      window.open(file.url);\n    }\n  }\n\n  detectChanges(): void {\n    this.fixData();\n    this.cdr.detectChanges();\n  }\n\n  ngOnChanges(): void {\n    this.fixData();\n    this.genThumb();\n  }\n\n  private generateClass(suffix: string): string {\n    return generateClassName(CLASS_NAME, suffix);\n  }\n}\n"
  },
  {
    "path": "components/upload/upload-list.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Component, DebugElement, provideZoneChangeDetection, ViewChild } from '@angular/core';\nimport { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { Observable, of } from 'rxjs';\n\nimport { provideNzNoAnimation } from 'ng-zorro-antd/core/animation';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport { NzShowUploadList, NzUploadFile, NzUploadListType } from './interface';\nimport { NzUploadListComponent } from './upload-list.component';\n\ndescribe('upload-list', () => {\n  describe('basic', () => {\n    let fixture: ComponentFixture<TestUploadListComponent>;\n    let dl: DebugElement;\n    let instance: TestUploadListComponent;\n\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        // todo: use zoneless\n        providers: [provideZoneChangeDetection(), provideNzIconsTesting(), provideNzNoAnimation()]\n      });\n      fixture = TestBed.createComponent(TestUploadListComponent);\n      dl = fixture.debugElement;\n      instance = dl.componentInstance;\n      fixture.detectChanges();\n    });\n\n    describe('[listType]', () => {\n      for (const type of ['text', 'picture', 'picture-card']) {\n        it(`with [${type}]`, () => {\n          instance.listType = type as NzUploadListType;\n          fixture.detectChanges();\n          expect(dl.query(By.css(`.ant-upload-list-${type}`)) != null).toBe(true);\n        });\n      }\n    });\n\n    it('[items]', () => {\n      expect(dl.queryAll(By.css(`.ant-upload-list-item`)).length).toBe(instance.items.length);\n    });\n\n    describe('[icons]', () => {\n      it('should be show preview', () => {\n        expect(instance._onPreview).toBe(false);\n        const actions = dl.queryAll(By.css('.ant-upload-list-item-actions'));\n        expect(actions.length).toBe(instance.items.length);\n        actions[0].query(By.css('a')).nativeElement.click();\n        fixture.detectChanges();\n        expect(instance._onPreview).toBe(true);\n      });\n\n      it('should be hide preview', () => {\n        instance.icons = {\n          showPreviewIcon: false,\n          showRemoveIcon: true\n        };\n        fixture.detectChanges();\n        const actions = dl.queryAll(By.css('.ant-upload-list-item-actions a'));\n        expect(actions.length).toBe(0);\n        expect(instance._onPreview).toBe(false);\n      });\n\n      it('should be show remove', () => {\n        expect(instance._onRemove).toBe(false);\n        const actions = dl.queryAll(By.css('.ant-upload-list-item-actions'));\n        expect(actions.length).toBe(instance.items.length);\n        actions[0].query(By.css('.anticon-delete')).nativeElement.click();\n        fixture.detectChanges();\n        expect(instance._onRemove).toBe(true);\n      });\n\n      it('should be hide remove', () => {\n        instance.icons = {\n          showPreviewIcon: true,\n          showRemoveIcon: false\n        };\n        fixture.detectChanges();\n        const actions = dl.queryAll(By.css('.ant-upload-list-item-actions .anticon-delete'));\n        expect(actions.length).toBe(0);\n        expect(instance._onRemove).toBe(false);\n      });\n    });\n\n    describe('[onPreview]', () => {\n      it('should be handle preview', () => {\n        expect(instance._onPreview).toBe(false);\n        dl.query(By.css('.ant-upload-list-item-actions a')).nativeElement.click();\n        expect(instance._onPreview).toBe(true);\n      });\n\n      it('should be invalid handle preview when is a null', () => {\n        expect(instance._onPreview).toBe(false);\n        instance.onPreview = undefined;\n        fixture.detectChanges();\n        dl.query(By.css('.ant-upload-list-item-actions a')).nativeElement.click();\n        expect(instance._onPreview).toBe(false);\n      });\n\n      it('should support linkProps as object', fakeAsync(() => {\n        instance.items = [\n          {\n            uid: '-1',\n            name: 'foo.png',\n            status: 'done',\n            url: 'http://www.baidu.com/xxx.png',\n            linkProps: {\n              download: 'image'\n            }\n          }\n        ];\n        fixture.detectChanges();\n        tick();\n        fixture.detectChanges();\n        const el = dl.query(By.css('.ant-upload-list-item-name')).nativeElement as HTMLElement;\n        expect(el.attributes.getNamedItem('download')!.textContent).toBe('image');\n      }));\n\n      it('should support linkProps as json stringify', fakeAsync(() => {\n        const linkPropsString = JSON.stringify({ download: 'image' });\n        instance.items = [\n          {\n            uid: '-1',\n            name: 'foo.png',\n            status: 'done',\n            url: 'http://www.baidu.com/xxx.png',\n            linkProps: linkPropsString\n          }\n        ];\n        fixture.detectChanges();\n        tick();\n        fixture.detectChanges();\n        const el = dl.query(By.css('.ant-upload-list-item-name')).nativeElement as HTMLElement;\n        expect(el.attributes.getNamedItem('download')!.textContent).toBe('image');\n      }));\n    });\n\n    describe('[onRemove]', () => {\n      it('should be handle remove', () => {\n        expect(instance._onRemove).toBe(false);\n        dl.query(By.css('.ant-upload-list-item-actions .anticon-delete')).nativeElement.click();\n        expect(instance._onRemove).toBe(true);\n      });\n\n      it('should be invalid handle remove when is a null', () => {\n        expect(instance._onRemove).toBe(false);\n        instance.onRemove = null;\n        fixture.detectChanges();\n        dl.query(By.css('.ant-upload-list-item-actions .anticon-delete')).nativeElement.click();\n        expect(instance._onRemove).toBe(false);\n      });\n    });\n\n    describe('[isImageUrl]', () => {\n      describe('via image type', () => {\n        it('should be true when file object type value is a valid image', () => {\n          expect(instance.comp.isImageUrl({ type: 'image/' } as NzSafeAny)).toBe(true);\n        });\n      });\n\n      describe('via thumbUrl or url', () => {\n        it('should be false when not found url & thumbUrl', () => {\n          expect(instance.comp.isImageUrl({} as NzSafeAny)).toBe(false);\n        });\n\n        describe('via extension', () => {\n          it('with valid image extension', () => {\n            expect(instance.comp.isImageUrl({ url: '1.svg' } as NzSafeAny)).toBe(true);\n          });\n\n          it('with invalid image extension', () => {\n            expect(instance.comp.isImageUrl({ url: '1.pdf' } as NzSafeAny)).toBe(false);\n          });\n        });\n\n        describe('when url is base64', () => {\n          it('with valid image base64', () => {\n            expect(instance.comp.isImageUrl({ url: 'data:image/png;base64,1' } as NzSafeAny)).toBe(true);\n          });\n\n          it('with invalid image base64', () => {\n            expect(instance.comp.isImageUrl({ url: 'data:application/pdf;base64,1' } as NzSafeAny)).toBe(false);\n          });\n        });\n      });\n\n      it('#previewIsImage', fakeAsync(() => {\n        instance.previewIsImage = () => true;\n        instance.listType = 'picture';\n        instance.items = [{}];\n        fixture.detectChanges();\n        tick();\n        expect(instance.items[0].isImageUrl).toBe(true);\n      }));\n    });\n\n    describe('[genThumb]', () => {\n      class MockImage {\n        width = 1;\n        height = 2;\n\n        addEventListener(_name: string, callback: VoidFunction): void {\n          callback();\n        }\n        removeEventListener(): void {}\n\n        set src(_: string) {}\n      }\n\n      it('should be generate thumb when is valid image data', fakeAsync(() => {\n        spyOn(window as NzSafeAny, 'Image').and.returnValue(new MockImage());\n\n        instance.listType = 'picture';\n        instance.items = [{ originFileObj: new File([''], '1.png', { type: 'image/' }), thumbUrl: undefined }];\n        fixture.detectChanges();\n        tick();\n        expect(instance.items[0].thumbUrl.length).toBeGreaterThan(1);\n      }));\n\n      it('should be generate thumb when width greater than height', fakeAsync(() => {\n        const img = new MockImage();\n        img.width = 2;\n        img.height = 1;\n        spyOn(window as NzSafeAny, 'Image').and.returnValue(img);\n\n        instance.listType = 'picture';\n        instance.items = [{ originFileObj: new File([''], '1.png', { type: 'image/' }), thumbUrl: undefined }];\n        fixture.detectChanges();\n        tick();\n        expect(instance.items[0].thumbUrl.length).toBeGreaterThan(1);\n      }));\n\n      it('should be ignore thumb when is invalid image data', () => {\n        instance.listType = 'picture';\n        instance.items = [{ originFileObj: new File([''], '1.pdf', { type: 'pdf' }), thumbUrl: undefined }];\n        fixture.detectChanges();\n        expect(instance.items[0].thumbUrl).toBe('');\n      });\n\n      it('should be customize preview file', fakeAsync(() => {\n        instance.previewFile = () => of('11');\n        instance.listType = 'picture';\n        instance.items = [{ originFileObj: new File([''], '1.png', { type: 'image/' }), thumbUrl: undefined }];\n        fixture.detectChanges();\n        tick();\n        expect(instance.items[0].thumbUrl).toBe('11');\n      }));\n    });\n  });\n\n  describe('animation', () => {\n    it('should apply animate class correctly with text', async () => {\n      const fixture = TestBed.createComponent(TestUploadListComponent);\n      await fixture.whenStable();\n\n      const items = fixture.debugElement.queryAll(By.css('.ant-upload-list-item'));\n      expect(items.length).toBeGreaterThan(0);\n      expect(items.every(item => item.nativeElement.classList.contains('ant-upload-list-animate-enter')));\n    });\n\n    for (const type of ['picture', 'picture-card']) {\n      it(`should apply animate class correctly with ${type}`, async () => {\n        const fixture = TestBed.createComponent(TestUploadListComponent);\n        await fixture.whenStable();\n\n        const items = fixture.debugElement.queryAll(By.css('.ant-upload-list-item'));\n        expect(items.length).toBeGreaterThan(0);\n        expect(items.every(item => item.nativeElement.classList.contains('ant-upload-list-animate-inline-enter')));\n      });\n    }\n\n    describe('noAnimation', () => {\n      beforeEach(() => {\n        TestBed.configureTestingModule({\n          providers: [provideNzNoAnimation()]\n        });\n      });\n\n      it('should not apply animate class correctly with text', async () => {\n        const fixture = TestBed.createComponent(TestUploadListComponent);\n        await fixture.whenStable();\n\n        const items = fixture.debugElement.queryAll(By.css('.ant-upload-list-item'));\n        expect(items.length).toBeGreaterThan(0);\n        expect(items.every(item => !item.nativeElement.classList.contains('ant-upload-list-animate-enter')));\n      });\n\n      for (const type of ['picture', 'picture-card']) {\n        it(`should apply animate class correctly with ${type}`, async () => {\n          const fixture = TestBed.createComponent(TestUploadListComponent);\n          await fixture.whenStable();\n\n          const items = fixture.debugElement.queryAll(By.css('.ant-upload-list-item'));\n          expect(items.length).toBeGreaterThan(0);\n          expect(items.every(item => !item.nativeElement.classList.contains('ant-upload-list-animate-inline-enter')));\n        });\n      }\n    });\n  });\n});\n\n@Component({\n  selector: 'nz-test-upload-list',\n  imports: [NzUploadListComponent],\n  template: `\n    <nz-upload-list\n      #list\n      [listType]=\"listType\"\n      [items]=\"items\"\n      [icons]=\"icons\"\n      [onPreview]=\"onPreview\"\n      [previewFile]=\"previewFile\"\n      [previewIsImage]=\"previewIsImage\"\n      [onRemove]=\"onRemove!\"\n    />\n  `\n})\nclass TestUploadListComponent {\n  @ViewChild('list', { static: false }) comp!: NzUploadListComponent;\n  listType: NzUploadListType = 'picture-card';\n  items: NzSafeAny[] = [\n    {\n      uid: 1,\n      name: 'xxx.png',\n      status: 'done',\n      response: 'Server Error 500', // custom error message to show\n      url: 'http://www.baidu.com/xxx.png'\n    },\n    {\n      uid: 2,\n      name: 'yyy.png',\n      status: 'done',\n      url: 'http://www.baidu.com/yyy.png'\n    },\n    {\n      uid: 3,\n      name: 'zzz.png',\n      status: 'error',\n      response: 'Server Error 500', // custom error message to show\n      url: 'http://www.baidu.com/zzz.png'\n    }\n  ];\n  icons: NzShowUploadList = {\n    showPreviewIcon: true,\n    showRemoveIcon: true\n  };\n  _onPreview = false;\n  onPreview: VoidFunction | undefined = (): void => {\n    this._onPreview = true;\n  };\n  previewFile!: (file: NzUploadFile) => Observable<string>;\n  previewIsImage!: (file: NzUploadFile) => boolean;\n  _onRemove = false;\n  onRemove: null | ((file: NzUploadFile) => void) = (): void => {\n    this._onRemove = true;\n  };\n}\n"
  },
  {
    "path": "components/upload/upload.component.html",
    "content": "<ng-template #list>\n  @if (locale && !nzFileListRender) {\n    <nz-upload-list\n      #listComp\n      [style.display]=\"nzShowUploadList ? '' : 'none'\"\n      [locale]=\"locale\"\n      [listType]=\"nzListType\"\n      [items]=\"nzFileList || []\"\n      [icons]=\"$any(nzShowUploadList)\"\n      [iconRender]=\"nzIconRender\"\n      [previewFile]=\"nzPreviewFile\"\n      [previewIsImage]=\"nzPreviewIsImage\"\n      [onPreview]=\"nzPreview\"\n      [onRemove]=\"onRemove\"\n      [onDownload]=\"nzDownload\"\n    />\n  }\n  @if (nzFileListRender) {\n    <ng-container *ngTemplateOutlet=\"nzFileListRender; context: { $implicit: nzFileList }\" />\n  }\n</ng-template>\n<ng-template #con><ng-content /></ng-template>\n<ng-template #btn>\n  <div [class]=\"classList()\" [class.ant-upload-rtl]=\"dir() === 'rtl'\" [style.display]=\"nzShowButton ? '' : 'none'\">\n    <div nz-upload-btn #uploadComp [options]=\"_btnOptions!\">\n      <ng-template [ngTemplateOutlet]=\"con\" />\n    </div>\n  </div>\n</ng-template>\n@if (nzType === 'drag') {\n  <div\n    [class]=\"classList()\"\n    [class.ant-upload-rtl]=\"dir() === 'rtl'\"\n    (drop)=\"fileDrop($event)\"\n    (dragover)=\"fileDrop($event)\"\n    (dragleave)=\"fileDrop($event)\"\n  >\n    <div nz-upload-btn #uploadComp [options]=\"_btnOptions!\" class=\"ant-upload-btn\">\n      <div class=\"ant-upload-drag-container\">\n        <ng-template [ngTemplateOutlet]=\"con\" />\n      </div>\n    </div>\n  </div>\n  <ng-template [ngTemplateOutlet]=\"list\" />\n} @else {\n  @if (nzListType === 'picture-card') {\n    <ng-template [ngTemplateOutlet]=\"list\" />\n    <ng-template [ngTemplateOutlet]=\"btn\" />\n  } @else {\n    <ng-template [ngTemplateOutlet]=\"btn\" />\n    <ng-template [ngTemplateOutlet]=\"list\" />\n  }\n}\n"
  },
  {
    "path": "components/upload/upload.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { Platform } from '@angular/cdk/platform';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n  AfterViewInit,\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DestroyRef,\n  DOCUMENT,\n  EventEmitter,\n  inject,\n  input,\n  Input,\n  numberAttribute,\n  OnChanges,\n  OnInit,\n  Output,\n  signal,\n  TemplateRef,\n  ViewChild,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Observable, of, Subscription } from 'rxjs';\nimport { filter } from 'rxjs/operators';\n\nimport { BooleanInput, NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { fromEventOutsideAngular, generateClassName, toBoolean } from 'ng-zorro-antd/core/util';\nimport { NzI18nService, NzUploadI18nInterface } from 'ng-zorro-antd/i18n';\n\nimport {\n  NzIconRenderTemplate,\n  NzShowUploadList,\n  NzUploadChangeParam,\n  NzUploadFile,\n  NzUploadListType,\n  NzUploadTransformFileType,\n  NzUploadType,\n  NzUploadXHRArgs,\n  UploadFilter,\n  ZipButtonOptions,\n  type NzBeforeUploadFileType\n} from './interface';\nimport { NzUploadBtnComponent } from './upload-btn.component';\nimport { NzUploadListComponent } from './upload-list.component';\n\nconst CLASS_NAME = 'ant-upload';\n\n@Component({\n  selector: 'nz-upload',\n  exportAs: 'nzUpload',\n  templateUrl: './upload.component.html',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    '[class.ant-upload-picture-card-wrapper]': 'nzListType === \"picture-card\"'\n  },\n  imports: [NzUploadListComponent, NgTemplateOutlet, NzUploadBtnComponent]\n})\nexport class NzUploadComponent implements OnInit, AfterViewInit, OnChanges {\n  static ngAcceptInputType_nzShowUploadList: BooleanInput | NzShowUploadList;\n\n  private readonly cdr = inject(ChangeDetectorRef);\n  private readonly i18n = inject(NzI18nService);\n  private readonly destroyRef = inject(DestroyRef);\n  private readonly document = inject(DOCUMENT);\n  private readonly platform = inject(Platform);\n  protected readonly dir = inject(Directionality).valueSignal;\n\n  @ViewChild('uploadComp', { static: false }) uploadComp!: NzUploadBtnComponent;\n  @ViewChild('listComp', { static: false }) listComp!: NzUploadListComponent;\n\n  locale!: NzUploadI18nInterface;\n\n  // #region fields\n\n  @Input() nzType: NzUploadType = 'select';\n  @Input({ transform: numberAttribute }) nzLimit = 0;\n  @Input({ transform: numberAttribute }) nzSize = 0;\n\n  @Input() nzFileType?: string;\n  @Input() nzAccept?: string | string[];\n  @Input() nzAction?: string | ((file: NzUploadFile) => string | Observable<string>);\n  @Input({ transform: booleanAttribute }) nzDirectory = false;\n  @Input({ transform: booleanAttribute }) nzOpenFileDialogOnClick = true;\n  @Input() nzBeforeUpload?: (file: NzUploadFile, fileList: NzUploadFile[]) => NzBeforeUploadFileType;\n  @Input() nzCustomRequest?: (item: NzUploadXHRArgs) => Subscription;\n  @Input() nzData?: {} | ((file: NzUploadFile) => {} | Observable<{}>);\n  @Input() nzFilter: UploadFilter[] = [];\n  @Input() nzFileList: NzUploadFile[] = [];\n  @Input({ transform: booleanAttribute }) nzDisabled = false;\n  @Input() nzHeaders?: {} | ((file: NzUploadFile) => {} | Observable<{}>);\n  @Input() nzListType: NzUploadListType = 'text';\n  @Input({ transform: booleanAttribute }) nzMultiple = false;\n  @Input() nzName = 'file';\n\n  private _showUploadList: boolean | NzShowUploadList = true;\n\n  @Input()\n  set nzShowUploadList(value: boolean | NzShowUploadList) {\n    this._showUploadList = typeof value === 'boolean' ? toBoolean(value) : value;\n  }\n\n  get nzShowUploadList(): boolean | NzShowUploadList {\n    return this._showUploadList;\n  }\n\n  @Input({ transform: booleanAttribute }) nzShowButton = true;\n  @Input({ transform: booleanAttribute }) nzWithCredentials = false;\n\n  @Input() nzRemove?: (file: NzUploadFile) => boolean | Observable<boolean>;\n  @Input() nzPreview?: (file: NzUploadFile) => void;\n  @Input() nzPreviewFile?: (file: NzUploadFile) => Observable<string>;\n  @Input() nzPreviewIsImage?: (file: NzUploadFile) => boolean;\n  /**\n   * @deprecated will be removed in v22.0.0\n   * Use `nzBeforeUpload` instead.\n   */\n  @Input() nzTransformFile?: (file: NzUploadFile) => NzUploadTransformFileType;\n  @Input() nzDownload?: (file: NzUploadFile) => void;\n  @Input() nzIconRender: NzIconRenderTemplate | null = null;\n  @Input() nzFileListRender: TemplateRef<{ $implicit: NzUploadFile[] }> | null = null;\n\n  readonly nzMaxCount = input<number>();\n\n  @Output() readonly nzChange: EventEmitter<NzUploadChangeParam> = new EventEmitter<NzUploadChangeParam>();\n  @Output() readonly nzFileListChange: EventEmitter<NzUploadFile[]> = new EventEmitter<NzUploadFile[]>();\n\n  _btnOptions?: ZipButtonOptions;\n\n  private zipOptions(): this {\n    if (typeof this.nzShowUploadList === 'boolean' && this.nzShowUploadList) {\n      this.nzShowUploadList = {\n        showPreviewIcon: true,\n        showRemoveIcon: true,\n        showDownloadIcon: true\n      };\n    }\n    // filters\n    const filters: UploadFilter[] = this.nzFilter.slice();\n    if (this.nzMultiple && this.nzLimit > 0 && filters.findIndex(w => w.name === 'limit') === -1) {\n      filters.push({\n        name: 'limit',\n        fn: (fileList: NzUploadFile[]) => fileList.slice(-this.nzLimit)\n      });\n    }\n    if (this.nzSize > 0 && filters.findIndex(w => w.name === 'size') === -1) {\n      filters.push({\n        name: 'size',\n        fn: (fileList: NzUploadFile[]) => fileList.filter(w => w.size! / 1024 <= this.nzSize)\n      });\n    }\n    if (this.nzFileType && this.nzFileType.length > 0 && filters.findIndex(w => w.name === 'type') === -1) {\n      const types = this.nzFileType.split(',');\n      filters.push({\n        name: 'type',\n        fn: (fileList: NzUploadFile[]) => fileList.filter(w => ~types.indexOf(w.type!))\n      });\n    }\n    this._btnOptions = {\n      disabled: this.nzDisabled,\n      accept: this.nzAccept,\n      action: this.nzAction,\n      directory: this.nzDirectory,\n      openFileDialogOnClick: this.nzOpenFileDialogOnClick,\n      beforeUpload: this.nzBeforeUpload,\n      customRequest: this.nzCustomRequest,\n      data: this.nzData,\n      headers: this.nzHeaders,\n      name: this.nzName,\n      multiple: this.nzMultiple,\n      withCredentials: this.nzWithCredentials,\n      filters,\n      transformFile: this.nzTransformFile,\n      onStart: this.onStart,\n      onProgress: this.onProgress,\n      onSuccess: this.onSuccess,\n      onError: this.onError\n    };\n    return this;\n  }\n\n  // #endregion\n\n  // #region upload\n\n  private fileToObject(file: NzUploadFile): NzUploadFile {\n    return {\n      lastModified: file.lastModified,\n      lastModifiedDate: file.lastModifiedDate,\n      name: file.filename || file.name,\n      size: file.size,\n      type: file.type,\n      uid: file.uid,\n      response: file.response,\n      error: file.error,\n      percent: 0,\n      originFileObj: file as NzSafeAny\n    };\n  }\n\n  private getFileItem(file: NzUploadFile, fileList: NzUploadFile[]): NzUploadFile {\n    return fileList.filter(item => item.uid === file.uid)[0];\n  }\n\n  private removeFileItem(file: NzUploadFile, fileList: NzUploadFile[]): NzUploadFile[] {\n    return fileList.filter(item => item.uid !== file.uid);\n  }\n\n  private onStart = (file: NzUploadFile): void => {\n    const maxCount = this.nzMaxCount();\n    if (!this.nzFileList) {\n      this.nzFileList = [];\n    }\n    const targetItem = this.fileToObject(file);\n    targetItem.status = 'uploading';\n    if (maxCount === 1) {\n      this.nzFileList = [targetItem];\n    } else if (!maxCount || maxCount <= 0 || this.nzFileList.length < maxCount) {\n      this.nzFileList = [...this.nzFileList, targetItem];\n    }\n    this.nzFileListChange.emit(this.nzFileList);\n    this.nzChange.emit({ file: targetItem, fileList: this.nzFileList, type: 'start' });\n    this.detectChangesList();\n  };\n\n  private onProgress = (e: { percent: number }, file: NzUploadFile): void => {\n    const fileList = this.nzFileList;\n    const targetItem = this.getFileItem(file, fileList);\n\n    if (!targetItem) {\n      return;\n    }\n\n    targetItem.percent = e.percent;\n    this.nzChange.emit({\n      event: e,\n      file: targetItem,\n      fileList: this.nzFileList,\n      type: 'progress'\n    });\n    this.detectChangesList();\n  };\n\n  private onSuccess = (res: {}, file: NzUploadFile): void => {\n    const fileList = this.nzFileList;\n    const targetItem = this.getFileItem(file, fileList);\n    if (!targetItem) {\n      return;\n    }\n    targetItem.status = 'done';\n    targetItem.response = res;\n    this.nzChange.emit({\n      file: targetItem,\n      fileList,\n      type: 'success'\n    });\n    this.detectChangesList();\n  };\n\n  private onError = (err: {}, file: NzUploadFile): void => {\n    const fileList = this.nzFileList;\n    const targetItem = this.getFileItem(file, fileList);\n\n    if (!targetItem) {\n      return;\n    }\n\n    targetItem.error = err;\n    targetItem.status = 'error';\n    this.nzChange.emit({\n      file: { ...targetItem },\n      fileList,\n      type: 'error'\n    });\n    this.detectChangesList();\n  };\n\n  // #endregion\n\n  // #region drag\n\n  private dragState?: string;\n\n  // skip safari bug\n  fileDrop(e: DragEvent): void {\n    if (e.type === this.dragState) {\n      return;\n    }\n    this.dragState = e.type;\n    this.setClassMap();\n  }\n\n  // #endregion\n\n  // #region list\n\n  private detectChangesList(): void {\n    this.cdr.detectChanges();\n    this.listComp?.detectChanges();\n  }\n\n  onRemove = (file: NzUploadFile): void => {\n    this.uploadComp.abort(file);\n    file.status = 'removed';\n    const fnRes =\n      typeof this.nzRemove === 'function' ? this.nzRemove(file) : this.nzRemove == null ? true : this.nzRemove;\n    (fnRes instanceof Observable ? fnRes : of(fnRes)).pipe(filter((res: boolean) => res)).subscribe(() => {\n      this.nzFileList = this.removeFileItem(file, this.nzFileList);\n      this.nzChange.emit({\n        file,\n        fileList: this.nzFileList,\n        type: 'removed'\n      });\n      this.nzFileListChange.emit(this.nzFileList);\n      this.cdr.detectChanges();\n    });\n  };\n\n  // #endregion\n\n  // #region styles\n\n  protected readonly classList = signal<string[]>([]);\n\n  private setClassMap(): void {\n    let subCls: string[] = [];\n    if (this.nzType === 'drag') {\n      if (this.nzFileList.some(file => file.status === 'uploading')) {\n        subCls.push(this.generateClass('drag-uploading'));\n      }\n      if (this.dragState === 'dragover') {\n        subCls.push(this.generateClass('drag-hover'));\n      }\n    } else {\n      subCls = [this.generateClass(`select-${this.nzListType}`)];\n    }\n\n    if (this.nzDisabled) {\n      subCls.push(this.generateClass('disabled'));\n    }\n\n    this.classList.set([CLASS_NAME, this.generateClass(this.nzType), ...subCls]);\n  }\n\n  // #endregion\n\n  ngOnInit(): void {\n    this.i18n.localeChange.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {\n      this.locale = this.i18n.getLocaleData('Upload');\n      this.detectChangesList();\n    });\n  }\n\n  ngAfterViewInit(): void {\n    if (this.platform.FIREFOX) {\n      // fix firefox drop open new tab\n      fromEventOutsideAngular<MouseEvent>(this.document.body, 'drop')\n        .pipe(takeUntilDestroyed(this.destroyRef))\n        .subscribe(event => {\n          event.preventDefault();\n          event.stopPropagation();\n        });\n    }\n  }\n\n  ngOnChanges(): void {\n    this.zipOptions().setClassMap();\n  }\n\n  private generateClass(suffix: string): string {\n    return generateClassName(CLASS_NAME, suffix);\n  }\n}\n"
  },
  {
    "path": "components/upload/upload.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzUploadBtnComponent } from './upload-btn.component';\nimport { NzUploadListComponent } from './upload-list.component';\nimport { NzUploadComponent } from './upload.component';\n\n@NgModule({\n  imports: [NzUploadComponent, NzUploadBtnComponent, NzUploadListComponent],\n  exports: [NzUploadComponent]\n})\nexport class NzUploadModule {}\n"
  },
  {
    "path": "components/upload/upload.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { ENTER, TAB } from '@angular/cdk/keycodes';\nimport { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';\nimport { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';\nimport {\n  ApplicationRef,\n  Component,\n  DebugElement,\n  provideZoneChangeDetection,\n  TemplateRef,\n  ViewChild\n} from '@angular/core';\nimport { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { Observable, Observer, of, throwError } from 'rxjs';\nimport { delay } from 'rxjs/operators';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { provideNzNoAnimation } from 'ng-zorro-antd/core/animation';\nimport { dispatchKeyboardEvent, provideMockDirectionality } from 'ng-zorro-antd/core/testing';\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\nimport { NzI18nService } from 'ng-zorro-antd/i18n';\nimport en_US from 'ng-zorro-antd/i18n/languages/en_US';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { provideNzIconsTesting } from 'ng-zorro-antd/icon/testing';\n\nimport {\n  NzIconRenderTemplate,\n  NzShowUploadList,\n  NzUploadChangeParam,\n  NzUploadFile,\n  NzUploadListType,\n  NzUploadTransformFileType,\n  NzUploadType,\n  UploadFilter,\n  ZipButtonOptions\n} from './interface';\nimport { NzUploadBtnComponent } from './upload-btn.component';\nimport { NzUploadListComponent } from './upload-list.component';\nimport { NzUploadComponent } from './upload.component';\nimport { NzUploadModule } from './upload.module';\n\nconst FILE_CONTENT = [\n  `iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==`\n];\nconst FILE = new File(FILE_CONTENT, '');\nconst PNG_SMALL = {\n  target: {\n    files: [\n      new File(FILE_CONTENT, 'test.png', {\n        type: 'image/png'\n      })\n    ]\n  }\n};\nconst JPG_SMALL = {\n  target: {\n    files: [\n      new File(FILE_CONTENT, 'test.jpg', {\n        type: 'image/jpg'\n      })\n    ]\n  }\n};\nconst LARGE_FILE = {\n  name: 'test.png',\n  size: 500001,\n  type: 'image/png'\n};\nconst PNG_BIG = { target: { files: { 0: LARGE_FILE, length: 1, item: () => LARGE_FILE } } };\n\nclass Item {\n  children?: Item[];\n  constructor(public name: string) {}\n}\n\ndescribe('upload', () => {\n  describe('component', () => {\n    let fixture: ComponentFixture<TestUploadComponent>;\n    let dl: DebugElement;\n    let instance: TestUploadComponent;\n    let pageObject: NzUploadPageObject;\n    let httpMock: HttpTestingController;\n\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        providers: [\n          // todo: use zoneless\n          provideZoneChangeDetection(),\n          provideNzIconsTesting(),\n          provideNzNoAnimation(),\n          provideHttpClient(withInterceptorsFromDi()),\n          provideHttpClientTesting()\n        ]\n      });\n      fixture = TestBed.createComponent(TestUploadComponent);\n      dl = fixture.debugElement;\n      instance = dl.componentInstance;\n      fixture.detectChanges();\n      pageObject = new NzUploadPageObject();\n      httpMock = TestBed.inject(HttpTestingController);\n    });\n\n    describe('[default]', () => {\n      it('should be upload a file', () => {\n        expect(instance._nzChange).toBeUndefined();\n        pageObject.postFile(FILE);\n        const req = httpMock.expectOne(instance.nzAction as string);\n        pageObject.expectChange();\n        req.flush({});\n        pageObject.expectChange('success');\n        httpMock.verify();\n      });\n\n      it('should notify progress when upload a large file', () => {\n        pageObject.postLarge();\n        const req = httpMock.expectOne(instance.nzAction as string);\n        req.event({ type: 1, loaded: 0, total: 0 });\n        pageObject.expectChange('progress');\n        req.event({ type: 1, loaded: 10, total: 100 });\n        pageObject.expectChange('progress');\n        expect(instance._nzChange.event!.percent).toBe(10);\n        req.event({ type: 1, loaded: 20, total: 100 });\n        expect(instance._nzChange.event!.percent).toBe(20);\n        req.flush({ status: 'ok' });\n        httpMock.verify();\n      });\n\n      it('should be error when using 404 http', () => {\n        pageObject.postLarge();\n        const req = httpMock.expectOne(instance.nzAction as string);\n        req.error(new ProgressEvent('network'), { status: 404, statusText: 'not found' });\n        pageObject.expectChange('error');\n        httpMock.verify();\n      });\n\n      it('should limit 2 file when allow multiple', () => {\n        instance.nzLimit = 2;\n        instance.nzMultiple = true;\n        fixture.detectChanges();\n        expect(instance._beforeUploadList.length).toBe(0);\n        pageObject.postFile([...PNG_SMALL.target.files, ...PNG_SMALL.target.files, ...PNG_SMALL.target.files]);\n        expect(instance._beforeUploadList.length).toBe(instance.nzLimit);\n      });\n\n      it('should limit png file type', () => {\n        instance.nzFileType = 'image/png';\n        fixture.detectChanges();\n        expect(instance._beforeUploadList.length).toBe(0);\n        pageObject.postFile(JPG_SMALL.target.files);\n        expect(instance._beforeUploadList.length).toBe(0);\n      });\n\n      it('should limit 1kb size', () => {\n        instance.nzSize = 1;\n        fixture.detectChanges();\n        expect(instance._beforeUploadList.length).toBe(0);\n        pageObject.postLarge();\n        expect(instance._beforeUploadList.length).toBe(0);\n      });\n\n      it('should be abort when user canceled', () => {\n        pageObject.postLarge();\n        const req = httpMock.expectOne(instance.nzAction as string);\n        req.event({ type: 1, loaded: 10, total: 100 });\n        pageObject.expectLength(1);\n        pageObject.getByCss('.anticon-delete').nativeElement.click();\n        fixture.detectChanges();\n        pageObject.expectLength(0);\n        httpMock.verify();\n      });\n\n      it('should be removed via list', () => {\n        instance.nzFileList = [\n          {\n            uid: 1,\n            name: 'xxx.png',\n            status: 'done',\n            response: 'Server Error 500', // custom error message to show\n            url: 'http://www.baidu.com/xxx.png'\n          } as NzSafeAny\n        ];\n        fixture.detectChanges();\n        pageObject.expectLength(1);\n        pageObject.getByCss('.anticon-delete').nativeElement.click();\n        fixture.detectChanges();\n        pageObject.expectLength(0);\n      });\n\n      it('should be upload a file via drag', () => {\n        instance.nzType = 'drag';\n        fixture.detectChanges();\n        instance.comp.fileDrop({ type: 'dragover' } as NzSafeAny);\n        instance.comp.fileDrop({ type: 'dragover' } as NzSafeAny);\n        fixture.detectChanges();\n        expect(pageObject.getByCss('.ant-upload-drag-hover') != null).toBe(true);\n      });\n\n      it('should be show uploading status when via drag', () => {\n        instance.nzType = 'drag';\n        instance.nzFileList = [\n          {\n            uid: 1,\n            name: 'xxx.png',\n            status: 'uploading'\n          } as NzSafeAny\n        ];\n        fixture.detectChanges();\n        expect(pageObject.getByCss('.ant-upload-drag-uploading') != null).toBe(true);\n      });\n\n      it('#i18n', () => {\n        instance.nzFileList = [\n          {\n            uid: 1,\n            name: 'xxx.png',\n            status: 'done',\n            response: 'Server Error 500', // custom error message to show\n            url: 'http://www.baidu.com/xxx.png'\n          } as NzSafeAny\n        ];\n        fixture.detectChanges();\n        TestBed.inject(NzI18nService).setLocale(en_US);\n        fixture.detectChanges();\n        const removeFileText = pageObject.getByCss('.ant-upload-list-item-card-actions-btn > .anticon-delete')\n          .nativeElement as HTMLElement;\n        expect(removeFileText.parentElement!.title).toBe(en_US.Upload.removeFile);\n      });\n    });\n\n    describe('property', () => {\n      describe('[nzActive]', () => {\n        it('should be return string when is function', () => {\n          const url = `/new-url`;\n          instance.nzAction = () => url;\n          fixture.detectChanges();\n          pageObject.postSmall();\n          const req = httpMock.expectOne(() => true);\n          expect(req.request.url).toBe(url);\n        });\n\n        it('should be return Observable when is function', () => {\n          const url = `/new-url-with-observable`;\n          instance.nzAction = () => of(url);\n          fixture.detectChanges();\n          pageObject.postSmall();\n          const req = httpMock.expectOne(() => true);\n          expect(req.request.url).toBe(url);\n        });\n      });\n\n      describe('[nzData]', () => {\n        it('should custom form data vis function', () => {\n          instance.nzData = () => ({ a: 1 });\n          fixture.detectChanges();\n          pageObject.postSmall();\n          const req = httpMock.expectOne(instance.nzAction as string);\n          expect((req.request.body as FormData).get('a')).toBe('1');\n          req.flush({});\n          httpMock.verify();\n        });\n\n        it('should custom form data via object', () => {\n          instance.nzData = { a: 1 };\n          fixture.detectChanges();\n          pageObject.postSmall();\n          const req = httpMock.expectOne(instance.nzAction as string);\n          expect((req.request.body as FormData).get('a')).toBe('1');\n          req.flush({});\n          httpMock.verify();\n        });\n\n        it('should custom form data via Observable', () => {\n          instance.nzData = () => of({ a: 1 });\n          fixture.detectChanges();\n          pageObject.postSmall();\n          const req = httpMock.expectOne(instance.nzAction as string);\n          expect((req.request.body as FormData).get('a')).toBe('1');\n          req.flush({});\n          httpMock.verify();\n        });\n\n        it('should custom filter work', () => {\n          instance.nzFilter = [{ name: 'custom', fn: () => [] }];\n          fixture.detectChanges();\n          expect(instance._beforeUploadList.length).toBe(0);\n          pageObject.postLarge();\n          expect(instance._beforeUploadList.length).toBe(0);\n        });\n      });\n\n      it('[nzDisabled]', () => {\n        instance.nzDisabled = true;\n        fixture.detectChanges();\n        expect(pageObject.getByCss('.ant-upload-disabled') != null).toBe(true);\n      });\n\n      describe('[nzHeaders]', () => {\n        it('should custom form data vis function', () => {\n          instance.nzHeaders = () => ({ a: '1' });\n          fixture.detectChanges();\n          pageObject.postSmall();\n          const req = httpMock.expectOne(instance.nzAction as string);\n          expect(req.request.headers.get('a')).toBe('1');\n          req.flush({});\n          httpMock.verify();\n        });\n\n        it('should custom form data vis object', () => {\n          instance.nzHeaders = { a: '1' };\n          fixture.detectChanges();\n          pageObject.postSmall();\n          const req = httpMock.expectOne(instance.nzAction as string);\n          expect(req.request.headers.get('a')).toBe('1');\n          req.flush({});\n          httpMock.verify();\n        });\n\n        it('should custom form data vis Observable', () => {\n          instance.nzHeaders = () => of({ a: '1' });\n          fixture.detectChanges();\n          pageObject.postSmall();\n          const req = httpMock.expectOne(instance.nzAction as string);\n          expect(req.request.headers.get('a')).toBe('1');\n          req.flush({});\n          httpMock.verify();\n        });\n\n        it('should be allow null header', () => {\n          instance.nzHeaders = null;\n          fixture.detectChanges();\n          pageObject.postSmall().expectChange();\n        });\n      });\n\n      describe('[nzTransformFile]', () => {\n        it('should be from small to big', () => {\n          instance.nzTransformFile = () => new File([`1`], `1.png`);\n          fixture.detectChanges();\n          pageObject.postLarge();\n          const req = httpMock.expectOne(instance.nzAction as string);\n          expect((req.request.body.get('file') as NzUploadFile).size).toBe(1);\n          req.flush({});\n          httpMock.verify();\n        });\n\n        it('should return Observable', () => {\n          instance.nzTransformFile = () => of(new File([`123`], `1.png`));\n          fixture.detectChanges();\n          pageObject.postLarge();\n          const req = httpMock.expectOne(instance.nzAction as string);\n          expect((req.request.body.get('file') as NzUploadFile).size).toBe(3);\n          req.flush({});\n          httpMock.verify();\n        });\n      });\n\n      describe('when nzType is drag', () => {\n        it('should working', () => {\n          instance.nzType = 'drag';\n          fixture.detectChanges();\n          expect(pageObject.getByCss('.ant-upload-drag') != null).toBe(true);\n        });\n\n        it('should be remove item', () => {\n          instance.nzType = 'drag';\n          instance.nzFileList = [\n            {\n              uid: 1,\n              name: 'xxx.png',\n              status: 'done',\n              response: 'Server Error 500', // custom error message to show\n              url: 'http://www.baidu.com/xxx.png'\n            }\n          ] as NzSafeAny[];\n          fixture.detectChanges();\n          expect(instance._onRemove).toBe(false);\n          dl.query(By.css('.anticon-delete')).nativeElement.click();\n          expect(instance._onRemove).toBe(true);\n        });\n      });\n\n      it('[nzShowButton]', () => {\n        instance.nzShowButton = false;\n        fixture.detectChanges();\n        const btnAreaEl = pageObject.getByCss(`.ant-upload-${instance.nzType}`);\n        expect(btnAreaEl.styles.display).toBe('none');\n      });\n\n      it('[nzWithCredentials]', () => {\n        instance.nzWithCredentials = true;\n        fixture.detectChanges();\n        pageObject.postSmall();\n        const req = httpMock.expectOne(instance.nzAction as string);\n        expect(req.request.withCredentials).toBe(true);\n        req.flush({});\n        httpMock.verify();\n      });\n\n      describe('[nzBeforeUpload]', () => {\n        it('should be allow null', () => {\n          instance.beforeUpload = null;\n          fixture.detectChanges();\n          expect(instance._beforeUpload).toBe(false);\n          pageObject.postSmall();\n          expect(instance._beforeUpload).toBe(false);\n        });\n\n        describe('using observable', () => {\n          it('can return true', () => {\n            spyOn(instance, 'nzChange');\n            instance.beforeUpload = (): Observable<NzSafeAny> => of(true);\n            fixture.detectChanges();\n            pageObject.postSmall();\n            expect(instance.nzChange).toHaveBeenCalled();\n          });\n\n          it('can return same file', () => {\n            let ret = false;\n            instance.beforeUpload = (file: NzUploadFile): Observable<NzSafeAny> => {\n              ret = true;\n              return of(file);\n            };\n            fixture.detectChanges();\n            pageObject.postSmall();\n            expect(ret).toBe(true);\n          });\n\n          it('can return a string file', () => {\n            let ret = false;\n            instance.beforeUpload = (): Observable<NzSafeAny> => {\n              ret = true;\n              return of('file');\n            };\n            fixture.detectChanges();\n            pageObject.postSmall();\n            expect(ret).toBe(true);\n          });\n\n          it('can return a blob file', () => {\n            let ret = false;\n            instance.beforeUpload = (): Observable<NzSafeAny> => {\n              ret = true;\n              return of(new Blob([JSON.stringify(1, null, 2)], { type: 'application/json' }));\n            };\n            fixture.detectChanges();\n            pageObject.postSmall();\n            expect(ret).toBe(true);\n          });\n\n          it('cancel upload when return a false value', () => {\n            expect(instance._nzChange).toBeUndefined();\n            instance.beforeUpload = (): Observable<NzSafeAny> => of(false);\n            fixture.detectChanges();\n            pageObject.postSmall();\n            expect(instance._nzChange).toBeUndefined();\n          });\n\n          it('should be console.warn error', () => {\n            let warnMsg = '';\n            console.warn = jasmine.createSpy().and.callFake((...res: string[]) => (warnMsg = res.join(' ')));\n            expect(instance._nzChange).toBeUndefined();\n            instance.beforeUpload = (): Observable<NzSafeAny> => throwError(() => '');\n            fixture.detectChanges();\n            pageObject.postSmall();\n            expect(warnMsg).toContain(`Unhandled upload beforeUpload error`);\n          });\n        });\n\n        describe('using promise', () => {\n          it('should upload when promise resolves to true', fakeAsync(() => {\n            let hookExecuted = false;\n            instance.beforeUpload = (): Promise<boolean> => {\n              hookExecuted = true;\n              return Promise.resolve(true);\n            };\n            fixture.detectChanges();\n            pageObject.postSmall();\n            tick();\n            expect(hookExecuted).toBe(true);\n          }));\n\n          it('should upload when promise resolves to file', fakeAsync(() => {\n            let hookExecuted = false;\n            instance.beforeUpload = (file: NzUploadFile): Promise<NzUploadFile> => {\n              hookExecuted = true;\n              return Promise.resolve(file);\n            };\n            fixture.detectChanges();\n            pageObject.postSmall();\n            tick();\n            expect(hookExecuted).toBe(true);\n          }));\n\n          it('should upload with blob when promise resolves to blob', fakeAsync(() => {\n            let hookExecuted = false;\n            const testBlob = new Blob(['test content'], { type: 'text/plain' });\n            instance.beforeUpload = (): Promise<Blob> => {\n              hookExecuted = true;\n              return Promise.resolve(testBlob);\n            };\n            fixture.detectChanges();\n            pageObject.postSmall();\n            tick();\n            expect(hookExecuted).toBe(true);\n          }));\n\n          it('should cancel upload when promise resolves to false', fakeAsync(() => {\n            expect(instance._nzChange).toBeUndefined();\n            instance.beforeUpload = (): Promise<boolean> => Promise.resolve(false);\n            fixture.detectChanges();\n            pageObject.postSmall();\n            tick();\n            expect(instance._nzChange).toBeUndefined();\n          }));\n\n          it('should work with promise that resolves to boolean true', fakeAsync(() => {\n            let hookCalled = false;\n            instance.beforeUpload = (): Promise<boolean> => {\n              hookCalled = true;\n              return Promise.resolve(true);\n            };\n            fixture.detectChanges();\n            pageObject.postSmall();\n            tick();\n            expect(hookCalled).toBe(true);\n          }));\n\n          it('should cancel upload when promise rejects with false', fakeAsync(() => {\n            expect(instance._nzChange).toBeUndefined();\n            instance.beforeUpload = (): Promise<boolean> => Promise.reject(false);\n            fixture.detectChanges();\n            pageObject.postSmall();\n            tick();\n            expect(instance._nzChange).toBeUndefined();\n          }));\n        });\n      });\n\n      describe('[nzFilter]', () => {\n        it('should be custom limit', () => {\n          instance.nzMultiple = true;\n          instance.nzLimit = 1;\n          instance.nzFilter = [\n            {\n              name: 'limit',\n              fn: (fileList: NzUploadFile[]) => fileList.slice(-instance.nzLimit)\n            }\n          ];\n          fixture.detectChanges();\n          expect(instance._beforeUploadList.length).toBe(0);\n          pageObject.postFile([...PNG_SMALL.target.files, ...PNG_SMALL.target.files, ...PNG_SMALL.target.files]);\n          expect(instance._beforeUploadList.length).toBe(instance.nzLimit);\n        });\n\n        it('should be custom size', () => {\n          instance.nzSize = 1;\n          instance.nzFilter = [\n            {\n              name: 'size',\n              fn: (fileList: NzUploadFile[]) => fileList.filter(w => w.size! / 1024 <= instance.nzSize)\n            }\n          ];\n          fixture.detectChanges();\n          expect(instance._beforeUploadList.length).toBe(0);\n          pageObject.postLarge();\n          expect(instance._beforeUploadList.length).toBe(0);\n        });\n\n        it('should be custom type', () => {\n          instance.nzFileType = 'image/png';\n          instance.nzFilter = [\n            {\n              name: 'type',\n              fn: (fileList: NzUploadFile[]) => fileList.filter(w => ~[instance.nzFileType].indexOf(w.type))\n            }\n          ];\n          fixture.detectChanges();\n          expect(instance._beforeUploadList.length).toBe(0);\n          pageObject.postFile(JPG_SMALL.target.files);\n          expect(instance._beforeUploadList.length).toBe(0);\n        });\n\n        describe('with Observable', () => {\n          it('should working', () => {\n            instance.nzFilter = [\n              {\n                name: 'f1',\n                fn: (fileList: NzUploadFile[]) =>\n                  new Observable((observer: Observer<NzUploadFile[]>) => {\n                    observer.next(fileList.slice(1));\n                    observer.complete();\n                  })\n              },\n              {\n                name: 'f2',\n                fn: (fileList: NzUploadFile[]) =>\n                  new Observable((observer: Observer<NzUploadFile[]>) => {\n                    observer.next(fileList.slice(1));\n                    observer.complete();\n                  })\n              }\n            ];\n            fixture.detectChanges();\n            expect(instance._beforeUploadList.length).toBe(0);\n            pageObject.postFile([...PNG_SMALL.target.files, ...PNG_SMALL.target.files, ...PNG_SMALL.target.files]);\n            expect(instance._beforeUploadList.length).toBe(1);\n          });\n\n          it('should be console.warn error', () => {\n            let warnMsg = '';\n            console.warn = jasmine.createSpy().and.callFake((...res: string[]) => (warnMsg = res.join(' ')));\n            instance.nzFilter = [\n              {\n                name: 'f1',\n                fn: () =>\n                  new Observable((observer: Observer<NzUploadFile[]>) => {\n                    observer.error('filter error');\n                  })\n              }\n            ];\n            fixture.detectChanges();\n            pageObject.postFile(PNG_SMALL.target.files);\n            expect(warnMsg).toContain(`Unhandled upload filter error`);\n          });\n        });\n      });\n\n      it('#nzFileList, should be allow empty', () => {\n        instance.nzFileList = null!;\n        fixture.detectChanges();\n        expect(instance._nzChange).toBeUndefined();\n        pageObject.postFile(FILE);\n        const req = httpMock.expectOne(instance.nzAction as string);\n        pageObject.expectChange();\n        req.flush({});\n        pageObject.expectChange('success');\n        httpMock.verify();\n      });\n\n      describe('[nzRemove]', () => {\n        const count = 3;\n\n        beforeEach(() => {\n          instance.nzFileList = [\n            {\n              uid: 1,\n              name: 'xxx.png',\n              status: 'done',\n              response: 'Server Error 500', // custom error message to show\n              url: 'http://www.baidu.com/xxx.png'\n            },\n            {\n              uid: 2,\n              name: 'yyy.png',\n              status: 'done',\n              url: 'http://www.baidu.com/yyy.png'\n            },\n            {\n              uid: 3,\n              name: 'zzz.png',\n              status: 'error',\n              response: 'Server Error 500', // custom error message to show\n              url: 'http://www.baidu.com/zzz.png'\n            }\n          ] as NzSafeAny[];\n          fixture.detectChanges();\n        });\n\n        it('should be return a Observable', () => {\n          instance.onRemove = () => of(false);\n          fixture.detectChanges();\n          expect(dl.queryAll(By.css('.anticon-delete')).length).toBe(count);\n          dl.query(By.css('.anticon-delete')).nativeElement.click();\n          expect(dl.queryAll(By.css('.anticon-delete')).length).toBe(count);\n        });\n\n        it('should be return a Observable includes a delay operation', (done: () => void) => {\n          const DELAY = 20;\n          instance.onRemove = () => of(true).pipe(delay(DELAY));\n          fixture.detectChanges();\n          expect(dl.queryAll(By.css('.anticon-delete')).length).toBe(count);\n          dl.query(By.css('.anticon-delete')).nativeElement.click();\n          setTimeout(() => {\n            expect(dl.queryAll(By.css('.anticon-delete')).length).toBe(count - 1);\n            done();\n          }, DELAY + 1);\n        });\n\n        it('should be return a truth value', () => {\n          instance.onRemove = () => true;\n          fixture.detectChanges();\n          expect(dl.queryAll(By.css('.anticon-delete')).length).toBe(count);\n          dl.query(By.css('.anticon-delete')).nativeElement.click();\n          expect(dl.queryAll(By.css('.anticon-delete')).length).toBe(count - 1);\n        });\n\n        it('should be return a falsy value', () => {\n          instance.onRemove = () => false;\n          fixture.detectChanges();\n          expect(dl.queryAll(By.css('.anticon-delete')).length).toBe(count);\n          dl.query(By.css('.anticon-delete')).nativeElement.click();\n          expect(dl.queryAll(By.css('.anticon-delete')).length).toBe(count);\n        });\n\n        it('should be with null', () => {\n          instance.onRemove = undefined;\n          fixture.detectChanges();\n          expect(dl.queryAll(By.css('.anticon-delete')).length).toBe(count);\n          dl.query(By.css('.anticon-delete')).nativeElement.click();\n          expect(dl.queryAll(By.css('.anticon-delete')).length).toBe(count - 1);\n        });\n      });\n\n      describe('[nzListType]', () => {\n        describe(`should be only allow type is picture or picture-card generate thumbnail`, () => {\n          it('with text', () => {\n            instance.nzListType = 'text';\n            fixture.detectChanges();\n            pageObject.postSmall();\n            fixture.detectChanges();\n            expect(instance.comp.nzFileList[0].thumbUrl).toBeUndefined();\n          });\n\n          it('with picture', () => {\n            instance.nzListType = 'picture';\n            fixture.detectChanges();\n            pageObject.postSmall();\n            fixture.detectChanges();\n            expect(instance.comp.nzFileList[0].thumbUrl).not.toBeUndefined();\n          });\n        });\n      });\n\n      it('#nzIconRender', () => {\n        instance.nzFileList = [\n          {\n            uid: 1,\n            name: 'xxx.png',\n            status: 'uploading'\n          } as NzSafeAny\n        ];\n        instance.nzIconRender = instance.customIconRender;\n        fixture.detectChanges();\n        const el = pageObject.getByCss(`.customIconRender`);\n        expect(el != null).toBe(true);\n        expect((el.nativeElement as HTMLElement).textContent).toBe('asdf');\n      });\n\n      it('#nzFileListRender', () => {\n        instance.nzFileList = [\n          {\n            uid: 1,\n            name: 'xxx.png',\n            status: 'uploading'\n          } as NzSafeAny\n        ];\n        instance.nzFileListRender = instance.fileListRender;\n        fixture.detectChanges();\n        const el = pageObject.getByCss(`.fileListRender`);\n        expect(el != null).toBe(true);\n        expect((el.nativeElement as HTMLElement).textContent).toBe('asdf');\n      });\n\n      describe('[nzMaxCount]', () => {\n        it('should replace existing file when nzMaxCount is 1', () => {\n          instance.nzMaxCount = 1;\n          instance.nzFileList = [\n            {\n              uid: 1,\n              name: 'existing.png',\n              status: 'done'\n            } as NzSafeAny\n          ];\n          fixture.detectChanges();\n\n          expect(instance.nzFileList.length).toBe(1);\n          expect(instance.nzFileList[0].name).toBe('existing.png');\n\n          // Upload a new file\n          pageObject.postSmall();\n          const req = httpMock.expectOne(instance.nzAction as string);\n          req.flush({});\n\n          // Should replace the existing file\n          expect(instance.nzFileList.length).toBe(1);\n          expect(instance.nzFileList[0].name).toBe('test.png');\n        });\n\n        it('should limit files when nzMaxCount is greater than 1', () => {\n          instance.nzMaxCount = 2;\n          instance.nzFileList = [];\n          fixture.detectChanges();\n\n          // Upload first file\n          pageObject.postSmall();\n          let req = httpMock.expectOne(instance.nzAction as string);\n          req.flush({});\n          expect(instance.nzFileList.length).toBe(1);\n\n          // Upload second file\n          pageObject.postFile([new File(['content'], 'second.png', { type: 'image/png' })]);\n          req = httpMock.expectOne(instance.nzAction as string);\n          req.flush({});\n          expect(instance.nzFileList.length).toBe(2);\n\n          // Upload third file - upload happens but file is not added to list due to max count\n          pageObject.postFile([new File(['content'], 'third.png', { type: 'image/png' })]);\n          req = httpMock.expectOne(instance.nzAction as string);\n          req.flush({});\n          // File list should still be 2 because max count prevents adding more files\n          expect(instance.nzFileList.length).toBe(2);\n        });\n\n        it('should allow unlimited files when nzMaxCount is undefined', () => {\n          instance.nzMaxCount = undefined;\n          instance.nzFileList = [];\n          fixture.detectChanges();\n\n          // Upload multiple files\n          for (let i = 0; i < 5; i++) {\n            pageObject.postFile([new File(['content'], `file${i}.png`, { type: 'image/png' })]);\n            const req = httpMock.expectOne(instance.nzAction as string);\n            req.flush({});\n          }\n\n          expect(instance.nzFileList.length).toBe(5);\n        });\n\n        it('should only accept positive values for nzMaxCount', () => {\n          // Test with positive value (should limit)\n          instance.nzMaxCount = 2;\n          instance.nzFileList = [];\n          fixture.detectChanges();\n\n          // Upload first file\n          pageObject.postSmall();\n          let req = httpMock.expectOne(instance.nzAction as string);\n          req.flush({});\n          expect(instance.nzFileList.length).toBe(1);\n\n          // Upload second file\n          pageObject.postFile([new File(['content'], 'second.png', { type: 'image/png' })]);\n          req = httpMock.expectOne(instance.nzAction as string);\n          req.flush({});\n          expect(instance.nzFileList.length).toBe(2);\n\n          // Upload third file - should not be added due to limit\n          pageObject.postFile([new File(['content'], 'third.png', { type: 'image/png' })]);\n          req = httpMock.expectOne(instance.nzAction as string);\n          req.flush({});\n          expect(instance.nzFileList.length).toBe(2); // Still 2, not 3\n        });\n\n        it('should handle edge cases for nzMaxCount', () => {\n          // Test with 0 (should behave like undefined - no limit)\n          instance.nzMaxCount = 0;\n          instance.nzFileList = [];\n          fixture.detectChanges();\n\n          pageObject.postSmall();\n          let req = httpMock.expectOne(instance.nzAction as string);\n          req.flush({});\n          expect(instance.nzFileList.length).toBe(1);\n\n          // Add another file to confirm no limit with 0\n          pageObject.postFile([new File(['content'], 'second.png', { type: 'image/png' })]);\n          req = httpMock.expectOne(instance.nzAction as string);\n          req.flush({});\n          expect(instance.nzFileList.length).toBe(2);\n\n          // Test with negative value (should behave like undefined - no limit)\n          instance.nzMaxCount = -1;\n          fixture.detectChanges();\n\n          pageObject.postFile([new File(['content'], 'third.png', { type: 'image/png' })]);\n          req = httpMock.expectOne(instance.nzAction as string);\n          req.flush({});\n          expect(instance.nzFileList.length).toBe(3);\n        });\n\n        it('should work with existing nzLimit when both are set', () => {\n          instance.nzMaxCount = 3;\n          instance.nzLimit = 2; // This should be overridden by nzMaxCount logic\n          instance.nzMultiple = true;\n          fixture.detectChanges();\n\n          // Upload files one by one to test the maxCount behavior\n          pageObject.postSmall();\n          let req = httpMock.expectOne(instance.nzAction as string);\n          req.flush({});\n          expect(instance.nzFileList.length).toBe(1);\n\n          pageObject.postFile([new File(['content'], 'second.png', { type: 'image/png' })]);\n          req = httpMock.expectOne(instance.nzAction as string);\n          req.flush({});\n          expect(instance.nzFileList.length).toBe(2);\n\n          pageObject.postFile([new File(['content'], 'third.png', { type: 'image/png' })]);\n          req = httpMock.expectOne(instance.nzAction as string);\n          req.flush({});\n          expect(instance.nzFileList.length).toBe(3);\n\n          // Fourth file - upload happens but file is not added to list due to max count\n          pageObject.postFile([new File(['content'], 'fourth.png', { type: 'image/png' })]);\n          req = httpMock.expectOne(instance.nzAction as string);\n          req.flush({});\n          // File list should still be 3 because max count prevents adding more files\n          expect(instance.nzFileList.length).toBe(3);\n        });\n      });\n    });\n\n    describe('CORS', () => {\n      it('should be auto setting [X-Requested-With]', () => {\n        pageObject.postSmall();\n        const req = httpMock.expectOne(instance.nzAction as string);\n        expect(req.request.headers.get('X-Requested-With')).toBe('XMLHttpRequest');\n        req.flush({});\n        httpMock.verify();\n      });\n\n      it('should be allow override [X-Requested-With]', () => {\n        instance.nzHeaders = {\n          'X-Requested-With': null\n        };\n        fixture.detectChanges();\n        pageObject.postSmall();\n        const req = httpMock.expectOne(instance.nzAction as string);\n        expect(req.request.headers.has('X-Requested-With')).toBe(false);\n        req.flush({});\n        httpMock.verify();\n      });\n    });\n\n    describe('[test boundary]', () => {\n      it('clean a not exists request', () => {\n        instance.comp.uploadComp.reqs = {};\n        instance.show = false;\n        fixture.detectChanges();\n        expect(true).toBe(true);\n      });\n    });\n\n    class NzUploadPageObject {\n      private files: NzSafeAny;\n\n      constructor() {\n        spyOn(this.btnComp, 'onClick').and.callFake(() =>\n          this.btnComp.onChange({ target: { files: this.files } } as NzSafeAny)\n        );\n      }\n\n      get btnEl(): DebugElement {\n        return dl.query(By.directive(NzUploadBtnComponent));\n      }\n\n      get btnComp(): NzUploadBtnComponent {\n        return this.btnEl.injector.get(NzUploadBtnComponent) as NzUploadBtnComponent;\n      }\n\n      getByCss(css: string): DebugElement {\n        return dl.query(By.css(css));\n      }\n\n      postFile(files: NzSafeAny): this {\n        this.files = Array.isArray(files) ? files : [files];\n        this.btnEl.nativeElement.click();\n        return this;\n      }\n\n      postSmall(): this {\n        this.postFile(PNG_SMALL.target.files);\n        return this;\n      }\n\n      postLarge(): this {\n        this.postFile(PNG_BIG.target.files);\n        return this;\n      }\n\n      expectChange(type: string = 'start'): this {\n        expect(instance._nzChange.type).toBe(type);\n        return this;\n      }\n\n      expectLength(value: number = 0): this {\n        expect(instance.nzFileList!.length).toBe(value);\n        return this;\n      }\n    }\n  });\n\n  describe('btn', () => {\n    describe('component', () => {\n      let fixture: ComponentFixture<TestUploadBtnComponent>;\n      let dl: DebugElement;\n      let instance: TestUploadBtnComponent;\n\n      beforeEach(() => {\n        TestBed.configureTestingModule({\n          providers: [\n            // todo: use zoneless\n            provideZoneChangeDetection(),\n            provideNzIconsTesting(),\n            provideNzNoAnimation(),\n            provideHttpClient(withInterceptorsFromDi()),\n            provideHttpClientTesting()\n          ]\n        });\n        fixture = TestBed.createComponent(TestUploadBtnComponent);\n        dl = fixture.debugElement;\n        instance = dl.componentInstance;\n        fixture.detectChanges();\n      });\n\n      describe('should trigger upload', () => {\n        describe('change detection', () => {\n          it('should not run change detection when the <input type=file> is being clicked', () => {\n            const appRef = TestBed.inject(ApplicationRef);\n            spyOn(appRef, 'tick');\n            spyOn(instance.comp.file.nativeElement, 'click');\n            expect(instance.comp.file.nativeElement.click).not.toHaveBeenCalled();\n            fixture.debugElement.query(By.css('div')).nativeElement.click();\n            // Caretaker note: previously click events on the `nz-upload-btn` elements did trigger\n            // change detection since they were added via the `host` property.\n            expect(appRef.tick).toHaveBeenCalledTimes(0);\n            expect(instance.comp.file.nativeElement.click).toHaveBeenCalled();\n          });\n        });\n\n        describe('via onClick', () => {\n          it('', () => {\n            spyOn(instance.comp.file.nativeElement, 'click');\n            expect(instance.comp.file.nativeElement.click).not.toHaveBeenCalled();\n            instance.comp.onClick();\n            expect(instance.comp.file.nativeElement.click).toHaveBeenCalled();\n          });\n\n          it(', when nzOpenFileDialogOnClick is false', () => {\n            instance.options.openFileDialogOnClick = false;\n            spyOn(instance.comp.file.nativeElement, 'click');\n            expect(instance.comp.file.nativeElement.click).not.toHaveBeenCalled();\n            instance.comp.onClick();\n            expect(instance.comp.file.nativeElement.click).not.toHaveBeenCalled();\n          });\n        });\n\n        describe('via onKeyDown', () => {\n          it('normal', () => {\n            const appRef = TestBed.inject(ApplicationRef);\n            spyOn(appRef, 'tick');\n            spyOn(instance.comp, 'onClick');\n            expect(instance.comp.onClick).not.toHaveBeenCalled();\n            const uploadBtn = fixture.debugElement.query(By.css('div')).nativeElement;\n            dispatchKeyboardEvent(uploadBtn, 'keydown', ENTER);\n            expect(instance.comp.onClick).toHaveBeenCalled();\n            expect(appRef.tick).toHaveBeenCalledTimes(0);\n          });\n\n          it('when expect Enter', () => {\n            const appRef = TestBed.inject(ApplicationRef);\n            spyOn(appRef, 'tick');\n            spyOn(instance.comp, 'onClick');\n            expect(instance.comp.onClick).not.toHaveBeenCalled();\n            const uploadBtn = fixture.debugElement.query(By.css('div')).nativeElement;\n            dispatchKeyboardEvent(uploadBtn, 'keydown', TAB);\n            expect(instance.comp.onClick).not.toHaveBeenCalled();\n            expect(appRef.tick).toHaveBeenCalledTimes(0);\n          });\n        });\n\n        describe('via Drop', () => {\n          it('normal', () => {\n            spyOn(instance.comp, 'uploadFiles');\n            expect(instance.comp.uploadFiles).not.toHaveBeenCalled();\n            instance.comp.onFileDrop({\n              type: 'dragend',\n              dataTransfer: { files: [FILE] },\n              preventDefault: () => {}\n            } as NzSafeAny);\n            expect(instance.comp.uploadFiles).toHaveBeenCalled();\n          });\n\n          it('when dragover event', () => {\n            spyOn(instance.comp, 'uploadFiles');\n            expect(instance.comp.uploadFiles).not.toHaveBeenCalled();\n            instance.comp.onFileDrop({ type: 'dragover', preventDefault: () => {} } as NzSafeAny);\n            expect(instance.comp.uploadFiles).not.toHaveBeenCalled();\n          });\n\n          it('limit gif using resource type', () => {\n            instance.options.accept = 'image/gif';\n            fixture.detectChanges();\n            spyOn(instance.comp, 'uploadFiles');\n            expect(instance.comp.uploadFiles).not.toHaveBeenCalled();\n            instance.comp.onFileDrop({\n              type: 'dragend',\n              dataTransfer: { files: PNG_SMALL.target.files },\n              preventDefault: () => {}\n            } as NzSafeAny);\n            expect(instance.comp.uploadFiles).not.toHaveBeenCalled();\n          });\n\n          it('limit gif using file name', () => {\n            instance.options.accept = '.gif';\n            fixture.detectChanges();\n            spyOn(instance.comp, 'uploadFiles');\n            expect(instance.comp.uploadFiles).not.toHaveBeenCalled();\n            instance.comp.onFileDrop({\n              type: 'dragend',\n              dataTransfer: { files: PNG_SMALL.target.files },\n              preventDefault: () => {}\n            } as NzSafeAny);\n            expect(instance.comp.uploadFiles).not.toHaveBeenCalled();\n          });\n\n          it('allow type image/*', () => {\n            instance.options.accept = 'image/*';\n            fixture.detectChanges();\n            spyOn(instance.comp, 'uploadFiles');\n            expect(instance.comp.uploadFiles).not.toHaveBeenCalled();\n            instance.comp.onFileDrop({\n              type: 'dragend',\n              dataTransfer: { files: PNG_SMALL.target.files },\n              preventDefault: () => {}\n            } as NzSafeAny);\n            expect(instance.comp.uploadFiles).toHaveBeenCalled();\n          });\n\n          it(`allow type [ 'image/png', 'image/jpg' ]`, () => {\n            instance.options.accept = ['image/png', 'image/jpg'];\n            fixture.detectChanges();\n            spyOn(instance.comp, 'uploadFiles');\n            expect(instance.comp.uploadFiles).not.toHaveBeenCalled();\n            instance.comp.onFileDrop({\n              type: 'dragend',\n              dataTransfer: { files: PNG_SMALL.target.files },\n              preventDefault: () => {}\n            } as NzSafeAny);\n            expect(instance.comp.uploadFiles).toHaveBeenCalled();\n          });\n        });\n\n        it('via onChange', () => {\n          spyOn(instance.comp, 'uploadFiles');\n          expect(instance.comp.uploadFiles).not.toHaveBeenCalled();\n          instance.comp.onChange(PNG_SMALL as NzSafeAny);\n          expect(instance.comp.uploadFiles).toHaveBeenCalled();\n        });\n\n        describe('via directory', () => {\n          const makeFileSystemEntry = (item: Item): FileSystemEntry => {\n            const isDirectory = Array.isArray(item.children);\n            return {\n              isDirectory,\n              isFile: !isDirectory,\n              file: (handle: NzSafeAny): void => {\n                handle(new Item(item.name));\n              },\n              createReader: () => ({\n                readEntries: (handle: NzSafeAny) => handle(item.children!.map(makeFileSystemEntry))\n              })\n            } as unknown as FileSystemEntry;\n          };\n          const makeDataTransferItem = (item: Item): DataTransferItem =>\n            ({\n              webkitGetAsEntry: () => makeFileSystemEntry(item)\n            }) as DataTransferItem;\n\n          beforeEach(() => (instance.options.directory = true));\n\n          it('should working', () => {\n            spyOn(instance.comp, 'uploadFiles');\n            const files = {\n              name: 'foo',\n              children: [\n                {\n                  name: 'bar',\n                  children: [\n                    {\n                      name: 'is.webp'\n                    }\n                  ]\n                }\n              ]\n            };\n            instance.comp.onFileDrop({\n              type: 'dragend',\n              dataTransfer: {\n                items: [makeDataTransferItem(files)]\n              },\n              preventDefault: () => {}\n            } as NzSafeAny);\n            expect(instance.comp.uploadFiles).toHaveBeenCalled();\n          });\n\n          it('should be ignore invalid extension', () => {\n            instance.options.accept = ['.webp'];\n            spyOn(instance.comp, 'uploadFiles');\n            const files = {\n              name: 'foo',\n              children: [\n                {\n                  name: 'is.jpg'\n                }\n              ]\n            };\n            instance.comp.onFileDrop({\n              type: 'dragend',\n              dataTransfer: {\n                items: [makeDataTransferItem(files)]\n              },\n              preventDefault: () => {}\n            } as NzSafeAny);\n            expect(instance.comp.uploadFiles).not.toHaveBeenCalled();\n          });\n        });\n      });\n\n      describe('should be disabled upload', () => {\n        beforeEach(() => {\n          instance.options.disabled = true;\n          fixture.detectChanges();\n        });\n\n        it('[onClick]', () => {\n          spyOn<NzSafeAny>(instance.comp, 'file');\n          expect(instance.comp.file).not.toHaveBeenCalled();\n          instance.comp.onClick();\n          expect(instance.comp.file).not.toHaveBeenCalled();\n        });\n\n        it('[onKeyDown]', () => {\n          spyOn(instance.comp, 'onClick');\n          expect(instance.comp.onClick).not.toHaveBeenCalled();\n          // instance.comp.onKeyDown(null);\n          // expect(instance.comp.onClick).not.toHaveBeenCalled();\n        });\n\n        it('[onFileDrop]', () => {\n          spyOn(instance.comp, 'uploadFiles');\n          expect(instance.comp.uploadFiles).not.toHaveBeenCalled();\n          instance.comp.onFileDrop({ type: 'dragover', preventDefault: () => {} } as NzSafeAny);\n          expect(instance.comp.uploadFiles).not.toHaveBeenCalled();\n        });\n\n        it('[onChange]', () => {\n          spyOn(instance.comp, 'uploadFiles');\n          expect(instance.comp.uploadFiles).not.toHaveBeenCalled();\n          // instance.comp.onChange(null);\n          // expect(instance.comp.uploadFiles).not.toHaveBeenCalled();\n        });\n      });\n\n      describe('when has destroy', () => {\n        it('should be abort all uploading file', () => {\n          instance.comp.onChange({\n            target: {\n              files: [...PNG_SMALL.target.files, ...JPG_SMALL.target.files]\n            }\n          } as NzSafeAny);\n          expect(Object.keys(instance.comp.reqs).length).toBe(2);\n          fixture.destroy();\n          expect(Object.keys(instance.comp.reqs).length).toBe(0);\n        });\n\n        it('should be subsequent uploading', () => {\n          instance.comp.onChange(PNG_SMALL as NzSafeAny);\n          expect(Object.keys(instance.comp.reqs).length).toBe(1);\n          fixture.destroy();\n          instance.comp.onChange(PNG_SMALL as NzSafeAny);\n          expect(Object.keys(instance.comp.reqs).length).toBe(0);\n        });\n      });\n    });\n\n    describe('methods', () => {\n      let fixture: ComponentFixture<NzUploadBtnComponent>;\n      let comp: NzUploadBtnComponent;\n      let http: HttpTestingController;\n\n      beforeEach(() => {\n        TestBed.configureTestingModule({\n          // todo: use zoneless\n          providers: [\n            provideZoneChangeDetection(),\n            provideHttpClient(withInterceptorsFromDi()),\n            provideHttpClientTesting()\n          ]\n        });\n        fixture = TestBed.createComponent(NzUploadBtnComponent);\n        comp = fixture.debugElement.componentInstance;\n        comp.options = {\n          action: '/test',\n          accept: 'image/png',\n          filters: [],\n          data: { a: 1 },\n          headers: { token: 'asdf' },\n          name: 'avatar',\n          multiple: true,\n          withCredentials: true,\n          beforeUpload: () => true,\n          onStart: () => {},\n          onProgress: () => {},\n          onSuccess: () => {},\n          onError: () => {}\n        } as ZipButtonOptions;\n        http = TestBed.inject(HttpTestingController);\n      });\n\n      it('should uploading a png file', fakeAsync(() => {\n        spyOn<NzSafeAny>(comp.options, 'onStart');\n        spyOn<NzSafeAny>(comp.options, 'onProgress');\n        spyOn<NzSafeAny>(comp.options, 'onSuccess');\n        comp.onChange(PNG_SMALL as NzSafeAny);\n        tick(1);\n        const req = http.expectOne('/test');\n        req.event({ type: 1, loaded: 10, total: 100 });\n        req.flush('ok');\n        expect(comp.options.onProgress).toHaveBeenCalled();\n        expect(comp.options.onStart).toHaveBeenCalled();\n        expect(comp.options.onSuccess).toHaveBeenCalled();\n      }));\n\n      it('should contain the parameters of http request', fakeAsync(() => {\n        comp.onChange(PNG_SMALL as NzSafeAny);\n        tick(1);\n        const req = http.expectOne('/test');\n        expect(req.request.withCredentials).toBe(true);\n        expect(req.request.headers.get('token')).toBe('asdf');\n        const body = req.request.body as FormData;\n        expect(body.has('avatar')).toBe(true);\n        expect(body.has('a')).toBe(true);\n        req.flush('ok');\n      }));\n\n      it('should filter size', () => {\n        spyOn<NzSafeAny>(comp.options, 'onStart');\n        comp.options.filters = [\n          {\n            name: '',\n            fn: (fileList: NzUploadFile[]) => fileList.filter(w => w.size! / 1024 <= 0)\n          }\n        ];\n        comp.onChange(PNG_BIG as NzSafeAny);\n        expect(comp.options.onStart).not.toHaveBeenCalled();\n      });\n\n      it('should be no request when beforeUpload is false', () => {\n        spyOn<NzSafeAny>(comp.options, 'beforeUpload').and.returnValue(false);\n        spyOn<NzSafeAny>(comp.options, 'onStart');\n        comp.onChange(PNG_SMALL as NzSafeAny);\n        expect(comp.options.beforeUpload).toHaveBeenCalled();\n        expect(comp.options.onStart).not.toHaveBeenCalled();\n      });\n\n      it('should handle promise-based beforeUpload that resolves to true', fakeAsync(() => {\n        spyOn<NzSafeAny>(comp.options, 'onStart');\n        comp.options.beforeUpload = (): Promise<boolean> => Promise.resolve(true);\n        comp.onChange(PNG_SMALL as NzSafeAny);\n        tick();\n        const req = http.expectOne('/test');\n        expect(comp.options.onStart).toHaveBeenCalled();\n        req.flush('ok');\n      }));\n\n      it('should not start upload when promise-based beforeUpload resolves to false', fakeAsync(() => {\n        spyOn<NzSafeAny>(comp.options, 'onStart');\n        comp.options.beforeUpload = (): Promise<boolean> => Promise.resolve(false);\n        comp.onChange(PNG_SMALL as NzSafeAny);\n        tick();\n        expect(comp.options.onStart).not.toHaveBeenCalled();\n        http.expectNone('/test');\n      }));\n\n      it('should handle promise-based beforeUpload with file transformation', fakeAsync(() => {\n        spyOn<NzSafeAny>(comp.options, 'onStart');\n        const baseFile = new File(['modified'], 'modified.txt', { type: 'text/plain' });\n        const transformedFile: NzUploadFile = {\n          ...baseFile,\n          uid: 'test-uid',\n          name: baseFile.name,\n          size: baseFile.size,\n          type: baseFile.type,\n          lastModified: baseFile.lastModified.toString(),\n          originFileObj: baseFile\n        };\n        comp.options.beforeUpload = (): Promise<NzUploadFile> => Promise.resolve(transformedFile);\n        comp.onChange(PNG_SMALL as NzSafeAny);\n        tick();\n        const req = http.expectOne('/test');\n        expect(comp.options.onStart).toHaveBeenCalled();\n        req.flush('ok');\n      }));\n\n      it('should handle promise rejection in beforeUpload', fakeAsync(() => {\n        let warnMsg = '';\n        console.warn = jasmine.createSpy().and.callFake((...res: string[]) => (warnMsg = res.join(' ')));\n        spyOn<NzSafeAny>(comp.options, 'onStart');\n        comp.options.beforeUpload = (): Promise<boolean> => Promise.reject(new Error('Validation failed'));\n        comp.onChange(PNG_SMALL as NzSafeAny);\n        tick();\n        expect(comp.options.onStart).not.toHaveBeenCalled();\n        expect(warnMsg).toContain('Unhandled upload beforeUpload error');\n        http.expectNone('/test');\n      }));\n\n      it('should error when request error', fakeAsync(() => {\n        spyOn<NzSafeAny>(comp.options, 'onStart');\n        spyOn<NzSafeAny>(comp.options, 'onSuccess');\n        spyOn<NzSafeAny>(comp.options, 'onError');\n        comp.onChange(PNG_SMALL as NzSafeAny);\n        tick(1);\n        http.expectOne('/test').error({ status: 403 } as unknown as ProgressEvent);\n        expect(comp.options.onStart).toHaveBeenCalled();\n        expect(comp.options.onError).toHaveBeenCalled();\n        expect(comp.options.onSuccess).not.toHaveBeenCalled();\n      }));\n\n      it('should custom request', () => {\n        comp.options.customRequest = () => of(true).subscribe(() => {});\n        spyOn<NzSafeAny>(comp.options, 'customRequest');\n        comp.onChange(PNG_SMALL as NzSafeAny);\n        expect(comp.options.customRequest).toHaveBeenCalled();\n      });\n\n      it('should be warn \"Must return Subscription type in [nzCustomRequest] property\"', () => {\n        let warnMsg = '';\n        console.warn = jasmine.createSpy().and.callFake((...res: string[]) => (warnMsg = res.join(' ')));\n        comp.options.customRequest = (() => {}) as NzSafeAny;\n        comp.onChange(PNG_SMALL as NzSafeAny);\n        expect(warnMsg).toContain(`Must return Subscription type in '[nzCustomRequest]' property`);\n      });\n    });\n  });\n\n  describe('rtl', () => {\n    let dir: Directionality;\n    beforeEach(() => {\n      TestBed.configureTestingModule({\n        providers: [provideMockDirectionality()]\n      });\n      dir = TestBed.inject(Directionality);\n    });\n\n    it('should apply rtl class in upload component', async () => {\n      const fixture = TestBed.createComponent(TestUploadComponent);\n      await fixture.whenStable();\n\n      const el = fixture.debugElement.query(By.css('.ant-upload')).nativeElement as HTMLElement;\n      expect(el.classList).not.toContain('ant-upload-rtl');\n\n      dir.valueSignal.set('rtl');\n      await fixture.whenStable();\n      expect(el.classList).toContain('ant-upload-rtl');\n    });\n\n    it('should apply rtl class in upload list', async () => {\n      const fixture = TestBed.createComponent(NzUploadListComponent);\n      const el = fixture.debugElement.nativeElement as HTMLElement;\n      expect(el.classList).not.toContain('ant-upload-list-rtl');\n\n      dir.valueSignal.set('rtl');\n      await fixture.whenStable();\n      expect(el.classList).toContain('ant-upload-list-rtl');\n    });\n  });\n});\n\n@Component({\n  selector: 'nz-test-upload',\n  imports: [NzButtonModule, NzIconModule, NzUploadModule],\n  template: `\n    @if (show) {\n      <nz-upload\n        #upload\n        [nzType]=\"nzType\"\n        [nzLimit]=\"nzLimit\"\n        [nzSize]=\"nzSize\"\n        [nzFileType]=\"nzFileType\"\n        [nzAccept]=\"nzAccept\"\n        [nzAction]=\"nzAction\"\n        [nzBeforeUpload]=\"beforeUpload\"\n        [nzCustomRequest]=\"nzCustomRequest\"\n        [nzData]=\"nzData\"\n        [nzFilter]=\"nzFilter\"\n        [(nzFileList)]=\"nzFileList\"\n        [nzDisabled]=\"nzDisabled\"\n        [nzHeaders]=\"nzHeaders\"\n        [nzListType]=\"nzListType\"\n        [nzMultiple]=\"nzMultiple\"\n        [nzName]=\"nzName\"\n        [nzShowUploadList]=\"nzShowUploadList\"\n        [nzShowButton]=\"nzShowButton\"\n        [nzWithCredentials]=\"nzWithCredentials\"\n        [nzPreview]=\"onPreview\"\n        [nzPreviewFile]=\"previewFile\"\n        [nzRemove]=\"onRemove\"\n        [nzDirectory]=\"directory\"\n        [nzTransformFile]=\"nzTransformFile\"\n        [nzIconRender]=\"nzIconRender\"\n        [nzFileListRender]=\"nzFileListRender\"\n        [nzMaxCount]=\"nzMaxCount\"\n        (nzFileListChange)=\"nzFileListChange($event)\"\n        (nzChange)=\"nzChange($event)\"\n      >\n        <button nz-button>\n          <nz-icon nzType=\"upload\" />\n          <span>Click to Upload</span>\n        </button>\n      </nz-upload>\n    }\n    <ng-template #customIconRender>\n      <span class=\"customIconRender\">asdf</span>\n    </ng-template>\n    <ng-template #fileListRender>\n      <span class=\"fileListRender\">asdf</span>\n    </ng-template>\n  `\n})\nclass TestUploadComponent {\n  @ViewChild('upload', { static: false }) comp!: NzUploadComponent;\n  @ViewChild('customIconRender', { static: false }) customIconRender!: NzIconRenderTemplate;\n  @ViewChild('fileListRender', { static: false }) fileListRender!: TemplateRef<{ $implicit: NzUploadFile[] }>;\n  show = true;\n  nzType: NzUploadType = 'select';\n  nzLimit = 0;\n  nzSize = 0;\n  nzFileType: NzSafeAny;\n  nzAccept = 'image/png';\n  nzAction: string | ((file: NzUploadFile) => string | Observable<string>) = '/upload';\n  _beforeUpload = false;\n  _beforeUploadList: NzUploadFile[] = [];\n  beforeUpload: NzSafeAny = (_file: NzUploadFile, fileList: NzUploadFile[]): NzSafeAny => {\n    this._beforeUpload = true;\n    this._beforeUploadList = fileList;\n    return true;\n  };\n  nzCustomRequest: NzSafeAny;\n  nzData: NzSafeAny;\n  nzFilter: UploadFilter[] = [];\n  nzFileList: NzUploadFile[] = [];\n  nzDisabled = false;\n  nzHeaders: NzSafeAny = {};\n  nzListType: NzUploadListType = 'text';\n  nzMultiple = false;\n  nzName = 'file';\n  nzShowUploadList: boolean | NzShowUploadList = true;\n  nzShowButton = true;\n  nzWithCredentials = false;\n  nzTransformFile!: (file: NzUploadFile) => NzUploadTransformFileType;\n  nzIconRender: NzIconRenderTemplate | null = null;\n  nzFileListRender: TemplateRef<{ $implicit: NzUploadFile[] }> | null = null;\n  nzMaxCount: number | undefined = undefined;\n  _onPreview = false;\n  onPreview = (): void => {\n    this._onPreview = true;\n  };\n  previewFile!: (file: NzUploadFile) => Observable<string>;\n  _onRemove = false;\n  onRemove: undefined | ((file: NzUploadFile) => boolean | Observable<boolean>) = (): boolean => {\n    this._onRemove = true;\n    return true;\n  };\n  _nzChange!: NzUploadChangeParam;\n\n  nzChange(value: NzUploadChangeParam): void {\n    this._nzChange = value;\n  }\n\n  nzFileListChange(value: NzSafeAny): void {\n    this._nzChange = value;\n  }\n\n  directory = false;\n}\n\n@Component({\n  selector: 'nz-test-upload-btn',\n  imports: [NzUploadBtnComponent],\n  template: `<div nz-upload-btn #btn [options]=\"options\" class=\"test\">UPLOAD</div>`\n})\nclass TestUploadBtnComponent {\n  @ViewChild('btn', { static: false }) comp!: NzUploadBtnComponent;\n  options: ZipButtonOptions = {\n    disabled: false,\n    openFileDialogOnClick: true,\n    filters: [],\n    customRequest: undefined,\n    onStart: () => {},\n    onError: () => {}\n  };\n}\n"
  },
  {
    "path": "components/version/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/version/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/version/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './version';\n"
  },
  {
    "path": "components/version/version.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Version } from '@angular/core';\n\nexport const VERSION = new Version('21.2.0');\n"
  },
  {
    "path": "components/watermark/demo/basic.md",
    "content": "---\norder: 0\ntitle:\n  zh-CN: 基本\n  en-US: Basic\n---\n\n## zh-CN\n\n最简单的用法。\n\n## en-US\n\nThe most basic usage.\n"
  },
  {
    "path": "components/watermark/demo/basic.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzWatermarkModule } from 'ng-zorro-antd/watermark';\n\n@Component({\n  selector: 'nz-demo-watermark-basic',\n  imports: [NzWatermarkModule],\n  template: `\n    <nz-watermark nzContent=\"NG Ant Design\">\n      <div style=\"height: 500px\"></div>\n    </nz-watermark>\n  `\n})\nexport class NzDemoWatermarkBasicComponent {}\n"
  },
  {
    "path": "components/watermark/demo/custom.md",
    "content": "---\norder: 3\ntitle:\n  zh-CN: 自定义配置\n  en-US: Custom configuration\n---\n\n## zh-CN\n\n通过自定义参数配置预览水印效果。\n\n## en-US\n\nPreview the watermark effect by configuring custom parameters.\n"
  },
  {
    "path": "components/watermark/demo/custom.ts",
    "content": "import { ChangeDetectorRef, Component, inject, OnInit } from '@angular/core';\nimport { NonNullableFormBuilder, ReactiveFormsModule } from '@angular/forms';\n\nimport { NzColor, NzColorPickerModule } from 'ng-zorro-antd/color-picker';\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\nimport { NzFormModule } from 'ng-zorro-antd/form';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzInputNumberModule } from 'ng-zorro-antd/input-number';\nimport { NzSliderModule } from 'ng-zorro-antd/slider';\nimport { NzTypographyModule } from 'ng-zorro-antd/typography';\nimport { FontType, NzWatermarkModule } from 'ng-zorro-antd/watermark';\n\n@Component({\n  selector: 'nz-demo-watermark-custom',\n  imports: [\n    ReactiveFormsModule,\n    NzColorPickerModule,\n    NzDividerModule,\n    NzFormModule,\n    NzInputModule,\n    NzInputNumberModule,\n    NzSliderModule,\n    NzTypographyModule,\n    NzWatermarkModule\n  ],\n  template: `\n    <div style=\"display: flex;\">\n      <nz-watermark\n        [nzContent]=\"form.value.content!\"\n        [nzRotate]=\"form.value.rotate!\"\n        [nzZIndex]=\"form.value.zIndex!\"\n        [nzGap]=\"gap\"\n        [nzOffset]=\"offset\"\n        [nzFont]=\"font\"\n      >\n        <p nz-typography style=\"z-index: 10; position:relative;\">\n          The light-speed iteration of the digital world makes products more complex. However, human consciousness and\n          attention resources are limited. Facing this design contradiction, the pursuit of natural interaction will be\n          the consistent direction of Ant Design.\n        </p>\n        <p nz-typography style=\"z-index: 10; position:relative;\">\n          Natural user cognition: According to cognitive psychology, about 80% of external information is obtained\n          through visual channels. The most important visual elements in the interface design, including layout, colors,\n          illustrations, icons, etc., should fully absorb the laws of nature, thereby reducing the user&apos;s cognitive\n          cost and bringing authentic and smooth feelings. In some scenarios, opportunely adding other sensory channels\n          such as hearing, touch can create a richer and more natural product experience.\n        </p>\n        <p nz-typography style=\"z-index: 10; position:relative;\">\n          Natural user behavior: In the interaction with the system, the designer should fully understand the\n          relationship between users, system roles, and task objectives, and also contextually organize system functions\n          and services. At the same time, a series of methods such as behavior analysis, artificial intelligence and\n          sensors could be applied to assist users to make effective decisions and reduce extra operations of users, to\n          save users&apos; mental and physical resources and make human-computer interaction more natural.\n        </p>\n        <img\n          style=\"z-index: 30; position:relative; width: 100%; max-width: 800px;\"\n          src=\"https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*zx7LTI_ECSAAAAAAAAAAAABkARQnAQ\"\n          alt=\"示例图片\"\n        />\n      </nz-watermark>\n      <nz-divider nzType=\"vertical\" />\n      <form nz-form nzLayout=\"vertical\" [formGroup]=\"form\">\n        <nz-form-item>\n          <nz-form-label>Content</nz-form-label>\n          <nz-form-control>\n            <input nz-input type=\"text\" formControlName=\"content\" />\n          </nz-form-control>\n        </nz-form-item>\n        <nz-form-item>\n          <nz-form-label>Color</nz-form-label>\n          <nz-form-control>\n            <nz-color-picker [nzValue]=\"color\" (nzOnChange)=\"changeColor($event)\" />\n          </nz-form-control>\n        </nz-form-item>\n        <nz-form-item>\n          <nz-form-label>FontSize</nz-form-label>\n          <nz-form-control>\n            <nz-slider formControlName=\"fontSize\" />\n          </nz-form-control>\n        </nz-form-item>\n        <nz-form-item>\n          <nz-form-label>zIndex</nz-form-label>\n          <nz-form-control>\n            <nz-slider formControlName=\"zIndex\" />\n          </nz-form-control>\n        </nz-form-item>\n        <nz-form-item>\n          <nz-form-label>Rotate</nz-form-label>\n          <nz-form-control>\n            <nz-slider [nzMin]=\"-180\" [nzMax]=\"180\" formControlName=\"rotate\" />\n          </nz-form-control>\n        </nz-form-item>\n        <nz-form-item>\n          <nz-form-label>Gap</nz-form-label>\n          <nz-form-control>\n            <nz-input-number formControlName=\"gapX\" />\n            <nz-input-number formControlName=\"gapY\" />\n          </nz-form-control>\n        </nz-form-item>\n        <nz-form-item>\n          <nz-form-label>Offset</nz-form-label>\n          <nz-form-control>\n            <nz-input-number formControlName=\"offsetX\" />\n            <nz-input-number formControlName=\"offsetY\" />\n          </nz-form-control>\n        </nz-form-item>\n      </form>\n    </div>\n  `,\n  styles: `\n    nz-watermark {\n      flex: 1 1 auto;\n    }\n\n    nz-divider {\n      height: auto;\n      margin: 0 20px;\n    }\n\n    form {\n      flex: 0 0 280px;\n    }\n\n    nz-input-number {\n      margin-right: 12px;\n      width: 40%;\n    }\n  `\n})\nexport class NzDemoWatermarkCustomComponent implements OnInit {\n  private fb = inject(NonNullableFormBuilder);\n\n  form = this.fb.group({\n    content: 'NG Ant Design',\n    fontSize: 16,\n    zIndex: 11,\n    rotate: -22,\n    gapX: 100,\n    gapY: 100,\n    offsetX: 50,\n    offsetY: 50\n  });\n  color: string = 'rgba(0,0,0,.15)';\n  font: FontType = {\n    color: 'rgba(0,0,0,.15)',\n    fontSize: 16\n  };\n  gap: [number, number] = [100, 100];\n  offset: [number, number] = [50, 50];\n\n  constructor(private cdr: ChangeDetectorRef) {}\n\n  ngOnInit(): void {\n    this.form.valueChanges.subscribe(item => {\n      this.font = {\n        fontSize: item.fontSize,\n        color: this.color\n      };\n      this.gap = [item.gapX!, item.gapY!];\n      this.offset = [item.offsetX!, item.offsetY!];\n      this.cdr.markForCheck();\n    });\n  }\n\n  changeColor(value: { color: NzColor; format: string }): void {\n    this.color = value.color.toRgbString();\n    this.font = {\n      fontSize: this.form.value.fontSize,\n      color: value.color.toRgbString()\n    };\n    this.cdr.markForCheck();\n  }\n}\n"
  },
  {
    "path": "components/watermark/demo/image.md",
    "content": "---\norder: 2\ntitle:\n  zh-CN: 图片水印\n  en-US: Image watermark\n---\n\n## zh-CN\n\n通过 `nzImage` 指定图片地址。为保证图片高清且不被拉伸，请设置 width 和 height, 并上传至少两倍的宽高的 logo 图片地址。\n\n## en-US\n\nSpecify the image address via `nzImage`. To ensure that the image is high definition and not stretched, set the width and height, and upload at least twice the width and height of the logo image address.\n"
  },
  {
    "path": "components/watermark/demo/image.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzWatermarkModule } from 'ng-zorro-antd/watermark';\n\n@Component({\n  selector: 'nz-demo-watermark-image',\n  imports: [NzWatermarkModule],\n  template: `\n    <nz-watermark\n      [nzWidth]=\"212\"\n      [nzHeight]=\"32\"\n      nzImage=\"https://img.alicdn.com/imgextra/i3/O1CN01UR3Zkq1va9fnZsZcr_!!6000000006188-55-tps-424-64.svg\"\n    >\n      <div style=\"height: 500px\"></div>\n    </nz-watermark>\n  `\n})\nexport class NzDemoWatermarkImageComponent {}\n"
  },
  {
    "path": "components/watermark/demo/multi-line.md",
    "content": "---\norder: 1\ntitle:\n  zh-CN: 多行水印\n  en-US: Multi-line watermark\n---\n\n## zh-CN\n\n通过 `nzContent` 设置 字符串数组 指定多行文字水印内容。\n\n## en-US\n\nUse `nzContent` to set a string array to specify multi-line text watermark content.\n"
  },
  {
    "path": "components/watermark/demo/multi-line.ts",
    "content": "import { Component } from '@angular/core';\n\nimport { NzWatermarkModule } from 'ng-zorro-antd/watermark';\n\n@Component({\n  selector: 'nz-demo-watermark-multi-line',\n  imports: [NzWatermarkModule],\n  template: `\n    <nz-watermark [nzContent]=\"['Angular', 'NG Ant Design']\">\n      <div style=\"height: 500px\"></div>\n    </nz-watermark>\n  `\n})\nexport class NzDemoWatermarkMultiLineComponent {}\n"
  },
  {
    "path": "components/watermark/doc/index.en-US.md",
    "content": "---\ncategory: Components\ntype: Other\ncols: 1\ntitle: Watermark\ntag: 15.1.0\ncover: 'https://img.alicdn.com/imgextra/i2/O1CN01ozPPZp1wj9CwsVvDL_!!6000000006343-0-tps-1232-820.jpg'\ndescription: Add specific text or patterns to the page.\n---\n\n## When To Use\n\n- Use when the page needs to be watermarked to identify the copyright.\n- Suitable for preventing information theft.\n\n## API\n\n### nz-watermark\n\n| Property    | Description                                                                                       | Type                 | Default                    |\n| ----------- | ------------------------------------------------------------------------------------------------- | -------------------- | -------------------------- |\n| `nzContent` | Watermark text content                                                                            | `string \\| string[]` | -                          |\n| `nzWidth`   | The width of the watermark, the default value of `nzContent` is its own width                     | `number`             | `120`                      |\n| `nzHeight`  | The height of the watermark, the default value of `nzContent` is its own height                   | `number`             | `64`                       |\n| `nzRotate`  | When the watermark is drawn, the rotation Angle, unit `°`                                         | `number`             | `-22`                      |\n| `nzZIndex`  | The z-index of the appended watermark element                                                     | `number`             | `9`                        |\n| `nzImage`   | Image source, it is recommended to export 2x or 3x image, high priority (support base64 format)   | `string`             | -                          |\n| `nzFont`    | Text style                                                                                        | `FontType`           | FontType                   |\n| `nzGap`     | The spacing between watermarks                                                                    | `[number, number]`   | `[100, 100]`               |\n| `nzOffset`  | The offset of the watermark from the upper left corner of the container. The default is `nzGap/2` | `[number, number]`   | `[nzGap[0]/2, nzGap[1]/2]` |\n\n### FontType\n\n| Property     | Description | Type                                          | Default           |\n| ------------ | ----------- | --------------------------------------------- | ----------------- |\n| `color`      | font color  | `string`                                      | `rgba(0,0,0,.15)` |\n| `fontSize`   | font size   | `number`                                      | `16`              |\n| `fontWeight` | font weight | `'normal' \\| 'light' \\| 'weight' \\| number`   | `'normal'`        |\n| `fontFamily` | font family | `string`                                      | `'sans-serif'`    |\n| `fontStyle`  | font style  | `'none' \\| 'normal' \\| 'italic' \\| 'oblique'` | `'normal'`        |\n\n## FAQ\n\n### Handle abnormal image watermarks\n\nWhen using an image watermark and the image loads abnormally, you can add `nzContent` at the same time to prevent the watermark from becoming invalid.\n\n```html\n<nz-watermark\n  [nzWidth]=\"212\"\n  [nzHeight]=\"32\"\n  nzContent=\"NG Ant Design\"\n  nzImage=\"https://img.alicdn.com/imgextra/i3/O1CN01UR3Zkq1va9fnZsZcr_!!6000000006188-55-tps-424-64.svg\"\n>\n  <div style=\"height: 500px\"></div>\n</nz-watermark>\n```\n"
  },
  {
    "path": "components/watermark/doc/index.zh-CN.md",
    "content": "---\ncategory: Components\ntype: 其他\nsubtitle: 水印\ntitle: Watermark\ncols: 1\ntag: 15.1.0\ncover: 'https://img.alicdn.com/imgextra/i2/O1CN01ozPPZp1wj9CwsVvDL_!!6000000006343-0-tps-1232-820.jpg'\ndescription: 给页面的某个区域加上水印。\n---\n\n## 何时使用\n\n- 页面需要添加水印标识版权时使用。\n- 适用于防止信息盗用。\n\n## API\n\n### nz-watermark\n\n| 参数        | 说明                                                        | 类型                 | 默认值                     |\n| ----------- | ----------------------------------------------------------- | -------------------- | -------------------------- |\n| `nzContent` | 水印文字内容                                                | `string \\| string[]` | -                          |\n| `nzWidth`   | 水印的宽度，`nzContent` 的默认值为自身的宽度                | `number`             | `120`                      |\n| `nzHeight`  | 水印的高度，`nzContent` 的默认值为自身的高度                | `number`             | `64`                       |\n| `nzRotate`  | 水印绘制时，旋转的角度，单位 `°`                            | `number`             | `-22`                      |\n| `nzZIndex`  | 追加的水印元素的 z-index                                    | `number`             | `9`                        |\n| `nzImage`   | 图片源，建议导出 2 倍或 3 倍图，优先级高 (支持 base64 格式) | `string`             | -                          |\n| `nzFont`    | 文字样式                                                    | `FontType`           | FontType                   |\n| `nzGap`     | 水印之间的间距                                              | `[number, number]`   | `[100, 100]`               |\n| `nzOffset`  | 水印距离容器左上角的偏移量，默认为 `nzGap/2`                | `[number, number]`   | `[nzGap[0]/2, nzGap[1]/2]` |\n\n### FontType\n\n| 参数         | 说明     | 类型                                          | 默认值            |\n| ------------ | -------- | --------------------------------------------- | ----------------- |\n| `color`      | 字体颜色 | `string`                                      | `rgba(0,0,0,.15)` |\n| `fontSize`   | 字体大小 | `number`                                      | `16`              |\n| `fontWeight` | 字体粗细 | `'normal' \\| 'light' \\| 'weight' \\| number`   | `'normal'`        |\n| `fontFamily` | 字体类型 | `string`                                      | `'sans-serif'`    |\n| `fontStyle`  | 字体样式 | `'none' \\| 'normal' \\| 'italic' \\| 'oblique'` | `'normal'`        |\n\n## FAQ\n\n### 处理异常图片水印\n\n当使用图片水印且图片加载异常时，可以同时添加 `nzContent` 防止水印失效。\n\n```html\n<nz-watermark\n  [nzWidth]=\"212\"\n  [nzHeight]=\"32\"\n  nzContent=\"NG Ant Design\"\n  nzImage=\"https://img.alicdn.com/imgextra/i3/O1CN01UR3Zkq1va9fnZsZcr_!!6000000006188-55-tps-424-64.svg\"\n>\n  <div style=\"height: 500px\"></div>\n</nz-watermark>\n```\n"
  },
  {
    "path": "components/watermark/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './public-api';\n"
  },
  {
    "path": "components/watermark/ng-package.json",
    "content": "{\n  \"lib\": {\n    \"entryFile\": \"public-api.ts\"\n  }\n}\n"
  },
  {
    "path": "components/watermark/public-api.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './typings';\nexport * from './watermark.component';\nexport * from './watermark.module';\n"
  },
  {
    "path": "components/watermark/typings.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport interface FontType {\n  color?: string;\n  fontSize?: number;\n  fontWeight?: 'normal' | 'light' | 'weight' | number;\n  fontFamily?: string;\n  fontStyle?: 'none' | 'normal' | 'italic' | 'oblique';\n}\n\nexport interface MarkStyleType {\n  zIndex: number;\n  position: string;\n  left: string | number;\n  top: string | number;\n  width: string;\n  height: string;\n  pointerEvents: string;\n  backgroundRepeat: string;\n  backgroundPosition?: string;\n  visibility: string;\n}\n\nexport interface MarkStyleCanvasType extends MarkStyleType {\n  backgroundImage: string;\n  backgroundSize: string;\n}\n"
  },
  {
    "path": "components/watermark/util.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { MarkStyleCanvasType } from './typings';\n\n/** Returns the ratio of the device's physical pixel resolution to the css pixel resolution */\nexport function getPixelRatio(): number {\n  return window.devicePixelRatio || 1;\n}\n\nexport function toLowercaseSeparator(key: keyof MarkStyleCanvasType): string {\n  return key.replace(/([A-Z])/g, '-$1').toLowerCase();\n}\n\nexport function getStyleStr(style: MarkStyleCanvasType): string {\n  const keys = Object.keys(style) as Array<keyof MarkStyleCanvasType>;\n  const styleCss: string[] = keys.map(\n    (key: keyof MarkStyleCanvasType) => `${toLowercaseSeparator(key)}: ${style[key]};`\n  );\n  return styleCss.join(' ');\n}\n\n/** Whether to re-render the watermark */\nexport function reRendering(mutation: MutationRecord, watermarkElement?: HTMLElement): boolean {\n  let flag = false;\n  // Whether to delete the watermark node\n  if (mutation.removedNodes.length) {\n    flag = Array.from(mutation.removedNodes).some(node => node === watermarkElement);\n  }\n  // Whether the watermark dom property value has been modified\n  if (mutation.type === 'attributes' && mutation.target === watermarkElement) {\n    flag = true;\n  }\n  return flag;\n}\n\n/** Rotate with the watermark as the center point */\nexport function rotateWatermark(ctx: CanvasRenderingContext2D, rotateX: number, rotateY: number, rotate: number): void {\n  ctx.translate(rotateX, rotateY);\n  ctx.rotate((Math.PI / 180) * Number(rotate));\n  ctx.translate(-rotateX, -rotateY);\n}\n"
  },
  {
    "path": "components/watermark/watermark.component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { isPlatformServer } from '@angular/common';\nimport {\n  afterNextRender,\n  ChangeDetectionStrategy,\n  ChangeDetectorRef,\n  Component,\n  DestroyRef,\n  DOCUMENT,\n  ElementRef,\n  inject,\n  Input,\n  numberAttribute,\n  OnChanges,\n  OnInit,\n  PLATFORM_ID,\n  SimpleChanges\n} from '@angular/core';\n\nimport { FontType, MarkStyleType } from './typings';\nimport { getPixelRatio, getStyleStr, reRendering, rotateWatermark } from './util';\n\n/**\n * Base size of the canvas, 1 for parallel layout and 2 for alternate layout\n * Only alternate layout is currently supported\n */\nconst BaseSize = 2;\nconst FontGap = 3;\n\n@Component({\n  selector: 'nz-watermark',\n  exportAs: 'nzWatermark',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `<ng-content />`,\n  styles: `\n    :host {\n      position: relative;\n      display: block;\n      overflow: hidden;\n    }\n  `\n})\nexport class NzWatermarkComponent implements OnInit, OnChanges {\n  private isServer = isPlatformServer(inject(PLATFORM_ID));\n  private document = inject(DOCUMENT);\n  private el: HTMLElement = inject(ElementRef<HTMLElement>).nativeElement;\n  private cdr: ChangeDetectorRef = inject(ChangeDetectorRef);\n\n  @Input({ transform: numberAttribute }) nzWidth: number = 120;\n  @Input({ transform: numberAttribute }) nzHeight: number = 64;\n  @Input({ transform: numberAttribute }) nzRotate: number = -22;\n  @Input({ transform: numberAttribute }) nzZIndex: number = 9;\n  @Input() nzImage: string = '';\n  @Input() nzContent: string | string[] = '';\n  @Input() nzFont: FontType = {};\n  @Input() nzGap: [number, number] = [100, 100];\n  @Input() nzOffset: [number, number] = [this.nzGap[0] / 2, this.nzGap[1] / 2];\n\n  watermarkElement: HTMLDivElement = this.document.createElement('div');\n  stopObservation: boolean = false;\n  private observer: MutationObserver | null = null;\n  // for test usage\n  private onImageLoad?: VoidFunction;\n  private onImageError?: VoidFunction;\n\n  constructor() {\n    if (this.isServer) {\n      return;\n    }\n\n    const observer = (this.observer = new MutationObserver(mutations => {\n      if (this.stopObservation) {\n        return;\n      }\n      mutations.forEach(mutation => {\n        if (reRendering(mutation, this.watermarkElement)) {\n          this.destroyWatermark();\n          this.renderWatermark();\n        }\n      });\n    }));\n\n    afterNextRender(() => this.renderWatermark());\n\n    inject(DestroyRef).onDestroy(() => observer.disconnect());\n  }\n\n  ngOnInit(): void {\n    this.observer?.observe(this.el, {\n      subtree: true,\n      childList: true,\n      attributeFilter: ['style', 'class']\n    });\n  }\n\n  ngOnChanges(changes: SimpleChanges): void {\n    const { nzRotate, nzZIndex, nzWidth, nzHeight, nzImage, nzContent, nzFont, gapX, gapY, offsetLeft, offsetTop } =\n      changes;\n\n    if (\n      nzRotate ||\n      nzZIndex ||\n      nzWidth ||\n      nzHeight ||\n      nzImage ||\n      nzContent ||\n      nzFont ||\n      gapX ||\n      gapY ||\n      offsetLeft ||\n      offsetTop\n    ) {\n      this.renderWatermark();\n    }\n  }\n\n  getFont(): void {\n    const font: FontType = {\n      color: 'rgba(0,0,0,.15)',\n      fontSize: 16,\n      fontWeight: 'normal',\n      fontFamily: 'sans-serif',\n      fontStyle: 'normal'\n    };\n\n    this.nzFont = { ...font, ...this.nzFont };\n    this.cdr.markForCheck();\n  }\n\n  getMarkStyle(): MarkStyleType {\n    const markStyle: MarkStyleType = {\n      zIndex: this.nzZIndex,\n      position: 'absolute',\n      left: 0,\n      top: 0,\n      width: '100%',\n      height: '100%',\n      pointerEvents: 'none',\n      backgroundRepeat: 'repeat',\n      visibility: 'visible'\n    };\n\n    /** Calculate the style of the nzOffset */\n    let positionLeft = (this.nzOffset?.[0] ?? this.nzGap[0] / 2) - this.nzGap[0] / 2;\n    let positionTop = (this.nzOffset?.[1] ?? this.nzGap[1] / 2) - this.nzGap[1] / 2;\n    if (positionLeft > 0) {\n      markStyle.left = `${positionLeft}px`;\n      markStyle.width = `calc(100% - ${positionLeft}px)`;\n      positionLeft = 0;\n    }\n    if (positionTop > 0) {\n      markStyle.top = `${positionTop}px`;\n      markStyle.height = `calc(100% - ${positionTop}px)`;\n      positionTop = 0;\n    }\n    markStyle.backgroundPosition = `${positionLeft}px ${positionTop}px`;\n\n    return markStyle;\n  }\n\n  destroyWatermark(): void {\n    if (this.watermarkElement) {\n      this.watermarkElement.remove();\n    }\n  }\n\n  appendWatermark(base64Url: string, markWidth: number): void {\n    this.stopObservation = true;\n    this.watermarkElement.setAttribute(\n      'style',\n      getStyleStr({\n        ...this.getMarkStyle(),\n        backgroundImage: `url('${base64Url}')`,\n        backgroundSize: `${(this.nzGap[0] + markWidth) * BaseSize}px`\n      })\n    );\n    this.el.append(this.watermarkElement);\n    this.cdr.markForCheck();\n\n    // Delayed execution\n    setTimeout(() => {\n      this.stopObservation = false;\n      this.cdr.markForCheck();\n    });\n  }\n\n  getMarkSize(ctx: CanvasRenderingContext2D): [number, number] {\n    let defaultWidth = 120;\n    let defaultHeight = 64;\n    if (!this.nzImage && ctx.measureText) {\n      ctx.font = `${Number(this.nzFont.fontSize)}px ${this.nzFont.fontFamily}`;\n      const contents = Array.isArray(this.nzContent) ? this.nzContent : [this.nzContent];\n      const widths = contents.map(item => ctx.measureText(item!).width);\n      defaultWidth = Math.ceil(Math.max(...widths));\n      defaultHeight = Number(this.nzFont.fontSize) * contents.length + (contents.length - 1) * FontGap;\n    }\n    return [this.nzWidth ?? defaultWidth, this.nzHeight ?? defaultHeight];\n  }\n\n  fillTexts(ctx: CanvasRenderingContext2D, drawX: number, drawY: number, drawWidth: number, drawHeight: number): void {\n    const ratio = getPixelRatio();\n    const mergedFontSize = Number(this.nzFont.fontSize) * ratio;\n    ctx.font = `${this.nzFont.fontStyle} normal ${this.nzFont.fontWeight} ${mergedFontSize}px/${drawHeight}px ${this.nzFont.fontFamily}`;\n    if (this.nzFont.color) ctx.fillStyle = this.nzFont.color;\n    ctx.textAlign = 'center';\n    ctx.textBaseline = 'top';\n    ctx.translate(drawWidth / 2, 0);\n    const contents = Array.isArray(this.nzContent) ? this.nzContent : [this.nzContent];\n    contents?.forEach((item, index) => {\n      ctx.fillText(item ?? '', drawX, drawY + index * (mergedFontSize + FontGap * ratio));\n    });\n  }\n\n  drawText(\n    canvas: HTMLCanvasElement,\n    ctx: CanvasRenderingContext2D,\n    drawX: number,\n    drawY: number,\n    drawWidth: number,\n    drawHeight: number,\n    alternateRotateX: number,\n    alternateRotateY: number,\n    alternateDrawX: number,\n    alternateDrawY: number,\n    markWidth: number\n  ): void {\n    this.fillTexts(ctx, drawX, drawY, drawWidth, drawHeight);\n\n    /** Fill the interleaved text after rotation */\n    ctx.restore();\n    rotateWatermark(ctx, alternateRotateX, alternateRotateY, this.nzRotate);\n    this.fillTexts(ctx, alternateDrawX, alternateDrawY, drawWidth, drawHeight);\n    this.appendWatermark(canvas.toDataURL(), markWidth);\n  }\n\n  renderWatermark(): void {\n    if (this.isServer) {\n      return;\n    }\n\n    if (!this.nzContent && !this.nzImage) {\n      return;\n    }\n    const canvas: HTMLCanvasElement = this.document.createElement('canvas');\n    const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;\n\n    if (ctx) {\n      if (!this.watermarkElement) {\n        this.watermarkElement = this.document.createElement('div');\n      }\n      this.getFont();\n      const ratio = getPixelRatio();\n      const [markWidth, markHeight] = this.getMarkSize(ctx);\n      const canvasWidth = (this.nzGap[0] + markWidth) * ratio;\n      const canvasHeight = (this.nzGap[1] + markHeight) * ratio;\n      canvas.setAttribute('width', `${canvasWidth * BaseSize}px`);\n      canvas.setAttribute('height', `${canvasHeight * BaseSize}px`);\n\n      const drawX = (this.nzGap[0] * ratio) / 2;\n      const drawY = (this.nzGap[1] * ratio) / 2;\n      const drawWidth = markWidth * ratio;\n      const drawHeight = markHeight * ratio;\n      const rotateX = (drawWidth + this.nzGap[0] * ratio) / 2;\n      const rotateY = (drawHeight + this.nzGap[1] * ratio) / 2;\n\n      /** Alternate drawing parameters */\n      const alternateDrawX = drawX + canvasWidth;\n      const alternateDrawY = drawY + canvasHeight;\n      const alternateRotateX = rotateX + canvasWidth;\n      const alternateRotateY = rotateY + canvasHeight;\n\n      ctx.save();\n      rotateWatermark(ctx, rotateX, rotateY, this.nzRotate);\n\n      if (this.nzImage) {\n        const img = new Image();\n\n        this.onImageLoad = (): void => {\n          cleanup();\n\n          ctx.drawImage(img, drawX, drawY, drawWidth, drawHeight);\n\n          /** Draw interleaved pictures after rotation */\n          ctx.restore();\n          rotateWatermark(ctx, alternateRotateX, alternateRotateY, this.nzRotate);\n          ctx.drawImage(img, alternateDrawX, alternateDrawY, drawWidth, drawHeight);\n          this.appendWatermark(canvas.toDataURL(), markWidth);\n        };\n\n        this.onImageError = (): void => {\n          cleanup();\n\n          this.drawText(\n            canvas,\n            ctx,\n            drawX,\n            drawY,\n            drawWidth,\n            drawHeight,\n            alternateRotateX,\n            alternateRotateY,\n            alternateDrawX,\n            alternateDrawY,\n            markWidth\n          );\n        };\n\n        const cleanup = (): void => {\n          img.removeEventListener('load', this.onImageLoad!);\n          img.removeEventListener('error', this.onImageError!);\n        };\n\n        img.addEventListener('load', this.onImageLoad);\n        img.addEventListener('error', this.onImageError);\n\n        img.crossOrigin = 'anonymous';\n        img.referrerPolicy = 'no-referrer';\n        img.src = this.nzImage;\n      } else {\n        this.drawText(\n          canvas,\n          ctx,\n          drawX,\n          drawY,\n          drawWidth,\n          drawHeight,\n          alternateRotateX,\n          alternateRotateY,\n          alternateDrawX,\n          alternateDrawY,\n          markWidth\n        );\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "components/watermark/watermark.module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NgModule } from '@angular/core';\n\nimport { NzWatermarkComponent } from './watermark.component';\n\n@NgModule({\n  exports: [NzWatermarkComponent],\n  imports: [NzWatermarkComponent]\n})\nexport class NzWatermarkModule {}\n"
  },
  {
    "path": "components/watermark/watermark.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ApplicationRef, Component, DebugElement, destroyPlatform } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { bootstrapApplication, By } from '@angular/platform-browser';\nimport { renderApplication } from '@angular/platform-server';\n\nimport { NzSafeAny } from 'ng-zorro-antd/core/types';\n\nimport { FontType } from './typings';\nimport { NzWatermarkComponent } from './watermark.component';\nimport { NzWatermarkModule } from './watermark.module';\n\ndescribe('watermark', () => {\n  let fixture: ComponentFixture<NzTestWatermarkBasicComponent>;\n  let testComponent: NzTestWatermarkBasicComponent;\n  let resultEl: DebugElement;\n  let mockSrcSpy: jasmine.Spy;\n\n  beforeAll(() => {\n    mockSrcSpy = spyOnProperty(Image.prototype, 'src', 'set');\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(NzTestWatermarkBasicComponent);\n    testComponent = fixture.debugElement.componentInstance;\n    resultEl = fixture.debugElement.query(By.directive(NzWatermarkComponent));\n    mockSrcSpy.and.callFake(() => {\n      resultEl.componentInstance['onImageLoad']?.();\n    });\n  });\n\n  it('basic', async () => {\n    testComponent.nzContent = 'NG Ant Design';\n    await fixture.whenStable();\n    const view = resultEl.nativeElement.querySelector('.watermark > div');\n    expect(view).toBeTruthy();\n    expect(view.tagName).toBe('DIV');\n  });\n\n  it('image', async () => {\n    testComponent.nzImage =\n      'https://img.alicdn.com/imgextra/i3/O1CN01UR3Zkq1va9fnZsZcr_!!6000000006188-55-tps-424-64.svg';\n    await fixture.whenStable();\n    const view = resultEl.nativeElement.querySelector('.watermark > div');\n    expect(view).toBeTruthy();\n    expect(view.tagName).toBe('DIV');\n  });\n\n  it('invalid image', async () => {\n    mockSrcSpy.and.callFake(() => {\n      resultEl.componentInstance['onImageError']?.();\n    });\n    testComponent.nzImage = 'https://img.alicdn.com/test.svg';\n    await fixture.whenStable();\n    const view = resultEl.nativeElement.querySelector('.watermark > div');\n    expect(view).toBeTruthy();\n    expect(view.tagName).toBe('DIV');\n  });\n\n  it('should offset work', async () => {\n    testComponent.nzContent = ['Angular', 'NG Ant Design'];\n    testComponent.nzOffset = [200, 200];\n    await fixture.whenStable();\n\n    const view = resultEl.nativeElement.querySelector('.watermark > div');\n    expect(view?.style.left).toBe('150px');\n    expect(view?.style.top).toBe('150px');\n    expect(view?.style.width).toBe('calc(100% - 150px)');\n    expect(view?.style.height).toBe('calc(100% - 150px)');\n  });\n\n  it('should backgroundSize work', async () => {\n    testComponent.nzContent = 'NG Ant Design';\n    testComponent.nzGap = [100, 100];\n    testComponent.nzWidth = 200;\n    testComponent.nzHeight = 200;\n    await fixture.whenStable();\n\n    const view = resultEl.nativeElement.querySelector('.watermark > div');\n    expect(view?.style.backgroundSize).toBe('600px');\n  });\n\n  it('should MutationObserver work', async () => {\n    testComponent.nzContent = 'NG Ant Design';\n    await fixture.whenStable();\n\n    const view = resultEl.nativeElement.querySelector('.watermark > div');\n    view?.remove();\n    await fixture.whenStable();\n\n    expect(view).toBeTruthy();\n  });\n\n  it('should observe the modification of style', async () => {\n    testComponent.nzContent = 'NG Ant Design';\n    await fixture.whenStable();\n\n    const view = resultEl.nativeElement.querySelector('.watermark > div');\n    view?.setAttribute('style', '');\n    await fixture.whenStable();\n\n    expect(view.style).toBeTruthy();\n  });\n});\n\ndescribe('watermark (SSR)', () => {\n  it('should render water mark on server', async () => {\n    destroyPlatform();\n\n    // `as any` because `ngDevMode` is not exposed on the global namespace typings.\n    const ngDevMode = (globalThis as NzSafeAny)['ngDevMode'];\n\n    try {\n      // Disable development-mode checks for these tests (we don't care).\n      (globalThis as NzSafeAny)['ngDevMode'] = false;\n      // Enter server mode for the duration of this function.\n      globalThis['ngServerMode'] = true;\n\n      const bootstrap = (): Promise<ApplicationRef> =>\n        bootstrapApplication(NzTestWatermarkBasicComponent, { providers: [] });\n      const html = await renderApplication(bootstrap, {\n        document: '<html><head></head><body><nz-test-watermark-basic></nz-test-watermark-basic></body></html>'\n      });\n\n      expect(html).toContain('<nz-watermark class=\"watermark\"');\n    } finally {\n      // Restore the original value.\n      (globalThis as NzSafeAny)['ngDevMode'] = ngDevMode;\n      // Leave server mode so the remaining test is back in \"client mode\".\n      globalThis['ngServerMode'] = undefined;\n    }\n\n    destroyPlatform();\n  });\n});\n\n@Component({\n  selector: 'nz-test-watermark-basic',\n  imports: [NzWatermarkModule],\n  template: `\n    <nz-watermark\n      [nzContent]=\"nzContent\"\n      [nzWidth]=\"nzWidth\"\n      [nzHeight]=\"nzHeight\"\n      [nzRotate]=\"nzRotate\"\n      [nzZIndex]=\"nzZIndex\"\n      [nzImage]=\"nzImage\"\n      [nzFont]=\"nzFont\"\n      [nzGap]=\"nzGap\"\n      [nzOffset]=\"nzOffset\"\n      class=\"watermark\"\n    />\n  `\n})\nexport class NzTestWatermarkBasicComponent {\n  nzContent: string | string[] = 'NG Ant Design';\n  nzWidth: number = 120;\n  nzHeight: number = 64;\n  nzRotate: number = -22;\n  nzZIndex: number = 9;\n  nzImage: string = '';\n  nzFont: FontType = {};\n  nzGap: [number, number] = [100, 100];\n  nzOffset: [number, number] = [50, 50];\n}\n"
  },
  {
    "path": "docs/animations.en-US.md",
    "content": "---\norder: 8\ntitle: Animations Switch\ntag: updated\n---\n\n> Since v21, NG-ZORRO uses [native animation](https://angular.dev/guide/animations) to implement animation effects. You can remove the `@angular/animations` dependency as needed.\n\nNG-ZORRO allows developers to turn off the animations. You can set animations' switch by adding corresponding directives or\nconfigurations, or use the global configuration to turn off all animations associated with it.\n\n### Turn Off Globally or in Components\n\n`provideNoopAnimations` has been marked as deprecated. You can use `provideNzNoAnimation` to turn off animations.\n\n```ts\nimport { provideNzNoAnimation } from 'ng-zorro-antd/core/animation';\n\n// Turn off animations globally\nexport const appConfig: ApplicationConfig = {\n  providers: [\n    // ...\n    provideNzNoAnimation()\n  ]\n};\n\n// Turn off animations in components\n@Component({\n  providers: [\n    // ...\n    provideNzNoAnimation()\n  ]\n})\n```\n\n### Turn Off in Templates\n\nImport the `NzNoAnimationDirective` and add the `nzNoAnimation` directive to the component where you want to turn off animations.\n\n```html\n<nz-modal nzNoAnimation></nz-modal> <ul nz-menu nzNoAnimation></ul>\n```\n\n### Turn Off in Services\n\nAdd the following configuration while invoking components' services.\n\n#### Modal, Drawer\n\n```ts\n{\n  // ...\n  nzNoAnimation: true;\n}\n```\n\n#### Notification, Message\n\n```ts\n{\n  // ...\n  nzAnimate: false;\n}\n```\n\n### Turn Off the Wave Effect\n\nSome components (such as Button) use dynamic styles to support wave effects, so their styles are unable to be overridden directly.\nYou can use `provideNzWave` or `provideNzNoAnimation` to turn off the wave effects.\n\n```ts\nimport { provideNzWave } from 'ng-zorro-antd/core/wave';\n\nexport const appConfig: ApplicationConfig = {\n  providers: [provideNzWave({ disabled: true })]\n};\n```\n"
  },
  {
    "path": "docs/animations.zh-CN.md",
    "content": "---\norder: 8\ntitle: 动画开关\ntag: updated\n---\n\n> 从 v21 版本开始，NG-ZORRO 完全使用 [native animation](https://angular.cn/guide/animations) 实现动画效果，你可以按需移除 `@angular/animations` 依赖。\n\nNG-ZORRO 允许开发者关闭动画效果，您可以通过添加对应指令或者配置来设置动画的开关，也可以通过全局配置关闭所有动画。\n\n### 在全局或组件中关闭\n\n`provideNoopAnimations` 已被标记为废弃，你可以通过 `provideNzNoAnimation` 来关闭动画。\n\n```ts\nimport { provideNzNoAnimation } from 'ng-zorro-antd/core/animation';\n\n// 在全局中关闭动画\nexport const appConfig: ApplicationConfig = {\n  providers: [\n    // ...\n    provideNzNoAnimation()\n  ]\n};\n\n// 在组件中关闭动画\n@Component({\n  providers: [\n    // ...\n    provideNzNoAnimation()\n  ]\n})\n```\n\n### 在模版中关闭\n\n引入 `NzNoAnimationDirective` 指令，在期望关闭动画的组件上添加 `nzNoAnimation` 指令。\n\n```html\n<nz-modal nzNoAnimation></nz-modal> <ul nz-menu nzNoAnimation></ul>\n```\n\n### 在服务中关闭\n\n在调用组件服务时传入以下配置来关闭动画。\n\n#### Modal, Drawer\n\n```ts\n{\n  // ...\n  nzNoAnimation: true;\n}\n```\n\n#### Notification, Message\n\n```ts\n{\n  // ...\n  nzAnimate: false;\n}\n```\n\n### 关闭波浪效果\n\n部分组件（如：Button）为了支持波纹效果，使用了动态样式，因此无法直接使用样式覆盖。\n你可以通过 `provideNzWave` 或者使用 `provideNzNoAnimation` 来关闭波浪效果。\n\n```ts\nimport { provideNzWave } from 'ng-zorro-antd/core/wave';\n\nexport const appConfig: ApplicationConfig = {\n  providers: [provideNzWave({ disabled: true })]\n};\n```\n"
  },
  {
    "path": "docs/changelog.en-US.md",
    "content": "---\norder: 13\ntitle: Change Log\ntoc:\n  depth: 2\ntag: '{{version}}'\n---\n\n`ng-zorro-antd` strictly follows [Semantic Versioning 2.0.0](https://semver.org).\n\n### Release Schedule\n\n- Weekly release: patch version at the end of every week for routine bugfix (anytime for urgent bugfix).\n- Monthly release: minor version at the end of every month for new features.\n- Major version release is not included in this schedule for breaking change and new features.\n\n---\n\n## 21.2.0\n\n`2026-03-20`\n\n### Features\n\n- **alert:** add loop text ([#9697](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9697)) ([6b45037](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6b45037e4d71d7df60942ead1fab0ed06ac31911))\n- **form:** support `nzVariant` ([#9694](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9694)) ([51d6eb6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/51d6eb6e1c3b18e3a5dca7da266476a091ac2eaf))\n- **input-number:** add `emitter` in `nzOnStep` event options ([#9716](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9716)) ([f83af1e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f83af1e87a6eaab041c38f0ed7b26ff8d84568c4))\n- **input:** supports custom count logic for input-wrapper ([#9645](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9645)) ([2450a60](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2450a60e12b9707f71d603092207485decc9d127))\n- **tabs:** support `nzIndicator` ([#9704](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9704)) ([02befe7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/02befe7a77e2a67f41312bb498cc34372f3408c1))\n\n### Bug Fixes\n\n- **modal:** prevent flicker on open ([#9728](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9728)) ([56ad81d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/56ad81d90ee7bf5b63f53b4e4c5cb53785ae5c12))\n- **select:** fix dropdown position in Safari ([#9724](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9724)) ([1081620](https://github.com/NG-ZORRO/ng-zorro-antd/commit/10816209670407610b53ce8f2051fbd354fb620e))\n\n## 21.1.1\n\n`2026-03-06`\n\n### Bug Fixes\n\n- **anchor:** support number id in `nzHref` ([#9683](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9683)) ([fc8a096](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fc8a096bef670cf65df2cda8cbd2f4042fdc840c))\n- **carousel:** restore responsive height on window resize ([#9612](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9612)) ([b5558ae](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b5558ae679831fa5abc1d9e4ba23c85be5a0d690))\n- **cascader:** wrong padding size ([#9699](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9699)) ([b16da90](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b16da905867fc8235d413b44e32ba3233a74dadb))\n\n## 21.1.0\n\n`2026-02-05`\n\n### Features\n\n- **collapse:** sync the latest antd styles ([#9680](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9680)) ([4eec05f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4eec05f06def8d001e5f716372cee97859a7a5fa)) ([#9678](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9678)) ([2483498](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2483498b7f841eb2caede9cfe0ed975f1e6b284c))\n- **form:** support `nzSize` ([#9606](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9606)) ([785ca6f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/785ca6fc0dec71e84b6817a650d3976f39814518))\n- **time-picker:** support `nzPrefix` ([#9647](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9647)) ([8d75887](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8d75887faee74f7a371e4c6ca9825e30375bd295))\n- **time-picker:** support `nzNeedConfirm` ([#9638](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9638)) ([9f887af](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9f887af5e14332ecabab52560db548dbabe0158f))\n- **time-picker:** support `nzPlacement` ([#9630](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9630)) ([931b3f4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/931b3f45489c410d8f00a987b74e215fe630dfec))\n\n## 21.0.2\n\n`2026-01-23`\n\n### Bug Fixes\n\n- **i18n:** add missing translations to `he_IL` ([#9658](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9658)) ([a3410a0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a3410a0c60eea5367f7c9bb56da378e96920ba8c))\n- **form:** error message never disappear if animation is disabled ([#9660](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9660)) ([798a556](https://github.com/NG-ZORRO/ng-zorro-antd/commit/798a5566388a03d88e64799f0b568c5e7130709e))\n- **menu:** submenu should respect `provideNzNoAnimation` ([#9661](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9661)) ([79ffce9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/79ffce9621fde0f41e10de822ba8aa45dfdda7ae))\n\n## 21.0.1\n\n`2026-01-16`\n\n### Bug Fixes\n\n- bundle keyframes of animation into base style files ([#9653](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9653)) ([49ec060](https://github.com/NG-ZORRO/ng-zorro-antd/commit/49ec0605b31eef0a3d790319d55d9f44492b4c0b))\n- **collapse:** no ghost zone if collapsed ([#9649](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9649)) ([5378f8b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5378f8beec14f7b47e0a54b6c81583592825ffa1))\n\n## 21.0.0\n\n`2026-01-09`\n\n### Code Refactoring\n\n- migrate to native animation API, feel free to remove the `@angular/animations` dependency\n\n### Features\n\n- **color-picker:** support `nzPresets` ([#9341](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9341)) ([d59ec99](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d59ec995b42726470ebaea39ec7a52f5c9c5e58d))\n- **core:** add `provideNzNoAnimation` ([#9555](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9555)) ([c945e81](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c945e81ce5966f34e7a96a8bccbf628a5b8d8c06))\n- **date-picker:** output date range in correct order ([#9518](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9518)) ([d0b3185](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d0b3185fb2ae891a164d3b4f28e4f68add8e166b))\n- **float-button:** add pop animation to float button menu ([#9413](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9413)) ([b40ad91](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b40ad91b26aee48fc86d92da48071751f8345ab4))\n- **input-number:** supports mouse wheel control ([#9591](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9591)) ([6ce3545](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6ce354537ec59bd0c480eed61bb8f663d2429189))\n- **input,input-number:** add additional options for `focus` method ([#9595](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9595)) ([c336711](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c3367110ccd53c5debd74799070ac6565c13c483))\n- **qrcode:** support `nzType` and `nzBoostLevel`, delete array usage of `nzPadding` ([#9535](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9535)) ([5419b51](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5419b51781478369afe3c01fe24374f2f62eeffe))\n- **tree-view:** upgrade tree view component ([#9003](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9003)) ([ae9ad57](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ae9ad576292671f3228361733b47e890d425e713))\n- **upload:** add `nzMaxCount` feature ([#9424](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9424)) ([0bf13c3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0bf13c3fa5e41289315cf4d9642ed5aa7005af9e))\n\n### Bug Fixes\n\n- **i18n:** add missing translations to `fa_IR` ([#9615](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9615)) ([1e8845d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1e8845d245ce7a98850390c61e65b301fb8fcc05))\n- **popconfirm:** allow null for `nzIcon` hide icon ([#9569](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9569)) ([760b587](https://github.com/NG-ZORRO/ng-zorro-antd/commit/760b58745a1b377d4008825a3d4c157d8a1bd590))\n- **select:** disable `nzAutoClearSearchValue` in single mode ([#9605](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9605)) ([4720c21](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4720c2175dd2bc937d8ccbf66ab804c4782f23d4))\n- **tree:** no `preventDefault` when right-clicking the node title ([#9532](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9532)) ([900efad](https://github.com/NG-ZORRO/ng-zorro-antd/commit/900efad5b0a04b1a0aca2c68728f01ed8dc4ef3b))\n\n### ⚠ BREAKING CHANGES\n\n- **back-top:** removed, please use `float-button` instead\n- **color-picker:** change DOM structure to be simpler, and remove no unnecessary payload of `nzClick` output\n- **input-number-legacy:** removed, please use `input-number` instead\n- **qrcode:** change the type of `nzPadding` from `number | number[]` to `number` ([#9535](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9535))\n- **statistic:** rename `NzStatisticNumberComponent` to `NzStatisticContentValueComponent`\n- **tabs:** remove deprecated `nz-tabset` selector ([#9613](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9613))\n- **tree-view:** `nzTreeControl` has been removed, please use `nzLevelAccessor` or `nzChildrenAccessor` instead\n- **watermark:** change import path from `ng-zorro-antd/water-mark` to `ng-zorro-antd/watermark`\n\nRemove the following APIs which were marked as deprecated in the previous version:\n\n| Module                              | API                                    |\n| ----------------------------------- | -------------------------------------- |\n| `ng-zorro-antd/back-top`            | `*`                                    |\n| `ng-zorro-antd/dropdown`            | `NzDropdownButtonDirective`            |\n| `ng-zorro-antd/input-number-legacy` | `*`                                    |\n| `ng-zorro-antd/core`                | `NzHighlightModule`                    |\n| `ng-zorro-antd/auto-complete`       | `NZ_AUTOCOMPLETE_VALUE_ACCESSOR`       |\n| `ng-zorro-antd/checkbox`            | `nz-checkbox-wrapper`                  |\n| `ng-zorro-antd/date-picker`         | `NzDatePickerComponent#nzBorderless`   |\n| `ng-zorro-antd/input`               | `NzInputDirective#nzBorderless`        |\n| `ng-zorro-antd/input-number`        | `NzInputNumberComponent#nzBordered`    |\n| `ng-zorro-antd/mention`             | `NZ_MENTION_TRIGGER_ACCESSOR`          |\n| `ng-zorro-antd/select`              | `NzSelectComponent#nzBorderless`       |\n| `ng-zorro-antd/time-picker`         | `NzTimePickerComponent#nzBorderless`   |\n| `ng-zorro-antd/tooltip`             | `NzToolTipModule` `NzToolTipComponent` |\n\nUnify and standardize component naming, involving the following name changes:\n\n| Module      | Original                      | Current                       |\n| ----------- | ----------------------------- | ----------------------------- |\n| `core`      | `NzConfig#backTop`            | `NzConfig#floatButton`        |\n| `core`      | `NzConfig#dropDown`           | `NzConfig#dropdown`           |\n| `dropdown`  | `NzDropDownModule`            | `NzDropdownModule`            |\n| `dropdown`  | `NzDropDownADirective`        | `NzDropdownADirective`        |\n| `menu`      | `NzIsMenuInsideDropDownToken` | `NzIsMenuInsideDropdownToken` |\n| `watermark` | `NzWaterMarkModule`           | `NzWatermarkModule`           |\n| `watermark` | `NzWaterMarkComponent`        | `NzWatermarkComponent`        |\n\n### Deprecations\n\nThe following APIs are marked as **deprecated** in v20 and will be removed in the next major version.\nPlease refer to related documentation for better alternatives.\n\n| Module                   | API                                                               |\n| ------------------------ | ----------------------------------------------------------------- |\n| `ng-zorro-antd/collapse` | `nz-collapse-panel[nzDisabled]`                                   |\n| `ng-zorro-antd/input`    | `textarea[nzAutosize]`, `nz-input-group`, `[nz-input-group-slot]` |\n| `ng-zorro-antd/upload`   | `nz-upload[nzTransformFile]`, `NzUploadTransformFileType`         |\n\n## 20.4.4\n\n`2025-12-12`\n\n### Bug Fixes\n\n- **icon:** include nzSpin in change detection logic ([#9597](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9597)) ([46dc381](https://github.com/NG-ZORRO/ng-zorro-antd/commit/46dc3819244969963ca80eeac9f9c06482f48d29))\n- **result:** show default icon based on status ([#9568](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9568)) ([#9582](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9582)) ([b652105](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b652105ac71a022f4d7343e911f04fbeb2dee8d0))\n\n## 20.4.3\n\n`2025-11-28`\n\n### Bug Fixes\n\n- **form:** animation should respect NoopAnimations ([#9562](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9562)) ([5bccf96](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5bccf968ab8cbe4164fe09e691f6664ee2664a5c))\n- **input:** fix dependency cycle ([#9561](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9561)) ([8d5782d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8d5782d5ae35769fc73bcdb49d9d7897b9b92828))\n\n## 20.4.2\n\n`2025-11-21`\n\n### Bug Fixes\n\n- **cascader,select,date-picker,time-picker,tree-select:** add missing nzVariant global config ([#9543](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9543)) ([221386b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/221386b45cc20d6bea689a5a4c10e35ff15b06b7))\n- **button:** improve icon only logic in zoneless mode ([#9541](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9541)) ([9def420](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9def420d2da1a2b8a7993db814948151733ef772))\n\n## 20.4.1\n\n`2025-11-14`\n\n### Bug Fixes\n\n- **badge:** hex `nzColor` should work ([#9517](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9517)) ([47d44ba](https://github.com/NG-ZORRO/ng-zorro-antd/commit/47d44ba4f826f882ee3a9de64994ad5ebd89daa5))\n- **cascader:** fix zoneless `NG0100` issue ([#9504](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9504)) ([24b4e83](https://github.com/NG-ZORRO/ng-zorro-antd/commit/24b4e83e39fe3216d02857999df78cd4fbdc35fe))\n- **color-picker:** fix `NG01350` error ([#9525](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9525)) ([fbcb8c3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fbcb8c3f78c293bd510994a28de7295e4349576c))\n- **dropdown:** update arrow placement once the position of connected overlay changes ([#9519](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9519)) ([7ff7e09](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7ff7e09d4256e8b4bd54cf2e1e01f64cabadcf4d))\n- **input:** render icon when enterButton is an empty string ([#9498](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9498)) ([6a40b0d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6a40b0db8cd23584cc4a268c16eec14cf6bbaf29))\n- **result:** nz-result-icon in ng-content does not work ([#9511](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9511)) ([0e095a1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0e095a14e0bf6014cffcb95db007b750bfe84da7))\n- **segmented:** should not block the `selected$` if no animation ([#9512](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9512)) ([af8b531](https://github.com/NG-ZORRO/ng-zorro-antd/commit/af8b53186469aa9858a9eaa883e3e597db65c598))\n- **select:** correct font size in small size ([#9516](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9516)) ([6f79005](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6f7900548ccd128b430f7a09ee3ef07dd6ea482c))\n\n## 20.4.0\n\n`2025-10-31`\n\n### Features\n\n- **cascader:** control the visibility of popup panel by `nzOpen` ([#9448](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9448)) ([4d5ec65](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4d5ec6536f64690319e0fd219dc4b07c724764db))\n- **cascader:** toggle checkbox of option by `ENTER` key in multiple mode ([#9457](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9457)) ([e02f1f4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e02f1f45f6ae1d5836b1b751bb23bfa55c5f1c33))\n- **float-button:** support `nzBadge` ([#9489](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9489)) ([12beec7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/12beec73fe3071e116788635ae17b1668d3b5ad8))\n- **form:** support `nzRequiredMark` ([#9447](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9447)) ([800b6cf](https://github.com/NG-ZORRO/ng-zorro-antd/commit/800b6cf960af7c4dfce0378eeb9fd361d21ac06b))\n- **input-number:** add affix and addon inputs ([#9451](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9451)) ([dbebd02](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dbebd025cc5101d879301405f0e0ce4baca4bdf5))\n- **input:** add `nzAllowClear` input and `nzClear` callback ([#9452](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9452)) ([830b4b3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/830b4b3cced07ecc484375ab62a3593ac7140b39))\n- **input:** introduce new component `nz-input-wrapper` ([#9408](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9408)) ([a8e56ec](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a8e56ecbc5040dc36dd38881d2d3f7133c7c7991)), closes [#9403](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9403)\n- **input:** add affix and addon inputs to `nz-input-wrapper` ([#9450](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9450)) ([763f69e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/763f69e7e35ef3697245e9074034d17f110c5876))\n- **input:** introduce `nz-input-search` directive ([#9483](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9483)) ([af6f590](https://github.com/NG-ZORRO/ng-zorro-antd/commit/af6f590b30270205300e028287f205249b316efa))\n- **input:** introduce `nz-input-password` directive ([#9460](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9460)) ([f80832a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f80832a7741a6efd9049372a8759d710dc72bde4))\n- **message:** add support for custom styles and classes ([#9427](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9427)) ([2f866b3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2f866b31febe4c1f6dd784537fc8ca2b68a66a93))\n- **pagination:** support `nzAlign` ([#9433](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9433)) ([88d0864](https://github.com/NG-ZORRO/ng-zorro-antd/commit/88d08648570756e35b989f55e15bcb116175dbc2))\n- **segmented:** add default name if `nzName` is not provided ([#9466](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9466)) ([33f8142](https://github.com/NG-ZORRO/ng-zorro-antd/commit/33f8142626e337e1cef997bc99a289effcb64dd0))\n\n### Bug Fixes\n\n- **badge:** should `nzStyle` work even if `nzColor` is not provided ([#9486](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9486)) ([4424eb0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4424eb0a018c7d90fb74dfda6ceb5c54a080eb4d))\n- **cascader:** display activated column correctly when reopen the popup panel ([#9456](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9456)) ([7802a39](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7802a39167d0efaf1bca5e829fa4907f7af54650))\n\n## 20.3.1\n\n`2025-09-17`\n\n### Bug Fixes\n\n- **drawer:** fix `NG0203` ([#9418](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9418)) ([7fb58ae](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7fb58aea2f03902ce3b0ac626bed99b5d8de0c6b))\n\n## 20.3.0\n\n`2025-09-16`\n\n### Features\n\n- **carousel:** support `nzArrows` ([#9355](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9355)) ([1b9714b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1b9714baf8d320b423f390d713af6533e0390f24))\n- **check-list:** add badge and default checked ([#9343](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9343)) ([235b493](https://github.com/NG-ZORRO/ng-zorro-antd/commit/235b493705d297ccff21969f2d770b7f4eba7fb5))\n- **i18n:** enhance `provideNzI18n` to support factory function ([#9393](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9393)) ([1371265](https://github.com/NG-ZORRO/ng-zorro-antd/commit/13712654d1c3b5de2eabc577c22d0f98a59a8345))\n- **mention:** support `nzClear` ([#9377](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9377)) ([cbecebf](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cbecebfda401b2fd873163638d3e2cc4dfd638c1))\n- **mention:** support `nzVariant` ([#9379](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9379)) ([d92568b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d92568b781bb16bfef55e645a15022ef54583ba1))\n- **segmented:** support `nzShape`([#9368](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9368)) ([ffce6c3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ffce6c385a3c994132e096a33a83bd77d01a6b7b))\n- **segmented:** support `nzName` and keyboard interactions ([#9373](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9373)) ([ebd8bdc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ebd8bdc9d0c71fc6f691c7c900e8b43e26cc0e84))\n- **upload:** support promise return type for `nzBeforeUpload` ([#9402](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9402)) ([cece107](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cece1077e5f375c225ae32973b863f8123520717))\n\n### Bug Fixes\n\n- **badge:** after setting `nzColor`, display incorrect ([#9376](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9376)) ([e9abf92](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e9abf9250ab8c7c902933688610e0f2c731b97b1))\n- **input:** variant underline style on hover ([#9400](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9400)) ([74c2173](https://github.com/NG-ZORRO/ng-zorro-antd/commit/74c217382ed191b26990082586796f588fdd73c8))\n- **segmented:** fix `NG0950` error ([#9386](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9386)) ([e82fc01](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e82fc0186d2dc8061ff1db50aaa2e7b2f11beb9d))\n- **select:** refactor multiple select styles ([#9409](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9409)) ([38f9065](https://github.com/NG-ZORRO/ng-zorro-antd/commit/38f90653569b46e28e317e040040e98bee595761))\n- **schematics:** add `less` as devDependencies if choosing custom theme in non-less project ([#9412](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9412)) ([a18cffd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a18cffd8e2dd6e39836f00a42c95f1f5699d1829))\n\n## 20.2.1\n\n`2025-08-31`\n\n### Bug Fixes\n\n- **segmented:** correctly render with-icon & icon-only ([#9367](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9367)) ([9d42b42](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9d42b42ad103e8ca498e65e7aa6ad7e72075d609))\n\n## 20.2.0\n\n`2025-08-29`\n\n### Features\n\n- **cascader:** add `nzOpen` to control visibility ([#9339](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9339)) ([354c7cf](https://github.com/NG-ZORRO/ng-zorro-antd/commit/354c7cfb9e9746fc55ccc3f5967721ab01737652))\n- **collapse:** support `nzCollapsible` ([#9349](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9349)) ([1ddbcaf](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1ddbcaf8e8c5f47a5c2354ac61bf3da707e8a99c))\n- **collapse:** support `nzSize` ([#9348](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9348)) ([b5c256d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b5c256da531b5b306f831c8ee05acf0139bc7ad3))\n- **divider:** support `nzSize` ([#9346](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9346)) ([1f54536](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1f5453639f059c9058815834500e459df4082882))\n- **dropdown:** display arrow for content dropdown ([#9329](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9329)) ([3686b73](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3686b7375839412b0db26f896fb810a4bdb2ae0c))\n- **float-button:** `nzIcon` support string type ([#9302](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9302)) ([ce611e5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ce611e5d9096456e032db78acc886b5dde60220c))\n- **segmented:** support `nzVertical` ([#9359](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9359)) ([52322cd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/52322cd50c1d2883a0df7ca0aee91f803448315b))\n- **select,tree-select,cascader:** support prefix and suffix icon ([#9328](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9328)) ([527ffb6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/527ffb6efee5759e58c7472f1fae2a619092f246))\n- **tag:** export `NzTagColor` type ([#9314](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9314)) ([1efd29e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1efd29ee1de0f77854dd75c10c9156d50013067d))\n\n### Bug Fixes\n\n- **carousel:** wrong dot position when placement is left or right ([#9358](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9358)) ([f117ccb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f117ccb739754e5a1b73be844679357cc807a238))\n- **range-picker:** clear outline on mouse leaving ([#9352](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9352)) ([573d092](https://github.com/NG-ZORRO/ng-zorro-antd/commit/573d092f6e332acaeb33dfc03c0e370be6753df8))\n- **segmented:** should render single element in item if icon-only ([#9363](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9363)) ([89d2168](https://github.com/NG-ZORRO/ng-zorro-antd/commit/89d216871b0a9127aa4adbf6a034b7e2e1febf2d))\n\n## 20.1.3\n\n`2025-08-22`\n\n### Bug Fixes\n\n- **i18n:** add missing translations to `cs_CZ` ([#9334](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9334)) ([93e486e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/93e486eeb848fb3cbb2073f107ae7be4bba2457b))\n- **i18n:** add missing translations to `sk_SK` ([#9335](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9335)) ([ddefc7f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ddefc7f9e95cde34101896fd5bfe587ff1dd8a89))\n- **cascader:** invalid value and label when binding dynamically ([#9338](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9338)) ([324ab5b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/324ab5b2ad281abb77344b9ca0dd66d4ca55e794))\n- **popconfirm:** correctly render icon & title ([#9322](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9322)) ([2c83788](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2c837883853a77a5a8fe1c2245daa0548a7bb2d9))\n- **select:** shaking when closing dropdown if use a TemplateRef as `nzNotFoundContent` ([#9336](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9336)) ([366f8eb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/366f8ebcd79900a4d6a512b72094af3494c55871))\n\n## 20.1.2\n\n`2025-08-08`\n\n### Bug Fixes\n\n- **input-number:** make sure the displayed value is correct ([#9312](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9312)) ([7a2d3b6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7a2d3b6f97bf80f2f517626f5e02625c4488be80))\n- **select,tree-select,cascader:** selected item with long label displayed in ellipsis ([#9316](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9316)) ([30672d7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/30672d7978f0ca4b24ec04c196c967b69e614525))\n- **table:** add cdkScrollable to internal scrolling element ([#9308](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9308)) ([8cb4113](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8cb411332b90b55bab3ec742c455e3aaaf4618d7))\n\n## 20.1.1\n\n`2025-08-05`\n\n### Bug Fixes\n\n- **badge:** export `NzBadgeStatusType` type ([#9298](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9298)) ([91b1ad7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/91b1ad7af23eda253c21530e2a01a5ac9f7c62a8))\n- **layout:** fix showcases ([#9303](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9303)) ([9a37ef8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9a37ef8325522ee200462b75e13a72f403ec4bef))\n\n## 20.1.0\n\n`2025-07-21`\n\n### Features\n\n- add [llms.txt](https://ng.ant.design/llms.txt) and [llms-full.txt](https://ng.ant.design/llms-full.txt) ([#9281](https://github.com/NG-ZORRO/ng-zorro-antd/pull/9281)) ([165b963](https://github.com/NG-ZORRO/ng-zorro-antd/commit/165b96372e737a6dceac9404bded06041d286e2a))\n- **float-button:** support `nzPlacement` ([#9267](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9267)) ([9dc19f3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9dc19f35c9f4d9de0c6fc1f2b58c97f2aded95c1))\n- **input-number:** accepted numbers with commas ([#9256](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9256)) ([7567bd8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7567bd87a7862b52c12e152b9ce0c395b5e18ff0))\n- **input:** input-otp supports keyboard control positioning ([#9268](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9268)) ([da97b02](https://github.com/NG-ZORRO/ng-zorro-antd/commit/da97b02a82361e23c77f14bec76add77f6c39302))\n- **popconfirm:** add `nzDanger` support to cancel button ([#9270](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9270)) ([f94cb31](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f94cb318b05b01d1560ddfe3a5bfb226f23a83b4))\n- **space:** support array for size ([#9289](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9289)) ([8809885](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8809885be2b268e38c8ba04f57f46803e92e0c28))\n- **schematics:** align with the updated style guide ([#9295](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9295)) ([b5f607b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b5f607b874ed150fb1858eb81b19c3cc67478f37))\n\n### Bug Fixes\n\n- **core:** avoid using `setAttribute` to set `style` ([#9292](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9292)) ([12d58bd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/12d58bde7cb8d762405728825d6261fe5fc663b8))\n- **input-number:** ngModel value can be `undefined` ([#9269](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9269)) ([4c5666a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4c5666a90f477703dcda96ec135a6eea99d11105))\n- **tooltip:** rename `ToolTip` to `Tooltip` ([#9285](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9285)) ([2ebef97](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2ebef970cb7cd2855ee725b89ab8dfef9e6e35d6))\n- **schematics:** support `NzTooltipModule` migration ([#9294](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9294)) ([add21f7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/add21f71d92645be9f1c7684c2f213a6864f5891))\n\n## 20.0.0\n\n`2025-07-01`\n\n### Features\n\n- **cascader,date-picker,input-number,input,select,time-picker,tree-select:** support `nzVariant` ([#9131](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9131)) ([b342bb4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b342bb464eb544a2e3fda8723cac7e550828b3f2))\n- **popover:** add `nzPopoverTitleContext` and `nzPopoverContentContext` ([#9126](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9126)) ([df3ead9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/df3ead9af8368eb7e2374744f01cecd5ccc21440))\n- **select:** add `nzOnClear` callback ([#9188](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9188)) ([e047ac2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e047ac249b16b547525a0ca4d13beeef620f44c4))\n- **avatar:** add `loading` and `fetchpriority` attributes ([#7347](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7347)) ([ff8419f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ff8419f6614bdac8bc3c778e470da08b679889d0))\n- **popconfirm:** add `nzOkButtonProps` and `nzCancelButtonProps` ([#9245](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9245)) ([22e2a9f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/22e2a9fb148fd875c76fb339c6582d92aef62791))\n- **tree-select:** render title of selected node in innerHTML ([#9259](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9259)) ([8066f7b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8066f7bb082c95652a2e158a01e55382992fe8c6))\n\n### Bug Fixes\n\n- **flex:** fix `NzAlign` type ([#9151](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9151)) ([b271c19](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b271c19076ead71fabbe5b224072cfea975d801d))\n- **segmented:** accepts disabled state from ng control ([#9166](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9166)) ([134cd59](https://github.com/NG-ZORRO/ng-zorro-antd/commit/134cd5976220d51179118491a4b4b2e4d7cf761c))\n- **space:** border radius compact mode one item ([#9165](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9165)) ([d2f4541](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d2f4541a9ae01d6ea8705faf2bc4b96bf34b6945))\n- **tabs:** prevent incorrect scroll offset on tab focus ([#9186](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9186)) ([4f658e0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4f658e0834e99ea2be0ffd4ead2dd041ec88fb83))\n- **schematics:** ng add failed when call twice ([#9171](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9171)) ([d0a9748](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d0a974848c0e31ad41ba69a5af60c002a7b251cd))\n- **water-mark:** make server-side compatible ([#9250](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9250)) ([a70a682](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a70a682c8aa4d073bb150abd4b69104fbe21e2ed))\n- **icon:** debounce icon rendering on animation frame ([#8579](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8579)) ([c0709d1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c0709d1e01d80969a48634fe8194dbfd49f6192f))\n\n### Code Refactoring\n\n- **core:** cleanup animation frame polyfill ([#9243](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9243)) ([272237a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/272237a7a33d150ac9c0f6965df37a678221b074))\n- migrate to `inject` pattern\n\n### ⚠ BREAKING CHANGES\n\n- **core:** refactoring in `ng-zorro-antd/core/polyfill`:\n  - rename `cancelRequestAnimationFrame` to `cancelAnimationFrame`\n  - rename `reqAnimFrame` to `requestAnimationFrame`\n- **tabs:** rename `NzTabsetComponent` to `NzTabsComponent`, `nz-tabset` selector to `nz-tabs`, the original component and selector are marked as deprecated\n- **table:** no longer compatible with material components\n\n* **popconfirm:** `nzOkDisabled` and `nzOkDanger` are marked as deprecated, use `nzOkButtonProps` and `nzCancelButtonProps` instead\n\nRemove the following APIs which were marked as deprecated in the previous version:\n\n| Module                       | API                                                      |\n| ---------------------------- | -------------------------------------------------------- |\n| `ng-zorro-antd/button`       | `NzButtonGroupComponent`                                 |\n| `ng-zorro-antd/core/form`    | `NzFormPatchModule`                                      |\n| `ng-zorro-antd/checkbox`     | `NzCheckBoxOptionInterface`                              |\n| `ng-zorro-antd/input`        | `NzInputGroupComponent#nzCompact`                        |\n| `ng-zorro-antd/message`      | `NzMessageModule`                                        |\n| `ng-zorro-antd/notification` | `NzNotificationModule`<br/>`NzNotificationServiceModule` |\n\nThe `exportAs` of components are updated to follow `camelCase` and start with `nz`, `exportAs` of internal components are removed. Changes can be seen as follow:\n\n| Component                | Original               | Current                |\n| ------------------------ | ---------------------- | ---------------------- |\n| `calendar-footer`        | `calendarFooter`       | -                      |\n| `date-helper`            | `dateHelper`           | -                      |\n| `date-range-popup`       | `dateRangePopup`       | -                      |\n| `date-table`             | `dateTable`            | -                      |\n| `decade-helper`          | `decadeHelper`         | -                      |\n| `decade-table`           | `decadeTable`          | -                      |\n| `month-helper`           | `monthHelper`          | -                      |\n| `month-table`            | `monthTable`           | -                      |\n| `quarter-helper`         | `quarterHelper`        | -                      |\n| `quarter-table`          | `quarterTable`         | -                      |\n| `year-helper`            | `yearHelper`           | -                      |\n| `year-table`             | `yearTable`            | -                      |\n| `inner-popup`            | `innerPopup`           | -                      |\n| `nz-color-block`         | `NzColorBlock`         | `nzColorBlock`         |\n| `nz-color-format`        | `NzColorFormat`        | `nzColorFormat`        |\n| `nz-color-picker`        | `NzColorPicker`        | `nzColorPicker`        |\n| `nz-model-close`         | `NzModalCloseBuiltin`  | `nzModalCloseBuiltin`  |\n| `nz-model-footer`        | `NzModalFooterBuiltin` | `nzModalFooterBuiltin` |\n| `nz-model-title`         | `NzModalTitleBuiltin`  | `nzModalTitleBuiltin`  |\n| `nz-tree-drop-indicator` | `NzTreeDropIndicator`  | `nzTreeDropIndicator`  |\n| `nz-water-mark`          | `NzWaterMark`          | `nzWaterMark`          |\n| `nz-tabs`                | `nzTabset`             | `nzTabs`               |\n\n### Deprecations\n\nThe following APIs are marked as **deprecated** in v20 and will be removed in the next major version.\nPlease refer to related documentation for better alternatives.\n\n| Module                         | API                                                                          |\n| ------------------------------ | ---------------------------------------------------------------------------- |\n| `ng-zorro-antd/autocomplete`   | `NZ_AUTOCOMPLETE_VALUE_ACCESSOR` <br /> `getNzAutocompleteMissingPanelError` |\n| `ng-zorro-antd/button`         | `NzButtonGroupComponent`                                                     |\n| `ng-zorro-antd/core/form`      | `NzFormPatchModule`                                                          |\n| `ng-zorro-antd/core/highlight` | `NzHighlightModule`                                                          |\n| `ng-zorro-antd/checkbox`       | `NzCheckBoxOptionInterface`                                                  |\n| `ng-zorro-antd/input`          | `NzInputGroupComponent#nzCompact`                                            |\n| `ng-zorro-antd/mention`        | `NZ_MENTION_TRIGGER_ACCESSOR`                                                |\n| `ng-zorro-antd/message`        | `NzMessageModule`                                                            |\n| `ng-zorro-antd/notification`   | `NzNotificationModule`<br/>`NzNotificationServiceModule`                     |\n| `ng-zorro-antd/tabs`           | `NzTabsetComponent`                                                          |\n\n## 19.3.1\n\n`2025-05-29`\n\n### Bug Fixes\n\n- **cascader:** cannot update value when it is missing in options ([#9124](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9124)) ([689fc72](https://github.com/NG-ZORRO/ng-zorro-antd/commit/689fc72e5c8175c830f995155daf1d7d4c318c25))\n- **date-picker:** update input value when nzFormat changed ([#9129](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9129)) ([f4c4e05](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f4c4e05264dd3109a0c45018886603ddd9c45aa2))\n- **tabs:** `nzLinkRouter` not work for the first time load ([#9130](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9130)) ([925a6a5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/925a6a54dd477b687b3dd0b836c32cb17e6d8a0f))\n\n## 19.3.0\n\n`2025-05-23`\n\n### Features\n\n- **avatar:** support custom icon by ng-content ([#9090](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9090)) ([89d0767](https://github.com/NG-ZORRO/ng-zorro-antd/commit/89d076775b542996c46e48d2fb6f49c5981be40b))\n- **input-number:** add `nzBlur` and `nzFocus` output ([#9098](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9098)) ([1b1a013](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1b1a0130df4a86fb2abd42d95213d880fd0b14d7))\n- **tabs:** support for start and end extra content ([#9097](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9097)) ([2500821](https://github.com/NG-ZORRO/ng-zorro-antd/commit/250082160770d7f24404bbed86af5df96b9f3e53))\n- **transfer:** support multiple row selection with `Shift` key ([#9092](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9092)) ([b78b99f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b78b99f9f4cec6298cffc915b8ab86f708dccddf))\n\n### Bug Fixes\n\n- **i18n:** add missing translations to `es_ES` ([#9127](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9127)) ([0aadfdf](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0aadfdf39682bd779eabae57e02596fd0f730624))\n- **segmented:** fix emitting unnecessary value changed events ([#9125](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9125)) ([fb0635b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fb0635b0dc2fed0f28d60248b60b0ecd5e3294d4))\n- **tabs:** `nzLinkRouter` not work for the first time ([#9118](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9118)) ([0f7f94d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0f7f94dab24175b28f34720f5c98e7dc9a2c6c88))\n\n### Performance Improvements\n\n- **transfer:** use item.key as tracking for the list render ([#9123](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9123)) ([adb91e4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/adb91e4ba0cbcfc72cccb26a66580fa19dc9c8aa))\n\n## 19.2.2\n\n`2025-04-25`\n\n### Bug Fixes\n\n- **input-number:** fix `NG0600` error ([#9106](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9106)) ([9f5b525](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9f5b525e5eb5e50ed4f93ed15b6831d7db3483ee))\n- **checkbox:** fix `NG0600` error ([#9105](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9105)) ([61b6886](https://github.com/NG-ZORRO/ng-zorro-antd/commit/61b68861a6215e40bd29e14d2fe2bc02ce112ce0))\n- **checkbox:** fix type of `nzOptions` ([#9099](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9099)) ([7be2fe5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7be2fe5412aa00b9178dcae49f202b21a1b7e9e8))\n- **select:** limit number of pasted item to `nzMaxMultipleCount` ([#9080](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9080)) ([3714840](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3714840a8a72d4d7809a2cac339dd3891052225d))\n\n## 19.2.1\n\n`2025-03-29`\n\n### Bug Fixes\n\n- **select:** remove internal comment from select-arrow ([#9074](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9074)) ([c9b2dd9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c9b2dd96db78ff257137b7a2cba79bbf70f64d3e))\n\n## 19.2.0\n\n`2025-03-28`\n\n### Features\n\n- **splitter:** add splitter component ([#8987](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8987)) ([9b3f62e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9b3f62e088f3d0953f236910df00175edf07e26e))\n- **page-header:** disable back button if no history ([#9041](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9041)) ([bb48232](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bb482328637829b91443075dddaaaef74b85cda8))\n\n### Documentation\n\n- **tabs:** add draggable tabs [showcase](https://ng.ant.design/components/tabs/en#components-tabs-demo-card-draggable) via CDK `DragDropModule`\n\n### Bug Fixes\n\n- **input-number:** consider input value ends with 0 as incomplete ([#9051](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9051)) ([2a0c2e0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2a0c2e08bcec7577558bf2578adf7710a5235a38))\n- **segmented:** fix error with the FormControl first change ([#9039](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9039)) ([33fe53d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/33fe53de16bbafd234fa369f677355349d24860a))\n- **select:** disable `nzMaxMultipleCount` in default mode ([#9068](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9068)) ([dcf8a5d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dcf8a5d35785d5a4b282719601c0b226e67543bc))\n- **select:** ngModel change should update state of `nzMaxMultipleCount` reached ([#9056](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9056)) ([d7031da](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d7031dada3f24cf9c7e48a2eb09678d44caaf9b1))\n- **space:** nzSpaceItem margin in rtl ([#7801](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7801)) ([2d9ff5f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2d9ff5f0735afc4f4ae03e9f85ae4a8062c21f1a))\n- **tabs:** update active router tab after tabs changed ([#7649](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7649)) ([1f07121](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1f07121c3c8521036b011a6f71e1859f70cfe429))\n- **tree-select:** enable overflow-x for virtual scroll ([#9045](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9045)) ([e70cae3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e70cae3c7cbd47c82d575a49e1dc6a31faa5912d))\n\n## 19.1.0\n\n`2025-02-21`\n\n### Features\n\n- **check-list:** add check-list component ([#8969](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8969)) ([4cd298b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4cd298bfdce3c96e47c91e689fbad16c36d72b60))\n- **message,notification:** display `nzData` when content is a template ([#9001](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9001)) ([5157470](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5157470dd7d890703e4b3a8db9909891da4932c0))\n- **popover,popconfirm,tooltip:** `overlayClassName` supports space delimited classes string ([#8972](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8972)) ([3fcec91](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3fcec916b81a284fc8934846aab26d5b8ce99a1b))\n- **popover:** add `nzPopoverOverlayClickable` to disable click on mask ([#8878](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8878)) ([5898da7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5898da718f2568cdb2a6dcc63b6e7e18ccb217aa))\n\n### Bug Fixes\n\n- **input-number,checkbox:** accept the disabled change from ng control ([#8979](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8979)) ([2d8968d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2d8968d4709aee858634274d22196ecbbfbe8764))\n- **input-number:** use input event instead of change event ([#8989](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8989)) ([6d8d915](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d8d91521a6d4315b6a01fc173e3ed8df8bdecf0))\n- **tree-select:** fix error when judging multiple instances condition ([#9008](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9008)) ([5006ea6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5006ea695430c3c0f127f04c3a9bcf6dfd6c1a29))\n\n### Code Refactoring\n\n- use ECMAScript standard class field ([#8718](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8718)) ([f1d8d92](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f1d8d926b48a798489f54d4f3da6eec0f90f9955))\n- enable isolatedModules compiler option ([#8970](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8970)) ([0d42aa7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0d42aa7d4605c881c242e245b8127629e9657e39))\n\nNow feel free to use `isolatedModules` compiler option in your project.\n\n## 19.0.2\n\n`2025-01-10`\n\n### Bug Fixes\n\n- **auto-complete:** should open the popover when the focused input is clicked ([#8900](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8900)) ([79cc2f8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/79cc2f830133dfe0ee99eaabdb7b5b5f1eca2e02))\n- **progress:** fix `NG0956` error ([#8962](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8962)) ([c4d2f81](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c4d2f81f125feca0ce5ad90e12997875b4465230))\n- **transfer:** correctly set the transfer-list-body class ([#8960](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8960)) ([a3546a9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a3546a9032dcc8fbbd72088e4a431e83b99b32f1))\n\n## 19.0.1\n\n`2025-01-03`\n\n### Bug Fixes\n\n- **date-picker:** cell title should reflect `nzFormat` ([#8744](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8744)) ([1b7ab5a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1b7ab5adb5af783e3a6a47ffc4916961993f4d6f))\n- **i18n:** add missing translations to `zh_TW` ([#8950](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8950)) ([9607e11](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9607e1161244b441badb2c37093c4f44a2d63695))\n- **input-number:** fix `NG0600` error ([#8955](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8955)) ([8d6135e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8d6135e65a6aa716678b9485e3e7790182d160b1))\n- **table:** should col be wrapped within colgroup in ssr mode ([#8948](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8948)) ([0a73deb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0a73deb053d2d9ab8d8194038355fad898b60759))\n\n## 19.0.0\n\n`2024-12-06`\n\n### Bug Fixes\n\n- **autocomplete:** remove inline style (CSP compliant) ([#8875](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8875)) ([30c25f0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/30c25f0201130ccb00c8d2ba2e709763d7bcfd6e))\n- **avatar:** calculate size at the right time ([#8754](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8754)) ([3a5ba37](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3a5ba37de6553c5973ac1741a250dff957ca7ec5))\n- **card:** remove `nzBorderless` input ([#8741](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8741)) ([22ce17c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/22ce17c8a4bb7345cf026fd570bc8d3984722815))\n- **carousel:** carousel not working correctly in rtl mode ([#8770](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8770)) ([0202a19](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0202a191b3259e3dc454272b53feb3687a32cf0a))\n- **cascader:** correct menu display level ([#8866](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8866)) ([5fec53e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5fec53e597d50a26a1083bb1e726af885ba807ae))\n- **drawer:** should clear previously focused element ([#8893](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8893)) ([4498af0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4498af0f1a8c700099e82f4027bec30086f6d29a))\n- **i18n:** add missing translations to `vi_VN` ([#8894](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8894)) ([f08ad1c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f08ad1cb0728d19655c8143658e6a44f8843cb4a))\n- **tree-view:** `nzTreeNodePadding` not works in virtual scroll ([#8920](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8920)) ([82b660a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/82b660ac55539e9cb2c39b399884f8bec4d028d4))\n\n### Code Refactoring\n\n- cancel support for HTML string rendering ([#8831](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8831)) ([5fae01a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5fae01ad4120841390f7ebb6267a043774ea2266))\n- remove `ngClass` and `ngStyle` ([#8895](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8895)) ([c3ab3ba](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c3ab3ba6ad50dc4a8f23b43872b3f235ee316f4c))\n- **image:** remove deprecated `FADE_CLASS_NAME_MAP` and `IMAGE_PREVIEW_MASK_CLASS_NAME` ([#8912](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8912)) ([65223d9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/65223d9a595e78f8c73347c5d1b12a807389c434))\n- **transfer,tree,tree-select** rename `CheckBox` to `Checkbox` ([#8934](https://github.com/NG-ZORRO/ng-zorro-antd/pull/8934)) ([c76433d5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c76433d5533f6d5c0467ee99c61877a0ec4d35ac))\n\n### Features\n\n- **cascader:** support multiple selection ([#8903](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8903)) ([e5dfb49](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e5dfb495dc4f9e5493e425aeab3802a13a0f5e28))\n- **cascader:** support `nzPlacement` ([#8935](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8935)) ([6fbd22c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6fbd22c5b38b78cc991bb61446acbea635f30797))\n- **checkbox:** redesign the checkbox group component ([#8932](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8932)) ([489e0de](https://github.com/NG-ZORRO/ng-zorro-antd/commit/489e0defbfeeb03c29562d139614451575f8ed8d))\n- **divider:** add `nzVariant` option ([#8827](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8827)) ([2c63c87](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2c63c87f557e2400224566342a0185d212055004))\n- **float-button:** add float-button component ([#7884](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7884)) ([dab4d66](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dab4d669b3ef746d1761fbb2199c1b0ae704cda5))\n- **icon:** support `nz-icon` tag selector ([#8778](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8778)) ([1406241](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1406241f2e636bb3bf11515b0ad68cbe0535d5e1))\n- **image:** close image preview when escape key pressed ([#8809](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8809)) ([d587615](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d587615c7dd8d911af06551181f1bffb6eb67149))\n- **input:** support one time password (OTP) ([#8715](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8715)) ([cdbaf4d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cdbaf4de291f380cfcfdf6788d24da3e344175a9))\n- **menu:** add `nzTriggerSubMenuAction` to support click trigger for submenu ([#8461](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8461)) ([860df87](https://github.com/NG-ZORRO/ng-zorro-antd/commit/860df87a1be62f462ac3ea136d53948ccd69213a))\n- **qrcode:** add `nzStatusRender` to support customize state rendering ([#8714](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8714)) ([6f36d75](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6f36d75741e301bc3e7634a93c106c48a02c0a1b))\n- **segmented:** redesign the segmented component ([#8753](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8753)) ([4dc866c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4dc866cb2fcc7afb4cc309f433c216d1b7cba2e1))\n- **space:** add space compact component ([#8755](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8755)) ([b9c511d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b9c511db0b1b28521e23148a6fce5b1f169f99a2))\n- **table:** add `nzSortDirections` to global config ([#6613](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6613)) ([#8721](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8721)) ([eb1fdc5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/eb1fdc5037d9122a237e317e5b93857deb51e5d5))\n- **transfer:** add `nzOneWay` to support one way style ([#8717](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8717)) ([99fd4de](https://github.com/NG-ZORRO/ng-zorro-antd/commit/99fd4de95b2a5a44a2837af38d31ddcabf0a60bf))\n- **input-number:** redesign the input-number ([#8901](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8901)) ([df55d88](https://github.com/NG-ZORRO/ng-zorro-antd/commit/df55d8882c9f36bc6a0cd8a4d752e03070658ff7))\n- **schematics:** add v19 ng update migration ([#8911](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8911)) ([1a20de2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1a20de223bc6e214b54f741f42ed8260611b9b67))\n\n### BREAKING CHANGES\n\n- **All**\n  - `nzClass` / `nzStyle` input properties no longer support the following features:\n    - `Set()`: use arrays instead\n    - Keys which multiple styles/classes separated with keys: split a key with spaces into multiple keys\n  - Cancel support for HTML string rendering\n  - Migrate `@WithConfig` to standard decorator. If you're using `@WithConfig` in your library, please turn `experimentalDecorators` off in `tsconfig.json`\n  - Migrate `[nz-icon]` to `nz-icon` tag. If you're using `[nz-icon]` selector in stylesheet to select icon **inside** zorro component, please use `nz-icon` instead\n\n- **input-number:** Redesign the input-number so that it will be much simpler and more flexible.\n\n  Now you can use affixes or addons as follows, no need for `ng-template` and `nz-input-number-group`:\n\n  ```html\n  <!-- Custom handler icons -->\n  <nz-input-number>\n    <nz-icon nzInputNumberUpIcon />\n    <nz-icon nzInputNumberDownIcon />\n  </nz-input-number>\n\n  <!-- With affixes -->\n  <nz-input-number>\n    <span nzInputPrefix>Prefix</span>\n    <span nzInputSuffix>Suffix</span>\n  </nz-input-number>\n\n  <!-- With addons -->\n  <nz-input-number>\n    <span nzInputAddonBefore>Before</span>\n    <span nzInputAddonAfter>After</span>\n  </nz-input-number>\n  ```\n\n  The old input-number component is marked as **deprecated**, and its entrypoint had changed to `ng-zorro-antd/input-number-legacy`.\n  `NzInputNumberComponent` is now `NzInputNumberLegacyComponent`, and `NzInputNumberModule` is now `NzInputNumberLegacyModule`.\n\n  Don't worry, `ng update ng-zorro-antd` will automatically do the migration.\n\n- **cascader:** Cancel support for writing value with `NzCascaderOption[]` type.\n\n  In the past, the cascader component kept a trick that if you wrote value with `NzCascaderOption[]` type, it extracted value by mapping each item to its value property, for example:\n\n  ```ts\n  @Component({\n    template: `<nz-cascader [nzOptions]=\"options\" [ngModel]=\"value\"></nz-cascader>`\n  })\n  export class ExampleComponent {\n    value = [{ label: 'NG ZORRO', value: 'ng-zorro-antd' }];\n  }\n  ```\n\n  then the value of cascader would be `'ng-zorro-antd'`.\n  It's strange that the input and output values don't match when we haven't changed the values, and it's hard to maintain. We expect that the value passed in should be the value in the list of options.\n\n  In v19, this trick is removed and if you're already using this trick in your code, please consider the add a `map` function to pass the actual value.\n\n- **checkbox** Redesign the checkbox group component.\n  - Remove `NzCheckBoxOptionInterface['checked]` field. By the way, `NzCheckBoxOptionInterface` is marked as deprecated, use `NzCheckboxOption` instead\n  - `nz-checkbox-group`: Type of `ngModel` is changed from `NzCheckBoxOptionInterface[]` to `NzCheckboxOption['value'][]`\n\n- **card:** Remove redundant `nzBorderless` input property. Use `nzBordered` instead.\n- **image:** Remove deprecated `FADE_CLASS_NAME_MAP` and `IMAGE_PREVIEW_MASK_CLASS_NAME`\n- **pipes:** Remove deprecated `NzSafeNullPipe`\n- **segmented:** Redesign the segmented component.\n  - Value of `ngModel` is changed from `index` to option's value\n  - Change emission type of `nzValueChange` from `number` to option's value type (`string | number`)\n  - Remove `nzLabelTemplate`, use `nz-segmented-item` directive instead\n- **space:** Rename `exportAs` of `NzSpaceComponent` from `NzSpace` to standard `nzSpace`\n- **transfer:** Rename `nzTreeCheckBoxChange` to `nzTreeCheckboxChange`\n- **tree,tree-select:** Rename `nzCheckBoxChange` to `nzCheckboxChange`\n\n### Deprecations\n\nThe following APIs are marked as **deprecated** in v19 and will be removed in the next major version.\nPlease refer to related documentation for better alternatives.\n\n| Module                              | API                                                      |\n| ----------------------------------- | -------------------------------------------------------- |\n| `ng-zorro-antd/button`              | `NzButtonGroupComponent`                                 |\n| `ng-zorro-antd/core/form`           | `NzFormPatchModule`                                      |\n| `ng-zorro-antd/checkbox`            | `NzCheckboxWrapperComponent`                             |\n| `ng-zorro-antd/input`               | `NzInputGroupComponent#nzCompact`                        |\n| `ng-zorro-antd/input-number-legacy` | `*`                                                      |\n| `ng-zorro-antd/message`             | `NzMessageModule`                                        |\n| `ng-zorro-antd/notification`        | `NzNotificationModule`<br/>`NzNotificationServiceModule` |\n\n## 18.2.1\n\n`2024-11-15`\n\n### Bug Fixes\n\n- **anchor:** fix `a` tag problem with `null` or `undefined` value if TemplateRef provided ([#8864](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8864)) ([41f6609](https://github.com/NG-ZORRO/ng-zorro-antd/commit/41f66095fdaee05d8bfdae13e8ec18a63cee1f2c))\n- **color-picker:** remove inline style (CSP compliant) ([#8874](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8874)) ([0264da9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0264da98babca9f14a2c69ccb019944aa4e9f88f))\n- **image:** remove inline style (CSP compliant) ([#8876](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8876)) ([63c8953](https://github.com/NG-ZORRO/ng-zorro-antd/commit/63c895329a78575654994b607fa822f5735166f4))\n- **qrcode:** remove event listeners once settled ([#8861](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8861)) ([40d466d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/40d466dab751c51b8cecb97dc974a1d17a7692e6))\n- **select:** remove inline style (CSP compliant) ([#8873](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8873)) ([9431d0d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9431d0d9e54c76271f7dc13c9833c29bf4e7dc13))\n- **transfer:** cancel selecting all should emit `nzSelectChange` event ([#8872](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8872)) ([5ff9821](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5ff98216002da5c9fc23a9d9c8bd4d3b68495d51))\n- **watermark:** cleanup event listeners once settled ([#8862](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8862)) ([decd477](https://github.com/NG-ZORRO/ng-zorro-antd/commit/decd4772bdbfeb1a1397c2b597882503ca5685ad))\n\n## 18.2.0\n\n`2024-11-07`\n\n### Bug Fixes\n\n- **i18n:** add missing translations to `nb_NO` ([#8712](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8712)) ([8c9bcd1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8c9bcd18867fca3778d42b844034a4d3370ebe3b))\n- **i18n:** add missing translations to `hu_HU` ([#8769](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8769)) ([9e21ae8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9e21ae8c3c771ff3bce98a11c37f5c81c62f3402))\n- **badge:** NG0955 warning in nz-badge-sup component ([#8858](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8858)) ([cc52555](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cc5255587edae6731d38f39786c701679c50020b))\n- **select:** multiple select cause switch size flash when init ([#8851](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8851)) ([d28876c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d28876cdae5bb1b4df3fda66ebdf6248e43f5a36))\n- **carousel:** correctly switch slides in rtl mode ([#8705](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8705)) ([85f23a1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/85f23a1b768151a35637c054c7bf42cbf656268e))\n- **drawer:** emit `nzVisibleChange` when close on navigation ([#8850](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8850)) ([29827df](https://github.com/NG-ZORRO/ng-zorro-antd/commit/29827dfe2346badc5178da71884bb4c3264a695d))\n- **modal,drawer:** secondary overlays not scrolling inside ([#8804](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8804)) ([ed7951d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ed7951d2e95707c93e993dbb744382e6c9c7dee8))\n- **modal:** remove dark backdrop when `nzMask` is false ([#8798](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8798)) ([f2f04fe](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f2f04fe8971b23aba9ec5807414afe5ab6f27fc7))\n- **transfer:** correctly set transfer button disable state ([#8824](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8824)) ([195ad26](https://github.com/NG-ZORRO/ng-zorro-antd/commit/195ad260a8259129517ee18a208853b9e32c132d))\n\n### Features\n\n- **datepicker:** send event emitter when panel mode change ([#8685](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8685)) ([6462a47](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6462a47538a4c7f00f180d82dc3567379277e4b3))\n- **tabs:** support `destroyInactiveTabPane` ([#8845](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8845)) ([0de6d62](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0de6d627cb9105d97b1aca827b1f89a8f3bdcec9))\n\n## 18.1.1\n\n`2024-08-20`\n\n### Bug Fixes\n\n- fix ngtypecheck reference issue caused by [@angular/compiler-cli#56945](https://github.com/angular/angular/issues/56945) ([#8699](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8699)) ([8e459c1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8e459c192cf5c4b1903a744c0548df800aa64bfc))\n- **date-picker:** fix the NG0956 warning when recreating entire collection ([#8658](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8658)) ([70a0817](https://github.com/NG-ZORRO/ng-zorro-antd/commit/70a0817cd8db49234726f160d9c2ae36f5c650b7))\n- **grid:** fix the NG0955 warning in showcase ([#8679](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8679)) ([6414c92](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6414c924cdb013c0ffb96436dd89354e275fa544))\n- **tree-select:** clear selected nodes when user set value ([#8693](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8693)) ([91927bc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/91927bcede24a89ffc5ec4c814503547c86ad09e))\n\n## 18.1.0\n\n`2024-07-25`\n\n### Bug Fixes\n\n- **cascader:** hide placeholder when trigger `compositionstart` event ([#8641](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8641)) ([17b0ea3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/17b0ea362021a458c18204f73c34c08695300e2a))\n- **i18n:** add missing translations to `pt_BR` ([#7790](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7790)) ([6fc1c78](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6fc1c78b4ca0d37bf5eb6e9e52f0fd150ca5855d))\n- **i18n:** add scanned field to QRCode for `fr_BE`, `fr_CA`, `fr_FR` and `lv_LV` ([#8614](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8614)) ([9b69410](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9b69410ce8f84fbd65e2f0dc627189403888d8f1))\n- **schematics:** import missing `RouterLink` in template ([#8621](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8621)) ([032a0c2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/032a0c2384434fc042674a60b005a5a479f6626a))\n- **transfer:** disabling selection does not affect selecting all ([#8633](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8633)) ([75d8c7b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/75d8c7b93310cd54677ac75f470b2967ebd092cb))\n\n### Features\n\n- **breadcrumb:** add `nzRouteFn` ([#6313](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6313)) ([6d805c4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d805c44073297ea17742d43066c6b95e4af5ffe))\n- **i18n:** add `en_AU` ([#7919](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7919)) ([c4e6c8d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c4e6c8df3fe48ced3097f0f1347ddbbfde3fda9c))\n- **icon:** add `provideNzIcons` and `provideNzIconPatchs` API ([#8650](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8650)) ([b22672d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b22672db7cbce362b14a3dad1ff3b3c45abed27f))\n- **popconfirm:** support popconfirm template context ([#7989](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7989)) ([6d27073](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d27073a52a96d17d8625a9d5d7b820984aa5000))\n- **table:** support `nzSummary` ([#8639](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8639)) ([20bb5b2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/20bb5b24c7d01d87f0d50c37248ddd862d9bf341))\n- **table:** support `nzFixed` for `nzSummary` ([#8642](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8642)) ([bef12e6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bef12e6218c53028f8907f2e917945ddc8283db5))\n- **tree-select:** support TemplateRef type for `nzNotFoundContent` ([#8638](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8638)) ([13e8a45](https://github.com/NG-ZORRO/ng-zorro-antd/commit/13e8a452c4a96f78d6cf900830ba4b585ed36735))\n\n## 18.0.1\n\n`2024-06-27`\n\n### Bug Fixes\n\n- **graph:** fix [@for](https://angular.dev/guide/templates/control-flow#for-block---repeaters) track function ([#8587](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8587)) ([7687ff2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7687ff2c907ee5ab262ee08240bc932b6112b1ae))\n- **icon:** fix [@for](https://angular.dev/guide/templates/control-flow#for-block---repeaters) track function ([#8588](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8588)) ([8a27bab](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8a27babf30f7726113fed5511bfbd0067c0bbd37))\n- **table:** fix [@for](https://angular.dev/guide/templates/control-flow#for-block---repeaters) track function ([#8593](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8593)) ([b275063](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b2750630a0da3f415931cdf9ba6e6a618dd5d329))\n- **pagination:** fix [@for](https://angular.dev/guide/templates/control-flow#for-block---repeaters) track function ([#8586](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8586)) ([6bb95c0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6bb95c0905de9da1493590da2c6f76cc1b2a23bc))\n- **i18n:** add missing german translations `de_DE` ([#8605](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8605)) ([8d75378](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8d75378ea612a0ab91f03ec1a709f88c2d22af21))\n- **i18n:** add scanned field to QRCode `fa_IR` ([#8597](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8597)) ([9c6e4bf](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9c6e4bf6b65810b0f659a366d34b54528d55cc0f))\n- **table:** missing no-result in fixed header table ([#8574](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8574)) ([6cff80e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6cff80e90788ce0b84b232a0fb67516b795c88b0))\n\n## 18.0.0\n\n`2024-06-06`\n\n### ⚠ BREAKING CHANGES\n\n- **collapse:** change nzExpandIconPosition type from `left` | `right` to `start` | `end` ([#8561](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8561)) ([3ad5674](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3ad56749b0c8222b37444f27f81942fba4bc53e3))\n- no longer use inline JavaScript in Less ([#8552](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8552)) ([7e873c8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7e873c863a1c8e9c053f64aca86bf9c7c9a11a21))\n\nNo need to wrap Less functions provided by antd (including `colorEasing`, `colorPalette`, `tinycolor`) with ~\\`\\` anymore.\n\n```diff\n- color(~`colorPalette('@{primary-color}', 5)`)\n+ color(colorPalette('@{primary-color}', 5))\n```\n\n### Bug Fixes\n\n- **cascader,select,time-picker,tooltip,tree-select:** take in account shadow dom when getting the target of an event ([#7853](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7853)) ([843b703](https://github.com/NG-ZORRO/ng-zorro-antd/commit/843b7035225df3d3a635a5ef8926d1e80f10ae18))\n- **tooltip:** fix arrow color when custom color ([#8555](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8555)) ([92c586b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/92c586b8f5e5fc0ec0e4cb2cc10b73a699b1555a))\n- **upload:** prevent drop event for firefox only ([#8551](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8551)) ([c6e7bd7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c6e7bd7682a776a7ad3f34b589c9c473430e6baa))\n- **rate:** half value when allow half is false ([#8536](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8536)) ([7742fe3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7742fe30b718aa19f2988f6354d982d439ad2c7b))\n\n### Features\n\n- **date-picker:** support quarter selection of date picker ([#8478](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8478)) ([3513889](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3513889367ef468b9e792698f85bb6b890edec86)), closes [#7818](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7818) [#7380](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7380)\n- **qrcode:** qrcode supports scanned state ([#8447](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8447)) ([0be6178](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0be617854d1493a342c9354ce1156fcf323acc97))\n- **rate:** emit hover change when leave ([#8448](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8448)) ([38dcc31](https://github.com/NG-ZORRO/ng-zorro-antd/commit/38dcc3196c62369cd8061a9ead8ab20752e56a66))\n- **statistic:** support for loading state ([#8537](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8537)) ([21c8b62](https://github.com/NG-ZORRO/ng-zorro-antd/commit/21c8b621f15d642c391253ca91c3b124227ca2d9))\n- **table:** support setting virtual height when having no data ([#8457](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8457)) ([724d841](https://github.com/NG-ZORRO/ng-zorro-antd/commit/724d841ebd88a329c59e2cfeee3f9625393c8372))\n\n## 17.4.1\n\n`2024-05-24`\n\n### Bug Fixes\n\n- **card:** use skeleton instead to card-loading-content ([#8528](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8528)) ([a36ebd3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a36ebd329d042dad19733543ce96f459e4cc09d3))\n- **color-picker:** avoid emitted twice nzOnChange event ([#8530](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8530)) ([5dea059](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5dea059202947caf5ef86f802f08ba14a0867288))\n- **list:** static query list-item-action template ([#8527](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8527)) ([85301e0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/85301e0267593457560c5cdcc7fb09ed38944d45))\n- **popconfirm:** fix message icon style ([#8511](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8511)) ([4f1f9bb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4f1f9bba03f38d9ef4ee57380d61e5ca4188648c))\n- **tooltip,popover,popconfirm:** fix hydration error ([#8512](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8512)) ([5009ec0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5009ec0b3a6ff770186681bd4eb61ec662d9896e))\n\n### Features\n\n- **popconfirm:** popconfirm support for nzOkDisabled ([#8542](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8542)) ([8c247db](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8c247dbda2b633d522c53113456600315192a792))\n\n### Performance Improvements\n\n- **back-top:** remove the redundant changeDetectorRef ([c1e39e7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c1e39e7bbc1f863c3a1d26a9cc9cc359b4054dc5))\n- **qr-code:** improved background drawing efficiency ([#8543](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8543)) ([db09bf7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/db09bf73e45d03817c89bba97e1f340cc09ed5d0))\n\n## 17.4.0\n\n`2024-04-19`\n\n### Bug Fixes\n\n- **autocomplete:** remove `NgZone` dependency ([#8462](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8462)) ([24bb1bc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/24bb1bc5959c0e617090f0459c39db00fd4e2d9a))\n- **button:** add `ant-btn-default` class ([#8501](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8501)) ([1588199](https://github.com/NG-ZORRO/ng-zorro-antd/commit/15881996f0a9b1e93b0c81843132ba5d7651e528))\n- **calendar:** year dropdown update issue when date is changed programmatically ([#8286](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8286)) ([ee68a2c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ee68a2c90370a6e3a599fe9f914af20117d2faa6))\n- **date-picker:** remove unsafe style ([#8458](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8458)) ([e6b83eb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e6b83eb1881ece341b68f9048e9d3e5ea438ba19))\n- **drawer:** remove inline style to resolve CSP issue ([#8065](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8065)) ([5e89441](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5e89441c26a7df50d0feed746d5595cde2589a7a))\n- **graph:** bring back the disappeared arrows of edge ([#8493](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8493)) ([342841c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/342841ceafddb1b74f55e31bfa9ca3e7734e842e))\n- **graph:** remove `NgZone` dependency ([#8460](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8460)) ([a4ec21a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a4ec21a684b5c96a64bd66670c270533926252bb))\n- **icon:** missing swap icon ([#8433](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8433)) ([f1a4050](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f1a405042f84fbc96ed0587ea2e748dc7d468719))\n- **image:** wrong next/prev btn in rtl mode ([#8468](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8468)) ([886138d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/886138d630965b9a0a89d1727f76fed81c6f9528))\n- **list:** remove `NgZone` dependency ([#8439](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8439)) ([1ec0e76](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1ec0e7672eaba0890b145c706fcc0a75cb5c47f8))\n- **notification:** `nzMaxStack` initial value error ([#8451](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8451)) ([2c09162](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2c0916265c00cdc026a55b3ab9d829c5e207cf31))\n- **pagination:** add accessible name for `nz-pagination-item` ([#8476](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8476)) ([47ee143](https://github.com/NG-ZORRO/ng-zorro-antd/commit/47ee14325910c154f1541ee2d5e97539ba9a4e52))\n- **slider:** fix the style of markers in vertical mode ([#8494](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8494)) ([9bcce6c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9bcce6c969c0bef7bdf4526407b2dfc56b7ff660))\n- **tag:** borderless style is invalid in default state ([#8495](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8495)) ([b35e6d6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b35e6d6ba2422eb2c4725b2029a2f9c60720b697)), closes [#8492](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8492)\n- **typography:** remove `NgZone` dependency ([#8440](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8440)) ([af7fb5d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/af7fb5d27254d26a284faaaa5b812b105f539e3f))\n- **upload:** remove inline style to resolve CSP issue ([#8064](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8064)) ([1ac84a8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1ac84a8428fe644362e0f733c9a151fa848cedbf))\n\n### Features\n\n- **modal:** supports masked layer response for each click ([#8429](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8429)) ([31b90fa](https://github.com/NG-ZORRO/ng-zorro-antd/commit/31b90fa52232abe7b090f60797d4335329677c4c))\n- **notification:** popup order adjustment ([#8450](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8450)) ([742f14a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/742f14a93472772cbdd96ce89797dc4120c55330))\n- **select:** support `nzOptionHeightPx` in global config ([#8504](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8504)) ([4efc5ab](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4efc5ab38f74ce07a769f57453b0da375c17ce5c)), closes [#8503](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8503)\n- **skeleton:** support for square shape of skeleton button ([#8481](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8481)) ([af1483a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/af1483a9be544bd41b8f2a4a4c8027425f22b925))\n\n## 17.3.0\n\n`2024-03-11`\n\n### Bug Fixes\n\n- **doc:** replaced link for monaco editor options ([#8393](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8393)) ([fdfc816](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fdfc816e72938fce47bbdfe274de00ad4e89b242))\n- **docs:** fix progress, code-editor docs error ([#8383](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8383)) ([407e76a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/407e76a21afb4e1677fc73e89df69b26789da2fd))\n- **select:** issue with nzScrollToBottom while display scaling ([#8355](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8355)) ([bb0468e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bb0468e9e95c7c00efd2a5655d0266ae1ce17368))\n- **avatar:** avatar not re-scaling properly ([#8365](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8365)) ([e7b1fa0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e7b1fa0d36b173934bda10f796efa0c6e17d66e5))\n- **carousel:** not adapting to new size when resizing ([#8374](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8374)) ([6e1decb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6e1decbc7507b07dbb28897f53c6cbcc6ca2eaa6))\n- **cdk:** zIndex is not used properly when creating overlay ([#8373](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8373)) ([b932d65](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b932d65a546f0b2729249713fdaad41fefebb602))\n- **i18n:** add missing pt texts ([#8426](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8426)) ([d575c53](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d575c53371f34053a7cd2b6a020a3da1005b708a))\n- **i18n:** added missing translations to ja_JP ([#8290](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8290)) ([662b730](https://github.com/NG-ZORRO/ng-zorro-antd/commit/662b73049f8ed8ae70caea573e809016607a795a))\n- **i18n:** added missing translations to vi_VN ([#8295](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8295)) ([987a799](https://github.com/NG-ZORRO/ng-zorro-antd/commit/987a799ab1ca5bfdcef162d322423b65fb64dfe6))\n- **tabs:** slide indicator missing in small screens ([#8372](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8372)) ([a0b08be](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a0b08be73a77c0a0967f5a301fe8c7ebbfca103c))\n- **tabs:** wrong cursor ([#8386](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8386)) ([3dc1579](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3dc1579805f1a867689160fede25fd005983ddf1))\n\n### Features\n\n- improve schematics ([#8411](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8411)) ([921f1c1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/921f1c18266ead602c2e2c627a171608507807d4))\n- **anchor:** horizontal anchors ([#8342](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8342)) ([9cc44f8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9cc44f8bdb55fbf2fcf4c8ce4da4fab1120245dc))\n- **calendar:** custom header ([#8418](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8418)) ([ec7ec35](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ec7ec35573fc46ba01af1368087b5de0b13ab7c7))\n- **color-picker:** built-in color-picker package ([#8428](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8428)) ([534fe62](https://github.com/NG-ZORRO/ng-zorro-antd/commit/534fe6277287dd64730546d3d4cc0f1be90a211a))\n- **drawer:** return componentRef when nzContent is a component ([#8339](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8339)) ([f71162b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f71162bbbb30c7b362774b2bc170a0ffd1c0dcf7))\n- **image:** now supports horizontal and vertical flip ([#8168](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8168)) ([e856515](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e856515888102b5a3583a2223372263a4bff1c50))\n- **image:** zoom using mouse wheel ([#8180](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8180)) ([4235c29](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4235c293c0abf889bba0bc31d2ba18cf5d41b51d))\n- **modal:** draggable ([#8419](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8419)) ([ce33294](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ce332947c49e7e6dd02d9bb80eb2fe3f7beab3af))\n- **modal:** expose componentRef nzContent ([#8389](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8389)) ([e53000e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e53000e8b52972cc73070a8781d276dc26ebca0b))\n- **segmented:** now supports segmented with icon only ([#8368](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8368)) ([e8dea7a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e8dea7a83e6f98e2486c4e3f894f86b646025c1c))\n- **select:** select max tag count ([#8371](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8371)) ([18b898e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/18b898e8c5201c6785e5060850d3597601c39401))\n\n## 17.2.0\n\n`2024-01-29`\n\n### Bug Fixes\n\n- **table:** add missing import to nz-table-inner-scroll ([#8328](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8328)) ([936317e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/936317e6702e790f5f8827e074fe12fd55fbf0f3))\n- **tree-select:** fix search box exception when Chinese search ([#8324](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8324)) ([aacd62b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/aacd62b0beeac35b18829ae4e382626b655c7e05))\n- pipeline job failed ([#8367](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8367)) ([6024bcc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6024bcc7a9453976d0023fe7b455dc452ced8bd4))\n\n### Features\n\n- **color-picker:** make color picker standalone ([#8316](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8316)) ([b050474](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b05047433311fe60ee82d100467c896f2167d925))\n- **tag:** borderless mode ([#8320](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8320)) ([e428083](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e428083537c8c25d463980749f63b1b8ab129057))\n- **timeline:** allow custom color ([#8335](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8335)) ([66a88db](https://github.com/NG-ZORRO/ng-zorro-antd/commit/66a88dbbb1cdd26ee9411de2394fd2231a2807f0))\n\n## 17.1.0\n\n`2023-12-17`\n\n### Bug Fixes\n\n- fix logic for generating directive tags ([#8171](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8171)) ([e37eab2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e37eab2be160a0db8154a2074c836782caa8cda3))\n- **calendar:** style radio button not apply ([#8298](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8298)) ([996e141](https://github.com/NG-ZORRO/ng-zorro-antd/commit/996e141042470e487d915d38477ad51928d3e2a0))\n- **core:** warning cron parser common js dependencies ([#8277](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8277)) ([138d666](https://github.com/NG-ZORRO/ng-zorro-antd/commit/138d666e0527dba2f3f5ac43b05ce4810fffe9f7))\n- **cron-expression:** output type error ([#8189](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8189)) ([ad02381](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ad02381cfc4643b191caab7e056fd1a93086a45e)), closes [#8188](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8188)\n- **select:** input clear when nzAutoClear ([#8167](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8167)) ([fefcb68](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fefcb68dc9831eb2208746b3fe44346f80f8202f))\n- **tabs:** aria controls have wrong value ([#8237](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8237)) ([d9a2d27](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d9a2d27be30e9bfc635d8ac3d0e31538f6092b1c))\n- **tooltip:** color of the tooltip arrow does not change ([#8192](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8192)) ([bc344ed](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bc344edc3dca8cdf777bf986130eeae5c3543f63))\n\n### Features\n\n- **alert:** support standalone component ([#8182](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8182)) ([167bed0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/167bed0350400a4a69f727c62237953b71831f26))\n- **anchor:** support standalone component ([#8185](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8185)) ([03cda21](https://github.com/NG-ZORRO/ng-zorro-antd/commit/03cda216f2d0f1b31e365d6cb30a309309cbc868))\n- **autocomplete:** support standalone component ([#8193](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8193)) ([548e842](https://github.com/NG-ZORRO/ng-zorro-antd/commit/548e842c00d74fc4f8a8c9b69587bc14fdd9aecf))\n- **avatar:** support standalone component ([#8194](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8194)) ([4e2cb74](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4e2cb748b1c13ba1176b93f547fda10a188fec95))\n- **back-top:** support standalone component ([#8195](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8195)) ([db5d5f4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/db5d5f4d02531665e2a88dc114545ab225e61673))\n- **badge:** support standalone component ([#8201](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8201)) ([3d1427f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3d1427f60f450c9193669a39ef632017fa33c4f6))\n- **breadcrumb:** support standalone component ([#8202](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8202)) ([165f171](https://github.com/NG-ZORRO/ng-zorro-antd/commit/165f171dd51cff29ac3e02f046bf2966c4ad9aa0))\n- **button:** support standalone component ([#8275](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8275)) ([3c09507](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3c09507c2c50f67e4f500c4f08a15617ae8e42bc))\n- **calendar:** support standalone component ([#8274](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8274)) ([80d68a3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/80d68a31d65dd1d5505a1b96f3e02e6ea45e000b))\n- **card:** component support standalone ([#8273](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8273)) ([0902a4b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0902a4b2b3c3ad0a8bf1740c67bf94194212af7c))\n- **carousel:** support standalone component ([#8272](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8272)) ([e4244fb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e4244fb7891eed2f21253e922317eae3b8469a3a))\n- **cascader:** support standalone component ([#8271](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8271)) ([3ab6e5b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3ab6e5bafbb007a5929f347fb81ca83761e4e074))\n- **cdk:** support standalone component ([#8270](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8270)) ([d66bcba](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d66bcbad09552c3f86401948710d417bb39fd68f))\n- **checkbox:** support standalone component ([#8269](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8269)) ([1491fb3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1491fb3523ab4cd4b4ff498d37669dd9407e1638))\n- **code-editor:** support standalone component ([#8268](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8268)) ([24547c6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/24547c61858d0656a71c943a67395cffdfa05881))\n- **collapse:** support standalone component ([#8267](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8267)) ([dc43fa5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dc43fa5c189d8b6d09f661e52e10e955d873c264))\n- **color-picker:** disable alpha ([#8178](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8178)) ([0bebd6a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0bebd6a696cc29c179758951f706fd276a1dae89))\n- **comment:** support standalone component ([#8266](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8266)) ([5af11ea](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5af11ea0232c90d74607c9e4a9ffb053d0f0950c))\n- **core:** make no-animation standalone ([#8257](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8257)) ([de579bc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/de579bca2112bd9691429eee6144c09bb16d3b2b))\n- **core:** support standalone component ([#8265](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8265)) ([c51e8da](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c51e8daf1ba09646cf7c043756fd14274483c641))\n- **cron-expression:** support standalone component ([#8264](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8264)) ([ae6ceeb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ae6ceeb560f86ead21d6c9ce9a53f435c52f9944))\n- **date-picker:** support standalone component ([#8263](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8263)) ([ac48fba](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ac48fba4c6e591db03e41ab427b317c1868f8071))\n- **description:** support standalone component ([#8262](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8262)) ([128f4c0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/128f4c0055fd1150520509e1fa6bddbc74c65b85))\n- **divider:** support standalone component ([#8258](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8258)) ([3a7cd50](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3a7cd50e092ad712b66243fa5c2c582f169e658c))\n- **drawer:** support standalone component ([#8256](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8256)) ([2fbe4c0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2fbe4c0eb221f833fbb0d0801ce546a3c0300555))\n- **dropdown:** support standalone component [#8254](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8254) ([#8255](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8255)) ([c5df26f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c5df26f2ba94f00d80b66c24bf98b09e5f162081))\n- **empty:** support standalone component ([#8254](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8254)) ([15636d2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/15636d2c530f294e3b217e4150be70a5f050bccf))\n- **experimental-image:** support standalone component ([#8253](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8253)) ([7325781](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7325781367998543680af043bd19b911c3ac67e7))\n- **flex:** add flex component ([#8145](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8145)) ([f8fedfc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f8fedfc88957a449de2a9960605d3528848f9caa))\n- **form:** support standalone component ([#8252](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8252)) ([e742e39](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e742e399e2e870f7079f183f800d0d2023b8447d))\n- **graph:** support standalone component ([#8251](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8251)) ([d2f1d30](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d2f1d30fe7925205b79d7da4462a33a496fd94bf))\n- **grid:** support standalone component ([#8250](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8250)) ([208652c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/208652c1ffd98ef8ea8e52b69d9376aaafeb390a))\n- **i18n:** support standalone component ([#8249](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8249)) ([a91cac7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a91cac7e1bbd4379b9498d705a9b6fa1a00e4cd8))\n- **icon:** support standalone component ([#8248](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8248)) ([b0dbfbc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b0dbfbca5452b54ed7c8c4c0b6d1aa2ae0512a34))\n- **image:** support standalone component ([#8200](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8200)) ([63b8777](https://github.com/NG-ZORRO/ng-zorro-antd/commit/63b8777645fe93f587e7b09c5ea9d6efbd497b87))\n- **input-number:** support standalone component ([#8246](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8246)) ([6210fa0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6210fa0b571dd3d0a6b1069bcddd4ad44c3d6104))\n- **input:** support standalone component ([#8247](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8247)) ([0a7028c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0a7028c27c2018039b771cdfccd8cc0654e2a97a))\n- **layout:** support standalone component ([#8245](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8245)) ([d21f8a1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d21f8a10876d222160c5e60d467283562b21f087))\n- **list:** support standalone component ([#8244](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8244)) ([1f3010f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1f3010fccc0c6bfe8e6b0149152794e3e2371a9a))\n- **mention:** support standalone component ([#8243](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8243)) ([adc5e94](https://github.com/NG-ZORRO/ng-zorro-antd/commit/adc5e94cdd7dfc75800808a046861bc9943dd548))\n- **menu:** support standalone component ([#8242](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8242)) ([4673926](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4673926a581b532470062f7cd5672a176638f111))\n- **message:** support standalone component ([#8241](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8241)) ([c2120b2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c2120b2fad4b1ce30d496c75db27cf08d648ef8c))\n- **modal:** support standalone component ([#8240](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8240)) ([387d664](https://github.com/NG-ZORRO/ng-zorro-antd/commit/387d66434cad9b117cf3a5f54c75bc2eeab1f69f))\n- **notification:** support standalone component ([#8236](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8236)) ([686b6b0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/686b6b0d1183a15e69ba59b777d3d3078bacd1af))\n- **page-header:** support standalone component ([#8235](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8235)) ([aa91486](https://github.com/NG-ZORRO/ng-zorro-antd/commit/aa91486c5ec9ffe26a2aef62800793c909e4349f))\n- **pagination:** support standalone component ([#8234](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8234)) ([0f1690c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0f1690c89de63bc479653f4d3514a06f5d19a5f7))\n- **pipes:** make the css-unit pipe support more units ([#8260](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8260)) ([5e611e7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5e611e7d51a8cad3697a381612225b0d12879d55))\n- **pipes:** support standalone component ([#8233](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8233)) ([319381a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/319381a443b7cbb64053d7d30f12d501b0221bcb))\n- **pop-confirm:** support standalone component ([#8232](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8232)) ([9d656b2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9d656b2c9bde26bf4bb600ad5eff5fa0f3035804))\n- **popover:** support standalone component ([#8231](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8231)) ([f7468e2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f7468e212533d21655a7c74ab1efcf320facfc07))\n- **progress:** support standalone component ([#8230](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8230)) ([7022471](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7022471052e562a72e741abf5e9b9597f6437d2c))\n- **qr-code:** support standalone component ([#8228](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8228)) ([769f74c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/769f74c9323db91251c191151d48283be64781a8))\n- **radio:** support standalone component ([#8227](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8227)) ([b62ac64](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b62ac6471b7038db01ebfbb9efd597eae0b8517f))\n- **rate:** support standalone component ([#8226](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8226)) ([90edba6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/90edba69d11b82c5b31e91af8da34174b71c6fb8))\n- **resizable:** support standalone component ([#8225](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8225)) ([ff14ed0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ff14ed0e4a5ae6562a71459e407863bd9f84a1ca))\n- **result:** support standalone component ([#8224](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8224)) ([572965d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/572965d3b61045a01cb8fc14a132a5c0aa8574ec))\n- **segmented:** support standalone component ([#8223](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8223)) ([86a49d2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/86a49d277b8c8e66bd310d920c43b1e801c2d31c))\n- **select:** support standalone component ([#8222](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8222)) ([ed0de77](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ed0de779cfe63f1ca68b4b8dedbba40a5ad59e95))\n- **skeleton:** support standalone component ([#8220](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8220)) ([a2858d3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a2858d3bb10e87e472e4f917176172f283d46352))\n- **slider:** support standalone component ([#8219](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8219)) ([428c53c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/428c53c6361c5f9afe79ee147a28635c010fea4c))\n- **space:** support standalone component ([#8218](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8218)) ([a84ddef](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a84ddeff5582426a3dd608cab567245898be60c7))\n- **spin:** support standalone component ([#8217](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8217)) ([cd23e33](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cd23e3355d1f8828d93a7d3e331f20180ada4bef))\n- **statistics:** support standalone component ([#8216](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8216)) ([186ef60](https://github.com/NG-ZORRO/ng-zorro-antd/commit/186ef6049cae90e10a2c3f66186cf856f5b9abb2))\n- **steps:** support standalone component ([#8215](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8215)) ([dbb6fcb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dbb6fcb952366f200673bcec8e28097844370869))\n- **switch:** support standalone component ([#8214](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8214)) ([3f6a9ed](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3f6a9ed0a04ba93b97dedcb4b5625d3b79828c32))\n- **table:** support standalone component ([#8276](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8276)) ([5765ae9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5765ae93f1adf304020697fc84a1984ef54f9a1b))\n- **tab:** support standalone component ([#8213](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8213)) ([69dd31a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/69dd31ac275f6251b22f7af9aef4ea78fd278adf))\n- **tag:** support standalone component ([#8212](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8212)) ([15af7c8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/15af7c8956ed4c8f11f637446d0285b5a52339f1))\n- **time-picker:** support standalone component ([#8211](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8211)) ([641ebb2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/641ebb2d8072fa343c9275222be8c4a23f8fceb4))\n- **timeline:** support standalone component ([#8210](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8210)) ([b7c6859](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b7c685913abb14133955dfc81678207ec3e64aff))\n- **tooltip:** support standalone component ([#8209](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8209)) ([125768c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/125768c16f3c5030373058d120c05141208ec42c))\n- **transfer:** support standalone component ([#8208](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8208)) ([960144e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/960144e5f5a076fe8c7ad56a48ba97e147bc430b))\n- **tree-select:** support standalone component ([#8206](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8206)) ([64ec76a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/64ec76a2440c7befeaeb8409f84801fd8483af47))\n- **tree-view:** support standalone component ([#8205](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8205)) ([d4426fc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d4426fc6675515ddd1db54be84731d1ba44b52b8))\n- **tree:** support standalone component ([#8207](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8207)) ([b9cf3b0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b9cf3b03d8c51fcfd809dd8d4424aae70ff77094))\n- **typography:** support standalone component ([#8204](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8204)) ([d7e387f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d7e387fa707f3a8473225187e660459498d97ca2))\n- **upload:** support standalone component ([#8203](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8203)) ([7cd08ae](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7cd08ae3b6d7ff0e252eb237a60288930f73c15d))\n- **water-mark:** nzWaterMark is a block element && standalone ([#8197](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8197)) ([e4d6082](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e4d608274e0b56acf9b720cf519d757c660c125e)), closes [#8187](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8187)\n\n## 17.0.1\n\n`2023-11-20`\n\n### Bug Fixes\n\n- **schematics:** cannot generate files and add default builders ([#8176](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8176)) ([de8a6b7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/de8a6b782d16f906198d6d6ba512059b8dcb463c))\n\n## 17.0.0\n\n`2023-11-19`\n\n### Bug Fixes\n\n- **autocomplete:** fix the wrong value of internal nz-auto-option ([#7907](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7907)) ([0a312e3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0a312e3203db13cba6e4ebd6dc4c53e3c09ac206))\n- **cron-expression:** exception error & cancel format prompt copy ([#8114](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8114)) ([ea69790](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ea697909231753e438b2ba07d4ec15c255f3a5dc))\n- **form:** wrong element to focus when clicking label ([#8135](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8135)) ([b3d135f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b3d135fc512a016430426a36330c0f527234f4e4))\n- **i18n:** added missing translations to pl_PL ([#7950](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7950)) ([7819426](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7819426f9ff3a110e06aa9cb47e7396edcfc18d7))\n- **i18n:** update fa_IR translations ([#8143](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8143)) ([4f63198](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4f63198aae7441fe94de64e1740d1f2429a629c1))\n- **i18n:** Update fr/be/ca translations ([#8137](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8137)) ([211db31](https://github.com/NG-ZORRO/ng-zorro-antd/commit/211db31202ea7b099405aecaa5273461bbc26ef4))\n- **mention:** page not loading entirely ([#8146](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8146)) ([9505c7c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9505c7c4aa222d36e63597b128f01ab0ba3e934a))\n- **resizable:** fix pointer capture bug ([#8169](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8169)) ([a0b8a0b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a0b8a0baba0259552a8d0e9eae442daa99027f24))\n- **select:** do not run tick when scrolling to activated value ([#8159](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8159)) ([7ce50b3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7ce50b3494d01bedbfdd8413dc8ef36ef836e377))\n- **slider:** step can not click the problem ([#7820](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7820)) ([1e1c753](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1e1c753b04e5c01cc61589d16048815ec9f4b9c5))\n- **table:** custom column styles collapse when using nzScroll ([#8044](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8044)) ([fde48f9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fde48f9c8a5e934fe32f421d627960dbeb5615ef))\n- **tree-select:** 修复回显顺序问题 ([#8108](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8108)) ([eb4077d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/eb4077df104743fd7ccdc44307c2dc8aa5dbbbca))\n- **tree:** nzCheckBoxChange never emitting ([#8038](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8038)) ([a9dc205](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a9dc2052930b7f6694d5933a86fc3b488b7bd786))\n\n### Features\n\n- **affix:** support standalone component ([#8037](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8037)) ([583883c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/583883c0623d640bbea2d04b3a76896d08a68d4c))\n- **hash-code:** add HashCode component ([#8111](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8111)) ([0254ee2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0254ee2e673d8ac8cff42a2aef2933367f8b0931))\n- **image:** add scale step ([#8163](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8163)) ([5aa4db9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5aa4db9f3b429e1f973a75f65cdd8b107586634d))\n- **notification:** support for more custom templates ([#8046](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8046)) ([9689c42](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9689c4298e57d67eb340140c8924d4743f07bd04))\n- **schematics:** support ng-add in standalone app ([#8095](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8095)) ([c1b61f7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c1b61f720199ebfba0f48834b2ceaf93fed148d1))\n- **slider:** add the ability to use a template ([#7505](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7505)) ([7c79ab3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7c79ab37a8c0b4bc47bf1873c167417f316c94a9))\n- **table:** add `nzLabel` to include aria-label in checkboxes ([#7903](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7903)) ([5834e46](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5834e469291ee2a6975e4b74015468d7c1d739d2))\n- **table:** nzExpand supports custom icon ([#7886](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7886)) ([1507ed0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1507ed0e2c1e869bd45925f2335ff1c4a3570430))\n- **tooltip,popover,popconfirm:** make cdkConnectedOverlayPush open for tooltip ([#8166](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8166)) ([a821c62](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a821c62c5a438ff24282230376b18cd0bfdbfc19))\n\n## 16.2.2\n\n`2023-10-23`\n\n### Bug Fixes\n\n- inline cdk-overlay style ([#8132](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8132)) ([3209d74](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3209d744187133e518f564bfe5a2f56ac371fc22))\n- **cascader:** compatible with rxjs v6 ([#8133](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8133)) ([54a5c76](https://github.com/NG-ZORRO/ng-zorro-antd/commit/54a5c769a061bc07e342c1f462bf27c422df44a3))\n- **drawer:** drawer not open ([#8120](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8120)) ([24d0664](https://github.com/NG-ZORRO/ng-zorro-antd/commit/24d06640a623f3ea2fd9fa459c729a103938d7fc))\n\n## 16.2.1\n\n`2023-10-19`\n\n### Bug Fixes\n\n- inline external css ([#8122](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8122)) ([42da190](https://github.com/NG-ZORRO/ng-zorro-antd/commit/42da1905a74b5a2049c045cef90d3c5cd595b8a3))\n- **color-picker:** optimize demo copywriting and style ([#8088](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8088)) ([6d03099](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d03099e40364b85276db4c0163bae32c62bad73))\n- **menu:** ellipsis menu title content if overflow ([#8055](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8055)) ([0674f78](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0674f785213ad914ad58fddc42e3083ff750f102))\n- **tree-select:** fixed the bug that the back shortcut key can delete the bug when the node is disabled ([#8105](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8105)) ([07a1f5e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/07a1f5e41d82ac59c9de744a3528c23e2b871624))\n\n### Features\n\n- **select:** support to customize `attr.title` of `nz-option-item` ([#8097](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8097)) ([2ee261a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2ee261ac24f7ea0501d07ad35fcdb435714ffe9b))\n\n## 16.2.0\n\n`2023-09-18`\n\n### Bug Fixes\n\n- **list:** fix the bug that synchrone action item are not displayed in the item ([#7958](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7958)) ([3b6bdec](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3b6bdecef32ee4d9bb14491b617870733cfd9553))\n- **tree:** fix nz-tree-node keep dragging class with nzBeforeDrop ([#8015](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8015)) ([2d0b3f7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2d0b3f71490e38f8512285f81fcf3baa8f6eb4db))\n- **button:** fix add class ant-btn-icon-only([#7631](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7631)) ([#7678](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7678)) ([7470ed6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7470ed66e1651d753fa43e197a4ab0d548744885))\n- **cascader:** customize the option title to undefined ([#8011](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8011)) ([10003db](https://github.com/NG-ZORRO/ng-zorro-antd/commit/10003db77b9bda21772733c41b3c503ee85d5c81)), closes [#8006](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8006)\n- **core:** resolve CSP errors ([#8059](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8059)) ([295b333](https://github.com/NG-ZORRO/ng-zorro-antd/commit/295b333774990a420c39ba67912598dafd2f1842))\n- **cron-expression:** clear console warnings ([#7926](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7926)) ([b358345](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b358345c14746501e47d7e73dffe41d32b9ab118))\n- **date-picker:** fix code comment ([#7991](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7991)) ([8b6b653](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8b6b653547d92a27079c27b3ef7e68df68a4f5fd))\n- **i18n:** update zh_TW.ts ([#7901](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7901)) ([9bfce45](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9bfce45a37a9c50aafbcaf96a8db9450bc2c5bf1))\n- **message:** clean up DOM after usage ([#7965](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7965)) ([71ead99](https://github.com/NG-ZORRO/ng-zorro-antd/commit/71ead99aa781e50f3c896107f5b668b9a2cea767)), closes [#7772](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7772)\n- **message:** fix the z-index of overlay ([#8081](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8081)) ([b1d2095](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b1d20953eda23c9dcb4f74530621cf9cf1a33e45))\n- **notification:** don't create new messageId for update ([#8000](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8000)) ([e240264](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e240264796dfd3a8692efcb92178688b78d0b69f))\n- **qrcode:** optimize demo display and nzPadding value ([#8020](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8020)) ([078aaf9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/078aaf91335d2d9fa085d06a792ddd49c17948e0))\n- **table:** remove empty space in custom columns ([#8022](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8022)) ([15e244c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/15e244cc954cab1186d33006c7915f34d92e4d6d))\n- **time-picker:** modelChange trigger twice ([#7902](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7902)) ([74c13a4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/74c13a49f92a263a05a34af63f6a2b71a554078e))\n- **tree-view:** re-rendering fix ([#8035](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8035)) ([68cb4b2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/68cb4b2d25d3bc149e4f8e80c030a16db75959c2))\n- **tree:** remove console.log ([#8019](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8019)) ([fa0312a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fa0312a4c68b26902ca28ed974754599b17b2d8a))\n- **watermark:** removing the watermark fails to redraw ([#8012](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8012)) ([030318e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/030318e82725d7650c98bf0ec06d2b23df16d9f0))\n- **showcase:** ui bug in rtl mode inside the doc site ([#8063](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8063)) ([d57b7da](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d57b7dac5817cb1de9de9edda2343a6089854fff))\n\n### Features\n\n- add provide function ([#7952](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7952)) ([150c6ca](https://github.com/NG-ZORRO/ng-zorro-antd/commit/150c6cab4636fa9daa1e892d27b894c6b7381b35))\n- **cascader:** support for load options with observable ([#8048](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8048)) ([1436f21](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1436f212130041bec03d6f2d2d7f5591dff04b7a))\n- **color-picker:** add color-picker component ([#8013](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8013)) ([8439704](https://github.com/NG-ZORRO/ng-zorro-antd/commit/843970459fdb18dfa0ddc861d02e6c21e87c12b4))\n- **cron-expression:** add Unit Testing ([#7993](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7993)) ([605e969](https://github.com/NG-ZORRO/ng-zorro-antd/commit/605e969013cf48a29f4786765cf6c6da9f10643a))\n- **cron-expression:** support nzDisabled && nzBorderless ([#7992](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7992)) ([6d31bde](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d31bde3ef1f43cc145d2009afcf90931e96a731))\n- **dropdown:** close context menu on escape ([#7915](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7915)) ([6d0032e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d0032ededc140a017c01158ae76402a86c7b334))\n- **dropdown:** improve `NzContextMenuService#create()` ([#7768](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7768)) ([9b3e6cb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9b3e6cba852d4a782d15311c910b747a3bbc4d02))\n- **form:** support form label wrap ([#7892](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7892)) ([37391de](https://github.com/NG-ZORRO/ng-zorro-antd/commit/37391de29afdd3126dbbdcae6ca3ba2e637fd596))\n- **input:** hide stepper for type number ([#8003](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8003)) ([0f3aed5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0f3aed599874e0d1c2786f2d14fec52128afbec8))\n- **modal:** Remove nzComponentParams in v16 ([#7930](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7930)) ([baab16c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/baab16c497902f0cbf2668fb061ac8d40ffd18b2))\n- **qrcode:** padding & background color for qrcode ([#8001](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8001)) ([718ba29](https://github.com/NG-ZORRO/ng-zorro-antd/commit/718ba2943c7c7e12c8526e52e8806955d3fb0504))\n- **resizable:** add direction parameter in NzResizeEvent ([#7987](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7987)) ([4143473](https://github.com/NG-ZORRO/ng-zorro-antd/commit/41434734ffe839f3ed71bd19486a5f76adc20463))\n- **resizable:** support for multiple cursor types ([#8042](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8042)) ([e564714](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e56471423142d71ce9117707f7240c83f6fe44e5))\n- **table:** support display and sorting of custom table columns ([#7966](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7966)) ([d26870f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d26870f9ffd3f5122e95246a24587c739b04fd8a))\n\n### Performance Improvements\n\n- **select:** ability to pass nzKey to nz-option ([#8033](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8033)) ([e94da4e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e94da4eddd663a1e7a5e9e6e0781f1a6da59f1c7))\n- **select:** remove unused types ([#7850](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7850)) ([71c2138](https://github.com/NG-ZORRO/ng-zorro-antd/commit/71c2138ce28e07539784d8fb228adf122ed13a33))\n- **tabs:** need add .ant-tabs-tab class reduce css computing time consuming([#7935](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7935)) ([#7936](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7936)) ([198644a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/198644a09ac828c4e9b208799c8be1a57cd8ce86))\n\n## 16.1.0\n\n`2023-07-16`\n\n### Bug Fixes\n\n- **list:** fix the bug that synchrone action item are not displayed in the item ([#7958](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7958)) ([3b6bdec](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3b6bdecef32ee4d9bb14491b617870733cfd9553))\n- **tree:** fix nz-tree-node keep dragging class with nzBeforeDrop ([#8015](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8015)) ([2d0b3f7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2d0b3f71490e38f8512285f81fcf3baa8f6eb4db))\n- **cascader:** customize the option title to undefined ([#8011](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8011)) ([10003db](https://github.com/NG-ZORRO/ng-zorro-antd/commit/10003db77b9bda21772733c41b3c503ee85d5c81)), closes [#8006](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8006)\n- **date-picker:** fix code comment ([#7991](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7991)) ([8b6b653](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8b6b653547d92a27079c27b3ef7e68df68a4f5fd))\n- **i18n:** update zh_TW.ts ([#7901](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7901)) ([9bfce45](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9bfce45a37a9c50aafbcaf96a8db9450bc2c5bf1))\n- **notification:** don't create new messageId for update ([#8000](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8000)) ([e240264](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e240264796dfd3a8692efcb92178688b78d0b69f))\n- **time-picker:** modelChange trigger twice ([#7902](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7902)) ([74c13a4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/74c13a49f92a263a05a34af63f6a2b71a554078e))\n- **watermark:** removing the watermark fails to redraw ([#8012](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8012)) ([030318e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/030318e82725d7650c98bf0ec06d2b23df16d9f0))\n\n### Features\n\n- **cron-expression:** add Unit Testing ([#7993](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7993)) ([605e969](https://github.com/NG-ZORRO/ng-zorro-antd/commit/605e969013cf48a29f4786765cf6c6da9f10643a))\n- **cron-expression:** support nzDisabled && nzBorderless ([#7992](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7992)) ([6d31bde](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d31bde3ef1f43cc145d2009afcf90931e96a731))\n- **dropdown:** close context menu on escape ([#7915](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7915)) ([6d0032e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d0032ededc140a017c01158ae76402a86c7b334))\n- **dropdown:** improve `NzContextMenuService#create()` ([#7768](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7768)) ([9b3e6cb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9b3e6cba852d4a782d15311c910b747a3bbc4d02))\n- **form:** support form label wrap ([#7892](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7892)) ([37391de](https://github.com/NG-ZORRO/ng-zorro-antd/commit/37391de29afdd3126dbbdcae6ca3ba2e637fd596))\n- **modal:** Remove nzComponentParams in v16 ([#7930](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7930)) ([baab16c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/baab16c497902f0cbf2668fb061ac8d40ffd18b2))\n- **qrcode:** padding & background color for qrcode ([#8001](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8001)) ([718ba29](https://github.com/NG-ZORRO/ng-zorro-antd/commit/718ba2943c7c7e12c8526e52e8806955d3fb0504))\n- **resizable:** add direction parameter in NzResizeEvent ([#7987](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7987)) ([4143473](https://github.com/NG-ZORRO/ng-zorro-antd/commit/41434734ffe839f3ed71bd19486a5f76adc20463))\n- **table:** support display and sorting of custom table columns ([#7966](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7966)) ([d26870f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d26870f9ffd3f5122e95246a24587c739b04fd8a))\n\n### Performance Improvements\n\n- **select:** remove unused types ([#7850](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7850)) ([71c2138](https://github.com/NG-ZORRO/ng-zorro-antd/commit/71c2138ce28e07539784d8fb228adf122ed13a33))\n- **tabs:** need add .ant-tabs-tab class reduce css computing time consuming([#7935](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7935)) ([#7936](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7936)) ([198644a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/198644a09ac828c4e9b208799c8be1a57cd8ce86))\n\n## 16.0.0\n\n`2023-05-31`\n\n### Bug Fixes\n\n- **date-picker:** ng-untouched when loose focus ([#7922](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7922)) ([9ebcf72](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9ebcf72bde75b735c0798bc66bb62226b7f29536))\n- **date-picker:** week number error when cross years ([#7923](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7923)) ([e7f9538](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e7f953822133ce31d2523a48766dfe6572f95430))\n- **datepicker:** ngModel not update ([#7948](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7948)) ([100796c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/100796c74cd75de9cebbf89cb58f4bf3cc58b746))\n- **slider:** the first disable is invalid ([#7947](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7947)) ([ad2faf4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ad2faf4c67cb6e7bc1b12646d0ceb9153a59d75c)), closes [#7943](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7943)\n\n## Old Versions\n\nAll releases notes can be found [here](https://github.com/NG-ZORRO/ng-zorro-antd/releases)\n"
  },
  {
    "path": "docs/changelog.zh-CN.md",
    "content": "---\norder: 13\ntitle: 更新日志\ntoc:\n  depth: 2\ntag: '{{version}}'\n---\n\n`ng-zorro-antd` 严格遵循 [Semantic Versioning 2.0.0](https://semver.org/lang/zh-CN/) 语义化版本规范。\n\n### 发布周期\n\n- 修订版本号：每周五会进行日常 bugfix 更新。（如果有紧急的 bugfix，则任何时候都可发布）\n- 次版本号：每月发布一个带有新特性的向下兼容的版本。\n- 主版本号：含有破坏性更新和新特性，不在发布周期内。\n\n---\n\n## 21.2.0\n\n`2026-03-20`\n\n### Features\n\n- **alert:** 支持轮播的公告 ([#9697](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9697)) ([6b45037](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6b45037e4d71d7df60942ead1fab0ed06ac31911))\n- **form:** 新增 `nzVariant` 属性，改变表单内所有组件的变体 ([#9694](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9694)) ([51d6eb6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/51d6eb6e1c3b18e3a5dca7da266476a091ac2eaf))\n- **input-number:** `nzOnStep` 回调事件透出 `emitter` ([#9716](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9716)) ([f83af1e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f83af1e87a6eaab041c38f0ed7b26ff8d84568c4))\n- **input:** 支持自定义 input-wrapper 的计数逻辑 ([#9645](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9645)) ([2450a60](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2450a60e12b9707f71d603092207485decc9d127))\n- **tabs:** 新增 `nzIndicator` 属性，支持自定义 tab 的指示条 ([#9704](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9704)) ([02befe7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/02befe7a77e2a67f41312bb498cc34372f3408c1))\n\n### Bug Fixes\n\n- **modal:** 修复弹窗打开时动画闪烁的问题 ([#9728](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9728)) ([56ad81d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/56ad81d90ee7bf5b63f53b4e4c5cb53785ae5c12))\n- **select:** 修复 Safari 浏览器下下拉框位置不正确的问题 ([#9724](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9724)) ([1081620](https://github.com/NG-ZORRO/ng-zorro-antd/commit/10816209670407610b53ce8f2051fbd354fb620e))\n\n## 21.1.1\n\n`2026-03-06`\n\n### Bug Fixes\n\n- **anchor:** 修复 `nzHref` 无法处理数字类型的 id ([#9683](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9683)) ([fc8a096](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fc8a096bef670cf65df2cda8cbd2f4042fdc840c))\n- **carousel:** 修复窗口大小改变时高度无法响应式变化的问题 ([#9612](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9612)) ([b5558ae](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b5558ae679831fa5abc1d9e4ba23c85be5a0d690))\n- **cascader:** 优化弹出气泡内边距样式 ([#9699](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9699)) ([b16da90](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b16da905867fc8235d413b44e32ba3233a74dadb))\n\n## 21.1.0\n\n`2026-02-05`\n\n### Features\n\n- **collapse:** 同步最新 antd 样式 ([#9680](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9680)) ([4eec05f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4eec05f06def8d001e5f716372cee97859a7a5fa)) ([#9678](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9678)) ([2483498](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2483498b7f841eb2caede9cfe0ed975f1e6b284c))\n- **form:** 新增 `nzSize` 参数，支持设置表单组件尺寸 ([#9606](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9606)) ([785ca6f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/785ca6fc0dec71e84b6817a650d3976f39814518))\n- **time-picker:** 新增 `nzPrefix` 参数，支持自定义前缀 ([#9647](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9647)) ([8d75887](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8d75887faee74f7a371e4c6ca9825e30375bd295))\n- **time-picker:** 新增 `nzNeedConfirm` 参数，配置为 `true` 时需点击确认按钮才能完成选择 ([#9638](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9638)) ([9f887af](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9f887af5e14332ecabab52560db548dbabe0158f))\n- **time-picker:** 新增 `nzPlacement` 参数，支持设置选择框弹出的位置 ([#9630](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9630)) ([931b3f4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/931b3f45489c410d8f00a987b74e215fe630dfec))\n\n## 21.0.2\n\n`2026-01-23`\n\n### Bug Fixes\n\n- **i18n:** 更新 `he_IL` 国际化文案 ([#9658](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9658)) ([a3410a0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a3410a0c60eea5367f7c9bb56da378e96920ba8c))\n- **form:** 修复禁用动画时校验信息无法消失的问题 ([#9660](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9660)) ([798a556](https://github.com/NG-ZORRO/ng-zorro-antd/commit/798a5566388a03d88e64799f0b568c5e7130709e))\n- **menu:** 修复禁用动画时子菜单无法消失的问题 ([#9661](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9661)) ([79ffce9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/79ffce9621fde0f41e10de822ba8aa45dfdda7ae))\n\n## 21.0.1\n\n`2026-01-16`\n\n### Bug Fixes\n\n- 修复样式文件中 keyframes 样式缺失的问题 ([#9653](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9653)) ([49ec060](https://github.com/NG-ZORRO/ng-zorro-antd/commit/49ec0605b31eef0a3d790319d55d9f44492b4c0b))\n- **collapse:** 修复折叠状态下出现幽灵滚动区域的问题 ([#9649](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9649)) ([5378f8b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5378f8beec14f7b47e0a54b6c81583592825ffa1))\n\n## 21.0.0\n\n`2026-01-09`\n\n### Code Refactoring\n\n- 迁移至 native animation API，您可以按需移除依赖 `@angular/animations`\n\n### Features\n\n- **color-picker:** 新增 `nzPresets` 参数支持预设颜色 ([#9341](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9341)) ([d59ec99](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d59ec995b42726470ebaea39ec7a52f5c9c5e58d))\n- **core:** 新增 `provideNzNoAnimation` provider 用于禁用动画效果 ([#9555](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9555)) ([c945e81](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c945e81ce5966f34e7a96a8bccbf628a5b8d8c06))\n- **date-picker:** 日期范围选择顺序颠倒时确保能输出正确的范围 ([#9518](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9518)) ([d0b3185](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d0b3185fb2ae891a164d3b4f28e4f68add8e166b))\n- **float-button:** 悬浮按钮组合新增动画效果 ([#9413](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9413)) ([b40ad91](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b40ad91b26aee48fc86d92da48071751f8345ab4))\n- **input-number:** 支持鼠标滚轮控制 ([#9591](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9591)) ([6ce3545](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6ce354537ec59bd0c480eed61bb8f663d2429189))\n- **input,input-number:** `focus` 方法新增额外参数 ([#9595](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9595)) ([c336711](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c3367110ccd53c5debd74799070ac6565c13c483))\n- **qrcode:** 新增 `nzType` 和 `nzBoostLevel` 参数，`nzPadding` 类型从 `number | number[]` 调整为 `number` ([#9535](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9535)) ([5419b51](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5419b51781478369afe3c01fe24374f2f62eeffe))\n- **tree-view:** 升级 tree-view 组件，支持 `nzLevelAccessor` 和 `nzChildrenAccessor` ([#9003](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9003)) ([ae9ad57](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ae9ad576292671f3228361733b47e890d425e713))\n- **upload:** 新增 `nzMaxCount` 属性 ([#9424](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9424)) ([0bf13c3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0bf13c3fa5e41289315cf4d9642ed5aa7005af9e))\n\n### Bug Fixes\n\n- **i18n:** 更新 `fa_IR` 国际化文案 ([#9615](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9615)) ([1e8845d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1e8845d245ce7a98850390c61e65b301fb8fcc05))\n- **popconfirm:** 允许设置 `nzIcon` 为 `null` 以隐藏图标 ([#9569](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9569)) ([760b587](https://github.com/NG-ZORRO/ng-zorro-antd/commit/760b58745a1b377d4008825a3d4c157d8a1bd590))\n- **select:** 单选模式下 `nzAutoClearSearchValue` 不应生效 ([#9605](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9605)) ([4720c21](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4720c2175dd2bc937d8ccbf66ab804c4782f23d4))\n- **tree:** 不再阻止右键点击树节点标题的默认行为 ([#9532](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9532)) ([900efad](https://github.com/NG-ZORRO/ng-zorro-antd/commit/900efad5b0a04b1a0aca2c68728f01ed8dc4ef3b))\n\n### ⚠ BREAKING CHANGES\n\n- **back-top:** 移除，请使用 `float-button` 替代\n- **color-picker:** 简化 DOM 结构，移除 `nzClick` output 不必要的参数\n- **input-number-legacy:** 移除，请使用 `input-number` 替代\n- **qrcode:** `nzPadding` 类型从 `number | number[]` 调整为 `number`\n- **statistic:** 重命名 `NzStatisticNumberComponent` 为 `NzStatisticContentValueComponent`\n- **tabs:** 移除已弃用的 `nz-tabset` selector\n- **tree-view:** 移除 `nzTreeControl`，请使用 `nzLevelAccessor` 或 `nzChildrenAccessor` 替代\n- **watermark:** 将引入路径 `ng-zorro-antd/water-mark` 调整为 `ng-zorro-antd/watermark`\n\n移除以下在过去的版本中标记为废弃的 API:\n\n| Module                              | API                                    |\n| ----------------------------------- | -------------------------------------- |\n| `ng-zorro-antd/back-top`            | `*`                                    |\n| `ng-zorro-antd/input-number-legacy` | `*`                                    |\n| `ng-zorro-antd/dropdown`            | `NzDropdownButtonDirective`            |\n| `ng-zorro-antd/core`                | `NzHighlightModule`                    |\n| `ng-zorro-antd/auto-complete`       | `NZ_AUTOCOMPLETE_VALUE_ACCESSOR`       |\n| `ng-zorro-antd/checkbox`            | `nz-checkbox-wrapper`                  |\n| `ng-zorro-antd/date-picker`         | `NzDatePickerComponent#nzBorderless`   |\n| `ng-zorro-antd/input`               | `NzInputDirective#nzBorderless`        |\n| `ng-zorro-antd/input-number`        | `NzInputNumberComponent#nzBordered`    |\n| `ng-zorro-antd/mention`             | `NZ_MENTION_TRIGGER_ACCESSOR`          |\n| `ng-zorro-antd/select`              | `NzSelectComponent#nzBorderless`       |\n| `ng-zorro-antd/time-picker`         | `NzTimePickerComponent#nzBorderless`   |\n| `ng-zorro-antd/tooltip`             | `NzToolTipModule` `NzToolTipComponent` |\n\n统一组件命名规范，变化如下：\n\n| Module      | Original                      | Current                       |\n| ----------- | ----------------------------- | ----------------------------- |\n| `core`      | `NzConfig#backTop`            | `NzConfig#floatButton`        |\n| `core`      | `NzConfig#dropDown`           | `NzConfig#dropdown`           |\n| `dropdown`  | `NzDropDownModule`            | `NzDropdownModule`            |\n| `dropdown`  | `NzDropDownADirective`        | `NzDropdownADirective`        |\n| `menu`      | `NzIsMenuInsideDropDownToken` | `NzIsMenuInsideDropdownToken` |\n| `watermark` | `NzWaterMarkModule`           | `NzWatermarkModule`           |\n| `watermark` | `NzWaterMarkComponent`        | `NzWatermarkComponent`        |\n\n### Deprecations\n\n在 v21 中，以下 API 被标记为 **deprecated**，并将在下一个主要版本中移除。 请参考相关文档以获取更好的替代方案。\n\n| Module                   | API                                                               |\n| ------------------------ | ----------------------------------------------------------------- |\n| `ng-zorro-antd/collapse` | `nz-collapse-panel[nzDisabled]`                                   |\n| `ng-zorro-antd/input`    | `textarea[nzAutosize]`, `nz-input-group`, `[nz-input-group-slot]` |\n| `ng-zorro-antd/upload`   | `nz-upload[nzTransformFile]`, `NzUploadTransformFileType`         |\n\n## 20.4.4\n\n`2025-12-12`\n\n### Bug Fixes\n\n- **icon:** 将 `nzSpin` 纳入变更检测逻辑，修复图标旋转状态在某些情况下无法及时更新 ([#9597](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9597)) ([46dc381](https://github.com/NG-ZORRO/ng-zorro-antd/commit/46dc3819244969963ca80eeac9f9c06482f48d29))\n- **result:** 修复仅设置 `nzStatus` 时图标不显示的问题 ([#9568](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9568)) ([#9582](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9582)) ([b652105](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b652105ac71a022f4d7343e911f04fbeb2dee8d0))\n\n## 20.4.3\n\n`2025-11-28`\n\n### Bug Fixes\n\n- **form:** 修复无法禁用 nz-form-control 动画的问题 ([#9562](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9562)) ([5bccf96](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5bccf968ab8cbe4164fe09e691f6664ee2664a5c))\n- **input:** 修复循环依赖问题 ([#9561](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9561)) ([8d5782d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8d5782d5ae35769fc73bcdb49d9d7897b9b92828))\n\n## 20.4.2\n\n`2025-11-21`\n\n### Bug Fixes\n\n- **cascader,select,date-picker,time-picker,tree-select:** 补充 `nzVariant` 全局配置类型定义 ([#9543](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9543)) ([221386b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/221386b45cc20d6bea689a5a4c10e35ff15b06b7))\n- **button:** 优化 zoneless 模式下仅图标展示的逻辑 ([#9541](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9541)) ([9def420](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9def420d2da1a2b8a7993db814948151733ef772))\n\n## 20.4.1\n\n`2025-11-14`\n\n### Bug Fixes\n\n- **badge:** 修复十六进制 `nzColor` 不生效问题 ([#9517](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9517)) ([47d44ba](https://github.com/NG-ZORRO/ng-zorro-antd/commit/47d44ba4f826f882ee3a9de64994ad5ebd89daa5))\n- **cascader:** 修复 zoneless `NG0100` 问题 ([#9504](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9504)) ([24b4e83](https://github.com/NG-ZORRO/ng-zorro-antd/commit/24b4e83e39fe3216d02857999df78cd4fbdc35fe))\n- **color-picker:** 修复 `NG01350` 问题 ([#9525](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9525)) ([fbcb8c3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fbcb8c3f78c293bd510994a28de7295e4349576c))\n- **dropdown:** 修复部分情形箭头位置不正确 ([#9519](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9519)) ([7ff7e09](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7ff7e09d4256e8b4bd54cf2e1e01f64cabadcf4d))\n- **input:** 修复 nz-input-search `enterButton` 为空字符串时搜索图标不渲染 ([#9498](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9498)) ([6a40b0d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6a40b0db8cd23584cc4a268c16eec14cf6bbaf29))\n- **result:** 修复 ng-content 中的 nz-result-icon 不生效的问题 ([#9511](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9511)) ([0e095a1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0e095a14e0bf6014cffcb95db007b750bfe84da7))\n- **segmented:** 修复禁用动画效果时选中不生效的问题 ([#9512](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9512)) ([af8b531](https://github.com/NG-ZORRO/ng-zorro-antd/commit/af8b53186469aa9858a9eaa883e3e597db65c598))\n- **select:** 校正 small 尺寸下的字体大小 ([#9516](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9516)) ([6f79005](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6f7900548ccd128b430f7a09ee3ef07dd6ea482c))\n\n## 20.4.0\n\n`2025-10-31`\n\n### Features\n\n- **cascader:** 支持通过设置 `nzOpen` 使弹出面板完全受控 ([#9448](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9448)) ([4d5ec65](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4d5ec6536f64690319e0fd219dc4b07c724764db))\n- **cascader:** 多选模式下支持通过 `ENTER` 按钮改变选项 checkbox 值 ([#9457](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9457)) ([e02f1f4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e02f1f45f6ae1d5836b1b751bb23bfa55c5f1c33))\n- **float-button:** 新增 `nzBadge` 属性设置徽标 ([#9489](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9489)) ([12beec7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/12beec73fe3071e116788635ae17b1668d3b5ad8))\n- **form:** 新增 `nzRequiredMark` 属性自定义必选与可选样式 ([#9447](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9447)) ([800b6cf](https://github.com/NG-ZORRO/ng-zorro-antd/commit/800b6cf960af7c4dfce0378eeb9fd361d21ac06b))\n- **input-number:** 新增前置和后置元素的 inputs 属性 ([#9451](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9451)) ([dbebd02](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dbebd025cc5101d879301405f0e0ce4baca4bdf5))\n- **input:** 新增 `nzAllowClear` 属性以及 `nzClear` 回调 ([#9452](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9452)) ([830b4b3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/830b4b3cced07ecc484375ab62a3593ac7140b39))\n- **input:** 新增组件 `nz-input-wrapper` ([#9408](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9408)) ([a8e56ec](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a8e56ecbc5040dc36dd38881d2d3f7133c7c7991)), closes [#9403](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9403)\n- **input:** 为 `nz-input-wrapper` 新增前置和后置元素的 inputs 属性 ([#9450](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9450)) ([763f69e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/763f69e7e35ef3697245e9074034d17f110c5876))\n- **input:** 新增 `nz-input-search` 指令 ([#9483](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9483)) ([af6f590](https://github.com/NG-ZORRO/ng-zorro-antd/commit/af6f590b30270205300e028287f205249b316efa))\n- **input:** 新增 `nz-input-password` 指令 ([#9460](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9460)) ([f80832a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f80832a7741a6efd9049372a8759d710dc72bde4))\n- **message:** 支持自定义样式 ([#9427](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9427)) ([2f866b3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2f866b31febe4c1f6dd784537fc8ca2b68a66a93))\n- **pagination:** 新增 `nzAlign` 属性 ([#9433](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9433)) ([88d0864](https://github.com/NG-ZORRO/ng-zorro-antd/commit/88d08648570756e35b989f55e15bcb116175dbc2))\n- **segmented:** `nzName` 未设置时支持默认 name ([#9466](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9466)) ([33f8142](https://github.com/NG-ZORRO/ng-zorro-antd/commit/33f8142626e337e1cef997bc99a289effcb64dd0))\n\n### Bug Fixes\n\n- **badge:** 修复 `nzColor` 未设置时 `nzStyle` 不生效的问题 ([#9486](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9486)) ([4424eb0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4424eb0a018c7d90fb74dfda6ceb5c54a080eb4d))\n- **cascader:** 重新打开弹出面板时正确展示激活的列 ([#9456](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9456)) ([7802a39](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7802a39167d0efaf1bca5e829fa4907f7af54650))\n\n## 20.3.1\n\n`2025-09-17`\n\n### Bug Fixes\n\n- **drawer:** 修复 `NG0203` 问题 ([#9418](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9418)) ([7fb58ae](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7fb58aea2f03902ce3b0ac626bed99b5d8de0c6b))\n\n## 20.3.0\n\n`2025-09-16`\n\n### Features\n\n- **carousel:** 新增 `nzArrows` 属性 ([#9355](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9355)) ([1b9714b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1b9714baf8d320b423f390d713af6533e0390f24))\n- **check-list:** 清单项支持定义默认是否完成 ([#9343](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9343)) ([235b493](https://github.com/NG-ZORRO/ng-zorro-antd/commit/235b493705d297ccff21969f2d770b7f4eba7fb5))\n- **i18n:** `provideNzI18n` 支持 factory function 作为参数 ([#9393](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9393)) ([1371265](https://github.com/NG-ZORRO/ng-zorro-antd/commit/13712654d1c3b5de2eabc577c22d0f98a59a8345))\n- **mention:** 新增 `nzClear` 属性 ([#9377](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9377)) ([cbecebf](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cbecebfda401b2fd873163638d3e2cc4dfd638c1))\n- **mention:** 新增 `nzVariant` 属性 ([#9379](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9379)) ([d92568b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d92568b781bb16bfef55e645a15022ef54583ba1))\n- **segmented:** 新增 `nzShape` 属性 ([#9368](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9368)) ([ffce6c3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ffce6c385a3c994132e096a33a83bd77d01a6b7b))\n- **segmented:** 新增 `nzName` 属性并支持键盘交互 ([#9373](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9373)) ([ebd8bdc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ebd8bdc9d0c71fc6f691c7c900e8b43e26cc0e84))\n- **upload:** `nzBeforeUpload` 支持 promise 返回类型 ([#9402](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9402)) ([cece107](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cece1077e5f375c225ae32973b863f8123520717))\n\n### Bug Fixes\n\n- **badge:** 设置 `nzColor` 后徽标渲染异常 ([#9376](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9376)) ([e9abf92](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e9abf9250ab8c7c902933688610e0f2c731b97b1))\n- **input:** 修复 `underline` 变体下 hover 时样式问题 ([#9400](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9400)) ([74c2173](https://github.com/NG-ZORRO/ng-zorro-antd/commit/74c217382ed191b26990082586796f588fdd73c8))\n- **segmented:** 修复 `NG0950` 错误 ([#9386](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9386)) ([e82fc01](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e82fc0186d2dc8061ff1db50aaa2e7b2f11beb9d))\n- **select:** 修复多选模式下样式异常 ([#9409](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9409)) ([38f9065](https://github.com/NG-ZORRO/ng-zorro-antd/commit/38f90653569b46e28e317e040040e98bee595761))\n- **schematics:** 在非 LESS 项目中，选择自定义主题后将 `less` 添加到 devDependencies ([#9412](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9412)) ([a18cffd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a18cffd8e2dd6e39836f00a42c95f1f5699d1829))\n\n## 20.2.1\n\n`2025-08-31`\n\n### Bug Fixes\n\n- **segmented:** 带图标的和仅设置图标时正确渲染 ([#9367](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9367)) ([9d42b42](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9d42b42ad103e8ca498e65e7aa6ad7e72075d609))\n\n## 20.2.0\n\n`2025-08-29`\n\n### Features\n\n- **cascader:** 新增 `nzOpen` 属性控制可见性 ([#9339](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9339)) ([354c7cf](https://github.com/NG-ZORRO/ng-zorro-antd/commit/354c7cfb9e9746fc55ccc3f5967721ab01737652))\n- **collapse:** 新增 `nzCollapsible` 设置可折叠触发区域 ([#9349](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9349)) ([1ddbcaf](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1ddbcaf8e8c5f47a5c2354ac61bf3da707e8a99c))\n- **collapse:** 新增 `nzSize` 设置折叠面板大小 ([#9348](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9348)) ([b5c256d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b5c256da531b5b306f831c8ee05acf0139bc7ad3))\n- **divider:** 新增 `nzSize` 设置分割线大小 ([#9346](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9346)) ([1f54536](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1f5453639f059c9058815834500e459df4082882))\n- **dropdown:** 新增 `nzArrow` 属性控制是否展示箭头 ([#9329](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9329)) ([3686b73](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3686b7375839412b0db26f896fb810a4bdb2ae0c))\n- **float-button:** `nzIcon` 支持字符串类型 ([#9302](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9302)) ([ce611e5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ce611e5d9096456e032db78acc886b5dde60220c))\n- **segmented:** 新增 `nzVertical` 属性支持展示垂直方向 ([#9359](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9359)) ([52322cd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/52322cd50c1d2883a0df7ca0aee91f803448315b))\n- **select,tree-select,cascader:** 支持设置前缀和后缀图标 ([#9328](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9328)) ([527ffb6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/527ffb6efee5759e58c7472f1fae2a619092f246))\n- **tag:** 导出 `NzTagColor` 类型 ([#9314](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9314)) ([1efd29e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1efd29ee1de0f77854dd75c10c9156d50013067d))\n\n### Bug Fixes\n\n- **carousel:** `nzDotPotion` 为 `left` 或 `right` 时指示点位置不正确 ([#9358](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9358)) ([f117ccb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f117ccb739754e5a1b73be844679357cc807a238))\n- **range-picker:** 鼠标离开时清理 outline ([#9352](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9352)) ([573d092](https://github.com/NG-ZORRO/ng-zorro-antd/commit/573d092f6e332acaeb33dfc03c0e370be6753df8))\n- **segmented:** 仅图标时应只渲染一个元素 ([#9363](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9363)) ([89d2168](https://github.com/NG-ZORRO/ng-zorro-antd/commit/89d216871b0a9127aa4adbf6a034b7e2e1febf2d))\n\n## 20.1.3\n\n`2025-08-22`\n\n### Bug Fixes\n\n- **i18n:** 更新 `cs_CZ` 国际化文案 ([#9334](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9334)) ([93e486e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/93e486eeb848fb3cbb2073f107ae7be4bba2457b))\n- **i18n:** 更新 `sk_SK` 国际化文案 ([#9335](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9335)) ([ddefc7f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ddefc7f9e95cde34101896fd5bfe587ff1dd8a89))\n- **cascader:** 动态绑定时 value 和 label 不正确的问题 ([#9338](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9338)) ([324ab5b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/324ab5b2ad281abb77344b9ca0dd66d4ca55e794))\n- **popconfirm:** 正确渲染标题和图标 ([#9322](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9322)) ([2c83788](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2c837883853a77a5a8fe1c2245daa0548a7bb2d9))\n- **select:** 修复使用 `TemplateRef` 作为 `nzNotFoundContent` 时关闭下拉框时抖动的问题 ([#9336](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9336)) ([366f8eb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/366f8ebcd79900a4d6a512b72094af3494c55871))\n\n## 20.1.2\n\n`2025-08-08`\n\n### Bug Fixes\n\n- **input-number:** 修复展示值不正确的问题 ([#9312](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9312)) ([7a2d3b6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7a2d3b6f97bf80f2f517626f5e02625c4488be80))\n- **select,tree-select,cascader:** 已选项文本超出时展示省略号 ([#9316](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9316)) ([30672d7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/30672d7978f0ca4b24ec04c196c967b69e614525))\n- **table:** 内部滚动元素增加 `cdkScrollable` 指令 ([#9308](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9308)) ([8cb4113](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8cb411332b90b55bab3ec742c455e3aaaf4618d7))\n\n## 20.1.1\n\n`2025-08-05`\n\n### Bug Fixes\n\n- **badge:** 导出 `NzBadgeStatusType` 类型 ([#9298](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9298)) ([91b1ad7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/91b1ad7af23eda253c21530e2a01a5ac9f7c62a8))\n- **layout:** 修复代码示例问题 ([#9303](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9303)) ([9a37ef8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9a37ef8325522ee200462b75e13a72f403ec4bef))\n\n## 20.1.0\n\n`2025-07-21`\n\n### Features\n\n- 新增 [llms.txt](https://ng.ant.design/llms.txt) 和 [llms-full.txt](https://ng.ant.design/llms-full.txt) ([#9281](https://github.com/NG-ZORRO/ng-zorro-antd/pull/9281)) ([165b963](https://github.com/NG-ZORRO/ng-zorro-antd/commit/165b96372e737a6dceac9404bded06041d286e2a))\n- **float-button:** 新增 `nzPlacement` 属性自定义弹出位置 ([#9267](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9267)) ([9dc19f3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9dc19f35c9f4d9de0c6fc1f2b58c97f2aded95c1))\n- **input-number:** 支持输入的数字带 `,` ([#9256](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9256)) ([7567bd8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7567bd87a7862b52c12e152b9ce0c395b5e18ff0))\n- **input:** 一次性密码框支持通过键盘控制光标位置 ([#9268](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9268)) ([da97b02](https://github.com/NG-ZORRO/ng-zorro-antd/commit/da97b02a82361e23c77f14bec76add77f6c39302))\n- **popconfirm:** 取消按钮支持设置 `nzDanger` 属性 ([#9270](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9270)) ([f94cb31](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f94cb318b05b01d1560ddfe3a5bfb226f23a83b4))\n- **space:** 支持通过数组形式设置 `nzSize` ([#9289](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9289)) ([8809885](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8809885be2b268e38c8ba04f57f46803e92e0c28))\n- **schematics:** 对齐 Angular 20 更新的风格指南 ([#9295](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9295)) ([b5f607b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b5f607b874ed150fb1858eb81b19c3cc67478f37))\n\n### Bug Fixes\n\n- **core:** 避免使用 `setAttribute` 设置 `style` ([#9292](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9292)) ([12d58bd](https://github.com/NG-ZORRO/ng-zorro-antd/commit/12d58bde7cb8d762405728825d6261fe5fc663b8))\n- **input-number:** ngModel 的值可为 `undefined` ([#9269](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9269)) ([4c5666a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4c5666a90f477703dcda96ec135a6eea99d11105))\n- **tooltip:** 重命名 `ToolTip` 为 `Tooltip` ([#9285](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9285)) ([2ebef97](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2ebef970cb7cd2855ee725b89ab8dfef9e6e35d6))\n- **schematics:** 支持迁移 `ToolTip` 到 `Tooltip` ([#9294](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9294)) ([add21f7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/add21f71d92645be9f1c7684c2f213a6864f5891))\n\n## 20.0.0\n\n`2025-07-01`\n\n### Features\n\n- **cascader,date-picker,input-number,input,select,time-picker,tree-select:** 新增 `nzVariant` 属性设置变体 ([#9131](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9131)) ([b342bb4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b342bb464eb544a2e3fda8723cac7e550828b3f2))\n- **popover:** 新增 `nzPopoverTitleContext` 和 `nzPopoverContentContext` 属性 ([#9126](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9126)) ([df3ead9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/df3ead9af8368eb7e2374744f01cecd5ccc21440))\n- **select:** 新增 `nzOnClear` 事件回调 ([#9188](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9188)) ([e047ac2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e047ac249b16b547525a0ca4d13beeef620f44c4))\n- **avatar:** 支持设置原生 `<img>` 的 `loading` 和 `fetchpriority` 属性 ([#7347](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7347)) ([ff8419f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ff8419f6614bdac8bc3c778e470da08b679889d0))\n- **popconfirm:** 新增 `nzOkButtonProps` 和 `nzCancelButtonProps` ([#9245](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9245)) ([22e2a9f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/22e2a9fb148fd875c76fb339c6582d92aef62791))\n- **tree-select:** 支持以 innerHTML 渲染已选项的 title ([#9259](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9259)) ([8066f7b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8066f7bb082c95652a2e158a01e55382992fe8c6))\n\n### Bug Fixes\n\n- **flex:** 修复 `NzAlign` 类型 ([#9151](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9151)) ([b271c19](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b271c19076ead71fabbe5b224072cfea975d801d))\n- **segmented:** 接受 ng control 的禁用状态 ([#9166](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9166)) ([134cd59](https://github.com/NG-ZORRO/ng-zorro-antd/commit/134cd5976220d51179118491a4b4b2e4d7cf761c))\n- **space:** 紧凑模式下只有一个子元素时的 border-radius 不正确 ([#9165](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9165)) ([d2f4541](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d2f4541a9ae01d6ea8705faf2bc4b96bf34b6945))\n- **tabs:** 修复 tab focus 时不正确的滚动行为 ([#9186](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9186)) ([4f658e0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4f658e0834e99ea2be0ffd4ead2dd041ec88fb83))\n- **schematics:** 修复重复执行 `ng add` 时的问题 ([#9171](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9171)) ([d0a9748](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d0a974848c0e31ad41ba69a5af60c002a7b251cd))\n- **water-mark:** 修复 ssr 模式的兼容问题 ([#9250](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9250)) ([a70a682](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a70a682c8aa4d073bb150abd4b69104fbe21e2ed))\n- **icon:** 在 animation frame 上增加渲染防抖 ([#8579](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8579)) ([c0709d1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c0709d1e01d80969a48634fe8194dbfd49f6192f))\n\n### Code Refactoring\n\n- **core:** 移除对 animation frame 的 polyfill ([#9243](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9243)) ([272237a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/272237a7a33d150ac9c0f6965df37a678221b074))\n- 从基于 `constructor` 的依赖注入模式迁移到 `inject`\n\n### ⚠ BREAKING CHANGES\n\n- **core:** 移除对 animation frame 的 polyfill\n  - 重命名 `cancelRequestAnimationFrame` 为 `cancelAnimationFrame`\n  - 重命名 `reqAnimFrame` 为 `requestAnimationFrame`\n- **tabs:** 废弃 `NzTabsetComponent` 并重命名为 `NzTabsComponent`，废弃 `nz-tabset` 选择器并重命名为 `nz-tabs`\n- **table:** 移除对 material 组件的兼容\n\n* **popconfirm:** 废弃 `nzOkDisabled` 和 `nzOkDanger`，请使用 `nzOkButtonProps` 代替\n\n移除以下在过去的版本中标记为废弃的 API:\n\n| Module                       | API                                                      |\n| ---------------------------- | -------------------------------------------------------- |\n| `ng-zorro-antd/button`       | `NzButtonGroupComponent`                                 |\n| `ng-zorro-antd/core/form`    | `NzFormPatchModule`                                      |\n| `ng-zorro-antd/checkbox`     | `NzCheckBoxOptionInterface`                              |\n| `ng-zorro-antd/input`        | `NzInputGroupComponent#nzCompact`                        |\n| `ng-zorro-antd/message`      | `NzMessageModule`                                        |\n| `ng-zorro-antd/notification` | `NzNotificationModule`<br/>`NzNotificationServiceModule` |\n\n组件的 `exportAs` 属性命名统一采用小驼峰 `camelCase` 且以 `nz` 开头，并移除一些内部组件的 `exportAs` 属性。变化如下：\n\n| Component                | Original               | Current                |\n| ------------------------ | ---------------------- | ---------------------- |\n| `calendar-footer`        | `calendarFooter`       | -                      |\n| `date-helper`            | `dateHelper`           | -                      |\n| `date-range-popup`       | `dateRangePopup`       | -                      |\n| `date-table`             | `dateTable`            | -                      |\n| `decade-helper`          | `decadeHelper`         | -                      |\n| `decade-table`           | `decadeTable`          | -                      |\n| `month-helper`           | `monthHelper`          | -                      |\n| `month-table`            | `monthTable`           | -                      |\n| `quarter-helper`         | `quarterHelper`        | -                      |\n| `quarter-table`          | `quarterTable`         | -                      |\n| `year-helper`            | `yearHelper`           | -                      |\n| `year-table`             | `yearTable`            | -                      |\n| `inner-popup`            | `innerPopup`           | -                      |\n| `nz-color-block`         | `NzColorBlock`         | `nzColorBlock`         |\n| `nz-color-format`        | `NzColorFormat`        | `nzColorFormat`        |\n| `nz-color-picker`        | `NzColorPicker`        | `nzColorPicker`        |\n| `nz-model-close`         | `NzModalCloseBuiltin`  | `nzModalCloseBuiltin`  |\n| `nz-model-footer`        | `NzModalFooterBuiltin` | `nzModalFooterBuiltin` |\n| `nz-model-title`         | `NzModalTitleBuiltin`  | `nzModalTitleBuiltin`  |\n| `nz-tree-drop-indicator` | `NzTreeDropIndicator`  | `nzTreeDropIndicator`  |\n| `nz-water-mark`          | `NzWaterMark`          | `nzWaterMark`          |\n| `nz-tabs`                | `nzTabset`             | `nzTabs`               |\n\n### Deprecations\n\n在 v20 中，以下 API 被标记为 **deprecated**，并将在下一个主要版本中移除。 请参考相关文档以获取更好的替代方案。\n\n| Module                         | API                                                                          |\n| ------------------------------ | ---------------------------------------------------------------------------- |\n| `ng-zorro-antd/autocomplete`   | `NZ_AUTOCOMPLETE_VALUE_ACCESSOR` <br /> `getNzAutocompleteMissingPanelError` |\n| `ng-zorro-antd/button`         | `NzButtonGroupComponent`                                                     |\n| `ng-zorro-antd/core/highlight` | `NzHighlightModule`                                                          |\n| `ng-zorro-antd/core/form`      | `NzFormPatchModule`                                                          |\n| `ng-zorro-antd/checkbox`       | `NzCheckBoxOptionInterface`                                                  |\n| `ng-zorro-antd/input`          | `NzInputGroupComponent#nzCompact`                                            |\n| `ng-zorro-antd/mention`        | `NZ_MENTION_TRIGGER_ACCESSOR`                                                |\n| `ng-zorro-antd/message`        | `NzMessageModule`                                                            |\n| `ng-zorro-antd/notification`   | `NzNotificationModule`<br/>`NzNotificationServiceModule`                     |\n| `ng-zorro-antd/tabs`           | `NzTabsetComponent`                                                          |\n\n## 19.3.1\n\n`2025-05-29`\n\n### Bug Fixes\n\n- **cascader:** ngModel 值在选项中不存在时无法更新值 ([#9124](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9124)) ([689fc72](https://github.com/NG-ZORRO/ng-zorro-antd/commit/689fc72e5c8175c830f995155daf1d7d4c318c25))\n- **date-picker:** `nzFormat` 改变时更新 input 元素的值 ([#9129](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9129)) ([f4c4e05](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f4c4e05264dd3109a0c45018886603ddd9c45aa2))\n- **tabs:** 修复首次加载页面时 `nzLinkRouter` 不生效的问题 ([#9130](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9130)) ([925a6a5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/925a6a54dd477b687b3dd0b836c32cb17e6d8a0f))\n\n## 19.3.0\n\n`2025-05-23`\n\n### Features\n\n- **avatar:** 支持通过 ng-content 自定义图标 ([#9090](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9090)) ([89d0767](https://github.com/NG-ZORRO/ng-zorro-antd/commit/89d076775b542996c46e48d2fb6f49c5981be40b))\n- **input-number:** 新增 Output 属性 `nzBlur` 和 `nzFocus` ([#9098](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9098)) ([1b1a013](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1b1a0130df4a86fb2abd42d95213d880fd0b14d7))\n- **tabs:** 附加内容支持 start 和 end 两种位置 ([#9097](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9097)) ([2500821](https://github.com/NG-ZORRO/ng-zorro-antd/commit/250082160770d7f24404bbed86af5df96b9f3e53))\n- **transfer:** 支持键入 `Shift` 后多选 ([#9092](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9092)) ([b78b99f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b78b99f9f4cec6298cffc915b8ab86f708dccddf))\n\n### Bug Fixes\n\n- **i18n:** 更新 `es_ES` 国际化文案 ([#9127](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9127)) ([0aadfdf](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0aadfdf39682bd779eabae57e02596fd0f730624))\n- **segmented:** 修复初始化时发射不必要的值更新事件 ([#9125](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9125)) ([fb0635b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fb0635b0dc2fed0f28d60248b60b0ecd5e3294d4))\n- **tabs:** 修复首次加载页面时 `nzLinkRouter` 不生效的问题 ([#9118](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9118)) ([0f7f94d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0f7f94dab24175b28f34720f5c98e7dc9a2c6c88))\n\n### Performance Improvements\n\n- **transfer:** 使用 item.key 跟踪数据条目 ([#9123](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9123)) ([adb91e4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/adb91e4ba0cbcfc72cccb26a66580fa19dc9c8aa))\n\n## 19.2.2\n\n`2025-04-25`\n\n### Bug Fixes\n\n- **select:** 多选模式下，限制粘贴后的选项数不超过 `nzMaxMultipleCount` ([#9080](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9080)) ([3714840](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3714840a8a72d4d7809a2cac339dd3891052225d))\n- **input-number:** 修复 `NG0600` 错误 ([#9106](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9106)) ([9f5b525](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9f5b525e5eb5e50ed4f93ed15b6831d7db3483ee))\n- **checkbox:** 修复 `NG0600` 错误 ([#9105](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9105)) ([61b6886](https://github.com/NG-ZORRO/ng-zorro-antd/commit/61b68861a6215e40bd29e14d2fe2bc02ce112ce0))\n- **checkbox:** 修正 `nzOptions` 的类型定义 ([#9099](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9099)) ([7be2fe5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7be2fe5412aa00b9178dcae49f202b21a1b7e9e8))\n\n## 19.2.1\n\n`2025-03-29`\n\n### Bug Fixes\n\n- **select:** 修复 `@internal` 注释导致 select-arrow 组件在编译时未导出 ([#9074](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9074)) ([c9b2dd9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c9b2dd96db78ff257137b7a2cba79bbf70f64d3e))\n\n## 19.2.0\n\n`2025-03-28`\n\n### Features\n\n- **splitter:** 新增 `splitter` 组件 ([#8987](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8987)) ([9b3f62e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9b3f62e088f3d0953f236910df00175edf07e26e))\n- **page-header:** 无路由历史时隐藏回退按钮 ([#9041](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9041)) ([bb48232](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bb482328637829b91443075dddaaaef74b85cda8))\n\n### Documentation\n\n- **tabs:** 新增使用 CDK `DragDropModule` 实现可拖拽页签的[示例](https://ng.ant.design/components/tabs/zh#components-tabs-demo-card-draggable)\n\n### Bug Fixes\n\n- **input-number:** 输入数字以 0 结尾时视作输入进行中 ([#9051](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9051)) ([2a0c2e0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2a0c2e08bcec7577558bf2578adf7710a5235a38))\n- **segmented:** 修复 FormControl 第一次更新时不生效 ([#9039](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9039)) ([33fe53d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/33fe53de16bbafd234fa369f677355349d24860a))\n- **select:** 默认模式下禁用 `nzMaxMultipleCount` 属性 ([#9068](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9068)) ([dcf8a5d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dcf8a5d35785d5a4b282719601c0b226e67543bc))\n- **select:** 多选模式下 ngModel 值变化时更新是否达到 `nzMaxMultipleCount` 的状态 ([#9056](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9056)) ([d7031da](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d7031dada3f24cf9c7e48a2eb09678d44caaf9b1))\n- **space:** 修复 rtl 模式下 nzSpaceItem 的行内边距 ([#7801](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7801)) ([2d9ff5f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2d9ff5f0735afc4f4ae03e9f85ae4a8062c21f1a))\n- **tabs:** tabs 改变时更新活动的路由联动页签 ([#7649](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7649)) ([1f07121](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1f07121c3c8521036b011a6f71e1859f70cfe429))\n- **tree-select:** 修复虚拟滚动下选项无法水平滚动 ([#9045](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9045)) ([e70cae3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e70cae3c7cbd47c82d575a49e1dc6a31faa5912d))\n\n## 19.1.0\n\n`2025-02-21`\n\n### Features\n\n- **check-list:** 新增 `CheckList` 组件 ([#8969](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8969)) ([4cd298b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4cd298bfdce3c96e47c91e689fbad16c36d72b60))\n- **message,notification:** 内容为模板时支持通过 `nzData` 传入数据 ([#9001](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9001)) ([5157470](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5157470dd7d890703e4b3a8db9909891da4932c0))\n- **popover,popconfirm,tooltip:** 支持空格分割的字符串作为 `overlayClassName` ([#8972](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8972)) ([3fcec91](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3fcec916b81a284fc8934846aab26d5b8ce99a1b))\n- **popover:** 支持通过 `nzPopoverOverlayClickable` 禁止点击蒙层关闭面板 ([#8878](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8878)) ([5898da7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5898da718f2568cdb2a6dcc63b6e7e18ccb217aa))\n\n### Bug Fixes\n\n- **input-number,checkbox:** 接受来自 control 的禁用状态变化 ([#8979](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8979)) ([2d8968d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2d8968d4709aee858634274d22196ecbbfbe8764))\n- **input-number:** 修复一系列输入事件问题，详见 ([#8989](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8989)) ([6d8d915](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d8d91521a6d4315b6a01fc173e3ed8df8bdecf0))\n- **tree-select:** 修复判断多个实例条件错误 ([#9008](https://github.com/NG-ZORRO/ng-zorro-antd/issues/9008)) ([5006ea6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5006ea695430c3c0f127f04c3a9bcf6dfd6c1a29))\n\n### Code Refactoring\n\n- 重构为 ECMAScript 标准类成员 ([#8718](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8718)) ([f1d8d92](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f1d8d926b48a798489f54d4f3da6eec0f90f9955))\n- 启用 `isolatedModules` 编译选项 ([#8970](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8970)) ([0d42aa7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0d42aa7d4605c881c242e245b8127629e9657e39))\n\n现在你可以在项目中使用 `isolatedModules` 编译选项。\n\n## 19.0.2\n\n`2025-01-10`\n\n### Bug Fixes\n\n- **auto-complete:** 点击聚焦的输入框时应弹出浮层 ([#8900](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8900)) ([79cc2f8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/79cc2f830133dfe0ee99eaabdb7b5b5f1eca2e02))\n- **progress:** 修复 `NG0956` 错误 ([#8962](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8962)) ([c4d2f81](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c4d2f81f125feca0ce5ad90e12997875b4465230))\n- **transfer:** 修复 body 样式异常 ([#8960](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8960)) ([a3546a9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a3546a9032dcc8fbbd72088e4a431e83b99b32f1))\n\n## 19.0.1\n\n`2025-01-03`\n\n### Bug Fixes\n\n- **date-picker:** 原生 title 属性遵循 `nzFormat` 格式 ([#8744](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8744)) ([1b7ab5a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1b7ab5adb5af783e3a6a47ffc4916961993f4d6f))\n- **i18n:** 更新 `zh_TW` 国际化文案 ([#8950](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8950)) ([9607e11](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9607e1161244b441badb2c37093c4f44a2d63695))\n- **input-number:** 修复 `NG0600` 错误 ([#8955](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8955)) ([8d6135e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8d6135e65a6aa716678b9485e3e7790182d160b1))\n- **table:** 修复水合节点不匹配问题 ([#8948](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8948)) ([0a73deb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0a73deb053d2d9ab8d8194038355fad898b60759))\n\n## 19.0.0\n\n`2024-12-06`\n\n### Bug Fixes\n\n- **autocomplete:** 修复 CSP 问题 ([#8875](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8875)) ([30c25f0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/30c25f0201130ccb00c8d2ba2e709763d7bcfd6e))\n- **avatar:** 修复 overlay 中尺寸计算问题 ([#8754](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8754)) ([3a5ba37](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3a5ba37de6553c5973ac1741a250dff957ca7ec5))\n- **card:** 移除 `nzBorderless` input 属性 ([#8741](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8741)) ([22ce17c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/22ce17c8a4bb7345cf026fd570bc8d3984722815))\n- **carousel:** 修复 rtl 模式下轮播切换顺序问题 ([#8770](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8770)) ([0202a19](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0202a191b3259e3dc454272b53feb3687a32cf0a))\n- **cascader:** 取消选择时收起子选项列 ([#8866](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8866)) ([5fec53e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5fec53e597d50a26a1083bb1e726af885ba807ae))\n- **drawer:** 打开时清除之前 focus 的元素 ([#8893](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8893)) ([4498af0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4498af0f1a8c700099e82f4027bec30086f6d29a))\n- **i18n:** 更新 `vi_VN` 国际化文案 ([#8894](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8894)) ([f08ad1c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f08ad1cb0728d19655c8143658e6a44f8843cb4a))\n- **tree-view:** 修复 `nzTreeNodePadding` 在虚拟滚动中不生效问题 ([#8920](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8920)) ([82b660a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/82b660ac55539e9cb2c39b399884f8bec4d028d4))\n\n### Code Refactoring\n\n- 取消支持渲染 HTML 字符串 ([#8831](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8831)) ([5fae01a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5fae01ad4120841390f7ebb6267a043774ea2266))\n- 移除 `ngClass` and `ngStyle` ([#8895](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8895)) ([c3ab3ba](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c3ab3ba6ad50dc4a8f23b43872b3f235ee316f4c))\n- **image:** 移除废弃的 `FADE_CLASS_NAME_MAP` 和 `IMAGE_PREVIEW_MASK_CLASS_NAME` ([#8912](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8912)) ([65223d9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/65223d9a595e78f8c73347c5d1b12a807389c434))\n- **transfer,tree,tree-select** 相关 Output 属性中的 `CheckBox` 重命名为 `Checkbox` ([#8934](https://github.com/NG-ZORRO/ng-zorro-antd/pull/8934)) ([c76433d5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c76433d5533f6d5c0467ee99c61877a0ec4d35ac))\n\n### Features\n\n- **cascader:** 支持多选 ([#8903](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8903)) ([e5dfb49](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e5dfb495dc4f9e5493e425aeab3802a13a0f5e28))\n- **cascader:** 支持 `nzPlacement` 自定义浮层弹出位置 ([#8935](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8935)) ([6fbd22c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6fbd22c5b38b78cc991bb61446acbea635f30797))\n- **checkbox:** 重新设计 `nz-checkbox-group` 组件，支持自定义布局 ([#8932](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8932)) ([489e0de](https://github.com/NG-ZORRO/ng-zorro-antd/commit/489e0defbfeeb03c29562d139614451575f8ed8d))\n- **divider:** 新增 `nzVariant` 选项 ([#8827](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8827)) ([2c63c87](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2c63c87f557e2400224566342a0185d212055004))\n- **float-button:** 新增 float-button 组件 ([#7884](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7884)) ([dab4d66](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dab4d669b3ef746d1761fbb2199c1b0ae704cda5))\n- **icon:** 新增 `nz-icon` selector ([#8778](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8778)) ([1406241](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1406241f2e636bb3bf11515b0ad68cbe0535d5e1))\n- **image:** 支持通过 `esc` 按键关闭预览 ([#8809](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8809)) ([d587615](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d587615c7dd8d911af06551181f1bffb6eb67149))\n- **input:** 新增一次性密码框组件 ([#8715](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8715)) ([cdbaf4d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cdbaf4de291f380cfcfdf6788d24da3e344175a9))\n- **menu:** 新增 `nzTriggerSubMenuAction` 支持点击触发子菜单 ([#8461](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8461)) ([860df87](https://github.com/NG-ZORRO/ng-zorro-antd/commit/860df87a1be62f462ac3ea136d53948ccd69213a))\n- **qrcode:** 新增 `nzStatusRender` 支持自定义状态渲染 ([#8714](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8714)) ([6f36d75](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6f36d75741e301bc3e7634a93c106c48a02c0a1b))\n- **segmented:** 重新设计 segmented 组件 ([#8753](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8753)) ([4dc866c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4dc866cb2fcc7afb4cc309f433c216d1b7cba2e1))\n- **space:** 新增 `nz-space-compact` 组件 ([#8755](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8755)) ([b9c511d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b9c511db0b1b28521e23148a6fce5b1f169f99a2))\n- **table:** 支持在全局配置中设置 `nzSortDirections` ([#6613](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6613)) ([#8721](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8721)) ([eb1fdc5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/eb1fdc5037d9122a237e317e5b93857deb51e5d5))\n- **transfer:** 新增 `nzOneWay` 属性支持单向样式 ([#8717](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8717)) ([99fd4de](https://github.com/NG-ZORRO/ng-zorro-antd/commit/99fd4de95b2a5a44a2837af38d31ddcabf0a60bf))\n- **input-number:** 重新设计 input-number 组件 ([#8901](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8901)) ([df55d88](https://github.com/NG-ZORRO/ng-zorro-antd/commit/df55d8882c9f36bc6a0cd8a4d752e03070658ff7))\n- **schematics:** 支持 v19 ng update 迁移 ([#8911](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8911)) ([1a20de2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1a20de223bc6e214b54f741f42ed8260611b9b67))\n\n### BREAKING CHANGES\n\n- **All**\n  - `nzClass` / `nzStyle` 属性不再支持下列值：\n    - `Set()`： 使用数组代替\n    - 键分隔的多个类名或样式：使用空格分隔的多个键代替\n  - 移除一些组件内部支持渲染 HTML 字符串的功能，因为这是非良好的模式。message，notification，modal 组件除外，因为这些组件可以通过 service 方式创建，渲染 html 字符串的用例会比较多。\n  - 使用标准装饰器重写 `@WithConfig`。如果在库中使用了 `@WithConfig`，请在 `tsconfig.json` 中关闭 `experimentalDecorators` 选项\n  - 组件内部写法从 `[nz-icon]` 迁移到新的 `nz-icon` 标签。如果在 CSS 中使用了 `[nz-icon]` 选择器来选择**组件内部**的图标，请使用为 `nz-icon` 替代\n\n- **input-number:** 重新设计 input-number 组件，使其更加简单灵活\n\n  现在为新的 input-number 添加前缀或后缀的写法如下，不再需要使用 `nz-input-number-group` 与 `ng-template`：\n\n  ```html\n  <!-- Custom handler icons -->\n  <nz-input-number>\n    <nz-icon nzInputNumberUpIcon />\n    <nz-icon nzInputNumberDownIcon />\n  </nz-input-number>\n\n  <!-- With affixes -->\n  <nz-input-number>\n    <span nzInputPrefix>Prefix</span>\n    <span nzInputSuffix>Suffix</span>\n  </nz-input-number>\n\n  <!-- With addons -->\n  <nz-input-number>\n    <span nzInputAddonBefore>Before</span>\n    <span nzInputAddonAfter>After</span>\n  </nz-input-number>\n  ```\n\n  旧的 input-number 组件被标记为 **deprecated**，其入口已更改为 `ng-zorro-antd/input-number-legacy`。\n  `NzInputNumberComponent` 更名为 `NzInputNumberLegacyComponent`，`NzInputNumberModule` 更名为 `NzInputNumberLegacyModule`。\n\n  不用担心，`ng update ng-zorro-antd` 会自动迁移你的代码。\n\n- **cascader:** `ngModel` 取消支持 `NzCascaderOption[]` 类型\n\n  旧版本中，在表单中为 Cascader 组件赋值为 `NzCascaderOption[]` 类型时，Cascader 组件会根据提供的 `nzValueProperty` 映射成实际的值并写入，例如：\n\n  ```ts\n  @Component({\n    template: `<nz-cascader [nzOptions]=\"options\" [ngModel]=\"value\"></nz-cascader>`\n  })\n  export class ExampleComponent {\n    value = [{ label: 'NG ZORRO', value: 'ng-zorro-antd' }];\n  }\n  ```\n\n  此时 Cascader 组件输出的值将为 `'ng-zorro-antd'`。这就导致输入与输出的值不一致，可能存在潜在的数据问题。\n\n  在 v19 中，我们将移除该特性，如果您已经在代码中运用了该特性，请考虑增加一个 `map` 方法将其映射到实际的值。\n\n- **checkbox** Redesign the checkbox group component.\n  - 移除 `NzCheckBoxOptionInterface['checked]` 字段，另外 `NzCheckBoxOptionInterface` 被标记为弃用，请使用 `NzCheckboxOption` 替代\n  - `nz-checkbox-group`: `ngModel` 类型从 `NzCheckBoxOptionInterface[]` 改为选项值的类型 `NzCheckboxOption['value'][]`\n\n- **card:** 移除冗余的 `nzBorderless` 属性，使用 `nzBordered` 替代\n- **image:** 移除废弃的 `FADE_CLASS_NAME_MAP` 和 `IMAGE_PREVIEW_MASK_CLASS_NAME`\n- **pipes:** 移除废弃的 `NzSafeNullPipe`\n- **segmented:** 重新设计 segmented 组件\n  - `ngModel` 的值从索引值 `index` 改为选项值\n  - `nzValueChange` 发出值的类型从 `number` 改为选项值的类型 （`string | number`）\n  - 移除 `nzLabelTemplate`， 使用 `nz-segmented-item` 指令替代\n- **space:** `NzSpaceComponent` 的` exportAs` 属性重命名为标准 `nzSpace`\n- **transfer:** 属性 `nzTreeCheckBoxChange` 重命名为 `nzTreeCheckboxChange`\n- **tree,tree-select:** 属性 `nzCheckBoxChange` 重命名为 `nzCheckboxChange`\n\n### Deprecations\n\n在 v19 中，以下 API 被标记为 **deprecated**，并将在下一个主要版本中移除。 请参考相关文档以获取更好的替代方案。\n\n| Module                              | API                                                      |\n| ----------------------------------- | -------------------------------------------------------- |\n| `ng-zorro-antd/button`              | `NzButtonGroupComponent`                                 |\n| `ng-zorro-antd/core/form`           | `NzFormPatchModule`                                      |\n| `ng-zorro-antd/checkbox`            | `NzCheckboxWrapperComponent`                             |\n| `ng-zorro-antd/input`               | `NzInputGroupComponent#nzCompact`                        |\n| `ng-zorro-antd/input-number-legacy` | `*`                                                      |\n| `ng-zorro-antd/message`             | `NzMessageModule`                                        |\n| `ng-zorro-antd/notification`        | `NzNotificationModule`<br/>`NzNotificationServiceModule` |\n\n## 18.2.1\n\n`2024-11-15`\n\n### Bug Fixes\n\n- **anchor:** 修复 `nzTitle` 使用 TemplateRef 时 `a` 标签 title 内容异常 ([#8864](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8864)) ([41f6609](https://github.com/NG-ZORRO/ng-zorro-antd/commit/41f66095fdaee05d8bfdae13e8ec18a63cee1f2c))\n- **color-picker:** 修复 CSP 问题 ([#8874](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8874)) ([0264da9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0264da98babca9f14a2c69ccb019944aa4e9f88f))\n- **image:** 修复 CSP 问题 ([#8876](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8876)) ([63c8953](https://github.com/NG-ZORRO/ng-zorro-antd/commit/63c895329a78575654994b607fa822f5735166f4))\n- **select:** 修复 CSP 问题 ([#8873](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8873)) ([9431d0d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9431d0d9e54c76271f7dc13c9833c29bf4e7dc13))\n- **transfer:** 修复取消全选未触发 `nzSelectChange` 事件 ([#8872](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8872)) ([5ff9821](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5ff98216002da5c9fc23a9d9c8bd4d3b68495d51))\n- **qrcode:** 加载稳定后移除事件监听器 ([#8861](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8861)) ([40d466d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/40d466dab751c51b8cecb97dc974a1d17a7692e6))\n- **watermark:** 加载稳定后移除事件监听器 ([#8862](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8862)) ([decd477](https://github.com/NG-ZORRO/ng-zorro-antd/commit/decd4772bdbfeb1a1397c2b597882503ca5685ad))\n\n## 18.2.0\n\n`2024-11-07`\n\n### Bug Fixes\n\n- **i18n:** 添加国际化文案 `nb_NO` ([#8712](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8712)) ([8c9bcd1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8c9bcd18867fca3778d42b844034a4d3370ebe3b))\n- **i18n:** 添加国际化文案 `hu_HU` ([#8769](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8769)) ([9e21ae8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9e21ae8c3c771ff3bce98a11c37f5c81c62f3402))\n- **badge:** 修复组件中的 NG0955 警告 ([#8858](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8858)) ([cc52555](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cc5255587edae6731d38f39786c701679c50020b))\n- **select:** 修复多选模式下和 switch 一起使用时，引发初始化时 switch 组件大小闪烁 ([#8851](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8851)) ([d28876c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d28876cdae5bb1b4df3fda66ebdf6248e43f5a36))\n- **carousel:** 修复 rtl 模式下轮播图切换异常 ([#8705](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8705)) ([85f23a1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/85f23a1b768151a35637c054c7bf42cbf656268e))\n- **drawer:** 导航关闭时发射 `nzVisibleChange` 事件 ([#8850](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8850)) ([29827df](https://github.com/NG-ZORRO/ng-zorro-antd/commit/29827dfe2346badc5178da71884bb4c3264a695d))\n- **modal,drawer:** 修复弹出容器中滚动异常 ([#8804](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8804)) ([ed7951d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ed7951d2e95707c93e993dbb744382e6c9c7dee8))\n- **modal:** 修复 `nzMask` 为 `false` 时遮罩被渲染 ([#8798](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8798)) ([f2f04fe](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f2f04fe8971b23aba9ec5807414afe5ab6f27fc7))\n- **transfer:** 正确更新穿梭按钮的禁用状态 ([#8824](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8824)) ([195ad26](https://github.com/NG-ZORRO/ng-zorro-antd/commit/195ad260a8259129517ee18a208853b9e32c132d))\n\n### Features\n\n- **datepicker:** 新增改变模式或日期的回调 `nzOnPanelChange` ([#8685](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8685)) ([6462a47](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6462a47538a4c7f00f180d82dc3567379277e4b3))\n- **tabs:** 新增 `destroyInactiveTabPane` 支持销毁非活动状态的 tab ([#8845](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8845)) ([0de6d62](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0de6d627cb9105d97b1aca827b1f89a8f3bdcec9))\n\n## 18.1.1\n\n`2024-08-20`\n\n### Bug Fixes\n\n- 修复 [@angular/compiler-cli#56945](https://github.com/angular/angular/issues/56945) 导致的 ngtypecheck reference 问题 ([#8699](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8699)) ([8e459c1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8e459c192cf5c4b1903a744c0548df800aa64bfc))\n- **date-picker:** 修复重新渲染时的 NG0956 警告 ([#8658](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8658)) ([70a0817](https://github.com/NG-ZORRO/ng-zorro-antd/commit/70a0817cd8db49234726f160d9c2ae36f5c650b7))\n- **grid:** 修复示例中的 NG0955 警告 ([#8679](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8679)) ([6414c92](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6414c924cdb013c0ffb96436dd89354e275fa544))\n- **tree-select:** 修改值时清空选中节点 ([#8693](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8693)) ([91927bc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/91927bcede24a89ffc5ec4c814503547c86ad09e))\n\n## 18.1.0\n\n`2024-07-25`\n\n### Bug Fixes\n\n- **cascader:** `compositionstart` 事件触发时隐藏 placeholder ([#8641](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8641)) ([17b0ea3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/17b0ea362021a458c18204f73c34c08695300e2a))\n- **i18n:** 更新 `pt_BR` 国际化文案 ([#7790](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7790)) ([6fc1c78](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6fc1c78b4ca0d37bf5eb6e9e52f0fd150ca5855d))\n- **i18n:** 更新 `fr_BE`, `fr_CA`, `fr_FR`, `lv_LV` 国际化文案 ([#8614](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8614)) ([9b69410](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9b69410ce8f84fbd65e2f0dc627189403888d8f1))\n- **schematics:** 修复模板中 `RouterLink` 引入缺失问题 ([#8621](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8621)) ([032a0c2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/032a0c2384434fc042674a60b005a5a479f6626a))\n- **transfer:** 修复选项全部禁用后全选按钮仍可点击 ([#8633](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8633)) ([75d8c7b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/75d8c7b93310cd54677ac75f470b2967ebd092cb))\n\n### Features\n\n- **breadcrumb:** 新增 `nzRouteFn` 以格式化面包屑路由 ([#6313](https://github.com/NG-ZORRO/ng-zorro-antd/issues/6313)) ([6d805c4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d805c44073297ea17742d43066c6b95e4af5ffe))\n- **i18n:** 添加国际化文案 `en_AU` ([#7919](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7919)) ([c4e6c8d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c4e6c8df3fe48ced3097f0f1347ddbbfde3fda9c))\n- **icon:** 新增 `provideNzIcons` 和 `provideNzIconsPatch` API ([#8650](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8650)) ([b22672d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b22672db7cbce362b14a3dad1ff3b3c45abed27f))\n- **popconfirm:** 新增支持 `nzPopconfirmTitleContext` 上下文 ([#7989](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7989)) ([6d27073](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d27073a52a96d17d8625a9d5d7b820984aa5000))\n- **table:** 新增支持 `nzSummary` 总结栏 ([#8639](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8639)) ([20bb5b2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/20bb5b24c7d01d87f0d50c37248ddd862d9bf341))\n- **table:** 总结栏支持 `nzFixed` 固定 ([#8642](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8642)) ([bef12e6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bef12e6218c53028f8907f2e917945ddc8283db5))\n- **tree-select:** `nzNotFoundContent` 支持 TemplateRef 类型 ([#8638](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8638)) ([13e8a45](https://github.com/NG-ZORRO/ng-zorro-antd/commit/13e8a452c4a96f78d6cf900830ba4b585ed36735))\n\n## 18.0.1\n\n`2024-06-27`\n\n### Bug Fixes\n\n- **graph:** 修复 [@for](https://angular.dev/guide/templates/control-flow#for-block---repeaters) track 表达式异常 ([#8587](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8587)) ([7687ff2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7687ff2c907ee5ab262ee08240bc932b6112b1ae))\n- **icon:** 修复 [@for](https://angular.dev/guide/templates/control-flow#for-block---repeaters) track 表达式异常 ([#8588](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8588)) ([8a27bab](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8a27babf30f7726113fed5511bfbd0067c0bbd37))\n- **table:** 修复 [@for](https://angular.dev/guide/templates/control-flow#for-block---repeaters) track 表达式异常 ([#8593](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8593)) ([b275063](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b2750630a0da3f415931cdf9ba6e6a618dd5d329))\n- **pagination:** 修复 [@for](https://angular.dev/guide/templates/control-flow#for-block---repeaters) track 表达式异常 ([#8586](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8586)) ([6bb95c0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6bb95c0905de9da1493590da2c6f76cc1b2a23bc))\n- **i18n:** 更新 `de_DE` 国际化文案 ([#8605](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8605)) ([8d75378](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8d75378ea612a0ab91f03ec1a709f88c2d22af21))\n- **i18n:** 更新 `fa_IR` 国际化文案 ([#8597](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8597)) ([9c6e4bf](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9c6e4bf6b65810b0f659a366d34b54528d55cc0f))\n- **table:** 修复固定表头下渲染内容缺失问题 ([#8574](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8574)) ([6cff80e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6cff80e90788ce0b84b232a0fb67516b795c88b0))\n\n## 18.0.0\n\n`2024-06-06`\n\n### ⚠ BREAKING CHANGES\n\n- **collapse:** `nzExpandIconPosition` 类型从 `left` | `right` 变更为 `start` | `end` ([#8561](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8561)) ([3ad5674](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3ad56749b0c8222b37444f27f81942fba4bc53e3))\n- Less 中不再使用 inline JavaScript ([#8552](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8552)) ([7e873c8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7e873c863a1c8e9c053f64aca86bf9c7c9a11a21))\n\n使用 antd 提供的 Less 函数时不再需要用 ~\\`\\` 包裹，例如：\n\n```diff\n- color(~`colorPalette('@{primary-color}', 5)`)\n+ color(colorPalette('@{primary-color}', 5))\n```\n\n受影响的函数包括：`colorEasing`，`colorPalette`，`tinycolor`\n\n### Bug Fixes\n\n- **cascader,select,time-picker,tooltip,tree-select:** 修复在 shadow DOM 中获取 `EventTarget` 异常问题 ([#7853](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7853)) ([843b703](https://github.com/NG-ZORRO/ng-zorro-antd/commit/843b7035225df3d3a635a5ef8926d1e80f10ae18))\n- **tooltip:** 修复箭头颜色未被自定义颜色覆盖问题 ([#8555](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8555)) ([92c586b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/92c586b8f5e5fc0ec0e4cb2cc10b73a699b1555a))\n- **upload:** 仅在 firefox 浏览器中阻止拖拽事件 ([#8551](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8551)) ([c6e7bd7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c6e7bd7682a776a7ad3f34b589c9c473430e6baa))\n- **rate:** 修复 `nzAllowHalf` 为 `false` 时展示半星 ([#8536](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8536)) ([7742fe3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7742fe30b718aa19f2988f6354d982d439ad2c7b))\n\n### Features\n\n- **date-picker:** 支持季度选择 ([#8478](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8478)) ([3513889](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3513889367ef468b9e792698f85bb6b890edec86)), closes [#7818](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7818) [#7380](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7380)\n- **qrcode:** 新增已扫描状态 ([#8447](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8447)) ([0be6178](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0be617854d1493a342c9354ce1156fcf323acc97))\n- **rate:** 鼠标离开时触发 `nzOnHoverChange` 事件 ([#8448](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8448)) ([38dcc31](https://github.com/NG-ZORRO/ng-zorro-antd/commit/38dcc3196c62369cd8061a9ead8ab20752e56a66))\n- **statistic:** 新增加载中状态 ([#8537](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8537)) ([21c8b62](https://github.com/NG-ZORRO/ng-zorro-antd/commit/21c8b621f15d642c391253ca91c3b124227ca2d9))\n- **table:** 支持设置空数据时内部滚动的高度 ([#8457](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8457)) ([724d841](https://github.com/NG-ZORRO/ng-zorro-antd/commit/724d841ebd88a329c59e2cfeee3f9625393c8372))\n\n## 17.4.1\n\n`2024-05-24`\n\n### Bug Fixes\n\n- **card:** 使用 `skeleton` 代替 `card-loading-content` ([#8528](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8528)) ([a36ebd3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a36ebd329d042dad19733543ce96f459e4cc09d3))\n- **color-picker:** 避免两次 `nzOnChange` 事件 ([#8530](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8530)) ([5dea059](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5dea059202947caf5ef86f802f08ba14a0867288))\n- **list:** 静态查询列表项操作模板 ([#8527](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8527)) ([85301e0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/85301e0267593457560c5cdcc7fb09ed38944d45))\n- **popconfirm:** icon 样式丢失 ([#8511](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8511)) ([4f1f9bb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4f1f9bba03f38d9ef4ee57380d61e5ca4188648c))\n- **tooltip,popover,popconfirm:** SSR 引入的异常 ([#8512](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8512)) ([5009ec0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5009ec0b3a6ff770186681bd4eb61ec662d9896e))\n\n### Features\n\n- **popconfirm:** popconfirm 确认按钮支持禁用 ([#8542](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8542)) ([8c247db](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8c247dbda2b633d522c53113456600315192a792))\n\n### Performance Improvements\n\n- **back-top:** 删除多余的 `changeDetectorRef` ([c1e39e7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c1e39e7bbc1f863c3a1d26a9cc9cc359b4054dc5))\n- **qr-code:** 提高背景绘制效率 ([#8543](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8543)) ([db09bf7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/db09bf73e45d03817c89bba97e1f340cc09ed5d0))\n\n## 17.4.0\n\n`2024-04-19`\n\n### Bug Fixes\n\n- **autocomplete:** 移除 `NgZone` 依赖 ([#8462](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8462)) ([24bb1bc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/24bb1bc5959c0e617090f0459c39db00fd4e2d9a))\n- **button:** 补充 `ant-btn-default` Class ([#8501](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8501)) ([1588199](https://github.com/NG-ZORRO/ng-zorro-antd/commit/15881996f0a9b1e93b0c81843132ba5d7651e528))\n- **calendar:** 修复年份下拉框数据更新异常问题 ([#8286](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8286)) ([ee68a2c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ee68a2c90370a6e3a599fe9f914af20117d2faa6))\n- **date-picker:** 移除内联样式 ([#8458](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8458)) ([e6b83eb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e6b83eb1881ece341b68f9048e9d3e5ea438ba19))\n- **drawer:** 移除内联样式 ([#8065](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8065)) ([5e89441](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5e89441c26a7df50d0feed746d5595cde2589a7a))\n- **graph:** 修复箭头渲染异常问题 ([#8493](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8493)) ([342841c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/342841ceafddb1b74f55e31bfa9ca3e7734e842e))\n- **graph:** 移除 `NgZone` 依赖 ([#8460](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8460)) ([a4ec21a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a4ec21a684b5c96a64bd66670c270533926252bb))\n- **icon:** 补充 SwapOutline 图标 ([#8433](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8433)) ([f1a4050](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f1a405042f84fbc96ed0587ea2e748dc7d468719))\n- **image:** 修复 rtl 模式下预览切换按钮位置异常 ([#8468](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8468)) ([886138d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/886138d630965b9a0a89d1727f76fed81c6f9528))\n- **list:** 移除 `NgZone` 依赖 ([#8439](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8439)) ([1ec0e76](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1ec0e7672eaba0890b145c706fcc0a75cb5c47f8))\n- **notification:** 修复 `nzMaxStack` 初始值问题 ([#8451](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8451)) ([2c09162](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2c0916265c00cdc026a55b3ab9d829c5e207cf31))\n- **pagination:** `nz-pagination-item` 支持可访问名称 ([#8476](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8476)) ([47ee143](https://github.com/NG-ZORRO/ng-zorro-antd/commit/47ee14325910c154f1541ee2d5e97539ba9a4e52))\n- **slider:** 修复垂直模式下标度刻记样式异常 ([#8494](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8494)) ([9bcce6c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9bcce6c969c0bef7bdf4526407b2dfc56b7ff660))\n- **tag:** 修复无边框样式异常 ([#8495](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8495)) ([b35e6d6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b35e6d6ba2422eb2c4725b2029a2f9c60720b697)), closes [#8492](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8492)\n- **typography:** 移除 `NgZone` 依赖 ([#8440](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8440)) ([af7fb5d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/af7fb5d27254d26a284faaaa5b812b105f539e3f))\n- **upload:** 移除内联样式 ([#8064](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8064)) ([1ac84a8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1ac84a8428fe644362e0f733c9a151fa848cedbf))\n\n### Features\n\n- **modal:** 遮罩层支持响应每次点击 ([#8429](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8429)) ([31b90fa](https://github.com/NG-ZORRO/ng-zorro-antd/commit/31b90fa52232abe7b090f60797d4335329677c4c))\n- **notification:** 调整弹出顺序 ([#8450](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8450)) ([742f14a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/742f14a93472772cbdd96ce89797dc4120c55330))\n- **select:** 支持在全局配置中设置 `nzOptionHeightPx` ([#8504](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8504)) ([4efc5ab](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4efc5ab38f74ce07a769f57453b0da375c17ce5c)), closes [#8503](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8503)\n- **skeleton:** 支持正方形骨架按钮 ([#8481](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8481)) ([af1483a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/af1483a9be544bd41b8f2a4a4c8027425f22b925))\n\n## 17.3.0\n\n`2024-03-11`\n\n### Bug Fixes\n\n- **doc:** 更新 monaco editor 参考链接 ([#8393](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8393)) ([fdfc816](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fdfc816e72938fce47bbdfe274de00ad4e89b242))\n- **docs:** 修复部分文档问题 ([#8383](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8383)) ([407e76a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/407e76a21afb4e1677fc73e89df69b26789da2fd))\n- **select:** 修复缩放页面时 `nzScrollToBottom` 未触发问题 ([#8355](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8355)) ([bb0468e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bb0468e9e95c7c00efd2a5655d0266ae1ce17368))\n- **avatar:** 修复部分场景无法正确缩放问题 ([#8365](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8365)) ([e7b1fa0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e7b1fa0d36b173934bda10f796efa0c6e17d66e5))\n- **carousel:** 修复调整大小时不适应新的大小问题 ([#8374](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8374)) ([6e1decb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6e1decbc7507b07dbb28897f53c6cbcc6ca2eaa6))\n- **cdk:** `zIndex` 设置问题 ([#8373](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8373)) ([b932d65](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b932d65a546f0b2729249713fdaad41fefebb602))\n- **i18n:** 添加国际化文案 ([#8426](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8426)) ([d575c53](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d575c53371f34053a7cd2b6a020a3da1005b708a))\n- **i18n:** 添加国际化文案 `ja_JP` ([#8290](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8290)) ([662b730](https://github.com/NG-ZORRO/ng-zorro-antd/commit/662b73049f8ed8ae70caea573e809016607a795a))\n- **i18n:** 添加国际化文案 `vi_VN` ([#8295](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8295)) ([987a799](https://github.com/NG-ZORRO/ng-zorro-antd/commit/987a799ab1ca5bfdcef162d322423b65fb64dfe6))\n- **tabs:** 修复小屏幕下 `tab` 定位样式丢失问题 ([#8372](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8372)) ([a0b08be](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a0b08be73a77c0a0967f5a301fe8c7ebbfca103c))\n- **tabs:** 修复光标样式 ([#8386](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8386)) ([3dc1579](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3dc1579805f1a867689160fede25fd005983ddf1))\n\n### Features\n\n- 优化 schematics ([#8411](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8411)) ([921f1c1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/921f1c18266ead602c2e2c627a171608507807d4))\n- **anchor:** 支持水平锚点 ([#8342](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8342)) ([9cc44f8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9cc44f8bdb55fbf2fcf4c8ce4da4fab1120245dc))\n- **calendar:** 支持自定义 header ([#8418](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8418)) ([ec7ec35](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ec7ec35573fc46ba01af1368087b5de0b13ab7c7))\n- **color-picker:** 转为内置 `color-picker` 组件 ([#8428](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8428)) ([534fe62](https://github.com/NG-ZORRO/ng-zorro-antd/commit/534fe6277287dd64730546d3d4cc0f1be90a211a))\n- **drawer:** `nzContent` 类型为组件时返回 `componentRef` ([#8339](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8339)) ([f71162b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f71162bbbb30c7b362774b2bc170a0ffd1c0dcf7))\n- **image:** 支持水平和垂直翻转 ([#8168](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8168)) ([e856515](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e856515888102b5a3583a2223372263a4bff1c50))\n- **image:** 支持鼠标滚动缩放 ([#8180](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8180)) ([4235c29](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4235c293c0abf889bba0bc31d2ba18cf5d41b51d))\n- **modal:** 支持拖拽 ([#8419](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8419)) ([ce33294](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ce332947c49e7e6dd02d9bb80eb2fe3f7beab3af))\n- **modal:** `nzContent` 返回 `componentRef` 对象 ([#8389](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8389)) ([e53000e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e53000e8b52972cc73070a8781d276dc26ebca0b))\n- **segmented:** 支持仅图标展示 ([#8368](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8368)) ([e8dea7a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e8dea7a83e6f98e2486c4e3f894f86b646025c1c))\n- **select:** 支持多选最大值设置 ([#8371](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8371)) ([18b898e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/18b898e8c5201c6785e5060850d3597601c39401))\n\n## 17.2.0\n\n`2024-01-29`\n\n### Bug Fixes\n\n- **table:** 修复 `nz-table-inner-scroll` 未正确 import 问题 ([#8328](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8328)) ([936317e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/936317e6702e790f5f8827e074fe12fd55fbf0f3))\n- **tree-select:** 修复中文搜索异常问题 ([#8324](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8324)) ([aacd62b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/aacd62b0beeac35b18829ae4e382626b655c7e05))\n- 修复 pipeline 依赖报错问题 ([#8367](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8367)) ([6024bcc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6024bcc7a9453976d0023fe7b455dc452ced8bd4))\n\n### Features\n\n- **color-picker:** 支持 `standalone` ([#8316](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8316)) ([b050474](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b05047433311fe60ee82d100467c896f2167d925))\n- **tag:** 支持无边框模式 ([#8320](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8320)) ([e428083](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e428083537c8c25d463980749f63b1b8ab129057))\n- **timeline:** 支持自定义颜色 ([#8335](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8335)) ([66a88db](https://github.com/NG-ZORRO/ng-zorro-antd/commit/66a88dbbb1cdd26ee9411de2394fd2231a2807f0))\n\n## 17.1.0\n\n`2023-12-17`\n\n### Bug Fixes\n\n- **calendar:** 修复单选按钮样式问题 ([#8298](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8298)) ([996e141](https://github.com/NG-ZORRO/ng-zorro-antd/commit/996e141042470e487d915d38477ad51928d3e2a0))\n- **core:** 隐藏构建时 cron 警告信息 ([#8277](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8277)) ([138d666](https://github.com/NG-ZORRO/ng-zorro-antd/commit/138d666e0527dba2f3f5ac43b05ce4810fffe9f7))\n- **cron-expression:** 输出类型错误 ([#8189](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8189)) ([ad02381](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ad02381cfc4643b191caab7e056fd1a93086a45e)), closes [#8188](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8188)\n- **select:** `nzAutoClear` 设置 true 时自动清理输入 ([#8167](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8167)) ([fefcb68](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fefcb68dc9831eb2208746b3fe44346f80f8202f))\n- **tabs:** 修复 `aria` 错误值 ([#8237](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8237)) ([d9a2d27](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d9a2d27be30e9bfc635d8ac3d0e31538f6092b1c))\n- **tooltip:** 修复箭头颜色未更新问题 ([#8192](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8192)) ([bc344ed](https://github.com/NG-ZORRO/ng-zorro-antd/commit/bc344edc3dca8cdf777bf986130eeae5c3543f63))\n\n### Features\n\n- **alert:** 支持 `standalone` ([#8182](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8182)) ([167bed0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/167bed0350400a4a69f727c62237953b71831f26))\n- **anchor:** 支持 `standalone` ([#8185](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8185)) ([03cda21](https://github.com/NG-ZORRO/ng-zorro-antd/commit/03cda216f2d0f1b31e365d6cb30a309309cbc868))\n- **autocomplete:** 支持 `standalone` ([#8193](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8193)) ([548e842](https://github.com/NG-ZORRO/ng-zorro-antd/commit/548e842c00d74fc4f8a8c9b69587bc14fdd9aecf))\n- **avatar:** 支持 `standalone` ([#8194](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8194)) ([4e2cb74](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4e2cb748b1c13ba1176b93f547fda10a188fec95))\n- **back-top:** 支持 `standalone` ([#8195](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8195)) ([db5d5f4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/db5d5f4d02531665e2a88dc114545ab225e61673))\n- **badge:** 支持 `standalone` ([#8201](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8201)) ([3d1427f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3d1427f60f450c9193669a39ef632017fa33c4f6))\n- **breadcrumb:** 支持 `standalone` ([#8202](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8202)) ([165f171](https://github.com/NG-ZORRO/ng-zorro-antd/commit/165f171dd51cff29ac3e02f046bf2966c4ad9aa0))\n- **button:** 支持 `standalone` ([#8275](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8275)) ([3c09507](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3c09507c2c50f67e4f500c4f08a15617ae8e42bc))\n- **calendar:** 支持 `standalone` ([#8274](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8274)) ([80d68a3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/80d68a31d65dd1d5505a1b96f3e02e6ea45e000b))\n- **card:** 支持 `standalone` ([#8273](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8273)) ([0902a4b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0902a4b2b3c3ad0a8bf1740c67bf94194212af7c))\n- **carousel:** 支持 `standalone` ([#8272](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8272)) ([e4244fb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e4244fb7891eed2f21253e922317eae3b8469a3a))\n- **cascader:** 支持 `standalone` ([#8271](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8271)) ([3ab6e5b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3ab6e5bafbb007a5929f347fb81ca83761e4e074))\n- **cdk:** 支持 `standalone` ([#8270](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8270)) ([d66bcba](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d66bcbad09552c3f86401948710d417bb39fd68f))\n- **checkbox:** 支持 `standalone` ([#8269](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8269)) ([1491fb3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1491fb3523ab4cd4b4ff498d37669dd9407e1638))\n- **code-editor:** 支持 `standalone` ([#8268](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8268)) ([24547c6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/24547c61858d0656a71c943a67395cffdfa05881))\n- **collapse:** 支持 `standalone` ([#8267](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8267)) ([dc43fa5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dc43fa5c189d8b6d09f661e52e10e955d873c264))\n- **color-picker:** 禁用 alpha ([#8178](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8178)) ([0bebd6a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0bebd6a696cc29c179758951f706fd276a1dae89))\n- **comment:** 支持 `standalone` ([#8266](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8266)) ([5af11ea](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5af11ea0232c90d74607c9e4a9ffb053d0f0950c))\n- **core:** `no-animation` 支持 `standalone` ([#8257](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8257)) ([de579bc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/de579bca2112bd9691429eee6144c09bb16d3b2b))\n- **core:** 支持 `standalone` ([#8265](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8265)) ([c51e8da](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c51e8daf1ba09646cf7c043756fd14274483c641))\n- **cron-expression:** 支持 `standalone` ([#8264](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8264)) ([ae6ceeb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ae6ceeb560f86ead21d6c9ce9a53f435c52f9944))\n- **date-picker:** 支持 `standalone` ([#8263](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8263)) ([ac48fba](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ac48fba4c6e591db03e41ab427b317c1868f8071))\n- **description:** 支持 `standalone` ([#8262](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8262)) ([128f4c0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/128f4c0055fd1150520509e1fa6bddbc74c65b85))\n- **divider:** 支持 `standalone` ([#8258](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8258)) ([3a7cd50](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3a7cd50e092ad712b66243fa5c2c582f169e658c))\n- **drawer:** 支持 `standalone` ([#8256](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8256)) ([2fbe4c0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2fbe4c0eb221f833fbb0d0801ce546a3c0300555))\n- **dropdown:** 支持 `standalone` [#8254](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8254) ([#8255](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8255)) ([c5df26f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c5df26f2ba94f00d80b66c24bf98b09e5f162081))\n- **empty:** 支持 `standalone` ([#8254](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8254)) ([15636d2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/15636d2c530f294e3b217e4150be70a5f050bccf))\n- **experimental-image:** 支持 `standalone` ([#8253](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8253)) ([7325781](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7325781367998543680af043bd19b911c3ac67e7))\n- **flex:** 新增 `flex` 组件 ([#8145](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8145)) ([f8fedfc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f8fedfc88957a449de2a9960605d3528848f9caa))\n- **form:** 支持 `standalone` ([#8252](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8252)) ([e742e39](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e742e399e2e870f7079f183f800d0d2023b8447d))\n- **graph:** 支持 `standalone` ([#8251](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8251)) ([d2f1d30](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d2f1d30fe7925205b79d7da4462a33a496fd94bf))\n- **grid:** 支持 `standalone` ([#8250](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8250)) ([208652c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/208652c1ffd98ef8ea8e52b69d9376aaafeb390a))\n- **i18n:** 支持 `standalone` ([#8249](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8249)) ([a91cac7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a91cac7e1bbd4379b9498d705a9b6fa1a00e4cd8))\n- **icon:** 支持 `standalone` ([#8248](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8248)) ([b0dbfbc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b0dbfbca5452b54ed7c8c4c0b6d1aa2ae0512a34))\n- **image:** 支持 `standalone` ([#8200](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8200)) ([63b8777](https://github.com/NG-ZORRO/ng-zorro-antd/commit/63b8777645fe93f587e7b09c5ea9d6efbd497b87))\n- **input-number:** 支持 `standalone` ([#8246](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8246)) ([6210fa0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6210fa0b571dd3d0a6b1069bcddd4ad44c3d6104))\n- **input:** 支持 `standalone` ([#8247](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8247)) ([0a7028c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0a7028c27c2018039b771cdfccd8cc0654e2a97a))\n- **layout:** 支持 `standalone` ([#8245](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8245)) ([d21f8a1](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d21f8a10876d222160c5e60d467283562b21f087))\n- **list:** 支持 `standalone` ([#8244](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8244)) ([1f3010f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1f3010fccc0c6bfe8e6b0149152794e3e2371a9a))\n- **mention:** 支持 `standalone` ([#8243](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8243)) ([adc5e94](https://github.com/NG-ZORRO/ng-zorro-antd/commit/adc5e94cdd7dfc75800808a046861bc9943dd548))\n- **menu:** 支持 `standalone` ([#8242](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8242)) ([4673926](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4673926a581b532470062f7cd5672a176638f111))\n- **message:** 支持 `standalone` ([#8241](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8241)) ([c2120b2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c2120b2fad4b1ce30d496c75db27cf08d648ef8c))\n- **modal:** 支持 `standalone` ([#8240](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8240)) ([387d664](https://github.com/NG-ZORRO/ng-zorro-antd/commit/387d66434cad9b117cf3a5f54c75bc2eeab1f69f))\n- **notification:** 支持 `standalone` ([#8236](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8236)) ([686b6b0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/686b6b0d1183a15e69ba59b777d3d3078bacd1af))\n- **page-header:** 支持 `standalone` ([#8235](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8235)) ([aa91486](https://github.com/NG-ZORRO/ng-zorro-antd/commit/aa91486c5ec9ffe26a2aef62800793c909e4349f))\n- **pagination:** 支持 `standalone` ([#8234](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8234)) ([0f1690c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0f1690c89de63bc479653f4d3514a06f5d19a5f7))\n- **pipes:** `css-unit` pipe 支持更多 ([#8260](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8260)) ([5e611e7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5e611e7d51a8cad3697a381612225b0d12879d55))\n- **pipes:** 支持 `standalone` ([#8233](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8233)) ([319381a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/319381a443b7cbb64053d7d30f12d501b0221bcb))\n- **pop-confirm:** 支持 `standalone` ([#8232](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8232)) ([9d656b2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9d656b2c9bde26bf4bb600ad5eff5fa0f3035804))\n- **popover:** 支持 `standalone` ([#8231](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8231)) ([f7468e2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/f7468e212533d21655a7c74ab1efcf320facfc07))\n- **progress:** 支持 `standalone` ([#8230](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8230)) ([7022471](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7022471052e562a72e741abf5e9b9597f6437d2c))\n- **qr-code:** 支持 `standalone` ([#8228](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8228)) ([769f74c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/769f74c9323db91251c191151d48283be64781a8))\n- **radio:** 支持 `standalone` ([#8227](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8227)) ([b62ac64](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b62ac6471b7038db01ebfbb9efd597eae0b8517f))\n- **rate:** 支持 `standalone` ([#8226](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8226)) ([90edba6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/90edba69d11b82c5b31e91af8da34174b71c6fb8))\n- **resizable:** 支持 `standalone` ([#8225](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8225)) ([ff14ed0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ff14ed0e4a5ae6562a71459e407863bd9f84a1ca))\n- **result:** 支持 `standalone` ([#8224](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8224)) ([572965d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/572965d3b61045a01cb8fc14a132a5c0aa8574ec))\n- **segmented:** 支持 `standalone` ([#8223](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8223)) ([86a49d2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/86a49d277b8c8e66bd310d920c43b1e801c2d31c))\n- **select:** 支持 `standalone` ([#8222](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8222)) ([ed0de77](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ed0de779cfe63f1ca68b4b8dedbba40a5ad59e95))\n- **skeleton:** 支持 `standalone` ([#8220](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8220)) ([a2858d3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a2858d3bb10e87e472e4f917176172f283d46352))\n- **slider:** 支持 `standalone` ([#8219](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8219)) ([428c53c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/428c53c6361c5f9afe79ee147a28635c010fea4c))\n- **space:** 支持 `standalone` ([#8218](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8218)) ([a84ddef](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a84ddeff5582426a3dd608cab567245898be60c7))\n- **spin:** 支持 `standalone` ([#8217](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8217)) ([cd23e33](https://github.com/NG-ZORRO/ng-zorro-antd/commit/cd23e3355d1f8828d93a7d3e331f20180ada4bef))\n- **statistics:** 支持 `standalone` ([#8216](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8216)) ([186ef60](https://github.com/NG-ZORRO/ng-zorro-antd/commit/186ef6049cae90e10a2c3f66186cf856f5b9abb2))\n- **steps:** 支持 `standalone` ([#8215](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8215)) ([dbb6fcb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/dbb6fcb952366f200673bcec8e28097844370869))\n- **switch:** 支持 `standalone` ([#8214](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8214)) ([3f6a9ed](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3f6a9ed0a04ba93b97dedcb4b5625d3b79828c32))\n- **table:** 支持 `standalone` ([#8276](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8276)) ([5765ae9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5765ae93f1adf304020697fc84a1984ef54f9a1b))\n- **tab:** 支持 `standalone` ([#8213](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8213)) ([69dd31a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/69dd31ac275f6251b22f7af9aef4ea78fd278adf))\n- **tag:** 支持 `standalone` ([#8212](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8212)) ([15af7c8](https://github.com/NG-ZORRO/ng-zorro-antd/commit/15af7c8956ed4c8f11f637446d0285b5a52339f1))\n- **time-picker:** 支持 `standalone` ([#8211](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8211)) ([641ebb2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/641ebb2d8072fa343c9275222be8c4a23f8fceb4))\n- **timeline:** 支持 `standalone` ([#8210](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8210)) ([b7c6859](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b7c685913abb14133955dfc81678207ec3e64aff))\n- **tooltip:** 支持 `standalone` ([#8209](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8209)) ([125768c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/125768c16f3c5030373058d120c05141208ec42c))\n- **transfer:** 支持 `standalone` ([#8208](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8208)) ([960144e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/960144e5f5a076fe8c7ad56a48ba97e147bc430b))\n- **tree-select:** 支持 `standalone` ([#8206](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8206)) ([64ec76a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/64ec76a2440c7befeaeb8409f84801fd8483af47))\n- **tree-view:** 支持 `standalone` ([#8205](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8205)) ([d4426fc](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d4426fc6675515ddd1db54be84731d1ba44b52b8))\n- **tree:** 支持 `standalone` ([#8207](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8207)) ([b9cf3b0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b9cf3b03d8c51fcfd809dd8d4424aae70ff77094))\n- **typography:** 支持 `standalone` ([#8204](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8204)) ([d7e387f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d7e387fa707f3a8473225187e660459498d97ca2))\n- **upload:** 支持 `standalone` ([#8203](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8203)) ([7cd08ae](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7cd08ae3b6d7ff0e252eb237a60288930f73c15d))\n- **water-mark:** 支持 `standalone` ([#8197](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8197)) ([e4d6082](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e4d608274e0b56acf9b720cf519d757c660c125e)), closes [#8187](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8187)\n\n## 17.0.1\n\n`2023-11-20`\n\n### Bug Fixes\n\n- **schematics:** 修复 schematics 命令问题 ([#8176](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8176)) ([de8a6b7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/de8a6b782d16f906198d6d6ba512059b8dcb463c))\n\n## 17.0.0\n\n`2023-11-19`\n\n### Bug Fixes\n\n- **autocomplete:** 修复内部 `nz-auto-option` 的错误值 ([#7907](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7907)) ([0a312e3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0a312e3203db13cba6e4ebd6dc4c53e3c09ac206))\n- **cron-expression:** 修复报错信息 ([#8114](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8114)) ([ea69790](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ea697909231753e438b2ba07d4ec15c255f3a5dc))\n- **form:** 修复点击 label 聚焦元素错误问题 ([#8135](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8135)) ([b3d135f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b3d135fc512a016430426a36330c0f527234f4e4))\n- **i18n:** 添加 `pl_PL` 语言 ([#7950](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7950)) ([7819426](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7819426f9ff3a110e06aa9cb47e7396edcfc18d7))\n- **i18n:** 更新 `fa_IR` 语言 ([#8143](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8143)) ([4f63198](https://github.com/NG-ZORRO/ng-zorro-antd/commit/4f63198aae7441fe94de64e1740d1f2429a629c1))\n- **i18n:** 更新 `fr/be/ca` 语言 ([#8137](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8137)) ([211db31](https://github.com/NG-ZORRO/ng-zorro-antd/commit/211db31202ea7b099405aecaa5273461bbc26ef4))\n- **mention:** 修复表单内未完全加载问题 ([#8146](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8146)) ([9505c7c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9505c7c4aa222d36e63597b128f01ab0ba3e934a))\n- **resizable:** 修复 pointer capture 问题 ([#8169](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8169)) ([a0b8a0b](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a0b8a0baba0259552a8d0e9eae442daa99027f24))\n- **select:** 性能优化 ([#8159](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8159)) ([7ce50b3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7ce50b3494d01bedbfdd8413dc8ef36ef836e377))\n- **slider:** 修复 step 不可点击问题 ([#7820](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7820)) ([1e1c753](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1e1c753b04e5c01cc61589d16048815ec9f4b9c5))\n- **table:** 优化样式文件 ([#8044](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8044)) ([fde48f9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fde48f9c8a5e934fe32f421d627960dbeb5615ef))\n- **tree-select:** 修复回显顺序问题 ([#8108](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8108)) ([eb4077d](https://github.com/NG-ZORRO/ng-zorro-antd/commit/eb4077df104743fd7ccdc44307c2dc8aa5dbbbca))\n- **tree:** 修复 nzCheckBoxChange 事件未发出问题 ([#8038](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8038)) ([a9dc205](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a9dc2052930b7f6694d5933a86fc3b488b7bd786))\n\n### Features\n\n- **affix:** 支持 `standalone` 用法 ([#8037](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8037)) ([583883c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/583883c0623d640bbea2d04b3a76896d08a68d4c))\n- **hash-code:** 新增 `HashCode` 组件 ([#8111](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8111)) ([0254ee2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0254ee2e673d8ac8cff42a2aef2933367f8b0931))\n- **image:** 支持指定缩放步骤比例 ([#8163](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8163)) ([5aa4db9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5aa4db9f3b429e1f973a75f65cdd8b107586634d))\n- **notification:** 支持自定义 template ([#8046](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8046)) ([9689c42](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9689c4298e57d67eb340140c8924d4743f07bd04))\n- **schematics:** 支持 `standalone` 下 ng-add 命令 ([#8095](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8095)) ([c1b61f7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/c1b61f720199ebfba0f48834b2ceaf93fed148d1))\n- **slider:** `nzTipFormatter` 支持 Template 类型 ([#7505](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7505)) ([7c79ab3](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7c79ab37a8c0b4bc47bf1873c167417f316c94a9))\n- **table:** 添加 `nzLabel` 以在复选框中包含 `aria-label` ([#7903](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7903)) ([5834e46](https://github.com/NG-ZORRO/ng-zorro-antd/commit/5834e469291ee2a6975e4b74015468d7c1d739d2))\n- **table:** 支持自定义展开图标 ([#7886](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7886)) ([1507ed0](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1507ed0e2c1e869bd45925f2335ff1c4a3570430))\n- **tooltip,popover,popconfirm:** 暴露 `cdkConnectedOverlayPush` 配置 ([#8166](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8166)) ([a821c62](https://github.com/NG-ZORRO/ng-zorro-antd/commit/a821c62c5a438ff24282230376b18cd0bfdbfc19))\n\n## 16.2.2\n\n`2023-10-23`\n\n### Bug Fixes\n\n- 内置 `cdk-overlay` 样式 ([#8132](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8132)) ([3209d74](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3209d744187133e518f564bfe5a2f56ac371fc22))\n- **cascader:** 兼容 rxjs v6 ([#8133](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8133)) ([54a5c76](https://github.com/NG-ZORRO/ng-zorro-antd/commit/54a5c769a061bc07e342c1f462bf27c422df44a3))\n- **drawer:** `drawer` 不能打开 ([#8120](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8120)) ([24d0664](https://github.com/NG-ZORRO/ng-zorro-antd/commit/24d06640a623f3ea2fd9fa459c729a103938d7fc))\n\n## 16.2.1\n\n`2023-10-19`\n\n### Bug Fixes\n\n- `@angular/cdk/overlay-prebuilt.css` 样式报错 ([#8122](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8122)) ([42da190](https://github.com/NG-ZORRO/ng-zorro-antd/commit/42da1905a74b5a2049c045cef90d3c5cd595b8a3))\n- **color-picker:** 优化 `demo` 展示 ([#8088](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8088)) ([6d03099](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d03099e40364b85276db4c0163bae32c62bad73))\n- **menu:** menu title 溢出省略 ([#8055](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8055)) ([0674f78](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0674f785213ad914ad58fddc42e3083ff750f102))\n- **tree-select:** 修复节点为禁用状态时，back快捷键能删除bug ([#8105](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8105)) ([07a1f5e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/07a1f5e41d82ac59c9de744a3528c23e2b871624))\n\n### Features\n\n- **select:** 支持自定义 `nz-option-item` 的 `attr.title` ([#8097](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8097)) ([2ee261a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2ee261ac24f7ea0501d07ad35fcdb435714ffe9b))\n\n## 16.2.0\n\n`2023-09-18`\n\n### Bug Fixes\n\n- **list:** 修复同步操作项不显示在项目中的问题 ([#7958](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7958)) ([3b6bdec](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3b6bdecef32ee4d9bb14491b617870733cfd9553))\n- **tree:** 修复 `nzBeforeDrop` 拖拽样式不消失问题 ([#8015](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8015)) ([2d0b3f7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2d0b3f71490e38f8512285f81fcf3baa8f6eb4db))\n- **button:** 添加 `ant-btn-icon-only` class ([#7631](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7631)) ([#7678](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7678)) ([7470ed6](https://github.com/NG-ZORRO/ng-zorro-antd/commit/7470ed66e1651d753fa43e197a4ab0d548744885))\n- **cascader:** 修复自定义已选项后会出现 title undefined 问题 ([#8011](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8011)) ([10003db](https://github.com/NG-ZORRO/ng-zorro-antd/commit/10003db77b9bda21772733c41b3c503ee85d5c81)), closes [#8006](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8006)\n- **core:** 修复 CSP 问题 ([#8059](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8059)) ([295b333](https://github.com/NG-ZORRO/ng-zorro-antd/commit/295b333774990a420c39ba67912598dafd2f1842))\n- **cron-expression:** 清除 console 警告 ([#7926](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7926)) ([b358345](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b358345c14746501e47d7e73dffe41d32b9ab118))\n- **date-picker:** 更新代码注释 ([#7991](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7991)) ([8b6b653](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8b6b653547d92a27079c27b3ef7e68df68a4f5fd))\n- **i18n:** 更新国际化文案 ([#7901](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7901)) ([9bfce45](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9bfce45a37a9c50aafbcaf96a8db9450bc2c5bf1))\n- **message:** 关闭后清理 DOM ([#7965](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7965)) ([71ead99](https://github.com/NG-ZORRO/ng-zorro-antd/commit/71ead99aa781e50f3c896107f5b668b9a2cea767)), closes [#7772](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7772)\n- **message:** 修复 `overlay` 的 `z-index` ([#8081](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8081)) ([b1d2095](https://github.com/NG-ZORRO/ng-zorro-antd/commit/b1d20953eda23c9dcb4f74530621cf9cf1a33e45))\n- **notification:** 更新操作不创建新的 `messageId` ([#8000](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8000)) ([e240264](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e240264796dfd3a8692efcb92178688b78d0b69f))\n- **qrcode:** 优化 demo 样式 ([#8020](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8020)) ([078aaf9](https://github.com/NG-ZORRO/ng-zorro-antd/commit/078aaf91335d2d9fa085d06a792ddd49c17948e0))\n- **table:** 自定义列移除空格 ([#8022](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8022)) ([15e244c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/15e244cc954cab1186d33006c7915f34d92e4d6d))\n- **time-picker:** 修复 `modelChange` 触发两次问题 ([#7902](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7902)) ([74c13a4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/74c13a49f92a263a05a34af63f6a2b71a554078e))\n- **tree-view:** 修复重复渲染问题 ([#8035](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8035)) ([68cb4b2](https://github.com/NG-ZORRO/ng-zorro-antd/commit/68cb4b2d25d3bc149e4f8e80c030a16db75959c2))\n- **tree:** 移除 console ([#8019](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8019)) ([fa0312a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/fa0312a4c68b26902ca28ed974754599b17b2d8a))\n- **watermark:** 修复重绘问题 ([#8012](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8012)) ([030318e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/030318e82725d7650c98bf0ec06d2b23df16d9f0))\n- **showcase:** 修复 `rtl` 模式的样式问题 ([#8063](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8063)) ([d57b7da](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d57b7dac5817cb1de9de9edda2343a6089854fff))\n\n### Features\n\n- **core:** 支持 `provide` 使用方式 ([#7952](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7952)) ([150c6ca](https://github.com/NG-ZORRO/ng-zorro-antd/commit/150c6cab4636fa9daa1e892d27b894c6b7381b35))\n- **cascader:** 支持 `observable` 加载数据 ([#8048](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8048)) ([1436f21](https://github.com/NG-ZORRO/ng-zorro-antd/commit/1436f212130041bec03d6f2d2d7f5591dff04b7a))\n- **color-picker:** 支持颜色选择器组件 ([#8013](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8013)) ([8439704](https://github.com/NG-ZORRO/ng-zorro-antd/commit/843970459fdb18dfa0ddc861d02e6c21e87c12b4))\n- **cron-expression:** 新增单元测试 ([#7993](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7993)) ([605e969](https://github.com/NG-ZORRO/ng-zorro-antd/commit/605e969013cf48a29f4786765cf6c6da9f10643a))\n- **cron-expression:** 支持 `nzDisabled` && `nzBorderless` 属性 ([#7992](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7992)) ([6d31bde](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d31bde3ef1f43cc145d2009afcf90931e96a731))\n- **dropdown:** close context menu on escape ([#7915](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7915)) ([6d0032e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d0032ededc140a017c01158ae76402a86c7b334))\n- **dropdown:** 优化 `NzContextMenuService#create()` ([#7768](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7768)) ([9b3e6cb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9b3e6cba852d4a782d15311c910b747a3bbc4d02))\n- **form:** 支持 `label wrap` ([#7892](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7892)) ([37391de](https://github.com/NG-ZORRO/ng-zorro-antd/commit/37391de29afdd3126dbbdcae6ca3ba2e637fd596))\n- **input:** `number` 类型支持隐藏步骤 ([#8003](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8003)) ([0f3aed5](https://github.com/NG-ZORRO/ng-zorro-antd/commit/0f3aed599874e0d1c2786f2d14fec52128afbec8))\n- **modal:** 移除 `nzComponentParams` 过期属性 ([#7930](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7930)) ([baab16c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/baab16c497902f0cbf2668fb061ac8d40ffd18b2))\n- **qrcode:** 支持新特性 ([#8001](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8001)) ([718ba29](https://github.com/NG-ZORRO/ng-zorro-antd/commit/718ba2943c7c7e12c8526e52e8806955d3fb0504))\n- **resizable:** `NzResizeEvent` 暴露 `direction` ([#7987](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7987)) ([4143473](https://github.com/NG-ZORRO/ng-zorro-antd/commit/41434734ffe839f3ed71bd19486a5f76adc20463))\n- **resizable:** 支持更多鼠标类型 ([#8042](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8042)) ([e564714](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e56471423142d71ce9117707f7240c83f6fe44e5))\n- **table:** 支持自定义展示列 ([#7966](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7966)) ([d26870f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d26870f9ffd3f5122e95246a24587c739b04fd8a))\n\n### Performance Improvements\n\n- **select:** 支持传递 `nzKey` ([#8033](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8033)) ([e94da4e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e94da4eddd663a1e7a5e9e6e0781f1a6da59f1c7))\n- **select:** 移除不必要的类型 ([#7850](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7850)) ([71c2138](https://github.com/NG-ZORRO/ng-zorro-antd/commit/71c2138ce28e07539784d8fb228adf122ed13a33))\n- **tabs:** 添加 `.ant-tabs-tab` 样式以减少 css 计算消耗 ([#7935](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7935)) ([#7936](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7936)) ([198644a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/198644a09ac828c4e9b208799c8be1a57cd8ce86))\n\n## 16.1.0\n\n`2023-07-16`\n\n### Bug Fixes\n\n- **list:** 修复异步节点未正确展示问题 ([#7958](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7958)) ([3b6bdec](https://github.com/NG-ZORRO/ng-zorro-antd/commit/3b6bdecef32ee4d9bb14491b617870733cfd9553))\n- **tree:** 修复拖拽节点样式未正确取消问题 ([#8015](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8015)) ([2d0b3f7](https://github.com/NG-ZORRO/ng-zorro-antd/commit/2d0b3f71490e38f8512285f81fcf3baa8f6eb4db))\n- **cascader:** 修复自定义项导致 title undefined 问题 ([#8011](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8011)) ([10003db](https://github.com/NG-ZORRO/ng-zorro-antd/commit/10003db77b9bda21772733c41b3c503ee85d5c81)), closes [#8006](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8006)\n- **date-picker:** 更新代码注释 ([#7991](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7991)) ([8b6b653](https://github.com/NG-ZORRO/ng-zorro-antd/commit/8b6b653547d92a27079c27b3ef7e68df68a4f5fd))\n- **i18n:** 更新繁体文案 ([#7901](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7901)) ([9bfce45](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9bfce45a37a9c50aafbcaf96a8db9450bc2c5bf1))\n- **notification:** 更新组件不创建新的 messageId ([#8000](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8000)) ([e240264](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e240264796dfd3a8692efcb92178688b78d0b69f))\n- **time-picker:** 修复 modelChange 触发多次问题 ([#7902](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7902)) ([74c13a4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/74c13a49f92a263a05a34af63f6a2b71a554078e))\n- **watermark:** 修复水印组件重绘问题 ([#8012](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8012)) ([030318e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/030318e82725d7650c98bf0ec06d2b23df16d9f0))\n\n### Features\n\n- **cron-expression:** 新增单元测试 ([#7993](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7993)) ([605e969](https://github.com/NG-ZORRO/ng-zorro-antd/commit/605e969013cf48a29f4786765cf6c6da9f10643a))\n- **cron-expression:** 支持 `nzDisabled` && `nzBorderless` 属性 ([#7992](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7992)) ([6d31bde](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d31bde3ef1f43cc145d2009afcf90931e96a731))\n- **dropdown:** 支持 ESC 退出 ([#7915](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7915)) ([6d0032e](https://github.com/NG-ZORRO/ng-zorro-antd/commit/6d0032ededc140a017c01158ae76402a86c7b334))\n- **dropdown:** create 返回 `EmbeddedViewRef` 对象 ([#7768](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7768)) ([9b3e6cb](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9b3e6cba852d4a782d15311c910b747a3bbc4d02))\n- **form:** 支持 `nzLabelWrap` 属性控制换行 ([#7892](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7892)) ([37391de](https://github.com/NG-ZORRO/ng-zorro-antd/commit/37391de29afdd3126dbbdcae6ca3ba2e637fd596))\n- **modal:** 移除废弃属性 `nzComponentParams` ([#7930](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7930)) ([baab16c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/baab16c497902f0cbf2668fb061ac8d40ffd18b2))\n- **qrcode:** 支持 `nzBgColor` & `nzPadding` 优化另存为图片效果 ([#8001](https://github.com/NG-ZORRO/ng-zorro-antd/issues/8001)) ([718ba29](https://github.com/NG-ZORRO/ng-zorro-antd/commit/718ba2943c7c7e12c8526e52e8806955d3fb0504))\n- **resizable:** `NzResizeEvent` 支持 `NzResizeDirection` 属性 ([#7987](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7987)) ([4143473](https://github.com/NG-ZORRO/ng-zorro-antd/commit/41434734ffe839f3ed71bd19486a5f76adc20463))\n- **table:** 支持自定义展示列 ([#7966](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7966)) ([d26870f](https://github.com/NG-ZORRO/ng-zorro-antd/commit/d26870f9ffd3f5122e95246a24587c739b04fd8a))\n\n### Performance Improvements\n\n- **select:** 移除多余的方法参数类型 ([#7850](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7850)) ([71c2138](https://github.com/NG-ZORRO/ng-zorro-antd/commit/71c2138ce28e07539784d8fb228adf122ed13a33))\n- **tabs:** 优化 css 渲染性能 ([#7935](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7935)) ([#7936](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7936)) ([198644a](https://github.com/NG-ZORRO/ng-zorro-antd/commit/198644a09ac828c4e9b208799c8be1a57cd8ce86))\n\n## 16.0.0\n\n`2023-05-31`\n\n### Bug Fixes\n\n- **date-picker:** 修复 `ng-untouched` 问题 ([#7922](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7922)) ([9ebcf72](https://github.com/NG-ZORRO/ng-zorro-antd/commit/9ebcf72bde75b735c0798bc66bb62226b7f29536))\n- **date-picker:** 修复跨年选择周期显示不正确问题 ([#7923](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7923)) ([e7f9538](https://github.com/NG-ZORRO/ng-zorro-antd/commit/e7f953822133ce31d2523a48766dfe6572f95430))\n- **datepicker:** 修复 `ngModel` 未更新问题 ([#7948](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7948)) ([100796c](https://github.com/NG-ZORRO/ng-zorro-antd/commit/100796c74cd75de9cebbf89cb58f4bf3cc58b746))\n- **slider:** 修复首个禁用失效问题 ([#7947](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7947)) ([ad2faf4](https://github.com/NG-ZORRO/ng-zorro-antd/commit/ad2faf4c67cb6e7bc1b12646d0ceb9153a59d75c)), closes [#7943](https://github.com/NG-ZORRO/ng-zorro-antd/issues/7943)\n\n## 历史版本\n\n历史版本的更新记录可以在 [Github](https://github.com/NG-ZORRO/ng-zorro-antd/releases) 查看。\n"
  },
  {
    "path": "docs/contributing.en-US.md",
    "content": "---\norder: 12\ntitle: How to Contribute\n---\n\nThe following is a set of guidelines about making contributions to NG-ZORRO. Please spend several minutes in reading these guidelines before submitting an issue or pull request.\n\n## Code of Conduct\n\nWe have adopted a [Code of Conduct](https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/CODE_OF_CONDUCT.md) that we expect every contributor to adhere to. Please look through each section carefully so that you can understand what actions will and will not be allowed.\n\n## Open Development\n\nAll work on NG-ZORRO happens directly on [GitHub](https://github.com/NG-ZORRO/ng-zorro-antd). Both core team members and external contributors go through the same reviewing process in order to submit a pull request.\n\n## Bugs\n\nWe are using [GitHub Issues](https://github.com/NG-ZORRO/ng-zorro-antd/issues) for bug tracing. The best way to get your bug fixed is using our [issue helper](https://ng.ant.design/issue-helper/#/en) and provide a reproduction following this [template](https://stackblitz.com/edit/ng-zorro-antd-ivy).\n\nBefore reporting a new bug, please make sure you have filtered existing issues, and read our [FAQ](docs/faq/en).\n\n## Propose a Change\n\nIf you intend to change a public API or introduce a new feature, we also recommend you to use our [issue helper](https://ng.ant.design/issue-helper/#/en) to submit a feature request issue.\n\n## Your First Pull Request\n\nPlease use the following resources for your first pull request:\n\n- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)\n- [First Contributions](https://github.com/firstcontributions/first-contributions)\n\nTo help you get your feet wet and get familiar with our contribution process, we have a list of [Good First Issue](https://github.com/NG-ZORRO/ng-zorro-antd/labels/good%20first%20issue) that contain either bugs that are relatively easy to be fixed or small features. These issues are considered as great starting points.\n\nIf you decide to handle an issue, please be sure to check the comment thread in case someone else has already been working on it. If nobody is working on it at the moment, please leave a comment stating that you intend to work on it, preventing others from doing duplicate work.\n\nIf somebody claimed an issue without any follow up for more than two weeks, it should be fine to take over it. Nevertheless, be sure to leave a comment under such issues.\n\n## Contribute\n\nThe core team is monitoring all pull requests. Your pull request will be either successfully merged, requested for a change, or closed with a reasonable explanation.\n\n**Before submitting a pull request**, please make sure to follow the steps below:\n\n1. Run `npm install` in the repository root.\n2. If you have fixed a bug or added a feature that should be tested, please add test cases!\n3. Make sure the test suite passes (`npm run test`).\n4. Make sure your code lints (`npm run lint`).\n5. Make sure rebase your code to keep the history clean.\n6. Make sure your commit message meet the requirements of [guidelines](https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/CONTRIBUTING.md#-commit-message-guidelines)\n\n## How to Submit a Pull Request\n\n1. Fork the repository of `ng-zorro-antd`. The later steps must be done on the forked repository\n2. On `master`: `git remote add upstream https://github.com/NG-ZORRO/ng-zorro-antd.git`\n3. On `master`: `git pull upstream master`\n4. On `master`: `git push origin master`\n5. Checkout to the feature branch (for example, if the branch is called `docs-fix`): `git checkout docs-fix`\n6. On `docs-fix` rebase on master: `git rebase origin/master`\n7. On `docs-fix` resolve codes and commit: `git commit -a`, you need to follow the [commit message guidelines](https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/CONTRIBUTING.md#-commit-message-guidelines)\n8. Then, push up: `git push` (might need `-f`, just be sure you understand force pushing before you do it)\n9. Submit a Pull Request on the Github\n\n## Development Workflow\n\nAfter cloning `ng-zorro-antd` and running `npm install` to install its dependencies, you can also run the following commands:\n\n- `npm start` runs NG-ZORRO website locally.\n- `npm run lint` checks the code style.\n- `npm test` runs the complete test suite.\n- `npm run test:watch [name]` run some test files and monitor changes.\n- `npm run build:lib` creates a build of `ng-zorro-antd` under `publish` directory.\n\nIf you encounter problems while developing `ng-zorro-antd`, please refer to our [development guide](https://github.com/NG-ZORRO/ng-zorro-antd/wiki/Development-Guide) on the GitHub.\n"
  },
  {
    "path": "docs/contributing.zh-CN.md",
    "content": "---\norder: 12\ntitle: 贡献指南\n---\n\n这篇指南会指导你如何为 NG-ZORRO 贡献一份自己的力量，请在你要提 issue 或者 pull request 之前花几分钟来阅读一遍这篇指南。\n\n## 行为准则\n\n我们有一份 [行为准则](https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/CODE_OF_CONDUCT.md)，希望所有的贡献者都能遵守，请花时间阅读一遍全文以确保你能明白哪些是可以做的，哪些是不可以做的。\n\n## 透明的开发\n\n我们所有的工作都会放在 [GitHub](https://github.com/NG-ZORRO/ng-zorro-antd) 上。不管是核心团队的成员还是外部贡献者的 pull request 都需要经过同样流程的 review。\n\n## Bugs\n\n我们使用 [GitHub Issues](https://github.com/NG-ZORRO/ng-zorro-antd/issues) 来做 bug 追踪。 如果你想要你发现的 bug 被快速解决，最好的办法就是通过我们提供的 [issue 小助手](https://ng.ant.design/issue-helper/#/zh) 来提 issue。 并且能使用这个 [模板](https://stackblitz.com/edit/ng-zorro-antd-ivy) 来提供重现。\n\n在你报告一个 bug 之前，请先确保已经搜索过已有的 issue 和阅读了我们的 [常见问题](docs/faq/zh)。\n\n## 新增功能\n\n如果你有改进我们的 API 或者新增功能的想法，我们同样推荐你使用我们提供的 [issue 小助手](https://ng.ant.design/issue-helper/#/zh) 来新建一个添加新功能的 issue。\n\n## 第一次贡献\n\n如果你还不清楚怎么在 GitHub 上提 Pull Request ，可以阅读下面这些文章来学习：\n\n- [如何为开源做贡献](https://opensource.guide/zh-cn/how-to-contribute/)\n- [第一次参与开源](https://github.com/firstcontributions/first-contributions/blob/master/translations/README.chs.md)\n\n为了能帮助你开始你的第一次尝试，我们用 [Good First Issue](https://github.com/NG-ZORRO/ng-zorro-antd/labels/good%20first%20issue) 标记了一些比较比较容易修复的 bug 和小功能。这些 issue 可以很好地做为你的首次尝试。\n\n如果你打算开始处理一个 issue，请先检查一下 issue 下面的留言以确保没有别人正在处理这个 issue。如果当前没有人在处理的话你可以留言告知其他人你将会处理这个 issue，以免别人重复劳动。\n\n如果之前有人留言说会处理这个 issue 但是一两个星期都没有动静，那么你也可以接手处理这个 issue，当然还是需要留言告知其他人。\n\n## 贡献代码\n\nNG ZORRO 团队会关注所有的 Pull Request，我们会 review 以及合并你的代码，也有可能要求你做一些修改或者告诉你我们为什么不能接受这样的修改。\n\n**在你发送 Pull Request 之前**，请确认你是按照下面的步骤来做的：\n\n1. 在项目根目录下运行了 `npm install`。\n2. 如果你修复了一个 bug 或者新增了一个功能，请确保写了相应的测试，这很重要。\n3. 确认所有的测试都是通过的 `npm run test`。\n4. 确保你的代码通过了 lint 检查 `npm run lint`。\n5. 确保你的代码在提交之前经过了正确的 [Rebase](https://www.digitalocean.com/community/tutorials/how-to-rebase-and-update-a-pull-request)。\n6. 确保你的提交信息符合[我们的 commit 规范](https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/CONTRIBUTING.md#-commit-message-guidelines)。\n\n## 如何提出 Pull Request\n\n1. fork `ng-zorro-antd` 仓库，以下所有操作均在 fork 之后的仓库上执行\n2. 在 `master` 分支运行：`git remote add upstream https://github.com/NG-ZORRO/ng-zorro-antd.git`\n3. 在 `master` 分支运行: `git pull upstream master`\n4. 在 `master` 分支运行: `git push origin master`\n5. 切换到你要工作的 feature 分支 (例如有一个分支叫 `docs-fix`): `git checkout docs-fix`\n6. 在 `docs-fix` 分支运行: `git rebase origin/master`\n7. 在 `docs-fix` 分支修改代码，并 commit: `git commit -a`，按照我们 [commit 规范](https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/CONTRIBUTING.md#-commit-message-guidelines)进行填写。\n8. 推送代码 `git push` (可能需要 `-f`)\n9. 在 Github 上发起 Pull Request 请求\n\n## 开发流程\n\n在你 clone 了 `ng-zorro-antd` 的代码并且使用 `npm install` 安装完依赖后，你还可以运行下面几个常用的命令：\n\n- `npm start` 在本地运行 `NG-ZORRO` 的网站。\n- `npm run lint` 检查代码风格。\n- `npm test` 运行测试。\n- `npm run test:watch [name]` 运行某文件测试，并监视变化。\n- `npm run build:lib` 构建 `ng-zorro-antd` 到 `publish` 目录。\n\n如果在开发过程中遇到问题，可查看 GitHub 上的[开发指南](https://github.com/NG-ZORRO/ng-zorro-antd/wiki/%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97)。\n"
  },
  {
    "path": "docs/customize-theme-variable.en-US.md",
    "content": "---\norder: 6.1\ntitle: Dynamic Theme (Experimental)\n---\n\nExcept [less customize theme](/docs/customize-theme/en), We also provide CSS Variable version to enable dynamic theme.\n\n> This feature depends on CSS Variables. Please check the [browser compatibility](https://caniuse.com/css-variables).\n\n## How to use\n\n### Import antd.variable.min.css\n\nReplace your import style file with CSS Variable version:\n\n```diff\n- @import \"~ng-zorro-antd/ng-zorro-antd.min.css\";\n+ @import \"~ng-zorro-antd/ng-zorro-antd.variable.min.css\";\n```\n\nNote: You need remove `babel-plugin-import` for the dynamic theme.\n\n### Static config\n\nIn order to provide default configurations in certain components, please pass an object that implements the interface `NzConfig` through the injection token `NZ_CONFIG` in the root injector. For example:\n\n```typescript\nimport { NzConfig, provideNzConfig } from 'ng-zorro-antd/core/config';\n\nconst ngZorroConfig: NzConfig = {\n  theme: {\n    primaryColor: '#1890ff'\n  }\n};\n\nexport const appConfig: ApplicationConfig = {\n  providers: [provideNzConfig(ngZorroConfig)]\n};\n```\n\nThese global configurations would be injected and stored in a service named `NzConfigService`.\n\n### Dynamically Change Configurations\n\nYou can alter the global configuration of CSS Variable through the `set` method of `NzConfigService`. For example:\n\n```typescript\nimport { NzConfigService } from 'ng-zorro-antd/core/config';\n\n@Component({\n  selector: 'app-change-zorro-config'\n})\nexport class ChangeZorroConfigComponent {\n  private nzConfigService = inject(NzConfigService);\n\n  onChangeConfig() {\n    this.nzConfigService.set('theme', { primaryColor: '#1890ff' });\n  }\n}\n```\n\nAll component instances is responsive to this configuration change (as long as they are not configured independently).\n\n## Conflict resolve\n\nCSS Variable use `--ant` prefix by default. When exist multiple antd style file in your project, you can modify prefix to fix it.\n\n### Compile less\n\nSince prefix modified. Origin `antd.variable.css` should also be replaced:\n\n```bash\nlessc --js --modify-var=\"ant-prefix=custom\" antd/dist/antd.variable.less modified.css\n```\n\n### Related changes\n\nIn order to implement CSS Variable and maintain original usage compatibility, we added `@root-entry-name: xxx;` entry injection to the `ng-zorro-antd.xxx.less` file to support less dynamic loading of the corresponding less file. Under normal circumstances, you do not need to pay attention to this change.\n"
  },
  {
    "path": "docs/customize-theme-variable.zh-CN.md",
    "content": "---\norder: 6.1\ntitle: 动态主题（实验性）\n---\n\n除了 [less 定制主题](/docs/customize-theme/zh) 外，我们还提供了 CSS Variable 版本以支持动态切换主题能力。\n\n> 该功能通过动态修改 CSS Variable 实现，在 IE 中页面将无法正常展示\n\n## 如何使用\n\n### 引入 ng-zorro-antd.variable.min.css\n\n替换当前项目引入样式文件为 CSS Variable 版本：\n\n```diff\n- @import \"~ng-zorro-antd/ng-zorro-antd.min.css\";\n+ @import \"~ng-zorro-antd/ng-zorro-antd.variable.min.css\";\n```\n\n注：如果你使用了 `babel-plugin-import`，需要将其去除。\n\n### 静态方法配置\n\n利用全局配置项功能，在根注入器中根据注入令牌 `NZ_CONFIG` 提供一个符合 `NzConfig` 接口的对象，例如：\n\n```typescript\nimport { NzConfig, provideNzConfig } from 'ng-zorro-antd/core/config';\n\nconst ngZorroConfig: NzConfig = {\n  // 注意组件名称没有 nz 前缀\n  theme: {\n    primaryColor: '#1890ff'\n  }\n};\n\nexport const appConfig: ApplicationConfig = {\n  providers: [provideNzConfig(ngZorroConfig)]\n};\n```\n\n这些全局配置项将会被注入 `NzConfigService` 当中并保存。\n\n### 动态变更\n\n你可以通过调用 `NzConfigService` 的 `set` 方法来改变 CSS Variable 样式配置项，例如：\n\n```typescript\nimport { NzConfigService } from 'ng-zorro-antd/core/config';\n\n@Component({\n  selector: 'app-change-zorro-config'\n})\nexport class ChangeZorroConfigComponent {\n  private nzConfigService = inject(NzConfigService);\n\n  onChangeConfig() {\n    this.nzConfigService.set('theme', { primaryColor: '#1890ff' });\n  }\n}\n```\n\n所有的组件实例都会响应这些改变（只要它们没有被单独赋值）。\n\n## 冲突解决\n\n默认情况下，CSS Variable 会以 `--ant` 作为前缀。当你的项目中引用多份 css 文件时，可以通过修改前缀的方式避免冲突。\n\n### 编译 less\n\n由于前缀变更，你需要重新生成一份对应的 css 文件。\n\n```bash\nlessc --js --modify-var=\"ant-prefix=custom\" ng-zorro-antd/ng-zorro-antd.variable.less modified.css\n```\n\n### 相关变更\n\n为了实现 CSS Variable 并保持原始用法兼容性，我们于 `ng-zorro-antd.xxx.less` 文件中添加了 `@root-entry-name: xxx;` 入口注入以支持 less 动态加载对应的 less 文件。一般情况下，你不需要关注该变化。\n"
  },
  {
    "path": "docs/customize-theme.en-US.md",
    "content": "---\norder: 6\ntitle: Theme Customization\n---\n\nAnt Design allows you to customize some basic design aspects in order to meet the needs of UI diversity from business and brand, including primary color, border radius, border color, etc.\n\n![Example](https://zos.alipayobjects.com/rmsportal/zTFoszBtDODhXfLAazfSpYbSLSEeytoG.png)\n\nWe are using [Less](https://lesscss.org/) as the development language for styling. A set of Less variables are defined for each design aspect that can be customized to your needs.\n\n> You can use the theme define file of react version in ng-zorro-antd too.\n\n## Use Pre-defined Themes\n\n### Customize the theme\n\n1. Configure with schematics. Run `ng add ng-zorro-antd`, choose not to set up custom theme file and your `angular.json` will be configured automatically:\n\n```json\n{\n  \"build\": {\n    \"options\": {\n      \"styles\": [\"./node_modules/ng-zorro-antd/ng-zorro-antd.min.css\"]\n    }\n  }\n}\n```\n\nYou can also add this config manually in `angular.json`.\n\n### Official Themes\n\nBesides the default theme, we have provided 3 more official themes. Please try them out and give us feedbacks.\n\n- 🌑 Dark Theme\n- 📦 Compact Theme\n- ☁️ Aliyun Theme\n\n#### Method 1: Less\n\nImport `ng-zorro-antd.less`, `ng-zorro-antd.dark.less`, `ng-zorro-antd.compact.less` or `ng-zorro-antd.aliyun.less` in the style file and override style variables.\n\n```less\n// Import the official default less style file\n@import '~ng-zorro-antd/ng-zorro-antd.less';\n\n// Import the official dark less style file\n//@import \"~ng-zorro-antd/ng-zorro-antd.dark.less\";\n\n// Import the official compact less style file\n//@import \"~ng-zorro-antd/ng-zorro-antd.compact.less\";\n\n// Import the official Aliyun less style file\n//@import \"~ng-zorro-antd/ng-zorro-antd.aliyun.less\";\n```\n\n#### Method 2: CSS\n\nIf the project does not use Less, you can include `ng-zorro-antd.css`, `ng-zorro-antd.dark.css`, `ng-zorro-antd.compact.css` or `ng-zorro-antd.aliyun.css` in the CSS file or add to the `angular.json` config.\n\nCSS file:\n\n```css\n@import '~ng-zorro-antd/ng-zorro-antd.css';\n/*@import \"~ng-zorro-antd/ng-zorro-antd.dark.css\";*/\n/*@import \"~ng-zorro-antd/ng-zorro-antd.compact.css\";*/\n/*@import \"~ng-zorro-antd/ng-zorro-antd.aliyun.css\";*/\n```\n\nIn `angular.json`:\n\n```json\n{\n  \"build\": {\n    \"options\": {\n      \"styles\": [\"node_modules/ng-zorro-antd/ng-zorro-antd.css\"]\n    }\n  }\n}\n```\n\n## Customize Pre-defined Theme\n\n### Method 1: Override style variables in Less\n\n#### Import pre-defined theme file\n\nImport pre-defined theme file in the `src/styles.less` (or run `ng add ng-zorro-antd`, choose to set up custom theme automatically):\n\n```less\n// Custom Theming for NG-ZORRO\n// For more information: https://ng.ant.design/docs/customize-theme/en\n@import \"../node_modules/ng-zorro-antd/ng-zorro-antd.less\";\n...\n```\n\n#### Customize style variables\n\nAfter importing the theme file, override the values of theme style variables based on the project requirements. For example, the demo below illustrates how we can override the `ng-zorro-antd` default theme's `@primary-color` to `#f5222d`:\n\n```less\n// -------- import official less file -----------\n@import '../node_modules/ng-zorro-antd/ng-zorro-antd.less';\n\n// -------- override less variables -----------\n@primary-color: #f5222d;\n```\n\n### Method 2: Override theme variables in webpack\n\n#### Override by pre-defined theme variables\n\nUsing less-loader in webpack if needed:\n\n```javascript\nconst darkThemeVars = require('ng-zorro-antd/dark-theme');\nconst compactThemeVars = require('ng-zorro-antd/compact-theme');\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.less$/,\n        loader: 'less-loader',\n        options: {\n          modifyVars: {\n            hack: `true;@import \"${require.resolve('ng-zorro-antd/style/color/colorPalette.less')}\";`,\n            ...darkThemeVars,\n            ...compactThemeVars\n          },\n          javascriptEnabled: true\n        }\n      }\n    ]\n  }\n};\n```\n\n#### Override by customized style variables\n\nAngular CLI provide [custom-webpack-builder](https://www.npmjs.com/package/@angular-builders/custom-webpack), you can modify the less variable via adjusting the [less-loader](https://github.com/webpack-contrib/less-loader) options in webpack.\n\n1. Import `ng-zorro-antd.less` in `angular.json`\n\n   ```json\n   {\n     \"styles\": [\"node_modules/ng-zorro-antd/ng-zorro-antd.less\"]\n   }\n   ```\n\n2. Install `@angular-builders/custom-webpack` builder\n\n   ```bash\n   npm i -D @angular-builders/custom-webpack\n   ```\n\n3. create `extra-webpack.config.js`\n\n   ```javascript\n   module.exports = {\n     module: {\n       rules: [\n         {\n           test: /\\.less$/,\n           loader: 'less-loader',\n           options: {\n             modifyVars: {\n               // modify theme variable\n               'primary-color': '#1DA57A',\n               'link-color': '#1DA57A',\n               'border-radius-base': '2px'\n             },\n             javascriptEnabled: true\n           }\n         }\n       ]\n     }\n   };\n   ```\n\n4. Customize builder in `angular.json`\n\n   ```diff\n     \"architect\": {\n       \"build\": {\n   -     \"builder\": \"@angular-devkit/build-angular:browser\",\n   +     \"builder\": \"@angular-builders/custom-webpack:browser\",\n         \"options\": {\n   +        \"customWebpackConfig\": {\n   +          \"path\": \"./extra-webpack.config.js\",\n   +          \"mergeStrategies\": {\n   +            \"module.rules\": \"append\"\n   +          },\n   +          \"replaceDuplicatePlugins\": true\n   +        }\n         },\n       },\n       \"serve\": {\n   -      \"builder\": \"@angular-devkit/build-angular:dev-server\",\n   +      \"builder\": \"@angular-builders/custom-webpack:dev-server\",\n       }\n     }\n   ```\n\nYou can get more information about custom-webpack builder following the articles\n\n- [Angular Builder Document](https://www.npmjs.com/package/@angular-builders/custom-webpack)\n- [Angular CLI: Custom webpack Config](https://alligator.io/angular/custom-webpack-config/)\n- [Customize Webpack Configuration in Your Angular Application](https://netbasal.com/customize-webpack-configuration-in-your-angular-application-d09683f6bd22)\n\nAll less variables can be viewed [here](https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/components/style/themes/default.less) is a sample of theme define file.\n\n## Theme Dynamic Switching\n\nWe have prepared you a demonstration project illustrating how theme dynamic switching works, you can check it out [here](https://github.com/yangjunhan/nz-themes).\n\n### Configure angular.json file\n\n1. Style preprocessor option `stylePreprocessorOptions`\n\n   Add path in a style preprocessor option called `stylePreprocessorOptions` in `angular.json`:\n\n   ```json\n   \"stylePreprocessorOptions\": {\n     \"includePaths\": [\n       \"src/path-to-mixin\"\n     ]\n   },\n   ```\n\n   As such, this config allows you to import `.themeMixin(@rules)` definition file which is under `src/path-to-mixin` path anywhere in the project without the need of using relative path:\n\n   ```css\n   // A relative path works\n   @import 'src/path-to-mixin/mixin';\n   // But now this works as well\n   @import 'mixin';\n   ```\n\n2. `bundleName` and `inject` in styles\n\n   If you intend to dynamically switch the pre-defined themes at runtime, you would need to configure every theme's bundling strategy for the bundler. For example, if your app has default and dark themes, the `styles` option of `angular.json` needs to be configured as below:\n\n   ```json\n   \"styles\": [\n     \"src/styles.less\",\n     {\n       \"input\": \"src/styles/default.less\",\n       \"bundleName\": \"default\",\n       \"inject\": false\n     },\n     {\n       \"input\": \"src/styles/dark.less\",\n       \"bundleName\": \"dark\",\n       \"inject\": false\n     }\n   ],\n   ```\n\n`bundleName` refers to the CSS bundle filename which is used for the href attribute in link tag for switching the pre-defined themes in the later section. `inject`'s default value is `true`, which the bundle is injected by default. For the purpose of theme dynamic switching, you need to set it to false to exclude the bundle from injection.\n\n### Customize theme stylesheets\n\nIn the context of multiple themes, every theme is supposed to have its own style entry file. For better project manageability, we also recommend you to put all relevant theme entry files under `src/styles` path. For a project with default and dark themes, your project styles can be in the following structure:\n\n<pre>\n  src/styles\n  ├── dark.less\n  ├── default.less\n  └── themes\n      ├── base.less\n      ├── dark.less\n      ├── default.less\n      └── mixin.less\n</pre>\n\nStylesheets under `src/styles/` are entry files which are used to import the pre-defined official entry file as well as theme customization stylesheets under `src/styles/themes/`. For example, `src/styles/dark.less` entry file contains the following lines:\n\n```less\n@import '../../node_modules/ng-zorro-antd/ng-zorro-antd';\n@import './themes/dark';\n```\n\nAccordingly, `src/styles/themes/dark.less` is in charge of customizing dark theme:\n\n```less\n@import (multiple) '../../../node_modules/ng-zorro-antd/src/style/themes/dark';\n@import './base';\n\n@layout-sider-background: @component-background;\n@layout-header-background: @component-background;\n```\n\n> The theme filename that you define can be identical to corresponding pre-defined theme filename. In such cases, `@import '<url>';` has no effects. Less provides us a solution to this circumstance which uses `multiple` method to import `.less` files with identical filenames, i.e. `@import (multiple) '<url>';`.\n\nNote that if there exists common style variables for all themes, you should create a `base.less` stylesheet and import it in every theme customization stylesheet:\n\n```less\n// base.less customizes common style variables\n@margin-md: 17px;\n...\n```\n\n### Switch themes\n\nSwitching themes involves two parts. First is switching the project component theme, and the other is switching the pre-defined theme.\n\n#### Switching component theme\n\nThe default encapsulation policy of Angular for the template and CSS styles is `ViewEncapsulation.Emulated`, also known as shimmed CSS that emulates the native behavior. Based on different encapsulation policy, Angular will package component styles into a JS file in different ways.\n\nHowever, it is troublesome to define styles in the following format:\n\n```less\nhtml {\n  &.default {\n    @import 'default';\n    // Component styles\n    ...;\n  }\n  &.dark {\n    @import 'dark';\n    // Component styles\n    ...;\n  }\n}\n```\n\n> Be noted that the configured path in the style preprocessor option `stylePreprocessorOptions` allows you to import file without the need of relative path.\n\nA better way to achieve this is to define a Mixin called `.themeMixin(@rules)` in the `mixin.less` file mentioned above:\n\n```less\n.themeMixin(@rules) {\n  html {\n    &.default {\n      @import './default.less';\n      @rules();\n    }\n    &.dark {\n      @import './dark.less';\n      @rules();\n    }\n  }\n}\n```\n\nThen, wrap all the component styles in the `.themeMixin(@rules)`:\n\n```less\n@import 'mixin'; // Similarly, no need for relative path\n\n.themeMixin({\n  :host {\n    // Component styles\n    ...\n  }\n});\n```\n\n#### Switch pre-defined theme\n\nLoading a pre-defined theme file can be achieved by dynamically creating a `link` tag, append it on the DOM and remove previous tag.\n\n```ts\nprivate loadCss(href: string, id: string): Promise<Event> {\n  return new Promise((resolve, reject) => {\n    const style = document.createElement('link');\n    style.rel = 'stylesheet';\n    style.href = href;\n    style.id = id;\n    style.onload = resolve;\n    style.onerror = reject;\n    document.head.append(style);\n  });\n}\n```\n\n`href` here refers to the path of the [bundle name](/docs/customize-theme/zh#Configure-angular-json-file), i.e. `bundleName`.\n\n#### Synchronize the style switching\n\nProject component styles will be packaged into a JS file which take effects immediately while switching themes via html `className`. On the other hand, it takes time to dynamically load the CSS theme file. If you attempt to perform two actions simultaneously, project styles will change immediately whereas styles of the pre-defined theme remain unchanged until the CSS theme file is fully loaded, resulting two themes mixing on the web page. As such, you must wrap the loading CSS process in a Promise and force the `className` switching to wait until the former completely finishes.\n\n```ts\nprivate removeUnusedTheme(theme: ThemeType): void {\n  document.documentElement.classList.remove(theme);\n  const removedThemeStyle = document.getElementById(theme);\n  if (removedThemeStyle) {\n    document.head.removeChild(removedThemeStyle);\n  }\n}\n\nloadTheme(firstLoad = true): Promise<Event> {\n  const theme = this.currentTheme;\n  if (firstLoad) {\n    document.documentElement.classList.add(theme);\n  }\n  this.loadCss(`${theme}.css`, theme).then(\n    e => {\n      if (!firstLoad) {\n        document.documentElement.classList.add(theme);\n      }\n      this.removeUnusedTheme(this.previousTheme);\n      resolve(e);\n    },\n    e => reject(e)\n  );\n}\n```\n\nNote: First-time loading of the user-defined default component theme must be performed immediately or there is a short period of time the app has no class of theme.\n"
  },
  {
    "path": "docs/customize-theme.zh-CN.md",
    "content": "---\norder: 6\ntitle: 定制主题\n---\n\nAnt Design 设计规范上支持一定程度的样式定制，以满足业务和品牌上多样化的视觉需求，包括但不限于主色、圆角、边框和部分组件的视觉定制。\n\n![Example](https://zos.alipayobjects.com/rmsportal/zTFoszBtDODhXfLAazfSpYbSLSEeytoG.png)\n\nAnt Design 的样式使用了 [Less](https://lesscss.org/) 作为开发语言，并定义了一系列全局/组件的样式变量，你可以根据需求进行相应调整，[默认样式变量](https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/components/style/themes/default.less)\n\n> Ant Design React 的主题定制文件在 `ng-zorro-antd` 中同样可以使用。\n\n## 使用预定义主题\n\n### 配置非定制主题\n\n在初始化项目时，运行 `ng add ng-zorro-antd` 命令之后，选择不配置自定义主题文件，你的项目则会自动在 `angular.json` 中配置：\n\n```json\n{\n  \"build\": {\n    \"options\": {\n      \"styles\": [\"./node_modules/ng-zorro-antd/ng-zorro-antd.min.css\"]\n    }\n  }\n}\n```\n\n当然，你也可以在 `angular.json` 中手动添加该配置。\n\n### 官方主题\n\n除了默认主题外，我们还提供了三种官方主题，欢迎在项目中试用，并且给我们提供反馈。\n\n- 🌑 暗黑主题\n- 📦 紧凑主题\n- ☁️ 阿里云主题\n\n#### 方式一： Less\n\n在样式文件全量，如 `style.less`，中引入 `ng-zorro-antd.less`、`ng-zorro-antd.dark.less`、`ng-zorro-antd.compact.less` 或 `ng-zorro-antd.aliyun.less` 覆盖主题变量。\n\n```less\n// 引入官方提供的默认 less 样式文件\n@import '~ng-zorro-antd/ng-zorro-antd.less';\n\n// 引入官方提供的暗黑 less 样式文件\n//@import \"~ng-zorro-antd/ng-zorro-antd.dark.less\";\n\n// 引入官方提供的紧凑 less 样式文件\n//@import \"~ng-zorro-antd/ng-zorro-antd.compact.less\";\n\n// 引入官方提供的阿里云 less 样式文件\n//@import \"~ng-zorro-antd/ng-zorro-antd.aliyun.less\";\n```\n\n#### 方式二: CSS\n\n如果项目不使用 Less，可在 CSS 文件或者 `angular.json` 的 `styles` 字段中，全量引入 `ng-zorro-antd.css`、`ng-zorro-antd.dark.css`、`ng-zorro-antd.compact.css` 或者 `ng-zorro-antd.aliyun.css`。\n\n样式文件中：\n\n```css\n@import '~ng-zorro-antd/ng-zorro-antd.css';\n/*@import \"~ng-zorro-antd/ng-zorro-antd.dark.css\";*/\n/*@import \"~ng-zorro-antd/ng-zorro-antd.compact.css\";*/\n/*@import \"~ng-zorro-antd/ng-zorro-antd.aliyun.css\";*/\n```\n\n`angular.json` 中：\n\n```json\n{\n  \"build\": {\n    \"options\": {\n      \"styles\": [\"node_modules/ng-zorro-antd/ng-zorro-antd.css\"]\n    }\n  }\n}\n```\n\n## 修改预定义主题\n\n### 方式一：在 Less 中覆盖主题变量\n\n#### 引入预定义主题文件\n\n在 `src/styles.less` 里引入预定义主题文件 （也可以在初始化项目运行 `ng add ng-zorro-antd` 命令之后，选择配置自定义主题文件）：\n\n```less\n// Custom Theming for NG-ZORRO\n// For more information: https://ng.ant.design/docs/customize-theme/en\n@import '../node_modules/ng-zorro-antd/ng-zorro-antd.less';\n```\n\n#### 自定义样式变量\n\n引入官方主题文件之后，再根据实际需求自定义覆盖主题样式变量的参数。例如，在以下样例中通过修改 `@primary-color` 的数值将预定义默认主题的基础色修改为 `#f5222d`：\n\n```less\n// -------- 引入官方提供的 less 样式入口文件 -----------\n@import '../node_modules/ng-zorro-antd/ng-zorro-antd.less';\n\n// -------- 自定义参数覆盖 -----------\n@primary-color: #f5222d;\n```\n\n### 方式二：webpack 中覆盖主题变量\n\n#### 覆盖为预定义主题变量\n\n在 webpack 中使用 less-loader 按需引入：\n\n```javascript\nconst darkThemeVars = require('ng-zorro-antd/dark-theme');\nconst compactThemeVars = require('ng-zorro-antd/compact-theme');\nmodule.exports = {\n  module: {\n    rules: [\n      {\n        test: /\\.less$/,\n        loader: 'less-loader',\n        options: {\n          modifyVars: {\n            hack: `true;@import \"${require.resolve('ng-zorro-antd/style/color/colorPalette.less')}\";`,\n            ...darkThemeVars,\n            ...compactThemeVars\n          },\n          javascriptEnabled: true\n        }\n      }\n    ]\n  }\n};\n```\n\n#### 覆盖为定制主题变量\n\nAngular CLI 提供了 [custom-webpack](https://www.npmjs.com/package/@angular-builders/custom-webpack) 的 builder，可以通过该 builder 轻松的调整 webpack 中 [less-loader](https://github.com/webpack-contrib/less-loader) 的配置来进行主题配置。\n\n1. 在 `angular.json` 中引入 `ng-zorro-antd.less` 文件\n\n   ```json\n   {\n     \"styles\": [\"node_modules/ng-zorro-antd/ng-zorro-antd.less\"]\n   }\n   ```\n\n2. 安装 `@angular-builders/custom-webpack` builder\n\n   ```bash\n   npm i -D @angular-builders/custom-webpack\n   ```\n\n3. 新建 webpack 配置文件 `extra-webpack.config.js`\n\n   ```javascript\n   module.exports = {\n     module: {\n       rules: [\n         {\n           test: /\\.less$/,\n           loader: 'less-loader',\n           options: {\n             modifyVars: {\n               // 修改主题变量\n               'primary-color': '#1DA57A',\n               'link-color': '#1DA57A',\n               'border-radius-base': '2px'\n             },\n             javascriptEnabled: true\n           }\n         }\n       ]\n     }\n   };\n   ```\n\n4. 在 `angular.json` 中配置自定义 builder\n\n   ```diff\n     \"architect\": {\n       \"build\": {\n   -     \"builder\": \"@angular-devkit/build-angular:browser\",\n   +     \"builder\": \"@angular-builders/custom-webpack:browser\",\n         \"options\": {\n   +        \"customWebpackConfig\": {\n   +          \"path\": \"./extra-webpack.config.js\",\n   +          \"mergeStrategies\": {\n   +            \"module.rules\": \"append\"\n   +          },\n   +          \"replaceDuplicatePlugins\": true\n   +        }\n         },\n       },\n       \"serve\": {\n   -      \"builder\": \"@angular-devkit/build-angular:dev-server\",\n   +      \"builder\": \"@angular-builders/custom-webpack:dev-server\",\n       }\n     }\n   ```\n\n更多在 Angular CLI 中定制 webpack 的文章可以参考\n\n- [Angular Builder Document](https://www.npmjs.com/package/@angular-builders/custom-webpack)\n- [Angular CLI: Custom webpack Config](https://alligator.io/angular/custom-webpack-config/)\n- [Customize Webpack Configuration in Your Angular Application](https://netbasal.com/customize-webpack-configuration-in-your-angular-application-d09683f6bd22)\n\n全部可被自定义 less 变量可以参考 [这里](https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/components/style/themes/default.less)。\n\n## 动态切换主题\n\n我们为你准备了一个演示动态切换主题的项目，欢迎前往 [这里](https://github.com/yangjunhan/nz-themes) 查看。\n\n### 配置 angular.json 文件\n\n1. 样式预处理器选项 `stylePreprocessorOptions`\n\n   在`angular.json` 中配置样式预处理器选项 `stylePreprocessorOptions` 并添加路径：\n\n   ```json\n   \"stylePreprocessorOptions\": {\n     \"includePaths\": [\n       \"src/styles/themes\"\n     ]\n   },\n   ```\n\n   于是，在项目组件样式文件里，无需相对路径，`src/styles/themes` 路径下的任意文件定义文件都可以从项目中的任何位置导入，例如：\n\n   ```less\n   // A relative path works\n   @import 'src/styles/themes/mixin';\n   // But now this works as well\n   @import 'mixin';\n   ```\n\n2. styles 里的 `bundleName` 和 `inject`\n\n   如果需要在项目运行时动态切换主题，你就需要为构建器配置好每个主题的全局上下文样式文件。继续以默认和暗黑主题为例，请在 `angular.json` 的 `styles` 选项数组里进行如下配置：\n\n   ```json\n   \"styles\": [\n     \"src/styles.less\",\n     {\n       \"input\": \"src/styles/default.less\",\n       \"bundleName\": \"default\",\n       \"inject\": false\n     },\n     {\n       \"input\": \"src/styles/dark.less\",\n       \"bundleName\": \"dark\",\n       \"inject\": false\n     }\n   ],\n   ```\n\n   `bundleName` 指捆绑包的自定义 CSS 文件名称，方便了之后切换主题创建所需的 link 标签的 href 属性。`inject` 默认为 `true`，会将捆绑包注入。为了动态主题切换则需要将主题捆绑包从注入中排除。\n\n### 多主题定制\n\n在多主题项目的情景下，每一个主题都应该创建一个单独的样式入口文件。为了更好管理多主题项目，我们推荐将所有类似的主题定义入口文件放在 `src/styles` 路径下。例如，当你的项目有默认和暗黑主题时，你的项目 styles 可能会是以下结构：\n\n<pre>\n  src/styles\n  ├── dark.less\n  ├── default.less\n  └── themes\n      ├── base.less\n      ├── dark.less\n      ├── default.less\n      └── mixin.less\n</pre>\n\n`src/styles/` 下的主题文件是主题入口文件，它的作用是引入预定义官方 Less 样式入口文件以及 `src/styles/themes/` 下对应的主题样式定制文件。例如，`src/styles/dark.less` 入口文件含有以下代码：\n\n```less\n@import '../../node_modules/ng-zorro-antd/ng-zorro-antd';\n@import './themes/dark';\n```\n\n相应的，`src/styles/themes/dark.less` 文件负责定制暗黑主题的样式：\n\n```less\n@import (multiple) '../../../node_modules/ng-zorro-antd/src/style/themes/dark';\n@import './base';\n\n@layout-sider-background: @component-background;\n@layout-header-background: @component-background;\n```\n\n> 当引入对应的预定义主题样式变量文件的时候，会遇到 `.less` 样式文件名跟项目自己的主题样式文件名是一样的情况，这样的话单单使用 `@import '<url>';` 是无法生效的。这种时候， Less 为我们提供了 `@import (multiple) '<url>';` 的 `multiple` 方法来引入这些同名的 `.less` 文件。\n\n注意，如果存在所有主题通用的样式变量，还可以引入一个统一的 `base.less` 基本样式文件并在每个主题样式定制文件中引入它：\n\n```less\n// base.less 定制通用样式变量\n@margin-md: 17px;\n```\n\n### 切换主题\n\n切换主题包括两部分，一是切换项目组件主题，二是切换预定义主题。\n\n#### 切换项目组件主题\n\nAngular 目前默认的模板和 CSS 样式使用的样式封装策略是 `ViewEncapsulation.Emulated`，也就是使用垫片 CSS 来模拟原生行为。根据不同的样式封装策略，Angular 会将项目组件样式以不同方式打包进 JS 文件里。\n\n切换项目组件主题的策略是在定制项目组件样式时，会通过 html 里的代表主题 class 的 `className`，例如 `default` 和 `dark`，以切换打包好的主题。\n\n但是，在每一个项目组件样式文件里根据以下格式写样式会很繁琐：\n\n```less\nhtml {\n  &.default {\n    @import 'default';\n    // 组件样式\n    ...;\n  }\n  &.dark {\n    @import 'dark';\n    // 组件样式\n    ...;\n  }\n}\n```\n\n> 注意，由于已经配置了样式预处理器选项 `stylePreprocessorOptions` 里的路径 `src/styles/themes`，这里的 `@import` 不需要完整的相对路径。\n\n更好的实现方式是，在上文提到的 `mixin.less` 中定义一个 Mixin `.themeMixin(@rules)`：\n\n```less\n.themeMixin(@rules) {\n  html {\n    &.default {\n      @import './default.less';\n      @rules();\n    }\n    &.dark {\n      @import './dark.less';\n      @rules();\n    }\n  }\n}\n```\n\n并在所有的项目组件样式文件里，只需要将所有样式传入 `.themeMixin(@rules)` 里即可：\n\n```less\n@import 'mixin'; // 同样的，不需要完整的相对路径\n\n.themeMixin({\n  :host {\n    // 组件样式\n    ...\n  }\n});\n```\n\n#### 切换预定义主题\n\n切换预定义主题样式文件则是需要动态创建 `link` 标签，将样式文件动态加载在应用中，并移除上个主题的 `link` 标签。\n\n```ts\nprivate loadCss(href: string, id: string): Promise<Event> {\n  return new Promise((resolve, reject) => {\n    const style = document.createElement('link');\n    style.rel = 'stylesheet';\n    style.href = href;\n    style.id = id;\n    style.onload = resolve;\n    style.onerror = reject;\n    document.head.append(style);\n  });\n}\n\n```\n\n这里的 `href` 将指代上文配置的[捆绑包](/docs/customize-theme/zh#配置-angular-json-文件)的路径，也就是 `bundleName`的路径。\n\n#### 同步两种主题切换\n\n项目组件样式会被打包进 js 文件，因此在切换 html 的 `className` 的时候主题样式会立即生效。另一方面，动态地加载 CSS 预定义主题文件却是需要时间完成的。如果两个操作同时进行，页面则会出现一部分是立即生效的项目组件样式，另一部分是切换主题加载之前的样式。因此，整个切换主题 `className` 操作需要包裹在 `Promise` 里等待 CSS 文件加载完成后才执行。\n\n```ts\nprivate removeUnusedTheme(theme: ThemeType): void {\n  document.documentElement.classList.remove(theme);\n  const removedThemeStyle = document.getElementById(theme);\n  if (removedThemeStyle) {\n    document.head.removeChild(removedThemeStyle);\n  }\n}\n\nloadTheme(firstLoad = true): Promise<Event> {\n  const theme = this.currentTheme;\n  if (firstLoad) {\n    document.documentElement.classList.add(theme);\n  }\n  this.loadCss(`${theme}.css`, theme).then(\n    e => {\n      if (!firstLoad) {\n        document.documentElement.classList.add(theme);\n      }\n      this.removeUnusedTheme(this.previousTheme);\n      resolve(e);\n    },\n    e => reject(e)\n  );\n}\n```\n\n注意：第一次加载首先需要先将用户默认的项目组件主题加入 html 里，而不是包进 Promise 里，否则开始有一段时间会出现没有主题 `className` 的情况。\n\n## Q&A\n"
  },
  {
    "path": "docs/direction.en-US.md",
    "content": "---\norder: 9\ntitle: Direction\n---\n\nSet the direction (LTR / RTL).\n\n## Set the default direction\n\nSet the `dir` attribute on the document `body` or `html` tag.\n\n```html\n<html dir=\"rtl\"></html>\n```\n\n## Set in the template\n\nImport the Angular CDK bidi module.\n\n```typescript\nimport { BidiModule } from '@angular/cdk/bidi';\n```\n\nSet the direction for the application or its descendants in the template.\n\n```html\n<div dir=\"rtl\"></div>\n```\n\n## Set in the service\n\nFor example, the modal service.\n\n```typescript\nclass MyComponent {\n  private modalService = inject(NzModalService);\n  private nzConfigService = inject(NzConfigService);\n\n  openModal(): void {\n    this.modal.create({ nzDirection: 'rtl' });\n  }\n\n  setDirWithConfig(): void {\n    this.nzConfigService.set('modal', { nzDirection: 'rtl' });\n  }\n}\n```\n\n## References\n\n- [Angular CDK Bidirectionality](https://material.angular.io/cdk/bidi/api)\n- [dir - HTML | MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/dir)\n"
  },
  {
    "path": "docs/direction.zh-CN.md",
    "content": "---\norder: 9\ntitle: 文字方向\n---\n\n设置文字方向（LTR / RTL）。\n\n## 设置默认方向\n\n在文档 `body` 或者 `html` 标签上设置 `dir` 属性。\n\n```html\n<html dir=\"rtl\"></html>\n```\n\n## 在模版中设置\n\n引入 Angular CDK bidi 模块\n\n```typescript\nimport { BidiModule } from '@angular/cdk/bidi';\n```\n\n在模版中为应用或其后代设置方向。\n\n```html\n<div dir=\"rtl\"></div>\n```\n\n## 在服务中设置\n\n例如对话框（Modal）服务。\n\n```typescript\nclass MyComponent {\n  private modalService = inject(NzModalService);\n  private nzConfigService = inject(NzConfigService);\n\n  openModal(): void {\n    this.modal.create({ nzDirection: 'rtl' });\n  }\n\n  setDirWithConfig(): void {\n    this.nzConfigService.set('modal', { nzDirection: 'rtl' });\n  }\n}\n```\n\n## 参考\n\n- [Angular CDK Bidirectionality](https://material.angular.io/cdk/bidi/api)\n- [dir - HTML | MDN](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Global_attributes/dir)\n"
  },
  {
    "path": "docs/faq.en-US.md",
    "content": "---\norder: 11\ntitle: FAQ\n---\n\n<blockquote style=\"border-color: #faad14;\"><p>For more questions please search <a href=\"https://github.com/NG-ZORRO/ng-zorro-antd/issues?q=is%3Aopen+is%3Aissue+label%3A%22%3Aquestion%3A+FAQ%22\" target=\"_blank\" rel=\"noopener\">issues with FAQ tag</a>.</p></blockquote>\n\n### The bundle size of Angular and `ng-zorro-antd`\n\nThe size hello-world project of angular after gzip is about `30KB`, the size of `ng-zorro-antd`'s doc site is about `287KB`.\n\nIf you meet the bundle size issue, please make sure you use `ng build --prod` correctly to compile. If other third-party component kits other than `ng-zorro-antd` are imported, you could generate a sourcemap file using this command `ng build --prod --sourceMap=true` to check every dependency's bundled size. You can check [this link](https://angular.io/guide/deployment#inspect-the-bundles) for further instructions.\n\n### Runtime performance of Angular and `ng-zorro-antd`\n\nAngular Vue and React have very similar benchmarks, which should not be a deciding factor, ref [benchmark](https://github.com/krausest/js-framework-benchmark)。All components of `ng-zorro-antd` are Angular Native and under `OnPush` mode, which will provide the best performance of Angular.\n\n### Can I use ng-zorro-antd in other Angular version?\n\n`ng-zorro-antd` keeps the same major version with `@angular/core`, for example `ng-zorro-antd@8` supports `@angular/core@8`. In order to get the best performance, we recommend to use the latest version of angular, ref [update docs](https://angular.dev/update-guide).\n\n### Can I use only some of the components of ng-zorro-antd?\n\nYes, all components of `ng-zorro-antd` can be imported separately.\n\n### Why ng-zorro-antd use less？ Can I use sass instead？\n\nng-zorro-antd follow the design spec of Ant Design, which could customize theme by less. `@angular/cli` support using both `less` and `sass` in the same project, they could work together.\n\n### Can I use ng-zorro-antd with d3, jquery?\n\nAll codes of ng-zorro-antd are native angular code, they won't have conflict with the other third libs.\n\n### Can't Bind to since it isn't a known property of\n\nPlease make sure you have export NG-ZORRO's feature modules in `ShareModule` if you have more than one module in your angular project, [ref](https://angular.dev/guide/ngmodules/sharing).\n\n### Expression Changed After It Has Been Checked Error\n\nThis [doc](https://blog.angularindepth.com/everything-you-need-to-know-about-the-expressionchangedafterithasbeencheckederror-error-e3fd9ce7dbb4) will help you.\n\n### Can't bind to 'formGroup' since it isn't a known property of 'form'\n\nDon't forget to import `ReactiveFormsModule`, [ref](https://angular.dev/guide/forms/reactive-forms).\n\n### The difference between `[nzValue]=\"data\"` `nzValue=\"data\"` and `nzValue=\"{{data}}\"`\n\n`nzValue=\"data\"` the component would get the `data` string, `nzValue=\"{{data}}\"` equals to `[nzValue]=\"data.toString()\"`. If you need pass `number` or `boolean` data, you should use `[nzValue]=\"data\"`.\n\n### Why my page content is not updated after I change the data?\n\nIn order to get better performance, all NG-ZORRO's components are running under [OnPush](https://angular.dev/guide/components/advanced-configuration#changedetectionstrategy) mode, this means any mutate to the `@Input()` data won't trigger change detection, please use immutable way to update array or object.\n\n```typescript\n// add data\nthis.dataSet = [\n  ...this.dataSet,\n  {\n    key: `${this.i}`,\n    name: `Edward King ${this.i}`,\n    age: '32',\n    address: `London, Park Lane no. ${this.i}`\n  }\n];\n// remove data\nthis.dataSet = this.dataSet.filter(d => d.key !== i);\n```\n\nRecommend using [immer](https://immerjs.github.io/immer/docs/introduction) for a better development experience.\n\n### My Angular app is deadlock, what happened?\n\nEvaluation of a template expression should have no visible side effects. It would cause performance issue or deadlock if you go against the rule. The following component will print `I will run every time` every time.\n\n```typescript\n@Component({\n  template: ` <input [value]=\"value\" /> `\n})\nexport class BugComponent {\n  value(): string {\n    console.log('I will run every time');\n    return 'value';\n  }\n}\n```\n\n### How to make Angular applications faster?\n\nRead [https://web.dev/angular](https://web.dev/angular).\n\n### Why some features are not supported?\n\n`ng-zorro-antd` is an implementation of Ant Design for Angular, which means only features supported by Ant Design would be implemented by `ng-zorro-antd`.\n\n### Browser compatibility\n\nPlease make sure your browser is [supported by Angular](https://github.com/angular/angular) and you have imported the [polyfill](https://angular.dev/reference/versions#polyfills) file correctly. And some components' usages are not supported by some browsers (i.e `flex` property). Please submit an issue if none of these is your case.\n\n### Why my issue is closed?\n\nIssue is designed for maintainers and users to track the development process of the project, which means only bug reports and feature requests are accepted and usage questions are not. And to give priority to well-explained jobs, issues that are not written in the given format would be closed automatically by the bot right away.\n\n### Where can I get help with Angular?\n\nYou can checkout the official docs and Angular forums. A good trick is to search on Google using `[keywords] -angularjs` to prevent `angularjs`'s interference. For example, you can type in `angular ngmodel -angularjs` to learn more about `ngModel` without struggling in out-dated Angular.js things.\n"
  },
  {
    "path": "docs/faq.zh-CN.md",
    "content": "---\norder: 11\ntitle: 常见问题\n---\n\n<blockquote style=\"border-color: #faad14;\"><p>更多常见问题请搜索<a href=\"https://github.com/NG-ZORRO/ng-zorro-antd/issues?q=is%3Aopen+is%3Aissue+label%3A%22%3Aquestion%3A+FAQ%22\" target=\"_blank\" rel=\"noopener\">标有 FAQ 的 issue</a>。</p></blockquote>\n\n### Angular 是不是打出来的包很大？ `ng-zorro-antd` 打包大小如何？\n\nAngular 的 hello-world 项目（包含路由、动画与 Http 等模块） gzip 之后大概 `30KB`，`ng-zorro-antd` 的官网（包含所有组件，懒加载）打包后 gzip 之后为 `287KB`。这与 React 或者 Vue 增加路由、动画、Http 等模块之后 gzip 的体积不会有太大差异。\n\n如果碰到了打包大小问题，首先请确定使用了 `ng build --prod` 正确的方式进行了打包，如果除 `ng-zorro-antd` 之外还引入了其他第三方组件库，你可以通过 `ng build --prod --sourceMap=true` 命令生成 sourcemap 文件后，再通过 source-map-explorer 检查每个模块所占用的体积，具体操作可以参考[官方文档](https://angular.cn/guide/deployment#inspect-the-bundles)。\n\n### Angular 是不是过时了，运行会慢吗？`ng-zorro-antd` 性能如何？\n\nAngular 与 angular.js 不是同一种前端框架，angular.js 发布的时间在 2010 年 10 月份，而 Angular 诞生时间在 2016 年 9 月份，比 React 和 Vue 的诞生时间都要晚。\n\n总体而言 Angular Vue 与 React 三种框架的运行速度没有太大差异，也不会是你项目运行时快慢的决定因素，具体的性能参数可以参考[该项目](https://github.com/krausest/js-framework-benchmark)。`ng-zorro-antd` 的所有组件均为原生 Angular 组件，并且默认运行在 `OnPush` 模式下，能够保证以 Angular 支持的最优速度运行。\n\n### 我可以在 Angular 其他版本中使用 ng-zorro-antd 吗？\n\n`ng-zorro-antd` 与 `@angular/core` 保持相同的主版本号，例如 `ng-zorro-antd@8` 支持 `@angular/core@8` 版本，依次类推，为了获得最好的性能，推荐升级至最新版本的 Angular。升级 Angular 可以参考[此文档](https://angular.cn/update-guide)。\n\n### 我可以只使用 ng-zorro-antd 的部分组件吗？\n\n`ng-zorro-antd` 的所有组件均支持单独导入使用，与其他的流行组件库可以混用。\n\n### ng-zorro-antd 为什么使用 less 定制主题？ 我能使用 sass 吗？\n\nng-zorro-antd 的设计规范遵从 ant design，因此同样使用了 less 文件来定制主题，`@angular/cli` 支持同一个项目中混用多种 css 预处理器， 与 sass 等文件不会互相干扰。\n\n### ng-zorro-antd 能和 d3, echarts ...一起使用吗？\n\nng-zorro-antd 本质上是组件库，与用户自己写的 `@Component` 没有任何的区别，也不会与第三方库产生冲突。\n\n### Can't Bind to since it isn't a known property of\n\n如果使用多 Module 管理方式，NG-ZORRO 的模块需要在每个子 Module 中都要 import，或者在 `ShareModule` 中 export，可以参考[官方文档](https://angular.cn/guide/ngmodules/sharing)。\n\n### Expression Changed After It Has Been Checked Error 错误\n\nAngular 的数据流是单向数据流，违反数据流走向会引起该问题，[这篇文章](https://blog.angularindepth.com/everything-you-need-to-know-about-the-expressionchangedafterithasbeencheckederror-error-e3fd9ce7dbb4)会帮助你理解原因。\n\n### Can't bind to 'formGroup' since it isn't a known property of 'form'\n\n使用 Reactive Forms 需要额外引入 `ReactiveFormsModule`，可以参考[官方文档](https://angular.cn/guide/forms/reactive-forms)。\n\n### 模板中 `[nzValue]=\"data\"` `nzValue=\"data\"` 与 `nzValue=\"{{data}}\"` 有什么区别\n\n`nzValue=\"data\"` 组件收到的是字符串 `data`，`nzValue=\"{{data}}\"` 等价于 `[nzValue]=\"data.toString()\"`。如果你需要传入 `number` 或者 `boolean` 类型时，应当使用 `[nzValue]=\"data\"` 的方式。\n\n### 数据修改后页面为什么没有更新\n\n为了获得更好的性能，NG-ZORRO 所有组件都运行在 [OnPush](https://angular.cn/guide/components/advanced-configuration#changedetectionstrategy) 模式下，这意味着对 `@Input()` 数据的 mutate 将不会生效，请使用 immutable 方式操作数组或者对象。\n\n```typescript\n// 增加数据\nthis.dataSet = [\n  ...this.dataSet,\n  {\n    key: `${this.i}`,\n    name: `Edward King ${this.i}`,\n    age: '32',\n    address: `London, Park Lane no. ${this.i}`\n  }\n];\n// 删除数据\nthis.dataSet = this.dataSet.filter(d => d.key !== i);\n```\n\n开发者也可以使用 [immer](https://immerjs.github.io/immer/docs/introduction) 获得更好的操作体验\n\n### 我的页面卡死了，函数不停的在执行\n\n在 Angular 的模板表达式中，绑定带有副作用的属性或者方法都是[危险的](https://angular.cn/guide/template-syntax#avoid-side-effects)，如果你违反了这条规则，很可能会造成性能下降甚至引起死循环。以下的代码会在页面中不停输出 `I will run every time`，因为 `console.log` 本身是一种副作用函数。\n\n```typescript\n@Component({\n  template: ` <input [value]=\"value\" /> `\n})\nexport class BugComponent {\n  value(): string {\n    console.log('I will run every time');\n    return 'value';\n  }\n}\n```\n\n### 怎样才能进一步提高 Angular 项目性能？\n\n推荐 [https://web.dev/angular](https://web.dev/angular) 的系列文章\n\n### 为什么我的 ISSUE 会被关闭\n\nISSUE 列表是为了 开发者 和 用户 追踪相关的开发进度而设计的，这意味 ISSUE 只接受 bug 报告或是新功能请求 (feature requests)，这意味着我们不接受用法问题。\n另外为了给予 更具体的工作更高的优先级和提高 ISSUE 处理的效率，未按照 格式提交的 ISSUE 也将会被立刻自动关闭。\n\n### 有些特性为什么不会被支持\n\n`ng-zorro-antd` 是 Angular 版本 Ant Design 的实现，这意味着只有 Ant Design 支持的交互、功能 才会被 `ng-zorro-antd` 实现。\n\n### 浏览器兼容性问题\n\n首先请确定浏览器版本得到了 Angular 的[官方支持](https://github.com/angular/angular)，并正确引入了 [polyfill](https://angular.cn/reference/versions#polyfills) 文件，另外有些组件的部分使用方式不支持部分浏览器（例如 flex显示方式），如果不是以上问题，请提 ISSUE 给我们。\n\n### 官网能正常工作，相同的用法本地运行有问题，是组件库的 BUG 吗？\n\n不会，NG-ZORRO 的官网使用在 npm 上发布的相同版本构建，所有的构建日志都可以在 [Azure](https://dev.azure.com/ng-zorro/NG-ZORRO) 查看，请仔细检查本地运行环境（版本，其他依赖包）等问题。\n\n### Angular的相关问题在哪里提问\n\n除了Angular的官方文档和相关的论坛之外，Angular的相关问题可以在 Google 或者 百度 上搜索 `关键字 -angularjs` 来避免 `angularjs` 的干扰，例如 `angular ngmodel -angularjs` 就可以获得 Angular 关于 `ngModel` 的相关文章。\n"
  },
  {
    "path": "docs/getting-started.en-US.md",
    "content": "---\norder: 1\ntitle: Getting Started\n---\n\nAnt Design of Angular is dedicated to providing a **good development experience** for programmers.\n\n> The prerequisite of Ant Design Angular is a solid background knowledge of [Angular](https://angular.dev) and [JavaScript ES2015](http://babeljs.io/docs/learn-es2015/).\n\n## Playground\n\nThe following StackBlitz link demonstrates a basic use case, and it is recommended to fork this demo as a baseline while doing `Bug Report`. However, please do not use this demo as a scaffold in a real production environment.\n\n- [NG-ZORRO StackBlitz](https://stackblitz.com/edit/ng-zorro-antd-ivy)\n\n## First Local Development\n\nThere are several engineering requirements during development, including compiling, debugging, proxying, and packaging codes in TypeScript. We strongly encourage you to develop your project with the help of Angular official CLI `@angular/cli`. To be concise, a simple example is demonstrated below.\n\n### Installation\n\n> Read the documentation of [Angular](https://angular.dev/cli) to explore more features.\n\n```bash\n$ npm install -g @angular/cli\n# Or if you use yarn\n$ yarn global add @angular/cli\n```\n\n### Create a New Project\n\nThe following command allows `@angular/cli` to create a folder called `PROJECT-NAME` under the current directory, with necessary dependencies.\n\n```bash\n$ ng new PROJECT-NAME\n```\n\n`@angular/cli` will run `npm install` or `yarn` after a project is created. You can run `npm install` or `yarn` by yourself if it fails.\n\n### Install ng-zorro-antd\n\nAfter changing the directory to the newly created project, you can automatically run the following commands to initialize the project's configuration, including importing i18n files and stylesheets and loading initial modules.\n\n```bash\n$ cd PROJECT-NAME\n$ ng add ng-zorro-antd\n```\n\n<img alt=\"CLI\" style=\"display: block; border-radius: 4px; box-shadow: 1px 1px 4px 0px rgba(0, 0, 0, 0.2);\" src=\"https://img.alicdn.com/tfs/TB19fFHdkxz61VjSZFtXXaDSVXa-680-243.svg\">\n\n`ng-zorro-antd` supports initializing configuration with schematics, more information is available in the [schematics](/docs/schematics/en) section.\n\n### Development & Debugging\n\nYour project is now ready to run. After running the following command, a welcome page will be displayed in your browser.\n\n```bash\n$ ng serve --port 0 --open\n```\n\n<img alt=\"welcome\" style=\"display: block;padding: 30px 30%;height: 260px;\" src=\"https://img.alicdn.com/tfs/TB1X.qJJgHqK1RjSZFgXXa7JXXa-89-131.svg\">\n\n### Building & Deployment\n\n```bash\n$ ng build --prod\n```\n\nProject files are built and generated in the `dist` directory by default.\n\n## Customized Build\n\nYou may use any existing scaffold tools in the Angular ecosystem in order to customize the building process. Please refer to [configure](https://github.com/NG-ZORRO/ng-zorro-antd/tree/master/integration) section if you encounter any issues.\n\n### Install ng-zorro-antd\n\n```bash\n$ npm install ng-zorro-antd --save\n# Or if you use yarn\n$ yarn add ng-zorro-antd\n```\n\n### Import Styles\n\n#### Use all component styles\n\nThis configuration contains all the styles of our components' library.\nIf you want to use only certain components' styles, please refer to [Use only certain component styles](/docs/getting-started/en#use-only-certain-component-styles) section.\n\nImport the pre-built stylesheet in `angular.json`\n\n```json\n{\n  \"styles\": [\"node_modules/ng-zorro-antd/ng-zorro-antd.min.css\"]\n}\n```\n\nImport the pre-built stylesheet in `style.css`\n\n```css\n@import '~ng-zorro-antd/ng-zorro-antd.min.css';\n```\n\nImport the less stylesheet in `style.less`\n\n```less\n@import '~ng-zorro-antd/ng-zorro-antd.less';\n```\n\n#### Use only certain component styles\n\n> Please note that importing CSS files of several components may result in code redundancy due to the dependency relationships among some components' styles.\n\nIt is necessary to import base styles (common to all components) before using certain components' styles.\n\nImport the pre-build styles in `style.css`\n\n```css\n@import '~ng-zorro-antd/style/index.min.css'; /* Import base styles */\n@import '~ng-zorro-antd/button/style/index.min.css'; /* Import one component's styles */\n```\n\nImport the less styles in `style.less`\n\n```less\n@import '~ng-zorro-antd/style/entry.less'; /* Import base styles */\n@import '~ng-zorro-antd/button/style/entry.less'; /* Import one component's styles */\n```\n\n#### Import component module\n\nFinally, you need to import the component modules that you want to use into your components.\n\nTaking the following `NzButtonModule` module as an example, first import the component module:\n\n```ts\nimport { Component } from '@angular/core';\nimport { NzButtonModule } from 'ng-zorro-antd/button';\n\n@Component({\n  imports: [NzButtonModule]\n})\nexport class AppComponent {}\n```\n\nThen use the component inside the template:\n\n```html\n<button nz-button nzType=\"primary\">Primary</button>\n```\n\n# Precautions\n\n- `ng-zorro-antd` already contains `@angular/cdk/overlay-prebuilt.css` overlay style, no additional import is required.\n\n## Other\n\n- [I18n](/docs/i18n/en)\n- [Customize Theme](/docs/customize-theme/en)\n- [Use Icons](/components/icon/en)\n"
  },
  {
    "path": "docs/getting-started.zh-CN.md",
    "content": "---\norder: 1\ntitle: 快速上手\n---\n\nNG-ZORRO 致力于提供给程序员**愉悦**的开发体验。\n\n<blockquote style=\"border-color: red;\"><p><strong>官方指南假设你已了解关于 HTML、CSS 和 JavaScript 的中级知识，并且已经完全掌握了 Angular 及配套设施的正确开发方式。如果你刚开始学习前端或者 Angular ，将框架作为你的第一步可能不是最好的主意 —— 掌握好基础知识再来吧！</strong></p></blockquote>\n\n## 在线演示\n\n最简单的使用方式参照以下 StackBlitz 演示，也推荐 Fork 本例来进行 `Bug Report`，注意不要在实际项目中这样使用。\n\n- [NG-ZORRO StackBlitz](https://stackblitz.com/edit/ng-zorro-antd-ivy)\n\n## 第一个本地实例\n\n实际项目开发中，你会需要对 TypeScript 代码的构建、调试、代理、打包部署等一系列工程化的需求。\n我们强烈建议使用官方的 `@angular/cli` 工具链辅助进行开发，下面我们用一个简单的实例来说明。\n\n### 安装脚手架工具\n\n> 如果你想了解更多CLI工具链的功能和命令，建议访问 [Angular](https://angular.cn/cli) 了解更多。\n\n```bash\n$ npm install -g @angular/cli\n```\n\n### 创建一个项目\n\n> 在创建项目之前，请确保 `@angular/cli` 已被成功安装。\n\n执行以下命令，`@angular/cli` 会在当前目录下新建一个名称为 `PROJECT-NAME` 的文件夹，并自动安装好相应依赖。\n\n```bash\n$ ng new PROJECT-NAME\n```\n\n### 初始化配置\n\n进入项目文件夹，执行以下命令后将自动完成 `ng-zorro-antd` 的初始化配置，包括引入国际化文件，导入模块，引入样式文件等工作。\n\n```bash\n$ ng add ng-zorro-antd\n```\n\n<img alt=\"CLI\" style=\"display: block; border-radius: 4px; box-shadow: 1px 1px 4px 0px rgba(0, 0, 0, 0.2);\" src=\"https://img.alicdn.com/tfs/TB19fFHdkxz61VjSZFtXXaDSVXa-680-243.svg\">\n\n开发者可以通过增加参数来完成个性化的初始化配置，例如国际化或者自定义主题等，详细可以参考 [脚手架](/docs/schematics/zh) 部分。\n\n### 开发调试\n\n一键启动调试，运行成功后显示欢迎页面。\n\n```bash\n$ ng serve --port 0 --open\n```\n\n<img alt=\"welcome\" style=\"display: block;padding: 30px 30%;height: 260px;\" src=\"https://img.alicdn.com/tfs/TB1X.qJJgHqK1RjSZFgXXa7JXXa-89-131.svg\">\n\n### 构建和部署\n\n```bash\n$ ng build --prod\n```\n\n文件会被打包到 `dist` 目录中。\n\n## 手动安装\n\n如果想自己维护工作流，理论上你可以利用 Angular 生态圈中的 各种脚手架进行开发，如果遇到问题可参考我们所使用的 [配置](https://github.com/NG-ZORRO/ng-zorro-antd/tree/master/integration) 进行定制。\n\n### 安装组件\n\n```bash\n$ npm install ng-zorro-antd --save\n```\n\n### 引入样式\n\n#### 使用全部组件样式\n\n该配置将包含组件库的全部样式，如果只想使用某些组件请查看 [使用特定组件样式](/docs/getting-started/zh#使用特定组件样式) 配置。\n\n在 `angular.json` 中引入了\n\n```json\n{\n  \"styles\": [\"node_modules/ng-zorro-antd/ng-zorro-antd.min.css\"]\n}\n```\n\n在 `style.css` 中引入预构建样式文件\n\n```css\n@import '~ng-zorro-antd/ng-zorro-antd.min.css';\n```\n\n在 `style.less` 中引入 less 样式文件\n\n```less\n@import '~ng-zorro-antd/ng-zorro-antd.less';\n```\n\n#### 使用特定组件样式\n\n> 由于组件之间的样式也存在依赖关系，单独引入多个组件的 CSS 可能导致 CSS 的冗余。\n\n使用特定组件样式时前需要先引入基本样式(所有组件的共用样式)。\n\n在 `style.css` 中引入预构建样式文件\n\n```css\n@import '~ng-zorro-antd/style/index.min.css'; /* 引入基本样式 */\n@import '~ng-zorro-antd/button/style/index.min.css'; /* 引入组件样式 */\n```\n\n在 `style.less` 中引入 less 样式文件\n\n```less\n@import '~ng-zorro-antd/style/entry.less'; /* 引入基本样式 */\n@import '~ng-zorro-antd/button/style/entry.less'; /* 引入组件样式 */\n```\n\n### 引入组件模块\n\n最后你需要将想要使用的组件模块引入到你的组件中。\n\n以下面的 `NzButtonModule` 模块为例：\n\n```ts\nimport { Component } from '@angular/core';\nimport { NzButtonModule } from 'ng-zorro-antd/button';\n\n@Component({\n  imports: [NzButtonModule]\n})\nexport class AppComponent {}\n```\n\n然后在模板中使用：\n\n```html\n<button nz-button nzType=\"primary\">Primary</button>\n```\n\n# 注意事项\n\n- `ng-zorro-antd` 已经包含了 `@angular/cdk/overlay-prebuilt.css` 浮层样式，无需额外导入。\n\n## 其他\n\n- [国际化配置](/docs/i18n/zh)\n- [自定义主题](/docs/customize-theme/zh)\n- [使用图标](/components/icon/zh)\n"
  },
  {
    "path": "docs/global-config.en-US.md",
    "content": "---\norder: 7\ntitle: Global Configuration\n---\n\nWe add a **global configuration** support to many components. You can define the default behavior of these components through the global configuration, which reduces redundant codes that must be written in the templates (makes your codes concise). Moreover, it supports altering the global configuration at runtime.\n\n## How to Use?\n\nIn order to provide default configurations in certain components, please use `provideNzConfig` function. object providing implements interface `NzConfig`For example:\n\n```typescript\nimport { NzConfig, provideNzConfig } from 'ng-zorro-antd/core/config';\n\nconst ngZorroConfig: NzConfig = {\n  message: { nzTop: 120 },\n  notification: { nzTop: 240 }\n};\n\nexport const appConfig: ApplicationConfig = {\n  providers: [provideNzConfig(ngZorroConfig)]\n};\n```\n\nThese global configurations would be injected and stored in a service named `NzConfigService`.\n\n### Provide Template Instances\n\nSome components accept `TemplateRef<T>` as a default parameter.\n\nOne of the easiest approaches is to invoke relevant functions from `NzConfigService` in the root component.\n\n```typescript\nimport { NzConfigService } from 'ng-zorro-antd/core/config';\n\nexport class AppComponent implements OnInit {\n  private nzConfigService = inject(NzConfigService);\n\n  @ViewChild('nzIndicatorTpl', { static: true })\n  nzIndicator!: TemplateRef<void>;\n\n  ngOnInit(): void {\n    this.nzConfigService.set('spin', { nzIndicator: this.nzIndicator });\n  }\n}\n```\n\nHowever, this violates the separation of concerns principle and causes codes to be bloated in the `AppComponent`.\n\nTo solve this, it is recommended to use a `FactoryProvider` instead of a `ValueProvider` (shown above) at the `NgModule` level.\n\n```typescript\n// The module-level Component which contains template references.\n// Exporting is required for AOT compatibility\n@Component({\n  template: `\n    <ng-template #nzIndicatorTpl>\n      <span class=\"ant-spin-dot\">\n        <nz-icon nzType=\"loading\" />\n      </span>\n    </ng-template>\n  `\n})\nexport class GlobalTemplatesComponent {\n  @ViewChild('nzIndicatorTpl', { static: true })\n  nzIndicator!: TemplateRef<void>;\n}\n\n// The Factory function\nconst nzConfigFactory = (): NzConfig => {\n  const environmentInjector = inject(EnvironmentInjector);\n  const { nzIndicator } = createComponent(component, { environmentInjector }).instance;\n  return {\n    spin: {\n      nzIndicator\n    }\n  };\n};\n\nexport const appConfig: ApplicationConfig = {\n  providers: [\n    {\n      // The FactoryProvider\n      provide: NZ_CONFIG,\n      useFactory: nzConfigFactory\n    }\n  ]\n};\n```\n\n## Overwrite inside Component\n\nDevelopers can use Dependency Injection to reset `NZ_CONFIG` within a particular component, which will not affect configurations outside it.\n\n```typescript\n@Component({\n  providers: [\n    // reset local NzConfigService\n    NzConfigService,\n    {\n      provide: NZ_CONFIG,\n      useValue: {\n        button: {\n          nzSize: 'large'\n        }\n      }\n    }\n  ]\n})\n```\n\nYou can also use `useFactory` to combine the global configuration with the local configuration to take effect\n\n> Note: Change global configuration after component initialization won't affect local configuration\n\n```typescript\n@Component({\n  providers: [\n    // reset local NzConfigService\n    NzConfigService,\n    {\n      provide: NZ_CONFIG,\n      useFactory: () => {\n        // get global NzConfigService\n        const globalConfig = inject(NzConfigService, { skipSelf: true }).getConfig();\n        const localConfig = {\n          select: {\n            nzVariant: 'borderless'\n          }\n        };\n        // merge local and global config\n        const mergedConfig = {\n          ...globalConfig,\n          ...localConfig\n        };\n        return mergedConfig;\n      },\n    }\n  ]\n})\n```\n\n## Dynamically Change Configurations\n\nYou can alter the global configuration of a specific component through the `set` method of `NzConfigService`. For example:\n\n```typescript\nimport { NzConfigService } from 'ng-zorro-antd/core/config';\n\n@Component({})\nexport class ChangeZorroConfigComponent {\n  private nzConfigService = inject(NzConfigService);\n\n  onChangeConfig() {\n    this.nzConfigService.set('button', { nzSize: 'large' });\n  }\n}\n```\n\nAll component instances is responsive to this configuration change (as long as they are not configured independently).\n\n## Priority of Global Configurations\n\nFor any property that supports global configuration, the sequence of priority is based on following:\n\n**Parameters passed to a component instance (in templates or through methods like `service.create` > global configuration provided by the injection token `NZ_CONFIG` > default value in ng-zorro-antd**\n\nFor example, if you want to create a `NzNotification` component:\n\n1. When you call `NzNotificationService.success`, you pass `{ nzDuration: 6000 }` as the third parameter\n2. You provide `{ notification: { nzDuration: 5000 } }` through the injection token `NZ_CONFIG`\n3. `ng-zorro-antd` has a default value of 4500\n\nConsequently, this particular notification will be visible for 6000 milliseconds.\n\n## Check all Available Globally Configurable Parameters\n\nThe interface `NzConfig` provide complete information about all components and parameters that are globally configurable. You can also check each individual component's API for more details.\n"
  },
  {
    "path": "docs/global-config.zh-CN.md",
    "content": "---\norder: 7\ntitle: 全局配置项\n---\n\n我们给众多组件添加了**全局配置**功能，你可以通过全局配置来定义组件的默认行为，从而减少在模板中需要写的代码（让你的代码更加清爽），还能在运行时修改全局配置项。\n\n## 如何使用\n\n想要为某些组件提供默认配置项, 可以使用 `provideNzConfig` 函数，传入一个符合 `NzConfig` 接口的对象。例如：\n\n```typescript\nimport { NzConfig, provideNzConfig } from 'ng-zorro-antd/core/config';\n\nconst ngZorroConfig: NzConfig = {\n  // 注意组件名称没有 nz 前缀\n  message: { nzTop: 120 },\n  notification: { nzTop: 240 }\n};\n\nexport const appConfig: ApplicationConfig = {\n  providers: [provideNzConfig(ngZorroConfig)]\n};\n```\n\n这些全局配置项将会被注入 `NzConfigService` 当中并保存。\n\n### 提供模板\n\n一些组件支持传递模板 `TemplateRef<T>` 作为默认参数，我们来了解一下如何做到这一点。\n\n最简单的方式是在应用的根组件中调用 `NzConfigService` 的相关方法：\n\n```typescript\nimport { NzConfigService } from 'ng-zorro-antd/core/config';\n\nexport class AppComponent implements OnInit {\n  private nzConfigService = inject(NzConfigService);\n\n  @ViewChild('nzIndicatorTpl', { static: true })\n  nzIndicator!: TemplateRef<void>;\n\n  ngOnInit(): void {\n    this.nzConfigService.set('spin', { nzIndicator: this.nzIndicator });\n  }\n}\n```\n\n然而这种方式可能会让你的 AppComponent 相当臃肿，并违反关注分离原则。\n\n因此，当你的项目比较大时，我们建议你使用一个 `FactoryProvider`，如下所示：\n\n```typescript\n// The module-level Component which contains template references.\n// Exporting is required for AOT compatibility\n@Component({\n  template: `\n    <ng-template #nzIndicatorTpl>\n      <span class=\"ant-spin-dot\">\n        <nz-icon nzType=\"loading\" />\n      </span>\n    </ng-template>\n  `\n})\nexport class GlobalTemplatesComponent {\n  @ViewChild('nzIndicatorTpl', { static: true })\n  nzIndicator!: TemplateRef<void>;\n}\n\n// The Factory function\nconst nzConfigFactory = (): NzConfig => {\n  const environmentInjector = inject(EnvironmentInjector);\n  const { nzIndicator } = createComponent(component, { environmentInjector }).instance;\n  return {\n    spin: {\n      nzIndicator\n    }\n  };\n};\n\nexport const appConfig: ApplicationConfig = {\n  providers: [\n    {\n      // The FactoryProvider\n      provide: NZ_CONFIG,\n      useFactory: nzConfigFactory\n    }\n  ]\n};\n```\n\n## 局部生效\n\n开发者可以利用 Angular 自带的依赖注入机制，在特定组件内重新设定 `NZ_CONFIG`， 该设定不会影响该组件以外的配置。\n\n```typescript\n@Component({\n  providers: [\n    // 重设本地 NzConfigService\n    NzConfigService,\n    {\n      provide: NZ_CONFIG,\n      useValue: {\n        button: {\n          nzSize: 'large'\n        }\n      }\n    }\n  ]\n})\n```\n\n也可以使用 `useFactory` 将全局配置与区域配置合并后生效\n\n> 注意：全局配置在初始化之后修改将不会影响该部分配置结果\n\n```typescript\n@Component({\n  providers: [\n    // 重设本地 NzConfigService\n    NzConfigService,\n    {\n      provide: NZ_CONFIG,\n      useFactory: () => {\n        // 获取全局 NzConfigService\n        const globalConfig = inject(NzConfigService, { skipSelf: true }).getConfig();\n        const localConfig = {\n          select: {\n            nzVariant: 'borderless'\n          }\n        };\n        // 合并全局配置与本地配置\n        const mergedConfig = {\n          ...globalConfig,\n          ...localConfig\n        };\n        return mergedConfig;\n      },\n    }\n  ]\n})\n```\n\n## 动态变更\n\n你可以通过调用 `NzConfigService` 的 `set` 方法来改变某个组件的配置项，例如：\n\n```typescript\nimport { NzConfigService } from 'ng-zorro-antd/core/config';\n\n@Component({})\nexport class ChangeZorroConfigComponent {\n  private nzConfigService = inject(NzConfigService);\n\n  onChangeConfig() {\n    this.nzConfigService.set('button', { nzSize: 'large' });\n  }\n}\n```\n\n所有的组件实例都会响应这些改变（只要它们没有被单独赋值）。\n\n## 优先级说明\n\n对于任何一个属性来说，各个来源的值的优先级如下：\n\n**为组件的某个实例单独设置的值（通过模板或类似于 `service.create` 的方法）> 通过 `NZ_CONFIG` 提供的全局默认值（包括 `set` 方法） > NG-ZORRO 内置的默认值。**\n\n例如，你想创建一个 NzNotification 组件：\n\n1. 你在调用 `NzNotificationService.success` 时传递参数 `{ nzDuration: 6000 }`\n2. 你通过 `NZ_CONFIG` 提供了全局默认值 `{ notification: { nzDuration: 5000 } }`\n3. NG-ZORRO 内部默认值为 4500\n\n最终该 Notification 将会显示 6000 毫秒。\n\n## 可配置项\n\n`NzConfig` 接口提供的类型定义信息能够帮助你找到所有支持全局配置项的组件和属性。另外，每个组件的文档都会指出哪些属性可以通过全局配置项的方式指定。\n"
  },
  {
    "path": "docs/i18n.en-US.md",
    "content": "---\norder: 3\ntitle: Internationalization\n---\n\nThe default language of `ng-zorro-antd` is Chinese yet.\nIf you want to use other languages, you can follow the instructions below.\nYou can also set the language with `ng add ng-zorro-antd` when creating project.\n\n## Default i18n Language\n\n`ng-zorro-antd` provides several configuration tokens for global configuration of international copy and date,\n`NZ_I18N` for the international copy, and `NZ_DATE_CONFIG` for date-related features. In addition, we use Angular's\nlanguage pack for date formatting by default (need to introduce the corresponding Angular language pack).\n\n<!-- todo: provideNzDateConfig, provideNzDateLocale  APIs  -->\n\nIn addition, we also provide an optional `NZ_DATE_LOCALE` for date-fns mode to format local dates (depending on the [`date-fns`](https://date-fns.org/docs/I18n) library,\nsee `How to use date-fns for date formatting`) below.\n\n```ts\n/** config angular i18n **/\nimport { registerLocaleData } from '@angular/common';\nimport en from '@angular/common/locales/en';\nregisterLocaleData(en);\n\n/** config ng-zorro-antd i18n **/\nimport { provideNzI18n, en_US } from 'ng-zorro-antd/i18n';\n\n/** set the default i18n config **/\nexport const appConfig: ApplicationConfig = {\n  providers: [\n    // ...\n    provideNzI18n(en_US)\n  ]\n};\n```\n\n## Work with Angular localize\n\nWhen using [@angular/localize](https://angular.dev/guide/i18n/add-package), ng-zorro-antd could keep the same localization with angular via [LOCALE_ID](https://angular.dev/api/core/LOCALE_ID)\n\n```ts\n/** import all locales data **/\nimport { LOCALE_ID } from '@angular/core';\nimport { registerLocaleData } from '@angular/common';\nimport en from '@angular/common/locales/en';\nimport zh from '@angular/common/locales/zh';\nregisterLocaleData(en);\nregisterLocaleData(zh);\n\n/** config ng-zorro-antd i18n **/\nimport { en_US, provideNzI18n, fr_FR } from 'ng-zorro-antd/i18n';\n\n/** switch ng-zorro-antd locales via LOCALE_ID **/\nexport const appConfig: ApplicationConfig = {\n  providers: [\n    // ...\n    provideNzI18n(() => (inject(LOCALE_ID) === 'fr' ? fr_FR : en_US))\n  ]\n};\n```\n\n## Service\n\n`ng-zorro-antd` provides the service of `NzI18nService` to dynamic change the locale text.\n\n```ts\nimport { en_US, NzI18nService } from 'ng-zorro-antd/i18n';\n\nclass DemoComponent {\n  private i18n = inject(NzI18nService);\n\n  switchLanguage() {\n    this.i18n.setLocale(en_US);\n  }\n}\n```\n\nNote: `en_US` is the package name, follow below.\n\nSupported languages:\n\n| Package Name | Language              |\n| ------------ | --------------------- |\n| ar_EG        | Arabic                |\n| az_AZ        | Azerbaijani           |\n| bg_BG        | Bulgarian             |\n| bn_BD        | Bangla (Bangladesh)   |\n| by_BY        | Belarusian            |\n| ca_ES        | Catalan               |\n| cs_CZ        | Czech                 |\n| da_DK        | Danish                |\n| de_DE        | German                |\n| el_GR        | Greek                 |\n| en_AU        | English (Australia)   |\n| en_GB        | English               |\n| en_US        | English (America)     |\n| es_ES        | Spanish               |\n| et_EE        | Estonian              |\n| fa_IR        | Persian               |\n| fi_FI        | Finnish               |\n| fr_BE        | French (Belgium)      |\n| fr_CA        | French (Canada)       |\n| fr_FR        | French (France)       |\n| ga_IE        | Irish Gaelic          |\n| gl_ES        | Galician (Spain)      |\n| he_IL        | Hebrew                |\n| hi_IN        | Hindi                 |\n| hr_HR        | Croatian              |\n| hu_HU        | Hungarian             |\n| hy_AM        | Armenian              |\n| id_ID        | Indonesian            |\n| is_IS        | Icelandic             |\n| it_IT        | Italian               |\n| ja_JP        | Japanese              |\n| ka_GE        | Georgian              |\n| kk_KZ        | Kazakh                |\n| km_KH        | Khmer                 |\n| kmr_IQ       | Kurmanji              |\n| kn_IN        | Kannada               |\n| ko_KR        | Korean                |\n| ku_IQ        | Kurdish               |\n| lt_LT        | Lithuanian            |\n| lv_LV        | Latvian               |\n| mk_MK        | Macedonian            |\n| ml_IN        | Malayalam (India)     |\n| mn_MN        | Mongolian             |\n| ms_MY        | Malay                 |\n| nb_NO        | Norwegian             |\n| ne_NP        | Nepali                |\n| nl_BE        | Dutch (Belgium)       |\n| nl_NL        | Dutch                 |\n| pl_PL        | Polish                |\n| pt_BR        | Portuguese (Brazil)   |\n| pt_PT        | Portuguese            |\n| ro_RO        | Romanian              |\n| ru_RU        | Russian               |\n| sk_SK        | Slovak                |\n| sl_SI        | Slovenian             |\n| sr_RS        | Serbian               |\n| sv_SE        | Swedish               |\n| ta_IN        | Tamil                 |\n| th_TH        | Thai                  |\n| tr_TR        | Turkish               |\n| uk_UA        | Ukrainian             |\n| ur_PK        | Urdu (Pakistan)       |\n| vi_VN        | Vietnamese            |\n| zh_CN        | Chinese (Simplified)  |\n| zh_HK        | Chinese (Traditional) |\n| zh_TW        | Chinese (Traditional) |\n\n## How to format a date using date-fns\n\nFor date formatting, we use Angular's DatePipe ([syntax reference](https://angular.dev/api/common/DatePipe) to implement (depending on Angular's locale language pack),\nbut due to Angular's own DatePipe is not implemented according to the ISO standard algorithm ([issue #25380](https://github.com/angular/angular/issues/25380)),\nthe week number may not match expectations (related issues: [#2406](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2406), [#2819](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2819) ).\n\nSo we have a new `date-fns` method ([syntax reference](https://date-fns.org/docs/format#description)) for standard date formatting, you can switch to it by the following way\n(after switching, it will affect the date formatting of all date related components such as Calendar/DatePicker):\n\n```ts\n// Set the value of NZ_DATE_LOCALE in the `app.config.ts` to activate date-fns mode\nimport { enUS, ja } from 'date-fns/locale';\n\nexport const appConfig: ApplicationConfig = {\n  providers: [{ provide: NZ_DATE_LOCALE, useValue: enUS }]\n};\n\n// Switch language to Japanese at runtime\nimport { NzI18nService } from 'ng-zorro-antd/i18n';\n\nexport class AppComponent {\n  private i18n = inject(NzI18nService);\n\n  switchLanguage() {\n    this.i18n.setDateLocale(ja);\n  }\n}\n```\n\nAfter the switch is successful, you can also choose to remove the dependency on the Angular Locales package (remove the code below) to reduce the package size:\n\n```ts\n// The following code can be removed as needed\nimport { registerLocaleData } from '@angular/common';\nimport en from '@angular/common/locales/en';\nregisterLocaleData(en);\n```\n\n### NZ_DATE_CONFIG (Date global configuration)\n\nThe default configuration is as follows:\n\n```ts\n{\n  /** Specify which day is the beginning of the week (null for default, 0 for Sunday, 1 for Monday, and so on) */\n  firstDayOfWeek: null;\n}\n```\n\n## Language supported by date-fns\n\n[https://date-fns.org/docs/I18n#supported-languages](https://date-fns.org/docs/I18n#supported-languages)\n\n## How to override internationalization configuration\n\nThe text of some components in `ng-zorro` depends on the internationalized text, such as the `size changer` in `nz-pagination`. At this time, you can modify the internationalization configuration to change the text content in the `size changer`:\n\n```ts\nimport { en_US, provideNzI18n } from 'ng-zorro-antd/i18n';\n\nconst customLanguagePack = {\n  en_US,\n  ...{\n    Pagination: {\n      items_per_page: 'per page'\n    }\n  }\n};\n\nexport const appConfig: ApplicationConfig = {\n  providers: [provideNzI18n(customLanguagePack)]\n};\n```\n"
  },
  {
    "path": "docs/i18n.zh-CN.md",
    "content": "---\norder: 3\ntitle: 国际化\n---\n\n目前的默认文案是中文，如果需要使用其他语言，可以在初始化时进行配置，也可以在运行中随时修改，可以参考下面的方案。\n你也可以在新建项目时通过 `ng add ng-zorro-antd` 设置国际化语言。\n\n## 配置默认国际化语言\n\n`ng-zorro-antd` 提供了几个配置型 token 用于全局配置国际化文案和日期，`NZ_I18N`用于国际化文案，`NZ_DATE_CONFIG`用于修改日期相关特性。\n此外，我们默认使用 Angular 的语言包来进行日期格式化（需要引入相应的 Angular 语言包）。\n\n<!-- todo: provideNzDateConfig, provideNzDateLocale  APIs  -->\n\n另外，我们还提供了可选的 `NZ_DATE_LOCALE` 用于 date-fns 方式来格式化本地日期（依赖 [`date-fns`](https://date-fns.org/docs/I18n) 库，详见下方的`如何使用 date-fns 进行日期格式化`）。\n\n```ts\n/** 导入需要使用的 Angular 语言包 **/\nimport { registerLocaleData } from '@angular/common';\nimport en from '@angular/common/locales/en';\nregisterLocaleData(en);\n\n/** 配置 ng-zorro-antd 国际化 **/\nimport { provideNzI18n, en_US } from 'ng-zorro-antd/i18n';\n\n/** 静态配置 **/\nexport const appConfig: ApplicationConfig = {\n  providers: [\n    // ...\n    provideNzI18n(en_US)\n  ]\n};\n```\n\n## 与 Angular 应用本地化方案联动\n\n当使用 Angular [应用本地化方案](https://angular.cn/guide/i18n) 时，可以根据 [LOCALE_ID](https://angular.cn/api/core/LOCALE_ID) 自动切换 `ng-zorro-antd` 默认语言\n\n```typescript\n/** 导入需要使用的语言包 **/\nimport { LOCALE_ID } from '@angular/core';\nimport { registerLocaleData } from '@angular/common';\nimport en from '@angular/common/locales/en';\nimport zh from '@angular/common/locales/zh';\nregisterLocaleData(en);\nregisterLocaleData(zh);\n\n/** 配置 ng-zorro-antd 国际化 **/\nimport { en_US, provideNzI18n, zh_CN } from 'ng-zorro-antd/i18n';\n\n/** 根据 LOCALE_ID 自动切换 ng-zorro-antd 语言 **/\nexport const appConfig: ApplicationConfig = {\n  providers: [\n    // ...\n    provideNzI18n(() => (inject(LOCALE_ID) === 'zh' ? zh_CN : en_US))\n  ]\n};\n```\n\n## 运行时修改\n\n`ng-zorro-antd` 提供了 `NzI18nService` 服务用于动态修改国际化文案。\n\n```ts\nimport { en_US, NzI18nService } from 'ng-zorro-antd/i18n';\n\nclass SomeComponent {\n  private i18n = inject(NzI18nService);\n\n  switchLanguage() {\n    this.i18n.setLocale(en_US);\n  }\n}\n```\n\n注意：`en_US` 是语言包名称，以下表格也遵循同样的规则。\n\n## 支持语言\n\n| 语言包名 | 语言                 |\n| -------- | -------------------- |\n| ar_EG    | 阿拉伯               |\n| az_AZ    | 阿塞拜疆             |\n| bg_BG    | 保加利亚语           |\n| bn_BD    | 孟加拉语（孟加拉国） |\n| by_BY    | 白俄罗斯语           |\n| ca_ES    | 加泰罗尼亚语         |\n| cs_CZ    | 捷克语               |\n| da_DK    | 丹麦语               |\n| de_DE    | 德语                 |\n| el_GR    | 希腊语               |\n| en_AU    | 英语（澳大利亚）     |\n| en_GB    | 英语                 |\n| en_US    | 英语（美式）         |\n| es_ES    | 西班牙语             |\n| et_EE    | 爱沙尼亚语           |\n| fa_IR    | 波斯语               |\n| fi_FI    | 芬兰语               |\n| fr_BE    | 法语（比利时）       |\n| fr_CA    | 法语（加拿大）       |\n| fr_FR    | 法语                 |\n| ga_IE    | 爱尔兰盖尔语         |\n| gl_ES    | 加利西亚语（西班牙） |\n| he_IL    | 希伯来语             |\n| hi_IN    | 印地语               |\n| hr_HR    | 克罗地亚语           |\n| hu_HU    | 匈牙利               |\n| hy_AM    | 亚美尼亚             |\n| id_ID    | 印度尼西亚语         |\n| is_IS    | 冰岛语               |\n| it_IT    | 意大利语             |\n| ja_JP    | 日语                 |\n| ka_GE    | 格鲁吉亚语           |\n| kk_KZ    | 哈萨克语             |\n| km_KH    | 高棉语               |\n| kmr_IQ   | 北库尔德语           |\n| kn_IN    | 卡纳达语             |\n| ko_KR    | 韩语/朝鲜语          |\n| ku_IQ    | 库尔德语             |\n| lt_LT    | 立陶宛语             |\n| lv_LV    | 拉脱维亚语           |\n| ml_IN    | 马拉雅拉姆语         |\n| mn_MN    | 蒙古语               |\n| ms_MY    | 马来语               |\n| nb_NO    | 挪威                 |\n| ne_NP    | 尼泊尔语             |\n| nl_BE    | 荷兰语（比利时）     |\n| nl_NL    | 荷兰语               |\n| pl_PL    | 波兰语               |\n| pt_BR    | 葡萄牙语(巴西)       |\n| pt_PT    | 葡萄牙语             |\n| ro_RO    | 罗马尼亚语           |\n| ru_RU    | 俄罗斯语             |\n| sk_SK    | 斯洛伐克语           |\n| sl_SI    | 斯洛文尼亚           |\n| sr_RS    | 塞尔维亚             |\n| sv_SE    | 瑞典语               |\n| ta_IN    | 泰米尔语             |\n| th_TH    | 泰语                 |\n| tr_TR    | 土耳其语             |\n| uk_UA    | 乌克兰语             |\n| ur_PK    | 乌尔都语 (巴基斯坦)  |\n| vi_VN    | 越南语               |\n| zh_CN    | 简体中文             |\n| zh_HK    | 繁体中文             |\n| zh_TW    | 繁体中文             |\n\n## 如何使用 date-fns 进行日期格式化\n\n对于日期的格式化，我们默认采用 Angular 的 DatePipe（[语法参考](https://angular.cn/api/common/DatePipe)来实现（依赖Angular的locale语言包），但由于Angular自带的DatePipe并非按照ISO标准算法实现（[issue #25380](https://github.com/angular/angular/issues/25380)），使用时周数的展示可能与预期不符（相关issue: [#2406](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2406), [#2819](https://github.com/NG-ZORRO/ng-zorro-antd/issues/2819)）。\n\n所以我们新提供了`date-fns`方式（[语法参考](https://date-fns.org/docs/format#description)）来进行标准的日期格式化，您可以通过以下方式切换至 `date-fns`（切换后将影响所有日期类组件如Calendar/DatePicker的日期格式化）：\n\n```ts\n// 在 App Config 中设置 NZ_DATE_LOCALE 的值，将激活 date-fns 方式的日期格式化展示\nimport { enUS, ja } from 'date-fns/locale';\n\nexport const appConfig: ApplicationConfig = {\n  providers: [{ provide: NZ_DATE_LOCALE, useValue: enUS }]\n};\n\n// 运行时切换语言为日语\nimport { NzI18nService } from 'ng-zorro-antd/i18n';\n\nexport class AppComponent {\n  private i18n = inject(NzI18nService);\n\n  switchLanguage() {\n    this.i18n.setDateLocale(ja);\n  }\n}\n```\n\n切换成功后，可以选择移除掉对 Angular Locales 包的依赖（删除下方代码）来减小打包体积（前提是代码对其无依赖）:\n\n```ts\n// 以下代码可根据需要移除\nimport { registerLocaleData } from '@angular/common';\nimport en from '@angular/common/locales/en';\nregisterLocaleData(en);\n```\n\n### NZ_DATE_CONFIG 日期全局配置\n\n默认配置如下：\n\n```ts\n{\n  /** 指定哪一天为一周的开始（null表示采用内部默认值，0表示星期日，1表示星期一，以此类推） */\n  firstDayOfWeek: null;\n}\n```\n\n## date-fns 支持语言\n\n[https://date-fns.org/docs/I18n#supported-languages](https://date-fns.org/docs/I18n#supported-languages)\n\n## 如何更改默认国际化语言包配置\n\n`ng-zorro` 中有些组件的文本依赖于国际化文本，例如 `nz-pagination` 中的 `size changer`, 这时候你可以修改国际化配置来更改 `size changer` 中的文本内容：\n\n```ts\nimport { en_US, provideNzI18n } from 'ng-zorro-antd/i18n';\n\nconst customLanguagePack = {\n  en_US,\n  ...{\n    Pagination: {\n      items_per_page: 'per page'\n    }\n  }\n};\n\nexport const appConfig: ApplicationConfig = {\n  providers: [provideNzI18n(customLanguagePack)]\n};\n```\n"
  },
  {
    "path": "docs/introduce.en-US.md",
    "content": "---\norder: 0\ntitle: Ant Design of Angular\n---\n\nAn enterprise-class Angular UI component library based on Ant Design, all components are open source and free to use under MIT license.\n\n<div class=\"pic-plus\">\n  <img alt=\"Ant Design\" style=\"margin-right: 24px\" width=\"150\" height=\"150\" src=\"https://img.alicdn.com/tfs/TB1g.mWZAL0gK0jSZFtXXXQCXXa-200-200.svg\">\n  <span>+</span>\n  <img alt=\"Angular\" width=\"180\" height=\"180\" src=\"https://img.alicdn.com/imgextra/i1/O1CN01RSfkps1J0vtVaKr0U_!!6000000000967-49-tps-1920-1920.webp\">\n</div>\n\n## Features\n\n- An enterprise-class UI design language for Angular applications.\n- 70+ high-quality Angular components out of the box.\n- Written in TypeScript with complete defined types.\n- Support Zoneless and OnPush mode, high performance.\n- Powerful theme customization in every detail.\n- Internationalization support for dozens of languages.\n\n## Environment Support\n\n- Modern browsers, [Browser support](https://angular.dev/reference/versions#browser-support)\n- Server-side Rendering\n- [Electron](https://www.electronjs.org/)\n\n| [<img src=\"https://img.alicdn.com/tfs/TB1G5ewZuL2gK0jSZPhXXahvXXa-48-48.png\" alt=\"Edge\" width=\"24px\" height=\"24px\" />](https://godban.github.io/browsers-support-badges//)<br>Edge | [<img src=\"https://img.alicdn.com/tfs/TB1Dx73o79l0K4jSZFKXXXFjpXa-48-48.png\" alt=\"Firefox\" width=\"24px\" height=\"24px\" />](https://godban.github.io/browsers-support-badges/)<br>Firefox | [<img src=\"https://img.alicdn.com/tfs/TB1mY9FZrr1gK0jSZFDXXb9yVXa-48-48.png\" alt=\"Chrome\" width=\"24px\" height=\"24px\" />](https://godban.github.io/browsers-support-badges/)<br>Chrome | [<img src=\"https://img.alicdn.com/tfs/TB1Vas5o79l0K4jSZFKXXXFjpXa-48-48.png\" alt=\"Safari\" width=\"24px\" height=\"24px\" />](https://godban.github.io/browsers-support-badges/)<br>Safari | [<img src=\"https://img.alicdn.com/tfs/TB12EmNZET1gK0jSZFrXXcNCXXa-48-48.png\" alt=\"Opera\" width=\"24px\" height=\"24px\" />](https://godban.github.io/browsers-support-badges/)<br>Opera | [<img src=\"https://img.alicdn.com/tfs/TB1TMW8paNj0u4jSZFyXXXgMVXa-48-48.png\" alt=\"Electron\" width=\"24px\" height=\"24px\" />](https://godban.github.io/browsers-support-badges/)<br>Electron |\n| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| last 2 versions                                                                                                                                                                    | last 2 versions                                                                                                                                                                         | last 2 versions                                                                                                                                                                       | last 2 versions                                                                                                                                                                       | last 2 versions                                                                                                                                                                     | last 2 versions                                                                                                                                                                           |\n\n## Version\n\n[![npm package](https://img.shields.io/npm/v/ng-zorro-antd.svg?style=flat-square)](https://www.npmjs.org/package/ng-zorro-antd)\n\n## Angular Support\n\n`ng-zorro-antd` keeps the same major version with `@angular/core`, now supports Angular `^21.0.0`.\n\n## Design Specification\n\n`ng-zorro-antd` synchronizes design specification with [Ant Design](https://ant.design/docs/spec/introduce) on a regular basis, you can check the [log](https://github.com/NG-ZORRO/ng-zorro-antd/actions?query=workflow:\"styles-sync\") online.\n\n## Installation\n\n**We recommend using `@angular/cli` to install**，it not only makes development easier，but also allow you to take advantage of the rich ecosystem of angular packages and tooling.\n\n```bash\n$ ng new PROJECT_NAME\n$ cd PROJECT_NAME\n$ ng add ng-zorro-antd\n```\n\n> More information about `@angular/cli` [here](https://github.com/angular/angular-cli).\n\nYou can also install `ng-zorro-antd` with npm or yarn\n\n```bash\n$ npm install ng-zorro-antd\n```\n\n## Companies using ng-zorro-antd\n\n- [Alibaba](https://www.alibaba.com/)\n- [Aliyun](https://www.aliyun.com/)\n- [ThoughtWorks](https://www.thoughtworks.com/)\n- [China Merchants Bank](https://english.cmbchina.com/)\n- [Ververica](https://www.ververica.com/)\n- [Apache Flink](https://flink.apache.org/)\n- [Apache Zeppelin](https://zeppelin.apache.org/)\n- [Apache Submarine](https://submarine.apache.org/)\n- [Apache Metron](https://metron.apache.org/)\n- [Process Automation Group](https://pag.company/)\n- [AISINOCO](https://www.aisino.com/)\n- [GongDao](https://www.gongdao.com/)\n- [UC Express](https://www.uce.cn/)\n- [Qingflow](https://qingflow.com/)\n- [DataGrand](https://datagrand.com/)\n- [ScentBird](https://www.scentbird.com/)\n- [Southern Institute of Technology](https://www.sit.ac.nz/)\n- [Hapify (Dynamic boilerplates tool)](https://hub.hapify.io/)\n\n> We list some users here, if your company or product uses ng-zorro-antd, let us know [here](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1142)!\n\n## Contributing\n\nPlease read our [CONTRIBUTING.md](https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/CONTRIBUTING.md) first.\n\nIf you'd like to help us improve ng-zorro-antd, just create a [Pull Request](https://github.com/NG-ZORRO/ng-zorro-antd/pulls). Feel free to report bugs and issues [here](https://ng.ant.design/issue-helper/#/en).\n\n> If you're new to posting issues, we ask that you read [_How To Ask Questions The Smart Way_](https://www.catb.org/~esr/faqs/smart-questions.html)(This guide does not provide actual support services for this project!) and [How to Ask a Question in Open Source Community](https://github.com/seajs/seajs/issues/545) and [How to Report Bugs Effectively](https://www.chiark.greenend.org.uk/~sgtatham/bugs.html) prior to posting. Well written bug reports help us help you!\n\n## Need Help?\n\nFor questions on how to use ng-zorro-antd, please post questions to [<img alt=\"Stack Overflow\" src=\"https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-logo.svg?v=2bb144720a66\" width=\"140\" />](https://stackoverflow.com/questions/tagged/ng-zorro-antd) using the `ng-zorro-antd` tag. If you're not finding what you need on stackoverflow, you can find us on [Discussions · NG-ZORRO/ng-zorro-antd](https://github.com/NG-ZORRO/ng-zorro-antd/discussions) as well.\n\nAs always, we encourage experienced users to help those who are not familiar with `ng-zorro-antd`!\n"
  },
  {
    "path": "docs/introduce.zh-CN.md",
    "content": "---\norder: 0\ntitle: Ant Design of Angular\n---\n\n`ng-zorro-antd` 是遵循 Ant Design 设计规范的 Angular UI 组件库，主要用于研发企业级中后台产品。全部代码开源并遵循 MIT 协议，任何企业、组织及个人均可免费使用。\n\n<div class=\"pic-plus\">\n  <img alt=\"Ant Design\" style=\"margin-right: 24px\" width=\"150\" height=\"150\" src=\"https://img.alicdn.com/tfs/TB1g.mWZAL0gK0jSZFtXXXQCXXa-200-200.svg\">\n  <span>+</span>\n  <img alt=\"Angular\" width=\"180\" height=\"180\" src=\"https://img.alicdn.com/imgextra/i1/O1CN01RSfkps1J0vtVaKr0U_!!6000000000967-49-tps-1920-1920.webp\">\n</div>\n\n## 特性\n\n- 提炼自企业级中后台产品的交互语言和视觉风格。\n- 开箱即用的高质量 Angular 组件库，与 Angular 保持同步升级。\n- 使用 TypeScript 构建，提供完整的类型定义文件。\n- 支持 Zoneless 和 OnPush 模式，性能卓越。\n- 数十个国际化语言支持。\n- 深入每个细节的主题定制能力。\n\n## 支持环境\n\n- 现代浏览器，[浏览器支持](https://angular.cn/reference/versions#browser-support)\n- 支持服务端渲染\n- [Electron](https://www.electronjs.org/)\n\n| [<img src=\"https://img.alicdn.com/tfs/TB1G5ewZuL2gK0jSZPhXXahvXXa-48-48.png\" alt=\"Edge\" width=\"24px\" height=\"24px\" />](https://godban.github.io/browsers-support-badges//)<br>Edge | [<img src=\"https://img.alicdn.com/tfs/TB1Dx73o79l0K4jSZFKXXXFjpXa-48-48.png\" alt=\"Firefox\" width=\"24px\" height=\"24px\" />](https://godban.github.io/browsers-support-badges/)<br>Firefox | [<img src=\"https://img.alicdn.com/tfs/TB1mY9FZrr1gK0jSZFDXXb9yVXa-48-48.png\" alt=\"Chrome\" width=\"24px\" height=\"24px\" />](https://godban.github.io/browsers-support-badges/)<br>Chrome | [<img src=\"https://img.alicdn.com/tfs/TB1Vas5o79l0K4jSZFKXXXFjpXa-48-48.png\" alt=\"Safari\" width=\"24px\" height=\"24px\" />](https://godban.github.io/browsers-support-badges/)<br>Safari | [<img src=\"https://img.alicdn.com/tfs/TB12EmNZET1gK0jSZFrXXcNCXXa-48-48.png\" alt=\"Opera\" width=\"24px\" height=\"24px\" />](https://godban.github.io/browsers-support-badges/)<br>Opera | [<img src=\"https://img.alicdn.com/tfs/TB1TMW8paNj0u4jSZFyXXXgMVXa-48-48.png\" alt=\"Electron\" width=\"24px\" height=\"24px\" />](https://godban.github.io/browsers-support-badges/)<br>Electron |\n| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| last 2 versions                                                                                                                                                                    | last 2 versions                                                                                                                                                                         | last 2 versions                                                                                                                                                                       | last 2 versions                                                                                                                                                                       | last 2 versions                                                                                                                                                                     | last 2 versions                                                                                                                                                                           |\n\n## 当前版本\n\n[![npm package](https://img.shields.io/npm/v/ng-zorro-antd.svg?style=flat-square)](https://www.npmjs.org/package/ng-zorro-antd)\n\n## 支持 Angular 版本\n\n`ng-zorro-antd` 与 `@angular/core` 保持相同的主版本号，目前支持 Angular `^21.0.0` 版本。\n\n## 设计规范\n\n与 Ant Design 设计规范定期同步，你可以在线查看[同步日志](https://github.com/NG-ZORRO/ng-zorro-antd/actions?query=workflow:\"styles-sync\")。\n\n## 安装\n\n我们强烈推荐官方的 `@angular/cli` 工具链辅助进行开发，在实际项目开发中，它可以很好的满足对 TypeScript 代码的构建、调试、代理、打包部署等一系列工程化的需求。\n\n```bash\n$ ng new PROJECT_NAME\n$ cd PROJECT_NAME\n$ ng add ng-zorro-antd\n```\n\n> 如果你想了解更多CLI工具链的功能和命令，建议访问 [Angular CLI](https://github.com/angular/angular-cli) 了解更多\n\n## 链接\n\n- [首页](https://ng.ant.design)\n- [Angular官方文档](https://angular.dev/)\n- [开发脚手架](https://angular.cn/tools/cli)\n- [TypeScript](https://www.typescriptlang.org/)\n- [RxJS](https://github.com/ReactiveX/rxjs)\n- [VSCode Snippet 插件](https://marketplace.visualstudio.com/items?itemName=cipchk.ng-zorro-vscode)\n\n## 谁在使用\n\n- [阿里巴巴](https://www.alibaba.com/)\n- [阿里云](https://www.aliyun.com/)\n- [思特沃克](https://www.thoughtworks.com/)\n- [招商银行](https://www.cmbchina.com/)\n- [共道科技](https://www.gongdao.com/)\n- [优速快递](https://www.uce.cn/)\n- [轻流](https://qingflow.com/)\n- [航天信息股份有限公司](https://www.aisino.com/)\n- [达观数据](https://datagrand.com/)\n- [Ververica](https://www.ververica.com/)\n- [Apache Flink](https://flink.apache.org/)\n- [Apache Zeppelin](https://zeppelin.apache.org/)\n- [Apache Submarine](https://submarine.apache.org/)\n- [Apache Metron](https://metron.apache.org/)\n- [Process Automation Group](https://pag.company/)\n- [ScentBird](https://www.scentbird.com/)\n- [Southern Institute of Technology](https://www.sit.ac.nz/)\n- [Hapify (Dynamic boilerplates tool)](https://hub.hapify.io/)\n\n> 这里列出了部分使用者，如果你的公司和产品使用了 NG-ZORRO，欢迎到 [这里](https://github.com/NG-ZORRO/ng-zorro-antd/issues/1142) 留言。\n\n## 如何贡献\n\n在任何形式的参与前，请先阅读 [贡献者文档](https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/CONTRIBUTING.md)。如果你希望参与贡献，欢迎 [Pull Request](https://github.com/NG-ZORRO/ng-zorro-antd/pulls)，或给我们 [报告 Bug](https://ng.ant.design/issue-helper/#/en)。\n\n> 强烈推荐阅读 [《提问的智慧》](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way)、[《如何向开源社区提问题》](https://github.com/seajs/seajs/issues/545) 和 [《如何有效地报告 Bug》](https://www.chiark.greenend.org.uk/%7Esgtatham/bugs-cn.html)、[《如何向开源项目提交无法解答的问题》](https://zhuanlan.zhihu.com/p/25795393)，更好的问题更容易获得帮助。\n\n## 社区互助\n\n如果您在使用的过程中碰到问题，可以通过下面几个途径寻求帮助，同时我们也鼓励资深用户通过下面的途径给新人提供帮助。\n\n通过 Stack Overflow 或者 Segment Fault 提问时，建议加上 `ng-zorro-antd` 标签。\n\n1. [Stack Overflow](https://stackoverflow.com/questions/tagged/ng-zorro-antd)（English）\n2. [Segment Fault](https://segmentfault.com/t/ng-zorro)（中文）\n3. [Discussions · NG-ZORRO/ng-zorro-antd](https://github.com/NG-ZORRO/ng-zorro-antd/discussions)\n4. 加入钉钉 NG-ZORRO 自助服务群（中文）\n\n<img src=\"https://img.alicdn.com/imgextra/i2/O1CN01996NqO1ykdnAdOLqG_!!6000000006617-2-tps-864-822.png\" width=\"400\" height=\"400\" loading=\"lazy\" alt=\"ding talk qr-code\">\n"
  },
  {
    "path": "docs/join.en-US.md",
    "content": "---\norder: 16\ntitle: Join us\nhidden: true\n---\n"
  },
  {
    "path": "docs/join.zh-CN.md",
    "content": "---\norder: 16\ntitle: 社区招募\n---\n\nNG-ZORRO 经过多年发展，受到的许多开发者的青睐帮助，目前已成为年下载量超 **400+** 万的组件库。\n在此感谢每一位参与社区推广与开发的同学，以及每一位 NG-ZORRO 用户!\n\n## 求贤若渴\n\n为了更好地提升 NG-ZORRO 的用户体验，我们也期望更多的同学能够参与到组件库的日常开发与社区答疑，\n来帮助 NG-ZORRO 快速支持更多用户期待的功能开发与问题修复。\n<br>\n对于有意愿长期参与社区工作的同学，我们也会将各位加入到社区 Member 中来，共同管理 PR 及 Issue 答疑。\n\n## 欢迎咨询\n\n任何疑问可咨询：[simplejason.coder@gmail.com](mailto:simplejason.coder@gmail.com)\n<br>\n也可进钉钉群进行咨询，再次感谢每一位同学的努力与付出。\n"
  },
  {
    "path": "docs/llms.en-US.md",
    "content": "---\norder: 7\ntitle: LLMs.txt\ntag: new\n---\n\nThis guide explains how to enable AI tools like Cursor, Windsurf, and Claude to better understand `ng-zorro-antd`.\n\n## What is LLMs.txt?\n\nWe support [LLMs.txt](https://llmstxt.org/) files for making the Ant Design documentation available to large language models (LLMs). This feature helps AI tools better understand our component library, its APIs, and usage patterns.\n\n## Available Routes\n\nWe provide several LLMs.txt routes to help AI tools access our documentation:\n\n- [llms.txt](https://ng.ant.design/llms.txt) - Contains a structured overview of all components and their documentation links\n- [llms-full.txt](https://ng.ant.design/llms-full.txt) - Provides comprehensive documentation including implementation details and examples\n\n## Usage with AI Tools\n\n### GitHub Copilot\n\nIn GitHub Copilot, you can reference LLMs.txt files by adding them to your workspace's `.github/copilot-instructions.md` or mentioning the documentation URL directly in conversations.\n\n[Learn more about GitHub Copilot instructions](https://docs.github.com/en/copilot/customizing-copilot/adding-custom-instructions-for-github-copilot)\n\n### Cursor\n\nUse the `@Docs` feature in Cursor to include the LLMs.txt files in your project. This helps Cursor provide more accurate code suggestions and documentation for `ng-zorro-antd`.\n\n[Read more about @Docs in Cursor](https://docs.cursor.com/context/@-symbols/@-docs)\n\n### Windsurf\n\nReference the LLMs.txt files using `@` or in your `.windsurf/rules` files to enhance Windsurf's understanding of `ng-zorro-antd` components.\n\n[Read more about Windsurf Memories](https://docs.windsurf.com/windsurf/cascade/memories)\n\n### Claude Code\n\nIn Claude Code, add `LLMs.txt` to the workspace Knowledge Base (Docs / Context Files) configuration. This allows the file to be referenced during code completion and explanation, improving understanding of `ng-zorro-antd` components.\n\n[Learn more about Claude Code document context configuration](https://code.claude.com/docs)\n\n### Gemini CLI\n\nIn Gemini CLI, you can specify the `LLMs.txt` file path with the `--context` parameter or in `.gemini/config.json`, enabling Gemini to reference the document when answering or generating code.\n\n[Learn more about Gemini CLI context configuration](https://ai.google.dev/gemini-api/docs?hl=en)\n\n### Trae\n\nIn Trae, place the `LLMs.txt` file into the project’s knowledge sources and enable referencing in the settings.\n\n[Learn more about Trae knowledge sources](https://trae.ai/docs)\n\n### Qoder\n\nIn Qoder, you can add `LLMs.txt` as an external knowledge file in `.qoder/config.yml`, or temporarily reference it in a conversation with `@docs LLMs.txt`, enhancing support for `ng-zorro-antd` components.\n\n[Learn more about Qoder configuration](https://docs.qoder.com/)\n\n### Other AI Tools\n\nAny AI tool that supports LLMs.txt can use these routes to better understand `ng-zorro-antd`. Simply point your tool to any of the routes above.\n"
  },
  {
    "path": "docs/llms.zh-CN.md",
    "content": "---\norder: 7\ntitle: LLMs.txt\ntag: new\n---\n\n本指南介绍如何让 Cursor、Windsurf 和 Claude 等 AI 工具更好地理解 `ng-zorro-antd`。\n\n## 什么是 LLMs.txt？\n\n我们支持通过 [LLMs.txt](https://llmstxt.org/) 文件向大语言模型（LLMs）提供 Ant Design 文档。此功能可帮助 AI 工具更好地理解我们的组件库、API 及使用模式。\n\n## 可用资源\n\n我们提供多个 LLMs.txt 路由来帮助 AI 工具访问文档：\n\n- [llms.txt](https://ng.ant.design/llms.txt) - 包含所有组件及其文档链接的结构化概览\n- [llms-full.txt](https://ng.ant.design/llms-full.txt) - 提供包含实现细节和示例的完整文档\n\n## 在 AI 工具中的使用\n\n### GitHub Copilot\n\n在 GitHub Copilot 中，可以通过在工作区的 `.github/copilot-instructions.md` 文件中添加 LLMs.txt 的引用，或在对话中直接提及文档 URL 来使用。\n\n[详细了解 GitHub Copilot 自定义指令](https://docs.github.com/zh/copilot/customizing-copilot/adding-custom-instructions-for-github-copilot)\n\n### Cursor\n\n在 Cursor 中使用 `@Docs` 功能将 LLMs.txt 文件包含到您的项目中。这有助于 Cursor 为 `ng-zorro-antd` 组件提供更准确的代码建议和文档。\n\n[详细了解 Cursor 中的 @Docs 功能](https://docs.cursor.com/zh/context/@-symbols/@-docs)\n\n### Windsurf\n\n通过 `@` 引用或在 `.windsurf/rules` 文件中配置 LLMs.txt 文件，以增强 Windsurf 对 `ng-zorro-antd` 组件的理解。\n\n[详细了解 Windsurf Memories 功能](https://docs.windsurf.com/windsurf/cascade/memories)\n\n### Claude Code\n\n在 Claude Code 中，将 `LLMs.txt` 添加到工作区的知识库（Docs / Context Files）配置中，即可在代码补全与解释时引用其中的内容,从而提升对 Ant Design 组件的理解。\n\n[详细了解 Claude Code 文档上下文配置](https://code.claude.com/docs)\n\n### Gemini CLI\n\n在 Gemini CLI 中，可以通过 `--context` 参数或在 `.gemini/config.json` 中指定 `LLMs.txt` 文件路径，让 Gemini 在回答和生成代码时参考该文档。\n\n[详细了解 Gemini CLI 上下文配置](https://ai.google.dev/gemini-api/docs?hl=zh-cn)\n\n### Trae\n\n在 Trae 中，将 `LLMs.txt` 文件放入项目的 knowledge sources 并在设置里开启引用，即可让 Trae 在生成或分析代码时更好地支持 `ng-zorro-antd` 组件。\n\n[详细了解 Trae 的知识源功能](https://trae.ai/docs)\n\n### Qoder\n\n在 Qoder 中，可以在 `.qoder/config.yml` 中添加 `LLMs.txt` 作为外部知识文件，或在对话中通过 `@docs LLMs.txt` 进行临时引用，增强对 `ng-zorro-antd` 组件的支持。\n\n[详细了解 Qoder 配置方法](https://docs.qoder.com/)\n\n### 其他 AI 工具\n\n任何支持 LLMs.txt 的 AI 工具均可使用以上路径来更好地理解 `ng-zorro-antd`。\n"
  },
  {
    "path": "docs/migration-v21.en-US.md",
    "content": "---\norder: 15\ntitle: v21 Migration Guide\ntoc: false\n---\n\nThis document will help you upgrade from `ng-zorro-antd` 20.x version to 21.x version.\n\n## Before upgrade\n\n1. Make sure `Node.js` >= `20.19.0` or >= `22.12.0` or >= `24.0.0`.\n2. Create a new branch, or use other methods to back up the current project.\n3. Delete the package-lock.json file.\n\n## Upgrade steps\n\n### 1. Upgrade dependencies\n\n- Upgrade Angular to 21.x version, ref [https://angular.dev/update-guide](https://angular.dev/update-guide).\n- Run `ng update @angular/cdk`, if you have used `@angular/cdk`.\n- Remove the `@angular/animations` dependency as needed.\n\n### 2. Upgrade NG-ZORRO\n\n- Run `ng update ng-zorro-antd`.\n- If any warning messages appear in the console, follow the prompts to modify the corresponding code.\n\n### 3. Remove deprecated APIs\n\n- Remove deprecated APIs, please refer to the [v21 changelog](/docs/changelog/en#2100) for more information.\n"
  },
  {
    "path": "docs/migration-v21.zh-CN.md",
    "content": "---\norder: 15\ntitle: v21 升级指南\ntoc: false\n---\n\n本文档将帮助你从 `ng-zorro-antd` 20.x 版本升级到 21.x 版本。\n\n## 开始之前\n\n1. 确保 `Node.js` >= `20.19.0` 或 >= `22.12.0` 或 >= `24.0.0`\n2. 创建新的分支，或者使用其他方式备份当前项目\n3. 删除项目下 package-lock.json 文件\n\n## 升级步骤\n\n### 1. 升级相关依赖\n\n- 参考[升级指南](https://angular.dev/update-guide)将项目升级到 Angular 21\n- 如果有单独使用 `@angular/cdk` 请执行 `ng update @angular/cdk`\n- 按需移除 `@angular/animations` 依赖\n\n### 2. 升级 NG-ZORRO\n\n- 运行 `ng update ng-zorro-antd`\n- 如果控制台出现警告消息请按提示修改对应代码\n\n### 3. 移除废弃 API\n\n- 请参考 [v21 changelog](/docs/changelog/zh#2100) 移除废弃 API\n"
  },
  {
    "path": "docs/recommendation.en-US.md",
    "content": "---\norder: 10\ntitle: Resources\n---\n\n## Tools\n\n`ng-zorro-antd` is essentially implementing Ant Design in Angular. We recommend you to use the following existing\nresources, which can hopefully serve well during your project development.\n\n| Category         | Recommended Components                                           | Details                                        |\n| ---------------- | ---------------------------------------------------------------- | ---------------------------------------------- |\n| Component Lib    | [NG ALAIN](https://ng-alain.com/)                                | Admin Template work with ng-zorro-antd         |\n| Component Lib    | [ng-antd-admin](https://github.com/huajian123/ng-antd-admin)     | The Admin Template imitating Ant Design Pro    |\n| Component Lib    | [Material Design](https://material.angular.io)                   | Material Design                                |\n| Component Lib    | [Clarity](https://github.com/vmware/clarity)                     | Vmware Angular Component Lib                   |\n| Component Lib    | [Nebular](https://github.com/akveo/nebular/)                     | Nebular Angular Component Lib                  |\n| Component Lib    | [Bootstrap](https://github.com/ng-bootstrap/ng-bootstrap)        | Bootstrap Angular Component Lib                |\n| Component Lib    | [DevUI](https://github.com/DevCloudFE/ng-devui)                  | Huawei Angular Component Lib                   |\n| Component Lib    | [ng-zorro-mobile](https://ng.mobile.ant.design/)                 | Ant Design Mobile of Angular                   |\n| Component Lib    | [Jigsaw](https://github.com/rdkmaster/jigsaw)                    | ZTE Angular Component Lib                      |\n| Component Lib    | [ag-Grid](https://www.ag-grid.com/angular-grid/)                 | Angular Grid Component                         |\n| Component Lib    | [ngx-datatable](https://github.com/swimlane/ngx-datatable)       | Swimlane Grid Component                        |\n| Component Lib    | [ngx-charts](https://swimlane.github.io/ngx-charts/)             | Charts based on D3                             |\n| Component Lib    | [ngx-graph](https://swimlane.github.io/ngx-graph/)               | Graph based on dagre.js                        |\n| Component Lib    | [ngx-formly](https://github.com/ngx-formly/ngx-formly)           | Form based on JSON schema                      |\n| Dev Kit          | [Component Dev Kit](https://material.angular.io/cdk/categories)  | Component Developer Kit                        |\n| Dev Kit          | [Spectator](https://github.com/ngneat/spectator)                 | A Powerful Tool to Simplify Your Angular Tests |\n| Dev Kit          | [Scully](https://github.com/scullyio/scully)                     | The Static Site Generator for Angular apps     |\n| Dev Kit          | [Angular CLI](https://angular.dev/tools/cli)                     | Angular CLI                                    |\n| Dev Kit          | [Angular Builders](https://github.com/just-jeb/angular-builders) | Angular build facade extensions                |\n| Dev Kit          | [ngx-planet](https://github.com/worktile/ngx-planet)             | Micro Frontend library for Angular             |\n| Dev Kit          | [@angular/ssr](https://angular.dev/guide/ssr/)                   | Server-side Rendering                          |\n| State Management | [Akita](https://datorama.github.io/akita/)                       | Akita state management                         |\n| State Management | [ngxs](https://ngxs.io/)                                         | NGXS state management                          |\n| State Management | [ngrx](https://ngrx.io/)                                         | NGRX state management                          |\n\n## Blog & Website\n\n- [Angular](https://angular.dev/)\n- [Angular Blog](https://blog.angular.dev/)\n- [Angular Weekly Meeting Notes](https://g.co/ng/weekly-notes)\n- [ThoughtRam Blog](https://blog.thoughtram.io/)\n- [Mgechev Blog](https://blog.mgechev.com/)\n- [Angular In Depth](https://indepth.dev/)\n- [Angular Fast](https://web.dev/angular/#fast)\n\n## Design Resources\n\nSeveral designing resources which are relevant to Ant Design are provided below. You may write feedback about the Sketch Symbols component [here](https://www.yuque.com/kitchen/topics/216).\n\n<div class=\"ant-row resource-cards\" style=\"margin:-12px -12px 0 -12px\"><div class=\"ant-col ant-col-xs-24 ant-col-sm-12 ant-col-md-8 ant-col-lg-8 gutter-row\" style=\"padding:12px\"><a class=\"resource-card\" target=\"_blank\" rel=\"noopener\" href=\"https://github.com/ant-design/ant-design/releases/download/resource/Ant.Design.Components.4.0.zip\"><img class=\"resource-card-image\" src=\"https://gw.alipayobjects.com/zos/basement_prod/048ee28f-2c80-4d15-9aa3-4f5ddac50465.svg\" alt=\"RENEW Sketch Symbols\"><p class=\"resource-card-title\">RENEW Sketch Symbols</p><p class=\"resource-card-description\">Sketch Symbols for Desktop</p></a></div><div class=\"ant-col ant-col-xs-24 ant-col-sm-12 ant-col-md-8 ant-col-lg-8 gutter-row\" style=\"padding:12px\"><a class=\"resource-card\" target=\"_blank\" rel=\"noopener\" href=\"http://p.tb.cn/rmsportal_3436_AntDesignMobile_20Template_20V1.0.sketch\"><img class=\"resource-card-image\" src=\"https://gw.alipayobjects.com/zos/basement_prod/c0c3852c-d245-4330-886b-cb02ef49eb6d.svg\" alt=\"Mobile Components\"><p class=\"resource-card-title\">Mobile Components</p><p class=\"resource-card-description\">Sketch Symbols File for Mobile</p></a></div><div class=\"ant-col ant-col-xs-24 ant-col-sm-12 ant-col-md-8 ant-col-lg-8 gutter-row\" style=\"padding:12px\"><a class=\"resource-card\" target=\"_blank\" rel=\"noopener\" href=\"https://github.com/ant-design/ant-design/releases/download/resource/Ant.Design.Pro.3.0.sketch\"><img class=\"resource-card-image\" src=\"https://gw.alipayobjects.com/zos/basement_prod/5edc7f4d-3302-4710-963b-7b6c77ea8d06.svg\" alt=\"Ant Design Pro\"><p class=\"resource-card-title\">Ant Design Pro</p><p class=\"resource-card-description\">Common Templates and Pages</p></a></div><div class=\"ant-col ant-col-xs-24 ant-col-sm-12 ant-col-md-8 ant-col-lg-8 gutter-row\" style=\"padding:12px\"><a class=\"resource-card\" target=\"_blank\" rel=\"noopener\" href=\"http://library.ant.design\"><img class=\"resource-card-image\" src=\"https://gw.alipayobjects.com/zos/basement_prod/90740380-bbb7-4329-95e5-64533934c6cf.svg\" alt=\"Ant Design Library\"><p class=\"resource-card-title\">Ant Design Library</p><p class=\"resource-card-description\">A powerful Axure library</p></a></div><div class=\"ant-col ant-col-xs-24 ant-col-sm-12 ant-col-md-8 ant-col-lg-8 gutter-row\" style=\"padding:12px\"><a class=\"resource-card\" target=\"_blank\" rel=\"noopener\" href=\"http://kitchen.alipay.com\"><img class=\"resource-card-image\" src=\"https://gw.alipayobjects.com/zos/basement_prod/d475d063-2754-4442-b9db-5d164e06acc9.svg\" alt=\"Kitchen\"><p class=\"resource-card-title\">Kitchen</p><p class=\"resource-card-description\">A Sketch plugin collection</p></a></div><div class=\"ant-col ant-col-xs-24 ant-col-sm-12 ant-col-md-8 ant-col-lg-8 gutter-row\" style=\"padding:12px\"><a class=\"resource-card\" target=\"_blank\" rel=\"noopener\" href=\"https://landing.ant.design/docs/download-cn\"><img class=\"resource-card-image\" src=\"https://gw.alipayobjects.com/zos/basement_prod/b443f4be-5116-49b7-873f-a7c8502b8f0e.svg\" alt=\"Ant Design Landing\"><p class=\"resource-card-title\">Ant Design Landing</p><p class=\"resource-card-description\">Landing Templates</p></a></div><div class=\"ant-col ant-col-xs-24 ant-col-sm-12 ant-col-md-8 ant-col-lg-8 gutter-row\" style=\"padding:12px\"><a class=\"resource-card\" target=\"_blank\" rel=\"noopener\" href=\"http://ux.ant.design\"><img class=\"resource-card-image\" src=\"https://gw.alipayobjects.com/zos/basement_prod/51682163-e01a-46fe-810c-ac0062379717.svg\" alt=\"Ant UX\"><p class=\"resource-card-title\">Ant UX</p><p class=\"resource-card-description\">A set of page logic prototype libraries</p></a></div><div class=\"ant-col ant-col-xs-24 ant-col-sm-12 ant-col-md-8 ant-col-lg-8 gutter-row\" style=\"padding:12px\"><a class=\"resource-card\" target=\"_blank\" rel=\"noopener\" href=\"https://www.xiaopiu.com/topic/ant-design\"><img class=\"resource-card-image\" src=\"https://gw.alipayobjects.com/zos/basement_prod/77e6a9ae-24a9-4be6-be42-f7fa8ee0eecf.svg\" alt=\"Ant Design Prototype (xiaopiu)\"><p class=\"resource-card-title\">Ant Design Prototype (xiaopiu)</p><p class=\"resource-card-description\">Online library and prototype</p></a></div><div class=\"ant-col ant-col-xs-24 ant-col-sm-12 ant-col-md-8 ant-col-lg-8 gutter-row\" style=\"padding:12px\"><a class=\"resource-card\" target=\"_blank\" rel=\"noopener\" href=\"https://www.antforfigma.com\"><img class=\"resource-card-image\" src=\"https://gw.alipayobjects.com/zos/basement_prod/7b9ed3f2-6f05-4ddb-bac3-d55feb71e0ac.svg\" alt=\"UI Kit for Figma\"><p class=\"resource-card-title\">UI Kit for Figma</p><p class=\"resource-card-description\">Library of components for Desktop</p></a></div><div class=\"ant-col ant-col-xs-24 ant-col-sm-12 ant-col-md-8 ant-col-lg-8 gutter-row\" style=\"padding:12px\"><a class=\"resource-card\" target=\"_blank\" rel=\"noopener\" href=\"https://gw.alipayobjects.com/os/basement_prod/862ee74f-4ac5-482c-b1ae-3165684cedbe.sketch\"><img class=\"resource-card-image\" src=\"https://gw.alipayobjects.com/zos/basement_prod/a9dc586a-fe0a-4c7d-ab4f-f5ed779b963d.svg\" alt=\"Ant Design Chart\"><p class=\"resource-card-title\">Ant Design Chart</p><p class=\"resource-card-description\">Sketch Symbols for Chart</p></a></div></div>\n"
  },
  {
    "path": "docs/recommendation.zh-CN.md",
    "content": "---\norder: 10\ntitle: 资源推荐\n---\n\n我们根据自己的开发和使用经验总结了一些可能对开发者有用的资源。\n\n## 工具及解决方案\n\n`ng-zorro-antd` 是 Ant Design 设计规范的 Angular 实现，我们推荐使用以下社区已有的优秀实现和网站，希望能为你的开发过程提供帮助。\n\n| 类型       | 名称                                                             | 描述                                                                                     |\n| ---------- | ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |\n| 组件库     | [NG ALAIN](https://ng-alain.com/)                                | [cipchk](https://github.com/cipchk) 个人开发的基于 `ng-zorro-antd` 的 Admin 系统解决方案 |\n| 组件库     | [ng-antd-admin](https://github.com/huajian123/ng-antd-admin)     | [华舰](https://github.com/huajian123) 个人开发的仿 Ant Design Pro 的 Admin 模板          |\n| 组件库     | [Material Design](https://material.angular.io)                   | Angular 官方 Material 组件库                                                             |\n| 组件库     | [Clarity](https://github.com/vmware/clarity)                     | Vmware Angular 组件库                                                                    |\n| 组件库     | [Nebular](https://github.com/akveo/nebular/)                     | Nebular Angular 组件库                                                                   |\n| 组件库     | [Bootstrap](https://github.com/ng-bootstrap/ng-bootstrap)        | Bootstrap Angular 组件库                                                                 |\n| 组件库     | [ng-zorro-mobile](https://ng.mobile.ant.design/)                 | Ant Design Mobile 设计规范的 Angular 实现                                                |\n| 组件库     | [DevUI](https://github.com/DevCloudFE/ng-devui)                  | 华为 Angular 组件库                                                                      |\n| 组件库     | [Jigsaw](https://github.com/rdkmaster/jigsaw)                    | 中兴 Angular 组件库                                                                      |\n| 组件库     | [ag-Grid](https://www.ag-grid.com/angular-grid/)                 | Angular 表格综合解决方案                                                                 |\n| 组件库     | [ngx-datatable](https://github.com/swimlane/ngx-datatable)       | Swimlane 的 Table 解决方案                                                               |\n| 组件库     | [ngx-charts](https://swimlane.github.io/ngx-charts/)             | 基于 D3 的Angular 可视化组件库                                                           |\n| 组件库     | [ngx-graph](https://swimlane.github.io/ngx-graph/)               | 基于 Dagre 的有向无环图可视化组件库                                                      |\n| 组件库     | [ngx-formly](https://github.com/ngx-formly/ngx-formly)           | 基于 JSON Schema 的表单方案                                                              |\n| 开发工具   | [Component Dev Kit](https://material.angular.io/cdk/categories)  | Angular 官方的提供的组件库工具，包含拖拽、浮层、虚拟滚动等大量功能                       |\n| 开发工具   | [Spectator](https://github.com/ngneat/spectator)                 | Angular 测试工具库                                                                       |\n| 开发工具   | [Scully](https://github.com/scullyio/scully)                     | 基于 Angular 的静态博客生成器                                                            |\n| 开发工具   | [Angular CLI](https://angular.cn/tools/cli)                      | Angular 的配套打包工具                                                                   |\n| 开发工具   | [Angular Builders](https://github.com/just-jeb/angular-builders) | Angular CLI 的 Webpack 拓展工具                                                          |\n| 开发工具   | [ngx-planet](https://github.com/worktile/ngx-planet)             | Angular 的微前端方案                                                                     |\n| 开发工具   | [@angular/ssr](https://angular.cn/guide/ssr)                     | Angular 服务端渲染工具                                                                   |\n| 数据流方案 | [Akita](https://datorama.github.io/akita/)                       | Akita 数据流方案                                                                         |\n| 数据流方案 | [ngxs](https://ngxs.io/)                                         | NGXS 数据流方案                                                                          |\n| 数据流方案 | [ngrx](https://ngrx.io/)                                         | NGRX 数据流方案                                                                          |\n\n## 博客及网站\n\n这里包含了一些优秀的 Angular 博客和网站，供开发者参考。\n\n- [Angular In Depth](https://indepth.dev/)\n- [Angular调优指南](https://web.dev/angular/#fast)\n- [Angular中文官网](https://angular.cn/)\n- [Angular英文官网](https://angular.dev/)\n- [Mgechev Blog](https://blog.mgechev.com/)\n- [ThoughtRam Blog](https://blog.thoughtram.io/)\n- [Reactive How](https://reactive.how/)\n- [30 天精通 RxJS](https://blog.jerry-hong.com/series/rxjs)\n- [Angular官方博客](https://blog.angular.dev)\n- [Angular Weekly Meeting Notes](https://g.co/ng/weekly-notes)\n\n## 设计资源\n\n这里提供 Ant Design 相关设计资源和设计工具的下载，更多设计资源正在整理和完善中。你可以在这个[地址](https://www.yuque.com/kitchen/topics/216)中反馈对新版本 Sketch Symbols 组件的意见。\n\n<div class=\"ant-row resource-cards\" style=\"margin: -12px -12px 0px;\"><div class=\"ant-col ant-col-xs-24 ant-col-sm-12 ant-col-md-8 ant-col-lg-8 gutter-row\" style=\"padding: 12px;\"><a class=\"resource-card\" target=\"_blank\" rel=\"noopener\" href=\"https://gw.alipayobjects.com/os/antfincdn/EfSt1N5LCk/Ant.Design.Components.4.0.zip\"><img class=\"resource-card-image\" src=\"https://gw.alipayobjects.com/zos/basement_prod/048ee28f-2c80-4d15-9aa3-4f5ddac50465.svg\" alt=\"全新 Sketch 组件包\"><p class=\"resource-card-title\">全新 Sketch 组件包</p><p class=\"resource-card-description\">桌面组件 Sketch 模板包</p></a></div><div class=\"ant-col ant-col-xs-24 ant-col-sm-12 ant-col-md-8 ant-col-lg-8 gutter-row\" style=\"padding: 12px;\"><a class=\"resource-card\" target=\"_blank\" rel=\"noopener\" href=\"http://p.tb.cn/rmsportal_3436_AntDesignMobile_20Template_20V1.0.sketch\"><img class=\"resource-card-image\" src=\"https://gw.alipayobjects.com/zos/basement_prod/c0c3852c-d245-4330-886b-cb02ef49eb6d.svg\" alt=\"Mobile Components\"><p class=\"resource-card-title\">Mobile Components</p><p class=\"resource-card-description\">移动组件 Sketch 模板</p></a></div><div class=\"ant-col ant-col-xs-24 ant-col-sm-12 ant-col-md-8 ant-col-lg-8 gutter-row\" style=\"padding: 12px;\"><a class=\"resource-card\" target=\"_blank\" rel=\"noopener\" href=\"https://gw.alipayobjects.com/os/bmw-prod/e9882e0c-a85c-428a-b8a8-656f1aa83036.sketch\"><img class=\"resource-card-image\" src=\"https://gw.alipayobjects.com/zos/basement_prod/5edc7f4d-3302-4710-963b-7b6c77ea8d06.svg\" alt=\"Ant Design Pro\"><p class=\"resource-card-title\">Ant Design Pro</p><p class=\"resource-card-description\">典型页面 + 通用业务模板</p></a></div><div class=\"ant-col ant-col-xs-24 ant-col-sm-12 ant-col-md-8 ant-col-lg-8 gutter-row\" style=\"padding: 12px;\"><a class=\"resource-card\" target=\"_blank\" rel=\"noopener\" href=\"http://library.ant.design\"><img class=\"resource-card-image\" src=\"https://gw.alipayobjects.com/zos/basement_prod/90740380-bbb7-4329-95e5-64533934c6cf.svg\" alt=\"Ant Design Library\"><p class=\"resource-card-title\">Ant Design Library</p><p class=\"resource-card-description\">一套强大的 Axure 部件库</p></a></div><div class=\"ant-col ant-col-xs-24 ant-col-sm-12 ant-col-md-8 ant-col-lg-8 gutter-row\" style=\"padding: 12px;\"><a class=\"resource-card\" target=\"_blank\" rel=\"noopener\" href=\"http://kitchen.alipay.com\"><img class=\"resource-card-image\" src=\"https://gw.alipayobjects.com/zos/basement_prod/d475d063-2754-4442-b9db-5d164e06acc9.svg\" alt=\"Kitchen\"><p class=\"resource-card-title\">Kitchen</p><p class=\"resource-card-description\">Sketch 工具集</p></a></div><div class=\"ant-col ant-col-xs-24 ant-col-sm-12 ant-col-md-8 ant-col-lg-8 gutter-row\" style=\"padding: 12px;\"><a class=\"resource-card\" target=\"_blank\" rel=\"noopener\" href=\"https://landing.ant.design/docs/download-cn\"><img class=\"resource-card-image\" src=\"https://gw.alipayobjects.com/zos/basement_prod/b443f4be-5116-49b7-873f-a7c8502b8f0e.svg\" alt=\"Ant Design Landing\"><p class=\"resource-card-title\">Ant Design Landing</p><p class=\"resource-card-description\">首页模板集</p></a></div><div class=\"ant-col ant-col-xs-24 ant-col-sm-12 ant-col-md-8 ant-col-lg-8 gutter-row\" style=\"padding: 12px;\"><a class=\"resource-card\" target=\"_blank\" rel=\"noopener\" href=\"http://ux.ant.design\"><img class=\"resource-card-image\" src=\"https://gw.alipayobjects.com/zos/basement_prod/51682163-e01a-46fe-810c-ac0062379717.svg\" alt=\"Ant UX\"><p class=\"resource-card-title\">Ant UX</p><p class=\"resource-card-description\">一套页面逻辑原型库</p></a></div><div class=\"ant-col ant-col-xs-24 ant-col-sm-12 ant-col-md-8 ant-col-lg-8 gutter-row\" style=\"padding: 12px;\"><a class=\"resource-card\" target=\"_blank\" rel=\"noopener\" href=\"https://www.xiaopiu.com/topic/ant-design\"><img class=\"resource-card-image\" src=\"https://gw.alipayobjects.com/zos/basement_prod/77e6a9ae-24a9-4be6-be42-f7fa8ee0eecf.svg\" alt=\"Ant Design 原型 (xiaopiu)\"><p class=\"resource-card-title\">Ant Design 原型 (xiaopiu)</p><p class=\"resource-card-description\">可在线编辑的组件库和交互原型</p></a></div><div class=\"ant-col ant-col-xs-24 ant-col-sm-12 ant-col-md-8 ant-col-lg-8 gutter-row\" style=\"padding: 12px;\"><a class=\"resource-card\" target=\"_blank\" rel=\"noopener\" href=\"https://www.antforfigma.com\"><img class=\"resource-card-image\" src=\"https://gw.alipayobjects.com/zos/basement_prod/7b9ed3f2-6f05-4ddb-bac3-d55feb71e0ac.svg\" alt=\"Figma 组件包\"><p class=\"resource-card-title\">Figma 组件包</p><p class=\"resource-card-description\">在 Figma 使用 Ant Design 进行设计</p></a></div><div class=\"ant-col ant-col-xs-24 ant-col-sm-12 ant-col-md-8 ant-col-lg-8 gutter-row\" style=\"padding: 12px;\"><a class=\"resource-card\" target=\"_blank\" rel=\"noopener\" href=\"https://gw.alipayobjects.com/os/basement_prod/862ee74f-4ac5-482c-b1ae-3165684cedbe.sketch\"><img class=\"resource-card-image\" src=\"https://gw.alipayobjects.com/zos/basement_prod/a9dc586a-fe0a-4c7d-ab4f-f5ed779b963d.svg\" alt=\"全新 Chart 组件包\"><p class=\"resource-card-title\">全新 Chart 组件包</p><p class=\"resource-card-description\">桌面组件 Chart 模板包</p></a></div></div>\n"
  },
  {
    "path": "docs/schematics.en-US.md",
    "content": "---\norder: 2\ntitle: Schematics\n---\n\nUsing a CLI helps initialize projects, generate template codes and reduce development time.\n\n> The`ng-zorro-antd` scaffolding is essentially based on [schematics](https://blog.angular.dev/schematics-an-introduction-dc1dfbc2a2b2).\n\n## Initialize A Project\n\nInitialize a project with `ng-zorro-antd`.\n\nRun the command `ng add ng-zorro-antd` under your project directory, and follow the options to configure settings including whether you want to import i18n files and stylesheets, and load initial modules.\n\n<img alt=\"NG-ZORRO CLI\" style=\"display: block; border-radius: 4px; box-shadow: 1px 1px 4px 0px rgba(0, 0, 0, 0.2);\" src=\"https://img.alicdn.com/tfs/TB19fFHdkxz61VjSZFtXXaDSVXa-680-243.svg\">\n\nIn the meantime, you can choose an existing project template while creating your project, and then develop the project on the basis of it.\n\n<img alt aria-hidden=\"true\" style=\"display: block; border-radius: 4px; box-shadow: 1px 1px 4px 0px rgba(0, 0, 0, 0.2); max-width: 680px;\" src=\"https://img.alicdn.com/tfs/TB1IC0TeEWF3KVjSZPhXXXclXXa-2000-1078.png\">\n\n### Command\n\n```bash\nng add ng-zorro-antd [options]\n```\n\n## Component Generation\n\nThere are template source codes under every component API show case, you may obtain these codes by expanding `Show Code`.\n\n### Command\n\n```bash\nng g ng-zorro-antd:[schematic] <name> [options]\n```\n\nFor example, you can generate a login form with the follow command.\n\n```bash\nng g ng-zorro-antd:form-normal-login login\n```\n"
  },
  {
    "path": "docs/schematics.zh-CN.md",
    "content": "---\norder: 2\ntitle: 脚手架\n---\n\n使用脚手架可以更加方便的初始化项目，生成模板代码，节省开发时间。\n\n> 脚手架部分完全基于 [Schematics](https://blog.angular.dev/schematics-an-introduction-dc1dfbc2a2b2) 部分进行开发。\n\n## 项目初始化\n\n在项目下运行命令 `ng add ng-zorro-antd` 跟随选项便可完成初始化配置，包括引入国际化文件，导入模块，引入样式文件等工作。\n\n<img alt=\"NG-ZORRO CLI\" style=\"display: block; border-radius: 4px; box-shadow: 1px 1px 4px 0px rgba(0, 0, 0, 0.2);\" src=\"https://img.alicdn.com/tfs/TB19fFHdkxz61VjSZFtXXaDSVXa-680-243.svg\">\n\n同时你可以通过选择预设的模板创建一个 Angular 项目，并在此基础上进行开发。\n\n<img alt aria-hidden=\"true\" style=\"display: block; border-radius: 4px; box-shadow: 1px 1px 4px 0px rgba(0, 0, 0, 0.2); max-width: 680px;\" src=\"https://img.alicdn.com/tfs/TB1IC0TeEWF3KVjSZPhXXXclXXa-2000-1078.png\">\n\n## 生成组件\n\n快速生成模板代码，每个官网的代码演示都附有可生成的模板，开发者可以通过展开每个组件的代码演示部分获取其生成代码。\n\n### 命令\n\n```bash\nng g ng-zorro-antd:[schematic] <name> [options]\n```\n\n例如通过以下代码可以快速生成一个登录框组件\n\n```bash\nng g ng-zorro-antd:form-normal-login login\n```\n"
  },
  {
    "path": "eslint.config.mjs",
    "content": "// @ts-check\n\nimport eslint from '@eslint/js';\nimport markdown from '@eslint/markdown';\nimport angular from 'angular-eslint';\nimport tseslint from 'typescript-eslint';\n\nimport header from 'eslint-plugin-header';\nimport importPlugin from 'eslint-plugin-import';\nimport jsdoc from 'eslint-plugin-jsdoc';\nimport prettier from 'eslint-plugin-prettier';\nimport unusedImports from 'eslint-plugin-unused-imports';\n\nheader.rules.header.meta.schema = false;\n\nexport default tseslint.config(\n  {\n    ignores: [\n      '.*/',\n      'site/',\n      'publish/',\n      'lib/',\n      'dist/',\n      'scripts/site/{doc,template}/**/*',\n      'junit/',\n      'coverage-report/'\n    ]\n  },\n  {\n    files: ['**/*.ts'],\n    languageOptions: {\n      parserOptions: {\n        projectService: true,\n        tsconfigRootDir: import.meta.dirname\n      }\n    },\n    plugins: {\n      jsdoc,\n      import: importPlugin,\n      header,\n      prettier,\n      'unused-imports': unusedImports\n    },\n    extends: [\n      eslint.configs.recommended,\n      ...tseslint.configs.recommended,\n      ...tseslint.configs.stylistic,\n      ...angular.configs.tsRecommended\n    ],\n    processor: angular.processInlineTemplates,\n    rules: {\n      'prettier/prettier': 'error',\n      'header/header': [\n        2,\n        'block',\n        [\n          '*',\n          ' * Use of this source code is governed by an MIT-style license that can be',\n          ' * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE',\n          ' '\n        ],\n        2\n      ],\n      '@angular-eslint/component-selector': [\n        'error',\n        {\n          type: ['element', 'attribute'],\n          prefix: ['nz', 'test'],\n          style: 'kebab-case'\n        }\n      ],\n      '@angular-eslint/directive-class-suffix': [\n        'error',\n        {\n          suffixes: ['Directive', 'Component', 'Base']\n        }\n      ],\n      '@angular-eslint/directive-selector': [\n        'warn',\n        [\n          {\n            type: 'attribute',\n            prefix: ['nz'],\n            style: 'camelCase'\n          },\n          {\n            type: 'element',\n            prefix: ['nz'],\n            style: 'kebab-case'\n          }\n        ]\n      ],\n      '@angular-eslint/prefer-inject': 'off',\n      '@angular-eslint/no-rename-input': 'off',\n      '@angular-eslint/no-attribute-decorator': 'error',\n      '@angular-eslint/no-conflicting-lifecycle': 'off',\n      '@angular-eslint/no-forward-ref': 'off',\n      '@angular-eslint/no-host-metadata-property': 'off',\n      '@angular-eslint/no-lifecycle-call': 'off',\n      '@angular-eslint/no-pipe-impure': 'error',\n      '@angular-eslint/prefer-output-readonly': 'error',\n      '@angular-eslint/use-component-selector': 'off',\n      '@angular-eslint/use-component-view-encapsulation': 'off',\n      '@angular-eslint/no-implicit-take-until-destroyed': 'error',\n      '@angular-eslint/consistent-component-styles': [\n        'error',\n        'string'\n      ],\n      '@angular-eslint/use-lifecycle-interface': 'error',\n      '@typescript-eslint/array-type': [\n        'error',\n        {\n          default: 'array-simple'\n        }\n      ],\n      '@typescript-eslint/no-empty-object-type': [\n        'error',\n        {\n          allowInterfaces: 'always',\n          allowObjectTypes: 'always'\n        }\n      ],\n      '@typescript-eslint/ban-ts-comment': 'off',\n      '@typescript-eslint/no-unsafe-function-type': 'error',\n      '@typescript-eslint/no-wrapper-object-types': 'error',\n      '@typescript-eslint/consistent-indexed-object-style': 'off',\n      '@typescript-eslint/consistent-type-definitions': 'error',\n      '@typescript-eslint/explicit-member-accessibility': [\n        'off',\n        {\n          accessibility: 'explicit'\n        }\n      ],\n      '@typescript-eslint/no-empty-function': 'off',\n      '@typescript-eslint/no-explicit-any': 'error',\n      '@typescript-eslint/no-floating-promises': 'off',\n      '@typescript-eslint/no-for-in-array': 'error',\n      '@typescript-eslint/no-inferrable-types': [\n        'error',\n        {\n          ignoreParameters: true,\n          ignoreProperties: true\n        }\n      ],\n      '@typescript-eslint/no-non-null-assertion': 'off',\n      '@typescript-eslint/no-this-alias': 'error',\n      '@typescript-eslint/naming-convention': 'off',\n      '@typescript-eslint/no-unused-expressions': 'off',\n      '@typescript-eslint/explicit-function-return-type': [\n        'error',\n        {\n          allowExpressions: true,\n          allowConciseArrowFunctionExpressionsStartingWithVoid: true\n        }\n      ],\n      '@typescript-eslint/no-require-imports': 'warn',\n      '@typescript-eslint/no-unused-vars': 'off',\n      'unused-imports/no-unused-imports': 'error',\n      'unused-imports/no-unused-vars': [\n        'warn',\n        {\n          vars: 'all',\n          varsIgnorePattern: '^_',\n          args: 'after-used',\n          argsIgnorePattern: '^_'\n        }\n      ],\n      'prefer-arrow/prefer-arrow-functions': 'off',\n      'import/no-cycle': 'error',\n      'import/no-duplicates': 'error',\n      'import/no-unused-modules': 'error',\n      'import/no-unassigned-import': 'error',\n      'import/order': [\n        'error',\n        {\n          alphabetize: { order: 'asc', caseInsensitive: false },\n          'newlines-between': 'always',\n          groups: ['external', 'builtin', 'internal', ['parent', 'sibling', 'index']],\n          pathGroups: [\n            {\n              pattern: '{@angular/**,rxjs,rxjs/operators}',\n              group: 'external',\n              position: 'before'\n            },\n            {\n              pattern: 'ng-zorro-antd/**',\n              group: 'internal',\n              position: 'before'\n            }\n          ],\n          pathGroupsExcludedImportTypes: []\n        }\n      ],\n      'no-prototype-builtins': 'off',\n      'no-bitwise': 'off',\n      'no-duplicate-imports': 'error',\n      'no-invalid-this': 'off',\n      'no-irregular-whitespace': 'error',\n      'no-magic-numbers': 'off',\n      'no-multiple-empty-lines': 'error',\n      'no-redeclare': 'off',\n      'no-underscore-dangle': 'off',\n      'no-sparse-arrays': 'error',\n      'no-template-curly-in-string': 'off',\n      'prefer-object-spread': 'error',\n      'prefer-template': 'error',\n      yoda: 'error'\n    }\n  },\n  {\n    files: ['components/**/demo/*.ts'],\n    rules: {\n      'header/header': 'off'\n    }\n  },\n  {\n    files: ['**/*.html'],\n    plugins: {\n      prettier\n    },\n    extends: [\n      ...angular.configs.templateRecommended\n      // todo(a11y)\n      // ...angular.configs.templateAccessibility,\n    ],\n    rules: {\n      'prettier/prettier': [\n        'error',\n        {\n          parser: 'angular'\n        }\n      ],\n      '@angular-eslint/template/prefer-self-closing-tags': 'error',\n      '@angular-eslint/template/prefer-at-empty': 'error',\n      '@angular-eslint/template/prefer-static-string-properties': 'error',\n      '@angular-eslint/template/prefer-contextual-for-variables': 'error',\n      // TODO: This rule has some bugs; we'll try enabling it again in the future.\n      // '@angular-eslint/template/prefer-template-literal': 'error',\n    }\n  },\n  {\n    files: ['**/*.md'],\n    plugins: {\n      prettier,\n      markdown\n    },\n    extends: [markdown.configs.recommended],\n    rules: {\n      'prettier/prettier': 'error',\n      'markdown/no-missing-label-refs': 'off'\n    }\n  }\n);\n"
  },
  {
    "path": "gulpfile.js",
    "content": "const path = require('path');\n\nconst projectDir = __dirname;\nconst tsconfigPath = path.join(projectDir, 'scripts/gulp/tsconfig.json');\n\nif (projectDir.includes(' ')) {\n  console.error('Error: Cannot run the build tasks if the project is ' +\n    'located in a directory with spaces in between. Please rename your project directory.');\n  process.exit(1);\n}\n\n// Register TS compilation.\nrequire('ts-node').register({\n  project: tsconfigPath\n});\n\nrequire('./scripts/gulp/gulpfile');"
  },
  {
    "path": "ngsw-config.json",
    "content": "{\n  \"index\": \"/index.html\",\n  \"assetGroups\": [\n    {\n      \"name\": \"app\",\n      \"installMode\": \"prefetch\",\n      \"updateMode\": \"prefetch\",\n      \"ignoreSearch\": true,\n      \"resources\": {\n        \"files\": [\n          \"/favicon.ico\",\n          \"/index.html\",\n          \"/*.css\",\n          \"/*.js\",\n          \"!/*-es5*.js\"\n        ],\n        \"urls\": [\n          \"https://gw.alipayobjects.com/**\",\n          \"https://img.alicdn.com/**\"\n        ]\n      }\n    }, {\n      \"name\": \"assets\",\n      \"installMode\": \"lazy\",\n      \"updateMode\": \"prefetch\",\n      \"resources\": {\n        \"files\": [\n          \"/assets/**\",\n          \"!/assets/codes/**\"\n        ]\n      }\n    }\n  ],\n  \"navigationUrls\": [\n    \"/**\",\n    \"!/**/*.*\",\n    \"!/**/*__*\",\n    \"!/**/*__*/**\",\n    \"!/assets/codes/**\",\n    \"!/**/stackblitz\",\n    \"!/version/**\",\n    \"!/issue-helper/**\",\n    \"!/blog/**\",\n    \"!/docs/**/*\",\n    \"!/docs/?*\",\n    \"!/components/**/*\",\n    \"!/components/?*\",\n    \"!/experimental/**/*\",\n    \"!/experimental/?*\",\n    \"!/x/**/*\"\n  ]\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"ng-zorro-antd\",\n  \"version\": \"0.0.0-NOT-USED\",\n  \"license\": \"MIT\",\n  \"description\": \"An enterprise-class UI components based on Ant Design and Angular\",\n  \"engines\": {\n    \"node\": \"^20.19.0 || ^22.12.0 || ^24.0.0\"\n  },\n  \"scripts\": {\n    \"start\": \"cross-env NODE_ENV=development gulp start:dev\",\n    \"test\": \"ng test --watch=false --progress=false --browsers=ChromeHeadlessCI --code-coverage\",\n    \"test:watch\": \"gulp test:watch --tags\",\n    \"test:schematics\": \"gulp build:schematics && gulp test:schematics\",\n    \"build:schematics\": \"gulp build:schematics\",\n    \"build\": \"gulp build:release\",\n    \"build:lib\": \"gulp build:library\",\n    \"changelog\": \"conventional-changelog -p conventionalcommits -i CHANGELOG.md -s --pkg components/package.json && tsx scripts/site/replace-scope-prefix.ts\",\n    \"format\": \"prettier --config .prettierrc.js --list-different \\\\\\\"component/**/*{.ts}\\\\\\\"\",\n    \"gulp\": \"gulp\",\n    \"stage-release\": \"tsx scripts/release/release.ts\",\n    \"llms\": \"tsx scripts/generate-llms.ts\",\n    \"lint\": \"npm run lint:script && npm run lint:style\",\n    \"lint:script\": \"eslint --cache\",\n    \"lint:style\": \"stylelint components/**/*.less\",\n    \"lint:fix\": \"npm run lint-fix:script && npm run lint-fix:style\",\n    \"lint-fix:script\": \"npm run lint:script -- --fix\",\n    \"lint-fix:style\": \"npm run lint:style -- --fix\",\n    \"pre-commit\": \"tsc -p components/tsconfig.json --noEmit && lint-staged\",\n    \"prepare\": \"husky\"\n  },\n  \"dependencies\": {\n    \"@angular/cdk\": \"^21.2.0\",\n    \"@ant-design/icons-angular\": \"^21.0.0\",\n    \"date-fns\": \"^2.16.1\"\n  },\n  \"devDependencies\": {\n    \"@angular-devkit/core\": \"^21.2.0\",\n    \"@angular-devkit/schematics\": \"^21.2.0\",\n    \"@angular/animations\": \"^21.2.0\",\n    \"@angular/build\": \"^21.2.0\",\n    \"@angular/cli\": \"^21.2.0\",\n    \"@angular/common\": \"^21.2.0\",\n    \"@angular/compiler\": \"^21.2.0\",\n    \"@angular/compiler-cli\": \"^21.2.0\",\n    \"@angular/core\": \"^21.2.0\",\n    \"@angular/forms\": \"^21.2.0\",\n    \"@angular/language-service\": \"^21.2.0\",\n    \"@angular/platform-browser\": \"^21.2.0\",\n    \"@angular/platform-browser-dynamic\": \"^21.2.0\",\n    \"@angular/platform-server\": \"^21.2.0\",\n    \"@angular/router\": \"^21.2.0\",\n    \"@angular/service-worker\": \"^21.2.0\",\n    \"@angular/ssr\": \"^21.2.0\",\n    \"@commitlint/cli\": \"^20.3.0\",\n    \"@commitlint/config-angular\": \"^20.3.0\",\n    \"@ctrl/tinycolor\": \"^3.6.0\",\n    \"@eslint/js\": \"^9.39.0\",\n    \"@eslint/markdown\": \"^7.5.0\",\n    \"@inquirer/prompts\": \"^7.0.0\",\n    \"@schematics/angular\": \"^21.2.0\",\n    \"@stackblitz/sdk\": \"^1.11.0\",\n    \"@types/d3\": \"^6.2.0\",\n    \"@types/express\": \"^5.0.2\",\n    \"@types/fs-extra\": \"^11.0.4\",\n    \"@types/gulp\": \"^4.0.17\",\n    \"@types/html-minifier-terser\": \"^7.0.2\",\n    \"@types/jasmine\": \"^6.0.0\",\n    \"@types/less\": \"^3.0.7\",\n    \"@types/lodash\": \"^4.17.23\",\n    \"@types/minimist\": \"^1.2.5\",\n    \"@types/node\": \"^20.11.1\",\n    \"@types/pascalcase\": \"^1.0.3\",\n    \"@types/prismjs\": \"^1.26.5\",\n    \"@types/yaml-front-matter\": \"^4.1.3\",\n    \"angular-eslint\": \"^21.3.0\",\n    \"chalk\": \"^4.1.0\",\n    \"conventional-changelog\": \"^7.1.1\",\n    \"conventional-changelog-conventionalcommits\": \"^9.1.0\",\n    \"cron-parser\": \"^4.6.0\",\n    \"cross-env\": \"^10.0.0\",\n    \"d3\": \"^6.3.1\",\n    \"dagre\": \"^0.8.5\",\n    \"dagre-compound\": \"^0.0.8\",\n    \"del\": \"^8.0.0\",\n    \"detect-port\": \"^2.1.0\",\n    \"eslint\": \"^9.39.0\",\n    \"eslint-plugin-header\": \"~3.1.1\",\n    \"eslint-plugin-import\": \"^2.32.0\",\n    \"eslint-plugin-jsdoc\": \"^62.0.0\",\n    \"eslint-plugin-prefer-arrow\": \"~1.2.2\",\n    \"eslint-plugin-prettier\": \"~5.5.0\",\n    \"eslint-plugin-unused-imports\": \"^4.3.0\",\n    \"express\": \"^5.1.0\",\n    \"fs-extra\": \"^11.3.0\",\n    \"gulp\": \"^5.0.0\",\n    \"html-minifier-terser\": \"^7.2.0\",\n    \"husky\": \"^9.0.0\",\n    \"jasmine\": \"^6.0.0\",\n    \"jasmine-core\": \"^6.0.0\",\n    \"jasmine-spec-reporter\": \"^7.0.0\",\n    \"karma\": \"^6.4.4\",\n    \"karma-chrome-launcher\": \"^3.1.0\",\n    \"karma-coverage\": \"^2.0.3\",\n    \"karma-jasmine\": \"^5.0.0\",\n    \"karma-jasmine-html-reporter\": \"^2.0.0\",\n    \"karma-junit-reporter\": \"^2.0.1\",\n    \"karma-spec-reporter\": \"^0.0.36\",\n    \"karma-viewport\": \"^1.0.7\",\n    \"less\": \"^4.5.0\",\n    \"less-plugin-clean-css\": \"^1.6.0\",\n    \"less-plugin-npm-import\": \"^2.1.0\",\n    \"less-vars-to-js\": \"^1.3.0\",\n    \"lint-staged\": \"^16.2.0\",\n    \"lodash\": \"^4.17.23\",\n    \"marked\": \"^17.0.0\",\n    \"marked-highlight\": \"^2.2.2\",\n    \"minimist\": \"^1.2.5\",\n    \"monaco-editor\": \"^0.33.0\",\n    \"ng-packagr\": \"^21.2.0\",\n    \"parse5\": \"^8.0.0\",\n    \"pascalcase\": \"^2.0.0\",\n    \"postcss\": \"^8.5.1\",\n    \"prettier\": \"^3.8.0\",\n    \"prismjs\": \"^1.29.0\",\n    \"process\": \"^0.11.10\",\n    \"puppeteer\": \"^24.36.0\",\n    \"remark\": \"^15.0.0\",\n    \"rxjs\": \"~7.8.1\",\n    \"sitemap\": \"^9.0.0\",\n    \"slugify\": \"^1.6.6\",\n    \"stylelint\": \"^17.0.0\",\n    \"stylelint-config-rational-order\": \"^0.1.2\",\n    \"stylelint-config-standard\": \"^40.0.0\",\n    \"stylelint-config-standard-less\": \"^4.0.0\",\n    \"stylelint-declaration-block-no-ignored-properties\": \"^3.0.0\",\n    \"stylelint-order\": \"^7.0.0\",\n    \"terser\": \"^5.46.0\",\n    \"ts-node\": \"^10.9.1\",\n    \"tslib\": \"^2.0.3\",\n    \"tsx\": \"^4.21.0\",\n    \"typescript\": \"~5.9.0\",\n    \"typescript-eslint\": \"^8.54.0\",\n    \"yaml-front-matter\": \"^4.1.1\",\n    \"zone.js\": \"~0.16.0\"\n  }\n}\n"
  },
  {
    "path": "schematics/README.md",
    "content": "# ng-zorro-antd Schematics\n\n## Schematics\n\n### ng-add\n\n添加 ng-zorro-antd 与它的依赖，并根据需要自动配置。\n\n- 添加 ng-zorro-antd 到 `package.json`\n- 替换 `app.html` 引导内容\n- 在根模块导入必要的模块\n- 进行国际化配置\n- 将用于自定义的 `theme.less` 或编译后的 css 导入 `angular.json`\n\n```bash\n$ ng add ng-zorro-antd [--locale=zh-CN] [--theme] [--skipPackageJson]\n```\n\n## 开发\n\n### 首次运行\n\n`npm run build:schematic` 编译到 publish 文件夹，创建一个新的 ng 项目。\n\n1. `cd publish && npm link`\n2. `ng new schematic-debug`\n3. `cd schematic-debug && npm link ng-zorro-antd`\n\n### 调试\n\n1. `schematic:build` 修改代码后编译\n2. `cd schematic-debug` 切换到 ng 项目\n3. `git checkout . && git clean -fd` 还原更改\n4. `ng g ng-zorro-antd:[schematic]` 运行 schematic\n\n比如，你可以运行 `ng g ng-zorro-antd:ng-add` 来测试 `ng-add`。\n\n## 发布\n\n原有发布流程不变，但是 `schematics/utils/custom-theme.ts` 和 `schematics/utils/lib-versions.ts` 内容为动态生成，不提交到版本管理。"
  },
  {
    "path": "schematics/collection.json",
    "content": "{\n  \"$schema\": \"../node_modules/@angular-devkit/schematics/collection-schema.json\",\n  \"schematics\": {\n    \"ng-add\": {\n      \"description\": \"add NG-ZORRO\",\n      \"factory\": \"./ng-add/index\",\n      \"schema\": \"./ng-add/schema.json\"\n    },\n    \"ng-add-setup-project\": {\n      \"description\": \"Sets up the specified project after the ng-add dependencies have been installed.\",\n      \"private\": true,\n      \"factory\": \"./ng-add/setup-project/index\",\n      \"schema\": \"./ng-add/schema.json\"\n    },\n    \"blank\": {\n      \"description\": \"Set up boot page\",\n      \"private\": true,\n      \"factory\": \"./ng-generate/blank/index\",\n      \"schema\": \"./ng-generate/blank/schema.json\"\n    },\n    \"sidemenu\": {\n      \"description\": \"Add Sidebar Navigation Layout in your project.\",\n      \"factory\": \"./ng-generate/side-menu/index\",\n      \"schema\": \"./ng-generate/side-menu/schema.json\"\n    },\n    \"topnav\": {\n      \"description\": \"Add Top Navigation Layout in your project.\",\n      \"factory\": \"./ng-generate/topnav/index\",\n      \"schema\": \"./ng-generate/topnav/schema.json\"\n    },\n    \"add-icon-assets\": {\n      \"description\": \"Add icon assets into CLI config\",\n      \"factory\": \"./ng-add/setup-project/add-icon-assets#addIconToAssets\",\n      \"schema\": \"./ng-generate/blank/schema.json\",\n      \"aliases\": [\"fix-icon\"]\n    },\n    \"component\": {\n      \"aliases\": [ \"c\" ],\n      \"factory\": \"./ng-component\",\n      \"description\": \"Create an Angular component.\",\n      \"schema\": \"./ng-component/schema.json\"\n    }\n  }\n}\n"
  },
  {
    "path": "schematics/migration.json",
    "content": "{\n  \"$schema\": \"../node_modules/@angular-devkit/schematics/collection-schema.json\",\n  \"schematics\": {\n    \"migration-v21\": {\n      \"version\": \"21.0.0-0\",\n      \"description\": \"Updates NG-ZORRO to v21 [https://github.com/NG-ZORRO/ng-zorro-antd/issues/9536]\",\n      \"factory\": \"./ng-update/index#updateToV21\"\n    },\n    \"ng-post-update\": {\n      \"description\": \"Prints out results after ng-update.\",\n      \"factory\": \"./ng-update/index#postUpdate\",\n      \"private\": true\n    }\n  }\n}"
  },
  {
    "path": "schematics/ng-add/index.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { getProjectFromWorkspace, getProjectTargetOptions } from '@angular/cdk/schematics';\n\nimport { normalize } from '@angular-devkit/core';\nimport { Tree } from '@angular-devkit/schematics';\nimport { NodePackageName } from '@angular-devkit/schematics/tasks/package-manager/options';\nimport { SchematicTestRunner } from '@angular-devkit/schematics/testing';\nimport { readWorkspace } from '@schematics/angular/utility';\nimport { getPackageJsonDependency } from '@schematics/angular/utility/dependencies';\n\nimport { join } from 'path';\n\nimport { Schema as NzOptions } from './schema';\nimport { createTestApp } from '../testing/test-app';\nimport { createCustomTheme } from '../utils/create-custom-theme';\nimport { getFileContent } from '../utils/get-file-content';\n\ndescribe('ng-add schematic', () => {\n  const defaultOptions: NzOptions = {\n    project: 'ng-zorro'\n  };\n\n  let runner: SchematicTestRunner;\n  let appTree: Tree;\n\n  beforeEach(async () => {\n    runner = new SchematicTestRunner('schematics', require.resolve('../collection.json'));\n    appTree = await createTestApp(runner, { standalone: false });\n  });\n\n  it('should update package.json', async () => {\n    const options = { ...defaultOptions };\n    const tree = await runner.runSchematic('ng-add', options, appTree);\n    expect(getPackageJsonDependency(tree, 'ng-zorro-antd')).not.toBeNull();\n    expect(runner.tasks.some(task => task.name === NodePackageName)).toBe(true);\n  });\n\n  it('should add hammerjs to package.json', async () => {\n    const options = { ...defaultOptions, gestures: true };\n    const tree = await runner.runSchematic('ng-add', options, appTree);\n    expect(getPackageJsonDependency(tree, 'hammerjs')).not.toBeNull();\n  });\n\n  it('should skip package.json', async () => {\n    const options = { ...defaultOptions, skipPackageJson: true };\n    const tree = await runner.runSchematic('ng-add', options, appTree);\n    expect(getPackageJsonDependency(tree, 'ng-zorro-antd')).toBeNull();\n  });\n\n  it('should skip install dependency package', async () => {\n    const options = { ...defaultOptions, skipInstall: true };\n    await runner.runSchematic('ng-add', options, appTree);\n    expect(runner.tasks.some(task => task.name === NodePackageName)).toBe(false);\n  });\n\n  it('should add less as devDependencies when choosing custom theme in non-LESS project', async () => {\n    const options = { ...defaultOptions, theme: true };\n    const tree = await runner.runSchematic('ng-add', options, appTree);\n    expect(getPackageJsonDependency(tree, 'less')).not.toBeNull();\n  });\n\n  it('should add hammerjs import to project main file', async () => {\n    const options = { ...defaultOptions, gestures: true };\n    const tree = await runner.runSchematic('ng-add-setup-project', options, appTree);\n    const workspace = await readWorkspace(tree);\n    const project = getProjectFromWorkspace(workspace, defaultOptions.project);\n    const fileContent = getFileContent(tree, normalize(join(project.sourceRoot, 'main.ts')));\n\n    expect(fileContent).toContain(`import 'hammerjs';`);\n  });\n\n  it('should add default theme', async () => {\n    const options = { ...defaultOptions };\n    const tree = await runner.runSchematic('ng-add-setup-project', options, appTree);\n    const workspace = await readWorkspace(tree);\n    const project = getProjectFromWorkspace(workspace, defaultOptions.project);\n\n    expect(getProjectTargetOptions(project, 'build').styles).toContain(\n      './node_modules/ng-zorro-antd/ng-zorro-antd.min.css'\n    );\n  });\n\n  it('should add custom theme', async () => {\n    const options = { ...defaultOptions, theme: true };\n\n    appTree = await createTestApp(runner, { style: 'less', standalone: false });\n    const tree = await runner.runSchematic('ng-add-setup-project', options, appTree);\n    const workspace = await readWorkspace(tree);\n    const project = getProjectFromWorkspace(workspace, defaultOptions.project);\n\n    const customThemePath = normalize(join(project.sourceRoot, 'styles.less'));\n    const buffer = tree.read(customThemePath);\n    const themeContent = buffer!.toString();\n\n    expect(themeContent).toContain(createCustomTheme());\n\n    expect(getProjectTargetOptions(project, 'build').styles).toContain('projects/ng-zorro/src/styles.less');\n  });\n\n  it('should add custom theme file when no LESS file in project', async () => {\n    const options = { ...defaultOptions, theme: true };\n    const tree = await runner.runSchematic('ng-add-setup-project', options, appTree);\n    const workspace = await readWorkspace(tree);\n    const project = getProjectFromWorkspace(workspace, defaultOptions.project);\n\n    expect(getProjectTargetOptions(project, 'build').styles).toContain('projects/ng-zorro/src/theme.less');\n  });\n\n  it('should add icon assets', async () => {\n    const options = { ...defaultOptions, dynamicIcon: true };\n    const tree = await runner.runSchematic('ng-add-setup-project', options, appTree);\n    const workspace = await readWorkspace(tree);\n    const project = getProjectFromWorkspace(workspace, defaultOptions.project);\n    const assets = getProjectTargetOptions(project, 'build').assets;\n\n    const assetsString = JSON.stringify(assets);\n    const iconPathSegment = '@ant-design/icons-angular';\n\n    expect(assetsString).toContain(iconPathSegment);\n  });\n\n  it('should not add provideNzNoAnimation() function call if animations is enable', async () => {\n    const options = { ...defaultOptions, animations: true };\n    const tree = await runner.runSchematic('ng-add-setup-project', options, appTree);\n    const fileContent = getFileContent(tree, '/projects/ng-zorro/src/app/app-module.ts');\n    expect(fileContent).not.toContain('provideNzNoAnimation()');\n  });\n\n  it(`should add provideNzNoAnimation() function call if animations is disable`, async () => {\n    const options = { ...defaultOptions, animations: false };\n    const tree = await runner.runSchematic('ng-add-setup-project', options, appTree);\n    const fileContent = getFileContent(tree, '/projects/ng-zorro/src/app/app-module.ts');\n\n    expect(fileContent).toContain(`provideNzNoAnimation()`);\n  });\n\n  it('should register default locale id', async () => {\n    const options = { ...defaultOptions };\n    const tree = await runner.runSchematic('ng-add-setup-project', options, appTree);\n    const fileContent = getFileContent(tree, '/projects/ng-zorro/src/app/app-module.ts');\n\n    expect(fileContent).not.toContain('NZ_I18N');\n    expect(fileContent).toContain('provideNzI18n(en_US)');\n    expect(fileContent).toContain('registerLocaleData(en)');\n  });\n\n  it('should register specified locale id', async () => {\n    const options = { ...defaultOptions, locale: 'zh_CN' };\n    const tree = await runner.runSchematic('ng-add-setup-project', options, appTree);\n    const fileContent = getFileContent(tree, '/projects/ng-zorro/src/app/app-module.ts');\n\n    expect(fileContent).not.toContain('NZ_I18N');\n    expect(fileContent).toContain('provideNzI18n(zh_CN)');\n    expect(fileContent).toContain('registerLocaleData(zh)');\n  });\n\n  it('should not add locale id if locale id is set up', async () => {\n    const options = { ...defaultOptions, i18n: 'zh_CN' };\n    await runner.runSchematic('ng-add-setup-project', { ...defaultOptions }, appTree);\n\n    spyOn(console, 'log');\n\n    const tree = await runner.runSchematic('ng-add-setup-project', options, appTree);\n    const fileContent = getFileContent(tree, '/projects/ng-zorro/src/app/app-module.ts');\n\n    expect(fileContent).toContain('provideNzI18n(en_US)');\n    expect(fileContent).toContain('registerLocaleData(en)');\n    expect(fileContent).not.toContain('NZ_I18N');\n    expect(fileContent).not.toContain('provideNzI18n(zh_CN)');\n    expect(fileContent).not.toContain('registerLocaleData(zh)');\n\n    expect(console.log).toHaveBeenCalledWith(jasmine.stringMatching(/Could not add the registerLocaleData to file/));\n  });\n});\n"
  },
  {
    "path": "schematics/ng-add/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { getProjectFromWorkspace } from '@angular/cdk/schematics';\n\nimport { chain, noop, Rule, schematic, SchematicContext, Tree } from '@angular-devkit/schematics';\nimport { NodePackageInstallTask, RunSchematicTask } from '@angular-devkit/schematics/tasks';\nimport { readWorkspace } from '@schematics/angular/utility';\nimport { addPackageJsonDependency, NodeDependencyType } from '@schematics/angular/utility/dependencies';\nimport { latestVersions } from '@schematics/angular/utility/latest-versions';\n\nimport { Schema } from './schema';\nimport { getProjectStyle } from '../utils/project-style';\n// generated by scripts/schematics/set-version.ts\n// @ts-ignore\nimport { hammerjsVersion, zorroVersion } from '../utils/version-names';\n\nexport default function(options: Schema): Rule {\n  return chain([\n    (host: Tree, context: SchematicContext) => {\n      // The CLI inserts `ng-zorro-antd` into the `package.json` before this schematic runs.\n      // This means that we do not need to insert Angular Material into `package.json` files again.\n      // In some cases though, it could happen that this schematic runs outside of the CLI `ng add`\n      // command, or Material is only listed a dev dependency. If that is the case, we insert a\n      // version based on the current build version (substituted version placeholder).\n      if (!options.skipPackageJson) {\n        addPackageJsonDependency(host, { name: 'ng-zorro-antd', version: zorroVersion, type: NodeDependencyType.Default });\n        if (options.gestures) {\n          addPackageJsonDependency(host, { name: 'hammerjs', version: hammerjsVersion, type: NodeDependencyType.Default });\n        }\n\n        // Since Angular CLI v20 no longer installs `less` for the project which prefers `css` or \n        // `scss` as default stylesheet format, and ng-zorro-antd's custom theming requires `less`,\n        // we should add `less` as a dev dependency.\n        if (options.theme) {\n          addPackageJsonDependency(host, { name: 'less', version: latestVersions['less'], type: NodeDependencyType.Dev });\n        }\n      }\n\n      // Since the Angular Material schematics depend on the schematic utility functions from the\n      // CDK, we need to install the CDK before loading the schematic files that import from the CDK.\n      if (!options.skipInstall) {\n        const installTaskId = context.addTask(new NodePackageInstallTask());\n        context.addTask(new RunSchematicTask('ng-add-setup-project', options), [installTaskId]);\n      }\n    },\n    options.template ? applyTemplate(options) : noop()\n  ]);\n}\n\nfunction applyTemplate(options: Schema): Rule {\n  return async (host: Tree) => {\n    const workspace = await readWorkspace(host);\n    const project = getProjectFromWorkspace(workspace, options.project);\n    const style = getProjectStyle(project);\n\n    return schematic(options.template, { ...options, style });\n  };\n}"
  },
  {
    "path": "schematics/ng-add/schema.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/schema\",\n  \"$id\": \"nz-ng-add\",\n  \"title\": \"Ant Design of Angular(NG-ZORRO) ng-add schematic\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"project\": {\n      \"type\": \"string\",\n      \"description\": \"Name of the project.\",\n      \"$default\": {\n        \"$source\": \"projectName\"\n      }\n    },\n    \"skipPackageJson\": {\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"description\": \"Do not add ng-zorro-antd dependencies to package.json (e.g., --skipPackageJson)\"\n    },\n    \"skipInstall\": {\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"description\": \"Do not install dependency package.\"\n    },\n    \"dynamicIcon\": {\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"description\": \"Whether icon should dynamic loading.\",\n      \"x-prompt\": \"Enable icon dynamic loading [ Detail: https://ng.ant.design/components/icon/en ]\"\n    },\n    \"theme\": {\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"description\": \"Whether custom theme file should be set up.\",\n      \"x-prompt\": \"Set up custom theme file [ Detail: https://ng.ant.design/docs/customize-theme/en ]\"\n    },\n    \"locale\": {\n      \"type\": \"string\",\n      \"description\": \"Add locale code to module (e.g., --locale=en_US)\",\n      \"default\": \"en_US\",\n      \"x-prompt\": {\n        \"message\": \"Choose your locale code:\",\n        \"type\": \"list\",\n        \"items\": [\n          \"en_US\",\n          \"uk_UA\",\n          \"de_DE\",\n          \"fr_FR\",\n          \"zh_CN\",\n          \"zh_TW\",\n          \"ko_KR\",\n          \"ja_JP\",\n          \"ar_EG\",\n          \"cs_CZ\",\n          \"el_GR\",\n          \"et_EE\",\n          \"hu_HU\",\n          \"it_IT\",\n          \"ms_MY\",\n          \"nl_NL\",\n          \"pt_PT\",\n          \"sl_SI\",\n          \"th_TH\",\n          \"vi_VN\",\n          \"bg_BG\",\n          \"da_DK\",\n          \"en_GB\",\n          \"fa_IR\",\n          \"he_IL\",\n          \"hy_AM\",\n          \"ku_IQ\",\n          \"nb_NO\",\n          \"ro_RO\",\n          \"sr_RS\",\n          \"ca_ES\",\n          \"fi_FI\",\n          \"hi_IN\",\n          \"id_ID\",\n          \"ka_GE\",\n          \"lv_LV\",\n          \"ne_NP\",\n          \"pl_PL\",\n          \"ru_RU\",\n          \"sv_SE\",\n          \"tr_TR\",\n          \"es_ES\",\n          \"fr_BE\",\n          \"hr_HR\",\n          \"is_IS\",\n          \"kn_IN\",\n          \"mn_MN\",\n          \"nl_BE\",\n          \"pt_BR\",\n          \"sk_SK\",\n          \"ta_IN\"\n        ]\n      }\n    },\n    \"template\": {\n      \"type\": \"string\",\n      \"default\": \"blank\",\n      \"description\": \"Create an Angular project with using preset template.\",\n      \"x-prompt\": {\n        \"message\": \"Choose template to create project:\",\n        \"type\": \"list\",\n        \"items\": [\n          \"blank\",\n          \"sidemenu\",\n          \"topnav\"\n        ]\n      }\n    },\n    \"gestures\": {\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"description\": \"Whether gesture support should be set up.\"\n    },\n    \"animations\": {\n      \"type\": \"boolean\",\n      \"default\": true,\n      \"description\": \"Whether Angular browser animations should be set up.\"\n    }\n  },\n  \"required\": []\n}\n"
  },
  {
    "path": "schematics/ng-add/schema.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport type Locale =\n  | 'ar_EG'\n  | 'bg_BG'\n  | 'ca_ES'\n  | 'cs_CZ'\n  | 'da_DK'\n  | 'de_DE'\n  | 'el_GR'\n  | 'en_GB'\n  | 'en_US'\n  | 'es_ES'\n  | 'et_EE'\n  | 'fa_IR'\n  | 'fi_FI'\n  | 'fr_BE'\n  | 'fr_FR'\n  | 'is_IS'\n  | 'it_IT'\n  | 'ja_JP'\n  | 'ka_GE'\n  | 'ko_KR'\n  | 'nb_NO'\n  | 'nl_BE'\n  | 'nl_NL'\n  | 'pl_PL'\n  | 'pt_BR'\n  | 'pt_PT'\n  | 'sk_SK'\n  | 'sr_RS'\n  | 'sv_SE'\n  | 'th_TH'\n  | 'tr_TR'\n  | 'ru_RU'\n  | 'uk_UA'\n  | 'vi_VN'\n  | 'zh_CN'\n  | 'zh_TW';\n\nexport enum ProjectTemplate {\n  Blank = 'blank',\n  Sidemenu = 'sidemenu',\n  Topnav = 'topnav',\n  None = 'none'\n}\n\nexport interface Schema {\n  /** Name of the project to target. */\n  project?: string;\n  /** Whether to skip package.json install. */\n  skipPackageJson?: boolean;\n  skipInstall?: boolean;\n  dynamicIcon?: boolean;\n  theme?: boolean;\n  gestures?: boolean;\n  animations?: boolean;\n  locale?: Locale;\n  i18n?: Locale;\n  template?: ProjectTemplate;\n}\n"
  },
  {
    "path": "schematics/ng-add/setup-project/add-icon-assets.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { getProjectFromWorkspace, getProjectTargetOptions } from '@angular/cdk/schematics';\n\nimport { Rule } from '@angular-devkit/schematics';\nimport { updateWorkspace } from '@schematics/angular/utility';\nimport { cyan, yellow } from 'chalk';\n\nimport { Schema } from '../schema';\n\nconst iconPathSegment = '@ant-design/icons-angular';\nconst iconAssetObject = {\n  'glob': '**/*',\n  'input': './node_modules/@ant-design/icons-angular/src/inline-svg/',\n  'output': '/assets/'\n};\n\nexport function addIconToAssets(options: Schema): Rule {\n  return updateWorkspace(workspace => {\n    const project = getProjectFromWorkspace(workspace, options.project);\n    const targetOptions = getProjectTargetOptions(project, 'build');\n\n    if (!targetOptions.assets) {\n      targetOptions.assets = [{ ...iconAssetObject }];\n    } else {\n      const assets = targetOptions.assets as Array<string | object>;\n      const assetsString = JSON.stringify(assets);\n      if (!assetsString.includes(iconPathSegment)) {\n        assets.push({ ...iconAssetObject });\n      } else {\n        console.log();\n        console.log(yellow(`Could not add the icon assets to the CLI project assets ` +\n          `because there is already a icon assets file referenced.`));\n        console.log(yellow(`Please manually add the following config to your assets:`));\n        console.log(cyan(JSON.stringify(iconAssetObject, null, 2)));\n        return;\n      }\n    }\n  });\n}\n"
  },
  {
    "path": "schematics/ng-add/setup-project/add-required-providers.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Rule, chain, noop } from '@angular-devkit/schematics';\nimport { addRootProvider } from '@schematics/angular/utility';\n\nimport { Schema } from '../schema';\n\nexport function addRequiredProviders(options: Schema): Rule {\n  return chain([\n    addAnimations(options)\n  ]);\n}\n\nfunction addAnimations(options: Schema): Rule {\n  if (options.animations) {\n    return noop();\n  }\n\n  return addRootProvider(options.project, ({ code, external }) => {\n    return code`${external(\n      'provideNzNoAnimation',\n      'ng-zorro-antd/core/animation'\n    )}()`;\n  });\n}\n"
  },
  {
    "path": "schematics/ng-add/setup-project/hammerjs-import.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { getProjectFromWorkspace, getProjectMainFile } from '@angular/cdk/schematics';\n\nimport { Rule, Tree } from '@angular-devkit/schematics';\nimport { readWorkspace } from '@schematics/angular/utility';\nimport { blue, red } from 'chalk';\n\nimport { Schema } from '../schema';\n\nconst hammerjsImportStatement = `import 'hammerjs';`;\n\n/** Adds HammerJS to the main file of the specified Angular CLI project. */\nexport function hammerjsImport(options: Schema): Rule {\n  return async (host: Tree) => {\n    const workspace = await readWorkspace(host);\n    const project = getProjectFromWorkspace(workspace, options.project);\n    const mainFile = getProjectMainFile(project);\n\n    const recorder = host.beginUpdate(mainFile);\n    const buffer = host.read(mainFile);\n\n    if (!buffer) {\n      console.log();\n      console.error(red(`Could not read the project main file (${blue(mainFile)}). Please manually ` +\n        `import HammerJS in your main TypeScript file.`));\n      return;\n    }\n\n    const fileContent = buffer.toString('utf8');\n\n    if (fileContent.includes(hammerjsImportStatement)) {\n      console.log();\n      console.log(`HammerJS is already imported in the project main file (${blue(mainFile)}).`);\n      return;\n    }\n\n    recorder.insertRight(0, `${hammerjsImportStatement}\\n`);\n    host.commitUpdate(recorder);\n  };\n}\n"
  },
  {
    "path": "schematics/ng-add/setup-project/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { chain, noop, Rule } from '@angular-devkit/schematics';\n\nimport { Schema } from '../schema';\nimport { addIconToAssets } from './add-icon-assets';\nimport { addRequiredProviders } from './add-required-providers';\nimport { hammerjsImport } from './hammerjs-import';\nimport { registerLocale } from './register-locale';\nimport { addThemeToAppStyles } from './theming';\n\nexport default function (options: Schema): Rule {\n  return chain([\n    registerLocale(options),\n    addRequiredProviders(options),\n    addThemeToAppStyles(options),\n    options.dynamicIcon ? addIconToAssets(options) : noop(),\n    options.gestures ? hammerjsImport(options) : noop()\n  ]);\n}\n"
  },
  {
    "path": "schematics/ng-add/setup-project/register-locale.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  addSymbolToNgModuleMetadata,\n  findNodes,\n  getAppModulePath,\n  getDecoratorMetadata,\n  getProjectFromWorkspace,\n  getProjectMainFile,\n  insertAfterLastOccurrence,\n  insertImport,\n  isStandaloneApp,\n  parseSourceFile\n} from '@angular/cdk/schematics';\n\nimport { chain, Rule, Tree } from '@angular-devkit/schematics';\nimport { addRootProvider, readWorkspace } from '@schematics/angular/utility';\nimport { Change, InsertChange, NoopChange } from '@schematics/angular/utility/change';\nimport { findAppConfig } from '@schematics/angular/utility/standalone/app_config';\nimport { findBootstrapApplicationCall } from '@schematics/angular/utility/standalone/util';\nimport { blue, cyan, yellow } from 'chalk';\nimport * as ts from 'typescript';\n\nimport { applyChangesToFile } from '../../utils/apply-changes';\nimport { Schema } from '../schema';\n\nexport function registerLocale(options: Schema): Rule {\n  return async (host: Tree) => {\n    const workspace = await readWorkspace(host);\n    const project = getProjectFromWorkspace(workspace, options.project);\n    const mainFile = getProjectMainFile(project);\n    if (isStandaloneApp(host, mainFile)) {\n      return registerLocaleInStandaloneApp(mainFile, options);\n    } else {\n      return registerLocaleInAppModule(mainFile, options);\n    }\n  };\n}\n\n/**\n * Safely creates an import change, returning NoopChange if the moduleSource is invalid\n * or if the import already exists.\n */\nfunction safeInsertImport(moduleSource: ts.SourceFile | undefined, filePath: string, symbolName: string, fileName: string, isDefault = false): Change {\n  if (!moduleSource) {\n    console.log();\n    console.log(yellow(`Could not insert import for ${symbolName} in file (${blue(filePath)}).`));\n    console.log(yellow(`The source file is invalid.`));\n    return new NoopChange();\n  }\n\n  // Check if the import already exists\n  const allImports = findNodes(moduleSource, ts.SyntaxKind.ImportDeclaration);\n  if (!allImports) {\n    return new NoopChange();\n  }\n\n  const importExists = allImports.some(node => {\n    // Make sure it's an import declaration\n    if (!ts.isImportDeclaration(node)) {\n      return false;\n    }\n\n    if (!node.moduleSpecifier) {\n      return false;\n    }\n\n    // Check if this import is from the same file\n    if (!ts.isStringLiteral(node.moduleSpecifier)) {\n      return false;\n    }\n    const importPath = node.moduleSpecifier.text;\n    if (importPath !== fileName) {\n      return false;\n    }\n\n    // Check if the symbol is already imported\n    if (!node.importClause) {\n      return false;\n    }\n    const namedBindings = node.importClause.namedBindings;\n    if (!namedBindings) {\n      return false;\n    }\n\n    if (ts.isNamedImports(namedBindings)) {\n      return namedBindings.elements.some(element =>\n        element.name.text === symbolName\n      );\n    }\n\n    return false;\n  });\n\n  if (importExists) {\n    return new NoopChange();\n  }\n\n  try {\n    return insertImport(moduleSource, filePath, symbolName, fileName, isDefault);\n  } catch (e) {\n    console.log();\n    console.log(yellow(`Could not insert import for ${symbolName} in file (${blue(filePath)}).`));\n    console.log(yellow(`Error: ${e.message}`));\n    return new NoopChange();\n  }\n}\n\nfunction registerLocaleInAppModule(mainFile: string, options: Schema): Rule {\n  return async (host: Tree) => {\n    const appModulePath = getAppModulePath(host, mainFile);\n    const moduleSource = parseSourceFile(host, appModulePath);\n\n    const locale = options.locale || 'en_US';\n    const localePrefix = locale.split('_')[0];\n\n    applyChangesToFile(host, appModulePath, [\n      safeInsertImport(moduleSource, appModulePath, 'provideNzI18n', 'ng-zorro-antd/i18n'),\n      safeInsertImport(moduleSource, appModulePath, locale, 'ng-zorro-antd/i18n'),\n      safeInsertImport(moduleSource, appModulePath, 'registerLocaleData', '@angular/common'),\n      safeInsertImport(moduleSource, appModulePath, localePrefix, `@angular/common/locales/${localePrefix}`, true),\n      registerLocaleData(moduleSource, appModulePath, localePrefix),\n      ...insertI18nTokenProvide(moduleSource, appModulePath, locale)\n    ]);\n  };\n}\n\nfunction registerLocaleInStandaloneApp(mainFile: string, options: Schema): Rule {\n  const locale = options.locale || 'en_US';\n\n  return chain([\n    async (host: Tree) => {\n      try {\n        const bootstrapCall = findBootstrapApplicationCall(host, mainFile);\n        if (!bootstrapCall) {\n          console.log();\n          console.log(yellow(`Could not find bootstrap application call in file (${blue(mainFile)}).`));\n          return void 0;\n        }\n\n        const appConfig = findAppConfig(bootstrapCall, host, mainFile);\n        if (!appConfig || !appConfig.filePath) {\n          console.log();\n          console.log(yellow(`Could not find app config in file (${blue(mainFile)}).`));\n          return void 0;\n        }\n\n        const appConfigFile = appConfig.filePath;\n        const appConfigSource = parseSourceFile(host, appConfig.filePath);\n        if (!appConfigSource) {\n          console.log();\n          console.log(yellow(`Could not parse app config file (${blue(appConfigFile)}).`));\n          return void 0;\n        }\n\n        const localePrefix = locale.split('_')[0];\n\n        applyChangesToFile(host, appConfigFile, [\n          safeInsertImport(appConfigSource, appConfigFile, locale, 'ng-zorro-antd/i18n'),\n          safeInsertImport(appConfigSource, appConfigFile, 'registerLocaleData', '@angular/common'),\n          safeInsertImport(appConfigSource, appConfigFile, localePrefix, `@angular/common/locales/${localePrefix}`, true),\n          registerLocaleData(appConfigSource, appConfigFile, localePrefix)\n        ]);\n      } catch (e) {\n        console.log(yellow(`Error registering locale in standalone app: ${e.message}`));\n      }\n    },\n    addRootProvider(options.project, ({ code, external }) => {\n      return code`${external('provideNzI18n', 'ng-zorro-antd/i18n')}(${locale})`;\n    })\n  ]);\n}\n\nfunction registerLocaleData(moduleSource: ts.SourceFile, modulePath: string, locale: string): Change {\n  const allImports = findNodes(moduleSource, ts.SyntaxKind.ImportDeclaration);\n  const allFun = findNodes(moduleSource, ts.SyntaxKind.ExpressionStatement);\n\n  // Check if allImports is valid before proceeding\n  if (!allImports || allImports.length === 0) {\n    console.log(yellow(`Could not add the registerLocaleData to file (${blue(modulePath)}).` +\n      `because no import declarations were found.`));\n    console.log(yellow(`Please manually add the following code:`));\n    console.log(cyan(`registerLocaleData(${locale});`));\n    return new NoopChange();\n  }\n\n  // Safely filter the expression statements\n  const registerLocaleDataFun = allFun.filter(node => {\n    if (!node) return false;\n    const children = node.getChildren();\n    if (!children || children.length === 0) {\n      return false;\n    }\n    const firstChild = children[0];\n    if (!firstChild) {\n      return false;\n    }\n    const firstChildChildren = firstChild.getChildren();\n    if (!firstChildChildren || firstChildChildren.length === 0) {\n      return false;\n    }\n    const firstChildFirstChild = firstChildChildren[0];\n    if (!firstChildFirstChild) {\n      return false;\n    }\n    return firstChildFirstChild.getText() === 'registerLocaleData';\n  });\n\n  if (registerLocaleDataFun.length === 0) {\n    return insertAfterLastOccurrence(allImports, `\\n\\nregisterLocaleData(${locale});`,\n      modulePath, 0) as InsertChange;\n  } else {\n    console.log(yellow(`Could not add the registerLocaleData to file (${blue(modulePath)}).` +\n      `because there is already a registerLocaleData function.`));\n    console.log(yellow(`Please manually add the following code:`));\n    console.log(cyan(`registerLocaleData(${locale});`));\n    return new NoopChange();\n  }\n}\n\nfunction insertI18nTokenProvide(moduleSource: ts.SourceFile, modulePath: string, locale: string): Change[] {\n  const metadataField = 'providers';\n  const nodes = getDecoratorMetadata(moduleSource, 'NgModule', '@angular/core');\n\n  // Check if nodes are valid\n  if (!nodes || nodes.length === 0) {\n    console.log(yellow(`Could not find NgModule decorator in file (${blue(modulePath)}).`));\n    console.log(yellow(`Please manually add the following code to your providers:`));\n    console.log(cyan(`provideNzI18n(${locale})`));\n    return [];\n  }\n\n  const addProvide = addSymbolToNgModuleMetadata(\n    moduleSource,\n    modulePath,\n    'providers',\n    `provideNzI18n(${locale})`,\n    null\n  );\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  const node: any = nodes[0];\n\n  if (!node) {\n    return [];\n  }\n\n  // Check if a node has properties\n  if (!node.properties) {\n    console.log(yellow(`Could not find properties in NgModule decorator in file (${blue(modulePath)}).`));\n    console.log(yellow(`Please manually add the following code to your providers:`));\n    console.log(cyan(`provideNzI18n(${locale})`));\n    return [];\n  }\n\n  const matchingProperties: ts.ObjectLiteralElement[] =\n    (node as ts.ObjectLiteralExpression).properties\n      .filter(prop => prop && prop.kind === ts.SyntaxKind.PropertyAssignment)\n      .filter((prop: ts.PropertyAssignment) => {\n        if (!prop || !prop.name) return false;\n        const name = prop.name;\n        switch (name.kind) {\n          case ts.SyntaxKind.Identifier:\n            return (name as ts.Identifier).getText(moduleSource) === metadataField;\n          case ts.SyntaxKind.StringLiteral:\n            return (name as ts.StringLiteral).text === metadataField;\n        }\n\n        return false;\n      });\n\n  if (!matchingProperties) {\n    return [];\n  }\n\n  if (matchingProperties.length) {\n    const assignment = matchingProperties[0] as ts.PropertyAssignment;\n    if (!assignment || !assignment.initializer || assignment.initializer.kind !== ts.SyntaxKind.ArrayLiteralExpression) {\n      return [];\n    }\n    const arrLiteral = assignment.initializer as ts.ArrayLiteralExpression;\n    if (!arrLiteral.elements || arrLiteral.elements.length === 0) {\n      return addProvide;\n    } else {\n      // Safely check for getText method before calling it\n      const provideWithToken = arrLiteral.elements.some(e => e && typeof e.getText === 'function' && e.getText().includes('NZ_I18N'));\n      const provideWithFunc = arrLiteral.elements.some(e => e && typeof e.getText === 'function' && e.getText().includes('provideNzI18n'));\n\n      if (!provideWithFunc && !provideWithToken) {\n        return addProvide;\n      }\n\n      console.log();\n      console.log(yellow(`Could not provide the locale token to file (${blue(modulePath)}), because there is already a locale token in providers.`));\n\n      if (provideWithToken) {\n        console.log(yellow(`Please manually add the following code to your providers:`));\n        console.log(cyan(`provideNzI18n(${locale})`));\n      }\n      return [];\n    }\n  } else {\n    return addProvide;\n  }\n}\n"
  },
  {
    "path": "schematics/ng-add/setup-project/theming.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { getProjectFromWorkspace, getProjectStyleFile, getProjectTargetOptions } from '@angular/cdk/schematics';\n\nimport { logging, normalize } from '@angular-devkit/core';\nimport { noop, Rule, SchematicContext, SchematicsException, Tree } from '@angular-devkit/schematics';\nimport { ProjectDefinition, readWorkspace, updateWorkspace } from '@schematics/angular/utility';\nimport { InsertChange } from '@schematics/angular/utility/change';\n\nimport { join } from 'path';\n\nimport { createCustomTheme } from '../../utils/create-custom-theme';\nimport { Schema } from '../schema';\n\nconst compiledThemePathSegment = 'ng-zorro-antd';\nconst compiledThemePath = './node_modules/ng-zorro-antd/ng-zorro-antd.min.css';\nconst defaultCustomThemeFilename = 'theme.less';\n\n/** Add pre-built styles to the main project style file. */\nexport function addThemeToAppStyles(options: Schema): Rule {\n  return async (host: Tree, context: SchematicContext) => {\n    if (options.theme) {\n      return insertCustomTheme(options.project, host, context.logger);\n    } else {\n      // Insert a pre-built theme into the angular.json file\n      return addThemeStyleToTarget(options.project, compiledThemePath, context.logger);\n    }\n  };\n}\n\n/**\n * Insert a custom theme to a project style file. If no valid style file could be found, a new\n * Scss file for the custom theme will be created.\n */\nasync function insertCustomTheme(projectName: string, host: Tree, logger: logging.LoggerApi): Promise<Rule> {\n  const workspace = await readWorkspace(host);\n  const project = getProjectFromWorkspace(workspace, projectName);\n  const stylesPath = getProjectStyleFile(project, 'less');\n  const themeContent = createCustomTheme();\n\n  if (!stylesPath) {\n    if (!project.sourceRoot) {\n      throw new SchematicsException(\n        `Could not find source root for project: \"${projectName}\". ` +\n        `Please make sure that the \"sourceRoot\" property is set in the workspace config.`\n      );\n    }\n\n    // Normalize the path through the devkit utilities because we want to avoid having\n    // unnecessary path segments and window backslash delimiters.\n    const customThemePath = normalize(join(project.sourceRoot, defaultCustomThemeFilename));\n\n    if (host.exists(customThemePath)) {\n      logger.warn(`Cannot create a custom NG-ZORRO theme because ${customThemePath} already exists. Skipping custom theme generation.`);\n      return noop();\n    }\n\n    host.create(customThemePath, themeContent);\n    return addThemeStyleToTarget(projectName, customThemePath, logger);\n  }\n\n  const insertion = new InsertChange(stylesPath, 0, themeContent);\n  const recorder = host.beginUpdate(stylesPath);\n\n  recorder.insertLeft(insertion.pos, insertion.toAdd);\n  host.commitUpdate(recorder);\n}\n\n/** Adds a theming style entry to the given project target options. */\nfunction addThemeStyleToTarget(\n  projectName: string,\n  assetPath: string,\n  logger: logging.LoggerApi\n): Rule {\n  return updateWorkspace(workspace => {\n    const project = getProjectFromWorkspace(workspace, projectName);\n    // Do not update the builder options in case the target does not use the default CLI builder.\n    if (!validateDefaultTargetBuilder(project)) {\n      return;\n    }\n    const targetOptions = getProjectTargetOptions(project, 'build');\n    const styles = targetOptions.styles as Array<string | { input: string }>;\n\n    if (!styles) {\n      targetOptions.styles = [assetPath];\n    } else {\n      const existingStyles = styles.map(s => (typeof s === 'string' ? s : s.input));\n\n      for (const [index, stylePath] of existingStyles.entries()) {\n        // If the given asset is already specified in the styles, we don't need to do anything.\n        if (stylePath === assetPath) {\n          return;\n        }\n\n        // In case a prebuilt theme is already set up, we can safely replace the theme with the new\n        // theme file. If a custom theme is set up, we are not able to safely replace the custom\n        // theme because these files can contain custom styles, while prebuilt themes are\n        // always packaged and considered replaceable.\n        if (stylePath.includes(defaultCustomThemeFilename)) {\n          logger.error(\n            `Could not style file to the CLI project configuration ` +\n            `because there is already a custom theme file referenced.`\n          );\n          logger.info(`Please manually add the following style file to your configuration:`);\n          logger.info(`${assetPath}`);\n          return;\n        } else if (stylePath.includes(compiledThemePathSegment)) {\n          styles.splice(index, 1);\n        }\n      }\n    }\n    styles.unshift(assetPath);\n  });\n}\n\n// Default target builder for build, which is provided by the Angular CLI.\nconst defaultTargetBuilder = '@angular/build:application';\n\n/**\n * Validates that the build target is configured with the default builder which is provided\n * by the Angular CLI. If the configured builder does not match the default builder, this\n * function can throw an exception\n */\nfunction validateDefaultTargetBuilder(project: ProjectDefinition): boolean {\n  const targetConfig = project.targets && project.targets.get('build');\n  const isDefaultBuilder = targetConfig && targetConfig.builder === defaultTargetBuilder;\n\n  if (!isDefaultBuilder) {\n    throw new SchematicsException(\n      `Your project is not using the default builder for \"build\".` +\n      `The NG-ZORRO schematics cannot add a theme to the workspace ` +\n      `configuration if the builder has been changed.`\n    );\n  }\n\n  return isDefaultBuilder;\n}\n"
  },
  {
    "path": "schematics/ng-add/standalone.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { getProjectFromWorkspace, getProjectTargetOptions } from '@angular/cdk/schematics';\n\nimport { normalize } from '@angular-devkit/core';\nimport { Tree } from '@angular-devkit/schematics';\nimport { NodePackageName } from '@angular-devkit/schematics/tasks/package-manager/options';\nimport { SchematicTestRunner } from '@angular-devkit/schematics/testing';\nimport { readWorkspace } from '@schematics/angular/utility';\n\nimport { join } from 'path';\n\nimport { Schema as NzOptions } from './schema';\nimport { createTestApp } from '../testing/test-app';\nimport { createCustomTheme } from '../utils/create-custom-theme';\nimport { getFileContent } from '../utils/get-file-content';\n\ndescribe('[standalone] ng-add schematic', () => {\n  const defaultOptions: NzOptions = {\n    project: 'ng-zorro'\n  };\n\n  let runner: SchematicTestRunner;\n  let appTree: Tree;\n\n  beforeEach(async () => {\n    runner = new SchematicTestRunner('schematics', require.resolve('../collection.json'));\n    appTree = await createTestApp(runner);\n  });\n\n  it('should update package.json', async () => {\n    const options = { ...defaultOptions };\n    const tree = await runner.runSchematic('ng-add', options, appTree);\n    const packageJson = JSON.parse(getFileContent(tree, '/package.json'));\n    const dependencies = packageJson.dependencies;\n\n    expect(dependencies['ng-zorro-antd']).toBeDefined();\n\n    expect(runner.tasks.some(task => task.name === NodePackageName)).toBe(true);\n  });\n\n  it('should add hammerjs to package.json', async () => {\n    const options = { ...defaultOptions, gestures: true };\n    const tree = await runner.runSchematic('ng-add', options, appTree);\n\n    const packageJson = JSON.parse(getFileContent(tree, '/package.json'));\n    const dependencies = packageJson.dependencies;\n\n    expect(dependencies.hammerjs).toBeDefined();\n  });\n\n  it('should skip package.json', async () => {\n    const options = { ...defaultOptions, skipPackageJson: true };\n    const tree = await runner.runSchematic('ng-add', options, appTree);\n\n    const packageJson = JSON.parse(getFileContent(tree, '/package.json'));\n    const dependencies = packageJson.dependencies;\n\n    expect(dependencies['ng-zorro-antd']).toBeUndefined();\n  });\n\n  it('should skip install dependency package', async () => {\n    const options = { ...defaultOptions, skipInstall: true };\n    await runner.runSchematic('ng-add', options, appTree);\n\n    expect(runner.tasks.some(task => task.name === NodePackageName)).toBe(false);\n  });\n\n  it('should add hammerjs import to project main file', async () => {\n    const options = { ...defaultOptions, gestures: true };\n    const tree = await runner.runSchematic('ng-add-setup-project', options, appTree);\n    const workspace = await readWorkspace(tree);\n    const project = getProjectFromWorkspace(workspace, defaultOptions.project);\n    const fileContent = getFileContent(tree, normalize(join(project.sourceRoot, 'main.ts')));\n\n    expect(fileContent).toContain(`import 'hammerjs';`);\n  });\n\n  it('should add default theme', async () => {\n    const options = { ...defaultOptions };\n    const tree = await runner.runSchematic('ng-add-setup-project', options, appTree);\n    const workspace = await readWorkspace(tree);\n    const project = getProjectFromWorkspace(workspace, defaultOptions.project);\n\n    expect(getProjectTargetOptions(project, 'build').styles).toContain(\n      './node_modules/ng-zorro-antd/ng-zorro-antd.min.css'\n    );\n  });\n\n  it('should add custom theme', async () => {\n    const options = { ...defaultOptions, theme: true };\n\n    appTree = await createTestApp(runner, { style: 'less' });\n    const tree = await runner.runSchematic('ng-add-setup-project', options, appTree);\n    const workspace = await readWorkspace(tree);\n    const project = getProjectFromWorkspace(workspace, defaultOptions.project);\n\n    const customThemePath = normalize(join(project.sourceRoot, 'styles.less'));\n    const buffer = tree.read(customThemePath);\n    const themeContent = buffer!.toString();\n\n    expect(themeContent).toContain(createCustomTheme());\n\n    expect(getProjectTargetOptions(project, 'build').styles).toContain('projects/ng-zorro/src/styles.less');\n  });\n\n  it('should add custom theme file when no LESS file in project', async () => {\n    const options = { ...defaultOptions, theme: true };\n    const tree = await runner.runSchematic('ng-add-setup-project', options, appTree);\n    const workspace = await readWorkspace(tree);\n    const project = getProjectFromWorkspace(workspace, defaultOptions.project);\n\n    expect(getProjectTargetOptions(project, 'build').styles).toContain('projects/ng-zorro/src/theme.less');\n  });\n\n  it('should add icon assets', async () => {\n    const options = { ...defaultOptions, dynamicIcon: true };\n    const tree = await runner.runSchematic('ng-add-setup-project', options, appTree);\n    const workspace = await readWorkspace(tree);\n    const project = getProjectFromWorkspace(workspace, defaultOptions.project);\n    const assets = getProjectTargetOptions(project, 'build').assets;\n\n    const assetsString = JSON.stringify(assets);\n    const iconPathSegment = '@ant-design/icons-angular';\n\n    expect(assetsString).toContain(iconPathSegment);\n  });\n\n  it('should not add provideNzNoAnimation() call function if animations is enable', async () => {\n    const options = { ...defaultOptions, animations: true };\n    const tree = await runner.runSchematic('ng-add-setup-project', options, appTree);\n    const fileContent = getFileContent(tree, '/projects/ng-zorro/src/app/app.config.ts');\n\n    expect(fileContent).not.toContain('provideNzNoAnimation()');\n  });\n\n  it(`should add provideNzNoAnimation() function call if animations is disable`, async () => {\n    const options = { ...defaultOptions, animations: false };\n    const tree = await runner.runSchematic('ng-add-setup-project', options, appTree);\n    const fileContent = getFileContent(tree, '/projects/ng-zorro/src/app/app.config.ts');\n\n    expect(fileContent).toContain(`provideNzNoAnimation()`);\n  });\n\n  it('should register default locale id', async () => {\n    const options = { ...defaultOptions };\n    const tree = await runner.runSchematic('ng-add-setup-project', options, appTree);\n    const fileContent = getFileContent(tree, '/projects/ng-zorro/src/app/app.config.ts');\n\n    expect(fileContent).toContain('provideNzI18n(en_US)');\n    expect(fileContent).toContain('registerLocaleData(en)');\n  });\n\n  it('should register specified locale id', async () => {\n    const options = { ...defaultOptions, locale: 'zh_CN' };\n    const tree = await runner.runSchematic('ng-add-setup-project', options, appTree);\n    const fileContent = getFileContent(tree, '/projects/ng-zorro/src/app/app.config.ts');\n\n    expect(fileContent).toContain('provideNzI18n(zh_CN)');\n    expect(fileContent).toContain('registerLocaleData(zh)');\n  });\n\n  it('should not add locale id if locale id is set up', async () => {\n    const options = { ...defaultOptions, i18n: 'zh_CN' };\n    await runner.runSchematic('ng-add-setup-project', { ...defaultOptions }, appTree);\n\n    spyOn(console, 'log');\n\n    const tree = await runner.runSchematic('ng-add-setup-project', options, appTree);\n    const fileContent = getFileContent(tree, '/projects/ng-zorro/src/app/app.config.ts');\n\n    expect(fileContent).toContain('provideNzI18n(en_US)');\n    expect(fileContent).toContain('registerLocaleData(en)');\n    expect(fileContent).not.toContain('provideNzI18n(zh_CN)');\n    expect(fileContent).not.toContain('registerLocaleData(zh)');\n\n    expect(console.log).toHaveBeenCalledWith(jasmine.stringMatching(/Could not add the registerLocaleData to file/));\n  });\n});\n"
  },
  {
    "path": "schematics/ng-component/files/__path__/__name@dasherize@if-flat__/__name@dasherize__.__type@dasherize__.__style__.template",
    "content": "<% if(displayBlock){ if(style != 'sass') { %>:host {\n  display: block;\n}\n<% } else { %>\\:host\n  display: block;\n<% }} %>"
  },
  {
    "path": "schematics/ng-component/files/__path__/__name@dasherize@if-flat__/__name@dasherize__.__type@dasherize__.spec.ts.template",
    "content": "import { ComponentFixture, TestBed } from '@angular/core/testing';\n\nimport <% if(!exportDefault) { %>{ <% }%><%= classify(name) %><%= classify(type) %> <% if(!exportDefault) {%>} <% }%>from './<%= dasherize(name) %><%= type ? '.' + dasherize(type): '' %>';\n\ndescribe('<%= classify(name) %><%= classify(type) %>', () => {\n  let component: <%= classify(name) %><%= classify(type) %>;\n  let fixture: ComponentFixture<<%= classify(name) %><%= classify(type) %>>;\n\n  beforeEach(async () => {\n    await TestBed.configureTestingModule({\n      <%= standalone ? 'imports' : 'declarations' %>: [<%= classify(name) %><%= classify(type) %>]\n    })\n    .compileComponents();\n\n    fixture = TestBed.createComponent(<%= classify(name) %><%= classify(type) %>);\n    component = fixture.componentInstance;\n    fixture.detectChanges();\n  });\n\n  it('should create', () => {\n    expect(component).toBeTruthy();\n  });\n});"
  },
  {
    "path": "schematics/ng-component/files/__path__/__name@dasherize@if-flat__/__name@dasherize__.__type@dasherize__.ts.template",
    "content": "import { <% if(changeDetection !== 'Default') { %>ChangeDetectionStrategy, <% }%>Component<% if(!!viewEncapsulation) { %>, ViewEncapsulation<% }%> } from '@angular/core';\n\n@Component({<% if(!skipSelector) {%>\n  selector: '<%= selector %>',<%}%><% if(standalone) {%>\n  imports: [],<%} else { %>\n  standalone: false,<% }%><% if(inlineTemplate) { %>\n  template: `\n    <p>\n      <%= dasherize(name) %> works!\n    </p>\n  `<% } else { %>\n  templateUrl: './<%= dasherize(name) %><%= type ? '.' + dasherize(type): '' %><%= ngext %>.html'<% } if(inlineStyle) { %>,\n  styles: `<% if(displayBlock){ %>\n    :host {\n      display: block;\n    }\n  <% } %>`<% } else if (style !== 'none') { %>,\n  styleUrl: './<%= dasherize(name) %><%= type ? '.' + dasherize(type): '' %>.<%= style %>'<% } %><% if(!!viewEncapsulation) { %>,\n  encapsulation: ViewEncapsulation.<%= viewEncapsulation %><% } if (changeDetection !== 'Default') { %>,\n  changeDetection: ChangeDetectionStrategy.<%= changeDetection %><% } %>\n})\nexport <% if(exportDefault) {%>default <%}%>class <%= classify(name) %><%= classify(type) %> {}\n"
  },
  {
    "path": "schematics/ng-component/files/__path__/__name@dasherize@if-flat__/__name@dasherize__.__type@dasherize____ngext__.html.template",
    "content": "<p><%= dasherize(name) %> works!</p>"
  },
  {
    "path": "schematics/ng-component/index.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Tree } from '@angular-devkit/schematics';\nimport { SchematicTestRunner } from '@angular-devkit/schematics/testing';\nimport { ChangeDetection, Style } from '@schematics/angular/component/schema';\n\nimport { createTestApp } from '../testing/test-app';\n\nconst appOptions = {\n  name: 'ng-zorro',\n  inlineStyle: false,\n  inlineTemplate: false,\n  routing: false,\n  style: Style.Less,\n  skipTests: false,\n  skipPackageJson: false\n};\n\nconst defaultOptions = {\n  name: 'test',\n  inlineStyle: false,\n  inlineTemplate: false,\n  changeDetection: ChangeDetection.Default,\n  style: Style.Less,\n  type: 'Component',\n  skipTests: false,\n  module: undefined,\n  export: false,\n  project: 'ng-zorro'\n};\n\nfunction generateModuleContent(moduleName: string): string {\n  return `\nimport { NgModule } from '@angular/core';\n@NgModule({\n  imports: [],\n  declarations: []\n})\nexport class ${moduleName} {}\n`;\n}\n\ndescribe('[schematic] ng-component', () => {\n  let runner: SchematicTestRunner;\n  let appTree: Tree;\n\n  beforeEach(async () => {\n    runner = new SchematicTestRunner('schematics', require.resolve('../collection.json'));\n    appTree = await createTestApp(runner, { ...appOptions });\n  });\n\n  it('should create a component', async () => {\n    const options = { ...defaultOptions };\n    const tree = await runner.runSchematic('component', options, appTree);\n    const files = tree.files;\n\n    expect(files).toEqual(\n      jasmine.arrayContaining([\n        '/projects/ng-zorro/src/app/test/test.component.less',\n        '/projects/ng-zorro/src/app/test/test.component.html',\n        '/projects/ng-zorro/src/app/test/test.component.spec.ts',\n        '/projects/ng-zorro/src/app/test/test.component.ts'\n      ])\n    );\n  });\n\n  it('should respect the type option', async () => {\n    const options = { ...defaultOptions, type: 'container' };\n    const tree = await runner.runSchematic('component', options, appTree);\n    const files = tree.files;\n\n    expect(files).toEqual(\n      jasmine.arrayContaining([\n        '/projects/ng-zorro/src/app/test/test.container.less',\n        '/projects/ng-zorro/src/app/test/test.container.html',\n        '/projects/ng-zorro/src/app/test/test.container.spec.ts',\n        '/projects/ng-zorro/src/app/test/test.container.ts'\n      ])\n    );\n  });\n\n  it('should allow empty string in the type option', async () => {\n    const options = { ...defaultOptions, type: '' };\n    const tree = await runner.runSchematic('component', options, appTree);\n    const files = tree.files;\n\n    expect(files).toEqual(\n      jasmine.arrayContaining([\n        '/projects/ng-zorro/src/app/test/test.less',\n        '/projects/ng-zorro/src/app/test/test.html',\n        '/projects/ng-zorro/src/app/test/test.spec.ts',\n        '/projects/ng-zorro/src/app/test/test.ts'\n      ])\n    );\n  });\n\n  it('should not use `.ng.html` extension when ngHtml is false', async () => {\n    const options = { ...defaultOptions, ngHtml: false };\n    const tree = await runner.runSchematic('component', options, appTree);\n    const content = tree.readContent('/projects/ng-zorro/src/app/test/test.component.ts');\n    const files = tree.files;\n\n    expect(content).toContain('test.component.html');\n    expect(files).toContain('/projects/ng-zorro/src/app/test/test.component.less');\n    expect(files).toContain('/projects/ng-zorro/src/app/test/test.component.html');\n  });\n\n  it('should use `.ng.html` extension when ngHtml is true', async () => {\n    const options = { ...defaultOptions, ngHtml: true };\n    const tree = await runner.runSchematic('component', options, appTree);\n    const content = tree.readContent('/projects/ng-zorro/src/app/test/test.component.ts');\n    const files = tree.files;\n\n    expect(content).toContain('test.component.ng.html');\n    expect(files).toContain('/projects/ng-zorro/src/app/test/test.component.less');\n    expect(files).toContain('/projects/ng-zorro/src/app/test/test.component.ng.html');\n  });\n\n  describe('style', () => {\n    it('should create specified style', async () => {\n      const options = { ...defaultOptions, style: Style.Sass };\n      const tree = await runner.runSchematic('component', options, appTree);\n      const files = tree.files;\n\n      expect(files).toEqual(\n        jasmine.arrayContaining([\n          '/projects/ng-zorro/src/app/test/test.component.sass',\n          '/projects/ng-zorro/src/app/test/test.component.html',\n          '/projects/ng-zorro/src/app/test/test.component.spec.ts',\n          '/projects/ng-zorro/src/app/test/test.component.ts'\n        ])\n      );\n    });\n\n    it('should not create style file when inlineStyle is true', async () => {\n      const options = { ...defaultOptions, inlineStyle: true };\n      const tree = await runner.runSchematic('component', options, appTree);\n      const files = tree.files;\n\n      expect(files).toEqual(\n        jasmine.arrayContaining([\n          '/projects/ng-zorro/src/app/test/test.component.html',\n          '/projects/ng-zorro/src/app/test/test.component.spec.ts',\n          '/projects/ng-zorro/src/app/test/test.component.ts'\n        ])\n      );\n      expect(files).not.toContain('/projects/ng-zorro/src/app/test/test.component.less');\n    });\n\n    it('should not create style file when style is none', async () => {\n      const options = { ...defaultOptions, style: Style.None };\n      const tree = await runner.runSchematic('component', options, appTree);\n      const files = tree.files;\n\n      expect(files).toEqual(\n        jasmine.arrayContaining([\n          '/projects/ng-zorro/src/app/test/test.component.html',\n          '/projects/ng-zorro/src/app/test/test.component.spec.ts',\n          '/projects/ng-zorro/src/app/test/test.component.ts'\n        ])\n      );\n      expect(files).not.toContain('/projects/ng-zorro/src/app/test/test.component.less');\n    });\n  });\n\n  describe('displayBlock', () => {\n    it('should add display block styles to the component', async () => {\n      const options = { ...defaultOptions, displayBlock: true };\n      const tree = await runner.runSchematic('component', options, appTree);\n      const content = tree.readContent('/projects/ng-zorro/src/app/test/test.component.less');\n\n      expect(content).toMatch(/display: block/);\n    });\n\n    it('should add display block styles to the component when inlineStyle is true', async () => {\n      const options = { ...defaultOptions, displayBlock: true, inlineStyle: true };\n      const tree = await runner.runSchematic('component', options, appTree);\n      const content = tree.readContent('/projects/ng-zorro/src/app/test/test.component.ts');\n\n      expect(content).toMatch(/display: block/);\n    });\n  });\n\n  describe('flat', () => {\n    it('should create a flat component', async () => {\n      const options = { ...defaultOptions, flat: true };\n      const tree = await runner.runSchematic('component', options, appTree);\n      const files = tree.files;\n\n      expect(files).toEqual(\n        jasmine.arrayContaining([\n          '/projects/ng-zorro/src/app/test.component.less',\n          '/projects/ng-zorro/src/app/test.component.html',\n          '/projects/ng-zorro/src/app/test.component.spec.ts',\n          '/projects/ng-zorro/src/app/test.component.ts'\n        ])\n      );\n    });\n  });\n\n  describe('classnameWithModule', () => {\n    it('should find the closest module', async () => {\n      const options = { ...defaultOptions, standalone: false };\n      const closestModule = '/projects/ng-zorro/src/app/test/test-module.ts';\n\n      appTree.create(\n        closestModule,\n        generateModuleContent('ClosestModule')\n      );\n      const tree = await runner.runSchematic('component', options, appTree);\n      const fooModuleContent = tree.readContent(closestModule);\n\n      expect(fooModuleContent).toMatch(/import { TestComponent } from '.\\/test.component'/);\n    });\n\n    it('should set classname with the closest module', async () => {\n      const options = { ...defaultOptions, classnameWithModule: true, standalone: false };\n      const testModule = '/projects/ng-zorro/src/app/test/test-module.ts';\n\n      appTree.create(\n        testModule,\n        generateModuleContent('TestModule')\n      );\n\n      const tree = await runner.runSchematic('component', options, appTree);\n      const fooModuleContent = tree.readContent(testModule);\n\n      expect(fooModuleContent).toMatch(/import { TestTestComponent } from '.\\/test.component'/);\n    });\n\n    it('should set classname with the specified module', async () => {\n      const options = { ...defaultOptions, classnameWithModule: true, module: 'app-module.ts', standalone: false };\n      const app = await createTestApp(runner, { ...appOptions, standalone: false });\n      const tree = await runner.runSchematic('component', options, app);\n\n      const appComponentContent = tree.readContent('/projects/ng-zorro/src/app/app-module.ts');\n      expect(appComponentContent).toMatch(/import { AppTestComponent } from '.\\/test\\/test.component'/);\n    });\n  });\n});\n"
  },
  {
    "path": "schematics/ng-component/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { chain, Rule } from '@angular-devkit/schematics';\n\nimport { Schema } from './schema';\nimport { buildComponent } from '../utils/build-component';\n\nexport default function(options: Schema): Rule {\n  return chain([\n    buildComponent({ ...options })\n  ]);\n}\n"
  },
  {
    "path": "schematics/ng-component/schema.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-07/schema\",\n  \"$id\": \"PLACEHOLDER_SCHEMATICS_ID\",\n  \"title\": \"PLACEHOLDER_SCHEMATICS_TITLE\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"path\": {\n      \"type\": \"string\",\n      \"format\": \"path\",\n      \"description\": \"The path to create the component.\",\n      \"visible\": false\n    },\n    \"project\": {\n      \"type\": \"string\",\n      \"description\": \"The name of the project.\",\n      \"$default\": {\n        \"$source\": \"projectName\"\n      }\n    },\n    \"name\": {\n      \"type\": \"string\",\n      \"description\": \"The name of the component.\",\n      \"$default\": {\n        \"$source\": \"argv\",\n        \"index\": 0\n      },\n      \"x-prompt\": \"What should be the name of the component?\"\n    },\n    \"displayBlock\": {\n      \"description\": \"Specifies if the style will contain `:host { display: block; }`.\",\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"alias\": \"b\"\n    },\n    \"inlineStyle\": {\n      \"description\": \"When true, includes styles inline in the component.ts file. Only CSS styles can be included inline. By default, an external styles file is created and referenced in the component.ts file.\",\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"alias\": \"s\"\n    },\n    \"inlineTemplate\": {\n      \"description\": \"When true, includes template inline in the component.ts file. By default, an external template file is created and referenced in the component.ts file.\",\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"alias\": \"t\"\n    },\n    \"standalone\": {\n      \"description\": \"Whether the generated component is standalone.\",\n      \"type\": \"boolean\",\n      \"default\": true\n    },\n    \"viewEncapsulation\": {\n      \"description\": \"The view encapsulation strategy to use in the new component.\",\n      \"enum\": [\"Emulated\", \"Native\", \"None\", \"ShadowDom\"],\n      \"type\": \"string\",\n      \"alias\": \"v\"\n    },\n    \"changeDetection\": {\n      \"description\": \"Specifies the change detection strategy.\",\n      \"enum\": [\"Default\", \"OnPush\"],\n      \"type\": \"string\",\n      \"default\": \"Default\",\n      \"alias\": \"c\"\n    },\n    \"prefix\": {\n      \"type\": \"string\",\n      \"description\": \"The prefix to apply to the generated component selector.\",\n      \"alias\": \"p\",\n      \"oneOf\": [\n        {\n          \"maxLength\": 0\n        },\n        {\n          \"minLength\": 1,\n          \"format\": \"html-selector\"\n        }\n      ]\n    },\n    \"style\": {\n      \"description\": \"The file extension or preprocessor to use for style files, or 'none' to skip generating the style file.\",\n      \"type\": \"string\",\n      \"default\": \"css\",\n      \"enum\": [\n        \"css\",\n        \"scss\",\n        \"sass\",\n        \"less\",\n        \"styl\",\n        \"none\"\n      ]\n    },\n    \"type\": {\n      \"type\": \"string\",\n      \"description\": \"Append a custom type to the component's filename. For example, if you set the type to `container`, the file will be named `my-component.container.ts`.\"\n    },\n    \"skipTests\": {\n      \"type\": \"boolean\",\n      \"description\": \"When true, does not create \\\"spec.ts\\\" test files for the new component.\",\n      \"default\": false\n    },\n    \"flat\": {\n      \"type\": \"boolean\",\n      \"description\": \"Flag to indicate if a dir is created.\",\n      \"default\": false\n    },\n    \"skipImport\": {\n      \"type\": \"boolean\",\n      \"description\": \"When true, does not import this component into the owning NgModule.\",\n      \"default\": false\n    },\n    \"selector\": {\n      \"type\": \"string\",\n      \"format\": \"html-selector\",\n      \"description\": \"The selector to use for the component.\"\n    },\n    \"skipSelector\": {\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"description\": \"Skip the generation of an HTML selector for the component.\"\n    },\n    \"module\": {\n      \"type\": \"string\",\n      \"description\": \"Allows specification of the declaring module.\",\n      \"alias\": \"m\"\n    },\n    \"export\": {\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"description\": \"When true, the declaring NgModule exports this component.\"\n    },\n    \"exportDefault\": {\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"description\": \"Use a default export for the component in its TypeScript file instead of a named export.\"\n    },\n    \"ngHtml\": {\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"description\": \"Generate component template files with an '.ng.html' file extension instead of '.html'.\"\n    },\n    \"entryComponent\": {\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"description\": \"When true, the new component is the entry component of the declaring NgModule.\"\n    },\n    \"classnameWithModule\": {\n      \"type\": \"boolean\",\n      \"description\": \"When true, Use module class name as additional prefix for the component classname.\",\n      \"default\": false\n    }\n  },\n  \"required\": [\n    \"name\"\n  ]\n}\n"
  },
  {
    "path": "schematics/ng-component/schema.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ZorroComponentOptions } from '../utils/build-component';\n\nexport interface Schema extends ZorroComponentOptions {\n  [key: string]: string | boolean;\n}\n"
  },
  {
    "path": "schematics/ng-generate/blank/index.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Tree } from '@angular-devkit/schematics';\nimport { SchematicTestRunner } from '@angular-devkit/schematics/testing';\n\nimport { Schema as NzOptions } from '../../ng-add/schema';\nimport { createTestApp } from '../../testing/test-app';\n\ndescribe('[schematic] ng-generate', () => {\n  const defaultOptions: NzOptions = {\n    project: 'ng-zorro',\n  };\n  let runner: SchematicTestRunner;\n  let appTree: Tree;\n\n  beforeEach(async () => {\n    runner = new SchematicTestRunner('schematics', require.resolve('../../collection.json'));\n    appTree = await createTestApp(runner);\n  });\n\n  it('should update app.html', async () => {\n    const options = {...defaultOptions};\n    const appComponentHTMLPath = '/projects/ng-zorro/src/app/app.html';\n    const tree = await runner.runSchematic('blank', options, appTree);\n    const appComponentHTML = tree.readContent(appComponentHTMLPath);\n    const files = tree.files;\n\n    expect(files).toEqual(jasmine.arrayContaining([ appComponentHTMLPath ]));\n    expect(appComponentHTML).toContain('href=\"https://github.com/NG-ZORRO/ng-zorro-antd\"');\n  });\n});\n"
  },
  {
    "path": "schematics/ng-generate/blank/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { getProjectFromWorkspace } from '@angular/cdk/schematics';\n\n\nimport { noop, Rule, Tree } from '@angular-devkit/schematics';\nimport { readWorkspace } from '@schematics/angular/utility';\n\nimport { existsSync, statSync } from 'fs';\n\nimport { Schema } from './schema';\n\nconst bootPageHTML = `<!-- NG-ZORRO -->\n<a href=\"https://github.com/NG-ZORRO/ng-zorro-antd\" target=\"_blank\" style=\"display: flex;align-items: center;justify-content: center;height: 100%;width: 100%;\">\n  <img height=\"300\" alt=\"logo\" src=\"https://img.alicdn.com/tfs/TB1X.qJJgHqK1RjSZFgXXa7JXXa-89-131.svg\">\n</a>`;\n\nexport default function(options: Schema): Rule {\n  return async (host: Tree, context) => {\n    const workspace = await readWorkspace(host);\n    const project = getProjectFromWorkspace(workspace, options.project);\n    const appHTMLFile = `${project.sourceRoot}/app/app.html`;\n    const buffer = host.read(appHTMLFile);\n\n    if (!buffer) {\n      context.logger.error(\n        `Could not find the project ${appHTMLFile} file inside of the ` + `workspace config`\n      );\n      return noop();\n    }\n    if (existsSync(appHTMLFile)) {\n      const stat = statSync(appHTMLFile);\n      if (stat.mtimeMs === stat.ctimeMs) {\n        host.overwrite(appHTMLFile, bootPageHTML);\n      }\n    } else {\n      host.overwrite(appHTMLFile, bootPageHTML);\n    }\n\n    return noop();\n  };\n}\n"
  },
  {
    "path": "schematics/ng-generate/blank/schema.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/schema\",\n  \"$id\": \"nz-ng-generate-boot\",\n  \"title\": \"Ant Design of Angular(NG-ZORRO) boot page schematic\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"project\": {\n      \"type\": \"string\",\n      \"description\": \"Name of the project.\",\n      \"$default\": {\n        \"$source\": \"projectName\"\n      }\n    }\n  },\n  \"required\": []\n}"
  },
  {
    "path": "schematics/ng-generate/blank/schema.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport interface Schema {\n  /** Name of the project to target. */\n  project?: string;\n}\n"
  },
  {
    "path": "schematics/ng-generate/side-menu/files/src/app/app-routing-module.ts.template",
    "content": "import { NgModule } from '@angular/core';\nimport { Routes, RouterModule } from '@angular/router';\n\nconst routes: Routes = [\n  { path: '', pathMatch: 'full', redirectTo: '/welcome' },\n  { path: 'welcome', loadChildren: () => import('./pages/welcome/welcome-module').then(m => m.WelcomeModule) }\n];\n\n@NgModule({\n  imports: [RouterModule.forRoot(routes)],\n  exports: [RouterModule]\n})\nexport class AppRoutingModule {}\n"
  },
  {
    "path": "schematics/ng-generate/side-menu/files/src/app/app.__style__.template",
    "content": ":host {\n  display: flex;\n  text-rendering: optimizeLegibility;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\n.app-layout {\n  height: 100vh;\n}\n\n.menu-sidebar {\n  position: relative;\n  z-index: 10;\n  min-height: 100vh;\n  box-shadow: 2px 0 6px rgba(0,21,41,.35);\n}\n\n.header-trigger {\n  height: 64px;\n  padding: 20px 24px;\n  font-size: 20px;\n  cursor: pointer;\n  transition: all .3s,padding 0s;\n}\n\n.trigger:hover {\n  color: #1890ff;\n}\n\n.sidebar-logo {\n  position: relative;\n  height: 64px;\n  padding-left: 24px;\n  overflow: hidden;\n  line-height: 64px;\n  background: #001529;\n  transition: all .3s;\n}\n\n.sidebar-logo img {\n  display: inline-block;\n  height: 32px;\n  width: 32px;\n  vertical-align: middle;\n}\n\n.sidebar-logo h1 {\n  display: inline-block;\n  margin: 0 0 0 20px;\n  color: #fff;\n  font-weight: 600;\n  font-size: 14px;\n  font-family: Avenir,Helvetica Neue,Arial,Helvetica,sans-serif;\n  vertical-align: middle;\n}\n\nnz-header {\n  padding: 0;\n  width: 100%;\n  z-index: 2;\n}\n\n.app-header {\n  position: relative;\n  height: 64px;\n  padding: 0;\n  background: #fff;\n  box-shadow: 0 1px 4px rgba(0,21,41,.08);\n}\n\nnz-content {\n  margin: 24px;\n}\n\n.inner-content {\n  padding: 24px;\n  background: #fff;\n  height: 100%;\n}\n"
  },
  {
    "path": "schematics/ng-generate/side-menu/files/src/app/app.html.template",
    "content": "<nz-layout class=\"app-layout\">\n  <nz-sider class=\"menu-sidebar\"\n    nzCollapsible\n    nzWidth=\"256px\"\n    nzBreakpoint=\"md\"\n    [(nzCollapsed)]=\"isCollapsed\"\n    [nzTrigger]=\"null\">\n    <div class=\"sidebar-logo\">\n      <a href=\"https://ng.ant.design/\" target=\"_blank\">\n        <img src=\"https://ng.ant.design/assets/img/logo.svg\" alt=\"logo\">\n        <h1>Ant Design Of Angular</h1>\n      </a>\n    </div>\n    <ul nz-menu nzTheme=\"dark\" nzMode=\"inline\" [nzInlineCollapsed]=\"isCollapsed\">\n      <li nz-submenu nzOpen nzTitle=\"Dashboard\" nzIcon=\"dashboard\">\n        <ul>\n          <li nz-menu-item nzMatchRouter>\n            <a routerLink=\"/welcome\">Welcome</a>\n          </li>\n          <li nz-menu-item nzMatchRouter>\n            <a>Monitor</a>\n          </li>\n          <li nz-menu-item nzMatchRouter>\n            <a>Workplace</a>\n          </li>\n        </ul>\n      </li>\n      <li nz-submenu nzOpen nzTitle=\"Form\" nzIcon=\"form\">\n        <ul>\n          <li nz-menu-item nzMatchRouter>\n            <a>Basic Form</a>\n          </li>\n        </ul>\n      </li>\n    </ul>\n  </nz-sider>\n  <nz-layout>\n    <nz-header>\n      <div class=\"app-header\">\n        <span class=\"header-trigger\" (click)=\"isCollapsed = !isCollapsed\">\n          <nz-icon class=\"trigger\" [nzType]=\"isCollapsed ? 'menu-unfold' : 'menu-fold'\" />\n        </span>\n      </div>\n    </nz-header>\n    <nz-content>\n      <div class=\"inner-content\">\n        <router-outlet></router-outlet>\n      </div>\n    </nz-content>\n  </nz-layout>\n</nz-layout>\n"
  },
  {
    "path": "schematics/ng-generate/side-menu/files/src/app/app.ts.template",
    "content": "import { Component } from '@angular/core';\n\n@Component({\n  selector: '<%= prefix %>-root',\n  standalone: false,\n  templateUrl: './app.html',\n  styleUrl: './app.<%= style %>'\n})\nexport class App {\n  isCollapsed = false;\n}\n"
  },
  {
    "path": "schematics/ng-generate/side-menu/files/src/app/icons-provider.module.ts.template",
    "content": "import { NgModule } from '@angular/core';\nimport { NzIconModule, provideNzIcons } from 'ng-zorro-antd/icon';\n\nimport {\n  MenuFoldOutline,\n  MenuUnfoldOutline,\n  FormOutline,\n  DashboardOutline\n} from '@ant-design/icons-angular/icons';\n\nconst icons = [MenuFoldOutline, MenuUnfoldOutline, DashboardOutline, FormOutline];\n\n@NgModule({\n  imports: [NzIconModule],\n  exports: [NzIconModule],\n  providers: [\n    provideNzIcons(icons)\n  ]\n})\nexport class IconsProviderModule {}\n"
  },
  {
    "path": "schematics/ng-generate/side-menu/files/src/app/pages/welcome/welcome-module.ts.template",
    "content": "import { NgModule } from '@angular/core';\n\nimport { WelcomeRoutingModule } from './welcome-routing-module';\n\nimport <% if(!exportDefault) { %>{ <% }%>Welcome<%= classify(type) %> <% if(!exportDefault) {%>} <% }%>from './welcome<%= type ? '.' + dasherize(type): '' %>';\n\n@NgModule({\n  imports: [WelcomeRoutingModule],\n  declarations: [Welcome<%= type ? classify(type): '' %>],\n  exports: [Welcome<%= type ? classify(type): '' %>]\n})\nexport class WelcomeModule {}\n"
  },
  {
    "path": "schematics/ng-generate/side-menu/files/src/app/pages/welcome/welcome-routing-module.ts.template",
    "content": "import { NgModule } from '@angular/core';\nimport { Routes, RouterModule } from '@angular/router';\n\nimport <% if(!exportDefault) { %>{ <% }%>Welcome<%= classify(type) %> <% if(!exportDefault) {%>} <% }%>from './welcome<%= type ? '.' + dasherize(type): '' %>';\n\nconst routes: Routes = [\n  { path: '', component: Welcome<%= type ? classify(type): '' %> },\n];\n\n@NgModule({\n  imports: [RouterModule.forChild(routes)],\n  exports: [RouterModule]\n})\nexport class WelcomeRoutingModule {}\n"
  },
  {
    "path": "schematics/ng-generate/side-menu/index.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Tree } from '@angular-devkit/schematics';\nimport { SchematicTestRunner } from '@angular-devkit/schematics/testing';\nimport { Style } from '@schematics/angular/ng-new/schema';\n\nimport { Schema as NzOptions } from '../../ng-add/schema';\nimport { createTestApp } from '../../testing/test-app';\nimport { getFileContent } from '../../utils/get-file-content';\n\ndescribe('[schematic] side-menu', () => {\n  const defaultOptions: NzOptions = {\n    project: 'ng-zorro'\n  };\n\n  let runner: SchematicTestRunner;\n  let appTree: Tree;\n\n  beforeEach(async () => {\n    runner = new SchematicTestRunner('schematics', require.resolve('../../collection.json'));\n    appTree = await createTestApp(runner, { standalone: false });\n  });\n\n  it('should create side-menu files', async () => {\n    const options = { ...defaultOptions };\n    const tree = await runner.runSchematic('sidemenu', options, appTree);\n    const appContent = getFileContent(tree, '/projects/ng-zorro/src/app/app.ts');\n    const welcomeContent = getFileContent(tree, '/projects/ng-zorro/src/app/pages/welcome/welcome.component.ts');\n    expect(appContent).toContain('standalone: false');\n    expect(welcomeContent).toContain('standalone: false');\n\n    expect(tree.files).toEqual(\n      jasmine.arrayContaining([\n        '/projects/ng-zorro/src/app/app.html',\n        '/projects/ng-zorro/src/app/app.css',\n        '/projects/ng-zorro/src/app/app.ts',\n        '/projects/ng-zorro/src/app/app-routing-module.ts',\n        '/projects/ng-zorro/src/app/pages/welcome/welcome-module.ts',\n        '/projects/ng-zorro/src/app/pages/welcome/welcome-routing-module.ts',\n        '/projects/ng-zorro/src/app/pages/welcome/welcome.component.ts',\n        '/projects/ng-zorro/src/app/pages/welcome/welcome.component.css',\n        '/projects/ng-zorro/src/app/pages/welcome/welcome.component.html'\n      ])\n    );\n  });\n\n  describe('style option', () => {\n    it('should set the style preprocessor correctly', async () => {\n      const options = { ...defaultOptions, style: Style.Less };\n      const tree = await runner.runSchematic('sidemenu', options, appTree);\n      const appContent = getFileContent(tree, '/projects/ng-zorro/src/app/app.ts');\n      const welcomeContent = getFileContent(tree, '/projects/ng-zorro/src/app/pages/welcome/welcome.component.ts');\n      expect(appContent).toContain('app.less');\n      expect(welcomeContent).toContain('welcome.component.less');\n\n      expect(tree.files).toEqual(\n        jasmine.arrayContaining([\n          '/projects/ng-zorro/src/app/app.less',\n          '/projects/ng-zorro/src/app/pages/welcome/welcome.component.less'\n        ])\n      );\n    });\n\n    it('should fall back to the @schematics/angular:component option value', async () => {\n      const options = { ...defaultOptions, template: 'sidemenu' };\n      appTree = await createTestApp(runner, { style: Style.Less, standalone: false });\n      const tree = await runner.runSchematic('ng-add', options, appTree);\n\n      expect(tree.files).toEqual(\n        jasmine.arrayContaining([\n          '/projects/ng-zorro/src/app/app.less',\n          '/projects/ng-zorro/src/app/pages/welcome/welcome.component.less'\n        ])\n      );\n    });\n  });\n\n  it('should set the prefix correctly', async () => {\n    const options = { ...defaultOptions, prefix: 'nz' };\n    const tree = await runner.runSchematic('sidemenu', options, appTree);\n    const appContent = getFileContent(tree, '/projects/ng-zorro/src/app/app.ts');\n    const welcomeContent = getFileContent(tree, '/projects/ng-zorro/src/app/pages/welcome/welcome.component.ts');\n\n    expect(appContent).toContain(`selector: 'nz-root'`);\n    expect(welcomeContent).toContain(`selector: 'nz-welcome'`);\n  });\n\n  it('should set standalone to be false', async () => {\n    const options = { ...defaultOptions };\n    const tree = await runner.runSchematic('ng-add-setup-project', options, appTree);\n    const appContent = getFileContent(tree, '/projects/ng-zorro/src/app/app.ts');\n    expect(appContent).toContain('standalone: false');\n  });\n});\n"
  },
  {
    "path": "schematics/ng-generate/side-menu/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  getProjectFromWorkspace,\n  getProjectMainFile,\n  insertImport,\n  isStandaloneApp,\n  parseSourceFile\n} from '@angular/cdk/schematics';\n\nimport {\n  apply,\n  applyTemplates,\n  chain,\n  FileEntry,\n  forEach,\n  MergeStrategy,\n  mergeWith,\n  move,\n  Rule,\n  schematic,\n  strings,\n  Tree,\n  url\n} from '@angular-devkit/schematics';\nimport { addRootProvider, readWorkspace } from '@schematics/angular/utility';\nimport { findAppConfig } from '@schematics/angular/utility/standalone/app_config';\nimport { findBootstrapApplicationCall } from '@schematics/angular/utility/standalone/util';\n\nimport { Schema } from './schema';\nimport { applyChangesToFile } from '../../utils/apply-changes';\nimport { getAppOptions } from '../../utils/config';\nimport { addModule } from '../../utils/root-module';\n\nexport default function(options: Schema): Rule {\n  return async (host: Tree) => {\n    const workspace = await readWorkspace(host);\n    const project = getProjectFromWorkspace(workspace, options.project);\n    const mainFile = getProjectMainFile(project);\n    const { componentOptions, sourceDir } = await getAppOptions(options.project, project.root);\n    const prefix = options.prefix || project.prefix;\n    const style = options.style || componentOptions.style;\n    const exportDefault = componentOptions.exportDefault ?? false;\n\n    const isStandalone = isStandaloneApp(host, mainFile);\n    const templateSourcePath = isStandalone ? './standalone' : './files';\n\n    return chain([\n      mergeWith(\n        apply(url(`${templateSourcePath}/src`), [\n          applyTemplates({\n            ...strings,\n            ...componentOptions,\n            exportDefault,\n            prefix,\n            style\n          }),\n          move(project.sourceRoot as string),\n          forEach((fileEntry: FileEntry) => {\n            if (host.exists(fileEntry.path)) {\n              host.overwrite(fileEntry.path, fileEntry.content);\n            }\n            return fileEntry;\n          })\n        ]),\n        MergeStrategy.Overwrite\n      ),\n      schematic('component', {\n        name: 'welcome',\n        project: options.project,\n        standalone: isStandalone,\n        ...componentOptions,\n        path: `${sourceDir}/pages`,\n        skipImport: true,\n        skipTests: true,\n        prefix,\n        style\n      }),\n      isStandalone ? addIconsProvider(options.project, mainFile) : addModules(options.project)\n    ]);\n  };\n}\n\nfunction addModules(project: string): Rule {\n  return chain([\n    addModule('AppRoutingModule', './app-routing-module', project),\n    addModule('IconsProviderModule', './icons-provider.module', project),\n    addModule('NzLayoutModule', 'ng-zorro-antd/layout', project),\n    addModule('NzMenuModule', 'ng-zorro-antd/menu', project)\n  ]);\n}\n\nfunction addIconsProvider(project: string, mainFile: string): Rule {\n  return chain([\n    importIconDefinitions(mainFile),\n    addRootProvider(project, ({ code, external }) => {\n      return code`${external('provideNzIcons', 'ng-zorro-antd/icon')}(icons)`;\n    })\n  ]);\n}\n\nfunction importIconDefinitions(mainFile: string): Rule {\n  return async (host: Tree) => {\n    const bootstrapCall = findBootstrapApplicationCall(host, mainFile);\n    const appConfig = findAppConfig(bootstrapCall, host, mainFile);\n    const appConfigFile = appConfig.filePath;\n    const appConfigSource = parseSourceFile(host, appConfig.filePath);\n\n    applyChangesToFile(host, appConfigFile, [\n      insertImport(appConfigSource, appConfigFile, 'icons', './icons-provider')\n    ]);\n  };\n}"
  },
  {
    "path": "schematics/ng-generate/side-menu/schema.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/schema\",\n  \"$id\": \"sidebar-nav\",\n  \"title\": \"Sidebar Navigation Layout\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"project\": {\n      \"type\": \"string\",\n      \"description\": \"The name of the project.\",\n      \"$default\": {\n        \"$source\": \"projectName\"\n      }\n    },\n    \"style\": {\n      \"description\": \"The file extension or preprocessor to use for style files.\",\n      \"type\": \"string\",\n      \"default\": \"css\",\n      \"enum\": [\n        \"css\",\n        \"scss\",\n        \"sass\",\n        \"less\"\n      ]\n    },\n    \"prefix\": {\n      \"type\": \"string\",\n      \"format\": \"html-selector\",\n      \"description\": \"A prefix to apply to generated selectors.\",\n      \"default\": \"app\",\n      \"alias\": \"p\"\n    }\n  }\n}\n"
  },
  {
    "path": "schematics/ng-generate/side-menu/schema.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Schema as ApplicationSchema, Style } from '@schematics/angular/application/schema';\n\nexport interface Schema extends ApplicationSchema {\n  project: string;\n  style: Style;\n  prefix: string;\n}\n"
  },
  {
    "path": "schematics/ng-generate/side-menu/standalone/src/app/app.__style__.template",
    "content": ":host {\n  display: flex;\n  text-rendering: optimizeLegibility;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\n.app-layout {\n  height: 100vh;\n}\n\n.menu-sidebar {\n  position: relative;\n  z-index: 10;\n  min-height: 100vh;\n  box-shadow: 2px 0 6px rgba(0,21,41,.35);\n}\n\n.header-trigger {\n  height: 64px;\n  padding: 20px 24px;\n  font-size: 20px;\n  cursor: pointer;\n  transition: all .3s,padding 0s;\n}\n\n.trigger:hover {\n  color: #1890ff;\n}\n\n.sidebar-logo {\n  position: relative;\n  height: 64px;\n  padding-left: 24px;\n  overflow: hidden;\n  line-height: 64px;\n  background: #001529;\n  transition: all .3s;\n}\n\n.sidebar-logo img {\n  display: inline-block;\n  height: 32px;\n  width: 32px;\n  vertical-align: middle;\n}\n\n.sidebar-logo h1 {\n  display: inline-block;\n  margin: 0 0 0 20px;\n  color: #fff;\n  font-weight: 600;\n  font-size: 14px;\n  font-family: Avenir,Helvetica Neue,Arial,Helvetica,sans-serif;\n  vertical-align: middle;\n}\n\nnz-header {\n  padding: 0;\n  width: 100%;\n  z-index: 2;\n}\n\n.app-header {\n  position: relative;\n  height: 64px;\n  padding: 0;\n  background: #fff;\n  box-shadow: 0 1px 4px rgba(0,21,41,.08);\n}\n\nnz-content {\n  margin: 24px;\n}\n\n.inner-content {\n  padding: 24px;\n  background: #fff;\n  height: 100%;\n}\n"
  },
  {
    "path": "schematics/ng-generate/side-menu/standalone/src/app/app.html.template",
    "content": "<nz-layout class=\"app-layout\">\n  <nz-sider class=\"menu-sidebar\"\n    nzCollapsible\n    nzWidth=\"256px\"\n    nzBreakpoint=\"md\"\n    [(nzCollapsed)]=\"isCollapsed\"\n    [nzTrigger]=\"null\"\n  >\n    <div class=\"sidebar-logo\">\n      <a href=\"https://ng.ant.design/\" target=\"_blank\">\n        <img src=\"https://ng.ant.design/assets/img/logo.svg\" alt=\"logo\">\n        <h1>Ant Design of Angular</h1>\n      </a>\n    </div>\n    <ul nz-menu nzTheme=\"dark\" nzMode=\"inline\" [nzInlineCollapsed]=\"isCollapsed\">\n      <li nz-submenu nzOpen nzTitle=\"Dashboard\" nzIcon=\"dashboard\">\n        <ul>\n          <li nz-menu-item nzMatchRouter>\n            <a routerLink=\"/welcome\">Welcome</a>\n          </li>\n          <li nz-menu-item nzMatchRouter>\n            <a>Monitor</a>\n          </li>\n          <li nz-menu-item nzMatchRouter>\n            <a>Workplace</a>\n          </li>\n        </ul>\n      </li>\n      <li nz-submenu nzOpen nzTitle=\"Form\" nzIcon=\"form\">\n        <ul>\n          <li nz-menu-item nzMatchRouter>\n            <a>Basic Form</a>\n          </li>\n        </ul>\n      </li>\n    </ul>\n  </nz-sider>\n  <nz-layout>\n    <nz-header>\n      <div class=\"app-header\">\n        <span class=\"header-trigger\" (click)=\"isCollapsed = !isCollapsed\">\n          <nz-icon class=\"trigger\" [nzType]=\"isCollapsed ? 'menu-unfold' : 'menu-fold'\" />\n        </span>\n      </div>\n    </nz-header>\n    <nz-content>\n      <div class=\"inner-content\">\n        <router-outlet></router-outlet>\n      </div>\n    </nz-content>\n  </nz-layout>\n</nz-layout>\n"
  },
  {
    "path": "schematics/ng-generate/side-menu/standalone/src/app/app.routes.ts.template",
    "content": "import { Routes } from '@angular/router';\n\nexport const routes: Routes = [\n  { path: '', pathMatch: 'full', redirectTo: '/welcome' },\n  { path: 'welcome', loadChildren: () => import('./pages/welcome/welcome.routes').then(m => m.WELCOME_ROUTES) }\n];\n"
  },
  {
    "path": "schematics/ng-generate/side-menu/standalone/src/app/app.ts.template",
    "content": "import { Component } from '@angular/core';\nimport { RouterLink, RouterOutlet } from '@angular/router';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzLayoutModule } from 'ng-zorro-antd/layout';\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\n\n@Component({\n  selector: '<%= prefix %>-root',\n  imports: [RouterLink, RouterOutlet, NzIconModule, NzLayoutModule, NzMenuModule],\n  templateUrl: './app.html',\n  styleUrl: './app.<%= style %>'\n})\nexport class App {\n  isCollapsed = false;\n}\n"
  },
  {
    "path": "schematics/ng-generate/side-menu/standalone/src/app/icons-provider.ts.template",
    "content": "import {\n  MenuFoldOutline,\n  MenuUnfoldOutline,\n  FormOutline,\n  DashboardOutline\n} from '@ant-design/icons-angular/icons';\n\nexport const icons = [MenuFoldOutline, MenuUnfoldOutline, DashboardOutline, FormOutline];\n"
  },
  {
    "path": "schematics/ng-generate/side-menu/standalone/src/app/pages/welcome/welcome.routes.ts.template",
    "content": "import { Routes } from '@angular/router';\nimport <% if(!exportDefault) { %>{ <% }%>Welcome<%= classify(type) %> <% if(!exportDefault) {%>} <% }%>from './welcome<%= type ? '.' + dasherize(type): '' %>';\n\nexport const WELCOME_ROUTES: Routes = [\n  { path: '', component: Welcome<%= type ? classify(type): '' %> },\n];\n"
  },
  {
    "path": "schematics/ng-generate/side-menu/standalone.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Tree } from '@angular-devkit/schematics';\nimport { SchematicTestRunner } from '@angular-devkit/schematics/testing';\nimport { Style } from '@schematics/angular/ng-new/schema';\n\nimport { Schema as NzOptions } from '../../ng-add/schema';\nimport { createTestApp } from '../../testing/test-app';\nimport { getFileContent } from '../../utils/get-file-content';\n\ndescribe('[schematic][standalone] side-menu', () => {\n  const defaultOptions: NzOptions = {\n    project: 'ng-zorro'\n  };\n\n  let runner: SchematicTestRunner;\n  let appTree: Tree;\n\n  beforeEach(async () => {\n    runner = new SchematicTestRunner('schematics', require.resolve('../../collection.json'));\n    appTree = await createTestApp(runner);\n  });\n\n  it('should create side-menu files', async () => {\n    const options = { ...defaultOptions };\n    const tree = await runner.runSchematic('sidemenu', options, appTree);\n    const files = tree.files;\n\n    expect(files).toEqual(\n      jasmine.arrayContaining([\n        '/projects/ng-zorro/src/app/app.html',\n        '/projects/ng-zorro/src/app/app.css',\n        '/projects/ng-zorro/src/app/app.ts',\n        '/projects/ng-zorro/src/app/app.routes.ts',\n        '/projects/ng-zorro/src/app/icons-provider.ts',\n        '/projects/ng-zorro/src/app/pages/welcome/welcome.component.ts',\n        '/projects/ng-zorro/src/app/pages/welcome/welcome.component.css',\n        '/projects/ng-zorro/src/app/pages/welcome/welcome.component.html',\n        '/projects/ng-zorro/src/app/pages/welcome/welcome.routes.ts'\n      ])\n    );\n  });\n\n  it('should infer the standalone option from the project structure', async () => {\n    const options = { ...defaultOptions };\n    const tree = await runner.runSchematic('sidemenu', options, appTree);\n    const appContent = getFileContent(tree, '/projects/ng-zorro/src/app/app.ts');\n\n    expect(tree.exists('/projects/material/src/app/app-module.ts')).toBe(false);\n\n    // since v19, the standalone option is removed\n    expect(appContent).not.toContain('standalone: true');\n    expect(appContent).toContain('imports: [');\n  });\n\n  describe('style option', () => {\n    it('should set the style preprocessor correctly', async () => {\n      const options = { ...defaultOptions, style: Style.Less };\n      const tree = await runner.runSchematic('sidemenu', options, appTree);\n      const files = tree.files;\n      const appContent = getFileContent(tree, '/projects/ng-zorro/src/app/app.ts');\n      const welcomeContent = getFileContent(tree, '/projects/ng-zorro/src/app/pages/welcome/welcome.component.ts');\n\n      expect(appContent).toContain('app.less');\n      expect(welcomeContent).toContain('welcome.component.less');\n\n      expect(files).toEqual(\n        jasmine.arrayContaining([\n          '/projects/ng-zorro/src/app/app.less',\n          '/projects/ng-zorro/src/app/pages/welcome/welcome.component.less'\n        ])\n      );\n    });\n\n    it('should fall back to the @schematics/angular:component option value', async () => {\n      const options = { ...defaultOptions, template: 'sidemenu' };\n      appTree = await createTestApp(runner, { style: Style.Less });\n      const tree = await runner.runSchematic('ng-add', options, appTree);\n\n      expect(tree.files).toEqual(\n        jasmine.arrayContaining([\n          '/projects/ng-zorro/src/app/app.less',\n          '/projects/ng-zorro/src/app/pages/welcome/welcome.component.less'\n        ])\n      );\n    });\n  });\n\n  it('should set the prefix correctly', async () => {\n    const options = { ...defaultOptions, prefix: 'nz' };\n    const tree = await runner.runSchematic('sidemenu', options, appTree);\n    const appContent = getFileContent(tree, '/projects/ng-zorro/src/app/app.ts');\n    const welcomeContent = getFileContent(tree, '/projects/ng-zorro/src/app/pages/welcome/welcome.component.ts');\n\n    expect(appContent).toContain(`selector: 'nz-root'`);\n    expect(welcomeContent).toContain(`selector: 'nz-welcome'`);\n  });\n});\n"
  },
  {
    "path": "schematics/ng-generate/topnav/files/src/app/app-routing-module.ts.template",
    "content": "import { NgModule } from '@angular/core';\nimport { Routes, RouterModule } from '@angular/router';\n\nconst routes: Routes = [\n  { path: '', pathMatch: 'full', redirectTo: '/welcome' },\n  { path: 'welcome', loadChildren: () => import('./pages/welcome/welcome-module').then(m => m.WelcomeModule) }\n];\n\n@NgModule({\n  imports: [RouterModule.forRoot(routes)],\n  exports: [RouterModule]\n})\nexport class AppRoutingModule {}\n"
  },
  {
    "path": "schematics/ng-generate/topnav/files/src/app/app.__style__.template",
    "content": ":host {\n  display: flex;\n}\n\n.app-layout {\n  height: 100vh;\n}\n\n.top-nav {\n  line-height: 64px;\n}\n\n.logo {\n  float: left;\n  height: 64px;\n  padding-right: 24px;\n  line-height: 64px;\n  background: #001529;\n}\n\n.logo img {\n  display: inline-block;\n  height: 32px;\n  width: 32px;\n  vertical-align: middle;\n}\n\n.logo h1 {\n  display: inline-block;\n  margin: 0 0 0 15px;\n  color: #fff;\n  font-weight: 600;\n  font-size: 20px;\n  font-family: Avenir,Helvetica Neue,Arial,Helvetica,sans-serif;\n  vertical-align: middle;\n}\n\nnz-content {\n  padding: 24px 50px;\n}\n\n.inner-content {\n  padding: 24px;\n  background: #fff;\n  height: 100%;\n}\n"
  },
  {
    "path": "schematics/ng-generate/topnav/files/src/app/app.html.template",
    "content": "<nz-layout class=\"app-layout\">\n  <nz-header>\n    <div class=\"logo\">\n      <a>\n        <img src=\"https://ng.ant.design/assets/img/logo.svg\" alt=\"logo\">\n        <h1>NG-ZORRO</h1>\n      </a>\n    </div>\n    <ul nz-menu class=\"top-nav\" nzTheme=\"dark\" nzMode=\"horizontal\">\n      <li nz-menu-item routerLinkActive=\"ant-menu-item-selected\" routerLink=\"/welcome\">Home</li>\n      <li nz-menu-item>Account</li>\n      <li nz-menu-item>Profile</li>\n    </ul>\n  </nz-header>\n  <nz-content>\n    <div class=\"inner-content\">\n      <router-outlet></router-outlet>\n    </div>\n  </nz-content>\n</nz-layout>\n"
  },
  {
    "path": "schematics/ng-generate/topnav/files/src/app/app.ts.template",
    "content": "import { Component } from '@angular/core';\n\n@Component({\n  selector: '<%= prefix %>-root',\n  standalone: false,\n  templateUrl: './app.html',\n  styleUrl: './app.<%= style %>'\n})\nexport class App {}\n"
  },
  {
    "path": "schematics/ng-generate/topnav/files/src/app/pages/welcome/welcome-module.ts.template",
    "content": "import { NgModule } from '@angular/core';\n\nimport { WelcomeRoutingModule } from './welcome-routing-module';\n\nimport <% if(!exportDefault) { %>{ <% }%>Welcome<%= classify(type) %> <% if(!exportDefault) {%>} <% }%>from './welcome<%= type ? '.' + dasherize(type): '' %>';\n\n@NgModule({\n  imports: [WelcomeRoutingModule],\n  declarations: [Welcome<%= type ? classify(type): '' %>],\n  exports: [Welcome<%= type ? classify(type): '' %>]\n})\nexport class WelcomeModule {}\n"
  },
  {
    "path": "schematics/ng-generate/topnav/files/src/app/pages/welcome/welcome-routing-module.ts.template",
    "content": "import { NgModule } from '@angular/core';\nimport { Routes, RouterModule } from '@angular/router';\n\nimport <% if(!exportDefault) { %>{ <% }%>Welcome<%= classify(type) %> <% if(!exportDefault) {%>} <% }%>from './welcome<%= type ? '.' + dasherize(type): '' %>';\n\nconst routes: Routes = [\n  { path: '', component: Welcome<%= type ? classify(type): '' %> },\n];\n\n@NgModule({\n  imports: [RouterModule.forChild(routes)],\n  exports: [RouterModule]\n})\nexport class WelcomeRoutingModule {}\n"
  },
  {
    "path": "schematics/ng-generate/topnav/index.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Tree } from '@angular-devkit/schematics';\nimport { SchematicTestRunner } from '@angular-devkit/schematics/testing';\nimport { Style } from '@schematics/angular/ng-new/schema';\n\n\nimport { Schema as NzOptions } from '../../ng-add/schema';\nimport { createTestApp } from '../../testing/test-app';\nimport { getFileContent } from '../../utils/get-file-content';\n\ndescribe('[schematic] top-nav', () => {\n  const defaultOptions: NzOptions = {\n    project: 'ng-zorro'\n  };\n  let runner: SchematicTestRunner;\n  let appTree: Tree;\n\n  beforeEach(async () => {\n    runner = new SchematicTestRunner('schematics', require.resolve('../../collection.json'));\n    appTree = await createTestApp(runner, { name: 'ng-zorro', standalone: false });\n  });\n\n  it('should create top-nav files', async () => {\n    const options = {...defaultOptions};\n\n    const tree = await runner.runSchematic('topnav', options, appTree);\n    const files = tree.files;\n    expect(files).toEqual(\n      jasmine.arrayContaining([\n        '/projects/ng-zorro/src/app/app.html',\n        '/projects/ng-zorro/src/app/app.css',\n        '/projects/ng-zorro/src/app/app.ts',\n        '/projects/ng-zorro/src/app/app-routing-module.ts',\n        '/projects/ng-zorro/src/app/pages/welcome/welcome-module.ts',\n        '/projects/ng-zorro/src/app/pages/welcome/welcome-routing-module.ts',\n        '/projects/ng-zorro/src/app/pages/welcome/welcome.component.ts',\n        '/projects/ng-zorro/src/app/pages/welcome/welcome.component.css',\n        '/projects/ng-zorro/src/app/pages/welcome/welcome.component.html'\n      ])\n    );\n  });\n\n  it('should set the style preprocessor correctly', async () => {\n    const options = {...defaultOptions, style: Style.Less};\n    const tree = await runner.runSchematic('topnav', options, appTree);\n    const files = tree.files;\n    const appContent = getFileContent(tree, '/projects/ng-zorro/src/app/app.ts');\n    const welcomeContent = getFileContent(tree, '/projects/ng-zorro/src/app/pages/welcome/welcome.component.ts');\n\n    expect(appContent).toContain('app.less');\n    expect(welcomeContent).toContain('welcome.component.less');\n\n    expect(files).toEqual(\n      jasmine.arrayContaining([\n        '/projects/ng-zorro/src/app/app.less',\n        '/projects/ng-zorro/src/app/pages/welcome/welcome.component.less'\n      ])\n    );\n  });\n\n  it('should set the prefix correctly', async () => {\n    const options = {...defaultOptions, prefix: 'nz'};\n    const tree = await runner.runSchematic('topnav', options, appTree);\n    const appContent = getFileContent(tree, '/projects/ng-zorro/src/app/app.ts');\n    const welcomeContent = getFileContent(tree, '/projects/ng-zorro/src/app/pages/welcome/welcome.component.ts');\n\n    expect(appContent).toContain(`selector: 'nz-root'`);\n    expect(welcomeContent).toContain(`selector: 'nz-welcome'`);\n  });\n\n  it('should set standalone to be false', async () => {\n    const tree = await runner.runSchematic('topnav', defaultOptions, appTree);\n    const appContent = getFileContent(tree, '/projects/ng-zorro/src/app/app.ts');\n    const welcomeContent = getFileContent(tree, '/projects/ng-zorro/src/app/pages/welcome/welcome.component.ts');\n\n    expect(appContent).toContain('standalone: false');\n    expect(welcomeContent).toContain('standalone: false');\n  });\n});\n"
  },
  {
    "path": "schematics/ng-generate/topnav/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { getProjectFromWorkspace, getProjectMainFile, isStandaloneApp } from '@angular/cdk/schematics';\n\nimport {\n  apply,\n  applyTemplates,\n  chain,\n  FileEntry,\n  forEach,\n  MergeStrategy,\n  mergeWith,\n  move,\n  noop,\n  Rule,\n  schematic,\n  strings,\n  Tree,\n  url\n} from '@angular-devkit/schematics';\nimport { readWorkspace } from '@schematics/angular/utility';\n\nimport { Schema } from './schema';\nimport { getAppOptions } from '../../utils/config';\nimport { addModule } from '../../utils/root-module';\n\nexport default function(options: Schema): Rule {\n  return async (host: Tree) => {\n    const workspace = await readWorkspace(host);\n    const project = getProjectFromWorkspace(workspace, options.project);\n    const mainFile = getProjectMainFile(project);\n    const { componentOptions, sourceDir } = await getAppOptions(options.project, project.root);\n    const prefix = options.prefix || project.prefix;\n    const style = options.style || componentOptions.style;\n    const exportDefault = componentOptions.exportDefault ?? false;\n\n    const isStandalone = isStandaloneApp(host, mainFile);\n    const templateSourcePath = isStandalone ? './standalone' : './files';\n\n    return chain([\n      mergeWith(\n        apply(\n          url(`${templateSourcePath}/src`), [\n            applyTemplates({\n              ...strings,\n              ...componentOptions,\n              exportDefault,\n              prefix,\n              style\n            }),\n            move(project.sourceRoot),\n            forEach((fileEntry: FileEntry) => {\n              if (host.exists(fileEntry.path)) {\n                host.overwrite(fileEntry.path, fileEntry.content);\n              }\n              return fileEntry;\n            })\n          ]\n        ),\n        MergeStrategy.Overwrite\n      ),\n      schematic('component', {\n        name: 'welcome',\n        project: options.project,\n        standalone: isStandalone,\n        ...componentOptions,\n        path: `${sourceDir}/pages`,\n        skipImport: true,\n        skipTests: true,\n        prefix,\n        style\n      }),\n      isStandalone ? noop() : addModules(options.project)\n    ]);\n  };\n}\n\n\nfunction addModules(project: string): Rule {\n  return chain([\n    addModule('AppRoutingModule', './app-routing-module', project),\n    addModule('NzLayoutModule', 'ng-zorro-antd/layout', project),\n    addModule('NzMenuModule', 'ng-zorro-antd/menu', project)\n  ]);\n}\n"
  },
  {
    "path": "schematics/ng-generate/topnav/schema.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/schema\",\n  \"$id\": \"top-nav\",\n  \"title\": \"Top Navigation Layout\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"project\": {\n      \"type\": \"string\",\n      \"description\": \"The name of the project.\",\n      \"$default\": {\n        \"$source\": \"projectName\"\n      }\n    },\n    \"style\": {\n      \"description\": \"The file extension or preprocessor to use for style files.\",\n      \"type\": \"string\",\n      \"default\": \"css\",\n      \"enum\": [\n        \"css\",\n        \"scss\",\n        \"sass\",\n        \"less\",\n        \"styl\"\n      ]\n    },\n    \"prefix\": {\n      \"type\": \"string\",\n      \"format\": \"html-selector\",\n      \"description\": \"A prefix to apply to generated selectors.\",\n      \"default\": \"app\",\n      \"alias\": \"p\"\n    }\n  }\n}\n"
  },
  {
    "path": "schematics/ng-generate/topnav/schema.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Schema as ApplicationSchema, Style } from '@schematics/angular/application/schema';\n\nexport interface Schema extends ApplicationSchema {\n  project: string;\n  style: Style;\n  prefix: string;\n}\n"
  },
  {
    "path": "schematics/ng-generate/topnav/standalone/src/app/app.__style__.template",
    "content": ":host {\n  display: flex;\n}\n\n.app-layout {\n  height: 100vh;\n}\n\n.top-nav {\n  line-height: 64px;\n}\n\n.logo {\n  float: left;\n  height: 64px;\n  padding-right: 24px;\n  line-height: 64px;\n  background: #001529;\n}\n\n.logo img {\n  display: inline-block;\n  height: 32px;\n  width: 32px;\n  vertical-align: middle;\n}\n\n.logo h1 {\n  display: inline-block;\n  margin: 0 0 0 15px;\n  color: #fff;\n  font-weight: 600;\n  font-size: 20px;\n  font-family: Avenir,Helvetica Neue,Arial,Helvetica,sans-serif;\n  vertical-align: middle;\n}\n\nnz-content {\n  padding: 24px 50px;\n}\n\n.inner-content {\n  padding: 24px;\n  background: #fff;\n  height: 100%;\n}\n"
  },
  {
    "path": "schematics/ng-generate/topnav/standalone/src/app/app.html.template",
    "content": "<nz-layout class=\"app-layout\">\n  <nz-header>\n    <div class=\"logo\">\n      <a>\n        <img src=\"https://ng.ant.design/assets/img/logo.svg\" alt=\"logo\">\n        <h1>NG-ZORRO</h1>\n      </a>\n    </div>\n    <ul nz-menu class=\"top-nav\" nzTheme=\"dark\" nzMode=\"horizontal\">\n      <li nz-menu-item routerLinkActive=\"ant-menu-item-selected\" routerLink=\"/welcome\">Home</li>\n      <li nz-menu-item>Account</li>\n      <li nz-menu-item>Profile</li>\n    </ul>\n  </nz-header>\n  <nz-content>\n    <div class=\"inner-content\">\n      <router-outlet></router-outlet>\n    </div>\n  </nz-content>\n</nz-layout>\n"
  },
  {
    "path": "schematics/ng-generate/topnav/standalone/src/app/app.routes.ts.template",
    "content": "import { Routes } from '@angular/router';\n\nexport const routes: Routes = [\n  { path: '', pathMatch: 'full', redirectTo: '/welcome' },\n  { path: 'welcome', loadChildren: () => import('./pages/welcome/welcome.routes').then(m => m.WELCOME_ROUTES) }\n];\n"
  },
  {
    "path": "schematics/ng-generate/topnav/standalone/src/app/app.ts.template",
    "content": "import { Component } from '@angular/core';\nimport { RouterOutlet } from '@angular/router';\nimport { NzLayoutModule } from 'ng-zorro-antd/layout';\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\n\n@Component({\n  selector: '<%= prefix %>-root',\n  imports: [RouterOutlet, NzLayoutModule, NzMenuModule],\n  templateUrl: './app.html',\n  styleUrl: './app.<%= style %>'\n})\nexport class App {}\n"
  },
  {
    "path": "schematics/ng-generate/topnav/standalone/src/app/pages/welcome/welcome.routes.ts.template",
    "content": "import { Routes } from '@angular/router';\nimport <% if(!exportDefault) { %>{ <% }%>Welcome<%= classify(type) %> <% if(!exportDefault) {%>} <% }%>from './welcome<%= type ? '.' + dasherize(type): '' %>';\n\nexport const WELCOME_ROUTES: Routes = [\n  { path: '', component: Welcome<%= type ? classify(type): '' %> },\n];\n"
  },
  {
    "path": "schematics/ng-generate/topnav/standalone.spec.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Tree } from '@angular-devkit/schematics';\nimport { SchematicTestRunner } from '@angular-devkit/schematics/testing';\nimport { Style } from '@schematics/angular/ng-new/schema';\n\n\nimport { Schema as NzOptions } from '../../ng-add/schema';\nimport { createTestApp } from '../../testing/test-app';\nimport { getFileContent } from '../../utils/get-file-content';\n\ndescribe('[schematic][standalone] top-nav', () => {\n  const defaultOptions: NzOptions = {\n    project: 'ng-zorro'\n  };\n  let runner: SchematicTestRunner;\n  let appTree: Tree;\n\n  beforeEach(async () => {\n    runner = new SchematicTestRunner('schematics', require.resolve('../../collection.json'));\n    appTree = await createTestApp(runner, { name: 'ng-zorro' });\n  });\n\n  it('should create top-nav files', async () => {\n    const options = { ...defaultOptions };\n\n    const tree = await runner.runSchematic('topnav', options, appTree);\n    const files = tree.files;\n    expect(files).toEqual(\n      jasmine.arrayContaining([\n        '/projects/ng-zorro/src/app/app.html',\n        '/projects/ng-zorro/src/app/app.css',\n        '/projects/ng-zorro/src/app/app.ts',\n        '/projects/ng-zorro/src/app/app.routes.ts',\n        '/projects/ng-zorro/src/app/pages/welcome/welcome.component.ts',\n        '/projects/ng-zorro/src/app/pages/welcome/welcome.component.css',\n        '/projects/ng-zorro/src/app/pages/welcome/welcome.component.html',\n        '/projects/ng-zorro/src/app/pages/welcome/welcome.routes.ts'\n      ])\n    );\n  });\n\n  it('should fall back to the @schematics/angular:component option value', async () => {\n    const options = { ...defaultOptions };\n    const tree = await runner.runSchematic('topnav', options, appTree);\n    const appContent = getFileContent(tree, '/projects/ng-zorro/src/app/app.ts');\n\n    expect(tree.exists('/projects/ng-zorro/src/app/app-module.ts')).toBe(false);\n\n    // since v19, the standalone option is removed\n    expect(appContent).not.toContain('standalone: true');\n    expect(appContent).toContain('imports: [');\n  });\n\n  it('should set the style preprocessor correctly', async () => {\n    const options = { ...defaultOptions, style: Style.Less };\n\n    const tree = await runner.runSchematic('topnav', options, appTree);\n    const files = tree.files;\n    const appContent = getFileContent(tree, '/projects/ng-zorro/src/app/app.ts');\n    const welcomeContent = getFileContent(tree, '/projects/ng-zorro/src/app/pages/welcome/welcome.component.ts');\n\n    expect(appContent).toContain('app.less');\n    expect(welcomeContent).toContain('welcome.component.less');\n\n    expect(files).toEqual(\n      jasmine.arrayContaining([\n        '/projects/ng-zorro/src/app/app.less',\n        '/projects/ng-zorro/src/app/pages/welcome/welcome.component.less'\n      ])\n    );\n  });\n\n  it('should set the prefix correctly', async () => {\n    const options = { ...defaultOptions, prefix: 'nz' };\n    const tree = await runner.runSchematic('topnav', options, appTree);\n    const appContent = getFileContent(tree, '/projects/ng-zorro/src/app/app.ts');\n    const welcomeContent = getFileContent(tree, '/projects/ng-zorro/src/app/pages/welcome/welcome.component.ts');\n\n    expect(appContent).toContain(`selector: 'nz-root'`);\n    expect(welcomeContent).toContain(`selector: 'nz-welcome'`);\n  });\n});\n"
  },
  {
    "path": "schematics/ng-update/data/attribute-selectors.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { AttributeSelectorUpgradeData, TargetVersion, VersionChanges } from '@angular/cdk/schematics';\n\nexport const attributeSelectors: VersionChanges<AttributeSelectorUpgradeData> = {\n  [TargetVersion.V21]: []\n};\n"
  },
  {
    "path": "schematics/ng-update/data/class-names.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ClassNameUpgradeData, TargetVersion, VersionChanges } from '@angular/cdk/schematics';\n\nexport const classNames: VersionChanges<ClassNameUpgradeData> = {\n  [TargetVersion.V21]: [{\n    pr: 'https://github.com/NG-ZORRO/ng-zorro-antd/pull/9238',\n    changes: [{\n      replace: 'NzTabsetComponent',\n      replaceWith: 'NzTabsComponent'\n    }]\n  }, {\n    pr: 'https://github.com/NG-ZORRO/ng-zorro-antd/pull/9285',\n    changes: [{\n      replace: 'NzToolTipComponent',\n      replaceWith: 'NzTooltipComponent'\n    }, {\n      replace: 'NzToolTipModule',\n      replaceWith: 'NzTooltipModule'\n    }]\n  }, {\n    pr: 'https://github.com/NG-ZORRO/ng-zorro-antd/pull/9330',\n    changes: [{\n      replace: 'NzStatisticNumberComponent',\n      replaceWith: 'NzStatisticContentValueComponent'\n    }]\n  }, {\n    pr: 'https://github.com/NG-ZORRO/ng-zorro-antd/pull/9527',\n    changes: [{\n      replace: 'NzDropDownModule',\n      replaceWith: 'NzDropdownModule'\n    }, {\n      replace: 'NzDropDownADirective',\n      replaceWith: 'NzDropdownADirective'\n    }]\n  }, {\n    pr: 'https://github.com/NG-ZORRO/ng-zorro-antd/pull/9528',\n    changes: [{\n      replace: 'NzWaterMarkModule',\n      replaceWith: 'NzWatermarkModule'\n    }, {\n      replace: 'NzWaterMarkComponent',\n      replaceWith: 'NzWatermarkComponent'\n    }]\n  }]\n};\n"
  },
  {
    "path": "schematics/ng-update/data/constructor-checks.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ConstructorChecksUpgradeData, TargetVersion, VersionChanges } from '@angular/cdk/schematics';\n\n/**\n * List of class names for which the constructor signature has been changed. The new constructor\n * signature types don't need to be stored here because the signature will be determined\n * automatically through type checking.\n */\nexport const constructorChecks: VersionChanges<ConstructorChecksUpgradeData> = {\n  [TargetVersion.V21]: []\n};\n"
  },
  {
    "path": "schematics/ng-update/data/css-selectors.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { CssSelectorUpgradeData, TargetVersion, VersionChanges } from '@angular/cdk/schematics';\n\nexport const cssSelectors: VersionChanges<CssSelectorUpgradeData> = {\n  [TargetVersion.V21]: [{\n    pr: 'https://github.com/NG-ZORRO/ng-zorro-antd/pull/9238',\n    changes: [{\n      replace: 'nz-tabset',\n      replaceWith: 'nz-tabs'\n    }]\n  }, {\n    pr: 'https://github.com/NG-ZORRO/ng-zorro-antd/pull/9330',\n    changes: [{\n      replace: 'nz-statistic-number',\n      replaceWith: 'nz-statistic-content-value'\n    }]\n  }]\n};\n"
  },
  {
    "path": "schematics/ng-update/data/css-tokens.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { CssTokenUpgradeData, TargetVersion, VersionChanges } from '@angular/cdk/schematics';\n\nexport const cssTokens: VersionChanges<CssTokenUpgradeData> = {\n  [TargetVersion.V21]: []\n};\n"
  },
  {
    "path": "schematics/ng-update/data/element-selectors.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ElementSelectorUpgradeData, TargetVersion, VersionChanges } from '@angular/cdk/schematics';\n\nexport const elementSelectors: VersionChanges<ElementSelectorUpgradeData> = {\n  [TargetVersion.V21]: [{\n    pr: 'https://github.com/NG-ZORRO/ng-zorro-antd/pull/9238',\n    changes: [{\n      replace: 'nz-tabset',\n      replaceWith: 'nz-tabs'\n    }]\n  }, {\n    pr: 'https://github.com/NG-ZORRO/ng-zorro-antd/pull/9330',\n    changes: [{\n      replace: 'nz-statistic-number',\n      replaceWith: 'nz-statistic-content-value'\n    }]\n  }]\n};\n"
  },
  {
    "path": "schematics/ng-update/data/import-specifiers.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { TargetVersion, VersionChanges } from '@angular/cdk/schematics';\n\nexport interface ImportSpecifierUpgradeData {\n  replace: string;\n  replaceWith: string;\n}\n\nconst resolve = (module: string): string => `ng-zorro-antd/${module}`;\n\nexport const importSpecifiers: VersionChanges<ImportSpecifierUpgradeData> = {\n  [TargetVersion.V21]: [{\n    pr: 'https://github.com/NG-ZORRO/ng-zorro-antd/pull/9528',\n    changes: [{\n      replace: resolve('water-mark'),\n      replaceWith: resolve('watermark'),\n    }]\n  }, {\n    pr: 'https://github.com/NG-ZORRO/ng-zorro-antd/pull/9555',\n    changes: [{\n      replace: resolve('core/no-animation'),\n      replaceWith: resolve('core/animation'),\n    }]\n  }]\n};\n"
  },
  {
    "path": "schematics/ng-update/data/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport * from './attribute-selectors';\nexport * from './class-names';\nexport * from './constructor-checks';\nexport * from './css-selectors';\nexport * from './css-tokens';\nexport * from './element-selectors';\nexport * from './input-names';\nexport * from './method-call-checks';\nexport * from './output-names';\nexport * from './property-names';\nexport * from './symbol-removal';\nexport * from './import-specifiers';\n"
  },
  {
    "path": "schematics/ng-update/data/input-names.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { InputNameUpgradeData, TargetVersion, VersionChanges } from '@angular/cdk/schematics';\n\nexport const inputNames: VersionChanges<InputNameUpgradeData> = {\n  [TargetVersion.V21]: []\n};\n"
  },
  {
    "path": "schematics/ng-update/data/method-call-checks.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { MethodCallUpgradeData, TargetVersion, VersionChanges } from '@angular/cdk/schematics';\n\nexport const methodCallChecks: VersionChanges<MethodCallUpgradeData> = {\n  [TargetVersion.V21]: []\n};\n"
  },
  {
    "path": "schematics/ng-update/data/output-names.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { OutputNameUpgradeData, TargetVersion, VersionChanges } from '@angular/cdk/schematics';\n\nexport const outputNames: VersionChanges<OutputNameUpgradeData> = {\n  [TargetVersion.V21]: [{\n    pr: 'https://github.com/NG-ZORRO/ng-zorro-antd/pull/8934',\n    changes: [{\n      replace: 'nzCheckBoxChange',\n      replaceWith: 'nzCheckboxChange',\n      limitedTo: {\n        elements: ['nz-tree', 'nz-tree-node']\n      }\n    }, {\n      replace: 'nzTreeCheckBoxChange',\n      replaceWith: 'nzTreeCheckboxChange',\n      limitedTo: {\n        elements: ['nz-tree-select']\n      }\n    }]\n  }]\n};\n"
  },
  {
    "path": "schematics/ng-update/data/property-names.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { PropertyNameUpgradeData, TargetVersion, VersionChanges } from '@angular/cdk/schematics';\n\nexport const propertyNames: VersionChanges<PropertyNameUpgradeData> = {\n  [TargetVersion.V21]: []\n};\n"
  },
  {
    "path": "schematics/ng-update/data/symbol-removal.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { SymbolRemovalUpgradeData, TargetVersion, VersionChanges } from '@angular/cdk/schematics';\n\nexport const symbolRemoval: VersionChanges<SymbolRemovalUpgradeData> = {\n  [TargetVersion.V21]: []\n};\n"
  },
  {
    "path": "schematics/ng-update/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { createMigrationSchematicRule, TargetVersion } from '@angular/cdk/schematics';\n\nimport { Rule, SchematicContext } from '@angular-devkit/schematics';\n\nimport { nzMigrations } from './migrations';\nimport { nzUpgradeData } from './upgrade-data';\nimport { nzUpgradeRules } from './upgrade-rules';\n\nexport function updateToV21(): Rule {\n  return createMigrationSchematicRule(\n    TargetVersion.V21,\n    [...nzUpgradeRules, ...nzMigrations],\n    nzUpgradeData,\n    postUpdate\n  );\n}\n\n/** Post-update schematic to be called when update is finished. */\nexport function postUpdate(context: SchematicContext, targetVersion: TargetVersion, hasFailures: boolean): void {\n\n  context.logger.info('');\n  context.logger.info(`  ✓  Updated NG-ZORRO to ${targetVersion}`);\n  context.logger.info('');\n\n  if (hasFailures) {\n    context.logger.warn(\n      '  ⚠  Some issues were detected but could not be fixed automatically. Please check the ' +\n      'output above and fix these issues manually.');\n  }\n\n}\n"
  },
  {
    "path": "schematics/ng-update/migrations/class-names.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ClassNameUpgradeData,\n  isExportSpecifierNode,\n  isImportSpecifierNode,\n  isNamespaceImportNode,\n  Migration\n} from '@angular/cdk/schematics';\n\nimport * as ts from 'typescript';\n\nimport { isNgZorroExportDeclaration, isNgZorroImportDeclaration } from '../../utils/ng-update/module-specifiers';\nimport { getVersionUpgradeData, NzUpgradeData } from '../upgrade-data';\n\nexport class ClassNamesMigration extends Migration<NzUpgradeData> {\n  /** Change data that upgrades to the specified target version. */\n  data: ClassNameUpgradeData[] = getVersionUpgradeData(this, 'classNames');\n\n  /**\n   * List of identifier names that have been imported from `@ng-zorro-antd`\n   * in the current source file and therefore can be considered trusted.\n   */\n  trustedIdentifiers = new Set<string>();\n\n  /** List of namespaces that have been imported from `@ng-zorro-antd`. */\n  trustedNamespaces = new Set<string>();\n\n  // Only enable the migration rule if there is upgrade data.\n  enabled: boolean = this.data.length !== 0;\n\n  visitNode(node: ts.Node): void {\n    if (ts.isIdentifier(node)) {\n      this.visitIdentifier(node);\n    }\n  }\n\n  /** Method that is called for every identifier inside of the specified project. */\n  private visitIdentifier(identifier: ts.Identifier): void {\n    if (!this.data.some(data => data.replace === identifier.text)) {\n      return;\n    }\n\n    if (isNamespaceImportNode(identifier) && isNgZorroImportDeclaration(identifier)) {\n      this.trustedNamespaces.add(identifier.text);\n\n      return this._createFailureWithReplacement(identifier);\n    }\n\n    if (isExportSpecifierNode(identifier) && isNgZorroExportDeclaration(identifier)) {\n      return this._createFailureWithReplacement(identifier);\n    }\n\n    if (isImportSpecifierNode(identifier) && isNgZorroImportDeclaration(identifier)) {\n      this.trustedIdentifiers.add(identifier.text);\n      return this._createFailureWithReplacement(identifier);\n    }\n\n    if (ts.isPropertyAccessExpression(identifier.parent)) {\n      const expression = identifier.parent.expression;\n\n      if (ts.isIdentifier(expression) && this.trustedNamespaces.has(expression.text)) {\n        return this._createFailureWithReplacement(identifier);\n      }\n    } else if (this.trustedIdentifiers.has(identifier.text)) {\n      return this._createFailureWithReplacement(identifier);\n    }\n  }\n\n  /** Creates a failure and replacement for the specified identifier. */\n  private _createFailureWithReplacement(identifier: ts.Identifier): void {\n    const classData = this.data.find(data => data.replace === identifier.text)!;\n    const filePath = this.fileSystem.resolve(identifier.getSourceFile().fileName);\n\n    this.fileSystem.edit(filePath)\n      .remove(identifier.getStart(), identifier.getWidth())\n      .insertRight(identifier.getStart(), classData.replaceWith);\n  }\n}\n"
  },
  {
    "path": "schematics/ng-update/migrations/import-specifiers.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Migration } from '@angular/cdk/schematics';\n\nimport * as ts from 'typescript';\n\nimport { isNgZorroImportDeclaration } from '../../utils/ng-update/module-specifiers';\nimport { ImportSpecifierUpgradeData } from '../data';\nimport { getVersionUpgradeData, NzUpgradeData } from '../upgrade-data';\n\nexport class ImportSpecifiersMigration extends Migration<NzUpgradeData> {\n  /** Change data that upgrades to the specified target version. */\n  data: ImportSpecifierUpgradeData[] = getVersionUpgradeData(this, 'importSpecifiers');\n\n\n  // Only enable the migration rule if there is upgrade data.\n  enabled: boolean = this.data.length !== 0;\n\n  visitNode(node: ts.Node): void {\n    if (ts.isImportDeclaration(node)) {\n      this.visitImportDeclaration(node);\n    }\n  }\n\n  private visitImportDeclaration(node: ts.ImportDeclaration): void {\n    if (isNgZorroImportDeclaration(node)) {\n      return this._createFailureWithReplacement(node);\n    }\n  }\n\n  /** Creates a failure and replacement for the specified identifier. */\n  private _createFailureWithReplacement(identifier: ts.ImportDeclaration): void {\n    const upgradeData = this.data.find(({ replace }) => identifier.moduleSpecifier.getText().indexOf(replace) !== -1)!;\n\n    if (upgradeData) {\n      const filePath = this.fileSystem.resolve(identifier.getSourceFile().fileName);\n\n      this.fileSystem.edit(filePath)\n        .remove(identifier.moduleSpecifier.getStart() + 1, identifier.moduleSpecifier.getWidth() - 2) // quotes\n        .insertRight(identifier.moduleSpecifier.getStart() + 1, upgradeData.replaceWith);\n    }\n  }\n}\n"
  },
  {
    "path": "schematics/ng-update/migrations/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NullableDevkitMigration } from '@angular/cdk/schematics';\n\nimport { ClassNamesMigration } from './class-names';\nimport { ImportSpecifiersMigration } from './import-specifiers';\nimport { OutputNamesMigration } from './output-names';\n\nexport const nzMigrations: NullableDevkitMigration[] = [\n  ClassNamesMigration,\n  ImportSpecifiersMigration,\n  OutputNamesMigration\n];\n"
  },
  {
    "path": "schematics/ng-update/migrations/input-names.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  findAllSubstringIndices,\n  findInputsOnElementWithAttr,\n  findInputsOnElementWithTag,\n  InputNameUpgradeData,\n  Migration,\n  ResolvedResource,\n  WorkspacePath\n} from '@angular/cdk/schematics';\n\nimport { getVersionUpgradeData, NzUpgradeData } from '../upgrade-data';\n\n/**\n * Migration that walks through every template or stylesheet and replaces outdated input\n * names to the new input name. Selectors in stylesheets could also target input\n * bindings declared as static attribute. See for example:\n *\n * e.g. `<my-component color=\"primary\">` becomes `my-component[color]`\n */\nexport class InputNamesMigration extends Migration<NzUpgradeData> {\n  /** Change data that upgrades to the specified target version. */\n  data: InputNameUpgradeData[] = getVersionUpgradeData(this, 'inputNames');\n\n  // Only enable the migration rule if there is upgrade data.\n  enabled = this.data.length !== 0;\n\n  override visitStylesheet(stylesheet: ResolvedResource): void {\n    this.data.forEach(name => {\n      const currentSelector = `[${name.replace}]`;\n      const updatedSelector = `[${name.replaceWith}]`;\n\n      findAllSubstringIndices(stylesheet.content, currentSelector)\n        .map(offset => stylesheet.start + offset)\n        .forEach(start =>\n          this._replaceInputName(\n            stylesheet.filePath,\n            start,\n            currentSelector.length,\n            updatedSelector\n          )\n        );\n    });\n  }\n\n  override visitTemplate(template: ResolvedResource): void {\n    this.data.forEach(name => {\n      const limitedTo = name.limitedTo;\n      const relativeOffsets: number[] = [];\n\n      if (limitedTo.attributes) {\n        relativeOffsets.push(\n          ...findInputsOnElementWithAttr(template.content, name.replace, limitedTo.attributes)\n        );\n      }\n\n      if (limitedTo.elements) {\n        relativeOffsets.push(\n          ...findInputsOnElementWithTag(template.content, name.replace, limitedTo.elements)\n        );\n      }\n\n      relativeOffsets\n        .map(offset => template.start + offset)\n        .forEach(start =>\n          this._replaceInputName(template.filePath, start, name.replace.length, name.replaceWith)\n        );\n    });\n  }\n\n  private _replaceInputName(\n    filePath: WorkspacePath,\n    start: number,\n    width: number,\n    newName: string\n  ): void {\n    this.fileSystem.edit(filePath).remove(start, width).insertRight(start, newName);\n  }\n}"
  },
  {
    "path": "schematics/ng-update/migrations/output-names.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  Migration,\n  OutputNameUpgradeData,\n  ResolvedResource,\n  WorkspacePath,\n  findOutputsOnElementWithAttr,\n  findOutputsOnElementWithTag\n} from '@angular/cdk/schematics';\n\nimport { getVersionUpgradeData, NzUpgradeData } from '../upgrade-data';\n\n/**\n * Migration that walks through every inline or external HTML template and switches\n * changed output binding names to the proper new output name.\n */\nexport class OutputNamesMigration extends Migration<NzUpgradeData> {\n  /** Change data that upgrades to the specified target version. */\n  data: OutputNameUpgradeData[] = getVersionUpgradeData(this, 'outputNames');\n\n  // Only enable the migration rule if there is upgrade data.\n  enabled = this.data.length !== 0;\n\n  override visitTemplate(template: ResolvedResource): void {\n    this.data.forEach(name => {\n      const limitedTo = name.limitedTo;\n      const relativeOffsets: number[] = [];\n\n      if (limitedTo.attributes) {\n        relativeOffsets.push(\n          ...findOutputsOnElementWithAttr(template.content, name.replace, limitedTo.attributes)\n        );\n      }\n\n      if (limitedTo.elements) {\n        relativeOffsets.push(\n          ...findOutputsOnElementWithTag(template.content, name.replace, limitedTo.elements)\n        );\n      }\n\n      relativeOffsets\n        .map(offset => template.start + offset)\n        .forEach(start =>\n          this._replaceOutputName(template.filePath, start, name.replace.length, name.replaceWith)\n        );\n    });\n  }\n\n  private _replaceOutputName(\n    filePath: WorkspacePath,\n    start: number,\n    width: number,\n    newName: string\n  ): void {\n    this.fileSystem.edit(filePath).remove(start, width).insertRight(start, newName);\n  }\n}"
  },
  {
    "path": "schematics/ng-update/upgrade-data.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  getChangesForTarget,\n  Migration,\n  UpgradeData,\n  ValueOfChanges,\n  VersionChanges\n} from '@angular/cdk/schematics';\n\nimport {\n  attributeSelectors,\n  classNames,\n  constructorChecks,\n  cssSelectors,\n  cssTokens,\n  elementSelectors,\n  inputNames,\n  methodCallChecks,\n  outputNames,\n  propertyNames,\n  symbolRemoval,\n  importSpecifiers,\n  ImportSpecifierUpgradeData\n} from './data';\n\nexport interface NzUpgradeData extends UpgradeData {\n  importSpecifiers: VersionChanges<ImportSpecifierUpgradeData>;\n}\n\n/** Upgrade data that will be used for the NG-ZORRO ng-update schematic. */\nexport const nzUpgradeData: NzUpgradeData = {\n  attributeSelectors,\n  classNames,\n  constructorChecks,\n  cssSelectors,\n  cssTokens,\n  elementSelectors,\n  inputNames,\n  methodCallChecks,\n  outputNames,\n  propertyNames,\n  symbolRemoval,\n  importSpecifiers\n};\n\n/**\n * Gets the reduced upgrade data for the specified data key. The function reads out the\n * target version and upgrade data object from the migration and resolves the specified\n * data portion that is specifically tied to the target version.\n */\nexport function getVersionUpgradeData<\n  T extends keyof NzUpgradeData,\n  U = ValueOfChanges<NzUpgradeData[T]>,\n>(migration: Migration<NzUpgradeData>, dataName: T): U[] {\n  if (migration.targetVersion === null) {\n    return [];\n  }\n\n  // Note that below we need to cast to `unknown` first TS doesn't infer the type of T correctly.\n  return getChangesForTarget<U>(\n    migration.targetVersion,\n    migration.upgradeData[dataName] as unknown as VersionChanges<U>,\n  );\n}\n"
  },
  {
    "path": "schematics/ng-update/upgrade-rules/checks/calendar-input-rule.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { findInputsOnElementWithTag, Migration, ResolvedResource, UpgradeData } from '@angular/cdk/schematics';\n\nexport class CalendarTemplateRule extends Migration<UpgradeData> {\n\n  enabled = false;\n\n  visitTemplate(template: ResolvedResource): void {\n\n    findInputsOnElementWithTag(template.content, 'nzCard', ['nz-calendar'])\n      .forEach(offset => {\n        this.failures.push({\n          filePath: template.filePath,\n          position: template.getCharacterAndLineOfPosition(offset),\n          message: `Found deprecated input \"nzCard\" component. Use \"nzFullscreen\" to instead please.`\n        });\n      })\n\n  }\n}\n"
  },
  {
    "path": "schematics/ng-update/upgrade-rules/checks/carousel-like-template-rule.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { findInputsOnElementWithTag, Migration, ResolvedResource, UpgradeData } from '@angular/cdk/schematics';\n\nexport class CarouselTemplateRule extends Migration<UpgradeData> {\n\n  enabled = false;\n\n  visitTemplate(template: ResolvedResource): void {\n\n    findInputsOnElementWithTag(template.content, 'nzVertical', ['nz-carousel'])\n      .forEach(offset => {\n        this.failures.push({\n          filePath: template.filePath,\n          position: template.getCharacterAndLineOfPosition(offset),\n          message: `Found deprecated \"[nzVertical]\" input. Use \"[nzDotPosition]\" to instead please.`\n        });\n      });\n\n  }\n}\n"
  },
  {
    "path": "schematics/ng-update/upgrade-rules/checks/dropdown-class-rule.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Migration, UpgradeData } from '@angular/cdk/schematics';\n\nimport * as ts from 'typescript';\n\nexport class DropdownClassRule extends Migration<UpgradeData> {\n\n  enabled = false;\n\n  visitNode(node: ts.Node): void {\n    if (ts.isIdentifier(node)) {\n      this._visitIdentifier(node);\n    }\n  }\n\n  private _visitIdentifier(identifier: ts.Identifier): void {\n    if (identifier.getText() === 'NzDropdownContextComponent') {\n      this.createFailureAtNode(\n        identifier,\n        `Found \"NzDropdownContextComponent\" which has been removed. Your code need to be updated.`);\n    }\n\n    if (identifier.getText() === 'NzDropdownService') {\n      this.createFailureAtNode(\n        identifier,\n        `Found usage of \"NzDropdownService\" which has been removed. Please use \"NzContextMenuService\" instead.`);\n    }\n  }\n}\n"
  },
  {
    "path": "schematics/ng-update/upgrade-rules/checks/dropdown-template-rule.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ElementSelectorUpgradeData,\n  Migration,\n  ResolvedResource,\n  UpgradeData\n} from '@angular/cdk/schematics';\n\nimport { deprecatedComponent } from '../utils/deprecated-component';\n\nexport class DropdownTemplateRule extends Migration<UpgradeData> {\n\n  enabled = false;\n\n  deprecatedComponents: ElementSelectorUpgradeData[] = [{\n    replace: 'nz-dropdown',\n    replaceWith: '[nz-dropdown]'\n  }, {\n    replace: 'nz-dropdown-button',\n    replaceWith: '[nz-dropdown]'\n  }]\n\n  visitTemplate(template: ResolvedResource): void {\n    this.deprecatedComponents.forEach(data => {\n      this.failures.push(...deprecatedComponent(template, data.replace, data.replaceWith));\n    })\n  }\n}\n"
  },
  {
    "path": "schematics/ng-update/upgrade-rules/checks/form-template-rule.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ElementSelectorUpgradeData, Migration, ResolvedResource, UpgradeData } from '@angular/cdk/schematics';\n\nimport { deprecatedComponent } from '../utils/deprecated-component';\n\nexport class FormTemplateRule extends Migration<UpgradeData> {\n\n  enabled = false;\n\n  deprecatedComponents: ElementSelectorUpgradeData[] = [{\n    replace: 'nz-form-extra',\n    replaceWith: 'nz-form-control[nzExtra]'\n  }, {\n    replace: 'nz-form-explain',\n    replaceWith: 'nz-form-control[nzSuccessTip][nzWarningTip][nzErrorTip][nzValidatingTip]...'\n  }];\n\n  visitTemplate(template: ResolvedResource): void {\n    this.deprecatedComponents.forEach(data => {\n      this.failures.push(...deprecatedComponent(template, data.replace, data.replaceWith));\n    });\n  }\n}\n"
  },
  {
    "path": "schematics/ng-update/upgrade-rules/checks/global-config-rule.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { InjectionTokenRule } from './injection-token-rule';\n\nexport class GlobalConfigRule extends InjectionTokenRule {\n  enabled = false;\n  tokens = [];\n  getFailure(token: string): string {\n    return `Found deprecated symbol \"${token}\" which has been removed. Please use 'NzConfigService' instead.`;\n  }\n}\n"
  },
  {
    "path": "schematics/ng-update/upgrade-rules/checks/grid-template-rule.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  findInputsOnElementWithAttr,\n  findInputsOnElementWithTag,\n  Migration,\n  ResolvedResource, UpgradeData\n} from '@angular/cdk/schematics';\n\nexport class GridTemplateRule extends Migration<UpgradeData> {\n\n  enabled = false;\n\n  visitTemplate(template: ResolvedResource): void {\n\n    const offsets = []\n\n    offsets.push(...findInputsOnElementWithAttr(template.content, 'nzType', ['nz-row']))\n    offsets.push(...findInputsOnElementWithTag(template.content, 'nzType', ['nz-form-item', 'nz-row']))\n\n    offsets.forEach(offset => {\n      this.failures.push({\n        filePath: template.filePath,\n        position: template.getCharacterAndLineOfPosition(offset),\n          message: `Found deprecated input '[nzType]'. Please manually remove this input.`\n      });\n    })\n\n    findInputsOnElementWithTag(template.content, 'nzFlex', ['nz-form-item']).forEach(offset => {\n      this.failures.push({\n        filePath: template.filePath,\n        position: template.getCharacterAndLineOfPosition(offset),\n        message: `Found deprecated input '[nzFlex]'. Please manually remove this input.`\n      });\n    })\n\n  }\n}\n"
  },
  {
    "path": "schematics/ng-update/upgrade-rules/checks/icon-template-rule.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Migration, ResolvedResource, UpgradeData } from '@angular/cdk/schematics';\n\nimport { findElementWithClassName } from '../../../utils/ng-update/elements';\n\nexport class IconTemplateRule extends Migration<UpgradeData> {\n\n  enabled = false;\n\n  visitTemplate(template: ResolvedResource): void {\n\n    findElementWithClassName(template.content, 'anticon', 'i')\n      .forEach(offset => {\n        this.failures.push({\n          filePath: template.filePath,\n          position: template.getCharacterAndLineOfPosition(offset),\n          message: `Found deprecated css selector \"i.anticon\" component. Use \"<nz-icon>\" to instead please.`\n        });\n      })\n\n  }\n}\n"
  },
  {
    "path": "schematics/ng-update/upgrade-rules/checks/injection-token-rule.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Migration, UpgradeData } from '@angular/cdk/schematics';\n\nimport * as ts from 'typescript';\n\nimport { isNgZorroImportDeclaration } from \"../../../utils/ng-update/module-specifiers\";\n\nexport abstract class InjectionTokenRule extends Migration<UpgradeData> {\n  abstract tokens: string[];\n\n  visitNode(node: ts.Node): void {\n    if (ts.isImportDeclaration(node)) {\n      this._visitImportDeclaration(node);\n    }\n  }\n\n  private _visitImportDeclaration(node: ts.ImportDeclaration): void {\n    if (!isNgZorroImportDeclaration(node) || !node.importClause ||\n      !node.importClause.namedBindings) {\n      return;\n    }\n\n    const namedBindings = node.importClause.namedBindings;\n\n    if (ts.isNamedImports(namedBindings)) {\n      this._checkInjectionToken(namedBindings);\n    }\n  }\n\n  private _checkInjectionToken(namedImports: ts.NamedImports): void {\n    namedImports.elements.filter(element => ts.isIdentifier(element.name)).forEach(element => {\n      const importName = element.name.text;\n\n      if (this.tokens.indexOf(importName) !== -1) {\n        this.createFailureAtNode(\n          element, this.getFailure(importName));\n      }\n    });\n  }\n\n  abstract getFailure(token: string): string;\n}\n"
  },
  {
    "path": "schematics/ng-update/upgrade-rules/checks/modal-template-rule.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  findInputsOnElementWithTag,\n  Migration,\n  ResolvedResource, UpgradeData\n} from '@angular/cdk/schematics';\n\nexport class ModalTemplateRule extends Migration<UpgradeData> {\n\n  enabled = false;\n\n  visitTemplate(template: ResolvedResource): void {\n    findInputsOnElementWithTag(template.content, 'nzGetContainer', ['nz-modal'])\n      .forEach(offset => {\n        this.failures.push({\n          filePath: template.filePath,\n          position: template.getCharacterAndLineOfPosition(offset),\n          message: `Found deprecated input '[nzGetContainer]'. Please manually remove this input.`\n        });\n      })\n  }\n}\n"
  },
  {
    "path": "schematics/ng-update/upgrade-rules/checks/secondary-entry-points-rule.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Migration, UpgradeData } from '@angular/cdk/schematics';\n\nimport * as ts from 'typescript';\n\nexport class SecondaryEntryPointsRule extends Migration<UpgradeData> {\n  enabled = false;\n\n  visitNode(declaration: ts.Node): void {\n    if (!ts.isImportDeclaration(declaration) ||\n      !ts.isStringLiteralLike(declaration.moduleSpecifier)) {\n      return;\n    }\n\n    const importLocation = declaration.moduleSpecifier.text;\n    if (importLocation === 'ng-zorro-antd/core') {\n      this.createFailureAtNode(declaration, 'The entry-point \"ng-zorro-antd/core\" is removed, ' +\n        'use \"ng-zorro-antd/core/**\" instead.');\n    }\n\n    if (importLocation === 'ng-zorro-antd') {\n      this.createFailureAtNode(declaration, 'The entry-point \"ng-zorro-antd\" is removed, ' +\n        'use \"ng-zorro-antd/**\" instead.');\n    }\n\n  }\n}\n"
  },
  {
    "path": "schematics/ng-update/upgrade-rules/checks/space-template-rule.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Migration, ResolvedResource, UpgradeData } from '@angular/cdk/schematics';\n\nimport { deprecatedComponent } from '../utils/deprecated-component';\n\nexport class SpaceTemplateRule extends Migration<UpgradeData> {\n\n  enabled = false;\n\n  visitTemplate(template: ResolvedResource): void {\n    this.failures.push(\n      ...deprecatedComponent(template, 'nz-space-item', 'ng-template[nzSpaceItem]')\n    );\n  }\n}\n"
  },
  {
    "path": "schematics/ng-update/upgrade-rules/checks/table-template-rule.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  findInputsOnElementWithTag, findOutputsOnElementWithTag,\n  Migration,\n  ResolvedResource, UpgradeData\n} from '@angular/cdk/schematics';\n\nexport class TableTemplateRule extends Migration<UpgradeData> {\n\n  enabled = false;\n\n  visitTemplate(template: ResolvedResource): void {\n\n    const content = template.content.replace('nz-table', 'table  ')\n    findOutputsOnElementWithTag(content, 'nzSortChangeWithKey', ['th'])\n      .forEach(offset => {\n        this.failures.push({\n          filePath: template.filePath,\n          position: template.getCharacterAndLineOfPosition(offset),\n          message: `Found deprecated output 'th(nzSortChangeWithKey)'. Please manually remove this output.`\n        });\n      });\n\n    findInputsOnElementWithTag(content, 'nzSingleSort', ['thead'])\n      .forEach(offset => {\n        this.failures.push({\n          filePath: template.filePath,\n          position: template.getCharacterAndLineOfPosition(offset),\n          message: `Found deprecated input 'thead[nzSingleSort]'. Please manually change to 'th[nzSortFn]'.`\n        });\n      });\n\n    findInputsOnElementWithTag(content, 'nzSortKey', ['th'])\n      .forEach(offset => {\n        this.failures.push({\n          filePath: template.filePath,\n          position: template.getCharacterAndLineOfPosition(offset),\n          message: `Found deprecated input 'th[nzSortKey]'. Please manually change to 'th[nzSortFn]'.`\n        });\n      });\n  }\n}\n"
  },
  {
    "path": "schematics/ng-update/upgrade-rules/checks/tooltip-like-template-rule.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  ElementSelectorUpgradeData,\n  Migration,\n  ResolvedResource,\n  UpgradeData\n} from '@angular/cdk/schematics';\n\nimport { deprecatedComponent } from '../utils/deprecated-component';\n\nexport class TooltipLikeTemplateRule extends Migration<UpgradeData> {\n\n  enabled = true;\n\n  deprecatedComponents: ElementSelectorUpgradeData[] = [{\n    replace: 'nz-tooltip',\n    replaceWith: '[nz-tooltip]'\n  }, {\n    replace: 'nz-popover',\n    replaceWith: '[nz-popover]'\n  }, {\n    replace: 'nz-popconfirm',\n    replaceWith: '[nz-popconfirm]'\n  }];\n\n  visitTemplate(template: ResolvedResource): void {\n    this.deprecatedComponents.forEach(data => {\n      this.failures.push(...deprecatedComponent(template, data.replace, data.replaceWith));\n    });\n  }\n}\n"
  },
  {
    "path": "schematics/ng-update/upgrade-rules/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { NullableDevkitMigration } from '@angular/cdk/schematics';\n\nimport { CalendarTemplateRule } from './checks/calendar-input-rule';\nimport { CarouselTemplateRule } from './checks/carousel-like-template-rule';\nimport { DropdownClassRule } from './checks/dropdown-class-rule';\nimport { DropdownTemplateRule } from './checks/dropdown-template-rule';\nimport { FormTemplateRule } from './checks/form-template-rule';\nimport { GlobalConfigRule } from './checks/global-config-rule';\nimport { GridTemplateRule } from './checks/grid-template-rule';\nimport { IconTemplateRule } from './checks/icon-template-rule';\nimport { ModalTemplateRule } from './checks/modal-template-rule';\nimport { SecondaryEntryPointsRule } from './checks/secondary-entry-points-rule';\nimport { SpaceTemplateRule } from './checks/space-template-rule';\nimport { TableTemplateRule } from './checks/table-template-rule';\nimport { TooltipLikeTemplateRule } from './checks/tooltip-like-template-rule';\n\nexport const nzUpgradeRules: NullableDevkitMigration[] = [\n  TooltipLikeTemplateRule,\n  DropdownTemplateRule,\n  DropdownClassRule,\n  IconTemplateRule,\n  CalendarTemplateRule,\n  CarouselTemplateRule,\n  GlobalConfigRule,\n  FormTemplateRule,\n  GridTemplateRule,\n  TableTemplateRule,\n  ModalTemplateRule,\n  SecondaryEntryPointsRule,\n  SpaceTemplateRule\n];"
  },
  {
    "path": "schematics/ng-update/upgrade-rules/utils/deprecated-component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { MigrationFailure, ResolvedResource } from '@angular/cdk/schematics';\n\nimport { findElementWithTag } from '../../../utils/ng-update/elements';\n\nexport const deprecatedComponent = (template: ResolvedResource, deprecated: string, instead: string): MigrationFailure[] => {\n  return findElementWithTag(template.content, deprecated)\n    .map(offset => ({\n      filePath: template.filePath,\n      position: template.getCharacterAndLineOfPosition(offset),\n      message: `Found deprecated '<${deprecated}>' component. Please use '${instead}' instead.`\n    }));\n};\n"
  },
  {
    "path": "schematics/testing/test-app.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Tree } from '@angular-devkit/schematics';\nimport { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';\n\nimport { createTestProject } from './test-project';\n\n/** Create a base app used for testing. */\nexport async function createTestApp(runner: SchematicTestRunner, appOptions = {}, tree?: Tree): Promise<UnitTestTree> {\n  return createTestProject(runner, 'application', appOptions, tree);\n}\n"
  },
  {
    "path": "schematics/testing/test-project.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Tree } from '@angular-devkit/schematics';\nimport { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';\n\n/** Create a base project used for testing. */\nexport async function createTestProject(\n  runner: SchematicTestRunner,\n  projectType: 'application' | 'library',\n  appOptions = {},\n  tree?: Tree\n): Promise<UnitTestTree> {\n  const workspaceTree = await runner.runExternalSchematic(\n    '@schematics/angular',\n    'workspace',\n    {\n      name: 'workspace',\n      version: '6.0.0',\n      newProjectRoot: 'projects'\n    },\n    tree\n  );\n  return runner.runExternalSchematic(\n    '@schematics/angular',\n    projectType,\n    { name: 'ng-zorro', ...appOptions },\n    workspaceTree\n  );\n}\n"
  },
  {
    "path": "schematics/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"lib\": [\n      \"es2017\",\n      \"dom\"\n    ],\n    \"module\": \"commonjs\",\n    \"moduleResolution\": \"node\",\n    \"outDir\": \"../publish/schematics\",\n    \"noEmitOnError\": false,\n    \"resolveJsonModule\": true,\n    \"skipDefaultLibCheck\": true,\n    \"skipLibCheck\": true,\n    \"sourceMap\": true,\n    \"target\": \"es6\",\n    \"typeRoots\": [\n      \"../node_modules/@types\"\n    ],\n    \"types\": [\n      \"jasmine\",\n      \"node\"\n    ]\n  },\n  \"include\": [\n    \"**/*\"\n  ],\n  \"exclude\": [\n    \"**/*.component.ts\",\n    \"template/**/*\",\n    \"**/files/**/*\"\n  ]\n}"
  },
  {
    "path": "schematics/utils/apply-changes.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Tree } from '@angular-devkit/schematics';\nimport { Change, InsertChange } from '@schematics/angular/utility/change';\n\nexport function applyChangesToFile(host: Tree, filePath: string, changes: Change[]): void {\n  const recorder = host.beginUpdate(filePath);\n\n  changes.forEach((change) => {\n    if (change instanceof InsertChange) {\n      recorder.insertLeft(change.pos, change.toAdd);\n    }\n  });\n\n  host.commitUpdate(recorder);\n}\n"
  },
  {
    "path": "schematics/utils/build-component.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { getDefaultComponentOptions, getProjectFromWorkspace, isStandaloneSchematic } from '@angular/cdk/schematics';\n\nimport { template as interpolateTemplate } from '@angular-devkit/core';\nimport {\n  apply,\n  applyTemplates,\n  chain,\n  FileOperator,\n  filter,\n  forEach,\n  mergeWith,\n  move,\n  noop,\n  Rule,\n  SchematicsException,\n  strings,\n  Tree,\n  url\n} from '@angular-devkit/schematics';\nimport { FileSystemSchematicContext } from '@angular-devkit/schematics/tools';\nimport { Schema as ComponentOptions, Style } from '@schematics/angular/component/schema';\nimport * as ts from '@schematics/angular/third_party/github.com/Microsoft/TypeScript/lib/typescript';\nimport { ProjectDefinition, readWorkspace } from '@schematics/angular/utility';\nimport { addDeclarationToModule, addExportToModule, getDecoratorMetadata } from '@schematics/angular/utility/ast-utils';\nimport { InsertChange } from '@schematics/angular/utility/change';\nimport { buildRelativePath, findModuleFromOptions } from '@schematics/angular/utility/find-module';\nimport { parseName } from '@schematics/angular/utility/parse-name';\nimport { validateHtmlSelector } from '@schematics/angular/utility/validation';\nimport { ProjectType } from '@schematics/angular/utility/workspace-models';\n\nimport { readFileSync, statSync } from 'fs';\nimport { dirname, join, resolve } from 'path';\n\nfunction findClassDeclarationParent(node: ts.Node): ts.ClassDeclaration | undefined {\n  if (ts.isClassDeclaration(node)) {\n    return node;\n  }\n\n  return node.parent && findClassDeclarationParent(node.parent);\n}\n\nfunction getFirstNgModuleName(source: ts.SourceFile): string | undefined {\n  // First, find the @NgModule decorators.\n  const ngModulesMetadata = getDecoratorMetadata(source, 'NgModule', '@angular/core');\n  if (ngModulesMetadata.length === 0) {\n    return undefined;\n  }\n\n  // Then walk parent pointers up the AST, looking for the ClassDeclaration parent of the NgModule\n  // metadata.\n  const moduleClass = findClassDeclarationParent(ngModulesMetadata[0]);\n  if (!moduleClass || !moduleClass.name) {\n    return undefined;\n  }\n\n  // Get the class name of the module ClassDeclaration.\n  return moduleClass.name.text;\n}\n\nexport interface ZorroComponentOptions extends ComponentOptions {\n  classnameWithModule: boolean;\n}\n\n/**\n * Build a default project path for generating.\n *\n * @param project The project to build the path for.\n */\nfunction buildDefaultPath(project: ProjectDefinition): string {\n  const root = project.sourceRoot ? `/${project.sourceRoot}/` : `/${project.root}/src/`;\n\n  const projectDirName = project.extensions['projectType'] === ProjectType.Application ? 'app' : 'lib';\n\n  return `${root}${projectDirName}`;\n}\n\n/**\n * List of style extensions which are CSS compatible. All supported CLI style extensions can be\n * found here: angular/angular-cli/master/packages/schematics/angular/ng-new/schema.json#L118-L122\n */\nconst supportedCssExtensions = ['css', 'scss', 'sass', 'less', 'none'];\n\nfunction readIntoSourceFile(host: Tree, modulePath: string): ts.SourceFile {\n  const text = host.read(modulePath);\n  if (text === null) {\n    throw new SchematicsException(`File ${modulePath} does not exist.`);\n  }\n\n  return ts.createSourceFile(modulePath, text.toString('utf-8'), ts.ScriptTarget.Latest, true);\n}\n\nfunction getModuleClassnamePrefix(source: ts.SourceFile): string {\n  const className = getFirstNgModuleName(source);\n  if (className) {\n    const execArray = /(\\w+)Module/gi.exec(className);\n    return execArray?.[1] ?? null;\n  } else {\n    return null;\n  }\n}\n\nfunction addDeclarationToNgModule(options: ZorroComponentOptions): Rule {\n  return (host: Tree) => {\n    if (options.skipImport || options.standalone || !options.module) {\n      return host;\n    }\n\n    const modulePath = options.module;\n    let source = readIntoSourceFile(host, modulePath);\n\n    const componentPath = `/${options.path}/${\n      options.flat ? '' : `${strings.dasherize(options.name)}/`\n    }${strings.dasherize(options.name)}.component`;\n    const relativePath = buildRelativePath(modulePath, componentPath);\n    let classifiedName = strings.classify(`${options.name}Component`);\n\n    if (options.classnameWithModule) {\n      const modulePrefix = getModuleClassnamePrefix(source);\n      if (modulePrefix) {\n        classifiedName = `${modulePrefix}${classifiedName}`;\n      }\n    }\n\n    const declarationChanges = addDeclarationToModule(source, modulePath, classifiedName, relativePath);\n\n    const declarationRecorder = host.beginUpdate(modulePath);\n    for (const change of declarationChanges) {\n      if (change instanceof InsertChange) {\n        declarationRecorder.insertLeft(change.pos, change.toAdd);\n      }\n    }\n    host.commitUpdate(declarationRecorder);\n\n    if (options.export) {\n      // Need to refresh the AST because we overwrote the file in the host.\n      source = readIntoSourceFile(host, modulePath);\n\n      const exportRecorder = host.beginUpdate(modulePath);\n      const exportChanges = addExportToModule(\n        source,\n        modulePath,\n        strings.classify(`${options.name}Component`),\n        relativePath\n      );\n\n      for (const change of exportChanges) {\n        if (change instanceof InsertChange) {\n          exportRecorder.insertLeft(change.pos, change.toAdd);\n        }\n      }\n      host.commitUpdate(exportRecorder);\n    }\n\n    return host;\n  };\n}\n\nfunction buildSelector(options: ZorroComponentOptions, projectPrefix: string, modulePrefixName: string): string {\n  let selector = strings.dasherize(options.name);\n  let modulePrefix = '';\n  if (modulePrefixName) {\n    modulePrefix = `${strings.dasherize(modulePrefixName)}-`;\n  }\n  if (options.prefix) {\n    selector = `${options.prefix}-${modulePrefix}${selector}`;\n  } else if (options.prefix === undefined && projectPrefix) {\n    selector = `${projectPrefix}-${modulePrefix}${selector}`;\n  }\n  return selector;\n}\n\n/**\n * Indents the text content with the amount of specified spaces. The spaces will be added after\n * every line-break. This utility function can be used inside EJS templates to properly\n * include the additional files.\n */\nfunction indentTextContent(text: string, numSpaces: number): string {\n  // In the Material project there should be only LF line-endings, but the schematic files\n  // are not being linted and therefore there can be also CRLF or just CR line-endings.\n  return text.replace(/(\\r\\n|\\r|\\n)/g, `$1${' '.repeat(numSpaces)}`);\n}\n\n/**\n * Rule that copies and interpolates the files that belong to this schematic context. Additionally\n * a list of file paths can be passed to this rule in order to expose them inside the EJS\n * template context.\n *\n * This allows inlining the external template or stylesheet files in EJS without having\n * to manually duplicate the file content.\n */\nexport function buildComponent(options: ZorroComponentOptions, additionalFiles: Record<string, string> = {}): Rule {\n  return async (host: Tree, context: FileSystemSchematicContext) => {\n    const workspace = await readWorkspace(host);\n    const project = getProjectFromWorkspace(workspace, options.project);\n    const defaultZorroComponentOptions = getDefaultComponentOptions(project);\n    let modulePrefix = '';\n    // TODO(devversion): Remove if we drop support for older CLI versions.\n    // This handles an unreported breaking change from the @angular-devkit/schematics. Previously\n    // the description path resolved to the factory file, but starting from 6.2.0, it resolves\n    // to the factory directory.\n    const schematicPath = statSync(context.schematic.description.path).isDirectory()\n      ? context.schematic.description.path\n      : dirname(context.schematic.description.path);\n\n    const schematicFilesUrl = './files';\n    const schematicFilesPath = resolve(schematicPath, schematicFilesUrl);\n\n    options.style = options.style || Style.Css;\n    // Add the default component option values to the options if an option is not explicitly\n    // specified but a default component option is available.\n    Object.keys(options)\n      .filter(optionName => options[optionName] == null && defaultZorroComponentOptions[optionName])\n      .forEach(optionName => (options[optionName] = defaultZorroComponentOptions[optionName]));\n\n    if (options.path === undefined) {\n      options.path = buildDefaultPath(project);\n    }\n\n    options.standalone = await isStandaloneSchematic(host, options);\n\n    if (!options.standalone) {\n      options.module = findModuleFromOptions(host, options);\n    }\n\n    options.type ??= '';\n\n    const parsedPath = parseName(options.path!, options.name);\n    if (options.classnameWithModule && !options.skipImport && options.module) {\n      const source = readIntoSourceFile(host, options.module);\n      modulePrefix = getModuleClassnamePrefix(source);\n    }\n\n    options.name = parsedPath.name;\n    options.path = parsedPath.path;\n    options.selector = options.selector || buildSelector(options, project.prefix, modulePrefix);\n\n    validateHtmlSelector(options.selector!);\n\n    const skipStyleFile = options.inlineStyle || options.style === Style.None;\n    // In case the specified style extension is not part of the supported CSS supersets,\n    // we generate the stylesheets with the \"css\" extension. This ensures that we don't\n    // accidentally generate invalid stylesheets (e.g. drag-drop-comp.styl) which will\n    // break the Angular CLI project. See: https://github.com/angular/components/issues/15164\n    if (!skipStyleFile && !supportedCssExtensions.includes(options.style!)) {\n      options.style = Style.Css;\n    }\n\n    const classifyCovered = (name: string): string => {\n      return `${modulePrefix}${strings.classify(name)}`;\n    };\n    // Object that will be used as context for the EJS templates.\n    const baseTemplateContext = {\n      ...strings,\n      'if-flat': (s: string) => (options.flat ? '' : s),\n      classify: classifyCovered,\n      ngext: options.ngHtml ? '.ng' : '',\n      ...options\n    };\n\n    // Key-value object that includes the specified additional files with their loaded content.\n    // The resolved contents can be used inside EJS templates.\n    const resolvedFiles: Record<string, string> = {};\n\n    for (const key in additionalFiles) {\n      if (additionalFiles[key]) {\n        const fileContent = readFileSync(join(schematicFilesPath, additionalFiles[key]), 'utf-8');\n\n        // Interpolate the additional files with the base EJS template context.\n        resolvedFiles[key] = interpolateTemplate(fileContent)(baseTemplateContext);\n      }\n    }\n\n    const templateSource = apply(url(schematicFilesUrl), [\n      options.skipTests ? filter(path => !path.endsWith('.spec.ts.template')) : noop(),\n      skipStyleFile ? filter(path => !path.endsWith('.__style__.template')) : noop(),\n      options.inlineTemplate ? filter(path => !path.endsWith('.html.template')) : noop(),\n      // Treat the template options as any, because the type definition for the template options\n      // is made unnecessarily explicit. Every type of object can be used in the EJS template.\n      applyTemplates({ indentTextContent, resolvedFiles, ...baseTemplateContext }),\n      // remove multiple dots if no type is specified\n      !options.type\n        ? forEach(((file) => {\n            return file.path.includes('..')\n              ? {\n                content: file.content,\n                path: file.path.replace('..', '.')\n              }\n              : file;\n          }\n        ) as FileOperator)\n        : noop(),\n      // TODO(devversion): figure out why we cannot just remove the first parameter\n      // See for example: angular-cli#schematics/angular/component/index.ts#L160\n      move(null, parsedPath.path)\n    ]);\n\n    return () => chain([\n      addDeclarationToNgModule(options),\n      mergeWith(templateSource)\n    ])(host, context);\n  };\n}\n"
  },
  {
    "path": "schematics/utils/config.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { getSchematicDefaults } from '@angular/cli/src/utilities/config';\n\nimport { normalize } from '@angular-devkit/core';\nimport { Schema } from '@schematics/angular/component/schema';\n\n/**\n * Returns the default options for the `@schematics/angular:component` schematic which would\n * have been specified at project initialization (ng new or ng init).\n */\nexport async function getDefaultComponentOptions(project?: string): Promise<Partial<Schema>> {\n  return getSchematicDefaults('@schematics/angular', 'component', project);\n}\n\nexport async function getAppOptions(\n  project: string,\n  projectRoot?: string\n): Promise<{\n  componentOptions: Partial<Schema>;\n  sourceDir: string;\n}> {\n  const componentOptions = await getDefaultComponentOptions(project);\n  componentOptions.type ??= '';\n\n  const appDir = normalize(projectRoot);\n  const sourceDir = `${appDir}/src/app`;\n\n  return {\n    componentOptions,\n    sourceDir\n  };\n}"
  },
  {
    "path": "schematics/utils/create-custom-theme.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport function createCustomTheme(): string {\n  return `\n// Custom Theming for NG-ZORRO\n// For more information: https://ng.ant.design/docs/customize-theme/en\n@import \"../node_modules/ng-zorro-antd/ng-zorro-antd.less\";\n\n// Override less variables to here\n// View all variables: https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/components/style/themes/default.less\n\n// @primary-color: #1890ff;\n`;\n}\n"
  },
  {
    "path": "schematics/utils/get-file-content.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Tree } from '@angular-devkit/schematics';\n\nexport function getFileContent(tree: Tree, path: string): string {\n  const fileEntry = tree.get(path);\n\n  if (!fileEntry) {\n    throw new Error(`The file (${path}) does not exist.`);\n  }\n\n  return fileEntry.content.toString();\n}"
  },
  {
    "path": "schematics/utils/ng-update/elements.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { DefaultTreeAdapterMap, parseFragment } from 'parse5';\n\n/**\n * Get the type of the item in an array.\n */\nexport type ArrayItem<T> = T extends Array<infer U> ? U : never;\n\n// At the time of writing `parse5` doesn't expose the node interfaces directly, even though\n// they're used as return types, but We can still access them through `DefaultTreeAdapterMap`.\nexport type Element = DefaultTreeAdapterMap['element'];\nexport type ChildNode = DefaultTreeAdapterMap['childNode'];\nexport type Attribute = ArrayItem<Element['attrs']>;\n\nconst hasClassName = (node: Element, className: string): Attribute | undefined => {\n  return node.attrs?.find?.(attr => attr.name === 'class' && attr.value.indexOf(className) !== -1);\n};\n\nconst compareCaseInsensitive = (a: string, b: string): boolean => a?.toLowerCase() === b?.toLowerCase();\n\nexport function findElementWithoutStructuralDirective(html: string, tagName: string, directiveName: string, attr: string): number[] {\n  const document = parseFragment(html, { sourceCodeLocationInfo: true });\n  const elements: Element[] = [];\n\n  const visitNodes = (nodes: ChildNode[]): void => {\n    nodes.forEach(node => {\n      if (node['childNodes'] && !(node['tagName'] === 'ng-template' && !!(node as Element).attrs.find(a => compareCaseInsensitive(a.name!, directiveName)))) {\n        visitNodes(node['childNodes']);\n      }\n\n      if (compareCaseInsensitive(node['tagName'], tagName)) {\n        const element = node as Element;\n        const directive = `*${directiveName}`;\n        if (!!element.attrs.find(a => compareCaseInsensitive(a.name!, attr)) && !element.attrs.find(a => compareCaseInsensitive(a.name!, directive))) {\n          elements.push(element);\n        }\n      }\n    });\n  };\n\n  visitNodes(document.childNodes);\n\n  return elements\n    .filter(e => e?.sourceCodeLocation?.startTag)\n    .map(element => element.sourceCodeLocation.startTag.startOffset);\n}\n\nexport function findElementWithTag(html: string, tagName: string): number[] {\n  const document = parseFragment(html, { sourceCodeLocationInfo: true });\n  const elements: Element[] = [];\n\n  const visitNodes = (nodes: ChildNode[]): void => {\n    nodes.forEach(node => {\n      if (node['childNodes']) {\n        visitNodes(node['childNodes']);\n      }\n\n      if (compareCaseInsensitive(node['tagName'], tagName)) {\n        elements.push(node as Element);\n      }\n    });\n  };\n\n  visitNodes(document.childNodes);\n\n  return elements\n    .filter(e => e?.sourceCodeLocation?.startTag)\n    .map(element => element.sourceCodeLocation.startTag.startOffset);\n}\n\nexport function findElementWithClassName(html: string, className: string, tagName: string): number[] {\n  const document = parseFragment(html, { sourceCodeLocationInfo: true });\n  const elements: Element[] = [];\n\n  const visitNodes = (nodes: ChildNode[]): void => {\n    nodes.forEach(node => {\n      if (node['childNodes']) {\n        visitNodes(node['childNodes']);\n      }\n\n      if (compareCaseInsensitive(node['tagName'], tagName) && hasClassName(node as Element, className)) {\n        elements.push(node as Element);\n      }\n    });\n  };\n\n  visitNodes(document.childNodes);\n\n  return elements\n    .filter(e => e?.sourceCodeLocation?.startTag)\n    .map(element => element.sourceCodeLocation.attrs.class.startOffset);\n}\n"
  },
  {
    "path": "schematics/utils/ng-update/module-specifiers.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { getExportDeclaration, getImportDeclaration } from '@angular/cdk/schematics';\n\nimport * as ts from 'typescript';\n\nexport const ngZorroModuleSpecifier = 'ng-zorro-antd';\n\nexport function isNgZorroImportDeclaration(node: ts.Node): boolean {\n  return isNgZorroDeclaration(getImportDeclaration(node));\n}\n\nexport function isNgZorroExportDeclaration(node: ts.Node): boolean {\n  return isNgZorroDeclaration(getExportDeclaration(node));\n}\n\nfunction isNgZorroDeclaration(declaration: ts.ImportDeclaration | ts.ExportDeclaration): boolean {\n  if (!declaration.moduleSpecifier) {\n    return false;\n  }\n\n  const moduleSpecifier = declaration.moduleSpecifier.getText();\n  return moduleSpecifier.indexOf(ngZorroModuleSpecifier) !== -1;\n}\n"
  },
  {
    "path": "schematics/utils/project-style.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { getProjectStyleFile } from '@angular/cdk/schematics';\n\nimport { Style } from '@schematics/angular/application/schema';\nimport { ProjectDefinition } from '@schematics/angular/utility';\n\nexport function getProjectStyle(project: ProjectDefinition): Style {\n  const stylesPath = getProjectStyleFile(project);\n  const style = stylesPath ? stylesPath.split('.').pop() : Style.Css;\n  return style as Style;\n}\n"
  },
  {
    "path": "schematics/utils/root-module.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport {\n  addDeclarationToModule,\n  addModuleImportToRootModule,\n  getProjectFromWorkspace,\n  getProjectMainFile\n} from '@angular/cdk/schematics';\n\nimport { noop, Rule, SchematicsException, Tree } from '@angular-devkit/schematics';\nimport { readWorkspace } from '@schematics/angular/utility';\nimport { InsertChange } from '@schematics/angular/utility/change';\nimport { buildRelativePath } from '@schematics/angular/utility/find-module';\nimport { getAppModulePath } from '@schematics/angular/utility/ng-ast-utils';\nimport * as ts from 'typescript';\n\nfunction readIntoSourceFile(host: Tree, modulePath: string): ts.SourceFile {\n  const text = host.read(modulePath);\n  if (text === null) {\n    throw new SchematicsException(`File ${modulePath} does not exist.`);\n  }\n  const sourceText = text.toString('utf-8');\n\n  return ts.createSourceFile(modulePath, sourceText, ts.ScriptTarget.Latest, true);\n}\n\nexport function addModule(moduleName: string, modulePath: string, projectName: string): Rule {\n  return async (host: Tree) => {\n    const workspace = await readWorkspace(host);\n    const project = getProjectFromWorkspace(workspace, projectName);\n    addModuleImportToRootModule(host, moduleName, modulePath, project);\n    return noop();\n  };\n}\n\nexport function addDeclaration(componentName: string, componentPath: string, projectName: string): Rule {\n  return async (host: Tree) => {\n    const workspace = await readWorkspace(host);\n    const project = getProjectFromWorkspace(workspace, projectName);\n    const appModulePath = getAppModulePath(host, getProjectMainFile(project));\n    const source = readIntoSourceFile(host, appModulePath);\n    const relativePath = buildRelativePath(appModulePath, componentPath);\n    const declarationChanges = addDeclarationToModule(source, appModulePath, componentName, relativePath);\n    const declarationRecorder = host.beginUpdate(appModulePath);\n    for (const change of declarationChanges) {\n      if (change instanceof InsertChange) {\n        declarationRecorder.insertLeft(change.pos, change.toAdd);\n      }\n    }\n    host.commitUpdate(declarationRecorder);\n\n    return noop();\n  };\n}\n"
  },
  {
    "path": "scripts/build/aliyun-vars.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { readFileSync } from 'fs-extra';\nimport lessToJs from 'less-vars-to-js';\n\nimport path from 'path';\n\nimport { buildConfig } from '../build-config';\n\nconst stylePath = path.join(buildConfig.componentsDir, 'style');\nconst aliyunLess = readFileSync(path.join(stylePath, 'themes', 'aliyun.less'), 'utf8');\n\nexport const aliyunPaletteLess = lessToJs(`${aliyunLess}`, {\n  stripPrefix: true,\n  resolveVariables: false\n});\n"
  },
  {
    "path": "scripts/build/compact-vars.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { readFileSync } from 'fs-extra';\nimport lessToJs from 'less-vars-to-js';\n\nimport path from 'path';\n\nimport { buildConfig } from '../build-config';\n\nconst stylePath = path.join(buildConfig.componentsDir, 'style');\nconst compactLess = readFileSync(path.join(stylePath, 'themes', 'compact.less'), 'utf8');\n\nexport const compactPaletteLess = lessToJs(`${compactLess}`, {\n  stripPrefix: true,\n  resolveVariables: false\n});\n"
  },
  {
    "path": "scripts/build/compile-styles.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { copy, pathExists, readdirSync, readFile, writeFile } from 'fs-extra';\nimport less from 'less';\nimport LessPluginCleanCSS from 'less-plugin-clean-css';\nimport NpmImportPlugin from 'less-plugin-npm-import';\n\nimport path from 'path';\n\nimport { buildConfig } from '../build-config';\n\nasync function compileLess(\n  content: string,\n  savePath: string,\n  min: boolean,\n  sub?: boolean,\n  rootPath?: string\n): Promise<void> {\n  const plugins: Less.Plugin[] = [];\n  const lessOptions: Less.Options = { plugins };\n\n  if (min) {\n    plugins.push(new LessPluginCleanCSS({ advanced: true }));\n  }\n\n  if (sub) {\n    lessOptions.paths = [path.dirname(rootPath as string)];\n    lessOptions.filename = rootPath;\n    plugins.push(new NpmImportPlugin({ prefix: '~' }));\n  }\n\n  return less\n    .render(content, lessOptions)\n    .then(({ css }) => writeFile(savePath, css))\n    .catch(err => Promise.reject(err));\n}\n\nconst sourcePath = buildConfig.componentsDir;\nconst targetPath = buildConfig.publishDir;\n\nexport async function compile(): Promise<void | void[]> {\n  const componentFolders = readdirSync(targetPath);\n  const promiseList: Array<Promise<void>> = [];\n\n  for (const dir of componentFolders) {\n    if (await pathExists(`${sourcePath}/${dir}/style/index.less`)) {\n      // Copy style files for each component.\n      await copy(`${sourcePath}/${dir}/style`, `${targetPath}/${dir}/style`);\n\n      // Compile `.less` files to CSS and delete the `entry.less` file.\n      const buildFilePath = `${sourcePath}/${dir}/style/entry.less`;\n      const componentLess = await readFile(buildFilePath, { encoding: 'utf8' });\n      if (await pathExists(buildFilePath)) {\n        // Rewrite `entry.less` file with `root-entry-name`\n        const entryLessFileContent = needTransformStyle(componentLess)\n          ? `@root-entry-name: default;\\n${componentLess}`\n          : componentLess;\n        promiseList.push(\n          compileLess(\n            entryLessFileContent,\n            path.join(targetPath, dir, 'style', `index.css`),\n            false,\n            true,\n            buildFilePath\n          )\n        );\n        promiseList.push(\n          compileLess(\n            entryLessFileContent,\n            path.join(targetPath, dir, 'style', `index.min.css`),\n            true,\n            true,\n            buildFilePath\n          )\n        );\n      }\n    }\n  }\n\n  // Copy concentrated `.less` files.\n  await copy(path.resolve(sourcePath, 'style'), path.resolve(targetPath, 'style'));\n  await writeFile(`${targetPath}/components.less`, await readFile(`${sourcePath}/components.less`));\n  await writeFile(`${targetPath}/ng-zorro-antd.less`, await readFile(`${sourcePath}/ng-zorro-antd.less`));\n  await writeFile(`${targetPath}/ng-zorro-antd.dark.less`, await readFile(`${sourcePath}/ng-zorro-antd.dark.less`));\n  await writeFile(`${targetPath}/ng-zorro-antd.aliyun.less`, await readFile(`${sourcePath}/ng-zorro-antd.aliyun.less`));\n  await writeFile(\n    `${targetPath}/ng-zorro-antd.compact.less`,\n    await readFile(`${sourcePath}/ng-zorro-antd.compact.less`)\n  );\n\n  await writeFile(\n    `${targetPath}/ng-zorro-antd.variable.less`,\n    await readFile(`${sourcePath}/ng-zorro-antd.variable.less`)\n  );\n\n  // Compile concentrated less file to CSS file.\n  const lessContent = `@import \"${path.posix.join(targetPath, 'ng-zorro-antd.less')}\";`;\n  promiseList.push(compileLess(lessContent, path.join(targetPath, 'ng-zorro-antd.css'), false));\n  promiseList.push(compileLess(lessContent, path.join(targetPath, 'ng-zorro-antd.min.css'), true));\n\n  // Compile the dark theme less file to CSS file.\n  const darkLessContent = `@import \"${path.posix.join(targetPath, 'ng-zorro-antd.dark.less')}\";`;\n  promiseList.push(compileLess(darkLessContent, path.join(targetPath, 'ng-zorro-antd.dark.css'), false));\n  promiseList.push(compileLess(darkLessContent, path.join(targetPath, 'ng-zorro-antd.dark.min.css'), true));\n\n  // Compile the compact theme less file to CSS file.\n  const compactLessContent = `@import \"${path.posix.join(targetPath, 'ng-zorro-antd.compact.less')}\";`;\n  promiseList.push(compileLess(compactLessContent, path.join(targetPath, 'ng-zorro-antd.compact.css'), false));\n  promiseList.push(compileLess(compactLessContent, path.join(targetPath, 'ng-zorro-antd.compact.min.css'), true));\n\n  // Compile the aliyun theme less file to CSS file.\n  const aliyunLessContent = `@import \"${path.posix.join(targetPath, 'ng-zorro-antd.aliyun.less')}\";`;\n  promiseList.push(compileLess(aliyunLessContent, path.join(targetPath, 'ng-zorro-antd.aliyun.css'), false));\n  promiseList.push(compileLess(aliyunLessContent, path.join(targetPath, 'ng-zorro-antd.aliyun.min.css'), true));\n\n  // Compile the aliyun theme less file to CSS file.\n  const variableLessContent = `@import \"${path.posix.join(targetPath, 'ng-zorro-antd.variable.less')}\";`;\n  promiseList.push(compileLess(variableLessContent, path.join(targetPath, 'ng-zorro-antd.variable.css'), false));\n  promiseList.push(compileLess(variableLessContent, path.join(targetPath, 'ng-zorro-antd.variable.min.css'), true));\n\n  // Compile css file that doesn't have component-specific styles.\n  const cssIndexPath = path.join(sourcePath, 'style', 'entry.less');\n  const cssIndex = await readFile(cssIndexPath, { encoding: 'utf8' });\n  // Rewrite `entry.less` file with `root-entry-name`\n  const entryLessInStyle = needTransformStyle(cssIndex) ? `@root-entry-name: default;\\n${cssIndex}` : cssIndex;\n\n  promiseList.push(\n    compileLess(entryLessInStyle, path.join(targetPath, 'style', 'index.css'), false, true, cssIndexPath)\n  );\n  promiseList.push(\n    compileLess(entryLessInStyle, path.join(targetPath, 'style', 'index.min.css'), true, true, cssIndexPath)\n  );\n  return Promise.all(promiseList).catch(e => console.log(e));\n}\n\nfunction needTransformStyle(content: string): boolean {\n  return (\n    content.includes('../../style/index.less') || content.includes('./index.less') || content.includes('/entry.less')\n  );\n}\n"
  },
  {
    "path": "scripts/build/dark-vars.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { readFileSync } from 'fs-extra';\nimport lessToJs from 'less-vars-to-js';\n\nimport path from 'path';\n\nimport { buildConfig } from '../build-config';\n\nconst stylePath = path.join(buildConfig.componentsDir, 'style');\nconst colorLess = readFileSync(path.join(stylePath, 'color', 'colors.less'), 'utf8');\nconst defaultLess = readFileSync(path.join(stylePath, 'themes', 'default.less'), 'utf8');\nconst darkLess = readFileSync(path.join(stylePath, 'themes', 'dark.less'), 'utf8');\n\nexport const darkPaletteLess = lessToJs(`${colorLess}${defaultLess}${darkLess}`, {\n  stripPrefix: true,\n  resolveVariables: false\n});\n"
  },
  {
    "path": "scripts/build/generate-less-vars.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { writeFileSync } from 'fs-extra';\n\nimport path from 'path';\n\nimport { buildConfig } from '../build-config';\nimport { compactPaletteLess } from './compact-vars';\nimport { darkPaletteLess } from './dark-vars';\n\nexport function generateLessVars(): void {\n  const dist = buildConfig.publishDir;\n  writeFileSync(path.join(dist, 'dark-theme.js'), `module.exports = ${JSON.stringify(darkPaletteLess)}`, 'utf8');\n  writeFileSync(path.join(dist, 'compact-theme.js'), `module.exports = ${JSON.stringify(compactPaletteLess)}`, 'utf8');\n}\n"
  },
  {
    "path": "scripts/build/less.d.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\ndeclare module 'less-vars-to-js' {\n  interface ConvertOption {\n    stripPrefix: boolean;\n    resolveVariables: boolean;\n  }\n\n  export default function lessToJs(vars: string, options?: Partial<ConvertOptions>): Record<string, string | number>;\n}\n\nabstract class LessPlugin implements Less.Plugin {\n  constructor(options?: Record<string, unknown>);\n  install: (less: LessStatic, pluginManager: PluginManager) => void;\n  minVersion?: [number, number, number] | undefined;\n}\n\ndeclare module 'less-plugin-clean-css' {\n  export default class LessPluginCleanCSS extends LessPlugin {}\n}\n\ndeclare module 'less-plugin-npm-import' {\n  export default class NpmImportPlugin extends LessPlugin {}\n}\n"
  },
  {
    "path": "scripts/build/migration-styles.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { mkdirsSync, copySync, outputFileSync } from 'fs-extra';\n\nimport path from 'path';\n\nimport { buildConfig } from '../build-config';\n\nconst sourcePath = buildConfig.publishDir;\nconst targetPath = path.join(buildConfig.publishDir, `src`);\nconst lessContent = `@root-entry-name: default;\n@import \"../style/entry.less\";\n@import \"../components.less;`;\n\nexport function copyStylesToSrc(): void {\n  mkdirsSync(targetPath);\n  copySync(path.resolve(sourcePath, `style`), path.resolve(targetPath, `style`));\n  copySync(path.resolve(sourcePath, `ng-zorro-antd.css`), path.resolve(targetPath, `ng-zorro-antd.css`));\n  copySync(path.resolve(sourcePath, `ng-zorro-antd.min.css`), path.resolve(targetPath, `ng-zorro-antd.min.css`));\n  outputFileSync(path.resolve(targetPath, `ng-zorro-antd.less`), lessContent);\n}\n"
  },
  {
    "path": "scripts/build-config.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { existsSync } from 'fs';\nimport { dirname, join, resolve } from 'path';\n\nexport interface BuildConfig {\n  projectVersion: string;\n  projectDir: string;\n  componentsDir: string;\n  scriptsDir: string;\n  outputDir: string;\n  publishDir: string;\n  libDir: string;\n}\n\nconst BUILD_CONFIG_FILENAME = 'build-config.js';\n\nexport function findBuildConfig(): string {\n  let currentDir = process.cwd();\n\n  while (!existsSync(resolve(currentDir, BUILD_CONFIG_FILENAME))) {\n    currentDir = dirname(currentDir);\n  }\n\n  return join(currentDir, BUILD_CONFIG_FILENAME);\n}\n\nconst buildConfigPath = findBuildConfig();\n\nexport const buildConfig = require(buildConfigPath) as BuildConfig;\n"
  },
  {
    "path": "scripts/generate-llms.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ensureDir, readFile, writeFile } from 'fs-extra';\nimport { glob } from 'glob';\n\nimport { resolve, join } from 'path';\n\n/**\n * @see https://github.com/ant-design/ant-design/blob/master/scripts/generate-llms.ts\n */\nexport async function generateLLms(): Promise<void> {\n  const cwd = process.cwd();\n  const siteDir = resolve(cwd, 'site');\n  const docsDir = ['components', 'docs'];\n\n  const matchSuffix = '.en-US.md';\n\n  // Ensure siteDir\n  await ensureDir(siteDir);\n\n  const docs = await glob(`{${docsDir.join(',')}}/**/*.md`);\n  const ignoreDocs = ['changelog', 'join', 'migration', 'recommendation'];\n  const filteredDocs = docs.filter(doc => doc.includes(matchSuffix) && !ignoreDocs.some(title => doc.includes(title)));\n\n  const docsIndex: Array<{ title: string; url: string }> = [];\n  const docsBody: string[] = [];\n\n  for (const markdown of filteredDocs) {\n    const mdPath = join(cwd, markdown);\n\n    const fsContent = (await readFile(mdPath, 'utf-8')).trim();\n\n    // e.g. title: Button -> Button\n    const title = fsContent.match(/title:\\s*(.*)/)?.[1].trim();\n\n    if (!title) {\n      console.log('MISS title, ignore:', mdPath);\n      continue;\n    }\n\n    // URL\n    let url = `https://ng.ant.design/${markdown.replace(matchSuffix, '')}/en`;\n    if (url.includes('/components/')) {\n      url = url.replace('/doc/index', '');\n    }\n\n    // Docs: title\n    docsIndex.push({\n      title,\n      url\n    });\n\n    // Docs: content\n    const parsedContent = fsContent.replace(/^---[\\s\\S]*?---\\n/, '').trim();\n\n    const fullContent = [\n      // Title\n      '---',\n      `Title: ${title}`,\n      `URL: ${url}`,\n      '---',\n      '',\n      // Content\n      parsedContent,\n      ''\n    ].join('\\n');\n\n    docsBody.push(fullContent);\n  }\n  const docsIndexContent = [\n    '# ng-zorro-antd - Ant Design of Angular',\n    '',\n    '- An enterprise-class Angular UI component library based on Ant Design, which aims to provide a high-quality design language and development framework for enterprise-level backend management systems. It offers a rich set of components and design guidelines, helping developers build modern, responsive, and high-performance web applications.\\n' +\n      '',\n    '## Docs',\n    '',\n    ...docsIndex.map(({ title, url }) => `- [${title}](${url})`),\n    ''\n  ].join('\\n');\n\n  const docsBodyContent = docsBody.join('\\n');\n\n  await writeFile(join(siteDir, 'llms.txt'), docsIndexContent);\n  await writeFile(join(siteDir, 'llms-full.txt'), docsBodyContent);\n  console.log('Generated llms.txt and llms-full.txt');\n}\n\n(async () => {\n  if (require.main === module) {\n    await generateLLms();\n  }\n})().catch(e => {\n  console.error(e);\n  process.exit(1);\n});\n"
  },
  {
    "path": "scripts/gulp/gulpfile.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\n/* eslint-disable import/no-unassigned-import */\nimport { series, task } from 'gulp';\nimport './tasks/clean';\nimport './tasks/default';\nimport './tasks/schematic';\nimport './tasks/unit-test';\nimport './tasks/library';\nimport './tasks/site';\n\ntask('build:release', series('clean', 'build:library', 'build:release-site'));\n\ntask('start:dev', series('clean', 'start:site'));\n"
  },
  {
    "path": "scripts/gulp/tasks/clean.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { task } from 'gulp';\n\nimport { buildConfig } from '../../build-config';\nimport { cleanTask } from '../util/task-helpers';\n\n/** Deletes the dist/ publish/ directory. */\ntask('clean', cleanTask([buildConfig.outputDir, buildConfig.publishDir]));\n"
  },
  {
    "path": "scripts/gulp/tasks/default.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { yellow } from 'chalk';\nimport { parallel, task } from 'gulp';\n\ntask('help', done => {\n  console.log();\n  console.log('Please specify a gulp task you want to run.');\n  console.log(yellow('start:dev    '), 'Start development.');\n  console.log(yellow('build:library'), 'Build ng-zorro-antd-lib to publish/ directory.');\n  console.log(\n    yellow('build:release'),\n    'Build releasable library to publish/ directory and deployable site to dist/ directory.'\n  );\n  console.log();\n  done();\n});\n\ntask('default', parallel('help'));\n"
  },
  {
    "path": "scripts/gulp/tasks/library.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { dest, parallel, series, src, task } from 'gulp';\n\nimport { join } from 'path';\n\nimport { compile as compileLess } from '../../build/compile-styles';\nimport { generateLessVars } from '../../build/generate-less-vars';\nimport { copyStylesToSrc } from '../../build/migration-styles';\nimport { buildConfig } from '../../build-config';\nimport { execTask } from '../util/task-helpers';\n\n/** Run `ng build ng-zorro-antd-lib` */\ntask('library:build-zorro', execTask('ng', ['build', 'ng-zorro-antd-lib']));\n\n// Compile less to the public directory.\ntask('library:compile-less', done => {\n  compileLess().then(() => {\n    copyStylesToSrc();\n    done();\n  });\n});\n\n// Compile less to the public directory.\ntask('library:generate-less-vars', done => {\n  generateLessVars();\n  done();\n});\n\n// Copies README.md file to the public directory.\ntask('library:copy-resources', () => {\n  return src([join(buildConfig.projectDir, 'README.md'), join(buildConfig.componentsDir)]).pipe(\n    dest(join(buildConfig.publishDir))\n  );\n});\n\n// Copies files without ngcc to lib folder.\ntask('library:copy-libs', () => {\n  return src([join(buildConfig.publishDir, '**/*')]).pipe(dest(join(buildConfig.libDir)));\n});\n\ntask(\n  'build:library',\n  series(\n    'library:build-zorro',\n    parallel('library:compile-less', 'library:copy-resources', 'library:generate-less-vars', 'build:schematics'),\n    'library:copy-libs'\n  )\n);\n"
  },
  {
    "path": "scripts/gulp/tasks/schematic.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { series, task } from 'gulp';\n\nimport { join } from 'path';\n\nimport { buildConfig } from '../../build-config';\nimport { copyResources } from '../../schematics/copy-resources';\nimport { generate as demo2schematics } from '../../schematics/demo2schematics';\nimport { setVersion } from '../../schematics/set-version';\nimport { cleanTask, execTask } from '../util/task-helpers';\n\nconst schematicsDir = join(buildConfig.projectDir, 'schematics');\nconst tsconfigFile = join(schematicsDir, 'tsconfig.json');\nconst cleanGlob = [join(schematicsDir, 'demo'), join(schematicsDir, 'utils/version-names.ts')];\n\n/** Generate the schematics in the schematics directory */\ntask('generate:schematics', done => {\n  demo2schematics();\n  setVersion();\n  done();\n});\n\n/** Build the schematics in the publish directory. */\ntask('tsc:schematics', execTask('tsc', ['-p', tsconfigFile]));\n\n/** Copies all resources files to the publish directory. */\ntask('schematics:copy-resources', done => {\n  copyResources();\n  done();\n});\n\n/** Deletes the schematics/ directory and utils/(version-names).ts. files */\ntask('clean:schematics', cleanTask(cleanGlob));\n\n/** Task that run the generate script and builds the schematics in the publish directory. */\ntask(\n  'build:schematics',\n  series('generate:schematics', 'tsc:schematics', 'schematics:copy-resources', 'clean:schematics')\n);\n\n/** Test the schematics */\ntask('test:schematics', execTask('jasmine', ['publish/schematics/**/*.spec.js']));\n\n/** Test the ng-update schematics */\ntask('test:schematics-update', execTask('jasmine', ['publish/schematics/ng-update/**/*.spec.js']));\n"
  },
  {
    "path": "scripts/gulp/tasks/site.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { detect } from 'detect-port';\nimport { readJSONSync, writeJSON } from 'fs-extra';\nimport { parallel, series, task, watch } from 'gulp';\nimport { debounce } from 'lodash';\n\nimport { join } from 'path';\n\nimport { buildConfig } from '../../build-config';\nimport { generateLLms } from '../../generate-llms';\nimport { generate } from '../../prerender/ngsw-config';\nimport { generateSitemap } from '../../prerender/sitemap';\nimport siteGenerate from '../../site/generate-site';\nimport themeGenerate from '../../site/generate-theme';\nimport { execTask } from '../util/task-helpers';\n\nconst docsGlob = join(buildConfig.componentsDir, `**/doc/*.+(md|txt)`);\nconst demoGlob = join(buildConfig.componentsDir, `**/demo/*.+(md|ts)`);\nconst issueHelperScriptFile = join(buildConfig.scriptsDir, 'release-helper.sh');\nconst tsconfigFile = join(buildConfig.projectDir, 'site/tsconfig.app.json');\n\n/**\n * Development app watch task,\n * to ensures the demos and docs have changes are rebuild.\n */\ntask('watch:site', () => {\n  // Globs accepts the Unix-style path separators only\n  const globs = [docsGlob, demoGlob].map(p => p.replace(/\\\\/g, '/'));\n  watch(globs).on(\n    'change',\n    debounce(path => {\n      const p = path.replace(/\\\\/g, '/');\n      const execArray = /components\\/(.+)\\/(doc|demo)/.exec(p);\n      if (execArray && execArray[1]) {\n        const component = execArray[1];\n        console.log(`Reload '${component}'`);\n        siteGenerate(component);\n      }\n    }, 3000)\n  );\n});\n\n/** Parse demos and docs to site directory. */\ntask('init:site', async done => {\n  siteGenerate('init');\n  await themeGenerate();\n  done();\n});\n\n/** Run `ng serve` */\ntask('serve:site', async done => {\n  const port = await detect(4200);\n  execTask('ng', ['serve', 'ng-zorro-antd-doc', '--port', port === 4200 ? '4200' : '0'])(done);\n});\n\n/** Run `ng build ng-zorro-antd-doc --configuration=production` */\ntask('build:site-doc', execTask('ng', ['build', 'ng-zorro-antd-doc', '--configuration=production']));\n\n/** Generate llms.txt and llms-full.txt */\ntask('site:llms-txt', generateLLms);\n\n/** Replace the library paths to publish/ directory */\ntask('site:replace-path', () => {\n  const tsconfig = readJSONSync(tsconfigFile);\n  tsconfig.compilerOptions.paths['ng-zorro-antd'] = ['../publish'];\n  tsconfig.compilerOptions.paths['ng-zorro-antd/*'] = ['../publish/*'];\n  return writeJSON(tsconfigFile, tsconfig);\n});\n\n/** Run sitemap script on the output directory, to create sitemap.xml */\ntask('site:sitemap', generateSitemap);\n\n/** Regenerate the ngsw-config to fix https://github.com/angular/angular/issues/23613 */\ntask('site:regen-ngsw-config', generate);\n\n/** Run release-helper.sh\n * Clone issue-helper builds from GitHub and copy to the output directory.\n */\ntask('build:site-issue-helper', execTask('bash', [issueHelperScriptFile]));\n\n/** Build all site projects to the output directory. */\ntask(\n  'build:site',\n  series('build:site-doc', parallel('site:sitemap', 'site:regen-ngsw-config', 'build:site-issue-helper'))\n);\n\n/** Init site directory, and start watch and ng-serve */\ntask('start:site', series('init:site', parallel('watch:site', 'serve:site')));\n\n/** Task that use publish code to build ng-zorro-antd-doc project,\n * output included issue-helper and prerender.\n */\ntask('build:release-site', series('init:site', 'site:replace-path', 'site:llms-txt', 'build:site'));\n"
  },
  {
    "path": "scripts/gulp/tasks/unit-test.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { task } from 'gulp';\nimport minimist from 'minimist';\n\nimport { execTask } from '../util/task-helpers';\n\ntask('test:watch', done => {\n  const argv = minimist(process.argv.slice(2));\n  let tags = '';\n  if (argv.tags && typeof argv.tags === 'string') {\n    tags = argv.tags;\n  }\n  return execTask('ng', ['test', '--watch=true', '--code-coverage'], {\n    NG_TEST_TAGS: tags\n  })(done);\n});\n"
  },
  {
    "path": "scripts/gulp/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"lib\": [\n      \"es2015\",\n      \"dom\"\n    ],\n    \"module\": \"commonjs\",\n    \"moduleResolution\": \"node\",\n    \"outDir\": \"../../dist\",\n    \"esModuleInterop\": true,\n    \"strictNullChecks\": true,\n    \"strictFunctionTypes\": true,\n    \"noImplicitThis\": true,\n    \"noEmitOnError\": true,\n    \"noImplicitAny\": true,\n    \"target\": \"es5\",\n    \"types\": [\n      \"node\",\n      \"../build/less.d.ts\"\n    ],\n    \"baseUrl\": \".\"\n  },\n  \"files\": [\n    \"gulpfile.ts\"\n  ]\n}\n"
  },
  {
    "path": "scripts/gulp/util/task-helpers.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { deleteSync } from 'del';\nimport { TaskFunction, TaskFunctionCallback } from 'gulp';\n\nimport { spawn } from 'child_process';\nimport { platform } from 'os';\n\nexport function cleanTask(patterns: string | string[]): TaskFunction {\n  return (done: TaskFunctionCallback) => {\n    deleteSync(patterns);\n    done();\n  };\n}\n\nexport function execTask(binPath: string, args: string[], env = {}): TaskFunction {\n  return (done: TaskFunctionCallback) => {\n    // https://github.com/angular/angular-cli/issues/10922\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    (process.stdout as any)._handle.setBlocking(true);\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    (process.stderr as any)._handle.setBlocking(true);\n\n    const bin = platform() === 'win32' && binPath === 'ng' ? `${binPath}.cmd` : binPath;\n    const childProcess = spawn(bin, args, {\n      env: { ...process.env, ...env },\n      cwd: process.cwd(),\n      stdio: 'inherit'\n    });\n\n    childProcess.on('close', (code: number) => {\n      code !== 0 ? done(new Error(`Process failed with code ${code}`)) : done();\n    });\n  };\n}\n"
  },
  {
    "path": "scripts/prerender/minify.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { readFile, writeFile } from 'fs-extra';\nimport { minify as htmlMinifier } from 'html-minifier-terser';\nimport { minify as jsMinifier, MinifyOptions } from 'terser';\n\nconst minifyJsOptions: MinifyOptions = {\n  keep_classnames: true,\n  keep_fnames: true,\n  format: {\n    comments: false\n  }\n};\n\nasync function minifyJs(content: string): Promise<string> {\n  return jsMinifier(content, minifyJsOptions).then(({ code }) => code || '');\n}\n\nasync function minifyHtml(content: string): Promise<string> {\n  return htmlMinifier(content, {\n    collapseBooleanAttributes: true,\n    collapseWhitespace: false,\n    decodeEntities: true,\n    includeAutoGeneratedTags: false,\n    minifyCSS: true,\n    minifyJS: minifyJsOptions,\n    minifyURLs: true,\n    processScripts: ['text/html'],\n    ignoreCustomComments: [],\n    removeComments: false,\n    removeRedundantAttributes: true,\n    removeScriptTypeAttributes: true,\n    removeStyleLinkTypeAttributes: true,\n    trimCustomFragments: true,\n    useShortDoctype: true\n  });\n}\n\nasync function minifyJson(content: string): Promise<string> {\n  let json: Record<string, unknown> = {};\n  try {\n    json = JSON.parse(content);\n    if (json.$schema) {\n      // $schema is only needed for autocompletion\n      delete json.$schema;\n    }\n    return JSON.stringify(json);\n  } catch {\n    return content;\n  }\n}\n\nexport async function minifyFile(filePath: string, type: 'svg' | 'html' | 'json' | 'js' | string): Promise<void> {\n  const content = await readFile(filePath, 'utf8');\n\n  let minified: Promise<string>;\n  switch (type) {\n    case 'svg':\n    case 'html':\n      minified = minifyHtml(content);\n      break;\n    case 'js':\n      minified = minifyJs(content);\n      break;\n    case 'json':\n      minified = minifyJson(content);\n      break;\n    default:\n      throw new Error(`Unknown extension: ${type}`);\n  }\n  const result = await minified;\n  await writeFile(filePath, result);\n}\n"
  },
  {
    "path": "scripts/prerender/ngsw-config.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { readFile, readJSON, writeFile, writeJSON } from 'fs-extra';\nimport { sync as glob } from 'glob';\n\nimport * as child_process from 'child_process';\nimport { resolve } from 'path';\n\nimport { buildConfig } from '../build-config';\nimport { minifyFile } from './minify';\n\ntype Local = 'en' | 'zh';\n\nconst browserOutput = `${buildConfig.outputDir}/browser`;\n\nconst distFiles: Record<string, string[]> = {\n  html: ['index.html', 'docs/**/index.html', 'experimental/**/index.html', 'components/**/index.html'],\n  js: ['ngsw-worker.js', 'worker-basic.min.js', 'safety-worker.js'],\n  json: ['manifest.json']\n};\n\nasync function minifyFiles(): Promise<void> {\n  for (const type of Object.keys(distFiles)) {\n    const paths: string[] = distFiles[type]\n      .map(pattern => glob(pattern, { cwd: browserOutput }))\n      .reduce((a, b) => [...a, ...b], []);\n    for (const contentPath of paths) {\n      await minifyFile(resolve(browserOutput, contentPath), type);\n    }\n  }\n}\n\nasync function runNGSWConfig(): Promise<void> {\n  return new Promise((res, reject) => {\n    const childProcess = child_process.spawn('node_modules/.bin/ngsw-config', ['dist/browser', 'ngsw-config.json'], {\n      env: { ...process.env },\n      cwd: buildConfig.projectDir,\n      stdio: ['pipe', 'ignore', 'ignore']\n    });\n    childProcess.on('close', (code: number) => {\n      code !== 0 ? reject(`Process failed with code ${code}`) : res();\n    });\n  });\n}\n\nasync function setLocalizedIndex(local: Local): Promise<void> {\n  const content = await readFile(resolve(browserOutput, 'docs/introduce', local, 'index.html'));\n  await writeFile(resolve(browserOutput, 'index.html'), content);\n}\n\nasync function saveAsNGSWConfig(local: Local): Promise<void> {\n  const config = await readJSON(resolve(browserOutput, 'ngsw.json'));\n  config.local = local;\n  await writeJSON(resolve(browserOutput, `ngsw.${local}.json`), config);\n}\n\nasync function rewriteConfig(local: Local): Promise<void> {\n  await setLocalizedIndex(local);\n  await runNGSWConfig();\n  await saveAsNGSWConfig(local);\n}\n\nexport const generate = async (): Promise<void> => {\n  await minifyFiles();\n  await rewriteConfig('zh');\n  await rewriteConfig('en');\n};\n"
  },
  {
    "path": "scripts/prerender/sitemap.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { createWriteStream, readFileSync } from 'fs-extra';\nimport { EnumChangefreq, SitemapItemLoose, SitemapStream } from 'sitemap';\n\nimport { resolve } from 'path';\n\nimport { buildConfig } from '../build-config';\n\nconst priorityMap: Record<string, number> = {\n  '/docs/introduce/en': 1,\n  '/docs/getting-started/en': 0.8,\n  '/docs/schematics/en': 0.8,\n  '/docs/i18n/en': 0.8,\n  '/docs/faq/en': 0.8\n};\n\nconst PRERENDERED_ROUTES_PATH = resolve(buildConfig.outputDir, 'prerendered-routes.json');\n\nfunction loadRoutes(): string[] {\n  const raw = readFileSync(PRERENDERED_ROUTES_PATH, 'utf8');\n  const parsed = JSON.parse(raw) as { routes: Record<string, unknown> };\n  return Object.keys(parsed.routes);\n}\n\nfunction generateUrls(lang: 'zh' | 'en'): SitemapItemLoose[] {\n  const routes = loadRoutes();\n  const urls = Array.from(new Set(routes.filter(r => r !== '/').map(r => r.replace(/\\/(zh|en)$/, ''))));\n  return urls.map((r: string) => {\n    const url = `${r}/${lang}`;\n    return {\n      url,\n      changefreq: EnumChangefreq.HOURLY,\n      priority: priorityMap[url] || 0.6,\n      lastmodrealtime: true,\n      lastmodISO: new Date().toISOString(),\n      links: [\n        { lang: 'en', url: `${r}/en` },\n        { lang: 'zh', url: `${r}/zh` },\n        { lang: 'x-default', url: `${r}/en` }\n      ]\n    };\n  });\n}\n\nexport function generateSitemap(): void {\n  const sms = new SitemapStream({ hostname: 'https://ng.ant.design' });\n  sms.pipe(createWriteStream(resolve(`${buildConfig.outputDir}/browser`, 'sitemap.xml')));\n\n  const urls: SitemapItemLoose[] = [\n    {\n      url: '/',\n      changefreq: EnumChangefreq.HOURLY,\n      priority: 1,\n      lastmodrealtime: true,\n      lastmodISO: new Date().toISOString()\n    },\n    ...generateUrls('en'),\n    ...generateUrls('zh')\n  ];\n  urls.forEach(url => sms.write(url));\n  sms.end();\n}\n"
  },
  {
    "path": "scripts/prerender/tsconfig.json",
    "content": "{\n  \"compileOnSave\": false,\n  \"compilerOptions\": {\n    \"outDir\": \"../../dist\",\n    \"sourceMap\": true,\n    \"declaration\": false,\n    \"moduleResolution\": \"node\",\n    \"target\": \"es5\",\n    \"typeRoots\": [\n      \"../../node_modules/@types\"\n    ],\n    \"lib\": [\n      \"es2017\",\n      \"dom\"\n    ]\n  },\n  \"include\": [\n    \"sitemap.ts\"\n  ]\n}\n"
  },
  {
    "path": "scripts/prerender/types.d.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\ndeclare module 'sitemap' {\n  interface Sitemap {\n    toXML(fun: (err: Error, xml: string) => void): void;\n    toString(): string;\n  }\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  export function createSitemap(option: any): Sitemap;\n}\n"
  },
  {
    "path": "scripts/release/git-client.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { spawnSync, SpawnSyncReturns } from 'child_process';\n\nexport class GitClient {\n  constructor(\n    public projectDir: string,\n    public remoteGitUrl: string\n  ) {}\n\n  spawnGitProcess(args: string[], printStderr: boolean = true): SpawnSyncReturns<string> {\n    return spawnSync('git', args, {\n      cwd: this.projectDir,\n      stdio: ['pipe', 'pipe', printStderr ? 'inherit' : 'pipe'],\n      encoding: 'utf8'\n    });\n  }\n\n  clone(): void {\n    this.spawnGitProcess(['clone', this.remoteGitUrl, '.', '--depth=1']);\n  }\n\n  stageAllChanges(): boolean {\n    return this.spawnGitProcess(['add', '-A']).status === 0;\n  }\n\n  createNewCommit(message: string): boolean {\n    return this.spawnGitProcess(['commit', '--no-verify', '-m', message]).status === 0;\n  }\n\n  checkoutNewBranch(branchName: string): boolean {\n    return this.spawnGitProcess(['checkout', '-b', branchName]).status === 0;\n  }\n\n  pushBranchToRemote(branchName: string, force: boolean = false, remoteName: string = this.remoteGitUrl): boolean {\n    return this.spawnGitProcess(['push', remoteName, branchName, `${force && '-f'}`]).status === 0;\n  }\n}\n"
  },
  {
    "path": "scripts/release/parse-version.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport interface Version {\n  major: number;\n  minor: number;\n  patch: number;\n  preTag: string;\n  pre: number;\n}\n\nconst versionNameRegex = /^(\\d+)\\.(\\d+)\\.(\\d+)(?:-(alpha|beta|rc)\\.(\\d+))?$/;\n\nexport function validVersion(version: string): boolean {\n  return versionNameRegex.test(version);\n}\n\nexport function parseVersion(version: string): Version | null {\n  const matches = version.match(versionNameRegex);\n\n  if (!matches) {\n    return null;\n  }\n\n  return {\n    major: Number(matches[1]),\n    minor: Number(matches[2]),\n    patch: Number(matches[3]),\n    preTag: matches[4],\n    pre: Number(matches[5])\n  };\n}\n\nexport function checkVersionNumber(cur: string, next: string): boolean {\n  // Must be numbers and dots.\n  if (!validVersion(next)) {\n    return false;\n  }\n\n  const curVersion = parseVersion(cur);\n  const nextVersion = parseVersion(next);\n\n  if (!nextVersion || !curVersion) {\n    return false;\n  }\n\n  if (curVersion.major !== nextVersion.major) {\n    return curVersion.major < nextVersion.major;\n  }\n\n  if (curVersion.minor !== nextVersion.minor) {\n    return curVersion.minor < nextVersion.minor;\n  }\n\n  if (curVersion.patch !== nextVersion.patch) {\n    return curVersion.patch < nextVersion.patch;\n  }\n\n  if (curVersion.preTag !== nextVersion.preTag) {\n    return true;\n  }\n\n  return curVersion.pre < nextVersion.pre;\n}\n"
  },
  {
    "path": "scripts/release/release-site.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { copySync, emptyDirSync, removeSync } from 'fs-extra';\nimport * as minimatch from 'minimatch';\n\nimport { join } from 'path';\n\nimport { buildConfig } from '../build-config';\nimport { GitClient } from './git-client';\n\nconst docDir = join(buildConfig.projectDir, 'ng-zorro.github.io');\n\nexport function releaseSite(version: string): boolean {\n  emptyDirSync(docDir);\n  const git = new GitClient(docDir, 'https://github.com/NG-ZORRO/ng-zorro.github.io.git');\n  const branchName = `release/${version}`;\n\n  git.clone();\n  git.checkoutNewBranch(branchName);\n  emptyDirSync(docDir);\n\n  copySync(buildConfig.outputDir, docDir, {\n    overwrite: true,\n    filter: file => {\n      const fileGlobs = [\n        '.DS_Store',\n        '.gitignore',\n        'sitemap.js?(.map)',\n        'static.paths.js?(.map)',\n        'prerender.js?(.map)',\n        'server/**/*',\n        '.idea/**/*',\n        '.vscode/**/*',\n        '.git/**/*'\n      ].map(f => join(buildConfig.outputDir, f));\n      return !fileGlobs.some(p => minimatch.minimatch(file, p));\n    }\n  });\n\n  git.stageAllChanges();\n  git.createNewCommit(`release: ${version}`);\n  const pushed = git.pushBranchToRemote(branchName, true);\n  removeSync(docDir);\n  return pushed;\n}\n"
  },
  {
    "path": "scripts/release/release.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { confirm, input, select } from '@inquirer/prompts';\nimport { bgBlue, bgGreen, bgRed, bgYellow, blue, green, red, yellow } from 'chalk';\nimport { readFileSync, readJsonSync, writeFileSync, writeJsonSync } from 'fs-extra';\n\nimport { execSync, spawnSync } from 'child_process';\nimport path from 'path';\n\nimport { buildConfig } from '../build-config';\nimport { checkVersionNumber } from './parse-version';\nimport { releaseSite } from './release-site';\n\nconst handleExitPromptError = (error: Error): void => {\n  if (error.name === 'ExitPromptError') {\n    log.info('Exited, see you next time :)');\n    process.exit(1);\n  }\n};\n\n/* Shortcut methods */\nconst print = console.log;\nconst log = {\n  info: (msg: string) => print(bgBlue.black(' INFO\\t'), blue(msg)),\n  warn: (msg: string) => print(bgYellow.black(' WARN\\t'), yellow(msg)),\n  error: (msg: string) => {\n    print(bgRed.black(' ERROR\\t'), red(msg));\n    process.exit(1);\n  },\n  success: (msg: string) => print(bgGreen.black(' SUCCESS\\t'), green(msg))\n};\n\n/* The whole process */\nrun();\n\nasync function run(): Promise<void> {\n  const stages = [\n    {\n      name: 'Fetch upstream',\n      fun: fetchUpstream\n    },\n    {\n      name: 'Bump version',\n      fun: bumpVersion\n    },\n    {\n      name: 'Update changelog',\n      fun: updateChangelog\n    },\n    {\n      name: 'Build release',\n      fun: buildRelease\n    },\n    {\n      name: 'Push library release',\n      fun: pushLibraryRelease\n    },\n    {\n      name: 'Push site release',\n      fun: pushSiteRelease\n    }\n  ];\n\n  try {\n    let index = await select({\n      message: 'Where do you want to start?',\n      choices: stages.map((stage, index) => ({\n        name: `[${index}] ${stage.name}`,\n        value: index\n      }))\n    });\n    log.info('Starting publishing process...');\n    for (index; index < stages.length; index++) {\n      await stages[index].fun();\n    }\n  } catch (e) {\n    handleExitPromptError(e);\n  }\n}\n\n/** git has uncommitted changes */\nfunction hasUncommittedChanges(): boolean {\n  const output = spawnSync('git', ['diff-index', '--quiet', 'HEAD'], {\n    encoding: 'utf-8'\n  });\n  return output.status !== 0;\n}\n\nfunction getUpstreamRemoteName(): string | null {\n  const output = spawnSync('git', ['remote', 'show'], {\n    encoding: 'utf-8'\n  });\n  const names: string[] = (output.stdout as string).split('\\n').map(e => e.trim());\n  let i = 0;\n  while (i < names.length) {\n    const url = getRemoteUrl(names[i]);\n    if (url.search(/github\\.com(\\/|:)NG-ZORRO\\/ng-zorro-antd/) !== -1) {\n      return names[i];\n    }\n    i++;\n  }\n  return null;\n}\n\nfunction getRemoteUrl(remote: string): string {\n  const output = spawnSync('git', ['remote', 'get-url', remote], {\n    encoding: 'utf-8'\n  });\n\n  return output.stdout.trim();\n}\n\n/**\n * Publisher should input the new version number. This script would check if the input is valid.\n */\nasync function bumpVersion(): Promise<void> {\n  log.info('Updating version number...');\n\n  const packageJsonPath = path.join(buildConfig.componentsDir, 'package.json');\n  const packageJson = readJsonSync(packageJsonPath);\n  const zorroVersionPath = path.join(buildConfig.componentsDir, 'version', 'version.ts');\n  const currentVersion = packageJson.version;\n  let versionNumberValid = false;\n  let version: string;\n\n  while (!versionNumberValid) {\n    version = await input({ message: 'Please input the new version:' });\n    if (checkVersionNumber(currentVersion, version)) {\n      versionNumberValid = true;\n    } else {\n      log.error(\n        `Your input ${version} is not after the current version ${currentVersion} or is invalid. Please check it.`\n      );\n    }\n  }\n\n  writeJsonSync(packageJsonPath, { ...packageJson, version }, { spaces: 2 });\n  writeFileSync(\n    zorroVersionPath,\n    readFileSync(zorroVersionPath, 'utf-8').replace(/Version\\('.+'\\);/g, `Version('${version}');`)\n  );\n  log.success('Version updated!');\n}\n\nfunction fetchUpstream(): void {\n  if (hasUncommittedChanges()) {\n    log.error(\n      'Current working tree has changes which are not committed. ' + 'Please make sure your working tree is clean.'\n    );\n    return;\n  }\n  log.info('Fetching upstream...');\n  const remoteName = getUpstreamRemoteName();\n  if (!remoteName) {\n    log.error(\n      'The valid remote name does not exist. View detail https://help.github.com/en/articles/configuring-a-remote-for-a-fork'\n    );\n    return;\n  }\n  execSync('git checkout master');\n  execSync(`git pull ${remoteName} master -f`);\n  execSync(`git fetch ${remoteName} master --prune --tags`);\n  log.success('Older versions fetched!');\n}\n\nasync function updateChangelog(): Promise<void> {\n  log.info('Generating changelog...');\n  execSync('npm run changelog');\n  log.success('Changelog generated!');\n\n  let completeEditing = false;\n\n  while (!completeEditing) {\n    const result = await confirm({ message: 'Please manually update docs/changelog. Press [Y] if you are done:' });\n    if (result) {\n      completeEditing = true;\n    }\n  }\n\n  log.success('Change log finished!');\n}\n\nfunction buildRelease(): void {\n  log.info('Running pre-release script... Be patient...');\n  execSync('npm run build', { stdio: [0, 1, 2] });\n  log.info('pre-release completed!');\n}\n\nfunction pushLibraryRelease(): void {\n  const releaseVersion = getCurrentVersion();\n  log.info('Checkout and push a new branch for publishing...');\n  execSync(`git checkout -b release/${releaseVersion}`);\n  execSync('git add .');\n  execSync(`git commit -m \"chore(release): release ${releaseVersion}\"`);\n  execSync(`git push origin release/${releaseVersion}`);\n  log.success('Push library release completed!');\n  log.info('Please go to GitHub and make a pull request.');\n}\n\nfunction pushSiteRelease(): void {\n  log.info('Checkout and push a new branch to ng-zorro.github.io...');\n  releaseSite(getCurrentVersion());\n  log.success('Push site release completed!');\n  log.info('Please go to GitHub and make a pull request.');\n}\n\nfunction getCurrentVersion(): string {\n  const packageJsonPath = path.join(buildConfig.componentsDir, 'package.json');\n  const packageJson = readJsonSync(packageJsonPath);\n  return packageJson.version;\n}\n"
  },
  {
    "path": "scripts/release/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"lib\": [\"es2016\"],\n    \"types\": [\"node\"]\n  }\n}"
  },
  {
    "path": "scripts/release-helper.sh",
    "content": "#!/usr/bin/env bash\nrm -rf archive-docs\ngit clone git@github.com:NG-ZORRO/archive-docs.git --branch=master --depth=1\ncp -r archive-docs/issue-helper dist/browser/issue-helper\ncp -r archive-docs/version dist/browser/version\nrm -rf archive-docs"
  },
  {
    "path": "scripts/schematics/copy-resources.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { copySync, outputJsonSync, readJsonSync, removeSync} from 'fs-extra';\n\nimport  path from 'path';\n\n\nimport { buildConfig } from '../build-config';\n\nconst srcPath = path.join(buildConfig.projectDir, `schematics`);\nconst targetPath = path.join(buildConfig.publishDir, `schematics`);\nconst copyFilter = (p: string): boolean => (/files(\\/|\\\\)__path__/.test(p) || !/.+\\.ts/.test(p) || /.template$/.test(p));\n\nfunction mergeDemoCollection(): void {\n  const demoCollectionPath = path.resolve(targetPath, `demo/collection.json`);\n  const targetCollectionPath = path.resolve(targetPath, `collection.json`);\n  const demoCollectionJson = readJsonSync(demoCollectionPath, { throws: false }) || {schematics: {}};\n  const targetCollectionJson = readJsonSync(targetCollectionPath, { throws: false }) || {schematics: {}};\n  targetCollectionJson.schematics = {\n    ...targetCollectionJson.schematics,\n    ...demoCollectionJson.schematics\n    };\n  outputJsonSync(targetCollectionPath, targetCollectionJson);\n  removeSync(demoCollectionPath);\n}\n\nexport function copyResources(): void {\n  copySync(srcPath, targetPath, { filter: copyFilter });\n  mergeDemoCollection();\n}\n"
  },
  {
    "path": "scripts/schematics/demo2schematics.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { copySync, mkdirsSync, readFileSync, readJsonSync, outputFileSync, outputJsonSync, } from 'fs-extra';\nimport { sync as glob } from 'glob';\n\nimport path from 'path';\n\nimport { buildConfig } from '../build-config';\n\ninterface DemoMeta {\n  fileContent: string,\n  componentName: string,\n  demoName: string,\n  template: string,\n  styles: string,\n  selector: string,\n  className: string\n}\n\nconst componentsPath = buildConfig.componentsDir;\nconst demoDirPath = path.join(buildConfig.projectDir, 'schematics/demo');\nconst collectionPath = path.join(demoDirPath, 'collection.json');\n\nconst TEST_FILE_CONTENT =\n  `import { fakeAsync, ComponentFixture, TestBed } from '@angular/core/testing';\nimport { <%= classify(name) %>Component } from './<%= dasherize(name) %>.component';\n\ndescribe('<%= classify(name) %>Component', () => {\n  let component: <%= classify(name) %>Component;\n  let fixture: ComponentFixture<<%= classify(name) %>Component>;\n\n  beforeEach(fakeAsync(() => {\n    TestBed.configureTestingModule({\n      declarations: [ <%= classify(name) %>Component ]\n    })\n    .compileComponents();\n    ;\n\n    fixture = TestBed.createComponent(<%= classify(name) %>Component);\n    component = fixture.componentInstance;\n    fixture.detectChanges();\n  }));\n\n  it('should compile', () => {\n    expect(component).toBeTruthy();\n  });\n});\n`;\n\nfunction getComponentPaths(): string[] {\n  return glob(path.join(componentsPath, '**/demo/*.ts'));\n}\n\nfunction parse(filePath: string): DemoMeta {\n  const fileContent = readFileSync(filePath, 'utf-8');\n  const pathSplit = filePath.split('components/')[1].split('/');\n  const componentName = pathSplit[0] || '';\n  const demoName = (pathSplit[2] && pathSplit[2].split('.')[0]) ? pathSplit[2].split('.')[0] : '';\n  const template = getTemplate(fileContent);\n  const styles = getStyles(fileContent);\n  const selector = getSelector(fileContent);\n  const className = getClassName(fileContent);\n  return {\n    fileContent,\n    componentName,\n    demoName,\n    template,\n    styles,\n    selector,\n    className\n  };\n}\n\nfunction getTemplate(fileContent: string): string {\n  const match = fileContent.match(/template\\s*:\\s*`([\\s\\S]*?)`/);\n  return match ? match[1] || '' : '';\n}\n\nfunction getStyles(fileContent: string): string {\n  const match = fileContent.match(/styles\\s*:\\s*\\[\\s*`([\\s\\S]*?)`\\s*\\]/);\n  return match ? match[1] || '' : '';\n}\n\nfunction getClassName(fileContent: string): string {\n  const match = fileContent.match(/export\\s*class\\s*(.+?)\\s.*/);\n  return match ? match[1] || '' : '';\n}\n\nfunction getSelector(fileContent: string): string {\n  const match = fileContent.match(/selector\\s*:\\s*'(.+?)'\\s*/);\n  return match ? match[1] || '' : '';\n}\n\nfunction replaceTemplate(demoComponent: DemoMeta): string {\n  return demoComponent.fileContent\n    .replace(/selector\\s*:\\s*'(.+?)'\\s*/, () => `selector: '<%= selector %>'`)\n    .replace(new RegExp(demoComponent.className), () => `<%= classify(name) %>Component`)\n    .replace(/styles\\s*:\\s*\\[\\s*`([\\s\\S]*?)`\\s*\\]/, () => `<% if(inlineStyle) { %>styles: [\\`${demoComponent.styles}\\`]<% } else { %>styleUrls: ['./<%= dasherize(name) %>.component.<%= style %>']<% } %>`)\n    .replace(/template\\s*:\\s*`([\\s\\S]*?)`/, () => `<% if(inlineTemplate) { %>template: \\`${demoComponent.template}\\`<% } else { %>templateUrl: './<%= dasherize(name) %>.component.html'<% } %>`);\n}\n\nfunction createSchematic(demoComponent: DemoMeta): void {\n  const demoPath = path.resolve(demoDirPath, `./${demoComponent.componentName}-${demoComponent.demoName}`);\n  const filesPath = path.resolve(__dirname, `${demoPath}/files/__path__/__name@dasherize@if-flat__`);\n  const schemaPath = `${demoPath}/schema.json`;\n  mkdirsSync(filesPath);\n\n  copySync(path.resolve(__dirname, `./template/index.ts.template`), `${demoPath}/index.ts`);\n  copySync(path.resolve(__dirname, `./template/schema.json.template`), `${demoPath}/schema.json`);\n  copySync(path.resolve(__dirname, `./template/schema.ts.template`), `${demoPath}/schema.ts`);\n\n  const schemaJson = readJsonSync(schemaPath);\n  schemaJson.$id = `${demoComponent.demoName}-${demoComponent.componentName}`;\n  schemaJson.title = `NG-ZORRO ${demoComponent.demoName} ${demoComponent.componentName}`;\n  outputJsonSync(schemaPath, schemaJson);\n\n  outputFileSync(`${filesPath}/__name@dasherize__.component.__style__.template`, demoComponent.styles);\n  outputFileSync(`${filesPath}/__name@dasherize__.component.html.template`, demoComponent.template);\n  outputFileSync(`${filesPath}/__name@dasherize__.component.spec.ts.template`, TEST_FILE_CONTENT);\n  outputFileSync(`${filesPath}/__name@dasherize__.component.ts.template`, replaceTemplate(demoComponent));\n\n  const collectionJson = readJsonSync(collectionPath, { throws: false }) || { schematics: {} };\n  collectionJson.schematics = {\n    ...collectionJson.schematics,\n    [`${demoComponent.componentName}-${demoComponent.demoName}`]: {\n      description: schemaJson.title,\n      factory: `./demo/${demoComponent.componentName}-${demoComponent.demoName}`,\n      schema: `./demo/${demoComponent.componentName}-${demoComponent.demoName}/schema.json`\n    }\n  };\n  outputJsonSync(collectionPath, collectionJson, { spaces: '  ' });\n}\n\nexport function generate(): void {\n  const componentPath = getComponentPaths();\n  componentPath.forEach(p => {\n    try {\n      createSchematic(parse(p));\n    } catch (e) {\n      console.error(`error ${p}`);\n      console.error(e);\n    }\n  });\n}\n"
  },
  {
    "path": "scripts/schematics/set-version.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { outputFileSync } from 'fs-extra';\n\nimport path from 'path';\n\nimport { buildConfig } from '../build-config';\n\nexport function setVersion(): void {\n  outputFileSync(\n    path.join(buildConfig.projectDir, `schematics/utils/version-names.ts`),\n    `\nexport const zorroVersion = '^${buildConfig.projectVersion}';\nexport const hammerjsVersion = '^2.0.8';\n`);\n}\n"
  },
  {
    "path": "scripts/schematics/template/index.ts.template",
    "content": "import {\n  chain,\n  Rule\n} from '@angular-devkit/schematics';\nimport { buildComponent } from '../../utils/build-component';\n\nimport { Schema } from './schema';\n\nexport default function(options: Schema): Rule {\n  return chain([\n    buildComponent(\n      { ...options },\n      {\n        template: './__path__/__name@dasherize@if-flat__/__name@dasherize__.component.html.template',\n        stylesheet: './__path__/__name@dasherize@if-flat__/__name@dasherize__.component.__style__.template'\n      }\n    )\n  ]);\n}\n"
  },
  {
    "path": "scripts/schematics/template/schema.json.template",
    "content": "{\n  \"$schema\": \"http://json-schema.org/schema\",\n  \"$id\": \"PLACEHOLDER_SCHEMATICS_ID\",\n  \"title\": \"PLACEHOLDER_SCHEMATICS_TITLE\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"path\": {\n      \"type\": \"string\",\n      \"format\": \"path\",\n      \"description\": \"The path to create the component.\",\n      \"visible\": false\n    },\n    \"project\": {\n      \"type\": \"string\",\n      \"description\": \"The name of the project.\",\n      \"$default\": {\n        \"$source\": \"projectName\"\n      }\n    },\n    \"name\": {\n      \"type\": \"string\",\n      \"description\": \"The name of the component.\",\n      \"$default\": {\n        \"$source\": \"argv\",\n        \"index\": 0\n      },\n      \"x-prompt\": \"What should be the name of the component?\"\n    },\n    \"inlineStyle\": {\n      \"description\": \"When true, includes styles inline in the component.ts file. Only CSS styles can be included inline. By default, an external styles file is created and referenced in the component.ts file.\",\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"alias\": \"s\"\n    },\n    \"inlineTemplate\": {\n      \"description\": \"When true, includes template inline in the component.ts file. By default, an external template file is created and referenced in the component.ts file.\",\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"alias\": \"t\"\n    },\n    \"standalone\": {\n      \"description\": \"Whether the generated component is standalone.\",\n      \"type\": \"boolean\"\n    },\n    \"prefix\": {\n      \"type\": \"string\",\n      \"description\": \"The prefix to apply to the generated component selector.\",\n      \"alias\": \"p\",\n      \"oneOf\": [\n        {\n          \"maxLength\": 0\n        },\n        {\n          \"minLength\": 1,\n          \"format\": \"html-selector\"\n        }\n      ]\n    },\n    \"styleext\": {\n      \"description\": \"The file extension to use for style files.\",\n      \"type\": \"string\",\n      \"default\": \"css\",\n      \"x-deprecated\": \"Use \\\"style\\\" instead.\"\n    },\n    \"style\": {\n      \"description\": \"The file extension or preprocessor to use for style files.\",\n      \"type\": \"string\",\n      \"default\": \"css\",\n      \"enum\": [\n        \"css\",\n        \"scss\",\n        \"sass\",\n        \"less\",\n        \"styl\"\n      ]\n    },\n    \"spec\": {\n      \"type\": \"boolean\",\n      \"description\": \"When true (the default), generates a  \\\"spec.ts\\\" test file for the new component.\",\n      \"default\": true,\n      \"x-deprecated\": \"Use \\\"skipTests\\\" instead.\"\n    },\n    \"skipTests\": {\n      \"type\": \"boolean\",\n      \"description\": \"When true, does not create \\\"spec.ts\\\" test files for the new component.\"\n    },\n    \"flat\": {\n      \"type\": \"boolean\",\n      \"description\": \"Flag to indicate if a dir is created.\",\n      \"default\": false\n    },\n    \"skipImport\": {\n      \"type\": \"boolean\",\n      \"description\": \"When true, does not import this component into the owning NgModule.\"\n    },\n    \"selector\": {\n      \"type\": \"string\",\n      \"format\": \"html-selector\",\n      \"description\": \"The selector to use for the component.\"\n    },\n    \"module\": {\n      \"type\": \"string\",\n      \"description\": \"Allows specification of the declaring module.\",\n      \"alias\": \"m\"\n    },\n    \"export\": {\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"description\": \"When true, the declaring NgModule exports this component.\"\n    },\n    \"entryComponent\": {\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"description\": \"When true, the new component is the entry component of the declaring NgModule.\"\n    },\n    \"classnameWithModule\": {\n      \"type\": \"boolean\",\n      \"description\": \"When true, Use module class name as additional prefix for the component classname.\",\n      \"default\": false\n    }\n  },\n  \"required\": [\n    \"name\"\n  ]\n}\n"
  },
  {
    "path": "scripts/schematics/template/schema.ts.template",
    "content": "import { ZorroComponentOptions } from '../../utils/build-component';\n\nexport interface Schema extends ZorroComponentOptions {\n  [key: string]: string | boolean;\n}\n"
  },
  {
    "path": "scripts/site/doc/404.html",
    "content": "<!DOCTYPE html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\">\n    <title>NG-ZORRO - Ant Design Of Angular</title>\n\t\t<script type=\"text/javascript\">\n      // Single Page Apps for GitHub Pages\n      // https://github.com/rafrex/spa-github-pages\n      // Copyright (c) 2016 Rafael Pedicini, licensed under the MIT License\n      // ----------------------------------------------------------------------\n      // This script takes the current url and converts the path and query\n      // string into just a query string, and then redirects the browser\n      // to the new url with only a query string and hash fragment,\n      // e.g. http://www.foo.tld/one/two?a=b&c=d#qwe, becomes\n      // http://www.foo.tld/?p=/one/two&q=a=b~and~c=d#qwe\n      // Note: this 404.html file must be at least 512 bytes for it to work\n      // with Internet Explorer (it is currently > 512 bytes)\n\n      // If you're creating a Project Pages site and NOT using a custom domain,\n      // then set segmentCount to 1 (enterprise users may need to set it to > 1).\n      // This way the code will only replace the route part of the path, and not\n      // the real directory in which the app resides, for example:\n      // https://username.github.io/repo-name/one/two?a=b&c=d#qwe becomes\n      // https://username.github.io/repo-name/?p=/one/two&q=a=b~and~c=d#qwe\n      // Otherwise, leave segmentCount as 0.\n      var segmentCount = 0;\n\n      var l = window.location;\n      l.replace(\n        l.protocol + '//' + l.hostname + (l.port ? ':' + l.port : '') +\n        l.pathname.split('/').slice(0, 1 + segmentCount).join('/') + '/?p=/' +\n        l.pathname.slice(1).split('/').slice(segmentCount).join('/').replace(/&/g, '~and~') +\n        (l.search ? '&q=' + l.search.slice(1).replace(/&/g, '~and~') : '') +\n        l.hash\n      );\n\n\t\t</script>\n\t</head>\n\t<body>\n\t</body>\n</html>\n"
  },
  {
    "path": "scripts/site/doc/app/app.component.html",
    "content": "<app-nav-progress-bar />\n\n<div id=\"ng-content\" [style.transform]=\"isDrawerOpen ? 'translateX(245px)' : null\">\n  <div class=\"page-wrapper\" [class.page-wrapper-rtl]=\"dir() === 'rtl'\" [dir]=\"dir()\">\n    <app-header />\n    <div class=\"main-wrapper\">\n      <div nz-row>\n        @if (!app.isMobile()) {\n          <div nz-col [nzXs]=\"24\" [nzSm]=\"24\" [nzMd]=\"6\" [nzLg]=\"6\" [nzXl]=\"5\" [nzXXl]=\"4\" class=\"main-menu\">\n            <nz-affix [nzOffsetTop]=\"0\">\n              <section class=\"main-menu-inner\">\n                <ng-template [ngTemplateOutlet]=\"sideOrDrawerTpl\"></ng-template>\n              </section>\n            </nz-affix>\n          </div>\n        }\n        <div\n          nz-col\n          class=\"main-container main-container-component\"\n          [nzXs]=\"24\"\n          [nzSm]=\"24\"\n          [nzMd]=\"18\"\n          [nzLg]=\"18\"\n          [nzXl]=\"19\"\n          [nzXXl]=\"20\"\n        >\n          <router-outlet />\n          <app-contributors-list />\n        </div>\n      </div>\n      <div nz-row>\n        <div\n          nz-col\n          [nzXs]=\"{ span: 24 }\"\n          [nzSm]=\"{ span: 24 }\"\n          [nzMd]=\"{ span: 24 }\"\n          [nzLg]=\"{ span: 18, offset: 6 }\"\n          [nzXl]=\"{ span: 19, offset: 5 }\"\n          [nzXXl]=\"{ span: 20, offset: 4 }\"\n        >\n          <app-fixed-widgets (themeChange)=\"onThemeChange($event)\" />\n          <app-nav-bottom />\n          <app-footer [colorHex]=\"color\" (colorChange)=\"changeColor($event)\" />\n        </div>\n      </div>\n    </div>\n  </div>\n</div>\n\n@if (app.isMobile()) {\n  <div class=\"drawer-wrapper\">\n    <div class=\"drawer drawer-left\" [class.drawer-open]=\"isDrawerOpen\">\n      <div class=\"drawer-mask\" (click)=\"isDrawerOpen = false\"></div>\n      <div class=\"drawer-content-wrapper\" [style.transform]=\"isDrawerOpen ? null : 'translateX(-100%)'\">\n        <div class=\"drawer-content\">\n          <ng-container [ngTemplateOutlet]=\"sideOrDrawerTpl\"></ng-container>\n        </div>\n        <div class=\"drawer-handle\" (click)=\"isDrawerOpen = !isDrawerOpen\">\n          <span class=\"drawer-handle-icon\"></span>\n        </div>\n      </div>\n    </div>\n  </div>\n}\n\n<ng-template #sideOrDrawerTpl>\n  <app-side />\n</ng-template>\n"
  },
  {
    "path": "scripts/site/doc/app/app.component.ts",
    "content": "import { BidiModule } from '@angular/cdk/bidi';\nimport { Platform } from '@angular/cdk/platform';\nimport { DOCUMENT, NgTemplateOutlet } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, computed, effect, inject, OnInit, Renderer2 } from '@angular/core';\nimport { Meta, Title } from '@angular/platform-browser';\nimport { NavigationEnd, Router, RouterOutlet } from '@angular/router';\nimport { debounceTime, filter, startWith } from 'rxjs/operators';\n\nimport { NzAffixModule } from 'ng-zorro-antd/affix';\nimport { NzBadgeModule } from 'ng-zorro-antd/badge';\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzColor } from 'ng-zorro-antd/color-picker';\nimport { NzConfigService } from 'ng-zorro-antd/core/config';\nimport { fromEventOutsideAngular } from 'ng-zorro-antd/core/util';\nimport { NzGridModule } from 'ng-zorro-antd/grid';\nimport { en_US, NzI18nService, zh_CN } from 'ng-zorro-antd/i18n';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\nimport { NzMessageRef, NzMessageService } from 'ng-zorro-antd/message';\nimport { NzPopoverModule } from 'ng-zorro-antd/popover';\nimport { NzSelectModule } from 'ng-zorro-antd/select';\n\nimport { AppService, SiteTheme } from './app.service';\nimport { APP_LANGUAGE, APP_PAGE } from './app.token';\nimport { ContributorsListComponent } from './contributors-list/contributors-list.component';\nimport { FixedWidgetsComponent } from './fixed-widgets/fixed-widgets.component';\nimport { FooterComponent } from './footer/footer.component';\nimport { HeaderComponent } from './header/header.component';\nimport { NavBottomComponent } from './nav-bottom/nav-bottom.component';\nimport { NavProgressBar } from './nav-progress-bar/nav-progress-bar.component';\nimport { ROUTER_LIST } from './router';\nimport { SideComponent } from './side/side.component';\n\ninterface DocPageMeta {\n  path: string;\n  label: string;\n  order?: number;\n  zh: string;\n  description: string;\n}\n\nconst defaultKeywords =\n  'angular, ant design, ant, angular ant design, web, ui, components, ng, zorro, responsive, typescript, css, mobile web, open source, 组件库, 组件, UI 框架';\n\n@Component({\n  selector: 'app-root',\n  imports: [\n    BidiModule,\n    NgTemplateOutlet,\n    RouterOutlet,\n    NzGridModule,\n    NzAffixModule,\n    NzMenuModule,\n    NzIconModule,\n    NzSelectModule,\n    NzPopoverModule,\n    NzButtonModule,\n    NzInputModule,\n    NzBadgeModule,\n    NavBottomComponent,\n    ContributorsListComponent,\n    HeaderComponent,\n    FooterComponent,\n    SideComponent,\n    FixedWidgetsComponent,\n    NavProgressBar\n  ],\n  templateUrl: './app.component.html',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    '[dir]': 'dir()'\n  },\n})\nexport class AppComponent implements OnInit {\n  private readonly page = inject(APP_PAGE);\n  protected readonly language = inject(APP_LANGUAGE);\n  protected readonly app = inject(AppService);\n  private readonly router = inject(Router);\n  private readonly title = inject(Title);\n  private readonly nzI18nService = inject(NzI18nService);\n  private readonly nzMessageService = inject(NzMessageService);\n  private readonly nzConfigService = inject(NzConfigService);\n  private readonly platform = inject(Platform);\n  private readonly meta = inject(Meta);\n  private readonly renderer = inject(Renderer2);\n  private readonly document = inject(DOCUMENT);\n  protected readonly dir = this.app.directionality.valueSignal.asReadonly();\n\n  isDrawerOpen = false;\n  routerList = ROUTER_LIST;\n  componentList: DocPageMeta[] = [];\n  searchComponent = null;\n  color = `#1890ff`;\n\n  readonly isEn = computed(() => this.language() === 'en')\n\n  constructor() {\n    effect(() => {\n      const language = this.language();\n      const languageFromURL = this.getLanguageFromURL(this.router.url);\n      if (languageFromURL && languageFromURL !== language) {\n        this.switchLanguage(this.language());\n      }\n    });\n  }\n\n  switchLanguage(language: string): void {\n    const url = this.router.url.split('/');\n    url.splice(-1);\n    this.router.navigateByUrl(`${url.join('/')}/${language}`).then();\n  }\n\n  initTheme(): void {\n    const theme = (localStorage.getItem('site-theme') as SiteTheme) || 'default';\n    this.onThemeChange(theme, false);\n  }\n\n  onThemeChange(theme: SiteTheme, notification: boolean = true): void {\n    if (!this.platform.isBrowser) {\n      return;\n    }\n    let loading: NzMessageRef | null = null;\n    if (notification) {\n      loading = this.nzMessageService.loading(this.isEn() ? `Switching theme...` : `切换主题中...`, {\n        nzDuration: 0\n      });\n    }\n    this.renderer.addClass(this.document.activeElement, 'preload');\n    const successLoaded = () => {\n      this.app.theme.set(theme);\n      localStorage.setItem('site-theme', theme);\n      this.renderer.setAttribute(document.body, 'data-theme', theme);\n      // remove previous theme\n      ['dark', 'compact', 'aliyun']\n        .filter(item => item !== theme)\n        .forEach(item => {\n          const dom = document.getElementById(`site-theme-${item}`);\n          dom?.remove();\n        });\n      setTimeout(() => this.renderer.removeClass(this.document.activeElement, 'preload'));\n      if (notification) {\n        this.nzMessageService.remove(loading?.messageId);\n        this.nzMessageService.success(this.isEn() ? `Switching theme successfully` : `切换主题成功`);\n      }\n    };\n    if (theme !== 'default') {\n      const style = document.createElement('link');\n      style.type = 'text/css';\n      style.rel = 'stylesheet';\n      style.id = `site-theme-${theme}`;\n      style.href = `assets/${theme}.css`;\n      document.head.append(style);\n\n      style.onload = () => {\n        successLoaded();\n      };\n      style.onerror = () => {\n        this.nzMessageService.remove(loading?.messageId);\n        this.nzMessageService.error(this.isEn() ? `Switching theme failed` : `切换主题失败`);\n        document.getElementById(style.id)?.remove();\n      };\n    } else {\n      successLoaded();\n    }\n  }\n\n  setPage(url: string): void {\n    const match = url.match(/\\/(\\w+)/);\n    if (match && match[1]) {\n      this.page.set(match[1]);\n    }\n  }\n\n  private getLanguageFromURL(url: string): 'en' | 'zh' | null {\n    const language = url.split('/')[url.split('/').length - 1].split('#')[0].split('?')[0];\n    if (['zh', 'en'].indexOf(language) !== -1) {\n      return language as 'en' | 'zh';\n    }\n    return null;\n  }\n\n  ngOnInit(): void {\n    if (this.platform.isBrowser) {\n      this.renderer.removeClass(this.document.activeElement, 'preload');\n      this.addWindowWidthListener();\n      this.initTheme();\n      this.detectLanguage();\n    }\n\n    this.routerList.components.forEach(group => {\n      this.componentList = this.componentList.concat([...group.children]);\n    });\n\n    this.router.events.pipe(filter(e => e instanceof NavigationEnd)).subscribe(() => {\n      this.language.set(this.getLanguageFromURL(this.router.url)!);\n\n      this.nzI18nService.setLocale(this.isEn() ? en_US : zh_CN);\n      const currentDemoComponent = this.componentList.find(component =>\n        // url may contains hash\n        this.router.url.startsWith(`/${component.path}`)\n      );\n\n      if (currentDemoComponent) {\n        const path = currentDemoComponent.path.replace(/\\/(en|zh)/, '');\n        if (this.isEn()) {\n          this.updateMetaTitle(`${currentDemoComponent.label} | NG-ZORRO`);\n        } else {\n          this.updateMetaTitle(`${currentDemoComponent.zh}(${currentDemoComponent.label}) | NG-ZORRO`);\n        }\n        this.updateDocMetaAndLocale(\n          currentDemoComponent.description,\n          `${currentDemoComponent.label}, ${currentDemoComponent.zh}`,\n          path\n        );\n      }\n\n      const currentIntroComponent = this.routerList.intro.find(component => `/${component.path}` === this.router.url);\n      if (currentIntroComponent) {\n        const path = currentIntroComponent.path.replace(/\\/(en|zh)/, '');\n        if (/docs\\/introduce/.test(this.router.url)) {\n          if (this.isEn()) {\n            this.updateMetaTitle(`NG-ZORRO - Angular UI component library`);\n          } else {\n            this.updateMetaTitle(`NG-ZORRO - 企业级 UI 设计语言和 Angular 组件库`);\n          }\n        } else {\n          this.updateMetaTitle(`${currentIntroComponent.label} | NG-ZORRO`);\n        }\n        this.updateDocMetaAndLocale(currentIntroComponent.description, currentIntroComponent.label, path);\n      }\n\n      if (!currentIntroComponent && !currentDemoComponent) {\n        if (/components\\/overview/.test(this.router.url)) {\n          if (this.isEn()) {\n            this.updateMetaTitle('Components | NG-ZORRO');\n            this.updateDocMetaAndLocale(\n              'NG-ZORRO provides plenty of UI components to enrich your web applications, and we will improve components experience consistently.',\n              'overview',\n              'components/overview'\n            );\n          } else {\n            this.updateMetaTitle('组件(Components) | NG-ZORRO');\n            this.updateDocMetaAndLocale(\n              'NG-ZORRO 为 Web 应用提供了丰富的基础 UI 组件，我们还将持续探索企业级应用的最佳 UI 实践。',\n              'overview, 预览',\n              'components/overview'\n            );\n          }\n        } else {\n          this.updateMetaTitle(`NG-ZORRO - Angular UI component library`);\n          this.updateDocMetaAndLocale();\n        }\n      }\n\n      if (this.router.url !== '/' + this.searchComponent) {\n        this.searchComponent = null;\n      }\n      this.setPage(this.router.url);\n\n      if (this.platform.isBrowser) {\n        window.scrollTo(0, 0);\n\n        setTimeout(() => {\n          const toc = this.router.parseUrl(this.router.url).fragment || '';\n          if (toc) {\n            document.getElementById(toc)?.scrollIntoView();\n          }\n        }, 200);\n      }\n    });\n  }\n\n  updateMetaTitle(title: string = 'NG-ZORRO | Angular UI component library'): void {\n    this.title.setTitle(title);\n    this.meta.updateTag({\n      property: 'og:title',\n      content: title\n    });\n    this.meta.updateTag({\n      name: 'twitter:title',\n      content: title\n    });\n  }\n\n  updateDocMetaAndLocale(description?: string, keywords?: string, path?: string): void {\n    const enDescription =\n      'An enterprise-class UI design language and Angular-based implementation with a set of high-quality Angular components, one of best Angular UI library for enterprises';\n    const zhDescription =\n      'Ant Design 的 Angular 实现，开发和服务于企业级后台产品，开箱即用的高质量 Angular UI 组件库。';\n    const descriptionContent = description ?? (this.isEn() ? enDescription : zhDescription);\n\n    if (path) {\n      this.addHreflang(path);\n    }\n\n    this.meta.updateTag({\n      name: 'keywords',\n      content: keywords ? `${defaultKeywords}, ${keywords}` : defaultKeywords\n    });\n    this.meta.updateTag({\n      name: 'description',\n      content: descriptionContent\n    });\n    this.meta.updateTag({\n      name: 'twitter:description',\n      content: descriptionContent\n    });\n    this.meta.updateTag({\n      property: 'og:description',\n      content: descriptionContent\n    });\n    this.meta.updateTag({\n      property: 'og:locale',\n      content: this.isEn() ? 'en_US' : 'zh_CN'\n    });\n    this.renderer.setAttribute(this.document.documentElement, 'lang', this.isEn() ? 'en' : 'zh-Hans');\n  }\n\n  private addHreflang(href: string): void {\n    if (!this.platform.isBrowser) {\n      const hreflangs = [\n        {\n          hreflang: 'en',\n          suffix: 'en'\n        },\n        {\n          hreflang: 'x-default',\n          suffix: 'en'\n        },\n        {\n          hreflang: 'zh',\n          suffix: 'zh'\n        }\n      ];\n      hreflangs.forEach(hreflang => {\n        const link = this.renderer.createElement('link');\n        this.renderer.setAttribute(link, 'rel', 'alternate');\n        this.renderer.setAttribute(link, 'hreflang', hreflang.hreflang);\n        this.renderer.setAttribute(link, 'href', `https://ng.ant.design/${href}/${hreflang.suffix}`);\n        this.renderer.appendChild(this.document.head, link);\n      });\n    }\n  }\n\n  changeColor(res: { color: NzColor; format: string }): void {\n    if (!this.platform.isBrowser) {\n      return;\n    }\n\n    this.nzConfigService.set('theme', { primaryColor: res.color.toHexString() });\n  }\n\n  // endregion\n  private addWindowWidthListener(): void {\n    fromEventOutsideAngular(window, 'resize')\n      .pipe(startWith(true), debounceTime(50))\n      .subscribe(() => this.app.windowWidth.set(window.innerWidth));\n  }\n\n  private detectLanguage(): void {\n    const language = navigator.language.toLowerCase();\n    const pathname = location.pathname;\n    const hasLanguage = pathname.match(/(en|zh)(\\/?)$/);\n    if (language === 'zh-cn' && !hasLanguage) {\n      this.nzI18nService.setLocale(zh_CN);\n      // redirect to default page\n      this.router.navigate(['docs', 'introduce', 'zh']).then();\n    }\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/app/app.config.server.ts",
    "content": "import { provideServerRendering } from '@angular/ssr';\nimport { registerLocaleData } from '@angular/common';\nimport en from '@angular/common/locales/en';\nimport zh from '@angular/common/locales/zh';\nimport { ApplicationConfig, mergeApplicationConfig } from '@angular/core';\n\nimport { appConfig } from './app.config';\n\nregisterLocaleData(zh, 'zh-cn');\nregisterLocaleData(en);\n\nconst serverConfig: ApplicationConfig = {\n  providers: [provideServerRendering()]\n};\n\nexport const config = mergeApplicationConfig(appConfig, serverConfig);\n"
  },
  {
    "path": "scripts/site/doc/app/app.config.ts",
    "content": "import { provideHttpClient, withFetch, withJsonpSupport } from '@angular/common/http';\nimport { ApplicationConfig } from '@angular/core';\nimport { provideClientHydration } from '@angular/platform-browser';\nimport { provideRouter, withInMemoryScrolling } from '@angular/router';\nimport { provideServiceWorker } from '@angular/service-worker';\n\nimport { IconDefinition } from '@ant-design/icons-angular';\nimport * as AllIcons from '@ant-design/icons-angular/icons';\nimport { NzConfig, provideNzConfig } from 'ng-zorro-antd/core/config';\nimport { provideNzIcons } from 'ng-zorro-antd/icon';\n\nimport { environment } from '../environments/environment';\nimport { routes } from './app.routes';\n\nconst antDesignIcons = AllIcons as Record<string, IconDefinition>;\nconst icons: IconDefinition[] = Object.keys(antDesignIcons).map(key => antDesignIcons[key]);\n\nconst nzConfig: NzConfig = {\n  codeEditor: {\n    monacoEnvironment: { globalAPI: true }\n  },\n  icon: { nzTwotoneColor: '#1890ff' }\n};\n\nexport const appConfig: ApplicationConfig = {\n  providers: [\n    provideNzConfig(nzConfig),\n    provideNzIcons(icons),\n    provideRouter(\n      routes,\n      withInMemoryScrolling({ scrollPositionRestoration: environment.production ? 'enabled' : 'disabled' })\n    ),\n    provideClientHydration(),\n    provideHttpClient(withJsonpSupport(), withFetch()),\n    provideServiceWorker('ngsw-worker.js', { enabled: environment.production }),\n  ]\n};\n"
  },
  {
    "path": "scripts/site/doc/app/app.routes.ts",
    "content": "import { Routes } from '@angular/router';\n\nimport { DEMO_ROUTES } from './router';\n\nexport const routes: Routes = [\n  { path: '', pathMatch: 'full', redirectTo: '/docs/introduce/en' },\n  ...DEMO_ROUTES,\n  { path: 'docs', loadChildren: () => import('./docs/routes') },\n  {\n    path: 'components/overview',\n    loadChildren: () => import('./components-overview/routes')\n  },\n  {\n    path: 'components/changelog/en',\n    loadComponent: () => import('./docs/changelog-en')\n  },\n  {\n    path: 'components/changelog/zh',\n    loadComponent: () => import('./docs/changelog-zh')\n  },\n  { path: '**', redirectTo: '/docs/introduce/en', pathMatch: 'full' }\n];\n"
  },
  {
    "path": "scripts/site/doc/app/app.service.ts",
    "content": "import { HttpClient } from '@angular/common/http';\nimport { computed, inject, Injectable, signal } from '@angular/core';\nimport { Observable, of, ReplaySubject } from 'rxjs';\nimport { tap } from 'rxjs/operators';\nimport { Directionality } from '@angular/cdk/bidi';\n\nexport interface DemoCode {\n  rawCode: string;\n  highlightCode: string;\n}\n\nexport const RESPONSIVE_XXS = 768;\nexport const RESPONSIVE_XS = 1120;\nexport const RESPONSIVE_SM = 1200;\n\nexport type SiteTheme = 'default' | 'dark' | 'compact' | 'aliyun';\n\n@Injectable({\n  providedIn: 'root'\n})\nexport class AppService {\n  private readonly http = inject(HttpClient);\n  private readonly codeMap = new Map<string, DemoCode>();\n\n  readonly directionality = inject(Directionality);\n  readonly theme = signal<SiteTheme>('default');\n  readonly windowWidth = signal(1400);\n  /**\n   * When the screen size is smaller than 768 pixel, show the drawer and hide\n   * the navigation on the side.\n   **/\n  readonly isMobile = computed(() => this.windowWidth() <= RESPONSIVE_XXS);\n  readonly responsive = computed(() => {\n    if (this.windowWidth() < RESPONSIVE_XS) {\n      return 'crowded';\n    } else if (this.windowWidth() < RESPONSIVE_SM) {\n      return 'narrow';\n    }\n    return null;\n  });\n\n  getCode(componentId: string): Observable<DemoCode> {\n    if (this.codeMap.has(componentId)) {\n      return of(this.codeMap.get(componentId)!);\n    }\n\n    const path = componentId.startsWith('components-') ? componentId.split('components-')[1] : componentId;\n    return this.http\n      .get<DemoCode>(`assets/codes/${path}.json`, { responseType: 'json' })\n      .pipe(tap(data => this.codeMap.set(componentId, data)));\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/app/app.token.ts",
    "content": "import { InjectionToken, signal, WritableSignal } from '@angular/core';\n\nexport const APP_PAGE = new InjectionToken<WritableSignal<'docs' | 'components' | 'experimental' | string>>(\n  'app-page',\n  {\n    providedIn: 'root',\n    factory: () => signal('docs')\n  }\n);\n\nexport const APP_LANGUAGE = new InjectionToken<WritableSignal<'zh' | 'en'>>('app-language', {\n  providedIn: 'root',\n  factory: () => signal('en')\n});\n"
  },
  {
    "path": "scripts/site/doc/app/codebox/codebox.component.html",
    "content": "<section class=\"code-box\" [class.expand]=\"expanded()\" [attr.id]=\"nzId\">\n  <section class=\"code-box-demo\">\n    @if (!nzIframe || !iframe) {\n      @let simulateIframe = nzIframe && !iframe;\n      <div\n        [class.simulate-iframe]=\"simulateIframe\"\n        [class.browser-mockup]=\"simulateIframe\"\n        [class.with-url]=\"simulateIframe\"\n      >\n        <div [style.height.px]=\"simulateIframe && nzIframeHeight\">\n          <ng-content select=\"[demo]\"></ng-content>\n        </div>\n      </div>\n    } @else {\n      <div class=\"browser-mockup with-url\">\n        <iframe [src]=\"iframe\" [height]=\"nzIframeHeight\" title=\"demo\"></iframe>\n      </div>\n    }\n  </section>\n  <section class=\"code-box-meta markdown\">\n    <div class=\"code-box-title\">\n      <a (click)=\"navigateToFragment()\">{{ nzTitle }}</a>\n      <a class=\"edit-button\" [attr.href]=\"nzHref\" target=\"_blank\" rel=\"noopener noreferrer\">\n        <nz-icon nzType=\"edit\" />\n      </a>\n    </div>\n    <div class=\"code-box-description\">\n      <ng-content select=\"[intro]\"></ng-content>\n    </div>\n    <div class=\"code-box-actions\">\n      <nz-icon\n        nz-tooltip\n        [nzTooltipTitle]=\"\n          !onlineIDELoading()\n            ? language() === 'zh'\n              ? '在 StackBlitz 上打开'\n              : 'Edit On StackBlitz'\n            : language() === 'zh'\n              ? '加载中...'\n              : 'Loading...'\n        \"\n        nzType=\"thunderbolt\"\n        (click)=\"openOnlineIDE()\"\n      />\n      <nz-icon\n        nz-tooltip\n        [nzTooltipTitle]=\"\n          !codeLoading()\n            ? language() === 'zh'\n              ? '复制代码'\n              : 'Copy Code'\n            : language() === 'zh'\n              ? '加载中...'\n              : 'Loading...'\n        \"\n        [nzType]=\"copied() ? 'check' : 'snippets'\"\n        [class.ant-tooltip-open]=\"copied()\"\n        (click)=\"copyCode()\"\n      />\n      @if (nzGenerateCommand) {\n        <nz-icon\n          nz-tooltip\n          [nzTooltipTitle]=\"language() === 'zh' ? '复制生成代码命令' : 'Copy Generate Command'\"\n          [nzType]=\"commandCopied() ? 'check' : 'code'\"\n          [class.ant-tooltip-open]=\"commandCopied()\"\n          (click)=\"copyGenerateCommand(nzGenerateCommand)\"\n        />\n      }\n      <span\n        nz-tooltip\n        [nzTooltipTitle]=\"\n          expanded() ? (language() === 'zh' ? '收起代码' : 'Hide Code') : language() === 'zh' ? '显示代码' : 'Show Code'\n        \"\n        (click)=\"expandCode(!expanded())\"\n      >\n        <nz-icon [class.code-expand-icon-show]=\"expanded()\" [class.code-expand-icon-hide]=\"!expanded()\">\n          <svg viewBox=\"0 0 1024 1024\" fill=\"currentColor\">\n            <path\n              d=\"M1018.645 531.298c8.635-18.61 4.601-41.42-11.442-55.864l-205.108-184.68c-19.7-17.739-50.05-16.148-67.789 3.552-17.738 19.7-16.148 50.051 3.553 67.79l166.28 149.718-167.28 150.62c-19.7 17.738-21.291 48.088-3.553 67.789 17.739 19.7 48.089 21.291 67.79 3.553l205.107-184.68a47.805 47.805 0 0 0 12.442-17.798zM119.947 511.39l166.28-149.719c19.7-17.738 21.29-48.088 3.552-67.789-17.738-19.7-48.088-21.291-67.789-3.553L16.882 475.01C.84 489.456-3.194 512.264 5.44 530.874a47.805 47.805 0 0 0 12.442 17.798l205.108 184.68c19.7 17.739 50.05 16.148 67.79-3.552 17.738-19.7 16.147-50.051-3.553-67.79l-167.28-150.62z\"\n              fill-rule=\"evenodd\"\n              opacity=\"0.78\"\n            ></path>\n          </svg>\n        </nz-icon>\n        <nz-icon [class.code-expand-icon-show]=\"!expanded()\" [class.code-expand-icon-hide]=\"expanded()\">\n          <svg viewBox=\"0 0 1024 1024\" fill=\"currentColor\">\n            <path\n              d=\"M1018.645 531.298c8.635-18.61 4.601-41.42-11.442-55.864l-205.108-184.68c-19.7-17.739-50.05-16.148-67.789 3.552-17.738 19.7-16.148 50.051 3.553 67.79l166.28 149.718-167.28 150.62c-19.7 17.738-21.291 48.088-3.553 67.789 17.739 19.7 48.089 21.291 67.79 3.553l205.107-184.68a47.805 47.805 0 0 0 12.442-17.798zM119.947 511.39l166.28-149.719c19.7-17.738 21.29-48.088 3.552-67.789-17.738-19.7-48.088-21.291-67.789-3.553L16.882 475.01C.84 489.456-3.194 512.264 5.44 530.874a47.805 47.805 0 0 0 12.442 17.798l205.108 184.68c19.7 17.739 50.05 16.148 67.79-3.552 17.738-19.7 16.147-50.051-3.553-67.79l-167.28-150.62zm529.545-377.146c24.911 9.066 37.755 36.61 28.688 61.522L436.03 861.068c-9.067 24.911-36.611 37.755-61.522 28.688-24.911-9.066-37.755-36.61-28.688-61.522l242.15-665.302c9.067-24.911 36.611-37.755 61.522-28.688z\"\n              fill-rule=\"evenodd\"\n              opacity=\"0.78\"\n            ></path>\n          </svg>\n        </nz-icon>\n      </span>\n    </div>\n  </section>\n  <section class=\"highlight-wrapper\" [class.highlight-wrapper-expand]=\"expanded()\">\n    <div class=\"highlight\">\n      <ng-content select=\"[code]\"></ng-content>\n      <nz-highlight [nzCode]=\"codeLoaded() ? highlightCode()! : language() === 'zh' ? '加载中' : 'Loading...'\" />\n    </div>\n  </section>\n</section>\n@if (!!nzVersion) {\n  <div class=\"ant-ribbon ant-ribbon-placement-end ant-ribbon-rt\">\n    <div class=\"ant-ribbon-text\">{{nzVersion}}</div>\n    <div class=\"ant-ribbon-corner\"></div>\n  </div>\n}\n\n"
  },
  {
    "path": "scripts/site/doc/app/codebox/codebox.component.less",
    "content": ".simulate-iframe {\n  display: block;\n  transform: translateX(0);\n\n  > * {\n    display: block;\n    height: 100%;\n    overflow: auto;\n    transform: translateX(0);\n\n    > * {\n      height: 100%;\n      overflow: auto;\n    }\n  }\n}\n\nnz-code-box {\n  position: relative;\n  display: block;\n}\n"
  },
  {
    "path": "scripts/site/doc/app/codebox/codebox.component.ts",
    "content": "import { Clipboard } from '@angular/cdk/clipboard';\nimport { Platform } from '@angular/cdk/platform';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  computed,\n  DestroyRef,\n  inject,\n  Input,\n  signal,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { DomSanitizer, SafeUrl } from '@angular/platform-browser';\nimport { Observable } from 'rxjs';\nimport { tap } from 'rxjs/operators';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzTooltipModule } from 'ng-zorro-antd/tooltip';\n\nimport { AppService, DemoCode } from '../app.service';\nimport { APP_LANGUAGE } from '../app.token';\nimport { OnlineIdeService } from '../online-ide/online-ide.service';\nimport { NzHighlightComponent } from './highlight.component';\n\n@Component({\n  selector: 'nz-code-box',\n  encapsulation: ViewEncapsulation.None,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  imports: [NzIconModule, NzTooltipModule, NzHighlightComponent],\n  templateUrl: './codebox.component.html',\n  styleUrl: './codebox.component.less',\n  host: {\n    ngSkipHydration: ''\n  }\n})\nexport class NzCodeBoxComponent {\n  protected readonly language = inject(APP_LANGUAGE);\n  private readonly sanitizer = inject(DomSanitizer);\n  private readonly appService = inject(AppService);\n  private readonly platform = inject(Platform);\n  private readonly clipboard = inject(Clipboard);\n  private readonly destroyRef = inject(DestroyRef);\n  private readonly onlineIdeService = inject(OnlineIdeService);\n\n  iframe?: SafeUrl;\n  readonly highlightCode = signal<string>(null!);\n  readonly commandCopied = signal(false);\n  readonly codeLoaded = computed(() => !!this.highlightCode());\n  readonly onlineIDELoading = signal(false);\n  readonly copied = signal(false);\n  readonly codeLoading = signal(false);\n  readonly expanded = signal(false);\n\n  @Input() nzTitle!: string;\n  @Input() nzVersion!: string;\n  @Input() nzHref!: string;\n  @Input() nzLink!: string;\n  @Input() nzId!: string;\n  @Input() nzIframeHeight: number | null = 360;\n  @Input() nzComponentName = '';\n  @Input() nzSelector = '';\n  @Input() nzGenerateCommand = '';\n  @Input() nzIframe: boolean = false;\n\n  @Input()\n  set nzIframeSource(value: string) {\n    if (value !== 'null') {\n      this.iframe = this.sanitizer.bypassSecurityTrustResourceUrl(value);\n    }\n  }\n\n  navigateToFragment(): void {\n    if (this.platform.isBrowser) {\n      window.location.hash = this.nzLink;\n    }\n  }\n\n  copyCode(): void {\n    setTimeout(() => this.codeLoading.set(!this.codeLoaded()), 100);\n    this.getDemoCode().subscribe(data => {\n      this.codeLoading.set(false);\n      this.clipboard.copy(data.rawCode);\n      this.copied.set(true);\n      setTimeout(() => this.copied.set(false), 1000);\n    });\n  }\n\n  copyGenerateCommand(command: string): void {\n    this.clipboard.copy(command);\n    this.commandCopied.set(true);\n    setTimeout(() => this.commandCopied.set(false), 1000);\n  }\n\n  expandCode(expanded: boolean): void {\n    this.expanded.set(expanded);\n    if (expanded) {\n      this.getDemoCode().subscribe();\n    }\n  }\n\n  openOnlineIDE(): void {\n    setTimeout(() => this.onlineIDELoading.set(!this.codeLoaded()), 100);\n    this.getDemoCode().subscribe(data => {\n      this.onlineIDELoading.set(false);\n      this.onlineIdeService.openOnStackBlitz(this.nzComponentName, data.rawCode, this.nzSelector);\n    });\n  }\n\n  private getDemoCode(): Observable<DemoCode> {\n    return this.appService.getCode(this.nzId).pipe(\n      takeUntilDestroyed(this.destroyRef),\n      tap(data => {\n        this.highlightCode.set(data.highlightCode);\n      })\n    );\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/app/codebox/highlight.component.ts",
    "content": "import { ChangeDetectionStrategy, Component, input } from '@angular/core';\n\nimport { NzSanitizerPipe } from 'ng-zorro-antd/pipes';\n\n@Component({\n  selector: 'nz-highlight',\n  imports: [NzSanitizerPipe],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    <pre class=\"language-angular\">\n      <code [innerHTML]=\"nzCode() | nzSanitizer: 'html'\"></code>\n    </pre>\n  `\n})\nexport class NzHighlightComponent {\n  nzCode = input<string>();\n}\n"
  },
  {
    "path": "scripts/site/doc/app/component-meta/component-meta.component.html",
    "content": "{{ description() }}\n\n<nz-descriptions nzSize=\"small\" [nzColumn]=\"1\" [nzColon]=\"false\">\n  <nz-descriptions-item [nzTitle]=\"isEn() ? 'Import' : '使用'\">\n    <button nz-button nzType=\"text\" nzSize=\"small\" (click)=\"copy()\" nz-tooltip [nzTooltipTitle]=\"tip\" nzTooltipPlacement=\"right\" (nzTooltipVisibleChange)=\"usageTooltipVisibleChange($event)\">\n      <span nz-typography>{{ usage }}</span>\n    </button>\n  </nz-descriptions-item>\n  <nz-descriptions-item [nzTitle]=\"isEn() ? 'Source' : '源码'\">\n    <nz-flex nzGap=\"small\">\n      <a nz-button nzType=\"text\" nzSize=\"small\" [attr.href]=\"sourceCode\" target=\"_blank\" rel=\"noopener noreferrer\">\n        <nz-icon nzType=\"github\" />\n        <span nz-typography>components/{{ path() }}</span>\n      </a>\n      <a nz-button nzType=\"text\" nzSize=\"small\" [attr.href]=\"reportIssue\" target=\"_blank\" rel=\"noopener noreferrer\">\n        <nz-icon nzType=\"bug\" />\n        <span nz-typography>{{ isEn() ? 'Issue' : '提交问题' }}</span>\n      </a>\n      <a nz-button nzType=\"text\" nzSize=\"small\" [attr.href]=\"openIssues\" target=\"_blank\" rel=\"noopener noreferrer\">\n        <nz-icon nzType=\"issues-close\" />\n        <span nz-typography>\n          {{ isEn() ? 'Open issues' : '待解决' }}\n          @if (issues.hasValue()) {\n            {{ issues.value() }}\n          }\n        </span>\n      </a>\n    </nz-flex>\n  </nz-descriptions-item>\n  <nz-descriptions-item [nzTitle]=\"isEn() ? 'Docs' : '文档'\">\n    <a nz-button nzType=\"text\" nzSize=\"small\" [attr.href]=\"document()\" target=\"_blank\" rel=\"noopener noreferrer\">\n      <nz-icon nzType=\"edit\" />\n      <span nz-typography>{{ isEn() ? 'Edit this page' : '编辑此页' }}</span>\n    </a>\n  </nz-descriptions-item>\n</nz-descriptions>\n\n<ng-template #tip>\n  @if (copied()) {\n    {{ isEn() ? 'Copied' : '已复制' }}\n  } @else {\n    {{ isEn() ? 'Copy' : '复制' }}\n  }\n</ng-template>"
  },
  {
    "path": "scripts/site/doc/app/component-meta/component-meta.component.ts",
    "content": "import { Clipboard } from '@angular/cdk/clipboard';\nimport { Component, computed, inject, input, resource, signal } from '@angular/core';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzDescriptionsModule } from 'ng-zorro-antd/descriptions';\nimport { NzFlexModule } from 'ng-zorro-antd/flex';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzTooltipModule } from 'ng-zorro-antd/tooltip';\nimport { NzTypographyModule } from 'ng-zorro-antd/typography';\nimport { rxResource } from '@angular/core/rxjs-interop';\n\n@Component({\n  selector: 'component-meta',\n  imports: [NzButtonModule, NzDescriptionsModule, NzFlexModule, NzIconModule, NzTooltipModule, NzTypographyModule],\n  templateUrl: './component-meta.component.html',\n  styles: `\n    :host {\n      nz-descriptions {\n        margin-top: 16px;\n        overflow-x: scroll;\n      }\n\n      ::ng-deep .ant-descriptions-item-label {\n        padding-inline-end: 16px;\n        width: 56px;\n        word-break: keep-all;\n      }\n\n      .ant-typography {\n        font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;\n      }\n\n      a:hover .ant-typography {\n        text-decoration: underline;\n      }\n    }\n  `\n})\nexport class ComponentMetaComponent {\n  name = input.required<string>();\n  language = input<string>();\n  description = input<string>();\n\n  readonly clipboard = inject(Clipboard);\n\n  readonly path = computed(() => {\n    return this.name().startsWith('experimental-') ? `experimental/${this.name().slice(13)}` : this.name();\n  });\n\n  get sourceCode(): string {\n    return `https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/components/${this.path()}`;\n  }\n\n  get openIssues(): string {\n    return `https://github.com/NG-ZORRO/ng-zorro-antd/issues?q=is%3Aopen%20is%3Aissue%20label%3A%22Component%3A%20${this.componentName()}%22`;\n  }\n\n  get reportIssue(): string {\n    return `https://ng.ant.design/issue-helper/#/${this.language()}`;\n  }\n\n  readonly isEn = computed(() => this.language() === 'en');\n  readonly document = computed(() => {\n    const lang = this.isEn() ? 'en-US' : 'zh-CN';\n    return `https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/components/${this.name()}/doc/index.${lang}.md`;\n  });\n  readonly copied = signal(false);\n\n  // the name of component in camel case\n  readonly componentName = computed(() => {\n    const componentName = this.name().startsWith('experimental-') ? this.name().slice(13) : this.name();\n    return componentName\n      .split('-')\n      .map(part => part.charAt(0).toUpperCase() + part.slice(1))\n      .join('');\n  });\n  readonly serviceOnlyComponents = ['Notification', 'Message'];\n\n  get usage(): string {\n    const camelCaseName = this.componentName();\n    const importTargetName = this.serviceOnlyComponents.includes(camelCaseName)\n      ? `Nz${camelCaseName}Service`\n      : `Nz${camelCaseName}Module`;\n    return `import { ${importTargetName} } from 'ng-zorro-antd/${this.path()}';`;\n  }\n\n  readonly issues = resource({\n    params: () => ({ component: this.componentName() }),\n    loader: ({ params }) => {\n      const q = [\n        `repo:NG-ZORRO/ng-zorro-antd`,\n        'is:issue',\n        'is:open',\n        `label:\"Component: ${params.component}\"`\n      ].join(' ');\n      return fetch(`https://api.github.com/search/issues?q=${encodeURIComponent(q)}`)\n        .then(res => res.json())\n        .then(res => res.total_count)\n    }\n  });\n\n  usageTooltipVisibleChange(visible: boolean): void {\n    if (!visible) {\n      this.copied.set(false);\n    }\n  }\n\n  copy(): void {\n    this.clipboard.copy(this.usage);\n    this.copied.set(true);\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/app/components-overview/components-overview.component.html",
    "content": "<section class=\"markdown\">\n  <h1>{{ language() === 'en' ? 'Components Overview' : '组件总览' }}</h1>\n\n  <section>\n    @if (language() === 'zh') {\n      <p>\n        <span><code>ng-zorro-antd</code></span>\n        是 Ant Design 的 Angular 实现，为网页开发提供高质量的 UI 组件。\n      </p>\n    } @else {\n      <p>\n        <span><code>ng-zorro-antd</code></span>\n        is an Angular UI library, follows Ant Design specification, to provide high quantity UI components for web\n        development.\n      </p>\n    }\n  </section>\n\n  <section #componentsList>\n    <nz-divider></nz-divider>\n\n    <nz-affix [nzOffsetTop]=\"10\" (nzChange)=\"onSearchAffixed($event)\">\n      <nz-input-wrapper class=\"components-overview-search\">\n        <input\n          type=\"text\"\n          #searchBox\n          nz-input\n          placeholder=\"{{ language() === 'en' ? 'Search components' : '搜索组件' }}\"\n          nzSize=\"large\"\n          (input)=\"onSearch(searchBox.value)\"\n        />\n        <nz-icon nzInputSuffix nzType=\"search\" />\n      </nz-input-wrapper>\n    </nz-affix>\n\n    <nz-divider></nz-divider>\n\n    @for (group of displayedComponents(); track group.name) {\n      <div class=\"components-overview\">\n        <h3 nz-typography class=\"components-overview-group-title\">\n          {{ group.name }}\n          <nz-tag>{{ group.children.length }}</nz-tag>\n        </h3>\n\n        <div nz-row>\n          @for (component of group.children; track $index) {\n            <div nz-col nzXs=\"24\" nzSm=\"12\" nzMd=\"12\" nzLg=\"8\" nzXl=\"6\" nzXXl=\"6\" class=\"components-overview-card\">\n              <a routerLink=\"/{{ component.path }}\">\n                <nz-card nzHoverable nzTitle=\"{{ component.label }} {{ component.zh }}\">\n                  <div class=\"components-overview-img\">\n                    <img [alt]=\"component.label\" [src]=\"component.cover\" />\n                  </div>\n                </nz-card>\n              </a>\n            </div>\n          }\n        </div>\n      </div>\n    }\n  </section>\n</section>\n"
  },
  {
    "path": "scripts/site/doc/app/components-overview/components-overview.component.less",
    "content": ".components-overview {\n  padding: 0;\n\n  &-group-title {\n    display: flex;\n    gap: 8px;\n    align-items: center;\n    margin-top: 24px !important;\n  }\n\n  &-img {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    height: 152px;\n  }\n\n  &-card {\n    padding: 12px;\n    cursor: pointer;\n  }\n}\n\nnz-input-wrapper.components-overview-search {\n  width: 100%;\n  padding: 0;\n  font-size: 20px;\n  border: 0;\n  box-shadow: none;\n\n  input {\n    color: rgba(0, 0, 0, 0.85);\n    font-size: 20px;\n  }\n\n  .anticon {\n    color: #bbb;\n  }\n}\n\n.ant-affix {\n  .components-overview-search {\n    margin: -8px;\n    padding: 8px;\n    border-radius: 6px;\n    box-shadow: rgba(50, 50, 93, 0.25) 0 6px 12px -2px, rgba(0, 0, 0, 0.3) 0 3px 7px -3px;\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/app/components-overview/components-overview.component.ts",
    "content": "import {\n  afterNextRender,\n  ChangeDetectionStrategy,\n  Component,\n  computed,\n  effect,\n  ElementRef,\n  inject,\n  signal,\n  viewChild,\n  ViewEncapsulation\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { RouterLink } from '@angular/router';\nimport { Subject } from 'rxjs';\nimport { debounceTime } from 'rxjs/operators';\n\nimport { NzAffixModule } from 'ng-zorro-antd/affix';\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzCardModule } from 'ng-zorro-antd/card';\nimport { NzDividerModule } from 'ng-zorro-antd/divider';\nimport { NzGridModule } from 'ng-zorro-antd/grid';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputModule } from 'ng-zorro-antd/input';\nimport { NzTagModule } from 'ng-zorro-antd/tag';\nimport { NzTypographyModule } from 'ng-zorro-antd/typography';\n\nimport { APP_LANGUAGE } from '../app.token';\nimport { ROUTER_LIST } from '../router';\n\n@Component({\n  selector: 'app-components-overview',\n  imports: [\n    RouterLink,\n    NzAffixModule,\n    NzCardModule,\n    NzButtonModule,\n    NzTagModule,\n    NzGridModule,\n    NzTypographyModule,\n    NzDividerModule,\n    NzIconModule,\n    NzInputModule\n  ],\n  templateUrl: './components-overview.component.html',\n  styleUrl: './components-overview.component.less',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None\n})\nexport default class ComponentsOverviewComponent {\n  protected readonly language = inject(APP_LANGUAGE);\n  readonly routerList = signal(ROUTER_LIST.components);\n  affixed = false;\n  readonly searchValue = signal('');\n  readonly searchChange$ = new Subject<string>();\n\n  readonly componentsList = viewChild.required<ElementRef<HTMLElement>>('componentsList');\n  readonly searchBox = viewChild.required<ElementRef<HTMLInputElement>>('searchBox');\n\n  readonly displayedComponents = computed(() => {\n    const routerList = JSON.parse(JSON.stringify(ROUTER_LIST.components)) as typeof ROUTER_LIST['components'];\n    const language = this.language();\n    const searchValue = this.searchValue();\n\n    const groups = routerList.filter(group => group.language === language);\n    if (searchValue) {\n      for (const group of groups) {\n        group.children = group.children.filter(\n          component => component.label.toLowerCase().includes(searchValue) || component.zh.includes(searchValue)\n        );\n      }\n    }\n\n    return groups.filter(g => g.children.length > 0);\n  });\n\n  constructor() {\n    this.searchChange$\n      .asObservable()\n      .pipe(debounceTime(20), takeUntilDestroyed())\n      .subscribe(searchValue => this.searchValue.set(searchValue));\n\n    effect(() => {\n      if (this.affixed && this.displayedComponents()) {\n        this.scrollIntoView();\n      }\n    });\n\n    // autofocus\n    afterNextRender(() => {\n      this.searchBox().nativeElement.focus();\n    });\n  }\n\n  onSearchAffixed(affixed: boolean): void {\n    this.affixed = affixed;\n  }\n\n  onSearch(searchValue: string): void {\n    this.searchChange$.next(searchValue.toLowerCase());\n  }\n\n  private scrollIntoView(): void {\n    this.componentsList().nativeElement.scrollIntoView({\n      block: 'start',\n      behavior: 'smooth'\n    });\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/app/components-overview/routes.ts",
    "content": "import { Routes } from '@angular/router';\n\nconst COMPONENTS_OVERVIEW_ROUTES: Routes = [\n  {\n    path: '**',\n    loadComponent: () => import('./components-overview.component')\n  }\n];\n\nexport default COMPONENTS_OVERVIEW_ROUTES;\n"
  },
  {
    "path": "scripts/site/doc/app/contributors-list/contributors-list.component.ts",
    "content": "import { Platform } from '@angular/cdk/platform';\nimport { HttpClient } from '@angular/common/http';\nimport { ChangeDetectionStrategy, Component, DestroyRef, ElementRef, inject, OnInit, signal } from '@angular/core';\nimport { NavigationEnd, Router } from '@angular/router';\nimport { filter, map, take } from 'rxjs/operators';\n\nimport { NzAvatarModule } from 'ng-zorro-antd/avatar';\nimport { NzFlexModule } from 'ng-zorro-antd/flex';\nimport { NzTooltipModule } from 'ng-zorro-antd/tooltip';\n\nimport { APP_LANGUAGE } from '../app.token';\n\ninterface GithubCommit {\n  author: {\n    login: string; // id\n    avatar_url: string;\n  };\n  commit: {\n    author: {\n      name: string;\n    };\n  };\n}\n\ninterface Contributor {\n  id: string;\n  count: number;\n  name: string;\n  url: string;\n  avatar: string;\n}\n\n@Component({\n  selector: 'app-contributors-list',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  imports: [NzAvatarModule, NzTooltipModule, NzFlexModule],\n  template: `\n    <ul nz-flex nzWrap=\"wrap\" nzGap=\"small\" [style.margin-top.px]=\"120\">\n      @for (item of list(); track $index) {\n        <a\n          nz-tooltip\n          [nzTooltipTitle]=\"(language() === 'en' ? 'Contributors: ' : '文档贡献者: ') + item.name\"\n          [attr.href]=\"item.url\"\n          target=\"_blank\"\n        >\n          <nz-avatar [nzText]=\"item.name\" [nzSrc]=\"item.avatar\" />\n        </a>\n      }\n    </ul>\n  `\n})\nexport class ContributorsListComponent implements OnInit {\n  protected language = inject(APP_LANGUAGE).asReadonly();\n  private readonly router = inject(Router);\n  private readonly platform = inject(Platform);\n  private readonly http = inject(HttpClient);\n  private readonly elementRef = inject(ElementRef);\n\n  list = signal<Contributor[]>([]);\n  filePath = '';\n  isIntersecting = false;\n  intersectionObserver!: IntersectionObserver;\n\n  constructor() {\n    inject(DestroyRef).onDestroy(() => {\n      this.intersectionObserver?.unobserve(this.elementRef.nativeElement);\n    });\n  }\n\n  ngOnInit(): void {\n    if (!this.platform.isBrowser) {\n      return;\n    }\n    this.intersectionObserver = new IntersectionObserver(entries => {\n      entries.forEach(({ isIntersecting }) => {\n        this.isIntersecting = isIntersecting;\n        this.reloadContributors();\n      });\n    });\n    const navigationEnd$ = this.router.events.pipe(filter(e => e instanceof NavigationEnd));\n    navigationEnd$.pipe(take(1)).subscribe(() => {\n      this.intersectionObserver.observe(this.elementRef.nativeElement);\n    });\n    navigationEnd$.subscribe(() => {\n      const url = window.location.pathname.slice(1);\n      const language = this.router.url.split('/')[this.router.url.split('/').length - 1].split('#')[0];\n      let filePath = '';\n      const docsMatch = /docs\\/(.+)\\//.exec(url);\n      const componentMatch = /(?:components|experimental)\\/(.+)\\//.exec(url);\n\n      if (docsMatch && docsMatch[1]) {\n        filePath = `docs/${docsMatch[1]}.${language === 'en' ? 'en-US' : 'zh-CN'}.md`;\n      } else if (componentMatch && componentMatch[1]) {\n        filePath = `components/${componentMatch[1]}/doc`;\n      }\n      this.list.set([]);\n      this.filePath = filePath;\n      this.reloadContributors();\n    });\n  }\n\n  reloadContributors(): void {\n    if (this.isIntersecting && this.filePath && this.list.length === 0) {\n      this.getContributors(this.filePath);\n    }\n  }\n\n  getContributors(path: string): void {\n    this.http\n      .get<GithubCommit[]>(`https://api.github.com/repos/NG-ZORRO/ng-zorro-antd/commits`, {\n        params: { path }\n      })\n      .pipe(\n        map(data => {\n          const list: Contributor[] = [];\n          data\n            .filter(e => e.author?.login)\n            .forEach(e => {\n              const id = e.author.login;\n              const index = list.findIndex(i => i.id === id);\n              if (index === -1) {\n                list.push({\n                  id,\n                  count: 1,\n                  name: e.commit.author.name,\n                  url: `https://github.com/${id}`,\n                  avatar: e.author.avatar_url\n                });\n              } else {\n                list[index].count = list[index].count + 1;\n              }\n            });\n          return list.sort((a, b) => b.count - a.count);\n        })\n      )\n      .subscribe(this.list.set);\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/app/demo/demo.component.ts",
    "content": ""
  },
  {
    "path": "scripts/site/doc/app/fixed-widgets/fixed-widgets.component.ts",
    "content": "import { ChangeDetectionStrategy, Component, computed, inject, input, output } from '@angular/core';\n\nimport { NzDropdownModule } from 'ng-zorro-antd/dropdown';\n\nimport { AppService, SiteTheme } from '../app.service';\nimport { APP_LANGUAGE } from '../app.token';\nimport { ThemingIcon } from './theming-icon';\n\n@Component({\n  selector: 'app-fixed-widgets',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  imports: [NzDropdownModule, ThemingIcon],\n  template: `\n    <div class=\"fixed-widgets\">\n      <div\n        class=\"ant-avatar ant-avatar-circle ant-avatar-icon fixed-widgets-avatar\"\n        nz-dropdown\n        nzPlacement=\"topCenter\"\n        [nzDropdownMenu]=\"menu\"\n      >\n        <theming-icon />\n      </div>\n      <nz-dropdown-menu #menu=\"nzDropdownMenu\">\n        <ul nz-menu nzSelectable>\n          @for (theme of themes(); track theme.value) {\n            <li nz-menu-item [nzSelected]=\"currentTheme() === theme.value\" (click)=\"themeChange.emit(theme.value)\">\n              {{ theme.label }}\n            </li>\n          }\n        </ul>\n      </nz-dropdown-menu>\n    </div>\n  `\n})\nexport class FixedWidgetsComponent {\n  protected readonly language = inject(APP_LANGUAGE);\n  protected readonly currentTheme = inject(AppService).theme.asReadonly();\n  readonly themeChange = output<SiteTheme>();\n\n  readonly themes = computed<Array<{ label: string; value: SiteTheme }>>(() => {\n    const language = this.language();\n    return [\n      {\n        label: language === 'zh' ? '默认主题' : 'Default',\n        value: 'default'\n      },\n      {\n        label: language === 'zh' ? '暗黑主题' : 'Dark Theme',\n        value: 'dark'\n      },\n      {\n        label: language === 'zh' ? '紧凑主题' : 'Compact Theme',\n        value: 'compact'\n      },\n      {\n        label: language === 'zh' ? '阿里云主题' : 'Aliyun Theme',\n        value: 'aliyun'\n      }\n    ];\n  });\n}\n"
  },
  {
    "path": "scripts/site/doc/app/fixed-widgets/theming-icon.ts",
    "content": "import { Component } from '@angular/core';\n\n@Component({\n  selector: 'theming-icon',\n  template: `\n    <svg width=\"21\" height=\"21\" viewBox=\"0 0 21 21\" fill=\"currentColor\">\n      <g fill-rule=\"evenodd\">\n        <g fill-rule=\"nonzero\">\n          <path\n            d=\"M7.02 3.635l12.518 12.518a1.863 1.863 0 010 2.635l-1.317 1.318a1.863 1.863 0 01-2.635 0L3.068 7.588A2.795 2.795 0 117.02 3.635zm2.09 14.428a.932.932 0 110 1.864.932.932 0 010-1.864zm-.043-9.747L7.75 9.635l9.154 9.153 1.318-1.317-9.154-9.155zM3.52 12.473c.514 0 .931.417.931.931v.932h.932a.932.932 0 110 1.864h-.932v.931a.932.932 0 01-1.863 0l-.001-.931h-.93a.932.932 0 010-1.864h.93v-.932c0-.514.418-.931.933-.931zm15.374-3.727a1.398 1.398 0 110 2.795 1.398 1.398 0 010-2.795zM4.385 4.953a.932.932 0 000 1.317l2.046 2.047L7.75 7 5.703 4.953a.932.932 0 00-1.318 0zM14.701.36a.932.932 0 01.931.932v.931h.932a.932.932 0 010 1.864h-.933l.001.932a.932.932 0 11-1.863 0l-.001-.932h-.93a.932.932 0 110-1.864h.93v-.931a.932.932 0 01.933-.932z\"></path>\n        </g>\n      </g>\n    </svg>\n  `,\n  host: {\n    class: 'anticon',\n    role: 'img'\n  }\n})\nexport class ThemingIcon {}\n\n"
  },
  {
    "path": "scripts/site/doc/app/footer/footer-col.component.ts",
    "content": "import { ChangeDetectionStrategy, Component, input, Input } from '@angular/core';\n\n@Component({\n  selector: 'div[app-footer-col]',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    <h2>{{ title() }}</h2>\n    <ng-content></ng-content>\n  `,\n  host: {\n    class: 'rc-footer-column'\n  }\n})\nexport class FooterColComponent {\n  title = input<string>();\n}\n"
  },
  {
    "path": "scripts/site/doc/app/footer/footer-item.component.ts",
    "content": "import { ChangeDetectionStrategy, Component, input, Input } from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\n@Component({\n  selector: 'app-footer-item',\n  imports: [NzIconModule],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    @if (link()) {\n      <a [attr.href]=\"link()\" target=\"_blank\" rel=\"noopener\">\n        @if (icon()) {\n          <nz-icon [nzType]=\"icon()!\" class=\"rc-footer-item-icon\" />\n        }\n        {{ title() }}\n      </a>\n    }\n    @if (description()) {\n      <span class=\"rc-footer-item-separator\">-</span>\n      <span class=\"rc-footer-item-description\">{{ description() }}</span>\n    }\n    <ng-content></ng-content>\n  `,\n  host: {\n    class: 'rc-footer-item',\n    '[style.display]': '\"block\"'\n  }\n})\nexport class FooterItemComponent {\n  icon = input<string>();\n  link = input<string>();\n  title = input<string>();\n  description = input<string>();\n}\n"
  },
  {
    "path": "scripts/site/doc/app/footer/footer.component.ts",
    "content": "import { ChangeDetectionStrategy, Component, inject, input, output } from '@angular/core';\n\nimport { NzColor, NzColorPickerModule } from 'ng-zorro-antd/color-picker';\n\nimport { APP_LANGUAGE } from '../app.token';\nimport { FooterColComponent } from './footer-col.component';\nimport { FooterItemComponent } from './footer-item.component';\n\n@Component({\n  selector: 'app-footer',\n  imports: [NzColorPickerModule, FooterColComponent, FooterItemComponent],\n  template: `\n    <footer class=\"rc-footer\">\n      <section class=\"rc-footer-container\">\n        <section class=\"rc-footer-columns\">\n          <div app-footer-col [title]=\"language() === 'zh' ? '相关资源' : 'Resources'\">\n            <app-footer-item\n              title=\"NG-ZORRO-MOBILE\"\n              link=\"https://ng.mobile.ant.design/\"\n              description=\"Angular\"\n            />\n            <app-footer-item\n              title=\"Ant Design\"\n              link=\"https://ant.design/docs/react/introduce\"\n              description=\"React\"\n            />\n            <!-- <app-footer-item title=\"Ant Design\" link=\"https://vue.ant.design/\" description=\"Vue\" /> -->\n            <app-footer-item\n              title=\"Angular\"\n              [link]=\"language() === 'zh' ? 'https://angular.cn/' : 'https://angular.dev/'\"\n            />\n            <app-footer-item\n              title=\"Angular Aira\"\n              [link]=\"language() === 'zh' ? 'https://angular.cn/guide/aria/overview' : 'https://angular.dev/guide/aria/overview'\"\n            />\n            <app-footer-item\n              title=\"Angular CDK\"\n              [link]=\"language() === 'zh' ? 'https://material.angular.cn/cdk/categories' : 'https://material.angular.dev/cdk/categories'\"\n            />\n            <app-footer-item\n              title=\"Angular CLI\"\n              [link]=\"language() === 'zh' ? 'https://angular.cn/tools/cli' : 'https://angular.dev/tools/cli'\"\n            />\n          </div>\n          <div app-footer-col [title]=\"language() === 'zh' ? '社区' : 'Community'\">\n            <app-footer-item\n              icon=\"ant-design\"\n              title=\"Awesome Ant Design\"\n              link=\"https://github.com/websemantics/awesome-ant-design\"\n            />\n            <app-footer-item icon=\"global\" title=\"Blog\" link=\"https://ng.ant.design/blog\" />\n            <app-footer-item icon=\"x\" title=\"X\" link=\"https://x.com/ng_zorro\" />\n            <app-footer-item icon=\"discord\" title=\"Discord\" link=\"https://discord.gg/Ga6Nd7aqVC\" />\n            @if (language() === 'zh') {\n              <app-footer-item\n                icon=\"zhihu\"\n                title=\"知乎专栏\"\n                link=\"https://zhuanlan.zhihu.com/100000\"\n              />\n            }\n            <app-footer-item icon=\"medium\" title=\"Medium\" link=\"https://medium.com/ng-zorro\" />\n          </div>\n          <div app-footer-col [title]=\"language() === 'zh' ? '帮助' : 'Help'\">\n            <app-footer-item\n              icon=\"github\"\n              title=\"GitHub\"\n              link=\"https://github.com/NG-ZORRO/ng-zorro-antd\"\n            />\n            <app-footer-item\n              icon=\"history\"\n              [title]=\"language() === 'zh' ? '更新日志' : 'Changelog'\"\n              link=\"https://ng.ant.design/docs/changelog/{{ language() }}\"\n            />\n            <app-footer-item\n              icon=\"profile\"\n              [title]=\"language() === 'zh' ? '常见问题' : 'FAQ'\"\n              link=\"https://ng.ant.design/docs/faq/{{ language() }}\"\n            ></app-footer-item>\n            <app-footer-item\n              icon=\"bug\"\n              [title]=\"language() === 'zh' ? '报告 Bug' : 'Bug Report'\"\n              link=\"https://ng.ant.design/issue-helper/#/{{ language() }}\"\n            />\n            <app-footer-item\n              icon=\"issues-close\"\n              [title]=\"language() === 'zh' ? '讨论列表' : 'Discussions'\"\n              link=\"https://github.com/NG-ZORRO/ng-zorro-antd/discussions\"\n            />\n            <app-footer-item\n              icon=\"book\"\n              [title]=\"language() === 'zh' ? '实战教程' : 'Tutorials'\"\n              link=\"https://github.com/NG-ZORRO/today-ng-steps\"\n            />\n            <app-footer-item\n              icon=\"question-circle\"\n              title=\"StackOverflow\"\n              link=\"https://stackoverflow.com/questions/tagged/ng-zorro-antd\"\n            />\n            <app-footer-item>\n              <nz-color-picker [nzValue]=\"colorHex()\" (nzOnChange)=\"colorChange.emit($event)\" />\n            </app-footer-item>\n          </div>\n        </section>\n      </section>\n      <section class=\"rc-footer-bottom\">\n        <div class=\"rc-footer-bottom-container\">\n          Made with\n          <span style=\"color: rgb(255, 255, 255);\">❤</span>\n          by NG-ZORRO team\n        </div>\n      </section>\n    </footer>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class FooterComponent {\n  protected readonly language = inject(APP_LANGUAGE);\n\n  colorHex = input('#1890ff');\n  readonly colorChange = output<{ color: NzColor; format: string }>();\n}\n"
  },
  {
    "path": "scripts/site/doc/app/header/github-button.component.ts",
    "content": "import { Platform } from '@angular/cdk/platform';\nimport { HttpClient } from '@angular/common/http';\nimport { ChangeDetectionStrategy, Component, inject, OnInit, signal } from '@angular/core';\nimport { AppService } from '../app.service';\n\n@Component({\n  selector: 'app-github-btn',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    <a\n      class=\"gh-btn\"\n      tabindex=\"-1\"\n      [attr.href]=\"'https://github.com/' + repo\"\n      target=\"_blank\"\n      rel=\"noopener\"\n      aria-hidden=\"true\"\n    >\n      <span class=\"gh-ico\" aria-hidden=\"true\"></span>\n      <span class=\"gh-text\">Star</span>\n    </a>\n    <a\n      class=\"gh-count\"\n      target=\"_blank\"\n      rel=\"noopener\"\n      style=\"display: block\"\n      [attr.href]=\"'https://github.com/' + repo + '/stargazers'\"\n    >\n      {{ starCount() }}\n    </a>\n  `,\n  host: {\n    id: 'github-btn',\n    class: 'github-btn',\n    '[class.responsive-mode]': 'responsive()',\n    '[class.responsive-narrow]': 'responsive() === \"narrow\"',\n    '[class.responsive-crowded]': 'responsive() === \"crowded\"'\n  }\n})\nexport class GithubButtonComponent implements OnInit {\n  readonly starCount = signal(0);\n  readonly repo = 'NG-ZORRO/ng-zorro-antd';\n\n  private readonly http = inject(HttpClient);\n  private readonly platform = inject(Platform);\n  protected readonly responsive = inject(AppService).responsive;\n\n  ngOnInit(): void {\n    if (this.platform.isBrowser) {\n      this.getStar();\n    }\n  }\n\n  private getStar(): void {\n    this.http\n      .get<{ stargazers_count: number }>(`https://api.github.com/repos/${this.repo}`)\n      .subscribe(res => this.starCount.set(res.stargazers_count));\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/app/header/header.component.html",
    "content": "<header id=\"header\" class=\"clearfix\">\n  @if (app.isMobile()) {\n    <nz-icon\n      class=\"nav-phone-icon\"\n      nzType=\"unordered-list\"\n      nzPopoverOverlayClassName=\"popover-menu\"\n      nzPopoverPlacement=\"bottomLeft\"\n      nz-popover\n      [nzPopoverContent]=\"menu\"\n    />\n  }\n\n  <div nz-row style=\"flex-flow: nowrap\">\n    <div nz-col [nzXs]=\"24\" [nzSm]=\"24\" [nzMd]=\"6\" [nzLg]=\"6\" [nzXl]=\"5\" [nzXXl]=\"4\">\n      <a href=\"/\" id=\"logo\">\n        <img width=\"32\" height=\"28.27\" alt=\"logo\" src=\"./assets/img/logo.svg\" />\n        <strong>NG-ZORRO</strong>\n      </a>\n    </div>\n    <div nz-col [nzXs]=\"0\" [nzSm]=\"0\" [nzMd]=\"18\" [nzLg]=\"18\" [nzXl]=\"19\" [nzXXl]=\"20\" class=\"menu-row\">\n      <div app-searchbar (focusChange)=\"onFocusChange($event)\"></div>\n      @if (!app.isMobile()) {\n        <ng-container [ngTemplateOutlet]=\"menu\"></ng-container>\n      }\n    </div>\n  </div>\n</header>\n\n<ng-template #menu>\n  @if (!searching() || !app.responsive()) {\n    <ul\n      nz-menu\n      app-navigation\n      class=\"menu-site\"\n      [nzMode]=\"app.isMobile() ? 'inline' : 'horizontal'\"\n      [nzSelectable]=\"false\"\n      (languageChange)=\"toggleLanguage()\"\n    ></ul>\n\n    @if (app.responsive() !== 'crowded') {\n      <nz-select\n        nzSize=\"small\"\n        nzVariant=\"filled\"\n        [style.max-width.px]=\"126\"\n        [style.min-width.px]=\"90\"\n        [nzOptions]=\"versions\"\n        [ngModel]=\"currentVersion\"\n        (ngModelChange)=\"navigateToVersion($event)\"\n      />\n      <button\n        id=\"language\"\n        nz-tooltip\n        [nzTooltipTitle]=\"language() === 'en' ? 'English / 中文' : '中文 / English'\"\n        nzTooltipPlacement=\"bottom\"\n        nz-button\n        nzSize=\"small\"\n        nzType=\"text\"\n        (click)=\"toggleLanguage()\"\n      >\n        <span [class.active]=\"language() === 'zh'\">中</span>\n        <span [class.active]=\"language() === 'en'\">En</span>\n      </button>\n      <button\n        id=\"direction\"\n        [class]=\"dir()\"\n        nz-tooltip\n        [nzTooltipTitle]=\"dir() | uppercase\"\n        nzTooltipPlacement=\"bottom\"\n        nz-button\n        nzSize=\"small\"\n        nzType=\"text\"\n        (click)=\"toggleDirection()\"\n      >\n        <nz-icon>\n          <svg viewBox=\"0 0 20 20\" width=\"20\" height=\"20\" fill=\"currentColor\">\n            <path\n              d=\"m14.6961816 11.6470802.0841184.0726198 2 2c.2662727.2662727.2904793.682876.0726198.9764816l-.0726198.0841184-2 2c-.2929.2929-.7677.2929-1.0606 0-.2662727-.2662727-.2904793-.682876-.0726198-.9764816l.0726198-.0841184.7196-.7197h-10.6893c-.41421 0-.75-.3358-.75-.75 0-.3796833.28215688-.6934889.64823019-.7431531l.10176981-.0068469h10.6893l-.7196-.7197c-.2929-.2929-.2929-.7677 0-1.0606.2662727-.2662727.682876-.2904793.9764816-.0726198zm-8.1961616-8.6470802c.30667 0 .58246.18671.69635.47146l3.00003 7.50004c.1538.3845-.0333.821-.41784.9749-.38459.1538-.82107-.0333-.9749-.4179l-.81142-2.0285h-2.98445l-.81142 2.0285c-.15383.3846-.59031.5717-.9749.4179-.38458-.1539-.57165-.5904-.41781-.9749l3-7.50004c.1139-.28475.38968-.47146.69636-.47146zm8.1961616 1.14705264.0841184.07261736 2 2c.2662727.26626364.2904793.68293223.0726198.97654222l-.0726198.08411778-2 2c-.2929.29289-.7677.29289-1.0606 0-.2662727-.26626364-.2904793-.68293223-.0726198-.97654222l.0726198-.08411778.7196-.7196675h-3.6893c-.4142 0-.75-.3357925-.75-.7500025 0-.3796925.2821653-.69348832.6482323-.74315087l.1017677-.00684663h3.6893l-.7196-.7196725c-.2929-.29289-.2929-.76777 0-1.06066.2662727-.26626364.682876-.29046942.9764816-.07261736zm-8.1961616 1.62238736-.89223 2.23056h1.78445z\"></path>\n          </svg>\n        </nz-icon>\n      </button>\n      <app-github-btn />\n    }\n  }\n</ng-template>\n"
  },
  {
    "path": "scripts/site/doc/app/header/header.component.ts",
    "content": "import { NgTemplateOutlet, UpperCasePipe } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, inject, signal, Version } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzConfigService } from 'ng-zorro-antd/core/config';\nimport { NzDropdownModule } from 'ng-zorro-antd/dropdown';\nimport { NzGridModule } from 'ng-zorro-antd/grid';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\nimport { NzPopoverModule } from 'ng-zorro-antd/popover';\nimport { NzSelectModule } from 'ng-zorro-antd/select';\nimport { NzTooltipModule } from 'ng-zorro-antd/tooltip';\nimport { VERSION } from 'ng-zorro-antd/version';\n\nimport { AppService } from '../app.service';\nimport { APP_LANGUAGE } from '../app.token';\nimport { GithubButtonComponent } from './github-button.component';\nimport { NavigationComponent } from './navigation.component';\nimport { SearchbarComponent } from './searchbar.component';\n\n@Component({\n  selector: 'app-header',\n  templateUrl: './header.component.html',\n  imports: [\n    FormsModule,\n    NgTemplateOutlet,\n    NzGridModule,\n    NzIconModule,\n    NzMenuModule,\n    NzSelectModule,\n    NzButtonModule,\n    NzDropdownModule,\n    NzPopoverModule,\n    NzTooltipModule,\n    GithubButtonComponent,\n    SearchbarComponent,\n    NavigationComponent,\n    UpperCasePipe\n  ],\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class HeaderComponent {\n  private readonly nzConfigService = inject(NzConfigService);\n  protected readonly app = inject(AppService);\n  protected readonly language = inject(APP_LANGUAGE);\n  protected readonly dir = this.app.directionality.valueSignal;\n\n  readonly searching = signal(false);\n  readonly oldVersionList = [\n    '20.4.x',\n    '19.3.x',\n    '18.2.x',\n    '17.4.x',\n    '16.2.x',\n    '15.1.x',\n    '14.3.x',\n    '13.4.x',\n    '12.1.x',\n    '11.4.x',\n    '10.2.x',\n    '9.3.x',\n    '8.5.x',\n    '7.5.x'\n  ];\n  readonly currentVersion: string = VERSION.full;\n  readonly versions = [this.currentVersion, ...this.oldVersionList].map(v => ({\n    label: this.getVersionLabel(v),\n    value: v\n  }));\n\n  getVersionLabel(version: string): string {\n    if (version.includes('next')) {\n      return 'next';\n    } else if (version.includes('alpha')) {\n      return 'alpha';\n    } else if (version.includes('beta')) {\n      return 'beta';\n    }\n    const major = new Version(version).major;\n    return VERSION.major === major ? version : `v${major}`;\n  }\n\n  onFocusChange(focus: boolean): void {\n    this.searching.set(focus);\n  }\n\n  toggleLanguage(): void {\n    this.language.update(lang => (lang === 'zh' ? 'en' : 'zh'));\n  }\n\n  toggleDirection(): void {\n    this.dir.update(dir => (dir === 'rtl' ? 'ltr' : 'rtl'));\n    this.nzConfigService.set('modal', { nzDirection: this.dir() });\n    this.nzConfigService.set('drawer', { nzDirection: this.dir() });\n    this.nzConfigService.set('message', { nzDirection: this.dir() });\n    this.nzConfigService.set('notification', { nzDirection: this.dir() });\n    this.nzConfigService.set('image', { nzDirection: this.dir() });\n  }\n\n  navigateToVersion(version: string): void {\n    if (version !== this.currentVersion) {\n      window.location.href = `${window.location.origin}/version/${version}`;\n    } else {\n      window.location.href = window.location.origin;\n    }\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/app/header/header.less",
    "content": "@import '../../style/github-button';\n\n@header-height: 64px;\n@menu-item-border: 2px;\n@mobile-max-width: 767.99px;\n\n#header {\n  position: relative;\n  z-index: 10;\n  max-width: 100%;\n  background: @component-background;\n  box-shadow: 0 2px 8px rgba(240, 241, 242, 65);\n\n  #logo strong {\n    font-weight: 500;\n  }\n\n  .menu-row {\n    display: flex;\n    align-items: center;\n    margin: 0;\n\n    > * {\n      flex: none;\n      margin: 0 16px 0 0;\n\n      &:last-child {\n        margin-inline-end: 40px;\n      }\n    }\n  }\n}\n\n@media only screen and (max-width: @mobile-max-width) {\n  #header {\n    text-align: center;\n  }\n}\n\n#github-btn {\n  display: flex;\n  flex-flow: nowrap;\n  height: auto;\n\n  .gh-btn {\n    height: auto;\n    padding: 1px 4px;\n    background: transparent;\n    border: 0;\n\n    .gh-ico {\n      width: 20px;\n      height: 20px;\n      margin: 0;\n    }\n\n    .gh-text {\n      display: none;\n    }\n  }\n\n  .gh-count {\n    min-width: 45px;\n    height: auto;\n    padding: 4px 8px;\n    font-weight: normal;\n    background: #fff;\n\n    &:hover {\n      color: @primary-color;\n    }\n  }\n\n  &.responsive-mode {\n    .gh-count {\n      display: none !important;\n    }\n  }\n}\n\n#logo {\n  height: @header-height;\n  padding-inline-start: 40px;\n  overflow: hidden;\n  color: @site-heading-color;\n  font-size: 18px;\n  font-family: AlibabaSans, @font-family, sans-serif;\n  line-height: @header-height;\n  white-space: nowrap;\n  text-decoration: none;\n\n  img {\n    position: relative;\n    top: -1.5px;\n    width: 28.27px;\n    height: 32px;\n    margin-inline-end: 16px;\n  }\n}\n\n@media only screen and (max-width: @mobile-max-width) {\n  #logo {\n    padding-inline: 0;\n  }\n}\n\n#nav {\n  height: 100%;\n  font-size: 14px;\n  font-family: AlibabaSans, @font-family, sans-serif;\n  border: 0;\n\n  &.ant-menu-horizontal {\n    border-bottom: none;\n\n    & > .ant-menu-item,\n    & > .ant-menu-submenu {\n      min-width: (40px + 12px * 2);\n      height: @header-height;\n      padding-inline: 12px;\n      line-height: @header-height;\n\n      &::after {\n        inset-inline: 12px;\n        top: 0;\n        bottom: auto;\n        border-width: @menu-item-border;\n      }\n    }\n\n    & .ant-menu-submenu-title .anticon {\n      margin: 0;\n    }\n\n    & > .ant-menu-item-selected {\n      a {\n        color: @primary-color;\n      }\n    }\n  }\n\n  & > .ant-menu-item,\n  & > .ant-menu-submenu {\n    text-align: center;\n  }\n}\n\n.header-link {\n  color: @site-text-color;\n}\n\n.ant-menu-item-active .header-link {\n  color: @primary-color;\n}\n\n// Popover menu is only used for mobile\n.popover-menu {\n  width: 300px;\n\n  .ant-popover-inner-content {\n    padding: 0;\n\n    #nav {\n      .ant-menu-item,\n      .ant-menu-submenu {\n        text-align: left;\n      }\n\n      .ant-menu-item-group-title {\n        padding-inline-start: 24px;\n      }\n\n      .ant-menu-item-group-list {\n        padding: 0 16px;\n      }\n\n      .ant-menu-item,\n      a {\n        color: #333;\n      }\n    }\n  }\n}\n\n@search-icon-color: #ced4d9;\n\n#search-box {\n  position: relative;\n  display: flex;\n  flex: auto !important;\n  align-items: center;\n  height: 22px;\n  margin-inline-end: auto;\n  padding-inline-start: 16px;\n  line-height: 22px;\n  white-space: nowrap;\n  border-inline-start: 1px solid @site-border-color-split;\n  transition: width 0.5s;\n\n  > * {\n    flex: auto;\n  }\n\n  .anticon {\n    position: absolute;\n    top: 50%;\n    z-index: 1;\n    flex: none;\n    color: @search-icon-color;\n    transform: translateY(-50%);\n    pointer-events: none;\n  }\n\n  input {\n    width: 100%;\n    max-width: 200px;\n    padding-inline-start: 20px;\n    font-size: 14px;\n    background: transparent;\n    border: 0;\n    box-shadow: none;\n\n    &::placeholder {\n      color: #a3b1bf;\n    }\n  }\n\n  // ================ Narrow ================\n  &.narrow-mode {\n    flex: none !important;\n    width: 30px;\n\n    &:hover {\n      .anticon {\n        color: #a3b1bf;\n      }\n    }\n\n    .anticon {\n      inset-inline-end: 0;\n      inset-inline-start: auto;\n    }\n\n    input {\n      max-width: none;\n      padding-inline-start: 11px;\n      padding-inline-end: 20px;\n      cursor: pointer;\n    }\n\n    &.focused {\n      width: 500px;\n\n      .anticon {\n        color: @search-icon-color;\n      }\n\n      input {\n        cursor: text;\n      }\n    }\n  }\n}\n\n#language {\n  position: relative;\n  width: 1.2em;\n  height: 1.2em;\n  transition: all 0.2s;\n\n  span {\n    position: absolute;\n    color: rgba(0, 0, 0, 0.88);\n    font-size: 1.2em;\n    line-height: 1;\n    border: 1px solid rgba(0, 0, 0, 0.88);\n  }\n\n  span.active {\n    top: -5%;\n    z-index: 1;\n    color: #fff;\n    background-color: rgba(0, 0, 0, 0.88);\n    transform: scale(0.7);\n    transform-origin: 0 0;\n    inset-inline-start: -5%;\n  }\n\n  span:not(.active) {\n    inset-inline-end: -5%;\n    bottom: -5%;\n    z-index: 0;\n    transform: scale(0.5);\n    transform-origin: 100% 100%;\n  }\n}\n\n#direction.rtl {\n  svg {\n    transform: scaleX(-1);\n  }\n}\n\n.component-select {\n  &.ant-select-dropdown {\n    font-size: 14px;\n    border: 0;\n    border-radius: 0;\n    box-shadow: 0 0 8px rgba(0, 0, 0, 0.25);\n  }\n\n  .ant-select-dropdown-menu {\n    max-height: 200px;\n  }\n\n  .ant-select-dropdown-menu-item {\n    border-radius: 0 !important;\n  }\n}\n\n@media only screen and (max-width: @mobile-max-width) {\n  #search-box {\n    display: none;\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/app/header/navigation.component.ts",
    "content": "import { NgTemplateOutlet } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, inject, ViewEncapsulation } from '@angular/core';\nimport { RouterLink } from '@angular/router';\n\nimport { NzButtonModule } from 'ng-zorro-antd/button';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\n\nimport { APP_LANGUAGE, APP_PAGE } from '../app.token';\nimport { AppService } from '../app.service';\n\n@Component({\n  selector: 'ul[nz-menu][app-navigation]',\n  imports: [RouterLink, NgTemplateOutlet, NzButtonModule, NzMenuModule, NzIconModule],\n  template: `\n    <li nz-menu-item [nzSelected]=\"page() === 'docs'\">\n      <a [routerLink]=\"['docs', 'introduce', language()]\">\n        <span>{{ language() === 'zh' ? '文档' : 'Docs' }}</span>\n      </a>\n    </li>\n    <li nz-menu-item [nzSelected]=\"page() === 'components'\">\n      <a [routerLink]=\"['components', 'overview', language()]\">\n        <span>{{ language() === 'zh' ? '组件' : 'Components' }}</span>\n      </a>\n    </li>\n    <li nz-menu-item [nzSelected]=\"page() === 'experimental'\">\n      <a [routerLink]=\"['experimental', 'pipes', language()]\">\n        <span>{{ language() === 'zh' ? '实验性功能' : 'Experimental' }}</span>\n      </a>\n    </li>\n    @if (app.isMobile()) {\n      <ng-container [ngTemplateOutlet]=\"additionalItems\"></ng-container>\n    } @else if (app.responsive() === 'crowded') {\n      <li nz-submenu [nzTitle]=\"additionalTitle\" nzMenuClassName=\"top-menu-additional\">\n        <ng-template #additionalTitle>\n          <nz-icon nzType=\"unordered-list\" />\n        </ng-template>\n        <ul>\n          <ng-container [ngTemplateOutlet]=\"additionalItems\"></ng-container>\n        </ul>\n      </li>\n    }\n    <ng-template #additionalItems>\n      <li nz-menu-item>\n        <a href=\"https://github.com/NG-ZORRO/ng-zorro-antd\" target=\"_blank\" rel=\"noopener noreferrer\">Github</a>\n      </li>\n      <li nz-menu-item>\n        <a (click)=\"changeLanguage()\">{{ language() == 'zh' ? 'English' : '中文' }}</a>\n      </li>\n    </ng-template>\n  `,\n  styles:\n    `\n      ::ng-deep .top-menu-additional {\n        position: relative;\n        inset-inline-end: 80px;\n        width: 190px;\n      }\n    `\n  ,\n  host: {\n    id: 'nav'\n  },\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None\n})\nexport class NavigationComponent {\n  protected readonly page = inject(APP_PAGE).asReadonly();\n  protected readonly language = inject(APP_LANGUAGE);\n  protected readonly app = inject(AppService);\n\n  changeLanguage(): void {\n    this.language.update(lang => lang === 'zh' ? 'en' : 'zh');\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/app/header/searchbar.component.ts",
    "content": "import {\n  ChangeDetectionStrategy,\n  Component,\n  effect,\n  ElementRef,\n  inject,\n  output,\n  signal,\n  viewChild,\n  ViewEncapsulation\n} from '@angular/core';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzInputModule } from 'ng-zorro-antd/input';\n\nimport { loadScript } from '../utils/load-script';\nimport { APP_LANGUAGE } from '../app.token';\nimport { AppService } from '../app.service';\n\ndeclare const docsearch: any;\n\n@Component({\n  selector: 'div[app-searchbar]',\n  imports: [NzIconModule, NzInputModule],\n  template: `\n    <nz-icon nzType=\"search\" />\n    <input\n      nz-input\n      #searchInput\n      (focus)=\"triggerFocus(true)\"\n      (blur)=\"triggerFocus(false)\"\n      [placeholder]=\"language() == 'zh' ? '在 ng.ant.design 中搜索' : 'Search in ng.ant.design'\"\n    />\n  `,\n  host: {\n    id: 'search-box',\n    '[class.focused]': 'focused',\n    '[class.narrow-mode]': 'app.responsive()',\n    '(document:keyup.s)': 'onKeyUp($any($event))'\n  },\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None\n})\nexport class SearchbarComponent {\n  protected readonly language = inject(APP_LANGUAGE);\n  protected readonly app = inject(AppService);\n\n  readonly searchInput = viewChild.required<ElementRef<HTMLInputElement>>('searchInput');\n  readonly focusChange = output<boolean>();\n\n  focused = signal(false);\n  docsearch: any = null;\n\n  constructor() {\n    effect(() => {\n      if (this.docsearch) {\n        this.docsearch.algoliaOptions = { hitsPerPage: 5, facetFilters: [`tags:${this.language()}`] };\n      }\n    });\n  }\n\n  triggerFocus(focus: boolean): void {\n    if (this.docsearch) {\n      this.focused.set(focus);\n      this.focusChange.emit(focus);\n    } else {\n      this.init();\n    }\n  }\n\n  onKeyUp(event: KeyboardEvent): void {\n    if (this.searchInput().nativeElement && event.target === document.body) {\n      this.searchInput().nativeElement.focus();\n    }\n  }\n\n  init(): void {\n    loadScript('https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.js').then(() => {\n      this.docsearch = docsearch({\n        appId: 'BH4D9OD16A',\n        apiKey: '9f7d9d6527ff52ec484e90bb1f256971',\n        indexName: 'ng_zorro',\n        inputSelector: '#search-box input',\n        algoliaOptions: { hitsPerPage: 5, facetFilters: [`tags:${this.language()}`] },\n        transformData(hits: any): void {\n          hits.forEach((hit: any) => {\n            hit.url = hit.url.replace('ng.ant.design', location.host);\n            hit.url = hit.url.replace('https:', location.protocol);\n          });\n          return hits;\n        },\n        debug: false\n      });\n      this.searchInput().nativeElement.focus();\n    });\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/app/nav-bottom/nav-bottom.component.ts",
    "content": "import { Platform } from '@angular/cdk/platform';\nimport { ChangeDetectionStrategy, Component, inject, signal } from '@angular/core';\nimport { NavigationEnd, Router, RouterLink } from '@angular/router';\n\nimport { NzIconModule } from 'ng-zorro-antd/icon';\n\nimport { ROUTER_LIST } from '../router';\nimport { APP_LANGUAGE } from '../app.token';\nimport { filter, withLatestFrom } from 'rxjs/operators';\nimport { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';\n\n@Component({\n  selector: 'app-nav-bottom',\n  imports: [RouterLink, NzIconModule],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `\n    <section class=\"prev-next-nav\">\n      @if (index() > 1) {\n        @let prev = list()[index() - 1];\n        <a class=\"prev-page\" [routerLink]=\"prev.path\">\n          <nz-icon nzType=\"left\" class=\"footer-nav-icon-before\" />\n          {{ prev.label }}\n          <nz-icon nzType=\"right\" class=\"footer-nav-icon-after\" />\n        </a>\n      }\n      @if (index() < list().length - 1) {\n        @let next = list()[index() + 1];\n        <a class=\"next-page\" [routerLink]=\"next.path\">\n          <nz-icon nzType=\"left\" class=\"footer-nav-icon-before\" />\n          {{ next.label }}\n          <nz-icon nzType=\"right\" class=\"footer-nav-icon-after\" />\n        </a>\n      }\n    </section>\n  `\n})\nexport class NavBottomComponent {\n  readonly list = signal<any[]>([]);\n  readonly index = signal(0);\n\n  constructor() {\n    if (inject(Platform).isBrowser) {\n      const navigated$ = inject(Router).events.pipe(filter(e => e instanceof NavigationEnd));\n      const language$ = toObservable(inject(APP_LANGUAGE));\n\n      navigated$.pipe(withLatestFrom(language$), takeUntilDestroyed()).subscribe(([_, language]) => {\n        const url = window.location.pathname.slice(1);\n        const componentsList = ROUTER_LIST.components\n          .filter(e => e.language === language)\n          .map(({ children }) => children)\n          .flat();\n        const list = [\n          ...ROUTER_LIST.intro.filter(item => item.language === language),\n          ...componentsList.filter(item => !item.experimental)\n        ];\n\n        this.list.set(list);\n        this.index.set(list.findIndex(item => item.path === url));\n      });\n    }\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/app/nav-progress-bar/nav-progress-bar.component.less",
    "content": ":host {\n  position: fixed;\n  top: 0;\n  left: 0;\n  z-index: 999;\n  display: block;\n  width: 100%;\n  height: 2.5px;\n  background: transparent;\n\n  &::after {\n    display: block;\n    width: 40%;\n    height: 100%;\n    background: var(--ant-primary-color);\n    transform-origin: left;\n    animation: nav-progress 1.5s infinite linear;\n    content: '';\n  }\n}\n\n@keyframes nav-progress {\n  0% {\n    transform: translateX(250%) scaleX(0.2);\n  }\n\n  80% {\n    transform: translateX(0) scaleX(1);\n  }\n\n  100% {\n    transform: translateX(0) scaleX(0);\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/app/nav-progress-bar/nav-progress-bar.component.ts",
    "content": "import { ChangeDetectionStrategy, Component, inject } from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { NavigationCancel, NavigationEnd, NavigationError, NavigationStart, Router } from '@angular/router';\nimport { filter, map } from 'rxjs';\n\n@Component({\n  selector: 'app-nav-progress-bar',\n  template: '',\n  styleUrl: './nav-progress-bar.component.less',\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    class: 'nav-progress-bar',\n    '[hidden]': '!navigating()'\n  }\n})\nexport class NavProgressBar {\n  readonly navigating = toSignal(\n    inject(Router).events.pipe(\n      filter(event =>\n        [NavigationStart, NavigationEnd, NavigationError, NavigationCancel].some(o => event instanceof o)\n      ),\n      map(event => event instanceof NavigationStart)\n    ),\n    { initialValue: true }\n  )\n}\n"
  },
  {
    "path": "scripts/site/doc/app/online-ide/files/angular.json.ts",
    "content": "export default {\n  $schema: './node_modules/@angular/cli/lib/config/schema.json',\n  version: 1,\n  newProjectRoot: 'projects',\n  projects: {\n    demo: {\n      root: '',\n      sourceRoot: 'src',\n      projectType: 'application',\n      prefix: 'app',\n      architect: {\n        build: {\n          builder: '@angular/build:application',\n          options: {\n            browser: 'src/main.ts',\n            tsConfig: 'tsconfig.app.json',\n            assets: [\n              'src/favicon.ico',\n              'src/assets',\n              {\n                glob: '**/*',\n                input: 'node_modules/monaco-editor/min/vs',\n                output: 'assets/vs'\n              }\n            ],\n            styles: [\n              'node_modules/ng-zorro-antd/src/ng-zorro-antd.min.css',\n              'node_modules/ng-zorro-antd/resizable/style/index.min.css',\n              'node_modules/ng-zorro-antd/code-editor/style/index.min.css',\n              'node_modules/ng-zorro-antd/graph/style/index.min.css',\n              'src/styles.css'\n            ]\n          },\n          configurations: {\n            production: {\n              budgets: [\n                {\n                  type: 'initial',\n                  maximumWarning: '500kB',\n                  maximumError: '1MB'\n                },\n                {\n                  type: 'anyComponentStyle',\n                  maximumWarning: '4kB',\n                  maximumError: '8kB'\n                }\n              ],\n              outputHashing: 'all'\n            },\n            development: {\n              optimization: false,\n              extractLicenses: false,\n              sourceMap: true\n            }\n          },\n          defaultConfiguration: 'production'\n        },\n        serve: {\n          builder: '@angular/build:dev-server',\n          configurations: {\n            production: {\n              buildTarget: 'demo:build:production'\n            },\n            development: {\n              buildTarget: 'demo:build:development'\n            }\n          },\n          defaultConfiguration: 'development'\n        }\n      }\n    }\n  }\n};\n"
  },
  {
    "path": "scripts/site/doc/app/online-ide/files/app.config.ts",
    "content": "export default `import { registerLocaleData } from '@angular/common';\nimport { ApplicationConfig } from '@angular/core';\nimport { provideHttpClient, withJsonpSupport } from '@angular/common/http';\nimport en from '@angular/common/locales/en';\n\nimport { provideNzIcons } from 'ng-zorro-antd/icon';\nimport { en_US, provideNzI18n } from 'ng-zorro-antd/i18n';\nimport { IconDefinition } from '@ant-design/icons-angular';\nimport * as AllIcons from '@ant-design/icons-angular/icons';\n\nregisterLocaleData(en);\n\nconst antDesignIcons = AllIcons as {\n  [key: string]: IconDefinition;\n};\nconst icons: IconDefinition[] = Object.keys(antDesignIcons).map(key => antDesignIcons[key])\n\nexport const appConfig: ApplicationConfig = {\n  providers: [\n    provideHttpClient(withJsonpSupport()),\n    provideNzIcons(icons),\n    provideNzI18n(en_US)\n  ]\n};\n`;\n"
  },
  {
    "path": "scripts/site/doc/app/online-ide/files/main.ts",
    "content": "export default (componentName: string) => `import { bootstrapApplication } from '@angular/platform-browser';\n\nimport { appConfig } from './app/app.config';\nimport { ${componentName} } from './app/app';\n\nbootstrapApplication(${componentName}, appConfig)\n  .catch((err) => console.error(err));\n`;\n"
  },
  {
    "path": "scripts/site/doc/app/online-ide/files/package.json.ts",
    "content": "/**\n * Generate package.json content\n * @param nzVersion version of ng-zorro-antd\n * @param ngVersion version of Angular\n */\nexport default (nzVersion: string, ngVersion: string) => {\n  return {\n    name: 'ng-zorro-demo',\n    private: true,\n    scripts: {\n      ng: 'ng',\n      start: 'ng serve',\n      build: 'ng build'\n    },\n    dependencies: {\n      '@angular/core': ngVersion,\n      '@angular/forms': ngVersion,\n      '@angular/common': ngVersion,\n      '@angular/router': ngVersion,\n      '@angular/compiler': ngVersion,\n      '@angular/platform-browser': ngVersion,\n      '@angular/cdk': ngVersion,\n      '@angular/platform-browser-dynamic': ngVersion,\n      '@ant-design/icons-angular': ngVersion,\n      'date-fns': '^2.16.1',\n      rxjs: '~7.8.1',\n      tslib: '^2.0.0',\n      'ng-zorro-antd': nzVersion,\n      // demo needs\n      d3: '^6.3.1',\n      dagre: '^0.8.5',\n      'dagre-compound': '^0.0.8',\n      'cron-parser': '^4.6.0',\n      'monaco-editor': '^0.33.0'\n    },\n    devDependencies: {\n      '@angular/build': ngVersion,\n      '@angular/cli': ngVersion,\n      '@angular/compiler-cli': ngVersion,\n      typescript: '~5.9.2'\n    }\n  };\n};\n"
  },
  {
    "path": "scripts/site/doc/app/online-ide/files/tsconfig.app.json.ts",
    "content": "export default {\n  extends: './tsconfig.json',\n  compilerOptions: {\n    outDir: './out-tsc/app',\n    types: []\n  },\n  include: ['src/**/*.ts']\n};\n"
  },
  {
    "path": "scripts/site/doc/app/online-ide/files/tsconfig.json.ts",
    "content": "export default {\n  compileOnSave: false,\n  compilerOptions: {\n    strict: true,\n    noImplicitOverride: true,\n    noPropertyAccessFromIndexSignature: true,\n    noImplicitReturns: true,\n    noFallthroughCasesInSwitch: true,\n    skipLibCheck: true,\n    isolatedModules: true,\n    importHelpers: true,\n    target: 'ES2022',\n    module: 'preserve'\n  },\n  angularCompilerOptions: {\n    enableI18nLegacyMessageIdFormat: false,\n    strictInjectionParameters: true,\n    strictInputAccessModifiers: true,\n    typeCheckHostBindings: true,\n    strictTemplates: true\n  }\n};\n"
  },
  {
    "path": "scripts/site/doc/app/online-ide/online-ide.service.ts",
    "content": "import { Injectable } from '@angular/core';\n\nimport sdk from '@stackblitz/sdk';\nimport { VERSION } from 'ng-zorro-antd/version';\n\nimport angularJSON from './files/angular.json';\nimport appConfigTS from './files/app.config';\nimport mainTS from './files/main';\nimport packageJSON from './files/package.json';\nimport tsconfigJSON from './files/tsconfig.json';\nimport tsconfigAppJSON  from './files/tsconfig.app.json';\n\n@Injectable({\n  providedIn: 'root'\n})\nexport class OnlineIdeService {\n  openOnStackBlitz(componentName: string, appComponentCode: string, selector: string): void {\n    sdk.openProject({\n      title: 'NG-ZORRO',\n      description: 'Ant Design of Angular',\n      template: 'node',\n      files: {\n        'package.json': JSON.stringify(packageJSON(`^${VERSION.full}`, `^${VERSION.major}.0.0`), null, 2),\n        'angular.json':  JSON.stringify(angularJSON, null, 2),\n        'tsconfig.json':  JSON.stringify(tsconfigJSON, null, 2),\n        'tsconfig.app.json': JSON.stringify(tsconfigAppJSON, null, 2),\n        'src/index.html': `<${selector}>loading</${selector}>`,\n        'src/main.ts': mainTS(componentName),\n        'src/app/app.ts': appComponentCode,\n        'src/app/app.config.ts': appConfigTS,\n        'src/styles.css': `/* Add application styles & imports to this file! */`\n      }\n    }, {\n      // open demo component by default\n      openFile: 'src/app/app.ts'\n    });\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/app/router.ts",
    "content": "import { RouterList } from './types';\nimport { Routes } from '@angular/router';\n\nexport const ROUTER_LIST: RouterList = {\n  components: [],\n  intro: []\n}\n\nexport const DEMO_ROUTES: Routes = [];\n"
  },
  {
    "path": "scripts/site/doc/app/share/share.module.ts",
    "content": "import { DragDropModule } from '@angular/cdk/drag-drop';\nimport { ScrollingModule } from '@angular/cdk/scrolling';\nimport { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { FormsModule, ReactiveFormsModule } from '@angular/forms';\nimport { RouterModule } from '@angular/router';\n\nimport { NzAffixModule } from 'ng-zorro-antd/affix';\nimport { NzAnchorModule } from 'ng-zorro-antd/anchor';\nimport { NzGridModule } from 'ng-zorro-antd/grid';\nimport { NzIconModule } from 'ng-zorro-antd/icon';\nimport { NzSpaceModule } from 'ng-zorro-antd/space';\nimport { NzTooltipModule } from 'ng-zorro-antd/tooltip';\n\nimport { NzCodeBoxComponent } from '../codebox/codebox.component';\nimport { ComponentMetaComponent } from '../component-meta/component-meta.component';\n\n@NgModule({\n  imports: [\n    CommonModule,\n    FormsModule,\n    RouterModule,\n    ReactiveFormsModule,\n    ComponentMetaComponent,\n    NzCodeBoxComponent,\n    NzTooltipModule,\n    NzAnchorModule,\n    NzAffixModule,\n    NzGridModule,\n    NzIconModule,\n    NzSpaceModule,\n    // third libs\n    DragDropModule\n  ],\n  exports: [\n    CommonModule,\n    FormsModule,\n    ReactiveFormsModule,\n    RouterModule,\n    NzCodeBoxComponent,\n    ComponentMetaComponent,\n    NzAnchorModule,\n    NzAffixModule,\n    NzGridModule,\n    NzTooltipModule,\n    NzIconModule,\n    NzSpaceModule,\n    // third libs\n    ScrollingModule,\n    DragDropModule\n  ]\n})\nexport class ShareModule {}\n"
  },
  {
    "path": "scripts/site/doc/app/side/side.component.html",
    "content": "<ul\n  class=\"aside-container\"\n  nz-menu\n  nzMode=\"inline\"\n  [nzInlineIndent]=\"40\"\n  [dir]=\"dir()\"\n>\n  @if (page() === 'docs') {\n    @for (intro of intro(); track $index) {\n      <li nz-menu-item nzMatchRouter>\n        <a class=\"menu-title-content-link\" routerLink=\"{{ intro.path }}\">\n          <span>{{ intro.label }}</span>\n          @if (intro.tag) {\n            <ng-container *ngTemplateOutlet=\"tag; context: { $implicit: intro.tag }\"></ng-container>\n          }\n        </a>\n      </li>\n    }\n  } @else if (page() === 'components') {\n    <li nz-menu-item nzMatchRouter>\n      <a [routerLink]=\"`components/overview/${language()}`\">\n        <span>{{ language() === 'zh' ? '组件总览' : 'Components Overview' }}</span>\n      </a>\n    </li>\n    <li nz-menu-item nzMatchRouter>\n      <a class=\"menu-title-content-link\" [routerLink]=\"`components/changelog/${language()}`\">\n        <span>{{ language() === 'zh' ? '更新日志' : 'Change Log' }}</span>\n        <ng-container *ngTemplateOutlet=\"tag; context: { $implicit: '{{version}}' }\"></ng-container>\n      </a>\n    </li>\n\n    @for (group of componentList(); track $index) {\n      <li nz-menu-group [nzTitle]=\"group.name\">\n        <ul>\n          @for (component of group.children; track $index) {\n            <li nz-menu-item nzMatchRouter>\n              <a class=\"menu-title-content-link\" [routerLink]=\"component.path\">\n                <span>\n                  {{ component.label }}\n                  <span class=\"chinese\">{{ component.zh }}</span>\n                </span>\n                @if (component.tag) {\n                  <ng-container *ngTemplateOutlet=\"tag; context: { $implicit: component.tag }\"></ng-container>\n                }\n              </a>\n            </li>\n          }\n        </ul>\n      </li>\n    }\n  } @else if (page() === 'experimental') {\n    @for (group of componentList(); track $index) {\n      <li nz-menu-group [nzTitle]=\"group.name\">\n        <ul>\n          @for (component of group.experimentalChildren; track $index) {\n            <li nz-menu-item nzMatchRouter>\n              <a class=\"menu-title-content-link\" [routerLink]=\"component.path\">\n                <span>\n                  {{ component.label }}\n                  <span class=\"chinese\">{{ component.zh }}</span>\n                </span>\n                @if (component.tag) {\n                  <ng-container *ngTemplateOutlet=\"tag; context: { $implicit: component.tag }\"></ng-container>\n                }\n              </a>\n            </li>\n          }\n        </ul>\n      </li>\n    }\n  }\n</ul>\n\n<ng-template #tag let-tag>\n  @let semantic = semanticTags[tag];\n  @if (semantic) {\n    <nz-tag [nzColor]=\"semantic.color\" [nzBordered]=\"false\">\n      {{ semantic.label[language()] }}\n    </nz-tag>\n  } @else {\n    <nz-tag nzColor=\"success\" [nzBordered]=\"false\">{{ tag }}</nz-tag>\n  }\n</ng-template>\n"
  },
  {
    "path": "scripts/site/doc/app/side/side.component.ts",
    "content": "import { BidiModule } from '@angular/cdk/bidi';\nimport { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { RouterLink } from '@angular/router';\n\nimport { NzMenuModule } from 'ng-zorro-antd/menu';\nimport { NzTagColor, NzTagModule } from 'ng-zorro-antd/tag';\nimport { VERSION } from 'ng-zorro-antd/version';\n\nimport { APP_LANGUAGE, APP_PAGE } from '../app.token';\nimport { ROUTER_LIST } from '../router';\nimport { AppService } from '../app.service';\n\ntype I18n<T> = {\n  zh: T;\n  en: T;\n}\n\n@Component({\n  selector: 'app-side',\n  imports: [RouterLink, NgTemplateOutlet, NzMenuModule, NzTagModule, BidiModule],\n  templateUrl: './side.component.html',\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class SideComponent {\n  protected readonly routerList = ROUTER_LIST;\n  protected readonly dir = inject(AppService).directionality.valueSignal;\n  protected readonly page = inject(APP_PAGE).asReadonly();\n  protected readonly language = inject(APP_LANGUAGE).asReadonly();\n  protected readonly intro = computed(() =>\n    this.routerList.intro.filter(intro => intro.language === this.language() && !intro.hidden)\n  );\n  protected readonly componentList = computed(() =>\n    this.routerList.components.filter(\n      group =>\n        group.language === this.language() &&\n        !(this.page() === 'experimental' && group.experimentalChildren.length === 0)\n    )\n  );\n  protected readonly semanticTags : Record<string, {\n    label: I18n<string>,\n    color: NzTagColor\n  }> = {\n    deprecated: { label: { zh: '废弃', en: 'Deprecated' }, color: 'warning' },\n    new: { label: { zh: '新增', en: 'New' }, color: 'success' },\n    updated: { label: { zh: '更新', en: 'Updated' }, color: 'processing' },\n    '{{version}}': { label: { zh: VERSION.full, en: VERSION.full }, color: 'success' }\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/app/types.ts",
    "content": "export interface IntroRouter {\n  path: string;\n  label: string;\n  language: string;\n  order: number;\n  hidden: boolean;\n  description: string;\n  tag?: string;\n  experimental?: boolean;\n}\n\nexport interface ComponentChildRouter {\n  path: string;\n  label: string;\n  description: string;\n  zh: string;\n  cover?: string;\n  /**\n   * The tag of version since the component is available.\n   */\n  tag?: string;\n  /**\n   * Whether the component is hidden.\n   */\n  hidden?: boolean;\n  /**\n   * Whether the component is experimental.\n   */\n  experimental?: boolean;\n}\n\nexport interface ComponentRouter {\n  name: string;\n  language: string;\n  children: ComponentChildRouter[];\n  experimentalChildren: ComponentChildRouter[];\n}\n\nexport interface RouterList {\n  intro: IntroRouter[];\n  components: ComponentRouter[];\n}\n\n"
  },
  {
    "path": "scripts/site/doc/app/utils/load-script.ts",
    "content": "export function loadScript(url: string): Promise<void> {\n  return new Promise((resolve, reject) => {\n    const script = document.createElement('script');\n    script.type = 'text/javascript';\n    script.src = url;\n    script.onload = () => resolve();\n    script.onerror = e => reject(e);\n    document.head!.appendChild(script);\n  });\n}\n"
  },
  {
    "path": "scripts/site/doc/assets/fonts/Raleway/OFL.txt",
    "content": "Copyright (c) 2010, Matt McInerney (matt@pixelspread.com),\nCopyright (c) 2011, Pablo Impallari (www.impallari.com|impallari@gmail.com),\nCopyright (c) 2011, Rodrigo Fuenzalida (www.rfuenzalida.com|hello@rfuenzalida.com), with Reserved Font Name Raleway\nThis Font Software is licensed under the SIL Open Font License, Version 1.1.\nThis license is copied below, and is also available with a FAQ at:\nhttp://scripts.sil.org/OFL\n\n\n-----------------------------------------------------------\nSIL OPEN FONT LICENSE Version 1.1 - 26 February 2007\n-----------------------------------------------------------\n\nPREAMBLE\nThe goals of the Open Font License (OFL) are to stimulate worldwide\ndevelopment of collaborative font projects, to support the font creation\nefforts of academic and linguistic communities, and to provide a free and\nopen framework in which fonts may be shared and improved in partnership\nwith others.\n\nThe OFL allows the licensed fonts to be used, studied, modified and\nredistributed freely as long as they are not sold by themselves. The\nfonts, including any derivative works, can be bundled, embedded, \nredistributed and/or sold with any software provided that any reserved\nnames are not used by derivative works. The fonts and derivatives,\nhowever, cannot be released under any other type of license. The\nrequirement for fonts to remain under this license does not apply\nto any document created using the fonts or their derivatives.\n\nDEFINITIONS\n\"Font Software\" refers to the set of files released by the Copyright\nHolder(s) under this license and clearly marked as such. This may\ninclude source files, build scripts and documentation.\n\n\"Reserved Font Name\" refers to any names specified as such after the\ncopyright statement(s).\n\n\"Original Version\" refers to the collection of Font Software components as\ndistributed by the Copyright Holder(s).\n\n\"Modified Version\" refers to any derivative made by adding to, deleting,\nor substituting -- in part or in whole -- any of the components of the\nOriginal Version, by changing formats or by porting the Font Software to a\nnew environment.\n\n\"Author\" refers to any designer, engineer, programmer, technical\nwriter or other person who contributed to the Font Software.\n\nPERMISSION & CONDITIONS\nPermission is hereby granted, free of charge, to any person obtaining\na copy of the Font Software, to use, study, copy, merge, embed, modify,\nredistribute, and sell modified and unmodified copies of the Font\nSoftware, subject to the following conditions:\n\n1) Neither the Font Software nor any of its individual components,\nin Original or Modified Versions, may be sold by itself.\n\n2) Original or Modified Versions of the Font Software may be bundled,\nredistributed and/or sold with any software, provided that each copy\ncontains the above copyright notice and this license. These can be\nincluded either as stand-alone text files, human-readable headers or\nin the appropriate machine-readable metadata fields within text or\nbinary files as long as those fields can be easily viewed by the user.\n\n3) No Modified Version of the Font Software may use the Reserved Font\nName(s) unless explicit written permission is granted by the corresponding\nCopyright Holder. This restriction only applies to the primary font name as\npresented to the users.\n\n4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font\nSoftware shall not be used to promote, endorse or advertise any\nModified Version, except to acknowledge the contribution(s) of the\nCopyright Holder(s) and the Author(s) or with their explicit written\npermission.\n\n5) The Font Software, modified or unmodified, in part or in whole,\nmust be distributed entirely under this license, and must not be\ndistributed under any other license. The requirement for fonts to\nremain under this license does not apply to any document created\nusing the Font Software.\n\nTERMINATION\nThis license becomes null and void if any of the above conditions are\nnot met.\n\nDISCLAIMER\nTHE FONT SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\nOF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE\nCOPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nINCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL\nDAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM\nOTHER DEALINGS IN THE FONT SOFTWARE.\n"
  },
  {
    "path": "scripts/site/doc/browserslist",
    "content": "# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers\n# For additional information regarding the format and rule options, please see:\n# https://github.com/browserslist/browserslist#queries\n> 0.5%\nlast 2 versions\nFirefox ESR\nnot dead"
  },
  {
    "path": "scripts/site/doc/environments/environment.prod.ts",
    "content": "export const environment = {\n  production: true\n};\n"
  },
  {
    "path": "scripts/site/doc/environments/environment.ts",
    "content": "// This file can be replaced during build by using the `fileReplacements` array.\n// `ng build ---prod` replaces `environment.ts` with `environment.prod.ts`.\n// The list of file replacements can be found in `angular.json`.\n\nexport const environment = {\n  production: false\n};\n"
  },
  {
    "path": "scripts/site/doc/google854eb8b183564acb.html",
    "content": "google-site-verification: google854eb8b183564acb.html"
  },
  {
    "path": "scripts/site/doc/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <link rel=\"preconnect\" href=\"https://gw.alipayobjects.com\" crossorigin=\"anonymous\">\n    <link rel=\"preconnect\" href=\"https://img.alicdn.com\" crossorigin=\"anonymous\">\n    <link rel=\"preconnect\" href=\"https://cdnjs.cloudflare.com\" crossorigin=\"anonymous\">\n    <link rel=\"preconnect\" href=\"https://vars.hotjar.com\">\n    <link rel=\"preconnect\" href=\"https://script.hotjar.com\">\n    <link rel=\"preconnect\" href=\"https://www.google-analytics.com\">\n    <link rel=\"dns-prefetch\" href=\"https://www.google-analytics.com\">\n    <link rel=\"preconnect\" href=\"https://cdn.jsdelivr.net\">\n    <link rel=\"preconnect\" href=\"https://api.github.com\">\n    <link rel=\"preload\" href=\"https://script.hotjar.com/font-hotjar_5.65042d.woff2\" as=\"font\" type=\"font/woff2\" crossorigin>\n\n    <meta name=\"apple-mobile-web-app-capable\" content=\"yes\">\n    <meta name=\"apple-mobile-web-app-status-bar-style\" content=\"translucent\">\n    <meta name=\"mobile-web-app-capable\" content=\"yes\">\n    <meta name=\"keywords\" content=\"angular, ant design, ant, angular ant design, web, ui, components, ng, zorro, responsive, typescript, css, mobile web, open source, 组件库, 组件, UI 框架\">\n    <meta name=\"author\" content=\"NG-ZORRO Team\">\n    <meta name=\"description\" content=\"An enterprise-class UI design language and Angular-based implementation with a set of high-quality Angular components, one of best Angular UI library for enterprises\">\n    <!--Twitter card metadata-->\n    <meta name=\"twitter:card\" content=\"summary\">\n    <meta name=\"twitter:site\" content=\"@ng_zorro\">\n    <meta name=\"twitter:creator\" content=\"@ng_zorro\">\n    <meta name=\"twitter:title\" content=\"NG-ZORRO - Ant Design Of Angular\">\n    <meta name=\"twitter:description\" content=\"An enterprise-class UI design language and Angular-based implementation with a set of high-quality Angular components, one of best Angular UI library for enterprises\">\n    <meta name=\"twitter:image\" content=\"https://ng.ant.design/assets/img/site-preview.png\">\n    <!--Open Graph-->\n    <meta property=\"og:url\" content=\"https://ng.ant.design/\">\n    <meta property=\"og:type\" content=\"website\">\n    <meta property=\"og:title\" content=\"NG-ZORRO - Ant Design Of Angular\">\n    <meta property=\"og:site_name\" content=\"NG-ZORRO - Ant Design Of Angular\">\n    <meta property=\"og:locale\" content=\"en_US\">\n    <meta property=\"og:description\" content=\"An enterprise-class UI design language and Angular-based implementation with a set of high-quality Angular components, one of best Angular UI library for enterprises\">\n    <meta property=\"og:image\" content=\"https://ng.ant.design/assets/img/site-preview.png\">\n    <meta property=\"og:image:secure_url\" content=\"https://ng.ant.design/assets/img/site-preview.png\">\n    <meta property=\"og:image:type\" content=\"image/png\">\n    <meta property=\"og:image:width\" content=\"2048\">\n    <meta property=\"og:image:height\" content=\"1536\">\n    <meta name=\"theme-color\" content=\"#1890ff\">\n\n    <link rel=\"icon shortcut\" href=\"https://img.alicdn.com/tfs/TB1Jr2ASQvoK1RjSZFDXXXY3pXa-200-200.png\" type=\"image/x-icon\">\n    <link rel=\"apple-touch-icon\" sizes=\"180x180\" href=\"assets/icons/apple-icon-180.png\">\n    <link rel=\"apple-touch-icon\" sizes=\"167x167\" href=\"assets/icons/apple-icon-167.png\">\n    <link rel=\"apple-touch-icon\" sizes=\"152x152\" href=\"assets/icons/apple-icon-152.png\">\n    <link rel=\"apple-touch-icon\" sizes=\"120x120\" href=\"assets/icons/apple-icon-120.png\">\n    <link rel=\"manifest\" href=\"manifest.json\">\n    <title>NG-ZORRO Angular UI component library</title>\n    <base href=\"/\">\n    <!-- Hotjar Tracking Code for ng.ant.design -->\n    <script>\n      (function(h,o,t,j,a,r){\n        h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};\n        h._hjSettings={hjid:792689,hjsv:6};\n        a=o.getElementsByTagName('head')[0];\n        r=o.createElement('script');r.async=1;\n        r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;\n        a.appendChild(r);\n      })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');\n    </script>\n\n    <style type=\"text/css\">\n       /* Prevent trigger animations before page load, will be removed when the page is ready */\n      .preload * {\n        -webkit-transition: none !important;\n        -moz-transition: none !important;\n        -ms-transition: none !important;\n        -o-transition: none !important;\n      }\n    </style>\n  </head>\n  <body class=\"preload\">\n    <app-root></app-root>\n    <!-- Global site tag (gtag.js) - Google Analytics -->\n    <script async src=\"https://www.googletagmanager.com/gtag/js?id=UA-52892298-2\"></script>\n    <script>\n      window.dataLayer = window.dataLayer || [];\n      function gtag(){dataLayer.push(arguments);}\n      gtag('js', new Date());\n\n      gtag('config', 'UA-52892298-2');\n    </script>\n    <noscript>Please enable JavaScript to continue using this application.</noscript>\n  </body>\n</html>\n"
  },
  {
    "path": "scripts/site/doc/main.server.ts",
    "content": "import { enableProdMode } from '@angular/core';\nimport { bootstrapApplication, BootstrapContext } from '@angular/platform-browser';\n\nimport { AppComponent } from './app/app.component';\nimport { config } from './app/app.config.server';\nimport { environment } from './environments/environment';\n\nif (environment.production) {\n  enableProdMode();\n}\n\nconst bootstrap = (context: BootstrapContext) => bootstrapApplication(AppComponent, config, context);\n\nexport default bootstrap;\n"
  },
  {
    "path": "scripts/site/doc/main.ts",
    "content": "import { registerLocaleData } from '@angular/common';\nimport zh from '@angular/common/locales/zh';\nimport { enableProdMode } from '@angular/core';\nimport { bootstrapApplication } from '@angular/platform-browser';\n\nimport { AppComponent } from './app/app.component';\nimport { appConfig } from './app/app.config';\nimport { environment } from './environments/environment';\n\nregisterLocaleData(zh);\n\nif (environment.production) {\n  enableProdMode();\n}\n\nbootstrapApplication(AppComponent, appConfig).catch(err => console.log(err));\n"
  },
  {
    "path": "scripts/site/doc/manifest.json",
    "content": "{\n  \"name\": \"Ant Design of Angular - NG-ZORRO\",\n  \"short_name\": \"NG-ZORRO\",\n  \"theme_color\": \"#1976d2\",\n  \"background_color\": \"#fafafa\",\n  \"display\": \"standalone\",\n  \"scope\": \"/\",\n  \"start_url\": \"/\",\n  \"icons\": [\n    {\n      \"src\": \"assets/icons/icon-72.png\",\n      \"sizes\": \"72x72\",\n      \"type\": \"image/png\",\n      \"purpose\": \"any maskable\"\n    },\n    {\n      \"src\": \"assets/icons/icon-96.png\",\n      \"sizes\": \"96x96\",\n      \"type\": \"image/png\",\n      \"purpose\": \"any maskable\"\n    },\n    {\n      \"src\": \"assets/icons/icon-128.png\",\n      \"sizes\": \"128x128\",\n      \"type\": \"image/png\",\n      \"purpose\": \"any maskable\"\n    },\n    {\n      \"src\": \"assets/icons/icon-144.png\",\n      \"sizes\": \"144x144\",\n      \"type\": \"image/png\",\n      \"purpose\": \"any maskable\"\n    },\n    {\n      \"src\": \"assets/icons/icon-152.png\",\n      \"sizes\": \"152x152\",\n      \"type\": \"image/png\",\n      \"purpose\": \"any maskable\"\n    },\n    {\n      \"src\": \"assets/icons/manifest-icon-192.png\",\n      \"sizes\": \"192x192\",\n      \"type\": \"image/png\",\n      \"purpose\": \"any maskable\"\n    },\n    {\n      \"src\": \"assets/icons/manifest-icon-512.png\",\n      \"sizes\": \"512x512\",\n      \"type\": \"image/png\",\n      \"purpose\": \"any maskable\"\n    }\n  ]\n}"
  },
  {
    "path": "scripts/site/doc/robots.txt",
    "content": "user-agent: *\ndisallow: /version/\nsitemap: https://ng.ant.design/sitemap.xml\n"
  },
  {
    "path": "scripts/site/doc/server.ts",
    "content": "import {\n  AngularNodeAppEngine,\n  createNodeRequestHandler,\n  isMainModule,\n  writeResponseToNodeResponse,\n} from '@angular/ssr/node';\nimport express from 'express';\nimport { join } from 'node:path';\n\nconst browserDistFolder = join(import.meta.dirname, '../browser');\n\nconst app = express();\nconst angularApp = new AngularNodeAppEngine();\n\n/**\n * Serve static files from /browser\n */\napp.use(\n  express.static(browserDistFolder, {\n    maxAge: '1y',\n    index: false,\n    redirect: false,\n  }),\n);\n\n/**\n * Handle all other requests by rendering the Angular application.\n */\napp.use((req, res, next) => {\n  angularApp\n    .handle(req)\n    .then((response) =>\n      response ? writeResponseToNodeResponse(response, res) : next(),\n    )\n    .catch(next);\n});\n\n/**\n * Start the server if this module is the main entry point.\n * The server listens on the port defined by the `PORT` environment variable, or defaults to 4000.\n */\nif (isMainModule(import.meta.url)) {\n  const port = process.env['PORT'] || 4000;\n  app.listen(port, (error) => {\n    if (error) {\n      throw error;\n    }\n\n    console.log(`Node Express server listening on http://localhost:${port}`);\n  });\n}\n\n/**\n * Request handler used by the Angular CLI (for dev-server and during build) or Firebase Cloud Functions.\n */\nexport const reqHandler = createNodeRequestHandler(app);\n"
  },
  {
    "path": "scripts/site/doc/style/colors.less",
    "content": ".make-palette(@color, @index: 1) when (@index <= 10) {\n  .palette-@{color}-@{index} {\n    @background: '@{color}-@{index}';\n\n    background: @@background;\n  }\n  .make-palette(@color, (@index + 1)); // next iteration\n}\n\n@gray-1: #fff;\n@gray-2: #fafafa;\n@gray-3: #f5f5f5;\n@gray-4: #f0f0f0;\n@gray-5: #d9d9d9;\n@gray-6: #bfbfbf;\n@gray-7: #8c8c8c;\n@gray-8: #595959;\n@gray-9: #434343;\n@gray-10: #262626;\n@gray-11: #1f1f1f;\n@gray-12: #141414;\n@gray-13: #000;\n@border-color: rgba(229, 231, 235, 100);\n\n.color-palettes {\n  margin: 0 1%;\n\n  &-dark {\n    margin: 0;\n    padding: 0 28px;\n    background-color: #141414;\n\n    .color-title {\n      color: fade(@white, 85);\n    }\n\n    .color-description {\n      color: fade(@white, 45);\n    }\n\n    .color-palette {\n      margin: 45px 3.5% 45px 0;\n\n      &:nth-of-type(3n) {\n        margin-right: 0;\n      }\n\n      .main-color-item {\n        margin-right: 0;\n\n        &:hover {\n          margin-right: -8px;\n        }\n      }\n    }\n  }\n}\n\n.color-palette {\n  display: inline-block;\n  width: 31%;\n  margin: 45px 1%;\n\n  &-pick {\n    margin: 0 0 20px;\n    font-size: 20px;\n    text-align: center;\n  }\n\n  &-picker {\n    margin: 24px 0;\n\n    &-value {\n      position: relative;\n      top: -3px;\n      margin-left: 16px;\n      font-size: 14px;\n      font-family: Consolas, sans-serif;\n    }\n\n    &-validation {\n      position: relative;\n      top: -3px;\n      margin-left: 16px;\n      color: @error-color;\n      font-size: 13px;\n\n      &-dark {\n        margin-left: 0;\n      }\n    }\n  }\n}\n\n.main-color {\n  .make-palette(blue);\n  .make-palette(purple);\n  .make-palette(cyan);\n  .make-palette(green);\n  .make-palette(magenta);\n  .make-palette(red);\n  .make-palette(volcano);\n  .make-palette(orange);\n  .make-palette(gold);\n  .make-palette(yellow);\n  .make-palette(lime);\n  .make-palette(geekblue);\n  .make-palette(gray);\n\n  .palette-gray-11 {\n    background: @gray-11;\n  }\n\n  .palette-gray-12 {\n    background: @gray-12;\n  }\n\n  .palette-gray-13 {\n    background: @gray-13;\n  }\n\n  text-align: left;\n\n  &-item {\n    position: relative;\n    height: 44px;\n    margin-right: 4px;\n    padding: 0 12px;\n    font-size: 14px;\n    font-family: Consolas, sans-serif;\n    line-height: 44px;\n    cursor: pointer;\n    transition: all 0.2s;\n\n    &:first-child {\n      border-radius: 4px 4px 0 0;\n    }\n\n    &:last-child {\n      border-radius: 0 0 4px 4px;\n    }\n\n    &:hover {\n      margin-right: -8px;\n      border-radius: 0 4px 4px 0;\n    }\n  }\n\n  &-item &-text {\n    float: left;\n    transition: all 0.3s;\n  }\n\n  &-item &-value {\n    position: relative;\n    left: 3px;\n    float: right;\n    transform: scale(0.85);\n    transform-origin: 100% 50%;\n    opacity: 0;\n    transition: all 0.3s;\n  }\n}\n\n.color-title {\n  margin: 0 0 24px;\n  color: #5c6b77;\n  font-weight: 500;\n  font-size: 22px;\n  text-align: center;\n  text-transform: capitalize;\n}\n\n.color-description {\n  display: block;\n  color: #777;\n  font-weight: lighter;\n  font-size: 14px;\n}\n\n.main-color:hover {\n  .main-color-value {\n    left: 0;\n    opacity: 0.7;\n  }\n}\n\n.color-palette-horizontal {\n  width: 100%;\n\n  &-dark {\n    height: 303px;\n    padding: 32px 28px;\n    background-color: #141414;\n\n    .color-palette-picker {\n      margin-bottom: 0;\n    }\n\n    .color-palette-pick {\n      color: fade(@white, 65);\n      text-align: left;\n\n      &-hex {\n        color: fade(@white, 65);\n      }\n    }\n  }\n\n  .main-color {\n    display: flex;\n\n    &-item {\n      position: relative;\n      flex: 1;\n      height: 86px;\n      margin-right: 0;\n      padding: 37px 0 0;\n      line-height: normal;\n      text-align: center;\n      border-radius: 0;\n\n      .main-color-text {\n        float: none;\n      }\n\n      &:hover {\n        height: 96px;\n        margin-top: -10px;\n        border-radius: 4px 4px 0 0;\n      }\n    }\n\n    &-value {\n      position: absolute;\n      bottom: 0;\n      left: 0;\n      width: 100%;\n      text-align: center;\n      transform-origin: unset;\n    }\n\n    &:hover {\n      .main-color-item {\n        padding-top: 8px;\n      }\n\n      .main-color-value {\n        bottom: 8px;\n        opacity: 0.7;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/style/common.less",
    "content": "@font-face {\n  font-weight: 300;\n  font-family: AlibabaSans;\n  font-style: normal;\n  src: url('//mdn.alipayobjects.com/huamei_iwk9zp/afts/file/A*1GSgSYDD_aIAAAAAQsAAAAgAegCCAQ/AlibabaSans-Light.woff2')\n    format('woff2');\n  font-display: swap;\n}\n\n@font-face {\n  font-weight: 400;\n  font-family: AlibabaSans;\n  font-style: normal;\n  src: url('//mdn.alipayobjects.com/huamei_iwk9zp/afts/file/A*2zEUQqnPNesAAAAAQtAAAAgAegCCAQ/AlibabaSans-Regular.woff2')\n    format('woff2');\n  font-display: swap;\n}\n\n@font-face {\n  font-weight: 500;\n  font-family: AlibabaSans;\n  font-style: normal;\n  src: url('//mdn.alipayobjects.com/huamei_iwk9zp/afts/file/A*E_cxRbMlZqUAAAAAQuAAAAgAegCCAQ/AlibabaSans-Medium.woff2')\n    format('woff2');\n  font-display: swap;\n}\n\n@font-face {\n  font-weight: 600;\n  font-family: AlibabaSans;\n  font-style: normal;\n  src: url('//mdn.alipayobjects.com/huamei_iwk9zp/afts/file/A*E_cxRbMlZqUAAAAAQuAAAAgAegCCAQ/AlibabaSans-Bold.woff2')\n    format('woff2');\n  font-display: swap;\n}\n\n@font-face {\n  font-weight: 700;\n  font-family: AlibabaSans;\n  font-style: normal;\n  src: url('//mdn.alipayobjects.com/huamei_iwk9zp/afts/file/A*E_cxRbMlZqUAAAAAQuAAAAgAegCCAQ/AlibabaSans-Heavy.woff2')\n    format('woff2');\n  font-display: swap;\n}\n\nbody {\n  color: @site-text-color;\n  font-size: 14px;\n  font-family: AlibabaSans, @font-family;\n  background: @body-background;\n  transition: background-color 1s cubic-bezier(0.075, 0.82, 0.165, 1);\n}\n\na {\n  transition: color 0.3s ease;\n}\n\n.main-wrapper {\n  position: relative;\n  padding: 40px 0 0;\n  background: @component-background;\n}\n\n.main-container {\n  position: relative;\n  min-height: 500px;\n  padding-bottom: 32px;\n  padding-inline-start: 64px;\n  padding-inline-end: 170px; // toc\n  background: @component-background;\n}\n\n.main-menu {\n  z-index: 1;\n\n  &-inner {\n    height: 100%;\n    max-height: 100vh;\n    overflow: hidden;\n  }\n\n  &:hover &-inner {\n    overflow-y: auto;\n  }\n\n  > div,\n  > div > div {\n    height: 100%;\n  }\n}\n\n.aside-container {\n  min-height: 100%;\n  padding-bottom: 48px;\n  font-family: AlibabaSans, @font-family, sans-serif;\n\n  &.ant-menu-inline {\n    .ant-menu-submenu-title h4,\n    > .ant-menu-item,\n    .ant-menu-item a {\n      overflow: hidden;\n      font-size: 14px;\n      text-overflow: ellipsis;\n    }\n\n    > .ant-menu-item-group > .ant-menu-item-group-title {\n      margin-top: 16px;\n      margin-bottom: 16px;\n      font-size: 13px;\n\n      &::after {\n        position: relative;\n        top: 12px;\n        display: block;\n        width: calc(100% - 20px);\n        height: 1px;\n        background: @border-color-split;\n        content: '';\n      }\n    }\n\n    > .ant-menu-item,\n    > .ant-menu-submenu > .ant-menu-submenu-title,\n    > .ant-menu-item-group > .ant-menu-item-group-title,\n    > .ant-menu-item-group > .ant-menu-item-group-list > .ant-menu-item,\n    &.ant-menu-inline > .ant-menu-item-group > .ant-menu-item-group-list > .ant-menu-item {\n      padding-inline-start: 40px !important;\n    }\n\n    // Nest Category > Type > Article\n    &.ant-menu-inline {\n      .ant-menu-item-group-title {\n        padding-inline-start: 56px;\n      }\n\n      .ant-menu-item-group-list > .ant-menu-item {\n        padding-inline-start: 80px !important;\n      }\n    }\n\n    .ant-menu-item-group:first-child {\n      .ant-menu-item-group-title {\n        margin-top: 0;\n      }\n    }\n  }\n\n  a[disabled] {\n    color: #ccc;\n  }\n\n  .menu-item-link-outside {\n    position: relative;\n\n    .anticon {\n      position: absolute;\n      top: 16px;\n      right: -10px;\n      color: @primary-color;\n      font-size: 12px;\n      opacity: 0;\n      transition: all 0.3s;\n    }\n\n    &:hover .anticon {\n      opacity: 1;\n    }\n  }\n\n  .menu-title-content-link {\n    display: flex;\n    align-items: center;\n\n    > .ant-tag {\n      position: absolute;\n      inset-inline-end: @padding-xs;\n    }\n  }\n}\n\n.aside-container .chinese {\n  margin-left: 6px;\n  font-weight: normal;\n  font-size: 12px;\n  opacity: 0.67;\n}\n\n.outside-link {\n  display: inline-block;\n}\n\n.outside-link-icon {\n  margin-left: 5px;\n  color: #aaa;\n  font-size: 12px;\n}\n\n// reset menu text color\n.menu-site {\n  .ant-menu-item > a {\n    color: @site-text-color;\n  }\n\n  .ant-menu-item-selected > a,\n  .ant-menu-item > a:hover {\n    color: @primary-color;\n  }\n}\n\n.page-wrapper {\n  width: 100%;\n  padding: 0;\n  overflow: hidden;\n\n  &-rtl {\n    direction: rtl;\n  }\n}\n\n.drawer-content {\n  padding: 40px 0;\n\n  &-wrapper {\n    background-color: @component-background;\n  }\n}\n\n.drawer {\n  z-index: 1029;\n}\n\n.fixed-widgets {\n  position: fixed;\n  inset-inline-end: 32px;\n  bottom: 102px;\n  z-index: 2147483640;\n  display: flex;\n  flex-direction: column;\n  cursor: pointer;\n\n  &-tooltip {\n    .ant-tooltip-inner {\n      min-width: 100px;\n    }\n  }\n\n  & > div {\n    display: block;\n  }\n\n  &-active {\n    color: @primary-color;\n  }\n\n  & &-avatar {\n    width: 44px;\n    height: 44px;\n    color: #000;\n    font-size: 22px;\n    line-height: 44px;\n    background-color: #fff;\n    box-shadow: @shadow-2;\n    transition: color 0.3s;\n\n    &:hover {\n      color: @primary-color;\n    }\n  }\n}\n\n// keep transition consistent to make mode toggle animation be more smooth, include:\n// nav bar background\n// nav search border\n// nav menu background\n// wrapper content\n// sidemenu background\n// sidemenu active background\n// content background\n// affix toc\n#header,\n#header #search-box,\n#header #nav.ant-menu,\n.main-wrapper,\n.main-wrapper > .ant-row > .main-menu .main-menu-inner > .ant-menu,\n.main-wrapper\n  > .ant-row\n  > .main-menu\n  .main-menu-inner\n  > .ant-menu.aside-container.ant-menu-inline\n  > .ant-menu-item-group\n  > .ant-menu-item-group-title::after,\n.main-wrapper .main-container,\n#demo-toc.toc {\n  transition: all 0.3s @ease-in-out-circ;\n}\n\n// remove margin-bottom from dark theme (why need margin-bottom in dark theme?)\n#header > .ant-row > .ant-col h1 {\n  margin-bottom: 0;\n}\n"
  },
  {
    "path": "scripts/site/doc/style/dark.less",
    "content": "[data-theme='dark'] {\n  /* Change autocomplete styles in WebKit */\n  input:-webkit-autofill,\n  input:-webkit-autofill:hover,\n  input:-webkit-autofill:focus,\n  textarea:-webkit-autofill,\n  textarea:-webkit-autofill:hover,\n  textarea:-webkit-autofill:focus,\n  select:-webkit-autofill,\n  select:-webkit-autofill:hover,\n  select:-webkit-autofill:focus {\n    border: 1px solid @border-color-base;\n    -webkit-text-fill-color: @text-color;\n    box-shadow: none;\n    transition: background-color 5000s ease-in-out 0s;\n  }\n\n  #header {\n    box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.65);\n  }\n\n  #search-box input {\n    &::placeholder {\n      color: fade(@white, 30%);\n    }\n  }\n\n  .toc-affix {\n    .ant-affix {\n      background: @component-background;\n    }\n  }\n\n  :not(pre) > code[class*='language-'],\n  pre[class*='language-'] {\n    color: rgba(255, 255, 255, 0.65);\n    background: #262626;\n  }\n\n  .code-box {\n    border: 1px solid @border-color-split;\n\n    .markdown {\n      pre {\n        margin: 0.5em 0;\n        padding: 6px 12px;\n      }\n\n      pre code {\n        margin: 0;\n        background: #262626;\n      }\n    }\n\n    &-debug {\n      border-color: @purple-3;\n    }\n\n    &-expand-trigger {\n      position: relative;\n      color: #fff;\n      font-size: 20px;\n      cursor: pointer;\n      opacity: 0.45;\n      transition: all 0.3s;\n\n      &:hover {\n        opacity: 0.65;\n      }\n    }\n\n    &-demo {\n      border-bottom: 1px solid @border-color-split;\n    }\n\n    &-actions > &-code-action {\n      color: @site-text-color-secondary;\n\n      &:hover {\n        color: @site-text-color;\n      }\n    }\n  }\n\n  ul.anticons-list {\n    li {\n      color: #acacac;\n\n      &.TwoTone:hover {\n        background-color: #15395b;\n      }\n\n      &:hover {\n        .anticon {\n          color: #fff;\n        }\n      }\n    }\n  }\n\n  h1,\n  h2,\n  h3,\n  h4,\n  h5,\n  h6 {\n    color: @heading-color;\n  }\n\n  .markdown {\n    code,\n    pre,\n    pre code {\n      background: #262626;\n    }\n  }\n\n  .markdown.api-container {\n    table {\n      tbody tr {\n        &:hover {\n          background: #262626;\n        }\n      }\n    }\n  }\n\n  .markdown code {\n    background: fade(@white, 8%);\n  }\n\n  .prev-next-nav {\n    > a.prev-page {\n      .footer-nav-icon-before {\n        color: fade(@white, 45%);\n      }\n\n      &:hover .footer-nav-icon-before {\n        color: @primary-color;\n      }\n    }\n\n    > .next-page {\n      .footer-nav-icon-after {\n        color: fade(@white, 45%);\n      }\n\n      &:hover .footer-nav-icon-after {\n        color: @primary-color;\n      }\n    }\n  }\n\n  .grid-demo,\n  [id^='components-grid-demo-'] {\n    .demo-row,\n    .code-box-demo .demo-row {\n      background-image: linear-gradient(\n        90deg,\n        #1d1d1d 4.16666667%,\n        transparent 4.16666667%,\n        transparent 8.33333333%,\n        #1d1d1d 8.33333333%,\n        #1d1d1d 12.5%,\n        transparent 12.5%,\n        transparent 16.66666667%,\n        #1d1d1d 16.66666667%,\n        #1d1d1d 20.83333333%,\n        transparent 20.83333333%,\n        transparent 25%,\n        #1d1d1d 25%,\n        #1d1d1d 29.16666667%,\n        transparent 29.16666667%,\n        transparent 33.33333333%,\n        #1d1d1d 33.33333333%,\n        #1d1d1d 37.5%,\n        transparent 37.5%,\n        transparent 41.66666667%,\n        #1d1d1d 41.66666667%,\n        #1d1d1d 45.83333333%,\n        transparent 45.83333333%,\n        transparent 50%,\n        #1d1d1d 50%,\n        #1d1d1d 54.16666667%,\n        transparent 54.16666667%,\n        transparent 58.33333333%,\n        #1d1d1d 58.33333333%,\n        #1d1d1d 62.5%,\n        transparent 62.5%,\n        transparent 66.66666667%,\n        #1d1d1d 66.66666667%,\n        #1d1d1d 70.83333333%,\n        transparent 70.83333333%,\n        transparent 75%,\n        #1d1d1d 75%,\n        #1d1d1d 79.16666667%,\n        transparent 79.16666667%,\n        transparent 83.33333333%,\n        #1d1d1d 83.33333333%,\n        #1d1d1d 87.5%,\n        transparent 87.5%,\n        transparent 91.66666667%,\n        #1d1d1d 91.66666667%,\n        #1d1d1d 95.83333333%,\n        transparent 95.83333333%\n      );\n    }\n\n    .code-box-demo .ant-row > div:not(.gutter-row) {\n      padding: 16px 0;\n      background: #028ac8;\n\n      &:nth-child(2n + 1) {\n        background: fade(#0088c6, 70%);\n      }\n    }\n\n    .ant-row .demo-col,\n    .code-box-demo .ant-row .demo-col {\n      margin-top: 0;\n      margin-bottom: 0;\n      padding: 30px 0;\n      color: @black;\n      font-size: 18px;\n      text-align: center;\n      border: none;\n    }\n\n    .ant-row .demo-col-1 {\n      background: fade(#0088c6, 70%);\n    }\n\n    .ant-row .demo-col-3,\n    .code-box-demo .ant-row .demo-col-3 {\n      color: @site-text-color-secondary;\n      background: unset;\n    }\n\n    .ant-row .demo-col-5,\n    .code-box-demo .ant-row .demo-col-5 {\n      color: @site-text-color-secondary;\n      background: unset;\n    }\n  }\n\n  .markdown > table th {\n    color: fade(@white, 65%);\n    background: #1d1d1d;\n  }\n\n  .copied-code {\n    background: fade(@white, 8%);\n  }\n\n  .browser-mockup.with-url::after {\n    background-color: @component-background;\n  }\n\n  .browser-mockup {\n    border-top: 2em solid #262626;\n  }\n\n  .browser-mockup::before {\n    background-color: #fb4742;\n    box-shadow: 0 0 0 2px #fb4742, 1.5em 0 0 2px #99bc2e, 3em 0 0 2px #ffba5a;\n  }\n\n  .browser-mockup.with-tab::after {\n    border-bottom: 2em solid @component-background;\n  }\n\n  .algolia-autocomplete {\n    .ds-dropdown-menu {\n      [class^='ds-dataset-'] {\n        background: @popover-background;\n\n        .algolia-docsearch-suggestion {\n          background: @popover-background;\n        }\n      }\n\n      .ds-suggestion.ds-cursor {\n        .algolia-docsearch-suggestion:not(.suggestion-layout-simple) {\n          .algolia-docsearch-suggestion--content {\n            background-color: fade(@white, 8%);\n          }\n        }\n      }\n    }\n\n    .algolia-docsearch-suggestion--category-header {\n      color: rgba(255, 255, 255, 0.65);\n      border-bottom: 1px solid @border-color-split;\n    }\n\n    .algolia-docsearch-suggestion--subcategory-column::before {\n      background: @border-color-split;\n    }\n\n    .algolia-docsearch-suggestion--content {\n      &::before {\n        background: @border-color-split;\n      }\n    }\n  }\n\n  .token.comment,\n  .token.quote {\n    color: #b6b18b;\n  }\n\n  .token.property,\n  .token.variable,\n  .token.template-variable,\n  .token.tag,\n  .token.number,\n  .token.name,\n  .token.selector-id,\n  .token.selector-class,\n  .token.regexp,\n  .token.deletion {\n    color: #eb3c54;\n  }\n\n  .token.built_in,\n  .token.builtin-name,\n  .token.literal,\n  .token.type,\n  .token.params,\n  .token.meta,\n  .token.link {\n    color: #e7ce56;\n  }\n\n  .token.attribute {\n    color: #ee7c2b;\n  }\n\n  .token.string,\n  .token.symbol,\n  .token.bullet,\n  .token.addition {\n    color: @primary-color;\n  }\n\n  .token.title,\n  .token.section {\n    color: #78bb65;\n  }\n\n  .token.function,\n  .token.keyword,\n  .token.selector-tag {\n    color: #b45ea4;\n  }\n\n  .hljs {\n    display: block;\n    padding: 0.5em;\n    overflow-x: auto;\n    color: #c0c5ce;\n    background: #1c1d21;\n  }\n\n  .token.emphasis {\n    font-style: italic;\n  }\n\n  .token.strong {\n    font-weight: bold;\n  }\n\n  .components-overview {\n    &-img {\n      background-color: rgba(255, 255, 255, 0.1);\n    }\n\n    &-search input {\n      color: rgba(255, 255, 255, 0.65);\n    }\n  }\n\n  #language {\n    span.active {\n      color: #141414;\n      background-color: rgba(255, 255, 255, 0.85);\n      border: none;\n    }\n\n    span:not(.active) {\n      color: rgba(255, 255, 255, 0.85);\n      border: 1px solid rgba(255, 255, 255, 0.85);\n    }\n  }\n}"
  },
  {
    "path": "scripts/site/doc/style/demo.less",
    "content": ".code-boxes-col-1-1 {\n  width: 100%;\n}\n\n.code-box {\n  position: relative;\n  display: inline-block;\n  width: 100%;\n  margin: 0 0 16px;\n  border: 1px solid @site-border-color-split;\n  border-radius: @border-radius-base;\n  transition: all 0.2s;\n\n  .code-box-title {\n    &,\n    a {\n      color: @site-text-color;\n      background: @component-background;\n    }\n  }\n\n  .code-box-description {\n    p {\n      color: @site-text-color;\n    }\n  }\n\n  &,\n  .code-box-demo {\n    background-color: @component-background;\n  }\n\n  .markdown {\n    pre {\n      margin: 0.5em 0;\n      padding: 6px 12px;\n    }\n\n    pre code {\n      margin: 0;\n      background: #f5f5f5;\n    }\n  }\n\n  &:target {\n    border: 1px solid @primary-color;\n  }\n\n  &-expand-trigger {\n    position: relative;\n    margin-inline-start: 12px;\n    color: #3b4357;\n    font-size: 20px;\n    cursor: pointer;\n    opacity: 0.75;\n    transition: all 0.3s;\n\n    &:hover {\n      opacity: 1;\n    }\n  }\n\n  &-title {\n    position: absolute;\n    top: -14px;\n    margin-inline-start: 16px;\n    padding: 1px 8px;\n    color: #777;\n    background: @body-background;\n\n    border-radius: @border-radius-base @border-radius-base 0 0;\n    transition: background-color 0.4s;\n\n    .ant-row-rtl & {\n      border-radius: @border-radius-base 0 0 @border-radius-base;\n    }\n\n    a,\n    a:hover {\n      color: @site-text-color;\n      font-weight: 500;\n      font-size: @font-size-base;\n    }\n  }\n\n  &-description {\n    padding: 18px 24px 12px;\n  }\n\n  a.edit-button {\n    position: absolute;\n    top: 7px;\n    inset-inline-end: -16px;\n    padding-inline-end: 6px;\n    font-size: 12px;\n    text-decoration: none;\n    background: inherit;\n    transform: scale(0.9);\n\n    .anticon {\n      color: @site-text-color-secondary;\n      transition: all 0.3s;\n\n      &:hover {\n        color: @site-text-color;\n      }\n    }\n  }\n\n  &-demo {\n    padding: 42px 24px 50px;\n    color: @site-text-color;\n    border-bottom: 1px solid @site-border-color-split;\n  }\n\n  iframe {\n    width: 100%;\n    border: 0;\n  }\n\n  &-meta {\n    &.markdown {\n      position: relative;\n      width: 100%;\n      font-size: @font-size-base;\n      border-radius: 0 0 @border-radius-base @border-radius-base;\n      transition: background-color 0.4s;\n    }\n\n    blockquote {\n      margin: 0;\n    }\n\n    h4,\n    section& p {\n      margin: 0;\n    }\n\n    > p {\n      width: 100%;\n      margin: 0.5em 0;\n      padding-inline-end: 25px;\n      font-size: 12px;\n      word-break: break-word;\n    }\n  }\n\n  &.expand &-meta {\n    border-bottom: 1px dashed @site-border-color-split;\n    border-radius: 0;\n  }\n\n  .code-expand-icon-show,\n  .code-expand-icon-hide {\n    position: absolute;\n    top: 0;\n    inset-inline-end: 0;\n    width: 100%;\n    max-width: 100%;\n    margin: 0;\n    box-shadow: none;\n    transition: all 0.4s;\n    user-select: none;\n  }\n\n  .code-expand-icon-show {\n    opacity: 0.55;\n    pointer-events: auto;\n\n    &:hover {\n      opacity: 1;\n    }\n  }\n\n  .code-expand-icon.ant-tooltip-open .code-expand-icon-show {\n    opacity: 1;\n  }\n\n  .code-expand-icon-hide {\n    opacity: 0;\n    pointer-events: none;\n  }\n\n  .highlight-wrapper {\n    display: none;\n    overflow: auto;\n    border-radius: 0 0 @border-radius-base @border-radius-base;\n\n    &-expand {\n      display: block;\n    }\n  }\n\n  .highlight {\n    position: relative;\n\n    .ant-tabs-nav-scroll {\n      text-align: center;\n    }\n\n    pre {\n      margin: 0;\n      padding: 0;\n      background: @component-background;\n    }\n\n    &:not(:first-child) {\n      border-top: 1px dashed @site-border-color-split;\n    }\n  }\n\n  &-actions {\n    display: flex;\n    justify-content: center;\n    padding: 12px 0;\n    border-top: 1px dashed @site-border-color-split;\n    opacity: 0.7;\n    transition: opacity 0.3s;\n\n    &:hover {\n      opacity: 1;\n    }\n\n    > * {\n      position: relative;\n      display: inline-block;\n      width: 16px;\n      vertical-align: top;\n      cursor: pointer;\n      inset-inline-end: 16px;\n      margin-inline-start: 16px;\n\n      &:first-child {\n        margin-inline-start: 0;\n      }\n    }\n\n    .anticon-check {\n      color: @green-6 !important;\n      font-weight: bold;\n    }\n  }\n\n  &-code-action {\n    width: 20px;\n    height: 20px;\n    color: @site-text-color-secondary;\n    font-size: 16px;\n    line-height: 18px;\n    cursor: pointer;\n    transition: all 0.24s;\n\n    &:hover {\n      color: @icon-color-hover;\n    }\n  }\n\n  .highlight-wrapper:hover &-code-copy,\n  .highlight-wrapper:hover &-codepen,\n  .highlight-wrapper:hover &-codesandbox,\n  .highlight-wrapper:hover &-riddle {\n    opacity: 1;\n  }\n\n  pre {\n    width: auto;\n    margin: 0;\n\n    code {\n      background: @component-background;\n      border: none;\n    }\n  }\n\n  &-debug {\n    border-color: @purple-3;\n  }\n\n  &-debug &-title a {\n    color: @purple-6;\n  }\n}\n\n.ant-row-rtl {\n  #components-tooltip-demo-placement,\n  #components-popover-demo-placement,\n  #components-popconfirm-demo-placement {\n    .code-box-demo {\n      direction: ltr;\n    }\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/style/doc-search.less",
    "content": "/* stylelint-disable */\n\n.searchbox {\n  position: relative;\n  display: inline-block;\n  box-sizing: border-box;\n  width: 200px;\n  height: 32px !important;\n  white-space: nowrap;\n  visibility: visible !important;\n}\n\n.searchbox .algolia-autocomplete {\n  display: block;\n  width: 100%;\n  height: 100%;\n}\n\n.searchbox__wrapper {\n  position: relative;\n  z-index: 999;\n  width: 100%;\n  height: 100%;\n}\n\n.searchbox__input {\n  display: inline-block;\n  box-sizing: border-box;\n  width: 100%;\n  height: 100%;\n  padding: 0 26px 0 32px;\n  font-size: 12px;\n  white-space: normal;\n  vertical-align: middle;\n  background: #fff !important;\n  border: 0;\n  border-radius: 16px;\n  box-shadow: inset 0 0 0 1px #ccc;\n  transition:\n    box-shadow 0.4s ease,\n    background 0.4s ease;\n  appearance: none;\n}\n\n.searchbox__input::-webkit-search-cancel-button,\n.searchbox__input::-webkit-search-decoration,\n.searchbox__input::-webkit-search-results-button,\n.searchbox__input::-webkit-search-results-decoration {\n  display: none;\n}\n\n.searchbox__input:hover {\n  box-shadow: inset 0 0 0 1px #b3b3b3;\n}\n\n.searchbox__input:active,\n.searchbox__input:focus {\n  background: #fff;\n  outline: 0;\n  box-shadow: inset 0 0 0 1px #aaa;\n}\n\n.searchbox__input::input-placeholder {\n  color: #aaa;\n}\n\n.searchbox__input:input-placeholder {\n  color: #aaa;\n}\n\n.searchbox__input::input-placeholder {\n  color: #aaa;\n}\n\n.searchbox__input::placeholder {\n  color: #aaa;\n}\n\n.searchbox__submit {\n  position: absolute;\n  top: 0;\n  right: inherit;\n  left: 0;\n  width: 32px;\n  height: 100%;\n  margin: 0;\n  padding: 0;\n  font-size: inherit;\n  text-align: center;\n  vertical-align: middle;\n  background-color: rgba(69, 142, 225, 0);\n  border: 0;\n  border-radius: 16px 0 0 16px;\n  user-select: none;\n}\n\n.searchbox__submit::before {\n  display: inline-block;\n  height: 100%;\n  margin-right: -4px;\n  vertical-align: middle;\n  content: '';\n}\n\n.searchbox__submit:active,\n.searchbox__submit:hover {\n  cursor: pointer;\n}\n\n.searchbox__submit:focus {\n  outline: 0;\n}\n\n.searchbox__submit svg {\n  width: 14px;\n  height: 14px;\n  vertical-align: middle;\n  fill: #6d7e96;\n}\n\n.searchbox__reset {\n  position: absolute;\n  top: 8px;\n  right: 8px;\n  display: block;\n  margin: 0;\n  padding: 0;\n  font-size: inherit;\n  background: none;\n  border: 0;\n  cursor: pointer;\n  user-select: none;\n  fill: rgba(0, 0, 0, 0.5);\n}\n\n.searchbox__reset.hide {\n  display: none;\n}\n\n.searchbox__reset:focus {\n  outline: 0;\n}\n\n.searchbox__reset svg {\n  display: block;\n  width: 8px;\n  height: 8px;\n  margin: 4px;\n}\n\n.searchbox__input:valid ~ .searchbox__reset {\n  display: block;\n  animation-name: sbx-reset-in;\n  animation-duration: 0.15s;\n}\n@keyframes sbx-reset-in {\n  0% {\n    transform: translate3d(-20%, 0, 0);\n    opacity: 0;\n  }\n\n  100% {\n    transform: none;\n    opacity: 1;\n  }\n}\n@keyframes sbx-reset-in {\n  0% {\n    transform: translate3d(-20%, 0, 0);\n    opacity: 0;\n  }\n\n  100% {\n    transform: none;\n    opacity: 1;\n  }\n}\n\n.algolia-autocomplete.algolia-autocomplete-right .ds-dropdown-menu {\n  right: 0 !important;\n  left: inherit !important;\n}\n\n.algolia-autocomplete.algolia-autocomplete-right .ds-dropdown-menu::before {\n  right: 48px;\n}\n\n.algolia-autocomplete.algolia-autocomplete-left .ds-dropdown-menu {\n  right: inherit !important;\n  left: 0 !important;\n}\n\n.algolia-autocomplete.algolia-autocomplete-left .ds-dropdown-menu::before {\n  left: 48px;\n}\n\n.algolia-autocomplete .ds-dropdown-menu {\n  position: relative;\n  top: -6px;\n  z-index: 999;\n  min-width: 500px;\n  max-width: 600px;\n  height: auto;\n  margin: 6px 0 0;\n  padding: 0;\n  text-align: left;\n  background: transparent;\n  border: none;\n  border-radius: 4px;\n  box-shadow:\n    0 1px 0 0 rgba(0, 0, 0, 0.2),\n    0 2px 3px 0 rgba(0, 0, 0, 0.1);\n}\n\n.algolia-autocomplete .ds-dropdown-menu::before {\n  position: absolute;\n  top: -7px;\n  z-index: 1000;\n  display: block;\n  width: 14px;\n  height: 14px;\n  background: #fff;\n  border-top: 1px solid #d9d9d9;\n  border-right: 1px solid #d9d9d9;\n  border-radius: 2px;\n  transform: rotate(-45deg);\n  content: '';\n}\n\n.algolia-autocomplete .ds-dropdown-menu .ds-suggestions {\n  position: relative;\n  z-index: 1000;\n  margin-top: 8px;\n}\n\n.algolia-autocomplete .ds-dropdown-menu .ds-suggestions a:hover {\n  text-decoration: none;\n}\n\n.algolia-autocomplete .ds-dropdown-menu .ds-suggestion {\n  cursor: pointer;\n}\n\n.algolia-autocomplete .ds-dropdown-menu .ds-suggestion.ds-cursor .algolia-docsearch-suggestion.suggestion-layout-simple,\n.algolia-autocomplete\n  .ds-dropdown-menu\n  .ds-suggestion.ds-cursor\n  .algolia-docsearch-suggestion:not(.suggestion-layout-simple)\n  .algolia-docsearch-suggestion--content {\n  background-color: rgba(69, 142, 225, 0.05);\n}\n\n.algolia-autocomplete .ds-dropdown-menu [class^='ds-dataset-'] {\n  position: relative;\n  padding: 0 8px 8px;\n  overflow: auto;\n  background: #fff;\n  border: 1px solid #d9d9d9;\n  border-radius: 4px;\n}\n\n.algolia-autocomplete .ds-dropdown-menu * {\n  box-sizing: border-box;\n}\n\n.algolia-autocomplete .algolia-docsearch-suggestion {\n  position: relative;\n  display: block;\n  padding: 0 8px;\n  overflow: hidden;\n  color: #02060c;\n  background: #fff;\n}\n\n.algolia-autocomplete .algolia-docsearch-suggestion--highlight {\n  padding: 0.1em 0.05em;\n  color: #174d8c;\n  background: rgba(143, 187, 237, 0.1);\n}\n\n.algolia-autocomplete\n  .algolia-docsearch-suggestion--category-header\n  .algolia-docsearch-suggestion--category-header-lvl0\n  .algolia-docsearch-suggestion--highlight,\n.algolia-autocomplete\n  .algolia-docsearch-suggestion--category-header\n  .algolia-docsearch-suggestion--category-header-lvl1\n  .algolia-docsearch-suggestion--highlight,\n.algolia-autocomplete .algolia-docsearch-suggestion--text .algolia-docsearch-suggestion--highlight {\n  padding: 0 0 1px;\n  color: inherit;\n  background: inherit;\n  box-shadow: inset 0 -2px 0 0 rgba(69, 142, 225, 0.8);\n}\n\n.algolia-autocomplete .algolia-docsearch-suggestion--content {\n  position: relative;\n  display: block;\n  float: right;\n  width: 70%;\n  padding: 5.33333px 0 5.33333px 10.66667px;\n  cursor: pointer;\n}\n\n.algolia-autocomplete .algolia-docsearch-suggestion--content::before {\n  position: absolute;\n  top: 0;\n  left: -1px;\n  display: block;\n  width: 1px;\n  height: 100%;\n  background: #ddd;\n  content: '';\n}\n\n.algolia-autocomplete .algolia-docsearch-suggestion--category-header {\n  position: relative;\n  display: none;\n  margin-top: 8px;\n  padding: 4px 0;\n  color: #33363d;\n  font-size: 1em;\n  border-bottom: 1px solid #ddd;\n}\n\n.algolia-autocomplete .algolia-docsearch-suggestion--wrapper {\n  float: left;\n  width: 100%;\n  padding: 8px 0 0;\n}\n\n.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column {\n  position: relative;\n  float: left;\n  width: 30%;\n  padding: 5.33333px 10.66667px;\n  color: #a4a7ae;\n  font-size: 0.9em;\n  text-align: right;\n  word-wrap: break-word;\n}\n\n.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column::before {\n  position: absolute;\n  top: 0;\n  right: 0;\n  display: block;\n  width: 1px;\n  height: 100%;\n  background: #ddd;\n  content: '';\n}\n\n.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-inline {\n  display: none;\n}\n\n.algolia-autocomplete .algolia-docsearch-suggestion--title {\n  margin-bottom: 4px;\n  color: #02060c;\n  font-weight: 700;\n  font-size: 0.9em;\n}\n\n.algolia-autocomplete .algolia-docsearch-suggestion--text {\n  display: block;\n  color: #63676d;\n  font-size: 0.85em;\n  line-height: 1.2em;\n}\n\n.algolia-autocomplete .algolia-docsearch-suggestion--no-results {\n  width: 100%;\n  padding: 8px 0;\n  font-size: 1.2em;\n  text-align: center;\n}\n\n.algolia-autocomplete .algolia-docsearch-suggestion--no-results::before {\n  display: none;\n}\n\n.algolia-autocomplete .algolia-docsearch-suggestion code {\n  padding: 1px 5px;\n  color: #222;\n  font-size: 90%;\n  font-family: Menlo, Monaco, Consolas, 'Courier New', monospace;\n  background-color: #ebebeb;\n  border: none;\n  border-radius: 3px;\n}\n\n.algolia-autocomplete .algolia-docsearch-suggestion code .algolia-docsearch-suggestion--highlight {\n  background: none;\n}\n\n.algolia-autocomplete\n  .algolia-docsearch-suggestion.algolia-docsearch-suggestion__main\n  .algolia-docsearch-suggestion--category-header,\n.algolia-autocomplete .algolia-docsearch-suggestion.algolia-docsearch-suggestion__secondary {\n  display: block;\n}\n@media (min-width: 768px) {\n  .algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--subcategory-column {\n    display: block;\n  }\n}\n@media (max-width: 768px) {\n  .algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--subcategory-column {\n    display: inline-block;\n    float: left;\n    width: auto;\n    padding: 0;\n    color: #02060c;\n    font-weight: 700;\n    font-size: 0.9em;\n    text-align: left;\n    opacity: 0.5;\n  }\n\n  .algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--subcategory-column::before {\n    display: none;\n  }\n\n  .algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--subcategory-column::after {\n    content: '|';\n  }\n\n  .algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--content {\n    display: inline-block;\n    float: left;\n    width: auto;\n    padding: 0;\n    text-align: left;\n  }\n\n  .algolia-autocomplete .algolia-docsearch-suggestion .algolia-docsearch-suggestion--content::before {\n    display: none;\n  }\n}\n\n.algolia-autocomplete .suggestion-layout-simple.algolia-docsearch-suggestion {\n  margin: 0;\n  padding: 8px;\n  border-bottom: 1px solid #eee;\n}\n\n.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--content {\n  width: 100%;\n  padding: 0;\n}\n\n.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--content::before {\n  display: none;\n}\n\n.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--category-header {\n  display: block;\n  width: 100%;\n  margin: 0;\n  padding: 0;\n  border: none;\n}\n\n.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--category-header-lvl0,\n.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--category-header-lvl1 {\n  font-size: 0.85em;\n  opacity: 0.6;\n}\n\n.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--category-header-lvl1::before {\n  display: inline-block;\n  width: 10px;\n  height: 10px;\n  background-image: url('data:image/svg+xml;utf8,<svg width=\"10\" height=\"10\" viewBox=\"0 0 20 38\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M1.49 4.31l14 16.126.002-2.624-14 16.074-1.314 1.51 3.017 2.626 1.313-1.508 14-16.075 1.142-1.313-1.14-1.313-14-16.125L3.2.18.18 2.8l1.31 1.51z\" fill-rule=\"evenodd\" fill=\"%231D3657\" /></svg>');\n  content: '';\n}\n\n.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--wrapper {\n  float: left;\n  width: 100%;\n  margin: 0;\n  padding: 0;\n}\n\n.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--duplicate-content,\n.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--subcategory-inline {\n  display: none !important;\n}\n\n.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--title {\n  margin: 0;\n  color: #458ee1;\n  font-weight: 400;\n  font-size: 0.9em;\n}\n\n.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--title::before {\n  display: inline-block;\n  color: #458ee1;\n  font-weight: 700;\n  content: '#';\n}\n\n.algolia-autocomplete .suggestion-layout-simple .algolia-docsearch-suggestion--text {\n  display: block;\n  margin: 4px 0 0;\n  padding: 5.33333px 8px;\n  font-size: 0.85em;\n  line-height: 1.4em;\n  background: #f8f8f8;\n  opacity: 0.8;\n}\n\n.algolia-autocomplete\n  .suggestion-layout-simple\n  .algolia-docsearch-suggestion--text\n  .algolia-docsearch-suggestion--highlight {\n  color: #3f4145;\n  font-weight: 700;\n  box-shadow: none;\n}\n\n.algolia-autocomplete .algolia-docsearch-footer {\n  z-index: 2000;\n  float: right;\n  width: 134px;\n  height: 20px;\n  margin-top: 10.66667px;\n  font-size: 0;\n  line-height: 0;\n}\n\n.algolia-autocomplete .algolia-docsearch-footer--logo {\n  display: block;\n  width: 100%;\n  height: 100%;\n  padding: 0 !important;\n  overflow: hidden;\n  text-indent: -9000px;\n  background-image: url(\"data:image/svg+xml;charset=utf-8,%3Csvg width='168' height='24' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cpath d='M78.988.938h16.594a2.968 2.968 0 0 1 2.966 2.966V20.5a2.967 2.967 0 0 1-2.966 2.964H78.988a2.967 2.967 0 0 1-2.966-2.964V3.897A2.961 2.961 0 0 1 78.988.938zm41.937 17.866c-4.386.02-4.386-3.54-4.386-4.106l-.007-13.336 2.675-.424v13.254c0 .322 0 2.358 1.718 2.364v2.248zm-10.846-2.18c.821 0 1.43-.047 1.855-.129v-2.719a6.334 6.334 0 0 0-1.574-.199 5.7 5.7 0 0 0-.897.069 2.699 2.699 0 0 0-.814.24c-.24.116-.439.28-.582.491-.15.212-.219.335-.219.656 0 .628.219.991.616 1.23s.938.362 1.615.362zm-.233-9.7c.883 0 1.629.109 2.231.328.602.218 1.088.525 1.444.915.363.396.609.922.76 1.483.157.56.232 1.175.232 1.85v6.874a32.5 32.5 0 0 1-1.868.314c-.834.123-1.772.185-2.813.185-.69 0-1.327-.069-1.895-.198a4.001 4.001 0 0 1-1.471-.636 3.085 3.085 0 0 1-.951-1.134c-.226-.465-.343-1.12-.343-1.803 0-.656.13-1.073.384-1.525a3.24 3.24 0 0 1 1.047-1.106c.445-.287.95-.492 1.532-.615a8.8 8.8 0 0 1 1.82-.185 8.404 8.404 0 0 1 1.972.24v-.438c0-.307-.035-.6-.11-.874a1.88 1.88 0 0 0-.384-.73 1.784 1.784 0 0 0-.724-.493 3.164 3.164 0 0 0-1.143-.205c-.616 0-1.177.075-1.69.164a7.735 7.735 0 0 0-1.26.307l-.321-2.192c.335-.117.834-.233 1.478-.349a10.98 10.98 0 0 1 2.073-.178zm52.842 9.626c.822 0 1.43-.048 1.854-.13V13.7a6.347 6.347 0 0 0-1.574-.199c-.294 0-.595.021-.896.069a2.7 2.7 0 0 0-.814.24 1.46 1.46 0 0 0-.582.491c-.15.212-.218.335-.218.656 0 .628.218.991.615 1.23.404.245.938.362 1.615.362zm-.226-9.694c.883 0 1.629.108 2.231.327.602.219 1.088.526 1.444.915.355.39.609.923.759 1.483a6.8 6.8 0 0 1 .233 1.852v6.873c-.41.088-1.034.19-1.868.314-.834.123-1.772.184-2.813.184-.69 0-1.327-.068-1.895-.198a4.001 4.001 0 0 1-1.471-.635 3.085 3.085 0 0 1-.951-1.134c-.226-.465-.343-1.12-.343-1.804 0-.656.13-1.073.384-1.524.26-.45.608-.82 1.047-1.107.445-.286.95-.491 1.532-.614a8.803 8.803 0 0 1 2.751-.13c.329.034.671.096 1.04.185v-.437a3.3 3.3 0 0 0-.109-.875 1.873 1.873 0 0 0-.384-.731 1.784 1.784 0 0 0-.724-.492 3.165 3.165 0 0 0-1.143-.205c-.616 0-1.177.075-1.69.164a7.75 7.75 0 0 0-1.26.307l-.321-2.193c.335-.116.834-.232 1.478-.348a11.633 11.633 0 0 1 2.073-.177zm-8.034-1.271a1.626 1.626 0 0 1-1.628-1.62c0-.895.725-1.62 1.628-1.62.904 0 1.63.725 1.63 1.62 0 .895-.733 1.62-1.63 1.62zm1.348 13.22h-2.689V7.27l2.69-.423v11.956zm-4.714 0c-4.386.02-4.386-3.54-4.386-4.107l-.008-13.336 2.676-.424v13.254c0 .322 0 2.358 1.718 2.364v2.248zm-8.698-5.903c0-1.156-.253-2.119-.746-2.788-.493-.677-1.183-1.01-2.067-1.01-.882 0-1.574.333-2.065 1.01-.493.676-.733 1.632-.733 2.788 0 1.168.246 1.953.74 2.63.492.683 1.183 1.018 2.066 1.018.882 0 1.574-.342 2.067-1.019.492-.683.738-1.46.738-2.63zm2.737-.007c0 .902-.13 1.584-.397 2.33a5.52 5.52 0 0 1-1.128 1.906 4.986 4.986 0 0 1-1.752 1.223c-.685.286-1.739.45-2.265.45-.528-.006-1.574-.157-2.252-.45a5.096 5.096 0 0 1-1.744-1.223c-.487-.527-.863-1.162-1.137-1.906a6.345 6.345 0 0 1-.41-2.33c0-.902.123-1.77.397-2.508a5.554 5.554 0 0 1 1.15-1.892 5.133 5.133 0 0 1 1.75-1.216c.679-.287 1.425-.423 2.232-.423.808 0 1.553.142 2.237.423a4.88 4.88 0 0 1 1.753 1.216 5.644 5.644 0 0 1 1.135 1.892c.287.738.431 1.606.431 2.508zm-20.138 0c0 1.12.246 2.363.738 2.882.493.52 1.13.78 1.91.78.424 0 .828-.062 1.204-.178.377-.116.677-.253.917-.417V9.33a10.476 10.476 0 0 0-1.766-.226c-.971-.028-1.71.37-2.23 1.004-.513.636-.773 1.75-.773 2.788zm7.438 5.274c0 1.824-.466 3.156-1.404 4.004-.936.846-2.367 1.27-4.296 1.27-.705 0-2.17-.137-3.34-.396l.431-2.118c.98.205 2.272.26 2.95.26 1.074 0 1.84-.219 2.299-.656.459-.437.684-1.086.684-1.948v-.437a8.07 8.07 0 0 1-1.047.397c-.43.13-.93.198-1.492.198-.739 0-1.41-.116-2.018-.349a4.206 4.206 0 0 1-1.567-1.025c-.431-.45-.774-1.017-1.013-1.694-.24-.677-.363-1.885-.363-2.773 0-.834.13-1.88.384-2.577.26-.696.629-1.298 1.129-1.796.493-.498 1.095-.881 1.8-1.162a6.605 6.605 0 0 1 2.428-.457c.87 0 1.67.109 2.45.24.78.129 1.444.265 1.985.415V18.17z' fill='%235468FF'/%3E%3Cpath d='M6.972 6.677v1.627c-.712-.446-1.52-.67-2.425-.67-.585 0-1.045.13-1.38.391a1.24 1.24 0 0 0-.502 1.03c0 .425.164.765.494 1.02.33.256.835.532 1.516.83.447.192.795.356 1.045.495.25.138.537.332.862.582.324.25.563.548.718.894.154.345.23.741.23 1.188 0 .947-.334 1.691-1.004 2.234-.67.542-1.537.814-2.601.814-1.18 0-2.16-.229-2.936-.686v-1.708c.84.628 1.814.942 2.92.942.585 0 1.048-.136 1.388-.407.34-.271.51-.646.51-1.125 0-.287-.1-.55-.302-.79-.203-.24-.42-.42-.655-.542-.234-.123-.585-.29-1.053-.503a61.27 61.27 0 0 1-.582-.271 13.67 13.67 0 0 1-.55-.287 4.275 4.275 0 0 1-.567-.351 6.92 6.92 0 0 1-.455-.4c-.18-.17-.31-.34-.39-.51-.08-.17-.155-.37-.224-.598a2.553 2.553 0 0 1-.104-.742c0-.915.333-1.638.998-2.17.664-.532 1.523-.798 2.576-.798.968 0 1.793.17 2.473.51zm7.468 5.696v-.287c-.022-.607-.187-1.088-.495-1.444-.309-.357-.75-.535-1.324-.535-.532 0-.99.194-1.373.583-.382.388-.622.949-.717 1.683h3.909zm1.005 2.792v1.404c-.596.34-1.383.51-2.362.51-1.255 0-2.255-.377-3-1.132-.744-.755-1.116-1.744-1.116-2.968 0-1.297.34-2.316 1.021-3.055.68-.74 1.548-1.11 2.6-1.11 1.033 0 1.852.323 2.458.966.606.644.91 1.572.91 2.784 0 .33-.033.676-.096 1.038h-5.314c.107.702.405 1.239.894 1.611.49.372 1.106.558 1.85.558.862 0 1.58-.202 2.155-.606zm6.605-1.77h-1.212c-.596 0-1.045.116-1.349.35-.303.234-.454.532-.454.894 0 .372.117.664.35.877.235.213.575.32 1.022.32.51 0 .912-.142 1.204-.424.293-.281.44-.651.44-1.108v-.91zm-4.068-2.554V9.325c.627-.361 1.457-.542 2.489-.542 2.116 0 3.175 1.026 3.175 3.08V17h-1.548v-.957c-.415.68-1.143 1.02-2.186 1.02-.766 0-1.38-.22-1.843-.661-.462-.442-.694-1.003-.694-1.684 0-.776.293-1.38.878-1.81.585-.431 1.404-.647 2.457-.647h1.34V11.8c0-.554-.133-.971-.399-1.253-.266-.282-.707-.423-1.324-.423a4.07 4.07 0 0 0-2.345.718zm9.333-1.93v1.42c.394-1 1.101-1.5 2.123-1.5.148 0 .313.016.494.048v1.531a1.885 1.885 0 0 0-.75-.143c-.542 0-.989.24-1.34.718-.351.479-.527 1.048-.527 1.707V17h-1.563V8.91h1.563zm5.01 4.084c.022.82.272 1.492.75 2.019.479.526 1.15.79 2.01.79.639 0 1.235-.176 1.788-.527v1.404c-.521.319-1.186.479-1.995.479-1.265 0-2.276-.4-3.031-1.197-.755-.798-1.133-1.792-1.133-2.984 0-1.16.38-2.151 1.14-2.975.761-.825 1.79-1.237 3.088-1.237.702 0 1.346.149 1.93.447v1.436a3.242 3.242 0 0 0-1.77-.495c-.84 0-1.513.266-2.019.798-.505.532-.758 1.213-.758 2.042zM40.24 5.72v4.579c.458-1 1.293-1.5 2.505-1.5.787 0 1.42.245 1.899.734.479.49.718 1.17.718 2.042V17h-1.564v-5.106c0-.553-.14-.98-.422-1.284-.282-.303-.652-.455-1.11-.455-.531 0-1.002.202-1.411.606-.41.405-.615 1.022-.615 1.851V17h-1.563V5.72h1.563zm14.966 10.02c.596 0 1.096-.253 1.5-.758.404-.506.606-1.157.606-1.955 0-.915-.202-1.62-.606-2.114-.404-.495-.92-.742-1.548-.742-.553 0-1.05.224-1.491.67-.442.447-.662 1.133-.662 2.058 0 .958.212 1.67.638 2.138.425.469.946.703 1.563.703zM53.004 5.72v4.42c.574-.894 1.388-1.341 2.44-1.341 1.022 0 1.857.383 2.506 1.149.649.766.973 1.781.973 3.047 0 1.138-.309 2.109-.925 2.912-.617.803-1.463 1.205-2.537 1.205-1.075 0-1.894-.447-2.457-1.34V17h-1.58V5.72h1.58zm9.908 11.104l-3.223-7.913h1.739l1.005 2.632 1.26 3.415c.096-.32.48-1.458 1.15-3.415l.909-2.632h1.66l-2.92 7.866c-.777 2.074-1.963 3.11-3.559 3.11a2.92 2.92 0 0 1-.734-.079v-1.34c.17.042.351.064.543.064 1.032 0 1.755-.57 2.17-1.708z' fill='%235D6494'/%3E%3Cpath d='M89.632 5.967v-.772a.978.978 0 0 0-.978-.977h-2.28a.978.978 0 0 0-.978.977v.793c0 .088.082.15.171.13a7.127 7.127 0 0 1 1.984-.28c.65 0 1.295.088 1.917.259.082.02.164-.04.164-.13m-6.248 1.01l-.39-.389a.977.977 0 0 0-1.382 0l-.465.465a.973.973 0 0 0 0 1.38l.383.383c.062.061.15.047.205-.014.226-.307.472-.601.746-.874.281-.28.568-.526.883-.751.068-.042.075-.137.02-.2m4.16 2.453v3.341c0 .096.104.165.192.117l2.97-1.537c.068-.034.089-.117.055-.184a3.695 3.695 0 0 0-3.08-1.866c-.068 0-.136.054-.136.13m0 8.048a4.489 4.489 0 0 1-4.49-4.482 4.488 4.488 0 0 1 4.49-4.482 4.488 4.488 0 0 1 4.489 4.482 4.484 4.484 0 0 1-4.49 4.482m0-10.85a6.363 6.363 0 1 0 0 12.729 6.37 6.37 0 0 0 6.372-6.368 6.358 6.358 0 0 0-6.371-6.36' fill='%23FFF'/%3E%3C/g%3E%3C/svg%3E\");\n  background-repeat: no-repeat;\n  background-position: 50%;\n  background-size: 100%;\n}\n"
  },
  {
    "path": "scripts/site/doc/style/docsearch.less",
    "content": ".algolia-autocomplete {\n  .ds-dropdown-menu {\n    border: none;\n    box-shadow: @box-shadow-base;\n\n    [class^='ds-dataset-'] {\n      background: @component-background;\n      border: none;\n\n      .algolia-docsearch-suggestion {\n        background: @component-background;\n      }\n    }\n\n    &::before {\n      display: none;\n    }\n  }\n\n  .algolia-docsearch-suggestion--title {\n    color: @site-text-color;\n  }\n\n  .algolia-docsearch-suggestion--highlight {\n    color: @primary-color;\n  }\n\n  .page-wrapper-rtl & {\n    direction: rtl !important;\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/style/drawer.less",
    "content": "/* stylelint-disable */\n\n@ease-in-out-circ: cubic-bezier(0.78, 0.14, 0.15, 0.86);\n@duration: 0.3s;\n@drawer: drawer;\n.@{drawer} {\n  position: fixed;\n  top: 0;\n  z-index: 9999;\n  transition:\n    width 0s ease @duration,\n    height 0s ease @duration,\n    transform @duration @ease-in-out-circ;\n\n  > * {\n    transition:\n      transform @duration @ease-in-out-circ,\n      opacity @duration @ease-in-out-circ,\n      box-shadow @duration @ease-in-out-circ;\n  }\n  &.@{drawer}-open {\n    transition: transform @duration @ease-in-out-circ;\n  }\n\n  & &-mask {\n    position: absolute;\n    top: 0;\n    left: 0;\n    width: 100%;\n    height: 0;\n    background: #000;\n    opacity: 0;\n    transition:\n      opacity @duration @ease-in-out-circ,\n      height 0s ease @duration;\n  }\n\n  &-content-wrapper {\n    position: absolute;\n    background: #fff;\n  }\n\n  &-content {\n    position: relative;\n    z-index: 1;\n    overflow: auto;\n  }\n\n  &-handle {\n    position: absolute;\n    top: 72px;\n    z-index: 0;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    width: 41px;\n    height: 40px;\n    font-size: 16px;\n    line-height: 40px;\n    text-align: center;\n    background: #fff;\n    cursor: pointer;\n\n    &-icon {\n      position: relative;\n      width: 14px;\n      height: 2px;\n      background: #333;\n      transition: background @duration @ease-in-out-circ;\n\n      &::before,\n      &::after {\n        position: absolute;\n        display: block;\n        width: 100%;\n        height: 2px;\n        background: #333;\n        transition: transform @duration @ease-in-out-circ;\n        content: '';\n      }\n\n      &::before {\n        top: -5px;\n      }\n\n      &::after {\n        top: 5px;\n      }\n    }\n  }\n\n  &-left,\n  &-right {\n    width: 0%;\n    height: 100%;\n    .@{drawer}-content-wrapper,\n    .@{drawer}-content {\n      height: 100%;\n    }\n    &.@{drawer}-open {\n      width: 100%;\n\n      &.no-mask {\n        width: 0%;\n      }\n    }\n  }\n\n  &-left {\n    left: 0;\n    .@{drawer} {\n      &-handle {\n        right: -40px;\n        border-radius: 0 4px 4px 0;\n        box-shadow: 2px 0 8px rgba(0, 0, 0, 0.15);\n      }\n    }\n    &.@{drawer}-open {\n      .@{drawer} {\n        &-content-wrapper {\n          box-shadow: 2px 0 8px rgba(0, 0, 0, 0.15);\n        }\n      }\n    }\n  }\n\n  &-right {\n    right: 0;\n    .@{drawer} {\n      &-content-wrapper {\n        right: 0;\n      }\n\n      &-handle {\n        left: -40px;\n        border-radius: 4px 0 0 4px;\n        box-shadow: -2px 0 8px rgba(0, 0, 0, 0.15);\n      }\n    }\n    &.@{drawer}-open {\n      & .@{drawer} {\n        &-content-wrapper {\n          box-shadow: -2px 0 8px rgba(0, 0, 0, 0.15);\n        }\n      }\n\n      &.no-mask {\n        // https://github.com/ant-design/ant-design/issues/18607\n        right: 1px;\n        transform: translateX(1px);\n      }\n    }\n  }\n\n  &-top,\n  &-bottom {\n    width: 100%;\n    height: 0%;\n    .@{drawer}-content-wrapper,\n    .@{drawer}-content {\n      width: 100%;\n    }\n    .@{drawer}-content {\n      height: 100%;\n    }\n    &.@{drawer}-open {\n      height: 100%;\n\n      &.no-mask {\n        height: 0%;\n      }\n    }\n\n    .@{drawer} {\n      &-handle {\n        left: 50%;\n        margin-left: -20px;\n      }\n    }\n  }\n\n  &-top {\n    top: 0;\n    .@{drawer} {\n      &-handle {\n        top: auto;\n        bottom: -40px;\n        border-radius: 0 0 4px 4px;\n        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n      }\n    }\n    &.@{drawer}-open {\n      .@{drawer} {\n        &-content-wrapper {\n          box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n        }\n      }\n    }\n  }\n\n  &-bottom {\n    bottom: 0;\n    .@{drawer} {\n      &-content-wrapper {\n        bottom: 0;\n      }\n\n      &-handle {\n        top: -40px;\n        border-radius: 4px 4px 0 0;\n        box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.15);\n      }\n    }\n    &.@{drawer}-open {\n      .@{drawer} {\n        &-content-wrapper {\n          box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.15);\n        }\n      }\n\n      &.no-mask {\n        // https://github.com/ant-design/ant-design/issues/18607\n        bottom: 1px;\n        transform: translateY(1px);\n      }\n    }\n  }\n  &.@{drawer}-open {\n    .@{drawer} {\n      &-mask {\n        height: 100%;\n        opacity: 0.3;\n        transition: opacity 0.3s @ease-in-out-circ;\n      }\n\n      &-handle {\n        &-icon {\n          background: transparent;\n\n          &::before {\n            transform: translateY(5px) rotate(45deg);\n          }\n\n          &::after {\n            transform: translateY(-5px) rotate(-45deg);\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/style/footer.less",
    "content": "/* stylelint-disable */\n\n@import 'colors';\n\n.rc-footer {\n  position: relative;\n  clear: both;\n  color: rgba(0, 0, 0, 0.65);\n  font-size: 14px;\n  line-height: 1.5;\n  box-shadow: inset 0 106px 36px -116px rgba(0, 0, 0, 0.14);\n  background-color: #f0f3fa;\n}\n\n.rc-footer a {\n  text-decoration: none;\n  transition: all 0.3s;\n}\n\n.rc-footer a:hover {\n  color: #40a9ff;\n}\n\n.rc-footer-container {\n  width: 100%;\n  max-width: 1200px;\n  margin: auto;\n  padding: 80px 48px 20px;\n}\n\n.rc-footer-columns {\n  display: flex;\n  justify-content: space-around;\n}\n\n.rc-footer-column {\n  margin-bottom: 60px;\n}\n\n.rc-footer-column h2 {\n  position: relative;\n  margin: 0 auto 24px;\n  font-weight: 500;\n  font-size: 16px;\n}\n\n.rc-footer-column-icon {\n  position: relative;\n  top: -1px;\n  display: inline-block;\n  width: 22px;\n  margin-right: 0.5em;\n  text-align: center;\n  vertical-align: middle;\n}\n\n.rc-footer-column-icon > span,\n.rc-footer-column-icon > svg,\n.rc-footer-column-icon img {\n  display: block;\n  width: 100%;\n}\n\n.rc-footer-item {\n  margin: 12px 0;\n}\n\n.rc-footer-item-icon {\n  position: relative;\n  top: -1px;\n  display: inline-block;\n  width: 16px;\n  margin-right: 0.4em;\n  text-align: center;\n  vertical-align: middle;\n}\n\n.rc-footer-item-icon > span,\n.rc-footer-item-icon > svg,\n.rc-footer-item-icon img {\n  display: block;\n  width: 100%;\n}\n\n.rc-footer-item-separator {\n  margin: 0 0.3em;\n}\n\n.rc-footer-bottom {\n  box-shadow: inset 0 106px 36px -116px rgba(0, 0, 0, 0.14);\n\n  &-container {\n    width: 100%;\n    max-width: 1200px;\n    margin: 0 auto;\n    padding: 16px 0;\n    font-size: 14px;\n    line-height: 32px;\n    text-align: center;\n    border-top: 1px solid rgba(255, 255, 255, 0.25);\n    color: rgba(0, 0, 0, 0.65);\n  }\n}\n\n.rc-footer h2,\n.rc-footer a {\n  color: rgba(0, 0, 0, 0.88);\n}\n\n.rc-footer-bottom-container {\n  border-top-color: #e8e8e8;\n}\n\n.rc-footer-item-separator,\n.rc-footer-item-description {\n  color: rgba(0, 0, 0, 0.45);\n}\n\n[data-theme='dark'] {\n  .rc-footer {\n    background: #13161d;\n    color: rgba(255, 255, 255, 0.65);\n  }\n\n  .rc-footer h2,\n  .rc-footer a {\n    color: rgba(255, 255, 255, 0.85);\n  }\n\n  .rc-footer-item-separator,\n  .rc-footer-item-description {\n    color: rgba(255, 255, 255, 0.65);\n  }\n\n  .rc-footer-bottom-container {\n    border-color: rgba(255, 255, 255, 0.25);\n    color: rgba(255, 255, 255, 0.65);\n  }\n}\n\n@media only screen and (max-width: 767.99px) {\n  .rc-footer {\n    text-align: center;\n  }\n\n  .rc-footer-container {\n    padding: 40px 0;\n  }\n\n  .rc-footer-columns {\n    display: block;\n  }\n\n  .rc-footer-column {\n    display: block;\n    margin-bottom: 40px;\n  }\n\n  .rc-footer-column:last-child {\n    margin-bottom: 0;\n  }\n}\n\n.rc-footer {\n  z-index: 11;\n\n  &-columns {\n    justify-content: space-between;\n  }\n\n  &-item {\n    .page-wrapper-rtl & {\n      display: flex;\n      justify-content: flex-start;\n      text-align: right;\n    }\n\n    &-icon {\n      .page-wrapper-rtl & {\n        margin-right: 0;\n        margin-left: 0.4em;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/style/github-button.less",
    "content": ".github-btn {\n  height: 20px;\n  overflow: hidden;\n  font:\n    bold 11px/14px 'Helvetica Neue',\n    Helvetica,\n    Arial,\n    sans-serif;\n}\n\n.gh-btn,\n.gh-count,\n.gh-ico {\n  float: left;\n}\n\n.gh-btn,\n.gh-count {\n  padding: 2px 5px 2px 4px;\n  color: #333;\n  white-space: nowrap;\n  text-decoration: none;\n  border-radius: 3px;\n  cursor: pointer;\n}\n\n.gh-btn {\n  background-color: #eee;\n  background-image: linear-gradient(to bottom, #fcfcfc 0, #eee 100%);\n  background-repeat: no-repeat;\n  border: 1px solid #d5d5d5;\n  filter: \"progid:dximagetransform.microsoft.gradient(startColorstr='#fcfcfc', endColorstr='#eeeeee', GradientType=0)\";\n}\n\n.gh-btn:hover,\n.gh-btn:focus {\n  text-decoration: none;\n  background-color: #ddd;\n  background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #eee), color-stop(100%, #ddd));\n  background-image: linear-gradient(to bottom, #eee 0, #ddd 100%);\n  border-color: #ccc;\n  filter: \"progid:dximagetransform.microsoft.gradient(startColorstr='#eeeeee', endColorstr='#dddddd', GradientType=0)\";\n}\n\n.gh-btn:active {\n  background-color: #dcdcdc;\n  background-image: none;\n  border-color: #b5b5b5;\n  box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15);\n}\n\n.gh-ico {\n  width: 14px;\n  height: 14px;\n  margin-right: 4px;\n  background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2ZXJzaW9uPSIxLjEiIGlkPSJMYXllcl8xIiB4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjQwcHgiIGhlaWdodD0iNDBweCIgdmlld0JveD0iMTIgMTIgNDAgNDAiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMTIgMTIgNDAgNDAiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxwYXRoIGZpbGw9IiMzMzMzMzMiIGQ9Ik0zMiAxMy40Yy0xMC41IDAtMTkgOC41LTE5IDE5YzAgOC40IDUuNSAxNS41IDEzIDE4YzEgMC4yIDEuMy0wLjQgMS4zLTAuOWMwLTAuNSAwLTEuNyAwLTMuMiBjLTUuMyAxLjEtNi40LTIuNi02LjQtMi42QzIwIDQxLjYgMTguOCA0MSAxOC44IDQxYy0xLjctMS4yIDAuMS0xLjEgMC4xLTEuMWMxLjkgMC4xIDIuOSAyIDIuOSAyYzEuNyAyLjkgNC41IDIuMSA1LjUgMS42IGMwLjItMS4yIDAuNy0yLjEgMS4yLTIuNmMtNC4yLTAuNS04LjctMi4xLTguNy05LjRjMC0yLjEgMC43LTMuNyAyLTUuMWMtMC4yLTAuNS0wLjgtMi40IDAuMi01YzAgMCAxLjYtMC41IDUuMiAyIGMxLjUtMC40IDMuMS0wLjcgNC44LTAuN2MxLjYgMCAzLjMgMC4yIDQuNyAwLjdjMy42LTIuNCA1LjItMiA1LjItMmMxIDIuNiAwLjQgNC42IDAuMiA1YzEuMiAxLjMgMiAzIDIgNS4xYzAgNy4zLTQuNSA4LjktOC43IDkuNCBjMC43IDAuNiAxLjMgMS43IDEuMyAzLjVjMCAyLjYgMCA0LjYgMCA1LjJjMCAwLjUgMC40IDEuMSAxLjMgMC45YzcuNS0yLjYgMTMtOS43IDEzLTE4LjFDNTEgMjEuOSA0Mi41IDEzLjQgMzIgMTMuNHoiLz48L3N2Zz4=');\n  background-repeat: no-repeat;\n  background-size: 100% 100%;\n}\n\n.gh-count {\n  position: relative;\n  display: none; /* hidden to start */\n  margin-inline-start: 4px;\n  background-color: #fafafa;\n  border: 1px solid #d4d4d4;\n}\n\n.gh-count:hover,\n.gh-count:focus {\n  color: #4183c4;\n}\n\n.gh-count::before,\n.gh-count::after {\n  position: absolute;\n  display: inline-block;\n  width: 0;\n  height: 0;\n  border-color: transparent;\n  border-style: solid;\n  content: '';\n}\n\n.gh-count::before {\n  top: 50%;\n  left: -3px;\n  margin-top: -4px;\n  border-width: 4px 4px 4px 0;\n  border-right-color: #fafafa;\n\n  .page-wrapper-rtl & {\n    right: -3px;\n    left: auto;\n    transform: rotate(180deg);\n  }\n}\n\n.gh-count::after {\n  top: 50%;\n  left: -4px;\n  z-index: -1;\n  margin-top: -5px;\n  border-width: 5px 5px 5px 0;\n  border-right-color: #d4d4d4;\n\n  .page-wrapper-rtl & {\n    right: -4px;\n    left: auto;\n    transform: rotate(180deg);\n  }\n}\n\n.github-btn-large {\n  height: 30px;\n}\n\n.github-btn-large .gh-btn,\n.github-btn-large .gh-count {\n  padding: 3px 10px 3px 8px;\n  font-size: 16px;\n  line-height: 22px;\n  border-radius: 4px;\n}\n\n.github-btn-large .gh-ico {\n  width: 20px;\n  height: 20px;\n}\n\n.github-btn-large .gh-count {\n  margin-left: 6px;\n}\n\n.github-btn-large .gh-count::before {\n  left: -5px;\n  margin-top: -6px;\n  border-width: 6px 6px 6px 0;\n}\n\n.github-btn-large .gh-count::after {\n  left: -6px;\n  margin-top: -7px;\n  border-width: 7px 7px 7px 0;\n}\n"
  },
  {
    "path": "scripts/site/doc/style/header.less",
    "content": "#header {\n  // ===================== Home Page =====================\n  &.home-header {\n    position: absolute;\n    top: 0;\n    right: 0;\n    left: 0;\n    max-width: 1280px;\n    margin-right: auto;\n    margin-left: auto;\n    background: transparent;\n    box-shadow: none;\n\n    #logo {\n      padding-inline-start: 40px;\n      padding-inline-end: 16px;\n    }\n\n    .ant-menu {\n      background: transparent;\n    }\n  }\n}\n\n@media (max-width: @screen-sm-min) {\n  #header.home-header {\n    .ant-row {\n      .ant-col {\n        margin: 0 auto;\n\n        a {\n          padding-right: 0;\n          padding-left: 0;\n        }\n\n        &:last-child {\n          display: none;\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/style/highlight.less",
    "content": "/**\n* prism.js default theme for JavaScript, CSS and HTML\n* Based on dabblet (https://dabblet.com/)\n* @author Lea Verou\n*/\n\npre code {\n  display: block;\n  padding: 16px 32px;\n  color: @site-text-color;\n  font-size: @font-size-base;\n  font-family: 'Lucida Console', Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;\n  line-height: 2;\n  white-space: pre;\n  background: white;\n  border: 1px solid #e9e9e9;\n  border-radius: @border-radius-base;\n}\n\ncode[class*='language-'],\npre[class*='language-'] {\n  color: black;\n  font-family: 'Lucida Console', Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;\n  line-height: 1.5;\n  direction: ltr;\n  white-space: pre;\n  text-align: left;\n  word-wrap: normal;\n  word-break: normal;\n  word-spacing: normal;\n  tab-size: 4;\n  hyphens: none;\n  background: none;\n}\n\npre[class*='language-']::selection,\ncode[class*='language-']::selection {\n  text-shadow: none;\n  background: #b3d4fc;\n}\n\npre[class*='language-']::selection,\npre[class*='language-'] ::selection,\ncode[class*='language-']::selection,\ncode[class*='language-'] ::selection {\n  text-shadow: none;\n  background: #b3d4fc;\n}\n\n@media print {\n  code[class*='language-'],\n  pre[class*='language-'] {\n    text-shadow: none;\n  }\n}\n\n/* Code blocks */\npre[class*='language-'] {\n  margin: 16px 0;\n  padding: 12px 20px;\n  overflow: auto;\n}\n\n:not(pre) > code[class*='language-'],\npre[class*='language-'] {\n  background: #f5f5f5;\n}\n\n/* Inline code */\n:not(pre) > code[class*='language-'] {\n  padding: 0.1em;\n  white-space: normal;\n  border-radius: 0.3em;\n}\n\n.token.comment,\n.token.prolog,\n.token.doctype,\n.token.cdata {\n  color: slategray;\n}\n\n.token.punctuation {\n  color: #999;\n}\n\n.namespace {\n  opacity: 0.7;\n}\n\n.token.property,\n.token.tag,\n.token.boolean,\n.token.number,\n.token.constant,\n.token.symbol,\n.token.deleted {\n  color: #f81d22;\n}\n\n.token.selector,\n.token.attr-name,\n.token.string,\n.token.char,\n.token.builtin,\n.token.inserted {\n  color: #0b8235;\n}\n\n.token.operator,\n.token.entity,\n.token.url,\n.language-css .token.string,\n.style .token.string {\n  color: #0b8235;\n}\n\n.token.atrule,\n.token.attr-value,\n.token.keyword {\n  color: #008dff;\n}\n\n.token.function {\n  color: #f81d22;\n}\n\n.token.regex,\n.token.important,\n.token.variable {\n  color: #e90;\n}\n\n.token.important,\n.token.bold {\n  font-weight: bold;\n}\n\n.token.italic {\n  font-style: italic;\n}\n\n.token.entity {\n  cursor: help;\n}\n"
  },
  {
    "path": "scripts/site/doc/style/icon-pic-searcher.less",
    "content": ".icon-pic-searcher {\n  display: inline-block;\n  margin: 0 8px;\n\n  .icon-pic-btn {\n    color: @text-color-secondary;\n    cursor: pointer;\n    transition: all 0.3s;\n\n    &:hover {\n      color: @input-icon-hover-color;\n    }\n  }\n}\n\n.icon-pic-preview {\n  width: 66px;\n  height: 66px;\n  margin-top: 10px;\n  padding: 8px;\n  text-align: center;\n  border: 1px solid @border-color-base;\n  border-radius: 4px;\n\n  > img {\n    max-width: 50px;\n    max-height: 50px;\n  }\n}\n\n.icon-pic-search-result {\n  min-height: 50px;\n  padding: 0 10px;\n\n  > .result-tip {\n    padding: 10px 0;\n    color: @text-color-secondary;\n  }\n\n  > table {\n    width: 100%;\n\n    .col-icon {\n      width: 80px;\n      padding: 10px 0;\n\n      > i {\n        font-size: 30px;\n\n        :hover {\n          color: @link-hover-color;\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/style/icons.less",
    "content": "ul.anticons-list {\n  margin: 10px 0;\n  overflow: hidden;\n  list-style: none;\n\n  li {\n    position: relative;\n    float: left;\n    width: 16.66%;\n    height: 100px;\n    margin: 3px 0;\n    padding: 10px 0 0;\n    overflow: hidden;\n    color: #555;\n    text-align: center;\n    list-style: none;\n    background-color: inherit;\n    border-radius: 4px;\n    cursor: pointer;\n    transition: color 0.3s ease-in-out, background-color 0.3s ease-in-out;\n\n    .anticon {\n      margin: 12px 0 8px;\n      font-size: 36px;\n      transition: transform 0.3s ease-in-out;\n      will-change: transform;\n    }\n\n    .anticon-class {\n      display: block;\n      font-family: 'Lucida Console', Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;\n      white-space: nowrap;\n      text-align: center;\n      transform: scale(0.83);\n\n      .ant-badge {\n        transition: color 0.3s ease-in-out;\n      }\n    }\n\n    &:hover {\n      color: #fff;\n      background-color: @primary-color;\n\n      .anticon {\n        transform: scale(1.4);\n      }\n\n      .ant-badge {\n        color: #fff;\n      }\n    }\n\n    &.TwoTone:hover {\n      background-color: #8ecafe;\n    }\n\n    &.copied:hover {\n      color: rgba(255, 255, 255, 0.2);\n    }\n\n    &::after {\n      position: absolute;\n      top: 0;\n      left: 0;\n      width: 100%;\n      height: 100%;\n      color: #fff;\n      line-height: 110px;\n      text-align: center;\n      opacity: 0;\n      transition: all 0.3s cubic-bezier(0.18, 0.89, 0.32, 1.28);\n      content: 'Copied!';\n    }\n\n    &.copied::after {\n      top: -10px;\n      opacity: 1;\n    }\n  }\n}\n\n.copied-code {\n  padding: 2px 4px;\n  font-size: 12px;\n  background: #f5f5f5;\n  border-radius: 2px;\n}\n"
  },
  {
    "path": "scripts/site/doc/style/index.less",
    "content": "@import 'reset.less';\n@import 'common';\n@import 'header';\n@import 'footer';\n@import 'drawer';\n@import 'page-nav';\n@import 'markdown';\n@import 'preview-img';\n@import 'toc';\n@import 'highlight';\n@import 'demo';\n@import 'colors';\n@import 'icons';\n@import 'icon-pic-searcher';\n@import 'mock-browser';\n@import 'responsive';\n@import 'theme';\n@import 'docsearch';\n@import 'dark.less';\n"
  },
  {
    "path": "scripts/site/doc/style/markdown.less",
    "content": ".markdown {\n  color: @site-text-color;\n  font-size: 14px;\n  line-height: 2;\n}\n\n.highlight {\n  line-height: 1.5;\n}\n\n.markdown img {\n  max-width: ~'calc(100% - 32px)';\n  max-height: 100%;\n  object-fit: contain;\n}\n\n.markdown p > img {\n  margin: 34px 0;\n  box-shadow: 0 8px 20px rgba(143, 168, 191, 0.35);\n}\n\n.markdown p > img.markdown-inline-image {\n  margin: 0;\n  box-shadow: none;\n}\n\n.markdown h1 {\n  margin-bottom: 16px;\n  color: @site-heading-color;\n  font-weight: 600;\n  font-size: 32px;\n  font-family: AlibabaSans, @font-family, sans-serif;\n  line-height: 38px;\n}\n\n.markdown h2 {\n  font-size: 24px;\n  line-height: 32px;\n}\n\n.markdown h2,\n.markdown h3,\n.markdown h4,\n.markdown h5,\n.markdown h6 {\n  clear: both;\n  margin: 1.6em 0 0.6em;\n  color: @site-heading-color;\n  font-weight: 500;\n  font-family: Avenir, @font-family, sans-serif;\n}\n\n.markdown h3 {\n  font-size: 18px;\n}\n\n.markdown h4 {\n  font-size: 16px;\n}\n\n.markdown h5 {\n  font-size: 14px;\n}\n\n.markdown h6 {\n  font-size: 12px;\n}\n\n.markdown hr {\n  clear: both;\n  height: 1px;\n  margin: 56px 0;\n  background: @site-border-color-split;\n  border: 0;\n}\n\n.markdown p,\n.markdown pre {\n  margin: 1em 0;\n}\n\n.markdown ul > li {\n  margin-inline-start: 20px;\n  padding-inline-start: 4px;\n  list-style-type: circle;\n\n  &:empty {\n    display: none;\n  }\n}\n\n.markdown ol > li {\n  margin-inline-start: 20px;\n  padding-inline-start: 4px;\n  list-style-type: decimal;\n}\n\n.markdown ul > li > p,\n.markdown ol > li > p {\n  margin: 0.2em 0;\n}\n\n.markdown code {\n  margin: 0 1px;\n  padding: 0.2em 0.4em;\n  font-size: 0.9em;\n  background: @site-markdown-code-bg;\n  border: 1px solid @border-color-split;\n  border-radius: 3px;\n}\n\n.markdown pre {\n  font-family: @code-family;\n  background: @site-markdown-code-bg;\n  border-radius: @border-radius-base;\n}\n\n.markdown pre code {\n  margin: 0;\n  padding: 12px 20px;\n  overflow: auto;\n  color: @site-text-color;\n  font-size: @font-size-base - 1px;\n  background: #f5f5f5;\n  border: none;\n}\n\n.markdown strong,\n.markdown b {\n  font-weight: 500;\n}\n\n.markdown > table {\n  width: 100%;\n  margin: 8px 0 16px;\n  empty-cells: show;\n  border: 1px solid @site-border-color-split;\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n\n.markdown > table th {\n  color: #5c6b77;\n  font-weight: 500;\n  white-space: nowrap;\n  background: rgba(0, 0, 0, 0.02);\n}\n\n.markdown > table th,\n.markdown > table td {\n  padding: 16px 24px;\n  text-align: left;\n  border: 1px solid @site-border-color-split;\n}\n\n.markdown blockquote {\n  margin: 1em 0;\n  padding-inline-start: 0.8em;\n  color: @site-text-color-secondary;\n  font-size: 90%;\n  border-inline-start: 4px solid @site-border-color-split;\n}\n\n.markdown blockquote p {\n  margin: 0;\n}\n\n.markdown .anchor {\n  margin-inline-start: 8px;\n  opacity: 0;\n  transition: opacity 0.3s;\n}\n\n.markdown .waiting {\n  color: #ccc;\n  cursor: not-allowed;\n}\n\n.markdown a.edit-button {\n  display: inline-block;\n  margin-inline-start: 8px;\n  text-decoration: none;\n\n  .anticon {\n    display: block;\n    color: @site-text-color-secondary;\n    font-size: 16px;\n\n    &:hover {\n      color: @site-text-color;\n    }\n  }\n}\n\n.markdown h1:hover .anchor,\n.markdown h2:hover .anchor,\n.markdown h3:hover .anchor,\n.markdown h4:hover .anchor,\n.markdown h5:hover .anchor,\n.markdown h6:hover .anchor {\n  display: inline-block;\n  opacity: 1;\n}\n\n.markdown > br,\n.markdown > p > br {\n  clear: both;\n}\n\n.markdown.api-container {\n  overflow-x: auto;\n\n  table {\n    min-width: 720px;\n    margin: 2em 0;\n    font-size: @font-size-base - 1px;\n    font-family: @code-family;\n    line-height: @line-height-base;\n    border: 1px solid @border-color-split;\n\n    th,\n    td {\n      padding: 12px;\n      border-color: @border-color-split;\n      border-width: 1px 0;\n    }\n\n    th {\n      padding-top: 14px;\n      border-width: 0 0 2px;\n    }\n\n    tbody tr {\n      transition: all 0.3s;\n\n      &:hover {\n        background: rgba(60, 90, 100, 0.04);\n      }\n    }\n\n    td {\n      &:first-child {\n        width: 20%;\n        color: @gray-8;\n        font-weight: 600;\n      }\n\n      &:nth-child(3) {\n        width: 22%;\n        color: @magenta-7;\n        font-size: @font-size-base - 1px;\n        word-break: break-all;\n      }\n\n      &:nth-child(4) {\n        width: 16%;\n        font-size: @font-size-base - 1px;\n      }\n    }\n  }\n\n  hr {\n    margin: 12px 0;\n  }\n}\n\n@demo-grid-color: #0092ff;\n\n.grid-demo,\n[id^='components-grid-demo-'] {\n  .demo-row,\n  .code-box-demo .demo-row {\n    margin-bottom: 8px;\n    overflow: hidden;\n    background-image: linear-gradient(\n      90deg,\n      #f5f5f5 4.16666667%,\n      transparent 4.16666667%,\n      transparent 8.33333333%,\n      #f5f5f5 8.33333333%,\n      #f5f5f5 12.5%,\n      transparent 12.5%,\n      transparent 16.66666667%,\n      #f5f5f5 16.66666667%,\n      #f5f5f5 20.83333333%,\n      transparent 20.83333333%,\n      transparent 25%,\n      #f5f5f5 25%,\n      #f5f5f5 29.16666667%,\n      transparent 29.16666667%,\n      transparent 33.33333333%,\n      #f5f5f5 33.33333333%,\n      #f5f5f5 37.5%,\n      transparent 37.5%,\n      transparent 41.66666667%,\n      #f5f5f5 41.66666667%,\n      #f5f5f5 45.83333333%,\n      transparent 45.83333333%,\n      transparent 50%,\n      #f5f5f5 50%,\n      #f5f5f5 54.16666667%,\n      transparent 54.16666667%,\n      transparent 58.33333333%,\n      #f5f5f5 58.33333333%,\n      #f5f5f5 62.5%,\n      transparent 62.5%,\n      transparent 66.66666667%,\n      #f5f5f5 66.66666667%,\n      #f5f5f5 70.83333333%,\n      transparent 70.83333333%,\n      transparent 75%,\n      #f5f5f5 75%,\n      #f5f5f5 79.16666667%,\n      transparent 79.16666667%,\n      transparent 83.33333333%,\n      #f5f5f5 83.33333333%,\n      #f5f5f5 87.5%,\n      transparent 87.5%,\n      transparent 91.66666667%,\n      #f5f5f5 91.66666667%,\n      #f5f5f5 95.83333333%,\n      transparent 95.83333333%\n    );\n  }\n\n  .ant-row > div,\n  .code-box-demo .ant-row > div {\n    min-height: 30px;\n    margin-top: 8px;\n    margin-bottom: 8px;\n    color: #fff;\n    text-align: center;\n    border-radius: 0;\n  }\n\n  .code-box-demo .ant-row > div:not(.gutter-row) {\n    padding: 16px 0;\n    background: @demo-grid-color;\n\n    &:nth-child(2n + 1) {\n      background: fade(@demo-grid-color, 75%);\n    }\n  }\n\n  .ant-row .demo-col,\n  .code-box-demo .ant-row .demo-col {\n    margin-top: 0;\n    margin-bottom: 0;\n    padding: 30px 0;\n    color: @white;\n    font-size: 18px;\n    text-align: center;\n    border: none;\n  }\n\n  .ant-row .demo-col-1 {\n    background: fade(@demo-grid-color, 75%);\n  }\n\n  .ant-row .demo-col-2,\n  .code-box-demo .ant-row .demo-col-2 {\n    background: fade(@demo-grid-color, 50%);\n  }\n\n  .ant-row .demo-col-3,\n  .code-box-demo .ant-row .demo-col-3 {\n    color: #999;\n    background: rgba(255, 255, 255, 0.2);\n  }\n\n  .ant-row .demo-col-4,\n  .code-box-demo .ant-row .demo-col-4 {\n    background: fade(@demo-grid-color, 60%);\n  }\n\n  .ant-row .demo-col-5,\n  .code-box-demo .ant-row .demo-col-5 {\n    color: #999;\n    background: rgba(255, 255, 255, 0.2);\n  }\n\n  .code-box-demo .height-100 {\n    height: 100px;\n    line-height: 100px;\n  }\n\n  .code-box-demo .height-50 {\n    height: 50px;\n    line-height: 50px;\n  }\n\n  .code-box-demo .height-120 {\n    height: 120px;\n    line-height: 120px;\n  }\n\n  .code-box-demo .height-80 {\n    height: 80px;\n    line-height: 80px;\n  }\n}\n\n[id='components-grid-demo-playground'],\n[id='components-grid-demo-gutter'] {\n  > .code-box-demo .ant-row > div {\n    margin-top: 0;\n    margin-bottom: 0;\n  }\n}\n\n// For Changelog\n.markdown ul.ant-timeline {\n  line-height: 2;\n\n  li.ant-timeline-item {\n    margin: 0;\n    padding: 0 0 30px;\n    list-style: none;\n\n    .ant-timeline-item-content {\n      position: relative;\n      top: -14px;\n      padding-left: 32px;\n      font-size: 14px;\n\n      > h2 {\n        margin-top: 0;\n        padding-top: 4px;\n        direction: ltr;\n\n        span {\n          .ant-row-rtl & {\n            float: right;\n          }\n        }\n      }\n    }\n  }\n\n  li.ant-timeline-item:first-child {\n    margin-top: 40px;\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/style/mock-browser.less",
    "content": "/* Browser mockup code\n * Contribute: https://gist.github.com/jarthod/8719db9fef8deb937f4f\n * Live example: https://updown.io\n */\n\n.browser-mockup {\n  position: relative;\n  border-top: 2em solid rgba(230, 230, 230, 0.7);\n  border-radius: 3px 3px 0 0;\n  box-shadow: 0 0.1em 0.5em 0 rgba(0, 0, 0, 0.28);\n}\n\n.browser-mockup::before {\n  position: absolute;\n  top: -1.25em;\n  left: 1em;\n  display: block;\n  width: 0.5em;\n  height: 0.5em;\n  background-color: #f44;\n  border-radius: 50%;\n  box-shadow: 0 0 0 2px #f44, 1.5em 0 0 2px #9b3, 3em 0 0 2px #fb5;\n  content: '';\n}\n\n.browser-mockup.with-tab::after {\n  position: absolute;\n  top: -2em;\n  left: 5.5em;\n  display: block;\n  width: 20%;\n  height: 0;\n  border-right: 0.8em solid transparent;\n  border-bottom: 2em solid white;\n  border-left: 0.8em solid transparent;\n  content: '';\n}\n\n.browser-mockup.with-url::after {\n  position: absolute;\n  top: -1.6em;\n  left: 5.5em;\n  display: block;\n  width: ~'calc(100% - 6em)';\n  height: 1.2em;\n  background-color: white;\n  border-radius: 2px;\n  content: '';\n}\n\n.browser-mockup > * {\n  display: block;\n}\n"
  },
  {
    "path": "scripts/site/doc/style/page-nav.less",
    "content": ".prev-next-nav {\n  margin-right: 64px;\n  margin-left: 64px;\n  overflow: hidden;\n  font-size: 14px;\n  border-top: 1px solid @site-border-color-split;\n\n  > .prev-page,\n  > .next-page {\n    float: left;\n    width: 50%;\n    height: 72px;\n    line-height: 72px;\n    text-decoration: none;\n\n    .page-wrapper-rtl & {\n      float: right;\n    }\n  }\n\n  > a.prev-page {\n    .footer-nav-icon-before {\n      position: relative;\n      inset-inline-start: 0;\n      margin-inline-end: 1em;\n      color: @site-text-color-secondary;\n      font-size: 12px;\n      transition: all 0.3s;\n\n      .page-wrapper-rtl & {\n        transform: rotate(180deg);\n      }\n    }\n\n    .footer-nav-icon-after {\n      display: none;\n    }\n\n    &:hover .footer-nav-icon-before {\n      inset-inline-start: -3px;\n      color: @primary-color;\n    }\n  }\n\n  > .next-page {\n    float: right;\n    text-align: right;\n\n    .page-wrapper-rtl & {\n      float: left;\n      text-align: left;\n    }\n\n    .footer-nav-icon-after {\n      position: relative;\n      inset-inline-end: 0;\n      margin-inline-start: 1em;\n      color: @site-text-color-secondary;\n      font-size: 12px;\n      transition: all 0.3s;\n\n      .page-wrapper-rtl & {\n        transform: rotate(180deg);\n      }\n    }\n\n    .footer-nav-icon-before {\n      display: none;\n    }\n\n    &:hover .footer-nav-icon-after {\n      inset-inline-end: -3px;\n      color: @primary-color;\n    }\n  }\n\n  .chinese {\n    margin-inline: 0.5em;\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/style/patch.less",
    "content": "@media screen and (width <= 767px) {\n  .pic-plus img {\n    width: 120px;\n    height: auto;\n  }\n}\n\n.pic-plus>* {\n  display: inline-block !important;\n  vertical-align: middle;\n}\n\n.pic-plus span {\n  margin: 0 20px;\n  color: #aaa;\n  font-size: 30px;\n}\n\n.top-menu-additional {\n  position: relative;\n  right: 80px;\n  width: 190px;\n}\n\n.theme-color-content .ant-popover-inner-content {\n  width: 200px;\n  padding: 0;\n}\n\n#ng-content {\n  height: 100%;\n  transition: transform 0.3s @ease-in-out-circ;\n}\n\n.toc-affix {\n  .ant-anchor {\n    width: 128px;\n    font-size: 12px;\n\n    .ant-anchor-ink::before {\n      width: 1px;\n      border-left: 1px solid @site-border-color-split;\n    }\n\n    .ant-anchor-link-active {\n      position: relative;\n      z-index: 2;\n      margin-left: -2px;\n      border-left: 2px solid @primary-color;\n    }\n\n    .ant-anchor-ink-ball-visible {\n      display: none;\n    }\n\n    .ant-anchor-link {\n      &.toc-indent-1 {\n        padding-inline-start: 16px;\n      }\n\n      &.toc-indent-2 {\n        padding-inline-start: 32px;\n      }\n\n      &.ant-anchor-link-active {\n        .ant-anchor-link-title {\n          color: @primary-color;\n        }\n      }\n\n      .ant-anchor-link-title {\n        width: 110px;\n        color: @site-text-color;\n        white-space: nowrap;\n        text-overflow: ellipsis;\n      }\n    }\n  }\n}\n\n.site-page-header {\n  border: 1px solid rgb(235, 237, 240);\n}\n\n.site-page-header-ghost-wrapper {\n  padding: 24px;\n  background-color: #f5f5f5;\n}\n\nbody[data-theme='dark'],\n[data-theme='dark'] * {\n  scrollbar-color: #434343 #262626;\n\n  &::-webkit-scrollbar {\n    width: 14px;\n  }\n\n  &::-webkit-scrollbar-track {\n    background: #262626;\n  }\n\n  &::-webkit-scrollbar-thumb {\n    background-color: #434343;\n    border: 2px solid #262626;\n    border-radius: 6px;\n\n    :hover {\n      background-color: #262626;\n    }\n  }\n}\n\nlabel {\n  &.api-type-label {\n    display: inline;\n    margin-inline-start: 8px;\n    padding: 1px 10px;\n    color: @text-color-dark;\n    font-weight: normal;\n    font-size: 12px;\n    line-height: 18px;\n    text-transform: uppercase;\n    vertical-align: middle;\n    border-radius: @border-radius-base;\n\n    &.directive {\n      color: @magenta-6;\n      border: 2px solid @magenta-6;\n    }\n\n    &.component {\n      color: @blue-6;\n      border: 2px solid @blue-6;\n    }\n\n    &.service {\n      color: @green-6;\n      border: 2px solid @green-6;\n    }\n  }\n}\n\n\n[data-theme='dark'] {\n  .site-badge-count-4 .ant-badge-count {\n    background-color: @component-background !important;\n    box-shadow: 0 0 0 1px #434343 inset !important;\n  }\n\n  .head-example {\n    background: rgb(255, 255, 255, .12) !important;\n  }\n\n  .popover-menu .ant-popover-inner-content #nav a {\n    color: @text-color;\n  }\n\n  .gh-ico {\n    background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MzlFQkFERkU4NkJCMTFFM0FBNTJFRTMzNTJEMUJDNDYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MzlFQkFERkQ4NkJCMTFFM0FBNTJFRTMzNTJEMUJDNDYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkU1MTc4QTJFOTlBMDExRTI5QTE1QkMxMDQ2QTg5MDREIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkU1MTc4QTJGOTlBMDExRTI5QTE1QkMxMDQ2QTg5MDREIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+Kk5lQwAABYxJREFUeNrkm29oVXUYx3+7bM3V1FnbqlltrtXWtYRa1nqxooY5E7EhKWGuaTDBagol9SIMDCKICASj+cISw/DPi16ZBakrUBnoC7nNoTMWy6I1c+LmVq6t78N9jpyu555znt855+536IHPi939/jzP95zznN+/kzc1NaUitirwJJgPasF94DZQDG7hMqNgBFwEZ5kU+AH0R+lcXgQCJMBT4EXwLKgM2N7P4FvwJegCk6YKUA5eB23grogu2C/gc7AN/GGKABTsZtAOZqjc2DjYAT5kUfSNBNCkAGwGo1PTZ6PsQ4FuHLp3QD3YDR5QZtgZsAac1ElYokcGbATHDApesS/kUwf7GEkOKAK7wAvKbNsPXgZjYQowG3wNnlDxsONgCbgchgAU/GHwiIqXUT5o8hLBKwfcDA7FMHgrUR/iGLQEoGTyBWhQ8bUGjiFPR4A3QIuKv7VwLKIcQMnue5Dv0fjT/IwtAM3g+RyMBmkU+BXf3qc5Rx3xqDPBE7LjfkaCheCcj1HYKYe6JeBt8GcEo75L3HaJQ7+nfNQ/x7H9p67TFX4L1Pi4EocdfhsGH4BPwVbwqu0xGwI/8vT2N/77Gv+vAJSCO3n6PJ//Vjz72w62cPtORnfAwx7+1nBsW93ugGow7vOKtPkYa9eDl0Clxji9kuvW+yjb5tPncY7xet3MhjoFt2RzgIlU2DQL/O6017W/Be4BawXJqMCgTH+ToOxajvWG1+AmYVBlBglQKrxwmzIFoB9XCzt91CABpL6sti62JcBiXtKS2GMGCSD1pZxjvi7AKmED9PraYJAAG2yvVL+2yi7AImHl90C3QQJ03/B+97ZF1lCYVlN6BBV/BffykNQkoyF4H5grqJOkO6BR2NF2A4O35gifCOs0JjTW9vYaPPPbJ11LJAFqBRVoDf68wQLQI3BBUL424XPiY1lvDOb/ZwRla0iAOYIKv8dAgEFB2VtJgJmCChMxEEAyHigmAQoFFWbFQIDZgrKF0p2hmTEQQOQjCTAmKD8vBgJUCcqOkQBXBBXosEORwcEXKdmBjCskwICgQr5h0+BMW6i8V7LtNkAC9As7WWqwAM8Jy/cnhBMhspVKvq2eC0uwbxLrSWhMa+dpdJQLW6mRpLtpOlyuMcL7CTwErhoSPG2ApjQEuD3BQ0fp0ZJqlT6pZYpt0wieYh60nuWDGp2+At4xIPgt7IvU0jHzBkFdgD27HWDGNGyGFHHfulaXuTN0IkBjZ8EykJeDwKmPFtAXwN8TTltjrVkKfwcawXJW3G3v8DTYCKoiCLwGvAl6QthpbnU6J5jP2f1uh1Wgxbbxwv0qvT/vtZRGA6wuzs50+Pkb8JdgQtPMq1VJld7bnxtSzhjgJD5hzwEW611OZK6xlSvzeYbAsl3Cx4PK7ozodOl6t93hfJByqbzOVnYh+MdHhxfBLI1bnuoMhRx8imPMKgDR5LG/nrSVfddHpx8HeO4/ClmApsw+snXsdk7gYMat+r5Hp0sDCLAkxOA7nfrI1nGxx2tmQUb5x8FuzgvD4Dw4wNm2MIAA1SEF38cx+RaAeBCMZGlwb44GOyUhBD/CsTj24TatpddXq3L+RIVmXnE4QzjJMaSylvBxFdqzKHsVrDD8Dmj36sOvIx0unewHDRENg4MI0BH2FyP0RcZOlzW3Ib7VLvPqDK0z1PEq7bDmLVwCLgnr0AhvnUp/0eJp0k9m6HO4fUp2nGZODgUY5PzUJVlHkxg1TEfnjxqY8I6yb12SSjqLm7T9/Ax4TaW/+JxuIx862KcL4toBk1QFT1omXZLRHQHaL3Npl/r8jH3QjiGsbJ3kGd/fDo6WBWi31KG9a9xXMgzfw35tVfCR9l52dk8Ibe7htnq57YowfY7i4+lYWUL9z+1fAQYACqstE4NCc18AAAAASUVORK5CYII=')\n  }\n\n  .site-page-header {\n    border: 1px solid #303030;\n  }\n\n  .site-page-header-ghost-wrapper {\n    background-color: rgb(255, 255, 255, 0.08);\n  }\n\n  .drawer-content-wrapper {\n    background-color: @component-background;\n  }\n}\n\n.resource-cards {\n  .resource-card {\n    display: flex;\n    flex-direction: column;\n    height: 100%;\n    color: inherit;\n    list-style: none;\n    border: 1px solid #e6e6e6;\n    border-radius: 2px;\n    cursor: pointer;\n    transition: box-shadow 0.3s;\n\n    &:hover {\n      box-shadow: @shadow-2;\n    }\n\n    .resource-card-image {\n      width: calc(100% + 2px);\n      max-width: none;\n      height: 184px;\n      margin: -1px -1px 0;\n      object-fit: cover;\n    }\n\n    .resource-card-title {\n      margin: 16px 20px 8px;\n      color: #0d1a26;\n      font-size: 20px;\n      line-height: 28px;\n    }\n\n    .resource-card-description {\n      margin: 0 20px 20px;\n      color: #697b8c;\n      font-size: 14px;\n      line-height: 22px;\n    }\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/style/preview-img.less",
    "content": ".preview-image-boxes {\n  display: flex;\n  float: right;\n  clear: both;\n  width: 496px;\n  margin: 0 0 70px 64px;\n\n  &-with-carousel {\n    width: 420px;\n\n    .preview-image-box img {\n      padding: 0;\n    }\n  }\n}\n\n.preview-image-boxes + .preview-image-boxes {\n  margin-top: -35px;\n}\n\n.preview-image-box {\n  float: left;\n  width: 100%;\n}\n\n.preview-image-box + .preview-image-box {\n  margin-left: 24px;\n}\n\n.preview-image-wrapper {\n  position: relative;\n  display: inline-block;\n  width: 100%;\n  padding: 16px;\n  text-align: center;\n  background: #f2f4f5;\n}\n\n.preview-image-wrapper.video {\n  display: block;\n  padding: 0;\n  background: 0;\n}\n\n.preview-image-wrapper video {\n  display: block;\n  width: 100%;\n\n  + svg {\n    position: absolute;\n    top: 0;\n    left: 0;\n  }\n}\n\n.preview-image-wrapper.good::after {\n  position: absolute;\n  bottom: 0;\n  left: 0;\n  display: block;\n  width: 100%;\n  height: 3px;\n  background: @primary-color;\n  content: '';\n}\n\n.preview-image-wrapper.bad::after {\n  position: absolute;\n  bottom: 0;\n  left: 0;\n  display: block;\n  width: 100%;\n  height: 3px;\n  background: @error-color;\n  content: '';\n}\n\n.preview-image-title {\n  margin-top: 5px;\n  color: @site-text-color;\n  font-size: 12px;\n}\n\n.preview-image-description {\n  margin-top: 2px;\n  color: @site-text-color-secondary;\n  font-size: 12px;\n  line-height: 1.5;\n}\n\n.preview-image-description hr {\n  margin: 2px 0;\n  background: none;\n  border: 0;\n}\n\n.preview-image-box img {\n  max-width: 100%;\n  padding: 12px;\n  background: @body-background;\n  border-radius: @border-radius-base;\n  cursor: pointer;\n  transition: all 0.3s;\n\n  &.no-padding {\n    padding: 0;\n    background: none;\n  }\n}\n\n.preview-image-boxes.preview-image-boxes-with-carousel img {\n  padding: 0;\n  box-shadow: 0 1px 0 0 #ddd, 0 3px 0 0 @body-background, 0 4px 0 0 #ddd, 0 6px 0 0 @body-background,\n    0 7px 0 0 #ddd;\n}\n\n.preview-image-box img:hover {\n  box-shadow: 1px 1px 6px rgba(0, 0, 0, 0.3);\n}\n\n.image-modal {\n  text-align: center;\n\n  &-container {\n    position: relative;\n    text-align: center;\n  }\n\n  .ant-carousel {\n    .slick-slider {\n      padding-bottom: 24px;\n\n      img {\n        display: inline;\n        max-width: 100%;\n      }\n    }\n\n    .slick-dots {\n      bottom: 4px;\n\n      li button {\n        background: #888;\n      }\n    }\n  }\n\n  .image-modal-single.slick-slider {\n    padding-bottom: 0;\n  }\n\n  .image-modal-single .slick-dots {\n    display: none !important;\n  }\n}\n\n.transition-video-player,\n.motion-video-min {\n  float: right;\n  width: 600px;\n  padding: 0 0 70px 20px;\n\n  .preview-image-wrapper {\n    padding: 0;\n  }\n}\n\n.motion-video-min {\n  width: 390px;\n}\n\n.motion-principle-wrapper {\n  width: 100%;\n  max-width: 900px;\n  margin: 48px 0 24px;\n}\n\n.principle-wrapper {\n  width: 100%;\n\n  .principle {\n    display: inline-block;\n    width: 100%;\n    min-height: 180px;\n    margin-right: 12.5%;\n    margin-bottom: 24px;\n    padding: 24px;\n    font-size: 24px;\n    text-align: center;\n    border: 1px solid #e8e8e8;\n    border-radius: 4px;\n\n    &:last-child {\n      margin-right: 0;\n    }\n\n    h4 {\n      margin: 16px 0 8px;\n    }\n\n    p {\n      font-size: 12px;\n      line-height: 24px;\n    }\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/style/reset.less",
    "content": "body,\ndiv,\ndl,\ndt,\ndd,\nul,\nol,\nli,\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\npre,\ncode,\nform,\nfieldset,\nlegend,\ninput,\ntextarea,\np,\nblockquote,\nth,\ntd,\nhr,\nbutton,\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmenu,\nnav,\nsection {\n  margin: 0;\n  padding: 0;\n}\n\nul,\nol {\n  list-style: none;\n}\n"
  },
  {
    "path": "scripts/site/doc/style/responsive.less",
    "content": ".nav-phone-icon {\n  position: absolute;\n  top: 25px;\n  right: 30px;\n  z-index: 1;\n  display: none;\n  width: 16px;\n  height: 22px;\n  cursor: pointer;\n}\n\n@media only screen and (max-width: @screen-lg) {\n  .main-container,\n  .ant-row-rtl .main-container {\n    padding-right: 48px;\n    padding-left: 48px;\n\n    .toc-affix {\n      display: none;\n    }\n  }\n}\n\n@media only screen and (width <= 767.99px) {\n  .preview-image-boxes {\n    float: none;\n    width: 100%;\n    margin: 0 !important;\n  }\n\n  .preview-image-box {\n    width: 100%;\n    margin: 10px 0;\n    padding: 0;\n  }\n\n  .image-wrapper {\n    display: none;\n  }\n\n  .toc {\n    display: none;\n  }\n\n  .nav-phone-icon {\n    display: block;\n  }\n\n  .main {\n    height: calc(100% - 86px);\n  }\n\n  .aside-container {\n    float: none;\n    width: auto;\n    padding-bottom: 30px;\n    border-right: 0;\n  }\n\n  .main-container,\n  .ant-row-rtl .main-container {\n    margin-right: 0;\n    margin-left: 0;\n    padding-right: 16px;\n    padding-left: 16px;\n\n    > .markdown > * {\n      width: 100% !important;\n    }\n  }\n\n  .main-wrapper {\n    width: 100%;\n    margin: 0;\n    border-radius: 0;\n  }\n\n  .prev-next-nav {\n    width: ~'calc(100% - 32px)';\n    margin-left: 16px;\n  }\n\n  .drawer {\n    .ant-menu-inline .ant-menu-item::after,\n    .ant-menu-vertical .ant-menu-item::after {\n      right: auto;\n      left: 0;\n    }\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/style/theme.less",
    "content": "@site-heading-color: @heading-color;\n@site-text-color: @heading-color;\n@site-text-color-secondary: @text-color-secondary;\n@site-border-color-split: @border-color-split;\n@site-header-box-shadow: 0 2px 8px rgba(240, 241, 242, 65);\n@site-markdown-code-bg: #f2f4f5;\n"
  },
  {
    "path": "scripts/site/doc/style/toc.less",
    "content": ".toc {\n  margin: 16px 0;\n  padding-inline-start: 0;\n  font-size: 12px;\n  list-style: none;\n  border-inline-start: 1px solid @site-border-color-split;\n}\n\nul.toc > li {\n  margin-inline-start: 0;\n  padding-inline-start: 0;\n  line-height: 1.5;\n  list-style: none;\n\n  &:not(:last-child) {\n    margin-bottom: 4px;\n  }\n}\n\n.toc li > ul {\n  display: none;\n  font-size: 12px;\n  text-indent: 8px;\n}\n\n.toc a {\n  display: block;\n  width: 110px;\n  margin-inline-start: -1px;\n  padding-inline-start: 16px;\n  overflow: hidden;\n  color: @site-text-color;\n  white-space: nowrap;\n  text-overflow: ellipsis;\n  border-inline-start: 1px solid transparent;\n  transition: all 0.3s ease;\n}\n\n.toc a:hover {\n  color: @primary-color;\n}\n\n.toc a.current {\n  color: @primary-color;\n  border-color: @primary-color;\n}\n\n.toc-affix {\n  position: absolute;\n  top: 8px;\n  inset-inline-end: 20px;\n\n  .ant-affix {\n    z-index: 9;\n    max-height: ~'calc(100vh - 16px)';\n    overflow-x: hidden;\n    overflow-y: auto;\n    background: #fff;\n  }\n}\n"
  },
  {
    "path": "scripts/site/doc/styles.less",
    "content": "/* You can add global styles to this file, and also import other style files */\n@import '../components/ng-zorro-antd.variable.less';\n@import '../components/resizable/style/entry.less';\n@import '../components/code-editor/style/entry.less';\n@import '../components/graph/style/entry.less';\n@import '../components/tag/style/entry.less';\n@import './app/header/header';\n@import 'style/index';\n@import 'style/patch';\n@import 'style/doc-search';\n"
  },
  {
    "path": "scripts/site/doc/tsconfig.app.json",
    "content": "{\n  \"extends\": \"../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../out-tsc/app\",\n    \"baseUrl\": \"./\",\n    \"module\": \"es2020\",\n    \"isolatedModules\": true,\n    \"types\": [\n      \"node\",\n      \"express\"\n    ],\n    \"paths\": {\n      \"ng-zorro-antd\": [\n        \"../components/ng-zorro-antd.module.ts\"\n      ],\n      \"ng-zorro-antd/*\": [\n        \"../components/*\"\n      ]\n    }\n  },\n  \"exclude\": [\n    \"test.ts\",\n    \"**/*.spec.ts\"\n  ],\n  \"angularCompilerOptions\": {\n    \"strictInjectionParameters\": true,\n    \"strictInputAccessModifiers\": true,\n    \"strictTemplates\": true\n  }\n}\n"
  },
  {
    "path": "scripts/site/generate-site.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { copySync, existsSync, mkdirSync, readdirSync, readFileSync, removeSync, statSync } from 'fs-extra';\nimport pascalCase from 'pascalcase';\n\nimport path from 'path';\n\nimport { ComponentDemo, ComponentDemoDoc, ComponentDemoPage, ComponentIndexDocMeta, I18n } from './types';\nimport { generateCodeBox } from './utils/generate-code-box';\nimport { generateDemo } from './utils/generate-demo';\nimport { generateDemoCodeFiles } from './utils/generate-demo-code-files';\nimport { generateDocs } from './utils/generate-docs';\nimport { generateRoutes } from './utils/generate-routes';\nimport { getMeta } from './utils/get-meta';\nimport { parseDocMd, parseDemoMd } from './utils/parse-doc-md';\n\n// create site folder\nconst showCasePath = path.resolve(__dirname, '../../site');\n\nfunction nameWithoutSuffixUtil(name: string): string {\n  return name.split('.')[0];\n}\n\n// handle components->${component}->page folder, parent component of demo page\nfunction getPageDemo(componentDirPath: string): ComponentDemoPage | undefined {\n  const pageDirPath = path.join(componentDirPath, 'page');\n  if (existsSync(pageDirPath)) {\n    const pageDir = readdirSync(pageDirPath);\n    let zhLocale = '';\n    let enLocale = '';\n    let raw = '';\n\n    pageDir.forEach(file => {\n      if (/.ts$/.test(file)) {\n        raw = String(readFileSync(path.join(pageDirPath, file)));\n      }\n      if (/^zh-CN.txt$/.test(file)) {\n        zhLocale = String(readFileSync(path.join(pageDirPath, file)));\n      }\n      if (/^en-US.txt$/.test(file)) {\n        enLocale = String(readFileSync(path.join(pageDirPath, file)));\n      }\n    });\n\n    return {\n      raw,\n      enCode: raw.replace(/locale;/g, enLocale),\n      zhCode: raw.replace(/locale;/g, zhLocale)\n    };\n  }\n  return undefined;\n}\n\nexport default function generate(target: string): void {\n  const isSyncSpecific = target && target !== 'init';\n  if (!target || target === 'init') {\n    removeSync(showCasePath);\n    copySync(path.resolve(__dirname, 'doc'), `${showCasePath}`);\n  } else {\n    removeSync(`${showCasePath}/app/${target}`);\n  }\n  const showCaseTargetPath = `${showCasePath}/app/`;\n  // read components folder\n  const rootPath = path.resolve(__dirname, '../../components');\n  const rootDir = readdirSync(rootPath);\n  const componentsDocMap: Record<string, I18n<ComponentIndexDocMeta>> = {};\n  const componentsMap: Record<string, Record<string, ComponentDemoDoc>> = {};\n\n  rootDir.forEach(componentName => {\n    if (isSyncSpecific) {\n      if (componentName !== target) {\n        return;\n      }\n    }\n    const componentDirPath = path.join(rootPath, componentName);\n    const skips = ['style', 'core', 'locale', 'cdk', 'i18n', 'version', 'experimental'];\n    if (skips.indexOf(componentName) !== -1) {\n      return;\n    }\n    if (statSync(componentDirPath).isDirectory()) {\n      // create site/doc/app->${component} folder\n      const showCaseComponentPath = path.join(showCaseTargetPath, componentName);\n      mkdirSync(showCaseComponentPath);\n\n      // handle components->${component}->demo folder\n      const demoDirPath = path.join(componentDirPath, 'demo');\n      const demoMap: Record<string, ComponentDemoDoc> = {};\n      const debugDemos = new Set();\n\n      if (existsSync(demoDirPath)) {\n        const demoDir = readdirSync(demoDirPath);\n        demoDir.forEach(demo => {\n          const nameKey = nameWithoutSuffixUtil(demo);\n          if (/.md$/.test(demo)) {\n            const demoMarkDownFile = readFileSync(path.join(demoDirPath, demo));\n            const demoMeta = parseDemoMd(demoMarkDownFile);\n\n            if (demoMeta.meta.debug && process.env.NODE_ENV !== 'development') {\n              debugDemos.add(nameKey);\n              return;\n            }\n\n            const name = `NzDemo${pascalCase(componentName)}${pascalCase(nameKey)}Component`;\n            demoMap[nameKey] = {\n              ...demoMeta,\n              key: nameKey,\n              name,\n              enCode: generateCodeBox(\n                componentName,\n                name,\n                nameKey,\n                demoMeta.meta.title['en-US'],\n                demoMeta.meta.version,\n                demoMeta.en,\n                demoMeta.meta.iframe\n              ),\n              zhCode: generateCodeBox(\n                componentName,\n                name,\n                nameKey,\n                demoMeta.meta.title['zh-CN'],\n                demoMeta.meta.version,\n                demoMeta.zh,\n                demoMeta.meta.iframe\n              ),\n              ts: readFileSync(path.join(demoDirPath, `${nameKey}.ts`)).toString()\n            };\n          }\n\n          if (/.ts$/.test(demo) && !debugDemos.has(nameKey)) {\n            // copy ts file to site->${component} folder\n            copySync(path.join(demoDirPath, demo), path.join(showCaseComponentPath, demo));\n          }\n        });\n      }\n\n      // handle components->${component}->doc folder\n      const result: ComponentDemo = {\n        name: componentName,\n        docZh: parseDocMd(\n          readFileSync(path.join(componentDirPath, 'doc/index.zh-CN.md')),\n          `components/${componentName}/doc/index.zh-CN.md`\n        ),\n        docEn: parseDocMd(\n          readFileSync(path.join(componentDirPath, 'doc/index.en-US.md')),\n          `components/${componentName}/doc/index.en-US.md`\n        ),\n        demoMap,\n        pageDemo: getPageDemo(componentDirPath)\n      };\n      componentsDocMap[componentName] = {\n        zh: result.docZh.meta,\n        en: result.docEn.meta\n      };\n      componentsMap[componentName] = demoMap;\n      generateDemo(showCaseComponentPath, result);\n      generateDemoCodeFiles(result, showCasePath);\n    }\n  });\n\n  if (!isSyncSpecific) {\n    // read docs folder\n    const docsPath = path.resolve(__dirname, '../../docs');\n    const docsDir = readdirSync(docsPath);\n    const docsMap: Record<string, I18n<Buffer>> = {};\n    const docsMeta: Record<string, I18n<ComponentIndexDocMeta>> = {};\n    docsDir.forEach(doc => {\n      const name = nameWithoutSuffixUtil(doc);\n      docsMap[name] = {\n        zh: readFileSync(path.join(docsPath, `${name}.zh-CN.md`)),\n        en: readFileSync(path.join(docsPath, `${name}.en-US.md`))\n      };\n      docsMeta[name] = {\n        zh: getMeta(docsMap[name].zh),\n        en: getMeta(docsMap[name].en)\n      };\n    });\n\n    generateDocs(showCaseTargetPath, docsMap);\n    generateRoutes(showCaseTargetPath, componentsDocMap, docsMeta);\n  }\n}\n"
  },
  {
    "path": "scripts/site/generate-theme.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { writeFile } from 'fs-extra';\nimport less from 'less';\nimport LessPluginCleanCSS from 'less-plugin-clean-css';\n\nimport path from 'path';\n\nimport { aliyunPaletteLess } from '../build/aliyun-vars';\nimport { compactPaletteLess } from '../build/compact-vars';\nimport { darkPaletteLess } from '../build/dark-vars';\n\nconst themePath = path.join(__dirname, '../../site/styles.less');\nconst colorPalettePath = path.join(__dirname, '../../components/style/color/colorPalette.less');\nconst themeContent = `\n@import '${themePath}';\n`;\n\nasync function generateTheme(vars: Record<string, string | number>, fileName: string): Promise<void> {\n  const data = await less.render(themeContent, {\n    plugins: [new LessPluginCleanCSS({ advanced: true })],\n    modifyVars: {\n      hack: `true;@import '${colorPalettePath}';`,\n      ...vars,\n      '@site-markdown-code-bg': '@input-bg',\n      '@site-text-color': '@heading-color'\n    }\n  });\n\n  return writeFile(path.join(__dirname, `../../site/assets/${fileName}`), data.css);\n}\n\nexport default function generateAllTheme(): Promise<void[]> {\n  return Promise.all([\n    generateTheme(compactPaletteLess, 'compact.css'),\n    generateTheme(darkPaletteLess, 'dark.css'),\n    generateTheme(aliyunPaletteLess, 'aliyun.css')\n  ]);\n}\n"
  },
  {
    "path": "scripts/site/markdown/index.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Marked } from 'marked';\nimport { markedHighlight } from 'marked-highlight';\n\nimport * as prism from './prism';\nimport { getRenderer } from './renderer';\n\nconst highlight = markedHighlight({\n  langPrefix: 'language-',\n  highlight(code, lang) {\n    const language = prism.languages[lang] || prism.languages.autoit;\n    return prism.highlight(code, language, lang);\n  }\n});\n\nconst marked = new Marked(highlight);\n\nmarked.use({ renderer: getRenderer(marked) });\n\nexport default marked;\n"
  },
  {
    "path": "scripts/site/markdown/prism.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { highlight, languages } from 'prismjs';\n\nconst loadLanguages = require('prismjs/components/');\n\nloadLanguages(['bash', 'diff', 'markup-templating', 'json', 'less', 'typescript']);\n\nconst insideString = {\n  variable: [\n    // Arithmetic Environment\n    {\n      pattern: /\\$?\\(\\([\\w\\W]+?\\)\\)/,\n      inside: {\n        // If there is a $ sign at the beginning highlight $(( and )) as variable\n        variable: [\n          {\n            pattern: /(^\\$\\(\\([\\w\\W]+)\\)\\)/,\n            lookbehind: true\n          },\n          {\n            pattern: /^\\$\\(\\(/,\n            function: languages.bash['function'],\n            keyword: languages.bash.keyword,\n            boolean: languages.bash.boolean,\n            operator: languages.bash.operator,\n            punctuation: languages.bash.punctuation\n          }\n        ],\n        number: /\\b-?(?:0x[\\dA-Fa-f]+|\\d*\\.?\\d+(?:[Ee]-?\\d+)?)\\b/,\n        // Operators according to https://www.gnu.org/software/bash/manual/bashref.html#Shell-Arithmetic\n        operator: /--?|-=|\\+\\+?|\\+=|!=?|~|\\*\\*?|\\*=|\\/=?|%=?|<<=?|>>=?|<=?|>=?|==?|&&?|&=|\\^=?|\\|\\|?|\\|=|\\?|:/,\n        // If there is no $ sign at the beginning highlight (( and )) as punctuation\n        punctuation: /\\(\\(?|\\)\\)?|,|;/\n      }\n    },\n    // Command Substitution\n    {\n      pattern: /\\$\\([^)]+\\)|`[^`]+`/,\n      inside: {\n        variable: /^\\$\\(|^`|\\)$|`$/\n      }\n    },\n    /\\$(?:[a-z0-9_#?*!@]+|\\{[^}]+\\})/i\n  ]\n};\n\nlanguages.bash = {\n  shebang: {\n    pattern: /^#!\\s*\\/bin\\/bash|^#!\\s*\\/bin\\/sh/,\n    alias: 'important'\n  },\n  comment: {\n    pattern: /(^|[^\"{\\\\])#.*/,\n    lookbehind: true\n  },\n  string: [\n    //Support for Here-Documents https://en.wikipedia.org/wiki/Here_document\n    {\n      pattern: /((?:^|[^<])<<\\s*)(?:\"|')?(\\w+?)(?:\"|')?\\s*\\r?\\n(?:[\\s\\S])*?\\r?\\n\\2/g,\n      lookbehind: true,\n      greedy: true,\n      inside: insideString\n    },\n    {\n      pattern: /([\"'])(?:\\\\\\\\|\\\\?[^\\\\])*?\\1/g,\n      greedy: true,\n      inside: insideString\n    }\n  ],\n  variable: insideString.variable,\n  // Originally based on http://ss64.com/bash/\n  function: {\n    pattern:\n      /(^|\\s|;|\\||&)(?:alias|ng-zorro-antd|@angular\\/cli|apropos|apt-get|aptitude|aspell|awk|basename|bash|bc|bg|builtin|bzip2|cal|cat|cd|cfdisk|chgrp|chmod|chown|chroot|chkconfig|cksum|clear|cmp|comm|command|cp|cron|crontab|csplit|cut|date|dc|dd|ddrescue|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|du|egrep|eject|enable|env|ethtool|eval|exec|expand|expect|export|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|getopts|git|grep|groupadd|groupdel|groupmod|groups|gzip|hash|head|help|hg|history|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|jobs|join|kill|killall|less|link|ln|locate|logname|logout|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|make|man|mkdir|mkfifo|mkisofs|mknod|more|most|mount|mtools|mtr|mv|mmv|nano|netstat|nice|nl|nohup|notify-send|npm|ng|nslookup|open|op|passwd|paste|pathchk|ping|pkill|popd|pr|printcap|printenv|printf|ps|pushd|pv|pwd|quota|quotacheck|quotactl|ram|rar|rcp|read|readarray|readonly|reboot|rename|renice|remsync|rev|rm|rmdir|rsync|screen|scp|sdiff|sed|seq|service|sftp|shift|shopt|shutdown|sleep|slocate|sort|source|split|ssh|stat|strace|su|sudo|sum|suspend|sync|tail|tar|tee|test|time|timeout|times|touch|top|traceroute|trap|tr|tsort|tty|type|ulimit|umask|umount|unalias|uname|unexpand|uniq|units|unrar|unshar|uptime|useradd|userdel|usermod|users|uuencode|uudecode|v|vdir|vi|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yes|zip)(?=$|\\s|;|\\||&)/,\n    lookbehind: true\n  },\n  keyword: {\n    pattern:\n      /(^|\\s|;|\\||&)(?:let|:|\\.|if|then|else|elif|fi|for|break|continue|while|in|case|function|select|do|done|until|echo|exit|return|set|declare)(?=$|\\s|;|\\||&)/,\n    lookbehind: true\n  },\n  boolean: {\n    pattern: /(^|\\s|;|\\||&)(?:true|false)(?=$|\\s|;|\\||&)/,\n    lookbehind: true\n  },\n  operator: /&&?|\\|\\|?|==?|!=?|<<<?|>>|<=?|>=?|=~/,\n  punctuation: /\\$?\\(\\(?|\\)\\)?|\\.\\.|[{}[\\];]/\n};\n\n/**\n * Extend Angular\n */\nlanguages.angular = languages.extend('typescript', {});\n\nlanguages.insertBefore('angular', 'string', {\n  'template-string': {\n    pattern: /template[\\s]*:[\\s]*`(?:\\\\[\\s\\S]|[^\\\\`])*`/,\n    greedy: true,\n    inside: {\n      html: {\n        pattern: /`(?:\\\\[\\s\\S]|[^\\\\`])*`/,\n        inside: languages.html\n      }\n    }\n  },\n  'styles-string': {\n    pattern: /styles[\\s]*:[\\s]*(\\[)?[\\s]*`(?:\\\\[\\s\\S]|[^\\\\`])*`[\\s]*(\\])?/,\n    greedy: true,\n    inside: {\n      css: {\n        pattern: /`(?:\\\\[\\s\\S]|[^\\\\`])*`/,\n        inside: languages.css\n      }\n    }\n  }\n});\n\nexport { highlight, languages };\n"
  },
  {
    "path": "scripts/site/markdown/renderer.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Marked, RendererObject } from 'marked';\nimport { parseFragment, serialize } from 'parse5';\nimport slugify from 'slugify';\n\nconst DIRECTIVE_REGEX = /^\\[[a-zA-Z-]+]/;\nconst SERVICE_REGEX = /^Nz[a-zA-Z]+Service$/;\n\nfunction createLabel(label: 'component' | 'directive' | 'service'): string {\n  return `<label class=\"api-type-label ${label}\">${label}</label>`;\n}\n\nexport function getRenderer(marked: Marked): RendererObject {\n  const originLinkHandler = marked.defaults.renderer!.link;\n  return {\n    link(params) {\n      const { href } = params;\n      const str = originLinkHandler.call(this, params);\n      const a = parseFragment(str, {});\n      /**\n       * @description If the link is an anchor tag and the href is not an absolute path, open it in a new window\n       */\n      if (a && a.childNodes[0] && a.childNodes[0].nodeName === 'a') {\n        if (!/^(?!www\\.|(?:http|ftp)s?:\\/\\/|[A-Za-z]:\\\\|\\/\\/).*/.test(href)) {\n          // Open absolute path in new window\n          a.childNodes[0].attrs.push({\n            name: 'target',\n            value: '_blank'\n          });\n          a.childNodes[0].attrs.push({\n            name: 'rel',\n            value: 'noopener'\n          });\n        }\n        return serialize(a);\n      }\n\n      return str;\n    },\n    heading({ text, depth }) {\n      const title = marked.parseInline(text, { async: false });\n      const id = slugify(title, {\n        remove: /[*+~.()'\"!:@\\\\[\\]]/g,\n        replacement: '_',\n        lower: true\n      });\n      const isMarkedLabel = depth === 3 && title.indexOf('nz-') === 0;\n      const isDirective = DIRECTIVE_REGEX.test(title);\n      const isComponent = isMarkedLabel && !isDirective;\n      const isService = SERVICE_REGEX.test(title);\n\n      let head = `<h${depth} id=\"${id}\"><span>${title}</span>`;\n      const anchor = `<a onclick=\"window.location.hash = '${id}'\" class=\"anchor\">#</a></h${depth}>`;\n\n      if (isComponent) {\n        head += createLabel('component');\n      } else if (isDirective) {\n        head += createLabel('directive');\n      } else if (isService) {\n        head += createLabel('service');\n      }\n\n      return head + anchor;\n    }\n  };\n}\n"
  },
  {
    "path": "scripts/site/replace-scope-prefix.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { readFileSync, writeFileSync } from 'fs-extra';\n\nimport path from 'path';\n\nconst changelogPath = path.resolve(__dirname, `../../CHANGELOG.md`);\n\nfunction replace(path: string): void {\n  const content = readFileSync(path, 'utf8');\n  const replaced = content.replace(/\\*\\*\\w+:(?!\\*\\*)/g, '**').replace(/\\*\\s\\*\\*\\s/g, '* **');\n  writeFileSync(path, replaced);\n}\n\nreplace(changelogPath);\n"
  },
  {
    "path": "scripts/site/template/code-box.template.html",
    "content": "<nz-code-box\n  nzTitle=\"{{title}}\"\n  nzVersion=\"{{version}}\"\n  nzId=\"components-{{component}}-demo-{{key}}\"\n  nzSelector=\"nz-demo-{{component}}-{{key}}\"\n  nzLink=\"components-{{component}}-demo-{{key}}\"\n  nzGenerateCommand=\"{{nzGenerateCommand}}\"\n  nzComponentName=\"{{componentName}}\"\n  [nzIframe]=\"{{iframe}}\"\n  nzIframeSource=\"{{iframeSource}}\"\n  [nzIframeHeight]=\"{{iframeHeight}}\"\n  nzHref=\"https://github.com/NG-ZORRO/ng-zorro-antd/edit/master/components/{{component}}/demo/{{key}}.md\"\n>\n\t<nz-demo-{{component}}-{{key}} demo></nz-demo-{{component}}-{{key}}>\n\t<div intro ngNonBindable>{{doc}}</div>\n</nz-code-box>"
  },
  {
    "path": "scripts/site/template/demo-component.template.ts",
    "content": "import { Component, QueryList, ViewChildren } from '@angular/core';\nimport { NzCodeBoxComponent } from '../codebox/codebox.component';\nimport { ShareModule } from '../share/share.module';\n\n{{imports}}\n\n@Component({\n  selector     : 'nz-demo-{{component}}',\n  imports      : [ShareModule, {{declarations}}],\n  templateUrl  : './{{language}}.html'\n})\nexport default class {{componentName}} {\n  expanded = false;\n  @ViewChildren(NzCodeBoxComponent) codeBoxes!: QueryList<NzCodeBoxComponent>;\n\n  goLink(link: string): void {\n    if (window) {\n      window.location.hash = link;\n    }\n  }\n\n  expandAllCode(): void {\n    this.expanded = !this.expanded;\n    this.codeBoxes.forEach(code => code.expandCode(this.expanded));\n  }\n}\n"
  },
  {
    "path": "scripts/site/template/demo-routes.template.ts",
    "content": "import { Routes } from '@angular/router';\n\nconst routes: Routes = [\n  { path: 'en', loadComponent: () => import('./en.component') },\n  { path: 'zh', loadComponent: () => import('./zh.component') }\n];\n\nexport default routes;\n"
  },
  {
    "path": "scripts/site/template/doc-component.template.ts",
    "content": "import { Component } from '@angular/core';\nimport { ShareModule } from '../share/share.module';\n\n@Component({\n  selector     : 'nz-doc-{{component}}-{{language}}',\n  imports      : [ShareModule],\n  templateUrl  : './{{component}}-{{language}}.html'\n})\nexport default class NzDoc{{componentName}}Component {\n  goLink(link: string): void {\n    if (window) {\n      window.location.hash = link;\n    }\n  }\n}\n"
  },
  {
    "path": "scripts/site/template/doc-routes.template.ts",
    "content": "import { Routes } from '@angular/router';\n\nconst routes: Routes = [\n{{routes}}\n];\n\nexport default routes;\n"
  },
  {
    "path": "scripts/site/template/example-split.template.html",
    "content": "<div nz-row [nzGutter]=\"16\">\n\t<div nz-col [nzXl]=\"12\" [nzSpan]=\"24\">\n\t\t{{first}}\n\t</div>\n\t<div nz-col [nzXl]=\"12\" [nzSpan]=\"24\">\n\t\t{{second}}\n\t</div>\n</div>\n"
  },
  {
    "path": "scripts/site/template/example-union.template.html",
    "content": "<div nz-row [nzGutter]=\"8\">\n\t<div nz-col [nzSpan]=\"24\">\n\t\t{{content}}\n\t</div>\n</div>"
  },
  {
    "path": "scripts/site/template/router.template.ts",
    "content": "import { RouterList } from './types';\nimport { Routes } from '@angular/router';\n\nexport const ROUTER_LIST: RouterList = {\n  intro: {{intro}},\n  components: {{components}}\n}\n\nexport const DEMO_ROUTES: Routes = [\n{{routes}}\n];\n"
  },
  {
    "path": "scripts/site/template/title.template.html",
    "content": "<h1>\n  <nz-space>\n    <span *nzSpaceItem>{{title}}</span>\n    <span *nzSpaceItem>{{subtitle}}</span>\n\t</nz-space>\n</h1>\n"
  },
  {
    "path": "scripts/site/types.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nexport type Language = 'zh' | 'en';\nexport interface I18n<T> {\n  zh: T;\n  en: T;\n}\n\nexport interface IframeMeta {\n  /**\n   * iframe height\n   */\n  height: number;\n  /**\n   * iframe url\n   */\n  source?: string;\n}\n\nexport interface I18nTitle {\n  /**\n   * title in Chinese\n   */\n  'zh-CN': string;\n  /**\n   * title in English\n   */\n  'en-US': string;\n}\n\nexport interface ComponentIndexDocMeta {\n  /**\n   * category of the component\n   */\n  category: string;\n  /**\n   * type of the component\n   */\n  type: string;\n  /**\n   * title of the component\n   */\n  title: string;\n  /**\n   * cover image url\n   */\n  cover: string;\n  /**\n   * subtitle of the component\n   */\n  subtitle?: string;\n  /**\n   * description of the component\n   */\n  description?: string;\n  /**\n   * raw description content\n   */\n  rawDescription?: string;\n  /**\n   * order of the component\n   */\n  order?: number;\n  /**\n   * Columns of the showcases, defauls to 2\n   */\n  cols?: 1 | 2;\n  /**\n   * whether the documentation is hidden\n   */\n  hidden?: boolean;\n  /**\n   * whether the component is experimental\n   */\n  experimental?: boolean;\n  /**\n   * whether the demo page exists\n   */\n  hasDemoPage?: boolean;\n  /**\n   * tag of the component\n   */\n  tag?: string;\n  /**\n   * whether to generate toc\n   */\n  toc?: ComponentIndexDocMetaToc;\n  /**\n   * content of the component\n   */\n  __content?: string;\n}\n\nexport type ComponentIndexDocMetaToc = boolean | ComponentIndexDocMetaTocConfig;\n\nexport interface ComponentIndexDocMetaTocConfig {\n  /**\n   * maximum depth of the toc\n   * @default 3\n   */\n  depth?: number;\n}\n\nexport type ComponentIndexDocMap = Record<string, I18n<ComponentIndexDocMeta>>;\n\nexport interface ComponentIndexDoc {\n  /**\n   * path of the component\n   */\n  path: string;\n  /**\n   * when to use the component\n   */\n  whenToUse: string;\n  /**\n   * metadata of the component\n   */\n  meta: ComponentIndexDocMeta;\n  /**\n   * API documentation\n   */\n  api: string;\n}\n\nexport interface ComponentDemoDocMeta {\n  /**\n   * display order of the demo\n   */\n  order: number;\n  /**\n   * title of the demo\n   */\n  title: I18nTitle;\n  /**\n   * API support version\n   */\n  version: string;\n  /**\n   * iframe configuration\n   */\n  iframe?: IframeMeta;\n  /**\n   * whether the demo is debugging\n   */\n  debug?: boolean;\n  /**\n   * content of the demo\n   */\n  __content?: string;\n}\n\nexport interface ComponentDemoDoc {\n  key: string;\n  /**\n   * metadata of the demo\n   */\n  meta: ComponentDemoDocMeta;\n  /**\n   * name of the demo component\n   */\n  name: string;\n  /**\n   * content in Chinese\n   */\n  zh: string;\n  /**\n   * content in English\n   */\n  en: string;\n  /**\n   * code content in Chinese\n   */\n  zhCode: string;\n  /**\n   * code content in English\n   */\n  enCode: string;\n  /**\n   * code content in typescript\n   */\n  ts: string;\n}\n\nexport interface ComponentDemoPage {\n  /**\n   * raw content of demo page\n   */\n  raw: string;\n  /**\n   * chinese code content\n   */\n  zhCode: string;\n  /**\n   * english code content\n   */\n  enCode: string;\n}\n\nexport interface ComponentDemo {\n  /**\n   * demo name\n   */\n  name: string;\n  /**\n   * chinese doc content metadata\n   */\n  docZh: ComponentIndexDoc;\n  /**\n   * english doc content\n   */\n  docEn: ComponentIndexDoc;\n  /**\n   * demo content\n   */\n  demoMap: Record<string, ComponentDemoDoc>;\n  /**\n   * demo page content\n   */\n  pageDemo?: ComponentDemoPage;\n  /**\n   * standalone mode\n   */\n  standalone?: boolean;\n}\n\nexport interface IntroRouter {\n  path: string;\n  label: string;\n  language: string;\n  order: number;\n  hidden: boolean;\n  description: string;\n  tag?: string;\n  experimental?: boolean;\n}\n\nexport interface ComponentChildRouter {\n  path: string;\n  label: string;\n  description: string;\n  zh: string;\n  cover?: string;\n  /**\n   * The tag of version since the component is available.\n   */\n  tag?: string;\n  /**\n   * Whether the component is hidden.\n   */\n  hidden?: boolean;\n  /**\n   * Whether the component is experimental.\n   */\n  experimental?: boolean;\n}\n\nexport interface ComponentRouter {\n  name: string;\n  language: string;\n  children: ComponentChildRouter[];\n  experimentalChildren: ComponentChildRouter[];\n}\n\nexport interface RouterList {\n  intro: IntroRouter[];\n  components: ComponentRouter[];\n}\n"
  },
  {
    "path": "scripts/site/utils/angular-non-bindable.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\n/**\n * @description Replace `{`, `}`, `@` to html entities\n */\nexport function angularNonBindAble(content: string): string {\n  return content.replace(/{/g, '&#123;').replace(/}/g, '&#125;').replace(/@/g, '&#64;');\n}\n"
  },
  {
    "path": "scripts/site/utils/generate-code-box.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { readFileSync } from 'fs-extra';\n\nimport path from 'path';\n\nimport { IframeMeta } from '../types';\n\nconst template = String(readFileSync(path.resolve(__dirname, '../template/code-box.template.html')));\n\nexport function generateCodeBox(\n  component: string,\n  demoName: string,\n  key: string,\n  title: string,\n  version: string,\n  doc: string,\n  iframe?: IframeMeta\n): string {\n  let output = template;\n  output = output.replace(/{{title}}/g, title);\n  output = output.replace(/{{version}}/g, version ?? '');\n  output = output.replace(/{{component}}/g, component);\n  output = output.replace(/{{componentName}}/g, demoName);\n  output = output.replace(/{{key}}/g, key);\n  output = output.replace(/{{doc}}/g, doc);\n  output = output.replace(/{{iframe}}/g, iframe ? 'true' : 'false');\n  output = output.replace(/{{iframeSource}}/g, iframe?.source ?? '');\n  output = output.replace(/{{iframeHeight}}/g, String(iframe?.height ?? null));\n  output = output.replace(/{{nzGenerateCommand}}/g, `ng g ng-zorro-antd:${component}-${key} <name>`);\n  return output;\n}\n"
  },
  {
    "path": "scripts/site/utils/generate-demo-code-files.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { ensureFileSync, writeJSONSync } from 'fs-extra';\n\nimport path from 'path';\n\nimport { highlight, languages } from '../markdown/prism';\nimport { ComponentDemo } from '../types';\n\nconst lang = 'angular';\n\nexport function generateDemoCodeFiles(content: ComponentDemo, sitePath: string): void {\n  const demoMap = content.demoMap;\n  for (const key in demoMap) {\n    const rawCode = demoMap[key].ts;\n    const highlightCode = highlight(rawCode, languages[lang], lang);\n    const targetPath = path.join(sitePath, 'assets/codes', `${content.name}-demo-${key}.json`);\n\n    ensureFileSync(targetPath);\n    writeJSONSync(targetPath, {\n      highlightCode,\n      rawCode\n    });\n  }\n}\n"
  },
  {
    "path": "scripts/site/utils/generate-demo.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { readFileSync, writeFileSync } from 'fs-extra';\nimport pascalCase from 'pascalcase';\n\nimport path from 'path';\n\nimport { ComponentDemo, ComponentDemoDoc, ComponentIndexDocMeta, I18n, I18nTitle } from '../types';\nimport { generateTitle } from './generate-title';\n\nconst demoRoutesTemplate = String(readFileSync(path.resolve(__dirname, '../template/demo-routes.template.ts')));\n\n/**\n * Generate demos for the component\n * @param showCaseComponentPath The path of the component\n * @param result The result of the component\n */\nexport function generateDemo(showCaseComponentPath: string, result: ComponentDemo): void {\n  if (result.pageDemo) {\n    const pageDemoComponent = generatePageDemoComponent(result);\n    writeFileSync(path.join(showCaseComponentPath, `zh.page.component.ts`), pageDemoComponent.zh);\n    writeFileSync(path.join(showCaseComponentPath, `en.page.component.ts`), pageDemoComponent.en);\n  }\n  const demoTemplate = generateTemplate(result);\n  writeFileSync(path.join(showCaseComponentPath, `zh.html`), demoTemplate.zh);\n  writeFileSync(path.join(showCaseComponentPath, `en.html`), demoTemplate.en);\n  const demoComponent = generateDemoComponent(result);\n  writeFileSync(path.join(showCaseComponentPath, `zh.component.ts`), demoComponent.zh);\n  writeFileSync(path.join(showCaseComponentPath, `en.component.ts`), demoComponent.en);\n  writeFileSync(path.join(showCaseComponentPath, `routes.ts`), demoRoutesTemplate);\n}\n\nfunction generateDemoImports(content: ComponentDemo): { imports: string; declarations: string[] } {\n  const component = content.name;\n  const demoMap = content.demoMap;\n  let imports = '';\n  const declarations: string[] = [];\n  for (const key in demoMap) {\n    const declareComponents = [`NzDemo${pascalCase(component)}${pascalCase(key)}Component`];\n    const entries = retrieveEntryComponents(demoMap[key].ts);\n    declareComponents.push(...entries);\n    imports += `import { ${declareComponents.join(', ')} } from './${key}';\\n`;\n    declarations.push(...declareComponents);\n  }\n  return { imports, declarations };\n}\n\nfunction generateComponentName(component: string, language: string): string {\n  return `NzDemo${pascalCase(component)}${pascalCase(language)}Component`;\n}\n\nfunction generatePageDemoComponent(content: ComponentDemo): I18n<string> {\n  const component = content.name;\n  let zhOutput = content.pageDemo!.zhCode;\n  let enOutput = content.pageDemo!.enCode;\n  zhOutput = zhOutput\n    .replace(`NzPageDemo${pascalCase(component)}Component`, `NzPageDemo${pascalCase(component)}ZhComponent`)\n    .replace(`nz-page-demo-${component}`, `nz-page-demo-${component}-zh`);\n  enOutput = enOutput\n    .replace(`NzPageDemo${pascalCase(component)}Component`, `NzPageDemo${pascalCase(component)}EnComponent`)\n    .replace(`nz-page-demo-${component}`, `nz-page-demo-${component}-en`);\n  return {\n    en: enOutput,\n    zh: zhOutput\n  };\n}\n\nfunction generateDemoComponent(content: ComponentDemo): I18n<string> {\n  const demoComponentTemplate = String(readFileSync(path.resolve(__dirname, `../template/demo-component.template.ts`)));\n  const component = content.name;\n\n  let output = demoComponentTemplate.replace(/{{component}}/g, component);\n  let zhOutput = output;\n  let enOutput = output;\n\n  const { imports, declarations } = generateDemoImports(content);\n\n  if (content.pageDemo) {\n    // zh\n    const zhImports = `${imports}import { NzPageDemo${pascalCase(component)}ZhComponent } from './zh.page.component';\\n`;\n    const zhDeclarations = [...declarations, `NzPageDemo${pascalCase(component)}ZhComponent`];\n    zhOutput = zhOutput.replace(/{{imports}}/g, zhImports);\n    zhOutput = zhOutput.replace(/{{declarations}}/g, zhDeclarations.join(', '));\n    // en\n    const enImports = `${imports}import { NzPageDemo${pascalCase(component)}EnComponent } from './en.page.component';\\n`;\n    const enDeclarations = [...declarations, `NzPageDemo${pascalCase(component)}EnComponent`];\n    enOutput = enOutput.replace(/{{imports}}/g, enImports);\n    enOutput = enOutput.replace(/{{declarations}}/g, enDeclarations.join(', '));\n  } else {\n    output = output.replace(/{{imports}}/g, imports);\n    output = output.replace(/{{declarations}}/g, declarations.join(', '));\n    zhOutput = output;\n    enOutput = output;\n  }\n\n  enOutput = enOutput.replace(/{{componentName}}/g, generateComponentName(component, 'en'));\n  enOutput = enOutput.replace(/{{language}}/g, 'en');\n  zhOutput = zhOutput.replace(/{{componentName}}/g, generateComponentName(component, 'zh'));\n  zhOutput = zhOutput.replace(/{{language}}/g, 'zh');\n\n  return {\n    en: enOutput,\n    zh: zhOutput\n  };\n}\n\nfunction generateTemplate(result: ComponentDemo): I18n<string> {\n  const innerMap = generateExample(result);\n  const name = result.name;\n  const hasPageDemo = !!result.pageDemo;\n  return {\n    zh: wrapperAll(\n      generateToc('zh-CN', result.name, result.demoMap),\n      wrapperHeader(\n        generateTitle(result.docZh.meta),\n        result.docZh.whenToUse,\n        'zh',\n        innerMap.zh,\n        hasPageDemo,\n        name,\n        result.docZh.meta\n      ),\n      wrapperAPI(result.docZh.api)\n    ),\n    en: wrapperAll(\n      generateToc('en-US', result.name, result.demoMap),\n      wrapperHeader(\n        generateTitle(result.docEn.meta),\n        result.docEn.whenToUse,\n        'en',\n        innerMap.en,\n        hasPageDemo,\n        name,\n        result.docEn.meta\n      ),\n      wrapperAPI(result.docEn.api)\n    )\n  };\n}\n\nfunction wrapperAPI(content: string): string {\n  return `<section class=\"markdown api-container\" ngNonBindable>${content}</section>`;\n}\n\nfunction wrapperHeader(\n  title: string,\n  whenToUse: string,\n  language: string,\n  example: string,\n  hasPageDemo: boolean,\n  name: string,\n  metadata: ComponentIndexDocMeta\n): string {\n  const isZh = language === 'zh';\n  const meta = `<component-meta name=\"${name}\" description=\"${metadata.rawDescription}\" language=\"${language}\"></component-meta>`;\n  let experimental = '';\n\n  if (metadata.experimental) {\n    if (isZh) {\n      experimental = `\n<blockquote style=\"border-color: #faad14\">\n<p>NG-ZORRO 实验性功能是指已发布但不稳定或者还未准备好用于生产环境的功能。</p>\n<p>开发者或用户可以选择在正式发布前使用这些功能，但是每次发布版本时都可能存在 <strong>breaking changes</strong>。</p>\n</blockquote>`;\n    } else {\n      experimental = `\n<blockquote style=\"border-color: #faad14\">\n<p>NG-ZORRO experiments are features that are released but not yet considered stable or production ready</p>\n<p>Developers and users can opt in into these features before they are fully released. But <strong>breaking changes</strong> may occur with any release.</p>\n</blockquote>`;\n    }\n  }\n\n  const pageDemo = hasPageDemo\n    ? `<section class=\"page-demo\"><nz-page-demo-${name}-${language}></nz-page-demo-${name}-${language}></section>`\n    : '';\n\n  if (example) {\n    return `<section class=\"markdown\">\n  ${title}\n  ${meta}\n  ${experimental}\n  <section class=\"markdown\" ngNonBindable>\n    ${whenToUse}\n  </section>\n  ${pageDemo}\n  <h2 id=\"${isZh ? '代码演示' : 'examples'}\">\n    <span>${isZh ? '代码演示' : 'Examples'}</span>\n    <nz-icon nzType=\"appstore\" class=\"code-box-expand-trigger\" nz-tooltip nzTooltipTitle=\"${\n      isZh ? '展开全部代码' : 'Expand All Code'\n    }\" (click)=\"expandAllCode()\" />\n    <a onclick=\"window.location.hash = '${isZh ? '代码演示' : 'examples'}'\" class=\"anchor\">#</a>\n  </h2>\n</section>\n${example}`;\n  } else {\n    return `<section class=\"markdown\">\n  ${title}\n  ${meta}\n  <section class=\"markdown\">\n    ${whenToUse}\n  </section>\n</section>`;\n  }\n}\n\nfunction wrapperAll(toc: string, header: string, content: string): string {\n  return `<article>${toc}${header}${content}</article>`;\n}\n\nfunction generateToc(language: keyof I18nTitle, name: string, demoMap: Record<string, ComponentDemoDoc>): string {\n  const links = [\n    `<nz-link class=\"toc-indent-1\" nzHref=\"#${language === 'zh-CN' ? '何时使用' : 'when_to_use'}\" nzTitle=\"${language === 'zh-CN' ? '何时使用' : 'When To Use'}\"></nz-link>`,\n    `<nz-link class=\"toc-indent-1\" nzHref=\"#${language === 'zh-CN' ? '代码演示' : 'examples'}\" nzTitle=\"${language === 'zh-CN' ? '代码演示' : 'Examples'}\"></nz-link>`,\n    ...Object.values(demoMap)\n      .sort((pre, next) => pre.meta.order - next.meta.order)\n      .map(\n        demo =>\n          `<nz-link class=\"toc-indent-2\" nzHref=\"#components-${name}-demo-${demo.key}\" nzTitle=\"${demo.meta.title[language]}\"></nz-link>`\n      ),\n    `<nz-link class=\"toc-indent-1\" nzHref=\"#api\" nzTitle=\"API\"></nz-link>`\n  ].join('\\n');\n  return `\n<nz-affix class=\"toc-affix\" [nzOffsetTop]=\"16\">\n  <nz-anchor [nzAffix]=\"false\" nzShowInkInFixed (nzClick)=\"goLink($event)\">\n    ${links}\n  </nz-anchor>\n</nz-affix>`;\n}\n\nfunction generateExample(result: ComponentDemo): I18n<string> {\n  const demoMap = result.demoMap;\n  const isZhUnion = result.docZh.meta.cols === 1;\n  const isEnUnion = result.docEn.meta.cols === 1;\n  const templateSplit = String(readFileSync(path.resolve(__dirname, '../template/example-split.template.html')));\n  const templateUnion = String(readFileSync(path.resolve(__dirname, '../template/example-union.template.html')));\n  const demoList = Object.values(demoMap);\n  demoList.sort((pre, next) => pre.meta.order - next.meta.order);\n  let firstZhPart = '';\n  let secondZhPart = '';\n  let firstEnPart = '';\n  let secondEnPart = '';\n  let enPart = '';\n  let zhPart = '';\n  demoList.forEach((item, index) => {\n    enPart += item.enCode;\n    zhPart += item.zhCode;\n    if (index % 2 === 0) {\n      firstZhPart += item.zhCode;\n      firstEnPart += item.enCode;\n    } else {\n      secondZhPart += item.zhCode;\n      secondEnPart += item.enCode;\n    }\n  });\n  return {\n    zh: isZhUnion\n      ? templateUnion.replace(/{{content}}/g, zhPart)\n      : templateSplit.replace(/{{first}}/g, firstZhPart).replace(/{{second}}/g, secondZhPart),\n    en: isEnUnion\n      ? templateUnion.replace(/{{content}}/g, enPart)\n      : templateSplit.replace(/{{first}}/g, firstEnPart).replace(/{{second}}/g, secondEnPart)\n  };\n}\n\nfunction retrieveEntryComponents(plainCode: string): string[] {\n  const matches = `${plainCode}`.match(/^\\/\\*\\s*?declarations:\\s*([^\\n]+?)\\*\\//) || [];\n  if (matches[1]) {\n    return matches[1]\n      .split(',')\n      .map(className => className.trim())\n      .filter((value, index, self) => value && self.indexOf(value) === index);\n  }\n  return [];\n}\n"
  },
  {
    "path": "scripts/site/utils/generate-docs.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { mkdirSync, readFileSync, writeFileSync } from 'fs-extra';\nimport pascalCase from 'pascalcase';\nimport { remark } from 'remark';\n\nimport path from 'path';\n\nimport md from '../markdown';\nimport { ComponentIndexDocMetaTocConfig, I18n, Language } from '../types';\nimport { angularNonBindAble } from './angular-non-bindable';\nimport { generateTitle } from './generate-title';\nimport { getMeta } from './get-meta';\n\nconst componentTemplate = String(readFileSync(path.resolve(__dirname, '../template/doc-component.template.ts')));\nconst routesTemplate = String(readFileSync(path.resolve(__dirname, '../template/doc-routes.template.ts')));\n\n/**\n * Generate docs in `/docs` folder\n */\nexport function generateDocs(rootPath: string, docsMap: Record<string, I18n<Buffer>>): void {\n  const docsPath = `${rootPath}docs`;\n  mkdirSync(docsPath);\n  for (const name in docsMap) {\n    generateDoc(docsMap[name].zh, docsPath, name, 'zh');\n    generateDoc(docsMap[name].en, docsPath, name, 'en');\n  }\n  generateModule(docsPath, docsMap);\n}\n\nfunction generateDoc(file: Buffer, docsPath: string, name: string, language: Language): void {\n  const meta = getMeta(file);\n  const raw = meta.__content ?? '';\n  delete meta.__content;\n  const content = md.parse(raw, { async: false });\n  const filename = `${name}-${language}`;\n  const toc = meta.toc ?? true;\n\n  // template.html\n  writeFileSync(\n    path.join(docsPath, `${filename}.html`),\n    wrapperDocs(\n      toc ? generateToc(raw, typeof toc === 'boolean' ? {} : toc) : '',\n      generateTitle(meta),\n      angularNonBindAble(content)\n    )\n  );\n  // component.ts\n  const component = componentTemplate\n    .replace(/{{component}}/g, name)\n    .replace(/{{language}}/g, language)\n    .replace(/{{componentName}}/g, pascalCase(filename));\n  writeFileSync(path.join(docsPath, `${filename}.ts`), component);\n}\n\nfunction wrapperDocs(toc: string, title: string, content: string): string {\n  return `<article class=\"markdown\">\n  ${title}${toc}\n  <section class=\"markdown\" ngNonBindable>${content}</section>\n</article>`;\n}\n\nfunction generateToc(raw: string, config: ComponentIndexDocMetaTocConfig): string {\n  const ast = remark.parse(raw);\n  const { depth = 3 } = config;\n  const linkArray: string[] = [];\n  ast.children.forEach(child => {\n    if (child.type === 'heading' && child.depth > 1 && child.depth <= depth) {\n      const firstChild = child.children[0];\n      if (firstChild.type === 'text') {\n        const text = firstChild.value;\n        const lowerText = text\n          .toLowerCase()\n          .replace(/ /g, '_') // replace space with underscore\n          .replace(/[?.]/g, ''); // remove special chars: `?` `.`\n        const indent = child.depth - 1;\n        linkArray.push(`<nz-link nzHref=\"#${lowerText}\" class=\"toc-indent-${indent}\" nzTitle=\"${text}\"></nz-link>`);\n      }\n    }\n  });\n  const links = linkArray.join('\\n');\n  return `\n<nz-affix class=\"toc-affix\" [nzOffsetTop]=\"16\">\n  <nz-anchor [nzAffix]=\"false\" nzShowInkInFixed (nzClick)=\"goLink($event)\">\n    ${links}\n  </nz-anchor>\n</nz-affix>`;\n}\n\nfunction generateModule(docsPath: string, docsMap: Record<string, I18n<Buffer>>): void {\n  let router = '';\n  for (const name in docsMap) {\n    router += `\\t{ path: '${name}/zh', loadComponent: () => import('./${name}-zh') },\\n`;\n    router += `\\t{ path: '${name}/en', loadComponent: () => import('./${name}-en') },\\n`;\n  }\n  const module = routesTemplate.replace(/{{routes}}/g, router);\n  writeFileSync(path.join(docsPath, `routes.ts`), module);\n}\n"
  },
  {
    "path": "scripts/site/utils/generate-routes.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { readFileSync, writeFileSync } from 'fs-extra';\n\nimport path from 'path';\n\nimport {\n  ComponentChildRouter,\n  ComponentIndexDocMap,\n  ComponentIndexDocMeta,\n  I18n,\n  Language,\n  RouterList\n} from '../types';\n\nconst templateRouter = String(readFileSync(path.resolve(__dirname, '../template/router.template.ts')));\n\n/**\n * Generate routes for the target component\n */\nfunction generateLanguageData(\n  itemData: I18n<ComponentIndexDocMeta>,\n  language: Language,\n  reverseMap: Record<string, { list: ComponentChildRouter[]; language: Language }>,\n  key: string\n): void {\n  const { subtitle = '', title, type, tag = '', cover, experimental, description = '', hidden } = itemData[language];\n  const content: ComponentChildRouter = {\n    label: title,\n    path: `${experimental ? 'experimental' : 'components'}/${key}/${language}`,\n    zh: subtitle,\n    experimental,\n    hidden,\n    cover,\n    tag,\n    description\n  };\n  if (!reverseMap[type]) {\n    reverseMap[type] = { list: [content], language };\n  } else {\n    reverseMap[type].list.push(content);\n  }\n}\n\nfunction generateNav(componentsDocMap: ComponentIndexDocMap): {\n  reverseMap: Record<string, { list: ComponentChildRouter[]; language: string }>;\n  routes: string;\n} {\n  const reverseMap = {};\n  let routes = '';\n  for (const key in componentsDocMap) {\n    generateLanguageData(componentsDocMap[key], 'zh', reverseMap, key);\n    generateLanguageData(componentsDocMap[key], 'en', reverseMap, key);\n    const experimental = componentsDocMap[key]['zh'].experimental || componentsDocMap[key]['en'].experimental;\n    const routePath = `${experimental ? 'experimental' : 'components'}/${key}`;\n    routes += `  {path: '${routePath}', loadChildren: () => import('./${key}/routes')},\\n`;\n  }\n  return { reverseMap, routes };\n}\n\n/**\n * Generate routes file for the documentation site\n */\nexport function generateRoutes(\n  showCaseTargetPath: string,\n  componentsDocMap: ComponentIndexDocMap,\n  docsMeta: ComponentIndexDocMap\n): void {\n  const router: RouterList = { intro: [], components: [] };\n  for (const key in docsMeta) {\n    const enMeta = docsMeta[key].en;\n    const zhMeta = docsMeta[key].zh;\n    router.intro.push({\n      path: `docs/${key}/en`,\n      label: enMeta.title,\n      language: 'en',\n      order: enMeta.order ?? 0,\n      hidden: !!enMeta.hidden,\n      description: enMeta.description ?? '',\n      tag: enMeta.tag,\n      experimental: !!enMeta.experimental\n    });\n    router.intro.push({\n      path: `docs/${key}/zh`,\n      label: zhMeta.title,\n      language: 'zh',\n      order: zhMeta.order ?? 0,\n      hidden: !!zhMeta.hidden,\n      description: zhMeta.description ?? '',\n      tag: zhMeta.tag,\n      experimental: !!zhMeta.experimental\n    });\n  }\n  router.intro.sort((pre, next) => pre.order - next.order);\n  writeFileSync(path.join(showCaseTargetPath, `intros.json`), JSON.stringify(router.intro, null, 2));\n  const navData = generateNav(componentsDocMap);\n  const routes = navData.routes;\n  for (const key in navData.reverseMap) {\n    router.components.push({\n      name: key,\n      language: navData.reverseMap[key].language,\n      children: navData.reverseMap[key].list.filter(item => !item.experimental),\n      experimentalChildren: navData.reverseMap[key].list.filter(item => item.experimental && !item.hidden)\n    });\n  }\n\n  const sortMap: Record<string, number> = {\n    General: 0,\n    通用: 0,\n    Layout: 1,\n    布局: 1,\n    Navigation: 2,\n    导航: 2,\n    'Data Entry': 3,\n    数据录入: 3,\n    'Data Display': 4,\n    数据展示: 4,\n    Feedback: 5,\n    反馈: 5,\n    Localization: 6,\n    Other: 7,\n    其他: 7\n  };\n  router.components.sort((pre, next) => sortMap[pre.name] - sortMap[next.name]);\n  const fileContent = templateRouter\n    .replace(/{{intro}}/g, JSON.stringify(router.intro, null, 2))\n    .replace(/{{components}}/g, JSON.stringify(router.components, null, 2))\n    .replace(/{{routes}}/g, routes);\n  writeFileSync(path.join(showCaseTargetPath, `router.ts`), fileContent);\n}\n"
  },
  {
    "path": "scripts/site/utils/generate-title.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { readFileSync } from 'fs-extra';\n\nimport path from 'path';\n\nimport { ComponentIndexDocMeta } from '../types';\n\nconst template = String(readFileSync(path.resolve(__dirname, '../template/title.template.html')));\n\nexport function generateTitle(meta: ComponentIndexDocMeta): string {\n  return template.replace(/{{title}}/g, meta.title).replace(/{{subtitle}}/g, meta.subtitle || '');\n}\n"
  },
  {
    "path": "scripts/site/utils/get-meta.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { parseFragment, TreeAdapterTypeMap } from 'parse5';\nimport { loadFront } from 'yaml-front-matter';\n\nimport md from '../markdown';\nimport { ComponentIndexDocMeta } from '../types';\n\ninterface TextNode {\n  value: string;\n}\n\ntype DOMTreeAdapterTypeMap = TreeAdapterTypeMap<\n  Node,\n  ParentNode,\n  ChildNode,\n  Document,\n  DocumentFragment,\n  Element,\n  Comment,\n  TextNode,\n  unknown,\n  unknown\n>;\n\nfunction findNodeByName(fragment: Node, name: string[], result: Node[] = []): void {\n  if (name.includes(fragment.nodeName)) {\n    result.push(fragment);\n  }\n\n  if (fragment?.childNodes) {\n    fragment.childNodes.forEach(childNode => {\n      findNodeByName(childNode, name, result);\n    });\n  }\n}\n\nexport function getMeta(file: Buffer): ComponentIndexDocMeta {\n  const meta = loadFront(file) as ComponentIndexDocMeta;\n\n  let description = '';\n  if (meta.description) {\n    meta.rawDescription = meta.description;\n    if (meta.subtitle) {\n      description = `Angular ${meta.subtitle}组件，${meta.description}`;\n    } else if (meta.title) {\n      description = `Angular ${meta.title} Component, ${meta.description}`;\n    }\n    meta.description = description;\n    return meta;\n  }\n\n  const content = md.parse(meta.__content ?? '', { async: false });\n  const fragment = parseFragment<DOMTreeAdapterTypeMap>(content);\n  const paragraphs: Node[] = [];\n  findNodeByName(fragment, ['p', 'li'], paragraphs);\n  const contents = paragraphs\n    .map(f => {\n      const c: Node[] = [];\n      findNodeByName(f, ['#text'], c);\n      return c as unknown as TextNode[];\n    })\n    .flat();\n  for (const content of contents) {\n    if (description.length >= 150) {\n      break;\n    }\n    description = description + content['value'];\n  }\n  if (description.length > 150) {\n    description = `${description.slice(0, 150)}...`;\n  }\n  meta.description = description;\n  return meta;\n}\n"
  },
  {
    "path": "scripts/site/utils/parse-doc-md.ts",
    "content": "/**\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE\n */\n\nimport { Root, RootContent } from 'mdast';\nimport { remark } from 'remark';\nimport { loadFront } from 'yaml-front-matter';\n\nimport md from '../markdown';\nimport { angularNonBindAble } from './angular-non-bindable';\nimport { getMeta } from './get-meta';\nimport { ComponentIndexDoc, ComponentDemoDoc, ComponentDemoDocMeta } from '../types';\n\nfunction stringifyInlineCode(node: RootContent): string {\n  return remark.stringify(node as unknown as Root);\n}\n\n/**\n * Parse doc markdown file\n */\nexport function parseDocMd(file: Buffer, path: string): ComponentIndexDoc {\n  const meta = getMeta(file);\n  const content = meta.__content;\n  delete meta.__content;\n\n  const ast = remark.parse(content);\n  // 分离前后两部分\n  let isAfterAPIHeading = false;\n  let firstPart = '';\n  let secondPart = '';\n\n  ast.children.forEach(child => {\n    if (child.type === 'heading' && child.depth === 2) {\n      const firstChild = child.children[0];\n      if (firstChild.type === 'text' && firstChild.value === 'API') {\n        isAfterAPIHeading = true;\n      }\n    }\n    if (!isAfterAPIHeading) {\n      firstPart += md.parse(stringifyInlineCode(child));\n    } else {\n      secondPart += md.parse(stringifyInlineCode(child));\n    }\n  });\n\n  return {\n    meta: meta,\n    path: path,\n    whenToUse: angularNonBindAble(firstPart),\n    api: angularNonBindAble(secondPart)\n  };\n}\n\n/**\n * Parse demo markdown file\n */\nexport function parseDemoMd(file: Buffer): Pick<ComponentDemoDoc, 'meta' | 'zh' | 'en'> {\n  const meta = loadFront(file) as ComponentDemoDocMeta;\n  const content = meta.__content;\n  delete meta.__content;\n\n  const ast = remark.parse(content);\n  // 分离中英文\n  let isAfterENHeading = false;\n  let zhPart = '';\n  let enPart = '';\n\n  ast.children.forEach(child => {\n    if (child.type === 'heading' && child.depth === 2) {\n      const firstChild = child.children[0];\n      if (firstChild.type === 'text' && firstChild.value === 'en-US') {\n        isAfterENHeading = true;\n      }\n    } else if (!isAfterENHeading) {\n      zhPart += md.parse(stringifyInlineCode(child));\n    } else {\n      enPart += md.parse(stringifyInlineCode(child));\n    }\n  });\n\n  return {\n    meta,\n    zh: angularNonBindAble(zhPart),\n    en: angularNonBindAble(enPart)\n  };\n}\n"
  },
  {
    "path": "tea.yaml",
    "content": "# https://tea.xyz/what-is-this-file\n---\nversion: 1.0.0\ncodeOwners:\n  - '0x0C2E137F2641aB7B740Adec53ae152e8f4A9D761'\nquorum: 1\n"
  },
  {
    "path": "tsconfig-build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"./publish/src\",\n    \"inlineSources\": true,\n    \"declaration\": true,\n    \"types\": []\n  },\n  \"angularCompilerOptions\": {\n    \"strictInjectionParameters\": true,\n    \"strictInputAccessModifiers\": true,\n    \"strictTemplates\": true,\n    \"fullTemplateTypeCheck\": true,\n    \"enableResourceInlining\": true,\n    \"strictMetadataEmit\": true,\n    \"flatModuleOutFile\": \"index.js\",\n    \"flatModuleId\": \"ng-zorro-antd\",\n    \"skipTemplateCodegen\": true\n  }\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "// TypeScript config file that matches all source files in the project. This file is read by\n// IDEs and TSLint. For IDEs it ensures that `experimentalDecorator` warnings are not showing up.\n// optionalChainNotNullable: https://github.com/angular/angular/issues/46918\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \"./\",\n    \"module\": \"es2020\",\n    \"importHelpers\": true,\n    \"esModuleInterop\": true,\n    \"rootDir\": \".\",\n    \"outDir\": \"./dist/out-tsc\",\n    \"sourceMap\": true,\n    \"declaration\": false,\n    \"moduleResolution\": \"bundler\",\n    \"target\": \"ES2022\",\n    \"noImplicitAny\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitOverride\": true,\n    \"noFallthroughCasesInSwitch\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"strict\": true,\n    \"skipLibCheck\": true,\n    \"types\": [\n      \"jasmine\"\n    ]\n  },\n  \"angularCompilerOptions\": {\n    \"strictStandalone\": true,\n    \"typeCheckHostBindings\": true,\n    \"extendedDiagnostics\": {\n      \"checks\": {\n        \"optionalChainNotNullable\": \"suppress\"\n      }\n    }\n  }\n}\n"
  }
]